-
Notifications
You must be signed in to change notification settings - Fork 564
[Xamarin.Android.Build.Tasks] Path is too long #700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,6 +34,9 @@ public class ResolveLibraryProjectImports : Task | |
| [Required] | ||
| public bool UseShortFileNames { get; set; } | ||
|
|
||
| [Required] | ||
| public string AssemblyIdentityMapFile { get; set; } | ||
|
|
||
| public string CacheFile { get; set;} | ||
|
|
||
| [Output] | ||
|
|
@@ -51,13 +54,14 @@ public class ResolveLibraryProjectImports : Task | |
| [Output] | ||
| public ITaskItem [] ResolvedResourceDirectoryStamps { get; set; } | ||
|
|
||
| string imports_dir = "library_project_imports"; | ||
| AssemblyIdentityMap assemblyMap = new AssemblyIdentityMap(); | ||
|
|
||
| public ResolveLibraryProjectImports () | ||
| { | ||
| } | ||
|
|
||
| // Extracts library project contents under e.g. obj/Debug/[__library_projects__/*.jar | res/*/*] | ||
| // Extracts library project contents under e.g. obj/Debug/[lp/*.jar | res/*/*] | ||
| public override bool Execute () | ||
| { | ||
| Log.LogDebugMessage ("ResolveLibraryProjectImports Task"); | ||
|
|
@@ -72,6 +76,8 @@ public override bool Execute () | |
| var resolvedAssetDirectories = new List<string> (); | ||
| var resolvedEnvironmentFiles = new List<string> (); | ||
|
|
||
| assemblyMap.Load (AssemblyIdentityMapFile); | ||
|
|
||
| using (var resolver = new DirectoryAssemblyResolver (Log.LogWarning, loadDebugSymbols: false)) { | ||
| Extract (resolver, jars, resolvedResourceDirectories, resolvedAssetDirectories, resolvedEnvironmentFiles); | ||
| } | ||
|
|
@@ -112,6 +118,8 @@ public override bool Execute () | |
| document.Save (CacheFile); | ||
| } | ||
|
|
||
| assemblyMap.Save (AssemblyIdentityMapFile); | ||
|
|
||
| Log.LogDebugTaskItems (" Jars: ", Jars.Select (s => new TaskItem (s)).ToArray ()); | ||
| Log.LogDebugTaskItems (" ResolvedResourceDirectories: ", ResolvedResourceDirectories.Select (s => new TaskItem (s)).ToArray ()); | ||
| Log.LogDebugTaskItems (" ResolvedAssetDirectories: ", ResolvedAssetDirectories.Select (s => new TaskItem (s)).ToArray ()); | ||
|
|
@@ -135,13 +143,20 @@ static string GetTargetAssembly (ITaskItem assemblyName) | |
| } | ||
|
|
||
| // Extracts library project contents under e.g. obj/Debug/[__library_projects__/*.jar | res/*/*] | ||
| // Extracts library project contents under e.g. obj/Debug/[lp/*.jar | res/*/*] | ||
| void Extract ( | ||
| DirectoryAssemblyResolver res, | ||
| ICollection<string> jars, | ||
| ICollection<string> resolvedResourceDirectories, | ||
| ICollection<string> resolvedAssetDirectories, | ||
| ICollection<string> resolvedEnvironments) | ||
| { | ||
| // lets "upgrade" the old directory. | ||
| string oldPath = Path.GetFullPath (Path.Combine (OutputImportDirectory, "..", "__library_projects__")); | ||
| if (!OutputImportDirectory.Contains ("__library_projects__") && Directory.Exists (oldPath)) { | ||
| MonoAndroidHelper.SetDirectoryWriteable (Path.Combine (oldPath, "..")); | ||
| Directory.Delete (oldPath, recursive: true); | ||
| } | ||
| var outdir = new DirectoryInfo (OutputImportDirectory); | ||
| if (!outdir.Exists) | ||
| outdir.Create (); | ||
|
|
@@ -154,26 +169,95 @@ void Extract ( | |
| .Select (a => GetTargetAssembly (a)) | ||
| .Where (a => a != null) | ||
| .Distinct ()) { | ||
| foreach (var imp in new string [] {imports_dir, "library_project_imports"}.Distinct ()) { | ||
| string assemblyIdentName = Path.GetFileNameWithoutExtension (assemblyPath); | ||
| if (UseShortFileNames) { | ||
| assemblyIdentName = Xamarin.Android.Tasks.MonoAndroidHelper.GetLibraryImportDirectoryNameForAssembly (assemblyIdentName); | ||
| } | ||
| string outDirForDll = Path.Combine (OutputImportDirectory, assemblyIdentName); | ||
| string importsDir = Path.Combine (outDirForDll, imp); | ||
| string assemblyIdentName = Path.GetFileNameWithoutExtension (assemblyPath); | ||
| if (UseShortFileNames) { | ||
| assemblyIdentName = assemblyMap.GetLibraryImportDirectoryNameForAssembly (assemblyIdentName); | ||
| } | ||
| string outDirForDll = Path.Combine (OutputImportDirectory, assemblyIdentName); | ||
| string importsDir = Path.Combine (outDirForDll, ImportsDirectory); | ||
| #if SEPARATE_CRUNCH | ||
| // FIXME: review these binResDir thing and enable this. Eclipse does this. | ||
| // Enabling these blindly causes build failure on ActionBarSherlock. | ||
| //string binResDir = Path.Combine (importsDir, "bin", "res"); | ||
| //string binAssemblyDir = Path.Combine (importsDir, "bin", "assets"); | ||
| #endif | ||
| string resDir = Path.Combine (importsDir, "res"); | ||
| string assemblyDir = Path.Combine (importsDir, "assets"); | ||
|
|
||
| // Skip already-extracted resources. | ||
| var stamp = new FileInfo (Path.Combine (outdir.FullName, assemblyIdentName + ".stamp")); | ||
| if (stamp.Exists && stamp.LastWriteTime > new FileInfo (assemblyPath).LastWriteTime) { | ||
| Log.LogDebugMessage ("Skipped resource lookup for {0}: extracted files are up to date", assemblyPath); | ||
| #if SEPARATE_CRUNCH | ||
| // FIXME: review these binResDir thing and enable this. Eclipse does this. | ||
| // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this. | ||
| // Enabling these blindly causes build failure on ActionBarSherlock. | ||
| //string binResDir = Path.Combine (importsDir, "bin", "res"); | ||
| //string binAssemblyDir = Path.Combine (importsDir, "bin", "assets"); | ||
| if (Directory.Exists (binResDir)) | ||
| resolvedResourceDirectories.Add (binResDir); | ||
| if (Directory.Exists (binAssemblyDir)) | ||
| resolvedAssetDirectories.Add (binAssemblyDir); | ||
| #endif | ||
| string resDir = Path.Combine (importsDir, "res"); | ||
| string assemblyDir = Path.Combine (importsDir, "assets"); | ||
| if (Directory.Exists (resDir)) | ||
| resolvedResourceDirectories.Add (resDir); | ||
| if (Directory.Exists (assemblyDir)) | ||
| resolvedAssetDirectories.Add (assemblyDir); | ||
| continue; | ||
| } | ||
|
|
||
| if (Directory.Exists (outDirForDll)) | ||
| Directory.Delete (outDirForDll, true); | ||
|
|
||
| var assembly = res.GetAssembly (assemblyPath); | ||
|
|
||
| foreach (var mod in assembly.Modules) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I half wonder if the diff would be smaller if, before this line, we did: if (true) {so that the indentation matched what we had before. Even if this did result in a smaller diff, I'm not sure that would actually be a good idea. :-/ |
||
| // android environment files | ||
| foreach (var envtxt in mod.Resources | ||
| .Where (r => r.Name.StartsWith ("__AndroidEnvironment__", StringComparison.OrdinalIgnoreCase)) | ||
| .Where (r => r is EmbeddedResource) | ||
| .Cast<EmbeddedResource> ()) { | ||
| if (!Directory.Exists (outDirForDll)) | ||
| Directory.CreateDirectory (outDirForDll); | ||
| var finfo = new FileInfo (Path.Combine (outDirForDll, envtxt.Name)); | ||
| using (var fs = finfo.Create ()) { | ||
| var data = envtxt.GetResourceData (); | ||
| fs.Write (data, 0, data.Length); | ||
| } | ||
| resolvedEnvironments.Add (finfo.FullName); | ||
| } | ||
|
|
||
| // embedded jars (EmbeddedJar, EmbeddedReferenceJar) | ||
| var resjars = mod.Resources | ||
| .Where (r => r.Name.EndsWith (".jar", StringComparison.InvariantCultureIgnoreCase)) | ||
| .Select (r => (EmbeddedResource) r); | ||
| foreach (var resjar in resjars) { | ||
| var data = resjar.GetResourceData (); | ||
| if (!Directory.Exists (importsDir)) | ||
| Directory.CreateDirectory (importsDir); | ||
| using (var outfs = File.Create (Path.Combine (importsDir, resjar.Name))) | ||
| outfs.Write (data, 0, data.Length); | ||
| } | ||
|
|
||
| // Skip already-extracted resources. | ||
| var stamp = new FileInfo (Path.Combine (outdir.FullName, assemblyIdentName + ".stamp")); | ||
| if (stamp.Exists && stamp.LastWriteTime > new FileInfo (assemblyPath).LastWriteTime) { | ||
| Log.LogDebugMessage ("Skipped resource lookup for {0}: extracted files are up to date", assemblyPath); | ||
| // embedded AndroidResourceLibrary archive | ||
| var reszip = mod.Resources.FirstOrDefault (r => r.Name == "__AndroidLibraryProjects__.zip") as EmbeddedResource; | ||
| if (reszip != null) { | ||
| if (!Directory.Exists (outDirForDll)) | ||
| Directory.CreateDirectory (outDirForDll); | ||
| var finfo = new FileInfo (Path.Combine (outDirForDll, reszip.Name)); | ||
| using (var fs = finfo.Create ()) { | ||
| var data = reszip.GetResourceData (); | ||
| fs.Write (data, 0, data.Length); | ||
| } | ||
|
|
||
| // temporarily extracted directory will look like: | ||
| // __library_projects__/[dllname]/[library_project_imports | jlibs]/bin | ||
| using (var zip = MonoAndroidHelper.ReadZipFile (finfo.FullName)) { | ||
| Files.ExtractAll (zip, outDirForDll, modifyCallback: (entryFullName) => { | ||
| return entryFullName.Replace ("library_project_imports", ImportsDirectory); | ||
| }); | ||
| } | ||
|
|
||
| // We used to *copy* the resources to overwrite other resources, | ||
| // which resulted in missing resource issue. | ||
| // Here we replaced copy with use of '-S' option and made it to work. | ||
| #if SEPARATE_CRUNCH | ||
| // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this. | ||
| // Enabling these blindly causes build failure on ActionBarSherlock. | ||
|
|
@@ -186,80 +270,13 @@ void Extract ( | |
| resolvedResourceDirectories.Add (resDir); | ||
| if (Directory.Exists (assemblyDir)) | ||
| resolvedAssetDirectories.Add (assemblyDir); | ||
| continue; | ||
| } | ||
|
|
||
| if (Directory.Exists (outDirForDll)) | ||
| Directory.Delete (outDirForDll, true); | ||
|
|
||
| Directory.CreateDirectory (importsDir); | ||
|
|
||
| var assembly = res.GetAssembly (assemblyPath); | ||
|
|
||
| foreach (var mod in assembly.Modules) { | ||
| // android environment files | ||
| foreach (var envtxt in mod.Resources | ||
| .Where (r => r.Name.StartsWith ("__AndroidEnvironment__", StringComparison.OrdinalIgnoreCase)) | ||
| .Where (r => r is EmbeddedResource) | ||
| .Cast<EmbeddedResource> ()) { | ||
| if (!Directory.Exists (outDirForDll)) | ||
| Directory.CreateDirectory (outDirForDll); | ||
| var finfo = new FileInfo (Path.Combine (outDirForDll, envtxt.Name)); | ||
| using (var fs = finfo.Create ()) { | ||
| var data = envtxt.GetResourceData (); | ||
| fs.Write (data, 0, data.Length); | ||
| } | ||
| resolvedEnvironments.Add (finfo.FullName); | ||
| } | ||
|
|
||
| // embedded jars (EmbeddedJar, EmbeddedReferenceJar) | ||
| var resjars = mod.Resources | ||
| .Where (r => r.Name.EndsWith (".jar", StringComparison.InvariantCultureIgnoreCase)) | ||
| .Select (r => (EmbeddedResource) r); | ||
| foreach (var resjar in resjars) { | ||
| var data = resjar.GetResourceData (); | ||
| using (var outfs = File.Create (Path.Combine (importsDir, resjar.Name))) | ||
| outfs.Write (data, 0, data.Length); | ||
| } | ||
|
|
||
| // embedded AndroidResourceLibrary archive | ||
| var reszip = mod.Resources.FirstOrDefault (r => r.Name == "__AndroidLibraryProjects__.zip") as EmbeddedResource; | ||
| if (reszip != null) { | ||
| if (!Directory.Exists (outDirForDll)) | ||
| Directory.CreateDirectory (outDirForDll); | ||
| var finfo = new FileInfo (Path.Combine (outDirForDll, reszip.Name)); | ||
| using (var fs = finfo.Create ()) { | ||
| var data = reszip.GetResourceData (); | ||
| fs.Write (data, 0, data.Length); | ||
| } | ||
|
|
||
| // temporarily extracted directory will look like: | ||
| // __library_projects__/[dllname]/[library_project_imports | jlibs]/bin | ||
| using (var zip = MonoAndroidHelper.ReadZipFile (finfo.FullName)) | ||
| Files.ExtractAll (zip, outDirForDll); | ||
|
|
||
| // We used to *copy* the resources to overwrite other resources, | ||
| // which resulted in missing resource issue. | ||
| // Here we replaced copy with use of '-S' option and made it to work. | ||
| #if SEPARATE_CRUNCH | ||
| // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this. | ||
| // Enabling these blindly causes build failure on ActionBarSherlock. | ||
| if (Directory.Exists (binResDir)) | ||
| resolvedResourceDirectories.Add (binResDir); | ||
| if (Directory.Exists (binAssemblyDir)) | ||
| resolvedAssetDirectories.Add (binAssemblyDir); | ||
| #endif | ||
| if (Directory.Exists (resDir)) | ||
| resolvedResourceDirectories.Add (resDir); | ||
| if (Directory.Exists (assemblyDir)) | ||
| resolvedAssetDirectories.Add (assemblyDir); | ||
|
|
||
| finfo.Delete (); | ||
| } | ||
| finfo.Delete (); | ||
| } | ||
| } | ||
|
|
||
| if (Directory.Exists (importsDir)) | ||
| stamp.Create ().Close (); | ||
| } | ||
| } | ||
|
|
||
| foreach (var f in outdir.GetFiles ("*.jar") | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This presents a theoretical problem -- which presumably won't be all that theoretical? -- in which two assemblies have an md2 which is the same value. (This should plausibly be more common, since we're only taking the first 5 values in the md2 value! See
MonoAndroidHelper.GetLibraryImportDirectoryNameForAssembly(). That said, I don't see any issues in my$HOME/.local/share/Xamarin, so maybe conflict isn't that likely?)If we have two directories which hash to the same value, what should be done, and how can it be supported?
(Can it be supported?)
For example, assume that assemblies A1 and A2 have names which hash to the same value. The
Directory.Delete()here will nuke the extraction of one, which will presumably result in a later build break, as e.g. some resource is used which doesn't exist.Alternatively, instead of the
Directory.Delete(), we could instead extract both files into the same directory. The problem with this approach is deleting entries which no longer exist (bleh). Alternatively, there would be a problem if both assemblies provide a resource of the same name, e.g.classes.jar(which iirc is a fairly common name).Offhand, I'm not immediately sure if this is solvable. At the same time, I'm also not sure if its "fixable", or that it even should be fixed.
What might be a good idea, though, is to check for it: we have all of the
Assembliesof interest, and therefore we can compute the abbreviated md2 for all of those assemblies, and check to see if there are any conflicts at all:That's clearly not a great error message, but the idea is there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Hash has been replaced by a lookup cache file which will map the assembly to a integer index directory. So you get something like
MyProject=1
Xamarin.Android.Support.v7.AppCompat.21.0.3.0=2
So on the path we only take up "1" or "2" (up to the number of dependencies). Rather than a ton of redundant characters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As elaborated on in an earlier comment/down below, I believe that the lookup cache file needs to instead have: