public override bool Execute() { Log.LogTaskName("FindItemWithLogicalName"); Log.LogTaskProperty("Items", Items); Log.LogTaskProperty("LogicalName", LogicalName); Log.LogTaskProperty("ProjectDir", ProjectDir); Log.LogTaskProperty("ResourcePrefix", ResourcePrefix); if (Items != null) { var prefixes = BundleResource.SplitResourcePrefixes(ResourcePrefix); foreach (var item in Items) { var logical = BundleResource.GetLogicalName(ProjectDir, prefixes, item); if (logical == LogicalName) { Log.LogMessage(MessageImportance.Low, " {0} found at: {1}", LogicalName, item.ItemSpec); Item = item; break; } } } return(!Log.HasLoggedErrors); }
protected override string GenerateCommandLineCommands() { var prefixes = BundleResource.SplitResourcePrefixes(ResourcePrefix); var intermediate = Path.Combine(IntermediateOutputPath, ToolName); var logicalName = BundleResource.GetLogicalName(ProjectDir, prefixes, SourceFile, !string.IsNullOrEmpty(SessionId)); var path = Path.Combine(intermediate, logicalName); var args = new ProcessArgumentBuilder(); var dir = Path.GetDirectoryName(path); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } OutputFile = new TaskItem(Path.ChangeExtension(path, ".air")); OutputFile.SetMetadata("LogicalName", Path.ChangeExtension(logicalName, ".air")); args.Add("-arch", "air64"); args.Add("-emit-llvm"); args.Add("-c"); args.Add("-gline-tables-only"); args.Add("-ffast-math"); args.Add(string.Format("-std={0}-metal1.0", OperatingSystem)); args.Add("-serialize-diagnostics"); args.AddQuoted(Path.ChangeExtension(path, ".dia")); args.Add("-o"); args.AddQuoted(Path.ChangeExtension(path, ".air")); args.AddQuoted(SourceFile.ItemSpec); return(args.ToString()); }
protected override IEnumerable <ITaskItem> EnumerateInputs() { if (AtlasTextures == null) { yield break; } // group the atlas textures by their parent .atlas directories foreach (var item in AtlasTextures) { var atlas = Path.GetDirectoryName(BundleResource.GetVirtualProjectPath(ProjectDir, item)); List <ITaskItem> items; if (!atlases.TryGetValue(atlas, out items)) { items = new List <ITaskItem> (); atlases.Add(atlas, items); } items.Add(item); } foreach (var atlas in atlases.Keys) { yield return(new TaskItem(atlas)); } yield break; }
private void AddBundles(string[] bundles) { foreach (string thisBundle in bundles) { BundleResource newBundle = new BundleResource(Path.Combine(PathThirdPartyIOS, "bundle", thisBundle + ".bundle")); AdditionalBundleResources.Add(newBundle); } }
protected override string GenerateCommandLineCommands() { var prefixes = BundleResource.SplitResourcePrefixes(ResourcePrefix); var intermediate = Path.Combine(IntermediateOutputPath, ToolName); var logicalName = BundleResource.GetLogicalName(ProjectDir, prefixes, SourceFile, !string.IsNullOrEmpty(SessionId)); var path = Path.Combine(intermediate, logicalName); var args = new CommandLineArgumentBuilder(); var dir = Path.GetDirectoryName(path); string minimumDeploymentTarget; if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } if (AppManifest != null) { var plist = PDictionary.FromFile(AppManifest.ItemSpec); PString value; if (!plist.TryGetValue(MinimumDeploymentTargetKey, out value) || string.IsNullOrEmpty(value.Value)) { minimumDeploymentTarget = SdkVersion; } else { minimumDeploymentTarget = value.Value; } } else { minimumDeploymentTarget = SdkVersion; } OutputFile = new TaskItem(Path.ChangeExtension(path, ".air")); OutputFile.SetMetadata("LogicalName", Path.ChangeExtension(logicalName, ".air")); args.Add("-arch", "air64"); args.Add("-emit-llvm"); args.Add("-c"); args.Add("-gline-tables-only"); args.Add("-ffast-math"); args.Add("-serialize-diagnostics"); args.AddQuoted(Path.ChangeExtension(path, ".dia")); args.Add("-o"); args.AddQuoted(Path.ChangeExtension(path, ".air")); args.Add(string.Format("-m{0}-version-min={1}", OperatingSystem, minimumDeploymentTarget)); args.AddQuoted(SourceFile.ItemSpec); return(args.ToString()); }
public bool TryAdd(string version, BundleResource resource) { var addSuccessful = BundleVersions.TryAdd(version, new Dictionary <string, string>() { { "templates", version } }); addSuccessful = addSuccessful && Templates.v1.TryAdd(version, resource); return(addSuccessful); }
public override bool Execute() { var prefixes = BundleResource.SplitResourcePrefixes(ResourcePrefix); var intermediate = Path.Combine(IntermediateOutputPath, ToolName); var bundleResources = new List <ITaskItem> (); foreach (var input in EnumerateInputs()) { var relative = GetBundleRelativeOutputPath(prefixes, input); ITaskItem output; if (!string.IsNullOrEmpty(relative)) { string illegal; if (BundleResource.IsIllegalName(relative, out illegal)) { Log.LogError(null, null, null, input.ItemSpec, 0, 0, 0, 0, "The name '{0}' is reserved and cannot be used.", illegal); continue; } var rpath = Path.Combine(intermediate, relative); output = new TaskItem(rpath); } else { output = new TaskItem(intermediate); } output.SetMetadata("LogicalName", relative); if (NeedsBuilding(input, output)) { Directory.CreateDirectory(Path.GetDirectoryName(output.ItemSpec)); if (ExecuteTool(input, output) == -1) { return(false); } } bundleResources.AddRange(GetCompiledBundleResources(input, output)); } BundleResources = bundleResources.ToArray(); return(!Log.HasLoggedErrors); }
public void TestCreateResponse() { var twilioRestClient = Substitute.For <ITwilioRestClient>(); twilioRestClient.AccountSid.Returns("ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); twilioRestClient.Request(Arg.Any <Request>()) .Returns(new Response( System.Net.HttpStatusCode.Created, "{\"sid\": \"BUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"account_sid\": \"ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"regulation_sid\": \"RNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"friendly_name\": \"friendly_name\",\"status\": \"draft\",\"email\": \"email\",\"status_callback\": \"http://www.example.com\",\"date_created\": \"2019-07-30T22:29:24Z\",\"date_updated\": \"2019-07-31T01:09:00Z\",\"url\": \"https://numbers.twilio.com/v2/RegulatoryCompliance/Bundles/BUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"links\": {\"evaluations\": \"https://numbers.twilio.com/v2/RegulatoryCompliance/Bundles/BUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Evaluations\",\"item_assignments\": \"https://numbers.twilio.com/v2/RegulatoryCompliance/Bundles/BUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/ItemAssignments\"}}" )); var response = BundleResource.Create("friendly_name", "email", client: twilioRestClient); Assert.NotNull(response); }
public void TestDeleteResponse() { var twilioRestClient = Substitute.For <ITwilioRestClient>(); twilioRestClient.AccountSid.Returns("ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); twilioRestClient.Request(Arg.Any <Request>()) .Returns(new Response( System.Net.HttpStatusCode.NoContent, "null" )); var response = BundleResource.Delete("BUXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", client: twilioRestClient); Assert.NotNull(response); }
public void TestReadFullResponse() { var twilioRestClient = Substitute.For <ITwilioRestClient>(); twilioRestClient.AccountSid.Returns("ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); twilioRestClient.Request(Arg.Any <Request>()) .Returns(new Response( System.Net.HttpStatusCode.OK, "{\"results\": [{\"sid\": \"BUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"account_sid\": \"ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"regulation_sid\": \"RNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"friendly_name\": \"friendly_name\",\"status\": \"draft\",\"email\": \"email\",\"status_callback\": \"http://www.example.com\",\"date_created\": \"2019-07-30T22:29:24Z\",\"date_updated\": \"2019-07-31T01:09:00Z\",\"url\": \"https://numbers.twilio.com/v2/RegulatoryCompliance/Bundles/BUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"links\": {\"evaluations\": \"https://numbers.twilio.com/v2/RegulatoryCompliance/Bundles/BUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Evaluations\",\"item_assignments\": \"https://numbers.twilio.com/v2/RegulatoryCompliance/Bundles/BUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/ItemAssignments\"}}],\"meta\": {\"page\": 0,\"page_size\": 50,\"first_page_url\": \"https://numbers.twilio.com/v2/RegulatoryCompliance/Bundles?Status=draft&RegulationSid=RNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&IsoCountry=US&FriendlyName=friendly_name&NumberType=mobile&PageSize=50&Page=0\",\"previous_page_url\": null,\"url\": \"https://numbers.twilio.com/v2/RegulatoryCompliance/Bundles?Status=draft&RegulationSid=RNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&IsoCountry=US&FriendlyName=friendly_name&NumberType=mobile&PageSize=50&Page=0\",\"next_page_url\": null,\"key\": \"results\"}}" )); var response = BundleResource.Read(client: twilioRestClient); Assert.NotNull(response); }
public void TestReadEmptyResponse() { var twilioRestClient = Substitute.For <ITwilioRestClient>(); twilioRestClient.AccountSid.Returns("ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); twilioRestClient.Request(Arg.Any <Request>()) .Returns(new Response( System.Net.HttpStatusCode.OK, "{\"results\": [],\"meta\": {\"page\": 0,\"page_size\": 50,\"first_page_url\": \"https://numbers.twilio.com/v2/RegulatoryCompliance/Bundles?PageSize=50&Page=0\",\"previous_page_url\": null,\"url\": \"https://numbers.twilio.com/v2/RegulatoryCompliance/Bundles?PageSize=50&Page=0\",\"next_page_url\": null,\"key\": \"results\"}}" )); var response = BundleResource.Read(client: twilioRestClient); Assert.NotNull(response); }
protected override string GenerateCommandLineCommands() { var prefixes = BundleResource.SplitResourcePrefixes(ResourcePrefix); var intermediate = Path.Combine(IntermediateOutputPath, ToolName); var logicalName = BundleResource.GetLogicalName(ProjectDir, prefixes, SourceFile, !string.IsNullOrEmpty(SessionId)); var path = Path.Combine(intermediate, logicalName); var args = new CommandLineArgumentBuilder(); var dir = Path.GetDirectoryName(path); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } OutputFile = new TaskItem(Path.ChangeExtension(path, ".air")); OutputFile.SetMetadata("LogicalName", Path.ChangeExtension(logicalName, ".air")); args.Add("-arch", "air64"); args.Add("-emit-llvm"); args.Add("-c"); args.Add("-gline-tables-only"); args.Add("-ffast-math"); args.Add("-serialize-diagnostics"); args.AddQuoted(Path.ChangeExtension(path, ".dia")); args.Add("-o"); args.AddQuoted(Path.ChangeExtension(path, ".air")); if (Platform == ApplePlatform.MacCatalyst) { args.Add($"-target"); args.Add($"air64-apple-ios{MinimumOSVersion}-macabi"); } else { args.Add(PlatformFrameworkHelper.GetMinimumVersionArgument(TargetFrameworkMoniker, SdkIsSimulator, MinimumOSVersion)); } args.AddQuoted(SourceFile.ItemSpec); return(args.ToString()); }
public void TestReadRequest() { var twilioRestClient = Substitute.For <ITwilioRestClient>(); var request = new Request( HttpMethod.Get, Twilio.Rest.Domain.Numbers, "/v2/RegulatoryCompliance/Bundles", "" ); twilioRestClient.Request(request).Throws(new ApiException("Server Error, no content")); try { BundleResource.Read(client: twilioRestClient); Assert.Fail("Expected TwilioException to be thrown for 500"); } catch (ApiException) {} twilioRestClient.Received().Request(request); }
public override bool Execute() { if (Items != null) { var prefixes = BundleResource.SplitResourcePrefixes(ResourcePrefix); foreach (var item in Items) { var logical = BundleResource.GetLogicalName(ProjectDir, prefixes, item, !string.IsNullOrEmpty(SessionId)); if (logical == LogicalName) { Log.LogMessage(MessageImportance.Low, " {0} found at: {1}", LogicalName, item.ItemSpec); Item = item; break; } } } return(!Log.HasLoggedErrors); }
public void TestCreateRequest() { var twilioRestClient = Substitute.For <ITwilioRestClient>(); var request = new Request( HttpMethod.Post, Twilio.Rest.Domain.Numbers, "/v2/RegulatoryCompliance/Bundles", "" ); request.AddPostParam("FriendlyName", Serialize("friendly_name")); request.AddPostParam("Email", Serialize("email")); twilioRestClient.Request(request).Throws(new ApiException("Server Error, no content")); try { BundleResource.Create("friendly_name", "email", client: twilioRestClient); Assert.Fail("Expected TwilioException to be thrown for 500"); } catch (ApiException) {} twilioRestClient.Received().Request(request); }
private string TransformContent(BundleResource bundleResource, HttpContext context) { var bundleType = bundleResource.Type; var content = bundleResource.Content; var serverpath = bundleResource.ServerPath; try { if (bundleType == BundleResourceType.EmbeddedScript || bundleType == BundleResourceType.ScriptFile) { var compressor = new JavaScriptCompressor { CompressionType = CompressionType.Standard, Encoding = Encoding.UTF8, ObfuscateJavascript = bundleResource.ObfuscateJs }; //Minimize var contentOut = compressor.Compress(content.Trim()) + ";"; //Return deffered execution if (ClientSettings.IsJavascriptDefferingEnabled) { return string.Format(ClientSettings.JavascriptDefferingScript, JsonConvert.SerializeObject(contentOut)); } return contentOut; } if (!string.IsNullOrEmpty(serverpath)) { string directoryName = Path.GetDirectoryName(serverpath); if (directoryName != null) serverpath = directoryName.Replace('\\', '/'); } if (bundleType == BundleResourceType.EmbeddedStyle || bundleType == BundleResourceType.StyleFile) { var compressor = new CssCompressor { CompressionType = CompressionType.Standard, RemoveComments = true }; return ReplaceUrls(compressor.Compress(content), serverpath, context); } if (bundleType == BundleResourceType.LessFile) { DotlessConfiguration cfg = DotlessConfiguration.GetDefaultWeb(); cfg.Web = true; cfg.MinifyOutput = true; cfg.MapPathsToWeb = true; cfg.CacheEnabled = false; //Prefilter content = ReplaceImportRegex.Replace(content, match => ReplaceImports(match, serverpath)); string processed = ReplaceUrls(LessWeb.Parse(content, cfg), serverpath, context); return processed; } } catch (EcmaScript.NET.EcmaScriptException e) { _log.ErrorFormat("EcmaScriptException: {0} in {1} at {2} ({3}, {4}) at ", e.Message, serverpath, e.LineSource, e.LineNumber, e.ColumnNumber, e.ScriptStackTrace); } catch (Exception e) { _log.Error(e); } return content; }
protected virtual string GetBundleRelativeOutputPath(IList <string> prefixes, ITaskItem input) { return(BundleResource.GetLogicalName(ProjectDir, prefixes, input)); }
public override bool Execute() { var intermediate = Path.Combine(IntermediateOutputPath, ToolName); var intermediateBundleDir = Path.Combine(intermediate, "bundle"); var intermediateCloneDir = Path.Combine(intermediate, "cloned-assets"); var manifest = new TaskItem(Path.Combine(intermediate, "asset-manifest.plist")); var bundleResources = new List <ITaskItem> (); var outputManifests = new List <ITaskItem> (); var catalogs = new List <ITaskItem> (); var unique = new HashSet <string> (); string bundleIdentifier = null; var knownSpecs = new HashSet <string> (); var clones = new HashSet <string> (); var items = new List <ITaskItem> (); var specs = new PArray(); Log.LogTaskName("ACTool"); Log.LogTaskProperty("AppManifest", AppManifest); Log.LogTaskProperty("DeviceModel", DeviceModel); Log.LogTaskProperty("DeviceOSVersion", DeviceOSVersion); Log.LogTaskProperty("EnableOnDemandResources", EnableOnDemandResources); Log.LogTaskProperty("ImageAssets", ImageAssets); Log.LogTaskProperty("IntermediateOutputPath", IntermediateOutputPath); Log.LogTaskProperty("IsWatchApp", IsWatchApp); Log.LogTaskProperty("OptimizePNGs", OptimizePNGs); Log.LogTaskProperty("OutputPath", OutputPath); Log.LogTaskProperty("ProjectDir", ProjectDir); Log.LogTaskProperty("ResourcePrefix", ResourcePrefix); Log.LogTaskProperty("SdkBinPath", SdkBinPath); Log.LogTaskProperty("SdkPlatform", SdkPlatform); Log.LogTaskProperty("SdkVersion", SdkVersion); switch (SdkPlatform) { case "iPhoneSimulator": case "iPhoneOS": case "MacOSX": case "WatchSimulator": case "WatchOS": case "AppleTVSimulator": case "AppleTVOS": break; default: Log.LogError("Unrecognized platform: {0}", SdkPlatform); return(false); } if (AppManifest != null) { try { plist = PDictionary.FromFile(AppManifest.ItemSpec); } catch (Exception ex) { Log.LogError(null, null, null, AppManifest.ItemSpec, 0, 0, 0, 0, "{0}", ex.Message); return(false); } bundleIdentifier = plist.GetCFBundleIdentifier(); } for (int i = 0; i < ImageAssets.Length; i++) { var vpath = BundleResource.GetVirtualProjectPath(ProjectDir, ImageAssets[i], !string.IsNullOrEmpty(SessionId)); // Ignore MacOS .DS_Store files... if (Path.GetFileName(vpath).Equals(".DS_Store", StringComparison.OrdinalIgnoreCase)) { continue; } // get the parent (which will typically be .appiconset, .launchimage, .imageset, .iconset, etc) var catalog = Path.GetDirectoryName(vpath); // keep walking up the directory structure until we get to the .xcassets directory while (!string.IsNullOrEmpty(catalog) && Path.GetExtension(catalog) != ".xcassets") { catalog = Path.GetDirectoryName(catalog); } if (string.IsNullOrEmpty(catalog)) { Log.LogWarning(null, null, null, ImageAssets[i].ItemSpec, 0, 0, 0, 0, "Asset not part of an asset catalog: {0}", ImageAssets[i].ItemSpec); continue; } if (ImageAssets[i].GetMetadata("Link") != null) { // Note: if any of the files within a catalog are linked, we'll have to clone the *entire* catalog clones.Add(catalog); continue; } // filter out everything except paths containing a Contents.json file since our main processing loop only cares about these if (Path.GetFileName(vpath) != "Contents.json") { continue; } items.Add(ImageAssets[i]); } // clone any *.xcassets dirs that need cloning if (clones.Count > 0) { if (Directory.Exists(intermediateCloneDir)) { Directory.Delete(intermediateCloneDir, true); } Directory.CreateDirectory(intermediateCloneDir); items.Clear(); for (int i = 0; i < ImageAssets.Length; i++) { var vpath = BundleResource.GetVirtualProjectPath(ProjectDir, ImageAssets[i], !string.IsNullOrEmpty(SessionId)); var clone = false; ITaskItem item; // Ignore MacOS .DS_Store files... if (Path.GetFileName(vpath).Equals(".DS_Store", StringComparison.OrdinalIgnoreCase)) { continue; } foreach (var catalog in clones) { if (vpath.Length > catalog.Length && vpath[catalog.Length] == '/' && vpath.StartsWith(catalog, StringComparison.Ordinal)) { clone = true; break; } } if (clone) { var src = ImageAssets[i].GetMetadata("FullPath"); if (!File.Exists(src)) { Log.LogError(null, null, null, src, 0, 0, 0, 0, "File not found: {0}", src); return(false); } var dest = Path.Combine(intermediateCloneDir, vpath); var dir = Path.GetDirectoryName(dest); Directory.CreateDirectory(dir); File.Copy(src, dest, true); // filter out everything except paths containing a Contents.json file since our main processing loop only cares about these if (Path.GetFileName(vpath) != "Contents.json") { continue; } item = new TaskItem(dest); ImageAssets[i].CopyMetadataTo(item); item.SetMetadata("Link", vpath); } else { // filter out everything except paths containing a Contents.json file since our main processing loop only cares about these if (Path.GetFileName(vpath) != "Contents.json") { continue; } item = ImageAssets[i]; } items.Add(item); } } // Note: `items` contains only the Contents.json files at this point for (int i = 0; i < items.Count; i++) { var vpath = BundleResource.GetVirtualProjectPath(ProjectDir, items[i], !string.IsNullOrEmpty(SessionId)); var path = items[i].GetMetadata("FullPath"); // get the parent (which will typically be .appiconset, .launchimage, .imageset, .iconset, etc) var catalog = Path.GetDirectoryName(vpath); path = Path.GetDirectoryName(path); // keep walking up the directory structure until we get to the .xcassets directory while (!string.IsNullOrEmpty(catalog) && Path.GetExtension(catalog) != ".xcassets") { catalog = Path.GetDirectoryName(catalog); path = Path.GetDirectoryName(path); } if (unique.Add(catalog)) { var item = new TaskItem(path); item.SetMetadata("Link", catalog); catalogs.Add(item); } if (AppleSdkSettings.XcodeVersion.Major >= 7 && !string.IsNullOrEmpty(bundleIdentifier) && SdkPlatform != "WatchSimulator") { var text = File.ReadAllText(items[i].ItemSpec); if (string.IsNullOrEmpty(text)) { continue; } var json = JsonConvert.DeserializeObject(text) as JObject; if (json == null) { continue; } var properties = json.Property("properties"); if (properties == null) { continue; } var resourceTags = properties.Value.ToObject <JObject> ().Property("on-demand-resource-tags"); if (resourceTags == null || resourceTags.Value.Type != JTokenType.Array) { continue; } var tagArray = resourceTags.Value.ToObject <JArray> (); var tags = new HashSet <string> (); string hash; foreach (var tag in tagArray.Select(token => token.ToObject <string> ())) { tags.Add(tag); } var tagList = tags.ToList(); tagList.Sort(); var assetDir = AssetPackUtils.GetAssetPackDirectory(intermediate, bundleIdentifier, tagList, out hash); if (knownSpecs.Add(hash)) { var assetpack = new PDictionary(); var ptags = new PArray(); Directory.CreateDirectory(assetDir); for (int j = 0; j < tagList.Count; j++) { ptags.Add(new PString(tagList[j])); } assetpack.Add("bundle-id", new PString(string.Format("{0}.asset-pack-{1}", bundleIdentifier, hash))); assetpack.Add("bundle-path", new PString(Path.GetFullPath(assetDir))); assetpack.Add("tags", ptags); specs.Add(assetpack); } } } if (catalogs.Count == 0) { // There are no (supported?) asset catalogs return(true); } partialAppManifest = new TaskItem(Path.Combine(intermediate, "partial-info.plist")); if (specs.Count > 0) { outputSpecs = Path.Combine(intermediate, "output-specifications.plist"); specs.Save(outputSpecs, true); } Directory.CreateDirectory(intermediateBundleDir); // Note: Compile() will set the PartialAppManifest property if it is used... if ((Compile(catalogs.ToArray(), intermediateBundleDir, manifest)) != 0) { return(false); } if (PartialAppManifest != null && !File.Exists(PartialAppManifest.GetMetadata("FullPath"))) { Log.LogError("Partial Info.plist file was not generated: {0}", PartialAppManifest.GetMetadata("FullPath")); } try { var manifestOutput = PDictionary.FromFile(manifest.ItemSpec); LogWarningsAndErrors(manifestOutput, catalogs[0]); bundleResources.AddRange(GetCompiledBundleResources(manifestOutput, intermediateBundleDir)); outputManifests.Add(manifest); } catch (Exception ex) { Log.LogError("Failed to load output manifest for {0} for the file {2}: {1}", ToolName, ex.Message, manifest.ItemSpec); } foreach (var assetpack in specs.OfType <PDictionary> ()) { var path = Path.Combine(assetpack.GetString("bundle-path").Value, "Info.plist"); var bundlePath = PathUtils.AbsoluteToRelative(intermediate, path); var outputPath = Path.Combine(OutputPath, bundlePath); var rpath = Path.Combine(intermediate, bundlePath); var dict = new PDictionary(); dict.SetCFBundleIdentifier(assetpack.GetString("bundle-id").Value); dict.Add("Tags", assetpack.GetArray("tags").Clone()); dict.Save(path, true, true); var item = new TaskItem(rpath); item.SetMetadata("LogicalName", bundlePath); item.SetMetadata("OutputPath", outputPath); item.SetMetadata("Optimize", "false"); bundleResources.Add(item); } BundleResources = bundleResources.ToArray(); OutputManifests = outputManifests.ToArray(); return(!Log.HasLoggedErrors); }
public override bool Execute() { Log.LogTaskName("CompileSceneKitAssets"); Log.LogTaskProperty("IntermediateOutputPath", IntermediateOutputPath); Log.LogTaskProperty("ProjectDir", ProjectDir); Log.LogTaskProperty("ResourcePrefix", ResourcePrefix); Log.LogTaskProperty("SceneKitAssets", SceneKitAssets); Log.LogTaskProperty("SdkDevPath", SdkDevPath); Log.LogTaskProperty("SdkRoot", SdkRoot); Log.LogTaskProperty("SdkVersion", SdkVersion); var prefixes = BundleResource.SplitResourcePrefixes(ResourcePrefix); var intermediate = Path.Combine(IntermediateOutputPath, ToolName); var bundleResources = new List <ITaskItem> (); var modified = new HashSet <string> (); var items = new List <ITaskItem> (); string metadata; foreach (var asset in SceneKitAssets) { if (!File.Exists(asset.ItemSpec)) { continue; } // get the .scnassets directory path var scnassets = Path.GetDirectoryName(asset.ItemSpec); while (scnassets.Length > 0 && Path.GetExtension(scnassets).ToLowerInvariant() != ".scnassets") { scnassets = Path.GetDirectoryName(scnassets); } if (scnassets.Length == 0) { continue; } metadata = asset.GetMetadata("LogicalName"); if (!string.IsNullOrEmpty(metadata)) { asset.SetMetadata("LogicalName", string.Empty); } var bundleName = BundleResource.GetLogicalName(ProjectDir, prefixes, asset, !string.IsNullOrEmpty(SessionId)); var output = new TaskItem(Path.Combine(intermediate, bundleName)); if (!modified.Contains(scnassets) && (!File.Exists(output.ItemSpec) || File.GetLastWriteTimeUtc(asset.ItemSpec) > File.GetLastWriteTimeUtc(output.ItemSpec))) { var item = new TaskItem(scnassets); metadata = asset.GetMetadata("DefiningProjectFullPath"); if (!string.IsNullOrEmpty(metadata)) { item.SetMetadata("DefiningProjectFullPath", metadata); } modified.Add(scnassets); items.Add(item); } output.SetMetadata("LogicalName", bundleName); output.SetMetadata("Optimize", "false"); bundleResources.Add(output); } if (modified.Count == 0) { BundleResources = bundleResources.ToArray(); return(!Log.HasLoggedErrors); } if (!Directory.Exists(intermediate)) { Directory.CreateDirectory(intermediate); } foreach (var item in items) { var bundleDir = BundleResource.GetLogicalName(ProjectDir, prefixes, new TaskItem(item), !string.IsNullOrEmpty(SessionId)); var output = Path.Combine(intermediate, bundleDir); if (CopySceneKitAssets(item.ItemSpec, output, intermediate) == -1) { return(false); } } BundleResources = bundleResources.ToArray(); return(!Log.HasLoggedErrors); }
public override bool Execute() { var intermediate = Path.Combine(IntermediateOutputPath, ToolName); var intermediateBundleDir = Path.Combine(intermediate, "bundle"); var manifest = new TaskItem(Path.Combine(intermediate, "asset-manifest.plist")); var bundleResources = new List <ITaskItem> (); var outputManifests = new List <ITaskItem> (); var catalogs = new List <ITaskItem> (); var unique = new HashSet <string> (); string bundleIdentifier = null; var knownSpecs = new HashSet <string> (); var specs = new PArray(); int rc; Log.LogTaskName("ACTool"); Log.LogTaskProperty("AppManifest", AppManifest); Log.LogTaskProperty("DeviceModel", DeviceModel); Log.LogTaskProperty("DeviceOSVersion", DeviceOSVersion); Log.LogTaskProperty("ImageAssets", ImageAssets); Log.LogTaskProperty("IntermediateOutputPath", IntermediateOutputPath); Log.LogTaskProperty("IsWatchApp", IsWatchApp); Log.LogTaskProperty("OptimizePNGs", OptimizePNGs); Log.LogTaskProperty("OutputPath", OutputPath); Log.LogTaskProperty("ProjectDir", ProjectDir); Log.LogTaskProperty("ResourcePrefix", ResourcePrefix); Log.LogTaskProperty("SdkBinPath", SdkBinPath); Log.LogTaskProperty("SdkPlatform", SdkPlatform); Log.LogTaskProperty("SdkVersion", SdkVersion); switch (SdkPlatform) { case "iPhoneSimulator": case "iPhoneOS": case "MacOSX": case "WatchSimulator": case "WatchOS": case "AppleTVSimulator": case "AppleTVOS": break; default: Log.LogError("Unrecognized platform: {0}", SdkPlatform); return(false); } if (AppManifest != null) { try { plist = PDictionary.FromFile(AppManifest.ItemSpec); } catch (Exception ex) { Log.LogError(null, null, null, AppManifest.ItemSpec, 0, 0, 0, 0, "{0}", ex.Message); return(false); } bundleIdentifier = plist.GetCFBundleIdentifier(); } foreach (var asset in ImageAssets) { var vpath = BundleResource.GetVirtualProjectPath(ProjectDir, asset); if (Path.GetFileName(vpath) != "Contents.json") { continue; } // get the parent (which will typically be .appiconset, .launchimage, .imageset, .iconset, etc) var catalog = Path.GetDirectoryName(vpath); // keep walking up the directory structure until we get to the .xcassets directory while (!string.IsNullOrEmpty(catalog) && Path.GetExtension(catalog) != ".xcassets") { catalog = Path.GetDirectoryName(catalog); } if (string.IsNullOrEmpty(catalog)) { Log.LogWarning(null, null, null, asset.ItemSpec, 0, 0, 0, 0, "Asset not part of an asset catalog: {0}", asset.ItemSpec); continue; } if (unique.Add(catalog)) { catalogs.Add(new TaskItem(catalog)); } if (AppleSdkSettings.XcodeVersion.Major >= 7 && !string.IsNullOrEmpty(bundleIdentifier) && SdkPlatform != "WatchSimulator") { var text = File.ReadAllText(asset.ItemSpec); if (string.IsNullOrEmpty(text)) { continue; } var json = JsonConvert.DeserializeObject(text) as JObject; if (json == null) { continue; } var properties = json.Property("properties"); if (properties == null) { continue; } var resourceTags = properties.Value.ToObject <JObject> ().Property("on-demand-resource-tags"); if (resourceTags == null || resourceTags.Value.Type != JTokenType.Array) { continue; } var tagArray = resourceTags.Value.ToObject <JArray> (); var tags = new HashSet <string> (); string hash; foreach (var tag in tagArray.Select(token => token.ToObject <string> ())) { tags.Add(tag); } var tagList = tags.ToList(); tagList.Sort(); var path = AssetPackUtils.GetAssetPackDirectory(intermediate, bundleIdentifier, tagList, out hash); if (knownSpecs.Add(hash)) { var assetpack = new PDictionary(); var ptags = new PArray(); Directory.CreateDirectory(path); for (int i = 0; i < tags.Count; i++) { ptags.Add(new PString(tagList[i])); } assetpack.Add("bundle-id", new PString(string.Format("{0}.asset-pack-{1}", bundleIdentifier, hash))); assetpack.Add("bundle-path", new PString(Path.GetFullPath(path))); assetpack.Add("tags", ptags); specs.Add(assetpack); } } } if (catalogs.Count == 0) { // There are no (supported?) asset catalogs return(true); } partialAppManifest = new TaskItem(Path.Combine(intermediate, "partial-info.plist")); if (specs.Count > 0) { outputSpecs = Path.Combine(intermediate, "output-specifications.plist"); specs.Save(outputSpecs, true); } var output = new TaskItem(intermediateBundleDir); Directory.CreateDirectory(intermediateBundleDir); // Note: Compile() will set the PartialAppManifest property if it is used... if ((rc = Compile(catalogs.ToArray(), output, manifest)) != 0) { if (File.Exists(manifest.ItemSpec)) { try { var log = PDictionary.FromFile(manifest.ItemSpec); LogWarningsAndErrors(log, catalogs[0]); } catch (FormatException) { Log.LogError("actool exited with code {0}", rc); } File.Delete(manifest.ItemSpec); } return(false); } if (PartialAppManifest != null && !File.Exists(PartialAppManifest.GetMetadata("FullPath"))) { Log.LogError("Partial Info.plist file was not generated: {0}", PartialAppManifest.GetMetadata("FullPath")); } try { var manifestOutput = PDictionary.FromFile(manifest.ItemSpec); LogWarningsAndErrors(manifestOutput, catalogs[0]); bundleResources.AddRange(GetCompiledBundleResources(manifestOutput, intermediateBundleDir)); outputManifests.Add(manifest); } catch (Exception ex) { Log.LogError("Failed to load output manifest for {0} for the file {2}: {1}", ToolName, ex.Message, manifest.ItemSpec); } foreach (var assetpack in specs.OfType <PDictionary> ()) { var path = Path.Combine(assetpack.GetString("bundle-path").Value, "Info.plist"); var bundlePath = PathUtils.AbsoluteToRelative(intermediate, path); var outputPath = Path.Combine(OutputPath, bundlePath); var rpath = Path.Combine(intermediate, bundlePath); var dict = new PDictionary(); dict.SetCFBundleIdentifier(assetpack.GetString("bundle-id").Value); dict.Add("Tags", assetpack.GetArray("tags").Clone()); dict.Save(path, true, true); var item = new TaskItem(rpath); item.SetMetadata("LogicalName", bundlePath); item.SetMetadata("OutputPath", outputPath); item.SetMetadata("Optimize", "false"); bundleResources.Add(item); } BundleResources = bundleResources.ToArray(); OutputManifests = outputManifests.ToArray(); return(!Log.HasLoggedErrors); }
protected override void AppendCommandLineArguments(IDictionary <string, string> environment, ProcessArgumentBuilder args, ITaskItem[] items) { string minimumDeploymentTarget; if (plist != null) { PString value; if (!plist.TryGetValue(MinimumDeploymentTargetKey, out value) || string.IsNullOrEmpty(value.Value)) { minimumDeploymentTarget = SdkVersion; } else { minimumDeploymentTarget = value.Value; } var assetDirs = new HashSet <string> (items.Select(x => BundleResource.GetVirtualProjectPath(ProjectDir, x, !string.IsNullOrEmpty(SessionId)))); if (plist.TryGetValue(ManifestKeys.XSAppIconAssets, out value) && !string.IsNullOrEmpty(value.Value)) { int index = value.Value.IndexOf(".xcassets" + Path.DirectorySeparatorChar, StringComparison.Ordinal); string assetDir = null; var rpath = value.Value; if (index != -1) { assetDir = rpath.Substring(0, index + ".xcassets".Length); } if (assetDirs != null && assetDirs.Contains(assetDir)) { var assetName = Path.GetFileNameWithoutExtension(rpath); if (PartialAppManifest == null) { args.Add("--output-partial-info-plist"); args.AddQuoted(partialAppManifest.GetMetadata("FullPath")); PartialAppManifest = partialAppManifest; } args.Add("--app-icon"); args.AddQuoted(assetName); if (IsMessagesExtension(plist)) { args.Add("--product-type com.apple.product-type.app-extension.messages"); } } } if (plist.TryGetValue(ManifestKeys.XSLaunchImageAssets, out value) && !string.IsNullOrEmpty(value.Value)) { int index = value.Value.IndexOf(".xcassets" + Path.DirectorySeparatorChar, StringComparison.Ordinal); string assetDir = null; var rpath = value.Value; if (index != -1) { assetDir = rpath.Substring(0, index + ".xcassets".Length); } if (assetDirs != null && assetDirs.Contains(assetDir)) { var assetName = Path.GetFileNameWithoutExtension(rpath); if (PartialAppManifest == null) { args.Add("--output-partial-info-plist"); args.AddQuoted(partialAppManifest.GetMetadata("FullPath")); PartialAppManifest = partialAppManifest; } args.Add("--launch-image"); args.AddQuoted(assetName); } } if (plist.TryGetValue(ManifestKeys.CLKComplicationGroup, out value) && !string.IsNullOrEmpty(value.Value)) { args.Add("--complication", value); } } else { minimumDeploymentTarget = SdkVersion; } if (OptimizePNGs) { args.Add("--compress-pngs"); } if (AppleSdkSettings.XcodeVersion.Major >= 7) { if (!string.IsNullOrEmpty(outputSpecs)) { args.Add("--enable-on-demand-resources", EnableOnDemandResources ? "YES" : "NO"); } if (!string.IsNullOrEmpty(DeviceModel)) { args.Add("--filter-for-device-model", DeviceModel); } if (!string.IsNullOrEmpty(DeviceOSVersion)) { args.Add("--filter-for-device-os-version", DeviceOSVersion); } if (!string.IsNullOrEmpty(outputSpecs)) { args.Add("--asset-pack-output-specifications"); args.AddQuoted(Path.GetFullPath(outputSpecs)); } } if (plist != null) { foreach (var targetDevice in GetTargetDevices(plist)) { args.Add("--target-device", targetDevice); } } args.Add("--minimum-deployment-target", minimumDeploymentTarget); switch (SdkPlatform) { case "iPhoneSimulator": args.Add("--platform", IsWatchApp ? "watchsimulator" : "iphonesimulator"); break; case "iPhoneOS": args.Add("--platform", IsWatchApp ? "watchos" : "iphoneos"); break; case "MacOSX": args.Add("--platform", "macosx"); break; case "WatchSimulator": args.Add("--platform", "watchsimulator"); break; case "WatchOS": args.Add("--platform", "watchos"); break; case "AppleTVSimulator": args.Add("--platform", "appletvsimulator"); break; case "AppleTVOS": args.Add("--platform", "appletvos"); break; } }
void RegisterFonts(PDictionary plist) { if (FontFilesToRegister == null || FontFilesToRegister.Length == 0) { return; } // https://developer.apple.com/documentation/swiftui/applying-custom-fonts-to-text // Compute the relative location in the app bundle for each font file var prefixes = BundleResource.SplitResourcePrefixes(ResourcePrefix); const string logicalNameKey = "_ComputedLogicalName_"; foreach (var item in FontFilesToRegister) { var logicalName = BundleResource.GetLogicalName(ProjectDir, prefixes, item, !string.IsNullOrEmpty(SessionId)); item.SetMetadata(logicalNameKey, logicalName); } switch (Platform) { case ApplePlatform.iOS: case ApplePlatform.TVOS: case ApplePlatform.WatchOS: case ApplePlatform.MacCatalyst: // Fonts are listed in the Info.plist in a UIAppFonts entry for iOS, tvOS, watchOS and Mac Catalyst. var uiAppFonts = plist.GetArray("UIAppFonts"); if (uiAppFonts == null) { uiAppFonts = new PArray(); plist ["UIAppFonts"] = uiAppFonts; } foreach (var item in FontFilesToRegister) { uiAppFonts.Add(new PString(item.GetMetadata(logicalNameKey))); } break; case ApplePlatform.MacOSX: // The directory where the fonts are located is in the Info.plist in the ATSApplicationFontsPath entry for macOS. // It's relative to the Resources directory. // Make sure that all the fonts are in the same directory in the app bundle var allSubdirectories = FontFilesToRegister.Select(v => Path.GetDirectoryName(v.GetMetadata(logicalNameKey))); var distinctSubdirectories = allSubdirectories.Distinct().ToArray(); if (distinctSubdirectories.Length > 1) { Log.LogError(MSBStrings.E7083 /* "All font files must be located in the same directory in the app bundle. The following font files have different target directories in the app bundle:" */, CompiledAppManifest.ItemSpec); foreach (var fonts in FontFilesToRegister) { Log.LogError(null, null, null, fonts.ItemSpec, 0, 0, 0, 0, MSBStrings.E7084 /* "The target directory is {0}" */, fonts.GetMetadata(logicalNameKey)); } } else { plist.SetIfNotPresent("ATSApplicationFontsPath", string.IsNullOrEmpty(distinctSubdirectories [0]) ? "." : distinctSubdirectories [0]); } break; default: throw new InvalidOperationException(string.Format(MSBStrings.InvalidPlatform, Platform)); } }
public override bool Execute() { var intermediate = Path.Combine(IntermediateOutputPath, ToolName); var intermediateBundleDir = Path.Combine(intermediate, "bundle"); var intermediateCloneDir = Path.Combine(intermediate, "cloned-assets"); var manifest = new TaskItem(Path.Combine(intermediate, "asset-manifest.plist")); var bundleResources = new List <ITaskItem> (); var outputManifests = new List <ITaskItem> (); var catalogs = new List <ITaskItem> (); var unique = new HashSet <string> (); var knownSpecs = new HashSet <string> (); var clones = new HashSet <string> (); var items = new List <ITaskItem> (); var specs = new PArray(); if (AppManifest != null) { try { plist = PDictionary.FromFile(AppManifest.ItemSpec); } catch (Exception ex) { Log.LogError(null, null, null, AppManifest.ItemSpec, 0, 0, 0, 0, "{0}", ex.Message); return(false); } } for (int i = 0; i < ImageAssets.Length; i++) { var vpath = BundleResource.GetVirtualProjectPath(ProjectDir, ImageAssets[i], !string.IsNullOrEmpty(SessionId)); // Ignore MacOS .DS_Store files... if (Path.GetFileName(vpath).Equals(".DS_Store", StringComparison.OrdinalIgnoreCase)) { continue; } // get the parent (which will typically be .appiconset, .launchimage, .imageset, .iconset, etc) var catalog = Path.GetDirectoryName(vpath); // keep walking up the directory structure until we get to the .xcassets directory while (!string.IsNullOrEmpty(catalog) && Path.GetExtension(catalog) != ".xcassets") { catalog = Path.GetDirectoryName(catalog); } if (string.IsNullOrEmpty(catalog)) { Log.LogWarning(null, null, null, ImageAssets[i].ItemSpec, 0, 0, 0, 0, MSBStrings.W0090, ImageAssets[i].ItemSpec); continue; } if (ImageAssets[i].GetMetadata("Link") != null) { // Note: if any of the files within a catalog are linked, we'll have to clone the *entire* catalog clones.Add(catalog); continue; } // filter out everything except paths containing a Contents.json file since our main processing loop only cares about these if (Path.GetFileName(vpath) != "Contents.json") { continue; } items.Add(ImageAssets[i]); } // clone any *.xcassets dirs that need cloning if (clones.Count > 0) { if (Directory.Exists(intermediateCloneDir)) { Directory.Delete(intermediateCloneDir, true); } Directory.CreateDirectory(intermediateCloneDir); items.Clear(); for (int i = 0; i < ImageAssets.Length; i++) { var vpath = BundleResource.GetVirtualProjectPath(ProjectDir, ImageAssets[i], !string.IsNullOrEmpty(SessionId)); var clone = false; ITaskItem item; // Ignore MacOS .DS_Store files... if (Path.GetFileName(vpath).Equals(".DS_Store", StringComparison.OrdinalIgnoreCase)) { continue; } foreach (var catalog in clones) { if (vpath.Length > catalog.Length && vpath[catalog.Length] == '/' && vpath.StartsWith(catalog, StringComparison.Ordinal)) { clone = true; break; } } if (clone) { var src = ImageAssets[i].GetMetadata("FullPath"); if (!File.Exists(src)) { Log.LogError(null, null, null, src, 0, 0, 0, 0, MSBStrings.E0091, src); return(false); } var dest = Path.Combine(intermediateCloneDir, vpath); var dir = Path.GetDirectoryName(dest); Directory.CreateDirectory(dir); File.Copy(src, dest, true); // filter out everything except paths containing a Contents.json file since our main processing loop only cares about these if (Path.GetFileName(vpath) != "Contents.json") { continue; } item = new TaskItem(dest); ImageAssets[i].CopyMetadataTo(item); item.SetMetadata("Link", vpath); } else { // filter out everything except paths containing a Contents.json file since our main processing loop only cares about these if (Path.GetFileName(vpath) != "Contents.json") { continue; } item = ImageAssets[i]; } items.Add(item); } } // Note: `items` contains only the Contents.json files at this point for (int i = 0; i < items.Count; i++) { var vpath = BundleResource.GetVirtualProjectPath(ProjectDir, items[i], !string.IsNullOrEmpty(SessionId)); var path = items[i].GetMetadata("FullPath"); // get the parent (which will typically be .appiconset, .launchimage, .imageset, .iconset, etc) var catalog = Path.GetDirectoryName(vpath); path = Path.GetDirectoryName(path); // keep walking up the directory structure until we get to the .xcassets directory while (!string.IsNullOrEmpty(catalog) && Path.GetExtension(catalog) != ".xcassets") { catalog = Path.GetDirectoryName(catalog); path = Path.GetDirectoryName(path); } if (unique.Add(catalog)) { var item = new TaskItem(path); item.SetMetadata("Link", catalog); catalogs.Add(item); } if (AppleSdkSettings.XcodeVersion.Major >= 7 && SdkPlatform != "WatchSimulator") { var text = File.ReadAllText(items[i].ItemSpec); if (string.IsNullOrEmpty(text)) { continue; } JsonDocument json; JsonElement value; try { var options = new JsonDocumentOptions() { AllowTrailingCommas = true, }; json = JsonDocument.Parse(text, options); } catch (JsonException je) { var line = (int)(je.LineNumber + 1 ?? 0); var col = (int)(je.BytePositionInLine + 1 ?? 0); Log.LogError(null, null, null, items [i].ItemSpec, line, col, line, col, "{0}", je.Message); return(false); } catch (Exception e) { Log.LogError(null, null, null, items[i].ItemSpec, 0, 0, 0, 0, MSBStrings.E0092, e.Message); return(false); } if (!json.RootElement.TryGetProperty("properties", out value) || value.ValueKind != JsonValueKind.Object) { continue; } var properties = value; if (!properties.TryGetProperty("on-demand-resource-tags", out value) || value.ValueKind != JsonValueKind.Array) { continue; } var resourceTags = value; var tags = new HashSet <string> (); string hash; foreach (var tag in resourceTags.EnumerateArray()) { if (tag.ValueKind == JsonValueKind.String) { tags.Add(tag.GetString()); } } var tagList = tags.ToList(); tagList.Sort(); var assetDir = AssetPackUtils.GetAssetPackDirectory(intermediate, BundleIdentifier, tagList, out hash); if (knownSpecs.Add(hash)) { var assetpack = new PDictionary(); var ptags = new PArray(); Directory.CreateDirectory(assetDir); for (int j = 0; j < tagList.Count; j++) { ptags.Add(new PString(tagList[j])); } assetpack.Add("bundle-id", new PString(string.Format("{0}.asset-pack-{1}", BundleIdentifier, hash))); assetpack.Add("bundle-path", new PString(Path.GetFullPath(assetDir))); assetpack.Add("tags", ptags); specs.Add(assetpack); } } } if (catalogs.Count == 0) { // There are no (supported?) asset catalogs return(!Log.HasLoggedErrors); } partialAppManifest = new TaskItem(Path.Combine(intermediate, "partial-info.plist")); if (specs.Count > 0) { outputSpecs = Path.Combine(intermediate, "output-specifications.plist"); specs.Save(outputSpecs, true); } Directory.CreateDirectory(intermediateBundleDir); // Note: Compile() will set the PartialAppManifest property if it is used... if ((Compile(catalogs.ToArray(), intermediateBundleDir, manifest)) != 0) { return(false); } if (PartialAppManifest != null && !File.Exists(PartialAppManifest.GetMetadata("FullPath"))) { Log.LogError(MSBStrings.E0093, PartialAppManifest.GetMetadata("FullPath")); } try { var manifestOutput = PDictionary.FromFile(manifest.ItemSpec); LogWarningsAndErrors(manifestOutput, catalogs[0]); bundleResources.AddRange(GetCompiledBundleResources(manifestOutput, intermediateBundleDir)); outputManifests.Add(manifest); } catch (Exception ex) { Log.LogError(MSBStrings.E0094, ToolName, manifest.ItemSpec, ex.Message); } foreach (var assetpack in specs.OfType <PDictionary> ()) { var path = Path.Combine(assetpack.GetString("bundle-path").Value, "Info.plist"); var bundlePath = PathUtils.AbsoluteToRelative(intermediate, path); var outputPath = Path.Combine(OutputPath, bundlePath); var rpath = Path.Combine(intermediate, bundlePath); var dict = new PDictionary(); dict.SetCFBundleIdentifier(assetpack.GetString("bundle-id").Value); dict.Add("Tags", assetpack.GetArray("tags").Clone()); dict.Save(path, true, true); var item = new TaskItem(rpath); item.SetMetadata("LogicalName", bundlePath); item.SetMetadata("OutputPath", outputPath); item.SetMetadata("Optimize", "false"); bundleResources.Add(item); } BundleResources = bundleResources.ToArray(); OutputManifests = outputManifests.ToArray(); return(!Log.HasLoggedErrors); }
public override bool Execute() { var prefixes = BundleResource.SplitResourcePrefixes(ResourcePrefix); var bundleResources = new List <ITaskItem> (); if (BundleResources != null) { foreach (var item in BundleResources) { var logicalName = BundleResource.GetLogicalName(ProjectDir, prefixes, item, !string.IsNullOrEmpty(SessionId)); // We need a physical path here, ignore the Link element var path = item.GetMetadata("FullPath"); string illegal; if (!File.Exists(path)) { Log.LogError(" Bundle Resource '{0}' not found on disk (should be at '{1}')", logicalName, path); continue; } if (logicalName.StartsWith(".." + Path.DirectorySeparatorChar, StringComparison.Ordinal)) { Log.LogError(null, null, null, item.ItemSpec, 0, 0, 0, 0, "The path '{0}' would result in a file outside of the app bundle and cannot be used.", logicalName); continue; } if (logicalName == "Info.plist") { Log.LogWarning(null, null, null, item.ItemSpec, 0, 0, 0, 0, "Info.plist files should have a Build Action of 'None'."); continue; } if (BundleResource.IsIllegalName(logicalName, out illegal)) { Log.LogError(null, null, null, item.ItemSpec, 0, 0, 0, 0, "The name '{0}' is reserved and cannot be used.", illegal); continue; } var bundleResource = new TaskItem(item); bundleResource.SetMetadata("LogicalName", logicalName); bool optimize = false; if (CanOptimize(item.ItemSpec)) { var metadata = item.GetMetadata("Optimize"); // fall back to old metadata name if (string.IsNullOrEmpty(metadata)) { metadata = item.GetMetadata("OptimizeImage"); } if (string.IsNullOrEmpty(metadata) || !bool.TryParse(metadata, out optimize)) { switch (Path.GetExtension(item.ItemSpec).ToLowerInvariant()) { case ".plist": case ".strings": optimize = OptimizePropertyLists; break; case ".png": optimize = OptimizePNGs; break; } } } bundleResource.SetMetadata("Optimize", optimize.ToString()); bundleResources.Add(bundleResource); } } BundleResourcesWithLogicalNames = bundleResources.ToArray(); return(!Log.HasLoggedErrors); }
public override bool Execute() { var coremlcOutputDir = Path.Combine(IntermediateOutputPath, "coremlc"); var prefixes = BundleResource.SplitResourcePrefixes(ResourcePrefix); var mapping = new Dictionary <string, IDictionary> (); var bundleResources = new List <ITaskItem> (); var partialPlists = new List <ITaskItem> (); if (Models.Length > 0) { Directory.CreateDirectory(coremlcOutputDir); foreach (var model in Models) { var logicalName = BundleResource.GetLogicalName(ProjectDir, prefixes, model, !string.IsNullOrEmpty(SessionId)); var bundleName = GetPathWithoutExtension(logicalName) + ".mlmodelc"; var outputPath = Path.Combine(coremlcOutputDir, bundleName); var outputDir = Path.GetDirectoryName(outputPath); var partialPlist = GetPathWithoutExtension(outputPath) + "-partial.plist"; var log = GetPathWithoutExtension(outputPath) + ".log"; var resourceTags = model.GetMetadata("ResourceTags"); var output = new TaskItem(outputPath); output.SetMetadata("LogicalName", bundleName); output.SetMetadata("Optimize", "false"); if (EnableOnDemandResources && !string.IsNullOrEmpty(resourceTags)) { output.SetMetadata("ResourceTags", resourceTags); } var metadata = output.CloneCustomMetadata(); mapping[outputPath + "/"] = metadata; if (FileChanged(model, partialPlist)) { Directory.CreateDirectory(outputDir); if ((Compile(model, outputDir, log, partialPlist)) != 0) { return(false); } } else { Log.LogMessage(MessageImportance.Low, "Skipping `{0}' as the output file, `{1}', is newer.", model.ItemSpec, partialPlist); } } bundleResources.AddRange(GetCompiledOutput(coremlcOutputDir, mapping)); foreach (var path in Directory.EnumerateFiles(coremlcOutputDir, "*-partial.plist", SearchOption.AllDirectories)) { partialPlists.Add(new TaskItem(path)); } } BundleResources = bundleResources.ToArray(); PartialAppManifests = partialPlists.ToArray(); return(!Log.HasLoggedErrors); }
private void WriteResponse(BundleResource bundleResource, AsyncBundlingRequestState asyncState) { string content = TransformContent(bundleResource, asyncState.Context); asyncState.ResourceData.Append(content).Append(Environment.NewLine); asyncState.Context.Response.Write(content); asyncState.Context.Response.Write(Environment.NewLine); }
private void ProcessItem(BundleResource resource, AsyncBundlingRequestState asyncState) { if (resource == BundleResource.Empty) { return; } if (resource.Type == BundleResourceType.EmbeddedScript || resource.Type == BundleResourceType.EmbeddedStyle) { resource.ServerPath = null; WriteResponse(resource, asyncState); ProcessItem(GetNextResource(asyncState), asyncState); } else if (resource.Type == BundleResourceType.ClientScript) { try { var handler = ClientScriptBundle.GetHttpHandler(resource.ServerPath.Split('/').Last().Split('.').First()); var content = handler.GetData(asyncState.Context); asyncState.ResourceData.Append(content).Append(Environment.NewLine); asyncState.Context.Response.Write(content); asyncState.Context.Response.Write(Environment.NewLine); ProcessItem(GetNextResource(asyncState), asyncState); } catch (Exception e) { _log.Error("ClientScriptError", e); } } else { //If it's file begin read and go to IOCP thread if (File.Exists(resource.Content)) { FileStream file = File.Open(resource.Content, FileMode.Open, FileAccess.Read, FileShare.Read); var buffer = new byte[file.Length]; file.BeginRead(buffer, 0, (int)file.Length, result => { try { int readed = file.EndRead(result); var asyncObject = result.AsyncState as AsyncBundlingRequestState; HttpContext.Current = asyncState.Context; resource.Content = Encoding.UTF8.GetString(buffer, 0, readed); WriteResponse(resource, asyncState); ProcessItem(GetNextResource(asyncObject), asyncObject); } catch (Exception e) { _log.Error( string.Format( "Error while processing file:{0}", resource.Content), e); } finally { //We got wht we need in buffer. close stream file.Close(); file.Dispose(); } }, asyncState); } } }
protected override void AppendCommandLineArguments(IDictionary <string, string> environment, CommandLineArgumentBuilder args, ITaskItem[] items) { var assetDirs = new HashSet <string> (items.Select(x => BundleResource.GetVirtualProjectPath(ProjectDir, x, !string.IsNullOrEmpty(SessionId)))); if (!string.IsNullOrEmpty(XSAppIconAssets)) { int index = XSAppIconAssets.IndexOf(".xcassets" + Path.DirectorySeparatorChar, StringComparison.Ordinal); string assetDir = null; var rpath = XSAppIconAssets; if (index != -1) { assetDir = rpath.Substring(0, index + ".xcassets".Length); } if (assetDirs != null && assetDirs.Contains(assetDir)) { var assetName = Path.GetFileNameWithoutExtension(rpath); if (PartialAppManifest == null) { args.Add("--output-partial-info-plist"); args.AddQuoted(partialAppManifest.GetMetadata("FullPath")); PartialAppManifest = partialAppManifest; } args.Add("--app-icon"); args.AddQuoted(assetName); if (IsMessagesExtension) { args.Add("--product-type com.apple.product-type.app-extension.messages"); } } } if (!string.IsNullOrEmpty(XSLaunchImageAssets)) { int index = XSLaunchImageAssets.IndexOf(".xcassets" + Path.DirectorySeparatorChar, StringComparison.Ordinal); string assetDir = null; var rpath = XSLaunchImageAssets; if (index != -1) { assetDir = rpath.Substring(0, index + ".xcassets".Length); } if (assetDirs != null && assetDirs.Contains(assetDir)) { var assetName = Path.GetFileNameWithoutExtension(rpath); if (PartialAppManifest == null) { args.Add("--output-partial-info-plist"); args.AddQuoted(partialAppManifest.GetMetadata("FullPath")); PartialAppManifest = partialAppManifest; } args.Add("--launch-image"); args.AddQuoted(assetName); } } if (!string.IsNullOrEmpty(CLKComplicationGroup)) { args.Add("--complication", CLKComplicationGroup); } if (OptimizePNGs) { args.Add("--compress-pngs"); } if (AppleSdkSettings.XcodeVersion.Major >= 7) { if (!string.IsNullOrEmpty(outputSpecs)) { args.Add("--enable-on-demand-resources", EnableOnDemandResources ? "YES" : "NO"); } if (!string.IsNullOrEmpty(DeviceModel)) { args.Add("--filter-for-device-model", DeviceModel); } if (!string.IsNullOrEmpty(DeviceOSVersion)) { args.Add("--filter-for-device-os-version", DeviceOSVersion); } if (!string.IsNullOrEmpty(outputSpecs)) { args.Add("--asset-pack-output-specifications"); args.AddQuoted(Path.GetFullPath(outputSpecs)); } } if (Platform == ApplePlatform.MacCatalyst) { args.Add("--ui-framework-family"); args.Add("uikit"); } foreach (var targetDevice in GetTargetDevices()) { args.Add("--target-device", targetDevice); } args.Add("--minimum-deployment-target", MinimumOSVersion); var platform = PlatformUtils.GetTargetPlatform(SdkPlatform, IsWatchApp); if (platform != null) { args.Add("--platform", platform); } }
public override bool Execute() { var prefixes = BundleResource.SplitResourcePrefixes(ResourcePrefix); var bundleResources = new List <ITaskItem> (); if (BundleResources != null) { foreach (var item in BundleResources) { // Skip anything with the PublishFolderType metadata, these are copied directly to the ResolvedFileToPublish item group instead. var publishFolderType = item.GetMetadata("PublishFolderType"); if (!string.IsNullOrEmpty(publishFolderType)) { continue; } var logicalName = BundleResource.GetLogicalName(ProjectDir, prefixes, item, !string.IsNullOrEmpty(SessionId)); // We need a physical path here, ignore the Link element var path = item.GetMetadata("FullPath"); string illegal; if (!File.Exists(path)) { Log.LogError(MSBStrings.E0099, logicalName, path); continue; } if (logicalName.StartsWith(".." + Path.DirectorySeparatorChar, StringComparison.Ordinal)) { Log.LogError(null, null, null, item.ItemSpec, 0, 0, 0, 0, MSBStrings.E0100, logicalName); continue; } if (logicalName == "Info.plist") { Log.LogWarning(null, null, null, item.ItemSpec, 0, 0, 0, 0, MSBStrings.E0101); continue; } if (BundleResource.IsIllegalName(logicalName, out illegal)) { Log.LogError(null, null, null, item.ItemSpec, 0, 0, 0, 0, MSBStrings.E0102, illegal); continue; } var bundleResource = new TaskItem(item); bundleResource.SetMetadata("LogicalName", logicalName); bool optimize = false; if (CanOptimize(item.ItemSpec)) { var metadata = item.GetMetadata("Optimize"); // fall back to old metadata name if (string.IsNullOrEmpty(metadata)) { metadata = item.GetMetadata("OptimizeImage"); } if (string.IsNullOrEmpty(metadata) || !bool.TryParse(metadata, out optimize)) { switch (Path.GetExtension(item.ItemSpec).ToLowerInvariant()) { case ".plist": case ".strings": optimize = OptimizePropertyLists; break; case ".png": optimize = OptimizePNGs; break; } } } bundleResource.SetMetadata("Optimize", optimize.ToString()); bundleResources.Add(bundleResource); } } BundleResourcesWithLogicalNames = bundleResources.ToArray(); return(!Log.HasLoggedErrors); }
protected virtual string GetBundleRelativeOutputPath(IList <string> prefixes, ITaskItem input) { return(BundleResource.GetLogicalName(ProjectDir, prefixes, input, !string.IsNullOrEmpty(SessionId))); }
public override bool Execute() { var prefixes = BundleResource.SplitResourcePrefixes(ResourcePrefix); var intermediate = Path.Combine(IntermediateOutputPath, ToolName); var bundleResources = new List <ITaskItem> (); var modified = new HashSet <string> (); var items = new List <ITaskItem> (); string metadata; foreach (var asset in SceneKitAssets) { if (!File.Exists(asset.ItemSpec)) { continue; } // get the .scnassets directory path var scnassets = Path.GetDirectoryName(asset.ItemSpec); while (scnassets.Length > 0 && Path.GetExtension(scnassets).ToLowerInvariant() != ".scnassets") { scnassets = Path.GetDirectoryName(scnassets); } if (scnassets.Length == 0) { continue; } metadata = asset.GetMetadata("LogicalName"); if (!string.IsNullOrEmpty(metadata)) { asset.SetMetadata("LogicalName", string.Empty); } var bundleName = BundleResource.GetLogicalName(ProjectDir, prefixes, asset, !string.IsNullOrEmpty(SessionId)); var output = new TaskItem(Path.Combine(intermediate, bundleName)); if (!modified.Contains(scnassets) && (!File.Exists(output.ItemSpec) || File.GetLastWriteTimeUtc(asset.ItemSpec) > File.GetLastWriteTimeUtc(output.ItemSpec))) { // Base the new item on @asset, to get the `DefiningProject*` metadata too var scnassetsItem = new TaskItem(asset); // .. but we really want it to be for @scnassets, so set ItemSpec accordingly scnassetsItem.ItemSpec = scnassets; // .. and remove the @OriginalItemSpec which is for @asset scnassetsItem.RemoveMetadata("OriginalItemSpec"); var assetMetadata = asset.GetMetadata("DefiningProjectFullPath"); if (assetMetadata != scnassetsItem.GetMetadata("DefiningProjectFullPath")) { // xbuild doesn't set this, so we'll do it // // `DefiningProjectFullPath` is a reserved metadata for msbuild, so // setting this is not allowed anyway scnassetsItem.SetMetadata("DefiningProjectFullPath", assetMetadata); } modified.Add(scnassets); items.Add(scnassetsItem); } output.SetMetadata("LogicalName", bundleName); output.SetMetadata("Optimize", "false"); bundleResources.Add(output); } if (modified.Count == 0) { BundleResources = bundleResources.ToArray(); return(!Log.HasLoggedErrors); } if (!Directory.Exists(intermediate)) { Directory.CreateDirectory(intermediate); } foreach (var item in items) { var bundleDir = BundleResource.GetLogicalName(ProjectDir, prefixes, new TaskItem(item), !string.IsNullOrEmpty(SessionId)); var output = Path.Combine(intermediate, bundleDir); if (CopySceneKitAssets(item.ItemSpec, output, intermediate) == -1) { return(false); } } BundleResources = bundleResources.ToArray(); return(!Log.HasLoggedErrors); }
public BundleResourceDisplayProxy(BundleResource original) { Link = original.Link; UnevaluatedInclude = original.UnevaluatedInclude; }