public override Task ExecuteAsync(OutputContext output, ApplicationBuilder application, ServiceBuilder service) { if (SkipWithoutProject(output, service, out var project)) { return(Task.CompletedTask); } if (SkipWithoutContainerInfo(output, service, out var container)) { return(Task.CompletedTask); } DockerfileGenerator.ApplyContainerDefaults(application, project, container); return(Task.CompletedTask); }
internal static async Task<TemporaryApplicationAdapter> CreateApplicationAdapterAsync(OutputContext output, ConfigApplication application, bool interactive, bool requireRegistry) { var globals = new ApplicationGlobals() { Name = application.Name, Registry = application.Registry is null ? null : new ContainerRegistry(application.Registry), }; var services = new List<Tye.ServiceEntry>(); foreach (var configService in application.Services) { if (configService.Project is string projectFile) { var fullPathProjectFile = Path.Combine(application.Source.DirectoryName, projectFile); var project = new Project(fullPathProjectFile); var service = new Service(configService.Name) { Source = project, }; service.Replicas = configService.Replicas ?? 1; foreach (var configBinding in configService.Bindings) { var binding = new ServiceBinding(configBinding.Name ?? service.Name) { ConnectionString = configBinding.ConnectionString, Host = configBinding.Host, Port = configBinding.Port, Protocol = configBinding.Protocol, }; binding.Protocol ??= "http"; if (binding.Port == null && configBinding.AutoAssignPort) { if (binding.Protocol == "http" || binding.Protocol == null) { binding.Port = 80; } else if (binding.Protocol == "https") { binding.Port = 443; } } service.Bindings.Add(binding); } var serviceEntry = new ServiceEntry(service, configService.Name); await ProjectReader.ReadProjectDetailsAsync(output, new FileInfo(fullPathProjectFile), project); var container = new ContainerInfo() { UseMultiphaseDockerfile = false, }; service.GeneratedAssets.Container = container; services.Add(serviceEntry); } else { // For a non-project, we don't really need much info about it, just the name and bindings var service = new Service(configService.Name); foreach (var configBinding in configService.Bindings) { service.Bindings.Add(new ServiceBinding(configBinding.Name ?? service.Name) { ConnectionString = configBinding.ConnectionString, Host = configBinding.Host, Port = configBinding.Port, Protocol = configBinding.Protocol, }); } var serviceEntry = new ServiceEntry(service, configService.Name); services.Add(serviceEntry); } } var temporaryApplication = new TemporaryApplicationAdapter(application, globals, services); if (temporaryApplication.Globals.Registry?.Hostname == null && interactive) { var registry = output.Prompt("Enter the Container Registry (ex: 'example.azurecr.io' for Azure or 'example' for dockerhub)", allowEmpty: !requireRegistry); if (!string.IsNullOrWhiteSpace(registry)) { temporaryApplication.Globals.Registry = new ContainerRegistry(registry.Trim()); } } else if (temporaryApplication.Globals.Registry?.Hostname == null && requireRegistry) { throw new CommandException("A registry is required for deploy operations. Add the registry to 'tye.yaml' or use '-i' for interactive mode."); } else { // No registry specified, and that's OK! } foreach (var service in temporaryApplication.Services) { if (service.Service.Source is Project project && service.Service.GeneratedAssets.Container is ContainerInfo container) { DockerfileGenerator.ApplyContainerDefaults(temporaryApplication, service, project, container); } } return temporaryApplication; }
public override async Task <object?> ExecuteAsync() { if (callbacks.Count == 0) { return(Task.FromResult <object?>(null)); } if (callbacks.Count > 1) { throw new InvalidOperationException("More than one application type is not supported."); } var kvp = callbacks.Single(); var type = kvp.Key; var delegates = kvp.Value; output.WriteDebugLine($"Creating instance of application type '{type}'."); var application = Activator.CreateInstance(type); output.WriteDebugLine($"Done creating instance of application type '{type}'."); var wrapper = new ApplicationWrapper(application !, rootDirectory); wrapper.Globals.Name ??= name; foreach (var service in wrapper.Services) { output.WriteDebugLine($"Found service '{service.FriendlyName} {{ Name: {service.Service.Name} }}'."); string?projectRelativeFilePath = null; string?projectFilePath = null; if (solution != null) { var project = FindProjectInSolution(solution, service.FriendlyName); if (project == null) { output.WriteDebugLine($"Could not find project for service '{service.FriendlyName}'."); continue; } output.WriteDebugLine($"Found project '{project.RelativePath}' for service '{service.FriendlyName}'."); projectRelativeFilePath = project.RelativePath.Replace('\\', Path.DirectorySeparatorChar); projectFilePath = project.AbsolutePath.Replace('\\', Path.DirectorySeparatorChar); } else if (projectFile != null) { var normalized = Names.NormalizeToFriendly(Path.GetFileNameWithoutExtension(projectFile.Name)); if (!string.Equals(normalized, service.FriendlyName)) { output.WriteDebugLine($"Skipping service '{service.FriendlyName}'."); continue; } projectRelativeFilePath = projectFile.FullName; projectFilePath = projectFile.FullName; } if (projectFilePath != null) { var project = new Project(projectRelativeFilePath !); await ProjectReader.ReadProjectDetailsAsync(output, new FileInfo(projectFilePath), project); service.Service.Source = project; // Apply defaults to everything that has a project. var container = new ContainerInfo(); service.Service.GeneratedAssets.Container = container; DockerfileGenerator.ApplyContainerDefaults(wrapper, service, project, container); } } output.WriteDebugLine($"Running {delegates.Count} customization callbacks."); for (var i = 0; i < delegates.Count; i++) { delegates[i].DynamicInvoke(application); } output.WriteDebugLine($"Done running {delegates.Count} customization callbacks."); return(application); }