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); }
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); }