Esempio n. 1
0
        protected static bool ValidateOptions(OptionValues optionValues, bool userRequestsHelp, OptionSet options, string errorMessage)
        {
            string message = null;

            if (null != errorMessage)
            {
                message = errorMessage;
            }
            else if (userRequestsHelp)
            {
                message = "Showing Help";
            }
            else if (String.IsNullOrWhiteSpace(optionValues.BasePath))
            {
                message = "Missing base path";
            }
            else if (false == System.IO.Directory.Exists(optionValues.BasePath))
            {
                message = "Base path does not exist: '" + optionValues.BasePath + "'";
            }

            if (null != message)
            {
                ShowHelp(message, options);
                return(false);
            }
            return(true);
        }
Esempio n. 2
0
        private static int Main(string[] args)
        {
            log4net.Config.XmlConfigurator.Configure();

            var exlcudedSlns = new List <string>();
            var inputFiles   = new List <string>();
            var optionValues = new OptionValues();

            if (false == ParseOptions(args, exlcudedSlns, inputFiles, optionValues))
            {
                return(1);
            }

            UpdateLog4NetLevel(optionValues.LogLevel);

            try
            {
                PerformCommands(new HashSet <string>(exlcudedSlns), new HashSet <string>(inputFiles), optionValues);
            }
            catch (Exception e)
            {
                _logger.Error("Error reached top-level. To view exception stack trace and details use verbose (-v) flag");
                _logger.Info("Error reached top-level, details:\n", e);
                return(2);
            }

            return(0);
        }
Esempio n. 3
0
        private static void ValidateProject(Project project, OptionValues optionValues)
        {
            project.ValidateHintPaths(optionValues.MatchingAssemblyRegexes, optionValues.FlipIgnore);
            var basePath = PathExtensions.GetFullPath(optionValues.BasePath).Trim();

            foreach (var assemblyReference in project.AssemblyReferences.Where(x => false == String.IsNullOrWhiteSpace(x.HintPath)))
            {
                if (System.IO.Path.IsPathRooted(assemblyReference.ExplicitHintPath))
                {
                    var errorMessage = String.Format("Absolute path found in HintPath in assembly reference '{0}', project: '{1}' (will break easily when trying to compile on another machine!)", assemblyReference, project);
                    _logger.Warn(errorMessage);
                }
                var hintPathPrefix = PathExtensions.GetFullPath(assemblyReference.HintPath.Trim())
                                     .Substring(0, basePath.Length);
                if (false == basePath.Equals(
                        hintPathPrefix,
                        StringComparison.InvariantCultureIgnoreCase))
                {
                    var errorMessage = String.Format(
                        "HintPath is outside the given base path for finding projects in assembly reference '{0}', project: '{1}', base path: '{2}' expected to equal the prefix of the hint path: '{3}'",
                        assemblyReference, project, basePath, hintPathPrefix);
                    _logger.Warn(errorMessage);
                }
            }
        }
Esempio n. 4
0
        protected static bool ParseOptions(string[] args, List <string> exlcudedSlns, List <string> inputFiles, OptionValues optionValues)
        {
            bool userRequestsHelp = false;

            optionValues.BasePath                = null;
            optionValues.GenerateGraphviz        = false;
            optionValues.Build                   = false;
            optionValues.PrintSolutionBuildOrder = false;
            var assemblyMatchPatterns = new List <Regex>();

            var options = new OptionSet();

            options.LineWidth   = 150;
            options.OptionWidth = 30;
            options.Add("b|base-path=",
                        "(required) Base path for searching for sln / csproj files.",
                        x => optionValues.BasePath = x);
            options.Add("all-slns",
                        "Find all .sln files under base path and use them as inputs.",
                        x => optionValues.IncludeAllSLNsAsInputs = (null != x));
            options.Add("o|output-proj",
                        "Generate a single MSBuild (named " + MSBUILD_OUTPUT_FILENAME + @") that includes all inputs,
with dependency information (can be used for building the inter-sln dependencies correctly using MSBuild)",
                        x => optionValues.GenerateMSBuildFiles = (null != x));
            options.Add("split-proj",
                        "(requires -o) Generates the MSBuild project file as multiple files - generates a one per .sln (named " + MSBUILD_OUTPUT_FILENAME + ", in the .sln's directory)",
                        x => optionValues.OutputMultipleMSBuildFiles = (null != x));
            options.Add("n|nuspec",
                        "Generate .nuspec files for nuget packaging, one next to each .csproj file",
                        x => optionValues.GenerateNUSpecFiles = (null != x));
            options.Add("nuspec-no-deps",
                        "(requires --nuspec) When generating .nuspec files, don't include dependencies explicitly - for use with nuget's option -IncludeReferencedProjects",
                        x => optionValues.NUSpecWithoutDeps = (null != x));
            options.Add("packages-config",
                        "Generate a nuget packages.config file, one next to each .csproj file",
                        x => optionValues.GenerateNugetPackagesConfig = (null != x));
            options.Add("c|compile",
                        @"Full compile of the given inputs. Combine with -u to only build the dependencies (but not the direct input solutions).
Includes (recursively on all dependencies, using the calculated dependency order):
1. Find the full dependency graph (can be limited by -r)
2. Update the dependency assemblies
3. Run msbuild",
                        x => optionValues.Build = (null != x));
            options.Add("no-clean", @"Don't clean (don't run msbuild /t:clean) before building. Default is to clean.", x => optionValues.CleanBeforeBuild = false == (null != x));
            options.Add("u|update-dependencies",
                        @"Update dependencies (components) of the input solutions.
Finds the project that builds each dependent assembly and copies the project's outputs to the HintPath given in the input project's definition (.csproj).
Combine this with -c (--compile) to also compile whatever is neccesary for building the dependency assemblies and then copy them.",
                        x => optionValues.UpdateComponents = (null != x));
            options.Add("r=|recursion-level=",
                        "How many levels should the builder recurse when building a project's dependencies. Default is infinity (you can specify it by passing -1)." + Environment.NewLine
                        + "Zero means only the direct dependencies of the project itself will be considered.",
                        (int x) => optionValues.RecursionLevel = x);
            options.Add("p|print-slns",
                        "Print the .sln files of all dependencies in the calculated dependency order",
                        x => optionValues.PrintSolutionBuildOrder = (null != x));
            options.Add("print-csprojs",
                        "Print the .csprojs files of all dependencies in the calculated dependency order",
                        x => optionValues.PrintProjectBuildOrder = (null != x));
            options.Add("x|exclude=",
                        "Exclude this .sln when resolving dependency order (useful when temporarily ignoring cyclic dependencies)",
                        x => exlcudedSlns.Add(x));
            //options.Add("dependents",
            //            "Finds anything that depends on the projects/solutions and performs operations as if they were the inputs (builds, prints, updates components, etc. on the dependents)",
            //            x => optionValues.Dependents = (null != x));
            options.Add("m=|match-assembly=",
                        "When finding dependencies and copying components, ignore ALL referenced assemblies EXCEPT those matching the given regex pattern (case insensitive). May be given multiple times to accumulate patterns. Useful for ignoring system and third-party assemblies.",
                        x => assemblyMatchPatterns.Add(new Regex(x, RegexOptions.IgnoreCase)));
            options.Add("flip-ignore",
                        "Flips the meaning of match-assembly (-m) to ignore ONLY the matched patterns, and not ignore anything that doesn't match. If no -m is given, this option is ignored and all assemblies are included in the build.",
                        x => optionValues.FlipIgnore = (null != x));
            options.Add("ignore-missing",
                        "When copying dependency assemblies (components), ignore those that are missing - meaning, the ones that can't be copied because the compiled assembly file to be copied is not found.",
                        x => optionValues.IgnoreMissingAssemblies = (null != x));
            options.Add("v|verbose",
                        "Verbose output. Repeat this flag (e.g. -vvv) for more verbose output (will go to stderr)",
                        x => optionValues.LogLevel = IncreaseLogLevel(optionValues.LogLevel));
            options.Add("g|graph",
                        "Generate dependency graph output (requires GraphViz)",
                        x => optionValues.GenerateGraphviz = (null != x));
            options.Add("t|run-tests",
                        "Run all unit tests (using MSTest)",
                        x => optionValues.RunTests = (null != x));
            options.Add("ignore-failed-tests",
                        "When running tests, don't stop the build on failure of tests.",
                        x => optionValues.IgnoreFailedTests = (null != x));
            options.Add("h|help",
                        "Show help",
                        x => userRequestsHelp = (null != x));

            string errorMessage = null;

            try
            {
                inputFiles.AddRange(options.Parse(args));
            }
            catch (OptionException e)
            {
                errorMessage = e.Message;
            }
            optionValues.MatchingAssemblyRegexes = assemblyMatchPatterns.ToArray();
            return(ValidateOptions(optionValues, userRequestsHelp, options, errorMessage));
        }
Esempio n. 5
0
 protected static void PerformBuild(ProjectFinder projectFinder, BuildDependencyInfo dependencyInfo, OptionValues optionValues)
 {
     foreach (var solutionFileName in dependencyInfo.TrimmedSolutionDependencyGraph.TopologicalSort())
     {
         Builder.BuildSolution(projectFinder, solutionFileName, optionValues.MatchingAssemblyRegexes, optionValues.FlipIgnore, optionValues.IgnoreMissingAssemblies, optionValues.CleanBeforeBuild, optionValues.RunTests, optionValues.IgnoreFailedTests);
     }
 }
Esempio n. 6
0
        protected static void PerformUpdateComponents(ProjectFinder projectFinder, BuildDependencyInfo dependencyInfo, OptionValues optionValues)
        {
            var graph           = dependencyInfo.TrimmedSolutionDependencyGraph;
            var sortedSolutions = GetDependencySortedSolutionNames(dependencyInfo);

            if (optionValues.Build)
            {
                foreach (var solutionFileName in sortedSolutions.Where(x => graph.OutEdges(x).Any()))
                {
                    Builder.BuildSolution(projectFinder, solutionFileName, optionValues.MatchingAssemblyRegexes, optionValues.FlipIgnore, optionValues.IgnoreMissingAssemblies, optionValues.CleanBeforeBuild, optionValues.RunTests, optionValues.IgnoreFailedTests);
                }
            }
            foreach (var solutionFileName in sortedSolutions.Where(x => false == graph.OutEdges(x).Any()))
            {
                Builder.UpdateComponentsFromBuiltProjects(projectFinder, solutionFileName, optionValues.MatchingAssemblyRegexes, optionValues.FlipIgnore, optionValues.IgnoreMissingAssemblies);
            }
        }
Esempio n. 7
0
        protected static void GenerateNugetPackagesConfig(BuildDependencyInfo dependencyInfo, OptionValues optionValues)
        {
            var versions = new Dictionary <string, string>();

            foreach (var project in dependencyInfo.FullProjectDependencyGraph.Vertices)
            {
                StringBuilder dependenciesBuilder = new StringBuilder();
                var           edges = dependencyInfo.FullProjectDependencyGraph.Edges.Where(x => x.Target == project);
                foreach (var edge in edges)
                {
                    string version;
                    if (project.ProjectReferences.Contains(edge.Source))
                    {
                        continue;
                    }
                    var dependencyName = edge.Source.Name;
                    if (false == versions.TryGetValue(dependencyName, out version))
                    {
                        var processStartInfo = new ProcessStartInfo("nuget.exe", "list " + dependencyName);
                        processStartInfo.UseShellExecute        = false;
                        processStartInfo.RedirectStandardOutput = true;
                        processStartInfo.WorkingDirectory       = System.Environment.CurrentDirectory;
                        var process = Process.Start(processStartInfo);
                        while (true)
                        {
                            var line = process.StandardOutput.ReadLine();
                            if (null == line)
                            {
                                version = "unknown";
                                break;
                            }
                            var parts = line.Split(' ');
                            if (parts[0].Equals(dependencyName, StringComparison.InvariantCultureIgnoreCase))
                            {
                                version = parts[1];
                                break;
                            }
                        }
                        _logger.DebugFormat("{0} = {1}", dependencyName, version);
                        versions[dependencyName] = version;
                    }
                    dependenciesBuilder.AppendFormat("    <package id=\"{0}\" version=\"{1}\" />\n",
                                                     dependencyName,
                                                     version
                                                     );
                }
                var data = String.Format(@"<?xml version=""1.0"" encoding=""utf-8""?>
<packages>
{0}
</packages>
",
                                         dependenciesBuilder.ToString());
                var fileName = PackagesConfigFileName(project);
                _logger.InfoFormat("Generating file: {0} for project {1}", fileName, project.Name);
                File.WriteAllText(fileName, data);
            }
        }
Esempio n. 8
0
        protected static void GenerateNUSpecFiles(BuildDependencyInfo dependencyInfo, OptionValues optionValues)
        {
            foreach (var project in dependencyInfo.FullProjectDependencyGraph.Vertices)
            {
                StringBuilder dependenciesBuilder = new StringBuilder();
                if (false == optionValues.NUSpecWithoutDeps)
                {
                    var edges = dependencyInfo.FullProjectDependencyGraph.Edges.Where(x => x.Target == project);
                    foreach (var edge in edges)
                    {
                        dependenciesBuilder.AppendFormat("        <dependency id=\"{0}\" version=\"\" />\n",
                                                         edge.Source.Name
                                                         //edge.Target.ver
                                                         );
                    }
                }
                var data = String.Format(@"<?xml version=""1.0""?>
<package >
  <metadata>
    <id>{0}</id>
    <version>$version$</version>
    <title>{0}</title>
    <authors>Unknown</authors>
    <description>Built from {1}</description>
    <dependencies>
{2}
    </dependencies>

  </metadata>
</package>
",
                                         project.Name,
                                         project.Path,
                                         dependenciesBuilder.ToString());

                var fileName = NUSpecFileName(project);
                _logger.InfoFormat("Generating file: {0} for project {1}", fileName, project.Name);
                File.WriteAllText(fileName, data);
            }
        }
Esempio n. 9
0
        private static void PerformCommands(ISet <string> exlcudedSlns, ISet <string> inputFiles, OptionValues optionValues)
        {
            var projectFinder = new ProjectFinder(optionValues.BasePath, true);

            foreach (var project in projectFinder.AllProjectsInPath())
            {
                ValidateProject(project, optionValues);
            }

            if (optionValues.IncludeAllSLNsAsInputs)
            {
                var slnFiles = projectFinder.AllProjectsInPath()
                               .Where(projectFinder.ProjectHasMatchingSLNFile)
                               .Select(projectFinder.GetSLNFileForProject)
                               .Select(x => x.FullName)
                               .Distinct();
                _logger.Info("Adding SLN inputs:");
                foreach (var slnFile in slnFiles.OrderBy(x => x))
                {
                    inputFiles.Add(slnFile);
                    _logger.Info("\t" + slnFile);
                }
            }

            var dependencyInfo = Soldr.Resolver.BuildDependencyResolver.GetDependencyInfo(projectFinder, inputFiles, exlcudedSlns, optionValues.RecursionLevel); //, optionValues.Dependents);

            if (optionValues.GenerateGraphviz)
            {
                GenerateGraphViz(dependencyInfo.SolutionDependencyGraph);
            }

            if (optionValues.PrintSolutionBuildOrder)
            {
                PrintSolutionBuildOrder(dependencyInfo);
            }

            if (optionValues.PrintProjectBuildOrder)
            {
                PrintProjectBuildOrder(dependencyInfo);
            }

            if (optionValues.GenerateMSBuildFiles)
            {
                GenerateMSBuildFiles(dependencyInfo, false == optionValues.OutputMultipleMSBuildFiles);
            }

            if (optionValues.GenerateNUSpecFiles)
            {
                GenerateNUSpecFiles(dependencyInfo, optionValues);
            }

            if (optionValues.GenerateNugetPackagesConfig)
            {
                GenerateNugetPackagesConfig(dependencyInfo, optionValues);
            }

            if (optionValues.UpdateComponents)
            {
                PerformUpdateComponents(projectFinder, dependencyInfo, optionValues);
                Console.Error.WriteLine("Dependencies updated.");
            }
            else if (optionValues.Build)
            {
                PerformBuild(projectFinder, dependencyInfo, optionValues);
                Console.Error.WriteLine("Build complete.");
            }
        }