Merge branch 'stable-2.8' into stable-2.9
* stable-2.8: SideBySide2: Show [ and ] shortcut keys in nav arrow tooltips Always auto confirm adding reviewers for set-reviewers SSH command Improve wording of 'parents' field description in CommitInfo Fix 'parents' field name of CommitInfo in REST documentation Implement pagination in project list screen Add option 'S' to projects REST API to support query offset Fix: Failure of acceptance tests. Do not refresh project list if filter did not change Fix inconsistent behavior of diff view when viewing binary files Update cookbook plugin to latest revision Correct Javadoc of RestReadView in extension API Fix memory leak of SubIndex.NrtFuture objects Conflicts: gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java Change-Id: I4d432c6ce27d3fd76dd9f86b8685be15ec8f123d
This commit is contained in:
@@ -2903,10 +2903,10 @@ The `CommitInfo` entity contains information about a commit.
|
|||||||
|==========================
|
|==========================
|
||||||
|Field Name |Description
|
|Field Name |Description
|
||||||
|`commit` |The commit ID.
|
|`commit` |The commit ID.
|
||||||
|`parent` |
|
|`parents` |
|
||||||
The parent commits of this commit as a list of
|
The parent commits of this commit as a list of
|
||||||
link:#commit-info[CommitInfo] entities. In parent
|
link:#commit-info[CommitInfo] entities. In each parent
|
||||||
only `commit` and `subject` fields are populated.
|
only the `commit` and `subject` fields are populated.
|
||||||
|`author` |The author of the commit as a
|
|`author` |The author of the commit as a
|
||||||
link:#git-person-info[GitPersonInfo] entity.
|
link:#git-person-info[GitPersonInfo] entity.
|
||||||
|`committer` |The committer of the commit as a
|
|`committer` |The committer of the commit as a
|
||||||
|
@@ -92,6 +92,22 @@ List all projects that start with `platform/`:
|
|||||||
----
|
----
|
||||||
E.g. this feature can be used by suggestion client UI's to limit results.
|
E.g. this feature can be used by suggestion client UI's to limit results.
|
||||||
|
|
||||||
|
The `/projects/` URL also accepts a limit integer in the `n` parameter.
|
||||||
|
This limits the results to show `n` projects.
|
||||||
|
|
||||||
|
Query the first 25 projects in project list.
|
||||||
|
----
|
||||||
|
GET /projects/?n=25 HTTP/1.0
|
||||||
|
----
|
||||||
|
|
||||||
|
The `/projects/` URL also accepts a start integer in the `S` parameter.
|
||||||
|
The results will skip `S` projects from project list.
|
||||||
|
|
||||||
|
Query 25 projects starting from index 50.
|
||||||
|
----
|
||||||
|
GET /projects/?n=25&S=50 HTTP/1.0
|
||||||
|
----
|
||||||
|
|
||||||
[[get-project]]
|
[[get-project]]
|
||||||
=== Get Project
|
=== Get Project
|
||||||
--
|
--
|
||||||
|
@@ -23,7 +23,7 @@ public interface RestReadView<R extends RestResource> extends RestView<R> {
|
|||||||
/**
|
/**
|
||||||
* Process the view operation by reading from the resource.
|
* Process the view operation by reading from the resource.
|
||||||
*
|
*
|
||||||
* @param resource resource to modify.
|
* @param resource resource to read.
|
||||||
* @return result to return to the client. Use {@link BinaryResult} to avoid
|
* @return result to return to the client. Use {@link BinaryResult} to avoid
|
||||||
* automatic conversion to JSON.
|
* automatic conversion to JSON.
|
||||||
* @throws AuthException the client is not permitted to access this view.
|
* @throws AuthException the client is not permitted to access this view.
|
||||||
|
@@ -585,7 +585,7 @@ public class Dispatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isChangeScreen2() {
|
public static boolean isChangeScreen2() {
|
||||||
if (!Gerrit.getConfig().getNewFeatures()) {
|
if (!Gerrit.getConfig().getNewFeatures()) {
|
||||||
return false;
|
return false;
|
||||||
} else if (changeScreen2) {
|
} else if (changeScreen2) {
|
||||||
@@ -650,7 +650,20 @@ public class Dispatcher {
|
|||||||
panel = 0 <= c ? token.substring(c + 1) : "";
|
panel = 0 <= c ? token.substring(c + 1) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("unified".equals(panel)) {
|
if ("".equals(panel)) {
|
||||||
|
if (isChangeScreen2()) {
|
||||||
|
return new SideBySide2(baseId, id.getParentKey(), id.get(),
|
||||||
|
side, line);
|
||||||
|
}
|
||||||
|
return new PatchScreen.SideBySide( //
|
||||||
|
id, //
|
||||||
|
patchIndex, //
|
||||||
|
patchSetDetail, //
|
||||||
|
patchTable, //
|
||||||
|
top, //
|
||||||
|
baseId //
|
||||||
|
);
|
||||||
|
} else if ("unified".equals(panel)) {
|
||||||
return new PatchScreen.Unified( //
|
return new PatchScreen.Unified( //
|
||||||
id, //
|
id, //
|
||||||
patchIndex, //
|
patchIndex, //
|
||||||
|
@@ -134,4 +134,7 @@ public interface AdminConstants extends Constants {
|
|||||||
String sectionTypeReference();
|
String sectionTypeReference();
|
||||||
String sectionTypeSection();
|
String sectionTypeSection();
|
||||||
Map<String, String> sectionNames();
|
Map<String, String> sectionNames();
|
||||||
|
|
||||||
|
String pagedProjectListPrev();
|
||||||
|
String pagedProjectListNext();
|
||||||
}
|
}
|
||||||
|
@@ -99,6 +99,8 @@ noGroupSelected = (No group selected)
|
|||||||
errorNoMatchingGroups = No Matching Groups
|
errorNoMatchingGroups = No Matching Groups
|
||||||
errorNoGitRepository = No Git Repository
|
errorNoGitRepository = No Git Repository
|
||||||
|
|
||||||
|
pagedProjectListPrev = ⇦Prev
|
||||||
|
pagedProjectListNext = Next⇨
|
||||||
|
|
||||||
addPermission = Add Permission ...
|
addPermission = Add Permission ...
|
||||||
|
|
||||||
|
@@ -24,11 +24,13 @@ import com.google.gerrit.client.projects.ProjectMap;
|
|||||||
import com.google.gerrit.client.rpc.GerritCallback;
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
import com.google.gerrit.client.ui.FilteredUserInterface;
|
import com.google.gerrit.client.ui.FilteredUserInterface;
|
||||||
import com.google.gerrit.client.ui.HighlightingInlineHyperlink;
|
import com.google.gerrit.client.ui.HighlightingInlineHyperlink;
|
||||||
|
import com.google.gerrit.client.ui.Hyperlink;
|
||||||
import com.google.gerrit.client.ui.IgnoreOutdatedFilterResultsCallbackWrapper;
|
import com.google.gerrit.client.ui.IgnoreOutdatedFilterResultsCallbackWrapper;
|
||||||
import com.google.gerrit.client.ui.ProjectSearchLink;
|
import com.google.gerrit.client.ui.ProjectSearchLink;
|
||||||
import com.google.gerrit.client.ui.ProjectsTable;
|
import com.google.gerrit.client.ui.ProjectsTable;
|
||||||
import com.google.gerrit.client.ui.Screen;
|
import com.google.gerrit.client.ui.Screen;
|
||||||
import com.google.gerrit.common.PageLinks;
|
import com.google.gerrit.common.PageLinks;
|
||||||
|
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
|
||||||
import com.google.gwt.event.dom.client.KeyCodes;
|
import com.google.gwt.event.dom.client.KeyCodes;
|
||||||
import com.google.gwt.event.dom.client.KeyUpEvent;
|
import com.google.gwt.event.dom.client.KeyUpEvent;
|
||||||
import com.google.gwt.event.dom.client.KeyUpHandler;
|
import com.google.gwt.event.dom.client.KeyUpHandler;
|
||||||
@@ -42,11 +44,16 @@ import com.google.gwt.user.client.ui.Label;
|
|||||||
import com.google.gwtexpui.globalkey.client.NpTextBox;
|
import com.google.gwtexpui.globalkey.client.NpTextBox;
|
||||||
|
|
||||||
public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
||||||
|
private Hyperlink prev;
|
||||||
|
private Hyperlink next;
|
||||||
private ProjectsTable projects;
|
private ProjectsTable projects;
|
||||||
private NpTextBox filterTxt;
|
private NpTextBox filterTxt;
|
||||||
private String subname;
|
private String subname = "";
|
||||||
|
private int startPosition;
|
||||||
|
private int pageSize;
|
||||||
|
|
||||||
public ProjectListScreen() {
|
public ProjectListScreen() {
|
||||||
|
configurePageSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProjectListScreen(String params) {
|
public ProjectListScreen(String params) {
|
||||||
@@ -59,6 +66,22 @@ public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
|||||||
if ("filter".equals(kv[0])) {
|
if ("filter".equals(kv[0])) {
|
||||||
subname = URL.decodeQueryString(kv[1]);
|
subname = URL.decodeQueryString(kv[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("skip".equals(kv[0]) && URL.decodeQueryString(kv[1]).matches("^[\\d]+")) {
|
||||||
|
startPosition = Integer.parseInt(URL.decodeQueryString(kv[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
configurePageSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configurePageSize() {
|
||||||
|
if (Gerrit.isSignedIn()) {
|
||||||
|
final AccountGeneralPreferences p =
|
||||||
|
Gerrit.getUserAccount().getGeneralPreferences();
|
||||||
|
final short m = p.getMaximumPageSize();
|
||||||
|
pageSize = 0 < m ? m : AccountGeneralPreferences.DEFAULT_PAGESIZE;
|
||||||
|
} else {
|
||||||
|
pageSize = AccountGeneralPreferences.DEFAULT_PAGESIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,13 +89,17 @@ public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
|||||||
protected void onLoad() {
|
protected void onLoad() {
|
||||||
super.onLoad();
|
super.onLoad();
|
||||||
display();
|
display();
|
||||||
refresh(false);
|
refresh(false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refresh(final boolean open) {
|
private void refresh(final boolean open, final boolean filterModified) {
|
||||||
setToken(subname == null || "".equals(subname) ? ADMIN_PROJECTS
|
if (filterModified){
|
||||||
: ADMIN_PROJECTS + "?filter=" + URL.encodeQueryString(subname));
|
startPosition = 0;
|
||||||
ProjectMap.match(subname,
|
}
|
||||||
|
setToken(getTokenForScreen(subname, startPosition));
|
||||||
|
// Retrieve one more project than page size to determine if there are more
|
||||||
|
// projects to display
|
||||||
|
ProjectMap.match(subname, pageSize + 1, startPosition,
|
||||||
new IgnoreOutdatedFilterResultsCallbackWrapper<ProjectMap>(this,
|
new IgnoreOutdatedFilterResultsCallbackWrapper<ProjectMap>(this,
|
||||||
new GerritCallback<ProjectMap>() {
|
new GerritCallback<ProjectMap>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -81,12 +108,44 @@ public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
|||||||
Gerrit.display(PageLinks.toProject(
|
Gerrit.display(PageLinks.toProject(
|
||||||
result.values().get(0).name_key()));
|
result.values().get(0).name_key()));
|
||||||
} else {
|
} else {
|
||||||
projects.display(result);
|
if (result.size() <= pageSize) {
|
||||||
|
projects.display(result);
|
||||||
|
next.setVisible(false);
|
||||||
|
} else {
|
||||||
|
projects.displaySubset(result, 0, result.size() - 1);
|
||||||
|
setupNavigationLink(next, subname, startPosition + pageSize);
|
||||||
|
}
|
||||||
|
if (startPosition > 0) {
|
||||||
|
setupNavigationLink(prev, subname, startPosition - pageSize);
|
||||||
|
} else {
|
||||||
|
prev.setVisible(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupNavigationLink(Hyperlink link, String filter, int skip) {
|
||||||
|
link.setTargetHistoryToken(getTokenForScreen(filter, skip));
|
||||||
|
link.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTokenForScreen(String filter, int skip) {
|
||||||
|
String token = ADMIN_PROJECTS;
|
||||||
|
if (filter != null && !filter.isEmpty()) {
|
||||||
|
token += "?filter=" + URL.encodeQueryString(filter);
|
||||||
|
}
|
||||||
|
if (skip > 0) {
|
||||||
|
if (token.contains("?filter=")) {
|
||||||
|
token += ",";
|
||||||
|
} else {
|
||||||
|
token += "?";
|
||||||
|
}
|
||||||
|
token += "skip=" + skip;
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCurrentFilter() {
|
public String getCurrentFilter() {
|
||||||
return subname;
|
return subname;
|
||||||
@@ -98,6 +157,12 @@ public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
|||||||
setPageTitle(Util.C.projectListTitle());
|
setPageTitle(Util.C.projectListTitle());
|
||||||
initPageHeader();
|
initPageHeader();
|
||||||
|
|
||||||
|
prev = new Hyperlink(Util.C.pagedProjectListPrev(), true, "");
|
||||||
|
prev.setVisible(false);
|
||||||
|
|
||||||
|
next = new Hyperlink(Util.C.pagedProjectListNext(), true, "");
|
||||||
|
next.setVisible(false);
|
||||||
|
|
||||||
projects = new ProjectsTable() {
|
projects = new ProjectsTable() {
|
||||||
@Override
|
@Override
|
||||||
protected void initColumnHeaders() {
|
protected void initColumnHeaders() {
|
||||||
@@ -167,6 +232,11 @@ public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
|||||||
projects.setSavePointerId(PageLinks.ADMIN_PROJECTS);
|
projects.setSavePointerId(PageLinks.ADMIN_PROJECTS);
|
||||||
|
|
||||||
add(projects);
|
add(projects);
|
||||||
|
final HorizontalPanel buttons = new HorizontalPanel();
|
||||||
|
buttons.setStyleName(Gerrit.RESOURCES.css().changeTablePrevNextLinks());
|
||||||
|
buttons.add(prev);
|
||||||
|
buttons.add(next);
|
||||||
|
add(buttons);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initPageHeader() {
|
private void initPageHeader() {
|
||||||
@@ -180,8 +250,13 @@ public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
|||||||
filterTxt.addKeyUpHandler(new KeyUpHandler() {
|
filterTxt.addKeyUpHandler(new KeyUpHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onKeyUp(KeyUpEvent event) {
|
public void onKeyUp(KeyUpEvent event) {
|
||||||
subname = filterTxt.getValue();
|
boolean enterPressed =
|
||||||
refresh(event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER);
|
event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER;
|
||||||
|
boolean filterModified = !filterTxt.getValue().equals(subname);
|
||||||
|
if (enterPressed || filterModified) {
|
||||||
|
subname = filterTxt.getValue();
|
||||||
|
refresh(enterPressed, filterModified);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
hp.add(filterTxt);
|
hp.add(filterTxt);
|
||||||
|
@@ -22,6 +22,7 @@ import com.google.gerrit.client.ui.ListenableAccountDiffPreference;
|
|||||||
import com.google.gerrit.client.ui.NavigationTable;
|
import com.google.gerrit.client.ui.NavigationTable;
|
||||||
import com.google.gerrit.client.ui.PatchLink;
|
import com.google.gerrit.client.ui.PatchLink;
|
||||||
import com.google.gerrit.common.data.PatchSetDetail;
|
import com.google.gerrit.common.data.PatchSetDetail;
|
||||||
|
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DiffView;
|
||||||
import com.google.gerrit.reviewdb.client.Patch;
|
import com.google.gerrit.reviewdb.client.Patch;
|
||||||
import com.google.gerrit.reviewdb.client.Patch.ChangeType;
|
import com.google.gerrit.reviewdb.client.Patch.ChangeType;
|
||||||
import com.google.gerrit.reviewdb.client.Patch.Key;
|
import com.google.gerrit.reviewdb.client.Patch.Key;
|
||||||
@@ -238,21 +239,23 @@ public class PatchTable extends Composite {
|
|||||||
/**
|
/**
|
||||||
* @return a link to the the given patch.
|
* @return a link to the the given patch.
|
||||||
* @param index The patch to link to
|
* @param index The patch to link to
|
||||||
* @param patchType The type of patch display
|
* @param screenType The screen type of patch display
|
||||||
* @param before A string to display at the beginning of the href text
|
* @param before A string to display at the beginning of the href text
|
||||||
* @param after A string to display at the end of the href text
|
* @param after A string to display at the end of the href text
|
||||||
*/
|
*/
|
||||||
public PatchLink createLink(int index, PatchScreen.Type patchType,
|
public PatchLink createLink(int index, PatchScreen.Type screenType,
|
||||||
SafeHtml before, SafeHtml after) {
|
SafeHtml before, SafeHtml after) {
|
||||||
Patch patch = patchList.get(index);
|
Patch patch = patchList.get(index);
|
||||||
|
|
||||||
Key thisKey = patch.getKey();
|
Key thisKey = patch.getKey();
|
||||||
PatchLink link;
|
PatchLink link;
|
||||||
if (patchType == PatchScreen.Type.SIDE_BY_SIDE) {
|
|
||||||
link = new PatchLink.SideBySide("", base, thisKey, index, detail, this);
|
if (isUnifiedPatchLink(patch, screenType)) {
|
||||||
} else {
|
|
||||||
link = new PatchLink.Unified("", base, thisKey, index, detail, this);
|
link = new PatchLink.Unified("", base, thisKey, index, detail, this);
|
||||||
|
} else {
|
||||||
|
link = new PatchLink.SideBySide("", base, thisKey, index, detail, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SafeHtmlBuilder text = new SafeHtmlBuilder();
|
SafeHtmlBuilder text = new SafeHtmlBuilder();
|
||||||
text.append(before);
|
text.append(before);
|
||||||
text.append(getFileNameOnly(patch));
|
text.append(getFileNameOnly(patch));
|
||||||
@@ -261,6 +264,16 @@ public class PatchTable extends Composite {
|
|||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isUnifiedPatchLink(final Patch patch,
|
||||||
|
final PatchScreen.Type screenType) {
|
||||||
|
if (Dispatcher.isChangeScreen2()) {
|
||||||
|
return (patch.getPatchType().equals(PatchType.BINARY)
|
||||||
|
|| Gerrit.getUserAccount().getGeneralPreferences().getDiffView()
|
||||||
|
.equals(DiffView.UNIFIED_DIFF));
|
||||||
|
}
|
||||||
|
return screenType == PatchScreen.Type.UNIFIED;
|
||||||
|
}
|
||||||
|
|
||||||
private static String getFileNameOnly(Patch patch) {
|
private static String getFileNameOnly(Patch patch) {
|
||||||
// Note: use '/' here and not File.pathSeparator since git paths
|
// Note: use '/' here and not File.pathSeparator since git paths
|
||||||
// are always separated by /
|
// are always separated by /
|
||||||
|
@@ -250,11 +250,13 @@ class Header extends Composite {
|
|||||||
: Dispatcher.toSideBySide(base, patchSetId, info.path());
|
: Dispatcher.toSideBySide(base, patchSetId, info.path());
|
||||||
}
|
}
|
||||||
|
|
||||||
private KeyCommand setupNav(InlineHyperlink link, int key, String help, FileInfo info) {
|
private KeyCommand setupNav(InlineHyperlink link, char key, String help, FileInfo info) {
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
final String url = url(info);
|
final String url = url(info);
|
||||||
link.setTargetHistoryToken(url);
|
link.setTargetHistoryToken(url);
|
||||||
link.setTitle(FileInfo.getFileName(info.path()));
|
link.setTitle(PatchUtil.M.fileNameWithShortcutKey(
|
||||||
|
FileInfo.getFileName(info.path()),
|
||||||
|
Character.toString(key)));
|
||||||
KeyCommand k = new KeyCommand(0, key, help) {
|
KeyCommand k = new KeyCommand(0, key, help) {
|
||||||
@Override
|
@Override
|
||||||
public void onKeyPress(KeyPressEvent event) {
|
public void onKeyPress(KeyPressEvent event) {
|
||||||
|
@@ -23,4 +23,5 @@ public interface PatchMessages extends Messages {
|
|||||||
String expandAfter(int cnt);
|
String expandAfter(int cnt);
|
||||||
String draftSaved(Date when);
|
String draftSaved(Date when);
|
||||||
String patchSkipRegion(String lineNumber);
|
String patchSkipRegion(String lineNumber);
|
||||||
|
String fileNameWithShortcutKey(String file, String key);
|
||||||
}
|
}
|
||||||
|
@@ -2,3 +2,4 @@ expandBefore = +{0}⇧
|
|||||||
expandAfter = +{0}⇩
|
expandAfter = +{0}⇩
|
||||||
draftSaved = Draft saved at {0,time,short}
|
draftSaved = Draft saved at {0,time,short}
|
||||||
patchSkipRegion = ... skipped {0} common lines ...
|
patchSkipRegion = ... skipped {0} common lines ...
|
||||||
|
fileNameWithShortcutKey = {0} (Shortcut: {1})
|
||||||
|
@@ -53,16 +53,24 @@ public class ProjectMap extends NativeMap<ProjectInfo> {
|
|||||||
.get(NativeMap.copyKeysIntoChildren(cb));
|
.get(NativeMap.copyKeysIntoChildren(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void match(String match, AsyncCallback<ProjectMap> cb) {
|
public static void match(String match, int limit, int start, AsyncCallback<ProjectMap> cb) {
|
||||||
if (match == null || "".equals(match)) {
|
RestApi call = new RestApi("/projects/");
|
||||||
all(cb);
|
if (match != null) {
|
||||||
} else {
|
call.addParameter("m", match);
|
||||||
new RestApi("/projects/")
|
|
||||||
.addParameter("m", match)
|
|
||||||
.addParameterRaw("type", "ALL")
|
|
||||||
.addParameterTrue("d") // description
|
|
||||||
.get(NativeMap.copyKeysIntoChildren(cb));
|
|
||||||
}
|
}
|
||||||
|
if (limit > 0) {
|
||||||
|
call.addParameter("n", limit);
|
||||||
|
}
|
||||||
|
if (start > 0) {
|
||||||
|
call.addParameter("S", start);
|
||||||
|
}
|
||||||
|
call.addParameterRaw("type", "ALL");
|
||||||
|
call.addParameterTrue("d"); // description
|
||||||
|
call.get(NativeMap.copyKeysIntoChildren(cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void match(String match, AsyncCallback<ProjectMap> cb) {
|
||||||
|
match(match, 0, 0, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ProjectMap() {
|
protected ProjectMap() {
|
||||||
|
@@ -61,6 +61,10 @@ public class ProjectsTable extends NavigationTable<ProjectInfo> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void display(ProjectMap projects) {
|
public void display(ProjectMap projects) {
|
||||||
|
displaySubset(projects, 0, projects.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void displaySubset(ProjectMap projects, int fromIndex, int toIndex) {
|
||||||
while (1 < table.getRowCount())
|
while (1 < table.getRowCount())
|
||||||
table.removeRow(table.getRowCount() - 1);
|
table.removeRow(table.getRowCount() - 1);
|
||||||
|
|
||||||
@@ -71,7 +75,7 @@ public class ProjectsTable extends NavigationTable<ProjectInfo> {
|
|||||||
return a.name().compareTo(b.name());
|
return a.name().compareTo(b.name());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
for(ProjectInfo p : list)
|
for(ProjectInfo p : list.subList(fromIndex, toIndex))
|
||||||
insert(table.getRowCount(), p);
|
insert(table.getRowCount(), p);
|
||||||
|
|
||||||
finishDisplay();
|
finishDisplay();
|
||||||
|
@@ -16,7 +16,7 @@ package com.google.gerrit.lucene;
|
|||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.common.util.concurrent.AbstractFuture;
|
import com.google.common.util.concurrent.AbstractFuture;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
@@ -39,13 +39,12 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
/** Piece of the change index that is implemented as a separate Lucene index. */
|
/** Piece of the change index that is implemented as a separate Lucene index. */
|
||||||
class SubIndex {
|
class SubIndex {
|
||||||
@@ -55,7 +54,7 @@ class SubIndex {
|
|||||||
private final TrackingIndexWriter writer;
|
private final TrackingIndexWriter writer;
|
||||||
private final SearcherManager searcherManager;
|
private final SearcherManager searcherManager;
|
||||||
private final ControlledRealTimeReopenThread<IndexSearcher> reopenThread;
|
private final ControlledRealTimeReopenThread<IndexSearcher> reopenThread;
|
||||||
private final ConcurrentMap<RefreshListener, Boolean> refreshListeners;
|
private final Set<NrtFuture> notDoneNrtFutures;
|
||||||
|
|
||||||
SubIndex(File file, GerritIndexWriterConfig writerConfig) throws IOException {
|
SubIndex(File file, GerritIndexWriterConfig writerConfig) throws IOException {
|
||||||
this(FSDirectory.open(file), file.getName(), writerConfig);
|
this(FSDirectory.open(file), file.getName(), writerConfig);
|
||||||
@@ -107,7 +106,7 @@ class SubIndex {
|
|||||||
searcherManager = new SearcherManager(
|
searcherManager = new SearcherManager(
|
||||||
writer.getIndexWriter(), true, new SearcherFactory());
|
writer.getIndexWriter(), true, new SearcherFactory());
|
||||||
|
|
||||||
refreshListeners = Maps.newConcurrentMap();
|
notDoneNrtFutures = Sets.newConcurrentHashSet();
|
||||||
searcherManager.addListener(new RefreshListener() {
|
searcherManager.addListener(new RefreshListener() {
|
||||||
@Override
|
@Override
|
||||||
public void beforeRefresh() throws IOException {
|
public void beforeRefresh() throws IOException {
|
||||||
@@ -115,8 +114,8 @@ class SubIndex {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterRefresh(boolean didRefresh) throws IOException {
|
public void afterRefresh(boolean didRefresh) throws IOException {
|
||||||
for (RefreshListener l : refreshListeners.keySet()) {
|
for (NrtFuture f : notDoneNrtFutures) {
|
||||||
l.afterRefresh(didRefresh);
|
f.removeIfDone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -176,10 +175,8 @@ class SubIndex {
|
|||||||
searcherManager.release(searcher);
|
searcherManager.release(searcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class NrtFuture extends AbstractFuture<Void>
|
private final class NrtFuture extends AbstractFuture<Void> {
|
||||||
implements RefreshListener {
|
|
||||||
private final long gen;
|
private final long gen;
|
||||||
private final AtomicBoolean hasListeners = new AtomicBoolean();
|
|
||||||
|
|
||||||
NrtFuture(long gen) {
|
NrtFuture(long gen) {
|
||||||
this.gen = gen;
|
this.gen = gen;
|
||||||
@@ -198,9 +195,12 @@ class SubIndex {
|
|||||||
public Void get(long timeout, TimeUnit unit) throws InterruptedException,
|
public Void get(long timeout, TimeUnit unit) throws InterruptedException,
|
||||||
TimeoutException, ExecutionException {
|
TimeoutException, ExecutionException {
|
||||||
if (!isDone()) {
|
if (!isDone()) {
|
||||||
reopenThread.waitForGeneration(gen,
|
if (reopenThread.waitForGeneration(gen,
|
||||||
(int) MILLISECONDS.convert(timeout, unit));
|
(int) MILLISECONDS.convert(timeout, unit))) {
|
||||||
set(null);
|
set(null);
|
||||||
|
} else {
|
||||||
|
throw new TimeoutException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return super.get(timeout, unit);
|
return super.get(timeout, unit);
|
||||||
}
|
}
|
||||||
@@ -209,7 +209,7 @@ class SubIndex {
|
|||||||
public boolean isDone() {
|
public boolean isDone() {
|
||||||
if (super.isDone()) {
|
if (super.isDone()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (isSearcherCurrent()) {
|
} else if (isGenAvailableNowForCurrentSearcher()) {
|
||||||
set(null);
|
set(null);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -218,33 +218,31 @@ class SubIndex {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addListener(Runnable listener, Executor executor) {
|
public void addListener(Runnable listener, Executor executor) {
|
||||||
if (hasListeners.compareAndSet(false, true) && !isDone()) {
|
if (!isDone()) {
|
||||||
searcherManager.addListener(this);
|
notDoneNrtFutures.add(this);
|
||||||
}
|
}
|
||||||
super.addListener(listener, executor);
|
super.addListener(listener, executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||||
if (hasListeners.get()) {
|
boolean result = super.cancel(mayInterruptIfRunning);
|
||||||
refreshListeners.put(this, true);
|
if (result) {
|
||||||
|
notDoneNrtFutures.remove(this);
|
||||||
}
|
}
|
||||||
return super.cancel(mayInterruptIfRunning);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void removeIfDone() {
|
||||||
public void beforeRefresh() throws IOException {
|
if (isGenAvailableNowForCurrentSearcher()) {
|
||||||
}
|
notDoneNrtFutures.remove(this);
|
||||||
|
if (!isCancelled()) {
|
||||||
@Override
|
set(null);
|
||||||
public void afterRefresh(boolean didRefresh) throws IOException {
|
}
|
||||||
if (isSearcherCurrent()) {
|
|
||||||
refreshListeners.remove(this);
|
|
||||||
set(null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSearcherCurrent() {
|
private boolean isGenAvailableNowForCurrentSearcher() {
|
||||||
try {
|
try {
|
||||||
return reopenThread.waitForGeneration(gen, 0);
|
return reopenThread.waitForGeneration(gen, 0);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
@@ -143,6 +143,11 @@ public class ListProjects implements RestReadView<TopLevelResource> {
|
|||||||
this.limit = limit;
|
this.limit = limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Option(name = "-S", metaVar = "CNT", usage = "number of projects to skip")
|
||||||
|
public void setStart(int start) {
|
||||||
|
this.start = start;
|
||||||
|
}
|
||||||
|
|
||||||
@Option(name = "-p", metaVar = "PREFIX", usage = "match project prefix")
|
@Option(name = "-p", metaVar = "PREFIX", usage = "match project prefix")
|
||||||
public void setMatchPrefix(String matchPrefix) {
|
public void setMatchPrefix(String matchPrefix) {
|
||||||
this.matchPrefix = matchPrefix;
|
this.matchPrefix = matchPrefix;
|
||||||
@@ -165,6 +170,7 @@ public class ListProjects implements RestReadView<TopLevelResource> {
|
|||||||
private boolean showDescription;
|
private boolean showDescription;
|
||||||
private boolean all;
|
private boolean all;
|
||||||
private int limit;
|
private int limit;
|
||||||
|
private int start;
|
||||||
private String matchPrefix;
|
private String matchPrefix;
|
||||||
private String matchSubstring;
|
private String matchSubstring;
|
||||||
private AccountGroup.UUID groupUuid;
|
private AccountGroup.UUID groupUuid;
|
||||||
@@ -230,6 +236,7 @@ public class ListProjects implements RestReadView<TopLevelResource> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int foundIndex = 0;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
Map<String, ProjectInfo> output = Maps.newTreeMap();
|
Map<String, ProjectInfo> output = Maps.newTreeMap();
|
||||||
Map<String, String> hiddenNames = Maps.newHashMap();
|
Map<String, String> hiddenNames = Maps.newHashMap();
|
||||||
@@ -362,6 +369,10 @@ public class ListProjects implements RestReadView<TopLevelResource> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (foundIndex++ < start) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (limit > 0 && ++found > limit) {
|
if (limit > 0 && ++found > limit) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -39,8 +39,10 @@ import com.google.gerrit.server.config.GerritServerConfig;
|
|||||||
import com.google.gerrit.server.config.SitePath;
|
import com.google.gerrit.server.config.SitePath;
|
||||||
import com.google.gerrit.server.config.TrackingFooters;
|
import com.google.gerrit.server.config.TrackingFooters;
|
||||||
import com.google.gerrit.server.config.TrackingFootersProvider;
|
import com.google.gerrit.server.config.TrackingFootersProvider;
|
||||||
|
import com.google.gerrit.server.git.EmailReviewCommentsExecutor;
|
||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
import com.google.gerrit.server.git.PerThreadRequestScope;
|
import com.google.gerrit.server.git.PerThreadRequestScope;
|
||||||
|
import com.google.gerrit.server.git.WorkQueue;
|
||||||
import com.google.gerrit.server.index.ChangeSchemas;
|
import com.google.gerrit.server.index.ChangeSchemas;
|
||||||
import com.google.gerrit.server.index.IndexModule.IndexType;
|
import com.google.gerrit.server.index.IndexModule.IndexType;
|
||||||
import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier;
|
import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier;
|
||||||
@@ -174,6 +176,15 @@ public class InMemoryModule extends FactoryModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
@EmailReviewCommentsExecutor
|
||||||
|
public WorkQueue.Executor createEmailReviewCommentsExecutor(
|
||||||
|
@GerritServerConfig Config config, WorkQueue queues) {
|
||||||
|
int poolSize = config.getInt("sendemail", null, "threadPoolSize", 1);
|
||||||
|
return queues.createQueue(poolSize, "EmailReviewComments");
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
InMemoryDatabase getInMemoryDatabase(@Current SchemaVersion schemaVersion,
|
InMemoryDatabase getInMemoryDatabase(@Current SchemaVersion schemaVersion,
|
||||||
|
@@ -143,6 +143,7 @@ public class SetReviewersCommand extends SshCommand {
|
|||||||
for (String reviewer : toAdd) {
|
for (String reviewer : toAdd) {
|
||||||
AddReviewerInput input = new AddReviewerInput();
|
AddReviewerInput input = new AddReviewerInput();
|
||||||
input.reviewer = reviewer;
|
input.reviewer = reviewer;
|
||||||
|
input.confirmed = true;
|
||||||
String error;
|
String error;
|
||||||
try {
|
try {
|
||||||
error = post.apply(changeRsrc, input).error;
|
error = post.apply(changeRsrc, input).error;
|
||||||
|
Reference in New Issue
Block a user