summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 {