Merge "Describe how to generate iplog."
diff --git a/.eclipse_iplog b/.eclipse_iplog
index bc3b22e..dc70169 100644
--- a/.eclipse_iplog
+++ b/.eclipse_iplog
@@ -4,6 +4,9 @@
skipCommit = 1a6964c8274c50f0253db75f010d78ef0e739343
+[review]
+ url = http://egit.eclipse.org/r/r/
+
[CQ "3454"]
description = args4j Version: 2.0.12
license = BSD License
@@ -23,9 +26,9 @@
state = approved
[CQ "3904"]
- description = jsch Version: 0.1.37 (using Orbit CQ2014)
+ description = jsch Version: 0.1.37 (using Orbit CQ2002)
license = New BSD license
- use = unmodified binary
+ use = unmodified source & binary
state = approved
[CQ "3655"]
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java
index 6b746e3..731b4ca 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java
@@ -64,7 +64,6 @@
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.util.IO;
/**
* Dumps a file over HTTP GET (or its information via HEAD).
@@ -122,7 +121,8 @@
String getTailChecksum() throws IOException {
final int n = 20;
final byte[] buf = new byte[n];
- IO.readFully(source.getChannel(), fileLen - n, buf, 0, n);
+ source.seek(fileLen - n);
+ source.readFully(buf, 0, n);
return ObjectId.fromRaw(buf).getName();
}
@@ -140,6 +140,7 @@
final OutputStream out = rsp.getOutputStream();
try {
final byte[] buf = new byte[4096];
+ source.seek(pos);
while (pos < end) {
final int r = (int) Math.min(buf.length, end - pos);
final int n = source.read(buf, 0, r);
diff --git a/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/CSV.java b/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/CSV.java
index 3f80c7d..12dbf47 100644
--- a/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/CSV.java
+++ b/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/CSV.java
@@ -116,6 +116,8 @@
} else if (line.charAt(p) == ',') {
row.add("");
p++;
+ if (p == line.length())
+ row.add("");
} else {
int comma = line.indexOf(',', p);
diff --git a/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/IpLogGenerator.java b/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/IpLogGenerator.java
index a9fdb81..28df8b7 100644
--- a/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/IpLogGenerator.java
+++ b/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/IpLogGenerator.java
@@ -58,7 +58,6 @@
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
@@ -88,7 +87,6 @@
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.WindowCursor;
-import org.eclipse.jgit.revwalk.FooterKey;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
@@ -111,11 +109,12 @@
private static final String INDENT = "{http://xml.apache.org/xslt}indent-amount";
- private static final FooterKey BUG = new FooterKey("Bug");
-
/** Projects indexed by their ID string, e.g. {@code technology.jgit}. */
private final Map<String, Project> projects = new TreeMap<String, Project>();
+ /** Projects indexed by their ID string, e.g. {@code technology.jgit}. */
+ private final Map<String, Project> consumedProjects = new TreeMap<String, Project>();
+
/** Known committers, indexed by their foundation ID. */
private final Map<String, Committer> committersById = new HashMap<String, Committer>();
@@ -134,6 +133,9 @@
/** The meta file we loaded to bootstrap our definitions. */
private IpLogMeta meta;
+ /** URL to obtain review information about a specific contribution. */
+ private String reviewUrl;
+
private String characterEncoding = "UTF-8";
private Repository db;
@@ -223,7 +225,11 @@
p.setVersion(version);
projects.put(p.getName(), p);
}
+ for (Project p : meta.getConsumedProjects()) {
+ consumedProjects.put(p.getName(), p);
+ }
cqs.addAll(meta.getCQs());
+ reviewUrl = meta.getReviewUrl();
}
private void loadCommitters(Repository repo) throws IOException {
@@ -352,20 +358,6 @@
String subj = commit.getShortMessage();
SingleContribution item = new SingleContribution(id, when, subj);
- List<String> bugs = commit.getFooterLines(BUG);
- if (1 == bugs.size()) {
- item.setBugID(bugs.get(0));
-
- } else if (2 <= bugs.size()) {
- StringBuilder tmp = new StringBuilder();
- for (String bug : bugs) {
- if (tmp.length() > 0)
- tmp.append(",");
- tmp.append(bug);
- }
- item.setBugID(tmp.toString());
- }
-
if (2 <= cnt) {
item.setSize("(merge)");
contributor.add(item);
@@ -480,8 +472,19 @@
root.appendChild(createProject(project));
licenses.addAll(project.getLicenses());
}
+
+ if (!consumedProjects.isEmpty())
+ appendBlankLine(root);
+ for (Project project : sort(consumedProjects, Project.COMPARATOR)) {
+ root.appendChild(createConsumes(project));
+ licenses.addAll(project.getLicenses());
+ }
+
for (RevCommit c : sort(commits))
root.appendChild(createCommitMeta(c));
+
+ if (licenses.size() > 1)
+ appendBlankLine(root);
for (String name : sort(licenses))
root.appendChild(createLicense(name));
@@ -509,11 +512,21 @@
private Element createProject(Project p) {
Element project = createElement("project");
+ populateProjectType(p, project);
+ return project;
+ }
+
+ private Element createConsumes(Project p) {
+ Element project = createElement("consumes");
+ populateProjectType(p, project);
+ return project;
+ }
+
+ private void populateProjectType(Project p, Element project) {
required(project, "id", p.getID());
required(project, "name", p.getName());
optional(project, "comments", p.getComments());
optional(project, "version", p.getVersion());
- return project;
}
private Element createCommitMeta(RevCommit c) {
@@ -567,20 +580,15 @@
}
private Element createContribution(SingleContribution s) {
- Element r = createElement("bug");
+ Element r = createElement("contribution");
required(r, "id", s.getID());
- optional(r, "bug-id", s.getBugID());
+ required(r, "description", s.getSummary());
required(r, "size", s.getSize());
- required(r, "type", "A"); // assume attachment type
- required(r, "created", format(s.getCreated()));
- required(r, "summary", s.getSummary());
+ if (reviewUrl != null)
+ optional(r, "url", reviewUrl + s.getID());
return r;
}
- private String format(Date created) {
- return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(created);
- }
-
private Element createElement(String name) {
return doc.createElementNS(IPLOG_NS, IPLOG_PFX + name);
}
diff --git a/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/IpLogMeta.java b/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/IpLogMeta.java
index 8d73b02..89695bd 100644
--- a/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/IpLogMeta.java
+++ b/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/IpLogMeta.java
@@ -73,8 +73,16 @@
private static final String S_CQ = "CQ";
+ private static final String S_CONSUMES = "consumes";
+
+ private static final String S_REVIEW = "review";
+
+ private static final String K_URL = "url";
+
private static final String K_NAME = "name";
+ private static final String K_VERSION = "version";
+
private static final String K_COMMENTS = "comments";
private static final String K_SKIP_COMMIT = "skipCommit";
@@ -89,31 +97,35 @@
private List<Project> projects = new ArrayList<Project>();
+ private List<Project> consumedProjects = new ArrayList<Project>();
+
private Set<CQ> cqs = new HashSet<CQ>();
+ private String reviewUrl;
+
List<Project> getProjects() {
return projects;
}
+ List<Project> getConsumedProjects() {
+ return consumedProjects;
+ }
+
Set<CQ> getCQs() {
return cqs;
}
+ String getReviewUrl() {
+ return reviewUrl;
+ }
+
void loadFrom(Config cfg) {
projects.clear();
+ consumedProjects.clear();
cqs.clear();
- for (String id : cfg.getSubsections(S_PROJECT)) {
- String name = cfg.getString(S_PROJECT, id, K_NAME);
- Project project = new Project(id, name);
- project.setComments(cfg.getString(S_PROJECT, id, K_COMMENTS));
-
- for (String c : cfg.getStringList(S_PROJECT, id, K_SKIP_COMMIT))
- project.addSkipCommit(ObjectId.fromString(c));
- for (String license : cfg.getStringList(S_PROJECT, id, K_LICENSE))
- project.addLicense(license);
- projects.add(project);
- }
+ projects.addAll(parseProjects(cfg, S_PROJECT));
+ consumedProjects.addAll(parseProjects(cfg, S_CONSUMES));
for (String id : cfg.getSubsections(S_CQ)) {
CQ cq = new CQ(Long.parseLong(id));
@@ -124,6 +136,26 @@
cq.setComments(cfg.getString(S_CQ, id, K_COMMENTS));
cqs.add(cq);
}
+
+ reviewUrl = cfg.getString(S_REVIEW, null, K_URL);
+ }
+
+ private List<Project> parseProjects(final Config cfg,
+ final String sectionName) {
+ final List<Project> dst = new ArrayList<Project>();
+ for (String id : cfg.getSubsections(sectionName)) {
+ String name = cfg.getString(sectionName, id, K_NAME);
+ Project project = new Project(id, name);
+ project.setVersion(cfg.getString(sectionName, id, K_VERSION));
+ project.setComments(cfg.getString(sectionName, id, K_COMMENTS));
+
+ for (String c : cfg.getStringList(sectionName, id, K_SKIP_COMMIT))
+ project.addSkipCommit(ObjectId.fromString(c));
+ for (String license : cfg.getStringList(sectionName, id, K_LICENSE))
+ project.addLicense(license);
+ dst.add(project);
+ }
+ return dst;
}
/**
diff --git a/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/SingleContribution.java b/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/SingleContribution.java
index 2cd5562..96f3def 100644
--- a/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/SingleContribution.java
+++ b/org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/SingleContribution.java
@@ -61,8 +61,6 @@
private Date created;
- private String bugId;
-
private String size;
/**
@@ -91,17 +89,6 @@
return summary;
}
- /** @return Bugzilla bug id */
- String getBugID() {
- return bugId;
- }
-
- void setBugID(String id) {
- if (id.startsWith("https://bugs.eclipse.org/"))
- id = id.substring("https://bugs.eclipse.org/".length());
- bugId = id;
- }
-
String getSize() {
return size;
}
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties
index edf31e9..d13c47d 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties
@@ -8,6 +8,7 @@
IPZillaPasswordPrompt=IPZilla Password
authorInfo=Author: {0} <{1}>
averageMSPerRead=average {0} ms/read
+branchDetachedHEAD=detached HEAD
branchAlreadyExists=branch {0} already exists
branchCreatedFrom =branch: Created from {0}
branchIsNotAnAncestorOfYourCurrentHEAD=The branch '{0}' is not an ancestor of your current HEAD.\nIf you are sure you want to delete it, run 'jgit branch -D {0}'.
@@ -54,6 +55,7 @@
metaVar_DAG=DAG
metaVar_KEY=KEY
metaVar_arg=ARG
+metaVar_author=AUTHOR
metaVar_base=base
metaVar_bucket=BUCKET
metaVar_command=command
@@ -110,6 +112,8 @@
timeInMilliSeconds={0} ms
tooManyRefsGiven=Too many refs given
unsupportedOperation=Unsupported operation: {0}
+usage_CommitAuthor=Override the author name used in the commit. You can use the standard A U Thor <author@example.com> format.
+usage_CommitMessage=Use the given <msg> as the commit message
usage_CommandLineClientForamazonsS3Service=Command line client for Amazon's S3 service
usage_CreateABareRepository=Create a bare repository
usage_CreateATag=Create a tag
@@ -163,6 +167,7 @@
usage_produceAnEclipseIPLog=Produce an Eclipse IP log
usage_pruneStaleTrackingRefs=prune stale tracking refs
usage_recurseIntoSubtrees=recurse into subtrees
+usage_recordChangesToRepository=Record changes to the repository
usage_setTheGitRepositoryToOperateOn=set the git repository to operate on
usage_showRefNamesMatchingCommits=Show ref names matching commits
usage_symbolicVersionForTheProject=Symbolic version for the project
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java
index 8c811d4..bae895c 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java
@@ -63,6 +63,7 @@
/***/ public String averageMSPerRead;
/***/ public String branchAlreadyExists;
/***/ public String branchCreatedFrom;
+ /***/ public String branchDetachedHEAD;
/***/ public String branchIsNotAnAncestorOfYourCurrentHEAD;
/***/ public String branchNotFound;
/***/ public String cacheTreePathInfo;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
index 36e1a73..b26dde3 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
@@ -49,15 +49,15 @@
import org.eclipse.jgit.revwalk.RevCommit;
import org.kohsuke.args4j.Option;
-@Command(common = true, usage = "Record changes to the repository")
+@Command(common = true, usage = "usage_recordChangesToRepository")
class Commit extends TextBuiltin {
// I don't support setting the committer, because also the native git
// command doesn't allow this.
- @Option(name = "--author", metaVar="author", usage = "Override the author name used in the commit. You can use the standard A U Thor <author@example.com> format.")
+ @Option(name = "--author", metaVar="metaVar_author", usage = "usage_CommitAuthor")
private String author;
- @Option(name = "--message", aliases = { "-m" }, metaVar="msg", usage="Use the given <msg> as the commit message", required=true)
+ @Option(name = "--message", aliases = { "-m" }, metaVar="metaVar_message", usage="usage_CommitMessage", required=true)
private String message;
@Override
@@ -73,7 +73,7 @@
String branchName;
if (!head.isSymbolic())
- branchName="detached HEAD";
+ branchName = CLIText.get().branchDetachedHEAD;
else {
branchName = head.getTarget().getName();
if (branchName.startsWith(Constants.R_HEADS))
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PackFile.java
index 8f4e691..829832e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PackFile.java
@@ -65,7 +65,6 @@
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.PackInvalidException;
import org.eclipse.jgit.errors.PackMismatchException;
-import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.NB;
import org.eclipse.jgit.util.RawParseUtils;
@@ -90,6 +89,9 @@
private RandomAccessFile fd;
+ /** Serializes reads performed against {@link #fd}. */
+ private final Object readLock = new Object();
+
long length;
private int activeWindows;
@@ -364,9 +366,11 @@
try {
if (invalid)
throw new PackInvalidException(packFile);
- fd = new RandomAccessFile(packFile, "r");
- length = fd.length();
- onOpenPack();
+ synchronized (readLock) {
+ fd = new RandomAccessFile(packFile, "r");
+ length = fd.length();
+ onOpenPack();
+ }
} catch (IOException ioe) {
openFail();
throw ioe;
@@ -387,53 +391,61 @@
}
private void doClose() {
- if (fd != null) {
- try {
- fd.close();
- } catch (IOException err) {
- // Ignore a close event. We had it open only for reading.
- // There should not be errors related to network buffers
- // not flushed, etc.
+ synchronized (readLock) {
+ if (fd != null) {
+ try {
+ fd.close();
+ } catch (IOException err) {
+ // Ignore a close event. We had it open only for reading.
+ // There should not be errors related to network buffers
+ // not flushed, etc.
+ }
+ fd = null;
}
- fd = null;
}
}
ByteArrayWindow read(final long pos, int size) throws IOException {
- if (length < pos + size)
- size = (int) (length - pos);
- final byte[] buf = new byte[size];
- IO.readFully(fd.getChannel(), pos, buf, 0, size);
- return new ByteArrayWindow(this, pos, buf);
+ synchronized (readLock) {
+ if (length < pos + size)
+ size = (int) (length - pos);
+ final byte[] buf = new byte[size];
+ fd.seek(pos);
+ fd.readFully(buf, 0, size);
+ return new ByteArrayWindow(this, pos, buf);
+ }
}
ByteWindow mmap(final long pos, int size) throws IOException {
- if (length < pos + size)
- size = (int) (length - pos);
+ synchronized (readLock) {
+ if (length < pos + size)
+ size = (int) (length - pos);
- MappedByteBuffer map;
- try {
- map = fd.getChannel().map(MapMode.READ_ONLY, pos, size);
- } catch (IOException ioe1) {
- // The most likely reason this failed is the JVM has run out
- // of virtual memory. We need to discard quickly, and try to
- // force the GC to finalize and release any existing mappings.
- //
- System.gc();
- System.runFinalization();
- map = fd.getChannel().map(MapMode.READ_ONLY, pos, size);
+ MappedByteBuffer map;
+ try {
+ map = fd.getChannel().map(MapMode.READ_ONLY, pos, size);
+ } catch (IOException ioe1) {
+ // The most likely reason this failed is the JVM has run out
+ // of virtual memory. We need to discard quickly, and try to
+ // force the GC to finalize and release any existing mappings.
+ //
+ System.gc();
+ System.runFinalization();
+ map = fd.getChannel().map(MapMode.READ_ONLY, pos, size);
+ }
+
+ if (map.hasArray())
+ return new ByteArrayWindow(this, pos, map.array());
+ return new ByteBufferWindow(this, pos, map);
}
-
- if (map.hasArray())
- return new ByteArrayWindow(this, pos, map.array());
- return new ByteBufferWindow(this, pos, map);
}
private void onOpenPack() throws IOException {
final PackIndex idx = idx();
final byte[] buf = new byte[20];
- IO.readFully(fd.getChannel(), 0, buf, 0, 12);
+ fd.seek(0);
+ fd.readFully(buf, 0, 12);
if (RawParseUtils.match(buf, 0, Constants.PACK_SIGNATURE) != 4)
throw new IOException(JGitText.get().notAPACKFile);
final long vers = NB.decodeUInt32(buf, 4);
@@ -445,7 +457,8 @@
throw new PackMismatchException(MessageFormat.format(
JGitText.get().packObjectCountMismatch, packCnt, idx.getObjectCount(), getPackFile()));
- IO.readFully(fd.getChannel(), length - 20, buf, 0, 20);
+ fd.seek(length - 20);
+ fd.read(buf, 0, 20);
if (!Arrays.equals(buf, packChecksum))
throw new PackMismatchException(MessageFormat.format(
JGitText.get().packObjectCountMismatch
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java
index 1778654..1f2042d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java
@@ -51,8 +51,6 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
import java.text.MessageFormat;
import org.eclipse.jgit.JGitText;
@@ -139,36 +137,6 @@
}
/**
- * Read the entire byte array into memory, or throw an exception.
- *
- * @param fd
- * file to read the data from.
- * @param pos
- * position to read from the file at.
- * @param dst
- * buffer that must be fully populated, [off, off+len).
- * @param off
- * position within the buffer to start writing to.
- * @param len
- * number of bytes that must be read.
- * @throws EOFException
- * the stream ended before dst was fully populated.
- * @throws IOException
- * there was an error reading from the stream.
- */
- public static void readFully(final FileChannel fd, long pos,
- final byte[] dst, int off, int len) throws IOException {
- while (len > 0) {
- final int r = fd.read(ByteBuffer.wrap(dst, off, len), pos);
- if (r <= 0)
- throw new EOFException(JGitText.get().shortReadOfBlock);
- pos += r;
- off += r;
- len -= r;
- }
- }
-
- /**
* Skip an entire region of an input stream.
* <p>
* The input stream's position is moved forward by the number of requested