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 static void Clear() { // Clear Resource Directories ModelDirectories.Clear(); ResourceDirectories.Clear(); // Clear Viewport Models/Instances Viewport.SelectedInstances.Clear(); DefaultCube.Instances.Clear(); DefaultTerrainGroup.Clear(); TerrainGroups.Clear(); Objects.Clear(); // Clear Resources Materials.Clear(); Textures.Clear(); }
public void ScanDirectoriesForResources(IEnumerable <Resource> resources) { // Attempt to find a matching file for each resource and load it List <FileInfo> allFiles = ResourceDirectories.SelectMany(d => new DirectoryInfo(d).GetFiles()).ToList(); foreach (Resource r in resources) { FileInfo matchingFile = allFiles.FirstOrDefault(f => f.Name.ToUpper().Trim() == r.ResourceName); if (matchingFile != null) { r.Fields = DecodeStream(File.ReadAllBytes(matchingFile.FullName), true); // Also see if there are any additional resources to load from within those fields List <Resource> extraResources = LoadReferencedResources(r.Fields); // If there are, add them to the total resources list and recursively search for files within known directories if (extraResources.Any()) { Resources = Resources.Concat(extraResources).ToList(); ScanDirectoriesForResources(extraResources); } } } }
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); }
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); }
void FixupResources(ITaskItem item, Dictionary <string, string> acwMap) { 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 = ResourceDirectories.Where(s => s != item).Select(s => s.ItemSpec).ToArray(); // 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); MonoAndroidHelper.SetWriteable(file); bool success = AndroidResource.UpdateXmlResource(resdir, file, acwMap, 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); } }