[msbuild] Refactor the IBTool task to be cleaner and more efficient (#1457)
[msbuild] Refactor the IBTool task to be cleaner and more efficient Besides making the IBTool task cleaner and easier to understand, a side-effect of this refactor was also to optimize the collecting of the compiled outputs because we now only need to scan the obj/ibtool directory once to collect each of the outputs.
This commit is contained in:
Родитель
cf169d43ac
Коммит
e26ee5ca6c
|
@ -373,12 +373,10 @@ namespace Xamarin.MacDev.Tasks
|
||||||
specs.Save (outputSpecs, true);
|
specs.Save (outputSpecs, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
var output = new TaskItem (intermediateBundleDir);
|
|
||||||
|
|
||||||
Directory.CreateDirectory (intermediateBundleDir);
|
Directory.CreateDirectory (intermediateBundleDir);
|
||||||
|
|
||||||
// Note: Compile() will set the PartialAppManifest property if it is used...
|
// Note: Compile() will set the PartialAppManifest property if it is used...
|
||||||
if ((Compile (catalogs.ToArray (), output, manifest)) != 0)
|
if ((Compile (catalogs.ToArray (), intermediateBundleDir, manifest)) != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (PartialAppManifest != null && !File.Exists (PartialAppManifest.GetMetadata ("FullPath")))
|
if (PartialAppManifest != null && !File.Exists (PartialAppManifest.GetMetadata ("FullPath")))
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using Microsoft.Build.Framework;
|
using Microsoft.Build.Framework;
|
||||||
|
@ -68,11 +69,11 @@ namespace Xamarin.MacDev.Tasks
|
||||||
|
|
||||||
string GetBundleRelativeOutputPath (ITaskItem input)
|
string GetBundleRelativeOutputPath (ITaskItem input)
|
||||||
{
|
{
|
||||||
// Note: InterfaceDefinition files are *always* installed into the root of the app bundle
|
// Note: InterfaceDefinition files are *always* installed into the root of the app bundle.
|
||||||
// InterfaceDefinition files that are contained within an .lproj translation directory
|
//
|
||||||
// will retain the .lproj directory as their parent, but the .lproj directory will be
|
// InterfaceDefinition files that are contained within a *.lproj translation directory
|
||||||
|
// will retain the *.lproj directory as their parent, but the *.lproj directory will be
|
||||||
// in the root of the app bundle.
|
// in the root of the app bundle.
|
||||||
//var bundleName = BundleResource.GetLogicalName (ProjectDir, ResourcePrefixes, input);
|
|
||||||
var components = input.ItemSpec.Split (Path.DirectorySeparatorChar);
|
var components = input.ItemSpec.Split (Path.DirectorySeparatorChar);
|
||||||
var bundleName = components[components.Length - 1];
|
var bundleName = components[components.Length - 1];
|
||||||
if (components.Length > 1 && components[components.Length - 2].EndsWith (".lproj", StringComparison.Ordinal))
|
if (components.Length > 1 && components[components.Length - 2].EndsWith (".lproj", StringComparison.Ordinal))
|
||||||
|
@ -88,6 +89,236 @@ namespace Xamarin.MacDev.Tasks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static string GetPathWithoutExtension (string path)
|
||||||
|
{
|
||||||
|
int dot = path.LastIndexOf ('.');
|
||||||
|
|
||||||
|
return path.Substring (0, dot);
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerable<ITaskItem> GetCompilationDirectoryOutput (string baseOutputDir, IDictionary<string, IDictionary> mapping)
|
||||||
|
{
|
||||||
|
var baseOutputDirs = new List<string> ();
|
||||||
|
|
||||||
|
baseOutputDirs.Add (baseOutputDir);
|
||||||
|
|
||||||
|
// Note: all storyboardc's/nib's will be found in the top-level or within a top-level *.lproj dir (if they've been translated)
|
||||||
|
for (int i = 0; i < baseOutputDirs.Count; i++) {
|
||||||
|
foreach (var path in Directory.EnumerateFileSystemEntries (baseOutputDirs[i])) {
|
||||||
|
if (i == 0 && path.EndsWith (".lproj", StringComparison.Ordinal) && Directory.Exists (path)) {
|
||||||
|
baseOutputDirs.Add (path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDictionary metadata;
|
||||||
|
|
||||||
|
if (!mapping.TryGetValue (path, out metadata))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var compiled = new TaskItem (path, metadata);
|
||||||
|
|
||||||
|
// adjust the LogicalName since the LogicalName metadata is based on the generic output name
|
||||||
|
// (e.g. it does not include things like ~ipad or ~iphone)
|
||||||
|
var logicalName = compiled.GetMetadata ("LogicalName");
|
||||||
|
var logicalDir = Path.GetDirectoryName (logicalName);
|
||||||
|
var fileName = Path.GetFileName (path);
|
||||||
|
|
||||||
|
compiled.SetMetadata ("LogicalName", Path.Combine (logicalDir, fileName));
|
||||||
|
|
||||||
|
yield return compiled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerable<ITaskItem> GetCompilationOutput (ITaskItem expected)
|
||||||
|
{
|
||||||
|
if (IsWatchApp) {
|
||||||
|
var logicalName = expected.GetMetadata ("LogicalName");
|
||||||
|
|
||||||
|
foreach (var extension in WatchAppExtensions) {
|
||||||
|
var path = GetPathWithoutExtension (expected.ItemSpec) + extension;
|
||||||
|
if (File.Exists (path)) {
|
||||||
|
var item = new TaskItem (path);
|
||||||
|
expected.CopyMetadataTo (item);
|
||||||
|
item.SetMetadata ("LogicalName", GetPathWithoutExtension (logicalName) + extension);
|
||||||
|
yield return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool LogExists (string path)
|
||||||
|
{
|
||||||
|
if (!File.Exists (path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
PDictionary.FromFile (path);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
File.Delete (path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool InterfaceDefinitionChanged (ITaskItem interfaceDefinition, ITaskItem log)
|
||||||
|
{
|
||||||
|
return !LogExists (log.ItemSpec) || File.GetLastWriteTime (log.ItemSpec) < File.GetLastWriteTime (interfaceDefinition.ItemSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompileInterfaceDefinitions (string baseManifestDir, string baseOutputDir, List<ITaskItem> compiled, IList<ITaskItem> manifests, out bool changed)
|
||||||
|
{
|
||||||
|
var mapping = new Dictionary<string, IDictionary> ();
|
||||||
|
var unique = new Dictionary<string, ITaskItem> ();
|
||||||
|
var targets = GetTargetDevices (plist).ToList ();
|
||||||
|
|
||||||
|
changed = false;
|
||||||
|
|
||||||
|
foreach (var item in InterfaceDefinitions) {
|
||||||
|
var bundleName = GetBundleRelativeOutputPath (item);
|
||||||
|
var manifest = new TaskItem (Path.Combine (baseManifestDir, bundleName));
|
||||||
|
var manifestDir = Path.GetDirectoryName (manifest.ItemSpec);
|
||||||
|
ITaskItem duplicate;
|
||||||
|
string output;
|
||||||
|
|
||||||
|
if (!File.Exists (item.ItemSpec)) {
|
||||||
|
Log.LogError (null, null, null, item.ItemSpec, 0, 0, 0, 0, "The file '{0}' does not exist.", item.ItemSpec);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unique.TryGetValue (bundleName, out duplicate)) {
|
||||||
|
Log.LogError (null, null, null, item.ItemSpec, 0, 0, 0, 0, "The file '{0}' conflicts with '{1}'.", item.ItemSpec, duplicate.ItemSpec);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique.Add (bundleName, item);
|
||||||
|
|
||||||
|
var resourceTags = item.GetMetadata ("ResourceTags");
|
||||||
|
var path = Path.Combine (baseOutputDir, bundleName);
|
||||||
|
var outputDir = Path.GetDirectoryName (path);
|
||||||
|
var name = GetPathWithoutExtension (path);
|
||||||
|
var extension = Path.GetExtension (path);
|
||||||
|
var expected = new TaskItem (path);
|
||||||
|
|
||||||
|
expected.SetMetadata ("InterfaceDefinition", item.ItemSpec);
|
||||||
|
expected.SetMetadata ("LogicalName", bundleName);
|
||||||
|
expected.SetMetadata ("Optimize", "false");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty (resourceTags))
|
||||||
|
expected.SetMetadata ("ResourceTags", resourceTags);
|
||||||
|
|
||||||
|
if (UseCompilationDirectory) {
|
||||||
|
// Note: When using --compilation-directory, we need to specify the output path as the parent directory
|
||||||
|
output = Path.GetDirectoryName (path);
|
||||||
|
} else {
|
||||||
|
output = expected.ItemSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InterfaceDefinitionChanged (item, manifest)) {
|
||||||
|
Directory.CreateDirectory (manifestDir);
|
||||||
|
Directory.CreateDirectory (outputDir);
|
||||||
|
|
||||||
|
if ((Compile (new[] { item }, output, manifest)) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
changed = true;
|
||||||
|
} else {
|
||||||
|
Log.LogMessage (MessageImportance.Low, "Skipping `{0}' as the output file, `{1}', is newer.", item.ItemSpec, manifest.ItemSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var dict = PDictionary.FromFile (manifest.ItemSpec);
|
||||||
|
|
||||||
|
LogWarningsAndErrors (dict, item);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.LogError ("Failed to load output log file for {0}: {1}", ToolName, ex.Message);
|
||||||
|
if (File.Exists (manifest.ItemSpec))
|
||||||
|
Log.LogError ("ibtool log: {0}", File.ReadAllText (manifest.ItemSpec));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UseCompilationDirectory) {
|
||||||
|
// Note: When using a compilation-directory, we'll scan dir the baseOutputDir later as
|
||||||
|
// an optimization to collect all of the compiled output in one fell swoop.
|
||||||
|
var metadata = expected.CloneCustomMetadata ();
|
||||||
|
|
||||||
|
foreach (var target in targets)
|
||||||
|
mapping.Add (name + "~" + target + extension, metadata);
|
||||||
|
|
||||||
|
mapping.Add (path, metadata);
|
||||||
|
} else {
|
||||||
|
compiled.AddRange (GetCompilationOutput (expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
manifests.Add (manifest);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UseCompilationDirectory)
|
||||||
|
compiled.AddRange (GetCompilationDirectoryOutput (baseOutputDir, mapping));
|
||||||
|
|
||||||
|
return !Log.HasLoggedErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LinkStoryboards (string baseManifestDir, string baseOutputDir, List<ITaskItem> storyboards, List<ITaskItem> linked, IList<ITaskItem> manifests, bool changed)
|
||||||
|
{
|
||||||
|
var manifest = new TaskItem (Path.Combine (baseManifestDir, "link"));
|
||||||
|
var mapping = new Dictionary<string, IDictionary> ();
|
||||||
|
var unique = new HashSet<string> ();
|
||||||
|
var items = new List<ITaskItem> ();
|
||||||
|
|
||||||
|
// Make sure that `Main.storyboardc` is listed *before* `Main~ipad.storyboardc` and `Main~iphone.storyboardc`,
|
||||||
|
// this is important for the next step to filter out the device-specific storyboards based on the same source.
|
||||||
|
storyboards.Sort ((x, y) => string.Compare (x.ItemSpec, y.ItemSpec, StringComparison.Ordinal));
|
||||||
|
|
||||||
|
// Populate our metadata mapping table so we can properly restore the metadata to the linked items.
|
||||||
|
//
|
||||||
|
// While we are at it, we'll also filter out device-specific storyboards since ibtool doesn't
|
||||||
|
// require them if we have an equivalent generic version.
|
||||||
|
for (int i = 0; i < storyboards.Count; i++) {
|
||||||
|
var interfaceDefinition = storyboards[i].GetMetadata ("InterfaceDefinition");
|
||||||
|
var bundleName = storyboards[i].GetMetadata ("LogicalName");
|
||||||
|
var path = Path.Combine (baseOutputDir, bundleName);
|
||||||
|
|
||||||
|
storyboards[i].RemoveMetadata ("InterfaceDefinition");
|
||||||
|
var metadata = storyboards[i].CloneCustomMetadata ();
|
||||||
|
mapping.Add (path, metadata);
|
||||||
|
|
||||||
|
if (unique.Add (interfaceDefinition))
|
||||||
|
items.Add (storyboards[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only need to run `ibtool --link` if storyboards have changed...
|
||||||
|
if (changed) {
|
||||||
|
if (Directory.Exists (baseOutputDir))
|
||||||
|
Directory.Delete (baseOutputDir, true);
|
||||||
|
|
||||||
|
if (File.Exists (manifest.ItemSpec))
|
||||||
|
File.Delete (manifest.ItemSpec);
|
||||||
|
|
||||||
|
Directory.CreateDirectory (baseManifestDir);
|
||||||
|
Directory.CreateDirectory (baseOutputDir);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Link = true;
|
||||||
|
|
||||||
|
if ((Compile (items.ToArray (), baseOutputDir, manifest)) != 0)
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
Link = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
linked.AddRange (GetCompilationDirectoryOutput (baseOutputDir, mapping));
|
||||||
|
|
||||||
|
manifests.Add (manifest);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
IEnumerable<ITaskItem> RecursivelyEnumerateFiles (ITaskItem output)
|
IEnumerable<ITaskItem> RecursivelyEnumerateFiles (ITaskItem output)
|
||||||
{
|
{
|
||||||
var nibDir = output.GetMetadata ("LogicalName");
|
var nibDir = output.GetMetadata ("LogicalName");
|
||||||
|
@ -120,106 +351,36 @@ namespace Xamarin.MacDev.Tasks
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
static string GetPathWithoutExtension (string path)
|
IEnumerable<ITaskItem> GetBundleResources (ITaskItem compiledItem)
|
||||||
{
|
{
|
||||||
int dot = path.LastIndexOf ('.');
|
var baseLogicalName = compiledItem.GetMetadata ("LogicalName");
|
||||||
|
var baseDir = compiledItem.ItemSpec;
|
||||||
|
|
||||||
return path.Substring (0, dot);
|
// Note: Watch App storyboards will be compiled to something like Interface.storyboardc/Interface.plist, but
|
||||||
}
|
// Interface.plist needs to be moved up 1 level (e.g. drop the "Interface.storyboardc").
|
||||||
|
// See https://bugzilla.xamarin.com/show_bug.cgi?id=33853 for details
|
||||||
|
if (IsWatchApp && baseLogicalName.EndsWith (".storyboardc", StringComparison.Ordinal))
|
||||||
|
baseLogicalName = Path.GetDirectoryName (baseLogicalName);
|
||||||
|
|
||||||
IEnumerable<ITaskItem> GetCompilationDirectoryOutput (ITaskItem expected)
|
foreach (var path in Directory.EnumerateFiles (baseDir, "*.*", SearchOption.AllDirectories)) {
|
||||||
{
|
var rpath = PathUtils.AbsoluteToRelative (baseDir, Path.GetFullPath (path));
|
||||||
var dir = Path.GetDirectoryName (expected.ItemSpec);
|
var bundleResource = new TaskItem (path);
|
||||||
|
string logicalName;
|
||||||
|
|
||||||
if (!Directory.Exists (dir))
|
if (!string.IsNullOrEmpty (baseLogicalName))
|
||||||
yield break;
|
logicalName = Path.Combine (baseLogicalName, rpath);
|
||||||
|
else
|
||||||
|
logicalName = rpath;
|
||||||
|
|
||||||
var name = Path.GetFileNameWithoutExtension (expected.ItemSpec);
|
compiledItem.CopyMetadataTo (bundleResource);
|
||||||
var extension = Path.GetExtension (expected.ItemSpec);
|
bundleResource.SetMetadata ("LogicalName", logicalName);
|
||||||
var nibDir = expected.GetMetadata ("LogicalName");
|
|
||||||
var targets = GetTargetDevices (plist).ToList ();
|
|
||||||
|
|
||||||
foreach (var path in Directory.GetFileSystemEntries (dir)) {
|
yield return bundleResource;
|
||||||
// check that the FileNameWithoutExtension matches *exactly*
|
|
||||||
if (string.Compare (path, dir.Length + 1, name, 0, name.Length) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int startIndex = dir.Length + 1 + name.Length;
|
|
||||||
|
|
||||||
// match against files that have a "~" + $target (iphone, ipad, etc)
|
|
||||||
if (path.Length > startIndex && path[startIndex] == '~') {
|
|
||||||
bool matched = false;
|
|
||||||
|
|
||||||
startIndex++;
|
|
||||||
|
|
||||||
foreach (var target in targets) {
|
|
||||||
// Note: we match the target case-insensitively because of https://bugzilla.xamarin.com/show_bug.cgi?id=44811
|
|
||||||
if (string.Compare (path, startIndex, target, 0, target.Length, StringComparison.OrdinalIgnoreCase) == 0) {
|
|
||||||
startIndex += target.Length;
|
|
||||||
matched = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!matched)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// at this point, all that should be left is the file/directory extension
|
|
||||||
if (path.Length != startIndex + extension.Length || string.Compare (path, startIndex, extension, 0, extension.Length) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var fileName = Path.GetFileName (path);
|
|
||||||
var logicalName = !string.IsNullOrEmpty (nibDir) ? Path.Combine (nibDir, fileName) : fileName;
|
|
||||||
var item = new TaskItem (path);
|
|
||||||
expected.CopyMetadataTo (item);
|
|
||||||
item.SetMetadata ("LogicalName", logicalName);
|
|
||||||
|
|
||||||
yield return item;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<ITaskItem> GetCompiledBundleResources (ITaskItem output)
|
|
||||||
{
|
|
||||||
if (IsWatchApp && !UseCompilationDirectory) {
|
|
||||||
var logicalName = output.GetMetadata ("LogicalName");
|
|
||||||
|
|
||||||
foreach (var extension in WatchAppExtensions) {
|
|
||||||
var path = GetPathWithoutExtension (output.ItemSpec) + extension;
|
|
||||||
if (File.Exists (path)) {
|
|
||||||
var item = new TaskItem (path);
|
|
||||||
item.SetMetadata ("LogicalName", GetPathWithoutExtension (logicalName) + extension);
|
|
||||||
item.SetMetadata ("Optimize", "false");
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (Directory.Exists (output.ItemSpec)) {
|
|
||||||
// Note: historically, only storyboard files compiled to directories containing the real nib files, but the new iOS 8 .xib's do as well.
|
|
||||||
foreach (var file in RecursivelyEnumerateFiles (output))
|
|
||||||
yield return file;
|
|
||||||
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ManifestExists (string path)
|
|
||||||
{
|
|
||||||
if (!File.Exists (path))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
PDictionary.FromFile (path);
|
|
||||||
return true;
|
|
||||||
} catch {
|
|
||||||
File.Delete (path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Execute ()
|
public override bool Execute ()
|
||||||
{
|
{
|
||||||
Log.LogTaskName ("IBTool");
|
Log.LogTaskName ("IBTool");
|
||||||
|
@ -242,12 +403,11 @@ namespace Xamarin.MacDev.Tasks
|
||||||
return !Log.HasLoggedErrors;
|
return !Log.HasLoggedErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ibtoolManifestDir = Path.Combine (IntermediateOutputPath, ToolName + "-manifests");
|
var ibtoolManifestDir = Path.Combine (IntermediateOutputPath, "ibtool-manifests");
|
||||||
var ibtoolOutputDir = Path.Combine (IntermediateOutputPath, ToolName);
|
var ibtoolOutputDir = Path.Combine (IntermediateOutputPath, "ibtool");
|
||||||
var bundleResources = new List<ITaskItem> ();
|
|
||||||
var outputManifests = new List<ITaskItem> ();
|
var outputManifests = new List<ITaskItem> ();
|
||||||
var compiled = new List<ITaskItem> ();
|
var compiled = new List<ITaskItem> ();
|
||||||
bool changed = false;
|
bool changed;
|
||||||
|
|
||||||
if (InterfaceDefinitions.Length > 0) {
|
if (InterfaceDefinitions.Length > 0) {
|
||||||
if (AppManifest != null) {
|
if (AppManifest != null) {
|
||||||
|
@ -264,105 +424,51 @@ namespace Xamarin.MacDev.Tasks
|
||||||
|
|
||||||
Directory.CreateDirectory (ibtoolManifestDir);
|
Directory.CreateDirectory (ibtoolManifestDir);
|
||||||
Directory.CreateDirectory (ibtoolOutputDir);
|
Directory.CreateDirectory (ibtoolOutputDir);
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var item in InterfaceDefinitions) {
|
|
||||||
var bundleName = GetBundleRelativeOutputPath (item);
|
|
||||||
var manifest = new TaskItem (Path.Combine (ibtoolManifestDir, bundleName));
|
|
||||||
var manifestDir = Path.GetDirectoryName (manifest.ItemSpec);
|
|
||||||
var resourceTags = item.GetMetadata ("ResourceTags");
|
|
||||||
ITaskItem expected, output;
|
|
||||||
string rpath, outputDir;
|
|
||||||
|
|
||||||
if (!File.Exists (item.ItemSpec)) {
|
if (!CompileInterfaceDefinitions (ibtoolManifestDir, ibtoolOutputDir, compiled, outputManifests, out changed))
|
||||||
Log.LogError (null, null, null, item.ItemSpec, 0, 0, 0, 0, "The file '{0}' does not exist.", item.ItemSpec);
|
return false;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
rpath = Path.Combine (ibtoolOutputDir, bundleName);
|
if (CanLinkStoryboards) {
|
||||||
outputDir = Path.GetDirectoryName (rpath);
|
var storyboards = new List<ITaskItem> ();
|
||||||
expected = new TaskItem (rpath);
|
var linked = new List<ITaskItem> ();
|
||||||
|
var unique = new HashSet<string> ();
|
||||||
|
|
||||||
expected.SetMetadata ("LogicalName", bundleName);
|
for (int i = 0; i < compiled.Count; i++) {
|
||||||
expected.SetMetadata ("Optimize", "false");
|
// pretend that non-storyboardc items (e.g. *.nib) are already 'linked'
|
||||||
|
if (compiled[i].ItemSpec.EndsWith (".storyboardc", StringComparison.Ordinal)) {
|
||||||
|
var interfaceDefinition = compiled[i].GetMetadata ("InterfaceDefinition");
|
||||||
|
unique.Add (interfaceDefinition);
|
||||||
|
storyboards.Add (compiled[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty (resourceTags))
|
// just pretend any *nib's have already been 'linked'...
|
||||||
expected.SetMetadata ("ResourceTags", resourceTags);
|
compiled[i].RemoveMetadata ("InterfaceDefinition");
|
||||||
|
linked.Add (compiled[i]);
|
||||||
|
}
|
||||||
|
|
||||||
if (UseCompilationDirectory) {
|
// only link the storyboards if there are multiple unique storyboards
|
||||||
// Note: When using --compilation-directory, we need to specify the output path as the parent directory
|
if (unique.Count > 1) {
|
||||||
output = new TaskItem (expected);
|
var linkOutputDir = Path.Combine (IntermediateOutputPath, "ibtool-link");
|
||||||
output.ItemSpec = Path.GetDirectoryName (output.ItemSpec);
|
|
||||||
output.SetMetadata ("LogicalName", Path.GetDirectoryName (bundleName));
|
if (!LinkStoryboards (ibtoolManifestDir, linkOutputDir, storyboards, linked, outputManifests, changed))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
compiled = linked;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
output = expected;
|
for (int i = 0; i < compiled.Count; i++)
|
||||||
|
compiled[i].RemoveMetadata ("InterfaceDefinition");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ManifestExists (manifest.ItemSpec) || File.GetLastWriteTime (manifest.ItemSpec) < File.GetLastWriteTime (item.ItemSpec)) {
|
|
||||||
Directory.CreateDirectory (manifestDir);
|
|
||||||
Directory.CreateDirectory (outputDir);
|
|
||||||
|
|
||||||
if ((Compile (new[] { item }, output, manifest)) != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
changed = true;
|
|
||||||
} else {
|
|
||||||
Log.LogMessage (MessageImportance.Low, "Skipping `{0}' as the output file, `{1}', is newer.", item.ItemSpec, manifest.ItemSpec);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
var dict = PDictionary.FromFile (manifest.ItemSpec);
|
|
||||||
|
|
||||||
LogWarningsAndErrors (dict, item);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
Log.LogError ("Failed to load output manifest for {0}: {1}", ToolName, ex.Message);
|
|
||||||
if (File.Exists (manifest.ItemSpec))
|
|
||||||
Log.LogError ("Output manifest contents: {0}", File.ReadAllText (manifest.ItemSpec));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UseCompilationDirectory)
|
|
||||||
compiled.AddRange (GetCompilationDirectoryOutput (expected));
|
|
||||||
else
|
|
||||||
bundleResources.AddRange (GetCompiledBundleResources (output));
|
|
||||||
|
|
||||||
outputManifests.Add (manifest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (InterfaceDefinitions.Length > 0 && UseCompilationDirectory) {
|
var bundleResources = new List<ITaskItem> ();
|
||||||
var output = new TaskItem (ibtoolOutputDir);
|
|
||||||
output.SetMetadata ("LogicalName", "");
|
|
||||||
|
|
||||||
if (!CanLinkStoryboards)
|
foreach (var compiledItem in compiled) {
|
||||||
bundleResources.AddRange (GetCompiledBundleResources (output));
|
if (Directory.Exists (compiledItem.ItemSpec))
|
||||||
}
|
bundleResources.AddRange (GetBundleResources (compiledItem));
|
||||||
|
else if (File.Exists (compiledItem.ItemSpec))
|
||||||
if (CanLinkStoryboards && compiled.Count > 0) {
|
bundleResources.Add (compiledItem);
|
||||||
var linkOutputDir = Path.Combine (IntermediateOutputPath, ToolName + "-link");
|
|
||||||
var manifest = new TaskItem (Path.Combine (ibtoolManifestDir, "link"));
|
|
||||||
var output = new TaskItem (linkOutputDir);
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
if (Directory.Exists (output.ItemSpec))
|
|
||||||
Directory.Delete (output.ItemSpec, true);
|
|
||||||
|
|
||||||
if (File.Exists (manifest.ItemSpec))
|
|
||||||
File.Delete (manifest.ItemSpec);
|
|
||||||
|
|
||||||
Directory.CreateDirectory (Path.GetDirectoryName (manifest.ItemSpec));
|
|
||||||
Directory.CreateDirectory (output.ItemSpec);
|
|
||||||
|
|
||||||
Link = true;
|
|
||||||
|
|
||||||
if ((Compile (compiled.ToArray (), output, manifest)) != 0)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
output = new TaskItem (linkOutputDir);
|
|
||||||
output.SetMetadata ("LogicalName", "");
|
|
||||||
|
|
||||||
bundleResources.AddRange (GetCompiledBundleResources (output));
|
|
||||||
outputManifests.Add (manifest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BundleResources = bundleResources.ToArray ();
|
BundleResources = bundleResources.ToArray ();
|
||||||
|
|
|
@ -124,7 +124,7 @@ namespace Xamarin.MacDev.Tasks
|
||||||
return startInfo;
|
return startInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int Compile (ITaskItem[] items, ITaskItem output, ITaskItem manifest)
|
protected int Compile (ITaskItem[] items, string output, ITaskItem manifest)
|
||||||
{
|
{
|
||||||
var environment = new Dictionary<string, string> ();
|
var environment = new Dictionary<string, string> ();
|
||||||
var args = new ProcessArgumentBuilder ();
|
var args = new ProcessArgumentBuilder ();
|
||||||
|
@ -147,7 +147,7 @@ namespace Xamarin.MacDev.Tasks
|
||||||
else
|
else
|
||||||
args.Add ("--compile");
|
args.Add ("--compile");
|
||||||
|
|
||||||
args.AddQuoted (output.GetMetadata ("FullPath"));
|
args.AddQuoted (Path.GetFullPath (output));
|
||||||
|
|
||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
args.AddQuoted (item.GetMetadata ("FullPath"));
|
args.AddQuoted (item.GetMetadata ("FullPath"));
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11106"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="EHf-IW-A2E">
|
||||||
|
<objects>
|
||||||
|
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="53" y="375"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="5xv-Yx-H4r">
|
||||||
|
<device id="retina4_7" orientation="portrait">
|
||||||
|
<adaptation id="fullscreen"/>
|
||||||
|
</device>
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="lP3-9c-L6b">
|
||||||
|
<objects>
|
||||||
|
<viewController storyboardIdentifier="MyLinkedViewController" id="5xv-Yx-H4r" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="vTD-aw-nUj"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="IyX-Ik-oKG"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="gMo-tm-chA">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Linked!" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Gd9-6P-3AQ">
|
||||||
|
<rect key="frame" x="159" y="323" width="56" height="21"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
|
<nil key="textColor"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="J6q-Vo-r8c" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="201" y="102"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||||
|
<device id="retina4_7" orientation="portrait">
|
||||||
|
<adaptation id="fullscreen"/>
|
||||||
|
</device>
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="tne-QT-ifu">
|
||||||
|
<objects>
|
||||||
|
<viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="suC-9c-gGU">
|
||||||
|
<rect key="frame" x="164" y="318" width="46" height="30"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<state key="normal" title="Button"/>
|
||||||
|
<connections>
|
||||||
|
<segue destination="Xa5-w5-hXO" kind="show" id="1S1-fR-EBd"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
</scene>
|
||||||
|
<!--Linked-->
|
||||||
|
<scene sceneID="brE-JR-pH9">
|
||||||
|
<objects>
|
||||||
|
<viewControllerPlaceholder storyboardIdentifier="MyLinkedViewController" storyboardName="Linked" id="Xa5-w5-hXO" sceneMemberID="viewController"/>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="C8X-qd-oxE" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="522" y="94"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>IBToolTaskTest</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.your-company.ibtooltasktest</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>IBToolTaskTest</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>MinimumOSVersion</key>
|
||||||
|
<string>10.1</string>
|
||||||
|
<key>UIDeviceFamily</key>
|
||||||
|
<array>
|
||||||
|
<integer>1</integer>
|
||||||
|
<integer>2</integer>
|
||||||
|
</array>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>UIMainStoryboardFile</key>
|
||||||
|
<string>Main</string>
|
||||||
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
|
<array>
|
||||||
|
<string>armv7</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="5xv-Yx-H4r">
|
||||||
|
<device id="retina4_7" orientation="portrait">
|
||||||
|
<adaptation id="fullscreen"/>
|
||||||
|
</device>
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="lP3-9c-L6b">
|
||||||
|
<objects>
|
||||||
|
<viewController storyboardIdentifier="MyLinkedViewController" id="5xv-Yx-H4r" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="vTD-aw-nUj"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="IyX-Ik-oKG"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="gMo-tm-chA">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Linked!" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Gd9-6P-3AQ">
|
||||||
|
<rect key="frame" x="159" y="323" width="56" height="21"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
|
<nil key="textColor"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="J6q-Vo-r8c" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="201" y="102"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||||
|
<device id="retina4_7" orientation="portrait">
|
||||||
|
<adaptation id="fullscreen"/>
|
||||||
|
</device>
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="tne-QT-ifu">
|
||||||
|
<objects>
|
||||||
|
<viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="suC-9c-gGU">
|
||||||
|
<rect key="frame" x="164" y="318" width="46" height="30"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<state key="normal" title="Button"/>
|
||||||
|
<connections>
|
||||||
|
<segue destination="Xa5-w5-hXO" kind="show" id="1S1-fR-EBd"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
</scene>
|
||||||
|
<!--Linked-->
|
||||||
|
<scene sceneID="brE-JR-pH9">
|
||||||
|
<objects>
|
||||||
|
<viewControllerPlaceholder storyboardIdentifier="MyLinkedViewController" storyboardName="Linked" id="Xa5-w5-hXO" sceneMemberID="viewController"/>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="C8X-qd-oxE" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="522" y="94"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
|
@ -433,14 +433,9 @@ namespace Xamarin.iOS.Tasks
|
||||||
public void BundleResources ()
|
public void BundleResources ()
|
||||||
{
|
{
|
||||||
var actool = Path.Combine ("obj", "iPhoneSimulator", "Debug", "actool", "bundle");
|
var actool = Path.Combine ("obj", "iPhoneSimulator", "Debug", "actool", "bundle");
|
||||||
|
var ibtool = Path.Combine ("obj", "iPhoneSimulator", "Debug", "ibtool");
|
||||||
var path = Path.Combine (MonoTouchProjectPath, "Info.plist");
|
var path = Path.Combine (MonoTouchProjectPath, "Info.plist");
|
||||||
var plist = PDictionary.FromFile (path);
|
var plist = PDictionary.FromFile (path);
|
||||||
string ibtool;
|
|
||||||
|
|
||||||
if (AppleSdkSettings.XcodeVersion.Major >= 7)
|
|
||||||
ibtool = Path.Combine ("obj", "iPhoneSimulator", "Debug", "ibtool-link");
|
|
||||||
else
|
|
||||||
ibtool = Path.Combine ("obj", "iPhoneSimulator", "Debug", "ibtool");
|
|
||||||
|
|
||||||
plist.SetMinimumOSVersion ("6.1");
|
plist.SetMinimumOSVersion ("6.1");
|
||||||
plist.Save (path, true);
|
plist.Save (path, true);
|
||||||
|
|
|
@ -0,0 +1,173 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
using Xamarin.MacDev;
|
||||||
|
using Xamarin.MacDev.Tasks;
|
||||||
|
|
||||||
|
namespace Xamarin.iOS.Tasks
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class IBToolTaskTests
|
||||||
|
{
|
||||||
|
static IBTool CreateIBToolTask (PlatformFramework framework, string projectDir, string intermediateOutputPath)
|
||||||
|
{
|
||||||
|
var interfaceDefinitions = new List<ITaskItem> ();
|
||||||
|
var sdk = IPhoneSdks.GetSdk (framework);
|
||||||
|
var version = IPhoneSdkVersion.GetDefault (sdk, false);
|
||||||
|
var root = sdk.GetSdkPath (version, false);
|
||||||
|
var usr = Path.Combine (sdk.DeveloperRoot, "usr");
|
||||||
|
var bin = Path.Combine (usr, "bin");
|
||||||
|
string platform;
|
||||||
|
|
||||||
|
switch (framework) {
|
||||||
|
case PlatformFramework.WatchOS:
|
||||||
|
platform = "WatchOS";
|
||||||
|
break;
|
||||||
|
case PlatformFramework.TVOS:
|
||||||
|
platform = "AppleTVOS";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
platform = "iPhoneOS";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in Directory.EnumerateFiles (projectDir, "*.storyboard", SearchOption.AllDirectories))
|
||||||
|
interfaceDefinitions.Add (new TaskItem (item));
|
||||||
|
|
||||||
|
foreach (var item in Directory.EnumerateFiles (projectDir, "*.xib", SearchOption.AllDirectories))
|
||||||
|
interfaceDefinitions.Add (new TaskItem (item));
|
||||||
|
|
||||||
|
return new IBTool {
|
||||||
|
AppManifest = new TaskItem (Path.Combine (projectDir, "Info.plist")),
|
||||||
|
InterfaceDefinitions = interfaceDefinitions.ToArray (),
|
||||||
|
IntermediateOutputPath = intermediateOutputPath,
|
||||||
|
BuildEngine = new TestEngine (),
|
||||||
|
ResourcePrefix = "Resources",
|
||||||
|
ProjectDir = projectDir,
|
||||||
|
SdkPlatform = platform,
|
||||||
|
SdkVersion = version.ToString (),
|
||||||
|
SdkUsrPath = usr,
|
||||||
|
SdkBinPath = bin,
|
||||||
|
SdkRoot = root,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBasicIBToolFunctionality ()
|
||||||
|
{
|
||||||
|
var tmp = Path.Combine (Path.GetTempPath (), "basic-ibtool");
|
||||||
|
|
||||||
|
Directory.CreateDirectory (tmp);
|
||||||
|
|
||||||
|
try {
|
||||||
|
var ibtool = CreateIBToolTask (PlatformFramework.iOS, "../MyIBToolLinkTest", tmp);
|
||||||
|
var bundleResources = new HashSet<string> ();
|
||||||
|
|
||||||
|
Assert.IsTrue (ibtool.Execute (), "Execution of IBTool task failed.");
|
||||||
|
|
||||||
|
foreach (var bundleResource in ibtool.BundleResources) {
|
||||||
|
Assert.IsTrue (File.Exists (bundleResource.ItemSpec), "File does not exist: {0}", bundleResource.ItemSpec);
|
||||||
|
Assert.IsNotNullOrEmpty (bundleResource.GetMetadata ("LogicalName"), "The 'LogicalName' metadata must be set.");
|
||||||
|
Assert.IsNotNullOrEmpty (bundleResource.GetMetadata ("Optimize"), "The 'Optimize' metadata must be set.");
|
||||||
|
|
||||||
|
bundleResources.Add (bundleResource.GetMetadata ("LogicalName"));
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] expected = { "LaunchScreen~ipad.nib/objects-8.0+.nib",
|
||||||
|
"LaunchScreen~ipad.nib/runtime.nib",
|
||||||
|
"LaunchScreen~iphone.nib/objects-8.0+.nib",
|
||||||
|
"LaunchScreen~iphone.nib/runtime.nib",
|
||||||
|
"Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC~ipad.nib/objects-8.0+.nib",
|
||||||
|
"Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC~ipad.nib/runtime.nib",
|
||||||
|
"Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC~iphone.nib/objects-8.0+.nib",
|
||||||
|
"Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC~iphone.nib/runtime.nib",
|
||||||
|
"Main.storyboardc/UIViewController-BYZ-38-t0r~ipad.nib/objects-8.0+.nib",
|
||||||
|
"Main.storyboardc/UIViewController-BYZ-38-t0r~ipad.nib/runtime.nib",
|
||||||
|
"Main.storyboardc/UIViewController-BYZ-38-t0r~iphone.nib/objects-8.0+.nib",
|
||||||
|
"Main.storyboardc/UIViewController-BYZ-38-t0r~iphone.nib/runtime.nib",
|
||||||
|
"Main~ipad.storyboardc/Info-8.0+.plist",
|
||||||
|
"Main~ipad.storyboardc/Info.plist",
|
||||||
|
"Main~iphone.storyboardc/Info-8.0+.plist",
|
||||||
|
"Main~iphone.storyboardc/Info.plist"
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var bundleResource in expected)
|
||||||
|
Assert.IsTrue (bundleResources.Contains (bundleResource), "BundleResources should include '{0}'", bundleResource);
|
||||||
|
|
||||||
|
Assert.AreEqual (expected.Length, bundleResources.Count, "Unexpected number of BundleResources");
|
||||||
|
} finally {
|
||||||
|
Directory.Delete (tmp, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAdvancedIBToolFunctionality ()
|
||||||
|
{
|
||||||
|
var tmp = Path.Combine (Path.GetTempPath (), "advanced-ibtool");
|
||||||
|
IBTool ibtool;
|
||||||
|
|
||||||
|
Directory.CreateDirectory (tmp);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ibtool = CreateIBToolTask (PlatformFramework.iOS, "../IBToolTaskTests/LinkedAndTranslated", tmp);
|
||||||
|
var bundleResources = new HashSet<string> ();
|
||||||
|
|
||||||
|
// Add some ResourceTags...
|
||||||
|
foreach (var storyboard in ibtool.InterfaceDefinitions) {
|
||||||
|
var tag = Path.GetFileNameWithoutExtension (storyboard.ItemSpec);
|
||||||
|
storyboard.SetMetadata ("ResourceTags", tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.IsTrue (ibtool.Execute (), "Execution of IBTool task failed.");
|
||||||
|
|
||||||
|
foreach (var bundleResource in ibtool.BundleResources) {
|
||||||
|
var bundleName = bundleResource.GetMetadata ("LogicalName");
|
||||||
|
var tag = bundleResource.GetMetadata ("ResourceTags");
|
||||||
|
|
||||||
|
Assert.IsTrue (File.Exists (bundleResource.ItemSpec), "File does not exist: {0}", bundleResource.ItemSpec);
|
||||||
|
Assert.IsNotNullOrEmpty (bundleResource.GetMetadata ("LogicalName"), "The 'LogicalName' metadata must be set.");
|
||||||
|
Assert.IsNotNullOrEmpty (bundleResource.GetMetadata ("Optimize"), "The 'Optimize' metadata must be set.");
|
||||||
|
|
||||||
|
Assert.IsNotNullOrEmpty (tag, "The 'ResourceTags' metadata should be set.");
|
||||||
|
Assert.IsTrue (bundleName.Contains (".lproj/" + tag + ".storyboardc/"), "BundleResource does not have the proper ResourceTags set: {0}", bundleName);
|
||||||
|
|
||||||
|
bundleResources.Add (bundleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] expected = {
|
||||||
|
"Base.lproj/LaunchScreen.storyboardc/01J-lp-oVM-view-Ze5-6b-2t3.nib",
|
||||||
|
"Base.lproj/LaunchScreen.storyboardc/Info.plist",
|
||||||
|
"Base.lproj/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib",
|
||||||
|
"Base.lproj/Linked.storyboardc/5xv-Yx-H4r-view-gMo-tm-chA.nib",
|
||||||
|
"Base.lproj/Linked.storyboardc/Info.plist",
|
||||||
|
"Base.lproj/Linked.storyboardc/MyLinkedViewController.nib",
|
||||||
|
"Base.lproj/Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC.nib",
|
||||||
|
"Base.lproj/Main.storyboardc/Info.plist",
|
||||||
|
"Base.lproj/Main.storyboardc/MyLinkedViewController.nib",
|
||||||
|
"Base.lproj/Main.storyboardc/UIViewController-BYZ-38-t0r.nib",
|
||||||
|
"en.lproj/Linked.storyboardc/5xv-Yx-H4r-view-gMo-tm-chA.nib",
|
||||||
|
"en.lproj/Linked.storyboardc/Info.plist",
|
||||||
|
"en.lproj/Linked.storyboardc/MyLinkedViewController.nib",
|
||||||
|
"en.lproj/Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC.nib",
|
||||||
|
"en.lproj/Main.storyboardc/Info.plist",
|
||||||
|
"en.lproj/Main.storyboardc/MyLinkedViewController.nib",
|
||||||
|
"en.lproj/Main.storyboardc/UIViewController-BYZ-38-t0r.nib"
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var bundleResource in expected)
|
||||||
|
Assert.IsTrue (bundleResources.Contains (bundleResource), "BundleResources should include '{0}'", bundleResource);
|
||||||
|
|
||||||
|
Assert.AreEqual (expected.Length, bundleResources.Count, "Unexpected number of BundleResources");
|
||||||
|
} finally {
|
||||||
|
Directory.Delete (tmp, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -108,6 +108,7 @@
|
||||||
<Compile Include="TaskTests\GeneratePlistTaskTests\GeneratePlistTaskTests_watchOS.cs" />
|
<Compile Include="TaskTests\GeneratePlistTaskTests\GeneratePlistTaskTests_watchOS.cs" />
|
||||||
<Compile Include="ProjectsTests\ReleaseBuild.cs" />
|
<Compile Include="ProjectsTests\ReleaseBuild.cs" />
|
||||||
<Compile Include="TaskTests\PropertyListEditorTaskTests.cs" />
|
<Compile Include="TaskTests\PropertyListEditorTaskTests.cs" />
|
||||||
|
<Compile Include="TaskTests\IBToolTaskTests.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
|
|
Загрузка…
Ссылка в новой задаче