diff --git a/build-tools/unix-distribution-setup/unix-distribution-setup.targets b/build-tools/unix-distribution-setup/unix-distribution-setup.targets index edca94d5465..d7535d1c5d1 100644 --- a/build-tools/unix-distribution-setup/unix-distribution-setup.targets +++ b/build-tools/unix-distribution-setup/unix-distribution-setup.targets @@ -9,6 +9,14 @@ Condition=" '$(HostOS)' != 'Windows' " Command="chmod +x $(OutputPath)bin\generator" /> + + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Aapt.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Aapt.cs index 6e08e31f75a..de9ff551bd8 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/Aapt.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/Aapt.cs @@ -99,36 +99,37 @@ bool RunAapt (string commandLine) WindowStyle = ProcessWindowStyle.Hidden, }; - var proc = new Process (); - proc.OutputDataReceived += (sender, e) => { - if (e.Data != null) - LogEventsFromTextOutput (e.Data, MessageImportance.Normal); - else - stdout_completed.Set (); - }; - proc.ErrorDataReceived += (sender, e) => { - if (e.Data != null) - LogEventsFromTextOutput (e.Data, MessageImportance.Normal); - else - stderr_completed.Set (); - }; - proc.StartInfo = psi; - proc.Start (); - proc.BeginOutputReadLine (); - proc.BeginErrorReadLine (); - Token.Register (() => { - try { - proc.Kill (); - } catch (Exception) { - } - }); - LogDebugMessage ("Executing {0}", commandLine); - proc.WaitForExit (); - if (psi.RedirectStandardError) - stderr_completed.WaitOne (TimeSpan.FromSeconds (30)); - if (psi.RedirectStandardOutput) - stdout_completed.WaitOne (TimeSpan.FromSeconds (30)); - return proc.ExitCode == 0; + using (var proc = new Process ()) { + proc.OutputDataReceived += (sender, e) => { + if (e.Data != null) + LogEventsFromTextOutput (e.Data, MessageImportance.Normal); + else + stdout_completed.Set (); + }; + proc.ErrorDataReceived += (sender, e) => { + if (e.Data != null) + LogEventsFromTextOutput (e.Data, MessageImportance.Normal); + else + stderr_completed.Set (); + }; + proc.StartInfo = psi; + proc.Start (); + proc.BeginOutputReadLine (); + proc.BeginErrorReadLine (); + Token.Register (() => { + try { + proc.Kill (); + } catch (Exception) { + } + }); + LogDebugMessage ("Executing {0}", commandLine); + proc.WaitForExit (); + if (psi.RedirectStandardError) + stderr_completed.WaitOne (TimeSpan.FromSeconds (30)); + if (psi.RedirectStandardOutput) + stdout_completed.WaitOne (TimeSpan.FromSeconds (30)); + return proc.ExitCode == 0; + } } bool ExecuteForAbi (string cmd, string currentResourceOutputFile) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs index 6411dec6b70..4f00d3507cf 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs @@ -434,6 +434,8 @@ IEnumerable GetAotConfigs () bool RunAotCompiler (string assembliesPath, string aotCompiler, string aotOptions, string assembly, CancellationToken token) { + var stdout_completed = new ManualResetEvent (false); + var stderr_completed = new ManualResetEvent (false); var psi = new ProcessStartInfo () { FileName = aotCompiler, Arguments = aotOptions + " \"" + assembly + "\"", @@ -453,16 +455,32 @@ bool RunAotCompiler (string assembliesPath, string aotCompiler, string aotOption LogDebugMessage ("[AOT] MONO_PATH=\"{0}\" MONO_ENV_OPTIONS=\"{1}\" {2} {3}", psi.EnvironmentVariables ["MONO_PATH"], psi.EnvironmentVariables ["MONO_ENV_OPTIONS"], psi.FileName, psi.Arguments); - var proc = new Process (); - proc.OutputDataReceived += OnAotOutputData; - proc.ErrorDataReceived += OnAotErrorData; - proc.StartInfo = psi; - proc.Start (); - proc.BeginOutputReadLine (); - proc.BeginErrorReadLine (); - token.Register (() => { try { proc.Kill (); } catch (Exception) {} }); - proc.WaitForExit (); - return proc.ExitCode == 0; + using (var proc = new Process ()) { + proc.OutputDataReceived += (s, e) => { + if (e.Data != null) + OnAotOutputData (s, e); + else + stdout_completed.Set (); + }; + proc.ErrorDataReceived += (s, e) => { + if (e.Data != null) + OnAotErrorData (s, e); + else + stderr_completed.Set (); + }; + proc.StartInfo = psi; + proc.Start (); + proc.BeginOutputReadLine (); + proc.BeginErrorReadLine (); + token.Register (() => { try { proc.Kill (); } catch (Exception) { } }); + proc.WaitForExit (); + if (psi.RedirectStandardError) + stderr_completed.WaitOne (TimeSpan.FromSeconds (30)); + if (psi.RedirectStandardOutput) + stdout_completed.WaitOne (TimeSpan.FromSeconds (30)); + return proc.ExitCode == 0; + } + GC.Collect (); } void OnAotOutputData (object sender, DataReceivedEventArgs e) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs b/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs index 2246b7c75a7..54d2d6fbe85 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs @@ -116,34 +116,44 @@ void ExecuteWithAbi (string supportedAbis, string apkInputPath, string apkOutput ArchiveFileList files = new ArchiveFileList (); if (apkInputPath != null) File.Copy (apkInputPath, apkOutputPath + "new", overwrite: true); - using (var apk = ZipArchive.Open (apkOutputPath + "new", apkInputPath != null ? FileMode.Open : FileMode.Create )) { - apk.AddEntry ("NOTICE", + using (var apk = new ZipArchiveEx (apkOutputPath + "new", apkInputPath != null ? FileMode.Open : FileMode.Create )) { + apk.Archive.AddEntry ("NOTICE", Assembly.GetExecutingAssembly ().GetManifestResourceStream ("NOTICE.txt")); // Add classes.dx - apk.AddFiles (DalvikClasses, useFileDirectories: false); + apk.Archive.AddFiles (DalvikClasses, useFileDirectories: false); if (EmbedAssemblies && !BundleAssemblies) AddAssemblies (apk); AddEnvironment (apk); AddRuntimeLibraries (apk, supportedAbis); + apk.Flush(); AddNativeLibraries (files, supportedAbis); + apk.Flush(); AddAdditionalNativeLibraries (files, supportedAbis); + apk.Flush(); AddNativeLibrariesFromAssemblies (apk, supportedAbis); + apk.Flush(); foreach (ITaskItem typemap in TypeMappings) { - apk.AddFile (typemap.ItemSpec, Path.GetFileName(typemap.ItemSpec), compressionMethod: CompressionMethod.Store); + apk.Archive.AddFile (typemap.ItemSpec, Path.GetFileName(typemap.ItemSpec), compressionMethod: CompressionMethod.Store); } + int count = 0; foreach (var file in files) { var item = Path.Combine (file.Item2, Path.GetFileName (file.Item1)) .Replace (Path.DirectorySeparatorChar, '/'); - if (apk.ContainsEntry (item)) { + if (apk.Archive.ContainsEntry (item)) { Log.LogWarning (null, "XA4301", null, file.Item1, 0, 0, 0, 0, "Apk already contains the item {0}; ignoring.", item); continue; } - apk.AddFile (file.Item1, item); + apk.Archive.AddFile (file.Item1, item); + count++; + if (count == ZipArchiveEx.ZipFlushLimit) { + apk.Flush(); + count = 0; + } } if (_Debug) AddGdbservers (apk, files, supportedAbis, debugServer); @@ -160,6 +170,7 @@ void ExecuteWithAbi (string supportedAbis, string apkInputPath, string apkOutput var jarFilePaths = libraryProjectJars.Concat (jarFiles != null ? jarFiles.Select (j => j.ItemSpec) : Enumerable.Empty ()); jarFilePaths = MonoAndroidHelper.DistinctFilesByContent (jarFilePaths); + count = 0; foreach (var jarFile in jarFilePaths) { using (var jar = ZipArchive.Open (File.OpenRead (jarFile))) { foreach (var jarItem in jar.Where (ze => !ze.IsDirectory && !ze.FullName.StartsWith ("META-INF") && !ze.FullName.EndsWith (".class") && !ze.FullName.EndsWith (".java") && !ze.FullName.EndsWith ("MANIFEST.MF"))) { @@ -168,15 +179,20 @@ void ExecuteWithAbi (string supportedAbis, string apkInputPath, string apkOutput jarItem.Extract (d); data = d.ToArray (); } - if (apk.Any (e => e.FullName == jarItem.FullName)) + if (apk.Archive.Any (e => e.FullName == jarItem.FullName)) Log.LogMessage ("Warning: failed to add jar entry {0} from {1}: the same file already exists in the apk", jarItem.FullName, Path.GetFileName (jarFile)); else - apk.AddEntry (data, jarItem.FullName); + apk.Archive.AddEntry (data, jarItem.FullName); } } + count++; + if (count == ZipArchiveEx.ZipFlushLimit) { + apk.Flush(); + count = 0; + } } if (StubApplicationDataFile != null && File.Exists (StubApplicationDataFile)) - apk.AddFile (StubApplicationDataFile, Path.GetFileName (StubApplicationDataFile)); + apk.Archive.AddFile (StubApplicationDataFile, Path.GetFileName (StubApplicationDataFile)); } MonoAndroidHelper.CopyIfZipChanged (apkOutputPath + "new", apkOutputPath); File.Delete (apkOutputPath + "new"); @@ -249,14 +265,15 @@ public override bool Execute () return !Log.HasLoggedErrors; } - private void AddAssemblies (ZipArchive apk) + private void AddAssemblies (ZipArchiveEx apk) { bool debug = _Debug; bool use_shared_runtime = String.Equals (UseSharedRuntime, "true", StringComparison.OrdinalIgnoreCase); + int count = 0; foreach (ITaskItem assembly in ResolvedUserAssemblies) { // Add assembly - apk.AddFile (assembly.ItemSpec, GetTargetDirectory (assembly.ItemSpec) + "/" + Path.GetFileName (assembly.ItemSpec), compressionMethod: CompressionMethod.Store); + apk.Archive.AddFile (assembly.ItemSpec, GetTargetDirectory (assembly.ItemSpec) + "/" + Path.GetFileName (assembly.ItemSpec), compressionMethod: CompressionMethod.Store); // Try to add config if exists var config = Path.ChangeExtension (assembly.ItemSpec, "dll.config"); @@ -267,21 +284,27 @@ private void AddAssemblies (ZipArchive apk) var symbols = Path.ChangeExtension (assembly.ItemSpec, "dll.mdb"); if (File.Exists (symbols)) - apk.AddFile (symbols, "assemblies/" + Path.GetFileName (symbols), compressionMethod: CompressionMethod.Store); + apk.Archive.AddFile (symbols, "assemblies/" + Path.GetFileName (symbols), compressionMethod: CompressionMethod.Store); symbols = Path.ChangeExtension (assembly.ItemSpec, "pdb"); if (File.Exists (symbols)) - apk.AddFile (symbols, "assemblies/" + Path.GetFileName (symbols), compressionMethod: CompressionMethod.Store); + apk.Archive.AddFile (symbols, "assemblies/" + Path.GetFileName (symbols), compressionMethod: CompressionMethod.Store); + } + count++; + if (count == ZipArchiveEx.ZipFlushLimit) { + apk.Flush(); + count = 0; } } if (use_shared_runtime) return; + count = 0; // Add framework assemblies foreach (ITaskItem assembly in ResolvedFrameworkAssemblies) { - apk.AddFile (assembly.ItemSpec, "assemblies/" + Path.GetFileName (assembly.ItemSpec), compressionMethod: CompressionMethod.Store); + apk.Archive.AddFile (assembly.ItemSpec, "assemblies/" + Path.GetFileName (assembly.ItemSpec), compressionMethod: CompressionMethod.Store); var config = Path.ChangeExtension (assembly.ItemSpec, "dll.config"); AddAssemblyConfigEntry (apk, config); // Try to add symbols if Debug @@ -289,17 +312,22 @@ private void AddAssemblies (ZipArchive apk) var symbols = Path.ChangeExtension (assembly.ItemSpec, "dll.mdb"); if (File.Exists (symbols)) - apk.AddFile (symbols, "assemblies/" + Path.GetFileName (symbols), compressionMethod: CompressionMethod.Store); + apk.Archive.AddFile (symbols, "assemblies/" + Path.GetFileName (symbols), compressionMethod: CompressionMethod.Store); symbols = Path.ChangeExtension (assembly.ItemSpec, "pdb"); if (File.Exists (symbols)) - apk.AddFile (symbols, "assemblies/" + Path.GetFileName (symbols), compressionMethod: CompressionMethod.Store); + apk.Archive.AddFile (symbols, "assemblies/" + Path.GetFileName (symbols), compressionMethod: CompressionMethod.Store); + } + count++; + if (count == ZipArchiveEx.ZipFlushLimit) { + apk.Flush(); + count = 0; } } } - void AddAssemblyConfigEntry (ZipArchive apk, string configFile) + void AddAssemblyConfigEntry (ZipArchiveEx apk, string configFile) { if (!File.Exists (configFile)) return; @@ -309,7 +337,7 @@ void AddAssemblyConfigEntry (ZipArchive apk, string configFile) source.CopyTo (dest); dest.WriteByte (0); dest.Position = 0; - apk.AddEntry ("assemblies/" + Path.GetFileName (configFile), dest, compressionMethod: CompressionMethod.Store); + apk.Archive.AddEntry ("assemblies/" + Path.GetFileName (configFile), dest, compressionMethod: CompressionMethod.Store); } } @@ -322,7 +350,7 @@ static string GetTargetDirectory (string path) return "assemblies"; } - void AddEnvironment (ZipArchive apk) + void AddEnvironment (ZipArchiveEx apk) { var environment = new StringWriter () { NewLine = "\n", @@ -395,7 +423,7 @@ void AddEnvironment (ZipArchive apk) environment.WriteLine ("MONO_GC_PARAMS=major=marksweep"); } - apk.AddEntry ("environment", environment.ToString (), + apk.Archive.AddEntry ("environment", environment.ToString (), new UTF8Encoding (encoderShouldEmitUTF8Identifier:false)); } @@ -431,13 +459,13 @@ HashSet ParseProfilers (string value) return results; } - void AddNativeLibrary (ZipArchive apk, string abi, string filename) + void AddNativeLibrary (ZipArchiveEx apk, string abi, string filename) { var path = Path.Combine (MSBuildXamarinAndroidDirectory, "lib", abi, filename); - apk.AddEntry (string.Format ("lib/{0}/{1}", abi, filename), File.OpenRead (path)); + apk.Archive.AddEntry (string.Format ("lib/{0}/{1}", abi, filename), File.OpenRead (path)); } - void AddProfilers (ZipArchive apk, string abi) + void AddProfilers (ZipArchiveEx apk, string abi) { if (!string.IsNullOrEmpty (AndroidEmbedProfilers)) { foreach (var profiler in ParseProfilers (AndroidEmbedProfilers)) { @@ -447,7 +475,7 @@ void AddProfilers (ZipArchive apk, string abi) } } - void AddBtlsLibs (ZipArchive apk, string abi) + void AddBtlsLibs (ZipArchiveEx apk, string abi) { if (string.Compare ("btls", TlsProvider, StringComparison.OrdinalIgnoreCase) == 0) { AddNativeLibrary (apk, abi, "libmono-btls-shared.so"); @@ -457,14 +485,14 @@ void AddBtlsLibs (ZipArchive apk, string abi) // * "legacy": } - void AddRuntimeLibraries (ZipArchive apk, string supportedAbis) + void AddRuntimeLibraries (ZipArchiveEx apk, string supportedAbis) { bool use_shared_runtime = String.Equals (UseSharedRuntime, "true", StringComparison.OrdinalIgnoreCase); var abis = supportedAbis.Split (new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (var abi in abis) { string library = string.Format ("libmono-android.{0}.so", _Debug ? "debug" : "release"); var path = Path.Combine (MSBuildXamarinAndroidDirectory, "lib", abi, library); - apk.AddEntry (string.Format ("lib/{0}/libmonodroid.so", abi), File.OpenRead (path)); + apk.Archive.AddEntry (string.Format ("lib/{0}/libmonodroid.so", abi), File.OpenRead (path)); if (!use_shared_runtime) { // include the sgen AddNativeLibrary (apk, abi, "libmonosgen-2.0.so"); @@ -474,8 +502,9 @@ void AddRuntimeLibraries (ZipArchive apk, string supportedAbis) } } - void AddNativeLibrariesFromAssemblies (ZipArchive apk, string supportedAbis) + void AddNativeLibrariesFromAssemblies (ZipArchiveEx apk, string supportedAbis) { + int count = 0; var abis = supportedAbis.Split (new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); using (var res = new DirectoryAssemblyResolver (Console.WriteLine, loadDebugSymbols: false)) { foreach (var assembly in EmbeddedNativeLibraryAssemblies) @@ -493,19 +522,24 @@ void AddNativeLibrariesFromAssemblies (ZipArchive apk, string supportedAbis) if (e.IsDirectory) continue; var key = e.FullName.Replace ("native_library_imports", "lib"); - if (apk.Any (k => k.FullName == key)) { + if (apk.Archive.Any (k => k.FullName == key)) { Log.LogCodedWarning ("4301", "Apk already contains the item {0}; ignoring.", key); continue; } using (var s = new MemoryStream ()) { e.Extract (s); s.Position = 0; - apk.AddEntry (s.ToArray (), key); + apk.Archive.AddEntry (s.ToArray (), key); } } } } } + count++; + if (count == ZipArchiveEx.ZipFlushLimit) { + apk.Flush(); + count = 0; + } } } } @@ -566,11 +600,12 @@ void AddNativeLibrary (ArchiveFileList files, string path, string abi) files.Add (new Tuple (path, string.Format ("lib/{0}", abi))); } - private void AddGdbservers (ZipArchive apk, ArchiveFileList files, string supportedAbis, AndroidDebugServer debugServer) + private void AddGdbservers (ZipArchiveEx apk, ArchiveFileList files, string supportedAbis, AndroidDebugServer debugServer) { if (string.IsNullOrEmpty (AndroidNdkDirectory)) return; + int count = 0; foreach (var sabi in supportedAbis.Split (new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)) { var arch = GdbPaths.GetArchFromAbi (sabi); var abi = GdbPaths.GetAbiFromArch (arch); @@ -585,7 +620,12 @@ private void AddGdbservers (ZipArchive apk, ArchiveFileList files, string suppor if (!File.Exists (debugServerPath)) continue; Log.LogDebugMessage ("Adding {0} debug server '{1}' to the APK as '{2}'", sabi, debugServerPath, entryName); - apk.AddEntry (entryName, File.OpenRead (debugServerPath)); + apk.Archive.AddEntry (entryName, File.OpenRead (debugServerPath)); + count++; + if (count == ZipArchiveEx.ZipFlushLimit) { + apk.Flush(); + count = 0; + } } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs index a86d63ac458..70a4545bec9 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Linq; +using System.Text; using System.Xml.Linq; using Microsoft.Build.Framework; using NUnit.Framework; @@ -195,6 +196,101 @@ public void BuildInDesignTimeMode () Assert.IsTrue (builder.Output.IsTargetSkipped ("_ResolveLibraryProjectImports"), "target \"_ResolveLibraryProjectImports\' should have been skipped."); } } + + [Test] + public void BuildAMassiveApp() + { + var testPath = Path.Combine("temp", "BuildAMassiveApp"); + TestContext.CurrentContext.Test.Properties ["Output"] = new string [] { Path.Combine (Root, testPath) }; + var sb = new SolutionBuilder("BuildAMassiveApp.sln") { + SolutionPath = Path.Combine(Root, testPath), + Verbosity = LoggerVerbosity.Diagnostic, + }; + var app1 = new XamarinAndroidApplicationProject() { + ProjectName = "App1", + AotAssemblies = true, + IsRelease = true, + Packages = { + KnownPackages.AndroidSupportV4_21_0_3_0, + KnownPackages.GooglePlayServices_22_0_0_2, + }, + }; + app1.Imports.Add (new Import ("foo.targets") { + TextContent = () => @" + + + + armeabi-v7a;x86 + $(AndroidSupportedAbis);armeabi + $(AndroidSupportedAbis);arm64-v8a + $(AndroidSupportedAbis);x86_64 + + + + + + False + + + + +", + }); + app1.SetProperty(KnownProperties.AndroidUseSharedRuntime, "False"); + sb.Projects.Add(app1); + var code = new StringBuilder(); + code.AppendLine("using System;"); + code.AppendLine("namespace App1 {"); + code.AppendLine("\tpublic class AppCode {"); + code.AppendLine("\t\tpublic void Foo () {"); + for (int i = 0; i < 128; i++) { + var libName = $"Lib{i}"; + var lib = new XamarinAndroidLibraryProject() { + ProjectName = libName, + IsRelease = true, + OtherBuildItems = { + new AndroidItem.AndroidAsset ($"Assets\\{libName}.txt") { + TextContent = () => "Asset1", + Encoding = Encoding.ASCII, + }, + new AndroidItem.AndroidAsset ($"Assets\\subfolder\\{libName}.txt") { + TextContent = () => "Asset2", + Encoding = Encoding.ASCII, + }, + }, + Sources = { + new BuildItem.Source ($"{libName}.cs") { + TextContent = () => @"using System; + +namespace "+ libName + @" { + + public class " + libName + @" { + public static void Foo () { + } + } +}" + }, + } + }; + var strings = lib.AndroidResources.First(x => x.Include() == "Resources\\values\\Strings.xml"); + strings.TextContent = () => @" + + " + libName + @" +"; + sb.Projects.Add(lib); + app1.References.Add(new BuildItem.ProjectReference($"..\\{libName}\\{libName}.csproj", libName, lib.ProjectGuid)); + code.AppendLine($"\t\t\t{libName}.{libName}.Foo ();"); + } + code.AppendLine("\t\t}"); + code.AppendLine("\t}"); + code.AppendLine("}"); + app1.Sources.Add(new BuildItem.Source("Code.cs") { + TextContent = ()=> code.ToString (), + }); + Assert.IsTrue(sb.Build(new string[] { "Configuration=Release" }), "Solution should have built."); + Assert.IsTrue(sb.BuildProject(app1, "SignAndroidPackage"), "Build of project should have succeeded"); + sb.Dispose(); + } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs index 865556fb88f..3c35dea1417 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs @@ -17,8 +17,8 @@ public class IncrementalBuildTest : BaseTest public void AllProjectsHaveSameOutputDirectory() { var testPath = Path.Combine ("temp", "AllProjectsHaveSameOutputDirectory"); - var sb = new SolutionBuilder () { - SolutionPath = Path.Combine (Root, testPath, "AllProjectsHaveSameOutputDirectory.sln"), + var sb = new SolutionBuilder("AllProjectsHaveSameOutputDirectory.sln") { + SolutionPath = Path.Combine (Root, testPath), Verbosity = LoggerVerbosity.Diagnostic, }; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/SolutionBuilder.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/SolutionBuilder.cs index 22d9556f77e..3abae105911 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/SolutionBuilder.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/SolutionBuilder.cs @@ -10,17 +10,19 @@ public class SolutionBuilder : Builder { public IList Projects { get; } public string SolutionPath { get; set; } + public string SolutionName { get; set; } public bool BuildSucceeded { get; set; } - public SolutionBuilder () : base() + public SolutionBuilder (string solutionName) : base() { + SolutionName = solutionName; Projects = new List (); } public void Save () { foreach (var p in Projects) { - using (var pb = new ProjectBuilder (Path.Combine (Path.GetDirectoryName (SolutionPath), p.ProjectName))) { + using (var pb = new ProjectBuilder (Path.Combine (SolutionPath, p.ProjectName))) { pb.Save (p); } } @@ -47,27 +49,33 @@ public void Save () } sb.Append ("\tEndGlobalSection\n"); sb.Append ("EndGlobal\n"); - File.WriteAllText (SolutionPath, sb.ToString ()); + File.WriteAllText (Path.Combine (SolutionPath, SolutionName), sb.ToString ()); } - public bool Build () + public bool BuildProject(XamarinProject project, string target = "Build") + { + BuildSucceeded = BuildInternal(Path.Combine (SolutionPath, project.ProjectName, project.ProjectFilePath), target); + return BuildSucceeded; + } + + public bool Build (params string[] parameters) { Save (); - BuildSucceeded = BuildInternal (SolutionPath, "Build"); + BuildSucceeded = BuildInternal (Path.Combine (SolutionPath, SolutionName), "Build", parameters); return BuildSucceeded; } - public bool ReBuild () + public bool ReBuild(params string[] parameters) { Save (); - BuildSucceeded = BuildInternal (SolutionPath, "ReBuild"); + BuildSucceeded = BuildInternal(Path.Combine(SolutionPath, SolutionName), "ReBuild", parameters); return BuildSucceeded; } - public bool Clean () + public bool Clean(params string[] parameters) { Save (); - BuildSucceeded = BuildInternal (SolutionPath, "Clean"); + BuildSucceeded = BuildInternal(Path.Combine(SolutionPath, SolutionName), "Clean", parameters); return BuildSucceeded; } @@ -75,7 +83,7 @@ protected override void Dispose (bool disposing) { if (disposing) if (BuildSucceeded) - Directory.Delete (Path.GetDirectoryName (SolutionPath), recursive: true); + Directory.Delete (SolutionPath, recursive: true); } } } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ZipArchiveEx.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ZipArchiveEx.cs index 80aa16f051e..b9c7d3571b2 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ZipArchiveEx.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ZipArchiveEx.cs @@ -1,21 +1,33 @@ using System; using System.IO; +using System.Linq; using Xamarin.Tools.Zip; namespace Xamarin.Android.Tasks { public class ZipArchiveEx : IDisposable { + + public static int ZipFlushLimit = 50; + ZipArchive zip; string archive; - public ZipArchiveEx (string archive) + public ZipArchive Archive { + get { return zip; } + } + + public ZipArchiveEx (string archive) : this (archive, FileMode.CreateNew) + { + } + + public ZipArchiveEx(string archive, FileMode filemode) { this.archive = archive; - zip = ZipArchive.Open (archive, FileMode.CreateNew); + zip = ZipArchive.Open(archive, filemode); } - void Flush () + public void Flush () { if (zip != null) { zip.Close (); @@ -51,7 +63,7 @@ void AddFiles (string folder, string folderInArchive) continue; zip.AddFile (fileName, ArchiveNameForFile (fileName, folderInArchive)); count++; - if (count == 50) { + if (count == ZipArchiveEx.ZipFlushLimit) { Flush (); count = 0; }