Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workloads: Tooling changes to MSI and SWIX generation #7525

Merged
merged 1 commit into from
Jun 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public void ItGeneratesASwixProjectFromAWorkloadManifestPackage()
}

[Fact]
public void ItSkipsAbstractManifests()
public void ItIncludesAbstractManifests()
{
var buildTask = new GenerateVisualStudioWorkload()
{
Expand All @@ -132,11 +132,14 @@ public void ItSkipsAbstractManifests()
};

Assert.True(buildTask.Execute());
string outputPath = Path.GetDirectoryName(buildTask.SwixProjects[0].GetMetadata("FullPath"));
string componentSwr = File.ReadAllText(Path.Combine(outputPath, "component.swr"));
Assert.Single(buildTask.SwixProjects);
string blazorOutputPath = Path.GetDirectoryName(buildTask.SwixProjects[0].GetMetadata("FullPath"));
string blazorComponentSwr = File.ReadAllText(Path.Combine(blazorOutputPath, "component.swr"));
Assert.Contains(@"package name=microsoft.net.sdk.blazorwebassembly.aot
version=6.0.0.0", componentSwr);
version=6.0.0.0", blazorComponentSwr);
string androidOutputPath = Path.GetDirectoryName(buildTask.SwixProjects[1].GetMetadata("FullPath"));
string androidComponentSwr = File.ReadAllText(Path.Combine(androidOutputPath, "component.swr"));
Assert.Contains(@"package name=microsoft.net.runtime.android
version=6.0.0.0", androidComponentSwr);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace Microsoft.DotNet.Build.Tasks.Workloads.Tests
{
public class VisualStudioDependencyTests
{
[Theory]
[InlineData("1.0.0", null, "[1.0.0,)")]
[InlineData("1.0.0", "2.0.0", "[1.0.0,2.0.0)")]
[InlineData("1.0.0", "1.0.0", "[1.0.0]")]
public void ItGeneratesVersionRanges(string minVersion, string maxVersion, string expectedVersionRange)
{
Version v1 = string.IsNullOrWhiteSpace(minVersion) ? null : new Version(minVersion);
Version v2 = string.IsNullOrWhiteSpace(maxVersion) ? null : new Version(maxVersion);

VisualStudioDependency dep = new VisualStudioDependency("foo", v1, v2);

Assert.Equal(expectedVersionRange, dep.GetVersion());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ protected IEnumerable<ITaskItem> Generate(string sourcePackage, string swixPacka
MsiProperties msiProps = new MsiProperties
{
InstallSize = MsiUtils.GetInstallSize(msiPath),
Payload = Path.GetFileName(msiPath),
ProductCode = MsiUtils.GetProperty(msiPath, "ProductCode"),
ProductVersion = MsiUtils.GetProperty(msiPath, "ProductVersion"),
ProviderKeyName = $"{nupkg.Id},{nupkg.Version},{platform}",
Expand Down Expand Up @@ -330,7 +331,7 @@ private string GeneratePackageProject(string msiPath, string msiJsonPath, string

writer.WriteStartElement("ItemGroup");
WriteItem(writer, "None", msiPath, @"\data");
WriteItem(writer, "None", msiJsonPath, @"\data");
WriteItem(writer, "None", msiJsonPath, @"\data\msi.json");
WriteItem(writer, "None", licenseTextPath, @"\");
writer.WriteEndElement();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,14 +222,6 @@ internal IEnumerable<ITaskItem> ProcessWorkloadManifestFile(string workloadManif

foreach (WorkloadDefinition workloadDefinition in manifest.Workloads.Values)
{
// Abstract workloads can only be extended, so we can't generate items for this yet. Might need to do a second pass
// if there are other manifests that extend the workload.
if (workloadDefinition.IsAbstract)
{
Log?.LogMessage(MessageImportance.High, $"{workloadDefinition.Id} is abstract and will be skipped.");
continue;
}

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)}).");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ public long InstallSize
set;
}

public string Payload
{
get;
set;
}

public string ProductCode
{
get;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,10 @@
<OutputLocalized>false</OutputLocalized>
<OutputType>manifest</OutputType>
<OutputPath>$(ManifestOutputPath)</OutputPath>

<!-- Default to no, making this a component group. -->
<IsUIGroup Condition="'$(IsUIGroup)'==''">no</IsUIGroup>
</PropertyGroup>

<PropertyGroup>
<PackagePreprocessorDefinitions>$(PackagePreprocessorDefinitions);IsUIGroup=$(IsUIGroup)</PackagePreprocessorDefinitions>
<PackagePreprocessorDefinitions>$(PackagePreprocessorDefinitions)</PackagePreprocessorDefinitions>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ package name=__VS_PACKAGE_NAME__
vs.package.type=component

vs.properties
isUiGroup=$(IsUIGroup)
isUiGroup=__VS_IS_UI_GROUP__

vs.dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ public string Description
/// </summary>
public bool HasDependencies => Dependencies.Count > 0;

/// <summary>
/// When "no", the component is visible in both the workloads and individual components tab.
/// When "yes", the component is only visible in the workloads tab.
/// </summary>
public string IsUiGroup
{
get;
} = "no";

/// <summary>
/// The component name (ID).
/// </summary>
Expand Down Expand Up @@ -74,7 +83,7 @@ public Version Version

private ICollection<VisualStudioDependency> Dependencies = new List<VisualStudioDependency>();

public VisualStudioComponent(string name, string description, string title, Version version, ITaskItem[] shortNames,
public VisualStudioComponent(string name, string description, string title, Version version, string isUiGroup, ITaskItem[] shortNames,
string category)
{
Name = name;
Expand All @@ -83,16 +92,27 @@ public VisualStudioComponent(string name, string description, string title, Vers
Version = version;
ShortNames = shortNames;
Category = category;
IsUiGroup = isUiGroup;
}

/// <summary>
/// Add a component dependency using the provided name and version.
/// </summary>
/// <param name="name">The name (ID) of the dependency.</param>
/// <param name="exactVersion">The version of the dependency.</param>
public void AddDependency(string name, Version exactVersion)
{
AddDependency(new VisualStudioDependency(name, exactVersion, exactVersion));
}

/// <summary>
/// Add a component dependency using the provided name and version.
/// </summary>
/// <param name="name">The name (ID) of the dependency.</param>
/// <param name="version">The version of the dependency.</param>
public void AddDependency(string name, Version version)
public void AddDependency(string name, Version minVersion, Version maxVersion)
{
AddDependency(new VisualStudioDependency(name, version));
AddDependency(new VisualStudioDependency(name, minVersion, maxVersion));
}

/// <summary>
Expand All @@ -119,7 +139,7 @@ public void AddDependency(ITaskItem dependency)
/// <param name="pack">The dependency to add to this component.</param>
public void AddDependency(WorkloadPack pack)
{
AddDependency($"{pack.Id.ToString().Replace(ShortNames)}.{pack.Version}", new NuGetVersion(pack.Version).Version);
AddDependency($"{pack.Id.ToString().Replace(ShortNames)}.{pack.Version}", new NuGetVersion(pack.Version).Version, maxVersion: null);
}

public IEnumerable<VisualStudioDependency> GetAliasedDependencies(WorkloadPack pack)
Expand Down Expand Up @@ -164,7 +184,7 @@ public TaskItem Generate(string projectPath)
// version=[1.2.3.4]

swrWriter.WriteLine($" vs.dependency id={dependency.Id}");
swrWriter.WriteLine($" version=[{dependency.Version}]");
swrWriter.WriteLine($" version={dependency.GetVersion()}");
swrWriter.WriteLine($" behaviors=IgnoreApplicabilityFailures");
}

Expand All @@ -179,7 +199,8 @@ private Dictionary<string, string> GetReplacementTokens()
{"__VS_PACKAGE_VERSION__", Version.ToString() },
{"__VS_COMPONENT_TITLE__", Title },
{"__VS_COMPONENT_DESCRIPTION__", Description },
{"__VS_COMPONENT_CATEGORY__", Category ?? ".NET" }
{"__VS_COMPONENT_CATEGORY__", Category ?? ".NET" },
{"__VS_IS_UI_GROUP__", IsUiGroup ?? "no" }
};
}

Expand Down Expand Up @@ -214,13 +235,25 @@ public static VisualStudioComponent Create(TaskLoggingHelper log, WorkloadManife
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, shortNames, category);
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}"))}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,53 @@ public string Id
get;
}

/// <summary>
/// The version of the dependent.
/// </summary>
public Version Version
public Version MinVersion
{
get;
}

public VisualStudioDependency(string id, Version version)
public Version MaxVersion
{
get;
}

/// <summary>
/// Creates a dependency with an exact version.
/// </summary>
/// <param name="id"></param>
/// <param name="version"></param>
public VisualStudioDependency(string id, Version version) : this(id, version, version)
{

}

/// <summary>
/// Creates a dependency with a minimum and maximum versions.
/// </summary>
/// <param name="id">The Visual Studio package ID. The ID applies to packages, components, component groups, etc.</param>
/// <param name="minVersion">The minimum required version, inclusive.</param>
/// <param name="maxVersion">The maximum version, exclusive. May be <see langword="null"/> if there is only a minimum requirement. If
/// equal to <paramref name="minVersion"/>, an exact version requirement is created, e.g. [1.2.0].</param>
public VisualStudioDependency(string id, Version minVersion, Version maxVersion)
{
Id = id;
Version = version;
MinVersion = minVersion;
MaxVersion = maxVersion;
}

public string GetVersion()
{
if ((MaxVersion != null) && (MinVersion == MaxVersion))
{
return $"[{MinVersion}]";
}

if (MaxVersion == null)
{
return $"[{MinVersion},)";
}

return $"[{MinVersion},{MaxVersion})";
}
}
}