From cfa0e5cbd4313f3b00803f33a52db045e2adbcd4 Mon Sep 17 00:00:00 2001 From: Mike Lorbetske Date: Fri, 16 Dec 2016 15:15:48 -0800 Subject: [PATCH 1/4] First step to ingest template engine Please do not merge yet @piotrp @seancpeters @livarocc --- src/dotnet/Program.cs | 2 + .../commands/dotnet-new3/AppExtensions.cs | 111 +++ .../dotnet-new3/ExtendedCommandParser.cs | 413 ++++++++++ .../commands/dotnet-new3/HelpFormatter.cs | 228 ++++++ src/dotnet/commands/dotnet-new3/Program.cs | 716 ++++++++++++++++++ src/dotnet/dotnet.csproj | 13 + 6 files changed, 1483 insertions(+) create mode 100644 src/dotnet/commands/dotnet-new3/AppExtensions.cs create mode 100644 src/dotnet/commands/dotnet-new3/ExtendedCommandParser.cs create mode 100644 src/dotnet/commands/dotnet-new3/HelpFormatter.cs create mode 100644 src/dotnet/commands/dotnet-new3/Program.cs diff --git a/src/dotnet/Program.cs b/src/dotnet/Program.cs index 4d8786ccf..853a2d9bc 100644 --- a/src/dotnet/Program.cs +++ b/src/dotnet/Program.cs @@ -16,6 +16,7 @@ using Microsoft.DotNet.Tools.List; using Microsoft.DotNet.Tools.Migrate; using Microsoft.DotNet.Tools.MSBuild; using Microsoft.DotNet.Tools.New; +using Microsoft.DotNet.Tools.New3; using Microsoft.DotNet.Tools.NuGet; using Microsoft.DotNet.Tools.Pack; using Microsoft.DotNet.Tools.Publish; @@ -41,6 +42,7 @@ namespace Microsoft.DotNet.Cli ["migrate"] = MigrateCommand.Run, ["msbuild"] = MSBuildCommand.Run, ["new"] = NewCommand.Run, + ["new3"] = New3Command.Run, ["nuget"] = NuGetCommand.Run, ["pack"] = PackCommand.Run, ["publish"] = PublishCommand.Run, diff --git a/src/dotnet/commands/dotnet-new3/AppExtensions.cs b/src/dotnet/commands/dotnet-new3/AppExtensions.cs new file mode 100644 index 000000000..01db5122d --- /dev/null +++ b/src/dotnet/commands/dotnet-new3/AppExtensions.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Microsoft.DotNet.Cli.CommandLine; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Microsoft.DotNet.Tools.New3 +{ + internal static class AppExtensions + { + public static CommandOption Help(this CommandLineApplication app) + { + return app.Option("-h|--help", "Displays help for this command.", CommandOptionType.NoValue); + } + + public static IReadOnlyDictionary> ParseExtraArgs(this CommandLineApplication app, IList extraArgFileNames) + { + Dictionary> parameters = new Dictionary>(); + + // Note: If the same param is specified multiple times across the files, last-in-wins + // TODO: consider another course of action. + if (extraArgFileNames.Count > 0) + { + foreach (string argFile in extraArgFileNames) + { + using (Stream s = File.OpenRead(argFile)) + using (TextReader r = new StreamReader(s, Encoding.UTF8, true, 4096, true)) + using (JsonTextReader reader = new JsonTextReader(r)) + { + JObject obj = JObject.Load(reader); + + foreach (JProperty property in obj.Properties()) + { + if(property.Value.Type == JTokenType.String) + { + IList values = new List(); + values.Add(property.Value.ToString()); + // adding 2 dashes to the file-based params + // won't work right if there's a param that should have 1 dash + // + // TOOD: come up with a better way to deal with this + parameters["--" + property.Name] = values; + } + } + } + } + } + + for (int i = 0; i < app.RemainingArguments.Count; ++i) + { + string key = app.RemainingArguments[i]; + CommandOption arg = app.Options.FirstOrDefault(x => x.Template.Split('|').Any(y => string.Equals(y, key, StringComparison.OrdinalIgnoreCase))); + bool handled = false; + + if (arg != null) + { + if (arg.OptionType != CommandOptionType.NoValue) + { + handled = arg.TryParse(app.RemainingArguments[i + 1]); + ++i; + } + else + { + handled = arg.TryParse(null); + } + } + + if (handled) + { + continue; + } + + if (!key.StartsWith("-", StringComparison.Ordinal)) + { + throw new Exception("Parameter names must start with -- or -"); + } + + // Check the next value. If it doesn't start with a '-' then it's a value for the current param. + // Otherwise it's its own param. + string value = null; + if (app.RemainingArguments.Count > i + 1) + { + value = app.RemainingArguments[i + 1]; + + if (value.StartsWith("-", StringComparison.Ordinal)) + { + value = null; + } + else + { + ++i; + } + } + + IList valueList; + if (!parameters.TryGetValue(key, out valueList)) + { + valueList = new List(); + parameters.Add(key, valueList); + } + + valueList.Add(value); + } + + return parameters; + } + } +} \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-new3/ExtendedCommandParser.cs b/src/dotnet/commands/dotnet-new3/ExtendedCommandParser.cs new file mode 100644 index 000000000..e4f1799a5 --- /dev/null +++ b/src/dotnet/commands/dotnet-new3/ExtendedCommandParser.cs @@ -0,0 +1,413 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.TemplateEngine.Abstractions; +using Microsoft.TemplateEngine.Edge.Settings; + +namespace Microsoft.DotNet.Tools.New3 +{ + internal class ExtendedCommandParser + { + private CommandLineApplication _app; + + // Hidden & default options. Listed here to avoid clashes with on-the-fly params from individual templates. + private HashSet _defaultCommandOptions; + // key is the variant, value is the canonical version + private IDictionary _hiddenCommandCanonicalMapping; + // key is the canonical version + IDictionary _hiddenCommandOptions; + + // maps the template param variants to the canonical forms + private IDictionary _templateParamCanonicalMapping; + // Canonical form -> data type + private IDictionary _templateParamDataTypeMapping; + + // stores the parsed values + private IDictionary _parsedTemplateParams; + private IDictionary> _parsedInternalParams; + private IDictionary> _parsedRemainingParams; + + // stores the options & arguments that are NOT hidden + // this is used exclusively to show the help. + // it's a bit of a hack. + CommandLineApplication _helpDisplayer; + + public ExtendedCommandParser() + { + _app = new CommandLineApplication(false); + _defaultCommandOptions = new HashSet(); + _hiddenCommandOptions = new Dictionary(); + _hiddenCommandCanonicalMapping = new Dictionary(); + _templateParamCanonicalMapping = new Dictionary(); + _templateParamDataTypeMapping = new Dictionary(); + + _parsedTemplateParams = new Dictionary(); + _parsedInternalParams = new Dictionary>(); + _parsedRemainingParams = new Dictionary>(); + + _helpDisplayer = new CommandLineApplication(false); + } + + // TODO: consider optionally showing help for things not handled by the CommandLineApplication instance + public void ShowHelp() + { + _helpDisplayer.ShowHelp(); + } + + public void RemoveOption(CommandOption option) + { + _app.Options.Remove(option); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsParameterNameTaken(string testName) + { + return _defaultCommandOptions.Contains(testName) + || _hiddenCommandCanonicalMapping.ContainsKey(testName) + || _templateParamCanonicalMapping.ContainsKey(testName); + } + + public int Execute(params string[] args) + { + return _app.Execute(args); + } + + public void OnExecute(Func> invoke) + { + _app.OnExecute(invoke); + } + + // Returns the "standard" args that were input - the ones handled by the CommandLineApplication + public List RemainingArguments + { + get { return _app.RemainingArguments; } + } + + public CommandArgument Argument(string parameter, string description) + { + if (IsParameterNameTaken(parameter)) + { + throw new Exception($"Parameter name {parameter} cannot be used for multiple purposes"); + } + + _defaultCommandOptions.Add(parameter); + + // its not hidden, add it to the help + _helpDisplayer.Argument(parameter, description); + + return _app.Argument(parameter, description); + } + + public void InternalOption(string parameterVariants, string canonical, string description, CommandOptionType optionType) + { + _helpDisplayer.Option(parameterVariants, description, optionType); + HiddenInternalOption(parameterVariants, canonical, optionType); + } + + // NOTE: the exceptions here should never happen, this is strictly called by the program + // Once testing is done, we can probably remove them. + public void HiddenInternalOption(string parameterVariants, string canonical, CommandOptionType optionType) + { + string[] parameters = parameterVariants.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries); + + for (int i = 0; i < parameters.Length; i++) + { + if (IsParameterNameTaken(parameters[i])) + { + throw new Exception($"Parameter name {parameters[i]} cannot be used for multiple purposes"); + } + + _hiddenCommandCanonicalMapping.Add(parameters[i], canonical); + } + + _hiddenCommandOptions.Add(canonical, optionType); + } + + public bool TemplateParamHasValue(string paramName) + { + return _parsedTemplateParams.ContainsKey(paramName); + } + + public string TemplateParamValue(string paramName) + { + _parsedTemplateParams.TryGetValue(paramName, out string value); + return value; + } + + // returns a copy of the template params + public IReadOnlyDictionary AllTemplateParams + { + get + { + return new Dictionary(_parsedTemplateParams); + } + } + + public bool InternalParamHasValue(string paramName) + { + return _parsedInternalParams.ContainsKey(paramName); + } + + public string InternalParamValue(string paramName) + { + if (_parsedInternalParams.TryGetValue(paramName, out IList values)) + { + return values.FirstOrDefault(); + } + else + { + return null; + } + } + + public IList InternalParamValueList(string paramName) + { + _parsedInternalParams.TryGetValue(paramName, out IList values); + return values; + } + + public IDictionary> RemainingParameters + { + get + { + return _parsedRemainingParams; + } + } + + // Parses all command line args, and any input arg files. + // NOTE: any previously parsed values are lost - this resets the parsed values. + public void ParseArgs(IList extraArgFileNames = null) + { + _parsedTemplateParams = new Dictionary(); + _parsedInternalParams = new Dictionary>(); + _parsedRemainingParams = new Dictionary>(); + + if (extraArgFileNames == null) + { + extraArgFileNames = new List(); + } + IReadOnlyDictionary> allParameters = _app.ParseExtraArgs(extraArgFileNames); + + foreach (KeyValuePair> param in allParameters) + { + string canonicalName; + if (_hiddenCommandCanonicalMapping.TryGetValue(param.Key, out canonicalName)) + { + CommandOptionType optionType = _hiddenCommandOptions[canonicalName]; + + if (optionType == CommandOptionType.MultipleValue) + { + ; // nothing to check + } + else if (optionType == CommandOptionType.SingleValue) + { + if (param.Value.Count != 1) + { + throw new Exception($"Multiple values specified for single value parameter: {canonicalName}"); + } + } + else // NoValue + { + if (param.Value.Count != 1 || param.Value[0] != null) + { + throw new Exception($"Value specified for valueless parameter: {canonicalName}"); + } + } + + _parsedInternalParams.Add(canonicalName, param.Value); + } + else if (_templateParamCanonicalMapping.TryGetValue(param.Key, out canonicalName)) + { + if (_parsedTemplateParams.ContainsKey(canonicalName)) + { + // error, the same param was specified twice + throw new Exception($"Parameter [{canonicalName}] was specified multiple times, including with the flag [{param.Key}]"); + } + else + { + if ((param.Value[0] == null) && (_templateParamDataTypeMapping[canonicalName] != "bool")) + { + throw new Exception($"Parameter [{param.Key}] ({canonicalName}) must be given a value"); + } + + // TODO: allow for multi-valued params + _parsedTemplateParams[canonicalName] = param.Value[0]; + } + } + else + { + // not a known internal or template param. + _parsedRemainingParams[param.Key] = param.Value; + } + } + } + + // Canonical is the template param name without any dashes. The things mapped to it all have dashes, including the param name itself. + public void SetupTemplateParameters(IParameterSet allParams, IReadOnlyDictionary parameterNameMap) + { + HashSet invalidParams = new HashSet(); + + foreach (ITemplateParameter parameter in allParams.ParameterDefinitions.Where(x => x.Priority != TemplateParameterPriority.Implicit).OrderBy(x => x.Name)) + { + if (parameter.Name.IndexOf(':') >= 0) + { // Colon is reserved, template param names cannot have any. + invalidParams.Add(parameter.Name); + continue; + } + + string flagFullText; + if (parameterNameMap == null || !parameterNameMap.TryGetValue(parameter.Name, out flagFullText)) + { + flagFullText = parameter.Name; + } + + bool longNameFound = false; + bool shortNameFound = false; + + // always unless taken + string nameAsParameter = "--" + flagFullText; + if (!IsParameterNameTaken(nameAsParameter)) + { + MapTemplateParamToCanonical(nameAsParameter, parameter.Name); + longNameFound = true; + } + + // only as fallback + string qualifiedName = "--param:" + flagFullText; + if (!longNameFound && !IsParameterNameTaken(qualifiedName)) + { + MapTemplateParamToCanonical(qualifiedName, parameter.Name); + longNameFound = true; + } + + // always unless taken + string shortName = "-" + PosixNameToShortName(flagFullText); + if (!IsParameterNameTaken(shortName)) + { + MapTemplateParamToCanonical(shortName, parameter.Name); + shortNameFound = true; + } + + // only as fallback + string singleLetterName = "-" + flagFullText.Substring(0, 1); + if (!shortNameFound && !IsParameterNameTaken(singleLetterName)) + { + MapTemplateParamToCanonical(singleLetterName, parameter.Name); + shortNameFound = true; + } + + // only as fallback + string qualifiedShortName = "-p:" + PosixNameToShortName(flagFullText); + if (!shortNameFound && !IsParameterNameTaken(qualifiedShortName)) + { + MapTemplateParamToCanonical(qualifiedShortName, parameter.Name); + shortNameFound = true; + } + + // only as fallback + string qualifiedSingleLetterName = "-p:" + flagFullText.Substring(0, 1); + if (!shortNameFound && !IsParameterNameTaken(qualifiedSingleLetterName)) + { + MapTemplateParamToCanonical(qualifiedSingleLetterName, parameter.Name); + shortNameFound = true; + } + + if (!shortNameFound && !longNameFound) + { + invalidParams.Add(flagFullText); + } + else + { + _templateParamDataTypeMapping[parameter.Name] = parameter.DataType; + } + } + + if (invalidParams.Count > 0) + { + string unusableDisplayList = string.Join(", ", invalidParams); + throw new Exception($"Template is malformed. The following parameter names are invalid: {unusableDisplayList}"); + } + } + + private void MapTemplateParamToCanonical(string variant, string canonical) + { + if (_templateParamCanonicalMapping.TryGetValue(variant, out string existingCanonical)) + { + throw new Exception($"Option variant {variant} for canonical {canonical} was already defined for canonical {existingCanonical}"); + } + + _templateParamCanonicalMapping[variant] = canonical; + } + + // Concats the first letter of dash separated word. + private static string PosixNameToShortName(string name) + { + IList wordsInName = name.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries).ToList(); + IList firstLetters = new List(); + + foreach (string word in wordsInName) + { + firstLetters.Add(word.Substring(0, 1)); + } + + return string.Join("", firstLetters); + } + + private IDictionary> _canonicalToVariantsTemplateParamMap; + + public IDictionary> CanonicalToVariantsTemplateParamMap + { + get + { + if (_canonicalToVariantsTemplateParamMap == null) + { + _canonicalToVariantsTemplateParamMap = new Dictionary>(); + + foreach (KeyValuePair variantToCanonical in _templateParamCanonicalMapping) + { + string variant = variantToCanonical.Key; + string canonical = variantToCanonical.Value; + + IList variantList; + if (!_canonicalToVariantsTemplateParamMap.TryGetValue(canonical, out variantList)) + { + variantList = new List(); + _canonicalToVariantsTemplateParamMap.Add(canonical, variantList); + } + + variantList.Add(variant); + } + } + + return _canonicalToVariantsTemplateParamMap; + } + } + + public string Name + { + get + { + return _app.Name; + } + set + { + _app.Name = value; + } + } + + public string FullName + { + get + { + return _app.FullName; + } + set + { + _app.FullName = value; + } + } + } +} diff --git a/src/dotnet/commands/dotnet-new3/HelpFormatter.cs b/src/dotnet/commands/dotnet-new3/HelpFormatter.cs new file mode 100644 index 000000000..6dea14662 --- /dev/null +++ b/src/dotnet/commands/dotnet-new3/HelpFormatter.cs @@ -0,0 +1,228 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Microsoft.DotNet.Tools.New3 +{ + public class HelpFormatter + { + public static HelpFormatter For(IEnumerable items, int columnPadding, char? headerSeparator = null, bool blankLineBetweenRows = false) + { + return new HelpFormatter(items, columnPadding, headerSeparator, blankLineBetweenRows); + } + } + + public class HelpFormatter + { + private readonly bool _blankLineBetweenRows; + private readonly int _columnPadding; + private readonly List _columns = new List(); + private readonly char? _headerSeparator; + private readonly IEnumerable _items; + + public HelpFormatter(IEnumerable items, int columnPadding, char? headerSeparator, bool blankLineBetweenRows) + { + _items = items; + _columnPadding = columnPadding; + _headerSeparator = headerSeparator; + _blankLineBetweenRows = blankLineBetweenRows; + } + + public HelpFormatter DefineColumn(Func binder, string header = null, int maxWidth = 0, bool alwaysMaximizeWidth = false) + { + _columns.Add(new ColumnDefinition(header, binder, maxWidth, alwaysMaximizeWidth)); + return this; + } + + public string Layout() + { + Dictionary widthLookup = new Dictionary(); + Dictionary lineCountLookup = new Dictionary(); + List textByRow = new List(); + + TextWrapper[] header = new TextWrapper[_columns.Count]; + int headerLines = 0; + for (int i = 0; i < _columns.Count; ++i) + { + header[i] = new TextWrapper(_columns[i].Header, _columns[i].MaxWidth, _columns[i].AlwaysMaximizeWidth); + headerLines = Math.Max(headerLines, header[i].LineCount); + widthLookup[i] = header[i].MaxWidth; + } + + int lineNumber = 0; + + foreach (T item in _items) + { + TextWrapper[] line = new TextWrapper[_columns.Count]; + int maxLineCount = 0; + + for (int i = 0; i < _columns.Count; ++i) + { + line[i] = _columns[i].GetCell(item); + widthLookup[i] = Math.Max(widthLookup[i], line[i].MaxWidth); + maxLineCount = Math.Max(maxLineCount, line[i].LineCount); + } + + lineCountLookup[lineNumber++] = maxLineCount; + textByRow.Add(line); + } + + StringBuilder b = new StringBuilder(); + + if (_columns.Any(x => !string.IsNullOrEmpty(x.Header))) + { + for (int j = 0; j < headerLines; ++j) + { + for (int i = 0; i < _columns.Count - 1; ++i) + { + b.Append(header[i][j, widthLookup[i]]); + b.Append("".PadRight(_columnPadding)); + } + + b.AppendLine(header[_columns.Count - 1][j, widthLookup[_columns.Count - 1]]); + } + } + + if (_headerSeparator.HasValue) + { + int totalWidth = _columnPadding * (_columns.Count - 1); + + for (int i = 0; i < _columns.Count; ++i) + { + totalWidth += Math.Max(header[i].MaxWidth, widthLookup[i]); + } + + b.AppendLine("".PadRight(totalWidth, _headerSeparator.Value)); + } + + int currentLine = 0; + foreach (TextWrapper[] line in textByRow) + { + for (int j = 0; j < lineCountLookup[currentLine]; ++j) + { + for (int i = 0; i < _columns.Count - 1; ++i) + { + b.Append(line[i][j, widthLookup[i]]); + b.Append("".PadRight(_columnPadding)); + } + + b.AppendLine(line[_columns.Count - 1][j, widthLookup[_columns.Count - 1]]); + } + + if (_blankLineBetweenRows) + { + b.AppendLine(); + } + + ++currentLine; + } + + return b.ToString(); + } + + private class ColumnDefinition + { + private readonly int _maxWidth; + private readonly string _header; + private readonly Func _binder; + private readonly bool _alwaysMaximizeWidth; + + public ColumnDefinition(string header, Func binder, int maxWidth = -1, bool alwaysMaximizeWidth = false) + { + _header = header; + _maxWidth = maxWidth > 0 ? maxWidth : int.MaxValue; + _binder = binder; + _alwaysMaximizeWidth = alwaysMaximizeWidth && maxWidth > 0; + } + + public string Header => _header; + + public bool AlwaysMaximizeWidth => _alwaysMaximizeWidth; + + public int MaxWidth => _maxWidth; + + public TextWrapper GetCell(T value) + { + return new TextWrapper(_binder(value), _maxWidth, _alwaysMaximizeWidth); + } + } + + private class TextWrapper + { + private readonly IReadOnlyList _lines; + + public TextWrapper(string text, int maxWidth, bool alwaysMax) + { + List lines = new List(); + int position = 0; + int realMaxWidth = alwaysMax ? maxWidth : 0; + + while (position < text.Length) + { + int newline = text.IndexOf(Environment.NewLine, position, StringComparison.Ordinal); + + if (newline > -1) + { + if (newline - position <= maxWidth) + { + lines.Add(text.Substring(position, newline - position).TrimEnd()); + position = newline + Environment.NewLine.Length; + } + else + { + GetLineText(text, lines, maxWidth, newline, ref position); + } + } + else + { + GetLineText(text, lines, maxWidth, text.Length - 1, ref position); + } + + realMaxWidth = Math.Max(realMaxWidth, lines[lines.Count - 1].Length); + } + + _lines = lines; + MaxWidth = realMaxWidth; + } + + public int LineCount => _lines.Count; + + public int MaxWidth { get; } + + public string this[int index, int padTo = 0] + { + get { return (_lines.Count > index ? _lines[index] : string.Empty).PadRight(MaxWidth).PadRight(padTo > MaxWidth ? padTo : MaxWidth); } + } + + private static void GetLineText(string text, List lines, int maxLength, int end, ref int position) + { + if (text.Length - position < maxLength) + { + lines.Add(text.Substring(position)); + position = text.Length; + return; + } + + int lastBreak = text.LastIndexOfAny(new[] { ' ', '-' }, end, end - position); + while (lastBreak > 0 && lastBreak - position > maxLength) + { + --lastBreak; + lastBreak = text.LastIndexOfAny(new[] { ' ', '-' }, lastBreak, lastBreak - position); + } + + if (lastBreak > 0) + { + lines.Add(text.Substring(position, lastBreak - position + 1).TrimEnd()); + position = lastBreak + 1; + } + else + { + int properMax = Math.Min(maxLength - 1, text.Length - position); + lines.Add(text.Substring(position, properMax) + '-'); + position += maxLength - 1; + } + } + } + } +} diff --git a/src/dotnet/commands/dotnet-new3/Program.cs b/src/dotnet/commands/dotnet-new3/Program.cs new file mode 100644 index 000000000..daea87610 --- /dev/null +++ b/src/dotnet/commands/dotnet-new3/Program.cs @@ -0,0 +1,716 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.DotNet.Cli; +using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.TemplateEngine.Abstractions; +using Microsoft.TemplateEngine.Abstractions.Mount; +using Microsoft.TemplateEngine.Edge; +using Microsoft.TemplateEngine.Edge.Settings; +using Microsoft.TemplateEngine.Edge.Template; +using Microsoft.TemplateEngine.Utils; + +namespace Microsoft.DotNet.Tools.New3 +{ + public class New3Command + { + private static readonly string HostIdentifier = "dotnetcli"; + private static readonly Version HostVersion = typeof(Program).GetTypeInfo().Assembly.GetName().Version; + private static DefaultTemplateEngineHost Host; + + private static void SetupInternalCommands(ExtendedCommandParser appExt) + { + // visible + appExt.InternalOption("-l|--list", "--list", "List templates containing the specified name.", CommandOptionType.NoValue); + appExt.InternalOption("-n|--name", "--name", "The name for the output being created. If no name is specified, the name of the current directory is used.", CommandOptionType.SingleValue); + appExt.InternalOption("-h|--help", "--help", "Display help for the indicated template's parameters.", CommandOptionType.NoValue); + + // hidden + appExt.HiddenInternalOption("-d|--dir", "--dir", CommandOptionType.NoValue); + appExt.HiddenInternalOption("-a|--alias", "--alias", CommandOptionType.SingleValue); + appExt.HiddenInternalOption("-x|--extra-args", "--extra-args", CommandOptionType.MultipleValue); + appExt.HiddenInternalOption("--locale", "--locale", CommandOptionType.SingleValue); + appExt.HiddenInternalOption("--quiet", "--quiet", CommandOptionType.NoValue); + appExt.HiddenInternalOption("-i|--install", "--install", CommandOptionType.MultipleValue); + + // reserved but not currently used + appExt.HiddenInternalOption("-up|--update", "--update", CommandOptionType.MultipleValue); + appExt.HiddenInternalOption("-u|--uninstall", "--uninstall", CommandOptionType.MultipleValue); + appExt.HiddenInternalOption("--skip-update-check", "--skip-update-check", CommandOptionType.NoValue); + + // Preserve these for now - they've got the help text, in case we want it back. + // (they'll need to get converted to extended option calls) + // + //CommandOption dirOption = app.Option("-d|--dir", "Indicates whether to create a directory for the generated content.", CommandOptionType.NoValue); + //CommandOption aliasOption = app.Option("-a|--alias", "Creates an alias for the specified template.", CommandOptionType.SingleValue); + //CommandOption parametersFilesOption = app.Option("-x|--extra-args", "Specifies a file containing additional parameters.", CommandOptionType.MultipleValue); + //CommandOption localeOption = app.Option("--locale", "The locale to use", CommandOptionType.SingleValue); + //CommandOption quietOption = app.Option("--quiet", "Doesn't output any status information.", CommandOptionType.NoValue); + //CommandOption installOption = app.Option("-i|--install", "Installs a source or a template pack.", CommandOptionType.MultipleValue); + + //CommandOption update = app.Option("--update", "Update matching templates.", CommandOptionType.NoValue); + } + + public static int Run(string[] args) + { + // Initial host setup has the current locale. May need to be changed based on inputs. + Host = new DefaultTemplateEngineHost(HostIdentifier, HostVersion, CultureInfo.CurrentCulture.Name); + EngineEnvironmentSettings.Host = Host; + + ExtendedCommandParser app = new ExtendedCommandParser() + { + Name = "dotnet new3", + FullName = "Template Instantiation Commands for .NET Core CLI." + }; + SetupInternalCommands(app); + CommandArgument templateNames = app.Argument("template", "The template to instantiate."); + + app.OnExecute(async () => + { + app.ParseArgs(); + if (app.InternalParamHasValue("--extra-args")) + { + app.ParseArgs(app.InternalParamValueList("--extra-args")); + } + + if (app.RemainingParameters.ContainsKey("--debug:attach")) + { + Console.ReadLine(); + } + + if (app.InternalParamHasValue("--locale")) + { + string newLocale = app.InternalParamValue("--locale"); + if (!ValidateLocaleFormat(newLocale)) + { + EngineEnvironmentSettings.Host.LogMessage(string.Format("Invalid format for input locale: [{0}]. Example valid formats: [en] [en-US]", newLocale)); + return -1; + } + + Host.UpdateLocale(newLocale); + } + + int resultCode = InitializationAndDebugging(app, out bool shouldExit); + if (shouldExit) + { + return resultCode; + } + + resultCode = ParseTemplateArgs(app, templateNames.Value, out shouldExit); + if (shouldExit) + { + return resultCode; + } + + resultCode = MaintenanceAndInfo(app, templateNames.Value, out shouldExit); + if (shouldExit) + { + return resultCode; + } + + return await CreateTemplate(app, templateNames.Value); + }); + + int result; + try + { + using (Timing.Over("Execute")) + { + result = app.Execute(args); + } + } + catch (Exception ex) + { + AggregateException ax = ex as AggregateException; + + while (ax != null && ax.InnerExceptions.Count == 1) + { + ex = ax.InnerException; + ax = ex as AggregateException; + } + + Reporter.Error.WriteLine(ex.Message.Bold().Red()); + + while (ex.InnerException != null) + { + ex = ex.InnerException; + ax = ex as AggregateException; + + while (ax != null && ax.InnerExceptions.Count == 1) + { + ex = ax.InnerException; + ax = ex as AggregateException; + } + + Reporter.Error.WriteLine(ex.Message.Bold().Red()); + } + + Reporter.Error.WriteLine(ex.StackTrace.Bold().Red()); + result = 1; + } + + return result; + } + + private static async Task CreateTemplate(ExtendedCommandParser app, string templateName) + { + string nameValue = app.InternalParamValue("--name"); + string fallbackName = new DirectoryInfo(Directory.GetCurrentDirectory()).Name; + bool dirValue = app.InternalParamHasValue("--dir"); + string aliasName = app.InternalParamValue("--alias"); + bool skipUpdateCheckValue = app.InternalParamHasValue("--skip-update-check"); + + // TODO: refactor alias creation out of InstantiateAsync() + TemplateCreationResult instantiateResult = await TemplateCreator.InstantiateAsync(templateName ?? "", nameValue, fallbackName, dirValue, aliasName, app.AllTemplateParams, skipUpdateCheckValue); + + string resultTemplateName = string.IsNullOrEmpty(instantiateResult.TemplateFullName) ? templateName : instantiateResult.TemplateFullName; + + switch (instantiateResult.Status) + { + case CreationResultStatus.AliasSucceeded: + // TODO: get this localized - in the mean time just list the templates, showing the alias + //EngineEnvironmentSettings.Host.LogMessage("Alias creation successful"); + ListTemplates(templateName); + break; + case CreationResultStatus.AliasFailed: + EngineEnvironmentSettings.Host.LogMessage(string.Format("Specified alias {0} already exists. Please specify a different alias.", aliasName)); + ListTemplates(templateName); + break; + case CreationResultStatus.CreateSucceeded: + EngineEnvironmentSettings.Host.LogMessage(string.Format("The template {0} created successfully. Please run \"dotnet restore\" to get started!", resultTemplateName)); + break; + case CreationResultStatus.CreateFailed: + EngineEnvironmentSettings.Host.LogMessage(string.Format("Template {0} could not be created. Error returned was: {1}", resultTemplateName, instantiateResult.Message)); + ListTemplates(templateName); + break; + case CreationResultStatus.InstallSucceeded: + EngineEnvironmentSettings.Host.LogMessage(string.Format("The template {0} installed successfully. You can use \"dotnet new {0}\" to get started with the new template.", resultTemplateName)); + break; + case CreationResultStatus.InstallFailed: + EngineEnvironmentSettings.Host.LogMessage(string.Format("Template {0} could not be created. Error returned was: {1}.", resultTemplateName, instantiateResult.Message)); + break; + case CreationResultStatus.MissingMandatoryParam: + EngineEnvironmentSettings.Host.LogMessage(string.Format("Mandatory parameter {0} missing for template {1}.", instantiateResult.Message, resultTemplateName)); + break; + case CreationResultStatus.TemplateNotFound: + EngineEnvironmentSettings.Host.LogMessage(string.Format("Template {0} could not be created. Error returned was: {1}.", resultTemplateName, instantiateResult.Message)); + ListTemplates(templateName); + break; + default: + break; + } + + return instantiateResult.ResultCode; + } + + private static int InitializationAndDebugging(ExtendedCommandParser app, out bool shouldExit) + { + bool reinitFlag = app.RemainingArguments.Any(x => x == "--debug:reinit"); + if (reinitFlag) + { + Paths.User.FirstRunCookie.Delete(); + } + + // Note: this leaves things in a weird state. Might be related to the localized caches. + // not sure, need to look into it. + if (reinitFlag || app.RemainingArguments.Any(x => x == "--debug:reset-config")) + { + Paths.User.AliasesFile.Delete(); + Paths.User.SettingsFile.Delete(); + TemplateCache.DeleteAllLocaleCacheFiles(); + shouldExit = true; + return 0; + } + + if (!Paths.User.BaseDir.Exists() || !Paths.User.FirstRunCookie.Exists()) + { + if (!app.InternalParamHasValue("--quiet")) + { + Reporter.Output.WriteLine("Getting things ready for first use..."); + } + + ConfigureEnvironment(); + Paths.User.FirstRunCookie.WriteAllText(""); + } + + if (app.RemainingArguments.Any(x => x == "--debug:showconfig")) + { + ShowConfig(); + shouldExit = true; + return 0; + } + + shouldExit = false; + return 0; + } + + private static int ParseTemplateArgs(ExtendedCommandParser app, string templateName, out bool shouldExit) + { + try + { + IReadOnlyCollection templates = TemplateCreator.List(templateName); + if (templates.Count == 1) + { + ITemplateInfo templateInfo = templates.First(); + + ITemplate template = SettingsLoader.LoadTemplate(templateInfo); + IParameterSet allParams = template.Generator.GetParametersForTemplate(template); + IReadOnlyDictionary parameterNameMap = template.Generator.ParameterMapForTemplate(template); + app.SetupTemplateParameters(allParams, parameterNameMap); + } + + // re-parse after setting up the template params + app.ParseArgs(app.InternalParamValueList("--extra-args")); + } + catch (Exception ex) + { + Reporter.Error.WriteLine(ex.Message.Red().Bold()); + app.ShowHelp(); + shouldExit = true; + return -1; + } + + if (app.RemainingParameters.Any(x => !x.Key.StartsWith("--debug:"))) + { + EngineEnvironmentSettings.Host.LogMessage("Invalid input switch:"); + foreach (string flag in app.RemainingParameters.Keys) + { + EngineEnvironmentSettings.Host.LogMessage($"\t{flag}"); + } + + shouldExit = true; + return DisplayHelp(templateName, app, app.AllTemplateParams); + } + + shouldExit = false; + return 0; + } + + private static int MaintenanceAndInfo(ExtendedCommandParser app, string templateName, out bool shouldExit) + { + if (app.InternalParamHasValue("--list")) + { + ListTemplates(templateName); + shouldExit = true; + return -1; + } + + if (app.InternalParamHasValue("--help")) + { + shouldExit = true; + return DisplayHelp(templateName, app, app.AllTemplateParams); + } + + if (app.InternalParamHasValue("--install")) + { + InstallPackages(app.InternalParamValueList("--install").ToList(), app.InternalParamHasValue("--quiet")); + shouldExit = true; + return 0; + } + + //if (update.HasValue()) + //{ + // return PerformUpdateAsync(templateName, quiet, source); + //} + + if (string.IsNullOrEmpty(templateName)) + { + ListTemplates(string.Empty); + shouldExit = true; + return -1; + } + + shouldExit = false; + return 0; + } + + private static Regex _localeFormatRegex = new Regex(@" + ^ + [a-z]{2} + (?:-[A-Z]{2})? + $" + , RegexOptions.IgnorePatternWhitespace); + + private static bool ValidateLocaleFormat(string localeToCheck) + { + return _localeFormatRegex.IsMatch(localeToCheck); + } + + //private static async Task PerformUpdateAsync(string name, bool quiet, CommandOption source) + //{ + // HashSet allSources = new HashSet(); + // HashSet toInstall = new HashSet(StringComparer.OrdinalIgnoreCase); + + // foreach (ITemplate template in TemplateCreator.List(name, source)) + // { + // allSources.Add(template.Source); + // } + + // foreach (IConfiguredTemplateSource src in allSources) + // { + // if (!quiet) + // { + // Reporter.Output.WriteLine($"Checking for updates for {src.Alias}..."); + // } + + // bool updatesReady; + + // if (src.ParentSource != null) + // { + // updatesReady = await src.Source.CheckForUpdatesAsync(src.ParentSource, src.Location); + // } + // else + // { + // updatesReady = await src.Source.CheckForUpdatesAsync(src.Location); + // } + + // if (updatesReady) + // { + // if (!quiet) + // { + // Reporter.Output.WriteLine($"An update for {src.Alias} is available..."); + // } + + // string packageId = src.ParentSource != null + // ? src.Source.GetInstallPackageId(src.ParentSource, src.Location) + // : src.Source.GetInstallPackageId(src.Location); + + // toInstall.Add(packageId); + // } + // } + + // if(toInstall.Count == 0) + // { + // if (!quiet) + // { + // Reporter.Output.WriteLine("No updates were found."); + // } + + // return 0; + // } + + // if (!quiet) + // { + // Reporter.Output.WriteLine("Installing updates..."); + // } + + // List installCommands = new List(); + // List uninstallCommands = new List(); + + // foreach (string packageId in toInstall) + // { + // installCommands.Add("-i"); + // installCommands.Add(packageId); + + // uninstallCommands.Add("-i"); + // uninstallCommands.Add(packageId); + // } + + // installCommands.Add("--quiet"); + // uninstallCommands.Add("--quiet"); + + // Command.CreateDotNet("new3", uninstallCommands).ForwardStdOut().ForwardStdErr().Execute(); + // Command.CreateDotNet("new3", installCommands).ForwardStdOut().ForwardStdErr().Execute(); + // Broker.ComponentRegistry.ForceReinitialize(); + + // if (!quiet) + // { + // Reporter.Output.WriteLine("Done."); + // } + + // return 0; + //} + + private static void ConfigureEnvironment() + { + string userNuGetConfig = $@" + + + + +"; + Paths.User.NuGetConfig.WriteAllText(userNuGetConfig); + + string[] packageList = Paths.Global.DefaultInstallPackageList.ReadAllText().Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); + if (packageList.Length > 0) + { + InstallPackages(packageList, true); + } + + packageList = Paths.Global.DefaultInstallTemplateList.ReadAllText().Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); + if (packageList.Length > 0) + { + InstallPackages(packageList, true); + } + } + + private static void InstallPackages(IReadOnlyList packageNames, bool quiet = false) + { + List toInstall = new List(); + + foreach (string package in packageNames) + { + string pkg = package.Trim(); + pkg = Environment.ExpandEnvironmentVariables(pkg); + + try + { + if (Directory.Exists(pkg) || File.Exists(pkg)) + { + string packageLocation = new DirectoryInfo(pkg).FullName; + TemplateCache.Scan(packageLocation); + } + else + { + string directory = Path.GetDirectoryName(pkg); + string fileGlob = Path.GetFileName(pkg); + string fullDirectory = new DirectoryInfo(directory).FullName; + string fullPathGlob = Path.Combine(fullDirectory, fileGlob); + TemplateCache.Scan(fullPathGlob); + } + } + catch + { + EngineEnvironmentSettings.Host.OnNonCriticalError("InvalidPackageSpecification", string.Format($"Package [{pkg}] is not a valid package specification"), null, 0); + } + } + + TemplateCache.WriteTemplateCaches(); + + if (!quiet) + { + ListTemplates(string.Empty); + } + } + + private static void ListTemplates(string templateNames) + { + IEnumerable results = TemplateCreator.List(templateNames); + HelpFormatter formatter = new HelpFormatter(results, 6, '-', false); + formatter.DefineColumn(delegate (ITemplateInfo t) { return t.Name; }, "Templates"); + formatter.DefineColumn(delegate (ITemplateInfo t) { return $"[{t.ShortName}]"; }, "Short Name"); + formatter.DefineColumn(delegate (ITemplateInfo t) { return AliasRegistry.GetAliasForTemplate(t) ?? ""; }, "Alias"); + Reporter.Output.WriteLine(formatter.Layout()); + } + + private static void ShowConfig() + { + Reporter.Output.WriteLine("dotnet new3 current configuration:"); + Reporter.Output.WriteLine(" "); + TableFormatter.Print(SettingsLoader.MountPoints, "(No Items)", " ", '-', new Dictionary> + { + {"Mount Points", x => x.Place}, + {"Id", x => x.MountPointId}, + {"Parent", x => x.ParentMountPointId}, + {"Factory", x => x.MountPointFactoryId} + }); + + TableFormatter.Print(SettingsLoader.Components.OfType(), "(No Items)", " ", '-', new Dictionary> + { + {"Mount Point Factories", x => x.Id}, + {"Type", x => x.GetType().FullName}, + {"Assembly", x => x.GetType().GetTypeInfo().Assembly.FullName} + }); + + TableFormatter.Print(SettingsLoader.Components.OfType(), "(No Items)", " ", '-', new Dictionary> + { + {"Generators", x => x.Id}, + {"Type", x => x.GetType().FullName}, + {"Assembly", x => x.GetType().GetTypeInfo().Assembly.FullName} + }); + } + + private static int DisplayHelp(string templateNames, ExtendedCommandParser app, IReadOnlyDictionary userParameters) + { + if (string.IsNullOrWhiteSpace(templateNames)) + { // no template specified + app.ShowHelp(); + return 0; + } + + IReadOnlyCollection templates = TemplateCreator.List(templateNames); + + if (templates.Count > 1) + { + ListTemplates(templateNames); + return -1; + } + else if (templates.Count == 1) + { + ITemplateInfo templateInfo = templates.First(); + return TemplateHelp(templateInfo, app, userParameters); + } + else + { + // TODO: add a message indicating no templates matched the pattern. Requires LOC coordination + ListTemplates(string.Empty); + return -1; + } + } + + private static int TemplateHelp(ITemplateInfo templateInfo, ExtendedCommandParser app, IReadOnlyDictionary userParameters) + { + Reporter.Output.WriteLine(templateInfo.Name); + if (!string.IsNullOrWhiteSpace(templateInfo.Author)) + { + Reporter.Output.WriteLine($"Author: {templateInfo.Author}"); + } + + if (!string.IsNullOrWhiteSpace(templateInfo.Description)) + { + Reporter.Output.WriteLine($"Description: {templateInfo.Description}"); + } + + ITemplate template = SettingsLoader.LoadTemplate(templateInfo); + IParameterSet allParams = TemplateCreator.SetupDefaultParamValuesFromTemplateAndHost(template, template.DefaultName); + TemplateCreator.ResolveUserParameters(template, allParams, userParameters); + ParameterHelp(allParams, app); + + return 0; + } + + private static void ParameterHelp(IParameterSet allParams, ExtendedCommandParser app) + { + IEnumerable filteredParams = allParams.ParameterDefinitions.Where(x => x.Priority != TemplateParameterPriority.Implicit); + + if (filteredParams.Any()) + { + HelpFormatter formatter = new HelpFormatter(filteredParams, 2, null, true); + + formatter.DefineColumn(delegate (ITemplateParameter param) + { + // the key is guaranteed to exist + IList variants = app.CanonicalToVariantsTemplateParamMap[param.Name]; + string options = string.Join("|", variants.Reverse()); + return " " + options; + }, + "Options:" + ); + + formatter.DefineColumn(delegate (ITemplateParameter param) + { + StringBuilder displayValue = new StringBuilder(255); + displayValue.AppendLine(param.Documentation); + + if (string.Equals(param.DataType, "choice", StringComparison.OrdinalIgnoreCase)) + { + displayValue.AppendLine(string.Join(", ", param.Choices)); + } + else + { + displayValue.Append(param.DataType ?? "string"); + displayValue.AppendLine(" - " + param.Priority.ToString()); + } + + if (allParams.ResolvedValues.TryGetValue(param, out object resolvedValueObject)) + { + string resolvedValue = resolvedValueObject as string; + + if (!string.IsNullOrEmpty(resolvedValue) + && !string.IsNullOrEmpty(param.DefaultValue) + && !string.Equals(param.DefaultValue, resolvedValue)) + { + displayValue.AppendLine("Configured Value: " + resolvedValue); + } + } + + if (!string.IsNullOrEmpty(param.DefaultValue)) + { + displayValue.AppendLine("Default: " + param.DefaultValue); + } + + return displayValue.ToString(); + }, + string.Empty + ); + + Reporter.Output.WriteLine(formatter.Layout()); + } + else + { + Reporter.Output.WriteLine(" (No Parameters)"); + } + } + } + + internal class TableFormatter + { + public static void Print(IEnumerable items, string noItemsMessage, string columnPad, char header, Dictionary> dictionary) + { + List[] columns = new List[dictionary.Count]; + + for (int i = 0; i < dictionary.Count; ++i) + { + columns[i] = new List(); + } + + string[] headers = new string[dictionary.Count]; + int[] columnWidths = new int[dictionary.Count]; + int valueCount = 0; + + foreach (T item in items) + { + int index = 0; + foreach (KeyValuePair> act in dictionary) + { + headers[index] = act.Key; + columns[index++].Add(act.Value(item)?.ToString() ?? "(null)"); + } + ++valueCount; + } + + if (valueCount > 0) + { + for (int i = 0; i < columns.Length; ++i) + { + columnWidths[i] = Math.Max(columns[i].Max(x => x.Length), headers[i].Length); + } + } + else + { + int index = 0; + foreach (KeyValuePair> act in dictionary) + { + headers[index] = act.Key; + columnWidths[index++] = act.Key.Length; + } + } + + int headerWidth = columnWidths.Sum() + columnPad.Length * (dictionary.Count - 1); + + for (int i = 0; i < headers.Length - 1; ++i) + { + Reporter.Output.Write(headers[i].PadRight(columnWidths[i])); + Reporter.Output.Write(columnPad); + } + + Reporter.Output.WriteLine(headers[headers.Length - 1]); + Reporter.Output.WriteLine("".PadRight(headerWidth, header)); + + for (int i = 0; i < valueCount; ++i) + { + for (int j = 0; j < columns.Length - 1; ++j) + { + Reporter.Output.Write(columns[j][i].PadRight(columnWidths[j])); + Reporter.Output.Write(columnPad); + } + + Reporter.Output.WriteLine(columns[headers.Length - 1][i]); + } + + if (valueCount == 0) + { + Reporter.Output.WriteLine(noItemsMessage); + } + + Reporter.Output.WriteLine(" "); + } + } +} diff --git a/src/dotnet/dotnet.csproj b/src/dotnet/dotnet.csproj index 11905cb8b..877c6dc99 100755 --- a/src/dotnet/dotnet.csproj +++ b/src/dotnet/dotnet.csproj @@ -80,6 +80,19 @@ 1.0.1-beta-000933 + + + 1.0.0-beta1-20161216-12 + + + 1.0.0-beta1-20161216-12 + + + 1.0.0-beta1-20161216-12 + + + 1.0.0-beta1-20161216-12 + From ecfc0e10bafcfcb82f1d9fdacb1e371aa7eb2572 Mon Sep 17 00:00:00 2001 From: Mike Lorbetske Date: Fri, 16 Dec 2016 16:26:22 -0800 Subject: [PATCH 2/4] Localization --- .../commands/dotnet-new3/AppExtensions.cs | 14 +- .../dotnet-new3/ExtendedCommandParser.cs | 26 ++- .../dotnet-new3/LocalizableStrings.cs | 115 +++++++++++++ src/dotnet/commands/dotnet-new3/Program.cs | 156 +++++++++--------- 4 files changed, 211 insertions(+), 100 deletions(-) create mode 100644 src/dotnet/commands/dotnet-new3/LocalizableStrings.cs diff --git a/src/dotnet/commands/dotnet-new3/AppExtensions.cs b/src/dotnet/commands/dotnet-new3/AppExtensions.cs index 01db5122d..e69e15678 100644 --- a/src/dotnet/commands/dotnet-new3/AppExtensions.cs +++ b/src/dotnet/commands/dotnet-new3/AppExtensions.cs @@ -13,7 +13,7 @@ namespace Microsoft.DotNet.Tools.New3 { public static CommandOption Help(this CommandLineApplication app) { - return app.Option("-h|--help", "Displays help for this command.", CommandOptionType.NoValue); + return app.Option("-h|--help", LocalizableStrings.DisplaysHelp, CommandOptionType.NoValue); } public static IReadOnlyDictionary> ParseExtraArgs(this CommandLineApplication app, IList extraArgFileNames) @@ -36,8 +36,11 @@ namespace Microsoft.DotNet.Tools.New3 { if(property.Value.Type == JTokenType.String) { - IList values = new List(); - values.Add(property.Value.ToString()); + IList values = new List + { + property.Value.ToString() + }; + // adding 2 dashes to the file-based params // won't work right if there's a param that should have 1 dash // @@ -75,7 +78,7 @@ namespace Microsoft.DotNet.Tools.New3 if (!key.StartsWith("-", StringComparison.Ordinal)) { - throw new Exception("Parameter names must start with -- or -"); + throw new Exception(LocalizableStrings.ParameterNamePrefixError); } // Check the next value. If it doesn't start with a '-' then it's a value for the current param. @@ -95,8 +98,7 @@ namespace Microsoft.DotNet.Tools.New3 } } - IList valueList; - if (!parameters.TryGetValue(key, out valueList)) + if (!parameters.TryGetValue(key, out var valueList)) { valueList = new List(); parameters.Add(key, valueList); diff --git a/src/dotnet/commands/dotnet-new3/ExtendedCommandParser.cs b/src/dotnet/commands/dotnet-new3/ExtendedCommandParser.cs index e4f1799a5..684d41bee 100644 --- a/src/dotnet/commands/dotnet-new3/ExtendedCommandParser.cs +++ b/src/dotnet/commands/dotnet-new3/ExtendedCommandParser.cs @@ -90,7 +90,7 @@ namespace Microsoft.DotNet.Tools.New3 { if (IsParameterNameTaken(parameter)) { - throw new Exception($"Parameter name {parameter} cannot be used for multiple purposes"); + throw new Exception(string.Format(LocalizableStrings.ParameterReuseError, parameter)); } _defaultCommandOptions.Add(parameter); @@ -117,7 +117,7 @@ namespace Microsoft.DotNet.Tools.New3 { if (IsParameterNameTaken(parameters[i])) { - throw new Exception($"Parameter name {parameters[i]} cannot be used for multiple purposes"); + throw new Exception(string.Format(LocalizableStrings.ParameterReuseError, parameters[i])); } _hiddenCommandCanonicalMapping.Add(parameters[i], canonical); @@ -193,8 +193,7 @@ namespace Microsoft.DotNet.Tools.New3 foreach (KeyValuePair> param in allParameters) { - string canonicalName; - if (_hiddenCommandCanonicalMapping.TryGetValue(param.Key, out canonicalName)) + if (_hiddenCommandCanonicalMapping.TryGetValue(param.Key, out string canonicalName)) { CommandOptionType optionType = _hiddenCommandOptions[canonicalName]; @@ -206,14 +205,14 @@ namespace Microsoft.DotNet.Tools.New3 { if (param.Value.Count != 1) { - throw new Exception($"Multiple values specified for single value parameter: {canonicalName}"); + throw new Exception(string.Format(LocalizableStrings.MultipleValuesSpecifiedForSingleValuedParameter, canonicalName)); } } else // NoValue { if (param.Value.Count != 1 || param.Value[0] != null) { - throw new Exception($"Value specified for valueless parameter: {canonicalName}"); + throw new Exception(string.Format(LocalizableStrings.ValueSpecifiedForValuelessParameter, canonicalName)); } } @@ -224,13 +223,13 @@ namespace Microsoft.DotNet.Tools.New3 if (_parsedTemplateParams.ContainsKey(canonicalName)) { // error, the same param was specified twice - throw new Exception($"Parameter [{canonicalName}] was specified multiple times, including with the flag [{param.Key}]"); + throw new Exception(string.Format(LocalizableStrings.ParameterSpecifiedMultipleTimes, canonicalName, param.Key)); } else { if ((param.Value[0] == null) && (_templateParamDataTypeMapping[canonicalName] != "bool")) { - throw new Exception($"Parameter [{param.Key}] ({canonicalName}) must be given a value"); + throw new Exception(string.Format(LocalizableStrings.ParameterMissingValue, param.Key, canonicalName)); } // TODO: allow for multi-valued params @@ -258,8 +257,7 @@ namespace Microsoft.DotNet.Tools.New3 continue; } - string flagFullText; - if (parameterNameMap == null || !parameterNameMap.TryGetValue(parameter.Name, out flagFullText)) + if (parameterNameMap == null || !parameterNameMap.TryGetValue(parameter.Name, out string flagFullText)) { flagFullText = parameter.Name; } @@ -328,7 +326,7 @@ namespace Microsoft.DotNet.Tools.New3 if (invalidParams.Count > 0) { string unusableDisplayList = string.Join(", ", invalidParams); - throw new Exception($"Template is malformed. The following parameter names are invalid: {unusableDisplayList}"); + throw new Exception(string.Format(LocalizableStrings.TemplateMalformedDueToBadParameters, unusableDisplayList)); } } @@ -336,7 +334,7 @@ namespace Microsoft.DotNet.Tools.New3 { if (_templateParamCanonicalMapping.TryGetValue(variant, out string existingCanonical)) { - throw new Exception($"Option variant {variant} for canonical {canonical} was already defined for canonical {existingCanonical}"); + throw new Exception(string.Format(LocalizableStrings.OptionVariantAlreadyDefined, variant, canonical, existingCanonical)); } _templateParamCanonicalMapping[variant] = canonical; @@ -370,9 +368,7 @@ namespace Microsoft.DotNet.Tools.New3 { string variant = variantToCanonical.Key; string canonical = variantToCanonical.Value; - - IList variantList; - if (!_canonicalToVariantsTemplateParamMap.TryGetValue(canonical, out variantList)) + if (!_canonicalToVariantsTemplateParamMap.TryGetValue(canonical, out var variantList)) { variantList = new List(); _canonicalToVariantsTemplateParamMap.Add(canonical, variantList); diff --git a/src/dotnet/commands/dotnet-new3/LocalizableStrings.cs b/src/dotnet/commands/dotnet-new3/LocalizableStrings.cs new file mode 100644 index 000000000..8cf9fb73f --- /dev/null +++ b/src/dotnet/commands/dotnet-new3/LocalizableStrings.cs @@ -0,0 +1,115 @@ +using System; + +namespace Microsoft.DotNet.Tools.New3 +{ + internal class LocalizableStrings + { + public const string DisplaysHelp = "Displays help for this command."; + + public const string ParameterNamePrefixError = "Parameter names must start with -- or -"; + + public const string ParameterReuseError = "Parameter name {0} cannot be used for multiple purposes"; + + public const string MultipleValuesSpecifiedForSingleValuedParameter = "Multiple values specified for single value parameter: {0}"; + + public const string ValueSpecifiedForValuelessParameter = "Value specified for valueless parameter: {0}"; + + public const string ParameterSpecifiedMultipleTimes = "Parameter [{0}] was specified multiple times, including with the flag [{1}]"; + + public const string ParameterMissingValue = "Parameter [{0}] ({1}) must be given a value"; + + public const string TemplateMalformedDueToBadParameters = "Template is malformed. The following parameter names are invalid: {0}"; + + public const string OptionVariantAlreadyDefined = "Option variant {0} for canonical {1} was already defined for canonical {2}"; + + public const string ListsTemplates = "List templates containing the specified name."; + + public const string NameOfOutput = "The name for the output being created. If no name is specified, the name of the current directory is used."; + + public const string CreateDirectoryHelp = "Indicates whether to create a directory for the generated content."; + + public const string CreateAliasHelp = "Creates an alias for the specified template."; + + public const string ExtraArgsFileHelp = "Specifies a file containing additional parameters."; + + public const string LocaleHelp = "The locale to use"; + + public const string QuietModeHelp = "Doesn't output any status information."; + + public const string InstallHelp = "Installs a source or a template pack."; + + public const string UpdateHelp = "Update matching templates."; + + public const string CommandDescription = "Template Instantiation Commands for .NET Core CLI."; + + public const string TemplateArgumentHelp = "The template to instantiate."; + + public const string BadLocaleError = "Invalid format for input locale: [{0}]. Example valid formats: [en] [en-US]"; + + public const string AliasCreated = "Alias creation successful"; + + public const string AliasAlreadyExists = "Specified alias {0} already exists. Please specify a different alias."; + + public const string CreateSuccessful = "The template {0} created successfully."; + + public const string CreateFailed = "Template {0} could not be created. Error returned was: {1}"; + + public const string InstallSuccessful = "{0} was installed successfully."; + + public const string InstallFailed = "{0} could not be installed. Error returned was: {1}."; + + public const string MissingRequiredParameter = "Mandatory parameter {0} missing for template {1}."; + + public const string GettingReady = "Getting ready..."; + + public const string InvalidInputSwitch = "Invalid input switch:"; + + public const string CheckingForUpdates = "Checking for updates for {0}..."; + + public const string UpdateAvailable = "An update for {0} is available..."; + + public const string NoUpdates = "No updates were found."; + + public const string InstallingUpdates = "Installing updates..."; + + public const string BadPackageSpec = "Package [{0}] is not a valid package specification"; + + public const string Templates = "Templates"; + + public const string ShortName = "Short Name"; + + public const string Alias = "Alias"; + + public const string CurrentConfiguration = "Current configuration:"; + + public const string NoItems = "(No Items)"; + + public const string MountPoints = "Mount Points"; + + public const string MountPointFactories = "Mount Point Factories"; + + public const string Generators = "Generators"; + + public const string Id = "Id"; + + public const string Parent = "Parent"; + + public const string Assembly = "Assembly"; + + public const string Type = "Type"; + + public const string Factory = "Factory"; + + public const string Author = "Author: {0}"; + + public const string Description = "Description: {0}"; + + public const string Options = "Options:"; + + public const string ConfiguredValue = "Configured Value: {0}"; + + public const string DefaultValue = "Default: {0}"; + + public const string NoParameters = " (No Parameters)"; + } +} diff --git a/src/dotnet/commands/dotnet-new3/Program.cs b/src/dotnet/commands/dotnet-new3/Program.cs index daea87610..d59086fc0 100644 --- a/src/dotnet/commands/dotnet-new3/Program.cs +++ b/src/dotnet/commands/dotnet-new3/Program.cs @@ -28,9 +28,9 @@ namespace Microsoft.DotNet.Tools.New3 private static void SetupInternalCommands(ExtendedCommandParser appExt) { // visible - appExt.InternalOption("-l|--list", "--list", "List templates containing the specified name.", CommandOptionType.NoValue); - appExt.InternalOption("-n|--name", "--name", "The name for the output being created. If no name is specified, the name of the current directory is used.", CommandOptionType.SingleValue); - appExt.InternalOption("-h|--help", "--help", "Display help for the indicated template's parameters.", CommandOptionType.NoValue); + appExt.InternalOption("-l|--list", "--list", LocalizableStrings.ListsTemplates, CommandOptionType.NoValue); + appExt.InternalOption("-n|--name", "--name", LocalizableStrings.NameOfOutput, CommandOptionType.SingleValue); + appExt.InternalOption("-h|--help", "--help", LocalizableStrings.DisplaysHelp, CommandOptionType.NoValue); // hidden appExt.HiddenInternalOption("-d|--dir", "--dir", CommandOptionType.NoValue); @@ -48,14 +48,14 @@ namespace Microsoft.DotNet.Tools.New3 // Preserve these for now - they've got the help text, in case we want it back. // (they'll need to get converted to extended option calls) // - //CommandOption dirOption = app.Option("-d|--dir", "Indicates whether to create a directory for the generated content.", CommandOptionType.NoValue); - //CommandOption aliasOption = app.Option("-a|--alias", "Creates an alias for the specified template.", CommandOptionType.SingleValue); - //CommandOption parametersFilesOption = app.Option("-x|--extra-args", "Specifies a file containing additional parameters.", CommandOptionType.MultipleValue); - //CommandOption localeOption = app.Option("--locale", "The locale to use", CommandOptionType.SingleValue); - //CommandOption quietOption = app.Option("--quiet", "Doesn't output any status information.", CommandOptionType.NoValue); - //CommandOption installOption = app.Option("-i|--install", "Installs a source or a template pack.", CommandOptionType.MultipleValue); + //CommandOption dirOption = app.Option("-d|--dir", LocalizableStrings.CreateDirectoryHelp, CommandOptionType.NoValue); + //CommandOption aliasOption = app.Option("-a|--alias", LocalizableStrings.CreateAliasHelp, CommandOptionType.SingleValue); + //CommandOption parametersFilesOption = app.Option("-x|--extra-args", LocalizableString.ExtraArgsFileHelp, CommandOptionType.MultipleValue); + //CommandOption localeOption = app.Option("--locale", LocalizableStrings.LocaleHelp, CommandOptionType.SingleValue); + //CommandOption quietOption = app.Option("--quiet", LocalizableStrings.QuietModeHelp, CommandOptionType.NoValue); + //CommandOption installOption = app.Option("-i|--install", LocalizableStrings.InstallHelp, CommandOptionType.MultipleValue); - //CommandOption update = app.Option("--update", "Update matching templates.", CommandOptionType.NoValue); + //CommandOption update = app.Option("--update", LocalizableStrings.UpdateHelp, CommandOptionType.NoValue); } public static int Run(string[] args) @@ -66,11 +66,11 @@ namespace Microsoft.DotNet.Tools.New3 ExtendedCommandParser app = new ExtendedCommandParser() { - Name = "dotnet new3", - FullName = "Template Instantiation Commands for .NET Core CLI." + Name = "dotnet new", + FullName = LocalizableStrings.CommandDescription }; SetupInternalCommands(app); - CommandArgument templateNames = app.Argument("template", "The template to instantiate."); + CommandArgument templateNames = app.Argument("template", LocalizableStrings.TemplateArgumentHelp); app.OnExecute(async () => { @@ -90,7 +90,7 @@ namespace Microsoft.DotNet.Tools.New3 string newLocale = app.InternalParamValue("--locale"); if (!ValidateLocaleFormat(newLocale)) { - EngineEnvironmentSettings.Host.LogMessage(string.Format("Invalid format for input locale: [{0}]. Example valid formats: [en] [en-US]", newLocale)); + EngineEnvironmentSettings.Host.LogMessage(string.Format(LocalizableStrings.BadLocaleError, newLocale)); return -1; } @@ -115,7 +115,7 @@ namespace Microsoft.DotNet.Tools.New3 return resultCode; } - return await CreateTemplate(app, templateNames.Value); + return await CreateTemplateAsync(app, templateNames.Value); }); int result; @@ -159,7 +159,7 @@ namespace Microsoft.DotNet.Tools.New3 return result; } - private static async Task CreateTemplate(ExtendedCommandParser app, string templateName) + private static async Task CreateTemplateAsync(ExtendedCommandParser app, string templateName) { string nameValue = app.InternalParamValue("--name"); string fallbackName = new DirectoryInfo(Directory.GetCurrentDirectory()).Name; @@ -176,32 +176,29 @@ namespace Microsoft.DotNet.Tools.New3 { case CreationResultStatus.AliasSucceeded: // TODO: get this localized - in the mean time just list the templates, showing the alias - //EngineEnvironmentSettings.Host.LogMessage("Alias creation successful"); + //EngineEnvironmentSettings.Host.LogMessage(LocalizableStrings.AliasCreated); ListTemplates(templateName); break; case CreationResultStatus.AliasFailed: - EngineEnvironmentSettings.Host.LogMessage(string.Format("Specified alias {0} already exists. Please specify a different alias.", aliasName)); + EngineEnvironmentSettings.Host.LogMessage(string.Format(LocalizableStrings.AliasAlreadyExists, aliasName)); ListTemplates(templateName); break; case CreationResultStatus.CreateSucceeded: - EngineEnvironmentSettings.Host.LogMessage(string.Format("The template {0} created successfully. Please run \"dotnet restore\" to get started!", resultTemplateName)); + EngineEnvironmentSettings.Host.LogMessage(string.Format(LocalizableStrings.CreateSuccessful, resultTemplateName)); break; case CreationResultStatus.CreateFailed: - EngineEnvironmentSettings.Host.LogMessage(string.Format("Template {0} could not be created. Error returned was: {1}", resultTemplateName, instantiateResult.Message)); + case CreationResultStatus.TemplateNotFound: + EngineEnvironmentSettings.Host.LogMessage(string.Format(LocalizableStrings.CreateFailed, resultTemplateName, instantiateResult.Message)); ListTemplates(templateName); break; case CreationResultStatus.InstallSucceeded: - EngineEnvironmentSettings.Host.LogMessage(string.Format("The template {0} installed successfully. You can use \"dotnet new {0}\" to get started with the new template.", resultTemplateName)); + EngineEnvironmentSettings.Host.LogMessage(string.Format(LocalizableStrings.InstallSuccessful, resultTemplateName)); break; case CreationResultStatus.InstallFailed: - EngineEnvironmentSettings.Host.LogMessage(string.Format("Template {0} could not be created. Error returned was: {1}.", resultTemplateName, instantiateResult.Message)); + EngineEnvironmentSettings.Host.LogMessage(string.Format(LocalizableStrings.InstallFailed, resultTemplateName, instantiateResult.Message)); break; case CreationResultStatus.MissingMandatoryParam: - EngineEnvironmentSettings.Host.LogMessage(string.Format("Mandatory parameter {0} missing for template {1}.", instantiateResult.Message, resultTemplateName)); - break; - case CreationResultStatus.TemplateNotFound: - EngineEnvironmentSettings.Host.LogMessage(string.Format("Template {0} could not be created. Error returned was: {1}.", resultTemplateName, instantiateResult.Message)); - ListTemplates(templateName); + EngineEnvironmentSettings.Host.LogMessage(string.Format(LocalizableStrings.MissingRequiredParameter, instantiateResult.Message, resultTemplateName)); break; default: break; @@ -233,7 +230,7 @@ namespace Microsoft.DotNet.Tools.New3 { if (!app.InternalParamHasValue("--quiet")) { - Reporter.Output.WriteLine("Getting things ready for first use..."); + Reporter.Output.WriteLine(LocalizableStrings.GettingReady); } ConfigureEnvironment(); @@ -279,7 +276,7 @@ namespace Microsoft.DotNet.Tools.New3 if (app.RemainingParameters.Any(x => !x.Key.StartsWith("--debug:"))) { - EngineEnvironmentSettings.Host.LogMessage("Invalid input switch:"); + EngineEnvironmentSettings.Host.LogMessage(LocalizableStrings.InvalidInputSwitch); foreach (string flag in app.RemainingParameters.Keys) { EngineEnvironmentSettings.Host.LogMessage($"\t{flag}"); @@ -357,7 +354,7 @@ namespace Microsoft.DotNet.Tools.New3 // { // if (!quiet) // { - // Reporter.Output.WriteLine($"Checking for updates for {src.Alias}..."); + // Reporter.Output.WriteLine(string.Format(LocalizableStrings.CheckingForUpdates, src.Alias)); // } // bool updatesReady; @@ -375,7 +372,7 @@ namespace Microsoft.DotNet.Tools.New3 // { // if (!quiet) // { - // Reporter.Output.WriteLine($"An update for {src.Alias} is available..."); + // Reporter.Output.WriteLine(string.Format(LocalizableStrings.UpdateAvailable, src.Alias)); // } // string packageId = src.ParentSource != null @@ -390,7 +387,7 @@ namespace Microsoft.DotNet.Tools.New3 // { // if (!quiet) // { - // Reporter.Output.WriteLine("No updates were found."); + // Reporter.Output.WriteLine(LocalizableStrings.NoUpdates); // } // return 0; @@ -398,7 +395,7 @@ namespace Microsoft.DotNet.Tools.New3 // if (!quiet) // { - // Reporter.Output.WriteLine("Installing updates..."); + // Reporter.Output.WriteLine(LocalizableString.InstallingUpdates); // } // List installCommands = new List(); @@ -416,8 +413,8 @@ namespace Microsoft.DotNet.Tools.New3 // installCommands.Add("--quiet"); // uninstallCommands.Add("--quiet"); - // Command.CreateDotNet("new3", uninstallCommands).ForwardStdOut().ForwardStdErr().Execute(); - // Command.CreateDotNet("new3", installCommands).ForwardStdOut().ForwardStdErr().Execute(); + // Command.CreateDotNet("new", uninstallCommands).ForwardStdOut().ForwardStdErr().Execute(); + // Command.CreateDotNet("new", installCommands).ForwardStdOut().ForwardStdErr().Execute(); // Broker.ComponentRegistry.ForceReinitialize(); // if (!quiet) @@ -430,24 +427,24 @@ namespace Microsoft.DotNet.Tools.New3 private static void ConfigureEnvironment() { - string userNuGetConfig = $@" - - - - -"; - Paths.User.NuGetConfig.WriteAllText(userNuGetConfig); + string[] packageList; - string[] packageList = Paths.Global.DefaultInstallPackageList.ReadAllText().Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); - if (packageList.Length > 0) + if (Paths.Global.DefaultInstallPackageList.FileExists()) { - InstallPackages(packageList, true); + packageList = Paths.Global.DefaultInstallPackageList.ReadAllText().Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); + if (packageList.Length > 0) + { + InstallPackages(packageList, true); + } } - packageList = Paths.Global.DefaultInstallTemplateList.ReadAllText().Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); - if (packageList.Length > 0) + if (Paths.Global.DefaultInstallTemplateList.FileExists()) { - InstallPackages(packageList, true); + packageList = Paths.Global.DefaultInstallTemplateList.ReadAllText().Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); + if (packageList.Length > 0) + { + InstallPackages(packageList, true); + } } } @@ -478,7 +475,7 @@ namespace Microsoft.DotNet.Tools.New3 } catch { - EngineEnvironmentSettings.Host.OnNonCriticalError("InvalidPackageSpecification", string.Format($"Package [{pkg}] is not a valid package specification"), null, 0); + EngineEnvironmentSettings.Host.OnNonCriticalError("InvalidPackageSpecification", string.Format(LocalizableStrings.BadPackageSpec, pkg), null, 0); } } @@ -494,36 +491,36 @@ namespace Microsoft.DotNet.Tools.New3 { IEnumerable results = TemplateCreator.List(templateNames); HelpFormatter formatter = new HelpFormatter(results, 6, '-', false); - formatter.DefineColumn(delegate (ITemplateInfo t) { return t.Name; }, "Templates"); - formatter.DefineColumn(delegate (ITemplateInfo t) { return $"[{t.ShortName}]"; }, "Short Name"); - formatter.DefineColumn(delegate (ITemplateInfo t) { return AliasRegistry.GetAliasForTemplate(t) ?? ""; }, "Alias"); + formatter.DefineColumn(delegate (ITemplateInfo t) { return t.Name; }, LocalizableStrings.Templates); + formatter.DefineColumn(delegate (ITemplateInfo t) { return $"[{t.ShortName}]"; }, LocalizableStrings.ShortName); + formatter.DefineColumn(delegate (ITemplateInfo t) { return AliasRegistry.GetAliasForTemplate(t) ?? ""; }, LocalizableStrings.Alias); Reporter.Output.WriteLine(formatter.Layout()); } private static void ShowConfig() { - Reporter.Output.WriteLine("dotnet new3 current configuration:"); + Reporter.Output.WriteLine(LocalizableStrings.CurrentConfiguration); Reporter.Output.WriteLine(" "); - TableFormatter.Print(SettingsLoader.MountPoints, "(No Items)", " ", '-', new Dictionary> + TableFormatter.Print(SettingsLoader.MountPoints, LocalizableStrings.NoItems, " ", '-', new Dictionary> { - {"Mount Points", x => x.Place}, - {"Id", x => x.MountPointId}, - {"Parent", x => x.ParentMountPointId}, - {"Factory", x => x.MountPointFactoryId} + {LocalizableStrings.MountPoints, x => x.Place}, + {LocalizableStrings.Id, x => x.MountPointId}, + {LocalizableStrings.Parent, x => x.ParentMountPointId}, + {LocalizableStrings.Factory, x => x.MountPointFactoryId} }); - TableFormatter.Print(SettingsLoader.Components.OfType(), "(No Items)", " ", '-', new Dictionary> + TableFormatter.Print(SettingsLoader.Components.OfType(), LocalizableStrings.NoItems, " ", '-', new Dictionary> { - {"Mount Point Factories", x => x.Id}, - {"Type", x => x.GetType().FullName}, - {"Assembly", x => x.GetType().GetTypeInfo().Assembly.FullName} + {LocalizableStrings.MountPointFactories, x => x.Id}, + {LocalizableStrings.Type, x => x.GetType().FullName}, + {LocalizableStrings.Assembly, x => x.GetType().GetTypeInfo().Assembly.FullName} }); - TableFormatter.Print(SettingsLoader.Components.OfType(), "(No Items)", " ", '-', new Dictionary> + TableFormatter.Print(SettingsLoader.Components.OfType(), LocalizableStrings.NoItems, " ", '-', new Dictionary> { - {"Generators", x => x.Id}, - {"Type", x => x.GetType().FullName}, - {"Assembly", x => x.GetType().GetTypeInfo().Assembly.FullName} + {LocalizableStrings.Generators, x => x.Id}, + {LocalizableStrings.Type, x => x.GetType().FullName}, + {LocalizableStrings.Assembly, x => x.GetType().GetTypeInfo().Assembly.FullName} }); } @@ -560,12 +557,12 @@ namespace Microsoft.DotNet.Tools.New3 Reporter.Output.WriteLine(templateInfo.Name); if (!string.IsNullOrWhiteSpace(templateInfo.Author)) { - Reporter.Output.WriteLine($"Author: {templateInfo.Author}"); + Reporter.Output.WriteLine(string.Format(LocalizableStrings.Author, templateInfo.Author)); } if (!string.IsNullOrWhiteSpace(templateInfo.Description)) { - Reporter.Output.WriteLine($"Description: {templateInfo.Description}"); + Reporter.Output.WriteLine(string.Format(LocalizableStrings.Description, templateInfo.Description)); } ITemplate template = SettingsLoader.LoadTemplate(templateInfo); @@ -584,14 +581,15 @@ namespace Microsoft.DotNet.Tools.New3 { HelpFormatter formatter = new HelpFormatter(filteredParams, 2, null, true); - formatter.DefineColumn(delegate (ITemplateParameter param) - { - // the key is guaranteed to exist - IList variants = app.CanonicalToVariantsTemplateParamMap[param.Name]; - string options = string.Join("|", variants.Reverse()); - return " " + options; - }, - "Options:" + formatter.DefineColumn( + param => + { + // the key is guaranteed to exist + IList variants = app.CanonicalToVariantsTemplateParamMap[param.Name]; + string options = string.Join("|", variants.Reverse()); + return " " + options; + }, + LocalizableStrings.Options ); formatter.DefineColumn(delegate (ITemplateParameter param) @@ -617,13 +615,13 @@ namespace Microsoft.DotNet.Tools.New3 && !string.IsNullOrEmpty(param.DefaultValue) && !string.Equals(param.DefaultValue, resolvedValue)) { - displayValue.AppendLine("Configured Value: " + resolvedValue); + displayValue.AppendLine(string.Format(LocalizableStrings.ConfiguredValue, resolvedValue)); } } if (!string.IsNullOrEmpty(param.DefaultValue)) { - displayValue.AppendLine("Default: " + param.DefaultValue); + displayValue.AppendLine(string.Format(LocalizableStrings.DefaultValue, param.DefaultValue)); } return displayValue.ToString(); @@ -635,7 +633,7 @@ namespace Microsoft.DotNet.Tools.New3 } else { - Reporter.Output.WriteLine(" (No Parameters)"); + Reporter.Output.WriteLine(LocalizableStrings.NoParameters); } } } From 465655c85ad394d0170d9556d1b186847be0d73c Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Tue, 10 Jan 2017 13:36:40 -0600 Subject: [PATCH 3/4] Revert "Merge branch 'rel/1.0.0' of https://github.com/dotnet/cli into rel/1.0.0" This reverts commit 4e951a480b24c124450892e394d685d9c9d4434c, reversing changes made to 006fd49e5cfad2be4f75d0c311eef996e4f1fd02. --- .../commands/dotnet-new3/AppExtensions.cs | 113 --- .../dotnet-new3/ExtendedCommandParser.cs | 409 ---------- .../commands/dotnet-new3/HelpFormatter.cs | 228 ------ .../dotnet-new3/LocalizableStrings.cs | 115 --- src/dotnet/commands/dotnet-new3/Program.cs | 714 ------------------ 5 files changed, 1579 deletions(-) delete mode 100644 src/dotnet/commands/dotnet-new3/AppExtensions.cs delete mode 100644 src/dotnet/commands/dotnet-new3/ExtendedCommandParser.cs delete mode 100644 src/dotnet/commands/dotnet-new3/HelpFormatter.cs delete mode 100644 src/dotnet/commands/dotnet-new3/LocalizableStrings.cs delete mode 100644 src/dotnet/commands/dotnet-new3/Program.cs diff --git a/src/dotnet/commands/dotnet-new3/AppExtensions.cs b/src/dotnet/commands/dotnet-new3/AppExtensions.cs deleted file mode 100644 index e69e15678..000000000 --- a/src/dotnet/commands/dotnet-new3/AppExtensions.cs +++ /dev/null @@ -1,113 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using Microsoft.DotNet.Cli.CommandLine; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Microsoft.DotNet.Tools.New3 -{ - internal static class AppExtensions - { - public static CommandOption Help(this CommandLineApplication app) - { - return app.Option("-h|--help", LocalizableStrings.DisplaysHelp, CommandOptionType.NoValue); - } - - public static IReadOnlyDictionary> ParseExtraArgs(this CommandLineApplication app, IList extraArgFileNames) - { - Dictionary> parameters = new Dictionary>(); - - // Note: If the same param is specified multiple times across the files, last-in-wins - // TODO: consider another course of action. - if (extraArgFileNames.Count > 0) - { - foreach (string argFile in extraArgFileNames) - { - using (Stream s = File.OpenRead(argFile)) - using (TextReader r = new StreamReader(s, Encoding.UTF8, true, 4096, true)) - using (JsonTextReader reader = new JsonTextReader(r)) - { - JObject obj = JObject.Load(reader); - - foreach (JProperty property in obj.Properties()) - { - if(property.Value.Type == JTokenType.String) - { - IList values = new List - { - property.Value.ToString() - }; - - // adding 2 dashes to the file-based params - // won't work right if there's a param that should have 1 dash - // - // TOOD: come up with a better way to deal with this - parameters["--" + property.Name] = values; - } - } - } - } - } - - for (int i = 0; i < app.RemainingArguments.Count; ++i) - { - string key = app.RemainingArguments[i]; - CommandOption arg = app.Options.FirstOrDefault(x => x.Template.Split('|').Any(y => string.Equals(y, key, StringComparison.OrdinalIgnoreCase))); - bool handled = false; - - if (arg != null) - { - if (arg.OptionType != CommandOptionType.NoValue) - { - handled = arg.TryParse(app.RemainingArguments[i + 1]); - ++i; - } - else - { - handled = arg.TryParse(null); - } - } - - if (handled) - { - continue; - } - - if (!key.StartsWith("-", StringComparison.Ordinal)) - { - throw new Exception(LocalizableStrings.ParameterNamePrefixError); - } - - // Check the next value. If it doesn't start with a '-' then it's a value for the current param. - // Otherwise it's its own param. - string value = null; - if (app.RemainingArguments.Count > i + 1) - { - value = app.RemainingArguments[i + 1]; - - if (value.StartsWith("-", StringComparison.Ordinal)) - { - value = null; - } - else - { - ++i; - } - } - - if (!parameters.TryGetValue(key, out var valueList)) - { - valueList = new List(); - parameters.Add(key, valueList); - } - - valueList.Add(value); - } - - return parameters; - } - } -} \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-new3/ExtendedCommandParser.cs b/src/dotnet/commands/dotnet-new3/ExtendedCommandParser.cs deleted file mode 100644 index 684d41bee..000000000 --- a/src/dotnet/commands/dotnet-new3/ExtendedCommandParser.cs +++ /dev/null @@ -1,409 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using Microsoft.DotNet.Cli.CommandLine; -using Microsoft.TemplateEngine.Abstractions; -using Microsoft.TemplateEngine.Edge.Settings; - -namespace Microsoft.DotNet.Tools.New3 -{ - internal class ExtendedCommandParser - { - private CommandLineApplication _app; - - // Hidden & default options. Listed here to avoid clashes with on-the-fly params from individual templates. - private HashSet _defaultCommandOptions; - // key is the variant, value is the canonical version - private IDictionary _hiddenCommandCanonicalMapping; - // key is the canonical version - IDictionary _hiddenCommandOptions; - - // maps the template param variants to the canonical forms - private IDictionary _templateParamCanonicalMapping; - // Canonical form -> data type - private IDictionary _templateParamDataTypeMapping; - - // stores the parsed values - private IDictionary _parsedTemplateParams; - private IDictionary> _parsedInternalParams; - private IDictionary> _parsedRemainingParams; - - // stores the options & arguments that are NOT hidden - // this is used exclusively to show the help. - // it's a bit of a hack. - CommandLineApplication _helpDisplayer; - - public ExtendedCommandParser() - { - _app = new CommandLineApplication(false); - _defaultCommandOptions = new HashSet(); - _hiddenCommandOptions = new Dictionary(); - _hiddenCommandCanonicalMapping = new Dictionary(); - _templateParamCanonicalMapping = new Dictionary(); - _templateParamDataTypeMapping = new Dictionary(); - - _parsedTemplateParams = new Dictionary(); - _parsedInternalParams = new Dictionary>(); - _parsedRemainingParams = new Dictionary>(); - - _helpDisplayer = new CommandLineApplication(false); - } - - // TODO: consider optionally showing help for things not handled by the CommandLineApplication instance - public void ShowHelp() - { - _helpDisplayer.ShowHelp(); - } - - public void RemoveOption(CommandOption option) - { - _app.Options.Remove(option); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsParameterNameTaken(string testName) - { - return _defaultCommandOptions.Contains(testName) - || _hiddenCommandCanonicalMapping.ContainsKey(testName) - || _templateParamCanonicalMapping.ContainsKey(testName); - } - - public int Execute(params string[] args) - { - return _app.Execute(args); - } - - public void OnExecute(Func> invoke) - { - _app.OnExecute(invoke); - } - - // Returns the "standard" args that were input - the ones handled by the CommandLineApplication - public List RemainingArguments - { - get { return _app.RemainingArguments; } - } - - public CommandArgument Argument(string parameter, string description) - { - if (IsParameterNameTaken(parameter)) - { - throw new Exception(string.Format(LocalizableStrings.ParameterReuseError, parameter)); - } - - _defaultCommandOptions.Add(parameter); - - // its not hidden, add it to the help - _helpDisplayer.Argument(parameter, description); - - return _app.Argument(parameter, description); - } - - public void InternalOption(string parameterVariants, string canonical, string description, CommandOptionType optionType) - { - _helpDisplayer.Option(parameterVariants, description, optionType); - HiddenInternalOption(parameterVariants, canonical, optionType); - } - - // NOTE: the exceptions here should never happen, this is strictly called by the program - // Once testing is done, we can probably remove them. - public void HiddenInternalOption(string parameterVariants, string canonical, CommandOptionType optionType) - { - string[] parameters = parameterVariants.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries); - - for (int i = 0; i < parameters.Length; i++) - { - if (IsParameterNameTaken(parameters[i])) - { - throw new Exception(string.Format(LocalizableStrings.ParameterReuseError, parameters[i])); - } - - _hiddenCommandCanonicalMapping.Add(parameters[i], canonical); - } - - _hiddenCommandOptions.Add(canonical, optionType); - } - - public bool TemplateParamHasValue(string paramName) - { - return _parsedTemplateParams.ContainsKey(paramName); - } - - public string TemplateParamValue(string paramName) - { - _parsedTemplateParams.TryGetValue(paramName, out string value); - return value; - } - - // returns a copy of the template params - public IReadOnlyDictionary AllTemplateParams - { - get - { - return new Dictionary(_parsedTemplateParams); - } - } - - public bool InternalParamHasValue(string paramName) - { - return _parsedInternalParams.ContainsKey(paramName); - } - - public string InternalParamValue(string paramName) - { - if (_parsedInternalParams.TryGetValue(paramName, out IList values)) - { - return values.FirstOrDefault(); - } - else - { - return null; - } - } - - public IList InternalParamValueList(string paramName) - { - _parsedInternalParams.TryGetValue(paramName, out IList values); - return values; - } - - public IDictionary> RemainingParameters - { - get - { - return _parsedRemainingParams; - } - } - - // Parses all command line args, and any input arg files. - // NOTE: any previously parsed values are lost - this resets the parsed values. - public void ParseArgs(IList extraArgFileNames = null) - { - _parsedTemplateParams = new Dictionary(); - _parsedInternalParams = new Dictionary>(); - _parsedRemainingParams = new Dictionary>(); - - if (extraArgFileNames == null) - { - extraArgFileNames = new List(); - } - IReadOnlyDictionary> allParameters = _app.ParseExtraArgs(extraArgFileNames); - - foreach (KeyValuePair> param in allParameters) - { - if (_hiddenCommandCanonicalMapping.TryGetValue(param.Key, out string canonicalName)) - { - CommandOptionType optionType = _hiddenCommandOptions[canonicalName]; - - if (optionType == CommandOptionType.MultipleValue) - { - ; // nothing to check - } - else if (optionType == CommandOptionType.SingleValue) - { - if (param.Value.Count != 1) - { - throw new Exception(string.Format(LocalizableStrings.MultipleValuesSpecifiedForSingleValuedParameter, canonicalName)); - } - } - else // NoValue - { - if (param.Value.Count != 1 || param.Value[0] != null) - { - throw new Exception(string.Format(LocalizableStrings.ValueSpecifiedForValuelessParameter, canonicalName)); - } - } - - _parsedInternalParams.Add(canonicalName, param.Value); - } - else if (_templateParamCanonicalMapping.TryGetValue(param.Key, out canonicalName)) - { - if (_parsedTemplateParams.ContainsKey(canonicalName)) - { - // error, the same param was specified twice - throw new Exception(string.Format(LocalizableStrings.ParameterSpecifiedMultipleTimes, canonicalName, param.Key)); - } - else - { - if ((param.Value[0] == null) && (_templateParamDataTypeMapping[canonicalName] != "bool")) - { - throw new Exception(string.Format(LocalizableStrings.ParameterMissingValue, param.Key, canonicalName)); - } - - // TODO: allow for multi-valued params - _parsedTemplateParams[canonicalName] = param.Value[0]; - } - } - else - { - // not a known internal or template param. - _parsedRemainingParams[param.Key] = param.Value; - } - } - } - - // Canonical is the template param name without any dashes. The things mapped to it all have dashes, including the param name itself. - public void SetupTemplateParameters(IParameterSet allParams, IReadOnlyDictionary parameterNameMap) - { - HashSet invalidParams = new HashSet(); - - foreach (ITemplateParameter parameter in allParams.ParameterDefinitions.Where(x => x.Priority != TemplateParameterPriority.Implicit).OrderBy(x => x.Name)) - { - if (parameter.Name.IndexOf(':') >= 0) - { // Colon is reserved, template param names cannot have any. - invalidParams.Add(parameter.Name); - continue; - } - - if (parameterNameMap == null || !parameterNameMap.TryGetValue(parameter.Name, out string flagFullText)) - { - flagFullText = parameter.Name; - } - - bool longNameFound = false; - bool shortNameFound = false; - - // always unless taken - string nameAsParameter = "--" + flagFullText; - if (!IsParameterNameTaken(nameAsParameter)) - { - MapTemplateParamToCanonical(nameAsParameter, parameter.Name); - longNameFound = true; - } - - // only as fallback - string qualifiedName = "--param:" + flagFullText; - if (!longNameFound && !IsParameterNameTaken(qualifiedName)) - { - MapTemplateParamToCanonical(qualifiedName, parameter.Name); - longNameFound = true; - } - - // always unless taken - string shortName = "-" + PosixNameToShortName(flagFullText); - if (!IsParameterNameTaken(shortName)) - { - MapTemplateParamToCanonical(shortName, parameter.Name); - shortNameFound = true; - } - - // only as fallback - string singleLetterName = "-" + flagFullText.Substring(0, 1); - if (!shortNameFound && !IsParameterNameTaken(singleLetterName)) - { - MapTemplateParamToCanonical(singleLetterName, parameter.Name); - shortNameFound = true; - } - - // only as fallback - string qualifiedShortName = "-p:" + PosixNameToShortName(flagFullText); - if (!shortNameFound && !IsParameterNameTaken(qualifiedShortName)) - { - MapTemplateParamToCanonical(qualifiedShortName, parameter.Name); - shortNameFound = true; - } - - // only as fallback - string qualifiedSingleLetterName = "-p:" + flagFullText.Substring(0, 1); - if (!shortNameFound && !IsParameterNameTaken(qualifiedSingleLetterName)) - { - MapTemplateParamToCanonical(qualifiedSingleLetterName, parameter.Name); - shortNameFound = true; - } - - if (!shortNameFound && !longNameFound) - { - invalidParams.Add(flagFullText); - } - else - { - _templateParamDataTypeMapping[parameter.Name] = parameter.DataType; - } - } - - if (invalidParams.Count > 0) - { - string unusableDisplayList = string.Join(", ", invalidParams); - throw new Exception(string.Format(LocalizableStrings.TemplateMalformedDueToBadParameters, unusableDisplayList)); - } - } - - private void MapTemplateParamToCanonical(string variant, string canonical) - { - if (_templateParamCanonicalMapping.TryGetValue(variant, out string existingCanonical)) - { - throw new Exception(string.Format(LocalizableStrings.OptionVariantAlreadyDefined, variant, canonical, existingCanonical)); - } - - _templateParamCanonicalMapping[variant] = canonical; - } - - // Concats the first letter of dash separated word. - private static string PosixNameToShortName(string name) - { - IList wordsInName = name.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries).ToList(); - IList firstLetters = new List(); - - foreach (string word in wordsInName) - { - firstLetters.Add(word.Substring(0, 1)); - } - - return string.Join("", firstLetters); - } - - private IDictionary> _canonicalToVariantsTemplateParamMap; - - public IDictionary> CanonicalToVariantsTemplateParamMap - { - get - { - if (_canonicalToVariantsTemplateParamMap == null) - { - _canonicalToVariantsTemplateParamMap = new Dictionary>(); - - foreach (KeyValuePair variantToCanonical in _templateParamCanonicalMapping) - { - string variant = variantToCanonical.Key; - string canonical = variantToCanonical.Value; - if (!_canonicalToVariantsTemplateParamMap.TryGetValue(canonical, out var variantList)) - { - variantList = new List(); - _canonicalToVariantsTemplateParamMap.Add(canonical, variantList); - } - - variantList.Add(variant); - } - } - - return _canonicalToVariantsTemplateParamMap; - } - } - - public string Name - { - get - { - return _app.Name; - } - set - { - _app.Name = value; - } - } - - public string FullName - { - get - { - return _app.FullName; - } - set - { - _app.FullName = value; - } - } - } -} diff --git a/src/dotnet/commands/dotnet-new3/HelpFormatter.cs b/src/dotnet/commands/dotnet-new3/HelpFormatter.cs deleted file mode 100644 index 6dea14662..000000000 --- a/src/dotnet/commands/dotnet-new3/HelpFormatter.cs +++ /dev/null @@ -1,228 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Microsoft.DotNet.Tools.New3 -{ - public class HelpFormatter - { - public static HelpFormatter For(IEnumerable items, int columnPadding, char? headerSeparator = null, bool blankLineBetweenRows = false) - { - return new HelpFormatter(items, columnPadding, headerSeparator, blankLineBetweenRows); - } - } - - public class HelpFormatter - { - private readonly bool _blankLineBetweenRows; - private readonly int _columnPadding; - private readonly List _columns = new List(); - private readonly char? _headerSeparator; - private readonly IEnumerable _items; - - public HelpFormatter(IEnumerable items, int columnPadding, char? headerSeparator, bool blankLineBetweenRows) - { - _items = items; - _columnPadding = columnPadding; - _headerSeparator = headerSeparator; - _blankLineBetweenRows = blankLineBetweenRows; - } - - public HelpFormatter DefineColumn(Func binder, string header = null, int maxWidth = 0, bool alwaysMaximizeWidth = false) - { - _columns.Add(new ColumnDefinition(header, binder, maxWidth, alwaysMaximizeWidth)); - return this; - } - - public string Layout() - { - Dictionary widthLookup = new Dictionary(); - Dictionary lineCountLookup = new Dictionary(); - List textByRow = new List(); - - TextWrapper[] header = new TextWrapper[_columns.Count]; - int headerLines = 0; - for (int i = 0; i < _columns.Count; ++i) - { - header[i] = new TextWrapper(_columns[i].Header, _columns[i].MaxWidth, _columns[i].AlwaysMaximizeWidth); - headerLines = Math.Max(headerLines, header[i].LineCount); - widthLookup[i] = header[i].MaxWidth; - } - - int lineNumber = 0; - - foreach (T item in _items) - { - TextWrapper[] line = new TextWrapper[_columns.Count]; - int maxLineCount = 0; - - for (int i = 0; i < _columns.Count; ++i) - { - line[i] = _columns[i].GetCell(item); - widthLookup[i] = Math.Max(widthLookup[i], line[i].MaxWidth); - maxLineCount = Math.Max(maxLineCount, line[i].LineCount); - } - - lineCountLookup[lineNumber++] = maxLineCount; - textByRow.Add(line); - } - - StringBuilder b = new StringBuilder(); - - if (_columns.Any(x => !string.IsNullOrEmpty(x.Header))) - { - for (int j = 0; j < headerLines; ++j) - { - for (int i = 0; i < _columns.Count - 1; ++i) - { - b.Append(header[i][j, widthLookup[i]]); - b.Append("".PadRight(_columnPadding)); - } - - b.AppendLine(header[_columns.Count - 1][j, widthLookup[_columns.Count - 1]]); - } - } - - if (_headerSeparator.HasValue) - { - int totalWidth = _columnPadding * (_columns.Count - 1); - - for (int i = 0; i < _columns.Count; ++i) - { - totalWidth += Math.Max(header[i].MaxWidth, widthLookup[i]); - } - - b.AppendLine("".PadRight(totalWidth, _headerSeparator.Value)); - } - - int currentLine = 0; - foreach (TextWrapper[] line in textByRow) - { - for (int j = 0; j < lineCountLookup[currentLine]; ++j) - { - for (int i = 0; i < _columns.Count - 1; ++i) - { - b.Append(line[i][j, widthLookup[i]]); - b.Append("".PadRight(_columnPadding)); - } - - b.AppendLine(line[_columns.Count - 1][j, widthLookup[_columns.Count - 1]]); - } - - if (_blankLineBetweenRows) - { - b.AppendLine(); - } - - ++currentLine; - } - - return b.ToString(); - } - - private class ColumnDefinition - { - private readonly int _maxWidth; - private readonly string _header; - private readonly Func _binder; - private readonly bool _alwaysMaximizeWidth; - - public ColumnDefinition(string header, Func binder, int maxWidth = -1, bool alwaysMaximizeWidth = false) - { - _header = header; - _maxWidth = maxWidth > 0 ? maxWidth : int.MaxValue; - _binder = binder; - _alwaysMaximizeWidth = alwaysMaximizeWidth && maxWidth > 0; - } - - public string Header => _header; - - public bool AlwaysMaximizeWidth => _alwaysMaximizeWidth; - - public int MaxWidth => _maxWidth; - - public TextWrapper GetCell(T value) - { - return new TextWrapper(_binder(value), _maxWidth, _alwaysMaximizeWidth); - } - } - - private class TextWrapper - { - private readonly IReadOnlyList _lines; - - public TextWrapper(string text, int maxWidth, bool alwaysMax) - { - List lines = new List(); - int position = 0; - int realMaxWidth = alwaysMax ? maxWidth : 0; - - while (position < text.Length) - { - int newline = text.IndexOf(Environment.NewLine, position, StringComparison.Ordinal); - - if (newline > -1) - { - if (newline - position <= maxWidth) - { - lines.Add(text.Substring(position, newline - position).TrimEnd()); - position = newline + Environment.NewLine.Length; - } - else - { - GetLineText(text, lines, maxWidth, newline, ref position); - } - } - else - { - GetLineText(text, lines, maxWidth, text.Length - 1, ref position); - } - - realMaxWidth = Math.Max(realMaxWidth, lines[lines.Count - 1].Length); - } - - _lines = lines; - MaxWidth = realMaxWidth; - } - - public int LineCount => _lines.Count; - - public int MaxWidth { get; } - - public string this[int index, int padTo = 0] - { - get { return (_lines.Count > index ? _lines[index] : string.Empty).PadRight(MaxWidth).PadRight(padTo > MaxWidth ? padTo : MaxWidth); } - } - - private static void GetLineText(string text, List lines, int maxLength, int end, ref int position) - { - if (text.Length - position < maxLength) - { - lines.Add(text.Substring(position)); - position = text.Length; - return; - } - - int lastBreak = text.LastIndexOfAny(new[] { ' ', '-' }, end, end - position); - while (lastBreak > 0 && lastBreak - position > maxLength) - { - --lastBreak; - lastBreak = text.LastIndexOfAny(new[] { ' ', '-' }, lastBreak, lastBreak - position); - } - - if (lastBreak > 0) - { - lines.Add(text.Substring(position, lastBreak - position + 1).TrimEnd()); - position = lastBreak + 1; - } - else - { - int properMax = Math.Min(maxLength - 1, text.Length - position); - lines.Add(text.Substring(position, properMax) + '-'); - position += maxLength - 1; - } - } - } - } -} diff --git a/src/dotnet/commands/dotnet-new3/LocalizableStrings.cs b/src/dotnet/commands/dotnet-new3/LocalizableStrings.cs deleted file mode 100644 index 8cf9fb73f..000000000 --- a/src/dotnet/commands/dotnet-new3/LocalizableStrings.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System; - -namespace Microsoft.DotNet.Tools.New3 -{ - internal class LocalizableStrings - { - public const string DisplaysHelp = "Displays help for this command."; - - public const string ParameterNamePrefixError = "Parameter names must start with -- or -"; - - public const string ParameterReuseError = "Parameter name {0} cannot be used for multiple purposes"; - - public const string MultipleValuesSpecifiedForSingleValuedParameter = "Multiple values specified for single value parameter: {0}"; - - public const string ValueSpecifiedForValuelessParameter = "Value specified for valueless parameter: {0}"; - - public const string ParameterSpecifiedMultipleTimes = "Parameter [{0}] was specified multiple times, including with the flag [{1}]"; - - public const string ParameterMissingValue = "Parameter [{0}] ({1}) must be given a value"; - - public const string TemplateMalformedDueToBadParameters = "Template is malformed. The following parameter names are invalid: {0}"; - - public const string OptionVariantAlreadyDefined = "Option variant {0} for canonical {1} was already defined for canonical {2}"; - - public const string ListsTemplates = "List templates containing the specified name."; - - public const string NameOfOutput = "The name for the output being created. If no name is specified, the name of the current directory is used."; - - public const string CreateDirectoryHelp = "Indicates whether to create a directory for the generated content."; - - public const string CreateAliasHelp = "Creates an alias for the specified template."; - - public const string ExtraArgsFileHelp = "Specifies a file containing additional parameters."; - - public const string LocaleHelp = "The locale to use"; - - public const string QuietModeHelp = "Doesn't output any status information."; - - public const string InstallHelp = "Installs a source or a template pack."; - - public const string UpdateHelp = "Update matching templates."; - - public const string CommandDescription = "Template Instantiation Commands for .NET Core CLI."; - - public const string TemplateArgumentHelp = "The template to instantiate."; - - public const string BadLocaleError = "Invalid format for input locale: [{0}]. Example valid formats: [en] [en-US]"; - - public const string AliasCreated = "Alias creation successful"; - - public const string AliasAlreadyExists = "Specified alias {0} already exists. Please specify a different alias."; - - public const string CreateSuccessful = "The template {0} created successfully."; - - public const string CreateFailed = "Template {0} could not be created. Error returned was: {1}"; - - public const string InstallSuccessful = "{0} was installed successfully."; - - public const string InstallFailed = "{0} could not be installed. Error returned was: {1}."; - - public const string MissingRequiredParameter = "Mandatory parameter {0} missing for template {1}."; - - public const string GettingReady = "Getting ready..."; - - public const string InvalidInputSwitch = "Invalid input switch:"; - - public const string CheckingForUpdates = "Checking for updates for {0}..."; - - public const string UpdateAvailable = "An update for {0} is available..."; - - public const string NoUpdates = "No updates were found."; - - public const string InstallingUpdates = "Installing updates..."; - - public const string BadPackageSpec = "Package [{0}] is not a valid package specification"; - - public const string Templates = "Templates"; - - public const string ShortName = "Short Name"; - - public const string Alias = "Alias"; - - public const string CurrentConfiguration = "Current configuration:"; - - public const string NoItems = "(No Items)"; - - public const string MountPoints = "Mount Points"; - - public const string MountPointFactories = "Mount Point Factories"; - - public const string Generators = "Generators"; - - public const string Id = "Id"; - - public const string Parent = "Parent"; - - public const string Assembly = "Assembly"; - - public const string Type = "Type"; - - public const string Factory = "Factory"; - - public const string Author = "Author: {0}"; - - public const string Description = "Description: {0}"; - - public const string Options = "Options:"; - - public const string ConfiguredValue = "Configured Value: {0}"; - - public const string DefaultValue = "Default: {0}"; - - public const string NoParameters = " (No Parameters)"; - } -} diff --git a/src/dotnet/commands/dotnet-new3/Program.cs b/src/dotnet/commands/dotnet-new3/Program.cs deleted file mode 100644 index d59086fc0..000000000 --- a/src/dotnet/commands/dotnet-new3/Program.cs +++ /dev/null @@ -1,714 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Microsoft.DotNet.Cli; -using Microsoft.DotNet.Cli.CommandLine; -using Microsoft.DotNet.Cli.Utils; -using Microsoft.TemplateEngine.Abstractions; -using Microsoft.TemplateEngine.Abstractions.Mount; -using Microsoft.TemplateEngine.Edge; -using Microsoft.TemplateEngine.Edge.Settings; -using Microsoft.TemplateEngine.Edge.Template; -using Microsoft.TemplateEngine.Utils; - -namespace Microsoft.DotNet.Tools.New3 -{ - public class New3Command - { - private static readonly string HostIdentifier = "dotnetcli"; - private static readonly Version HostVersion = typeof(Program).GetTypeInfo().Assembly.GetName().Version; - private static DefaultTemplateEngineHost Host; - - private static void SetupInternalCommands(ExtendedCommandParser appExt) - { - // visible - appExt.InternalOption("-l|--list", "--list", LocalizableStrings.ListsTemplates, CommandOptionType.NoValue); - appExt.InternalOption("-n|--name", "--name", LocalizableStrings.NameOfOutput, CommandOptionType.SingleValue); - appExt.InternalOption("-h|--help", "--help", LocalizableStrings.DisplaysHelp, CommandOptionType.NoValue); - - // hidden - appExt.HiddenInternalOption("-d|--dir", "--dir", CommandOptionType.NoValue); - appExt.HiddenInternalOption("-a|--alias", "--alias", CommandOptionType.SingleValue); - appExt.HiddenInternalOption("-x|--extra-args", "--extra-args", CommandOptionType.MultipleValue); - appExt.HiddenInternalOption("--locale", "--locale", CommandOptionType.SingleValue); - appExt.HiddenInternalOption("--quiet", "--quiet", CommandOptionType.NoValue); - appExt.HiddenInternalOption("-i|--install", "--install", CommandOptionType.MultipleValue); - - // reserved but not currently used - appExt.HiddenInternalOption("-up|--update", "--update", CommandOptionType.MultipleValue); - appExt.HiddenInternalOption("-u|--uninstall", "--uninstall", CommandOptionType.MultipleValue); - appExt.HiddenInternalOption("--skip-update-check", "--skip-update-check", CommandOptionType.NoValue); - - // Preserve these for now - they've got the help text, in case we want it back. - // (they'll need to get converted to extended option calls) - // - //CommandOption dirOption = app.Option("-d|--dir", LocalizableStrings.CreateDirectoryHelp, CommandOptionType.NoValue); - //CommandOption aliasOption = app.Option("-a|--alias", LocalizableStrings.CreateAliasHelp, CommandOptionType.SingleValue); - //CommandOption parametersFilesOption = app.Option("-x|--extra-args", LocalizableString.ExtraArgsFileHelp, CommandOptionType.MultipleValue); - //CommandOption localeOption = app.Option("--locale", LocalizableStrings.LocaleHelp, CommandOptionType.SingleValue); - //CommandOption quietOption = app.Option("--quiet", LocalizableStrings.QuietModeHelp, CommandOptionType.NoValue); - //CommandOption installOption = app.Option("-i|--install", LocalizableStrings.InstallHelp, CommandOptionType.MultipleValue); - - //CommandOption update = app.Option("--update", LocalizableStrings.UpdateHelp, CommandOptionType.NoValue); - } - - public static int Run(string[] args) - { - // Initial host setup has the current locale. May need to be changed based on inputs. - Host = new DefaultTemplateEngineHost(HostIdentifier, HostVersion, CultureInfo.CurrentCulture.Name); - EngineEnvironmentSettings.Host = Host; - - ExtendedCommandParser app = new ExtendedCommandParser() - { - Name = "dotnet new", - FullName = LocalizableStrings.CommandDescription - }; - SetupInternalCommands(app); - CommandArgument templateNames = app.Argument("template", LocalizableStrings.TemplateArgumentHelp); - - app.OnExecute(async () => - { - app.ParseArgs(); - if (app.InternalParamHasValue("--extra-args")) - { - app.ParseArgs(app.InternalParamValueList("--extra-args")); - } - - if (app.RemainingParameters.ContainsKey("--debug:attach")) - { - Console.ReadLine(); - } - - if (app.InternalParamHasValue("--locale")) - { - string newLocale = app.InternalParamValue("--locale"); - if (!ValidateLocaleFormat(newLocale)) - { - EngineEnvironmentSettings.Host.LogMessage(string.Format(LocalizableStrings.BadLocaleError, newLocale)); - return -1; - } - - Host.UpdateLocale(newLocale); - } - - int resultCode = InitializationAndDebugging(app, out bool shouldExit); - if (shouldExit) - { - return resultCode; - } - - resultCode = ParseTemplateArgs(app, templateNames.Value, out shouldExit); - if (shouldExit) - { - return resultCode; - } - - resultCode = MaintenanceAndInfo(app, templateNames.Value, out shouldExit); - if (shouldExit) - { - return resultCode; - } - - return await CreateTemplateAsync(app, templateNames.Value); - }); - - int result; - try - { - using (Timing.Over("Execute")) - { - result = app.Execute(args); - } - } - catch (Exception ex) - { - AggregateException ax = ex as AggregateException; - - while (ax != null && ax.InnerExceptions.Count == 1) - { - ex = ax.InnerException; - ax = ex as AggregateException; - } - - Reporter.Error.WriteLine(ex.Message.Bold().Red()); - - while (ex.InnerException != null) - { - ex = ex.InnerException; - ax = ex as AggregateException; - - while (ax != null && ax.InnerExceptions.Count == 1) - { - ex = ax.InnerException; - ax = ex as AggregateException; - } - - Reporter.Error.WriteLine(ex.Message.Bold().Red()); - } - - Reporter.Error.WriteLine(ex.StackTrace.Bold().Red()); - result = 1; - } - - return result; - } - - private static async Task CreateTemplateAsync(ExtendedCommandParser app, string templateName) - { - string nameValue = app.InternalParamValue("--name"); - string fallbackName = new DirectoryInfo(Directory.GetCurrentDirectory()).Name; - bool dirValue = app.InternalParamHasValue("--dir"); - string aliasName = app.InternalParamValue("--alias"); - bool skipUpdateCheckValue = app.InternalParamHasValue("--skip-update-check"); - - // TODO: refactor alias creation out of InstantiateAsync() - TemplateCreationResult instantiateResult = await TemplateCreator.InstantiateAsync(templateName ?? "", nameValue, fallbackName, dirValue, aliasName, app.AllTemplateParams, skipUpdateCheckValue); - - string resultTemplateName = string.IsNullOrEmpty(instantiateResult.TemplateFullName) ? templateName : instantiateResult.TemplateFullName; - - switch (instantiateResult.Status) - { - case CreationResultStatus.AliasSucceeded: - // TODO: get this localized - in the mean time just list the templates, showing the alias - //EngineEnvironmentSettings.Host.LogMessage(LocalizableStrings.AliasCreated); - ListTemplates(templateName); - break; - case CreationResultStatus.AliasFailed: - EngineEnvironmentSettings.Host.LogMessage(string.Format(LocalizableStrings.AliasAlreadyExists, aliasName)); - ListTemplates(templateName); - break; - case CreationResultStatus.CreateSucceeded: - EngineEnvironmentSettings.Host.LogMessage(string.Format(LocalizableStrings.CreateSuccessful, resultTemplateName)); - break; - case CreationResultStatus.CreateFailed: - case CreationResultStatus.TemplateNotFound: - EngineEnvironmentSettings.Host.LogMessage(string.Format(LocalizableStrings.CreateFailed, resultTemplateName, instantiateResult.Message)); - ListTemplates(templateName); - break; - case CreationResultStatus.InstallSucceeded: - EngineEnvironmentSettings.Host.LogMessage(string.Format(LocalizableStrings.InstallSuccessful, resultTemplateName)); - break; - case CreationResultStatus.InstallFailed: - EngineEnvironmentSettings.Host.LogMessage(string.Format(LocalizableStrings.InstallFailed, resultTemplateName, instantiateResult.Message)); - break; - case CreationResultStatus.MissingMandatoryParam: - EngineEnvironmentSettings.Host.LogMessage(string.Format(LocalizableStrings.MissingRequiredParameter, instantiateResult.Message, resultTemplateName)); - break; - default: - break; - } - - return instantiateResult.ResultCode; - } - - private static int InitializationAndDebugging(ExtendedCommandParser app, out bool shouldExit) - { - bool reinitFlag = app.RemainingArguments.Any(x => x == "--debug:reinit"); - if (reinitFlag) - { - Paths.User.FirstRunCookie.Delete(); - } - - // Note: this leaves things in a weird state. Might be related to the localized caches. - // not sure, need to look into it. - if (reinitFlag || app.RemainingArguments.Any(x => x == "--debug:reset-config")) - { - Paths.User.AliasesFile.Delete(); - Paths.User.SettingsFile.Delete(); - TemplateCache.DeleteAllLocaleCacheFiles(); - shouldExit = true; - return 0; - } - - if (!Paths.User.BaseDir.Exists() || !Paths.User.FirstRunCookie.Exists()) - { - if (!app.InternalParamHasValue("--quiet")) - { - Reporter.Output.WriteLine(LocalizableStrings.GettingReady); - } - - ConfigureEnvironment(); - Paths.User.FirstRunCookie.WriteAllText(""); - } - - if (app.RemainingArguments.Any(x => x == "--debug:showconfig")) - { - ShowConfig(); - shouldExit = true; - return 0; - } - - shouldExit = false; - return 0; - } - - private static int ParseTemplateArgs(ExtendedCommandParser app, string templateName, out bool shouldExit) - { - try - { - IReadOnlyCollection templates = TemplateCreator.List(templateName); - if (templates.Count == 1) - { - ITemplateInfo templateInfo = templates.First(); - - ITemplate template = SettingsLoader.LoadTemplate(templateInfo); - IParameterSet allParams = template.Generator.GetParametersForTemplate(template); - IReadOnlyDictionary parameterNameMap = template.Generator.ParameterMapForTemplate(template); - app.SetupTemplateParameters(allParams, parameterNameMap); - } - - // re-parse after setting up the template params - app.ParseArgs(app.InternalParamValueList("--extra-args")); - } - catch (Exception ex) - { - Reporter.Error.WriteLine(ex.Message.Red().Bold()); - app.ShowHelp(); - shouldExit = true; - return -1; - } - - if (app.RemainingParameters.Any(x => !x.Key.StartsWith("--debug:"))) - { - EngineEnvironmentSettings.Host.LogMessage(LocalizableStrings.InvalidInputSwitch); - foreach (string flag in app.RemainingParameters.Keys) - { - EngineEnvironmentSettings.Host.LogMessage($"\t{flag}"); - } - - shouldExit = true; - return DisplayHelp(templateName, app, app.AllTemplateParams); - } - - shouldExit = false; - return 0; - } - - private static int MaintenanceAndInfo(ExtendedCommandParser app, string templateName, out bool shouldExit) - { - if (app.InternalParamHasValue("--list")) - { - ListTemplates(templateName); - shouldExit = true; - return -1; - } - - if (app.InternalParamHasValue("--help")) - { - shouldExit = true; - return DisplayHelp(templateName, app, app.AllTemplateParams); - } - - if (app.InternalParamHasValue("--install")) - { - InstallPackages(app.InternalParamValueList("--install").ToList(), app.InternalParamHasValue("--quiet")); - shouldExit = true; - return 0; - } - - //if (update.HasValue()) - //{ - // return PerformUpdateAsync(templateName, quiet, source); - //} - - if (string.IsNullOrEmpty(templateName)) - { - ListTemplates(string.Empty); - shouldExit = true; - return -1; - } - - shouldExit = false; - return 0; - } - - private static Regex _localeFormatRegex = new Regex(@" - ^ - [a-z]{2} - (?:-[A-Z]{2})? - $" - , RegexOptions.IgnorePatternWhitespace); - - private static bool ValidateLocaleFormat(string localeToCheck) - { - return _localeFormatRegex.IsMatch(localeToCheck); - } - - //private static async Task PerformUpdateAsync(string name, bool quiet, CommandOption source) - //{ - // HashSet allSources = new HashSet(); - // HashSet toInstall = new HashSet(StringComparer.OrdinalIgnoreCase); - - // foreach (ITemplate template in TemplateCreator.List(name, source)) - // { - // allSources.Add(template.Source); - // } - - // foreach (IConfiguredTemplateSource src in allSources) - // { - // if (!quiet) - // { - // Reporter.Output.WriteLine(string.Format(LocalizableStrings.CheckingForUpdates, src.Alias)); - // } - - // bool updatesReady; - - // if (src.ParentSource != null) - // { - // updatesReady = await src.Source.CheckForUpdatesAsync(src.ParentSource, src.Location); - // } - // else - // { - // updatesReady = await src.Source.CheckForUpdatesAsync(src.Location); - // } - - // if (updatesReady) - // { - // if (!quiet) - // { - // Reporter.Output.WriteLine(string.Format(LocalizableStrings.UpdateAvailable, src.Alias)); - // } - - // string packageId = src.ParentSource != null - // ? src.Source.GetInstallPackageId(src.ParentSource, src.Location) - // : src.Source.GetInstallPackageId(src.Location); - - // toInstall.Add(packageId); - // } - // } - - // if(toInstall.Count == 0) - // { - // if (!quiet) - // { - // Reporter.Output.WriteLine(LocalizableStrings.NoUpdates); - // } - - // return 0; - // } - - // if (!quiet) - // { - // Reporter.Output.WriteLine(LocalizableString.InstallingUpdates); - // } - - // List installCommands = new List(); - // List uninstallCommands = new List(); - - // foreach (string packageId in toInstall) - // { - // installCommands.Add("-i"); - // installCommands.Add(packageId); - - // uninstallCommands.Add("-i"); - // uninstallCommands.Add(packageId); - // } - - // installCommands.Add("--quiet"); - // uninstallCommands.Add("--quiet"); - - // Command.CreateDotNet("new", uninstallCommands).ForwardStdOut().ForwardStdErr().Execute(); - // Command.CreateDotNet("new", installCommands).ForwardStdOut().ForwardStdErr().Execute(); - // Broker.ComponentRegistry.ForceReinitialize(); - - // if (!quiet) - // { - // Reporter.Output.WriteLine("Done."); - // } - - // return 0; - //} - - private static void ConfigureEnvironment() - { - string[] packageList; - - if (Paths.Global.DefaultInstallPackageList.FileExists()) - { - packageList = Paths.Global.DefaultInstallPackageList.ReadAllText().Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); - if (packageList.Length > 0) - { - InstallPackages(packageList, true); - } - } - - if (Paths.Global.DefaultInstallTemplateList.FileExists()) - { - packageList = Paths.Global.DefaultInstallTemplateList.ReadAllText().Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); - if (packageList.Length > 0) - { - InstallPackages(packageList, true); - } - } - } - - private static void InstallPackages(IReadOnlyList packageNames, bool quiet = false) - { - List toInstall = new List(); - - foreach (string package in packageNames) - { - string pkg = package.Trim(); - pkg = Environment.ExpandEnvironmentVariables(pkg); - - try - { - if (Directory.Exists(pkg) || File.Exists(pkg)) - { - string packageLocation = new DirectoryInfo(pkg).FullName; - TemplateCache.Scan(packageLocation); - } - else - { - string directory = Path.GetDirectoryName(pkg); - string fileGlob = Path.GetFileName(pkg); - string fullDirectory = new DirectoryInfo(directory).FullName; - string fullPathGlob = Path.Combine(fullDirectory, fileGlob); - TemplateCache.Scan(fullPathGlob); - } - } - catch - { - EngineEnvironmentSettings.Host.OnNonCriticalError("InvalidPackageSpecification", string.Format(LocalizableStrings.BadPackageSpec, pkg), null, 0); - } - } - - TemplateCache.WriteTemplateCaches(); - - if (!quiet) - { - ListTemplates(string.Empty); - } - } - - private static void ListTemplates(string templateNames) - { - IEnumerable results = TemplateCreator.List(templateNames); - HelpFormatter formatter = new HelpFormatter(results, 6, '-', false); - formatter.DefineColumn(delegate (ITemplateInfo t) { return t.Name; }, LocalizableStrings.Templates); - formatter.DefineColumn(delegate (ITemplateInfo t) { return $"[{t.ShortName}]"; }, LocalizableStrings.ShortName); - formatter.DefineColumn(delegate (ITemplateInfo t) { return AliasRegistry.GetAliasForTemplate(t) ?? ""; }, LocalizableStrings.Alias); - Reporter.Output.WriteLine(formatter.Layout()); - } - - private static void ShowConfig() - { - Reporter.Output.WriteLine(LocalizableStrings.CurrentConfiguration); - Reporter.Output.WriteLine(" "); - TableFormatter.Print(SettingsLoader.MountPoints, LocalizableStrings.NoItems, " ", '-', new Dictionary> - { - {LocalizableStrings.MountPoints, x => x.Place}, - {LocalizableStrings.Id, x => x.MountPointId}, - {LocalizableStrings.Parent, x => x.ParentMountPointId}, - {LocalizableStrings.Factory, x => x.MountPointFactoryId} - }); - - TableFormatter.Print(SettingsLoader.Components.OfType(), LocalizableStrings.NoItems, " ", '-', new Dictionary> - { - {LocalizableStrings.MountPointFactories, x => x.Id}, - {LocalizableStrings.Type, x => x.GetType().FullName}, - {LocalizableStrings.Assembly, x => x.GetType().GetTypeInfo().Assembly.FullName} - }); - - TableFormatter.Print(SettingsLoader.Components.OfType(), LocalizableStrings.NoItems, " ", '-', new Dictionary> - { - {LocalizableStrings.Generators, x => x.Id}, - {LocalizableStrings.Type, x => x.GetType().FullName}, - {LocalizableStrings.Assembly, x => x.GetType().GetTypeInfo().Assembly.FullName} - }); - } - - private static int DisplayHelp(string templateNames, ExtendedCommandParser app, IReadOnlyDictionary userParameters) - { - if (string.IsNullOrWhiteSpace(templateNames)) - { // no template specified - app.ShowHelp(); - return 0; - } - - IReadOnlyCollection templates = TemplateCreator.List(templateNames); - - if (templates.Count > 1) - { - ListTemplates(templateNames); - return -1; - } - else if (templates.Count == 1) - { - ITemplateInfo templateInfo = templates.First(); - return TemplateHelp(templateInfo, app, userParameters); - } - else - { - // TODO: add a message indicating no templates matched the pattern. Requires LOC coordination - ListTemplates(string.Empty); - return -1; - } - } - - private static int TemplateHelp(ITemplateInfo templateInfo, ExtendedCommandParser app, IReadOnlyDictionary userParameters) - { - Reporter.Output.WriteLine(templateInfo.Name); - if (!string.IsNullOrWhiteSpace(templateInfo.Author)) - { - Reporter.Output.WriteLine(string.Format(LocalizableStrings.Author, templateInfo.Author)); - } - - if (!string.IsNullOrWhiteSpace(templateInfo.Description)) - { - Reporter.Output.WriteLine(string.Format(LocalizableStrings.Description, templateInfo.Description)); - } - - ITemplate template = SettingsLoader.LoadTemplate(templateInfo); - IParameterSet allParams = TemplateCreator.SetupDefaultParamValuesFromTemplateAndHost(template, template.DefaultName); - TemplateCreator.ResolveUserParameters(template, allParams, userParameters); - ParameterHelp(allParams, app); - - return 0; - } - - private static void ParameterHelp(IParameterSet allParams, ExtendedCommandParser app) - { - IEnumerable filteredParams = allParams.ParameterDefinitions.Where(x => x.Priority != TemplateParameterPriority.Implicit); - - if (filteredParams.Any()) - { - HelpFormatter formatter = new HelpFormatter(filteredParams, 2, null, true); - - formatter.DefineColumn( - param => - { - // the key is guaranteed to exist - IList variants = app.CanonicalToVariantsTemplateParamMap[param.Name]; - string options = string.Join("|", variants.Reverse()); - return " " + options; - }, - LocalizableStrings.Options - ); - - formatter.DefineColumn(delegate (ITemplateParameter param) - { - StringBuilder displayValue = new StringBuilder(255); - displayValue.AppendLine(param.Documentation); - - if (string.Equals(param.DataType, "choice", StringComparison.OrdinalIgnoreCase)) - { - displayValue.AppendLine(string.Join(", ", param.Choices)); - } - else - { - displayValue.Append(param.DataType ?? "string"); - displayValue.AppendLine(" - " + param.Priority.ToString()); - } - - if (allParams.ResolvedValues.TryGetValue(param, out object resolvedValueObject)) - { - string resolvedValue = resolvedValueObject as string; - - if (!string.IsNullOrEmpty(resolvedValue) - && !string.IsNullOrEmpty(param.DefaultValue) - && !string.Equals(param.DefaultValue, resolvedValue)) - { - displayValue.AppendLine(string.Format(LocalizableStrings.ConfiguredValue, resolvedValue)); - } - } - - if (!string.IsNullOrEmpty(param.DefaultValue)) - { - displayValue.AppendLine(string.Format(LocalizableStrings.DefaultValue, param.DefaultValue)); - } - - return displayValue.ToString(); - }, - string.Empty - ); - - Reporter.Output.WriteLine(formatter.Layout()); - } - else - { - Reporter.Output.WriteLine(LocalizableStrings.NoParameters); - } - } - } - - internal class TableFormatter - { - public static void Print(IEnumerable items, string noItemsMessage, string columnPad, char header, Dictionary> dictionary) - { - List[] columns = new List[dictionary.Count]; - - for (int i = 0; i < dictionary.Count; ++i) - { - columns[i] = new List(); - } - - string[] headers = new string[dictionary.Count]; - int[] columnWidths = new int[dictionary.Count]; - int valueCount = 0; - - foreach (T item in items) - { - int index = 0; - foreach (KeyValuePair> act in dictionary) - { - headers[index] = act.Key; - columns[index++].Add(act.Value(item)?.ToString() ?? "(null)"); - } - ++valueCount; - } - - if (valueCount > 0) - { - for (int i = 0; i < columns.Length; ++i) - { - columnWidths[i] = Math.Max(columns[i].Max(x => x.Length), headers[i].Length); - } - } - else - { - int index = 0; - foreach (KeyValuePair> act in dictionary) - { - headers[index] = act.Key; - columnWidths[index++] = act.Key.Length; - } - } - - int headerWidth = columnWidths.Sum() + columnPad.Length * (dictionary.Count - 1); - - for (int i = 0; i < headers.Length - 1; ++i) - { - Reporter.Output.Write(headers[i].PadRight(columnWidths[i])); - Reporter.Output.Write(columnPad); - } - - Reporter.Output.WriteLine(headers[headers.Length - 1]); - Reporter.Output.WriteLine("".PadRight(headerWidth, header)); - - for (int i = 0; i < valueCount; ++i) - { - for (int j = 0; j < columns.Length - 1; ++j) - { - Reporter.Output.Write(columns[j][i].PadRight(columnWidths[j])); - Reporter.Output.Write(columnPad); - } - - Reporter.Output.WriteLine(columns[headers.Length - 1][i]); - } - - if (valueCount == 0) - { - Reporter.Output.WriteLine(noItemsMessage); - } - - Reporter.Output.WriteLine(" "); - } - } -} From 6f506b331c85778a2ffd76c5e937875e89c6ad7d Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Tue, 10 Jan 2017 12:53:41 -0600 Subject: [PATCH 4/4] Fixing build break with latest NuGet packages. --- .../CommandResolution/DepsJsonBuilder.cs | 2 +- .../Resolution/PackageDependencyProvider.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/DepsJsonBuilder.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/DepsJsonBuilder.cs index 4de9841d5..b682bb5af 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/DepsJsonBuilder.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/DepsJsonBuilder.cs @@ -21,7 +21,7 @@ namespace Microsoft.DotNet.Cli.Utils public DepsJsonBuilder() { // This resolver is only used for building file names, so that base path is not required. - _versionFolderPathResolver = new VersionFolderPathResolver(path: null); + _versionFolderPathResolver = new VersionFolderPathResolver(rootPath: null); } public DependencyContext Build( diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/Microsoft.DotNet.Internal.ProjectModel/Resolution/PackageDependencyProvider.cs b/src/Microsoft.DotNet.ProjectJsonMigration/Microsoft.DotNet.Internal.ProjectModel/Resolution/PackageDependencyProvider.cs index c1661fd49..b554fb29f 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/Microsoft.DotNet.Internal.ProjectModel/Resolution/PackageDependencyProvider.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/Microsoft.DotNet.Internal.ProjectModel/Resolution/PackageDependencyProvider.cs @@ -28,7 +28,7 @@ namespace Microsoft.DotNet.Internal.ProjectModel.Resolution _packagePathResolver = new FallbackPackagePathResolver(nugetPathContext); // This resolver is only used for building file names, so that base path is not required. - _versionFolderPathResolver = new VersionFolderPathResolver(path: null); + _versionFolderPathResolver = new VersionFolderPathResolver(rootPath: null); } _frameworkReferenceResolver = frameworkReferenceResolver;