Merge "Cleanup implementation of REST views"
diff --git a/Documentation/cmd-gc.txt b/Documentation/cmd-gc.txt
index 50710e2..3066ca0 100644
--- a/Documentation/cmd-gc.txt
+++ b/Documentation/cmd-gc.txt
@@ -10,6 +10,7 @@
[verse]
'ssh' -p <port> <host> 'gerrit gc'
[--all]
+ [--show-progress]
<NAME> ...
DESCRIPTION
@@ -46,6 +47,9 @@
If specified the Git garbage collection is run for all projects
sequentially.
+--show-progress::
+ If specified progress information is shown.
+
EXAMPLES
--------
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index 1745e67..d1c79ac 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -497,9 +497,9 @@
$ ssh -p 29418 review.example.com sh ps
----
-[[configuration]]
-Configuration
--------------
+[[simple-configuration]]
+Simple Configuration in `gerrit.config`
+---------------------------------------
In Gerrit, global configuration is stored in the `gerrit.config` file.
If a plugin needs global configuration, this configuration should be
@@ -509,12 +509,12 @@
plugins that have a simple configuration that only consists of
key-value pairs. With this approach it is not possible to have
subsections in the plugin configuration. Plugins that require a complex
-configuration need to store their configuration in their own
-configuration file where they can make use of subsections. On the other
-hand storing the plugin configuration in a 'plugin' subsection in the
-`gerrit.config` file has the advantage that administrators have all
-configuration parameters in one file, instead of having one
-configuration file per plugin.
+configuration need to store their configuration in their
+link:#configuration[own configuration file] where they can make use of
+subsections. On the other hand storing the plugin configuration in a
+'plugin' subsection in the `gerrit.config` file has the advantage that
+administrators have all configuration parameters in one file, instead
+of having one configuration file per plugin.
To avoid conflicts with other plugins, it is recommended that plugins
only use the `plugin` subsection with their own name. For example the
@@ -541,9 +541,52 @@
.getString("language", "English");
----
-[[project-specific-configuration]]
-Project Specific Configuration
-------------------------------
+[[configuration]]
+Configuration in own config file
+--------------------------------
+
+Plugins can store their configuration in an own configuration file.
+This makes sense if the plugin configuration is rather complex and
+requires the usage of subsections. Plugins that have a simple
+key-value pair configuration can store their configuration in a
+link:#simple-configuration[`plugin` subsection of the `gerrit.config`
+file].
+
+The plugin configuration file must be named after the plugin and must
+be located in the `etc` folder of the review site. For example a
+configuration file for a `default-reviewer` plugin could look like
+this:
+
+.$site_path/etc/default-reviewer.config
+----
+[branch "refs/heads/master"]
+ reviewer = Project Owners
+ reviewer = john.doe@example.com
+[match "file:^.*\.txt"]
+ reviewer = My Info Developers
+----
+
+Via the `com.google.gerrit.server.config.PluginConfigFactory` class a
+plugin can easily access its configuration:
+
+[source,java]
+----
+@Inject
+private com.google.gerrit.server.config.PluginConfigFactory cfg;
+
+[...]
+
+String[] reviewers = cfg.getGlobalPluginConfig("default-reviewer")
+ .getStringList("branch", "refs/heads/master", "reviewer");
+----
+
+The plugin configuration is loaded only once and is then cached.
+Similar to changes in 'gerrit.config', changes to the plugin
+configuration file will only become effective after a Gerrit restart.
+
+[[simple-project-specific-configuration]]
+Simple Project Specific Configuration in `project.config`
+---------------------------------------------------------
In Gerrit, project specific configuration is stored in the project's
`project.config` file on the `refs/meta/config` branch. If a plugin
@@ -555,12 +598,12 @@
plugins that have a simple configuration that only consists of
key-value pairs. With this approach it is not possible to have
subsections in the plugin configuration. Plugins that require a complex
-configuration need to store their configuration in their own
-configuration file where they can make use of subsections. On the other
-hand storing the plugin configuration in a 'plugin' subsection in the
-`project.config` file has the advantage that project owners have all
-configuration parameters in one file, instead of having one
-configuration file per plugin.
+configuration need to store their configuration in their
+link:#project-specific-configuration[own configuration file] where they
+can make use of subsections. On the other hand storing the plugin
+configuration in a 'plugin' subsection in the `project.config` file has
+the advantage that project owners have all configuration parameters in
+one file, instead of having one configuration file per plugin.
To avoid conflicts with other plugins, it is recommended that plugins
only use the `plugin` subsection with their own name. For example the
@@ -605,6 +648,63 @@
`refs/meta/config` branch, editing the `project.config` file and
pushing the commit back.
+[[project-specific-configuration]]
+Project Specific Configuration in own config file
+-------------------------------------------------
+
+Plugins can store their project specific configuration in an own
+configuration file in the projects `refs/meta/config` branch.
+This makes sense if the plugins project specific configuration is
+rather complex and requires the usage of subsections. Plugins that
+have a simple key-value pair configuration can store their project
+specific configuration in a link:#simple-project-specific-configuration[
+`plugin` subsection of the `project.config` file].
+
+The plugin configuration file in the `refs/meta/config` branch must be
+named after the plugin. For example a configuration file for a
+`default-reviewer` plugin could look like this:
+
+.default-reviewer.config
+----
+[branch "refs/heads/master"]
+ reviewer = Project Owners
+ reviewer = john.doe@example.com
+[match "file:^.*\.txt"]
+ reviewer = My Info Developers
+----
+
+Via the `com.google.gerrit.server.config.PluginConfigFactory` class a
+plugin can easily access its project specific configuration:
+
+[source,java]
+----
+@Inject
+private com.google.gerrit.server.config.PluginConfigFactory cfg;
+
+[...]
+
+String[] reviewers = cfg.getProjectPluginConfig(project, "default-reviewer")
+ .getStringList("branch", "refs/heads/master", "reviewer");
+----
+
+It is also possible to get missing configuration parameters inherited
+from the parent projects:
+
+[source,java]
+----
+@Inject
+private com.google.gerrit.server.config.PluginConfigFactory cfg;
+
+[...]
+
+String[] reviewers = cfg.getFromPluginConfigWithInheritance(project, "default-reviewer")
+ .getStringList("branch", "refs/heads/master", "reviewer");
+----
+
+Project owners can edit the project configuration by fetching the
+`refs/meta/config` branch, editing the `<plugin-name>.config` file and
+pushing the commit back.
+
[[capabilities]]
Plugin Owned Capabilities
-------------------------
@@ -1037,6 +1137,51 @@
Gerrit-Module: com.googlesource.gerrit.plugins.helloworld.HelloWorldModule
----
+It is also possible to show some menu entries only if the user has a
+certain capability:
+
+[source,java]
+----
+public class MyTopMenuExtension implements TopMenu {
+ private final String pluginName;
+ private final Provider<CurrentUser> userProvider;
+ private final List<MenuEntry> menuEntries;
+
+ @Inject
+ public MyTopMenuExtension(@PluginName String pluginName,
+ Provider<CurrentUser> userProvider) {
+ this.pluginName = pluginName;
+ this.userProvider = userProvider;
+ menuEntries = new ArrayList<TopMenu.MenuEntry>();
+
+ // add menu entry that is only visible to users with a certain capability
+ if (canSeeMenuEntry()) {
+ menuEntries.add(new MenuEntry("Top Menu Entry", Collections
+ .singletonList(new MenuItem("Gerrit", "http://gerrit.googlecode.com/"))));
+ }
+
+ // add menu entry that is visible to all users (even anonymous users)
+ menuEntries.add(new MenuEntry("Top Menu Entry", Collections
+ .singletonList(new MenuItem("Documentation", "/plugins/myplugin/"))));
+ }
+
+ private boolean canSeeMenuEntry() {
+ if (userProvider.get().isIdentifiedUser()) {
+ CapabilityControl ctl = userProvider.get().getCapabilities();
+ return ctl.canPerform(pluginName + "-" + MyCapability.ID)
+ || ctl.canAdministrateServer();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public List<MenuEntry> getEntries() {
+ return menuEntries;
+ }
+}
+----
+
[[gwt_ui_extension]]
GWT UI Extension
----------------
@@ -1049,6 +1194,246 @@
The generated GWT plugin has a link:#top-menu-extensions[top menu] that
opens a GWT dialog box when the user clicks on it.
+In addition to the Gerrit-Plugin API a GWT plugin depends on
+`gerrit-plugin-gwtui`. This dependency must be specified in the
+`pom.xml`:
+
+[source,xml]
+----
+<dependency>
+ <groupId>com.google.gerrit</groupId>
+ <artifactId>gerrit-plugin-gwtui</artifactId>
+ <version>${Gerrit-ApiVersion}</version>
+</dependency>
+----
+
+A GWT plugin must contain a GWT module file, e.g. `HelloPlugin.gwt.xml`,
+that bundles together all the configuration settings of the GWT plugin:
+
+[source,xml]
+----
+<?xml version="1.0" encoding="UTF-8"?>
+<module rename-to="hello_gwt_plugin">
+ <!-- Inherit the core Web Toolkit stuff. -->
+ <inherits name="com.google.gwt.user.User"/>
+ <!-- Other module inherits -->
+ <inherits name="com.google.gerrit.Plugin"/>
+ <inherits name="com.google.gwt.http.HTTP"/>
+ <!-- Using GWT built-in themes adds a number of static -->
+ <!-- resources to the plugin. No theme inherits lines were -->
+ <!-- added in order to make this plugin as simple as possible -->
+ <!-- Specify the app entry point class. -->
+ <entry-point class="${package}.client.HelloPlugin"/>
+ <stylesheet src="hello.css"/>
+</module>
+----
+
+The GWT module must inherit `com.google.gerrit.Plugin` and
+`com.google.gwt.http.HTTP`.
+
+To register the GWT module a `GwtPlugin` needs to be bound.
+
+If no Guice modules are declared in the manifest, the GWT plugin may
+use auto-registration by using the `@Listen` annotation:
+
+[source,java]
+----
+@Listen
+public class MyExtension extends GwtPlugin {
+ public MyExtension() {
+ super("hello_gwt_plugin");
+ }
+}
+----
+
+Otherwise the binding must be done in an `HttpModule`:
+
+[source,java]
+----
+public class HttpModule extends HttpPluginModule {
+
+ @Override
+ protected void configureServlets() {
+ DynamicSet.bind(binder(), WebUiPlugin.class)
+ .toInstance(new GwtPlugin("hello_gwt_plugin"));
+ }
+}
+----
+
+The HTTP module above must be declared in the `pom.xml` for Maven
+driven plugins:
+
+[source,xml]
+----
+<manifestEntries>
+ <Gerrit-HttpModule>com.googlesource.gerrit.plugins.myplugin.HttpModule</Gerrit-HttpModule>
+</manifestEntries>
+----
+
+It is important that the module name that is provided to the
+`GwtPlugin` matches the GWT module contained in the plugin. The name
+of the GWT module can be explicitly set in the GWT module file by
+specifying the `rename-to` attribute on the module.
+
+[source,xml]
+----
+<module rename-to="hello_gwt_plugin">
+----
+
+The actual GWT code must be implemented in a class that extends
+`com.google.gerrit.plugin.client.Plugin`:
+
+[source,java]
+----
+public class HelloPlugin extends Plugin {
+
+ @Override
+ public void onModuleLoad() {
+ // Create the dialog box
+ final DialogBox dialogBox = new DialogBox();
+
+ // The content of the dialog comes from a User specified Preference
+ dialogBox.setText("Hello from GWT Gerrit UI plugin");
+ dialogBox.setAnimationEnabled(true);
+ Button closeButton = new Button("Close");
+ VerticalPanel dialogVPanel = new VerticalPanel();
+ dialogVPanel.setWidth("100%");
+ dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
+ dialogVPanel.add(closeButton);
+
+ closeButton.addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ dialogBox.hide();
+ }
+ });
+
+ // Set the contents of the Widget
+ dialogBox.setWidget(dialogVPanel);
+
+ RootPanel rootPanel = RootPanel.get(HelloMenu.MENU_ID);
+ rootPanel.getElement().removeAttribute("href");
+ rootPanel.addDomHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ dialogBox.center();
+ dialogBox.show();
+ }
+ }, ClickEvent.getType());
+ }
+}
+----
+
+This class must be set as entry point in the GWT module:
+
+[source,xml]
+----
+<entry-point class="${package}.client.HelloPlugin"/>
+----
+
+In addition this class must be defined as module in the `pom.xml` for the
+`gwt-maven-plugin` and the `webappDirectory` option of `gwt-maven-plugin`
+must be set to `${project.build.directory}/classes/static`:
+
+[source,xml]
+----
+<plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>gwt-maven-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <module>com.googlesource.gerrit.plugins.myplugin.HelloPlugin</module>
+ <disableClassMetadata>true</disableClassMetadata>
+ <disableCastChecking>true</disableCastChecking>
+ <webappDirectory>${project.build.directory}/classes/static</webappDirectory>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ </execution>
+ </executions>
+</plugin>
+----
+
+To attach a GWT widget defined by the plugin to the Gerrit core UI
+`com.google.gwt.user.client.ui.RootPanel` can be used to manipulate the
+Gerrit core widgets:
+
+[source,java]
+----
+RootPanel rootPanel = RootPanel.get(HelloMenu.MENU_ID);
+rootPanel.getElement().removeAttribute("href");
+rootPanel.addDomHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ dialogBox.center();
+ dialogBox.show();
+ }
+}, ClickEvent.getType());
+----
+
+GWT plugins can come with their own css file. This css file must have a
+unique name and must be registered in the GWT module:
+
+[source,xml]
+----
+<stylesheet src="hello.css"/>
+----
+
+If a GWT plugin wants to invoke the Gerrit REST API it can use
+`com.google.gerrit.plugin.client.rpc.RestApi` to contruct the URL
+path and to trigger the REST calls.
+
+Example for invoking a Gerrit core REST endpoint:
+
+[source,java]
+----
+new RestApi("projects").id(projectName).view("description")
+ .put("new description", new AsyncCallback<JavaScriptObject>() {
+
+ @Override
+ public void onSuccess(JavaScriptObject result) {
+ // TODO
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ // never invoked
+ }
+});
+----
+
+Example for invoking a REST endpoint defined by a plugin:
+
+[source,java]
+----
+new RestApi("projects").id(projectName).view("myplugin", "myview")
+ .get(new AsyncCallback<JavaScriptObject>() {
+
+ @Override
+ public void onSuccess(JavaScriptObject result) {
+ // TODO
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ // never invoked
+ }
+});
+----
+
+The `onFailure(Throwable)` of the provided callback is never invoked.
+If an error occurs, it is shown in an error dialog.
+
+In order to be able to do REST calls the GWT module must inherit
+`com.google.gwt.json.JSON`:
+
+[source,xml]
+----
+<inherits name="com.google.gwt.json.JSON"/>
+----
+
[[http]]
HTTP Servlets
-------------
diff --git a/Documentation/js-api.txt b/Documentation/js-api.txt
index 0e470e7..7411026 100644
--- a/Documentation/js-api.txt
+++ b/Documentation/js-api.txt
@@ -425,6 +425,13 @@
comes with an onkeypress handler installed to play nicely with
Gerrit's keyboard binding system.
+* `select(a,i)`: a new `<select>` element containing one `<option>`
+ element for each entry in the provided array `a`. The option with
+ the index `i` will be pre-selected in the drop-down-list.
+
+* `selected(s)`: returns the text of the `<option>` element that is
+ currently selected in the provided `<select>` element `s`.
+
* `span(...)`: a new `<span>` wrapping the (optional) arguments.
* `msg(label)`: a new label.
diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt
index 52c6ac9..f72c154 100644
--- a/Documentation/rest-api-accounts.txt
+++ b/Documentation/rest-api-accounts.txt
@@ -924,6 +924,7 @@
}
----
+[[get-starred-changes]]
Get Starred Changes
~~~~~~~~~~~~~~~~~~~
[verse]
@@ -967,6 +968,7 @@
]
----
+[[star-change]]
Star Change
~~~~~~~~~~~
[verse]
@@ -986,6 +988,7 @@
HTTP/1.1 204 No Content
----
+[[unstar-change]]
Unstar Change
~~~~~~~~~~~~~
[verse]
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index 1ac232a..c2e937a 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -552,9 +552,17 @@
Run the Git garbage collection for the repository of a project.
+Options for the Git garbage collection can be specified in the
+request body as a link:#gc-input[GCInput] entity.
+
.Request
----
POST /projects/plugins%2Freplication/gc HTTP/1.0
+ Content-Type: application/json;charset=UTF-8
+
+ {
+ "show_progress": true
+ }
----
The response is the streamed output of the garbage collection.
@@ -1317,6 +1325,19 @@
Tokens such as `${project}` are not resolved.
|===========================
+[[gc-input]]
+GCInput
+~~~~~~~
+The `GCInput` entity contains information to run the Git garbage
+collection.
+
+[options="header",width="50%",cols="1,^2,4"]
+|=============================
+|Field Name ||Description
+|`show_progress` |`false` if not set|
+Whether progress information should be shown.
+|=============================
+
[[head-input]]
HeadInput
~~~~~~~~~
diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt
index 87ea1cd..cb3a3b6 100644
--- a/Documentation/user-search.txt
+++ b/Documentation/user-search.txt
@@ -118,6 +118,12 @@
link:http://www.brics.dk/automaton/[dk.brics.automaton
library] is used for evaluation of such patterns.
+[[parentproject]]
+parentproject:'PROJECT'::
++
+Changes occurring in 'PROJECT' or in one of the child projects of
+'PROJECT'.
+
[[branch]]
branch:'BRANCH'::
+
diff --git a/ReleaseNotes/ReleaseNotes-2.8.txt b/ReleaseNotes/ReleaseNotes-2.8.txt
index 27ed297..d183cca 100644
--- a/ReleaseNotes/ReleaseNotes-2.8.txt
+++ b/ReleaseNotes/ReleaseNotes-2.8.txt
@@ -278,6 +278,15 @@
* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.8/rest-api-accounts.html#get-username[
Get account username]
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.8/rest-api-accounts.html#get-starred-changes[
+Get starred changes]
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.8/rest-api-accounts.html#star-change[
+Star change]
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.8/rest-api-accounts.html#unstar-change[
+Unstar change]
+
Changes
^^^^^^^
@@ -741,5 +750,7 @@
* Update guava to 15.0
* Update H2 to 1.3.173
* Update bouncycastle to 1.44
+* Update Apache Mina to 2.0.7
+* Update Apache SSHD to 0.9.0.201311081
* asciidoctor 0.1.4 is now required to build the documentation
* jsr305 library was removed
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
index 5576c4f..8548b5c 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
@@ -34,7 +34,6 @@
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.OrmRuntimeException;
import com.google.gwtorm.server.SchemaFactory;
-import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Provides;
import com.google.inject.Singleton;
@@ -46,7 +45,7 @@
import java.io.File;
-class InMemoryTestingDatabaseModule extends AbstractModule {
+class InMemoryTestingDatabaseModule extends LifecycleModule {
private final Config cfg;
InMemoryTestingDatabaseModule(Config cfg) {
@@ -71,12 +70,7 @@
bind(new TypeLiteral<SchemaFactory<ReviewDb>>() {})
.to(InMemoryDatabase.class);
- install(new LifecycleModule() {
- @Override
- protected void configure() {
- listener().to(CreateDatabase.class);
- }
- });
+ listener().to(CreateDatabase.class);
bind(SitePaths.class);
bind(TrackingFooters.class)
@@ -126,4 +120,4 @@
mem.drop();
}
}
-}
\ No newline at end of file
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/GitUtil.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/GitUtil.java
index c17598f..3d1b009 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/GitUtil.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/GitUtil.java
@@ -28,6 +28,7 @@
import org.eclipse.jgit.api.CheckoutCommand;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.CommitCommand;
+import org.eclipse.jgit.api.FetchCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.PushCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
@@ -105,10 +106,15 @@
}
public static Git cloneProject(String url) throws GitAPIException, IOException {
+ return cloneProject(url, true);
+ }
+
+ public static Git cloneProject(String url, boolean checkout) throws GitAPIException, IOException {
final File gitDir = TempFileUtil.createTempDirectory();
final CloneCommand cloneCmd = Git.cloneRepository();
cloneCmd.setURI(url);
cloneCmd.setDirectory(gitDir);
+ cloneCmd.setNoCheckout(!checkout);
return cloneCmd.call();
}
@@ -178,6 +184,12 @@
}
}
+ public static void fetch(Git git, String spec) throws GitAPIException {
+ FetchCommand fetch = git.fetch();
+ fetch.setRefSpecs(new RefSpec(spec));
+ fetch.call();
+ }
+
public static void checkout(Git git, String name) throws GitAPIException {
CheckoutCommand checkout = git.checkout();
checkout.setName(name);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
new file mode 100644
index 0000000..9fd7568
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
@@ -0,0 +1,147 @@
+// 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.
+
+package com.google.gerrit.acceptance.rest.project;
+
+import static com.google.gerrit.acceptance.git.GitUtil.checkout;
+import static com.google.gerrit.acceptance.git.GitUtil.cloneProject;
+import static com.google.gerrit.acceptance.git.GitUtil.createProject;
+import static com.google.gerrit.acceptance.git.GitUtil.fetch;
+import static com.google.gerrit.acceptance.git.GitUtil.initSsh;
+import static org.junit.Assert.assertEquals;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.AccountCreator;
+import com.google.gerrit.acceptance.SshSession;
+import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.git.PushOneCommit;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.config.AllProjectsNameProvider;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectState;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.inject.Inject;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.lib.Config;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class ProjectLevelConfigIT extends AbstractDaemonTest {
+
+ @Inject
+ private AccountCreator accounts;
+
+ @Inject
+ private SchemaFactory<ReviewDb> reviewDbProvider;
+
+ @Inject
+ private ProjectCache projectCache;
+
+ @Inject
+ private AllProjectsNameProvider allProjects;
+
+ private ReviewDb db;
+ private TestAccount admin;
+ private SshSession sshSession;
+ private String project;
+ private Git git;
+
+ @Before
+ public void setUp() throws Exception {
+ admin = accounts.admin();
+ initSsh(admin);
+ sshSession = new SshSession(server, admin);
+
+ project = "p";
+ createProject(sshSession, project, null, true);
+ git = cloneProject(sshSession.getUrl() + "/" + project);
+ fetch(git, GitRepositoryManager.REF_CONFIG + ":refs/heads/config");
+ checkout(git, "refs/heads/config");
+
+ db = reviewDbProvider.open();
+ }
+
+ @After
+ public void cleanup() {
+ db.close();
+ }
+
+ @Test
+ public void accessProjectSpecificConfig() throws GitAPIException, IOException {
+ String configName = "test.config";
+ Config cfg = new Config();
+ cfg.setString("s1", null, "k1", "v1");
+ cfg.setString("s2", "ss", "k2", "v2");
+ PushOneCommit push =
+ new PushOneCommit(db, admin.getIdent(), "Create Project Level Config",
+ configName, cfg.toText());
+ push.to(git, GitRepositoryManager.REF_CONFIG);
+
+ ProjectState state = projectCache.get(new Project.NameKey(project));
+ assertEquals(cfg.toText(), state.getConfig(configName).get().toText());
+ }
+
+ @Test
+ public void nonExistingConfig() {
+ ProjectState state = projectCache.get(new Project.NameKey(project));
+ assertEquals("", state.getConfig("test.config").get().toText());
+ }
+
+ @Test
+ public void withInheritance() throws GitAPIException, IOException {
+ String configName = "test.config";
+
+ Config parentCfg = new Config();
+ parentCfg.setString("s1", null, "k1", "parentValue1");
+ parentCfg.setString("s1", null, "k2", "parentValue2");
+ parentCfg.setString("s2", "ss", "k3", "parentValue3");
+ parentCfg.setString("s2", "ss", "k4", "parentValue4");
+
+ Git parentGit =
+ cloneProject(sshSession.getUrl() + "/" + allProjects.get().get(), false);
+ fetch(parentGit, GitRepositoryManager.REF_CONFIG + ":refs/heads/config");
+ checkout(parentGit, "refs/heads/config");
+ PushOneCommit push =
+ new PushOneCommit(db, admin.getIdent(), "Create Project Level Config",
+ configName, parentCfg.toText());
+ push.to(parentGit, GitRepositoryManager.REF_CONFIG);
+
+ Config cfg = new Config();
+ cfg.setString("s1", null, "k1", "childValue1");
+ cfg.setString("s2", "ss", "k3", "childValue2");
+ push = new PushOneCommit(db, admin.getIdent(), "Create Project Level Config",
+ configName, cfg.toText());
+ push.to(git, GitRepositoryManager.REF_CONFIG);
+
+ ProjectState state = projectCache.get(new Project.NameKey(project));
+
+ Config expectedCfg = new Config();
+ expectedCfg.setString("s1", null, "k1", "childValue1");
+ expectedCfg.setString("s1", null, "k2", "parentValue2");
+ expectedCfg.setString("s2", "ss", "k3", "childValue2");
+ expectedCfg.setString("s2", "ss", "k4", "parentValue4");
+
+ assertEquals(expectedCfg.toText(), state.getConfig(configName)
+ .getWithInheritance().toText());
+
+ assertEquals(cfg.toText(), state.getConfig(configName).get().toText());
+ }
+}
diff --git a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/DefaultCacheFactory.java b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/DefaultCacheFactory.java
index 1c850d1..4478cc9 100644
--- a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/DefaultCacheFactory.java
+++ b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/DefaultCacheFactory.java
@@ -27,7 +27,6 @@
import com.google.gerrit.server.cache.PersistentCacheFactory;
import com.google.gerrit.server.cache.h2.H2CacheImpl.ValueHolder;
import com.google.gerrit.server.config.ConfigUtil;
-import com.google.gerrit.server.config.FactoryModule;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.inject.Inject;
@@ -39,13 +38,7 @@
public static class Module extends LifecycleModule {
@Override
protected void configure() {
- install(new FactoryModule() {
- @Override
- protected void configure() {
- factory(ForwardingRemovalListener.Factory.class);
- }
- });
-
+ factory(ForwardingRemovalListener.Factory.class);
bind(DefaultCacheFactory.class);
bind(MemoryCacheFactory.class).to(DefaultCacheFactory.class);
bind(PersistentCacheFactory.class).to(H2CacheFactory.class);
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java
index ee6cc95..dd6c22b 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java
@@ -28,6 +28,7 @@
protected Set<String> ownerOf;
protected boolean isConfigVisible;
protected boolean canUpload;
+ protected boolean canChangeParent;
protected LabelTypes labelTypes;
protected Map<String, String> capabilities;
@@ -107,6 +108,14 @@
this.canUpload = canUpload;
}
+ public boolean canChangeParent() {
+ return canChangeParent;
+ }
+
+ public void setCanChangeParent(boolean canChangeParent) {
+ this.canChangeParent = canChangeParent;
+ }
+
public LabelTypes getLabelTypes() {
return labelTypes;
}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAdminService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAdminService.java
index 44f60861..652acac 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAdminService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAdminService.java
@@ -33,11 +33,11 @@
@Audit
@SignInRequired
void changeProjectAccess(Project.NameKey projectName, String baseRevision,
- String message, List<AccessSection> sections,
+ String message, List<AccessSection> sections, Project.NameKey parentProjectName,
AsyncCallback<ProjectAccess> callback);
@SignInRequired
void reviewProjectAccess(Project.NameKey projectName, String baseRevision,
- String message, List<AccessSection> sections,
+ String message, List<AccessSection> sections, Project.NameKey parentProjectName,
AsyncCallback<Change.Id> callback);
}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ReviewerInfo.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ReviewerInfo.java
index 063f13b..28a8340 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ReviewerInfo.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ReviewerInfo.java
@@ -51,7 +51,7 @@
if (accountInfo.getPreferredEmail() != null) {
return accountInfo.getPreferredEmail();
}
- return accountInfo.getFullName().toString();
+ return accountInfo.getFullName();
}
return groupReference.getName();
}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/errors/UpdateParentFailedException.java b/gerrit-common/src/main/java/com/google/gerrit/common/errors/UpdateParentFailedException.java
new file mode 100644
index 0000000..320d055
--- /dev/null
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/errors/UpdateParentFailedException.java
@@ -0,0 +1,27 @@
+// 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.
+
+package com.google.gerrit.common.errors;
+
+/** Error indicating that updating a parent project failed. */
+public class UpdateParentFailedException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public static final String MESSAGE = "Update Parent Project Failed: ";
+
+ public UpdateParentFailedException(final String message,
+ final Throwable why) {
+ super(MESSAGE + ": " + message, why);
+ }
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
index 969c23d..5f106fc 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
@@ -60,15 +60,15 @@
public String onBehalfOf;
public static enum DraftHandling {
- DELETE, PUBLISH, KEEP;
+ DELETE, PUBLISH, KEEP
}
public static enum NotifyHandling {
- NONE, OWNER, OWNER_REVIEWERS, ALL;
+ NONE, OWNER, OWNER_REVIEWERS, ALL
}
public static enum Side {
- PARENT, REVISION;
+ PARENT, REVISION
}
public static class Comment {
diff --git a/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritDebugLauncher.java b/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritDebugLauncher.java
index a2a770e..5770f58 100644
--- a/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritDebugLauncher.java
+++ b/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritDebugLauncher.java
@@ -368,7 +368,7 @@
AbstractConnector connector = getConnector();
if (bindAddress != null) {
- connector.setHost(bindAddress.toString());
+ connector.setHost(bindAddress);
}
connector.setPort(port);
diff --git a/gerrit-gwtui/BUCK b/gerrit-gwtui/BUCK
index 1ae823e..0c873ee 100644
--- a/gerrit-gwtui/BUCK
+++ b/gerrit-gwtui/BUCK
@@ -1,4 +1,5 @@
include_defs('//gerrit-gwtui/gwt.defs')
+include_defs('//tools/gwt-constants.defs')
genrule(
name = 'ui_optdbg',
@@ -25,13 +26,7 @@
gwt_application(
name = 'ui_opt',
module_target = MODULE,
- compiler_opts = [
- '-strict',
- '-style', 'OBF',
- '-optimize', '9',
- '-XdisableClassMetadata',
- '-XdisableCastChecking',
- ],
+ compiler_opts = GWT_COMPILER_OPTS,
deps = APP_DEPS,
)
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.java
index cbb5513..21da8ce 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.java
@@ -34,4 +34,6 @@
String pluginFailed(String scriptPath);
String cannotDownloadPlugin(String scriptPath);
+
+ String parentUpdateFailed(String message);
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.properties
index 5ab8b3b..8196e98 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.properties
@@ -15,3 +15,5 @@
pluginFailed = Plugin JavaScript {0} failed to load
cannotDownloadPlugin = Cannot download JavaScript plugin from: {0}.
+
+parentUpdateFailed = Setting parent project failed: {0}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
index a526c59..4c69300 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
@@ -22,13 +22,13 @@
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import java.util.TreeSet;
public class SearchSuggestOracle extends HighlightSuggestOracle {
private static final List<ParamSuggester> paramSuggester = Arrays.asList(
- new ParamSuggester("project:", new ProjectNameSuggestOracle()),
+ new ParamSuggester(Arrays.asList("project:", "parentproject:"),
+ new ProjectNameSuggestOracle()),
new ParamSuggester(Arrays.asList("owner:", "reviewer:"),
new AccountSuggestOracle() {
@Override
@@ -82,6 +82,7 @@
suggestions.add("comment:");
suggestions.add("conflicts:");
suggestions.add("project:");
+ suggestions.add("parentproject:");
suggestions.add("branch:");
suggestions.add("topic:");
suggestions.add("ref:");
@@ -207,11 +208,6 @@
private final List<String> operators;
private final SuggestOracle parameterSuggestionOracle;
- ParamSuggester(final String operator,
- final SuggestOracle parameterSuggestionOracle) {
- this(Collections.singletonList(operator), parameterSuggestionOracle);
- }
-
ParamSuggester(final List<String> operators,
final SuggestOracle parameterSuggestionOracle) {
this.operators = operators;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.java
index 49a9aa4..567f14c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.java
@@ -18,6 +18,7 @@
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.GitwebLink;
import com.google.gerrit.client.ui.Hyperlink;
+import com.google.gerrit.client.ui.ParentProjectBox;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.ProjectAccess;
import com.google.gerrit.reviewdb.client.Branch;
@@ -56,6 +57,10 @@
Hyperlink parentProject;
@UiField
+ @Editor.Ignore
+ ParentProjectBox parentProjectBox;
+
+ @UiField
DivElement history;
@UiField
@@ -106,6 +111,11 @@
parentProject.setText(parent.get());
parentProject.setTargetHistoryToken( //
Dispatcher.toProjectAdmin(parent, ProjectScreen.ACCESS));
+
+ parentProjectBox.setVisible(editing && value.canChangeParent());
+ parentProjectBox.setProject(value.getProjectName());
+ parentProjectBox.setParentProject(value.getInheritsFrom());
+ parentProject.setVisible(!parentProjectBox.isVisible());
} else {
inheritsFrom.getStyle().setDisplay(Display.NONE);
}
@@ -135,6 +145,7 @@
}
}
value.setLocal(keep);
+ value.setInheritsFrom(parentProjectBox.getParentProjectName());
}
@Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.ui.xml
index 4942b83..120824b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.ui.xml
@@ -56,6 +56,9 @@
<div ui:field='inheritsFrom' class='{style.inheritsFrom}'>
<span class='{style.parentTitle}'><ui:msg>Rights Inherit From:</ui:msg></span>
<q:Hyperlink ui:field='parentProject' styleName='{style.parentLink}'/>
+ <q:ParentProjectBox
+ ui:field='parentProjectBox'
+ visible='false'/>
</div>
<div ui:field='history' class='{style.history}'>
<span class='{style.historyTitle}'><ui:msg>History:</ui:msg></span>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java
index ef7f560..c76bba9 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java
@@ -17,6 +17,7 @@
import static com.google.gerrit.common.ProjectAccessUtil.mergeSections;
import static com.google.gerrit.common.ProjectAccessUtil.removeEmptyPermissionsAndSections;
+import com.google.gerrit.client.ErrorDialog;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.config.CapabilityInfo;
import com.google.gerrit.client.config.ConfigServerApi;
@@ -28,6 +29,7 @@
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.ProjectAccess;
+import com.google.gerrit.common.errors.UpdateParentFailedException;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.core.client.GWT;
@@ -45,6 +47,7 @@
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwtexpui.globalkey.client.NpTextArea;
+import com.google.gwtjsonrpc.client.RemoteJsonException;
import java.util.Collections;
import java.util.HashMap;
@@ -205,6 +208,7 @@
access.getRevision(), //
message, //
access.getLocal(), //
+ access.getInheritsFrom(), //
new GerritCallback<ProjectAccess>() {
@Override
public void onSuccess(ProjectAccess newAccess) {
@@ -250,7 +254,15 @@
public void onFailure(Throwable caught) {
error.clear();
enable(true);
- super.onFailure(caught);
+ if (caught instanceof RemoteJsonException
+ && caught.getMessage().startsWith(
+ UpdateParentFailedException.MESSAGE)) {
+ new ErrorDialog(Gerrit.M.parentUpdateFailed(caught.getMessage()
+ .substring(UpdateParentFailedException.MESSAGE.length() + 1)))
+ .center();
+ } else {
+ super.onFailure(caught);
+ }
}
});
}
@@ -275,6 +287,7 @@
access.getRevision(), //
message, //
access.getLocal(), //
+ access.getInheritsFrom(), //
new GerritCallback<Change.Id>() {
@Override
public void onSuccess(Change.Id changeId) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java
index 7b00821..f22fa3f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java
@@ -93,6 +93,21 @@
e.onkeypress = stopPropagation;
return e;
},
+ select: function(a,s) {
+ var e = doc.createElement('select');
+ for (var i = 0; i < a.length; i++) {
+ var o = doc.createElement('option');
+ if (i==s) {
+ o.setAttributeNode(doc.createAttribute("selected"));
+ }
+ o.appendChild(doc.createTextNode(a[i]));
+ e.appendChild(o);
+ }
+ return e;
+ },
+ selected: function(e) {
+ return e.options[e.selectedIndex].text;
+ },
popup: function(e){this._p=@com.google.gerrit.client.api.PopupHelper::popup(Lcom/google/gerrit/client/api/ActionContext;Lcom/google/gwt/dom/client/Element;)(this,e)},
hide: function() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/DefaultActions.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/DefaultActions.java
index fcd6056..53a3784 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/DefaultActions.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/DefaultActions.java
@@ -22,6 +22,7 @@
import com.google.gerrit.client.rpc.RestApi;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
@@ -44,7 +45,8 @@
invoke(action, api, cb);
}
- static void invokeProjectAction(ActionInfo action, RestApi api) {
+ static void invokeProjectAction(final Project.NameKey project,
+ ActionInfo action, RestApi api) {
AsyncCallback<JavaScriptObject> cb = new GerritCallback<JavaScriptObject>() {
@Override
public void onSuccess(JavaScriptObject msg) {
@@ -54,7 +56,7 @@
Window.alert(str.asString());
}
}
- Gerrit.display(PageLinks.ADMIN_PROJECTS);
+ Gerrit.display(PageLinks.toProject(project));
}
};
invoke(action, api, cb);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ProjectGlue.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ProjectGlue.java
index b95f4e0..bce691c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ProjectGlue.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ProjectGlue.java
@@ -35,7 +35,7 @@
c.button(button);
ApiGlue.invoke(f, c);
} else {
- DefaultActions.invokeProjectAction(action, api);
+ DefaultActions.invokeProjectAction(project, action, api);
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SidePanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SidePanel.java
index b0431e9..52bb003 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SidePanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SidePanel.java
@@ -114,7 +114,7 @@
Label gutter = wrapper.gutter;
final double height = cm.heightAtLine(line, "local");
final double scrollbarHeight = cmB.getScrollbarV().getClientHeight();
- double top = height / (double) cmB.getSizer().getClientHeight() *
+ double top = height / cmB.getSizer().getClientHeight() *
scrollbarHeight +
cmB.getScrollbarV().getAbsoluteTop();
if (top == 0) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
index 62dbf1c7..ebae86a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
@@ -110,6 +110,15 @@
});
}
+ public static void getChildren(Project.NameKey name, boolean recursive,
+ AsyncCallback<JsArray<ProjectInfo>> cb) {
+ RestApi view = project(name).view("children");
+ if (recursive) {
+ view.addParameterTrue("recursive");
+ }
+ view.get(cb);
+ }
+
public static void getDescription(Project.NameKey name,
AsyncCallback<NativeString> cb) {
project(name).view("description").get(cb);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java
index eeb45d4..5ae3091 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java
@@ -124,29 +124,31 @@
}
} else if (200 <= status && status < 300) {
- if (!isJsonBody(res)) {
+ T data;
+ if (isTextBody(res)) {
+ data = NativeString.wrap(res.getText()).cast();
+ } else if (isJsonBody(res)) {
+ try {
+ // javac generics bug
+ data = RestApi.<T>cast(parseJson(res));
+ } catch (JSONException e) {
+ if (!background) {
+ RpcStatus.INSTANCE.onRpcComplete();
+ }
+ cb.onFailure(new StatusCodeException(SC_BAD_RESPONSE,
+ "Invalid JSON: " + e.getMessage()));
+ return;
+ }
+ } else {
if (!background) {
RpcStatus.INSTANCE.onRpcComplete();
}
cb.onFailure(new StatusCodeException(SC_BAD_RESPONSE, "Expected "
- + JSON_TYPE + "; received Content-Type: "
+ + JSON_TYPE + " or " + TEXT_TYPE + "; received Content-Type: "
+ res.getHeader("Content-Type")));
return;
}
- T data;
- try {
- // javac generics bug
- data = RestApi.<T>cast(parseJson(res));
- } catch (JSONException e) {
- if (!background) {
- RpcStatus.INSTANCE.onRpcComplete();
- }
- cb.onFailure(new StatusCodeException(SC_BAD_RESPONSE,
- "Invalid JSON: " + e.getMessage()));
- return;
- }
-
cb.onSuccess(data);
if (!background) {
RpcStatus.INSTANCE.onRpcComplete();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ParentProjectBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ParentProjectBox.java
new file mode 100644
index 0000000..a03cb34
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ParentProjectBox.java
@@ -0,0 +1,101 @@
+// 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.
+
+package com.google.gerrit.client.ui;
+
+import com.google.gerrit.client.projects.ProjectApi;
+import com.google.gerrit.client.projects.ProjectInfo;
+import com.google.gerrit.client.rpc.Natives;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gwt.core.client.JsArray;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.SuggestBox;
+import com.google.gwtexpui.globalkey.client.NpTextBox;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class ParentProjectBox extends Composite {
+ private final NpTextBox textBox;
+ private final SuggestBox suggestBox;
+ private final ParentProjectNameSuggestOracle suggestOracle;
+
+ public ParentProjectBox() {
+ textBox = new NpTextBox();
+ suggestOracle = new ParentProjectNameSuggestOracle();
+ suggestBox = new SuggestBox(suggestOracle, textBox);
+ initWidget(suggestBox);
+ }
+
+ public void setVisibleLength(int len) {
+ textBox.setVisibleLength(len);
+ }
+
+ public void setProject(final Project.NameKey project) {
+ suggestOracle.setProject(project);
+ }
+
+ public void setParentProject(final Project.NameKey parent) {
+ suggestBox.setText(parent != null ? parent.get() : "");
+ }
+
+ public Project.NameKey getParentProjectName() {
+ final String projectName = suggestBox.getText().trim();
+ if (projectName.isEmpty()) {
+ return null;
+ }
+ return new Project.NameKey(projectName);
+ }
+
+ private static class ParentProjectNameSuggestOracle extends ProjectNameSuggestOracle {
+ private Set<String> exclude = new HashSet<String>();
+
+ public void setProject(Project.NameKey project) {
+ exclude.clear();
+ exclude.add(project.get());
+ ProjectApi.getChildren(project, true, new AsyncCallback<JsArray<ProjectInfo>>() {
+ @Override
+ public void onSuccess(JsArray<ProjectInfo> result) {
+ for (ProjectInfo p : Natives.asList(result)) {
+ exclude.add(p.name());
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ }
+ });
+ }
+
+ @Override
+ public void _onRequestSuggestions(Request req, final Callback callback) {
+ super._onRequestSuggestions(req, new Callback() {
+ public void onSuggestionsReady(Request request, Response response) {
+ if (exclude.size() > 0) {
+ Set<Suggestion> filteredSuggestions =
+ new HashSet<Suggestion>(response.getSuggestions());
+ for (Suggestion s : response.getSuggestions()) {
+ if (exclude.contains(s.getReplacementString())) {
+ filteredSuggestions.remove(s);
+ }
+ }
+ response.setSuggestions(filteredSuggestions);
+ }
+ callback.onSuggestionsReady(request, response);
+ }
+ });
+ }
+ }
+}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
index 5593baf..3443968 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
@@ -31,7 +31,6 @@
import com.google.gerrit.server.RemotePeer;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.config.CanonicalWebUrl;
-import com.google.gerrit.server.config.FactoryModule;
import com.google.gerrit.server.config.GerritRequestModule;
import com.google.gerrit.server.contact.ContactStore;
import com.google.gerrit.server.contact.ContactStoreProvider;
@@ -46,7 +45,7 @@
import java.net.SocketAddress;
-public class WebModule extends FactoryModule {
+public class WebModule extends LifecycleModule {
private final AuthConfig authConfig;
private final UrlModule.UrlConfig urlConfig;
private final boolean wantSSL;
@@ -132,11 +131,6 @@
bind(SocketAddress.class).annotatedWith(RemotePeer.class).toProvider(
HttpRemotePeerProvider.class).in(RequestScoped.class);
- install(new LifecycleModule() {
- @Override
- protected void configure() {
- listener().toInstance(registerInParentInjectors());
- }
- });
+ listener().toInstance(registerInParentInjectors());
}
}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectAccess.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectAccess.java
index 0dd3d16..57be31e 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectAccess.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectAccess.java
@@ -19,12 +19,15 @@
import com.google.gerrit.common.data.ProjectAccess;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.account.GroupBackend;
+import com.google.gerrit.server.config.AllProjectsNameProvider;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.server.project.SetParent;
import com.google.inject.Inject;
+import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.errors.ConfigInvalidException;
@@ -35,9 +38,11 @@
class ChangeProjectAccess extends ProjectAccessHandler<ProjectAccess> {
interface Factory {
- ChangeProjectAccess create(@Assisted Project.NameKey projectName,
+ ChangeProjectAccess create(
+ @Assisted("projectName") Project.NameKey projectName,
@Nullable @Assisted ObjectId base,
@Assisted List<AccessSection> sectionList,
+ @Nullable @Assisted("parentProjectName") Project.NameKey parentProjectName,
@Nullable @Assisted String message);
}
@@ -45,17 +50,21 @@
private final ProjectCache projectCache;
@Inject
- ChangeProjectAccess(final ProjectAccessFactory.Factory projectAccessFactory,
- final ProjectControl.Factory projectControlFactory,
- final ProjectCache projectCache, final GroupBackend groupBackend,
- final MetaDataUpdate.User metaDataUpdateFactory,
+ ChangeProjectAccess(ProjectAccessFactory.Factory projectAccessFactory,
+ ProjectControl.Factory projectControlFactory,
+ ProjectCache projectCache, GroupBackend groupBackend,
+ MetaDataUpdate.User metaDataUpdateFactory,
+ AllProjectsNameProvider allProjects,
+ Provider<SetParent> setParent,
- @Assisted final Project.NameKey projectName,
- @Nullable @Assisted final ObjectId base,
+ @Assisted("projectName") Project.NameKey projectName,
+ @Nullable @Assisted ObjectId base,
@Assisted List<AccessSection> sectionList,
+ @Nullable @Assisted("parentProjectName") Project.NameKey parentProjectName,
@Nullable @Assisted String message) {
super(projectControlFactory, groupBackend, metaDataUpdateFactory,
- projectName, base, sectionList, message, true);
+ allProjects, setParent, projectName, base, sectionList,
+ parentProjectName, message, true);
this.projectAccessFactory = projectAccessFactory;
this.projectCache = projectCache;
}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java
index 2c5681b..6e7150d 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java
@@ -203,6 +203,8 @@
detail.setOwnerOf(ownerOf);
detail.setCanUpload(pc.isOwner()
|| (metaConfigControl.isVisible() && metaConfigControl.canUpload()));
+ detail.setCanChangeParent(pc.getCurrentUser().getCapabilities()
+ .canAdministrateServer());
detail.setConfigVisible(pc.isOwner() || metaConfigControl.isVisible());
detail.setLabelTypes(pc.getLabelTypes());
return detail;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessHandler.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessHandler.java
index 0a50a38..971c4b3 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessHandler.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessHandler.java
@@ -22,16 +22,23 @@
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.common.errors.InvalidNameException;
import com.google.gerrit.common.errors.NoSuchGroupException;
+import com.google.gerrit.common.errors.UpdateParentFailedException;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.httpd.rpc.Handler;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.GroupBackends;
+import com.google.gerrit.server.config.AllProjectsNameProvider;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.project.RefControl;
+import com.google.gerrit.server.project.SetParent;
import com.google.gwtorm.server.OrmException;
+import com.google.inject.Provider;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
@@ -47,27 +54,32 @@
private final ProjectControl.Factory projectControlFactory;
protected final GroupBackend groupBackend;
private final MetaDataUpdate.User metaDataUpdateFactory;
+ private final AllProjectsNameProvider allProjects;
+ private final Provider<SetParent> setParent;
protected final Project.NameKey projectName;
protected final ObjectId base;
private List<AccessSection> sectionList;
+ private final Project.NameKey parentProjectName;
protected String message;
private boolean checkIfOwner;
- protected ProjectAccessHandler(
- final ProjectControl.Factory projectControlFactory,
- final GroupBackend groupBackend,
- final MetaDataUpdate.User metaDataUpdateFactory,
- final Project.NameKey projectName, final ObjectId base,
- final List<AccessSection> sectionList, final String message,
- final boolean checkIfOwner) {
+ protected ProjectAccessHandler(ProjectControl.Factory projectControlFactory,
+ GroupBackend groupBackend, MetaDataUpdate.User metaDataUpdateFactory,
+ AllProjectsNameProvider allProjects, Provider<SetParent> setParent,
+ Project.NameKey projectName, ObjectId base,
+ List<AccessSection> sectionList, Project.NameKey parentProjectName,
+ String message, boolean checkIfOwner) {
this.projectControlFactory = projectControlFactory;
this.groupBackend = groupBackend;
this.metaDataUpdateFactory = metaDataUpdateFactory;
+ this.allProjects = allProjects;
+ this.setParent = setParent;
this.projectName = projectName;
this.base = base;
this.sectionList = sectionList;
+ this.parentProjectName = parentProjectName;
this.message = message;
this.checkIfOwner = checkIfOwner;
}
@@ -75,7 +87,7 @@
@Override
public final T call() throws NoSuchProjectException, IOException,
ConfigInvalidException, InvalidNameException, NoSuchGroupException,
- OrmException {
+ OrmException, UpdateParentFailedException {
final ProjectControl projectControl =
projectControlFactory.controlFor(projectName);
@@ -120,6 +132,20 @@
}
}
+ if (!config.getProject().getNameKey().equals(allProjects.get()) &&
+ !config.getProject().getParent(allProjects.get()).equals(parentProjectName)) {
+ try {
+ setParent.get().validateParentUpdate(projectControl, parentProjectName.get());
+ } catch (AuthException e) {
+ throw new UpdateParentFailedException(e.getMessage(), e);
+ } catch (ResourceConflictException e) {
+ throw new UpdateParentFailedException(e.getMessage(), e);
+ } catch (UnprocessableEntityException e) {
+ throw new UpdateParentFailedException(e.getMessage(), e);
+ }
+ config.getProject().setParentName(parentProjectName);
+ }
+
if (message != null && !message.isEmpty()) {
if (!message.endsWith("\n")) {
message += "\n";
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAdminServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAdminServiceImpl.java
index 66ba75c..c378701 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAdminServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAdminServiceImpl.java
@@ -56,14 +56,16 @@
@Override
public void changeProjectAccess(Project.NameKey projectName,
String baseRevision, String msg, List<AccessSection> sections,
- AsyncCallback<ProjectAccess> cb) {
- changeProjectAccessFactory.create(projectName, getBase(baseRevision), sections, msg).to(cb);
+ Project.NameKey parentProjectName, AsyncCallback<ProjectAccess> cb) {
+ changeProjectAccessFactory.create(projectName, getBase(baseRevision),
+ sections, parentProjectName, msg).to(cb);
}
@Override
public void reviewProjectAccess(Project.NameKey projectName,
String baseRevision, String msg, List<AccessSection> sections,
- AsyncCallback<Change.Id> cb) {
- reviewProjectAccessFactory.create(projectName, getBase(baseRevision), sections, msg).to(cb);
+ Project.NameKey parentProjectName, AsyncCallback<Change.Id> cb) {
+ reviewProjectAccessFactory.create(projectName, getBase(baseRevision),
+ sections, parentProjectName, msg).to(cb);
}
}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java
index 27a02d9..3f4030d 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java
@@ -31,6 +31,7 @@
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.change.ChangeResource;
import com.google.gerrit.server.change.PostReviewers;
+import com.google.gerrit.server.config.AllProjectsNameProvider;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
@@ -39,6 +40,7 @@
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.server.project.SetParent;
import com.google.gerrit.server.util.TimeUtil;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
@@ -60,9 +62,11 @@
LoggerFactory.getLogger(ReviewProjectAccess.class);
interface Factory {
- ReviewProjectAccess create(@Assisted Project.NameKey projectName,
+ ReviewProjectAccess create(
+ @Assisted("projectName") Project.NameKey projectName,
@Nullable @Assisted ObjectId base,
@Assisted List<AccessSection> sectionList,
+ @Nullable @Assisted("parentProjectName") Project.NameKey parentProjectName,
@Nullable @Assisted String message);
}
@@ -84,13 +88,17 @@
ChangeControl.GenericFactory changeFactory,
ChangeIndexer indexer, ChangeHooks hooks,
CreateChangeSender.Factory createChangeSenderFactory,
+ AllProjectsNameProvider allProjects,
+ Provider<SetParent> setParent,
- @Assisted Project.NameKey projectName,
+ @Assisted("projectName") Project.NameKey projectName,
@Nullable @Assisted ObjectId base,
@Assisted List<AccessSection> sectionList,
+ @Nullable @Assisted("parentProjectName") Project.NameKey parentProjectName,
@Nullable @Assisted String message) {
super(projectControlFactory, groupBackend, metaDataUpdateFactory,
- projectName, base, sectionList, message, false);
+ allProjects, setParent, projectName, base, sectionList,
+ parentProjectName, message, false);
this.db = db;
this.user = user;
this.patchSetInfoFactory = patchSetInfoFactory;
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java
index ef96374..583e54f 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java
@@ -16,7 +16,6 @@
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.lifecycle.LifecycleModule;
-import com.google.gerrit.server.config.FactoryModule;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.index.ChangeSchemas;
import com.google.gerrit.server.index.IndexCollection;
@@ -45,12 +44,7 @@
@Override
protected void configure() {
- install(new FactoryModule() {
- @Override
- public void configure() {
- factory(LuceneChangeIndex.Factory.class);
- }
- });
+ factory(LuceneChangeIndex.Factory.class);
install(new IndexModule(threads));
if (singleVersion == null && base == null) {
install(new MultiVersionModule());
@@ -62,12 +56,7 @@
private class MultiVersionModule extends LifecycleModule {
@Override
public void configure() {
- install(new FactoryModule() {
- @Override
- public void configure() {
- factory(OnlineReindexer.Factory.class);
- }
- });
+ factory(OnlineReindexer.Factory.class);
listener().to(LuceneVersionManager.class);
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
index 68e0f6a..3cfd1bb 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
@@ -56,7 +56,7 @@
@Option(name = "--list-plugins", usage = "List available plugins")
private boolean listPlugins;
- @Option(name = "--install-plugin", usage = "Install given plugin without asking", multiValued = true)
+ @Option(name = "--install-plugin", usage = "Install given plugin without asking")
private List<String> installPlugins;
@Inject
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/PrologShell.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/PrologShell.java
index 803b702..4c66f0b 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/PrologShell.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/PrologShell.java
@@ -32,7 +32,7 @@
import java.util.List;
public class PrologShell extends AbstractProgram {
- @Option(name = "-s", multiValued = true, metaVar = "FILE.pl", usage = "file to load")
+ @Option(name = "-s", metaVar = "FILE.pl", usage = "file to load")
private List<String> fileName = new ArrayList<String>();
@Override
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/HiddenErrorHandler.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/HiddenErrorHandler.java
index 9fd8929..5ca53df 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/HiddenErrorHandler.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/HiddenErrorHandler.java
@@ -18,9 +18,9 @@
import com.google.common.base.Strings;
import com.google.gwtexpui.server.CacheHeaders;
-import org.eclipse.jetty.http.HttpHeaders;
+import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
-import org.eclipse.jetty.server.AbstractHttpConnection;
+import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.slf4j.Logger;
@@ -37,8 +37,8 @@
public void handle(String target, Request baseRequest,
HttpServletRequest req, HttpServletResponse res) throws IOException {
- AbstractHttpConnection conn = AbstractHttpConnection.getCurrentConnection();
- conn.getRequest().setHandled(true);
+ HttpConnection conn = HttpConnection.getCurrentConnection();
+ baseRequest.setHandled(true);
try {
log(req);
} finally {
@@ -46,10 +46,11 @@
}
}
- private void reply(AbstractHttpConnection conn, HttpServletResponse res)
+ private void reply(HttpConnection conn, HttpServletResponse res)
throws IOException {
byte[] msg = message(conn);
- res.setHeader(HttpHeaders.CONTENT_TYPE, "text/plain; charset=ISO-8859-1");
+ res.setHeader(HttpHeader.CONTENT_TYPE.asString(),
+ "text/plain; charset=ISO-8859-1");
res.setContentLength(msg.length);
try {
CacheHeaders.setNotCacheable(res);
@@ -63,10 +64,11 @@
}
}
- private static byte[] message(AbstractHttpConnection conn) {
- String msg = conn.getResponse().getReason();
+ private static byte[] message(HttpConnection conn) {
+ String msg = conn.getHttpChannel().getResponse().getReason();
if (msg == null) {
- msg = HttpStatus.getMessage(conn.getResponse().getStatus());
+ msg = HttpStatus.getMessage(conn.getHttpChannel()
+ .getResponse().getStatus());
}
return msg.getBytes(Charsets.ISO_8859_1);
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyModule.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyModule.java
index 1ae9355..b563349 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyModule.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyModule.java
@@ -15,9 +15,8 @@
package com.google.gerrit.pgm.http.jetty;
import com.google.gerrit.lifecycle.LifecycleModule;
-import com.google.inject.AbstractModule;
-public class JettyModule extends AbstractModule {
+public class JettyModule extends LifecycleModule {
private final JettyEnv env;
public JettyModule(final JettyEnv env) {
@@ -28,11 +27,6 @@
protected void configure() {
bind(JettyEnv.class).toInstance(env);
bind(JettyServer.class);
- install(new LifecycleModule() {
- @Override
- protected void configure() {
- listener().to(JettyServer.Lifecycle.class);
- }
- });
+ listener().to(JettyServer.Lifecycle.class);
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
index e1d1281b..615e11e 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
@@ -32,21 +32,24 @@
import com.google.inject.servlet.GuiceFilter;
import com.google.inject.servlet.GuiceServletContextListener;
-import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.ForwardedRequestCustomizer;
import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.RequestLogHandler;
-import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.server.session.SessionHandler;
-import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
@@ -131,9 +134,8 @@
throws MalformedURLException, IOException {
this.site = site;
- httpd = new Server();
- httpd.setConnectors(listen(cfg));
- httpd.setThreadPool(threadPool(cfg));
+ httpd = new Server(threadPool(cfg));
+ httpd.setConnectors(listen(httpd, cfg));
Handler app = makeContext(env, cfg);
if (cfg.getBoolean("httpd", "requestLog", !reverseProxy)) {
@@ -142,15 +144,12 @@
handler.setHandler(app);
app = handler;
}
- httpd.setHandler(app);
+ httpd.setHandler(app);
httpd.setStopAtShutdown(false);
- httpd.setSendDateHeader(true);
- httpd.setSendServerVersion(false);
- httpd.setGracefulShutdown((int) MILLISECONDS.convert(1, SECONDS));
}
- private Connector[] listen(final Config cfg) {
+ private Connector[] listen(Server server, Config cfg) {
// OpenID and certain web-based single-sign-on products can cause
// some very long headers, especially in the Referer header. We
// need to use a larger default header size to ensure we have
@@ -168,7 +167,8 @@
for (int idx = 0; idx < listenUrls.length; idx++) {
final URI u = listenUrls[idx];
final int defaultPort;
- final SelectChannelConnector c;
+ final ServerConnector c;
+ HttpConfiguration config = defaultConfig(requestHeaderSize);
if (AuthType.CLIENT_SSL_CERT_LDAP.equals(authType) && ! "https".equals(u.getScheme())) {
throw new IllegalArgumentException("Protocol '" + u.getScheme()
@@ -179,7 +179,9 @@
if ("http".equals(u.getScheme())) {
defaultPort = 80;
- c = new SelectChannelConnector();
+ c = new ServerConnector(server, null, null, null, 0, acceptors,
+ new HttpConnectionFactory(config));
+
} else if ("https".equals(u.getScheme())) {
SslContextFactory ssl = new SslContextFactory();
final File keystore = getFile(cfg, "sslkeystore", "etc/keystore");
@@ -188,7 +190,7 @@
password = "gerrit";
}
ssl.setKeyStorePath(keystore.getAbsolutePath());
- ssl.setTrustStore(keystore.getAbsolutePath());
+ ssl.setTrustStorePath(keystore.getAbsolutePath());
ssl.setKeyStorePassword(password);
ssl.setTrustStorePassword(password);
@@ -203,24 +205,27 @@
}
defaultPort = 443;
- c = new SslSelectChannelConnector(ssl);
+
+ config.addCustomizer(new SecureRequestCustomizer());
+ c = new ServerConnector(server,
+ null, null, null, 0, acceptors,
+ new SslConnectionFactory(ssl, "http/1.1"),
+ new HttpConnectionFactory(config));
} else if ("proxy-http".equals(u.getScheme())) {
defaultPort = 8080;
- c = new SelectChannelConnector();
- c.setForwarded(true);
+ config.addCustomizer(new ForwardedRequestCustomizer());
+ c = new ServerConnector(server,
+ null, null, null, 0, acceptors,
+ new HttpConnectionFactory(config));
} else if ("proxy-https".equals(u.getScheme())) {
defaultPort = 8080;
- c = new SelectChannelConnector() {
- @Override
- public void customize(EndPoint endpoint, Request request)
- throws IOException {
- request.setScheme("https");
- super.customize(endpoint, request);
- }
- };
- c.setForwarded(true);
+ config.addCustomizer(new ForwardedRequestCustomizer());
+ config.addCustomizer(new SecureRequestCustomizer());
+ c = new ServerConnector(server,
+ null, null, null, 0, acceptors,
+ new HttpConnectionFactory(config));
} else {
throw new IllegalArgumentException("Protocol '" + u.getScheme() + "' "
@@ -249,16 +254,20 @@
throw new IllegalArgumentException("Invalid httpd.listenurl " + u, e);
}
- c.setRequestHeaderSize(requestHeaderSize);
- c.setAcceptors(acceptors);
c.setReuseAddress(reuseAddress);
- c.setStatsOn(false);
-
connectors[idx] = c;
}
return connectors;
}
+ private HttpConfiguration defaultConfig(int requestHeaderSize) {
+ HttpConfiguration config = new HttpConfiguration();
+ config.setRequestHeaderSize(requestHeaderSize);
+ config.setSendServerVersion(false);
+ config.setSendDateHeader(true);
+ return config;
+ }
+
static boolean isReverseProxied(final URI[] listenUrls) {
for (URI u : listenUrls) {
if ("http".equals(u.getScheme()) || "https".equals(u.getScheme())) {
@@ -295,11 +304,20 @@
}
private ThreadPool threadPool(Config cfg) {
- final QueuedThreadPool pool = new QueuedThreadPool();
+ int maxThreads = cfg.getInt("httpd", null, "maxthreads", 25);
+ int minThreads = cfg.getInt("httpd", null, "minthreads", 5);
+ int maxCapacity = cfg.getInt("httpd", null, "maxqueued", 50);
+ int idleTimeout = (int)MILLISECONDS.convert(60, SECONDS);
+ QueuedThreadPool pool = new QueuedThreadPool(
+ maxThreads,
+ minThreads,
+ idleTimeout,
+ new BlockingArrayQueue<Runnable>(
+ minThreads, // capacity,
+ minThreads, // growBy,
+ maxCapacity // maxCapacity
+ ));
pool.setName("HTTP");
- pool.setMinThreads(cfg.getInt("httpd", null, "minthreads", 5));
- pool.setMaxThreads(cfg.getInt("httpd", null, "maxthreads", 25));
- pool.setMaxQueued(cfg.getInt("httpd", null, "maxqueued", 50));
return pool;
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/ConsoleUI.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/ConsoleUI.java
index e8cf0ab..9af95ab 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/ConsoleUI.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/ConsoleUI.java
@@ -179,7 +179,7 @@
}
console.printf(" Supported options are:\n");
for (final String v : allowedValues) {
- console.printf(" %s\n", v.toString().toLowerCase());
+ console.printf(" %s\n", v.toLowerCase());
}
}
}
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/gwt-hello-gadgets-igoogle-thumb.png b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/gwt-hello-gadgets-igoogle-thumb.png
deleted file mode 100644
index d45c63f..0000000
--- a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/gwt-hello-gadgets-igoogle-thumb.png
+++ /dev/null
Binary files differ
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/gwt-hello-gadgets-igoogle.png b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/gwt-hello-gadgets-igoogle.png
deleted file mode 100644
index 5c9009a..0000000
--- a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/gwt-hello-gadgets-igoogle.png
+++ /dev/null
Binary files differ
diff --git a/gerrit-server/src/main/java/com/google/gerrit/lifecycle/LifecycleModule.java b/gerrit-server/src/main/java/com/google/gerrit/lifecycle/LifecycleModule.java
index 04682f5..a22e6da 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/lifecycle/LifecycleModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/lifecycle/LifecycleModule.java
@@ -1,7 +1,7 @@
package com.google.gerrit.lifecycle;
import com.google.gerrit.extensions.events.LifecycleListener;
-import com.google.inject.AbstractModule;
+import com.google.gerrit.server.config.FactoryModule;
import com.google.inject.Singleton;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.internal.UniqueAnnotations;
@@ -9,7 +9,7 @@
import java.lang.annotation.Annotation;
/** Module to support registering a unique LifecyleListener. */
-public abstract class LifecycleModule extends AbstractModule {
+public abstract class LifecycleModule extends FactoryModule {
/**
* Create a unique listener binding.
* <p>
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java
index 8634045..03ba94f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java
@@ -58,7 +58,7 @@
@Option(name = "--format", usage = "(deprecated) output format")
private OutputFormat format;
- @Option(name = "-q", metaVar = "CAP", multiValued = true, usage = "Capability to inspect")
+ @Option(name = "-q", metaVar = "CAP", usage = "Capability to inspect")
void addQuery(String name) {
if (query == null) {
query = Sets.newHashSet();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetChange.java
index 4f6ceac..8b794f5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetChange.java
@@ -29,7 +29,7 @@
public class GetChange implements RestReadView<ChangeResource> {
private final ChangeJson json;
- @Option(name = "-o", multiValued = true, usage = "Output options")
+ @Option(name = "-o", usage = "Output options")
void addOption(ListChangesOption o) {
json.addOption(o);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDetail.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDetail.java
index 21c4c33..520a09f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDetail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDetail.java
@@ -26,7 +26,7 @@
public class GetDetail implements RestReadView<ChangeResource> {
private final GetChange delegate;
- @Option(name = "-o", multiValued = true, usage = "Output options")
+ @Option(name = "-o", usage = "Output options")
void addOption(ListChangesOption o) {
delegate.addOption(o);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/PluginConfigFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/PluginConfigFactory.java
index 294d8a5..8df7073 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/PluginConfigFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/PluginConfigFactory.java
@@ -14,27 +14,45 @@
package com.google.gerrit.server.config;
+import com.google.common.collect.Maps;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.git.ProjectLevelConfig;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
@Singleton
public class PluginConfigFactory {
+ private static final Logger log =
+ LoggerFactory.getLogger(PluginConfigFactory.class);
+
+ private final SitePaths site;
private final Config cfg;
private final ProjectCache projectCache;
private final ProjectState.Factory projectStateFactory;
+ private final Map<String, Config> pluginConfigs;
@Inject
- PluginConfigFactory(@GerritServerConfig Config cfg,
+ PluginConfigFactory(SitePaths site, @GerritServerConfig Config cfg,
ProjectCache projectCache, ProjectState.Factory projectStateFactory) {
+ this.site = site;
this.cfg = cfg;
this.projectCache = projectCache;
this.projectStateFactory = projectStateFactory;
+ this.pluginConfigs = Maps.newHashMap();
}
/**
@@ -128,4 +146,96 @@
return getFromProjectConfig(projectName, pluginName).withInheritance(
projectStateFactory);
}
+
+ /**
+ * Returns the configuration for the specified plugin that is stored in the
+ * plugin configuration file 'etc/<plugin-name>.config'.
+ *
+ * The plugin configuration is only loaded once and is then cached.
+ *
+ * @param pluginName the name of the plugin for which the configuration should
+ * be returned
+ * @return the plugin configuration from the 'etc/<plugin-name>.config' file
+ */
+ public Config getGlobalPluginConfig(String pluginName) {
+ if (pluginConfigs.containsKey(pluginName)) {
+ return pluginConfigs.get(pluginName);
+ }
+
+ File pluginConfigFile = new File(site.etc_dir, pluginName + ".config");
+ FileBasedConfig cfg = new FileBasedConfig(pluginConfigFile, FS.DETECTED);
+ pluginConfigs.put(pluginName, cfg);
+ if (!cfg.getFile().exists()) {
+ log.info("No " + pluginConfigFile.getAbsolutePath() + "; assuming defaults");
+ return cfg;
+ }
+
+ try {
+ cfg.load();
+ } catch (IOException e) {
+ log.warn("Failed to load " + pluginConfigFile.getAbsolutePath(), e);
+ } catch (ConfigInvalidException e) {
+ log.warn("Failed to load " + pluginConfigFile.getAbsolutePath(), e);
+ }
+
+ return cfg;
+ }
+
+ /**
+ * Returns the configuration for the specified plugin that is stored in the
+ * '<plugin-name>.config' file in the 'refs/meta/config' branch of the
+ * specified project.
+ *
+ * @param projectName the name of the project for which the plugin
+ * configuration should be returned
+ * @param pluginName the name of the plugin for which the configuration should
+ * be returned
+ * @return the plugin configuration from the '<plugin-name>.config' file of
+ * the specified project
+ * @throws NoSuchProjectException thrown if the specified project does not
+ * exist
+ */
+ public Config getProjectPluginConfig(Project.NameKey projectName,
+ String pluginName) throws NoSuchProjectException {
+ return getPluginConfig(projectName, pluginName).get();
+ }
+
+ /**
+ * Returns the configuration for the specified plugin that is stored in the
+ * '<plugin-name>.config' file in the 'refs/meta/config' branch of the
+ * specified project. Parameters which are not set in the
+ * '<plugin-name>.config' of this project are inherited from the parent
+ * project's '<plugin-name>.config' files.
+ *
+ * E.g.: child project: [mySection "mySubsection"] myKey = childValue
+ *
+ * parent project: [mySection "mySubsection"] myKey = parentValue anotherKey =
+ * someValue
+ *
+ * return: [mySection "mySubsection"] myKey = childValue anotherKey =
+ * someValue
+ *
+ * @param projectName the name of the project for which the plugin
+ * configuration should be returned
+ * @param pluginName the name of the plugin for which the configuration should
+ * be returned
+ * @return the plugin configuration from the '<plugin-name>.config' file of
+ * the specified project with inheriting non-set parameters from the
+ * parent projects
+ * @throws NoSuchProjectException thrown if the specified project does not
+ * exist
+ */
+ public Config getProjectPluginConfigWithInheritance(Project.NameKey projectName,
+ String pluginName) throws NoSuchProjectException {
+ return getPluginConfig(projectName, pluginName).getWithInheritance();
+ }
+
+ private ProjectLevelConfig getPluginConfig(Project.NameKey projectName,
+ String pluginName) throws NoSuchProjectException {
+ ProjectState projectState = projectCache.get(projectName);
+ if (projectState == null) {
+ throw new NoSuchProjectException(projectName);
+ }
+ return projectState.getConfig(pluginName);
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
index c51a6ec..43e0156 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
@@ -19,7 +19,6 @@
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
-import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -62,17 +61,11 @@
private static final String UNNAMED =
"Unnamed repository; edit this file to name it for gitweb.";
- public static class Module extends AbstractModule {
+ public static class Module extends LifecycleModule {
@Override
protected void configure() {
bind(GitRepositoryManager.class).to(LocalDiskRepositoryManager.class);
-
- install(new LifecycleModule() {
- @Override
- protected void configure() {
- listener().to(LocalDiskRepositoryManager.Lifecycle.class);
- }
- });
+ listener().to(LocalDiskRepositoryManager.Lifecycle.class);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectLevelConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectLevelConfig.java
new file mode 100644
index 0000000..fc95608
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectLevelConfig.java
@@ -0,0 +1,97 @@
+// 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.
+
+package com.google.gerrit.server.git;
+
+import com.google.common.collect.Iterables;
+import com.google.gerrit.server.project.ProjectState;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Config;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Set;
+
+/** Configuration file in the projects refs/meta/config branch. */
+public class ProjectLevelConfig extends VersionedMetaData {
+ private final String fileName;
+ private final ProjectState project;
+ private Config cfg;
+
+ public ProjectLevelConfig(String fileName, ProjectState project) {
+ this.fileName = fileName;
+ this.project = project;
+ }
+
+ @Override
+ protected String getRefName() {
+ return GitRepositoryManager.REF_CONFIG;
+ }
+
+ @Override
+ protected void onLoad() throws IOException, ConfigInvalidException {
+ cfg = readConfig(fileName);
+ }
+
+ public Config get() {
+ if (cfg == null) {
+ cfg = new Config();
+ }
+ return cfg;
+ }
+
+ public Config getWithInheritance() {
+ Config cfgWithInheritance = new Config();
+ try {
+ cfgWithInheritance.fromText(get().toText());
+ } catch (ConfigInvalidException e) {
+ // cannot happen
+ }
+ ProjectState parent = Iterables.getFirst(project.parents(), null);
+ if (parent != null) {
+ Config parentCfg = parent.getConfig(fileName).getWithInheritance();
+ for (String section : parentCfg.getSections()) {
+ Set<String> allNames = get().getNames(section);
+ for (String name : parentCfg.getNames(section)) {
+ if (!allNames.contains(name)) {
+ cfgWithInheritance.setStringList(section, null, name,
+ Arrays.asList(parentCfg.getStringList(section, null, name)));
+ }
+ }
+
+ for (String subsection : parentCfg.getSubsections(section)) {
+ allNames = get().getNames(section, subsection);
+ for (String name : parentCfg.getNames(section, subsection)) {
+ if (!allNames.contains(name)) {
+ cfgWithInheritance.setStringList(section, subsection, name,
+ Arrays.asList(parentCfg.getStringList(section, subsection, name)));
+ }
+ }
+ }
+ }
+ }
+ return cfgWithInheritance;
+ }
+
+ @Override
+ protected void onSave(CommitBuilder commit) throws IOException,
+ ConfigInvalidException {
+ if (commit.getMessage() == null || "".equals(commit.getMessage())) {
+ commit.setMessage("Updated configuration\n");
+ }
+ saveConfig(fileName, cfg);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/RebaseSorter.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/RebaseSorter.java
index ac1929b..09c970e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/RebaseSorter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/RebaseSorter.java
@@ -64,7 +64,7 @@
n.statusCode = CommitMergeStatus.MISSING_DEPENDENCY;
n.missing = new ArrayList<CodeReviewCommit>();
}
- n.missing.add((CodeReviewCommit) c);
+ n.missing.add(c);
} else {
contents.add(c);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
index 509c5a2..76e54b6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
@@ -93,7 +93,7 @@
@Option(name = "-m", metaVar = "MATCH", usage = "match group substring")
private String matchSubstring;
- @Option(name = "-o", multiValued = true, usage = "Output options per group")
+ @Option(name = "-o", usage = "Output options per group")
public void addOption(ListGroupsOption o) {
options.add(o);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineLoader.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineLoader.java
index b95994f..52cba09 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineLoader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineLoader.java
@@ -248,12 +248,14 @@
//
if (ab < ae //
&& (ab == 0 || a.charAt(ab - 1) == '\n') //
- && ae < a.size() && a.charAt(ae) == '\n') {
+ && ae < a.size() && a.charAt(ae - 1) != '\n'
+ && a.charAt(ae) == '\n') {
ae++;
}
if (bb < be //
&& (bb == 0 || b.charAt(bb - 1) == '\n') //
- && be < b.size() && b.charAt(be) == '\n') {
+ && be < b.size() && b.charAt(be - 1) != '\n'
+ && b.charAt(be) == '\n') {
be++;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginModule.java
index bd1c3c8..055baf1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginModule.java
@@ -16,9 +16,8 @@
import com.google.gerrit.extensions.systemstatus.ServerInformation;
import com.google.gerrit.lifecycle.LifecycleModule;
-import com.google.inject.AbstractModule;
-public class PluginModule extends AbstractModule {
+public class PluginModule extends LifecycleModule {
@Override
protected void configure() {
bind(ServerInformationImpl.class);
@@ -28,11 +27,6 @@
bind(PluginGuiceEnvironment.class);
bind(PluginLoader.class);
bind(CopyConfigModule.class);
- install(new LifecycleModule() {
- @Override
- protected void configure() {
- listener().to(PluginLoader.class);
- }
- });
+ listener().to(PluginLoader.class);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GarbageCollect.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GarbageCollect.java
index ca7f6f0..b98cb8b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/GarbageCollect.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GarbageCollect.java
@@ -20,6 +20,7 @@
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.extensions.webui.UiAction;
import com.google.gerrit.server.git.GarbageCollection;
import com.google.gerrit.server.project.GarbageCollect.Input;
import com.google.inject.Inject;
@@ -31,8 +32,10 @@
import java.util.Collections;
@RequiresCapability(GlobalCapability.RUN_GC)
-public class GarbageCollect implements RestModifyView<ProjectResource, Input> {
+public class GarbageCollect implements RestModifyView<ProjectResource, Input>,
+ UiAction<ProjectResource> {
public static class Input {
+ public boolean showProgress;
}
private GarbageCollection.Factory garbageCollectionFactory;
@@ -43,7 +46,7 @@
}
@Override
- public BinaryResult apply(final ProjectResource rsrc, Input input) {
+ public BinaryResult apply(final ProjectResource rsrc, final Input input) {
return new BinaryResult() {
@Override
public void writeTo(OutputStream out) throws IOException {
@@ -56,10 +59,10 @@
};
try {
GarbageCollectionResult result = garbageCollectionFactory.create().run(
- Collections.singletonList(rsrc.getNameKey()), writer);
+ Collections.singletonList(rsrc.getNameKey()), input.showProgress ? writer : null);
+ String msg = "garbage collection was successfully done";
if (result.hasErrors()) {
for (GarbageCollectionResult.Error e : result.getErrors()) {
- String msg;
switch (e.getType()) {
case REPOSITORY_NOT_FOUND:
msg = "error: project \"" + e.getProjectName() + "\" not found";
@@ -76,9 +79,9 @@
msg = "error: garbage collection for project \"" + e.getProjectName()
+ "\" failed: " + e.getType();
}
- writer.println(msg);
}
}
+ writer.println(msg);
} finally {
writer.flush();
}
@@ -87,4 +90,11 @@
.setCharacterEncoding(Charsets.UTF_8.name())
.disableGzip();
}
+
+ @Override
+ public UiAction.Description getDescription(ProjectResource rsrc) {
+ return new UiAction.Description()
+ .setLabel("Run GC")
+ .setTitle("Triggers the Git Garbage Collection for this project.");
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListChildProjects.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListChildProjects.java
index d4b84dd..58abe40 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListChildProjects.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListChildProjects.java
@@ -47,6 +47,10 @@
this.projectNodeFactory = projectNodeFactory;
}
+ public void setRecursive(boolean recursive) {
+ this.recursive = recursive;
+ }
+
@Override
public List<ProjectInfo> apply(ProjectResource rsrc) {
if (recursive) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
index f777039..e79912e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
@@ -109,7 +109,7 @@
@Option(name = "--format", usage = "(deprecated) output format")
private OutputFormat format = OutputFormat.TEXT;
- @Option(name = "--show-branch", aliases = {"-b"}, multiValued = true,
+ @Option(name = "--show-branch", aliases = {"-b"},
usage = "displays the sha of each project in the specified branch")
public void addShowBranch(String branch) {
showBranch.add(branch);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
index f98822f..8ab3311 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
@@ -496,14 +496,18 @@
try {
Map<String, Ref> allRefs = repo.getRefDatabase().getRefs(ALL);
for (Entry<String, Ref> entry : allRefs.entrySet()) {
+ String refName = entry.getKey();
+ if (!refName.startsWith("refs/heads") && !refName.startsWith("refs/tags")) {
+ continue;
+ }
RevCommit tip;
try {
tip = rw.parseCommit(entry.getValue().getObjectId());
} catch (IncorrectObjectTypeException e) {
continue;
}
- if (rw.isMergedInto(commit, tip)
- && controlForRef(entry.getKey()).canPerform(Permission.READ)) {
+ if (controlForRef(entry.getKey()).canPerform(Permission.READ)
+ && rw.isMergedInto(commit, tip)) {
return true;
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
index 800fa6e..2e79e2f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
@@ -40,12 +40,14 @@
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.server.git.ProjectLevelConfig;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.googlecode.prolog_cafe.compiler.CompileException;
import com.googlecode.prolog_cafe.lang.PrologMachineCopy;
+import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.slf4j.Logger;
@@ -83,6 +85,7 @@
private final List<CommentLinkInfo> commentLinks;
private final ProjectConfig config;
+ private final Map<String, ProjectLevelConfig> configs;
private final Set<AccountGroup.UUID> localOwners;
/** Prolog rule state. */
@@ -121,6 +124,7 @@
this.rulesCache = rulesCache;
this.commentLinks = commentLinks;
this.config = config;
+ this.configs = Maps.newHashMap();
this.capabilities = isAllProjects
? new CapabilityCollection(config.getAccessSection(AccessSection.GLOBAL_CAPABILITIES))
: null;
@@ -216,6 +220,29 @@
return config;
}
+ public ProjectLevelConfig getConfig(String fileName) {
+ if (configs.containsKey(fileName)) {
+ return configs.get(fileName);
+ }
+
+ ProjectLevelConfig cfg = new ProjectLevelConfig(fileName, this);
+ try {
+ Repository git = gitMgr.openRepository(getProject().getNameKey());
+ try {
+ cfg.load(git);
+ } finally {
+ git.close();
+ }
+ } catch (IOException e) {
+ log.warn("Failed to load " + fileName + " for " + getProject().getName(), e);
+ } catch (ConfigInvalidException e) {
+ log.warn("Failed to load " + fileName + " for " + getProject().getName(), e);
+ }
+
+ configs.put(fileName, cfg);
+ return cfg;
+ }
+
public long getMaxObjectSizeLimit() {
return config.getMaxObjectSizeLimit();
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetParent.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetParent.java
index 1dd8282..337c6f4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetParent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetParent.java
@@ -37,7 +37,7 @@
import java.io.IOException;
-class SetParent implements RestModifyView<ProjectResource, Input> {
+public class SetParent implements RestModifyView<ProjectResource, Input> {
static class Input {
@DefaultInput
String parent;
@@ -62,41 +62,14 @@
throws AuthException, ResourceConflictException,
ResourceNotFoundException, UnprocessableEntityException, IOException {
ProjectControl ctl = rsrc.getControl();
+ validateParentUpdate(ctl, input.parent);
IdentifiedUser user = (IdentifiedUser) ctl.getCurrentUser();
- if (!user.getCapabilities().canAdministrateServer()) {
- throw new AuthException("not administrator");
- }
-
- if (rsrc.getNameKey().equals(allProjects)) {
- throw new ResourceConflictException("cannot set parent of "
- + allProjects.get());
- }
-
- input.parent = Strings.emptyToNull(input.parent);
- if (input.parent != null) {
- ProjectState parent = cache.get(new Project.NameKey(input.parent));
- if (parent == null) {
- throw new UnprocessableEntityException("parent project " + input.parent
- + " not found");
- }
-
- if (Iterables.tryFind(parent.tree(), new Predicate<ProjectState>() {
- @Override
- public boolean apply(ProjectState input) {
- return input.getProject().getNameKey().equals(rsrc.getNameKey());
- }
- }).isPresent()) {
- throw new ResourceConflictException("cycle exists between "
- + rsrc.getName() + " and " + parent.getProject().getName());
- }
- }
-
try {
MetaDataUpdate md = updateFactory.create(rsrc.getNameKey());
try {
ProjectConfig config = ProjectConfig.read(md);
Project project = config.getProject();
- project.setParentName(input.parent);
+ project.setParentName(Strings.emptyToNull(input.parent));
String msg = Strings.emptyToNull(input.commitMessage);
if (msg == null) {
@@ -123,4 +96,39 @@
"invalid project.config: %s", e.getMessage()));
}
}
+
+ public void validateParentUpdate(final ProjectControl ctl, String newParent)
+ throws AuthException, ResourceConflictException,
+ UnprocessableEntityException {
+ IdentifiedUser user = (IdentifiedUser) ctl.getCurrentUser();
+ if (!user.getCapabilities().canAdministrateServer()) {
+ throw new AuthException("not administrator");
+ }
+
+ if (ctl.getProject().getNameKey().equals(allProjects)) {
+ throw new ResourceConflictException("cannot set parent of "
+ + allProjects.get());
+ }
+
+ newParent = Strings.emptyToNull(newParent);
+ if (newParent != null) {
+ ProjectState parent = cache.get(new Project.NameKey(newParent));
+ if (parent == null) {
+ throw new UnprocessableEntityException("parent project " + newParent
+ + " not found");
+ }
+
+ if (Iterables.tryFind(parent.tree(), new Predicate<ProjectState>() {
+ @Override
+ public boolean apply(ProjectState input) {
+ return input.getProject().getNameKey()
+ .equals(ctl.getProject().getNameKey());
+ }
+ }).isPresent()) {
+ throw new ResourceConflictException("cycle exists between "
+ + ctl.getProject().getName() + " and "
+ + parent.getProject().getName());
+ }
+ }
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BasicChangeRewrites.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BasicChangeRewrites.java
index f81b0ca..dd96d50 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BasicChangeRewrites.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BasicChangeRewrites.java
@@ -33,8 +33,8 @@
new ChangeQueryBuilder.Arguments( //
new InvalidProvider<ReviewDb>(), //
new InvalidProvider<ChangeQueryRewriter>(), //
- null, null, null, null, null, //
- null, null, null, null, null), null);
+ null, null, null, null, null, null, //
+ null, null, null, null, null, null), null);
static Schema<ChangeData> schema(@Nullable IndexCollection indexes) {
ChangeIndex index = indexes != null ? indexes.getSearchIndex() : null;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index 85459b7..37890a5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -37,6 +37,7 @@
import com.google.gerrit.server.index.Schema;
import com.google.gerrit.server.patch.PatchListCache;
import com.google.gerrit.server.project.ChangeControl;
+import com.google.gerrit.server.project.ListChildProjects;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.query.IntPredicate;
import com.google.gerrit.server.query.Predicate;
@@ -94,6 +95,7 @@
public static final String FIELD_MESSAGE = "message";
public static final String FIELD_OWNER = "owner";
public static final String FIELD_OWNERIN = "ownerin";
+ public static final String FIELD_PARENTPROJECT = "parentproject";
public static final String FIELD_PROJECT = "project";
public static final String FIELD_REF = "ref";
public static final String FIELD_REVIEWER = "reviewer";
@@ -140,6 +142,7 @@
final Provider<ReviewDb> dbProvider;
final Provider<ChangeQueryRewriter> rewriter;
final IdentifiedUser.GenericFactory userFactory;
+ final Provider<CurrentUser> self;
final CapabilityControl.Factory capabilityControlFactory;
final ChangeControl.GenericFactory changeControlGenericFactory;
final AccountResolver accountResolver;
@@ -148,6 +151,7 @@
final PatchListCache patchListCache;
final GitRepositoryManager repoManager;
final ProjectCache projectCache;
+ final Provider<ListChildProjects> listChildProjects;
final IndexCollection indexes;
@Inject
@@ -155,6 +159,7 @@
public Arguments(Provider<ReviewDb> dbProvider,
Provider<ChangeQueryRewriter> rewriter,
IdentifiedUser.GenericFactory userFactory,
+ Provider<CurrentUser> self,
CapabilityControl.Factory capabilityControlFactory,
ChangeControl.GenericFactory changeControlGenericFactory,
AccountResolver accountResolver,
@@ -163,10 +168,12 @@
PatchListCache patchListCache,
GitRepositoryManager repoManager,
ProjectCache projectCache,
+ Provider<ListChildProjects> listChildProjects,
IndexCollection indexes) {
this.dbProvider = dbProvider;
this.rewriter = rewriter;
this.userFactory = userFactory;
+ this.self = self;
this.capabilityControlFactory = capabilityControlFactory;
this.changeControlGenericFactory = changeControlGenericFactory;
this.accountResolver = accountResolver;
@@ -175,6 +182,7 @@
this.patchListCache = patchListCache;
this.repoManager = repoManager;
this.projectCache = projectCache;
+ this.listChildProjects = listChildProjects;
this.indexes = indexes;
}
}
@@ -321,6 +329,12 @@
}
@Operator
+ public Predicate<ChangeData> parentproject(String name) {
+ return new ParentProjectPredicate(args.dbProvider, args.projectCache,
+ args.listChildProjects, args.self, name);
+ }
+
+ @Operator
public Predicate<ChangeData> branch(String name) {
if (name.startsWith("^"))
return ref("^" + branchToRef(name.substring(1)));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsVisibleToPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsVisibleToPredicate.java
index 8992318..27b4994 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsVisibleToPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsVisibleToPredicate.java
@@ -30,7 +30,7 @@
return ((IdentifiedUser) user).getAccountId().toString();
}
if (user instanceof SingleGroupUser) {
- return "group:" + ((SingleGroupUser) user).getEffectiveGroups().getKnownGroups() //
+ return "group:" + user.getEffectiveGroups().getKnownGroups() //
.iterator().next().toString();
}
return user.toString();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ParentProjectPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ParentProjectPredicate.java
new file mode 100644
index 0000000..2f63f5e
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ParentProjectPredicate.java
@@ -0,0 +1,67 @@
+// 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.
+
+package com.google.gerrit.server.query.change;
+
+import com.google.common.collect.Lists;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.project.ListChildProjects;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectJson.ProjectInfo;
+import com.google.gerrit.server.project.ProjectResource;
+import com.google.gerrit.server.project.ProjectState;
+import com.google.gerrit.server.query.OrPredicate;
+import com.google.gerrit.server.query.Predicate;
+import com.google.inject.Provider;
+
+import java.util.Collections;
+import java.util.List;
+
+class ParentProjectPredicate extends OrPredicate<ChangeData> {
+ private final String value;
+
+ ParentProjectPredicate(Provider<ReviewDb> dbProvider,
+ ProjectCache projectCache, Provider<ListChildProjects> listChildProjects,
+ Provider<CurrentUser> self, String value) {
+ super(predicates(dbProvider, projectCache, listChildProjects, self, value));
+ this.value = value;
+ }
+
+ private static List<Predicate<ChangeData>> predicates(
+ Provider<ReviewDb> dbProvider, ProjectCache projectCache,
+ Provider<ListChildProjects> listChildProjects,
+ Provider<CurrentUser> self, String value) {
+ ProjectState projectState = projectCache.get(new Project.NameKey(value));
+ if (projectState == null) {
+ return Collections.emptyList();
+ }
+
+ List<Predicate<ChangeData>> r = Lists.newArrayList();
+ r.add(new ProjectPredicate(dbProvider, projectState.getProject().getName()));
+ ListChildProjects children = listChildProjects.get();
+ children.setRecursive(true);
+ for (ProjectInfo p : children.apply(new ProjectResource(
+ projectState.controlFor(self.get())))) {
+ r.add(new ProjectPredicate(dbProvider, p.name));
+ }
+ return r;
+ }
+
+ @Override
+ public String toString() {
+ return ChangeQueryBuilder.FIELD_PARENTPROJECT + ":" + value;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryChanges.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryChanges.java
index 4b6a5a6..6ba9e6d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryChanges.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryChanges.java
@@ -45,7 +45,7 @@
private boolean reverse;
private EnumSet<ListChangesOption> options;
- @Option(name = "--query", aliases = {"-q"}, metaVar = "QUERY", multiValued = true, usage = "Query string")
+ @Option(name = "--query", aliases = {"-q"}, metaVar = "QUERY", usage = "Query string")
private List<String> queries;
@Option(name = "--limit", aliases = {"-n"}, metaVar = "CNT", usage = "Maximum number of results to return")
@@ -53,7 +53,7 @@
imp.setLimit(limit);
}
- @Option(name = "-o", multiValued = true, usage = "Output options per change")
+ @Option(name = "-o", usage = "Output options per change")
public void addOption(ListChangesOption o) {
options.add(o);
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeQueryBuilder.java b/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeQueryBuilder.java
index 63e62a0..77633c8 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeQueryBuilder.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeQueryBuilder.java
@@ -26,7 +26,7 @@
new FakeQueryBuilder.Definition<ChangeData, FakeQueryBuilder>(
FakeQueryBuilder.class),
new ChangeQueryBuilder.Arguments(null, null, null, null, null, null,
- null, null, null, null, null, indexes),
+ null, null, null, null, null, null, null, indexes),
null);
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandModule.java
index c64f9d8..12f0db0 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandModule.java
@@ -16,13 +16,13 @@
import com.google.common.base.Objects;
import com.google.common.base.Strings;
-import com.google.inject.AbstractModule;
+import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.inject.binder.LinkedBindingBuilder;
import org.apache.sshd.server.Command;
/** Module to register commands in the SSH daemon. */
-public abstract class CommandModule extends AbstractModule {
+public abstract class CommandModule extends LifecycleModule {
/**
* Configure a command to be invoked by name.
*
@@ -72,7 +72,7 @@
*/
protected void command(final CommandName parent,
final Class<? extends BaseCommand> clazz) {
- CommandMetaData meta = (CommandMetaData)clazz.getAnnotation(CommandMetaData.class);
+ CommandMetaData meta = clazz.getAnnotation(CommandMetaData.class);
if (meta == null) {
throw new IllegalStateException("no CommandMetaData annotation found");
}
@@ -91,7 +91,7 @@
*/
protected void alias(final CommandName parent, final String name,
final Class<? extends BaseCommand> clazz) {
- CommandMetaData meta = (CommandMetaData)clazz.getAnnotation(CommandMetaData.class);
+ CommandMetaData meta = clazz.getAnnotation(CommandMetaData.class);
if (meta == null) {
throw new IllegalStateException("no CommandMetaData annotation found");
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java
index cde7ae8..78f006b 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java
@@ -106,7 +106,7 @@
} finally {
sshScope.set(old);
}
- err.write(Constants.encode(message.toString()));
+ err.write(Constants.encode(message));
err.flush();
in.close();
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
index 39b7f16..2322a3b 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
@@ -21,7 +21,6 @@
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.server.PeerDaemonUser;
import com.google.gerrit.server.RemotePeer;
-import com.google.gerrit.server.config.FactoryModule;
import com.google.gerrit.server.config.GerritRequestModule;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.AsyncReceiveCommits;
@@ -47,7 +46,7 @@
import java.util.Map;
/** Configures standard dependencies for {@link SshDaemon}. */
-public class SshModule extends FactoryModule {
+public class SshModule extends LifecycleModule {
private final Map<String, String> aliases;
@Inject
@@ -87,25 +86,20 @@
install(new DefaultCommandModule());
- install(new LifecycleModule() {
- @Override
- protected void configure() {
- bind(ModuleGenerator.class).to(SshAutoRegisterModuleGenerator.class);
- bind(SshPluginStarterCallback.class);
- bind(StartPluginListener.class)
- .annotatedWith(UniqueAnnotations.create())
- .to(SshPluginStarterCallback.class);
+ bind(ModuleGenerator.class).to(SshAutoRegisterModuleGenerator.class);
+ bind(SshPluginStarterCallback.class);
+ bind(StartPluginListener.class)
+ .annotatedWith(UniqueAnnotations.create())
+ .to(SshPluginStarterCallback.class);
- bind(ReloadPluginListener.class)
- .annotatedWith(UniqueAnnotations.create())
- .to(SshPluginStarterCallback.class);
+ bind(ReloadPluginListener.class)
+ .annotatedWith(UniqueAnnotations.create())
+ .to(SshPluginStarterCallback.class);
- listener().toInstance(registerInParentInjectors());
- listener().to(SshLog.class);
- listener().to(SshDaemon.class);
- listener().to(CommandFactoryProvider.class);
- }
- });
+ listener().toInstance(registerInParentInjectors());
+ listener().to(SshLog.class);
+ listener().to(SshDaemon.class);
+ listener().to(CommandFactoryProvider.class);
}
private void configureAliases() {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ApproveOption.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ApproveOption.java
index 29250d3..fea16cd 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ApproveOption.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ApproveOption.java
@@ -24,8 +24,10 @@
import org.kohsuke.args4j.spi.OneArgumentOptionHandler;
import org.kohsuke.args4j.spi.OptionHandler;
import org.kohsuke.args4j.spi.Setter;
+import org.kohsuke.args4j.spi.FieldSetter;
import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
final class ApproveOption implements Option, Setter<Short> {
private final String name;
@@ -46,6 +48,16 @@
}
@Override
+ public String[] depends() {
+ return new String[] {};
+ }
+
+ @Override
+ public boolean hidden() {
+ return false;
+ }
+
+ @Override
public Class<? extends OptionHandler<Short>> handler() {
return Handler.class;
}
@@ -56,11 +68,6 @@
}
@Override
- public boolean multiValued() {
- return false;
- }
-
- @Override
public String name() {
return name;
}
@@ -85,6 +92,16 @@
}
@Override
+ public FieldSetter asFieldSetter() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public AnnotatedElement asAnnotatedElement() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public void addValue(final Short val) {
this.value = val;
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
index 429caf6..75743b0 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
@@ -14,7 +14,6 @@
package com.google.gerrit.sshd.commands;
-import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.sshd.CommandModule;
import com.google.gerrit.sshd.CommandName;
import com.google.gerrit.sshd.Commands;
@@ -77,11 +76,6 @@
command("suexec").to(SuExec.class);
- install(new LifecycleModule() {
- @Override
- protected void configure() {
- listener().to(ShowCaches.StartupListener.class);
- }
- });
+ listener().to(ShowCaches.StartupListener.class);
}
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java
index 346bea7..81af0d8 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java
@@ -43,6 +43,9 @@
@Option(name = "--all", usage = "runs the Git garbage collection for all projects")
private boolean all;
+ @Option(name = "--show-progress", usage = "progress information is shown")
+ private boolean showProgress;
+
@Argument(index = 0, required = false, multiValued = true, metaVar = "NAME",
usage = "projects for which the Git garbage collection should be run")
private List<ProjectControl> projects = new ArrayList<ProjectControl>();
@@ -95,7 +98,7 @@
}
GarbageCollectionResult result =
- garbageCollectionFactory.create().run(projectNames, stdout);
+ garbageCollectionFactory.create().run(projectNames, showProgress ? stdout : null);
if (result.hasErrors()) {
for (GarbageCollectionResult.Error e : result.getErrors()) {
String msg;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
index 31f9301..2a8650a 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
@@ -62,12 +62,12 @@
private final Set<Account.Id> reviewerId = new HashSet<Account.Id>();
private final Set<Account.Id> ccId = new HashSet<Account.Id>();
- @Option(name = "--reviewer", aliases = {"--re"}, multiValued = true, metaVar = "EMAIL", usage = "request reviewer for change(s)")
+ @Option(name = "--reviewer", aliases = {"--re"}, metaVar = "EMAIL", usage = "request reviewer for change(s)")
void addReviewer(final Account.Id id) {
reviewerId.add(id);
}
- @Option(name = "--cc", aliases = {}, multiValued = true, metaVar = "EMAIL", usage = "CC user on change(s)")
+ @Option(name = "--cc", aliases = {}, metaVar = "EMAIL", usage = "CC user on change(s)")
void addCC(final Account.Id id) {
ccId.add(id);
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetAccountCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
index 5736bb6..f634147 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
@@ -70,16 +70,16 @@
@Option(name = "--inactive", usage = "set account's state to inactive")
private boolean inactive;
- @Option(name = "--add-email", multiValued = true, metaVar = "EMAIL", usage = "email addresses to add to the account")
+ @Option(name = "--add-email", metaVar = "EMAIL", usage = "email addresses to add to the account")
private List<String> addEmails = new ArrayList<String>();
- @Option(name = "--delete-email", multiValued = true, metaVar = "EMAIL", usage = "email addresses to delete from the account")
+ @Option(name = "--delete-email", metaVar = "EMAIL", usage = "email addresses to delete from the account")
private List<String> deleteEmails = new ArrayList<String>();
- @Option(name = "--add-ssh-key", multiValued = true, metaVar = "-|KEY", usage = "public keys to add to the account")
+ @Option(name = "--add-ssh-key", metaVar = "-|KEY", usage = "public keys to add to the account")
private List<String> addSshKeys = new ArrayList<String>();
- @Option(name = "--delete-ssh-key", multiValued = true, metaVar = "-|KEY", usage = "public keys to delete from the account")
+ @Option(name = "--delete-ssh-key", metaVar = "-|KEY", usage = "public keys to delete from the account")
private List<String> deleteSshKeys = new ArrayList<String>();
@Option(name = "--http-password", metaVar = "PASSWORD", usage = "password for HTTP authentication for the account")
diff --git a/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java b/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java
index b75635f..7fc6d6f 100644
--- a/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java
+++ b/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java
@@ -52,10 +52,13 @@
import org.kohsuke.args4j.spi.EnumOptionHandler;
import org.kohsuke.args4j.spi.OptionHandler;
import org.kohsuke.args4j.spi.Setter;
+import org.kohsuke.args4j.spi.FieldSetter;
+
import java.io.StringWriter;
import java.io.Writer;
import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -381,6 +384,16 @@
}
@Override
+ public String[] depends() {
+ return new String[] {};
+ }
+
+ @Override
+ public boolean hidden() {
+ return false;
+ }
+
+ @Override
public String usage() {
return "display this help text";
}
@@ -401,11 +414,6 @@
}
@Override
- public boolean multiValued() {
- return false;
- }
-
- @Override
public boolean required() {
return false;
}
@@ -416,13 +424,23 @@
}
@Override
+ public FieldSetter asFieldSetter() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public AnnotatedElement asAnnotatedElement() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public Class<Boolean> getType() {
return Boolean.class;
}
@Override
public boolean isMultiValued() {
- return multiValued();
+ return false;
}
}
}
diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
index 5936911..36595c0 100644
--- a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
+++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
@@ -196,16 +196,10 @@
final DataSourceType dst = Guice.createInjector(new DataSourceModule(),
configModule, sitePathModule).getInstance(
Key.get(DataSourceType.class, Names.named(dbType.toLowerCase())));
- modules.add(new AbstractModule() {
- @Override
- protected void configure() {
- bind(DataSourceType.class).toInstance(dst);
- }
- });
-
modules.add(new LifecycleModule() {
@Override
protected void configure() {
+ bind(DataSourceType.class).toInstance(dst);
bind(DataSourceProvider.Context.class).toInstance(
DataSourceProvider.Context.MULTI_USER);
bind(Key.get(DataSource.class, Names.named("ReviewDb"))).toProvider(
diff --git a/lib/BUCK b/lib/BUCK
index 5ee1bab..2469692 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -121,8 +121,8 @@
maven_jar(
name = 'args4j',
- id = 'args4j:args4j:2.0.16',
- sha1 = '9f00fb12820743b9e05c686eba543d64dd43f2b1',
+ id = 'args4j:args4j:2.0.26',
+ sha1 = '01ebb18ebb3b379a74207d5af4ea7c8338ebd78b',
license = 'args4j',
)
diff --git a/lib/jetty/BUCK b/lib/jetty/BUCK
index 6eac1a9..6314f99 100644
--- a/lib/jetty/BUCK
+++ b/lib/jetty/BUCK
@@ -1,12 +1,12 @@
include_defs('//lib/maven.defs')
-VERSION = '8.1.7.v20120910'
+VERSION = '9.0.6.v20130930'
EXCLUDE = ['about.html']
maven_jar(
name = 'servlet',
id = 'org.eclipse.jetty:jetty-servlet:' + VERSION,
- sha1 = '93da01e3ea26e70449e9a1a0affa5c31436be5a0',
+ sha1 = 'b6953af6f857e78fe3c46935fa96f9c80a9cbefd',
license = 'Apache2.0',
deps = [
':security',
@@ -18,7 +18,7 @@
maven_jar(
name = 'security',
id = 'org.eclipse.jetty:jetty-security:' + VERSION,
- sha1 = '8d78beb7a07f4cccee05a3f16a264f1025946258',
+ sha1 = 'b16cd29ad9d3d3cca8176a654adf4b2ddca0eb3e',
license = 'Apache2.0',
deps = [':server'],
exclude = EXCLUDE,
@@ -28,7 +28,7 @@
maven_jar(
name = 'server',
id = 'org.eclipse.jetty:jetty-server:' + VERSION,
- sha1 = '6c81f733f28713919e99c2f8952e6ca5178033cd',
+ sha1 = 'd89016c2bcd380f548530fa049295e62601dc564',
license = 'Apache2.0',
deps = [
':continuation',
@@ -41,7 +41,7 @@
maven_jar(
name = 'continuation',
id = 'org.eclipse.jetty:jetty-continuation:' + VERSION,
- sha1 = 'f60cfe6267038000b459508529c88737601081e4',
+ sha1 = '4f942a52a3e996634ff302ab98f46d224b0db9d2',
license = 'Apache2.0',
exclude = EXCLUDE,
)
@@ -49,7 +49,7 @@
maven_jar(
name = 'http',
id = 'org.eclipse.jetty:jetty-http:' + VERSION,
- sha1 = '10126433876cd74534695f7f99c4362596555493',
+ sha1 = 'b3a2302717ac1889b4a17ed03e2555f8291121b9',
license = 'Apache2.0',
deps = [':io'],
exclude = EXCLUDE,
@@ -58,7 +58,7 @@
maven_jar(
name = 'io',
id = 'org.eclipse.jetty:jetty-io:' + VERSION,
- sha1 = 'a81f746ae1b10c37e1bb0a01d1374c202c0bd549',
+ sha1 = 'f3a66e0507d963c51e280243f0472a5b2eadc8b1',
license = 'Apache2.0',
deps = [':util'],
exclude = EXCLUDE,
@@ -68,7 +68,7 @@
maven_jar(
name = 'util',
id = 'org.eclipse.jetty:jetty-util:' + VERSION,
- sha1 = '7eb2004ab2c22fd3b00095bd9ba0f32a9e88f6a5',
+ sha1 = 'f36c9e61559d1154be9b52803ef4f586e401dac6',
license = 'Apache2.0',
exclude = EXCLUDE,
visibility = [],
diff --git a/plugins/replication b/plugins/replication
index c126e78..5ee79cc 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit c126e78886cd985edddee66ad1aba0130a4a5819
+Subproject commit 5ee79cc5355e24bee7d38f697aa834e1bd6e0e7d
diff --git a/tools/default.defs b/tools/default.defs
index 4ed5635..b7ef6b4 100644
--- a/tools/default.defs
+++ b/tools/default.defs
@@ -14,6 +14,8 @@
# Rule definitions loaded by default into every BUCK file.
+include_defs('//tools/gwt-constants.defs')
+
def genantlr(
name,
srcs,
@@ -128,6 +130,7 @@
deps = [],
srcs = [],
resources = [],
+ gwt_module = None,
manifest_file = None,
manifest_entries = [],
type = 'plugin',
@@ -149,20 +152,47 @@
srcs = mf_src,
out = 'MANIFEST.MF',
)
+ gwt_deps = []
+ static_jars = []
+ if gwt_module:
+ gwt_deps = GWT_PLUGIN_DEPS
+ static_jars = [':%s-static-jar' % name]
java_library2(
name = name + '__plugin',
srcs = srcs,
resources = resources,
deps = deps,
- compile_deps = ['//:%s-lib' % type],
+ compile_deps = ['//:%s-lib' % type] + gwt_deps,
)
+ if gwt_module:
+ prebuilt_jar(
+ name = '%s-static-jar' % name,
+ binary_jar = genfile('%s-static.zip' % name),
+ deps = [':%s-static' % name],
+ )
+ genrule(
+ name = '%s-static' % name,
+ cmd = 'mkdir -p $TMP/static' +
+ ';unzip -qd $TMP/static $(location %s)' %
+ ':%s__gwt_application' % name +
+ ';cd $TMP' +
+ ';zip -qr $OUT .',
+ out = '%s-static.zip' % name,
+ deps = [':%s__gwt_application' % name]
+ )
+ gwt_application(
+ name = name + '__gwt_application',
+ module_target = gwt_module,
+ compiler_opts = GWT_COMPILER_OPTS,
+ deps = [':%s__plugin' % name] + gwt_deps,
+ )
java_binary(
name = name,
manifest_file = genfile('MANIFEST.MF'),
deps = [
':%s__plugin' % name,
':%s__manifest' % name,
- ],
+ ] + static_jars,
visibility = visibility,
)
diff --git a/tools/gwt-constants.defs b/tools/gwt-constants.defs
new file mode 100644
index 0000000..56978e7
--- /dev/null
+++ b/tools/gwt-constants.defs
@@ -0,0 +1,13 @@
+GWT_COMPILER_OPTS = [
+ '-strict',
+ '-style', 'OBF',
+ '-optimize', '9',
+ '-XdisableClassMetadata',
+ '-XdisableCastChecking',
+ '-XenableClosureCompiler',
+]
+
+GWT_PLUGIN_DEPS = [
+ '//gerrit-plugin-gwtui:client',
+ '//lib/gwt:user',
+]