Browse Source

Release ArchiveCommand's ObjectReader in call()

Make call() release all private resources so instead of using a
pattern like

	ArchiveCommand cmd = git.archive();
	try {
		cmd.setTree(tree)
			. ...
			.call();
	} finally {
		cmd.release();
	}

callers can just use git.archive().setTree(tree)....call() directly.

This involves pushing more work out of parameter setters and into
call() so the ObjectReader is not allocated and potentially leaked
before then.

Change-Id: I699f703c6302696e1cc276d7ab8ee597d82f2c5d
stable-3.1
Jonathan Nieder 12 years ago
parent
commit
f99fa9d23e
  1. 9
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
  2. 55
      org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java

9
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java

@ -72,15 +72,14 @@ class Archive extends TextBuiltin {
if (tree == null) if (tree == null)
throw die(CLIText.get().treeIsRequired); throw die(CLIText.get().treeIsRequired);
final ArchiveCommand cmd = new Git(db).archive();
try { try {
cmd.setTree(tree) new Git(db).archive()
.setTree(tree)
.setFormat(format) .setFormat(format)
.setOutputStream(outs).call(); .setOutputStream(outs)
.call();
} catch (GitAPIException e) { } catch (GitAPIException e) {
throw die(e.getMessage()); throw die(e.getMessage());
} finally {
cmd.release();
} }
} }
} }

55
org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java

@ -72,12 +72,12 @@ import org.eclipse.jgit.treewalk.TreeWalk;
* *
* <pre> * <pre>
* ArchiveCommand.registerFormat("tar", new TarFormat()); * ArchiveCommand.registerFormat("tar", new TarFormat());
* cmd = git.archive();
* try { * try {
* cmd.setTree(db.resolve(&quot;HEAD&quot;)) * git.archive()
* .setOutputStream(out).call(); * .setTree(db.resolve(&quot;HEAD&quot;))
* .setOutputStream(out)
* .call();
* } finally { * } finally {
* cmd.release();
* ArchiveCommand.unregisterFormat("tar"); * ArchiveCommand.unregisterFormat("tar");
* } * }
* </pre> * </pre>
@ -87,11 +87,12 @@ import org.eclipse.jgit.treewalk.TreeWalk;
* <pre> * <pre>
* ArchiveCommand.registerFormat("zip", new ZipFormat()); * ArchiveCommand.registerFormat("zip", new ZipFormat());
* try { * try {
* cmd.setTree(db.resolve(&quot;master&quot;)) * git.archive().
* .setTree(db.resolve(&quot;master&quot;))
* .setFormat("zip") * .setFormat("zip")
* .setOutputStream(out).call(); * .setOutputStream(out)
* .call();
* } finally { * } finally {
* cmd.release();
* ArchiveCommand.unregisterFormat("zip"); * ArchiveCommand.unregisterFormat("zip");
* } * }
* </pre> * </pre>
@ -197,7 +198,7 @@ public class ArchiveCommand extends GitCommand<OutputStream> {
} }
private OutputStream out; private OutputStream out;
private TreeWalk walk; private ObjectId tree;
private String format = "tar"; private String format = "tar";
/** /**
@ -205,27 +206,20 @@ public class ArchiveCommand extends GitCommand<OutputStream> {
*/ */
public ArchiveCommand(Repository repo) { public ArchiveCommand(Repository repo) {
super(repo); super(repo);
walk = new TreeWalk(repo); setCallable(false);
}
/**
* Release any resources used by the internal ObjectReader.
* <p>
* This does not close the output stream set with setOutputStream, which
* belongs to the caller.
*/
public void release() {
walk.release();
} }
private <T extends Closeable> private <T extends Closeable>
OutputStream writeArchive(Format<T> fmt) throws GitAPIException { OutputStream writeArchive(Format<T> fmt) throws GitAPIException {
final MutableObjectId idBuf = new MutableObjectId(); final TreeWalk walk = new TreeWalk(repo);
try {
final T outa = fmt.createArchiveOutputStream(out); final T outa = fmt.createArchiveOutputStream(out);
try {
final MutableObjectId idBuf = new MutableObjectId();
final ObjectReader reader = walk.getObjectReader(); final ObjectReader reader = walk.getObjectReader();
final RevWalk rw = new RevWalk(walk.getObjectReader());
try { walk.reset(rw.parseTree(tree));
try {
walk.setRecursive(true); walk.setRecursive(true);
while (walk.next()) { while (walk.next()) {
final String name = walk.getPathString(); final String name = walk.getPathString();
@ -242,13 +236,14 @@ public class ArchiveCommand extends GitCommand<OutputStream> {
} finally { } finally {
outa.close(); outa.close();
} }
return out;
} catch (IOException e) { } catch (IOException e) {
// TODO(jrn): Throw finer-grained errors. // TODO(jrn): Throw finer-grained errors.
throw new JGitInternalException( throw new JGitInternalException(
JGitText.get().exceptionCaughtDuringExecutionOfArchiveCommand, e); JGitText.get().exceptionCaughtDuringExecutionOfArchiveCommand, e);
} finally {
walk.release();
} }
return out;
} }
/** /**
@ -256,6 +251,8 @@ public class ArchiveCommand extends GitCommand<OutputStream> {
*/ */
@Override @Override
public OutputStream call() throws GitAPIException { public OutputStream call() throws GitAPIException {
checkCallable();
final Format<?> fmt = lookupFormat(format); final Format<?> fmt = lookupFormat(format);
return writeArchive(fmt); return writeArchive(fmt);
} }
@ -264,11 +261,13 @@ public class ArchiveCommand extends GitCommand<OutputStream> {
* @param tree * @param tree
* the tag, commit, or tree object to produce an archive for * the tag, commit, or tree object to produce an archive for
* @return this * @return this
* @throws IOException
*/ */
public ArchiveCommand setTree(ObjectId tree) throws IOException { public ArchiveCommand setTree(ObjectId tree) {
final RevWalk rw = new RevWalk(walk.getObjectReader()); if (tree == null)
walk.reset(rw.parseTree(tree)); throw new IllegalArgumentException();
this.tree = tree;
setCallable(true);
return this; return this;
} }

Loading…
Cancel
Save