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

[msbuild] Several updates to the ScnTool task. #19976

Merged
merged 4 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
146 changes: 56 additions & 90 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/ScnToolTaskBase.cs
Original file line number Diff line number Diff line change
@@ -1,147 +1,113 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;

using Xamarin.Messaging.Build.Client;
using Xamarin.Utils;

// Disable until we get around to enable + fix any issues.
#nullable disable

namespace Xamarin.MacDev.Tasks {
public class ScnTool : XamarinToolTask {
string sdkDevPath;

public class ScnTool : XamarinTask {
#region Inputs

[Required]
public string IntermediateOutputPath { get; set; }
public string IntermediateOutputPath { get; set; } = string.Empty;

[Required]
public string InputScene { get; set; }
public ITaskItem [] ColladaAssets { get; set; } = Array.Empty<ITaskItem> ();

[Required]
public string DeviceSpecificIntermediateOutputPath { get; set; } = string.Empty;

public bool IsWatchApp { get; set; }

[Required]
public string OutputScene { get; set; }
public string ProjectDir { get; set; } = string.Empty;

[Required]
public string SdkPlatform { get; set; }
public string ResourcePrefix { get; set; } = string.Empty;

[Required]
public string SdkRoot { get; set; }
public string SdkPlatform { get; set; } = string.Empty;

[Required]
public string SdkVersion { get; set; }
public string SdkRoot { get; set; } = string.Empty;

[Required]
public string SdkDevPath {
get { return sdkDevPath; }
set {
sdkDevPath = value;
public string SdkVersion { get; set; } = string.Empty;

SetEnvironmentVariable ("DEVELOPER_DIR", sdkDevPath);
}
}
[Required]
public string SdkDevPath { get; set; } = string.Empty;

#endregion

string DevicePlatformBinDir {
get { return Path.Combine (SdkDevPath, "usr", "bin"); }
}

protected virtual string OperatingSystem {
get {
return PlatformFrameworkHelper.GetOperatingSystem (TargetFrameworkMoniker);
}
}

protected override string ToolName {
get { return "scntool"; }
}

void SetEnvironmentVariable (string variableName, string value)
{
var envVariables = EnvironmentVariables;
var index = -1;

if (envVariables is null) {
envVariables = new string [1];
index = 0;
} else {
for (int i = 0; i < envVariables.Length; i++) {
if (envVariables [i].StartsWith (variableName + "=", StringComparison.Ordinal)) {
index = i;
break;
}
}

if (index < 0) {
Array.Resize<string> (ref envVariables, envVariables.Length + 1);
index = envVariables.Length - 1;
}
}

envVariables [index] = string.Format ("{0}={1}", variableName, value);

EnvironmentVariables = envVariables;
}

protected override string GenerateFullPathToTool ()
{
if (!string.IsNullOrEmpty (ToolPath))
return Path.Combine (ToolPath, ToolExe);

var path = Path.Combine (DevicePlatformBinDir, ToolExe);

return File.Exists (path) ? path : ToolExe;
}
#region Outputs
[Output]
public ITaskItem [] BundleResources { get; set; } = Array.Empty<ITaskItem> ();
#endregion

protected override string GenerateCommandLineCommands ()
IList<string> GenerateCommandLineCommands (string inputScene, string outputScene)
{
var args = new CommandLineArgumentBuilder ();
var args = new List<string> ();

args.Add ("scntool");
args.Add ("--compress");
args.AddQuoted (InputScene);
args.Add (inputScene);
args.Add ("-o");
args.AddQuoted (OutputScene);
args.AddQuotedFormat ("--sdk-root={0}", SdkRoot);
args.AddQuotedFormat ("--target-build-dir={0}", IntermediateOutputPath);
args.Add (outputScene);
args.Add ($"--sdk-root={SdkRoot}");
args.Add ($"--target-build-dir={IntermediateOutputPath}");
if (AppleSdkSettings.XcodeVersion.Major >= 13) {
// I'm not sure which Xcode version these options are available in, but it's at least Xcode 13+
args.AddQuotedFormat ("--target-version={0}", SdkVersion);
args.AddQuotedFormat ("--target-platform={0}", PlatformUtils.GetTargetPlatform (SdkPlatform, IsWatchApp));
args.Add ($"--target-version={SdkVersion}");
args.Add ($"--target-platform={PlatformUtils.GetTargetPlatform (SdkPlatform, IsWatchApp)}");
} else {
args.AddQuotedFormat ("--target-version-{0}={1}", OperatingSystem, SdkVersion);
args.Add ($"--target-version-{PlatformFrameworkHelper.GetOperatingSystem (TargetFrameworkMoniker)}={SdkVersion}");
}

return args.ToString ();
}

protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance)
{
// TODO: do proper parsing of error messages and such
Log.LogMessage (messageImportance, "{0}", singleLine);
return args;
}

public override bool Execute ()
{
if (ShouldExecuteRemotely ())
return new TaskRunner (SessionId, BuildEngine4).RunAsync (this).Result;

Directory.CreateDirectory (Path.GetDirectoryName (OutputScene));
var prefixes = BundleResource.SplitResourcePrefixes (ResourcePrefix);
var listOfArguments = new List<(IList<string> Arguments, ITaskItem Input)> ();
var bundleResources = new List<ITaskItem> ();
foreach (var asset in ColladaAssets) {
var inputScene = asset.ItemSpec;
var logicalName = BundleResource.GetLogicalName (ProjectDir, prefixes, asset, !string.IsNullOrEmpty (SessionId));
var outputScene = Path.Combine (DeviceSpecificIntermediateOutputPath, logicalName);
var args = GenerateCommandLineCommands (inputScene, outputScene);
listOfArguments.Add (new (args, asset));

Directory.CreateDirectory (Path.GetDirectoryName (outputScene));

var bundleResource = new TaskItem (outputScene);
asset.CopyMetadataTo (bundleResource);
bundleResource.SetMetadata ("Optimize", "false");
bundleResource.SetMetadata ("LogicalName", logicalName);
bundleResources.Add (bundleResource);
}

Parallel.ForEach (listOfArguments, (arg) => {
ExecuteAsync ("xcrun", arg.Arguments, sdkDevPath: SdkDevPath).Wait ();
});

return base.Execute ();
BundleResources = bundleResources.ToArray ();

return !Log.HasLoggedErrors;
}

public override void Cancel ()
public void Cancel ()
{
if (ShouldExecuteRemotely ())
BuildConnection.CancelAsync (BuildEngine4).Wait ();

base.Execute ();
}
}
}
62 changes: 39 additions & 23 deletions msbuild/Xamarin.Shared/Xamarin.Shared.targets
Original file line number Diff line number Diff line change
Expand Up @@ -1021,9 +1021,11 @@ Copyright (C) 2018 Microsoft. All rights reserved.

<PropertyGroup>
<CompileColladaAssetsDependsOn>
$(CompileColladaAssetsDependsOn);
_RemoveProcessedColladaAssets;
_CollectColladaAssets;
_CoreCompileColladaAssets
_BeforeCoreCompileColladaAssets;
_ReadCoreCompileColladaAssets;
_CoreCompileColladaAssets;
</CompileColladaAssetsDependsOn>
</PropertyGroup>

Expand All @@ -1042,46 +1044,57 @@ Copyright (C) 2018 Microsoft. All rights reserved.
</ItemGroup>
</Target>

<Target Name="_CollectColladaAssets">
<CollectBundleResources
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true'"
BundleResources="@(Collada)"
ProjectDir="$(MSBuildProjectDirectory)"
ResourcePrefix="$(_ResourcePrefix)">
<Output TaskParameter="BundleResourcesWithLogicalNames" ItemName="_ColladaAssetWithLogicalName" />
</CollectBundleResources>
<Target Name="_BeforeCoreCompileColladaAssets"
Inputs="@(Collada)"
Outputs="$(_ColladaCache)">

<!-- If any Collada asset is newer than the generated items list, we delete them so that the _CoreCompileCollada
target runs again and updates those lists for the next run
-->
<Delete Files="$(_ColladaCache)" />
</Target>

<Target Name="_ReadCoreCompileColladaAssets"
DependsOnTargets="_BeforeCoreCompileColladaAssets">

<!-- If _BeforeCoreCompileColladaAssets did not delete the generated items lists from _CoreCompileColladaAssets, then we read them
since that target won't run and we need to the output items that are cached in those files which includes full metadata -->
<ReadItemsFromFile File="$(_ColladaCache)" Condition="Exists('$(_ColladaCache)')">
<Output TaskParameter="Items" ItemName="_BundleResourceWithLogicalName" />
</ReadItemsFromFile>
</Target>

<Target Name="_CoreCompileColladaAssets"
DependsOnTargets="_CollectColladaAssets;_DetectSdkLocations;_ComputeTargetFrameworkMoniker"
Inputs="@(_ColladaAssetWithLogicalName)"
Outputs="$(DeviceSpecificIntermediateOutputPath)%(_ColladaAssetWithLogicalName.LogicalName)"
DependsOnTargets="_BeforeCoreCompileColladaAssets;_DetectSdkLocations;_ComputeTargetFrameworkMoniker"
Inputs="@(Collada)"
Outputs="$(_ColladaCache)"
>

<ScnTool
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true'"
DeviceSpecificIntermediateOutputPath="$(DeviceSpecificIntermediateOutputPath)"
IsWatchApp="$(IsWatchApp)"
ToolExe="$(ScnToolExe)"
ToolPath="$(ScnToolPath)"
ProjectDir="$(MSBuildProjectDirectory)"
ResourcePrefix="$(_ResourcePrefix)"
SdkPlatform="$(_SdkPlatform)"
SdkRoot="$(_SdkRoot)"
SdkDevPath="$(_SdkDevPath)"
SdkVersion="$(_SdkVersion)"
TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)"
IntermediateOutputPath="$(DeviceSpecificIntermediateOutputPath)"
InputScene="%(_ColladaAssetWithLogicalName.Identity)"
OutputScene="$(DeviceSpecificIntermediateOutputPath)%(_ColladaAssetWithLogicalName.LogicalName)">
ColladaAssets="@(Collada)"
>
<Output TaskParameter="BundleResources" ItemName="_BundleResourceWithLogicalName" />
<!-- Local items to be persisted to items files -->
<Output TaskParameter="BundleResources" ItemName="_Collada_BundleResources" />
</ScnTool>

<CreateItem Include="$(DeviceSpecificIntermediateOutputPath)%(_ColladaAssetWithLogicalName.LogicalName)" AdditionalMetadata="LogicalName=%(_ColladaAssetWithLogicalName.LogicalName);Optimize='False'">
<Output TaskParameter="Include" ItemName="_BundleResourceWithLogicalName" />
</CreateItem>

<WriteItemsToFile Items="@(_Collada_BundleResources)" ItemName="_BundleResourceWithLogicalName" File="$(_ColladaCache)" Overwrite="true" IncludeMetadata="true" />
<!-- Write out the list of assets we've processed, so that an inner build in a multi-rid build can skip processing them -->
<WriteItemsToFile Items="@(_ColladaAssetWithLogicalName)" Condition="'$(_SaveProcessedItems)' == 'true'" ItemName="_ColladaAssetWithLogicalName" File="$(_ProcessedColladaAssetsPath)" Overwrite="true" IncludeMetadata="false" />
<WriteItemsToFile Items="@(Collada)" Condition="'$(_SaveProcessedItems)' == 'true'" ItemName="Collada" File="$(_ProcessedColladaAssetsPath)" Overwrite="true" IncludeMetadata="false" />
<ItemGroup>
<FileWrites Include="$(_ColladaCache)" />
<FileWrites Include="$(_ProcessedColladaAssetsPath)" />
</ItemGroup>
</Target>
Expand Down Expand Up @@ -1137,6 +1150,9 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<!-- TextureAtlas output caches -->
<_TextureAtlasCache>$(DeviceSpecificIntermediateOutputPath)atlas\_BundleResourceWithLogicalName.items</_TextureAtlasCache>

<!-- Collada output caches -->
<_ColladaCache>$(DeviceSpecificIntermediateOutputPath)collada\_BundleResourceWithLogicalName.items</_ColladaCache>

<!-- processed items -->
<_ProcessedBundleResourcesPath Condition="'$(_ProcessedBundleResourcesPath)' == ''">$(DeviceSpecificIntermediateOutputPath)\_ProcessedBundleResourcesPath.items</_ProcessedBundleResourcesPath>
<_ProcessedContentPath Condition="'$(_ProcessedContentPath)' == ''">$(DeviceSpecificIntermediateOutputPath)\_ProcessedContentPath.items</_ProcessedContentPath>
Expand Down
Loading