Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 77 additions & 39 deletions source/Calamari.Common/CalamariFlavourProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Autofac;
using Autofac.Core;
using Autofac.Core.Registration;
using Calamari.Common.Commands;
using Calamari.Common.Features.Behaviours;
using Calamari.Common.Features.ConfigurationTransforms;
using Calamari.Common.Features.ConfigurationVariables;
using Calamari.Common.Features.EmbeddedResources;
Expand All @@ -21,18 +21,20 @@
using Calamari.Common.Features.Substitutions;
using Calamari.Common.Plumbing;
using Calamari.Common.Plumbing.Commands;
using Calamari.Common.Plumbing.Deployment.Journal;
using Calamari.Common.Plumbing.Extensions;
using Calamari.Common.Plumbing.FileSystem;
using Calamari.Common.Plumbing.Logging;
using Calamari.Common.Plumbing.Pipeline;
using Calamari.Common.Plumbing.Proxies;
using Calamari.Common.Plumbing.Variables;
using Calamari.Common.Util;

namespace Calamari.Common;

public abstract class CalamariFlavourProgram(ILog log)
{
protected int Run(string[] args)
protected async Task<int> Run(string[] args)
{
try
{
Expand All @@ -44,7 +46,9 @@ protected int Run(string[] args)
log.Verbose($"Calamari Version: {GetType().Assembly.GetInformationalVersion()}");

if (options.Command.Equals("version", StringComparison.OrdinalIgnoreCase))
{
return 0;
}

var envInfo = string.Join($"{Environment.NewLine} ",
EnvironmentHelper.SafelyGetEnvironmentInformation());
Expand All @@ -67,45 +71,72 @@ protected int Run(string[] args)

while (!Debugger.IsAttached)
{
Thread.Sleep(1000);
await Task.Delay(1000);
}
}
#endif
var isolation = container.Resolve<IScriptIsolationEnforcer>();
using var _ = isolation.Enforce(options.ScriptIsolation);
return ResolveAndExecuteCommand(container, options);
await using var _ = await isolation.EnforceAsync(options.ScriptIsolation, CancellationToken.None);
return await ResolveAndExecuteCommand(container, options);
}
catch (Exception ex)
{
return ConsoleFormatter.PrintError(log, ex);
}
}

protected abstract int ResolveAndExecuteCommand(IContainer container, CommonOptions options);
async Task<int> ResolveAndExecuteCommand(IContainer container, CommonOptions options)
{
try
{
if (container.IsRegisteredWithName<PipelineCommand>(options.Command))
{
try
{
var pipeline = container.ResolveNamed<PipelineCommand>(options.Command);
var variables = container.Resolve<IVariables>();
await pipeline.Execute(container, variables);
return 0;
}
catch (Exception ex)
{
return ConsoleFormatter.PrintError(log, ex);
}
}

return await ResolveAndExecuteCommandWithArgs(container, options);
}
catch (Exception e) when (e is ComponentNotRegisteredException or DependencyResolutionException)
{
throw new CommandException($"Could not find the command {options.Command}");
}
}

protected abstract Task<int> ResolveAndExecuteCommandWithArgs(IContainer container, CommonOptions options);

protected virtual void ConfigureContainer(ContainerBuilder builder, CommonOptions options)
{
{
//register the options into the DI
builder.RegisterInstance(options).AsSelf();
var fileSystem = CalamariPhysicalFileSystem.GetPhysicalFileSystem();
builder.RegisterInstance(fileSystem).As<ICalamariFileSystem>();
builder.RegisterType<ScriptEngine>().As<IScriptEngine>();
builder.RegisterType<VariableLogger>().AsSelf();
builder.RegisterInstance(log).As<ILog>().SingleInstance();
builder.RegisterType<FreeSpaceChecker>().As<IFreeSpaceChecker>().SingleInstance();
builder.RegisterType<CommandLineRunner>().As<ICommandLineRunner>().SingleInstance();
builder.RegisterType<CombinedPackageExtractor>().As<ICombinedPackageExtractor>();
builder.RegisterType<ExtractPackage>().As<IExtractPackage>();
builder.RegisterType<CodeGenFunctionsRegistry>().SingleInstance();
builder.RegisterType<AssemblyEmbeddedResources>().As<ICalamariEmbeddedResources>();
// For Pipeline Commands
builder.RegisterType<TransformFileLocator>().As<ITransformFileLocator>();
builder.Register(context => ConfigurationTransformer.FromVariables(context.Resolve<IVariables>(), context.Resolve<ILog>())).As<IConfigurationTransformer>();
builder.RegisterType<ConfigurationVariablesReplacer>().As<IConfigurationVariablesReplacer>();


var fileSystem = CalamariPhysicalFileSystem.GetPhysicalFileSystem();
builder.RegisterInstance(fileSystem).As<ICalamariFileSystem>();
builder.RegisterType<ScriptEngine>().As<IScriptEngine>();
builder.RegisterType<VariableLogger>().AsSelf();
builder.RegisterInstance(log).As<ILog>().SingleInstance();
builder.RegisterType<FreeSpaceChecker>().As<IFreeSpaceChecker>().SingleInstance();
builder.RegisterType<CommandLineRunner>().As<ICommandLineRunner>().SingleInstance();
builder.RegisterType<CombinedPackageExtractor>().As<ICombinedPackageExtractor>();
builder.RegisterType<ExtractPackage>().As<IExtractPackage>();
builder.RegisterType<CodeGenFunctionsRegistry>().SingleInstance();
builder.RegisterType<AssemblyEmbeddedResources>().As<ICalamariEmbeddedResources>();

// For Pipeline Commands
builder.RegisterType<TransformFileLocator>().As<ITransformFileLocator>();
builder.Register(context => ConfigurationTransformer.FromVariables(context.Resolve<IVariables>(), context.Resolve<ILog>())).As<IConfigurationTransformer>();
builder.RegisterType<DeploymentJournalWriter>().As<IDeploymentJournalWriter>().SingleInstance();
builder.RegisterType<ConfigurationVariablesReplacer>().As<IConfigurationVariablesReplacer>();

builder.RegisterModule<VariablesModule>();
builder.RegisterModule<SubstitutionsModule>();
builder.RegisterModule<ScriptIsolationModule>();
Expand All @@ -119,28 +150,35 @@ protected virtual void ConfigureContainer(ContainerBuilder builder, CommonOption
.Except<TerminalScriptWrapper>()
.As<IScriptWrapper>()
.SingleInstance();

// Register Behaviors
builder.RegisterAssemblyTypes(assemblies)
.Where(t => t.IsAssignableTo<IBehaviour>() && !t.IsAbstract)
.AsSelf()
.InstancePerDependency();

builder.RegisterInstance(options).AsSelf().SingleInstance();
// Register Behaviors
builder.RegisterAssemblyTypes(assemblies)
.Where(t => t.IsAssignableTo<IBehaviour>() && !t.IsAbstract)
.AsSelf()
.InstancePerDependency();

// Register Pipeline commands
builder.RegisterAssemblyTypes(assemblies)
.AssignableTo<PipelineCommand>()
.WithMetadataFrom<CommandAttribute>()
.Where(t => t.GetCustomAttribute<CommandAttribute>() is not null)
.Named<PipelineCommand>(t => t.GetCommandNameFromAttribute());

builder.RegisterModule<StructuredConfigVariablesModule>();
}

protected virtual Assembly GetProgramAssemblyToRegister()
protected virtual IEnumerable<Assembly> GetProgramAssembliesToRegister()
{
return GetType().Assembly;
yield return GetType().Assembly;
}

protected virtual IEnumerable<Assembly> GetAllAssembliesToRegister()
{
var programAssembly = GetProgramAssemblyToRegister();

yield return programAssembly; // Calamari Flavour
var programAssemblies = GetProgramAssembliesToRegister();

foreach (var assembly in programAssemblies)
yield return assembly; // Calamari Flavour & dependencies

yield return typeof(CalamariFlavourProgram).Assembly; // Calamari.Common
}
}
}
142 changes: 72 additions & 70 deletions source/Calamari.Common/CalamariFlavourProgramAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,60 +34,6 @@ namespace Calamari.Common;

public abstract class CalamariFlavourProgramAsync(ILog log)
{
protected virtual void ConfigureContainer(ContainerBuilder builder, CommonOptions options)
{
//register the options into the DI
builder.RegisterInstance(options).AsSelf();

var fileSystem = CalamariPhysicalFileSystem.GetPhysicalFileSystem();
builder.RegisterInstance(fileSystem).As<ICalamariFileSystem>();
builder.RegisterType<ScriptEngine>().As<IScriptEngine>();
builder.RegisterType<VariableLogger>().AsSelf();
builder.RegisterInstance(log).As<ILog>().SingleInstance();
builder.RegisterType<FreeSpaceChecker>().As<IFreeSpaceChecker>().SingleInstance();
builder.RegisterType<CommandLineRunner>().As<ICommandLineRunner>().SingleInstance();
builder.RegisterType<CombinedPackageExtractor>().As<ICombinedPackageExtractor>();
builder.RegisterType<ExtractPackage>().As<IExtractPackage>();
builder.RegisterType<AssemblyEmbeddedResources>().As<ICalamariEmbeddedResources>();
builder.RegisterType<ConfigurationVariablesReplacer>().As<IConfigurationVariablesReplacer>();
builder.RegisterType<TransformFileLocator>().As<ITransformFileLocator>();
builder.Register(context => ConfigurationTransformer.FromVariables(context.Resolve<IVariables>(), context.Resolve<ILog>())).As<IConfigurationTransformer>();
builder.RegisterType<DeploymentJournalWriter>().As<IDeploymentJournalWriter>().SingleInstance();
builder.RegisterType<CodeGenFunctionsRegistry>().SingleInstance();

builder.RegisterModule<VariablesModule>();
builder.RegisterModule<SubstitutionsModule>();
builder.RegisterModule<ScriptIsolationModule>();

var assemblies = GetAllAssembliesToRegister().ToArray();

builder.RegisterAssemblyTypes(assemblies).AssignableTo<ICodeGenFunctions>().As<ICodeGenFunctions>().SingleInstance();

builder.RegisterAssemblyTypes(assemblies)
.AssignableTo<IScriptWrapper>()
.Except<TerminalScriptWrapper>()
.As<IScriptWrapper>()
.SingleInstance();

builder.RegisterAssemblyTypes(assemblies)
.Where(t => t.IsAssignableTo<IBehaviour>() && !t.IsAbstract)
.AsSelf()
.InstancePerDependency();

builder.RegisterAssemblyTypes(assemblies)
.AssignableTo<PipelineCommand>()
.Where(t => t.GetCommandNameFromAttribute()
.Equals(options.Command, StringComparison.OrdinalIgnoreCase))
.Named<PipelineCommand>(t => t.GetCommandNameFromAttribute());

builder.RegisterModule<StructuredConfigVariablesModule>();
}

protected virtual IEnumerable<Assembly> GetProgramAssembliesToRegister()
{
yield return GetType().Assembly;
}

protected async Task<int> Run(string[] args)
{
try
Expand Down Expand Up @@ -121,7 +67,7 @@ protected async Task<int> Run(string[] args)
if (CalamariEnvironment.ShouldWaitForDebugger(container.Resolve<IVariables>()))
{
using var proc = Process.GetCurrentProcess();
Log.Info($"Waiting for debugger to attach... (PID: {proc.Id})");
log.Info($"Waiting for debugger to attach... (PID: {proc.Id})");

while (!Debugger.IsAttached)
{
Expand All @@ -131,34 +77,25 @@ protected async Task<int> Run(string[] args)
#endif
var isolation = container.Resolve<IScriptIsolationEnforcer>();
await using var _ = await isolation.EnforceAsync(options.ScriptIsolation, CancellationToken.None);
await ResolveAndExecuteCommand(container, options);
return 0;
return await ResolveAndExecuteCommand(container, options);

}
catch (Exception ex)
{
return ConsoleFormatter.PrintError(ConsoleLog.Instance, ex);
return ConsoleFormatter.PrintError(log, ex);
}
}

IEnumerable<Assembly> GetAllAssembliesToRegister()
{
var programAssemblies = GetProgramAssembliesToRegister();

foreach (var assembly in programAssemblies)
yield return assembly; // Calamari Flavour & dependencies

yield return typeof(CalamariFlavourProgramAsync).Assembly; // Calamari.Common
}

static Task ResolveAndExecuteCommand(ILifetimeScope container, CommonOptions options)
static async Task<int> ResolveAndExecuteCommand(ILifetimeScope container, CommonOptions options)
{
try
{
if (container.IsRegisteredWithName<PipelineCommand>(options.Command))
{
var pipeline = container.ResolveNamed<PipelineCommand>(options.Command);
var variables = container.Resolve<IVariables>();
return pipeline.Execute(container, variables);
await pipeline.Execute(container, variables);
return 0;
}

throw new CommandException($"Could not find the command {options.Command}");
Expand All @@ -168,4 +105,69 @@ static Task ResolveAndExecuteCommand(ILifetimeScope container, CommonOptions opt
throw new CommandException($"Could not find the command {options.Command}");
}
}

protected virtual void ConfigureContainer(ContainerBuilder builder, CommonOptions options)
{
//register the options into the DI
builder.RegisterInstance(options).AsSelf();

var fileSystem = CalamariPhysicalFileSystem.GetPhysicalFileSystem();
builder.RegisterInstance(fileSystem).As<ICalamariFileSystem>();
builder.RegisterType<ScriptEngine>().As<IScriptEngine>();
builder.RegisterType<VariableLogger>().AsSelf();
builder.RegisterInstance(log).As<ILog>().SingleInstance();
builder.RegisterType<FreeSpaceChecker>().As<IFreeSpaceChecker>().SingleInstance();
builder.RegisterType<CommandLineRunner>().As<ICommandLineRunner>().SingleInstance();
builder.RegisterType<CombinedPackageExtractor>().As<ICombinedPackageExtractor>();
builder.RegisterType<ExtractPackage>().As<IExtractPackage>();
builder.RegisterType<CodeGenFunctionsRegistry>().SingleInstance();
builder.RegisterType<AssemblyEmbeddedResources>().As<ICalamariEmbeddedResources>();
builder.RegisterType<TransformFileLocator>().As<ITransformFileLocator>();
builder.Register(context => ConfigurationTransformer.FromVariables(context.Resolve<IVariables>(), context.Resolve<ILog>())).As<IConfigurationTransformer>();
builder.RegisterType<DeploymentJournalWriter>().As<IDeploymentJournalWriter>().SingleInstance();
builder.RegisterType<ConfigurationVariablesReplacer>().As<IConfigurationVariablesReplacer>();

builder.RegisterModule<VariablesModule>();
builder.RegisterModule<SubstitutionsModule>();
builder.RegisterModule<ScriptIsolationModule>();

var assemblies = GetAllAssembliesToRegister().ToArray();

builder.RegisterAssemblyTypes(assemblies).AssignableTo<ICodeGenFunctions>().As<ICodeGenFunctions>().SingleInstance();

builder.RegisterAssemblyTypes(assemblies)
.AssignableTo<IScriptWrapper>()
.Except<TerminalScriptWrapper>()
.As<IScriptWrapper>()
.SingleInstance();

builder.RegisterAssemblyTypes(assemblies)
.Where(t => t.IsAssignableTo<IBehaviour>() && !t.IsAbstract)
.AsSelf()
.InstancePerDependency();

builder.RegisterAssemblyTypes(assemblies)
.AssignableTo<PipelineCommand>()
.Where(t => t.GetCommandNameFromAttribute()
.Equals(options.Command, StringComparison.OrdinalIgnoreCase))
.Named<PipelineCommand>(t => t.GetCommandNameFromAttribute());

builder.RegisterModule<StructuredConfigVariablesModule>();
}

protected virtual IEnumerable<Assembly> GetProgramAssembliesToRegister()
{
yield return GetType().Assembly;
}


IEnumerable<Assembly> GetAllAssembliesToRegister()
{
var programAssemblies = GetProgramAssembliesToRegister();

foreach (var assembly in programAssemblies)
yield return assembly; // Calamari Flavour & dependencies

yield return typeof(CalamariFlavourProgramAsync).Assembly; // Calamari.Common
}
}
Loading