xamarin-macios/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/CreateInstallerPackageTaskB...

179 строки
5.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.IO;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using System.Security.Cryptography.X509Certificates;
using Xamarin.MacDev;
namespace Xamarin.MacDev.Tasks
{
public class CreateInstallerPackageTaskBase : ToolTask
{
#region Inputs
public string SessionId { get; set; }
[Required]
public string OutputDirectory { get; set; }
[Required]
public string Name { get; set; }
[Required] // Used to get version
public string AppManifest { get; set; }
[Required] // Used for variable substitution in AppendExtraArgs
public string ProjectPath { get; set; }
[Required] // Used for variable substitution in AppendExtraArgs
public string AppBundleDir { get; set; }
[Required] // Used for variable substitution in AppendExtraArgs
public ITaskItem MainAssembly { get; set; }
[Required] // Should we even look at the PackageSigningKey?
// It has a default value when this is false, so we can't just switch off it being null
public bool EnablePackageSigning { get; set; }
public string ProductDefinition { get; set; }
public string PackageSigningKey { get; set; }
public string PackagingExtraArgs { get ; set; }
#endregion
string GetProjectVersion ()
{
PDictionary plist;
try {
plist = PDictionary.FromFile (AppManifest);
} catch (Exception ex) {
Log.LogError (null, null, null, AppManifest, 0, 0, 0, 0, "Error loading '{0}': {1}", AppManifest, ex.Message);
return null;
}
if (plist == null) {
Log.LogError (null, null, null, AppManifest, 0, 0, 0, 0, "Error loading '{0}'", AppManifest);
return null;
}
return plist.GetCFBundleShortVersionString ();
}
protected override string ToolName
{
get { return "productbuild"; }
}
protected override string GenerateFullPathToTool ()
{
return @"/usr/bin/productbuild";
}
protected override string GetWorkingDirectory ()
{
return OutputDirectory;
}
protected override string GenerateCommandLineCommands ()
{
Log.LogMessage ("Creating installer package");
var args = new CommandLineArgumentBuilder ();
if (!string.IsNullOrEmpty(ProductDefinition)) {
args.Add ("--product");
args.AddQuoted (ProductDefinition);
}
args.Add ("--component");
args.AddQuoted (Path.Combine (OutputDirectory, Path.GetFileName (AppBundleDir)));
args.Add ("/Applications");
if (EnablePackageSigning) {
args.Add ("--sign");
args.AddQuoted (GetPackageSigningCertificateCommonName ());
}
if (!string.IsNullOrEmpty (PackagingExtraArgs)) {
try {
AppendExtraArgs (args, PackagingExtraArgs);
} catch (FormatException) {
Log.LogError ("Package creation failed. Could not parse extra arguments.");
return string.Empty;
}
}
string projectVersion = GetProjectVersion ();
string target = string.Format ("{0}{1}.pkg", Name, String.IsNullOrEmpty (projectVersion) ? "" : "-" + projectVersion);
args.AddQuoted (Path.Combine (OutputDirectory, target));
return args.ToString ();
}
void AppendExtraArgs (CommandLineArgumentBuilder args, string extraArgs)
{
var target = this.MainAssembly.ItemSpec;
string[] argv = CommandLineArgumentBuilder.Parse (extraArgs);
var customTags = new Dictionary<string, string> (StringComparer.OrdinalIgnoreCase) {
{ "projectdir", Path.GetDirectoryName (this.ProjectPath) },
// Apparently msbuild doesn't propagate the solution path, so we can't get it. - MTouchTaskBase.cs
// { "solutiondir", proj.ParentSolution != null ? proj.ParentSolution.BaseDirectory : proj.BaseDirectory },
{ "appbundledir", this.AppBundleDir },
{ "targetpath", Path.Combine (Path.GetDirectoryName (target), Path.GetFileName (target)) },
{ "targetdir", Path.GetDirectoryName (target) },
{ "targetname", Path.GetFileName (target) },
{ "targetext", Path.GetExtension (target) },
};
for (int i = 0; i < argv.Length; i++)
args.AddQuoted (StringParserService.Parse (argv[i], customTags));
}
string GetPackageSigningCertificateCommonName ()
{
var certificates = Keychain.Default.GetAllSigningCertificates ();
DateTime now = DateTime.Now;
string key;
if (string.IsNullOrEmpty (PackageSigningKey))
key = "3rd Party Mac Developer Installer";
else
key = PackageSigningKey;
X509Certificate2 best = null;
foreach (var cert in certificates) {
if (now < cert.NotBefore || now >= cert.NotAfter)
continue;
string name = Keychain.GetCertificateCommonName (cert);
bool matches;
if (key == "3rd Party Mac Developer Installer" || key == "Developer ID Installer") {
matches = name.StartsWith (key, StringComparison.Ordinal);
} else {
matches = name == key || cert.Thumbprint == key;
}
if (matches && (best == null || cert.NotAfter > best.NotAfter))
best = cert;
}
if (best == null) {
string msg = string.Format ("The identity '{0}' doesn't match any valid certificate/private key pair in the default keychain", key);
Log.LogError (msg);
return string.Empty;
}
return Keychain.GetCertificateCommonName (best);
}
}
}