AddDependentPackage()
        {
            var packageNameArgument = new Options.PackageName();
            var packageName         = CommandLineProcessor.Evaluate(packageNameArgument);

            if (null == packageName)
            {
                throw new Exception("No name was defined. Use {0} on the command line to specify it.", (packageNameArgument as ICommandLineArgument).LongName);
            }

            var packageVersion = CommandLineProcessor.Evaluate(new Options.PackageVersion());

            var masterPackage = GetMasterPackage();

            if (null != masterPackage.Dependents.FirstOrDefault(item => item.Item1 == packageName && item.Item2 == packageVersion))
            {
                if (null != packageVersion)
                {
                    throw new Exception("Package dependency {0}, version {1}, is already present", packageName, packageVersion);
                }
                else
                {
                    throw new Exception("Package dependency {0} is already present", packageName);
                }
            }

            var newDepTuple = new System.Tuple <string, string, bool?>(packageName, packageVersion, null);

            masterPackage.Dependents.Add(newDepTuple);
            // TODO: this is unfortunate having to write the file in order to use it with IdentifyAllPackages
            masterPackage.Write();

            // validate that the addition is ok
            try
            {
                PackageUtilities.IdentifyAllPackages();
            }
            catch (Exception exception)
            {
                masterPackage.Dependents.Remove(newDepTuple);
                masterPackage.Write();
                throw new Exception(exception, "Failed to add dependent. Are all necessary package repositories specified?");
            }
        }
Exemple #2
0
        Execute(
            Array <Environment> environments,
            System.Reflection.Assembly packageAssembly = null)
        {
            PrintVersion();

            if (0 == environments.Count)
            {
                throw new Exception("No build configurations were specified");
            }

            var graph = Graph.Instance;

            if (null != packageAssembly)
            {
                PackageUtilities.IdentifyAllPackages();
                graph.ScriptAssembly         = packageAssembly;
                graph.ScriptAssemblyPathname = packageAssembly.Location;
            }
            else
            {
                PackageUtilities.CompilePackageAssembly();
                PackageUtilities.LoadPackageAssembly();
            }

            var packageMetaDataProfile = new TimeProfile(ETimingProfiles.PackageMetaData);

            packageMetaDataProfile.StartProfile();

            // validate that there is at most one local policy
            // if test mode is enabled, then the '.tests' sub-namespaces are also checked
            {
                var localPolicies = graph.ScriptAssembly.GetTypes().Where(t => typeof(ISitePolicy).IsAssignableFrom(t));
                var includeTests  = CommandLineProcessor.Evaluate(new Options.UseTests());
                if (!includeTests)
                {
                    localPolicies = localPolicies.Where(item => !item.Namespace.EndsWith(".tests"));
                }
                var numLocalPolicies = localPolicies.Count();
                if (numLocalPolicies > 0)
                {
                    if (numLocalPolicies > 1)
                    {
                        var message = new System.Text.StringBuilder();
                        message.AppendLine("Too many site policies exist in the package assembly:");
                        foreach (var policy in localPolicies)
                        {
                            message.AppendFormat("\t{0}", policy.ToString());
                            message.AppendLine();
                        }
                        throw new Exception(message.ToString());
                    }

                    Settings.LocalPolicy = System.Activator.CreateInstance(localPolicies.First()) as ISitePolicy;
                }
            }

            // find a product definition
            {
                var productDefinitions    = graph.ScriptAssembly.GetTypes().Where(t => typeof(IProductDefinition).IsAssignableFrom(t));
                var numProductDefinitions = productDefinitions.Count();
                if (numProductDefinitions > 0)
                {
                    if (numProductDefinitions > 1)
                    {
                        var message = new System.Text.StringBuilder();
                        message.AppendLine("Too many product definitions exist in the package assembly:");
                        foreach (var def in productDefinitions)
                        {
                            message.AppendFormat("\t{0}", def.ToString());
                            message.AppendLine();
                        }
                        throw new Exception(message.ToString());
                    }

                    graph.ProductDefinition = System.Activator.CreateInstance(productDefinitions.First()) as IProductDefinition;
                }
            }

            // get the metadata from the build mode package
            var metaName     = System.String.Format("{0}Builder.{0}Meta", graph.Mode);
            var metaDataType = graph.ScriptAssembly.GetType(metaName);

            if (null == metaDataType)
            {
                throw new Exception("No build mode {0} meta data type {1}", graph.Mode, metaName);
            }

            if (!typeof(IBuildModeMetaData).IsAssignableFrom(metaDataType))
            {
                throw new Exception("Build mode package meta data type {0} does not implement the interface {1}", metaDataType.ToString(), typeof(IBuildModeMetaData).ToString());
            }
            graph.BuildModeMetaData = System.Activator.CreateInstance(metaDataType) as IBuildModeMetaData;

            // packages can have meta data - instantiate where they exist
            foreach (var package in graph.Packages)
            {
                var ns       = package.Name;
                var metaType = graph.ScriptAssembly.GetTypes().FirstOrDefault(item => item.Namespace == ns && typeof(PackageMetaData).IsAssignableFrom(item));
                if (null == metaType)
                {
                    continue;
                }

                try
                {
                    package.MetaData = System.Activator.CreateInstance(metaType) as PackageMetaData;
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                catch (System.Reflection.TargetInvocationException exception)
                {
                    throw new Exception(exception, "Failed to create package metadata");
                }
            }

            packageMetaDataProfile.StopProfile();

            var topLevelNamespace = graph.MasterPackage.Name;

            var findBuildableModulesProfile = new TimeProfile(ETimingProfiles.IdentifyBuildableModules);

            findBuildableModulesProfile.StartProfile();

            // Phase 1: Instantiate all modules in the namespace of the package in which the tool was invoked
            Log.Detail("Creating modules");
            foreach (var env in environments)
            {
                graph.CreateTopLevelModules(graph.ScriptAssembly, env, topLevelNamespace);
            }

            findBuildableModulesProfile.StopProfile();

            var populateGraphProfile = new TimeProfile(ETimingProfiles.PopulateGraph);

            populateGraphProfile.StartProfile();
            // Phase 2: Graph now has a linear list of modules; create a dependency graph
            // NB: all those modules with 0 dependees are the top-level modules
            // NB: default settings have already been defined here
            // not only does this generate the dependency graph, but also creates the default settings for each module, and completes them
            graph.SortDependencies();
            populateGraphProfile.StopProfile();

            // TODO: make validation optional, if it starts showing on profiles
            var validateGraphProfile = new TimeProfile(ETimingProfiles.ValidateGraph);

            validateGraphProfile.StartProfile();
            graph.Validate();
            validateGraphProfile.StopProfile();

            // Phase 3: (Create default settings, and ) apply patches (build + shared) to each module
            // NB: some builders can use the patch directly for child objects, so this may be dependent upon the builder
            // Toolchains for modules need to be set here, as they might append macros into each module in order to evaluate paths
            // TODO: a parallel thread can be spawned here, that can check whether command lines have changed
            // the Settings object can be inspected, and a hash generated. This hash can be written to disk, and compared.
            // If a 'verbose' mode is enabled, then more work can be done to figure out what has changed. This would also require
            // serializing the binary Settings object
            var createPatchesProfile = new TimeProfile(ETimingProfiles.CreatePatches);

            createPatchesProfile.StartProfile();
            graph.ApplySettingsPatches();
            createPatchesProfile.StopProfile();

            // expand paths after patching settings, because some of the patches may contain tokenized strings
            // TODO: a thread can be spawned, to check for whether files were in date or not, which will
            // be ready in time for graph execution
            var parseStringsProfile = new TimeProfile(ETimingProfiles.ParseTokenizedStrings);

            parseStringsProfile.StartProfile();
            TokenizedString.ParseAll();
            parseStringsProfile.StopProfile();

            if (CommandLineProcessor.Evaluate(new Options.ViewDependencyGraph()))
            {
                // must come after all strings are parsed, in order to display useful paths
                graph.Dump();
            }

            // Phase 4: Execute dependency graph
            // N.B. all paths (including those with macros) have been delayed expansion until now
            var graphExecutionProfile = new TimeProfile(ETimingProfiles.GraphExecution);

            graphExecutionProfile.StartProfile();
            var executor = new Executor();

            executor.Run();
            graphExecutionProfile.StopProfile();
        }