protected override CommandResult ExecuteDetailed(GetSdksCommandArgs args, ChangeObservable observable) { IEnumerable <SdkPath> sdkPaths = Enumerable.Empty <SdkPath>(); IEnumerable <Exception> exceptions = Enumerable.Empty <Exception>(); if (args.All) { sdkPaths = sdkRepository.GetAllTargets() .GroupBy(target => sdkRepository.GetSdk(target).Root.FullName) .Select(group => new SdkPath(group.Key, group.Select(target => new TargetResult(target.Name, target.Version, target.LongVersion, target.ShortVersion)))); } else { ProjectEntity project = ProjectEntity.Decorate(entityFactory.Create(Guid.NewGuid().ToByteString(), args).Root); TargetsResult targetsResult = targetParser.Targets(project); sdkPaths = targetsResult.ValidTargets .GroupBy(target => sdkRepository.GetSdk(target).Root.FullName) .Select(group => new SdkPath(group.Key, group.Select(target => new TargetResult(target.Name, target.Version, target.LongVersion, target.ShortVersion)))); exceptions = targetsResult.Errors; } return(new CommandResult(0, new SdksCommandResult(sdkPaths))); }
public void Execute(Entity dataModel, ChangeObservable observable) { ProjectEntity project = ProjectEntity.Decorate(dataModel.Root); IEnumerable <Entity> targets = project.Targets.ToArray(); if (!targets.Any()) { throw new FormattableException("Please use --target to specify for which targets the library shall be generated."); } foreach (Entity target in targets) { VirtualDirectory deployRoot = DeployEntity.Decorate(target).DeployDirectory; VirtualDirectory deployDirectory = deployRoot.Directory("lib", project.Name); BuildEntity buildEntity = BuildEntity.Decorate(target); if (!buildEntity.HasBuildSystem) { TargetEntity targetEntity = TargetEntity.Decorate(target); executionContext.WriteWarning(new CMakeBuildSystemNotFoundException(targetEntity.FullName, buildEntity.BuildType).Message); return; } foreach (string externalLibrary in buildEntity.BuildSystem.ExternalLibraries) { VirtualFile newFile = fileSystem.GetFile(externalLibrary).CopyTo(deployDirectory); executionContext.Observable.OnNext(new Change(() => newFile.Delete(), $"Copied {externalLibrary} to {newFile.FullName}.")); } } }
protected override int Execute(SetTargetsCommandArgs args, ChangeObservable observable) { ProjectEntity project = ProjectEntity.Decorate(entityFactory.Create(Guid.NewGuid().ToByteString(), args).Root); FileEntity fileEntity = FileEntity.Decorate(project); if (!project.Settings.IsPersistent) { throw new TargetNotSettableForProjectException(); } if (args.Add) { Target result = targetParser.AddTarget(project, args.Name, args.Version); userInterface.WriteInformation($"Successfully added target {result.Name} {result.LongVersion} to project {fileEntity.Directory.FullName}."); } else if (args.Remove) { Target result = targetParser.RemoveTarget(project, args.Name, args.Version); userInterface.WriteInformation($"Successfully removed target {result.Name} {result.LongVersion} from project {fileEntity.Directory.FullName}."); } else { throw new SetTargetsOptionMissingException(); } return(0); }
protected override CommandResult ExecuteDetailed(GetTargetsCommandArgs args, ChangeObservable observable) { IEnumerable <Exception> exceptions = Enumerable.Empty <Exception>(); TargetsCommandResult commandResult; if (args.All) { commandResult = new TargetsCommandResult(sdkRepository.GetAllTargets() .Select(t => new TargetResult(t.Name, t.Version, t.LongVersion, t.ShortVersion)) .OrderBy(t => t.Name).ThenByDescending(t => t.Version)); } else { ExecutionContext.WriteWarning("This command is deprecated. Use 'get project-information' instead.", false); ProjectEntity project = ProjectEntity.Decorate(entityFactory.Create(Guid.NewGuid().ToByteString(), args).Root); TargetsResult targetsResult = targetParser.Targets(project, false); Target[] availableTargets = sdkRepository.GetAllTargets().ToArray(); commandResult = new TargetsCommandResult(targetsResult.ValidTargets .Select(t => new TargetResult(t.Name, t.Version, t.LongVersion, t.ShortVersion, availableTargets.Any(at => t.Name == at.Name && at.LongVersion == t.LongVersion))) .OrderBy(t => t.Name).ThenByDescending(t => t.Version)); exceptions = targetsResult.Errors; } return(new CommandResult(0, commandResult, exceptions)); }
protected override int Execute(UpdateTargetsCommandArgs args, ChangeObservable observable) { ProjectEntity project = ProjectEntity.Decorate(entityFactory.Create(Guid.NewGuid().ToByteString(), args).Root); targetParser.UpdateTargets(project, args.Downgrade); return(0); }
public void ExecuteBuild(BuildInformation buildInformation, ChangeObservable observable) { if (string.IsNullOrEmpty(binariesLocator.GetExecutableCommand("cmake"))) { throw new FormattableException("CMake cannot be found. Please install a new version of CMake and ensure that it will be added to the search path settings."); } (bool _, VirtualDirectory cmakeFolder) = EnsureConfigured(buildInformation, observable, true); TouchMainCMakeFile(); CallCmake(cmakeFolder, "--build . --target install", true, true); void TouchMainCMakeFile() { if (buildInformation.RootProjectEntity.Version > new Version(1, 0)) { //do not touch newer project version cmake file return; } if (!buildInformation.RootFileEntity.Directory.FileExists("CMakeLists.txt")) { throw new CMakeFileNotFoundException(); } VirtualFile cmakeFile = buildInformation.RootFileEntity.Directory.File("CMakeLists.txt"); cmakeFile.Touch(); } }
public void Execute(Entity dataModel, ChangeObservable observable) { int exitCode = builder.ExecuteAcf(dataModel); if (exitCode != 0) { throw new FormattableException("Deploying library failed!"); } }
protected override async Task <int> ExecuteAsync(ScanSdksCommandArgs args, ChangeObservable observable) { foreach (string sdkPath in settingsProvider.Settings.SdkPaths) { await sdkRepository.Update(sdkPath, true).ConfigureAwait(false); } return(0); }
public IDisposable RegisterObservable(ChangeObservable observable) { Observable = observable; OnObservableRegistered(); return(new DisposeAction(() => { Observable = null; OnObservableUnregistered(); })); }
protected override int Execute(GenerateLibraryCommandArgs args, ChangeObservable observable) { if (!string.IsNullOrEmpty(args.LibraryGuid) && !Guid.TryParse(args.LibraryGuid, out Guid realGuid)) { throw new LibraryIdMalformattedException(args.LibraryGuid); } Entity project = entityFactory.Create(Guid.NewGuid().ToByteString(), args).Root; return(builder.BuildLibraryForProject(project, observable, args.MetaFilesDirectory, args.LibraryLocation, args.OutputDirectory, realGuid, args.Target, args.ExternalLibraries, null)); }
protected override int Execute(BuildCommandArgs args, ChangeObservable observable) { string buildProperties = string.Join(" ", args.BuildProperties.Select(Unescape)); Entity rootEntity = entityFactory.Create(Guid.NewGuid().ToByteString(), args).Root; BuildInformation buildInfo = new BuildInformation(rootEntity, args.BuildType, args.Configure, args.NoConfigure, buildProperties, args.Output); builder.Build(buildInfo, observable, args.Target); return(0); string Unescape(string arg) { return(arg.Replace("%22", "\"")); } }
public int BuildLibraryForProject(Entity project, ChangeObservable observable, string metaFilesDirectory, string libraryLocation, string outputDirectory, Guid libraryGuid, IEnumerable <string> targets, IEnumerable <string> externalLibraries, string buildType) { userInterface.WriteInformation("Starting library generation..."); ProjectEntity projectEntity = ProjectEntity.Decorate(project); IEnumerable <(Target, string)> targetsSet; if (!targets.Any()) { TargetsResult ts = targetParser.Targets(projectEntity, false); if (!ts.ValidTargets.Any()) { throw new FormattableException ("Please use --target to specify for which targets the library shall be generated."); } else { HashSet <(Target, string)> targetsHashSet = new HashSet <(Target, string)>(); foreach (Target target in ts.ValidTargets) { targetsHashSet.Add((target, null)); } targetsSet = targetsHashSet; } } else { targetsSet = targetParser.GetSpecificTargets(targets, false); } Dictionary <Target, IEnumerable <VirtualFile> > externalLibs = ExternalLibrariesParser.ParseExternalLibraries(externalLibraries, targetParser, fileSystem, targetsSet.Select(t => t.Item1)); int result = libraryBuilderExecuter.Execute(projectEntity, metaFilesDirectory, libraryLocation, outputDirectory, observable, userInterface, libraryGuid, targetsSet, externalLibs, buildType); if (result == 0) { userInterface.WriteInformation("Successfully generated library!"); } return(result); }
public void Build(BuildInformation buildInfo, ChangeObservable observable, IEnumerable <string> targets) { if (!targets.Any()) { TargetsResult projectTargets = targetParser.Targets(buildInfo.RootProjectEntity); projectTargets.Errors.ThrowIfNotEmpty(); if (!projectTargets.ValidTargets.Any()) { throw new NoAssignedTargetsException(buildInfo.RootEntity.Name); } BuildProjectForTargets(buildInfo, observable, projectTargets.ValidTargets); } else { //build for selected target(s) BuildProjectForTargets(buildInfo, observable, targetParser.GetSpecificTargets(targets).Select(t => t.Item1)); } }
protected override async Task <int> ExecuteAsync(InstallSdkCommandArgs args, ChangeObservable observable) { VirtualDirectory directory = fileSystem.GetDirectory(args.Destination); VirtualFile sdk; if (fileSystem.FileExists(args.Sdk)) { sdk = fileSystem.GetFile(args.Sdk); } else { throw new SdkFileNotFoundException(args.Sdk); } await sdkInstaller.InstallSdk(sdk, directory, observable, args.Force).ConfigureAwait(false); userInterface.WriteInformation($"Successfully installed sdk {args.Sdk} in {args.Destination}."); return(0); }
public void Execute(Entity dataModel, ChangeObservable observable) { ProjectEntity project = ProjectEntity.Decorate(dataModel.Root); if (!project.Settings.IsPersistent) { try { ICodeModel codeModel = dataModel.Root.Value <ICodeModel>(); if (codeModel != null) { VirtualEntry acfFile = codeModel.SourceDirectories .SelectMany(directory => directory.Entries) .Where(entry => entry.Name.EndsWith(Constants.AcfConfigExtension, StringComparison.OrdinalIgnoreCase)) .FirstOrDefault(); if (acfFile != null) { using (Stream xmlStream = (acfFile as VirtualFile).OpenRead()) using (XmlReader reader = XmlReader.Create(xmlStream)) { while (reader.Read()) { if (reader.MoveToContent() == XmlNodeType.Element && reader.Name == "Component") { string componenttype = reader.GetAttribute("type"); if (componenttype.Contains("::")) { throw new OldAcfConfigException(); } } } } } } } catch (XmlException) { executionContext.WriteWarning("From version 2021.6 on the component type attribute inside the .acf.config file" + " must use the namespace separator '.' instead of '::'!"); } } }
public BuildSystemProperties RetrieveBuildSystemProperties(Entity rootEntity, Target projectTarget, ChangeObservable observable) { BuildInformation buildInformation = new BuildInformation(rootEntity, null, false, false, string.Empty, null) { Target = projectTarget, SdkInformation = sdkRepository.GetSdk(projectTarget) }; (bool success, VirtualDirectory cmakeFolder) = cmakeExecuter.EnsureConfigured( buildInformation, showWarningsToUser: true, observable, showMessagesToUser: false); JArray codeModel = buildInformation.BuildEntity.BuildSystem.Value <JArray>(); IEnumerable <string> includePaths = GetIncludePathsFromCodeModel(); return(new BuildSystemProperties(includePaths)); IEnumerable <string> GetIncludePathsFromCodeModel() { List <string> result = new List <string>(); JObject cmakeTarget = codeModel.GetProjectTarget(rootEntity.Name, false); if (cmakeTarget != null && cmakeTarget["fileGroups"] is JArray fileGroups) { foreach (JObject fileGroup in fileGroups.OfType <JObject>()) { if (fileGroup["includePath"] is JArray paths) { result.AddRange(paths.Select(path => path["path"]?.Value <string>()) .Where(include => !string.IsNullOrEmpty(include))); } } } return(result); } }
protected override CommandResult ExecuteDetailed(GetSdksCommandArgs args, ChangeObservable observable) { string[] sdks; IEnumerable <Exception> exceptions = Enumerable.Empty <Exception>(); if (args.All) { sdks = sdkRepository.Sdks.Select(s => s.Root.FullName).ToArray(); } else { ProjectEntity project = ProjectEntity.Decorate(entityFactory.Create(Guid.NewGuid().ToByteString(), args).Root); TargetsResult targetsResult = targetParser.Targets(project); sdks = targetsResult.ValidTargets.Select(sdkRepository.GetSdk).Distinct() .Select(s => s.Root.FullName).ToArray(); exceptions = targetsResult.Errors; } return(new CommandResult(0, new SdksCommandResult(sdks.Select(s => new Path(s))), exceptions)); }
protected override async Task <int> ExecuteAsync(UpdateCliCommandArgs args, ChangeObservable observable) { string startMessage = string.IsNullOrEmpty(args.File) ? (args.Version != null ? $"Updating to version {args.Version}" : "Updating to newest version") : $"Updating using the file {args.File}"; using (IProgressNotifier progressNotifier = progressVisualizer.Spawn(2, startMessage, "Completed update")) { VirtualFile download; VirtualDirectory directory = fileSystem.GetTemporaryDirectory(); observable.OnNext(new Change(() => {}, $"Create temporary folder {directory.FullName}")); if (string.IsNullOrEmpty(args.File)) { if (await cliUpdater.IsCurrentVersion(args.Version, args.Proxy).ConfigureAwait(false)) { directory.Delete(); userInterface.WriteInformation("Version is up-to-date."); return(0); } download = await cliUpdater.DownloadVersion(args.Version, directory, progressNotifier, args.Proxy).ConfigureAwait(false); } else { progressNotifier.TickIncrement(); if (!fileSystem.FileExists(args.File)) { throw new FormattableException($"The file {args.File} does not exist."); } download = fileSystem.GetFile(args.File); } await cliUpdater.InstallVersion(download, directory, progressNotifier).ConfigureAwait(false); } return(0); }
private void BuildProjectForTargets(BuildInformation buildInfo, ChangeObservable observable, IEnumerable <Target> targets) { targets = targets.ToArray(); MultiDictionary <SdkInformation, Target> sdks = new MultiDictionary <SdkInformation, Target>(); List <FormattableException> exceptions = new List <FormattableException>(); foreach (Target target in targets) { try { sdks.Add(sdkRepository.GetSdk(target), target); } catch (FormattableException ex) { exceptions.Add(ex); } } if (exceptions.Any()) { throw new AggregateException(exceptions); } userInterface.WriteInformation($"Requested build for targets {String.Join(", ", targets.Select(x => x.GetFullName()).ToArray())}"); foreach (SdkInformation sdk in sdks.Keys) { foreach (Target target in sdks.Get(sdk)) { userInterface.WriteInformation($"Starting build for target {target.GetFullName()}"); buildInfo.SdkInformation = sdk; buildInfo.Target = target; buildExecuter.ExecuteBuild(buildInfo, observable); userInterface.WriteInformation($"Successfully built the project {buildInfo.RootEntity.Name} for target {target.GetFullName()}."); } } userInterface.WriteInformation($"Finished build for all targets"); }
protected override int Execute(SetSettingsCommandArgs args, ChangeObservable observable) { using (IEditableSettings editableSettings = settingsProvider.StartSettingTransaction()) { if (args.Add) { editableSettings.AddSetting(args.Key, args.Value); } else if (args.Clear) { editableSettings.ClearSetting(args.Key); } else if (args.Remove) { editableSettings.RemoveSetting(args.Key, args.Value); } else { editableSettings.SetSetting(args.Key, args.Value); } } return(0); }
public (bool, VirtualDirectory) EnsureConfigured(BuildInformation buildInformation, bool showWarningsToUser, ChangeObservable observable = null, bool throwOnError = false, bool showMessagesToUser = true) { if (!CmakeFileExists()) { GenerateCmakeFile(); } VirtualDirectory cmakeFolder = CreateCmakeFolder(); bool success = ConfigureCMake(); return(success, cmakeFolder); void GenerateCmakeFile() { VirtualFile cMakeFile = buildInformation.RootFileEntity.Directory.File(Constants.CMakeFileName); //TODO Generate cmakefile with template system //TODO Set src folders in cmake file (consider foreign project structure) CMakeFileGenerator.WriteCMakeFile(cMakeFile, buildInformation.RootEntity.Name); observable?.OnNext(new Change(() => { /*Do not delete, because user need to make changes perhaps*/ }, $"Generated cmake file {cMakeFile.FullName}")); } bool CmakeFileExists() { return(buildInformation.RootFileEntity.Directory.FileExists(Constants.CMakeFileName)); } VirtualDirectory CreateCmakeFolder() { VirtualDirectory result = buildInformation.BuildEntity.BuildSystemDirectory; if (buildInformation.Configure && !buildInformation.NoConfigure) { result.Clear(); observable?.OnNext(new Change(() => result.UnClear(), $"Cleared cmake directory.")); } return(result); } string GetRealBuildType() { string buildType = !string.IsNullOrEmpty(buildInformation.BuildType) ? buildInformation.BuildType : Constants.ReleaseFolderName; return(buildType); } bool ConfigureCMake() { executionContext.WriteInformation("Checking if CMake needs to be reconfigured...", showMessagesToUser); if ((!cmakeFolder.FileExists("CMakeCache.txt") || buildInformation.Configure || !IsCorrectlyConfigured() || OutputOptionDiffersFromStagingPrefix()) && !buildInformation.NoConfigure) { string cmakeCommand = GenerateCmakeCommand(buildInformation.Target.Name, buildInformation.Target.LongVersion); if (showMessagesToUser) { executionContext.WriteInformation("Configuring CMake..."); } return(CallCmake(cmakeFolder, cmakeCommand, showMessagesToUser, throwOnError, showWarningsToUser)); } if (!string.IsNullOrEmpty(buildInformation.BuildProperties)) { executionContext.WriteWarning($"The specified build options will not be used, " + $"because no reconfiguration is necessary. " + $"To force a reconfiguration please use the '--configure' command option.", showMessagesToUser); } return(true); string GenerateCmakeCommand(string target, string version) { List <string> commandParts = new List <string>(); string sdkRoot = buildInformation.SdkInformation.Root.FullName.Replace("\\", "/"); if (!buildInformation.BuildProperties.Contains("-DCMAKE_TOOLCHAIN_FILE ")) { commandParts.Add(ToolchainFileOption.Replace("%SDK_ROOT%", sdkRoot)); } if (!buildInformation.BuildProperties.Contains("-DARP_TOOLCHAIN_ROOT ")) { commandParts.Add(ToolchainRootOption.Replace("%SDK_ROOT%", sdkRoot)); } if (!buildInformation.BuildProperties.Contains("-DCMAKE_BUILD_TYPE ")) { commandParts.Add(BuildTypeOption.Replace("%BUILD_TYPE%", GetRealBuildType())); } if (!buildInformation.BuildProperties.Contains("-DARP_DEVICE ")) { commandParts.Add(DeviceOption.Replace("%TARGET%", $"\"{target}\"")); } if (!buildInformation.BuildProperties.Contains("-DARP_DEVICE_VERSION ")) { commandParts.Add(DeviceVersionOption.Replace("%VERSION%", $"\"{version}\"")); } if (!buildInformation.BuildProperties.Contains("-DCMAKE_STAGING_PREFIX ")) { commandParts.Add(StagingPrefixOption.Replace("%STAGING_PREFIX%", GenerateStagingPrefixForTarget())); } if (!buildInformation.BuildProperties.Contains("-DCMAKE_PREFIX_PATH ") && IsIncludePathAvailable(out string includePath)) { commandParts.Add(PrefixPathOption.Replace("%PREFIX_PATH%", includePath)); } if (!buildInformation.BuildProperties.Contains("-G ")) { commandParts.Add(GeneratorOption); if (buildInformation.SdkInformation.MakeFile != null && !buildInformation.BuildProperties.Contains("-DCMAKE_MAKE_PROGRAM ")) { commandParts.Add(MakeFileOption.Replace("%MAKE_EXE%", $"\"{buildInformation.SdkInformation.MakeFile.FullName.Replace("\\", "/")}\"")); } } if (!string.IsNullOrEmpty(buildInformation.BuildProperties)) { commandParts.Add(buildInformation.BuildProperties); } commandParts.Add($"\"{buildInformation.RootFileEntity.Directory.FullName.Replace("\\", "/")}\""); return(string.Join(" ", commandParts)); string GenerateStagingPrefixForTarget() { string basePath = buildInformation.RootFileEntity.Directory.FullName; return(buildInformation.Output != null ? OutputOptionFullPath() : Path.Combine(basePath, Constants.LibraryFolderName) .Replace(Path.DirectorySeparatorChar, '/')); } bool IsIncludePathAvailable(out string path) { path = null; if (!buildInformation.RootFileEntity.Directory.DirectoryExists("external")) { return(false); } Dictionary <Version, VirtualDirectory> versions = new Dictionary <Version, VirtualDirectory>(); VirtualDirectory externalDirectory = buildInformation.RootFileEntity.Directory.Directory("external"); foreach (VirtualDirectory directory in externalDirectory.Directories) { Match patternMatch = IncludeDirectoryPattern.Match(directory.Name); if (!patternMatch.Success || !Version.TryParse(patternMatch.Groups["version"].Value, out Version includeVersion) || target != patternMatch.Groups["name"].Value) { continue; } versions.Add(includeVersion, directory); } Version actualVersion = Version.Parse(buildInformation.Target.Version); Version bestMatch = versions.Keys.Where(v => v <= actualVersion) .OrderByDescending(v => v) .FirstOrDefault(); if (bestMatch != null) { VirtualDirectory directory = versions[bestMatch]; if (directory.DirectoryExists(buildInformation.BuildType)) { path = directory.Directory(buildInformation.BuildType).FullName; } else if (directory.DirectoryExists(Constants.ReleaseFolderName)) { path = directory.Directory(Constants.ReleaseFolderName).FullName; } else { path = directory.FullName; } } else { path = externalDirectory.FullName; } return(true); } } string OutputOptionFullPath() { return(fileSystem.GetDirectory(buildInformation.Output, buildInformation.RootFileEntity.Directory.FullName) .FullName.Replace(Path.DirectorySeparatorChar, '/')); } bool OutputOptionDiffersFromStagingPrefix() { return(buildInformation.Output != null && !buildInformation.BuildEntity.BuildSystem.InstallationPaths.Any(p => p.StartsWith(OutputOptionFullPath(), StringComparison.Ordinal))); } bool IsCorrectlyConfigured() { try { return(buildInformation.BuildEntity.HasBuildSystem && buildInformation.BuildEntity.BuildSystem != null); } catch (Exception e) { if (!IsTimeout(e)) { executionContext.WriteVerbose($"The project is not correctly configured:{Environment.NewLine}{e}"); return(false); } } return(true); //this is a timeout so we dont know if it is correctly configured bool IsTimeout(Exception exception) { return(exception is TimeoutException || exception is AggregateException aggregate && aggregate.InnerExceptions.Any(e => e is TimeoutException)); } } } }
public (bool, VirtualDirectory) EnsureConfigured(BuildInformation buildInformation, ChangeObservable observable = null, bool throwOnError = false, bool showMessagesToUser = true) { return(EnsureConfigured(buildInformation, showMessagesToUser, observable, throwOnError, showMessagesToUser)); }
protected override CommandResult ExecuteDetailed(GetProjectInformationCommandArgs args, ChangeObservable observable) { Entity root = entityFactory.Create(Guid.NewGuid().ToByteString(), args).Root; propertiesProvider.Initialize(root); return(new CommandResult(0, new ProjectInformationCommandResult(propertiesProvider.ProjectName, propertiesProvider.ProjectNamespace, propertiesProvider.ProjectType, propertiesProvider.ProjectTargets.Select(t => new TargetResult(t.Target.Name, t.Target.Version, t.Target.LongVersion, t.Target.ShortVersion, t.IsAvailable)), propertiesProvider.ProjectCodeEntities.Select(kvp => new EntityResult(kvp.Key.Name, kvp.Key.Namespace, kvp.Key.Type, kvp.Value.Select(en => en.Name))), propertiesProvider.IncludePaths.Select(p => new CommandResults.IncludePath(p.PathValue, (p.Exists != null ? (bool)p.Exists : false), p.Targets .Select(t => new TargetResult(t.Name, t.Version, t.LongVersion, t.ShortVersion) ) ) ) ), propertiesProvider.Exceptions)); }
public async Task <int> Execute(CommandDefinition definition, ChangeObservable observable) { if (definition.BaseDefinition == newCommand) { Entity dataModel = entityFactory.Create(definition.Name, definition); IEnumerable <VirtualFile> files = await templateFileGenerator.InitalizeTemplate(dataModel, observable).ConfigureAwait(false); userInterface.WriteInformation($"Successfully created template '{dataModel.Template().name}' in {GetCommonPath(files,dataModel.Path)}."); } if (generateCommands.Contains(definition)) { Entity dataModel = entityFactory.Create(definition.Name, definition); userInterface.WriteInformation(definition.Name == "all" ? $"Generating all files for {dataModel.Root.Path}." : $"Generating all files with the '{definition.Name}' " + $"generator for {dataModel.Root.Path}."); SingleValueArgument singleValueArgument = definition.Argument <SingleValueArgument>(Constants.OutputArgumentName); await templateFileGenerator.GenerateFiles(dataModel.Root, definition.Name, singleValueArgument.Value, singleValueArgument.IsDefined, observable) .ConfigureAwait(false); userInterface.WriteInformation(definition.Name == "all" ? $"Successfully generated all files for {dataModel.Root.Path}." : $"Successfully generated all files with the '{definition.Name}' " + $"generator for {dataModel.Root.Path}."); } if (definition == deployCommand) { Entity dataModel = entityFactory.Create(definition.Name, definition); deployService.DeployFiles(dataModel); Entity root = dataModel.Root; TemplateDescription template = TemplateEntity.Decorate(root).Template; foreach (templateDeployPostStep deployPostStep in template.DeployPostStep ?? Enumerable.Empty <templateDeployPostStep>()) { IDeployStep step = deploySteps.FirstOrDefault(s => s.Identifier == deployPostStep.identifier); if (step != null) { step.Execute(dataModel, observable); } else { executionContext.WriteWarning( $"Deploy post step '{deployPostStep.identifier}' could not be executed because there is no implementation. " + $"Available implementations are:{Environment.NewLine}" + $"{string.Join(Environment.NewLine, deploySteps.Select(d => d.Identifier))}"); } } userInterface.WriteInformation($"Successfully deployed all files for {dataModel.Root.Path}."); } return(0); string GetCommonPath(IEnumerable <VirtualFile> generatedFiles, string fallback) { IEnumerable <IEnumerable <VirtualDirectory> > paths = generatedFiles.Select(GetPath); VirtualDirectory commonDirectory = paths.Transpose() .TakeWhile(d => d.Distinct().Count() == 1) .FirstOrDefault() ?.First(); return(commonDirectory?.FullName ?? fallback); IEnumerable <VirtualDirectory> GetPath(VirtualFile file) { VirtualDirectory current = file.Parent; while (current != null) { yield return(current); current = current.Parent; } } } }
protected override CommandResult ExecuteDetailed(GetComponentsCommandArgs args, ChangeObservable observable) { ExecutionContext.WriteWarning("This command is deprecated. Use 'get project-information' instead.", false); TemplateEntity project = TemplateEntity.Decorate(entityFactory.Create(Guid.NewGuid().ToByteString(), args).Root); IEnumerable <Entity> components = project.EntityHierarchy.Where(e => e.Type.Equals("component", StringComparison.OrdinalIgnoreCase)) .ToArray(); if (!components.Any()) { ExecutionContext.WriteInformation($"No components found for project {project.Name}"); return(new CommandResult(0, ComponentsCommandResult.Empty)); } return(new CommandResult(0, new ComponentsCommandResult(components.Select(c => { CodeEntity codeEntity = CodeEntity.Decorate(c); return new ComponentResult(c.Name, string.IsNullOrEmpty(codeEntity.Namespace) ? string.Empty : codeEntity.Namespace); })))); }
public async Task InstallSdk(VirtualFile packedSdk, VirtualDirectory destination, ChangeObservable observable, bool force) { using (IEditableSettings editableSettings = settingsProvider.StartSettingTransaction()) { if (!force && destination.Files(searchRecursive: true).Any()) { throw new FileExistsException(destination.FullName); } if (force) { destination.Clear(); observable.OnNext(new Change(destination.UnClear, "Cleared destination directory.")); } using (IProgressNotifier progressNotifier = Console.IsInputRedirected || Console.IsOutputRedirected ? null : progressVisualizer.Spawn(1, "Install SDK.", null)) { await fileUnpackService.Unpack(packedSdk, destination, progressNotifier, observable).ConfigureAwait(false); } editableSettings.AddSetting(Constants.SdkPathsKey, $"{destination.FullName}"); } }
public async Task <IEnumerable <VirtualFile> > InitalizeTemplate(Entity dataModel, ChangeObservable observable) { bool forced = dataModel.Value <CommandDefinition>() .Argument <BoolArgument>(TemplateCommandBuilder.ForcedArgumentName) .Value; TemplateDescription template = dataModel.Template(); List <VirtualFile> generatedFiles = new List <VirtualFile>(await InitializeFiles().ConfigureAwait(false)); generatedFiles.AddRange(await InitializeSubTemplates().ConfigureAwait(false)); Exception e = dataModel.GetCodeExceptions(); if (e != null) { e.CompleteCodeExceptions(fileSystem.GetDirectory(dataModel.Root.Path)); throw e; } return(generatedFiles); async Task <IEnumerable <VirtualFile> > InitializeFiles() { string basePath = dataModel.Root.Path; HashSet <VirtualFile> files = new HashSet <VirtualFile>(); foreach (templateFile file in template.File) { (string content, Encoding encoding) = await GetResolvedTemplateContent(dataModel, file, template).ConfigureAwait(false); VirtualFile destination = await GetFile(dataModel, file, forced, basePath, template).ConfigureAwait(false); observable.OnNext(new Change(() => destination.Restore(), $"Create file {Path.GetFileName(destination.Name)} for template " + $"{template.name} in {destination.Parent.FullName}.")); using (Stream fileStream = destination.OpenWrite()) using (StreamWriter writer = new StreamWriter(fileStream, encoding)) { fileStream.SetLength(0); await writer.WriteAsync(content).ConfigureAwait(false); } files.Add(destination); } return(files); } async Task <IEnumerable <VirtualFile> > InitializeSubTemplates() { List <VirtualFile> files = new List <VirtualFile>(); foreach (templateReference reference in SortByRelationship(template.AddTemplate ?? Enumerable.Empty <templateReference>())) { if (repository.Template(reference.template) == null) { throw new TemplateReferenceNotDefinedException(reference.template); } CommandDefinitionBuilder pseudoDefinition = CommandDefinitionBuilder.Create() .SetName(reference.template); foreach (templateArgumentInstance argumentInstance in reference.Arguments) { AddArgument(argumentInstance, pseudoDefinition); } IEnumerable <IGrouping <string, templateRelationshipInstance> > grouped = (reference.Relationship ?? Enumerable.Empty <templateRelationshipInstance>()).GroupBy(r => r.name); foreach (IGrouping <string, templateRelationshipInstance> relationshipInstances in grouped) { AddRelationships(relationshipInstances, pseudoDefinition, reference); } pseudoDefinition.CreateArgument() .SetName(TemplateCommandBuilder.ForcedArgumentName) .SetValue(forced) .Build(); Entity referencedTemplateEntity = dataModel.Create(reference.template, pseudoDefinition.Build()); dataModel.AddEntity(referencedTemplateEntity); files.AddRange(await InitalizeTemplate(referencedTemplateEntity, observable).ConfigureAwait(false)); } return(files); void AddArgument(templateArgumentInstance templateArgumentInstance, CommandDefinitionBuilder commandDefinitionBuilder) { string templateArgumentValue = resolver.Resolve(templateArgumentInstance.value, dataModel); bool argumentHasNoValue = bool.TryParse(templateArgumentValue, out bool boolValue); string[] argumentSplit = templateArgumentValue.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); bool isMultiArgument = argumentSplit.Length > 1; if (argumentHasNoValue) { commandDefinitionBuilder.CreateArgument() .SetName(templateArgumentInstance.name) .SetValue(boolValue) .Build(); } else if (isMultiArgument) { commandDefinitionBuilder.CreateArgument() .SetName(templateArgumentInstance.name) .SetValue(argumentSplit) .Build(); } else { commandDefinitionBuilder.CreateArgument() .SetName(templateArgumentInstance.name) .SetValue(templateArgumentValue) .Build(); } } void AddRelationships(IGrouping <string, templateRelationshipInstance> relationshipInstances, CommandDefinitionBuilder commandDefinitionBuilder, templateReference reference) { templateRelationship relationshipDefinition = repository.Template(reference.template).Relationship ?.FirstOrDefault(r => r.name == relationshipInstances.Key); if (relationshipDefinition == null) { throw new TemplateRelationshipNotFoundException(reference.template, relationshipInstances.Key); } bool multipleValues = relationshipDefinition.multiplicity == multiplicity.OneOrMore; if (multipleValues) { string[] relationships = relationshipInstances.Select(r => resolver.Resolve(r.value, dataModel)) .ToArray(); commandDefinitionBuilder.CreateArgument() .SetName(relationshipInstances.Key) .SetValue(relationships) .Build(); } else { if (relationshipInstances.Count() != 1) { throw new RelationshipMultiplicityMismatchException(relationshipInstances.Key, reference.template); } commandDefinitionBuilder.CreateArgument() .SetName(relationshipInstances.Key) .SetValue(resolver.Resolve(relationshipInstances.Single().value, dataModel)) .Build(); } } IEnumerable <templateReference> SortByRelationship(IEnumerable <templateReference> references) { List <templateReference> unsorted = references.ToList(); List <templateReference> sorted = new List <templateReference>(); while (unsorted.Any()) { Insert(unsorted[0]); } return(sorted); void Insert(templateReference current, CycleChecker <templateReference> cycleChecker = null) { using (cycleChecker = cycleChecker?.SpawnChild() ?? new CycleChecker <templateReference>( ExceptionTexts.TemplateRelationshipCycle, () => cycleChecker = null)) { cycleChecker.AddItem(current); List <templateReference> dependent = new List <templateReference>(); foreach (templateRelationshipInstance relationshipInstance in current.Relationship ?? Enumerable .Empty < templateRelationshipInstance >()) { templateReference reference = unsorted.FirstOrDefault(r => HasRelationship(r, relationshipInstance)); if (reference != null) { Insert(reference, cycleChecker); } else { reference = sorted.FirstOrDefault(r => HasRelationship(r, relationshipInstance)); } if (reference != null) { dependent.Add(reference); } } int skipping = dependent.Any() ? dependent.Select(d => sorted.IndexOf(d)).Max() : -1; int index = skipping + 1; sorted.Insert(index, current); unsorted.Remove(current); bool HasRelationship(templateReference currentReference, templateRelationshipInstance relationshipInstance) { templateArgumentInstance instance = currentReference.Arguments .FirstOrDefault(a => a.name .Equals( EntityKeys .NameKey, StringComparison .OrdinalIgnoreCase)); return(instance?.value?.Equals(relationshipInstance.value, StringComparison.OrdinalIgnoreCase) == true); } } } } } }
public async Task GenerateFiles(Entity rootEntity, string generator, string output, bool outputDefined, ChangeObservable observable) { IEnumerable <Entity> generatableEntities = rootEntity.Hierarchy(); HashSet <VirtualFile> generatedFiles = new HashSet <VirtualFile>(); HashSet <VirtualDirectory> rootDirectories = new HashSet <VirtualDirectory>(); foreach (Entity generatableEntity in generatableEntities) { await GenerateFilesForEntity(generatableEntity).ConfigureAwait(false); } Exception e = rootEntity.GetCodeExceptions(); if (e != null) { e.CompleteCodeExceptions(fileSystem.GetDirectory(rootEntity.Path)); throw e; } foreach (VirtualDirectory rootDirectory in rootDirectories) { DeleteRedundantFiles(rootDirectory); } void DeleteRedundantFiles(VirtualDirectory rootDirectory) { foreach (VirtualFile file in rootDirectory.Files(searchRecursive:true).Where(f => !generatedFiles.Contains(f)).ToArray()) { VirtualDirectory current = file.Parent; file.Delete(); while (current != null && !current.Entries.Any()) { VirtualDirectory next = current.Parent; current.Delete(); current = next; } } } async Task GenerateFilesForEntity(Entity generatableEntity) { TemplateDescription template = generatableEntity.Template(); if (template == null) { return; } foreach (templateGeneratedFile file in template.GeneratedFile ?? Enumerable.Empty <templateGeneratedFile>()) { if (generator != "all" && !file.generator.Equals(generator, StringComparison.OrdinalIgnoreCase)) { continue; } if (!string.IsNullOrEmpty(file.condition)) { string condition = await resolver.ResolveAsync(file.condition, generatableEntity).ConfigureAwait(false); if (condition.Equals("false", StringComparison.OrdinalIgnoreCase)) { continue; } } (string content, Encoding encoding) = await GetResolvedTemplateContent(generatableEntity, file, template).ConfigureAwait(false); VirtualDirectory baseDirectory = GetBaseDirectory(file); VirtualFile destination = await GetFile(generatableEntity, file, true, baseDirectory.FullName, template).ConfigureAwait(false); rootDirectories.Add(baseDirectory); generatedFiles.Add(destination); observable.OnNext(new Change(() => destination.Restore(), $"Generated the file {destination.FullName}.")); using (Stream fileStream = destination.OpenComparingWriteStream()) using (StreamWriter writer = new StreamWriter(fileStream, encoding)) { await writer.WriteAsync(content).ConfigureAwait(false); } } VirtualDirectory GetBaseDirectory(templateGeneratedFile file) { string generatorPath = output; if (!outputDefined) { generatorPath = Path.Combine(Constants.IntermediateFolderName, file.generator.ToLowerInvariant()); } else if (generator == "all") { generatorPath = Path.Combine(generatorPath, file.generator.ToLowerInvariant()); } return(fileSystem.GetDirectory(generatorPath, rootEntity.Path)); } } }
protected override CommandResult ExecuteDetailed(GetSettingsCommandArgs args, ChangeObservable observable) { return(new CommandResult(0, new SettingCommandResult(args.All ? settingsProvider.Settings : GetSingleSetting()))); object GetSingleSetting() { return(new JObject(new JProperty(args.Key, settingsProvider.GetSetting(args.Key)))); } }
protected virtual async Task <CommandResult> ExecuteDetailedAsync(T args, ChangeObservable observable) { return(new CommandResult(await ExecuteAsync(args, observable).ConfigureAwait(false), null)); }