void CopyFiles(string srcdir)
 {
     foreach (var file in Directory.GetFiles(srcdir))
     {
         if (file.EndsWith(".jar", StringComparison.OrdinalIgnoreCase))
         {
             var dstpath = Path.Combine(OutputJarsDirectory, Path.GetFileName(file));
             if (!File.Exists(dstpath))
             {
                 MonoAndroidHelper.CopyIfChanged(file, dstpath);
             }
         }
         else if (file.EndsWith("annotations.zip", StringComparison.OrdinalIgnoreCase))
         {
             var dstpath = Path.Combine(OutputAnnotationsDirectory, Path.GetFileName(file));
             if (!File.Exists(dstpath))
             {
                 MonoAndroidHelper.CopyIfChanged(file, dstpath);
             }
         }
         else
         {
             var dstpath = Path.Combine(OutputDirectory, Path.GetFileName(file));
             if (!File.Exists(dstpath))
             {
                 MonoAndroidHelper.CopyIfChanged(file, dstpath);
             }
         }
     }
 }
Ejemplo n.º 2
0
        public override bool Execute()
        {
            Log.LogDebugMessage("SourceTopDirectory: {0}", SourceTopDirectory);
            Log.LogDebugMessage("DestinationTopDirectory: {0}", DestinationTopDirectory);
            Log.LogDebugMessage("PrimaryPackageName: {0}", PrimaryPackageName);
            Log.LogDebugMessage("ExtraPackages: {0}", ExtraPackages);

            var list = new List <string> ();

            foreach (var pkg in GetPackages())
            {
                string subpath = Path.Combine(pkg.Split('.'));
                string src     = Path.Combine(SourceTopDirectory, subpath, "R.java");
                string dst     = Path.Combine(DestinationTopDirectory, subpath, "R.java");

                if (!File.Exists(src))
                {
                    continue;
                }

                var date = File.GetLastWriteTimeUtc(src);
                MonoAndroidHelper.CopyIfChanged(src, dst);
                list.Add(dst);
            }
            // so far we only need the package's R.java for GenerateResourceDesigner input.
            PrimaryJavaResgenFile = list.FirstOrDefault();

            Log.LogDebugMessage("Output PrimaryJavaResgenFile: {0}", PrimaryJavaResgenFile);

            return(true);
        }
Ejemplo n.º 3
0
        public override bool Execute()
        {
            Log.LogDebugMessage("CopyIfChanged Task");
            Log.LogDebugTaskItems("  SourceFiles: {0}", SourceFiles);
            Log.LogDebugTaskItems("  DestinationFiles: {0}", DestinationFiles);

            if (SourceFiles.Length != DestinationFiles.Length)
            {
                throw new ArgumentException("source and destination count mismatch");
            }

            for (int i = 0; i < SourceFiles.Length; i++)
            {
                var src = SourceFiles [i].ItemSpec;
                if (!File.Exists(src))
                {
                    continue;
                }
                var dest          = DestinationFiles [i].ItemSpec;
                var lastWriteTime = File.GetLastWriteTimeUtc(File.Exists(dest) ? dest : src);
                MonoAndroidHelper.SetWriteable(dest);
                if (!MonoAndroidHelper.CopyIfChanged(src, dest))
                {
                    continue;
                }
                if (KeepDestinationDates)
                {
                    MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(dest, lastWriteTime, Log);
                }
            }
            return(true);
        }
Ejemplo n.º 4
0
        public override bool Execute()
        {
            Log.LogDebugMessage("Crunch Task");
            Log.LogDebugTaskItems("  SourceFiles:", SourceFiles);
            Log.LogDebugMessage("  ToolPath: {0}", ToolPath);
            Log.LogDebugMessage("  ToolExe: {0}", ToolExe);

            // copy the changed files over to a temp location for processing
            var imageFiles = SourceFiles.Where(x => string.Equals(Path.GetExtension(x.ItemSpec), ".png", StringComparison.OrdinalIgnoreCase));

            if (!imageFiles.Any())
            {
                return(true);
            }

            foreach (var imageGroup in imageFiles.GroupBy(x => Path.GetDirectoryName(Path.GetFullPath(x.ItemSpec))))
            {
                tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                Directory.CreateDirectory(tempDirectory);
                tempOutputDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                Directory.CreateDirectory(tempOutputDirectory);
                try {
                    Log.LogDebugMessage("Crunch Processing : {0}", imageGroup.Key);
                    Log.LogDebugTaskItems("  Items :", imageGroup.ToArray());
                    foreach (var item in imageGroup)
                    {
                        var dest = Path.GetFullPath(item.ItemSpec).Replace(imageGroup.Key, tempDirectory);
                        Directory.CreateDirectory(Path.GetDirectoryName(dest));
                        MonoAndroidHelper.CopyIfChanged(item.ItemSpec, dest);
                        MonoAndroidHelper.SetWriteable(dest);
                    }

                    // crunch them
                    if (!base.Execute())
                    {
                        return(false);
                    }

                    // copy them back
                    foreach (var item in imageGroup)
                    {
                        var dest            = Path.GetFullPath(item.ItemSpec).Replace(imageGroup.Key, tempOutputDirectory);
                        var srcmodifiedDate = File.GetLastWriteTimeUtc(item.ItemSpec);
                        if (!File.Exists(dest))
                        {
                            continue;
                        }
                        MonoAndroidHelper.CopyIfChanged(dest, item.ItemSpec);
                        MonoAndroidHelper.SetWriteable(dest);
                        // reset the Dates so MSBuild/xbuild doesn't think they changed.
                        MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(item.ItemSpec, srcmodifiedDate, Log);
                    }
                } finally {
                    Directory.Delete(tempDirectory, recursive: true);
                    Directory.Delete(tempOutputDirectory, recursive: true);
                }
            }

            return(!Log.HasLoggedErrors);
        }
Ejemplo n.º 5
0
        void CopyResource(string src, string destPath)
        {
            var cachedDate = File.GetLastWriteTimeUtc(src);
            var path       = Path.GetDirectoryName(src).Trim(new char[] { Path.DirectorySeparatorChar });

            if (File.Exists(destPath))
            {
                if (merger.NeedsMerge(path))
                {
                    merger.MergeValues(src, destPath);
                }
                else
                {
                    MonoAndroidHelper.CopyIfChanged(src, destPath);
                }
            }
            else
            {
                if (merger.NeedsMerge(path))
                {
                    merger.MergeValues(src, destPath);
                }
                else
                {
                    MonoAndroidHelper.CopyIfChanged(src, destPath);
                }
            }
            MonoAndroidHelper.SetWriteable(destPath);
            MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(destPath, cachedDate, Log);
        }
Ejemplo n.º 6
0
        public override bool RunTask()
        {
            var list = new List <string> ();

            foreach (var pkg in GetPackages())
            {
                string subpath = Path.Combine(pkg.Split('.'));
                string src     = Path.Combine(SourceTopDirectory, subpath, "R.java");

                if (!File.Exists(src))
                {
                    continue;
                }

                //NOTE: DestinationTopDirectory is optional, and we can just use the file in SourceTopDirectory
                if (!string.IsNullOrEmpty(DestinationTopDirectory))
                {
                    string dst = Path.Combine(DestinationTopDirectory, subpath, "R.java");
                    MonoAndroidHelper.CopyIfChanged(src, dst);
                    list.Add(dst);
                }
                else
                {
                    list.Add(src);
                }
            }
            // so far we only need the package's R.java for GenerateResourceDesigner input.
            PrimaryJavaResgenFile = list.FirstOrDefault();

            Log.LogDebugMessage("Output PrimaryJavaResgenFile: {0}", PrimaryJavaResgenFile);

            return(true);
        }
Ejemplo n.º 7
0
        public override bool Execute()
        {
            Log.LogDebugTaskItems("SourceFiles:", SourceFiles);
            Log.LogDebugTaskItems("DestinationFiles:", DestinationFiles);

            if (SourceFiles.Length != DestinationFiles.Length)
            {
                throw new ArgumentException("source and destination count mismatch");
            }

            var copiedFiles = new List <ITaskItem> ();

            for (int i = 0; i < SourceFiles.Length; i++)
            {
                var src = SourceFiles[i].ItemSpec;
                if (File.Exists(src))
                {
                    var dst  = DestinationFiles [i].ItemSpec;
                    var date = DateTime.Now;
                    if (MonoAndroidHelper.CopyIfChanged(src, dst))
                    {
                        copiedFiles.Add(DestinationFiles [i]);
                        MonoAndroidHelper.SetWriteable(dst);
                        MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(dst, date, Log);
                    }
                }
            }
            CopiedFiles = copiedFiles.ToArray();
            Log.LogDebugTaskItems("[Output] CopiedFiles:", CopiedFiles);
            return(true);
        }
Ejemplo n.º 8
0
        public override bool Execute()
        {
            Log.LogDebugMessage("CreateAdditionalLibraryResourceCache Task");
            Log.LogDebugTaskItems("  AdditionalAndroidResourcePaths:", AdditionalAndroidResourcePaths);
            Log.LogDebugTaskItems("  AdditionalAndroidResourceCachePaths: ", AdditionalAndroidResourceCachePaths);
            var copiedResources = new List <ITaskItem> ();

            for (int i = 0; i < AdditionalAndroidResourcePaths.Length; i++)
            {
                var src  = Path.GetFullPath(AdditionalAndroidResourcePaths [i].ItemSpec);
                var dest = Path.GetFullPath(AdditionalAndroidResourceCachePaths [i].ItemSpec);

                foreach (string dirPath in Directory.EnumerateDirectories(src, "*", SearchOption.AllDirectories))
                {
                    Directory.CreateDirectory(dirPath.Replace(src, dest));
                }

                //Copy all the files & Replaces any files with the same name
                foreach (string newPath in Directory.EnumerateFiles(src, "*", SearchOption.AllDirectories))
                {
                    var destPath   = newPath.Replace(src, dest);
                    var cachedDate = File.GetLastWriteTimeUtc(src);
                    MonoAndroidHelper.CopyIfChanged(newPath, destPath);
                    MonoAndroidHelper.SetWriteable(destPath);
                    MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(destPath, cachedDate, Log);
                    copiedResources.Add(new TaskItem(destPath));
                }
            }

            CopiedResources = copiedResources.ToArray();

            Log.LogDebugTaskItems("  [Output] CopiedResources:", CopiedResources);
            return(!Log.HasLoggedErrors);
        }
 bool CopyLibraryContent(string projdir, bool isAar)
 {
     if (Path.GetFullPath(OutputDirectory).StartsWith(Path.GetFullPath(projdir), StringComparison.InvariantCultureIgnoreCase))
     {
         Log.LogError("The source directory is under the output directory. Skip it.");
         return(false);
     }
     foreach (var subdir in Directory.GetDirectories(projdir))
     {
         var dinfo = new DirectoryInfo(subdir);
         switch (dinfo.Name.ToLowerInvariant())
         {
         case "gen":
         case "src":
             continue;
         }
         CopyDirectory(dinfo, OutputDirectory, true);
         CopyFiles(subdir);
     }
     if (isAar)
     {
         CopyFiles(projdir);
         // for .aar, copy top-level files (*.jar, AndroidManifest.xml etc.) into bin too.
         var dstdir = Path.Combine(OutputDirectory, "bin");
         foreach (var file in Directory.GetFiles(projdir))
         {
             string dstpath = Path.Combine(dstdir, Path.GetFileName(file));
             if (!File.Exists(dstpath))
             {
                 MonoAndroidHelper.CopyIfChanged(file, dstpath);
             }
         }
     }
     return(true);
 }
        public override bool Execute()
        {
            Log.LogDebugMessage("EmbeddedNativeLibraries Task");
            Log.LogDebugMessage("  OutputDirectory: {0}", OutputDirectory);
            Log.LogDebugTaskItems("  EmbeddedNativeLibraries:", EmbeddedNativeLibraries);

            var outDirInfo = new DirectoryInfo(OutputDirectory);

            // Copy files into _NativeLibraryImportsDirectoryName (native_library_imports) dir.
            if (!outDirInfo.Exists)
            {
                outDirInfo.Create();
            }
            foreach (var lib in EmbeddedNativeLibraries)
            {
                // seealso bug #3477 to find out why we use this method.
                var abi = MonoAndroidHelper.GetNativeLibraryAbi(lib);
                if (abi == null)
                {
                    Log.LogWarning(
                        subcategory:      string.Empty,
                        warningCode:      "XA4300",
                        helpKeyword:      string.Empty,
                        file:             lib.ItemSpec,
                        lineNumber:       0,
                        columnNumber:     0,
                        endLineNumber:    0,
                        endColumnNumber:  0,
                        message:          "Native library '{0}' will not be bundled because it has an unsupported ABI.",
                        messageArgs:      new [] {
                        lib.ItemSpec,
                    }
                        );
                    continue;
                }
                if (!outDirInfo.GetDirectories(abi).Any())
                {
                    outDirInfo.CreateSubdirectory(abi);
                }
                MonoAndroidHelper.CopyIfChanged(lib.ItemSpec, Path.Combine(OutputDirectory, abi, Path.GetFileName(lib.ItemSpec)));
            }

            // Archive native libraries in a zip.
            using (var stream = new MemoryStream())
                using (var zip = new ZipArchive(stream, ZipArchiveMode.Create, true, new System.Text.UTF8Encoding(false))) {
                    zip.AddDirectory(OutputDirectory, outDirInfo.Name);
                    string outpath = Path.Combine(outDirInfo.Parent.FullName, "__AndroidNativeLibraries__.zip");
                    if (Files.ArchiveZip(outpath, f => {
                        using (var fs = new FileStream(f, FileMode.CreateNew)) {
                            stream.CopyTo(fs);
                        }
                    }))
                    {
                        Log.LogDebugMessage("Saving contents to " + outpath);
                    }
                }

            return(true);
        }
        void UpdateWhenChanged(string path, Action <Stream> generator)
        {
            var np = path + ".new";

            using (var o = File.OpenWrite(np))
                generator(o);
            MonoAndroidHelper.CopyIfChanged(np, path);
            File.Delete(np);
        }
Ejemplo n.º 12
0
        void UpdateWhenChanged(string path, Action <Stream> generator)
        {
            var np = path + ".new";

            using (var o = File.OpenWrite(np))
                generator(o);
            MonoAndroidHelper.CopyIfChanged(np, path);
            MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(path, DateTime.UtcNow, Log);
            File.Delete(np);
        }
Ejemplo n.º 13
0
        public async override System.Threading.Tasks.Task RunTaskAsync()
        {
            try {
                LoadResourceCaseMap();

                assemblyMap.Load(Path.Combine(WorkingDirectory, AssemblyIdentityMapFile));

                proguardRuleOutputTemp = GetTempFile();

                await this.WhenAll(ManifestFiles, ProcessManifest);

                ProcessOutput();
                // now check for
                foreach (var kvp in apks)
                {
                    string currentResourceOutputFile = kvp.Key;
                    bool   aaptResult = Daemon.JobSucceded(kvp.Value);
                    LogDebugMessage($"Processing {currentResourceOutputFile} JobId: {kvp.Value} Exists: {File.Exists (currentResourceOutputFile)} JobWorked: {aaptResult}");
                    if (!string.IsNullOrEmpty(currentResourceOutputFile))
                    {
                        var tmpfile = currentResourceOutputFile + ".bk";
                        // aapt2 might not produce an archive and we must provide
                        // and -o foo even if we don't want one.
                        if (File.Exists(tmpfile))
                        {
                            if (aaptResult)
                            {
                                LogDebugMessage($"Copying {tmpfile} to {currentResourceOutputFile}");
                                MonoAndroidHelper.CopyIfZipChanged(tmpfile, currentResourceOutputFile);
                            }
                            File.Delete(tmpfile);
                        }
                        // Delete the archive on failure
                        if (!aaptResult && File.Exists(currentResourceOutputFile))
                        {
                            LogDebugMessage($"Link did not succeed. Deleting {currentResourceOutputFile}");
                            File.Delete(currentResourceOutputFile);
                        }
                    }
                }
                if (!string.IsNullOrEmpty(ProguardRuleOutput))
                {
                    MonoAndroidHelper.CopyIfChanged(proguardRuleOutputTemp, ProguardRuleOutput);
                }
            } finally {
                lock (tempFiles) {
                    foreach (var temp in tempFiles)
                    {
                        File.Delete(temp);
                    }
                    tempFiles.Clear();
                }
            }
        }
        public static void SaveIfChanged(this XDocument document, string fileName)
        {
            var tempFile = System.IO.Path.GetTempFileName();

            try {
                document.Save(tempFile);
                MonoAndroidHelper.CopyIfChanged(tempFile, fileName);
            } finally {
                File.Delete(tempFile);
            }
        }
Ejemplo n.º 15
0
        public override bool RunTask()
        {
            string rawapk = "wearable_app.apk";
            string intermediateApkPath = Path.Combine(IntermediateOutputPath, "res", "raw", rawapk);
            string intermediateXmlFile = Path.Combine(IntermediateOutputPath, "res", "xml", "wearable_app_desc.xml");

            var doc             = XDocument.Load(WearAndroidManifestFile);
            var wearPackageName = AndroidAppManifest.CanonicalizePackageName(doc.Root.Attribute("package").Value);
            var modified        = new List <string> ();

            if (PackageName != wearPackageName)
            {
                Log.LogCodedError("XA5211", Properties.Resources.XA5211, wearPackageName, PackageName);
            }

            if (!File.Exists(WearApplicationApkPath))
            {
                Log.LogWarning("This application won't contain the paired Wear package because the Wear application package .apk is not created yet. If you are using MSBuild or XBuild, you have to invoke \"SignAndroidPackage\" target.");
                return(true);
            }

            var xml = string.Format(@"<wearableApp package=""{0}"">
  <versionCode>{1}</versionCode>
  <versionName>{2}</versionName>
  <rawPathResId>{3}</rawPathResId>
</wearableApp>
", wearPackageName, doc.Root.Attribute(androidNs + "versionCode").Value, doc.Root.Attribute(androidNs + "versionName").Value, Path.GetFileNameWithoutExtension(rawapk));

            if (MonoAndroidHelper.CopyIfChanged(WearApplicationApkPath, intermediateApkPath))
            {
                Log.LogDebugMessage("    Copied APK to {0}", intermediateApkPath);
                modified.Add(intermediateApkPath);
            }

            Directory.CreateDirectory(Path.GetDirectoryName(intermediateXmlFile));
            if (!File.Exists(intermediateXmlFile) || !XDocument.DeepEquals(XDocument.Load(intermediateXmlFile), XDocument.Parse(xml)))
            {
                File.WriteAllText(intermediateXmlFile, xml);
                Log.LogDebugMessage("    Created additional resource as {0}", intermediateXmlFile);
                modified.Add(intermediateXmlFile);
            }
            WearableApplicationDescriptionFile = new TaskItem(intermediateXmlFile);
            WearableApplicationDescriptionFile.SetMetadata("_FlatFile", Monodroid.AndroidResource.CalculateAapt2FlatArchiveFileName(intermediateXmlFile));
            WearableApplicationDescriptionFile.SetMetadata("_ArchiveDirectory", AndroidLibraryFlatFilesDirectory);
            WearableApplicationDescriptionFile.SetMetadata("IsWearApplicationResource", "True");
            BundledWearApplicationApkResourceFile = new TaskItem(intermediateApkPath);
            BundledWearApplicationApkResourceFile.SetMetadata("_FlatFile", Monodroid.AndroidResource.CalculateAapt2FlatArchiveFileName(intermediateApkPath));
            BundledWearApplicationApkResourceFile.SetMetadata("_ArchiveDirectory", AndroidLibraryFlatFilesDirectory);
            BundledWearApplicationApkResourceFile.SetMetadata("IsWearApplicationResource", "True");
            ModifiedFiles = modified.ToArray();

            return(true);
        }
        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 bool SaveIfChanged(this XDocument document, string fileName)
        {
            var tempFile = System.IO.Path.GetTempFileName();

            try {
                using (var stream = File.OpenWrite(tempFile))
                    using (var xw = new Monodroid.LinePreservedXmlWriter(new StreamWriter(stream)))
                        xw.WriteNode(document.CreateNavigator(), false);
                return(MonoAndroidHelper.CopyIfChanged(tempFile, fileName));
            } finally {
                File.Delete(tempFile);
            }
        }
        public override bool Execute()
        {
            var outDirInfo = new DirectoryInfo(OutputDirectory);

            // Copy files into _NativeLibraryImportsDirectoryName (native_library_imports) dir.
            if (!outDirInfo.Exists)
            {
                outDirInfo.Create();
            }
            foreach (var lib in EmbeddedNativeLibraries)
            {
                // seealso bug #3477 to find out why we use this method.
                var abi = MonoAndroidHelper.GetNativeLibraryAbi(lib);
                if (abi == null)
                {
                    Log.LogWarning(
                        subcategory:      string.Empty,
                        warningCode:      "XA4300",
                        helpKeyword:      string.Empty,
                        file:             lib.ItemSpec,
                        lineNumber:       0,
                        columnNumber:     0,
                        endLineNumber:    0,
                        endColumnNumber:  0,
                        message:          "Native library '{0}' will not be bundled because it has an unsupported ABI.",
                        messageArgs:      new [] {
                        lib.ItemSpec,
                    }
                        );
                    continue;
                }
                if (!outDirInfo.GetDirectories(abi).Any())
                {
                    outDirInfo.CreateSubdirectory(abi);
                }
                MonoAndroidHelper.CopyIfChanged(lib.ItemSpec, Path.Combine(OutputDirectory, abi, Path.GetFileName(lib.ItemSpec)));
            }

            var outpath = Path.Combine(outDirInfo.Parent.FullName, "__AndroidNativeLibraries__.zip");

            if (Files.ArchiveZip(outpath, f => {
                using (var zip = new ZipArchiveEx(f)) {
                    zip.AddDirectory(OutputDirectory, "native_library_imports");
                }
            }))
            {
                Log.LogDebugMessage("Saving contents to " + outpath);
            }

            return(!Log.HasLoggedErrors);
        }
Ejemplo n.º 19
0
        public override bool Execute()
        {
            Log.LogDebugMessage("CopyIfChanged Task");
            Log.LogDebugTaskItems("  SourceFiles: {0}", SourceFiles);
            Log.LogDebugTaskItems("  DestinationFiles: {0}", DestinationFiles);

            if (SourceFiles.Length != DestinationFiles.Length)
            {
                throw new ArgumentException("source and destination count mismatch");
            }

            for (int i = 0; i < SourceFiles.Length; i++)
            {
                var src = SourceFiles [i].ItemSpec;
                if (!File.Exists(src))
                {
                    continue;
                }
                var dest            = DestinationFiles [i].ItemSpec;
                var srcmodifiedDate = File.GetLastWriteTimeUtc(src);
                var dstmodifiedDate = File.Exists(dest) ? File.GetLastAccessTimeUtc(dest) : srcmodifiedDate;
                if (dstmodifiedDate > srcmodifiedDate)
                {
                    Log.LogDebugMessage($"  Skipping {src} its up to date");
                    continue;
                }
                if (!MonoAndroidHelper.CopyIfChanged(src, dest))
                {
                    Log.LogDebugMessage($"  Skipping {src} it was not changed.");
                    MonoAndroidHelper.SetWriteable(dest);
                    continue;
                }
                MonoAndroidHelper.SetWriteable(dest);
                modifiedFiles.Add(new TaskItem(dest));
                if (KeepDestinationDates)
                {
                    MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(dest, dstmodifiedDate, Log);
                }
                else
                {
                    MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(dest, DateTime.UtcNow, Log);
                }
            }

            ModifiedFiles = modifiedFiles.ToArray();

            Log.LogDebugTaskItems(" ModifiedFiles:", ModifiedFiles);

            return(true);
        }
Ejemplo n.º 20
0
 public override bool Execute()
 {
     if (AdditionalAssetDirectories != null)
     {
         foreach (var dir in AdditionalAssetDirectories)
         {
             foreach (var file in Directory.GetFiles(dir, "*", SearchOption.AllDirectories))
             {
                 MonoAndroidHelper.CopyIfChanged(file, file.Replace(dir, AssetDirectory));
             }
         }
     }
     return(true);
 }
        public override bool Execute()
        {
            Log.LogDebugMessage("PrepareWearApplicationFiles task");
            Log.LogDebugTaskItems("  WearAndroidManifestFile:", WearAndroidManifestFile);
            Log.LogDebugTaskItems("  IntermediateOutputPath:", IntermediateOutputPath);
            Log.LogDebugTaskItems("  WearApplicationApkPath:", WearApplicationApkPath);

            string rawapk = "wearable_app.apk";
            string intermediateApkPath = Path.Combine(IntermediateOutputPath, "res", "raw", rawapk);
            string intermediateXmlFile = Path.Combine(IntermediateOutputPath, "res", "xml", "wearable_app_desc.xml");

            var doc             = XDocument.Load(WearAndroidManifestFile);
            var wearPackageName = AndroidAppManifest.CanonicalizePackageName(doc.Root.Attribute("package").Value);

            if (PackageName != wearPackageName)
            {
                Log.LogCodedError("XA5211", "Embedded wear app package name differs from handheld app package name ({0} != {1}).", wearPackageName, PackageName);
            }

            if (!File.Exists(WearApplicationApkPath))
            {
                Log.LogWarning("This application won't contain the paired Wear package because the Wear application package .apk is not created yet. If you are using MSBuild or XBuild, you have to invoke \"SignAndroidPackage\" target.");
                return(true);
            }

            var xml = string.Format(@"<wearableApp package=""{0}"">
  <versionCode>{1}</versionCode>
  <versionName>{2}</versionName>
  <rawPathResId>{3}</rawPathResId>
</wearableApp>
", wearPackageName, doc.Root.Attribute(androidNs + "versionCode").Value, doc.Root.Attribute(androidNs + "versionName").Value, Path.GetFileNameWithoutExtension(rawapk));

            MonoAndroidHelper.CopyIfChanged(WearApplicationApkPath, intermediateApkPath);

            Directory.CreateDirectory(Path.GetDirectoryName(intermediateXmlFile));
            if (!File.Exists(intermediateXmlFile) || !XDocument.DeepEquals(XDocument.Load(intermediateXmlFile), XDocument.Parse(xml)))
            {
                File.WriteAllText(intermediateXmlFile, xml);
                Log.LogDebugMessage("    Created additional resource as {0}", intermediateXmlFile);
            }
            WearableApplicationDescriptionFile = new TaskItem(intermediateXmlFile);
            WearableApplicationDescriptionFile.SetMetadata("IsWearApplicationResource", "True");
            BundledWearApplicationApkResourceFile = new TaskItem(intermediateApkPath);
            BundledWearApplicationApkResourceFile.SetMetadata("IsWearApplicationResource", "True");

            return(true);
        }
Ejemplo n.º 22
0
        int DoExecute(IGrouping <string, ITaskItem> imageGroup, ThreadingTasks.ParallelLoopState state, int loop)
        {
            var tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());

            Directory.CreateDirectory(tempDirectory);
            var tempOutputDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());

            Directory.CreateDirectory(tempOutputDirectory);
            try {
                LogDebugMessage("Crunch Processing : {0}", imageGroup.Key);
                LogDebugTaskItems("  Items :", imageGroup.ToArray());
                foreach (var item in imageGroup)
                {
                    var dest = Path.GetFullPath(item.ItemSpec).Replace(imageGroup.Key, tempDirectory);
                    Directory.CreateDirectory(Path.GetDirectoryName(dest));
                    MonoAndroidHelper.CopyIfChanged(item.ItemSpec, dest);
                    MonoAndroidHelper.SetWriteable(dest);
                }

                // crunch them
                if (!RunAapt(GenerateCommandLineCommands(tempDirectory, tempOutputDirectory)))
                {
                    return(0);
                }

                // copy them back
                foreach (var item in imageGroup)
                {
                    var dest            = Path.GetFullPath(item.ItemSpec).Replace(imageGroup.Key, tempOutputDirectory);
                    var srcmodifiedDate = File.GetLastWriteTimeUtc(item.ItemSpec);
                    if (!File.Exists(dest))
                    {
                        continue;
                    }
                    MonoAndroidHelper.CopyIfChanged(dest, item.ItemSpec);
                    MonoAndroidHelper.SetWriteable(dest);
                    // reset the Dates so MSBuild/xbuild doesn't think they changed.
                    MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(item.ItemSpec, srcmodifiedDate, Log);
                }
            }
            finally {
                Directory.Delete(tempDirectory, recursive: true);
                Directory.Delete(tempOutputDirectory, recursive: true);
            }
            return(0);
        }
        static void CopyDirectory(DirectoryInfo srcSubdirInfo, string dst, bool top)
        {
            string dstsub = Path.Combine(dst, srcSubdirInfo.Name);

            if (!Directory.Exists(dstsub))
            {
                Directory.CreateDirectory(dstsub);
            }
            foreach (var subsub in srcSubdirInfo.GetDirectories())
            {
                // Skip "classes" dir.
                if (top && subsub.Name.ToLowerInvariant() == "classes")
                {
                    continue;
                }
                CopyDirectory(subsub, dstsub, false);
            }
            foreach (var file in srcSubdirInfo.GetFiles())
            {
                MonoAndroidHelper.CopyIfChanged(file.FullName, Path.Combine(dstsub, file.Name));
            }
        }
Ejemplo n.º 24
0
        public override bool Execute()
        {
            Log.LogDebugTaskItems("SourceFiles:", SourceFiles);
            Log.LogDebugTaskItems("DestinationFiles:", DestinationFiles);

            if (SourceFiles.Length != DestinationFiles.Length)
            {
                throw new ArgumentException("source and destination count mismatch");
            }

            for (int i = 0; i < SourceFiles.Length; i++)
            {
                var src  = SourceFiles [i].ItemSpec;
                var dst  = DestinationFiles [i].ItemSpec;
                var date = DateTime.Now;
                if (File.Exists(src))
                {
                    MonoAndroidHelper.CopyIfChanged(src, dst);
                }
            }
            return(true);
        }
Ejemplo n.º 25
0
        public override bool RunTask()
        {
            if (SourceFiles.Length != DestinationFiles.Length)
            {
                throw new ArgumentException("source and destination count mismatch");
            }

            for (int i = 0; i < SourceFiles.Length; i++)
            {
                var src = new FileInfo(SourceFiles [i].ItemSpec);
                if (!src.Exists)
                {
                    Log.LogDebugMessage($"  Skipping {src} it does not exist");
                    continue;
                }
                var dest = new FileInfo(DestinationFiles [i].ItemSpec);
                if (dest.Exists && dest.LastWriteTimeUtc > src.LastWriteTimeUtc && dest.Length == src.Length)
                {
                    Log.LogDebugMessage($"  Skipping {src} it is up to date");
                    continue;
                }
                if (!MonoAndroidHelper.CopyIfChanged(src.FullName, dest.FullName))
                {
                    Log.LogDebugMessage($"  Skipping {src} it was not changed.");
                    MonoAndroidHelper.SetWriteable(dest.FullName);
                    continue;
                }
                modifiedFiles.Add(new TaskItem(dest.FullName));
            }

            ModifiedFiles = modifiedFiles.ToArray();

            Log.LogDebugTaskItems(" ModifiedFiles:", ModifiedFiles);

            return(true);
        }
        private void WriteFile(string file, CodeTypeDeclaration resources, string language, bool isFSharp, bool isCSharp)
        {
            CodeDomProvider provider =
                isFSharp ? new FSharp.Compiler.CodeDom.FSharpCodeProvider() :
                CodeDomProvider.CreateProvider(language);

            string code = null;

            using (var o = new StringWriter()) {
                var options = new CodeGeneratorOptions()
                {
                    BracingStyle = "C",
                    IndentString = "\t",
                };

                var ns = string.IsNullOrEmpty(Namespace)
                                        ? new CodeNamespace()
                                        : new CodeNamespace(Namespace);

                if (resources != null)
                {
                    ns.Types.Add(resources);
                }

                var unit = new CodeCompileUnit();
                unit.Namespaces.Add(ns);

                var resgenatt = new CodeAttributeDeclaration(new CodeTypeReference("Android.Runtime.ResourceDesignerAttribute", CodeTypeReferenceOptions.GlobalReference));
                resgenatt.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(Namespace.Length > 0 ? Namespace + ".Resource" : "Resource")));
                resgenatt.Arguments.Add(new CodeAttributeArgument("IsApplication", new CodePrimitiveExpression(IsApplication)));
                unit.AssemblyCustomAttributes.Add(resgenatt);

                // Add Pragma to disable warnings about no Xml documentation
                if (isCSharp)
                {
                    provider.GenerateCodeFromCompileUnit(new CodeSnippetCompileUnit("#pragma warning disable 1591"), o, options);
                }

                provider.CreateGenerator(o).GenerateCodeFromCompileUnit(unit, o, options);

                // Add Pragma to re-enable warnings about no Xml documentation
                if (isCSharp)
                {
                    provider.GenerateCodeFromCompileUnit(new CodeSnippetCompileUnit("#pragma warning restore 1591"), o, options);
                }

                code = o.ToString();

                // post-processing for F#
                if (isFSharp)
                {
                    code = code.Replace("\r\n", "\n");
                    while (true)
                    {
                        int skipLen = " = class".Length;
                        int idx     = code.IndexOf(" = class");
                        if (idx < 0)
                        {
                            break;
                        }
                        int    end  = code.IndexOf("        end");
                        string head = code.Substring(0, idx);
                        string mid  = end < 0 ? code.Substring(idx) : code.Substring(idx + skipLen, end - idx - skipLen);
                        string last = end < 0 ? null : code.Substring(end + "        end".Length);
                        code = head + @" () =
            static do Android.Runtime.ResourceIdManager.UpdateIdValues()" + mid + "\n" + last;
                    }
                }
            }

            var temp_o = Path.Combine(Path.GetDirectoryName(file), "__" + Path.GetFileName(file) + ".new");

            using (TextWriter o = File.CreateText(temp_o))
                o.Write(code);
            MonoAndroidHelper.CopyIfChanged(temp_o, file);
            try { File.Delete(temp_o); } catch (Exception) { }
        }
        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 Execute()
        {
            Log.LogDebugMessage("GeneratePackageManagerJava Task");
            Log.LogDebugMessage("  OutputDirectory: {0}", OutputDirectory);
            Log.LogDebugMessage("  TargetFrameworkVersion: {0}", TargetFrameworkVersion);
            Log.LogDebugMessage("  Manifest: {0}", Manifest);
            Log.LogDebugMessage("  UseSharedRuntime: {0}", UseSharedRuntime);
            Log.LogDebugMessage("  MainAssembly: {0}", MainAssembly);
            Log.LogDebugTaskItems("  ResolvedAssemblies:", ResolvedAssemblies);
            Log.LogDebugTaskItems("  ResolvedUserAssemblies:", ResolvedUserAssemblies);

            var shared_runtime = string.Compare(UseSharedRuntime, "true", true) == 0;
            var doc            = AndroidAppManifest.Load(Manifest, MonoAndroidHelper.SupportedVersions);
            int minApiVersion  = doc.MinSdkVersion == null ? 4 : (int)doc.MinSdkVersion;
            // We need to include any special assemblies in the Assemblies list
            var assemblies = ResolvedUserAssemblies.Select(p => p.ItemSpec)
                             .Concat(MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies))
                             .ToList();
            var mainFileName = Path.GetFileName(MainAssembly);
            Func <string, string, bool> fileNameEq = (a, b) => a.Equals(b, StringComparison.OrdinalIgnoreCase);

            assemblies = assemblies.Where(a => fileNameEq(a, mainFileName)).Concat(assemblies.Where(a => !fileNameEq(a, mainFileName))).ToList();

            // Write first to a temporary file
            var temp = Path.GetTempFileName();

            using (var pkgmgr = File.CreateText(temp)) {
                // Write the boilerplate from the MonoPackageManager.java resource
                var packageManagerResource = minApiVersion < 9 ? "MonoPackageManager.api4.java" : "MonoPackageManager.java";
                using (var template = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream(packageManagerResource))) {
                    string line;
                    while ((line = template.ReadLine()) != null)
                    {
                        pkgmgr.WriteLine(line);
                    }
                }

                // Write all the user assemblies
                pkgmgr.WriteLine("class MonoPackageManager_Resources {");
                pkgmgr.WriteLine("\tpublic static final String[] Assemblies = new String[]{");

                pkgmgr.WriteLine("\t\t/* We need to ensure that \"{0}\" comes first in this list. */", mainFileName);
                foreach (var assembly in assemblies)
                {
                    pkgmgr.WriteLine("\t\t\"" + Path.GetFileName(assembly) + "\",");
                }

                // Write the assembly dependencies
                pkgmgr.WriteLine("\t};");
                pkgmgr.WriteLine("\tpublic static final String[] Dependencies = new String[]{");

                //foreach (var assembly in assemblies.Except (args.Assemblies)) {
                //        if (args.SharedRuntime && !Toolbox.IsInSharedRuntime (assembly))
                //                pkgmgr.WriteLine ("\t\t\"" + Path.GetFileName (assembly) + "\",");
                //}

                pkgmgr.WriteLine("\t};");

                // Write the platform api apk we need
                pkgmgr.WriteLine("\tpublic static final String ApiPackageName = {0};", shared_runtime
                                                ? string.Format("\"Mono.Android.Platform.ApiLevel_{0}\"",
                                                                MonoAndroidHelper.SupportedVersions.GetApiLevelFromFrameworkVersion(TargetFrameworkVersion))
                                                : "null");
                pkgmgr.WriteLine("}");
            }

            // Only copy to the real location if the contents actually changed
            var dest = Path.GetFullPath(Path.Combine(OutputDirectory, "MonoPackageManager.java"));

            MonoAndroidHelper.CopyIfChanged(temp, dest);

            try { File.Delete(temp); } catch (Exception) { }

            try { File.Delete(temp); } catch (Exception) { }

            return(!Log.HasLoggedErrors);
        }
Ejemplo n.º 29
0
        bool GenerateSource(BindingGenerator generator, string outputFilePath, ICollection <LayoutWidget> widgets, string classNamespace, string className, List <PartialClass> partialClasses)
        {
            bool result   = false;
            var  tempFile = Path.GetTempFileName();

            try {
                if (partialClasses != null && partialClasses.Count > 0)
                {
                    foreach (var pc in partialClasses)
                    {
                        if (pc == null)
                        {
                            continue;
                        }

                        pc.Stream = File.Open(pc.OutputFilePath, FileMode.Create);
                        pc.Writer = new StreamWriter(pc.Stream, Encoding.UTF8);
                    }
                }

                using (var fs = File.Open(tempFile, FileMode.Create)) {
                    using (var sw = new StreamWriter(fs, Encoding.UTF8)) {
                        result = GenerateSource(sw, generator, widgets, classNamespace, className, partialClasses);
                    }
                }
                if (result)
                {
                    MonoAndroidHelper.CopyIfChanged(tempFile, outputFilePath);
                }
            } finally {
                if (File.Exists(tempFile))
                {
                    File.Delete(tempFile);
                }
                if (partialClasses != null && partialClasses.Count > 0)
                {
                    foreach (var pc in partialClasses)
                    {
                        if (pc == null)
                        {
                            continue;
                        }

                        if (pc.Writer != null)
                        {
                            pc.Writer.Close();
                            pc.Writer.Dispose();
                        }

                        if (pc.Stream == null)
                        {
                            continue;
                        }

                        pc.Stream.Close();
                        pc.Stream.Dispose();
                    }
                }
            }
            return(result);
        }
Ejemplo n.º 30
0
        bool Execute(DirectoryAssemblyResolver res)
        {
            // Put every assembly we'll need in the resolver
            foreach (var assembly in ResolvedAssemblies)
            {
                res.Load(Path.GetFullPath(assembly.ItemSpec));
            }

            var resolver = new AssemblyResolver(res.ToResolverCache());

            // Set up for linking
            var options = new LinkerOptions();

            options.MainAssembly     = res.GetAssembly(MainAssembly);
            options.OutputDirectory  = Path.GetFullPath(OutputDirectory);
            options.LinkSdkOnly      = string.Compare(LinkMode, "SdkOnly", true) == 0;
            options.LinkNone         = string.Compare(LinkMode, "None", true) == 0;
            options.Resolver         = resolver;
            options.LinkDescriptions = LinkDescriptions.Select(item => Path.GetFullPath(item.ItemSpec)).ToArray();
            options.I18nAssemblies   = Linker.ParseI18nAssemblies(I18nAssemblies);
            if (!options.LinkSdkOnly)
            {
                options.RetainAssemblies = GetRetainAssemblies(res);
            }
            options.DumpDependencies          = DumpDependencies;
            options.HttpClientHandlerType     = HttpClientHandlerType;
            options.TlsProvider               = TlsProvider;
            options.PreserveJniMarshalMethods = PreserveJniMarshalMethods;

            var skiplist = new List <string> ();

            if (string.Compare(UseSharedRuntime, "true", true) == 0)
            {
                skiplist.AddRange(Profile.SharedRuntimeAssemblies.Where(a => a.EndsWith(".dll")).Select(a => Path.GetFileNameWithoutExtension(a)));
            }
            if (!string.IsNullOrWhiteSpace(LinkOnlyNewerThan) && File.Exists(LinkOnlyNewerThan))
            {
                var newerThan   = File.GetLastWriteTime(LinkOnlyNewerThan);
                var skipOldOnes = ResolvedAssemblies.Where(a => File.GetLastWriteTime(a.ItemSpec) < newerThan);
                foreach (var old in skipOldOnes)
                {
                    Log.LogMessage(MBF.MessageImportance.Low, "  Skip linking unchanged file: " + old.ItemSpec);
                }
                skiplist = skipOldOnes.Select(a => Path.GetFileNameWithoutExtension(a.ItemSpec)).Concat(skiplist).ToList();
            }

            // Add LinkSkip options
            if (!string.IsNullOrWhiteSpace(LinkSkip))
            {
                foreach (var assembly in LinkSkip.Split(',', ';'))
                {
                    skiplist.Add(assembly);
                }
            }

            options.SkippedAssemblies = skiplist;

            if (EnableProguard)
            {
                options.ProguardConfiguration = ProguardConfiguration;
            }

            // Link!
            try {
                LinkContext link_context;
                Linker.Process(options, this, out link_context);

                var copydst = OptionalDestinationDirectory ?? OutputDirectory;

                foreach (var assembly in ResolvedAssemblies)
                {
                    var copysrc             = assembly.ItemSpec;
                    var filename            = Path.GetFileName(assembly.ItemSpec);
                    var assemblyDestination = Path.Combine(copydst, filename);

                    if (options.LinkNone)
                    {
                        if (skiplist.Any(s => Path.GetFileNameWithoutExtension(filename) == s))
                        {
                            // For skipped assemblies, skip if there is existing file in the destination.
                            // We cannot just copy the linker output from *current* run output, because
                            // it always renew the assemblies, in *different* binary values, whereas
                            // the dll in the OptionalDestinationDirectory must retain old and unchanged.
                            if (File.Exists(assemblyDestination))
                            {
                                MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(assemblyDestination, DateTime.UtcNow, Log);
                                continue;
                            }
                        }
                        else
                        {
                            // Prefer fixup assemblies if exists, otherwise just copy the original.
                            copysrc = Path.Combine(OutputDirectory, filename);
                            copysrc = File.Exists(copysrc) ? copysrc : assembly.ItemSpec;
                        }
                    }
                    else if (!MonoAndroidHelper.IsForceRetainedAssembly(filename))
                    {
                        continue;
                    }

                    if (MonoAndroidHelper.CopyIfChanged(copysrc, assemblyDestination))
                    {
                        MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(assemblyDestination, DateTime.UtcNow, Log);
                    }
                    try {
                        var mdbDestination = assemblyDestination + ".mdb";
                        if (MonoAndroidHelper.CopyIfChanged(assembly.ItemSpec + ".mdb", mdbDestination))
                        {
                            MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(mdbDestination, DateTime.UtcNow, Log);
                        }
                    } catch (Exception) {                     // skip it, mdb sometimes fails to read and it's optional
                    }
                    var pdb = Path.ChangeExtension(copysrc, "pdb");
                    if (File.Exists(pdb) && Files.IsPortablePdb(pdb))
                    {
                        var pdbDestination = Path.ChangeExtension(Path.Combine(copydst, filename), "pdb");
                        if (MonoAndroidHelper.CopyIfChanged(pdb, pdbDestination))
                        {
                            MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(pdbDestination, DateTime.UtcNow, Log);
                        }
                    }
                }
            } catch (ResolutionException ex) {
                Diagnostic.Error(2006, ex, "Could not resolve reference to '{0}' (defined in assembly '{1}') with scope '{2}'. When the scope is different from the defining assembly, it usually means that the type is forwarded.", ex.Member, ex.Member.Module.Assembly, ex.Scope);
            }

            return(true);
        }