void FixupResources(ITaskItem item, Dictionary <string, string> acwMap) { var resdir = item.ItemSpec; // Find all the xml and axml files var xmls = new[] { resdir } .Concat(Directory.EnumerateDirectories(resdir, "*", SearchOption.AllDirectories) .Except(Directory.EnumerateDirectories(resdir, "color*", SearchOption.TopDirectoryOnly)) .Except(Directory.EnumerateDirectories(resdir, "raw*", SearchOption.TopDirectoryOnly))) .SelectMany(dir => Directory.EnumerateFiles(dir, "*.xml") .Concat(Directory.EnumerateFiles(dir, "*.axml"))); var lastUpdate = DateTime.MinValue; if (!string.IsNullOrEmpty(AndroidConversionFlagFile) && File.Exists(AndroidConversionFlagFile)) { lastUpdate = File.GetLastWriteTimeUtc(AndroidConversionFlagFile); } Log.LogDebugMessage(" AndroidResgenFlagFile modified: {0}", lastUpdate); // Fix up each file foreach (string file in xmls) { var srcmodifiedDate = File.GetLastWriteTimeUtc(file); if (srcmodifiedDate <= lastUpdate) { Log.LogDebugMessage(" Skipping: {0} {1} <= {2}", file, srcmodifiedDate, lastUpdate); continue; } Log.LogDebugMessage(" Processing: {0} {1} > {2}", file, srcmodifiedDate, lastUpdate); var tmpdest = Path.GetTempFileName(); MonoAndroidHelper.CopyIfChanged(file, tmpdest); MonoAndroidHelper.SetWriteable(tmpdest); try { AndroidResource.UpdateXmlResource(resdir, tmpdest, acwMap, ResourceDirectories.Where(s => s != item).Select(s => s.ItemSpec)); // We strip away an eventual UTF-8 BOM from the XML file. // This is a requirement for the Android designer because the desktop Java renderer // doesn't support those type of BOM (it really wants the document to start // with "<?"). Since there is no way to plug into the file saving mechanism in X.S // we strip those here and point the designer to use resources from obj/ MonoAndroidHelper.CleanBOM(tmpdest); if (MonoAndroidHelper.CopyIfChanged(tmpdest, file)) { MonoAndroidHelper.SetWriteable(file); MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(file, srcmodifiedDate, Log); } } finally { File.Delete(tmpdest); } } }
public XElement ToElement(string packageName) { var r = new XElement("intent-filter", ToAttribute("Icon", Icon), ToAttribute("Label", ReplacePackage(Label, packageName)), ToAttribute("Priority", Priority), ToAttribute("AutoVerify", _AutoVerify), Actions.Select(a => new XElement("action", new XAttribute(android + "name", ReplacePackage(a, packageName)))), (Categories ?? new string[0]).Select(c => new XElement("category", new XAttribute(android + "name", ReplacePackage(c, packageName)))), GetData(packageName)); AndroidResource.UpdateXmlResource(r); return(r); }
public ManifestDocument(string templateFilename, TaskLoggingHelper log) : base() { this.log = log; Assemblies = new List <string> (); attName = androidNs + "name"; if (!string.IsNullOrEmpty(templateFilename)) { doc = XDocument.Load(templateFilename, LoadOptions.SetLineInfo); AndroidResource.UpdateXmlResource(doc.Root); } else { doc = new XDocument(new XElement("manifest")); } }
void FixupResources(ITaskItem item, Dictionary <string, string> acwMap) { var resdir = item.ItemSpec; // Find all the xml and axml files var xmls = new[] { resdir } .Concat(Directory.EnumerateDirectories(resdir, "*", SearchOption.AllDirectories) .Except(Directory.EnumerateDirectories(resdir, "color*", SearchOption.TopDirectoryOnly)) .Except(Directory.EnumerateDirectories(resdir, "raw*", SearchOption.TopDirectoryOnly))) .SelectMany(dir => Directory.EnumerateFiles(dir, "*.xml") .Concat(Directory.EnumerateFiles(dir, "*.axml"))); var lastUpdate = DateTime.MinValue; if (!string.IsNullOrEmpty(AndroidConversionFlagFile) && File.Exists(AndroidConversionFlagFile)) { lastUpdate = File.GetLastWriteTimeUtc(AndroidConversionFlagFile); } Log.LogDebugMessage(" AndroidConversionFlagFile modified: {0}", lastUpdate); // Fix up each file foreach (string file in xmls) { var srcmodifiedDate = File.GetLastWriteTimeUtc(file); if (srcmodifiedDate <= lastUpdate) { Log.LogDebugMessage(" Skipping: {0} {1} <= {2}", file, srcmodifiedDate, lastUpdate); continue; } Log.LogDebugMessage(" Processing: {0} {1} > {2}", file, srcmodifiedDate, lastUpdate); var tmpdest = Path.GetTempFileName(); File.Copy(file, tmpdest, overwrite: true); MonoAndroidHelper.SetWriteable(tmpdest); try { bool success = AndroidResource.UpdateXmlResource(resdir, tmpdest, acwMap, ResourceDirectories.Where(s => s != item).Select(s => s.ItemSpec), (t, m) => { string targetfile = file; if (targetfile.StartsWith(resdir, StringComparison.InvariantCultureIgnoreCase)) { targetfile = file.Substring(resdir.Length).TrimStart(Path.DirectorySeparatorChar); if (resource_name_case_map.TryGetValue(targetfile, out string temp)) { targetfile = temp; } targetfile = Path.Combine("Resources", targetfile); } switch (t) { case TraceLevel.Error: Log.LogCodedError("XA1002", file: targetfile, lineNumber: 0, message: m); break; case TraceLevel.Warning: Log.LogCodedWarning("XA1001", file: targetfile, lineNumber: 0, message: m); break; default: Log.LogDebugMessage(m); break; } }); if (!success) { //If we failed to write the file, a warning is logged, we should skip to the next file continue; } // We strip away an eventual UTF-8 BOM from the XML file. // This is a requirement for the Android designer because the desktop Java renderer // doesn't support those type of BOM (it really wants the document to start // with "<?"). Since there is no way to plug into the file saving mechanism in X.S // we strip those here and point the designer to use resources from obj/ MonoAndroidHelper.CleanBOM(tmpdest); MonoAndroidHelper.CopyIfChanged(tmpdest, file); } finally { File.Delete(tmpdest); } } }
public override bool RunTask() { var resource_name_case_map = MonoAndroidHelper.LoadResourceCaseMap(ResourceNameCaseMap); var acw_map = MonoAndroidHelper.LoadAcwMapFile(AcwMapFile); var customViewMap = MonoAndroidHelper.LoadCustomViewMapFile(BuildEngine4, CustomViewMapFile); var processed = new HashSet <string> (); foreach (var kvp in acw_map) { var key = kvp.Key; var value = kvp.Value; if (key == value) { continue; } if (customViewMap.TryGetValue(key, out HashSet <string> resourceFiles)) { foreach (var file in resourceFiles) { if (processed.Contains(file)) { continue; } if (!File.Exists(file)) { continue; } var document = XDocument.Load(file, options: LoadOptions.SetLineInfo); var e = document.Root; bool update = false; foreach (var elem in AndroidResource.GetElements(e).Prepend(e)) { update |= TryFixCustomView(elem, acw_map, (level, message) => { ITaskItem resdir = ResourceDirectories?.FirstOrDefault(x => file.StartsWith(x.ItemSpec, StringComparison.OrdinalIgnoreCase)) ?? null; switch (level) { case TraceLevel.Error: Log.FixupResourceFilenameAndLogCodedError("XA1002", message, file, resdir?.ItemSpec, resource_name_case_map); break; case TraceLevel.Warning: Log.FixupResourceFilenameAndLogCodedError("XA1001", message, file, resdir?.ItemSpec, resource_name_case_map); break; default: Log.LogDebugMessage(message); break; } }); } foreach (XAttribute a in AndroidResource.GetAttributes(e)) { update |= TryFixCustomClassAttribute(a, acw_map); update |= TryFixFragment(a, acw_map); } if (update) { var lastModified = File.GetLastWriteTimeUtc(file); if (document.SaveIfChanged(file)) { Log.LogDebugMessage($"Fixed up Custom Views in {file}"); File.SetLastWriteTimeUtc(file, lastModified); } } processed.Add(file); } } } var output = new Dictionary <string, ITaskItem> (processed.Count); foreach (var file in processed) { ITaskItem resdir = ResourceDirectories?.FirstOrDefault(x => file.StartsWith(x.ItemSpec)) ?? null; var hash = resdir?.GetMetadata("Hash") ?? null; var stamp = resdir?.GetMetadata("StampFile") ?? null; var filename = !string.IsNullOrEmpty(hash) ? hash : "compiled"; var stampFile = !string.IsNullOrEmpty(stamp) ? stamp : $"{filename}.stamp"; Log.LogDebugMessage($"{filename} {stampFile}"); output.Add(file, new TaskItem(Path.GetFullPath(file), new Dictionary <string, string> { { "StampFile", stampFile }, { "Hash", filename }, { "Resource", resdir?.ItemSpec ?? file }, })); } Processed = output.Values.ToArray(); return(!Log.HasLoggedErrors); }
void FixupResources(ITaskItem item) { var resdir = item.ItemSpec; // Find all the xml and axml files var xmls = new List <string> (); var colorDir = Path.Combine(resdir, "color"); var rawDir = Path.Combine(resdir, "raw"); foreach (var file in Directory.GetFiles(resdir, "*.*xml", SearchOption.AllDirectories)) { if (file.StartsWith(colorDir, StringComparison.Ordinal) || file.StartsWith(rawDir, StringComparison.Ordinal)) { continue; } var ext = Path.GetExtension(file); if (ext != ".xml" && ext != ".axml") { continue; } xmls.Add(file); } var lastUpdate = DateTime.MinValue; if (!string.IsNullOrEmpty(AndroidConversionFlagFile) && File.Exists(AndroidConversionFlagFile)) { lastUpdate = File.GetLastWriteTimeUtc(AndroidConversionFlagFile); } Log.LogDebugMessage(" AndroidConversionFlagFile modified: {0}", lastUpdate); var resourcedirectories = new List <string> (); foreach (var dir in ResourceDirectories) { if (dir == item) { continue; } resourcedirectories.Add(dir.ItemSpec); } // Fix up each file foreach (string file in xmls) { var srcmodifiedDate = File.GetLastWriteTimeUtc(file); if (srcmodifiedDate <= lastUpdate) { continue; } Log.LogDebugMessage(" Processing: {0} {1} > {2}", file, srcmodifiedDate, lastUpdate); MonoAndroidHelper.SetWriteable(file); bool success = AndroidResource.UpdateXmlResource(resdir, file, resourcedirectories, (level, message) => { switch (level) { case TraceLevel.Error: Log.FixupResourceFilenameAndLogCodedError("XA1002", message, file, resdir, resource_name_case_map); break; case TraceLevel.Warning: Log.FixupResourceFilenameAndLogCodedWarning("XA1001", message, file, resdir, resource_name_case_map); break; default: Log.LogDebugMessage(message); break; } }, registerCustomView: (e, filename) => { if (customViewMap == null) { return; } HashSet <string> set; if (!customViewMap.TryGetValue(e, out set)) { customViewMap.Add(e, set = new HashSet <string> ()); } set.Add(filename); }); if (!success) { //If we failed to write the file, a warning is logged, we should skip to the next file continue; } // We strip away an eventual UTF-8 BOM from the XML file. // This is a requirement for the Android designer because the desktop Java renderer // doesn't support those type of BOM (it really wants the document to start // with "<?"). Since there is no way to plug into the file saving mechanism in X.S // we strip those here and point the designer to use resources from obj/ MonoAndroidHelper.CleanBOM(file); } }
public override bool Execute() { Log.LogDebugMessage("CopyAndConvertResources Task"); Log.LogDebugTaskItems(" SourceFiles:", SourceFiles); Log.LogDebugTaskItems(" DestinationFiles:", DestinationFiles); Log.LogDebugMessage(" AcwMapFile: {0}", AcwMapFile); if (SourceFiles.Length != DestinationFiles.Length) { throw new ArgumentException("source and destination count mismatch"); } var acw_map = MonoAndroidHelper.LoadAcwMapFile(AcwMapFile); var xmlFilesToUpdate = new Dictionary <string, string> (); for (int i = 0; i < SourceFiles.Length; i++) { var filename = SourceFiles [i].ItemSpec; if (File.Exists(filename)) { var ext = Path.GetExtension(filename); var destfilename = DestinationFiles [i].ItemSpec; var srcmodifiedDate = File.GetLastWriteTimeUtc(filename); var dstmodifiedDate = File.Exists(destfilename) ? File.GetLastAccessTimeUtc(destfilename) : DateTime.MinValue; var isXml = ext == ".xml" || ext == ".axml"; Directory.CreateDirectory(Path.GetDirectoryName(destfilename)); if (isXml) { xmlFilesToUpdate.Add(filename, DestinationFiles [i].ItemSpec); continue; } if (dstmodifiedDate < srcmodifiedDate && MonoAndroidHelper.CopyIfChanged(filename, destfilename)) { MonoAndroidHelper.SetWriteable(destfilename); // If the resource is not part of a raw-folder we strip away an eventual UTF-8 BOM // This is a requirement for the Android designer because the desktop Java renderer // doesn't support those type of BOM (it really wants the document to start // with "<?"). Since there is no way to plug into the file saving mechanism in X.S // we strip those here and point the designer to use resources from obj/ if (isXml && !MonoAndroidHelper.IsRawResourcePath(filename)) { MonoAndroidHelper.CleanBOM(destfilename); } MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(destfilename, srcmodifiedDate, Log); modifiedFiles.Add(new TaskItem(destfilename)); } } else { Log.LogMessage(" Warning: input resource '{0}' was not found", filename); } } var merger = new ResourceMerger() { CacheFile = CacheFile, Log = Log, }; merger.Load(); foreach (var p in xmlFilesToUpdate) { string filename = p.Key; var destfilename = p.Value; var srcmodifiedDate = File.GetLastWriteTimeUtc(filename); var dstmodifiedDate = File.Exists(destfilename) ? File.GetLastAccessTimeUtc(destfilename) : DateTime.MinValue; var tmpdest = p.Value + ".tmp"; MonoAndroidHelper.CopyIfChanged(filename, tmpdest); MonoAndroidHelper.SetWriteable(tmpdest); try { AndroidResource.UpdateXmlResource(tmpdest, acw_map); if (MonoAndroidHelper.CopyIfChanged(tmpdest, destfilename)) { MonoAndroidHelper.SetWriteable(destfilename); MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(destfilename, srcmodifiedDate, Log); if (!modifiedFiles.Any(i => i.ItemSpec == destfilename)) { modifiedFiles.Add(new TaskItem(destfilename)); } } } finally { File.Delete(tmpdest); } } merger.Save(); ModifiedFiles = modifiedFiles.ToArray(); Log.LogDebugTaskItems(" ModifiedFiles:", ModifiedFiles); return(true); }
public override bool Execute() { if (SourceFiles.Length != DestinationFiles.Length) { throw new ArgumentException("source and destination count mismatch"); } var acw_map = MonoAndroidHelper.LoadAcwMapFile(AcwMapFile); var resource_name_case_map = MonoAndroidHelper.LoadResourceCaseMap(ResourceNameCaseMap); if (CustomViewMapFile != null) { customViewMap = Xamarin.Android.Tasks.MonoAndroidHelper.LoadCustomViewMapFile(BuildEngine4, CustomViewMapFile); } var xmlFilesToUpdate = new Dictionary <string, string> (); for (int i = 0; i < SourceFiles.Length; i++) { var filename = SourceFiles [i].ItemSpec; if (File.Exists(filename)) { var ext = Path.GetExtension(filename); var destfilename = DestinationFiles [i].ItemSpec; var srcmodifiedDate = File.GetLastWriteTimeUtc(filename); var dstmodifiedDate = File.Exists(destfilename) ? File.GetLastWriteTimeUtc(destfilename) : DateTime.MinValue; var isXml = ext == ".xml" || ext == ".axml"; Directory.CreateDirectory(Path.GetDirectoryName(destfilename)); if (isXml) { xmlFilesToUpdate.Add(filename, DestinationFiles [i].ItemSpec); continue; } if (dstmodifiedDate < srcmodifiedDate && MonoAndroidHelper.CopyIfChanged(filename, destfilename)) { // If the resource is not part of a raw-folder we strip away an eventual UTF-8 BOM // This is a requirement for the Android designer because the desktop Java renderer // doesn't support those type of BOM (it really wants the document to start // with "<?"). Since there is no way to plug into the file saving mechanism in X.S // we strip those here and point the designer to use resources from obj/ if (isXml && !MonoAndroidHelper.IsRawResourcePath(filename)) { MonoAndroidHelper.CleanBOM(destfilename); } modifiedFiles.Add(new TaskItem(destfilename)); } } else { Log.LogMessage(" Warning: input resource '{0}' was not found", filename); } } var merger = new ResourceMerger() { CacheFile = CacheFile, Log = Log, }; merger.Load(); foreach (var p in xmlFilesToUpdate) { string filename = p.Key; var destfilename = p.Value; var srcmodifiedDate = File.GetLastWriteTimeUtc(filename); var dstmodifiedDate = File.Exists(destfilename) ? File.GetLastWriteTimeUtc(destfilename) : DateTime.MinValue; var res = Path.Combine(Path.GetDirectoryName(filename), ".."); MonoAndroidHelper.CopyIfChanged(filename, destfilename); MonoAndroidHelper.SetWriteable(destfilename); var updated = AndroidResource.UpdateXmlResource(res, destfilename, acw_map, logMessage: (level, message) => { ITaskItem resdir = ResourceDirectories?.FirstOrDefault(x => filename.StartsWith(x.ItemSpec)) ?? null; switch (level) { case TraceLevel.Error: Log.FixupResourceFilenameAndLogCodedError("XA1002", message, filename, resdir.ItemSpec, resource_name_case_map); break; case TraceLevel.Warning: Log.FixupResourceFilenameAndLogCodedWarning("XA1001", message, filename, resdir.ItemSpec, resource_name_case_map); break; default: Log.LogDebugMessage(message); break; } }, registerCustomView: (e, file) => { if (customViewMap == null) { return; } HashSet <string> set; if (!customViewMap.TryGetValue(e, out set)) { customViewMap.Add(e, set = new HashSet <string> ()); } set.Add(file); }); if (updated) { if (!modifiedFiles.Any(i => i.ItemSpec == destfilename)) { modifiedFiles.Add(new TaskItem(destfilename)); } } } merger.Save(); ModifiedFiles = modifiedFiles.ToArray(); Log.LogDebugTaskItems(" ModifiedFiles:", ModifiedFiles); if (customViewMap != null) { Xamarin.Android.Tasks.MonoAndroidHelper.SaveCustomViewMapFile(BuildEngine4, CustomViewMapFile, customViewMap); } return(true); }
public override bool Execute() { var resource_name_case_map = MonoAndroidHelper.LoadResourceCaseMap(ResourceNameCaseMap); var acw_map = MonoAndroidHelper.LoadAcwMapFile(AcwMapFile); var customViewMap = MonoAndroidHelper.LoadCustomViewMapFile(BuildEngine4, CustomViewMapFile); var processed = new HashSet <string> (); foreach (var kvp in acw_map) { var key = kvp.Key; var value = kvp.Value; if (key == value) { continue; } if (customViewMap.TryGetValue(key, out HashSet <string> resourceFiles)) { foreach (var file in resourceFiles) { if (processed.Contains(file)) { continue; } if (!File.Exists(file)) { continue; } var document = XDocument.Load(file); var e = document.Root; bool update = false; foreach (var elem in AndroidResource.GetElements(e).Prepend(e)) { update |= TryFixCustomView(elem, acw_map, (level, message) => { ITaskItem resdir = ResourceDirectories?.FirstOrDefault(x => file.StartsWith(x.ItemSpec)) ?? null; switch (level) { case TraceLevel.Error: Log.FixupResourceFilenameAndLogCodedError("XA1002", message, file, resdir.ItemSpec, resource_name_case_map); break; case TraceLevel.Warning: Log.FixupResourceFilenameAndLogCodedError("XA1001", message, file, resdir.ItemSpec, resource_name_case_map); break; default: Log.LogDebugMessage(message); break; } }); } foreach (XAttribute a in AndroidResource.GetAttributes(e)) { update |= TryFixCustomClassAttribute(a, acw_map); update |= TryFixFragment(a, acw_map); } if (update) { document.Save(file); } processed.Add(file); } } } return(!Log.HasLoggedErrors); }