179 строки
5.1 KiB
C#
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 ProcessArgumentBuilder ();
|
|
|
|
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 (ProcessArgumentBuilder args, string extraArgs)
|
|
{
|
|
var target = this.MainAssembly.ItemSpec;
|
|
|
|
string[] argv = ProcessArgumentBuilder.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);
|
|
}
|
|
}
|
|
}
|
|
|