Exemple #1
0
        public void Parse(ArgumentSyntax syntax, Preprocessor preprocessor)
        {
            // Global options
            if (GlobalArguments)
            {
                syntax.DefineOption("v|verbose", ref _verbose, "Turns on verbose output showing additional trace message useful for debugging.");
                syntax.DefineOption("attach", ref _attach, "Pause execution at the start of the program until a debugger is attached.");
            }

            // Command options
            ParseOptions(syntax);

            // Directives
            if (SupportedDirectives != null)
            {
                foreach (IDirective directive in preprocessor.Directives
                         .Where(x => SupportedDirectives.Contains(x.Name, StringComparer.OrdinalIgnoreCase)))
                {
                    // Get the option name and help text
                    string optionName = (string.IsNullOrEmpty(directive.ShortName) ? string.Empty : directive.ShortName + "|") + directive.Name;
                    string optionHelp = $"{directive.Description}{(string.IsNullOrEmpty(directive.GetHelpText()) ? string.Empty : " See below for syntax details.")}";

                    // Single or multiple?
                    if (directive.SupportsMultiple)
                    {
                        // Multiple
                        IReadOnlyList <string> directiveValues = null;
                        syntax.DefineOptionList(optionName, ref directiveValues, optionHelp);
                        if (directiveValues != null)
                        {
                            foreach (string directiveValue in directiveValues)
                            {
                                preprocessor.AddValue(new DirectiveValue(directive.Name, directiveValue));
                            }
                        }
                    }
                    else
                    {
                        // Single
                        string directiveValue = null;
                        syntax.DefineOption(optionName, ref directiveValue, optionHelp);
                        if (directiveValue != null)
                        {
                            preprocessor.AddValue(new DirectiveValue(directive.Name, directiveValue));
                        }
                    }
                }
            }

            // Command parameters
            ParseParameters(syntax);
        }
Exemple #2
0
        public bool ParseArgs(string[] args, Preprocessor preprocessor, out bool hasErrors)
        {
            System.CommandLine.ArgumentSyntax parsed = System.CommandLine.ArgumentSyntax.Parse(args, syntax =>
            {
                // Any changes here should also be made in Cake.Wyam

                if (syntax.DefineOption("help-directives", ref HelpDirectives, "Displays help for the various preprocessor directives.").IsSpecified)
                {
                    // Don't care about anything else
                    return;
                }
                syntax.DefineOption("w|watch", ref Watch, "Watches the input folder for any changes.");
                Preview = syntax.DefineOption("p|preview", ref PreviewPort, false, "Start the preview web server on the specified port (default is " + PreviewPort + ").").IsSpecified;
                if (syntax.DefineOption("force-ext", ref PreviewForceExtension, "Force the use of extensions in the preview web server (by default, extensionless URLs may be used).").IsSpecified&& !Preview)
                {
                    syntax.ReportError("force-ext can only be specified if the preview server is running.");
                }
                if (syntax.DefineOption("preview-root", ref PreviewRoot, DirectoryPath.FromString, "The path to the root of the preview server, if not the output folder.").IsSpecified&& !Preview)
                {
                    syntax.ReportError("preview-root can only be specified if the preview server is running.");
                }
                syntax.DefineOptionList("i|input", ref InputPaths, DirectoryPath.FromString, "The path(s) of input files, can be absolute or relative to the current folder.");
                syntax.DefineOption("o|output", ref OutputPath, DirectoryPath.FromString, "The path to output files, can be absolute or relative to the current folder.");
                syntax.DefineOption("c|config", ref ConfigFilePath, FilePath.FromString, "Configuration file (by default, config.wyam is used).");
                syntax.DefineOption("u|update-packages", ref UpdatePackages, "Check the NuGet server for more recent versions of each package and update them if applicable.");
                syntax.DefineOption("use-local-packages", ref UseLocalPackages, "Toggles the use of a local NuGet packages folder.");
                syntax.DefineOption("packages-path", ref PackagesPath, DirectoryPath.FromString, "The packages path to use (only if use-local is true).");
                syntax.DefineOption("output-script", ref OutputScript, "Outputs the config script after it's been processed for further debugging.");
                syntax.DefineOption("verify-config", ref VerifyConfig, false, "Compile the configuration but do not execute.");
                syntax.DefineOption("noclean", ref NoClean, "Prevents cleaning of the output path on each execution.");
                syntax.DefineOption("nocache", ref NoCache, "Prevents caching information during execution (less memory usage but slower execution).");
                syntax.DefineOption("v|verbose", ref Verbose, "Turns on verbose output showing additional trace message useful for debugging.");
                syntax.DefineOption("pause", ref Pause, "Pause execution at the start of the program until a key is pressed (useful for attaching a debugger).");
                syntax.DefineOptionList("meta", ref GlobalMetadataArgs, "Specifies global metadata which can be accessed from the engine or config file (--meta key=value).");

                LogFilePath = $"wyam-{DateTime.Now:yyyyMMddHHmmssfff}.txt";
                if (!syntax.DefineOption("l|log", ref LogFilePath, FilePath.FromString, false, "Log all trace messages to the specified log file (by default, wyam-[datetime].txt).").IsSpecified)
                {
                    LogFilePath = null;
                }

                foreach (IDirective directive in preprocessor.Directives.Where(x => x.SupportsCli))
                {
                    IReadOnlyList <string> directiveValues = null;
                    syntax.DefineOptionList(directive.DirectiveNames.First(), ref directiveValues, $"{directive.Description} See below for syntax details.");
                    if (directiveValues != null)
                    {
                        foreach (string directiveValue in directiveValues)
                        {
                            preprocessor.AddValue(new DirectiveValue(directive.DirectiveNames.First(), directiveValue));
                        }
                    }
                }

                if (syntax.DefineParameter("root", ref RootPath, DirectoryPath.FromString, "The folder (or config file) to use.").IsSpecified)
                {
                    // If a root folder was defined, but it actually points to a file, set the root folder to the directory
                    // and use the specified file as the config file (if a config file was already specified, it's an error)
                    FilePath rootDirectoryPathAsConfigFile = new DirectoryPath(Environment.CurrentDirectory).CombineFile(RootPath.FullPath);
                    if (File.Exists(rootDirectoryPathAsConfigFile.FullPath))
                    {
                        // The specified root actually points to a file...
                        if (ConfigFilePath != null)
                        {
                            syntax.ReportError("A config file was both explicitly specified and specified in the root folder.");
                        }
                        else
                        {
                            ConfigFilePath = rootDirectoryPathAsConfigFile.FileName;
                            RootPath       = rootDirectoryPathAsConfigFile.Directory;
                        }
                    }
                }
            });

            hasErrors = parsed.HasErrors;

            // Set verbose tracing
            if (Verbose)
            {
                Trace.Level = System.Diagnostics.SourceLevels.Verbose;
            }

            // Capture any stdin, but we have to be very careful because the calling process might have
            // opened stdin and just left it open, in which case it would register as redirected but the
            // stream won't ever return because it's just waiting for input
            if (Console.IsInputRedirected)
            {
                Trace.Verbose("Input is redirected, attempting to read...");
                using (Stream stream = Console.OpenStandardInput())
                {
                    byte[]        buffer    = new byte[1000];
                    StringBuilder stdin     = new StringBuilder();
                    int           totalRead = 0;
                    int           read      = -1;
                    while (true)
                    {
                        AutoResetEvent gotInput    = new AutoResetEvent(false);
                        Thread         inputThread = new Thread(() =>
                        {
                            try
                            {
                                read = stream.Read(buffer, 0, buffer.Length);
                                gotInput.Set();
                            }
                            catch (ThreadAbortException)
                            {
                                Thread.ResetAbort();
                            }
                        })
                        {
                            IsBackground = true
                        };

                        inputThread.Start();

                        // Timeout expired?
                        if (!gotInput.WaitOne(100))
                        {
                            inputThread.Abort();
                            Trace.Verbose("Timeout expired while reading from input");
                            break;
                        }

                        // End of stream?
                        if (read == 0)
                        {
                            Stdin = stdin.ToString();
                            Trace.Verbose($"Read {totalRead} bytes ({Stdin.Length} characters) from input");
                            break;
                        }

                        // Got data
                        stdin.Append(Console.InputEncoding.GetString(buffer, 0, read));
                        totalRead += read;
                    }
                }
            }

            if (parsed.IsHelpRequested())
            {
                foreach (IDirective directive in preprocessor.Directives.Where(x => x.SupportsCli))
                {
                    Console.WriteLine($"--{directive.DirectiveNames.First()} usage:");
                    Console.WriteLine();
                    Console.WriteLine(directive.GetHelpText());
                    Console.WriteLine();
                }
            }

            return(!(parsed.IsHelpRequested() || hasErrors));
        }