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);
        }
示例#6
0
        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);
            }
        }
示例#7
0
        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);
        }
示例#9
0
        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);
        }