committed by
GitHub
81 changed files with 169 additions and 753 deletions
@ -1,4 +1,4 @@ |
|||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public sealed class ApplicationGlobals |
public sealed class ApplicationGlobals |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public sealed class BuildDockerImageStep : ServiceExecutor.Step |
public sealed class BuildDockerImageStep : ServiceExecutor.Step |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public sealed class CombineStep : ServiceExecutor.Step |
public sealed class CombineStep : ServiceExecutor.Step |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
internal class CommandException : Exception |
internal class CommandException : Exception |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public class ComputedBindings : ServiceOutput |
public class ComputedBindings : ServiceOutput |
||||
{ |
{ |
||||
@ -1,4 +1,4 @@ |
|||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public sealed class ContainerInfo |
public sealed class ContainerInfo |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public sealed class ContainerRegistry |
public sealed class ContainerRegistry |
||||
{ |
{ |
||||
@ -1,4 +1,4 @@ |
|||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public enum DeploymentKind |
public enum DeploymentKind |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System.IO; |
using System.IO; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public static class DirectoryCopy |
public static class DirectoryCopy |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public sealed class DockerImage : Source |
public sealed class DockerImage : Source |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public class EnvironmentAttribute : Attribute |
public class EnvironmentAttribute : Attribute |
||||
{ |
{ |
||||
@ -1,4 +1,4 @@ |
|||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public static class Environments |
public static class Environments |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public sealed class Framework |
public sealed class Framework |
||||
{ |
{ |
||||
@ -1,7 +1,7 @@ |
|||||
using System.IO; |
using System.IO; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
internal sealed class GenerateDockerfileStep : ServiceExecutor.Step |
internal sealed class GenerateDockerfileStep : ServiceExecutor.Step |
||||
{ |
{ |
||||
@ -1,7 +1,7 @@ |
|||||
using System.IO; |
using System.IO; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
internal sealed class GenerateHelmChartStep : ServiceExecutor.Step |
internal sealed class GenerateHelmChartStep : ServiceExecutor.Step |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public sealed class GenerateKubernetesManifestStep : ServiceExecutor.Step |
public sealed class GenerateKubernetesManifestStep : ServiceExecutor.Step |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
internal sealed class GenerateOamComponentStep : ServiceExecutor.Step |
internal sealed class GenerateOamComponentStep : ServiceExecutor.Step |
||||
{ |
{ |
||||
@ -1,4 +1,4 @@ |
|||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public sealed class GeneratedAssets |
public sealed class GeneratedAssets |
||||
{ |
{ |
||||
@ -1,4 +1,4 @@ |
|||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public sealed class HelmChartStep : Step |
public sealed class HelmChartStep : Step |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using YamlDotNet.RepresentationModel; |
using YamlDotNet.RepresentationModel; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
internal interface IYamlManifestOutput |
internal interface IYamlManifestOutput |
||||
{ |
{ |
||||
@ -1,7 +1,7 @@ |
|||||
using System; |
using System; |
||||
using YamlDotNet.RepresentationModel; |
using YamlDotNet.RepresentationModel; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
internal sealed class KubernetesDeploymentOutput : ServiceOutput, IYamlManifestOutput |
internal sealed class KubernetesDeploymentOutput : ServiceOutput, IYamlManifestOutput |
||||
{ |
{ |
||||
@ -1,7 +1,7 @@ |
|||||
using System; |
using System; |
||||
using YamlDotNet.RepresentationModel; |
using YamlDotNet.RepresentationModel; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
internal sealed class KubernetesServiceOutput : ServiceOutput, IYamlManifestOutput |
internal sealed class KubernetesServiceOutput : ServiceOutput, IYamlManifestOutput |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
internal static class Names |
internal static class Names |
||||
{ |
{ |
||||
@ -1,7 +1,7 @@ |
|||||
using System; |
using System; |
||||
using YamlDotNet.RepresentationModel; |
using YamlDotNet.RepresentationModel; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
internal sealed class OamComponentOutput : ServiceOutput, IYamlManifestOutput |
internal sealed class OamComponentOutput : ServiceOutput, IYamlManifestOutput |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public sealed class PipelineHolder |
public sealed class PipelineHolder |
||||
{ |
{ |
||||
@ -1,4 +1,4 @@ |
|||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
static class Program |
static class Program |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public sealed class Project : Source |
public sealed class Project : Source |
||||
{ |
{ |
||||
@ -1,7 +1,7 @@ |
|||||
using System.Linq; |
using System.Linq; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public sealed class PushDockerImageStep : ServiceExecutor.Step |
public sealed class PushDockerImageStep : ServiceExecutor.Step |
||||
{ |
{ |
||||
@ -1,8 +1,8 @@ |
|||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ImportGroup Condition=" '$(TargetFramework)' == '' AND '$(ExcludeRestorePackageImports)' != 'true' "> |
<ImportGroup Condition=" '$(TargetFramework)' == '' AND '$(ExcludeRestorePackageImports)' != 'true' "> |
||||
<Import Project="$(OpulenceTargetLocation)\buildMultiTargeting\Opulence.targets" Condition="'$(OpulenceTargetLocation)'!=''" /> |
<Import Project="$(TyeTargetLocation)\buildMultiTargeting\Tye.targets" Condition="'$(TyeTargetLocation)'!=''" /> |
||||
</ImportGroup> |
</ImportGroup> |
||||
<ImportGroup Condition=" '$(TargetFramework)' != '' AND '$(ExcludeRestorePackageImports)' != 'true' "> |
<ImportGroup Condition=" '$(TargetFramework)' != '' AND '$(ExcludeRestorePackageImports)' != 'true' "> |
||||
<Import Project="$(OpulenceTargetLocation)\build\Opulence.targets" Condition="'$(OpulenceTargetLocation)'!=''" /> |
<Import Project="$(TyeTargetLocation)\build\Tye.targets" Condition="'$(TyeTargetLocation)'!=''" /> |
||||
</ImportGroup> |
</ImportGroup> |
||||
</Project> |
</Project> |
||||
@ -1,4 +1,4 @@ |
|||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public class Secret |
public class Secret |
||||
{ |
{ |
||||
@ -1,7 +1,7 @@ |
|||||
using System; |
using System; |
||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public sealed class Service |
public sealed class Service |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public class ServiceBinding |
public class ServiceBinding |
||||
{ |
{ |
||||
@ -1,4 +1,4 @@ |
|||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public abstract class Source |
public abstract class Source |
||||
{ |
{ |
||||
@ -1,4 +1,4 @@ |
|||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public abstract class Step |
public abstract class Step |
||||
{ |
{ |
||||
@ -1,4 +1,4 @@ |
|||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
internal class StepView |
internal class StepView |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System.IO; |
using System.IO; |
||||
|
|
||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
internal static class Templates |
internal static class Templates |
||||
{ |
{ |
||||
@ -0,0 +1,34 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.1</TargetFramework> |
||||
|
<RootNamespace>Tye</RootNamespace> |
||||
|
<LangVersion>8.0</LangVersion> |
||||
|
<Nullable>Enable</Nullable> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="KubernetesClient" Version="1.6.11" /> |
||||
|
<PackageReference Include="semver" Version="2.0.6" /> |
||||
|
<PackageReference Include="Sln" Version="0.3.0" /> |
||||
|
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20071.2" /> |
||||
|
<PackageReference Include="System.Commandline.Rendering" Version="0.3.0-alpha.20070.2" /> |
||||
|
<PackageReference Include="YamlDotNet" Version="8.0.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<Content Include="build\**" CopyToOutputDirectory="PreserveNewest" /> |
||||
|
<Content Include="buildMultiTargeting\**" CopyToOutputDirectory="PreserveNewest" /> |
||||
|
<Content Include="Templates\**" CopyToOutputDirectory="PreserveNewest" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<Compile Include="..\tye\TempDirectory.cs" Link="TempDirectory.cs" /> |
||||
|
<Compile Include="..\tye\TempFile.cs" Link="TempFile.cs" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<EmbeddedResource Include="Resources\Imports.targets" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -1,4 +1,4 @@ |
|||||
namespace Opulence |
namespace Tye |
||||
{ |
{ |
||||
public enum Verbosity |
public enum Verbosity |
||||
{ |
{ |
||||
@ -1,13 +0,0 @@ |
|||||
<Project Sdk="Microsoft.NET.Sdk"> |
|
||||
|
|
||||
<PropertyGroup> |
|
||||
<TargetFramework>netstandard2.0</TargetFramework> |
|
||||
<LangVersion>8.0</LangVersion> |
|
||||
<Nullable>Enable</Nullable> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<PackageReference Include="System.Text.Json" Version="4.7.0" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
</Project> |
|
||||
@ -1,142 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.IO; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.Build.Construction; |
|
||||
|
|
||||
namespace Opulence |
|
||||
{ |
|
||||
public static class ApplicationFactory |
|
||||
{ |
|
||||
public static async Task<Application> CreateApplicationAsync(OutputContext output, FileInfo projectFile) |
|
||||
{ |
|
||||
if (output is null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(output)); |
|
||||
} |
|
||||
|
|
||||
if (projectFile is null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(projectFile)); |
|
||||
} |
|
||||
|
|
||||
if (string.Equals(projectFile.Extension, ".sln", StringComparison.Ordinal)) |
|
||||
{ |
|
||||
output.WriteDebugLine($"Solution '{projectFile.FullName}' was provided as input."); |
|
||||
return await CreateApplicationForSolutionAsync(output, projectFile); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
output.WriteDebugLine($"Project '{projectFile.FullName}' was provided as input."); |
|
||||
return await CreateApplicationForProjectAsync(output, projectFile); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private static async Task<Application> CreateApplicationForProjectAsync(OutputContext output, FileInfo projectFile) |
|
||||
{ |
|
||||
// Project workflow:
|
|
||||
//
|
|
||||
// 1. Determine if there's an 'Opulence.csx' - use that to initialize the set of services.
|
|
||||
// 2. If there's not an 'Opulence.csx' then move on with just the project.
|
|
||||
|
|
||||
var application = await ScriptRunner.RunCustomizationScriptAsync(output, projectFile); |
|
||||
if (application != null) |
|
||||
{ |
|
||||
return application; |
|
||||
} |
|
||||
|
|
||||
return await InferApplicationForProject(output, projectFile); |
|
||||
} |
|
||||
|
|
||||
private static async Task<Application> InferApplicationForProject(OutputContext output, FileInfo projectFile) |
|
||||
{ |
|
||||
var globals = new ApplicationGlobals(); |
|
||||
globals.Name = Names.NormalizeToDns(Path.GetFileNameWithoutExtension(projectFile.Name)); |
|
||||
|
|
||||
var services = new List<ServiceEntry>(); |
|
||||
|
|
||||
var name = Path.GetFileNameWithoutExtension(projectFile.Name); |
|
||||
var project = new Project(projectFile.FullName); |
|
||||
var service = new ServiceEntry(new Service(name), name); |
|
||||
service.Service.Source = project; |
|
||||
services.Add(service); |
|
||||
|
|
||||
await ProjectReader.ReadProjectDetailsAsync(output, projectFile, project); |
|
||||
|
|
||||
var container = new ContainerInfo(); |
|
||||
service.Service.GeneratedAssets.Container = container; |
|
||||
|
|
||||
var application = new GroveledApplication(globals, projectFile.DirectoryName, services); |
|
||||
|
|
||||
DockerfileGenerator.ApplyContainerDefaults(application, service, project, container); |
|
||||
|
|
||||
return application; |
|
||||
} |
|
||||
|
|
||||
private static async Task<Application> CreateApplicationForSolutionAsync(OutputContext output, FileInfo solutionFile) |
|
||||
{ |
|
||||
// Solution workflow:
|
|
||||
//
|
|
||||
// 1. If there's an 'Opulence.csx' - use that that to initialize the set of services.
|
|
||||
// 2. If there's not an 'Opulence.csx' then grovel all of the projects in the solution looking
|
|
||||
// for executable projects.
|
|
||||
|
|
||||
SolutionFile solution; |
|
||||
try |
|
||||
{ |
|
||||
solution = SolutionFile.Parse(solutionFile.FullName); |
|
||||
} |
|
||||
catch (Exception ex) |
|
||||
{ |
|
||||
throw new CommandException($"Parsing solution file '{solutionFile.FullName}' failed.", ex); |
|
||||
} |
|
||||
|
|
||||
var application = await ScriptRunner.RunCustomizationScriptAsync(output, solutionFile, solution); |
|
||||
if (application != null) |
|
||||
{ |
|
||||
return application; |
|
||||
} |
|
||||
|
|
||||
return await InferApplicationForSolution(output, solutionFile, solution); |
|
||||
} |
|
||||
|
|
||||
private static async Task<Application> InferApplicationForSolution(OutputContext output, FileInfo solutionFile, SolutionFile solution) |
|
||||
{ |
|
||||
var globals = new ApplicationGlobals(); |
|
||||
|
|
||||
globals.Name = Names.NormalizeToDns(Path.GetFileNameWithoutExtension(solutionFile.Name)); |
|
||||
|
|
||||
var services = new List<ServiceEntry>(); |
|
||||
for (var i = 0; i < solution.ProjectsInOrder.Count; i++) |
|
||||
{ |
|
||||
// The library we're using doesn't translate Windows style paths automatically.
|
|
||||
var solutionProject = solution.ProjectsInOrder[i]; |
|
||||
if (solutionProject.AbsolutePath.EndsWith(".csproj", StringComparison.Ordinal)) |
|
||||
{ |
|
||||
var projectFilePath = solutionProject.RelativePath.Replace('\\', Path.DirectorySeparatorChar); |
|
||||
var projectFile = new FileInfo(projectFilePath); |
|
||||
|
|
||||
var name = Path.GetFileNameWithoutExtension(projectFile.Name); |
|
||||
var project = new Project(projectFile.FullName); |
|
||||
var service = new ServiceEntry(new Service(name), name); |
|
||||
service.Service.Source = project; |
|
||||
services.Add(service); |
|
||||
|
|
||||
await ProjectReader.ReadProjectDetailsAsync(output, projectFile, project); |
|
||||
|
|
||||
var container = new ContainerInfo(); |
|
||||
service.Service.GeneratedAssets.Container = container; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
var application = new GroveledApplication(globals, solutionFile.DirectoryName, services); |
|
||||
|
|
||||
foreach (var service in application.Services) |
|
||||
{ |
|
||||
DockerfileGenerator.ApplyContainerDefaults(application, service, (Project)service.Service.Source!, service.Service.GeneratedAssets.Container!); |
|
||||
} |
|
||||
|
|
||||
return application; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,59 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.CommandLine; |
|
||||
using System.CommandLine.Invocation; |
|
||||
using System.IO; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace Opulence |
|
||||
{ |
|
||||
internal static class GenerateCommand |
|
||||
{ |
|
||||
public static Command Create() |
|
||||
{ |
|
||||
var command = new Command("generate", "Generate assets") |
|
||||
{ |
|
||||
StandardOptions.Project, |
|
||||
StandardOptions.Verbosity, |
|
||||
StandardOptions.Outputs, |
|
||||
StandardOptions.Force, |
|
||||
}; |
|
||||
|
|
||||
command.Handler = CommandHandler.Create<IConsole, FileInfo, Verbosity, List<string>, bool>((console, project, verbosity, outputs, force) => |
|
||||
{ |
|
||||
var output = new OutputContext(console, verbosity); |
|
||||
return ExecuteAsync(output, project, outputs, force); |
|
||||
}); |
|
||||
|
|
||||
return command; |
|
||||
} |
|
||||
|
|
||||
private static async Task ExecuteAsync(OutputContext output, FileInfo projectFile, List<string> outputs, bool force) |
|
||||
{ |
|
||||
output.WriteBanner(); |
|
||||
|
|
||||
var application = await ApplicationFactory.CreateApplicationAsync(output, projectFile); |
|
||||
|
|
||||
var steps = new List<ServiceExecutor.Step>(); |
|
||||
|
|
||||
if (outputs.Count == 0 || outputs.Contains("container")) |
|
||||
{ |
|
||||
steps.Add(new GenerateDockerfileStep() { Force = force, }); |
|
||||
} |
|
||||
|
|
||||
if (outputs.Count == 0 || outputs.Contains("chart")) |
|
||||
{ |
|
||||
steps.Add(new GenerateHelmChartStep()); |
|
||||
} |
|
||||
|
|
||||
var executor = new ServiceExecutor(output, application, steps); |
|
||||
foreach (var service in application.Services) |
|
||||
{ |
|
||||
if (service.IsMatchForProject(application, projectFile)) |
|
||||
{ |
|
||||
await executor.ExecuteAsync(service); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,119 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.CommandLine; |
|
||||
using System.CommandLine.Invocation; |
|
||||
using System.IO; |
|
||||
using System.Text; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace Opulence |
|
||||
{ |
|
||||
public class PackageCommand |
|
||||
{ |
|
||||
public static Command Create() |
|
||||
{ |
|
||||
var command = new Command("package", "Package the project") |
|
||||
{ |
|
||||
StandardOptions.Project, |
|
||||
StandardOptions.Verbosity, |
|
||||
StandardOptions.Force, |
|
||||
StandardOptions.Environment, |
|
||||
new Option(new []{ "-o", "--output" }, "Output directory") |
|
||||
{ |
|
||||
Argument = new Argument<DirectoryInfo>("output", () => new DirectoryInfo(Environment.CurrentDirectory)) |
|
||||
{ |
|
||||
Arity = ArgumentArity.ExactlyOne, |
|
||||
}, |
|
||||
Required = false, |
|
||||
}, |
|
||||
}; |
|
||||
command.Handler = CommandHandler.Create<IConsole, FileInfo, DirectoryInfo, string, bool, Verbosity>((console, project, output, environment, force, verbosity) => |
|
||||
{ |
|
||||
return ExecuteAsync(new OutputContext(console, verbosity), project, output, environment, force); |
|
||||
}); |
|
||||
|
|
||||
return command; |
|
||||
} |
|
||||
|
|
||||
private static async Task ExecuteAsync(OutputContext output, FileInfo projectFile, DirectoryInfo outputDirectory, string environment, bool force) |
|
||||
{ |
|
||||
output.WriteBanner(); |
|
||||
|
|
||||
var application = await ApplicationFactory.CreateApplicationAsync(output, projectFile); |
|
||||
|
|
||||
var steps = new List<ServiceExecutor.Step> |
|
||||
{ |
|
||||
new CombineStep() { Environment = environment, }, |
|
||||
new BuildDockerImageStep() { Environment = environment, }, |
|
||||
}; |
|
||||
|
|
||||
if (application.Globals.DeploymentKind == DeploymentKind.None) |
|
||||
{ |
|
||||
// No extra steps
|
|
||||
} |
|
||||
else if (application.Globals.DeploymentKind == DeploymentKind.Kubernetes) |
|
||||
{ |
|
||||
steps.Add(new GenerateKubernetesManifestStep() { Environment = environment, }); |
|
||||
} |
|
||||
else if (application.Globals.DeploymentKind == DeploymentKind.Oam) |
|
||||
{ |
|
||||
steps.Add(new GenerateOamComponentStep() { Environment = environment, }); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
throw new InvalidOperationException($"Unknown DeploymentKind: " + application.Globals.DeploymentKind); |
|
||||
} |
|
||||
|
|
||||
// If this is command is for a project, then write out the component manifest
|
|
||||
// for just the project. We won't run the "application package" part.
|
|
||||
if (!string.Equals(".sln", projectFile.Extension, StringComparison.Ordinal)) |
|
||||
{ |
|
||||
steps.Add(new WriteServiceYamlStep() { OutputDirectory = outputDirectory, Force = force, }); |
|
||||
} |
|
||||
|
|
||||
var executor = new ServiceExecutor(output, application, steps); |
|
||||
foreach (var service in application.Services) |
|
||||
{ |
|
||||
if (service.IsMatchForProject(application, projectFile)) |
|
||||
{ |
|
||||
await executor.ExecuteAsync(service); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (string.Equals(".sln", projectFile.Extension, StringComparison.Ordinal)) |
|
||||
{ |
|
||||
await PackageApplicationAsync(output, application, outputDirectory, Path.GetFileNameWithoutExtension(projectFile.Name), environment); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private static async Task PackageApplicationAsync(OutputContext output, Application application, DirectoryInfo outputDirectory, string applicationName, string environment) |
|
||||
{ |
|
||||
using var step = output.BeginStep("Writing Application Manifests..."); |
|
||||
var outputFile = Path.Combine(outputDirectory.FullName, $"{applicationName}-{environment}.yaml"); |
|
||||
output.WriteInfoLine($"Writing output to '{outputFile}'."); |
|
||||
|
|
||||
File.Delete(outputFile); |
|
||||
using var stream = File.OpenWrite(outputFile); |
|
||||
using var writer = new StreamWriter(stream, Encoding.UTF8, leaveOpen: true); |
|
||||
|
|
||||
if (application.Globals.DeploymentKind == DeploymentKind.None) |
|
||||
{ |
|
||||
// No extra steps
|
|
||||
} |
|
||||
else if (application.Globals.DeploymentKind == DeploymentKind.Kubernetes) |
|
||||
{ |
|
||||
await ApplicationYamlWriter.WriteAsync(output, writer, application); |
|
||||
} |
|
||||
else if (application.Globals.DeploymentKind == DeploymentKind.Oam) |
|
||||
{ |
|
||||
await OamApplicationGenerator.WriteOamApplicationAsync(writer, output, application, applicationName, environment); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
throw new InvalidOperationException($"Unknown DeploymentKind: " + application.Globals.DeploymentKind); |
|
||||
} |
|
||||
|
|
||||
step.MarkComplete(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,8 +0,0 @@ |
|||||
{ |
|
||||
"profiles": { |
|
||||
"dotnet-opulence": { |
|
||||
"commandName": "Project", |
|
||||
"commandLineArgs": "" |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,55 +0,0 @@ |
|||||
using System; |
|
||||
using System.CommandLine; |
|
||||
using System.CommandLine.Invocation; |
|
||||
using System.IO; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace Opulence |
|
||||
{ |
|
||||
public class PushCommand |
|
||||
{ |
|
||||
public static Command Create() |
|
||||
{ |
|
||||
var command = new Command("push", "Push the application to registry") |
|
||||
{ |
|
||||
StandardOptions.Project, |
|
||||
StandardOptions.Verbosity, |
|
||||
StandardOptions.Environment, |
|
||||
}; |
|
||||
|
|
||||
command.Handler = CommandHandler.Create<IConsole, FileInfo, string, Verbosity>((console, project, environment, verbosity) => |
|
||||
{ |
|
||||
return ExecuteAsync(new OutputContext(console, verbosity), project, environment); |
|
||||
}); |
|
||||
|
|
||||
return command; |
|
||||
} |
|
||||
|
|
||||
private static async Task ExecuteAsync(OutputContext output, FileInfo projectFile, string environment) |
|
||||
{ |
|
||||
output.WriteBanner(); |
|
||||
|
|
||||
var application = await ApplicationFactory.CreateApplicationAsync(output, projectFile); |
|
||||
if (application.Globals.Registry?.Hostname == null) |
|
||||
{ |
|
||||
throw new CommandException("A registry is required for push operations. run 'dotnet-opulence init'."); |
|
||||
} |
|
||||
|
|
||||
var steps = new ServiceExecutor.Step[] |
|
||||
{ |
|
||||
new CombineStep() { Environment = environment, }, |
|
||||
new BuildDockerImageStep() { Environment = environment, }, |
|
||||
new PushDockerImageStep() { Environment = environment, }, |
|
||||
}; |
|
||||
|
|
||||
var executor = new ServiceExecutor(output, application, steps); |
|
||||
foreach (var service in application.Services) |
|
||||
{ |
|
||||
if (service.IsMatchForProject(application, projectFile)) |
|
||||
{ |
|
||||
await executor.ExecuteAsync(service); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,166 +0,0 @@ |
|||||
using System; |
|
||||
using System.IO; |
|
||||
using System.Text; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.Build.Construction; |
|
||||
using Microsoft.CodeAnalysis.CSharp; |
|
||||
using Microsoft.CodeAnalysis.CSharp.Scripting; |
|
||||
using Microsoft.CodeAnalysis.Scripting; |
|
||||
|
|
||||
namespace Opulence |
|
||||
{ |
|
||||
internal static class ScriptRunner |
|
||||
{ |
|
||||
public static async Task<ApplicationWrapper?> RunCustomizationScriptAsync(OutputContext output, FileInfo projectFile) |
|
||||
{ |
|
||||
if (output is null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(output)); |
|
||||
} |
|
||||
|
|
||||
using (var step = output.BeginStep("Applying Application Customizations...")) |
|
||||
{ |
|
||||
var scriptFilePath = DirectorySearch.AscendingSearch(projectFile.DirectoryName, "Opulence.csx"); |
|
||||
output.WriteDebugLine($"Looking for customization script above '{projectFile}'."); |
|
||||
if (!File.Exists(scriptFilePath)) |
|
||||
{ |
|
||||
output.WriteDebugLine($"No customization script found."); |
|
||||
step.MarkComplete("Skipping..."); |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
output.WriteInfoLine($"Configuring application using '{Path.GetFileName(scriptFilePath)}'."); |
|
||||
|
|
||||
var code = File.ReadAllText(scriptFilePath); |
|
||||
var script = CSharpScript.Create<object>( |
|
||||
code, |
|
||||
options: ScriptOptions.Default.WithImports(new[] { "System", "System.Collections.Generic", }), |
|
||||
globalsType: typeof(PipelineHolder), |
|
||||
assemblyLoader: null); |
|
||||
script = script.ContinueWith<object>(@"return await Pipeline.ExecuteAsync(__Pipeline);", options: ScriptOptions.Default); |
|
||||
|
|
||||
output.WriteDebugLine($"Compiling {Path.GetFileName(scriptFilePath)}'."); |
|
||||
script.Compile(); |
|
||||
var diagnostics = script.Compile(); |
|
||||
if (diagnostics.Length > 0) |
|
||||
{ |
|
||||
var builder = new StringBuilder(); |
|
||||
output.WriteDebugLine($"Script '{scriptFilePath}' had compilation errors."); |
|
||||
builder.AppendLine($"Script '{scriptFilePath}' had compilation errors."); |
|
||||
foreach (var diagnostic in diagnostics) |
|
||||
{ |
|
||||
output.WriteDebugLine(CSharpDiagnosticFormatter.Instance.Format(diagnostic)); |
|
||||
builder.AppendLine(CSharpDiagnosticFormatter.Instance.Format(diagnostic)); |
|
||||
} |
|
||||
|
|
||||
throw new CommandException(builder.ToString()); |
|
||||
} |
|
||||
output.WriteDebugLine($"Done compiling {Path.GetFileName(scriptFilePath)}'."); |
|
||||
|
|
||||
var pipeline = new CustomizationPipeline( |
|
||||
output, |
|
||||
rootDirectory: Path.GetDirectoryName(scriptFilePath)!, |
|
||||
name: Names.NormalizeToDns(Path.GetFileNameWithoutExtension(projectFile.Name)), |
|
||||
solution: null, |
|
||||
projectFile); |
|
||||
var holder = new PipelineHolder(pipeline); |
|
||||
|
|
||||
output.WriteDebugLine($"Running {Path.GetFileName(scriptFilePath)}'."); |
|
||||
object obj; |
|
||||
try |
|
||||
{ |
|
||||
var result = await script.RunAsync(holder); |
|
||||
obj = result.ReturnValue; |
|
||||
} |
|
||||
catch (Exception ex) |
|
||||
{ |
|
||||
throw new CommandException($"Failed executing {Path.GetFileName(scriptFilePath)}'.", ex); |
|
||||
} |
|
||||
|
|
||||
step.MarkComplete(); |
|
||||
return new ApplicationWrapper(obj, Path.GetDirectoryName(scriptFilePath)!); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public static async Task<ApplicationWrapper?> RunCustomizationScriptAsync(OutputContext output, FileInfo solutionFile, SolutionFile solution) |
|
||||
{ |
|
||||
if (output is null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(output)); |
|
||||
} |
|
||||
|
|
||||
if (solutionFile is null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(solutionFile)); |
|
||||
} |
|
||||
|
|
||||
if (solution is null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(solution)); |
|
||||
} |
|
||||
|
|
||||
using (var step = output.BeginStep("Applying Application Customizations...")) |
|
||||
{ |
|
||||
var scriptFilePath = Path.Combine(solutionFile.DirectoryName, "Opulence.csx"); |
|
||||
output.WriteDebugLine($"Looking for customization script at '{scriptFilePath}'."); |
|
||||
if (!File.Exists(scriptFilePath)) |
|
||||
{ |
|
||||
output.WriteDebugLine($"No customization script found."); |
|
||||
step.MarkComplete("Skipping..."); |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
output.WriteInfoLine($"Configuring application using '{Path.GetFileName(scriptFilePath)}'."); |
|
||||
|
|
||||
var code = File.ReadAllText(scriptFilePath); |
|
||||
var script = CSharpScript.Create<object>( |
|
||||
code, |
|
||||
options: ScriptOptions.Default.WithImports(new[] { "System", "System.Collections.Generic", }), |
|
||||
globalsType: typeof(PipelineHolder), |
|
||||
assemblyLoader: null); |
|
||||
script = script.ContinueWith<object>(@"return await Pipeline.ExecuteAsync(__Pipeline);", options: ScriptOptions.Default); |
|
||||
|
|
||||
output.WriteDebugLine($"Compiling {Path.GetFileName(scriptFilePath)}'."); |
|
||||
script.Compile(); |
|
||||
var diagnostics = script.Compile(); |
|
||||
if (diagnostics.Length > 0) |
|
||||
{ |
|
||||
var builder = new StringBuilder(); |
|
||||
output.WriteDebugLine($"Script '{scriptFilePath}' had compilation errors."); |
|
||||
builder.AppendLine($"Script '{scriptFilePath}' had compilation errors."); |
|
||||
foreach (var diagnostic in diagnostics) |
|
||||
{ |
|
||||
output.WriteDebugLine(CSharpDiagnosticFormatter.Instance.Format(diagnostic)); |
|
||||
builder.AppendLine(CSharpDiagnosticFormatter.Instance.Format(diagnostic)); |
|
||||
} |
|
||||
|
|
||||
throw new CommandException(builder.ToString()); |
|
||||
} |
|
||||
output.WriteDebugLine($"Done compiling {Path.GetFileName(scriptFilePath)}'."); |
|
||||
|
|
||||
var pipeline = new CustomizationPipeline( |
|
||||
output, |
|
||||
rootDirectory: Path.GetDirectoryName(scriptFilePath)!, |
|
||||
name: Names.NormalizeToDns(Path.GetFileNameWithoutExtension(solutionFile.Name)), |
|
||||
solution, |
|
||||
projectFile: null); |
|
||||
var holder = new PipelineHolder(pipeline); |
|
||||
|
|
||||
output.WriteDebugLine($"Running {Path.GetFileName(scriptFilePath)}'."); |
|
||||
object obj; |
|
||||
try |
|
||||
{ |
|
||||
var result = await script.RunAsync(holder); |
|
||||
obj = result.ReturnValue; |
|
||||
} |
|
||||
catch (Exception ex) |
|
||||
{ |
|
||||
throw new CommandException($"Failed executing {Path.GetFileName(scriptFilePath)}'.", ex); |
|
||||
} |
|
||||
|
|
||||
step.MarkComplete(); |
|
||||
return new ApplicationWrapper(obj, Path.GetDirectoryName(scriptFilePath)!); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,44 +0,0 @@ |
|||||
<Project Sdk="Microsoft.NET.Sdk"> |
|
||||
|
|
||||
<PropertyGroup> |
|
||||
<OutputType>Exe</OutputType> |
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework> |
|
||||
<RootNamespace>Opulence</RootNamespace> |
|
||||
<PackAsTool>true</PackAsTool> |
|
||||
<PackageId>Opulence.dotnet-opulence</PackageId> |
|
||||
<ToolCommandName>opulence</ToolCommandName> |
|
||||
<Nullable>Enable</Nullable> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<PackageReference Include="KubernetesClient" Version="1.6.11" /> |
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.4.0" /> |
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.4.0" /> |
|
||||
<PackageReference Include="semver" Version="2.0.6" /> |
|
||||
<PackageReference Include="Sln" Version="0.3.0" /> |
|
||||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20071.2" /> |
|
||||
<PackageReference Include="System.Commandline.Rendering" Version="0.3.0-alpha.20070.2" /> |
|
||||
<PackageReference Include="System.Reflection.Metadata" Version="1.8.0" /> |
|
||||
<PackageReference Include="YamlDotNet.Signed" Version="6.0.0" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<ProjectReference Include="..\Opulence\Opulence.csproj" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<Content Include="build\**" CopyToOutputDirectory="PreserveNewest" /> |
|
||||
<Content Include="buildMultiTargeting\**" CopyToOutputDirectory="PreserveNewest" /> |
|
||||
<Content Include="Templates\**" CopyToOutputDirectory="PreserveNewest" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<Compile Include="..\..\tye\TempDirectory.cs" Link="TempDirectory.cs" /> |
|
||||
<Compile Include="..\..\tye\TempFile.cs" Link="TempFile.cs" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<EmbeddedResource Include="Resources\Imports.targets" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
</Project> |
|
||||
Loading…
Reference in new issue