예제 #1
0
        static partial void Wain(IEnumerable <string> args)
        {
            const string csx = "csx";
            const string exe = "exe";

            var verbose          = false;
            var help             = false;
            var recurse          = false;
            var force            = false;
            var watching         = false;
            var incremental      = false;
            var extraPackageList = new List <PackageReference>();
            var extraImportList  = new List <string>();
            var cscPath          = (string)null;
            var target           = (string)null;
            var targetFramework  = NuGetFramework.Parse(AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName);

            var options = new OptionSet
            {
                { "?|help|h", "prints out the options", _ => help = true },
                { "verbose|v", "enable additional output", _ => verbose = true },
                { "d|debug", "debug break", _ => Debugger.Launch() },
                { "r|recurse", "include sub-directories", _ => recurse = true },
                { "f|force", "force continue on errors", _ => force = true },
                { "w|watch", "watch for changes and re-compile outdated", _ => watching = true },
                { "i|incremental", "compile outdated scripts only", _ => incremental = true },
                { "ref|reference=", "extra NuGet reference", v => { if (!string.IsNullOrEmpty(v))
                                                                    {
                                                                        extraPackageList.Add(ParseExtraPackageReference(v));
                                                                    }
                  } },
                { "imp|import=", "extra import", v => { extraImportList.Add(v); } },
                { "csc=", "C# compiler path", v => cscPath = v },
                { "t|target=", csx + " = C# script (default); " + exe + " = executable (experimental)", v => target = v },
                { "fx=", $"target framework; default: {targetFramework}", v => targetFramework = NuGetFramework.Parse(v) },
            };

            var tail = options.Parse(args.TakeWhile(arg => arg != "--"));

            if (verbose)
            {
                Trace.Listeners.Add(new ConsoleTraceListener(useErrorStream: true));
            }

            if (help || tail.Count == 0)
            {
                Help(options);
                return;
            }

            if (target == null)
            {
                target = !string.IsNullOrEmpty(cscPath) ? exe : csx;
            }

            var generator =
                csx.Equals(target, StringComparison.OrdinalIgnoreCase)
                ? GenerateCsx
                : exe.Equals(target, StringComparison.OrdinalIgnoreCase)
                ? GenerateExecutable(cscPath)
                : throw new Exception("Target is invalid or missing. Supported targets are: "
                                      + string.Join(", ", csx, exe));

            extraImportList.RemoveAll(string.IsNullOrEmpty);

            // TODO Allow package source to be specified via args

            var queries = GetQueries(tail, recurse);

            // TODO Allow packages directory to be specified via args

            const string packagesDirName = "packages";

            var compiler = Compiler(NuGetClient.CreateDefaultFactory(), packagesDirName, extraPackageList, extraImportList,
                                    targetFramework, generator,
                                    watching || incremental, force, verbose);

            if (watching)
            {
                if (tail.Count > 1)
                {
                    // TODO Support multiple watch roots

                    throw new NotSupportedException(
                              "Watch mode does not support multiple file specifications. " +
                              "Use a single wildcard specification instead instead to watch and re-compile several queries.");
                }

                var tokens = SplitDirFileSpec(tail.First()).Fold((dp, fs) =>
                                                                 (
                                                                     dirPath: dp ?? Environment.CurrentDirectory,
                                                                     fileSpec: fs
                                                                 ));

                using (var cts = new CancellationTokenSource())
                {
                    Console.CancelKeyPress += (_, e) =>
                    {
                        // TODO Re-consider proper cancellation

                        Console.WriteLine("Aborting...");
                        // ReSharper disable once AccessToDisposedClosure
                        cts.Cancel();
                        e.Cancel = true;
                    };

                    var changes =
                        FileMonitor.GetFolderChanges(
                            tokens.dirPath, tokens.fileSpec,
                            recurse,
                            NotifyFilters.FileName
                            | NotifyFilters.LastWrite,
                            WatcherChangeTypes.Created
                            | WatcherChangeTypes.Changed
                            | WatcherChangeTypes.Renamed,
                            cts.Token);

                    foreach (var e in from cs in changes.Throttle(TimeSpan.FromSeconds(2))
                             select cs.Length)
                    {
                        Console.WriteLine($"{e} change(s) detected. Re-compiling...");

                        var count         = 0;
                        var compiledCount = 0;
                        // ReSharper disable once LoopCanBeConvertedToQuery
                        // ReSharper disable once LoopCanBePartlyConvertedToQuery
                        // ReSharper disable once PossibleMultipleEnumeration
                        foreach (var query in queries)
                        {
                            // TODO Re-try on potential file locking issues

                            var compiled = compiler(query);
                            count++;
                            compiledCount += compiled ? 1 : 0;
                        }

                        if (count > 1)
                        {
                            Console.WriteLine($"Re-compiled {compiledCount:N0} of {count:N0} queries.");
                        }
                    }
                }
            }
            else
            {
                foreach (var query in queries)
                {
                    compiler(query);
                }
            }
        }