Exemplo n.º 1
0
        public void MultiPassResolutionDoesNotIntroduceConflictingRequirements()
        {
            var a = new Service
            {
                ProjectName = "Test",
                ServiceName = "A",
                DesiredLevel = ServiceDesiredLevel.Recommended,
                Requires = new List<string> { "Test/B" },
            };
            var b = new Service
            {
                ProjectName = "Test",
                ServiceName = "B",
            };
            var c = new Service
            {
                ProjectName = "Test",
                ServiceName = "C",
                Conflicts = new List<string> { "Test/A", "Test/B" },
            };

            var services = new List<Service> { a, b, c };

            var manager = new ServiceManager("Windows");
            manager.EnableService("Test/C");

            manager.EnableDefaultAndExplicitServices(services);

            // This should not throw an exception.
            var enabled = manager.ResolveServices(services);
            Assert.DoesNotContain(a, enabled);
            Assert.DoesNotContain(b, enabled);
            Assert.Contains(c, enabled);
        }
Exemplo n.º 2
0
        public override bool Execute()
        {
            if (string.Compare(this.Platform, "Web", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                // Trigger JSIL provider download if needed.
                string jsilDirectory, jsilCompilerFile;
                if (!this.m_JSILProvider.GetJSIL(out jsilDirectory, out jsilCompilerFile))
                {
                    return false;
                }
            }

            var module = ModuleInfo.Load(Path.Combine(this.RootPath, "Build", "Module.xml"));

            this.LogMessage(
                "Starting generation of projects for " + this.Platform);

            var definitions = module.GetDefinitionsRecursively(this.Platform).ToArray();
            var loadedProjects = new List<XmlDocument>();

            foreach (var definition in definitions)
            {
                this.LogMessage("Loading: " + definition.Name);
                loadedProjects.Add(
                    this.m_ProjectLoader.Load(
                        Path.Combine(
                            definition.ModulePath,
                            "Build",
                            "Projects",
                            definition.Name + ".definition"),
                        this.Platform,
                        module.Path,
                        definition.ModulePath));
            }

            var serviceManager = new ServiceManager(this.Platform);
            List<Service> services;
            string serviceSpecPath;

            if (this.ServiceSpecPath == null)
            {
                serviceManager.SetRootDefinitions(module.GetDefinitions());

                if (this.EnableServices == null)
                {
                    this.EnableServices = new string[0];
                }

                if (this.DisableServices == null)
                {
                    this.DisableServices = new string[0];
                }

                foreach (var service in this.EnableServices)
                {
                    serviceManager.EnableService(service);
                }

                foreach (var service in this.DisableServices)
                {
                    serviceManager.DisableService(service);
                }

                if (this.DebugServiceResolution)
                {
                    serviceManager.EnableDebugInformation();
                }

                try
                {
                    services = serviceManager.CalculateDependencyGraph(loadedProjects);
                }
                catch (InvalidOperationException ex)
                {
                    Console.WriteLine("Error during service resolution: " + ex.Message);
                    return false;
                }

                serviceSpecPath = serviceManager.SaveServiceSpec(services);

                foreach (var service in services)
                {
                    if (service.ServiceName != null)
                    {
                        this.LogMessage("Enabled service: " + service.FullName);
                    }
                }
            }
            else
            {
                services = serviceManager.LoadServiceSpec(this.ServiceSpecPath);
                serviceSpecPath = this.ServiceSpecPath;
            }

            // Run Protobuild in batch mode in each of the submodules
            // where it is present.
            foreach (var submodule in module.GetSubmodules(this.Platform))
            {
                this.LogMessage(
                    "Invoking submodule generation for " + submodule.Name);
                var noResolve = submodule.HasProtobuildFeature("no-resolve") ? " -no-resolve" : string.Empty;
                submodule.RunProtobuild(
                    "-generate " + this.Platform +
                    " -spec " + serviceSpecPath +
                    " " + this.m_PackageRedirector.GetRedirectionArguments() +
                    noResolve);
                this.LogMessage(
                    "Finished submodule generation for " + submodule.Name);
            }

            var repositoryPaths = new List<string>();

            foreach (var definition in definitions.Where(x => x.ModulePath == module.Path))
            {
                string repositoryPath;
                var definitionCopy = definition;
                this.m_ProjectGenerator.Generate(
                    loadedProjects,
                    this.RootPath,
                    definition.Name,
                    this.Platform,
                    services,
                    out repositoryPath,
                    () => this.LogMessage("Generating: " + definitionCopy.Name));

                // Only add repository paths if they should be generated.
                if (module.GenerateNuGetRepositories && !string.IsNullOrEmpty(repositoryPath))
                {
                    repositoryPaths.Add(repositoryPath);
                }
            }

            var solution = Path.Combine(
                this.RootPath,
                this.ModuleName + "." + this.Platform + ".sln");
            this.LogMessage("Generating: (solution)");
            this.m_SolutionGenerator.Generate(
                module,
                loadedProjects,
                this.Platform,
                solution,
                services,
                repositoryPaths);

            // Only save the specification cache if we allow synchronisation
            if (module.DisableSynchronisation == null || !module.DisableSynchronisation.Value)
            {
                var serviceCache = Path.Combine(this.RootPath, this.ModuleName + "." + this.Platform + ".speccache");
                this.LogMessage("Saving service specification");
                File.Copy(serviceSpecPath, serviceCache, true);
            }

            this.LogMessage(
                "Generation complete.");

            return true;
        }
        public void Synchronise(string platform)
        {
            var serviceCache = Path.Combine(
                this.m_ModuleInfo.Path,
                this.m_ModuleInfo.Name + "." + platform + ".speccache");
            var ignoreServiceFiles = !File.Exists(serviceCache);
            var serviceManager = new ServiceManager(null);
            List<Service> services = null;
            if (!ignoreServiceFiles)
            {
                services = serviceManager.LoadServiceSpec(serviceCache);
            }

            var document = new XmlDocument();
            document.Load(this.m_DefinitionInfo.DefinitionPath);

            var projectElement = document.ChildNodes.OfType<XmlElement>()
                .FirstOrDefault(x => x.Name == "Project");
            var elements = projectElement.ChildNodes.OfType<XmlElement>().ToList();

            var files = elements.First(x => x.Name == "Files");

            // Remove files that either have no Platforms child, or where the
            // Platforms child contains the current platform that we're synchronising for.
            // This is because if I generate a platform for Linux, and the definition
            // has Windows-only files in it, those won't be in the project file.
            // Also for files that have services in them, check to see if we have the
            // service cache.  If we don't have a service cache, don't remove any entries
            // that are conditional on services (because we don't know what services
            // were enabled when the project was generated).  Otherwise only allow removal
            // if the service was active at the time.
            foreach (var file in files.ChildNodes.OfType<XmlElement>().ToArray())
            {
                var children = file.ChildNodes.OfType<XmlElement>().ToArray();

                var platformsTag = children.FirstOrDefault(x => x.LocalName == "Platforms");
                var includePlatformsTag = children.FirstOrDefault(x => x.LocalName == "IncludePlatforms");
                var excludePlatformsTag = children.FirstOrDefault(x => x.LocalName == "ExcludePlatforms");

                var platformsTagString = platformsTag != null ? platformsTag.InnerText : string.Empty;
                var includePlatformsTagString = includePlatformsTag != null ? includePlatformsTag.InnerText : string.Empty;
                var excludePlatformsTagString = excludePlatformsTag != null ? excludePlatformsTag.InnerText : string.Empty;

                var servicesTag = children.FirstOrDefault(x => x.LocalName == "Services");
                var includeServicesTag = children.FirstOrDefault(x => x.LocalName == "IncludeServices");
                var excludeServicesTag = children.FirstOrDefault(x => x.LocalName == "ExcludeServices");

                var servicesTagString = servicesTag != null ? servicesTag.InnerText : string.Empty;
                var includeServicesTagString = includeServicesTag != null ? includeServicesTag.InnerText : string.Empty;
                var excludeServicesTagString = excludeServicesTag != null ? excludeServicesTag.InnerText : string.Empty;

                if (!string.IsNullOrEmpty(servicesTagString) || !string.IsNullOrEmpty(includeServicesTagString)
                    || !string.IsNullOrEmpty(excludeServicesTagString))
                {
                    if (ignoreServiceFiles)
                    {
                        // We don't know whether the service was enabled or not during generation, so we can't determine
                        // if the user wanted to remove this entry.
                        continue;
                    }

                    if (!string.IsNullOrEmpty(excludeServicesTagString))
                    {
                        var excluded = false;

                        foreach (var service in services)
                        {
                            if (excludeServicesTagString.Split(',').Contains(service.FullName, StringComparer.OrdinalIgnoreCase) ||
                                (service.ProjectName == this.m_DefinitionInfo.Name && excludeServicesTagString.Split(',').Contains(service.ServiceName, StringComparer.OrdinalIgnoreCase)))
                            {
                                // This file is excluded in the C# project for this platform
                                // and won't be present.
                                excluded = true;
                            }
                        }

                        if (excluded)
                        {
                            // This file is excluded in the C# project for this platform
                            // and won't be present.
                            continue;
                        }
                    }

                    // Fallback to <IncludeServices> if <Services> is not present.
                    if (string.IsNullOrEmpty(servicesTagString))
                    {
                        servicesTagString = includeServicesTagString;
                    }

                    var allowFallthrough = false;

                    // If both the <IncludeServices> and <Services> tags are not present, then this
                    // file is generated for all services regardless.
                    if (servicesTag == null && includeServicesTag == null)
                    {
                        allowFallthrough = true;
                    }
                    else
                    {
                        var included = false;

                        foreach (var service in services)
                        {
                            // If the included services string contains any enabled service, then we
                            // remove the file (because it will be present in the C# project).
                            if (servicesTagString.Split(',')
                                    .Contains(service.FullName, StringComparer.OrdinalIgnoreCase)
                                || (service.ProjectName == this.m_DefinitionInfo.Name
                                    && servicesTagString.Split(',')
                                           .Contains(service.ServiceName, StringComparer.OrdinalIgnoreCase)))
                            {
                                included = true;
                                break;
                            }
                        }

                        if (included)
                        {
                            // This file is included in the C# project for this service.
                            allowFallthrough = true;
                        }
                    }

                    if (!allowFallthrough)
                    {
                        // We weren't included with <Services> or <IncludeServices> so we won't
                        // be present regardless of platform settings.
                        continue;
                    }

                    // We were included by a service, but we might not have passed the platform check
                    // so continue performing checks.
                }

                if (!string.IsNullOrEmpty(excludePlatformsTagString))
                {
                    if (excludePlatformsTagString.Split(',').Contains(platform, StringComparer.OrdinalIgnoreCase))
                    {
                        // This file is excluded in the C# project for this platform
                        // and won't be present.
                        continue;
                    }
                }

                // Fallback to <IncludePlatforms> if <Platforms> is not present.
                if (string.IsNullOrEmpty(platformsTagString))
                {
                    platformsTagString = includePlatformsTagString;
                }

                // If both the <IncludePlatforms> and <Platforms> tags are not present, then this
                // file is generated for all platforms regardless.
                if (platformsTag == null && includePlatformsTag == null)
                {
                    files.RemoveChild(file);
                    continue;
                }

                // If the included platforms string contains the current platform, then we
                // remove the file (because it will be present in the C# project).
                if (platformsTagString.Split(',').Contains(platform, StringComparer.OrdinalIgnoreCase))
                {
                    files.RemoveChild(file);
                }
            }

            // Add the new files.
            var uniquePaths = new List<string>();
            foreach (var element in this.m_CSharpProject.Elements.OrderBy(x => x.Name).ThenBy(x => this.NormalizePath(x.GetAttribute("Include"))))
            {
                // Ignore Content files.
                if (element.Name == "None" || element.Name == "Content" || element.Name == "AndroidAsset")
                {
                    var linkElement = element.ChildNodes
                        .OfType<XmlNode>().FirstOrDefault(x => x.Name == "Link");
                    if (linkElement != null)
                    {
                        if (linkElement.InnerText.Trim().Replace('\\', '/').StartsWith("Content/", StringComparison.Ordinal))
                            continue;
                    }
                }

                // Ignore files included by include projects.
                if (element.ChildNodes.OfType<XmlNode>().Any(x => x.Name == "FromIncludeProject"))
                {
                    if (element.ChildNodes.OfType<XmlNode>().First(x => x.Name == "FromIncludeProject").InnerText.Trim() ==
                        "True")
                    {
                        continue;
                    }
                }

                // Ignore native binaries.
                if (element.Name == "None")
                {
                    if (element.ChildNodes.OfType<XmlNode>().Any(x => x.Name == "NativeBinary"))
                    {
                        continue;
                    }
                }

                var normalizedPath = this.NormalizePath(element.GetAttribute("Include"));

                // Ignore files that have already been added to the list.
                if (uniquePaths.Contains(normalizedPath))
                {
                    // Do not include again.
                    continue;
                }

                uniquePaths.Add(normalizedPath);

                // Change the path.
                element.SetAttribute("Include", normalizedPath);

                // Append the file element.
                files.AppendChild(document.ImportNode(element, true));
            }

            // Clean empty elements as well.
            var cleaned = this.WashNamespaces(document);
            foreach (var child in cleaned.ChildNodes.OfType<XmlElement>())
            {
                this.CleanNodes(child);
            }

            // Load into an XDocument to resort the list of elements by their Include.
            var xRoot = this.ToXDocument(cleaned);
            var xFiles = xRoot.Element(XName.Get("Project")).Element(XName.Get("Files"));
            var xOrderedNodes = xFiles.Elements()
                .OrderBy(x => x.Name.LocalName)
                .ThenBy(x => x.Attribute(XName.Get("Include")) == null ? "" : this.NormalizePath(x.Attribute(XName.Get("Include")).Value)).ToArray();
            xFiles.RemoveAll();
            foreach (var a in xOrderedNodes)
            {
                xFiles.Add(a);
            }
            cleaned = this.ToXmlDocument(xRoot);

            var settings = new XmlWriterSettings
            {
                Indent = true,
                IndentChars = "  ",
                NewLineChars = "\n",
                Encoding = Encoding.UTF8
            };
            using (var memory = new MemoryStream())
            {
                using (var writer = XmlWriter.Create(memory, settings))
                {
                    cleaned.Save(writer);
                }
                memory.Seek(0, SeekOrigin.Begin);
                var reader = new StreamReader(memory);
                var content = reader.ReadToEnd().Trim() + Environment.NewLine;
                using (var writer = new StreamWriter(this.m_DefinitionInfo.DefinitionPath, false, Encoding.UTF8))
                {
                    writer.Write(content);
                }
            }

            this.HandleNuGetConfig(platform);
        }
        public void Autopackage(
            FileFilter fileFilter,
            Execution execution,
            ModuleInfo module, 
            string rootPath,
            string platform,
            List<string> temporaryFiles)
        {
            var definitions = module.GetDefinitionsRecursively(platform).ToArray();
            var loadedProjects = new List<LoadedDefinitionInfo>();

            foreach (var definition in definitions)
            {
                Console.WriteLine("Loading: " + definition.Name);
                loadedProjects.Add(
                    this.m_ProjectLoader.Load(
                        platform,
                        module,
                        definition));
            }

            var serviceManager = new ServiceManager(platform);
            List<Service> services;

            serviceManager.SetRootDefinitions(module.GetDefinitions());

            var enabledServices = execution.EnabledServices.ToArray();
            var disabledServices = execution.DisabledServices.ToArray();

            foreach (var service in enabledServices)
            {
                serviceManager.EnableService(service);
            }

            foreach (var service in disabledServices)
            {
                serviceManager.DisableService(service);
            }

            if (execution.DebugServiceResolution)
            {
                serviceManager.EnableDebugInformation();
            }

            services = serviceManager.CalculateDependencyGraph(loadedProjects.Select(x => x.Project).ToList());

            foreach (var service in services)
            {
                if (service.ServiceName != null)
                {
                    Console.WriteLine("Enabled service: " + service.FullName);
                }
            }

            var packagePaths = module.Packages
                .Select(x => new DirectoryInfo(System.IO.Path.Combine(module.Path, x.Folder)).FullName)
                .ToArray();

            foreach (var definition in definitions)
            {
                if (definition.SkipAutopackage)
                {
                    Console.WriteLine("Skipping: " + definition.Name);
                    continue;
                }

                var definitionNormalizedPath = new FileInfo(definition.AbsolutePath).FullName;
                if (packagePaths.Any(definitionNormalizedPath.StartsWith))
                {
                    Console.WriteLine("Skipping: " + definition.Name + " (part of another package)");
                    continue;
                }

                switch (definition.Type)
                {
                    case "External":
                        Console.WriteLine("Packaging: " + definition.Name);
                        this.AutomaticallyPackageExternalProject(definitions, services, fileFilter, rootPath, platform, definition, temporaryFiles);
                        break;
                    case "Include":
                        Console.WriteLine("Packaging: " + definition.Name);
                        this.AutomaticallyPackageIncludeProject(definitions, services, fileFilter, rootPath, platform, definition);
                        break;
                    case "Content":
                        Console.WriteLine("Content project definition skipped: " + definition.Name);
                        break;
                    default:
                        Console.WriteLine("Packaging: " + definition.Name);
                        this.AutomaticallyPackageNormalProject(definitions, services, fileFilter, rootPath, platform, definition, temporaryFiles);
                        break;
                }
            }

            // If there is no Module.xml in the source mappings already, then copy the current module.
            var filterDictionary = fileFilter.ToDictionarySafe(
                k => k.Key,
                v => v.Value,
                (dict, d) => Console.WriteLine ("WARNING: More than one file maps to " + d.Key));
            if (!filterDictionary.ContainsValue("Build/Module.xml"))
            {
                fileFilter.AddManualMapping(Path.Combine(module.Path, "Build", "Module.xml"), "Build/Module.xml");
            }
        }
Exemplo n.º 5
0
        public override bool Execute()
        {
            if (string.Compare(Platform, "Web", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                // Trigger JSIL provider download if needed.
                string jsilDirectory, jsilCompilerFile;
                if (!m_JSILProvider.GetJSIL(out jsilDirectory, out jsilCompilerFile))
                {
                    return false;
                }
            }

            var module = ModuleInfo.Load(Path.Combine(RootPath, "Build", "Module.xml"));

            LogMessage(
                "Starting generation of projects for " + Platform);

            var definitions = module.GetDefinitionsRecursively(Platform).ToArray();
            var loadedProjects = new List<LoadedDefinitionInfo>();

            foreach (var definition in definitions)
            {
                LogMessage("Loading: " + definition.Name);
                loadedProjects.Add(
                    m_ProjectLoader.Load(
                        Platform,
                        module,
                        definition));
            }

            var serviceManager = new ServiceManager(Platform);
            List<Service> services;
            TemporaryServiceSpec serviceSpecPath;

            if (ServiceSpecPath == null)
            {
                serviceManager.SetRootDefinitions(module.GetDefinitions());

                if (EnableServices == null)
                {
                    EnableServices = new string[0];
                }

                if (DisableServices == null)
                {
                    DisableServices = new string[0];
                }

                foreach (var service in EnableServices)
                {
                    serviceManager.EnableService(service);
                }

                foreach (var service in DisableServices)
                {
                    serviceManager.DisableService(service);
                }

                if (DebugServiceResolution)
                {
                    serviceManager.EnableDebugInformation();
                }

                try
                {
                    services = serviceManager.CalculateDependencyGraph(loadedProjects.Select(x => x.Project).ToList());
                }
                catch (InvalidOperationException ex)
                {
                    Console.WriteLine("Error during service resolution: " + ex.Message);
                    return false;
                }

                serviceSpecPath = serviceManager.SaveServiceSpec(services);

                foreach (var service in services)
                {
                    if (service.ServiceName != null)
                    {
                        LogMessage("Enabled service: " + service.FullName);
                    }
                }
            }
            else
            {
                services = serviceManager.LoadServiceSpec(ServiceSpecPath);
                serviceSpecPath = new TemporaryServiceSpec(ServiceSpecPath, true);
            }

            using (serviceSpecPath)
            {
                // Run Protobuild in batch mode in each of the submodules
                // where it is present.
                foreach (var submodule in module.GetSubmodules(Platform))
                {
                    if (_featureManager.IsFeatureEnabledInSubmodule(module, submodule,
                        Feature.OptimizationSkipInvocationOnNoStandardProjects))
                    {
                        if (submodule.GetDefinitionsRecursively(Platform).All(x => !x.IsStandardProject))
                        {
                            // Do not invoke this submodule.
                            LogMessage(
                                "Skipping submodule generation for " + submodule.Name +
                                " (there are no projects to generate)");
                            continue;
                        }
                    }

                    LogMessage(
                        "Invoking submodule generation for " + submodule.Name);
                    var noResolve = _featureManager.IsFeatureEnabledInSubmodule(module, submodule,
                        Feature.PackageManagementNoResolve)
                        ? " -no-resolve"
                        : string.Empty;
                    var noHostPlatform = DisableHostPlatformGeneration &&
                                         _featureManager.IsFeatureEnabledInSubmodule(module, submodule,
                                             Feature.NoHostGenerate)
                        ? " -no-host-generate"
                        : string.Empty;
                    _moduleExecution.RunProtobuild(
                        submodule,
                        _featureManager.GetFeatureArgumentToPassToSubmodule(module, submodule) +
                        "-generate " + Platform +
                        " -spec " + serviceSpecPath +
                        " " + m_PackageRedirector.GetRedirectionArguments() +
                        noResolve + noHostPlatform);
                    LogMessage(
                        "Finished submodule generation for " + submodule.Name);
                }

                var repositoryPaths = new List<string>();

                foreach (var definition in definitions.Where(x => x.ModulePath == module.Path))
                {
                    if (definition.PostBuildHook && RequiresHostPlatform != null)
                    {
                        // We require the host platform projects at this point.
                        RequiresHostPlatform();
                    }

                    string repositoryPath;
                    var definitionCopy = definition;
                    m_ProjectGenerator.Generate(
                        definition,
                        loadedProjects,
                        RootPath,
                        definition.Name,
                        Platform,
                        services,
                        out repositoryPath,
                        () => LogMessage("Generating: " + definitionCopy.Name));

                    // Only add repository paths if they should be generated.
                    if (module.GenerateNuGetRepositories && !string.IsNullOrEmpty(repositoryPath))
                    {
                        repositoryPaths.Add(repositoryPath);
                    }
                }

                var solution = Path.Combine(
                    RootPath,
                    ModuleName + "." + Platform + ".sln");
                LogMessage("Generating: (solution)");
                m_SolutionGenerator.Generate(
                    module,
                    loadedProjects.Select(x => x.Project).ToList(),
                    Platform,
                    solution,
                    services,
                    repositoryPaths);

                // Only save the specification cache if we allow synchronisation
                if (module.DisableSynchronisation == null || !module.DisableSynchronisation.Value)
                {
                    var serviceCache = Path.Combine(RootPath, ModuleName + "." + Platform + ".speccache");
                    LogMessage("Saving service specification");
                    File.Copy(serviceSpecPath.Path, serviceCache, true);
                }

                LogMessage(
                    "Generation complete.");
            }

            return true;
        }