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>
This commit is contained in:
Edwin Kempin
2013-10-16 12:58:24 +02:00
committed by David Pursehouse
parent 78e868ef89
commit ea62148983
11 changed files with 278 additions and 275 deletions

View File

@@ -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
-------------

View File

@@ -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]]

View File

@@ -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;

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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() {

View File

@@ -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
protected void onLoad() {
if (scheme.getItemCount() == 0) {
renderScheme(fetch);
}
}
@UiHandler("scheme")
void onScheme(ChangeEvent event) {
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 (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();
}
@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();
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 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());
}
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,30 +131,36 @@ 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() == 0) {
scheme.setVisible(false);
} else {
if (scheme.getItemCount() == 1) {
scheme.setSelectedIndex(0);
scheme.setVisible(false);
@@ -166,6 +177,7 @@ class DownloadBox extends Composite {
}
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;
}

View File

@@ -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>

View File

@@ -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 () {
}

View File

@@ -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;
}

View File

@@ -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,29 +845,38 @@ public class ChangeJson {
private Map<String, FetchInfo> makeFetchMap(ChangeData cd, PatchSet in)
throws OrmException {
Map<String, FetchInfo> r = Maps.newLinkedHashMap();
String refName = in.getRefName();
for (DynamicMap.Entry<DownloadScheme> e : downloadSchemes) {
String schemeName = e.getExportName();
DownloadScheme scheme = e.getProvider().get();
if (!scheme.isEnabled()
|| (scheme.isAuthRequired() && !userProvider.get().isIdentifiedUser())) {
continue;
}
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));
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.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));
}
}
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 {