Merge changes from topic 'arbitrary-download-schemes'

* changes:
  Sort download schemes and command names
  SetPreferences: Enforce download scheme is registered
  Describe allowed values for download_scheme field
  DownloadUrlLink: Kill KnownScheme enum
  Store preferred download scheme as arbitrary strings
  DownloadConfig: Make set methods return ImmutableSet
  Remove DEFAULT_SCHEMES and DEFAULT_COMMANDS
This commit is contained in:
Dave Borowitz 2015-09-09 15:00:57 +00:00 committed by Gerrit Code Review
commit 1912561ec1
19 changed files with 199 additions and 207 deletions
Documentation
gerrit-gwtui-common/src/main/java/com/google/gerrit/client
gerrit-gwtui/src/main/java/com/google/gerrit/client
gerrit-httpd/src/main/java/com/google/gerrit/httpd
gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client
gerrit-server/src/main/java/com/google/gerrit/server
gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands
plugins

@ -1774,7 +1774,9 @@ Whether the site header should be shown.
|`use_flash_clipboard` |not set if `false`| |`use_flash_clipboard` |not set if `false`|
Whether to use the flash clipboard widget. Whether to use the flash clipboard widget.
|`download_scheme` || |`download_scheme` ||
The type of download URL the user prefers to use. The type of download URL the user prefers to use. May be any key from
the `schemes` map in
link:rest-api-config.html#download-info[DownloadInfo].
|`download_command` || |`download_command` ||
The type of download command the user prefers to use. The type of download command the user prefers to use.
|`copy_self_on_email` |not set if `false`| |`copy_self_on_email` |not set if `false`|

@ -21,7 +21,6 @@ import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DateFormat; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DateFormat;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DiffView; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DiffView;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.ReviewCategoryStrategy; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.ReviewCategoryStrategy;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.TimeFormat; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.TimeFormat;
import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JavaScriptObject;
@ -73,11 +72,7 @@ public class AccountPreferencesInfo extends JavaScriptObject {
public final native boolean useFlashClipboard() public final native boolean useFlashClipboard()
/*-{ return this.use_flash_clipboard || false }-*/; /*-{ return this.use_flash_clipboard || false }-*/;
public final DownloadScheme downloadScheme() { public final native String downloadScheme()
String s = downloadSchemeRaw();
return s != null ? DownloadScheme.valueOf(s) : null;
}
private final native String downloadSchemeRaw()
/*-{ return this.download_scheme }-*/; /*-{ return this.download_scheme }-*/;
public final DownloadCommand downloadCommand() { public final DownloadCommand downloadCommand() {
@ -142,10 +137,7 @@ public class AccountPreferencesInfo extends JavaScriptObject {
public final native void useFlashClipboard(boolean u) public final native void useFlashClipboard(boolean u)
/*-{ this.use_flash_clipboard = u }-*/; /*-{ this.use_flash_clipboard = u }-*/;
public final void downloadScheme(DownloadScheme d) { public final native void downloadScheme(String d)
downloadSchemeRaw(d != null ? d.toString() : null);
}
private final native void downloadSchemeRaw(String d)
/*-{ this.download_scheme = d }-*/; /*-{ this.download_scheme = d }-*/;
public final void downloadCommand(DownloadCommand d) { public final void downloadCommand(DownloadCommand d) {

@ -26,8 +26,8 @@ import java.util.List;
import java.util.Set; import java.util.Set;
public class DownloadInfo extends JavaScriptObject { public class DownloadInfo extends JavaScriptObject {
public final Set<String> schemes() { public final List<String> schemes() {
return Natives.keys(_schemes()); return _schemes().sortedKeys();
} }
public final List<String> archives() { public final List<String> archives() {
@ -46,8 +46,8 @@ public class DownloadInfo extends JavaScriptObject {
} }
public static class DownloadSchemeInfo extends JavaScriptObject { public static class DownloadSchemeInfo extends JavaScriptObject {
public final Set<String> commandNames() { public final List<String> commandNames() {
return Natives.keys(_commands()); return _commands().sortedKeys();
} }
public final Set<DownloadCommandInfo> commands(String project) { public final Set<DownloadCommandInfo> commands(String project) {
@ -67,13 +67,14 @@ public class DownloadInfo extends JavaScriptObject {
return project.substring(project.lastIndexOf('/') + 1); return project.substring(project.lastIndexOf('/') + 1);
} }
public final Set<String> cloneCommandNames() { public final List<String> cloneCommandNames() {
return Natives.keys(_cloneCommands()); return _cloneCommands().sortedKeys();
} }
public final Set<DownloadCommandInfo> cloneCommands(String project) { public final List<DownloadCommandInfo> cloneCommands(String project) {
Set<DownloadCommandInfo> commands = new HashSet<>(); List<String> commandNames = cloneCommandNames();
for (String commandName : cloneCommandNames()) { List<DownloadCommandInfo> commands = new ArrayList<>(commandNames.size());
for (String commandName : commandNames) {
commands.add(new DownloadCommandInfo(commandName, cloneCommand( commands.add(new DownloadCommandInfo(commandName, cloneCommand(
commandName, project))); commandName, project)));
} }

@ -18,6 +18,9 @@ import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray; import com.google.gwt.core.client.JsArray;
import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.AsyncCallback;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set; import java.util.Set;
/** A map of native JSON objects, keyed by a string. */ /** A map of native JSON objects, keyed by a string. */
@ -58,6 +61,13 @@ public class NativeMap<T extends JavaScriptObject> extends JavaScriptObject {
return Natives.keys(this); return Natives.keys(this);
} }
public final List<String> sortedKeys() {
Set<String> keys = keySet();
List<String> sorted = new ArrayList<>(keys);
Collections.sort(sorted);
return sorted;
}
public final native JsArray<T> values() public final native JsArray<T> values()
/*-{ /*-{
var s = this; var s = this;

@ -69,7 +69,6 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
public class ProjectInfoScreen extends ProjectScreen { public class ProjectInfoScreen extends ProjectScreen {
private boolean isOwner; private boolean isOwner;
@ -710,7 +709,7 @@ public class ProjectInfoScreen extends ProjectScreen {
} }
@Override @Override
protected Set<DownloadCommandInfo> getCommands(DownloadSchemeInfo schemeInfo) { protected List<DownloadCommandInfo> getCommands(DownloadSchemeInfo schemeInfo) {
return schemeInfo.cloneCommands(project); return schemeInfo.cloneCommands(project);
} }
} }

@ -23,10 +23,8 @@ import com.google.gerrit.client.info.ChangeInfo;
import com.google.gerrit.client.info.ChangeInfo.EditInfo; import com.google.gerrit.client.info.ChangeInfo.EditInfo;
import com.google.gerrit.client.info.ChangeInfo.FetchInfo; import com.google.gerrit.client.info.ChangeInfo.FetchInfo;
import com.google.gerrit.client.rpc.NativeMap; 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.client.rpc.RestApi;
import com.google.gerrit.extensions.client.ListChangesOption; import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeEvent;
@ -120,7 +118,7 @@ class DownloadBox extends VerticalPanel {
if (scheme.getItemCount() > 0) { if (scheme.getItemCount() > 0) {
FetchInfo fetchInfo = FetchInfo fetchInfo =
fetch.get(scheme.getValue(scheme.getSelectedIndex())); fetch.get(scheme.getValue(scheme.getSelectedIndex()));
for (String commandName : Natives.keys(fetchInfo.commands())) { for (String commandName : fetchInfo.commands().sortedKeys()) {
CopyableLabel copyLabel = CopyableLabel copyLabel =
new CopyableLabel(fetchInfo.command(commandName)); new CopyableLabel(fetchInfo.command(commandName));
copyLabel.setStyleName(Gerrit.RESOURCES.css().downloadBoxCopyLabel()); copyLabel.setStyleName(Gerrit.RESOURCES.css().downloadBoxCopyLabel());
@ -210,7 +208,7 @@ class DownloadBox extends VerticalPanel {
} }
private void renderScheme() { private void renderScheme() {
for (String id : fetch.keySet()) { for (String id : fetch.sortedKeys()) {
scheme.addItem(id); scheme.addItem(id);
} }
if (scheme.getItemCount() == 0) { if (scheme.getItemCount() == 0) {
@ -221,7 +219,7 @@ class DownloadBox extends VerticalPanel {
scheme.setVisible(false); scheme.setVisible(false);
} else { } else {
int select = 0; int select = 0;
String find = getUserPreference(); String find = Gerrit.getUserPreferences().downloadScheme();
if (find != null) { if (find != null) {
for (int i = 0; i < scheme.getItemCount(); i++) { for (int i = 0; i < scheme.getItemCount(); i++) {
if (find.equals(scheme.getValue(i))) { if (find.equals(scheme.getValue(i))) {
@ -236,35 +234,13 @@ class DownloadBox extends VerticalPanel {
renderCommands(); renderCommands();
} }
private static String getUserPreference() {
DownloadScheme pref = Gerrit.getUserPreferences().downloadScheme();
if (pref != null) {
switch (pref) {
case ANON_GIT:
return "git";
case ANON_HTTP:
return "anonymous http";
case HTTP:
return "http";
case SSH:
return "ssh";
case REPO_DOWNLOAD:
return "repo";
default:
return null;
}
}
return null;
}
private void saveScheme() { private void saveScheme() {
DownloadScheme scheme = getSelectedScheme(); String schemeStr = scheme.getValue(scheme.getSelectedIndex());
AccountPreferencesInfo prefs = Gerrit.getUserPreferences(); AccountPreferencesInfo prefs = Gerrit.getUserPreferences();
if (Gerrit.isSignedIn() && scheme != null if (Gerrit.isSignedIn() && !schemeStr.equals(prefs.downloadScheme())) {
&& scheme != prefs.downloadScheme()) { prefs.downloadScheme(schemeStr);
prefs.downloadScheme(scheme);
AccountPreferencesInfo in = AccountPreferencesInfo.create(); AccountPreferencesInfo in = AccountPreferencesInfo.create();
in.downloadScheme(scheme); in.downloadScheme(schemeStr);
AccountApi.self().view("preferences") AccountApi.self().view("preferences")
.put(in, new AsyncCallback<JavaScriptObject>() { .put(in, new AsyncCallback<JavaScriptObject>() {
@Override @Override
@ -277,20 +253,4 @@ class DownloadBox extends VerticalPanel {
}); });
} }
} }
private DownloadScheme getSelectedScheme() {
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;
}
} }

@ -21,7 +21,7 @@ import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.InlineLabel; import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwtexpui.clippy.client.CopyableLabel; import com.google.gwtexpui.clippy.client.CopyableLabel;
import java.util.Set; import java.util.List;
public abstract class DownloadPanel extends FlowPanel { public abstract class DownloadPanel extends FlowPanel {
protected final String project; protected final String project;
@ -63,6 +63,6 @@ public abstract class DownloadPanel extends FlowPanel {
commands.select(); commands.select();
} }
protected abstract Set<DownloadCommandInfo> getCommands( protected abstract List<DownloadCommandInfo> getCommands(
DownloadSchemeInfo schemeInfo); DownloadSchemeInfo schemeInfo);
} }

@ -18,7 +18,6 @@ import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.account.AccountApi; import com.google.gerrit.client.account.AccountApi;
import com.google.gerrit.client.info.AccountPreferencesInfo; import com.google.gerrit.client.info.AccountPreferencesInfo;
import com.google.gerrit.client.info.DownloadInfo.DownloadSchemeInfo; import com.google.gerrit.client.info.DownloadInfo.DownloadSchemeInfo;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
import com.google.gwt.aria.client.Roles; import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickEvent;
@ -31,32 +30,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class DownloadUrlLink extends Anchor implements ClickHandler { public class DownloadUrlLink extends Anchor implements ClickHandler {
private enum KnownScheme {
ANON_GIT(DownloadScheme.ANON_GIT, "git", Util.M.anonymousDownload("Git")),
ANON_HTTP(DownloadScheme.ANON_HTTP, "anonymous http", Util.M.anonymousDownload("HTTP")),
SSH(DownloadScheme.SSH, "ssh", "SSH"),
HTTP(DownloadScheme.HTTP, "http", "HTTP");
public final DownloadScheme downloadScheme;
public final String name;
public final String text;
private KnownScheme(DownloadScheme downloadScheme, String name, String text) {
this.downloadScheme = downloadScheme;
this.name = name;
this.text = text;
}
static KnownScheme get(String name) {
for (KnownScheme s : values()) {
if (s.name.equals(name)) {
return s;
}
}
return null;
}
}
public static List<DownloadUrlLink> createDownloadUrlLinks( public static List<DownloadUrlLink> createDownloadUrlLinks(
boolean allowAnonymous, DownloadPanel downloadPanel) { boolean allowAnonymous, DownloadPanel downloadPanel) {
List<DownloadUrlLink> urls = new ArrayList<>(); List<DownloadUrlLink> urls = new ArrayList<>();
@ -65,41 +38,29 @@ public class DownloadUrlLink extends Anchor implements ClickHandler {
if (scheme.isAuthRequired() && !allowAnonymous) { if (scheme.isAuthRequired() && !allowAnonymous) {
continue; continue;
} }
KnownScheme knownScheme = KnownScheme.get(s);
if (knownScheme != null) {
urls.add(new DownloadUrlLink(downloadPanel, scheme,
knownScheme.downloadScheme, knownScheme.text));
} else {
urls.add(new DownloadUrlLink(downloadPanel, scheme, s)); urls.add(new DownloadUrlLink(downloadPanel, scheme, s));
} }
}
return urls; return urls;
} }
private final DownloadPanel downloadPanel; private final DownloadPanel downloadPanel;
private final DownloadSchemeInfo schemeInfo; private final DownloadSchemeInfo schemeInfo;
private final DownloadScheme scheme; private final String schemeName;
public DownloadUrlLink(DownloadPanel downloadPanel, public DownloadUrlLink(DownloadPanel downloadPanel,
DownloadSchemeInfo schemeInfo, String text) { DownloadSchemeInfo schemeInfo, String schemeName) {
this(downloadPanel, schemeInfo, null, text); super(schemeName);
}
public DownloadUrlLink(DownloadPanel downloadPanel,
DownloadSchemeInfo schemeInfo, DownloadScheme urlType, String text) {
super(text);
setStyleName(Gerrit.RESOURCES.css().downloadLink()); setStyleName(Gerrit.RESOURCES.css().downloadLink());
Roles.getTabRole().set(getElement()); Roles.getTabRole().set(getElement());
addClickHandler(this); addClickHandler(this);
this.downloadPanel = downloadPanel; this.downloadPanel = downloadPanel;
this.schemeInfo = schemeInfo; this.schemeInfo = schemeInfo;
this.scheme = urlType; this.schemeName = schemeName;
} }
public DownloadScheme getUrlType() { public String getSchemeName() {
return scheme; return schemeName;
} }
@Override @Override
@ -110,11 +71,10 @@ public class DownloadUrlLink extends Anchor implements ClickHandler {
select(); select();
AccountPreferencesInfo prefs = Gerrit.getUserPreferences(); AccountPreferencesInfo prefs = Gerrit.getUserPreferences();
if (Gerrit.isSignedIn() && scheme != null if (Gerrit.isSignedIn() && !schemeName.equals(prefs.downloadScheme())) {
&& scheme != prefs.downloadScheme()) { prefs.downloadScheme(schemeName);
prefs.downloadScheme(scheme);
AccountPreferencesInfo in = AccountPreferencesInfo.create(); AccountPreferencesInfo in = AccountPreferencesInfo.create();
in.downloadScheme(scheme); in.downloadScheme(schemeName);
AccountApi.self().view("preferences") AccountApi.self().view("preferences")
.put(in, new AsyncCallback<JavaScriptObject>() { .put(in, new AsyncCallback<JavaScriptObject>() {
@Override @Override

@ -15,7 +15,6 @@
package com.google.gerrit.client.download; package com.google.gerrit.client.download;
import com.google.gerrit.client.Gerrit; import com.google.gerrit.client.Gerrit;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
import com.google.gwt.aria.client.Roles; import com.google.gwt.aria.client.Roles;
import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.client.ui.Widget;
@ -33,7 +32,7 @@ public class DownloadUrlPanel extends FlowPanel {
return getWidgetCount() == 0; return getWidgetCount() == 0;
} }
public void select(AccountGeneralPreferences.DownloadScheme urlType) { public void select(String schemeName) {
DownloadUrlLink first = null; DownloadUrlLink first = null;
for (Widget w : this) { for (Widget w : this) {
@ -42,7 +41,7 @@ public class DownloadUrlPanel extends FlowPanel {
if (first == null) { if (first == null) {
first = d; first = d;
} }
if (d.getUrlType() == urlType) { if (d.getSchemeName().equals(schemeName)) {
d.select(); d.select();
return; return;
} }

@ -1,21 +0,0 @@
// Copyright (C) 2008 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.
package com.google.gerrit.client.download;
import com.google.gwt.core.client.GWT;
public class Util {
public static final DownloadMessages M = GWT.create(DownloadMessages.class);
}

@ -14,7 +14,7 @@
package com.google.gerrit.httpd; package com.google.gerrit.httpd;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme; import com.google.gerrit.reviewdb.client.CoreDownloadSchemes;
import com.google.gerrit.server.config.AuthConfig; import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.config.DownloadConfig; import com.google.gerrit.server.config.DownloadConfig;
import com.google.inject.Inject; import com.google.inject.Inject;
@ -55,8 +55,7 @@ public class GitOverHttpModule extends ServletModule {
} }
private boolean isHttpEnabled(){ private boolean isHttpEnabled(){
return downloadConfig.getDownloadSchemes().contains(DownloadScheme.DEFAULT_DOWNLOADS) return downloadConfig.getDownloadSchemes().contains(CoreDownloadSchemes.ANON_HTTP)
|| downloadConfig.getDownloadSchemes().contains(DownloadScheme.ANON_HTTP) || downloadConfig.getDownloadSchemes().contains(CoreDownloadSchemes.HTTP);
|| downloadConfig.getDownloadSchemes().contains(DownloadScheme.HTTP);
} }
} }

@ -25,14 +25,9 @@ public final class AccountGeneralPreferences {
/** Valid choices for the page size. */ /** Valid choices for the page size. */
public static final short[] PAGESIZE_CHOICES = {10, 25, 50, 100}; public static final short[] PAGESIZE_CHOICES = {10, 25, 50, 100};
/** Preferred scheme type to download a change. */
public static enum DownloadScheme {
ANON_GIT, ANON_HTTP, HTTP, SSH, REPO_DOWNLOAD, DEFAULT_DOWNLOADS
}
/** Preferred method to download a change. */ /** Preferred method to download a change. */
public static enum DownloadCommand { public static enum DownloadCommand {
REPO_DOWNLOAD, PULL, CHECKOUT, CHERRY_PICK, FORMAT_PATCH, DEFAULT_DOWNLOADS REPO_DOWNLOAD, PULL, CHECKOUT, CHERRY_PICK, FORMAT_PATCH
} }
public static enum DateFormat { public static enum DateFormat {
@ -187,20 +182,50 @@ public final class AccountGeneralPreferences {
useFlashClipboard = b; useFlashClipboard = b;
} }
public DownloadScheme getDownloadUrl() { public String getDownloadUrl() {
if (downloadUrl == null) { // Translate from legacy enum names to modern display names. (May be removed
return null; // if accompanied by a 2-phase schema upgrade.)
if (downloadUrl != null) {
switch (downloadUrl) {
case "ANON_GIT":
return CoreDownloadSchemes.ANON_GIT;
case "ANON_HTTP":
return CoreDownloadSchemes.ANON_HTTP;
case "HTTP":
return CoreDownloadSchemes.HTTP;
case "SSH":
return CoreDownloadSchemes.SSH;
case "REPO_DOWNLOAD":
return CoreDownloadSchemes.REPO_DOWNLOAD;
} }
return DownloadScheme.valueOf(downloadUrl); }
return downloadUrl;
} }
public void setDownloadUrl(DownloadScheme url) { public void setDownloadUrl(String url) {
if (url != null) { // Translate from modern display names to legacy enum names. (May be removed
downloadUrl = url.name(); // if accompanied by a 2-phase schema upgrade.)
} else { if (downloadUrl != null) {
downloadUrl = null; switch (url) {
case CoreDownloadSchemes.ANON_GIT:
url = "ANON_GIT";
break;
case CoreDownloadSchemes.ANON_HTTP:
url = "ANON_HTTP";
break;
case CoreDownloadSchemes.HTTP:
url = "HTTP";
break;
case CoreDownloadSchemes.SSH:
url = "SSH";
break;
case CoreDownloadSchemes.REPO_DOWNLOAD:
url = "REPO_DOWNLOAD";
break;
} }
} }
downloadUrl = url;
}
public DownloadCommand getDownloadCommand() { public DownloadCommand getDownloadCommand() {
if (downloadCommand == null) { if (downloadCommand == null) {

@ -1,4 +1,4 @@
// Copyright (C) 2008 The Android Open Source Project // Copyright (C) 2015 The Android Open Source Project
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -12,10 +12,19 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package com.google.gerrit.client.download; package com.google.gerrit.reviewdb.client;
import com.google.gwt.i18n.client.Messages; /**
* Download scheme string constants supported by the download-commands core
* plugin.
*/
public class CoreDownloadSchemes {
public static final String ANON_GIT = "git";
public static final String ANON_HTTP = "anonymous http";
public static final String HTTP = "http";
public static final String SSH = "ssh";
public static final String REPO_DOWNLOAD = "repo";
public interface DownloadMessages extends Messages { private CoreDownloadSchemes() {
String anonymousDownload(String protocol); }
} }

@ -24,7 +24,6 @@ import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DateFormat; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DateFormat;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DiffView; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DiffView;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.ReviewCategoryStrategy; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.ReviewCategoryStrategy;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.TimeFormat; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.TimeFormat;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
@ -103,7 +102,7 @@ public class GetPreferences implements RestReadView<AccountResource> {
Short changesPerPage; Short changesPerPage;
Boolean showSiteHeader; Boolean showSiteHeader;
Boolean useFlashClipboard; Boolean useFlashClipboard;
DownloadScheme downloadScheme; String downloadScheme;
DownloadCommand downloadCommand; DownloadCommand downloadCommand;
Boolean copySelfOnEmail; Boolean copySelfOnEmail;
DateFormat dateFormat; DateFormat dateFormat;

@ -23,7 +23,10 @@ import static com.google.gerrit.server.account.GetPreferences.MY;
import static com.google.gerrit.server.account.GetPreferences.URL_ALIAS; import static com.google.gerrit.server.account.GetPreferences.URL_ALIAS;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.gerrit.extensions.config.DownloadScheme;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.extensions.webui.TopMenu; import com.google.gerrit.extensions.webui.TopMenu;
@ -32,7 +35,6 @@ import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DateFormat; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DateFormat;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DiffView; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DiffView;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.ReviewCategoryStrategy; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.ReviewCategoryStrategy;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.TimeFormat; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.TimeFormat;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
@ -60,7 +62,7 @@ public class SetPreferences implements RestModifyView<AccountResource, Input> {
public Short changesPerPage; public Short changesPerPage;
public Boolean showSiteHeader; public Boolean showSiteHeader;
public Boolean useFlashClipboard; public Boolean useFlashClipboard;
public DownloadScheme downloadScheme; public String downloadScheme;
public DownloadCommand downloadCommand; public DownloadCommand downloadCommand;
public Boolean copySelfOnEmail; public Boolean copySelfOnEmail;
public DateFormat dateFormat; public DateFormat dateFormat;
@ -80,22 +82,27 @@ public class SetPreferences implements RestModifyView<AccountResource, Input> {
private final Provider<ReviewDb> db; private final Provider<ReviewDb> db;
private final MetaDataUpdate.User metaDataUpdateFactory; private final MetaDataUpdate.User metaDataUpdateFactory;
private final AllUsersName allUsersName; private final AllUsersName allUsersName;
private final DynamicMap<DownloadScheme> downloadSchemes;
@Inject @Inject
SetPreferences(Provider<CurrentUser> self, AccountCache cache, SetPreferences(Provider<CurrentUser> self,
Provider<ReviewDb> db, MetaDataUpdate.User metaDataUpdateFactory, AccountCache cache,
AllUsersName allUsersName) { Provider<ReviewDb> db,
MetaDataUpdate.User metaDataUpdateFactory,
AllUsersName allUsersName,
DynamicMap<DownloadScheme> downloadSchemes) {
this.self = self; this.self = self;
this.cache = cache; this.cache = cache;
this.db = db; this.db = db;
this.metaDataUpdateFactory = metaDataUpdateFactory; this.metaDataUpdateFactory = metaDataUpdateFactory;
this.allUsersName = allUsersName; this.allUsersName = allUsersName;
this.downloadSchemes = downloadSchemes;
} }
@Override @Override
public GetPreferences.PreferenceInfo apply(AccountResource rsrc, Input i) public GetPreferences.PreferenceInfo apply(AccountResource rsrc, Input i)
throws AuthException, ResourceNotFoundException, OrmException, throws AuthException, ResourceNotFoundException, BadRequestException,
IOException, ConfigInvalidException { OrmException, IOException, ConfigInvalidException {
if (self.get() != rsrc.getUser() if (self.get() != rsrc.getUser()
&& !self.get().getCapabilities().canModifyAccount()) { && !self.get().getCapabilities().canModifyAccount()) {
throw new AuthException("restricted to members of Modify Accounts"); throw new AuthException("restricted to members of Modify Accounts");
@ -134,7 +141,7 @@ public class SetPreferences implements RestModifyView<AccountResource, Input> {
p.setUseFlashClipboard(i.useFlashClipboard); p.setUseFlashClipboard(i.useFlashClipboard);
} }
if (i.downloadScheme != null) { if (i.downloadScheme != null) {
p.setDownloadUrl(i.downloadScheme); setDownloadScheme(p, i.downloadScheme);
} }
if (i.downloadCommand != null) { if (i.downloadCommand != null) {
p.setDownloadCommand(i.downloadCommand); p.setDownloadCommand(i.downloadCommand);
@ -225,4 +232,16 @@ public class SetPreferences implements RestModifyView<AccountResource, Input> {
} }
} }
} }
private void setDownloadScheme(AccountGeneralPreferences p, String scheme)
throws BadRequestException {
for (DynamicMap.Entry<DownloadScheme> e : downloadSchemes) {
if (e.getExportName().equals(scheme)
&& e.getProvider().get().isEnabled()) {
p.setDownloadUrl(scheme);
return;
}
}
throw new BadRequestException("Unsupported download scheme: " + scheme);
}
} }

@ -14,65 +14,107 @@
package com.google.gerrit.server.config; package com.google.gerrit.server.config;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand; import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme; import com.google.gerrit.reviewdb.client.CoreDownloadSchemes;
import com.google.gerrit.server.change.ArchiveFormat; import com.google.gerrit.server.change.ArchiveFormat;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Config;
import java.util.Collections; import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
/** Download protocol from {@code gerrit.config}. */ /**
* Download protocol from {@code gerrit.config}.
* <p>
* Only used to configure the built-in set of schemes and commands in the core
* download-commands plugin; not used by other plugins.
*/
@Singleton @Singleton
public class DownloadConfig { public class DownloadConfig {
private final Set<DownloadScheme> downloadSchemes; private final ImmutableSet<String> downloadSchemes;
private final Set<DownloadCommand> downloadCommands; private final ImmutableSet<DownloadCommand> downloadCommands;
private final Set<ArchiveFormat> archiveFormats; private final ImmutableSet<ArchiveFormat> archiveFormats;
@Inject @Inject
DownloadConfig(@GerritServerConfig final Config cfg) { DownloadConfig(@GerritServerConfig final Config cfg) {
List<DownloadScheme> allSchemes = String[] allSchemes = cfg.getStringList("download", null, "scheme");
ConfigUtil.getEnumList(cfg, "download", null, "scheme", if (allSchemes.length == 0) {
DownloadScheme.DEFAULT_DOWNLOADS); downloadSchemes = ImmutableSet.of(
downloadSchemes = CoreDownloadSchemes.SSH,
Collections.unmodifiableSet(new HashSet<>(allSchemes)); CoreDownloadSchemes.HTTP,
CoreDownloadSchemes.ANON_HTTP);
} else {
List<String> normalized = new ArrayList<>(allSchemes.length);
for (String s : allSchemes) {
String core = toCoreScheme(s);
if (core == null) {
throw new IllegalArgumentException(
"not a core download scheme: " + s);
}
normalized.add(core);
}
downloadSchemes = ImmutableSet.copyOf(normalized);
}
DownloadCommand[] downloadCommandValues = DownloadCommand.values();
List<DownloadCommand> allCommands = List<DownloadCommand> allCommands =
ConfigUtil.getEnumList(cfg, "download", null, "command", ConfigUtil.getEnumList(cfg, "download", null, "command",
DownloadCommand.DEFAULT_DOWNLOADS); downloadCommandValues, null);
downloadCommands = if (isOnlyNull(allCommands)) {
Collections.unmodifiableSet(new HashSet<>(allCommands)); downloadCommands = ImmutableSet.copyOf(downloadCommandValues);
} else {
downloadCommands = ImmutableSet.copyOf(allCommands);
}
String v = cfg.getString("download", null, "archive"); String v = cfg.getString("download", null, "archive");
if (v == null) { if (v == null) {
archiveFormats = EnumSet.allOf(ArchiveFormat.class); archiveFormats = ImmutableSet.copyOf(EnumSet.allOf(ArchiveFormat.class));
} else if (v.isEmpty() || "off".equalsIgnoreCase(v)) { } else if (v.isEmpty() || "off".equalsIgnoreCase(v)) {
archiveFormats = Collections.emptySet(); archiveFormats = ImmutableSet.of();
} else { } else {
archiveFormats = new HashSet<>(ConfigUtil.getEnumList(cfg, archiveFormats = ImmutableSet.copyOf(ConfigUtil.getEnumList(cfg,
"download", null, "archive", "download", null, "archive",
ArchiveFormat.TGZ)); ArchiveFormat.TGZ));
} }
} }
private static boolean isOnlyNull(List<?> list) {
return list.size() == 1 && list.get(0) == null;
}
private static String toCoreScheme(String s) {
try {
Field f = CoreDownloadSchemes.class.getField(s.toUpperCase());
int m = Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL;
if ((f.getModifiers() & m) == m && f.getType() == String.class) {
return (String) f.get(null);
} else {
return null;
}
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException
| IllegalAccessException e) {
return null;
}
}
/** Scheme used to download. */ /** Scheme used to download. */
public Set<DownloadScheme> getDownloadSchemes() { public ImmutableSet<String> getDownloadSchemes() {
return downloadSchemes; return downloadSchemes;
} }
/** Command used to download. */ /** Command used to download. */
public Set<DownloadCommand> getDownloadCommands() { public ImmutableSet<DownloadCommand> getDownloadCommands() {
return downloadCommands; return downloadCommands;
} }
/** Archive formats for downloading. */ /** Archive formats for downloading. */
public Set<ArchiveFormat> getArchiveFormats() { public ImmutableSet<ArchiveFormat> getArchiveFormats() {
return archiveFormats; return archiveFormats;
} }
} }

@ -14,7 +14,7 @@
package com.google.gerrit.sshd.commands; package com.google.gerrit.sshd.commands;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme; import com.google.gerrit.reviewdb.client.CoreDownloadSchemes;
import com.google.gerrit.server.config.DownloadConfig; import com.google.gerrit.server.config.DownloadConfig;
import com.google.gerrit.sshd.CommandModule; import com.google.gerrit.sshd.CommandModule;
import com.google.gerrit.sshd.CommandName; import com.google.gerrit.sshd.CommandName;
@ -130,8 +130,6 @@ public class DefaultCommandModule extends CommandModule {
} }
private boolean sshEnabled() { private boolean sshEnabled() {
return downloadConfig.getDownloadSchemes().contains(DownloadScheme.SSH) return downloadConfig.getDownloadSchemes().contains(CoreDownloadSchemes.SSH);
|| downloadConfig.getDownloadSchemes().contains(
DownloadScheme.DEFAULT_DOWNLOADS);
} }
} }

@ -1 +1 @@
Subproject commit 99e61fb06a4505a9558c23a56213cb32ceaa9cca Subproject commit 6d4e0a45ad4d7faebc692e5f10e418cbfcf858cb