/// <summary> /// Reads the maven metadata for an artifact. /// This reads the list of available versions. /// </summary> /// <param name="dep">Dependency to process</param> /// <param name="fname">file name of the metadata.</param> internal static void ProcessMetadata(Dependency dep, string fname) { XmlTextReader reader = new XmlTextReader(new StreamReader(fname)); bool inVersions = false; while (reader.Read()) { if (reader.Name == "versions") { inVersions = reader.IsStartElement(); } else if (inVersions && reader.Name == "version") { dep.AddVersion(reader.ReadString()); } } }
/// <summary> /// Copies the dependencies from the repository to the specified directory. /// The destination directory is checked for an existing version of the /// dependency before copying. The OverwriteConfirmation delegate is /// called for the first existing file or directory. If the delegate /// returns true, the old dependency is deleted and the new one copied. /// </summary> /// <param name="dependencies">The dependencies to copy.</param> /// <param name="destDirectory">Destination directory.</param> /// <param name="confirmer">Confirmer - the delegate for confirming overwriting.</param> public void CopyDependencies( Dictionary <string, Dependency> dependencies, string destDirectory, OverwriteConfirmation confirmer) { if (!Directory.Exists(destDirectory)) { Directory.CreateDirectory(destDirectory); } foreach (Dependency dep in dependencies.Values) { // match artifact-*. The - is important to distinguish art-1.0.0 // from artifact-1.0.0 (or base and basement). string[] dups = Directory.GetFileSystemEntries(destDirectory, dep.Artifact + "-*"); bool doCopy = true; bool doCleanup = false; foreach (string s in dups) { // skip the .meta files (a little Unity creeps in). if (s.EndsWith(".meta")) { continue; } // Strip the package extension from filenames. Directories generated from // unpacked AARs do not have extensions. string existing = Directory.Exists(s) ? s : Path.GetFileNameWithoutExtension(s); // Extract the version from the filename. // dep.Artifact is the name of the package (prefix) // The regular expression extracts the version number from the filename // handling filenames like foo-1.2.3-alpha. System.Text.RegularExpressions.Match match = System.Text.RegularExpressions.Regex.Match( existing.Substring(dep.Artifact.Length + 1), "^([0-9.]+)"); if (!match.Success) { continue; } string artifactVersion = match.Groups[1].Value; Dependency oldDep = new Dependency(dep.Group, dep.Artifact, artifactVersion, packageIds: dep.PackageIds, repositories: dep.Repositories); // add the artifact version so BestVersion == version. oldDep.AddVersion(oldDep.Version); // If the existing artifact matches the new dependency, don't modify it. if (dep.Key == oldDep.Key) { continue; } doCleanup = doCleanup || confirmer == null || confirmer(oldDep, dep); if (doCleanup) { DeleteExistingFileOrDirectory(s); } else { doCopy = false; } } if (doCopy) { string aarFile = null; // TODO(wilkinsonclay): get the extension from the pom file. string baseName = null; string extension = null; foreach (string ext in Packaging) { string fname = Path.Combine(dep.BestVersionPath, dep.Artifact + "-" + dep.BestVersion + ext); if (File.Exists(fname)) { baseName = dep.Artifact + "-" + dep.BestVersion; aarFile = fname; extension = ext; } } if (aarFile != null) { string destName = Path.Combine(destDirectory, baseName) + (extension == ".srcaar" ? ".aar" : extension); string destNameUnpacked = Path.Combine( destDirectory, Path.GetFileNameWithoutExtension(destName)); string existingName = File.Exists(destName) ? destName : Directory.Exists(destNameUnpacked) ? destNameUnpacked : null; if (existingName != null) { doCopy = File.GetLastWriteTime(existingName).CompareTo( File.GetLastWriteTime(aarFile)) < 0; if (doCopy) { DeleteExistingFileOrDirectory(existingName); } } if (doCopy) { File.Copy(aarFile, destName); } } else { throw new ResolutionException("Cannot find artifact for " + dep); } } } }
/// <summary> /// Copies the dependencies from the repository to the specified directory. /// The destination directory is checked for an existing version of the /// dependency before copying. The OverwriteConfirmation delegate is /// called for the first existing file or directory. If the delegate /// returns true, the old dependency is deleted and the new one copied. /// </summary> /// <param name="dependencies">The dependencies to copy.</param> /// <param name="destDirectory">Destination directory.</param> /// <param name="confirmer">Confirmer - the delegate for confirming overwriting.</param> public void CopyDependencies( Dictionary <string, Dependency> dependencies, string destDirectory, OverwriteConfirmation confirmer) { if (!Directory.Exists(destDirectory)) { Directory.CreateDirectory(destDirectory); } foreach (Dependency dep in dependencies.Values) { // match artifact-*. The - is important to distinguish art-1.0.0 // from artifact-1.0.0 (or base and basement). string[] dups = Directory.GetFiles(destDirectory, dep.Artifact + "-*"); bool doCopy = true; bool doCleanup = false; foreach (string s in dups) { // skip the .meta files (a little Unity creeps in). if (s.EndsWith(".meta")) { continue; } string existing = Path.GetFileNameWithoutExtension(s); string artifactName = null; string artifactVersion = null; int idx = existing.Length; // handle artifacts like android-support-4.0.0-alpha.aar while (artifactVersion == null && idx > 0) { // the version is after the last - idx = existing.LastIndexOf("-", idx); if (idx > 0) { artifactName = existing.Substring(0, idx); artifactVersion = existing.Substring(idx + 1); if (!char.IsDigit(artifactVersion.ToCharArray()[0])) { idx--; artifactVersion = null; } } } Dependency oldDep = new Dependency(dep.Group, artifactName, artifactVersion); // add the artifact version so BestVersion == version. oldDep.AddVersion(oldDep.Version); doCleanup = doCleanup || confirmer == null || confirmer(oldDep, dep); if (doCleanup) { if (File.Exists(s)) { File.Delete(s); } else if (Directory.Exists(s)) { Directory.Delete(s); } } else { doCopy = false; } } if (doCopy) { string aarFile = null; // TODO(wilkinsonclay): get the extension from the pom file. string[] packaging = { ".aar", ".jar" }; string baseName = null; foreach (string ext in packaging) { string fname = Path.Combine(dep.BestVersionPath, dep.Artifact + "-" + dep.BestVersion + ext); if (File.Exists(fname)) { baseName = dep.Artifact + "-" + dep.BestVersion + ext; aarFile = fname; } } if (aarFile != null) { string destName = Path.Combine(destDirectory, baseName); if (File.Exists(destName)) { File.Delete(destName); } File.Copy(aarFile, destName); } else { throw new ResolutionException("Cannot find artifact for " + dep); } } } }
/// <summary> /// Get the current set of dependencies referenced by the project. /// </summary> /// <param name="dependencies">Dependencies to search for in the specified /// directory.</param> /// <param name="destDirectory">Directory where dependencies are located in the /// project.</param> /// <param name="explodeAar">Delegate that determines whether a dependency should be /// exploded. If a dependency is currently exploded but shouldn't be according to this /// delegate, the dependency is deleted.</param> /// <param name="repoPaths">Set of additional repo paths to search for the /// dependencies.</param> /// <returns>Dictionary indexed by Dependency.Key where each item is a tuple of /// Dependency instance and the path to the dependency in destDirectory.</returns> public static Dictionary <string, KeyValuePair <Dependency, string> > GetCurrentDependencies( Dictionary <string, Dependency> dependencies, string destDirectory, ExplodeAar explodeAar = null, List <string> repoPaths = null) { var currentDependencies = new Dictionary <string, KeyValuePair <Dependency, string> >(); if (dependencies.Count == 0) { return(currentDependencies); } // Copy the set of dependencies. var transitiveDependencies = new Dictionary <string, Dependency>(dependencies); // Expand set of transitive dependencies into the dictionary of dependencies. foreach (var rootDependency in dependencies.Values) { foreach (var transitiveDependency in GetDependencies(rootDependency, repoPaths)) { transitiveDependencies[transitiveDependency.Key] = transitiveDependency; } } // TODO(smiles): Need a callback that queries Unity's asset DB rather than touching // the filesystem here. string[] filesInDestDir = Directory.GetFileSystemEntries(destDirectory); foreach (var path in filesInDestDir) { // Ignore Unity's .meta files. if (path.EndsWith(MetaExtension)) { continue; } string filename = Path.GetFileName(path); // Strip the package extension from filenames. Directories generated from // unpacked AARs do not have extensions. bool pathIsDirectory = Directory.Exists(path); string filenameWithoutExtension = pathIsDirectory ? filename : Path.GetFileNameWithoutExtension(filename); foreach (var dep in transitiveDependencies.Values) { // Get the set of artifacts matching artifact-*. // The "-" is important to distinguish art-1.0.0 from artifact-1.0.0 // (or base- and basement-). var match = System.Text.RegularExpressions.Regex.Match( filenameWithoutExtension, String.Format("^{0}-.*", dep.Artifact)); if (match.Success) { // Extract the version from the filename. // dep.Artifact is the name of the package (prefix) // The regular expression extracts the version number from the filename // handling filenames like foo-1.2.3-alpha. match = System.Text.RegularExpressions.Regex.Match( filenameWithoutExtension.Substring( dep.Artifact.Length + 1), "^([0-9.]+)"); if (match.Success) { bool reportDependency = true; // If the AAR is exploded and it should not be, delete it and do not // report this dependency. if (pathIsDirectory && explodeAar != null) { string aarFile = dep.BestVersionArtifact; if (aarFile != null && !explodeAar(aarFile)) { DeleteExistingFileOrDirectory(path, includeMetaFiles: true); reportDependency = false; } } if (reportDependency) { string artifactVersion = match.Groups[1].Value; Dependency currentDep = new Dependency( dep.Group, dep.Artifact, artifactVersion, packageIds: dep.PackageIds, repositories: dep.Repositories); // Add the artifact version so BestVersion == Version. currentDep.AddVersion(currentDep.Version); currentDependencies[currentDep.Key] = new KeyValuePair <Dependency, string>(currentDep, path); } break; } } } } return(currentDependencies); }