summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdwin Kempin <edwin.kempin@sap.com>2013-10-16 12:58:24 +0200
committerDavid Pursehouse <david.pursehouse@sonymobile.com>2013-10-17 11:25:48 +0900
commitea62148983a4cee7ed0e44593a1926782372a768 (patch)
treefa3dd7d42154cf606ed5cab36f1b161caecb8086
parent78e868ef89c320559a9b28bfaf6f1462c26afdfa (diff)
ChangeScreen2: Show download commands defined by plugins
The download commands are returned as part of the FetchInfo of a revision, but only if the download commands are requested by setting the option DOWNLOAD_COMMANDS. This allows to completely customize the download commands on a Gerrit installation. This change only effects the download commands that are shown on ChangeScreen2. For non-anonymous download commands the username is now again included into the displayed download commands. Also the HTTP scheme and the Anonymous HTTP scheme can be used at the same time. With this change the patch download (base64 & zipped) is still hard-coded in Gerrit core and does not come from a plugin. Bug: issue 2116 Change-Id: I8fb21fdeb1a98548ce9027655e1b5e467ee2d27e Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
-rw-r--r--Documentation/dev-plugins.txt14
-rw-r--r--Documentation/rest-api-changes.txt49
-rw-r--r--gerrit-common/src/main/java/com/google/gerrit/common/changes/ListChangesOption.java5
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java6
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java7
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadAction.java20
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadBox.java203
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadBox.ui.xml98
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java2
-rw-r--r--gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css45
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java102
11 files changed, 277 insertions, 274 deletions
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index 2e74b7c281..8ab906b090 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -982,6 +982,20 @@ MyType(@PluginData java.io.File myDir) {
}
----
+[[download-commands]]
+Download Commands
+-----------------
+
+Gerrit offers commands for downloading changes using different
+download schemes (e.g. for downloading via different network
+protocols). Plugins can contribute download schemes and download
+commands by implementing
+`com.google.gerrit.extensions.config.DownloadScheme` and
+`com.google.gerrit.extensions.config.DownloadCommand`.
+
+The download schemes and download commands which are used most often
+are provided by the Gerrit core plugin `download-commands`.
+
[[documentation]]
Documentation
-------------
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 8c1fa16e9c..9404d00846 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -171,6 +171,13 @@ default. Optional fields are:
* `ALL_REVISIONS`: describe all revisions, not just current.
--
+[[download_commands]]
+--
+* `DOWNLOAD_COMMANDS`: include the `commands` field in the
+ link:#fetch-info[FetchInfo] for revisions. Only valid when the
+ `CURRENT_REVISION` or `ALL_REVISIONS` option is selected.
+--
+
[[draft_comments]]
--
* `DRAFT_COMMENTS`: include the `has_draft_comments` field for
@@ -233,7 +240,7 @@ default. Optional fields are:
.Request
----
- GET /changes/?q=97&o=CURRENT_REVISION&o=CURRENT_COMMIT&o=CURRENT_FILES HTTP/1.0
+ GET /changes/?q=97&o=CURRENT_REVISION&o=CURRENT_COMMIT&o=CURRENT_FILES&o=DOWNLOAD_COMMANDS HTTP/1.0
----
.Response
@@ -267,11 +274,33 @@ default. Optional fields are:
"fetch": {
"git": {
"url": "git://localhost/gerrit",
- "ref": "refs/changes/97/97/1"
+ "ref": "refs/changes/97/97/1",
+ "commands": {
+ "Checkout": "git fetch git://localhost/gerrit refs/changes/97/97/1 \u0026\u0026 git checkout FETCH_HEAD",
+ "Cherry-Pick": "git fetch git://localhost/gerrit refs/changes/97/97/1 \u0026\u0026 git cherry-pick FETCH_HEAD",
+ "Format-Patch": "git fetch git://localhost/gerrit refs/changes/97/97/1 \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD",
+ "Pull": "git pull git://localhost/gerrit refs/changes/97/97/1"
+ }
},
"http": {
- "url": "http://127.0.0.1:8080/gerrit",
- "ref": "refs/changes/97/97/1"
+ "url": "http://myuser@127.0.0.1:8080/gerrit",
+ "ref": "refs/changes/97/97/1",
+ "commands": {
+ "Checkout": "git fetch http://myuser@127.0.0.1:8080/gerrit refs/changes/97/97/1 \u0026\u0026 git checkout FETCH_HEAD",
+ "Cherry-Pick": "git fetch http://myuser@127.0.0.1:8080/gerrit refs/changes/97/97/1 \u0026\u0026 git cherry-pick FETCH_HEAD",
+ "Format-Patch": "git fetch http://myuser@127.0.0.1:8080/gerrit refs/changes/97/97/1 \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD",
+ "Pull": "git pull http://myuser@127.0.0.1:8080/gerrit refs/changes/97/97/1"
+ }
+ },
+ "ssh": {
+ "url": "ssh://myuser@*:29418/gerrit",
+ "ref": "refs/changes/97/97/1",
+ "commands": {
+ "Checkout": "git fetch ssh://myuser@*:29418/gerrit refs/changes/97/97/1 \u0026\u0026 git checkout FETCH_HEAD",
+ "Cherry-Pick": "git fetch ssh://myuser@*:29418/gerrit refs/changes/97/97/1 \u0026\u0026 git cherry-pick FETCH_HEAD",
+ "Format-Patch": "git fetch ssh://myuser@*:29418/gerrit refs/changes/97/97/1 \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD",
+ "Pull": "git pull ssh://myuser@*:29418/gerrit refs/changes/97/97/1"
+ }
}
},
"commit": {
@@ -2949,11 +2978,15 @@ FetchInfo
The `FetchInfo` entity contains information about how to fetch a patch
set via a certain protocol.
-[options="header",width="50%",cols="1,6"]
+[options="header",width="50%",cols="1,^1,5"]
|==========================
-|Field Name |Description
-|`url` |The URL of the project.
-|`ref` |The ref of the patch set.
+|Field Name ||Description
+|`url` ||The URL of the project.
+|`ref` ||The ref of the patch set.
+|`commands` |optional|
+The download commands for this patch set as a map that maps the command
+names to the commands. +
+Only set if link:#download_commands[download commands] are requested.
|==========================
[[file-info]]
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/changes/ListChangesOption.java b/gerrit-common/src/main/java/com/google/gerrit/common/changes/ListChangesOption.java
index ff80b43870..276c332607 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/changes/ListChangesOption.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/changes/ListChangesOption.java
@@ -46,7 +46,10 @@ public enum ListChangesOption {
REVIEWED(11),
/** Include draft comments for the caller. */
- DRAFT_COMMENTS(12);
+ DRAFT_COMMENTS(12),
+
+ /** Include download commands for the caller. */
+ DOWNLOAD_COMMANDS(13);
private final int value;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
index 0cb3fa20fb..9842049410 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
@@ -92,6 +92,12 @@ public interface GerritCss extends CssResource {
String diffTextHunkHeader();
String diffTextINSERT();
String diffTextNoLF();
+ String downloadBox();
+ String downloadBoxTable();
+ String downloadBoxTableCommandColumn();
+ String downloadBoxSpacer();
+ String downloadBoxScheme();
+ String downloadBoxCopyLabel();
String downloadLink();
String downloadLinkCopyLabel();
String downloadLinkHeader();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java
index 9ba04dd369..5f6b4e9615 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java
@@ -280,11 +280,8 @@ public class ChangeScreen2 extends Screen {
}
private void initDownloadAction(ChangeInfo info, String revision) {
- downloadAction = new DownloadAction(
- info.legacy_id(),
- info.project(),
- info.revision(revision),
- style, headerLine, download);
+ downloadAction =
+ new DownloadAction(info, revision, style, headerLine, download);
}
private void initProjectLink(ChangeInfo info) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadAction.java
index 91ff99cbcb..891cc10f21 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadAction.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadAction.java
@@ -14,10 +14,7 @@
package com.google.gerrit.client.change;
-import com.google.gerrit.client.changes.ChangeInfo.FetchInfo;
-import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
-import com.google.gerrit.client.rpc.NativeMap;
-import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.client.changes.ChangeInfo;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;
@@ -26,20 +23,15 @@ class DownloadAction extends RightSidePopdownAction {
private final DownloadBox downloadBox;
DownloadAction(
- Change.Id changeId,
- String project,
- RevisionInfo revision,
+ ChangeInfo info,
+ String revision,
ChangeScreen2.Style style,
UIObject relativeTo,
Widget downloadButton) {
super(style, relativeTo, downloadButton);
- this.downloadBox = new DownloadBox(
- revision.has_fetch()
- ? revision.fetch()
- : NativeMap.<FetchInfo> create(),
- revision.name(),
- project,
- new PatchSet.Id(changeId, revision._number()));
+ this.downloadBox = new DownloadBox(info, revision,
+ new PatchSet.Id(info.legacy_id(),
+ info.revision(revision)._number()));
}
Widget getWidget() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadBox.java
index ae29801eab..7c57620ad4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadBox.java
@@ -14,102 +14,107 @@
package com.google.gerrit.client.change;
-import static com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme.REPO_DOWNLOAD;
-
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.account.AccountApi;
+import com.google.gerrit.client.changes.ChangeApi;
+import com.google.gerrit.client.changes.ChangeInfo;
import com.google.gerrit.client.changes.ChangeInfo.FetchInfo;
+import com.google.gerrit.client.changes.ChangeList;
import com.google.gerrit.client.rpc.NativeMap;
+import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.rpc.RestApi;
+import com.google.gerrit.common.changes.ListChangesOption;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.dom.client.AnchorElement;
-import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ChangeEvent;
-import com.google.gwt.uibinder.client.UiBinder;
-import com.google.gwt.uibinder.client.UiField;
-import com.google.gwt.uibinder.client.UiHandler;
+import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.HTMLPanel;
+import com.google.gwt.user.client.ui.Anchor;
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.ListBox;
-import com.google.gwt.user.client.ui.UIObject;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
import com.google.gwtexpui.clippy.client.CopyableLabel;
-class DownloadBox extends Composite {
- interface Binder extends UiBinder<HTMLPanel, DownloadBox> {}
- private static final Binder uiBinder = GWT.create(Binder.class);
+import java.util.EnumSet;
- private final NativeMap<FetchInfo> fetch;
+class DownloadBox extends VerticalPanel {
+ private final ChangeInfo change;
private final String revision;
- private final String project;
private final PatchSet.Id psId;
+ private final FlexTable commandTable;
+ private final ListBox scheme;
+ private NativeMap<FetchInfo> fetch;
- @UiField ListBox scheme;
- @UiField CopyableLabel checkout;
- @UiField CopyableLabel cherryPick;
- @UiField CopyableLabel pull;
- @UiField AnchorElement patchBase64;
- @UiField AnchorElement patchZip;
- @UiField Element repoSection;
- @UiField CopyableLabel repoDownload;
-
- DownloadBox(NativeMap<FetchInfo> fetch, String revision,
- String project, PatchSet.Id psId) {
- this.fetch = fetch;
+ DownloadBox(ChangeInfo change, String revision, PatchSet.Id psId) {
+ this.change = change;
this.revision = revision;
- this.project = project;
this.psId = psId;
- initWidget(uiBinder.createAndBindUi(this));
+ this.commandTable = new FlexTable();
+ this.scheme = new ListBox();
+ this.scheme.addChangeHandler(new ChangeHandler() {
+ @Override
+ public void onChange(ChangeEvent event) {
+ renderCommands();
+ if (Gerrit.isSignedIn()) {
+ saveScheme();
+ }
+ }
+ });
+
+ setStyleName(Gerrit.RESOURCES.css().downloadBox());
+ commandTable.setStyleName(Gerrit.RESOURCES.css().downloadBoxTable());
+ scheme.setStyleName(Gerrit.RESOURCES.css().downloadBoxScheme());
+ add(commandTable);
}
@Override
protected void onLoad() {
- if (scheme.getItemCount() == 0) {
- renderScheme(fetch);
- }
- }
-
- @UiHandler("scheme")
- void onScheme(ChangeEvent event) {
- renderCommands();
+ if (fetch == null) {
+ RestApi call = ChangeApi.detail(change.legacy_id().get());
+ ChangeList.addOptions(call, EnumSet.of(
+ revision.equals(change.current_revision())
+ ? ListChangesOption.CURRENT_REVISION
+ : ListChangesOption.ALL_REVISIONS,
+ ListChangesOption.DOWNLOAD_COMMANDS));
+ call.get(new AsyncCallback<ChangeInfo>() {
+ @Override
+ public void onSuccess(ChangeInfo result) {
+ fetch = result.revision(revision).fetch();
+ renderScheme();
+ }
- if (Gerrit.isSignedIn()) {
- saveScheme();
+ @Override
+ public void onFailure(Throwable caught) {
+ }
+ });
}
}
private void renderCommands() {
- FetchInfo info = fetch.get(scheme.getValue(scheme.getSelectedIndex()));
- checkout(info);
- cherryPick(info);
- pull(info);
- patch(info);
- repo(info);
- }
+ commandTable.removeAllRows();
- private void checkout(FetchInfo info) {
- checkout.setText(
- "git fetch " + info.url() + " " + info.ref()
- + " && git checkout FETCH_HEAD");
- }
-
- private void cherryPick(FetchInfo info) {
- cherryPick.setText(
- "git fetch " + info.url() + " " + info.ref()
- + " && git cherry-pick FETCH_HEAD");
- }
-
- private void pull(FetchInfo info) {
- pull.setText("git pull " + info.url() + " " + info.ref());
+ if (scheme.getItemCount() > 0) {
+ FetchInfo fetchInfo =
+ fetch.get(scheme.getValue(scheme.getSelectedIndex()));
+ for (String commandName : Natives.keys(fetchInfo.commands())) {
+ CopyableLabel copyLabel =
+ new CopyableLabel(fetchInfo.command(commandName));
+ copyLabel.setStyleName(Gerrit.RESOURCES.css().downloadBoxCopyLabel());
+ insertCommand(commandName, copyLabel);
+ }
+ }
+ insertPatch();
+ insertCommand(null, scheme);
}
- private void patch(FetchInfo info) {
+ private void insertPatch() {
String id = revision.substring(0, 7);
- patchBase64.setInnerText(id + ".diff.base64");
+ Anchor patchBase64 = new Anchor(id + ".diff.base64");
patchBase64.setHref(new RestApi("/changes/")
.id(psId.getParentKey().get())
.view("revisions")
@@ -118,7 +123,7 @@ class DownloadBox extends Composite {
.addParameterTrue("download")
.url());
- patchZip.setInnerText(id + ".diff.zip");
+ Anchor patchZip = new Anchor(id + ".diff.zip");
patchZip.setHref(new RestApi("/changes/")
.id(psId.getParentKey().get())
.view("revisions")
@@ -126,45 +131,52 @@ class DownloadBox extends Composite {
.view("patch")
.addParameterTrue("zip")
.url());
+
+ HorizontalPanel p = new HorizontalPanel();
+ p.add(patchBase64);
+ InlineLabel spacer = new InlineLabel("|");
+ spacer.setStyleName(Gerrit.RESOURCES.css().downloadBoxSpacer());
+ p.add(spacer);
+ p.add(patchZip);
+ insertCommand("Patch-File", p);
}
- private void repo(FetchInfo info) {
- if (Gerrit.getConfig().getDownloadSchemes().contains(REPO_DOWNLOAD)) {
- UIObject.setVisible(repoSection, true);
- repoDownload.setText("repo download "
- + project
- + " " + psId.getParentKey().get() + "/" + psId.get());
+ private void insertCommand(String commandName, Widget w) {
+ int row = commandTable.getRowCount();
+ commandTable.insertRow(row);
+ commandTable.getCellFormatter().addStyleName(row, 0,
+ Gerrit.RESOURCES.css().downloadBoxTableCommandColumn());
+ if (commandName != null) {
+ commandTable.setText(row, 0, commandName);
+ }
+ if (w != null) {
+ commandTable.setWidget(row, 1, w);
}
}
- private void renderScheme(NativeMap<FetchInfo> fetch) {
+ private void renderScheme() {
for (String id : fetch.keySet()) {
- FetchInfo info = fetch.get(id);
- String u = info.url();
- int css = u.indexOf("://");
- if (css > 0) {
- int s = u.indexOf('/', css + 3);
- if (s > 0) {
- u = u.substring(0, s + 1);
- }
- }
- scheme.addItem(u, id);
+ scheme.addItem(id);
}
- if (scheme.getItemCount() == 1) {
- scheme.setSelectedIndex(0);
+ if (scheme.getItemCount() == 0) {
scheme.setVisible(false);
} else {
- int select = 0;
- String find = getUserPreference();
- if (find != null) {
- for (int i = 0; i < scheme.getItemCount(); i++) {
- if (find.equals(scheme.getValue(i))) {
- select = i;
- break;
+ if (scheme.getItemCount() == 1) {
+ scheme.setSelectedIndex(0);
+ scheme.setVisible(false);
+ } else {
+ int select = 0;
+ String find = getUserPreference();
+ if (find != null) {
+ for (int i = 0; i < scheme.getItemCount(); i++) {
+ if (find.equals(scheme.getValue(i))) {
+ select = i;
+ break;
+ }
}
}
+ scheme.setSelectedIndex(select);
}
- scheme.setSelectedIndex(select);
}
renderCommands();
}
@@ -177,11 +189,14 @@ class DownloadBox extends Composite {
switch (pref) {
case ANON_GIT:
return "git";
- case HTTP:
case ANON_HTTP:
+ return "anonymous http";
+ case HTTP:
return "http";
case SSH:
return "ssh";
+ case REPO_DOWNLOAD:
+ return "repo";
default:
return null;
}
@@ -216,10 +231,14 @@ class DownloadBox extends Composite {
String id = scheme.getValue(scheme.getSelectedIndex());
if ("git".equals(id)) {
return DownloadScheme.ANON_GIT;
+ } else if ("anonymous http".equals(id)) {
+ return DownloadScheme.ANON_HTTP;
} else if ("http".equals(id)) {
return DownloadScheme.HTTP;
} else if ("ssh".equals(id)) {
return DownloadScheme.SSH;
+ } else if ("repo".equals(id)) {
+ return DownloadScheme.REPO_DOWNLOAD;
}
return null;
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadBox.ui.xml
deleted file mode 100644
index 449098253c..0000000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/DownloadBox.ui.xml
+++ /dev/null
@@ -1,98 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Copyright (C) 2013 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<ui:UiBinder
- xmlns:ui='urn:ui:com.google.gwt.uibinder'
- xmlns:g='urn:import:com.google.gwt.user.client.ui'
- xmlns:c='urn:import:com.google.gwtexpui.clippy.client'>
- <ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
- <ui:style>
- @external .gwt-TextBox;
-
- .downloadBox {
- min-width: 580px;
- margin: 5px;
- }
-
- .table {
- border-spacing: 0;
- width: 100%;
- }
- .table th {
- text-align: left;
- font-weight: normal;
- white-space: nowrap;
- max-height: 18px;
- width: 80px;
- padding-right: 5px;
- }
-
- .scheme {
- float: right;
- }
-
- .clippy {
- font-size: smaller;
- font-family: monospace;
- }
- .clippy span {
- width: 500px;
- white-space: nowrap;
- display: inline-block;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- .clippy .gwt-TextBox {
- padding: 0;
- margin: 0;
- border: 0;
- max-height: 18px;
- width: 500px;
- }
- .clippy div {
- float: right;
- }
- </ui:style>
- <g:HTMLPanel styleName='{style.downloadBox}'>
- <table class='{style.table}'>
- <tr>
- <th><ui:msg>Checkout</ui:msg></th>
- <td><c:CopyableLabel ui:field='checkout' styleName='{style.clippy}'/></td>
- </tr>
- <tr>
- <th><ui:msg>Cherry Pick</ui:msg></th>
- <td><c:CopyableLabel ui:field='cherryPick' styleName='{style.clippy}'/></td>
- </tr>
- <tr>
- <th><ui:msg>Pull</ui:msg></th>
- <td><c:CopyableLabel ui:field='pull' styleName='{style.clippy}'/></td>
- </tr>
- <tr>
- <th><ui:msg>Patch File</ui:msg></th>
- <td><a ui:field='patchZip'/> | <a ui:field='patchBase64'/></td>
- </tr>
- <tr ui:field='repoSection' style='display: NONE' aria-hidden='true'>
- <th><ui:msg>repo</ui:msg></th>
- <td><c:CopyableLabel ui:field='repoDownload' styleName='{style.clippy}'/></td>
- </tr>
- <tr>
- <td colspan='2'>
- <g:ListBox ui:field='scheme' styleName='{style.scheme}'/>
- </td>
- </tr>
- </table>
- </g:HTMLPanel>
-</ui:UiBinder>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
index d46b7cabad..f82abee9ac 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
@@ -232,6 +232,8 @@ public class ChangeInfo extends JavaScriptObject {
public static class FetchInfo extends JavaScriptObject {
public final native String url() /*-{ return this.url }-*/;
public final native String ref() /*-{ return this.ref }-*/;
+ public final native NativeMap<NativeString> commands() /*-{ return this.commands }-*/;
+ public final native String command(String n) /*-{ return this.commands[n]; }-*/;
protected FetchInfo () {
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
index 651ab513ad..5e604fbacd 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
@@ -1090,6 +1090,51 @@ td.removeReviewerCell {
padding-left: 4em;
border-left: none;
}
+
+.downloadBox {
+ min-width: 580px;
+ margin: 5px;
+}
+.downloadBoxTable {
+ border-spacing: 0;
+ width: 100%;
+}
+.downloadBoxTableCommandColumn {
+ text-align: left;
+ font-weight: normal;
+ white-space: nowrap;
+ max-height: 18px;
+ width: 80px;
+ padding-right: 5px;
+}
+.downloadBoxSpacer {
+ margin-left: 5px;
+ margin-right: 5px;
+}
+.downloadBoxScheme {
+ float: right;
+}
+.downloadBoxCopyLabel {
+ font-size: smaller;
+ font-family: monospace;
+}
+.downloadBoxCopyLabel span {
+ width: 500px;
+ white-space: nowrap;
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.downloadBoxCopyLabel .gwt-TextBox {
+ padding: 0;
+ margin: 0;
+ border: 0;
+ max-height: 18px;
+ width: 500px;
+}
+.downloadBoxCopyLabel div {
+ float: right;
+}
td.downloadLinkListCell {
padding: 0px;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
index c7f6d162be..d6ecc5e4c9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
@@ -23,6 +23,7 @@ import static com.google.gerrit.common.changes.ListChangesOption.CURRENT_FILES;
import static com.google.gerrit.common.changes.ListChangesOption.CURRENT_REVISION;
import static com.google.gerrit.common.changes.ListChangesOption.DETAILED_ACCOUNTS;
import static com.google.gerrit.common.changes.ListChangesOption.DETAILED_LABELS;
+import static com.google.gerrit.common.changes.ListChangesOption.DOWNLOAD_COMMANDS;
import static com.google.gerrit.common.changes.ListChangesOption.DRAFT_COMMENTS;
import static com.google.gerrit.common.changes.ListChangesOption.LABELS;
import static com.google.gerrit.common.changes.ListChangesOption.MESSAGES;
@@ -30,7 +31,6 @@ import static com.google.gerrit.common.changes.ListChangesOption.REVIEWED;
import com.google.common.base.Joiner;
import com.google.common.base.Objects;
-import com.google.common.base.Strings;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
@@ -50,6 +50,8 @@ import com.google.gerrit.common.data.LabelValue;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRange;
import com.google.gerrit.common.data.SubmitRecord;
+import com.google.gerrit.extensions.config.DownloadCommand;
+import com.google.gerrit.extensions.config.DownloadScheme;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.extensions.restapi.Url;
@@ -69,8 +71,6 @@ import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountInfo;
import com.google.gerrit.server.actions.ActionInfo;
-import com.google.gerrit.server.config.CanonicalWebUrl;
-import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.extensions.webui.UiActions;
import com.google.gerrit.server.git.LabelNormalizer;
import com.google.gerrit.server.patch.PatchListNotAvailableException;
@@ -79,14 +79,11 @@ import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.query.change.ChangeData;
-import com.google.gerrit.server.ssh.SshAdvertisedAddresses;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.ResultSet;
import com.google.inject.Inject;
import com.google.inject.Provider;
-import com.google.inject.Singleton;
-import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -120,30 +117,6 @@ public class ChangeJson {
}
};
- @Singleton
- static class Urls {
- final String git;
- final String http;
- final String ssh;
-
- @Inject
- Urls(@GerritServerConfig Config cfg,
- @SshAdvertisedAddresses List<String> sshAddresses) {
- this.git = ensureSlash(cfg.getString("gerrit", null, "canonicalGitUrl"));
- this.http = ensureSlash(cfg.getString("gerrit", null, "gitHttpUrl"));
- this.ssh = !sshAddresses.isEmpty()
- ? ensureSlash("ssh://" + sshAddresses.get(0))
- : null;
- }
-
- private static String ensureSlash(String in) {
- if (in != null && !in.endsWith("/")) {
- return in + "/";
- }
- return in;
- }
- }
-
private final Provider<ReviewDb> db;
private final LabelNormalizer labelNormalizer;
private final Provider<CurrentUser> userProvider;
@@ -153,8 +126,8 @@ public class ChangeJson {
private final PatchSetInfoFactory patchSetInfoFactory;
private final FileInfoJson fileInfoJson;
private final AccountInfo.Loader.Factory accountLoaderFactory;
- private final Provider<String> urlProvider;
- private final Urls urls;
+ private final DynamicMap<DownloadScheme> downloadSchemes;
+ private final DynamicMap<DownloadCommand> downloadCommands;
private final DynamicMap<RestView<ChangeResource>> changes;
private final Revisions revisions;
@@ -175,8 +148,8 @@ public class ChangeJson {
PatchSetInfoFactory psi,
FileInfoJson fileInfoJson,
AccountInfo.Loader.Factory ailf,
- @CanonicalWebUrl Provider<String> curl,
- Urls urls,
+ DynamicMap<DownloadScheme> downloadSchemes,
+ DynamicMap<DownloadCommand> downloadCommands,
DynamicMap<RestView<ChangeResource>> changes,
Revisions revisions) {
this.db = db;
@@ -188,8 +161,8 @@ public class ChangeJson {
this.patchSetInfoFactory = psi;
this.fileInfoJson = fileInfoJson;
this.accountLoaderFactory = ailf;
- this.urlProvider = curl;
- this.urls = urls;
+ this.downloadSchemes = downloadSchemes;
+ this.downloadCommands = downloadCommands;
this.changes = changes;
this.revisions = revisions;
@@ -872,28 +845,37 @@ public class ChangeJson {
private Map<String, FetchInfo> makeFetchMap(ChangeData cd, PatchSet in)
throws OrmException {
Map<String, FetchInfo> r = Maps.newLinkedHashMap();
- String refName = in.getRefName();
- ChangeControl ctl = control(cd);
- if (ctl != null && ctl.forUser(anonymous).isPatchVisible(in, db.get())) {
- if (urls.git != null) {
- r.put("git", new FetchInfo(urls.git
- + cd.change(db).getProject().get(), refName));
+
+ for (DynamicMap.Entry<DownloadScheme> e : downloadSchemes) {
+ String schemeName = e.getExportName();
+ DownloadScheme scheme = e.getProvider().get();
+ if (!scheme.isEnabled()
+ || (scheme.isAuthRequired() && !userProvider.get().isIdentifiedUser())) {
+ continue;
}
- }
- if (urls.http != null) {
- r.put("http", new FetchInfo(urls.http
- + cd.change(db).getProject().get(), refName));
- } else {
- String http = urlProvider.get();
- if (!Strings.isNullOrEmpty(http)) {
- r.put("http", new FetchInfo(http
- + cd.change(db).getProject().get(), refName));
+
+ ChangeControl ctl = control(cd);
+ if (!scheme.isAuthRequired()
+ && !ctl.forUser(anonymous).isPatchVisible(in, db.get())) {
+ continue;
+ }
+
+ String projectName = ctl.getProject().getNameKey().get();
+ String url = scheme.getUrl(projectName);
+ String refName = in.getRefName();
+ FetchInfo fetchInfo = new FetchInfo(url, refName);
+ r.put(schemeName, fetchInfo);
+
+ if (has(DOWNLOAD_COMMANDS)) {
+ for (DynamicMap.Entry<DownloadCommand> e2 : downloadCommands) {
+ String commandName = e2.getExportName();
+ DownloadCommand command = e2.getProvider().get();
+ String c = command.getCommand(scheme, projectName, refName);
+ if (c != null) {
+ fetchInfo.addCommand(commandName, c);
+ }
+ }
}
- }
- if (urls.ssh != null) {
- r.put("ssh", new FetchInfo(
- urls.ssh + cd.change(db).getProject().get(),
- refName));
}
return r;
@@ -960,11 +942,19 @@ public class ChangeJson {
static class FetchInfo {
String url;
String ref;
+ Map<String, String> commands;
FetchInfo(String url, String ref) {
this.url = url;
this.ref = ref;
}
+
+ void addCommand(String name, String command) {
+ if (commands == null) {
+ commands = Maps.newTreeMap();
+ }
+ commands.put(name, command);
+ }
}
static class GitPerson {