Handle repo copyfile in bare repositories.
Change-Id: Ie06f0c3d1bc9b2123102efaa5542ec3c232b72cd Signed-off-by: Yuxuan 'fishy' Wang <fishywang@google.com>
This commit is contained in:
parent
d998bc938a
commit
0b15b48f74
|
@ -193,7 +193,7 @@ public void testRepoManifestGroups() throws Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRepoManifestCopyfile() throws Exception {
|
public void testRepoManifestCopyFile() throws Exception {
|
||||||
Repository localDb = createWorkRepository();
|
Repository localDb = createWorkRepository();
|
||||||
StringBuilder xmlContent = new StringBuilder();
|
StringBuilder xmlContent = new StringBuilder();
|
||||||
xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
|
xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
|
||||||
|
@ -373,6 +373,44 @@ public void testRevisionBare() throws Exception {
|
||||||
oldCommitId.name(), gitlink);
|
oldCommitId.name(), gitlink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCopyFileBare() throws Exception {
|
||||||
|
Repository remoteDb = createBareRepository();
|
||||||
|
Repository tempDb = createWorkRepository();
|
||||||
|
StringBuilder xmlContent = new StringBuilder();
|
||||||
|
xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
|
||||||
|
.append("<manifest>")
|
||||||
|
.append("<remote name=\"remote1\" fetch=\".\" />")
|
||||||
|
.append("<default revision=\"master\" remote=\"remote1\" />")
|
||||||
|
.append("<project path=\"foo\" name=\"")
|
||||||
|
.append(defaultUri)
|
||||||
|
.append("\" revision=\"")
|
||||||
|
.append(BRANCH)
|
||||||
|
.append("\" >")
|
||||||
|
.append("<copyfile src=\"hello.txt\" dest=\"Hello\" />")
|
||||||
|
.append("</project>")
|
||||||
|
.append("</manifest>");
|
||||||
|
JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", xmlContent.toString());
|
||||||
|
RepoCommand command = new RepoCommand(remoteDb);
|
||||||
|
command.setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
|
||||||
|
.setURI(rootUri)
|
||||||
|
.call();
|
||||||
|
// Clone it
|
||||||
|
File directory = createTempDirectory("testCopyFileBare");
|
||||||
|
CloneCommand clone = Git.cloneRepository();
|
||||||
|
clone.setDirectory(directory);
|
||||||
|
clone.setURI(remoteDb.getDirectory().toURI().toString());
|
||||||
|
Repository localDb = clone.call().getRepository();
|
||||||
|
// The Hello file should exist
|
||||||
|
File hello = new File(localDb.getWorkTree(), "Hello");
|
||||||
|
assertTrue("The Hello file exists", hello.exists());
|
||||||
|
// The content of Hello file should be expected
|
||||||
|
BufferedReader reader = new BufferedReader(new FileReader(hello));
|
||||||
|
String content = reader.readLine();
|
||||||
|
reader.close();
|
||||||
|
assertEquals("The Hello file has expected content", "branch world", content);
|
||||||
|
}
|
||||||
|
|
||||||
private void resolveRelativeUris() {
|
private void resolveRelativeUris() {
|
||||||
// Find the longest common prefix ends with "/" as rootUri.
|
// Find the longest common prefix ends with "/" as rootUri.
|
||||||
defaultUri = defaultDb.getDirectory().toURI().toString();
|
defaultUri = defaultDb.getDirectory().toURI().toString();
|
||||||
|
|
|
@ -51,6 +51,7 @@ cannotCreateConfig=cannot create config
|
||||||
cannotCreateDirectory=Cannot create directory {0}
|
cannotCreateDirectory=Cannot create directory {0}
|
||||||
cannotCreateHEAD=cannot create HEAD
|
cannotCreateHEAD=cannot create HEAD
|
||||||
cannotCreateIndexfile=Cannot create an index file with name {0}
|
cannotCreateIndexfile=Cannot create an index file with name {0}
|
||||||
|
cannotCreateTempDir=Cannot create a temp dir
|
||||||
cannotDeleteCheckedOutBranch=Branch {0} is checked out and can not be deleted
|
cannotDeleteCheckedOutBranch=Branch {0} is checked out and can not be deleted
|
||||||
cannotDeleteFile=Cannot delete file: {0}
|
cannotDeleteFile=Cannot delete file: {0}
|
||||||
cannotDeleteStaleTrackingRef=Cannot delete stale tracking ref {0}
|
cannotDeleteStaleTrackingRef=Cannot delete stale tracking ref {0}
|
||||||
|
|
|
@ -42,13 +42,13 @@
|
||||||
*/
|
*/
|
||||||
package org.eclipse.jgit.gitrepo;
|
package org.eclipse.jgit.gitrepo;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -59,8 +59,6 @@
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jgit.api.AddCommand;
|
|
||||||
import org.eclipse.jgit.api.LsRemoteCommand;
|
|
||||||
import org.eclipse.jgit.api.Git;
|
import org.eclipse.jgit.api.Git;
|
||||||
import org.eclipse.jgit.api.GitCommand;
|
import org.eclipse.jgit.api.GitCommand;
|
||||||
import org.eclipse.jgit.api.SubmoduleAddCommand;
|
import org.eclipse.jgit.api.SubmoduleAddCommand;
|
||||||
|
@ -78,6 +76,7 @@
|
||||||
import org.eclipse.jgit.lib.FileMode;
|
import org.eclipse.jgit.lib.FileMode;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.ObjectInserter;
|
import org.eclipse.jgit.lib.ObjectInserter;
|
||||||
|
import org.eclipse.jgit.lib.ObjectReader;
|
||||||
import org.eclipse.jgit.lib.PersonIdent;
|
import org.eclipse.jgit.lib.PersonIdent;
|
||||||
import org.eclipse.jgit.lib.ProgressMonitor;
|
import org.eclipse.jgit.lib.ProgressMonitor;
|
||||||
import org.eclipse.jgit.lib.Ref;
|
import org.eclipse.jgit.lib.Ref;
|
||||||
|
@ -87,6 +86,7 @@
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
import org.eclipse.jgit.revwalk.RevWalk;
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
|
import org.eclipse.jgit.util.FileUtils;
|
||||||
|
|
||||||
import org.xml.sax.Attributes;
|
import org.xml.sax.Attributes;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
|
@ -121,8 +121,11 @@ public class RepoCommand extends GitCommand<RevCommit> {
|
||||||
* A callback to get ref sha1 of a repository from its uri.
|
* A callback to get ref sha1 of a repository from its uri.
|
||||||
*
|
*
|
||||||
* We provided a default implementation {@link DefaultRemoteReader} to
|
* We provided a default implementation {@link DefaultRemoteReader} to
|
||||||
* use ls-remote command to read the sha1 from the repository. Callers may
|
* use ls-remote command to read the sha1 from the repository and clone the
|
||||||
* have their own quicker implementation.
|
* repository to read the file. Callers may have their own quicker
|
||||||
|
* implementation.
|
||||||
|
*
|
||||||
|
* @since 3.4
|
||||||
*/
|
*/
|
||||||
public interface RemoteReader {
|
public interface RemoteReader {
|
||||||
/**
|
/**
|
||||||
|
@ -135,6 +138,20 @@ public interface RemoteReader {
|
||||||
* @return the sha1 of the remote repository
|
* @return the sha1 of the remote repository
|
||||||
*/
|
*/
|
||||||
public ObjectId sha1(String uri, String ref) throws GitAPIException;
|
public ObjectId sha1(String uri, String ref) throws GitAPIException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a file from a remote repository.
|
||||||
|
*
|
||||||
|
* @param uri
|
||||||
|
* The URI of the remote repository
|
||||||
|
* @param ref
|
||||||
|
* The ref (branch/tag/etc.) to read
|
||||||
|
* @param path
|
||||||
|
* The relative path (inside the repo) to the file to read
|
||||||
|
* @return the file content.
|
||||||
|
*/
|
||||||
|
public byte[] readFile(String uri, String ref, String path)
|
||||||
|
throws GitAPIException, IOException;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A default implementation of {@link RemoteReader} callback. */
|
/** A default implementation of {@link RemoteReader} callback. */
|
||||||
|
@ -153,23 +170,50 @@ public ObjectId sha1(String uri, String ref) throws GitAPIException {
|
||||||
Ref r = RefDatabase.findRef(map, ref);
|
Ref r = RefDatabase.findRef(map, ref);
|
||||||
return r != null ? r.getObjectId() : null;
|
return r != null ? r.getObjectId() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] readFile(String uri, String ref, String path)
|
||||||
|
throws GitAPIException, IOException {
|
||||||
|
File dir = FileUtils.createTempDir("jgit_", ".git", null); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
Repository repo = Git
|
||||||
|
.cloneRepository()
|
||||||
|
.setBare(true)
|
||||||
|
.setDirectory(dir)
|
||||||
|
.setURI(uri)
|
||||||
|
.call()
|
||||||
|
.getRepository();
|
||||||
|
ObjectReader reader = repo.newObjectReader();
|
||||||
|
byte[] result;
|
||||||
|
try {
|
||||||
|
ObjectId oid = repo.resolve(ref + ":" + path); //$NON-NLS-1$
|
||||||
|
result = reader.open(oid).getBytes(Integer.MAX_VALUE);
|
||||||
|
} finally {
|
||||||
|
reader.release();
|
||||||
|
FileUtils.delete(dir, FileUtils.RECURSIVE);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class CopyFile {
|
private static class CopyFile {
|
||||||
|
final Repository repo;
|
||||||
|
final String path;
|
||||||
final String src;
|
final String src;
|
||||||
final String dest;
|
final String dest;
|
||||||
final String relativeDest;
|
|
||||||
|
|
||||||
CopyFile(Repository repo, String path, String src, String dest) {
|
CopyFile(Repository repo, String path, String src, String dest) {
|
||||||
this.src = repo.getWorkTree() + "/" + path + "/" + src; //$NON-NLS-1$ //$NON-NLS-2$
|
this.repo = repo;
|
||||||
this.relativeDest = dest;
|
this.path = path;
|
||||||
this.dest = repo.getWorkTree() + "/" + dest; //$NON-NLS-1$
|
this.src = src;
|
||||||
|
this.dest = dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
void copy() throws IOException {
|
void copy() throws IOException {
|
||||||
FileInputStream input = new FileInputStream(src);
|
File srcFile = new File(repo.getWorkTree(),
|
||||||
|
path + "/" + src); //$NON-NLS-1$
|
||||||
|
File destFile = new File(repo.getWorkTree(), dest);
|
||||||
|
FileInputStream input = new FileInputStream(srcFile);
|
||||||
try {
|
try {
|
||||||
FileOutputStream output = new FileOutputStream(dest);
|
FileOutputStream output = new FileOutputStream(destFile);
|
||||||
try {
|
try {
|
||||||
FileChannel channel = input.getChannel();
|
FileChannel channel = input.getChannel();
|
||||||
output.getChannel().transferFrom(channel, 0, channel.size());
|
output.getChannel().transferFrom(channel, 0, channel.size());
|
||||||
|
@ -185,9 +229,9 @@ void copy() throws IOException {
|
||||||
private static class Project {
|
private static class Project {
|
||||||
final String name;
|
final String name;
|
||||||
final String path;
|
final String path;
|
||||||
|
final String revision;
|
||||||
final Set<String> groups;
|
final Set<String> groups;
|
||||||
final List<CopyFile> copyfiles;
|
final List<CopyFile> copyfiles;
|
||||||
String revision;
|
|
||||||
|
|
||||||
Project(String name, String path, String revision, String groups) {
|
Project(String name, String path, String revision, String groups) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -315,26 +359,11 @@ public void endDocument() throws SAXException {
|
||||||
}
|
}
|
||||||
for (Project proj : projects) {
|
for (Project proj : projects) {
|
||||||
if (inGroups(proj)) {
|
if (inGroups(proj)) {
|
||||||
if (proj.revision == null)
|
command.addSubmodule(remoteUrl + proj.name,
|
||||||
proj.revision = defaultRevision;
|
proj.path,
|
||||||
String url = remoteUrl + proj.name;
|
proj.revision == null ?
|
||||||
command.addSubmodule(url, proj.path, proj.revision);
|
defaultRevision : proj.revision,
|
||||||
for (CopyFile copyfile : proj.copyfiles) {
|
proj.copyfiles);
|
||||||
try {
|
|
||||||
copyfile.copy();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new SAXException(
|
|
||||||
RepoText.get().copyFileFailed, e);
|
|
||||||
}
|
|
||||||
AddCommand add = command.git
|
|
||||||
.add()
|
|
||||||
.addFilepattern(copyfile.relativeDest);
|
|
||||||
try {
|
|
||||||
add.call();
|
|
||||||
} catch (GitAPIException e) {
|
|
||||||
throw new SAXException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -503,7 +532,7 @@ public RevCommit call() throws GitAPIException {
|
||||||
cfg.setString("submodule", name, "path", name); //$NON-NLS-1$ //$NON-NLS-2$
|
cfg.setString("submodule", name, "path", name); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
cfg.setString("submodule", name, "url", uri); //$NON-NLS-1$ //$NON-NLS-2$
|
cfg.setString("submodule", name, "url", uri); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
// create gitlink
|
// create gitlink
|
||||||
final DirCacheEntry dcEntry = new DirCacheEntry(name);
|
DirCacheEntry dcEntry = new DirCacheEntry(name);
|
||||||
ObjectId objectId;
|
ObjectId objectId;
|
||||||
if (ObjectId.isId(proj.revision))
|
if (ObjectId.isId(proj.revision))
|
||||||
objectId = ObjectId.fromString(proj.revision);
|
objectId = ObjectId.fromString(proj.revision);
|
||||||
|
@ -515,6 +544,16 @@ public RevCommit call() throws GitAPIException {
|
||||||
dcEntry.setObjectId(objectId);
|
dcEntry.setObjectId(objectId);
|
||||||
dcEntry.setFileMode(FileMode.GITLINK);
|
dcEntry.setFileMode(FileMode.GITLINK);
|
||||||
builder.add(dcEntry);
|
builder.add(dcEntry);
|
||||||
|
|
||||||
|
for (CopyFile copyfile : proj.copyfiles) {
|
||||||
|
byte[] src = callback.readFile(
|
||||||
|
uri, proj.revision, copyfile.src);
|
||||||
|
objectId = inserter.insert(Constants.OBJ_BLOB, src);
|
||||||
|
dcEntry = new DirCacheEntry(copyfile.dest);
|
||||||
|
dcEntry.setObjectId(objectId);
|
||||||
|
dcEntry.setFileMode(FileMode.REGULAR_FILE);
|
||||||
|
builder.add(dcEntry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
String content = cfg.toText();
|
String content = cfg.toText();
|
||||||
|
|
||||||
|
@ -578,9 +617,11 @@ public RevCommit call() throws GitAPIException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addSubmodule(String url, String name, String revision) throws SAXException {
|
private void addSubmodule(String url, String name, String revision,
|
||||||
|
List<CopyFile> copyfiles) throws SAXException {
|
||||||
if (repo.isBare()) {
|
if (repo.isBare()) {
|
||||||
Project proj = new Project(url, name, revision, null);
|
Project proj = new Project(url, name, revision, null);
|
||||||
|
proj.copyfiles.addAll(copyfiles);
|
||||||
bareProjects.add(proj);
|
bareProjects.add(proj);
|
||||||
} else {
|
} else {
|
||||||
SubmoduleAddCommand add = git
|
SubmoduleAddCommand add = git
|
||||||
|
@ -597,6 +638,10 @@ private void addSubmodule(String url, String name, String revision) throws SAXEx
|
||||||
sub.checkout().setName(findRef(revision, subRepo)).call();
|
sub.checkout().setName(findRef(revision, subRepo)).call();
|
||||||
git.add().addFilepattern(name).call();
|
git.add().addFilepattern(name).call();
|
||||||
}
|
}
|
||||||
|
for (CopyFile copyfile : copyfiles) {
|
||||||
|
copyfile.copy();
|
||||||
|
git.add().addFilepattern(copyfile.dest).call();
|
||||||
|
}
|
||||||
} catch (GitAPIException e) {
|
} catch (GitAPIException e) {
|
||||||
throw new SAXException(e);
|
throw new SAXException(e);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
|
@ -113,6 +113,7 @@ public static JGitText get() {
|
||||||
/***/ public String cannotCreateDirectory;
|
/***/ public String cannotCreateDirectory;
|
||||||
/***/ public String cannotCreateHEAD;
|
/***/ public String cannotCreateHEAD;
|
||||||
/***/ public String cannotCreateIndexfile;
|
/***/ public String cannotCreateIndexfile;
|
||||||
|
/***/ public String cannotCreateTempDir;
|
||||||
/***/ public String cannotDeleteCheckedOutBranch;
|
/***/ public String cannotDeleteCheckedOutBranch;
|
||||||
/***/ public String cannotDeleteFile;
|
/***/ public String cannotDeleteFile;
|
||||||
/***/ public String cannotDeleteStaleTrackingRef;
|
/***/ public String cannotDeleteStaleTrackingRef;
|
||||||
|
|
|
@ -362,4 +362,29 @@ public static void createSymLink(File path, String target)
|
||||||
public static String readSymLink(File path) throws IOException {
|
public static String readSymLink(File path) throws IOException {
|
||||||
return FS.DETECTED.readSymLink(path);
|
return FS.DETECTED.readSymLink(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a temporary directory.
|
||||||
|
*
|
||||||
|
* @param prefix
|
||||||
|
* @param suffix
|
||||||
|
* @param dir
|
||||||
|
* The parent dir, can be null to use system default temp dir.
|
||||||
|
* @return the temp dir created.
|
||||||
|
* @throws IOException
|
||||||
|
* @since 3.4
|
||||||
|
*/
|
||||||
|
public static File createTempDir(String prefix, String suffix, File dir)
|
||||||
|
throws IOException {
|
||||||
|
final int RETRY = 1; // When something bad happens, retry once.
|
||||||
|
for (int i = 0; i < RETRY; i++) {
|
||||||
|
File tmp = File.createTempFile(prefix, suffix, dir);
|
||||||
|
if (!tmp.delete())
|
||||||
|
continue;
|
||||||
|
if (!tmp.mkdir())
|
||||||
|
continue;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
throw new IOException(JGitText.get().cannotCreateTempDir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue