private void GenerateArgumentFromDefinition(Entity templateEntity, CommandDefinitionBuilder builder, templateArgumentDefinition templateArgumentDefinition, List <char> shortNames, string setName = null) { ArgumentBuilder argumentBuilder = builder.CreateArgument() .SetName(templateArgumentDefinition.name) .SetArgumentType(GetArgumentType(templateArgumentDefinition)) .SetHelp(resolver.Resolve( templateArgumentDefinition.help ?? string.Empty, templateEntity)) .SetRestriction( new ArgumentRestriction( templateArgumentDefinition.ValueRestriction).Verify); if (templateArgumentDefinition.separatorSpecified && !string.IsNullOrEmpty(templateArgumentDefinition.separator)) { argumentBuilder.SetSeparator(templateArgumentDefinition.separator[0]); } if (!string.IsNullOrEmpty(templateArgumentDefinition.shortname) && !shortNames.Contains(templateArgumentDefinition.shortname[0])) { argumentBuilder.SetShortName(templateArgumentDefinition.shortname[0]); shortNames.Add(templateArgumentDefinition.shortname[0]); } if (!string.IsNullOrEmpty(setName)) { argumentBuilder.SetSetName(setName); } argumentBuilder.Build(); ArgumentType GetArgumentType(templateArgumentDefinition argument) { return(argument.hasvalue ? (argument.multiplicity == multiplicity.OneOrMore ? ArgumentType.MultipleValue : ArgumentType.SingleValue) : ArgumentType.Bool); } }
public CommandDefinition GenerateDeployCommandDefinition(Entity templateEntity, TemplateDescription currentRootTemplate, CommandDefinition baseCommand, ICollection <TemplateDescription> allTemplates) { if (baseCommand == null) { return(GenerateBaseCommand()); } return(GenerateChildCommand()); CommandDefinition GenerateBaseCommand() { List <char> shortNames = new List <char>(); return(AddTemplateArguments(AddDefaultArguments(CommandDefinitionBuilder.Create() .SetName("deploy") .SetHelp( "Deploys files for production.") .EnableUseChildVerbsAsCategory() .AddExample($"deploy --path Path/To/Project", "Deploy files for all targets supported by project") .AddExample($"deploy --path Path/To/Project --files doc/HelpText.txt|doc", "Deploy doc/HelpText.txt to the doc directory in the deploy directory aditonally to the normally deployed files.") .AddExample($"deploy --path Path/To/Project --target AXCF2152 RFC4072S", "Deploy library for targets AXCF2152 and RFC4072S"), allTemplates.Where(t => !t.isHidden & t.isRoot), shortNames), allTemplates.Where(t => !t.isHidden & t.isRoot), shortNames, false) .Build()); } CommandDefinition GenerateChildCommand() { List <char> shortNames = new List <char>(); return(AddTemplateArguments(AddDefaultArguments(CommandDefinitionBuilder.Create() .SetBaseDefintion(baseCommand) .SetName(currentRootTemplate .name) .SetHelp( $"For {currentRootTemplate.name.Plural()}:"), new[] { currentRootTemplate }, shortNames), new[] { currentRootTemplate }, shortNames, true) .Build()); } CommandDefinitionBuilder AddTemplateArguments(CommandDefinitionBuilder builder, IEnumerable <TemplateDescription> descriptions, List <char> shortNames, bool addExamples) { string[] defaultArguments = { EntityKeys.PathKey.ToUpperInvariant(), Constants.OutputArgumentName.ToUpperInvariant(), Constants.FilesArgumentName.ToUpperInvariant(), Constants.TargetArgumentName.ToUpperInvariant(), }; Dictionary <templateArgumentDefinition, string> argumentToStringDictionary = new Dictionary <templateArgumentDefinition, string>(); List <templateArgumentDefinition> setlessArguments = new List <templateArgumentDefinition>(); foreach (TemplateDescription description in descriptions) { IEnumerable <templateArgumentDefinition> arguments = (description.DeployPostStep ?? Enumerable.Empty <templateDeployPostStep>()) .SelectMany(d => d.Arguments ?? Enumerable.Empty <templateArgumentDefinition>()); foreach (templateArgumentDefinition argument in arguments) { if (!defaultArguments.Contains(argument.name.ToUpperInvariant())) { templateArgumentDefinition existingDefinition = argumentToStringDictionary.Keys .FirstOrDefault(d => d.name .Equals(argument.name, StringComparison.OrdinalIgnoreCase)); if (existingDefinition != null) { if (argumentToStringDictionary[existingDefinition] != description.name) { argumentToStringDictionary.Remove(existingDefinition); setlessArguments.Add(existingDefinition); } } else { argumentToStringDictionary.Add(argument, description.name); } } } if (!addExamples) { continue; } IEnumerable <templateExample> examples = (description.DeployPostStep ?? Enumerable.Empty <templateDeployPostStep>()) .SelectMany(d => d.Example ?? Enumerable.Empty <templateExample>()); foreach (templateExample example in examples) { StringBuilder command = new StringBuilder("deploy"); ParseExample(description, example, command, false); builder.AddExample(command.ToString(), example.Description ?? string.Empty); } } foreach (templateArgumentDefinition argument in setlessArguments) { GenerateArgumentFromDefinition(templateEntity, builder, argument, shortNames, null); } foreach (templateArgumentDefinition argument in argumentToStringDictionary.Keys) { GenerateArgumentFromDefinition(templateEntity, builder, argument, shortNames, argumentToStringDictionary[argument]); } return(builder); } CommandDefinitionBuilder AddDefaultArguments(CommandDefinitionBuilder builder, IEnumerable <TemplateDescription> descriptions, List <char> shortNames) { IEnumerable <templateArgumentDefinition> arguments = descriptions.SelectMany(x => (x.DeployPostStep ?? Enumerable.Empty <templateDeployPostStep>()) .SelectMany(d => d.Arguments ?? Enumerable.Empty <templateArgumentDefinition>())); if (!ArgumentAvailableFromDescription(EntityKeys.PathKey)) { builder = builder.CreateArgument() .SetName(EntityKeys.PathKey) .SetShortName('p') .SetHelp( "The path to the project settings file or the project root directory. " + "Default is the current directory.") .SetArgumentType(ArgumentType.SingleValue) .Build(); shortNames.Add('p'); } if (!ArgumentAvailableFromDescription(Constants.OutputArgumentName)) { builder = builder.CreateArgument() .SetName(Constants.OutputArgumentName) .SetShortName('o') .SetHelp("The path where the files will be deployed in. " + "Default is the 'bin/target/Release' directory. Relative paths are relative " + "to the directory defined with the '--path' option.") .SetArgumentType(ArgumentType.SingleValue) .Build(); shortNames.Add('o'); } if (!ArgumentAvailableFromDescription(Constants.FilesArgumentName)) { builder = builder.CreateArgument() .SetName(Constants.FilesArgumentName) .SetShortName('f') .SetHelp( "Additional files to be deployed. Files are separated by ' '. Files need to be defined in the following format: " + "path/to/source|path/to/destination(|target). The path/to/source file will be relative to the " + $"root folder, defined with the '{EntityKeys.PathKey}' argument. It can contain the wildcard '*' " + $"at the end of the path. In this case all files from the directory and all sub-directories will " + $"be deployed. The sub-directories will be recreated in the deployment directory. The path/to/destination will be " + $"relative to the output/targetname/Release directory, where output is defined with the '{Constants.OutputArgumentName}' argument. " + "Optionally each file can have a target definition. Without the target definition the file is deployed to every target. " + "Targets need to be defined in the following format: targetname(,targetversion). The version is optional and " + "is only needed if there are multiple versions of a target in the project. The target must match one " + $"of the targets of the project or one of the targets defined with the '{Constants.TargetArgumentName}' " + "option, if it is defined.") .SetArgumentType(ArgumentType.MultipleValue) .SetSeparator(' ') .Build(); shortNames.Add('f'); } if (!ArgumentAvailableFromDescription(Constants.TargetArgumentName)) { builder = builder.CreateArgument() .SetName(Constants.TargetArgumentName) .SetShortName('t') .SetHelp( "List of targets for which files are deployed. Targets are separated by ' '. " + "Targets need to be defined in the following format: targetname(,targetversion). The version is optional and " + "is only needed if there are multiple versions of a target in the registered SDKs. " + "If used, this option overrides the targets defined in the project. Please consider, that the actual binaries " + "are deployed in the build step. Therefore if they are not built for a specific target, neither are they built here.") .SetArgumentType(ArgumentType.MultipleValue) .SetSeparator(' ') .Build(); shortNames.Add('t'); } if (!ArgumentAvailableFromDescription(Constants.BuildTypeArgumentName)) { builder = builder.CreateArgument() .SetName(Constants.BuildTypeArgumentName) .SetShortName('b') .SetHelp( "Build type for which the deploy should be executed. Default is 'Release'") .SetArgumentType(ArgumentType.SingleValue) .Build(); shortNames.Add('b'); } return(builder); bool ArgumentAvailableFromDescription(string argumentName) { templateArgumentDefinition argument = arguments.Where(a => a.name.Equals(argumentName, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); if (argument == null) { return(false); } GenerateArgumentFromDefinition(templateEntity, builder, argument, shortNames); return(true); } } }
public override Entity Resolve(Entity owner, string key, bool fallback = false) { templateRelationship[] relationships = owner.HasTemplate() ? owner.Template().Relationship : null; templateRelationship relationship = relationships?.FirstOrDefault(r => r.name.Equals(key, StringComparison.OrdinalIgnoreCase)) ?? relationships?.FirstOrDefault(r => r.name.Equals(key.Singular(), StringComparison.OrdinalIgnoreCase)); TemplateDescription relationshipDescription = relationship != null?templateRepository.Template(relationship.type) : null; if (relationshipDescription != null) { return(GetRelationship()); } if (key == EntityKeys.PathKey) { return(GetCommandPath()); } if (key == EntityKeys.FullNameKey) { return(GetFullName()); } return(GetArgument()); Entity GetFullName() { SingleValueArgument nameArgument = owner.Value <CommandDefinition>() .Argument <SingleValueArgument>(EntityKeys.NameKey); SingleValueArgument namespaceArgument = owner.Value <CommandDefinition>() .Argument <SingleValueArgument>(EntityKeys.NamespaceKey); string fullName = codeLanguage.CombineNamespace(Value(namespaceArgument, EntityKeys.NamespaceKey), Value(nameArgument, EntityKeys.NameKey)); return(owner.Create(key, fullName, nameArgument, namespaceArgument)); } Entity GetCommandPath() { SingleValueArgument singleValueArgument = owner.Value <CommandDefinition>() .Argument <SingleValueArgument>(EntityKeys.OutputKey); string basePath = owner.IsRoot() ? string.Empty : owner.Root.Path; string path = fileSystem.GetDirectory(Value(singleValueArgument), basePath, false).FullName; return(owner.Create(key, path, singleValueArgument)); } string Value(Argument arg, string argumentName = null) { if (string.IsNullOrEmpty(argumentName)) { argumentName = key; } if (arg != null && arg is BoolArgument boolArgument) { return(boolArgument.Value.ToString(CultureInfo.InvariantCulture)); } SingleValueArgument singleValueArgument = (SingleValueArgument)arg; if (singleValueArgument?.Value != null) { return(ResolveValue(singleValueArgument.Value)); } if ((arg != null && arg.Name != argumentName && TryGetTemplateDefault(arg.Name, out string result)) || TryGetTemplateDefault(argumentName, out result)) { return(result); } return(string.Empty); } string ResolveValue(string value) { string result = templateResolver.Resolve(value, owner); if (TryGetTemplateFormat(out string format) && !string.IsNullOrEmpty(format)) { Entity temporary = owner.Create(key, result); result = temporary.Format()[format].Value <string>(); } return(result); bool TryGetTemplateFormat(out string formattedValue) { TemplateDescription description = owner.HasTemplate() ? owner.Template() : null; if (description != null) { templateArgumentDefinition templateArgument = description.Arguments.FirstOrDefault(a => a.name == key); if (templateArgument != null) { formattedValue = templateArgument.format; return(true); } } formattedValue = null; return(false); } } bool TryGetTemplateDefault(string argumentName, out string value) { TemplateDescription description = owner.HasTemplate() ? owner.Template() : null; if (description != null) { templateArgumentDefinition templateArgument = description.Arguments.FirstOrDefault(a => a.name == argumentName); if (templateArgument != null) { value = ResolveValue(templateArgument.@default); return(true); } } value = null; return(false); } Entity GetArgument() { Argument argument = owner.Value <CommandDefinition>().Argument <Argument>(key); if (argument == null) { if (TryGetTemplateDefault(key, out string value)) { return(owner.Create(key, value)); } throw new ContentProviderException(key, owner); } switch (argument) { case BoolArgument boolArgument: return(owner.Create(key, Value(argument), boolArgument)); case SingleValueArgument singleValueArgument: return(owner.Create(key, Value(argument), singleValueArgument)); case MultipleValueArgument multipleValueArgument: IEnumerable <Entity> values = Values(multipleValueArgument); return(owner.Create(key, values)); default: throw new InvalidOperationException($"Unkown argument type {argument.GetType()}"); } IEnumerable <Entity> Values(MultipleValueArgument multipleValueArgument) { if (multipleValueArgument.Values != null) { return(multipleValueArgument.Values .Select(s => owner.Create(key, ResolveValue(s), multipleValueArgument))); } if (TryGetTemplateDefault(key, out string result)) { return(new[] { owner.Create(key, result, multipleValueArgument) }); } throw new ContentProviderException(key, owner); } } Entity GetRelationship() { if (relationshipDescription.isRoot) { return(owner.Root); } if (relationship.multiplicity == multiplicity.One) { string name = owner.Value <CommandDefinition>() .Argument <SingleValueArgument>(relationship.name) .Value; return(relationship.GetRelationship(relationshipDescription, owner, name)); } IEnumerable <string> names = owner.Value <CommandDefinition>() .Argument <MultipleValueArgument>(relationship.name) .Values; return(relationship.GetRelationship(relationshipDescription, owner, names.ToArray())); } }