public void ItCanOverrideDefaultValues()
        {
            WorkloadManifest   manifest   = Create("WorkloadManifest.json");
            WorkloadDefinition definition = manifest.Workloads.FirstOrDefault().Value;

            ITaskItem[] resources = new ITaskItem[]
            {
                new TaskItem("microsoft-net-sdk-blazorwebassembly-aot", new Dictionary <string, string> {
                    { "Title", "AOT" },
                    { "Description", "A long wordy description." },
                    { "Category", "Compilers, build tools, and runtimes" }
                })
            };

            VisualStudioComponent component = VisualStudioComponent.Create(null, manifest, definition, "1.2.3.4", NoItems, resources, NoItems);

            string swixProjDirectory = RandomPath;

            Directory.CreateDirectory(swixProjDirectory);
            component.Generate(swixProjDirectory);

            string componentResSwr = File.ReadAllText(Path.Combine(swixProjDirectory, "component.res.swr"));

            Assert.Contains(@"title=""AOT""", componentResSwr);
            Assert.Contains(@"description=""A long wordy description.""", componentResSwr);
            Assert.Contains(@"category=""Compilers, build tools, and runtimes""", componentResSwr);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Extracts the workload manifest from the manifest package and generate a SWIX project for a Visual Studio component
        /// matching the manifests dependencies.
        /// </summary>
        /// <param name="workloadManifestPackage">The path of the workload package containing the manifest.</param>
        /// <returns>A set of items containing the generated SWIX projects.</returns>
        internal IEnumerable <ITaskItem> ProcessWorkloadManifest(string workloadManifestPackage)
        {
            NugetPackage workloadPackage = new(workloadManifestPackage, Log);

            string packageContentPath = Path.Combine(PackageDirectory, $"{workloadPackage.Identity}");

            workloadPackage.Extract(packageContentPath, Enumerable.Empty <string>());
            string workloadManifestJsonPath = Directory.GetFiles(packageContentPath, "WorkloadManifest.json").FirstOrDefault();

            if (string.IsNullOrWhiteSpace(workloadManifestJsonPath))
            {
                throw new FileNotFoundException($"Unable to locate WorkloadManifest.json under '{packageContentPath}'.");
            }

            WorkloadManifest manifest = WorkloadManifestReader.ReadWorkloadManifest(File.OpenRead(workloadManifestJsonPath));

            List <TaskItem> swixProjects = new();

            foreach (WorkloadDefinition workloadDefinition in manifest.Workloads.Values)
            {
                VisualStudioComponent component = VisualStudioComponent.Create(manifest, workloadDefinition);
                swixProjects.Add(component.Generate(Path.Combine(SourceDirectory, $"{workloadDefinition.Id}.{manifest.Version}.0")));
            }

            return(swixProjects);
        }
Ejemplo n.º 3
0
        internal IEnumerable <ITaskItem> ProcessWorkloadManifestFile(string workloadManifestJsonPath)
        {
            WorkloadManifest manifest = WorkloadManifestReader.ReadWorkloadManifest(Path.GetFileNameWithoutExtension(workloadManifestJsonPath), File.OpenRead(workloadManifestJsonPath));

            List <TaskItem> swixProjects = new();

            foreach (WorkloadDefinition workloadDefinition in manifest.Workloads.Values)
            {
                if ((workloadDefinition.Platforms?.Count > 0) && (!workloadDefinition.Platforms.Any(p => p.StartsWith("win"))))
                {
                    Log?.LogMessage(MessageImportance.High, $"{workloadDefinition.Id} platforms does not support Windows and will be skipped ({string.Join(", ", workloadDefinition.Platforms)}).");
                    continue;
                }

                // Each workload maps to a Visual Studio component.
                VisualStudioComponent component = VisualStudioComponent.Create(Log, manifest, workloadDefinition,
                                                                               ComponentVersions, ShortNames, ComponentResources, MissingPacks);

                // If there are no dependencies, regardless of whether we are generating MSIs, we'll report an
                // error as we'd produce invalid SWIX.
                if (!component.HasDependencies)
                {
                    Log?.LogError($"Visual Studio components '{component.Name}' must have at least one dependency.");
                }

                string vsPayloadRelativePath = $"{component.Name},version={component.Version}\\_package.json";
                CheckRelativePayloadPath(vsPayloadRelativePath);

                swixProjects.Add(component.Generate(Path.Combine(SourceDirectory, $"{workloadDefinition.Id}.{manifest.Version}.0")));
            }

            return(swixProjects);
        }
Ejemplo n.º 4
0
        public IReadOnlyCollection <IOptionalSdkTemplatePackageInfo> GetDotnetSdkTemplatePackages(
            string sdkVersion,
            string dotnetRootPath)
        {
            if (string.IsNullOrWhiteSpace(sdkVersion))
            {
                throw new ArgumentException($"'{nameof(sdkVersion)}' cannot be null or whitespace", nameof(sdkVersion));
            }

            if (string.IsNullOrWhiteSpace(dotnetRootPath))
            {
                throw new ArgumentException($"'{nameof(dotnetRootPath)}' cannot be null or whitespace", nameof(dotnetRootPath));
            }

            if (!Version.TryParse(sdkVersion.Split('-')[0], out var sdkVersionParsed))
            {
                throw new ArgumentException($"'{nameof(sdkVersion)}' should be a version, but get {sdkVersion}");
            }

            bool FindSameVersionBand(DirectoryInfo manifestDirectory)
            {
                var directoryVersion = Version.Parse(manifestDirectory.Name);

                return(directoryVersion.Major == sdkVersionParsed.Major &&
                       directoryVersion.Minor == sdkVersionParsed.Minor &&
                       (directoryVersion.Revision / 100) == (sdkVersionParsed.Revision / 100));
            }

            var bondManifestDirectory = new DirectoryInfo(Path.Combine(dotnetRootPath, "workloadmanifests")).GetDirectories().Where(FindSameVersionBand)
                                        .OrderByDescending(d => Version.Parse(d.Name)).FirstOrDefault();

            if (bondManifestDirectory == null)
            {
                return(Array.Empty <IOptionalSdkTemplatePackageInfo>());
            }

            var manifestContent =
                WorkloadManifest.LoadFromFolder(bondManifestDirectory.FullName);
            var dotnetSdkTemplatePackages = new List <IOptionalSdkTemplatePackageInfo>();

            foreach (var pack in manifestContent.SdkPackDetail)
            {
                if (pack.Value.kind.Equals("Template", StringComparison.OrdinalIgnoreCase))
                {
                    var optionalSdkTemplatePackageInfo = new OptionalSdkTemplatePackageInfo(
                        pack.Key,
                        pack.Value.version,
                        Path.Combine(dotnetRootPath, "template-packs",
                                     pack.Key.ToLower() + "." + pack.Value.version.ToLower() + ".nupkg"));
                    dotnetSdkTemplatePackages.Add(optionalSdkTemplatePackageInfo);
                }
            }

            return(dotnetSdkTemplatePackages);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Creates a <see cref="VisualStudioComponent"/> using a workload definition.
        /// </summary>
        /// <param name="manifest"></param>
        /// <param name="workload"></param>
        /// <param name="componentVersions"></param>
        /// <param name="shortNames"></param>
        /// <param name="shortNameMetadata"></param>
        /// <param name="componentResources"></param>
        /// <returns></returns>
        public static VisualStudioComponent Create(TaskLoggingHelper log, WorkloadManifest manifest, WorkloadDefinition workload, ITaskItem[] componentVersions,
                                                   ITaskItem[] shortNames, ITaskItem[] componentResources, ITaskItem[] missingPacks)
        {
            log?.LogMessage("Creating Visual Studio component");
            string workloadId = $"{workload.Id}";

            // If there's an explicit version mapping we use that, otherwise we fall back to the manifest version
            // and normalize it since it can have semantic information and Visual Studio components do not support that.
            ITaskItem versionItem = componentVersions?.Where(v => string.Equals(v.ItemSpec, workloadId, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
            Version   version     = (versionItem != null) && !string.IsNullOrWhiteSpace(versionItem.GetMetadata(Metadata.Version))
                ? new Version(versionItem.GetMetadata(Metadata.Version))
                : (new NuGetVersion(manifest.Version)).Version;

            ITaskItem resourceItem = componentResources?.Where(
                r => string.Equals(r.ItemSpec, workloadId, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

            // Workload definitions do not have separate title/description fields so the only option
            // is to default to the workload description for both.
            string title       = resourceItem?.GetMetadata(Metadata.Title) ?? workload.Description;
            string description = resourceItem?.GetMetadata(Metadata.Description) ?? workload.Description;
            string category    = resourceItem?.GetMetadata(Metadata.Category) ?? ".NET";
            string isUiGroup   = workload.IsAbstract ? "yes" : "no";

            VisualStudioComponent component = new(Utils.ToSafeId(workloadId), description,
                                                  title, version, isUiGroup, shortNames, category);

            IEnumerable <string> missingPackIds = missingPacks.Select(p => p.ItemSpec);

            log?.LogMessage(MessageImportance.Low, $"Missing packs: {string.Join(", ", missingPackIds)}");

            // If the work extends other workloads, we add those as component dependencies before
            // processing direct pack dependencies
            if (workload.Extends?.Count() > 0)
            {
                foreach (WorkloadDefinitionId dependency in workload.Extends)
                {
                    // Component dependencies, aka. workload extensions only have minimum version dependencies.
                    component.AddDependency($"{Utils.ToSafeId(dependency.ToString())}", new Version("1.0.0.0"), maxVersion: null);
                }
            }

            // Visual Studio is case-insensitive.
            IEnumerable <WorkloadPackId> packIds = workload.Packs.Where(p => !missingPackIds.Contains($"{p}", StringComparer.OrdinalIgnoreCase));

            log?.LogMessage(MessageImportance.Low, $"Packs: {string.Join(", ", packIds.Select(p=>$"{p}"))}");

            foreach (WorkloadPackId packId in packIds)
            {
                log?.LogMessage(MessageImportance.Low, $"Adding component dependency for {packId} ");
                component.AddDependency(manifest.Packs[packId]);
            }

            return(component);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Creates a <see cref="VisualStudioComponent"/> using a workload definition.
        /// </summary>
        /// <param name="Definition"></param>
        /// <param name="packs"></param>
        /// <returns></returns>
        public static VisualStudioComponent Create(WorkloadManifest manifest, WorkloadDefinition definition)
        {
            VisualStudioComponent package = new(Utils.ToSafeId(definition.Id.ToString()), definition.Description,
                                                definition.Description, new Version($"{manifest.Version}.0"));

            foreach (WorkloadPackId packId in definition.Packs)
            {
                package.AddDependency(manifest.Packs[packId]);
            }

            return(package);
        }
        public void ItCreatesSafeComponentIds()
        {
            WorkloadManifest      manifest   = Create("WorkloadManifest.json");
            WorkloadDefinition    definition = manifest.Workloads.FirstOrDefault().Value;
            VisualStudioComponent component  = VisualStudioComponent.Create(null, manifest, definition, "1.2.3.4", NoItems, NoItems, NoItems);

            string swixProjDirectory = RandomPath;

            Directory.CreateDirectory(swixProjDirectory);
            component.Generate(swixProjDirectory);

            string componentSwr = File.ReadAllText(Path.Combine(swixProjDirectory, "component.swr"));

            Assert.Contains(@"microsoft.net.sdk.blazorwebassembly.aot", componentSwr);
        }
Ejemplo n.º 8
0
        public void ItCreatesComponentsWhenWorkloadsDoNotIncludePacks()
        {
            WorkloadManifest      manifest   = Create("mauiWorkloadManifest.json");
            WorkloadDefinition    definition = (WorkloadDefinition)manifest.Workloads.FirstOrDefault().Value;
            VisualStudioComponent component  = VisualStudioComponent.Create(null, manifest, definition, NoItems, NoItems, NoItems, NoItems);

            string swixProjDirectory = RandomPath;

            Directory.CreateDirectory(swixProjDirectory);
            component.Generate(swixProjDirectory);

            string componentSwr = File.ReadAllText(Path.Combine(swixProjDirectory, "component.swr"));

            Assert.Contains(@"vs.dependency id=maui.mobile", componentSwr);
            Assert.Contains(@"vs.dependency id=maui.desktop", componentSwr);
        }
        public void ItAssignsDefaultValues()
        {
            WorkloadManifest      manifest   = Create("WorkloadManifest.json");
            WorkloadDefinition    definition = manifest.Workloads.FirstOrDefault().Value;
            VisualStudioComponent component  = VisualStudioComponent.Create(null, manifest, definition, "1.2.3.4", NoItems, NoItems, NoItems);

            string swixProjDirectory = RandomPath;

            Directory.CreateDirectory(swixProjDirectory);
            component.Generate(swixProjDirectory);

            string componentResSwr = File.ReadAllText(Path.Combine(swixProjDirectory, "component.res.swr"));

            Assert.Contains(@"title=""Blazor WebAssembly AOT workload""", componentResSwr);
            Assert.Contains(@"description=""Blazor WebAssembly AOT workload""", componentResSwr);
            Assert.Contains(@"category="".NET""", componentResSwr);
        }
        internal IEnumerable <ITaskItem> ProcessWorkloadManifestFile(string workloadManifestJsonPath)
        {
            WorkloadManifest manifest = WorkloadManifestReader.ReadWorkloadManifest(Path.GetFileNameWithoutExtension(workloadManifestJsonPath), File.OpenRead(workloadManifestJsonPath));

            List <TaskItem> swixProjects = new();

            foreach (WorkloadDefinition workloadDefinition in manifest.Workloads.Values)
            {
                // Each workload maps to a Visual Studio component.
                VisualStudioComponent component = VisualStudioComponent.Create(Log, manifest, workloadDefinition,
                                                                               ComponentVersion, ShortNames, ComponentResources, MissingPacks);

                // If there are no dependencies, regardless of whether we are generating MSIs, we'll report an
                // error as we'd produce invalid SWIX.
                if (!component.HasDependencies)
                {
                    Log?.LogError($"Visual Studio components '{component.Name}' must have at least one dependency.");
                }

                swixProjects.Add(component.Generate(Path.Combine(SourceDirectory, $"{workloadDefinition.Id}.{manifest.Version}.0")));
            }

            return(swixProjects);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Creates a <see cref="VisualStudioComponent"/> using a workload definition.
        /// </summary>
        /// <param name="manifest"></param>
        /// <param name="workload"></param>
        /// <param name="componentVersion"></param>
        /// <param name="shortNames"></param>
        /// <param name="shortNameMetadata"></param>
        /// <param name="componentResources"></param>
        /// <returns></returns>
        public static VisualStudioComponent Create(TaskLoggingHelper log, WorkloadManifest manifest, WorkloadDefinition workload, string componentVersion,
                                                   ITaskItem[] shortNames, ITaskItem[] componentResources, ITaskItem[] missingPacks)
        {
            log?.LogMessage("Creating Visual Studio component");
            Version version = string.IsNullOrWhiteSpace(componentVersion) ? new Version($"{manifest.Version}.0") :
                              new Version(componentVersion);

            ITaskItem resourceItem = componentResources?.Where(
                r => string.Equals(r.ItemSpec, workload.Id.ToString(), StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

            // Workload definitions do not have separate title/description fields so the only option
            // is to default to the workload description for both.
            string title       = resourceItem?.GetMetadata(Metadata.Title) ?? workload.Description;
            string description = resourceItem?.GetMetadata(Metadata.Description) ?? workload.Description;
            string category    = resourceItem?.GetMetadata(Metadata.Category) ?? ".NET";

            VisualStudioComponent component = new(Utils.ToSafeId(workload.Id.ToString()), description,
                                                  title, version, shortNames, category);

            IEnumerable <string> missingPackIds = missingPacks.Select(p => p.ItemSpec);

            log?.LogMessage(MessageImportance.Low, $"Missing packs: {string.Join(", ", missingPackIds)}");

            // Visual Studio is case-insensitive.
            IEnumerable <WorkloadPackId> packIds = workload.Packs.Where(p => !missingPackIds.Contains($"{p}", StringComparer.OrdinalIgnoreCase));

            log?.LogMessage(MessageImportance.Low, $"Packs: {string.Join(", ", packIds.Select(p=>$"{p}"))}");

            foreach (WorkloadPackId packId in packIds)
            {
                log?.LogMessage(MessageImportance.Low, $"Adding component dependency for {packId} ");
                component.AddDependency(manifest.Packs[packId]);
            }

            return(component);
        }
        public override bool Execute()
        {
            try
            {
                Directory.CreateDirectory(Path.GetDirectoryName(ProjectFile));

                List <string> packs = new();

                var excludedPackIds = ExcludedPackIds.Select(i => i.ItemSpec);

                XmlWriterSettings settings = new XmlWriterSettings
                {
                    Indent      = true,
                    IndentChars = "  "
                };

                XmlWriter writer = XmlWriter.Create(ProjectFile, settings);

                writer.WriteStartElement("Project");
                writer.WriteAttributeString("Sdk", "Microsoft.NET.Sdk");

                writer.WriteStartElement("PropertyGroup");
                writer.WriteElementString("TargetFramework", "net6.0");
                writer.WriteElementString("IncludeBuildOutput", "false");
                writer.WriteEndElement();

                writer.WriteStartElement("ItemGroup");

                foreach (var manifestFile in ManifestFiles)
                {
                    WorkloadManifest manifest = WorkloadManifestReader.ReadWorkloadManifest(
                        Path.GetFileNameWithoutExtension(manifestFile.ItemSpec), File.OpenRead(manifestFile.ItemSpec), manifestFile.ItemSpec);

                    foreach (var pack in manifest.Packs.Values)
                    {
                        if (pack.IsAlias)
                        {
                            foreach (var alias in pack.AliasTo.Keys.Where(k => k.StartsWith("win")))
                            {
                                if (!excludedPackIds.Contains($"{pack.AliasTo[alias]}"))
                                {
                                    WriteItem(writer, "PackageDownload", ("Include", $"{pack.AliasTo[alias]}"), ("Version", $"[{pack.Version}]"));
                                    packs.Add($"$(NuGetPackageRoot){pack.AliasTo[alias]}\\{pack.Version}\\*.nupkg");
                                }
                            }
                        }
                        else if (!excludedPackIds.Contains($"{pack.Id}"))
                        {
                            WriteItem(writer, "PackageDownload", ("Include", $"{pack.Id}"), ("Version", $"[{pack.Version}]"));
                            packs.Add($"$(NuGetPackageRoot){pack.Id}\\{pack.Version}\\*.nupkg");
                        }
                    }
                }

                writer.WriteEndElement();

                writer.WriteStartElement("Target");
                writer.WriteAttributeString("Name", "CopyPacks");
                writer.WriteAttributeString("AfterTargets", "Build");

                writer.WriteStartElement("ItemGroup");

                foreach (var pack in packs)
                {
                    WriteItem(writer, "Pack", ("Include", pack));
                }

                writer.WriteEndElement();

                writer.WriteStartElement("Copy");
                writer.WriteAttributeString("SourceFiles", "@(Pack)");
                writer.WriteAttributeString("DestinationFolder", $"{PackageSource}");
                writer.WriteEndElement();

                writer.WriteEndElement();

                writer.WriteEndElement();
                writer.Flush();
                writer.Close();
            }
            catch (Exception e)
            {
                Log.LogErrorFromException(e);
            }

            return(!Log.HasLoggedErrors);
        }