Merge "Add --change-url parameter to hooks."
diff --git a/Documentation/cmd-ls-projects.txt b/Documentation/cmd-ls-projects.txt
index 1200e18..1e7b4cc 100644
--- a/Documentation/cmd-ls-projects.txt
+++ b/Documentation/cmd-ls-projects.txt
@@ -32,6 +32,11 @@
\-b::
Name of the branch for which the command will display the sha of each project.
+\--tree::
+\-t::
+ Displays project inheritance in a tree-like format.
+ This option does not work together with the show-branch option.
+
EXAMPLES
--------
diff --git a/ReleaseNotes/ReleaseNotes-2.1.2.5.txt b/ReleaseNotes/ReleaseNotes-2.1.2.5.txt
new file mode 100644
index 0000000..1cd5ae8
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.1.2.5.txt
@@ -0,0 +1,24 @@
+Release notes for Gerrit 2.1.2.5
+================================
+
+Gerrit 2.1.2.5 is now available in the usual location:
+
+link:http://code.google.com/p/gerrit/downloads/list[http://code.google.com/p/gerrit/downloads/list]
+
+Bug Fixes
+---------
+
+* issue 390 Resolve objects going missing
++
+Clients disconnecting from the SSH server sometimes caused an
+interrupt to be delivered to their corresponding server work thread.
+That interrupt delivered at the wrong time caused a file to be
+closed unexpectedly, resulting in JGit marking the file as invalid
+and thereby losing access to its contents. Fixed by serializing
+access to the file.
+
+* ps: Fix implementation to alias to gerrit show-queue
++
+The SSH command `ps` was meant to be an alias for `gerrit show-queue`
+but due to a copy-and-paste error was actually an alias for a
+different command. Fixed.
diff --git a/ReleaseNotes/index.txt b/ReleaseNotes/index.txt
index acf20a3..4a9cc3f 100644
--- a/ReleaseNotes/index.txt
+++ b/ReleaseNotes/index.txt
@@ -4,6 +4,7 @@
[[2_1]]
Version 2.1.x
-------------
+* link:ReleaseNotes-2.1.2.5.html[2.1.2.5]
* link:ReleaseNotes-2.1.2.4.html[2.1.2.4]
* link:ReleaseNotes-2.1.2.3.html[2.1.2.3]
* link:ReleaseNotes-2.1.2.2.html[2.1.2.2]
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AgreementInfoFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AgreementInfoFactory.java
index 8e22741..f638d48 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AgreementInfoFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AgreementInfoFactory.java
@@ -25,6 +25,7 @@
import com.google.inject.Inject;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -49,11 +50,18 @@
public AgreementInfo call() throws Exception {
final List<AccountAgreement> userAccepted =
db.accountAgreements().byAccount(user.getAccountId()).toList();
+
+ Collections.reverse(userAccepted);
+
final List<AccountGroupAgreement> groupAccepted =
new ArrayList<AccountGroupAgreement>();
for (final AccountGroup.Id groupId : user.getEffectiveGroups()) {
- groupAccepted.addAll(db.accountGroupAgreements().byGroup(groupId)
- .toList());
+ final List<AccountGroupAgreement> temp =
+ db.accountGroupAgreements().byGroup(groupId).toList();
+
+ Collections.reverse(temp);
+
+ groupAccepted.addAll(temp);
}
final Map<ContributorAgreement.Id, ContributorAgreement> agreements =
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountAgreementAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountAgreementAccess.java
index b9f8905..f65af5e 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountAgreementAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountAgreementAccess.java
@@ -25,6 +25,6 @@
@PrimaryKey("key")
AccountAgreement get(AccountAgreement.Key key) throws OrmException;
- @Query("WHERE key.accountId = ? ORDER BY acceptedOn DESC")
+ @Query("WHERE key.accountId = ? ORDER BY acceptedOn")
ResultSet<AccountAgreement> byAccount(Account.Id id) throws OrmException;
}
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupAgreementAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupAgreementAccess.java
index d471934..d4a1fcd 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupAgreementAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupAgreementAccess.java
@@ -25,7 +25,7 @@
@PrimaryKey("key")
AccountGroupAgreement get(AccountGroupAgreement.Key key) throws OrmException;
- @Query("WHERE key.groupId = ? ORDER BY acceptedOn DESC")
+ @Query("WHERE key.groupId = ? ORDER BY acceptedOn")
ResultSet<AccountGroupAgreement> byGroup(AccountGroup.Id id)
throws OrmException;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
index 6e8ae14..4ae0304 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
@@ -291,8 +291,12 @@
ContributorAgreement bestCla = null;
OUTER: for (AccountGroup.Id groupId : currentUser.getEffectiveGroups()) {
- for (final AccountGroupAgreement a : db.accountGroupAgreements().byGroup(
- groupId)) {
+ final List<AccountGroupAgreement> temp =
+ db.accountGroupAgreements().byGroup(groupId).toList();
+
+ Collections.reverse(temp);
+
+ for (final AccountGroupAgreement a : temp) {
final ContributorAgreement cla =
db.contributorAgreements().get(a.getAgreementId());
if (cla == null) {
@@ -306,8 +310,12 @@
}
if (bestAgreement == null) {
- for (final AccountAgreement a : db.accountAgreements().byAccount(
- currentUser.getAccountId()).toList()) {
+ final List<AccountAgreement> temp =
+ db.accountAgreements().byAccount(currentUser.getAccountId()).toList();
+
+ Collections.reverse(temp);
+
+ for (final AccountAgreement a : temp) {
final ContributorAgreement cla =
db.contributorAgreements().get(a.getAgreementId());
if (cla == null) {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjects.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjects.java
index fda0448..7618432 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjects.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjects.java
@@ -33,8 +33,16 @@
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.TreeMap;
final class ListProjects extends BaseCommand {
+ private static final String NODE_PREFIX = "|-- ";
+ private static final String LAST_NODE_PREFIX = "`-- ";
+ private static final String DEFAULT_TAB_SEPARATOR = "|";
+ private static final String NOT_VISIBLE_PROJECT = "(x)";
+
@Inject
private ReviewDb db;
@@ -54,6 +62,12 @@
@Option(name = "--show-branch", aliases = {"-b"}, usage = "displays the sha of each project in the specified branch")
private String showBranch;
+ @Option(name = "--tree", aliases = {"-t"}, usage = "displays project inheritance in a tree-like format\n" +
+ "this option does not work together with the show-branch option")
+ private boolean showTree;
+
+ private String currentTabSeparator = DEFAULT_TAB_SEPARATOR;
+
@Override
public void start(final Environment env) {
startThread(new CommandRunnable() {
@@ -66,7 +80,18 @@
}
private void display() throws Failure {
+ if (showTree && (showBranch != null)) {
+ throw new UnloggedFailure(1, "fatal: --tree and --show-branch options are not compatible.");
+ }
+
final PrintWriter stdout = toPrintWriter(out);
+
+ TreeMap<String, TreeNode> treeMap = null;
+
+ if (showTree) {
+ treeMap = new TreeMap<String, TreeNode>();
+ }
+
try {
for (final Project p : db.projects().all()) {
if (p.getNameKey().equals(wildProject)) {
@@ -83,27 +108,58 @@
}
final ProjectControl pctl = e.controlFor(currentUser);
- if (!pctl.isVisible()) {
- // Require the project itself to be visible to the user.
- //
- continue;
- }
- if (showBranch != null) {
- final Ref ref = getBranchRef(p.getNameKey());
- if (ref == null || ref.getObjectId() == null
- || !pctl.controlForRef(ref.getLeaf().getName()).isVisible()) {
- // No branch, or the user can't see this branch, so skip it.
+ if (!showTree) {
+
+ if (!pctl.isVisible()) {
+ // Require the project itself to be visible to the user.
//
continue;
}
- stdout.print(ref.getObjectId().name());
- stdout.print(' ');
+ if (showBranch != null) {
+ final Ref ref = getBranchRef(p.getNameKey());
+ if (ref == null || ref.getObjectId() == null
+ || !pctl.controlForRef(ref.getLeaf().getName()).isVisible()) {
+ // No branch, or the user can't see this branch, so skip it.
+ //
+ continue;
+ }
+
+ stdout.print(ref.getObjectId().name());
+ stdout.print(' ');
+ }
+
+ stdout.print(p.getName() + "\n");
+ } else {
+ treeMap.put(p.getName(), new TreeNode(p, pctl.isVisible()));
+ }
+ }
+
+ if (showTree && treeMap.size() > 0) {
+ final List<TreeNode> sortedNodes = new ArrayList<TreeNode>();
+
+ // Builds the inheritance tree using a list.
+ //
+ for (final TreeNode key : treeMap.values()) {
+ final String parentName = key.getParentName();
+ if (parentName != null) {
+ final TreeNode node = treeMap.get((String)parentName);
+ if (node != null) {
+ node.addChild(key);
+ } else {
+ sortedNodes.add(key);
+ }
+ } else {
+ sortedNodes.add(key);
+ }
}
- stdout.print(p.getName());
- stdout.println();
+ // Builds a fake root node, which contains the sorted projects.
+ //
+ final TreeNode fakeRoot = new TreeNode(null, sortedNodes, false);
+ printElement(stdout, fakeRoot, -1, false, sortedNodes.get(sortedNodes.size() - 1));
+ stdout.flush();
}
} catch (OrmException e) {
throw new Failure(1, "fatal: database error", e);
@@ -124,4 +180,139 @@
return null;
}
}
+
+ /** Class created to manipulate the nodes of the project inheritance tree **/
+ private static class TreeNode {
+ private final List<TreeNode> children;
+ private final Project project;
+ private final boolean isVisible;
+
+ /**
+ * Constructor
+ * @param p Project
+ */
+ public TreeNode(Project p, boolean visible) {
+ this.children = new ArrayList<TreeNode>();
+ this.project = p;
+ this.isVisible = visible;
+ }
+
+ /**
+ * Constructor used for creating the fake node
+ * @param p Project
+ * @param c List of nodes
+ */
+ public TreeNode(Project p, List<TreeNode> c, boolean visible) {
+ this.children = c;
+ this.project = p;
+ this.isVisible = visible;
+ }
+
+ /**
+ * Returns if the the node is leaf
+ * @return True if is lead, false, otherwise
+ */
+ public boolean isLeaf() {
+ return children.size() == 0;
+ }
+
+ /**
+ * Returns the project parent name
+ * @return Project parent name
+ */
+ public String getParentName() {
+ if (project.getParent() != null) {
+ return project.getParent().get();
+ }
+
+ return null;
+ }
+
+ /**
+ * Adds a child to the list
+ * @param node TreeNode child
+ */
+ public void addChild(TreeNode node) {
+ children.add(node);
+ }
+
+ /**
+ * Returns the project instance
+ * @return Project instance
+ */
+ public Project getProject() {
+ return project;
+ }
+
+ /**
+ * Returns the list of children nodes
+ * @return List of children nodes
+ */
+ public List<TreeNode> getChildren() {
+ return children;
+ }
+
+ /**
+ * Returns if the project is visible to the user
+ * @return True if is visible, false, otherwise
+ */
+ public boolean isVisible() {
+ return isVisible;
+ }
+ }
+
+ /**
+ * Used to display the project inheritance tree recursively
+ * @param stdout PrintWriter used do print
+ * @param node Tree node
+ * @param level Current level of the tree
+ * @param isLast True, if is the last node of a level, false, otherwise
+ * @param lastParentNode Last "root" parent node
+ */
+ private void printElement(final PrintWriter stdout, TreeNode node, int level, boolean isLast,
+ final TreeNode lastParentNode) {
+ // Checks if is not the "fake" root project.
+ //
+ if (node.getProject() != null) {
+
+ // Check if is not the last "root" parent node,
+ // so the "|" separator will not longer be needed.
+ //
+ if (!currentTabSeparator.equals(" ")) {
+ final String nodeProject = node.getProject().getName();
+ final String lastParentProject = lastParentNode.getProject().getName();
+
+ if (nodeProject.equals(lastParentProject)) {
+ currentTabSeparator = " ";
+ }
+ }
+
+ if (level > 0) {
+ stdout.print(String.format("%-" + 4 * level + "s", currentTabSeparator));
+ }
+
+ final String prefix = isLast ? LAST_NODE_PREFIX : NODE_PREFIX ;
+
+ String printout;
+
+ if (node.isVisible()) {
+ printout = prefix + node.getProject().getName();
+ } else {
+ printout = prefix + NOT_VISIBLE_PROJECT;
+ }
+
+ stdout.print(printout + "\n");
+ }
+
+ if (node.isLeaf()) {
+ return;
+ } else {
+ final List<TreeNode> children = node.getChildren();
+ ++level;
+ for(TreeNode treeNode : children) {
+ final boolean isLastIndex = children.indexOf(treeNode) == children.size() - 1;
+ printElement(stdout, treeNode, level, isLastIndex, lastParentNode);
+ }
+ }
+ }
}