From 77626f52328287140746775439323a282f4b3a70 Mon Sep 17 00:00:00 2001 From: Sanjin Sehic Date: Mon, 19 Dec 2011 10:43:42 +0100 Subject: [PATCH] Optimize retrieving from git repositories Instead of cloning from a remote git repository for each branch, revision or tag separately, the git resolver locally clones only once the remote git repository and then creates further local clones from this local copy of the remote repository. First, optimization, of course, is execution speed, because cloning local repository is much faster than remote repository. Furthermore, because git uses hard-linking when a clone of local repository is created, the second optimization is in space consumption. For example, if we have one project that uses https://github.com/harrah/xsbt.git#v0.11.1 and second project that uses https://github.com/harrah/xsbt.git#v0.11.2, in previous git resolver implementation it would require two separate clones of the remote git repository at https://github.com/harrah/xsbt.git. But, the new git resolver requires only one clone of the remote git repository and two local clones which take no space because of hard-linking. --- main/Resolvers.scala | 18 +++++++++++++----- util/io/RichURI.scala | 5 +++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/main/Resolvers.scala b/main/Resolvers.scala index 1ad6a1c71..0e7d49e42 100644 --- a/main/Resolvers.scala +++ b/main/Resolvers.scala @@ -51,19 +51,27 @@ object Resolvers run(Some(in), "git", "checkout", "-q", branch) } - def retrieveLocalCopy(at: URI, into: File) = + def normalized(uri: URI) = uri.copy(scheme = "git") + + def retrieveLocalCopy(at: URI, into: File) = creates(into) {clone(at.withoutFragment.toASCIIString, into)} + + def retrieveBranch(branch: String, from: File, into: File) = { creates(into) { - clone(at.withoutFragment.toASCIIString, into) - if (at.hasFragment) - checkout(branch = at.getFragment, in = into) + clone(at = from.getAbsolutePath, into = into) + checkout(branch, in = into) } } val uri = info.uri + val staging = info.staging Some { () => - retrieveLocalCopy(at = uri, into = uniqueSubdirectoryFor(uri, in = info.staging)) + val localCopy = retrieveLocalCopy(at = uri, into = uniqueSubdirectoryFor(normalized(uri.withoutFragment), in = staging)) + if (uri.hasFragment) + retrieveBranch(branch = uri.getFragment, from = localCopy, into = uniqueSubdirectoryFor(normalized(uri), in = staging)) + else + localCopy } } diff --git a/util/io/RichURI.scala b/util/io/RichURI.scala index 7e46af660..1cd4cab48 100644 --- a/util/io/RichURI.scala +++ b/util/io/RichURI.scala @@ -8,6 +8,11 @@ import java.net.URI class RichURI(uri: URI) { + def copy(scheme: String = uri.getScheme, userInfo: String = uri.getUserInfo, + host: String = uri.getHost, port: Int = uri.getPort, path: String = uri.getPath, + query: String = uri.getQuery, fragment: String = uri.getFragment) = + new URI(scheme, userInfo, host, port, path, query, fragment) + def hasFragment = uri.getFragment ne null def withoutFragment =