Merge changes from topic 'inline-4'
* changes: Inline Edit: Suggest paths to add ChangeScreen2: Fix double error glass when disconnected Inline Edit: Display cursor position in bottom left Inline Edit: Cleanup client utility API Remove /type REST API projections Inline Edit: Acquire content and type in one request Inline Edit: Honor project specific MIME types
This commit is contained in:
@@ -1408,8 +1408,16 @@ Retrieves content of a file from a change edit.
|
||||
GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/edit/foo HTTP/1.0
|
||||
----
|
||||
|
||||
The content of the file is returned as text encoded inside base64. When
|
||||
specified file was deleted in the change edit "`204 No Content`" is returned.
|
||||
The content of the file is returned as text encoded inside base64.
|
||||
The Content-Type header will always be `text/plain` reflecting the
|
||||
outer base64 encoding. A Gerrit-specific `X-FYI-Content-Type` header
|
||||
can be examined to find the server detected content type of the file.
|
||||
|
||||
When the specified file was deleted in the change edit
|
||||
"`204 No Content`" is returned.
|
||||
|
||||
If only the content type is required, callers should use HEAD to
|
||||
avoid downloading the encoded file contents.
|
||||
|
||||
.Response
|
||||
----
|
||||
@@ -1417,33 +1425,11 @@ specified file was deleted in the change edit "`204 No Content`" is returned.
|
||||
Content-Disposition: attachment
|
||||
Content-Type: text/plain; charset=ISO-8859-1
|
||||
X-FYI-Content-Encoding: base64
|
||||
X-FYI-Content-Type: text/xml
|
||||
|
||||
RnJvbSA3ZGFkY2MxNTNmZGVhMTdhYTg0ZmYzMmE2ZTI0NWRiYjY...
|
||||
----
|
||||
|
||||
[[get-edit-file-mime-type]]
|
||||
=== Retrieve file content MIME type from Change Edit
|
||||
--
|
||||
'GET /changes/link:#change-id[\{change-id\}]/edit/path%2fto%2ffile/type
|
||||
--
|
||||
|
||||
Retrieves content MIME type of a file from a change edit.
|
||||
|
||||
.Request
|
||||
----
|
||||
GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/edit/foo%2fbar%2fbaz%2fqux.txt/type HTTP/1.0
|
||||
----
|
||||
|
||||
.Response
|
||||
----
|
||||
HTTP/1.1 200 OK
|
||||
Content-Disposition: attachment
|
||||
Content-Type: application/json; charset=UTF-8
|
||||
|
||||
)]}'
|
||||
"text/plain"
|
||||
----
|
||||
|
||||
[[get-edit-message]]
|
||||
=== Retrieve commit message from Change Edit or current patch set of the change
|
||||
--
|
||||
@@ -2758,6 +2744,11 @@ The request parameter `reviewed` changes the response to return a list
|
||||
of the paths the caller has marked as reviewed. Clients that also
|
||||
need the FileInfo should make two requests.
|
||||
|
||||
The request parameter `q` changes the response to return a list
|
||||
of all files (modified or unmodified) that contain that substring
|
||||
in the path name. This is useful to implement suggestion services
|
||||
finding a file by partial name.
|
||||
|
||||
.Request
|
||||
----
|
||||
GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/674ac754f91e64a0efb8087e59a176484bd534d1/files/?reviewed HTTP/1.0
|
||||
@@ -2789,43 +2780,25 @@ Gets the content of a file from a certain revision.
|
||||
GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/674ac754f91e64a0efb8087e59a176484bd534d1/files/gerrit-server%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgoogle%2Fgerrit%2Fserver%2Fproject%2FRefControl.java/content HTTP/1.0
|
||||
----
|
||||
|
||||
The content is returned as base64 encoded string.
|
||||
The content is returned as base64 encoded string. The HTTP response
|
||||
Content-Type is always `text/plain`, reflecting the base64 wrapping.
|
||||
A Gerrit-specific `X-FYI-Content-Type` header is returned describing
|
||||
the server detected content type of the file.
|
||||
|
||||
If only the content type is required, callers should use HEAD to
|
||||
avoid downloading the encoded file contents.
|
||||
|
||||
.Response
|
||||
----
|
||||
HTTP/1.1 200 OK
|
||||
Content-Disposition: attachment
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Type: text/plain; charset=ISO-8859-1
|
||||
X-FYI-Content-Encoding: base64
|
||||
X-FYI-Content-Type: text/xml
|
||||
|
||||
Ly8gQ29weXJpZ2h0IChDKSAyMDEwIFRoZSBBbmRyb2lkIE9wZW4gU291cmNlIFByb2plY...
|
||||
----
|
||||
|
||||
[[get-content-type]]
|
||||
=== Get Content MIME Type
|
||||
--
|
||||
'GET /changes/link:#change-id[\{change-id\}]/revisions/link:#revision-id[\{revision-id\}]/files/link:#file-id[\{file-id\}]/type'
|
||||
--
|
||||
|
||||
Gets the content MIME type of a file from a certain revision.
|
||||
|
||||
.Request
|
||||
----
|
||||
GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/674ac754f91e64a0efb8087e59a176484bd534d1/files/readme.txt/type HTTP/1.0
|
||||
----
|
||||
|
||||
The content MIME type is returned as string. The content type for the commit
|
||||
message (`/COMMIT_MSG`) is always returned as "text/plain".
|
||||
|
||||
.Response
|
||||
----
|
||||
HTTP/1.1 200 OK
|
||||
Content-Disposition: attachment
|
||||
Content-Type: application/json; charset=UTF-8
|
||||
|
||||
)]}'
|
||||
"text/plain"
|
||||
----
|
||||
|
||||
[[get-diff]]
|
||||
=== Get Diff
|
||||
--
|
||||
|
||||
@@ -59,6 +59,7 @@ import com.google.inject.Inject;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.codec.binary.StringUtils;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
import org.eclipse.jgit.lib.RefUpdate;
|
||||
import org.joda.time.DateTime;
|
||||
@@ -194,10 +195,10 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
Date beforeRebase = edit.getEditCommit().getCommitterIdent().getWhen();
|
||||
modifier.rebaseEdit(edit, current);
|
||||
edit = editUtil.byChange(change).get();
|
||||
assertByteArray(fileUtil.getContent(edit.getChange().getProject(), edit
|
||||
.getRevision().get(), FILE_NAME), CONTENT_NEW);
|
||||
assertByteArray(fileUtil.getContent(edit.getChange().getProject(), edit
|
||||
.getRevision().get(), FILE_NAME2), CONTENT_NEW2);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()),
|
||||
ObjectId.fromString(edit.getRevision().get()), FILE_NAME), CONTENT_NEW);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()),
|
||||
ObjectId.fromString(edit.getRevision().get()), FILE_NAME2), CONTENT_NEW2);
|
||||
assertThat(edit.getBasePatchSet().getPatchSetId()).isEqualTo(
|
||||
current.getPatchSetId());
|
||||
Date afterRebase = edit.getEditCommit().getCommitterIdent().getWhen();
|
||||
@@ -218,10 +219,10 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
RestResponse r = adminSession.post(urlRebase());
|
||||
assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT);
|
||||
edit = editUtil.byChange(change).get();
|
||||
assertByteArray(fileUtil.getContent(edit.getChange().getProject(), edit
|
||||
.getRevision().get(), FILE_NAME), CONTENT_NEW);
|
||||
assertByteArray(fileUtil.getContent(edit.getChange().getProject(), edit
|
||||
.getRevision().get(), FILE_NAME2), CONTENT_NEW2);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()),
|
||||
ObjectId.fromString(edit.getRevision().get()), FILE_NAME), CONTENT_NEW);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()),
|
||||
ObjectId.fromString(edit.getRevision().get()), FILE_NAME2), CONTENT_NEW2);
|
||||
assertThat(edit.getBasePatchSet().getPatchSetId()).isEqualTo(
|
||||
current.getPatchSetId());
|
||||
Date afterRebase = edit.getEditCommit().getCommitterIdent().getWhen();
|
||||
@@ -235,9 +236,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW)))
|
||||
.isEqualTo(RefUpdate.Result.FORCED);
|
||||
edit = editUtil.byChange(change);
|
||||
assertByteArray(
|
||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
||||
.getRevision().get(), FILE_NAME), CONTENT_NEW);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW);
|
||||
editUtil.delete(edit.get());
|
||||
edit = editUtil.byChange(change);
|
||||
assertThat(edit.isPresent()).isFalse();
|
||||
@@ -364,8 +364,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
RefUpdate.Result.FORCED);
|
||||
edit = editUtil.byChange(change);
|
||||
try {
|
||||
fileUtil.getContent(edit.get().getChange().getProject(),
|
||||
edit.get().getRevision().get(), FILE_NAME);
|
||||
fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME);
|
||||
fail("ResourceNotFoundException expected");
|
||||
} catch (ResourceNotFoundException rnfe) {
|
||||
}
|
||||
@@ -377,8 +377,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT);
|
||||
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
||||
try {
|
||||
fileUtil.getContent(edit.get().getChange().getProject(),
|
||||
edit.get().getRevision().get(), FILE_NAME);
|
||||
fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME);
|
||||
fail("ResourceNotFoundException expected");
|
||||
} catch (ResourceNotFoundException rnfe) {
|
||||
}
|
||||
@@ -397,8 +397,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
SC_NO_CONTENT);
|
||||
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
||||
try {
|
||||
fileUtil.getContent(edit.get().getChange().getProject(),
|
||||
edit.get().getRevision().get(), FILE_NAME);
|
||||
fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME);
|
||||
fail("ResourceNotFoundException expected");
|
||||
} catch (ResourceNotFoundException rnfe) {
|
||||
}
|
||||
@@ -412,9 +412,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
assertThat(modifier.restoreFile(edit.get(), FILE_NAME)).isEqualTo(
|
||||
RefUpdate.Result.FORCED);
|
||||
edit = editUtil.byChange(change2);
|
||||
assertByteArray(
|
||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
||||
.getRevision().get(), FILE_NAME), CONTENT_OLD);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -424,9 +423,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
assertThat(adminSession.post(urlEdit2(), in).getStatusCode()).isEqualTo(
|
||||
SC_NO_CONTENT);
|
||||
Optional<ChangeEdit> edit = editUtil.byChange(change2);
|
||||
assertByteArray(
|
||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
||||
.getRevision().get(), FILE_NAME), CONTENT_OLD);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -436,15 +434,13 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW)))
|
||||
.isEqualTo(RefUpdate.Result.FORCED);
|
||||
edit = editUtil.byChange(change);
|
||||
assertByteArray(
|
||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
||||
.getRevision().get(), FILE_NAME), CONTENT_NEW);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW);
|
||||
assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW2)))
|
||||
.isEqualTo(RefUpdate.Result.FORCED);
|
||||
edit = editUtil.byChange(change);
|
||||
assertByteArray(
|
||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
||||
.getRevision().get(), FILE_NAME), CONTENT_NEW2);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -454,16 +450,14 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode())
|
||||
.isEqualTo(SC_NO_CONTENT);
|
||||
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
||||
assertByteArray(
|
||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
||||
.getRevision().get(), FILE_NAME), CONTENT_NEW);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW);
|
||||
in.content = RestSession.newRawInput(CONTENT_NEW2);
|
||||
assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode())
|
||||
.isEqualTo(SC_NO_CONTENT);
|
||||
edit = editUtil.byChange(change);
|
||||
assertByteArray(
|
||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
||||
.getRevision().get(), FILE_NAME), CONTENT_NEW2);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -474,9 +468,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode())
|
||||
.isEqualTo(SC_NO_CONTENT);
|
||||
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
||||
assertByteArray(
|
||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
||||
.getRevision().get(), FILE_NAME), CONTENT_NEW);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -485,9 +478,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
assertThat(adminSession.put(urlEditFile()).getStatusCode()).isEqualTo(
|
||||
SC_NO_CONTENT);
|
||||
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
||||
assertByteArray(
|
||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
||||
.getRevision().get(), FILE_NAME), "".getBytes());
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), "".getBytes());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -495,9 +487,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
assertThat(adminSession.post(urlEdit()).getStatusCode()).isEqualTo(
|
||||
SC_NO_CONTENT);
|
||||
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
||||
assertByteArray(
|
||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
||||
.getRevision().get(), FILE_NAME), CONTENT_OLD);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -517,18 +508,6 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
.isEqualTo(StringUtils.newStringUtf8(CONTENT_NEW2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFileContentTypeRest() throws Exception {
|
||||
Put.Input in = new Put.Input();
|
||||
in.content = RestSession.newRawInput(CONTENT_NEW);
|
||||
assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode())
|
||||
.isEqualTo(SC_NO_CONTENT);
|
||||
RestResponse r = adminSession.get(urlEditFileContentType());
|
||||
assertThat(r.getStatusCode()).isEqualTo(SC_OK);
|
||||
String res = newGson().fromJson(r.getReader(), String.class);
|
||||
assertThat(res).isEqualTo("application/octet-stream");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFileNotFoundRest() throws Exception {
|
||||
assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW);
|
||||
@@ -536,8 +515,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
SC_NO_CONTENT);
|
||||
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
||||
try {
|
||||
fileUtil.getContent(edit.get().getChange().getProject(),
|
||||
edit.get().getRevision().get(), FILE_NAME);
|
||||
fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME);
|
||||
fail("ResourceNotFoundException expected");
|
||||
} catch (ResourceNotFoundException rnfe) {
|
||||
}
|
||||
@@ -552,9 +531,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
assertThat(modifier.modifyFile(edit.get(), FILE_NAME2, RestSession.newRawInput(CONTENT_NEW)))
|
||||
.isEqualTo(RefUpdate.Result.FORCED);
|
||||
edit = editUtil.byChange(change);
|
||||
assertByteArray(
|
||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
||||
.getRevision().get(), FILE_NAME2), CONTENT_NEW);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME2), CONTENT_NEW);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -564,15 +542,13 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
assertThat(modifier.modifyFile(edit.get(), FILE_NAME2, RestSession.newRawInput(CONTENT_NEW)))
|
||||
.isEqualTo(RefUpdate.Result.FORCED);
|
||||
edit = editUtil.byChange(change);
|
||||
assertByteArray(
|
||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
||||
.getRevision().get(), FILE_NAME2), CONTENT_NEW);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME2), CONTENT_NEW);
|
||||
assertThat(modifier.modifyFile(edit.get(), FILE_NAME2, RestSession.newRawInput(CONTENT_NEW2)))
|
||||
.isEqualTo(RefUpdate.Result.FORCED);
|
||||
edit = editUtil.byChange(change);
|
||||
assertByteArray(
|
||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
||||
.getRevision().get(), FILE_NAME2), CONTENT_NEW2);
|
||||
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME2), CONTENT_NEW2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -684,13 +660,6 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
||||
+ FILE_NAME;
|
||||
}
|
||||
|
||||
private String urlEditFileContentType() {
|
||||
return urlEdit()
|
||||
+ "/"
|
||||
+ FILE_NAME
|
||||
+ "/type";
|
||||
}
|
||||
|
||||
private String urlGetFiles() {
|
||||
return urlEdit()
|
||||
+ "?list";
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
//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.change;
|
||||
|
||||
import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gwt.event.logical.shared.CloseEvent;
|
||||
import com.google.gwt.event.logical.shared.CloseHandler;
|
||||
import com.google.gwt.user.client.ui.PopupPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwtexpui.globalkey.client.GlobalKey;
|
||||
import com.google.gwtexpui.user.client.PluginSafePopupPanel;
|
||||
|
||||
class AddFileAction {
|
||||
private final Change.Id changeId;
|
||||
private final RevisionInfo revision;
|
||||
private final ChangeScreen2.Style style;
|
||||
private final Widget addButton;
|
||||
|
||||
private AddFileBox addBox;
|
||||
private PopupPanel popup;
|
||||
|
||||
AddFileAction(Change.Id changeId, RevisionInfo revision,
|
||||
ChangeScreen2.Style style, Widget addButton) {
|
||||
this.changeId = changeId;
|
||||
this.revision = revision;
|
||||
this.style = style;
|
||||
this.addButton = addButton;
|
||||
}
|
||||
|
||||
public void onEdit() {
|
||||
if (popup != null) {
|
||||
popup.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (addBox == null) {
|
||||
addBox = new AddFileBox(changeId, revision);
|
||||
}
|
||||
addBox.clearPath();
|
||||
|
||||
final PluginSafePopupPanel p = new PluginSafePopupPanel(true);
|
||||
p.setStyleName(style.replyBox());
|
||||
p.addAutoHidePartner(addButton.getElement());
|
||||
p.addCloseHandler(new CloseHandler<PopupPanel>() {
|
||||
@Override
|
||||
public void onClose(CloseEvent<PopupPanel> event) {
|
||||
if (popup == p) {
|
||||
popup = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
p.add(addBox);
|
||||
p.showRelativeTo(addButton);
|
||||
GlobalKey.dialog(p);
|
||||
addBox.setFocus(true);
|
||||
popup = p;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
//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.change;
|
||||
|
||||
import com.google.gerrit.client.Dispatcher;
|
||||
import com.google.gerrit.client.Gerrit;
|
||||
import com.google.gerrit.client.changes.ChangeApi;
|
||||
import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
|
||||
import com.google.gerrit.client.rpc.Natives;
|
||||
import com.google.gerrit.client.ui.RemoteSuggestBox;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.core.client.JsArrayString;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.logical.shared.CloseEvent;
|
||||
import com.google.gwt.event.logical.shared.CloseHandler;
|
||||
import com.google.gwt.event.logical.shared.SelectionEvent;
|
||||
import com.google.gwt.event.logical.shared.SelectionHandler;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.uibinder.client.UiHandler;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
import com.google.gwt.user.client.ui.PopupPanel;
|
||||
import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwtexpui.safehtml.client.HighlightSuggestOracle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
class AddFileBox extends Composite {
|
||||
interface Binder extends UiBinder<HTMLPanel, AddFileBox> {}
|
||||
private static final Binder uiBinder = GWT.create(Binder.class);
|
||||
|
||||
private final Change.Id changeId;
|
||||
private final RevisionInfo revision;
|
||||
|
||||
@UiField Button open;
|
||||
@UiField Button cancel;
|
||||
|
||||
@UiField(provided = true)
|
||||
RemoteSuggestBox path;
|
||||
|
||||
AddFileBox(Change.Id changeId, RevisionInfo revision) {
|
||||
this.changeId = changeId;
|
||||
this.revision = revision;
|
||||
|
||||
path = new RemoteSuggestBox(new PathSuggestOracle());
|
||||
path.addSelectionHandler(new SelectionHandler<String>() {
|
||||
@Override
|
||||
public void onSelection(SelectionEvent<String> event) {
|
||||
open(event.getSelectedItem());
|
||||
}
|
||||
});
|
||||
path.addCloseHandler(new CloseHandler<RemoteSuggestBox>() {
|
||||
@Override
|
||||
public void onClose(CloseEvent<RemoteSuggestBox> event) {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
}
|
||||
|
||||
void setFocus(boolean focus) {
|
||||
path.setFocus(focus);
|
||||
}
|
||||
|
||||
void clearPath() {
|
||||
path.setText("");
|
||||
}
|
||||
|
||||
@UiHandler("open")
|
||||
void onOpen(@SuppressWarnings("unused") ClickEvent e) {
|
||||
open(path.getText());
|
||||
}
|
||||
|
||||
private void open(String path) {
|
||||
hide();
|
||||
Gerrit.display(Dispatcher.toEditScreen(
|
||||
new PatchSet.Id(changeId, revision._number()),
|
||||
path));
|
||||
}
|
||||
|
||||
@UiHandler("cancel")
|
||||
void onCancel(@SuppressWarnings("unused") ClickEvent e) {
|
||||
hide();
|
||||
}
|
||||
|
||||
private void hide() {
|
||||
for (Widget w = getParent(); w != null; w = w.getParent()) {
|
||||
if (w instanceof PopupPanel) {
|
||||
((PopupPanel) w).hide();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PathSuggestOracle extends HighlightSuggestOracle {
|
||||
@Override
|
||||
protected void onRequestSuggestions(final Request req, final Callback cb) {
|
||||
ChangeApi.revision(changeId.get(), revision.name())
|
||||
.view("files")
|
||||
.addParameter("q", req.getQuery())
|
||||
.background()
|
||||
.get(new AsyncCallback<JsArrayString>() {
|
||||
@Override
|
||||
public void onSuccess(JsArrayString result) {
|
||||
List<Suggestion> r = new ArrayList<>();
|
||||
for (String path : Natives.asList(result)) {
|
||||
r.add(new PathSuggestion(path));
|
||||
}
|
||||
cb.onSuggestionsReady(req, new Response(r));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
List<Suggestion> none = Collections.emptyList();
|
||||
cb.onSuggestionsReady(req, new Response(none));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static class PathSuggestion implements Suggestion {
|
||||
private final String path;
|
||||
|
||||
PathSuggestion(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayString() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReplacementString() {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,40 +16,22 @@ limitations under the License.
|
||||
-->
|
||||
<ui:UiBinder
|
||||
xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||
xmlns:c='urn:import:com.google.gwtexpui.globalkey.client'
|
||||
xmlns:f='urn:import:com.google.gerrit.client.change'
|
||||
xmlns:u='urn:import:com.google.gerrit.client.ui'
|
||||
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
||||
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
|
||||
<ui:style>
|
||||
.fileContent {
|
||||
background-color: white;
|
||||
font-family: monospace;
|
||||
}
|
||||
.cancel { float: right; }
|
||||
</ui:style>
|
||||
<g:HTMLPanel>
|
||||
<div class='{res.style.section}'>
|
||||
<div>
|
||||
<ui:msg>Path:</ui:msg>
|
||||
</div>
|
||||
<div>
|
||||
<f:FileTextBox ui:field='file' visibleLength='79'/>
|
||||
</div>
|
||||
<div>
|
||||
<ui:msg>Content:</ui:msg>
|
||||
</div>
|
||||
<c:NpTextArea
|
||||
visibleLines='30'
|
||||
characterWidth='78'
|
||||
styleName='{style.fileContent}'
|
||||
ui:field='content'/>
|
||||
<ui:msg>Path: <u:RemoteSuggestBox ui:field='path' visibleLength='86'/></ui:msg>
|
||||
</div>
|
||||
<div class='{res.style.section}'>
|
||||
<g:Button ui:field='save'
|
||||
title='Create new revision edit'
|
||||
<g:Button ui:field='open'
|
||||
title='Open file in editor'
|
||||
styleName='{res.style.button}'>
|
||||
<ui:attribute name='title'/>
|
||||
<div><ui:msg>Save</ui:msg></div>
|
||||
<div><ui:msg>Open</ui:msg></div>
|
||||
</g:Button>
|
||||
<g:Button ui:field='cancel'
|
||||
styleName='{res.style.button}'
|
||||
@@ -193,7 +193,7 @@ public class ChangeScreen2 extends Screen {
|
||||
private IncludedInAction includedInAction;
|
||||
private PatchSetsAction patchSetsAction;
|
||||
private DownloadAction downloadAction;
|
||||
private EditFileAction editFileAction;
|
||||
private AddFileAction addFileAction;
|
||||
|
||||
public ChangeScreen2(Change.Id changeId, String base, String revision,
|
||||
boolean openReplyBox, FileTable.Mode mode) {
|
||||
@@ -215,11 +215,15 @@ public class ChangeScreen2 extends Screen {
|
||||
CallbackGroup group = new CallbackGroup();
|
||||
if (Gerrit.isSignedIn()) {
|
||||
ChangeApi.editWithFiles(changeId.get(), group.add(
|
||||
new GerritCallback<EditInfo>() {
|
||||
new AsyncCallback<EditInfo>() {
|
||||
@Override
|
||||
public void onSuccess(EditInfo result) {
|
||||
edit = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
}
|
||||
}));
|
||||
}
|
||||
loadChangeInfo(true, group.addFinal(
|
||||
@@ -444,9 +448,9 @@ public class ChangeScreen2 extends Screen {
|
||||
editMode.setVisible(fileTableMode == FileTable.Mode.REVIEW);
|
||||
addFile.setVisible(!editMode.isVisible());
|
||||
reviewMode.setVisible(!editMode.isVisible());
|
||||
editFileAction = new EditFileAction(
|
||||
new PatchSet.Id(changeId, edit == null ? rev._number() : 0),
|
||||
"", "", style, editMessage, reply);
|
||||
addFileAction = new AddFileAction(
|
||||
changeId, info.revision(revision),
|
||||
style, addFile);
|
||||
} else {
|
||||
editMode.setVisible(false);
|
||||
addFile.setVisible(false);
|
||||
@@ -621,7 +625,7 @@ public class ChangeScreen2 extends Screen {
|
||||
|
||||
@UiHandler("addFile")
|
||||
void onAddFile(@SuppressWarnings("unused") ClickEvent e) {
|
||||
editFileAction.onEdit();
|
||||
addFileAction.onEdit();
|
||||
}
|
||||
|
||||
private void refreshFileTable() {
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
//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.change;
|
||||
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gwt.event.logical.shared.CloseEvent;
|
||||
import com.google.gwt.event.logical.shared.CloseHandler;
|
||||
import com.google.gwt.user.client.ui.PopupPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwtexpui.globalkey.client.GlobalKey;
|
||||
import com.google.gwtexpui.user.client.PluginSafePopupPanel;
|
||||
|
||||
class EditFileAction {
|
||||
private final PatchSet.Id id;
|
||||
private final String content;
|
||||
private final String file;
|
||||
private final ChangeScreen2.Style style;
|
||||
private final Widget editMessageButton;
|
||||
private final Widget relativeTo;
|
||||
|
||||
private EditFileBox editBox;
|
||||
private PopupPanel popup;
|
||||
|
||||
EditFileAction(
|
||||
PatchSet.Id id,
|
||||
String content,
|
||||
String file,
|
||||
ChangeScreen2.Style style,
|
||||
Widget editButton,
|
||||
Widget relativeTo) {
|
||||
this.id = id;
|
||||
this.content = content;
|
||||
this.file = file;
|
||||
this.style = style;
|
||||
this.editMessageButton = editButton;
|
||||
this.relativeTo = relativeTo;
|
||||
}
|
||||
|
||||
public void onEdit() {
|
||||
if (popup != null) {
|
||||
popup.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (editBox == null) {
|
||||
editBox = new EditFileBox(
|
||||
id,
|
||||
content,
|
||||
file);
|
||||
}
|
||||
|
||||
final PluginSafePopupPanel p = new PluginSafePopupPanel(true);
|
||||
p.setStyleName(style.replyBox());
|
||||
p.addAutoHidePartner(editMessageButton.getElement());
|
||||
p.addCloseHandler(new CloseHandler<PopupPanel>() {
|
||||
@Override
|
||||
public void onClose(CloseEvent<PopupPanel> event) {
|
||||
if (popup == p) {
|
||||
popup = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
p.add(editBox);
|
||||
p.showRelativeTo(relativeTo);
|
||||
GlobalKey.dialog(p);
|
||||
popup = p;
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
//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.change;
|
||||
|
||||
import com.google.gerrit.client.Gerrit;
|
||||
import com.google.gerrit.client.VoidResult;
|
||||
import com.google.gerrit.client.changes.ChangeFileApi;
|
||||
import com.google.gerrit.client.rpc.GerritCallback;
|
||||
import com.google.gerrit.client.ui.TextBoxChangeListener;
|
||||
import com.google.gerrit.common.PageLinks;
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.core.client.Scheduler;
|
||||
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.uibinder.client.UiHandler;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
import com.google.gwt.user.client.ui.PopupPanel;
|
||||
import com.google.gwt.user.client.ui.TextBoxBase;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwtexpui.globalkey.client.NpTextArea;
|
||||
|
||||
class EditFileBox extends Composite {
|
||||
interface Binder extends UiBinder<HTMLPanel, EditFileBox> {}
|
||||
private static final Binder uiBinder = GWT.create(Binder.class);
|
||||
|
||||
private final PatchSet.Id id;
|
||||
private final String fileName;
|
||||
private final String fileContent;
|
||||
|
||||
@UiField FileTextBox file;
|
||||
@UiField NpTextArea content;
|
||||
@UiField Button save;
|
||||
@UiField Button cancel;
|
||||
|
||||
EditFileBox(
|
||||
PatchSet.Id id,
|
||||
String fileC,
|
||||
String fileName) {
|
||||
this.id = id;
|
||||
this.fileName = fileName;
|
||||
this.fileContent = fileC;
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
new EditFileBoxListener(content);
|
||||
new EditFileBoxListener(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoad() {
|
||||
file.set(id, content);
|
||||
file.setText(fileName);
|
||||
file.setEnabled(fileName.isEmpty());
|
||||
content.setText(fileContent);
|
||||
save.setEnabled(false);
|
||||
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||
@Override
|
||||
public void execute() {
|
||||
if (fileName.isEmpty()) {
|
||||
file.setFocus(true);
|
||||
} else {
|
||||
content.setFocus(true);
|
||||
}
|
||||
}});
|
||||
}
|
||||
|
||||
@UiHandler("save")
|
||||
void onSave(@SuppressWarnings("unused") ClickEvent e) {
|
||||
ChangeFileApi.putContent(id, file.getText(), content.getText(),
|
||||
new GerritCallback<VoidResult>() {
|
||||
@Override
|
||||
public void onSuccess(VoidResult result) {
|
||||
Gerrit.display(PageLinks.toChangeInEditMode(id.getParentKey()));
|
||||
hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@UiHandler("cancel")
|
||||
void onCancel(@SuppressWarnings("unused") ClickEvent e) {
|
||||
hide();
|
||||
}
|
||||
|
||||
protected void hide() {
|
||||
for (Widget w = getParent(); w != null; w = w.getParent()) {
|
||||
if (w instanceof PopupPanel) {
|
||||
((PopupPanel) w).hide();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class EditFileBoxListener extends TextBoxChangeListener {
|
||||
public EditFileBoxListener(TextBoxBase base) {
|
||||
super(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(String newText) {
|
||||
save.setEnabled(!file.getText().trim().isEmpty()
|
||||
&& !newText.trim().equals(fileContent));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ package com.google.gerrit.client.change;
|
||||
|
||||
import com.google.gerrit.client.Gerrit;
|
||||
import com.google.gerrit.client.VoidResult;
|
||||
import com.google.gerrit.client.changes.ChangeFileApi;
|
||||
import com.google.gerrit.client.changes.ChangeEditApi;
|
||||
import com.google.gerrit.client.rpc.GerritCallback;
|
||||
import com.google.gerrit.client.ui.TextBoxChangeListener;
|
||||
import com.google.gerrit.common.PageLinks;
|
||||
@@ -79,7 +79,7 @@ class EditMessageBox extends Composite {
|
||||
@UiHandler("save")
|
||||
void onSave(@SuppressWarnings("unused") ClickEvent e) {
|
||||
save.setEnabled(false);
|
||||
ChangeFileApi.putMessage(changeId, message.getText().trim(),
|
||||
ChangeEditApi.putMessage(changeId.get(), message.getText().trim(),
|
||||
new GerritCallback<VoidResult>() {
|
||||
@Override
|
||||
public void onSuccess(VoidResult result) {
|
||||
|
||||
@@ -18,7 +18,7 @@ import com.google.gerrit.client.Dispatcher;
|
||||
import com.google.gerrit.client.Gerrit;
|
||||
import com.google.gerrit.client.VoidResult;
|
||||
import com.google.gerrit.client.changes.ChangeApi;
|
||||
import com.google.gerrit.client.changes.ChangeFileApi;
|
||||
import com.google.gerrit.client.changes.ChangeEditApi;
|
||||
import com.google.gerrit.client.changes.CommentInfo;
|
||||
import com.google.gerrit.client.changes.ReviewInfo;
|
||||
import com.google.gerrit.client.changes.Util;
|
||||
@@ -317,7 +317,7 @@ public class FileTable extends FlowPanel {
|
||||
|
||||
void onDelete(int idx) {
|
||||
String path = list.get(idx).path();
|
||||
ChangeFileApi.deleteContent(curr, path,
|
||||
ChangeEditApi.delete(curr.getParentKey().get(), path,
|
||||
new AsyncCallback<VoidResult>() {
|
||||
@Override
|
||||
public void onSuccess(VoidResult result) {
|
||||
@@ -333,7 +333,7 @@ public class FileTable extends FlowPanel {
|
||||
|
||||
void onRestore(int idx) {
|
||||
String path = list.get(idx).path();
|
||||
ChangeFileApi.restoreContent(curr, path,
|
||||
ChangeEditApi.restore(curr.getParentKey().get(), path,
|
||||
new AsyncCallback<VoidResult>() {
|
||||
@Override
|
||||
public void onSuccess(VoidResult result) {
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
// Copyright (C) 2014 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.change;
|
||||
|
||||
import com.google.gerrit.client.changes.ChangeFileApi;
|
||||
import com.google.gerrit.client.rpc.GerritCallback;
|
||||
import com.google.gerrit.client.rpc.RestApi;
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gwt.event.dom.client.BlurEvent;
|
||||
import com.google.gwt.event.dom.client.BlurHandler;
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwtexpui.globalkey.client.NpTextArea;
|
||||
import com.google.gwtexpui.globalkey.client.NpTextBox;
|
||||
|
||||
class FileTextBox extends NpTextBox {
|
||||
private HandlerRegistration blurHandler;
|
||||
private NpTextArea textArea;
|
||||
private PatchSet.Id id;
|
||||
|
||||
@Override
|
||||
protected void onLoad() {
|
||||
blurHandler = addBlurHandler(new BlurHandler() {
|
||||
@Override
|
||||
public void onBlur(BlurEvent event) {
|
||||
loadFileContent();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUnload() {
|
||||
super.onUnload();
|
||||
blurHandler.removeHandler();
|
||||
}
|
||||
|
||||
void set(PatchSet.Id id, NpTextArea content) {
|
||||
this.id = id;
|
||||
this.textArea = content;
|
||||
}
|
||||
|
||||
private void loadFileContent() {
|
||||
ChangeFileApi.getContent(id, getText(), new GerritCallback<String>() {
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
textArea.setText(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
if (RestApi.isNotFound(caught)) {
|
||||
// that means that the file doesn't exist in the repository
|
||||
} else {
|
||||
super.onFailure(caught);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
// Copyright (C) 2014 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.changes;
|
||||
|
||||
import com.google.gerrit.client.VoidResult;
|
||||
import com.google.gerrit.client.rpc.GerritCallback;
|
||||
import com.google.gerrit.client.rpc.HttpCallback;
|
||||
import com.google.gerrit.client.rpc.NativeString;
|
||||
import com.google.gerrit.client.rpc.RestApi;
|
||||
import com.google.gerrit.reviewdb.client.Patch;
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
|
||||
/** REST API helpers to remotely edit a change. */
|
||||
public class ChangeEditApi {
|
||||
/** Get file (or commit message) contents. */
|
||||
public static void get(PatchSet.Id id, String path,
|
||||
HttpCallback<NativeString> cb) {
|
||||
RestApi api;
|
||||
if (id.get() != 0) {
|
||||
// Read from a published revision, when change edit doesn't
|
||||
// exist for the caller, or is not currently active.
|
||||
api = ChangeApi.revision(id).view("files").id(path).view("content");
|
||||
} else if (Patch.COMMIT_MSG.equals(path)) {
|
||||
api = editMessage(id.getParentKey().get());
|
||||
} else {
|
||||
api = editFile(id.getParentKey().get(), path);
|
||||
}
|
||||
api.get(cb);
|
||||
}
|
||||
|
||||
/** Put message into a change edit. */
|
||||
public static void putMessage(int id, String m, GerritCallback<VoidResult> cb) {
|
||||
editMessage(id).put(m, cb);
|
||||
}
|
||||
|
||||
/** Put contents into a file or commit message in a change edit. */
|
||||
public static void put(int id, String path, String content,
|
||||
GerritCallback<VoidResult> cb) {
|
||||
if (Patch.COMMIT_MSG.equals(path)) {
|
||||
putMessage(id, content, cb);
|
||||
} else {
|
||||
editFile(id, path).put(content, cb);
|
||||
}
|
||||
}
|
||||
|
||||
/** Delete a file in the pending edit. */
|
||||
public static void delete(int id, String path, AsyncCallback<VoidResult> cb) {
|
||||
editFile(id, path).delete(cb);
|
||||
}
|
||||
|
||||
/** Restore (undo delete/modify) a file in the pending edit. */
|
||||
public static void restore(int id, String path, AsyncCallback<VoidResult> cb) {
|
||||
Input in = Input.create();
|
||||
in.restore_path(path);
|
||||
ChangeApi.edit(id).post(in, cb);
|
||||
}
|
||||
|
||||
private static RestApi editMessage(int id) {
|
||||
return ChangeApi.change(id).view("edit:message");
|
||||
}
|
||||
|
||||
private static RestApi editFile(int id, String path) {
|
||||
return ChangeApi.edit(id).id(path);
|
||||
}
|
||||
|
||||
private static class Input extends JavaScriptObject {
|
||||
static Input create() {
|
||||
return createObject().cast();
|
||||
}
|
||||
|
||||
final native void restore_path(String p) /*-{ this.restore_path=p }-*/;
|
||||
|
||||
protected Input() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
// Copyright (C) 2014 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.changes;
|
||||
|
||||
import com.google.gerrit.client.VoidResult;
|
||||
import com.google.gerrit.client.rpc.GerritCallback;
|
||||
import com.google.gerrit.client.rpc.NativeString;
|
||||
import com.google.gerrit.client.rpc.RestApi;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.Patch;
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
|
||||
/**
|
||||
* A collection of static methods which work on the Gerrit REST API for specific
|
||||
* files in a change.
|
||||
*/
|
||||
public class ChangeFileApi {
|
||||
static abstract class CallbackWrapper<I, O> implements AsyncCallback<I> {
|
||||
protected AsyncCallback<O> wrapped;
|
||||
|
||||
public CallbackWrapper(AsyncCallback<O> callback) {
|
||||
wrapped = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void onSuccess(I result);
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
wrapped.onFailure(caught);
|
||||
}
|
||||
}
|
||||
|
||||
private static CallbackWrapper<NativeString, String> wrapper(
|
||||
AsyncCallback<String> cb) {
|
||||
return new CallbackWrapper<NativeString, String>(cb) {
|
||||
@Override
|
||||
public void onSuccess(NativeString b64) {
|
||||
if (b64 != null) {
|
||||
wrapped.onSuccess(b64decode(b64.asString()));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Get the contents of a File in a PatchSet or change edit. */
|
||||
public static void getContent(PatchSet.Id id, String filename,
|
||||
AsyncCallback<String> cb) {
|
||||
contentEditOrPs(id, filename).get(wrapper(cb));
|
||||
}
|
||||
|
||||
/** Get the content type of a File in a PatchSet or change edit. */
|
||||
public static void getContentType(PatchSet.Id id, String filename,
|
||||
AsyncCallback<String> cb) {
|
||||
contentTypeEditOrPs(id, filename).get(
|
||||
new CallbackWrapper<NativeString, String>(cb) {
|
||||
@Override
|
||||
public void onSuccess(NativeString str) {
|
||||
if (str != null) {
|
||||
wrapped.onSuccess(str.asString());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of a file or commit message in a PatchSet or change
|
||||
* edit.
|
||||
**/
|
||||
public static void getContentOrMessage(PatchSet.Id id, String path,
|
||||
AsyncCallback<String> cb) {
|
||||
RestApi api = (Patch.COMMIT_MSG.equals(path) && id.get() == 0)
|
||||
? messageEdit(id)
|
||||
: contentEditOrPs(id, path);
|
||||
api.get(wrapper(cb));
|
||||
}
|
||||
|
||||
/** Put contents into a File in a change edit. */
|
||||
public static void putContent(PatchSet.Id id, String filename,
|
||||
String content, GerritCallback<VoidResult> result) {
|
||||
contentEdit(id.getParentKey(), filename).put(content, result);
|
||||
}
|
||||
|
||||
/** Put contents into a File or commit message in a change edit. */
|
||||
public static void putContentOrMessage(PatchSet.Id id, String path,
|
||||
String content, GerritCallback<VoidResult> result) {
|
||||
if (Patch.COMMIT_MSG.equals(path)) {
|
||||
putMessage(id, content, result);
|
||||
} else {
|
||||
contentEdit(id.getParentKey(), path).put(content, result);
|
||||
}
|
||||
}
|
||||
|
||||
/** Put message into a change edit. */
|
||||
private static void putMessage(PatchSet.Id id, String m,
|
||||
GerritCallback<VoidResult> r) {
|
||||
putMessage(id.getParentKey(), m, r);
|
||||
}
|
||||
|
||||
/** Put message into a change edit. */
|
||||
public static void putMessage(Change.Id id, String m,
|
||||
GerritCallback<VoidResult> r) {
|
||||
ChangeApi.change(id.get()).view("edit:message").put(m, r);
|
||||
}
|
||||
|
||||
/** Restore contents of a File in a change edit. */
|
||||
public static void restoreContent(PatchSet.Id id, String filename,
|
||||
AsyncCallback<VoidResult> result) {
|
||||
Input in = Input.create();
|
||||
in.restore_path(filename);
|
||||
ChangeApi.edit(id.getParentKey().get()).post(in, result);
|
||||
}
|
||||
|
||||
/** Delete a file from a change edit. */
|
||||
public static void deleteContent(PatchSet.Id id, String filename,
|
||||
AsyncCallback<VoidResult> result) {
|
||||
contentEdit(id.getParentKey(), filename).delete(result);
|
||||
}
|
||||
|
||||
private static RestApi contentEditOrPs(PatchSet.Id id, String filename) {
|
||||
return id.get() == 0
|
||||
? contentEdit(id.getParentKey(), filename)
|
||||
: ChangeApi.revision(id).view("files").id(filename).view("content");
|
||||
}
|
||||
|
||||
private static RestApi messageEdit(PatchSet.Id id) {
|
||||
return ChangeApi.change(id.getParentKey().get()).view("edit:message");
|
||||
}
|
||||
|
||||
private static RestApi contentTypeEditOrPs(PatchSet.Id id, String filename) {
|
||||
return id.get() == 0
|
||||
? contentEdit(id.getParentKey(), filename).view("type")
|
||||
: ChangeApi.revision(id).view("files").id(filename).view("type");
|
||||
}
|
||||
|
||||
private static RestApi contentEdit(Change.Id id, String filename) {
|
||||
return ChangeApi.edit(id.get()).id(filename);
|
||||
}
|
||||
|
||||
private static native String b64decode(String a) /*-{ return window.atob(a); }-*/;
|
||||
|
||||
private static class Input extends JavaScriptObject {
|
||||
final native void restore_path(String p) /*-{ if(p)this.restore_path=p; }-*/;
|
||||
|
||||
static Input create() {
|
||||
return (Input) createObject();
|
||||
}
|
||||
|
||||
protected Input() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,11 @@ import com.google.gerrit.client.Gerrit;
|
||||
import com.google.gerrit.client.changes.CommentApi;
|
||||
import com.google.gerrit.client.changes.CommentInfo;
|
||||
import com.google.gerrit.client.rpc.CallbackGroup;
|
||||
import com.google.gerrit.client.rpc.GerritCallback;
|
||||
import com.google.gerrit.client.rpc.NativeMap;
|
||||
import com.google.gerrit.client.rpc.Natives;
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gwt.core.client.JsArray;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -53,39 +53,55 @@ class CommentsCollections {
|
||||
}
|
||||
}
|
||||
|
||||
private GerritCallback<NativeMap<JsArray<CommentInfo>>> publishedBase() {
|
||||
return new GerritCallback<NativeMap<JsArray<CommentInfo>>>() {
|
||||
private AsyncCallback<NativeMap<JsArray<CommentInfo>>> publishedBase() {
|
||||
return new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
|
||||
@Override
|
||||
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
|
||||
publishedBase = sort(result.get(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private GerritCallback<NativeMap<JsArray<CommentInfo>>> publishedRevision() {
|
||||
return new GerritCallback<NativeMap<JsArray<CommentInfo>>>() {
|
||||
private AsyncCallback<NativeMap<JsArray<CommentInfo>>> publishedRevision() {
|
||||
return new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
|
||||
@Override
|
||||
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
|
||||
publishedRevision = sort(result.get(path));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private GerritCallback<NativeMap<JsArray<CommentInfo>>> draftsBase() {
|
||||
return new GerritCallback<NativeMap<JsArray<CommentInfo>>>() {
|
||||
@Override
|
||||
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
|
||||
draftsBase = sort(result.get(path));
|
||||
public void onFailure(Throwable caught) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private GerritCallback<NativeMap<JsArray<CommentInfo>>> draftsRevision() {
|
||||
return new GerritCallback<NativeMap<JsArray<CommentInfo>>>() {
|
||||
private AsyncCallback<NativeMap<JsArray<CommentInfo>>> draftsBase() {
|
||||
return new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
|
||||
@Override
|
||||
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
|
||||
draftsBase = sort(result.get(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private AsyncCallback<NativeMap<JsArray<CommentInfo>>> draftsRevision() {
|
||||
return new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
|
||||
@Override
|
||||
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
|
||||
draftsRevision = sort(result.get(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -167,26 +167,36 @@ public class SideBySide2 extends Screen {
|
||||
protected void onLoad() {
|
||||
super.onLoad();
|
||||
|
||||
CallbackGroup cmGroup = new CallbackGroup();
|
||||
CodeMirror.initLibrary(cmGroup.<Void> addEmpty());
|
||||
CallbackGroup group1 = new CallbackGroup();
|
||||
final CallbackGroup group2 = new CallbackGroup();
|
||||
|
||||
final CallbackGroup group = new CallbackGroup();
|
||||
final AsyncCallback<Void> themeCallback = group.addEmpty();
|
||||
final AsyncCallback<Void> modeInjectorCb = group.addEmpty();
|
||||
CodeMirror.initLibrary(group1.add(new AsyncCallback<Void>() {
|
||||
final AsyncCallback<Void> themeCallback = group2.addEmpty();
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
// Load theme after CM library to ensure theme can override CSS.
|
||||
ThemeLoader.loadTheme(prefs.theme(), themeCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
}
|
||||
}));
|
||||
|
||||
DiffApi.diff(revision, path)
|
||||
.base(base)
|
||||
.wholeFile()
|
||||
.intraline(prefs.intralineDifference())
|
||||
.ignoreWhitespace(prefs.ignoreWhitespace())
|
||||
.get(cmGroup.addFinal(new GerritCallback<DiffInfo>() {
|
||||
.get(group1.addFinal(new GerritCallback<DiffInfo>() {
|
||||
final AsyncCallback<Void> modeInjectorCb = group2.addEmpty();
|
||||
|
||||
@Override
|
||||
public void onSuccess(DiffInfo diffInfo) {
|
||||
diff = diffInfo;
|
||||
fileSize = bucketFileSize(diffInfo);
|
||||
|
||||
// Load theme after CM library to ensure theme can override CSS.
|
||||
ThemeLoader.loadTheme(prefs.theme(), themeCallback);
|
||||
if (prefs.syntaxHighlighting()) {
|
||||
if (fileSize.compareTo(FileSize.SMALL) > 0) {
|
||||
modeInjectorCb.onSuccess(null);
|
||||
@@ -200,22 +210,26 @@ public class SideBySide2 extends Screen {
|
||||
}));
|
||||
|
||||
if (Gerrit.isSignedIn()) {
|
||||
ChangeApi.edit(changeId.get(), group.add(
|
||||
new GerritCallback<EditInfo>() {
|
||||
ChangeApi.edit(changeId.get(), group2.add(
|
||||
new AsyncCallback<EditInfo>() {
|
||||
@Override
|
||||
public void onSuccess(EditInfo result) {
|
||||
edit = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
final CommentsCollections comments = new CommentsCollections();
|
||||
comments.load(base, revision, path, group);
|
||||
comments.load(base, revision, path, group2);
|
||||
|
||||
RestApi call = ChangeApi.detail(changeId.get());
|
||||
ChangeList.addOptions(call, EnumSet.of(
|
||||
ListChangesOption.ALL_REVISIONS));
|
||||
call.get(group.add(new GerritCallback<ChangeInfo>() {
|
||||
call.get(group2.add(new AsyncCallback<ChangeInfo>() {
|
||||
@Override
|
||||
public void onSuccess(ChangeInfo info) {
|
||||
info.revisions().copyKeysIntoChildren("name");
|
||||
@@ -230,9 +244,14 @@ public class SideBySide2 extends Screen {
|
||||
diffTable.set(prefs, list, diff, edit != null, currentPatchSet,
|
||||
info.status().isOpen());
|
||||
header.setChangeInfo(info);
|
||||
}}));
|
||||
}
|
||||
|
||||
ConfigInfoCache.get(changeId, group.addFinal(
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
}
|
||||
}));
|
||||
|
||||
ConfigInfoCache.get(changeId, group2.addFinal(
|
||||
new ScreenLoadCallback<ConfigInfoCache.Entry>(SideBySide2.this) {
|
||||
@Override
|
||||
protected void preDisplay(ConfigInfoCache.Entry result) {
|
||||
|
||||
@@ -14,17 +14,23 @@
|
||||
|
||||
package com.google.gerrit.client.editor;
|
||||
|
||||
import static com.google.gwt.dom.client.Style.Visibility.HIDDEN;
|
||||
import static com.google.gwt.dom.client.Style.Visibility.VISIBLE;
|
||||
|
||||
import com.google.gerrit.client.Gerrit;
|
||||
import com.google.gerrit.client.JumpKeys;
|
||||
import com.google.gerrit.client.VoidResult;
|
||||
import com.google.gerrit.client.account.DiffPreferences;
|
||||
import com.google.gerrit.client.changes.ChangeApi;
|
||||
import com.google.gerrit.client.changes.ChangeFileApi;
|
||||
import com.google.gerrit.client.changes.ChangeEditApi;
|
||||
import com.google.gerrit.client.changes.ChangeInfo;
|
||||
import com.google.gerrit.client.diff.FileInfo;
|
||||
import com.google.gerrit.client.diff.Header;
|
||||
import com.google.gerrit.client.rpc.CallbackGroup;
|
||||
import com.google.gerrit.client.rpc.GerritCallback;
|
||||
import com.google.gerrit.client.rpc.HttpCallback;
|
||||
import com.google.gerrit.client.rpc.HttpResponse;
|
||||
import com.google.gerrit.client.rpc.NativeString;
|
||||
import com.google.gerrit.client.rpc.ScreenLoadCallback;
|
||||
import com.google.gerrit.client.ui.Screen;
|
||||
import com.google.gerrit.common.PageLinks;
|
||||
@@ -68,11 +74,14 @@ public class EditScreen extends Screen {
|
||||
private final String path;
|
||||
private DiffPreferences prefs;
|
||||
private CodeMirror cm;
|
||||
private String type;
|
||||
private HttpResponse<NativeString> content;
|
||||
|
||||
@UiField Element header;
|
||||
@UiField Element project;
|
||||
@UiField Element filePath;
|
||||
@UiField Element cursLine;
|
||||
@UiField Element cursCol;
|
||||
@UiField Element dirty;
|
||||
@UiField Button close;
|
||||
@UiField Button save;
|
||||
@UiField Element editor;
|
||||
@@ -100,10 +109,11 @@ public class EditScreen extends Screen {
|
||||
protected void onLoad() {
|
||||
super.onLoad();
|
||||
|
||||
CallbackGroup cmGroup = new CallbackGroup();
|
||||
final CallbackGroup group = new CallbackGroup();
|
||||
CodeMirror.initLibrary(cmGroup.add(new AsyncCallback<Void>() {
|
||||
final AsyncCallback<Void> themeCallback = group.addEmpty();
|
||||
CallbackGroup group1 = new CallbackGroup();
|
||||
final CallbackGroup group2 = new CallbackGroup();
|
||||
|
||||
CodeMirror.initLibrary(group1.add(new AsyncCallback<Void>() {
|
||||
final AsyncCallback<Void> themeCallback = group2.addEmpty();
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
@@ -116,36 +126,48 @@ public class EditScreen extends Screen {
|
||||
}
|
||||
}));
|
||||
|
||||
if (prefs.syntaxHighlighting() && !Patch.COMMIT_MSG.equals(path)) {
|
||||
final AsyncCallback<Void> modeInjectorCb = group.addEmpty();
|
||||
ChangeFileApi.getContentType(revision, path,
|
||||
cmGroup.add(new GerritCallback<String>() {
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
ModeInfo mode = ModeInfo.findMode(result, path);
|
||||
type = mode != null ? mode.mime() : null;
|
||||
injectMode(result, modeInjectorCb);
|
||||
}
|
||||
}));
|
||||
}
|
||||
cmGroup.done();
|
||||
|
||||
ChangeApi.detail(revision.getParentKey().get(),
|
||||
group.add(new GerritCallback<ChangeInfo>() {
|
||||
group1.add(new AsyncCallback<ChangeInfo>() {
|
||||
@Override
|
||||
public void onSuccess(ChangeInfo c) {
|
||||
project.setInnerText(c.project());
|
||||
SafeHtml.setInnerHTML(filePath, Header.formatPath(path, null, null));
|
||||
}
|
||||
}));
|
||||
|
||||
ChangeFileApi.getContentOrMessage(revision, path,
|
||||
group.addFinal(new ScreenLoadCallback<String>(this) {
|
||||
@Override
|
||||
protected void preDisplay(String content) {
|
||||
initEditor(content);
|
||||
public void onFailure(Throwable caught) {
|
||||
}
|
||||
}));
|
||||
|
||||
ChangeEditApi.get(revision, path,
|
||||
group1.add(new HttpCallback<NativeString>() {
|
||||
final AsyncCallback<Void> modeCallback = group2.addEmpty();
|
||||
|
||||
@Override
|
||||
public void onSuccess(HttpResponse<NativeString> fc) {
|
||||
content = fc;
|
||||
if (prefs.syntaxHighlighting()) {
|
||||
injectMode(fc.getContentType(), modeCallback);
|
||||
} else {
|
||||
modeCallback.onSuccess(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable e) {
|
||||
GerritCallback.showFailure(e);
|
||||
}
|
||||
}));
|
||||
|
||||
group2.addListener(new ScreenLoadCallback<Void>(this) {
|
||||
@Override
|
||||
protected void preDisplay(Void result) {
|
||||
initEditor(content);
|
||||
content = null;
|
||||
}
|
||||
});
|
||||
group1.done();
|
||||
group2.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -172,11 +194,11 @@ public class EditScreen extends Screen {
|
||||
});
|
||||
|
||||
generation = cm.changeGeneration(true);
|
||||
save.setEnabled(false);
|
||||
setClean(true);
|
||||
cm.on(new ChangesHandler() {
|
||||
@Override
|
||||
public void handle(CodeMirror cm) {
|
||||
save.setEnabled(!cm.isClean(generation));
|
||||
setClean(cm.isClean(generation));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -223,12 +245,12 @@ public class EditScreen extends Screen {
|
||||
Gerrit.display(PageLinks.toChangeInEditMode(revision.getParentKey()));
|
||||
}
|
||||
|
||||
private void initEditor(String content) {
|
||||
private void initEditor(HttpResponse<NativeString> file) {
|
||||
ModeInfo mode = prefs.syntaxHighlighting()
|
||||
? ModeInfo.findMode(type, path)
|
||||
? ModeInfo.findMode(file.getContentType(), path)
|
||||
: null;
|
||||
cm = CodeMirror.create(editor, Configuration.create()
|
||||
.set("value", content)
|
||||
.set("value", file.getResult().asString())
|
||||
.set("readOnly", false)
|
||||
.set("cursorBlinkRate", 0)
|
||||
.set("cursorHeight", 0.85)
|
||||
@@ -272,9 +294,16 @@ public class EditScreen extends Screen {
|
||||
|
||||
private void updateActiveLine() {
|
||||
Pos p = cm.getCursor("end");
|
||||
cursLine.setInnerText(Integer.toString(p.line() + 1));
|
||||
cursCol.setInnerText(Integer.toString(p.ch() + 1));
|
||||
cm.extras().activeLine(cm.getLineHandleVisualStart(p.line()));
|
||||
}
|
||||
|
||||
private void setClean(boolean clean) {
|
||||
save.setEnabled(!clean);
|
||||
dirty.getStyle().setVisibility(!clean ? VISIBLE : HIDDEN);
|
||||
}
|
||||
|
||||
private Runnable save() {
|
||||
return new Runnable() {
|
||||
@Override
|
||||
@@ -282,12 +311,12 @@ public class EditScreen extends Screen {
|
||||
if (!cm.isClean(generation)) {
|
||||
String text = cm.getValue();
|
||||
final int g = cm.changeGeneration(false);
|
||||
ChangeFileApi.putContentOrMessage(revision, path, text,
|
||||
ChangeEditApi.put(revision.getParentKey().get(), path, text,
|
||||
new GerritCallback<VoidResult>() {
|
||||
@Override
|
||||
public void onSuccess(VoidResult result) {
|
||||
generation = g;
|
||||
save.setEnabled(!cm.isClean(g));
|
||||
setClean(cm.isClean(g));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -62,6 +62,34 @@ limitations under the License.
|
||||
.path {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.statusLine {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 175px;
|
||||
height: 19px;
|
||||
background-color: #f7f7f7;
|
||||
border-top: 1px solid #ddd;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
.statusLine div {
|
||||
height: inherit;
|
||||
}
|
||||
|
||||
.cursorPosition {
|
||||
display: inline-block;
|
||||
margin: 0 5px 0 35px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.dirty {
|
||||
display: inline-block;
|
||||
margin: 0 5px 0 5px;
|
||||
padding: 0 0 0 5px;
|
||||
border-left: 1px solid #ddd;
|
||||
font-weight: bold;
|
||||
}
|
||||
</ui:style>
|
||||
<g:HTMLPanel>
|
||||
<div class='{style.headerLine}' ui:field='header'>
|
||||
@@ -82,5 +110,9 @@ limitations under the License.
|
||||
<span class='{style.path}'><span ui:field='project'/> / <span ui:field='filePath'/></span>
|
||||
</div>
|
||||
<div ui:field='editor' />
|
||||
<div class='{style.statusLine}'>
|
||||
<div class='{style.cursorPosition}'><span ui:field='cursLine'/> : <span ui:field='cursCol'/></div>
|
||||
<div class='{style.dirty}' ui:field='dirty'>Unsaved</div>
|
||||
</div>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
|
||||
@@ -42,8 +42,8 @@ import java.util.Set;
|
||||
* processing it.
|
||||
*/
|
||||
public class CallbackGroup {
|
||||
private final List<CallbackImpl<?>> callbacks;
|
||||
private final Set<CallbackImpl<?>> remaining;
|
||||
private final List<CallbackGlue> callbacks;
|
||||
private final Set<CallbackGlue> remaining;
|
||||
private boolean finalAdded;
|
||||
|
||||
private boolean failed;
|
||||
@@ -76,6 +76,27 @@ public class CallbackGroup {
|
||||
return handleAdd(cb);
|
||||
}
|
||||
|
||||
public <T> HttpCallback<T> add(HttpCallback<T> cb) {
|
||||
checkFinalAdded();
|
||||
if (failed) {
|
||||
cb.onFailure(failedThrowable);
|
||||
return new HttpCallback<T>() {
|
||||
@Override
|
||||
public void onSuccess(HttpResponse<T> result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
HttpCallbackImpl<T> w = new HttpCallbackImpl<>(cb);
|
||||
callbacks.add(w);
|
||||
remaining.add(w);
|
||||
return w;
|
||||
}
|
||||
|
||||
public <T> Callback<T> addFinal(final AsyncCallback<T> cb) {
|
||||
checkFinalAdded();
|
||||
finalAdded = true;
|
||||
@@ -84,7 +105,7 @@ public class CallbackGroup {
|
||||
|
||||
public void done() {
|
||||
finalAdded = true;
|
||||
applyAllSuccess();
|
||||
apply();
|
||||
}
|
||||
|
||||
public void addListener(AsyncCallback<Void> cb) {
|
||||
@@ -99,19 +120,30 @@ public class CallbackGroup {
|
||||
addListener(group.<Void> addEmpty());
|
||||
}
|
||||
|
||||
private void applyAllSuccess() {
|
||||
if (!failed && finalAdded && remaining.isEmpty()) {
|
||||
for (CallbackImpl<?> cb : callbacks) {
|
||||
cb.applySuccess();
|
||||
}
|
||||
callbacks.clear();
|
||||
}
|
||||
private void success(CallbackGlue cb) {
|
||||
remaining.remove(cb);
|
||||
apply();
|
||||
}
|
||||
|
||||
private void applyAllFailed() {
|
||||
if (failed && finalAdded && remaining.isEmpty()) {
|
||||
for (CallbackImpl<?> cb : callbacks) {
|
||||
cb.applyFailed();
|
||||
private <T> void failure(CallbackGlue w, Throwable caught) {
|
||||
if (!failed) {
|
||||
failed = true;
|
||||
failedThrowable = caught;
|
||||
}
|
||||
remaining.remove(w);
|
||||
apply();
|
||||
}
|
||||
|
||||
private void apply() {
|
||||
if (finalAdded && remaining.isEmpty()) {
|
||||
if (failed) {
|
||||
for (CallbackGlue cb : callbacks) {
|
||||
cb.applyFailed();
|
||||
}
|
||||
} else {
|
||||
for (CallbackGlue cb : callbacks) {
|
||||
cb.applySuccess();
|
||||
}
|
||||
}
|
||||
callbacks.clear();
|
||||
}
|
||||
@@ -139,7 +171,12 @@ public class CallbackGroup {
|
||||
extends AsyncCallback<T>, com.google.gwtjsonrpc.common.AsyncCallback<T> {
|
||||
}
|
||||
|
||||
private class CallbackImpl<T> implements Callback<T> {
|
||||
private interface CallbackGlue {
|
||||
void applySuccess();
|
||||
void applyFailed();
|
||||
}
|
||||
|
||||
private class CallbackImpl<T> implements Callback<T>, CallbackGlue {
|
||||
AsyncCallback<T> delegate;
|
||||
T result;
|
||||
|
||||
@@ -150,21 +187,16 @@ public class CallbackGroup {
|
||||
@Override
|
||||
public void onSuccess(T value) {
|
||||
this.result = value;
|
||||
remaining.remove(this);
|
||||
CallbackGroup.this.applyAllSuccess();
|
||||
success(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
if (!failed) {
|
||||
failed = true;
|
||||
failedThrowable = caught;
|
||||
}
|
||||
remaining.remove(this);
|
||||
CallbackGroup.this.applyAllFailed();
|
||||
failure(this, caught);
|
||||
}
|
||||
|
||||
void applySuccess() {
|
||||
@Override
|
||||
public void applySuccess() {
|
||||
AsyncCallback<T> cb = delegate;
|
||||
if (cb != null) {
|
||||
delegate = null;
|
||||
@@ -173,7 +205,8 @@ public class CallbackGroup {
|
||||
}
|
||||
}
|
||||
|
||||
void applyFailed() {
|
||||
@Override
|
||||
public void applyFailed() {
|
||||
AsyncCallback<T> cb = delegate;
|
||||
if (cb != null) {
|
||||
delegate = null;
|
||||
@@ -182,4 +215,44 @@ public class CallbackGroup {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class HttpCallbackImpl<T> implements HttpCallback<T>, CallbackGlue {
|
||||
private HttpCallback<T> delegate;
|
||||
private HttpResponse<T> result;
|
||||
|
||||
HttpCallbackImpl(HttpCallback<T> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(HttpResponse<T> result) {
|
||||
this.result = result;
|
||||
success(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
failure(this, caught);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applySuccess() {
|
||||
HttpCallback<T> cb = delegate;
|
||||
if (cb != null) {
|
||||
delegate = null;
|
||||
cb.onSuccess(result);
|
||||
result = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFailed() {
|
||||
HttpCallback<T> cb = delegate;
|
||||
if (cb != null) {
|
||||
delegate = null;
|
||||
result = null;
|
||||
cb.onFailure(failedThrowable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.google.gerrit.common.errors.NoSuchAccountException;
|
||||
import com.google.gerrit.common.errors.NoSuchEntityException;
|
||||
import com.google.gerrit.common.errors.NoSuchGroupException;
|
||||
import com.google.gerrit.common.errors.NotSignedInException;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.user.client.rpc.InvocationException;
|
||||
import com.google.gwtjsonrpc.client.RemoteJsonException;
|
||||
import com.google.gwtjsonrpc.client.ServerUnavailableException;
|
||||
@@ -35,6 +34,10 @@ public abstract class GerritCallback<T> implements
|
||||
com.google.gwt.user.client.rpc.AsyncCallback<T> {
|
||||
@Override
|
||||
public void onFailure(final Throwable caught) {
|
||||
showFailure(caught);
|
||||
}
|
||||
|
||||
public static void showFailure(Throwable caught) {
|
||||
if (isNotSignedIn(caught) || isInvalidXSRF(caught)) {
|
||||
new NotSignedInDialog().center();
|
||||
|
||||
@@ -70,7 +73,6 @@ public abstract class GerritCallback<T> implements
|
||||
new ErrorDialog(RpcConstants.C.errorServerUnavailable()).center();
|
||||
|
||||
} else {
|
||||
GWT.log(getClass().getName() + " caught " + caught, caught);
|
||||
new ErrorDialog(caught).center();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (C) 2015 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.rpc;
|
||||
|
||||
/** AsyncCallback supplied with HTTP response headers. */
|
||||
public interface HttpCallback<T> {
|
||||
void onSuccess(HttpResponse<T> result);
|
||||
void onFailure(Throwable caught);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright (C) 2015 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.rpc;
|
||||
|
||||
import com.google.gwt.http.client.Response;
|
||||
|
||||
/** Wraps decoded server reply with HTTP headers. */
|
||||
public class HttpResponse<T> {
|
||||
private final Response httpResponse;
|
||||
private final String contentType;
|
||||
private final T result;
|
||||
|
||||
HttpResponse(Response httpResponse, String contentType, T result) {
|
||||
this.httpResponse = httpResponse;
|
||||
this.contentType = contentType;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
/** HTTP status code, always in the 2xx family. */
|
||||
public int getStatusCode() {
|
||||
return httpResponse.getStatusCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Content type supplied by the server.
|
||||
*
|
||||
* This helper simplifies the common {@code getHeader("Content-Type")} case.
|
||||
*/
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
/** Lookup an arbitrary reply header. */
|
||||
public String getHeader(String header) {
|
||||
if ("Content-Type".equals(header)) {
|
||||
return contentType;
|
||||
}
|
||||
return httpResponse.getHeader(header);
|
||||
}
|
||||
|
||||
public T getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -104,21 +104,21 @@ public class RestApi {
|
||||
}
|
||||
}
|
||||
|
||||
private static class HttpCallback<T extends JavaScriptObject>
|
||||
private static class HttpImpl<T extends JavaScriptObject>
|
||||
implements RequestCallback {
|
||||
private final boolean background;
|
||||
private final AsyncCallback<T> cb;
|
||||
private final HttpCallback<T> cb;
|
||||
|
||||
HttpCallback(boolean bg, AsyncCallback<T> cb) {
|
||||
HttpImpl(boolean bg, HttpCallback<T> cb) {
|
||||
this.background = bg;
|
||||
this.cb = cb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponseReceived(Request req, Response res) {
|
||||
public void onResponseReceived(Request req, final Response res) {
|
||||
int status = res.getStatusCode();
|
||||
if (status == Response.SC_NO_CONTENT) {
|
||||
cb.onSuccess(null);
|
||||
cb.onSuccess(new HttpResponse<T>(res, null, null));
|
||||
if (!background) {
|
||||
RpcStatus.INSTANCE.onRpcComplete();
|
||||
}
|
||||
@@ -126,12 +126,12 @@ public class RestApi {
|
||||
} else if (200 <= status && status < 300) {
|
||||
long start = System.currentTimeMillis();
|
||||
final T data;
|
||||
if (isTextBody(res)) {
|
||||
data = NativeString.wrap(res.getText()).cast();
|
||||
} else if (isJsonBody(res)) {
|
||||
final String type;
|
||||
if (isJsonBody(res)) {
|
||||
try {
|
||||
// javac generics bug
|
||||
data = RestApi.<T>cast(parseJson(res));
|
||||
data = RestApi.<T> cast(parseJson(res));
|
||||
type = JSON_TYPE;
|
||||
} catch (JSONException e) {
|
||||
if (!background) {
|
||||
RpcStatus.INSTANCE.onRpcComplete();
|
||||
@@ -140,6 +140,12 @@ public class RestApi {
|
||||
"Invalid JSON: " + e.getMessage()));
|
||||
return;
|
||||
}
|
||||
} else if (isEncodedBase64(res)) {
|
||||
data = NativeString.wrap(decodeBase64(res.getText())).cast();
|
||||
type = simpleType(res.getHeader("X-FYI-Content-Type"));
|
||||
} else if (isTextBody(res)) {
|
||||
data = NativeString.wrap(res.getText()).cast();
|
||||
type = TEXT_TYPE;
|
||||
} else {
|
||||
if (!background) {
|
||||
RpcStatus.INSTANCE.onRpcComplete();
|
||||
@@ -154,7 +160,7 @@ public class RestApi {
|
||||
@Override
|
||||
public void execute() {
|
||||
try {
|
||||
cb.onSuccess(data);
|
||||
cb.onSuccess(new HttpResponse<>(res, type, data));
|
||||
} finally {
|
||||
if (!background) {
|
||||
RpcStatus.INSTANCE.onRpcComplete();
|
||||
@@ -318,21 +324,24 @@ public class RestApi {
|
||||
}
|
||||
|
||||
public <T extends JavaScriptObject> void get(AsyncCallback<T> cb) {
|
||||
get(wrap(cb));
|
||||
}
|
||||
|
||||
public <T extends JavaScriptObject> void get(HttpCallback<T> cb) {
|
||||
send(GET, cb);
|
||||
}
|
||||
|
||||
public <T extends JavaScriptObject> void delete(AsyncCallback<T> cb) {
|
||||
delete(wrap(cb));
|
||||
}
|
||||
|
||||
public <T extends JavaScriptObject> void delete(HttpCallback<T> cb) {
|
||||
send(DELETE, cb);
|
||||
}
|
||||
|
||||
public <T extends JavaScriptObject> void delete(JavaScriptObject content,
|
||||
AsyncCallback<T> cb) {
|
||||
sendJSON(DELETE, content, cb);
|
||||
}
|
||||
|
||||
private <T extends JavaScriptObject> void send(
|
||||
Method method, AsyncCallback<T> cb) {
|
||||
HttpCallback<T> httpCallback = new HttpCallback<>(background, cb);
|
||||
private <T extends JavaScriptObject> void send(Method method,
|
||||
HttpCallback<T> cb) {
|
||||
HttpImpl<T> httpCallback = new HttpImpl<>(background, cb);
|
||||
try {
|
||||
if (!background) {
|
||||
RpcStatus.INSTANCE.onRpcStart();
|
||||
@@ -346,33 +355,59 @@ public class RestApi {
|
||||
public <T extends JavaScriptObject> void post(
|
||||
JavaScriptObject content,
|
||||
AsyncCallback<T> cb) {
|
||||
post(content, wrap(cb));
|
||||
}
|
||||
|
||||
public <T extends JavaScriptObject> void post(
|
||||
JavaScriptObject content,
|
||||
HttpCallback<T> cb) {
|
||||
sendJSON(POST, content, cb);
|
||||
}
|
||||
|
||||
public <T extends JavaScriptObject> void post(String content,
|
||||
AsyncCallback<T> cb) {
|
||||
post(content, wrap(cb));
|
||||
}
|
||||
|
||||
public <T extends JavaScriptObject> void post(String content,
|
||||
HttpCallback<T> cb) {
|
||||
sendRaw(POST, content, cb);
|
||||
}
|
||||
|
||||
public <T extends JavaScriptObject> void put(AsyncCallback<T> cb) {
|
||||
put(wrap(cb));
|
||||
}
|
||||
|
||||
public <T extends JavaScriptObject> void put(HttpCallback<T> cb) {
|
||||
send(PUT, cb);
|
||||
}
|
||||
|
||||
public <T extends JavaScriptObject> void put(String content,
|
||||
AsyncCallback<T> cb) {
|
||||
put(content, wrap(cb));
|
||||
}
|
||||
|
||||
public <T extends JavaScriptObject> void put(String content,
|
||||
HttpCallback<T> cb) {
|
||||
sendRaw(PUT, content, cb);
|
||||
}
|
||||
|
||||
public <T extends JavaScriptObject> void put(
|
||||
JavaScriptObject content,
|
||||
AsyncCallback<T> cb) {
|
||||
put(content, wrap(cb));
|
||||
}
|
||||
|
||||
public <T extends JavaScriptObject> void put(
|
||||
JavaScriptObject content,
|
||||
HttpCallback<T> cb) {
|
||||
sendJSON(PUT, content, cb);
|
||||
}
|
||||
|
||||
private <T extends JavaScriptObject> void sendJSON(
|
||||
Method method, JavaScriptObject content,
|
||||
AsyncCallback<T> cb) {
|
||||
HttpCallback<T> httpCallback = new HttpCallback<>(background, cb);
|
||||
HttpCallback<T> cb) {
|
||||
HttpImpl<T> httpCallback = new HttpImpl<>(background, cb);
|
||||
try {
|
||||
if (!background) {
|
||||
RpcStatus.INSTANCE.onRpcStart();
|
||||
@@ -385,11 +420,15 @@ public class RestApi {
|
||||
}
|
||||
}
|
||||
|
||||
private static native String str(JavaScriptObject jso) /*-{ return JSON.stringify(jso); }-*/;
|
||||
private static native String str(JavaScriptObject jso)
|
||||
/*-{ return JSON.stringify(jso) }-*/;
|
||||
|
||||
private static native String decodeBase64(String a)
|
||||
/*-{ return $wnd.atob(a) }-*/;
|
||||
|
||||
private <T extends JavaScriptObject> void sendRaw(Method method, String body,
|
||||
AsyncCallback<T> cb) {
|
||||
HttpCallback<T> httpCallback = new HttpCallback<>(background, cb);
|
||||
HttpCallback<T> cb) {
|
||||
HttpImpl<T> httpCallback = new HttpImpl<>(background, cb);
|
||||
try {
|
||||
if (!background) {
|
||||
RpcStatus.INSTANCE.onRpcStart();
|
||||
@@ -422,16 +461,22 @@ public class RestApi {
|
||||
return isContentType(res, TEXT_TYPE);
|
||||
}
|
||||
|
||||
private static boolean isEncodedBase64(Response res) {
|
||||
return "base64".equals(res.getHeader("X-FYI-Content-Encoding"))
|
||||
&& isTextBody(res);
|
||||
}
|
||||
|
||||
private static boolean isContentType(Response res, String want) {
|
||||
String type = res.getHeader("Content-Type");
|
||||
if (type == null) {
|
||||
return false;
|
||||
}
|
||||
return type != null && want.equals(simpleType(type));
|
||||
}
|
||||
|
||||
private static String simpleType(String type) {
|
||||
int semi = type.indexOf(';');
|
||||
if (semi >= 0) {
|
||||
type = type.substring(0, semi).trim();
|
||||
return type.substring(0, semi).trim();
|
||||
}
|
||||
return want.equals(type);
|
||||
return type;
|
||||
}
|
||||
|
||||
private static JSONValue parseJson(Response res)
|
||||
@@ -464,4 +509,19 @@ public class RestApi {
|
||||
throw new JSONException("unsupported JSON type");
|
||||
}
|
||||
}
|
||||
|
||||
private static <T extends JavaScriptObject> HttpCallback<T> wrap(
|
||||
final AsyncCallback<T> cb) {
|
||||
return new HttpCallback<T>() {
|
||||
@Override
|
||||
public void onSuccess(HttpResponse<T> r) {
|
||||
cb.onSuccess(r.getResult());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable e) {
|
||||
cb.onFailure(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
package net.codemirror.lib;
|
||||
|
||||
import com.google.gerrit.client.rpc.CallbackGroup;
|
||||
import com.google.gerrit.client.rpc.GerritCallback;
|
||||
import com.google.gwt.core.client.Callback;
|
||||
import com.google.gwt.core.client.ScriptInjector;
|
||||
import com.google.gwt.dom.client.ScriptElement;
|
||||
@@ -39,11 +38,15 @@ public class Loader {
|
||||
|
||||
CallbackGroup group = new CallbackGroup();
|
||||
injectCss(Lib.I.css(), group.<Void> addEmpty());
|
||||
injectScript(Lib.I.js().getSafeUri(), group.add(new GerritCallback<Void>() {
|
||||
injectScript(Lib.I.js().getSafeUri(), group.add(new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
Vim.initKeyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
}
|
||||
}));
|
||||
group.addListener(cb);
|
||||
group.done();
|
||||
|
||||
@@ -187,7 +187,7 @@ class RevisionApiImpl extends RevisionApi.NotImplemented implements RevisionApi
|
||||
return ImmutableSet.copyOf((Iterable<String>) listFiles
|
||||
.get().setReviewed(true)
|
||||
.apply(revision).value());
|
||||
} catch (OrmException e) {
|
||||
} catch (OrmException | IOException e) {
|
||||
throw new RestApiException("Cannot list reviewed files", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.kohsuke.args4j.Option;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -433,8 +434,8 @@ public class ChangeEdits implements
|
||||
throws ResourceNotFoundException, IOException {
|
||||
try {
|
||||
return Response.ok(fileContentUtil.getContent(
|
||||
rsrc.getChangeEdit().getChange().getProject(),
|
||||
rsrc.getChangeEdit().getRevision().get(),
|
||||
rsrc.getControl().getProjectControl().getProjectState(),
|
||||
ObjectId.fromString(rsrc.getChangeEdit().getRevision().get()),
|
||||
rsrc.getPath()));
|
||||
} catch (ResourceNotFoundException rnfe) {
|
||||
return Response.none();
|
||||
@@ -502,29 +503,12 @@ public class ChangeEdits implements
|
||||
IOException, ResourceNotFoundException {
|
||||
Optional<ChangeEdit> edit = editUtil.byChange(rsrc.getChange());
|
||||
if (edit.isPresent()) {
|
||||
return BinaryResult.create(
|
||||
edit.get().getEditCommit().getFullMessage()).base64();
|
||||
String msg = edit.get().getEditCommit().getFullMessage();
|
||||
return BinaryResult.create(msg)
|
||||
.setContentType(FileContentUtil.TEXT_X_GERRIT_COMMIT_MESSAGE)
|
||||
.base64();
|
||||
}
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class GetType implements RestReadView<ChangeEditResource> {
|
||||
private final FileContentUtil fileContentUtil;
|
||||
|
||||
@Inject
|
||||
GetType(FileContentUtil fileContentUtil) {
|
||||
this.fileContentUtil = fileContentUtil;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apply(ChangeEditResource rsrc)
|
||||
throws ResourceNotFoundException, IOException {
|
||||
return fileContentUtil.getContentType(
|
||||
rsrc.getChangeEdit().getChange().getProject(),
|
||||
rsrc.getChangeEdit().getRevision().get(),
|
||||
rsrc.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,19 @@ package com.google.gerrit.server.change;
|
||||
|
||||
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
|
||||
|
||||
import com.google.gerrit.common.data.PatchScript.FileMode;
|
||||
import com.google.gerrit.extensions.restapi.BinaryResult;
|
||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.Patch;
|
||||
import com.google.gerrit.server.FileTypeRegistry;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.eclipse.jgit.errors.LargeObjectException;
|
||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectLoader;
|
||||
import org.eclipse.jgit.lib.ObjectReader;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
@@ -36,6 +41,11 @@ import java.io.OutputStream;
|
||||
|
||||
@Singleton
|
||||
public class FileContentUtil {
|
||||
public static final String TEXT_X_GERRIT_COMMIT_MESSAGE = "text/x-gerrit-commit-message";
|
||||
private static final String X_GIT_SYMLINK = "x-git/symlink";
|
||||
private static final String X_GIT_GITLINK = "x-git/gitlink";
|
||||
private static final int MAX_SIZE = 5 << 20;
|
||||
|
||||
private final GitRepositoryManager repoManager;
|
||||
private final FileTypeRegistry registry;
|
||||
|
||||
@@ -46,28 +56,50 @@ public class FileContentUtil {
|
||||
this.registry = ftr;
|
||||
}
|
||||
|
||||
public BinaryResult getContent(Project.NameKey project, String revstr,
|
||||
public BinaryResult getContent(ProjectState project, ObjectId revstr,
|
||||
String path) throws ResourceNotFoundException, IOException {
|
||||
Repository repo = repoManager.openRepository(project);
|
||||
Repository repo = openRepository(project);
|
||||
try {
|
||||
RevWalk rw = new RevWalk(repo);
|
||||
try {
|
||||
RevCommit commit = rw.parseCommit(repo.resolve(revstr));
|
||||
TreeWalk tw =
|
||||
TreeWalk.forPath(rw.getObjectReader(), path,
|
||||
commit.getTree().getId());
|
||||
RevCommit commit = rw.parseCommit(revstr);
|
||||
ObjectReader reader = rw.getObjectReader();
|
||||
TreeWalk tw = TreeWalk.forPath(reader, path, commit.getTree());
|
||||
if (tw == null) {
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
final ObjectLoader object = repo.open(tw.getObjectId(0));
|
||||
@SuppressWarnings("resource")
|
||||
BinaryResult result = new BinaryResult() {
|
||||
@Override
|
||||
public void writeTo(OutputStream os) throws IOException {
|
||||
object.copyTo(os);
|
||||
}
|
||||
};
|
||||
return result.setContentLength(object.getSize()).base64();
|
||||
|
||||
org.eclipse.jgit.lib.FileMode mode = tw.getFileMode(0);
|
||||
ObjectId id = tw.getObjectId(0);
|
||||
if (mode == org.eclipse.jgit.lib.FileMode.GITLINK) {
|
||||
return BinaryResult.create(id.name())
|
||||
.setContentType(X_GIT_GITLINK)
|
||||
.base64();
|
||||
}
|
||||
|
||||
final ObjectLoader obj = repo.open(id, OBJ_BLOB);
|
||||
byte[] raw;
|
||||
try {
|
||||
raw = obj.getCachedBytes(MAX_SIZE);
|
||||
} catch (LargeObjectException e) {
|
||||
raw = null;
|
||||
}
|
||||
|
||||
BinaryResult result;
|
||||
if (raw != null) {
|
||||
result = BinaryResult.create(raw);
|
||||
} else {
|
||||
result = asBinaryResult(obj);
|
||||
}
|
||||
|
||||
String type;
|
||||
if (mode == org.eclipse.jgit.lib.FileMode.SYMLINK) {
|
||||
type = X_GIT_SYMLINK;
|
||||
} else {
|
||||
type = registry.getMimeType(path, raw).toString();
|
||||
type = resolveContentType(project, path, FileMode.FILE, type);
|
||||
}
|
||||
return result.setContentType(type).base64();
|
||||
} finally {
|
||||
rw.release();
|
||||
}
|
||||
@@ -76,31 +108,44 @@ public class FileContentUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public String getContentType(Project.NameKey project, String revstr,
|
||||
String path) throws ResourceNotFoundException, IOException {
|
||||
Repository repo = repoManager.openRepository(project);
|
||||
try {
|
||||
RevWalk rw = new RevWalk(repo);
|
||||
ObjectReader reader = repo.newObjectReader();
|
||||
try {
|
||||
RevCommit commit = rw.parseCommit(repo.resolve(revstr));
|
||||
TreeWalk tw =
|
||||
TreeWalk.forPath(rw.getObjectReader(), path,
|
||||
commit.getTree().getId());
|
||||
if (tw == null) {
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
ObjectLoader blobLoader = reader.open(tw.getObjectId(0), OBJ_BLOB);
|
||||
byte[] raw = blobLoader.isLarge()
|
||||
? null
|
||||
: blobLoader.getCachedBytes();
|
||||
return registry.getMimeType(path, raw).toString();
|
||||
} finally {
|
||||
reader.release();
|
||||
rw.release();
|
||||
private static BinaryResult asBinaryResult(final ObjectLoader obj) {
|
||||
@SuppressWarnings("resource")
|
||||
BinaryResult result = new BinaryResult() {
|
||||
@Override
|
||||
public void writeTo(OutputStream os) throws IOException {
|
||||
obj.copyTo(os);
|
||||
}
|
||||
} finally {
|
||||
repo.close();
|
||||
}.setContentLength(obj.getSize());
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String resolveContentType(ProjectState project, String path,
|
||||
FileMode fileMode, String mimeType) {
|
||||
switch (fileMode) {
|
||||
case FILE:
|
||||
if (Patch.COMMIT_MSG.equals(path)) {
|
||||
return TEXT_X_GERRIT_COMMIT_MESSAGE;
|
||||
}
|
||||
if (project != null) {
|
||||
for (ProjectState p : project.tree()) {
|
||||
String t = p.getConfig().getMimeTypes().getMimeType(path);
|
||||
if (t != null) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mimeType;
|
||||
case GITLINK:
|
||||
return X_GIT_GITLINK;
|
||||
case SYMLINK:
|
||||
return X_GIT_SYMLINK;
|
||||
default:
|
||||
throw new IllegalStateException("file mode: " + fileMode);
|
||||
}
|
||||
}
|
||||
|
||||
private Repository openRepository(ProjectState project)
|
||||
throws RepositoryNotFoundException, IOException {
|
||||
return repoManager.openRepository(project.getProject().getNameKey());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,11 @@ import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectReader;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
import org.eclipse.jgit.treewalk.TreeWalk;
|
||||
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
|
||||
@@ -53,6 +56,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -96,6 +100,9 @@ public class Files implements ChildCollection<RevisionResource, FileResource> {
|
||||
@Option(name = "--reviewed")
|
||||
boolean reviewed;
|
||||
|
||||
@Option(name = "-q")
|
||||
String query;
|
||||
|
||||
private final Provider<ReviewDb> db;
|
||||
private final Provider<CurrentUser> self;
|
||||
private final FileInfoJson fileInfoJson;
|
||||
@@ -125,11 +132,13 @@ public class Files implements ChildCollection<RevisionResource, FileResource> {
|
||||
|
||||
@Override
|
||||
public Response<?> apply(RevisionResource resource) throws AuthException,
|
||||
BadRequestException, ResourceNotFoundException, OrmException {
|
||||
if (base != null && reviewed) {
|
||||
throw new BadRequestException("cannot combine base and reviewed");
|
||||
} else if (reviewed) {
|
||||
BadRequestException, ResourceNotFoundException, OrmException,
|
||||
RepositoryNotFoundException, IOException {
|
||||
checkOptions();
|
||||
if (reviewed) {
|
||||
return Response.ok(reviewed(resource));
|
||||
} else if (query != null) {
|
||||
return Response.ok(query(resource));
|
||||
}
|
||||
|
||||
PatchSet basePatchSet = null;
|
||||
@@ -152,6 +161,51 @@ public class Files implements ChildCollection<RevisionResource, FileResource> {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkOptions() throws BadRequestException {
|
||||
int supplied = 0;
|
||||
if (base != null) {
|
||||
supplied++;
|
||||
}
|
||||
if (reviewed) {
|
||||
supplied++;
|
||||
}
|
||||
if (query != null) {
|
||||
supplied++;
|
||||
}
|
||||
if (supplied > 1) {
|
||||
throw new BadRequestException("cannot combine base, reviewed, query");
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> query(RevisionResource resource)
|
||||
throws RepositoryNotFoundException, IOException {
|
||||
Repository git =
|
||||
gitManager.openRepository(resource.getChange().getProject());
|
||||
try {
|
||||
TreeWalk tw = new TreeWalk(git);
|
||||
try {
|
||||
RevCommit c = new RevWalk(tw.getObjectReader())
|
||||
.parseCommit(ObjectId.fromString(
|
||||
resource.getPatchSet().getRevision().get()));
|
||||
|
||||
tw.addTree(c.getTree());
|
||||
tw.setRecursive(true);
|
||||
List<String> paths = new ArrayList<>();
|
||||
while (tw.next() && paths.size() < 20) {
|
||||
String s = tw.getPathString();
|
||||
if (s.contains(query)) {
|
||||
paths.add(s);
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
} finally {
|
||||
tw.release();
|
||||
}
|
||||
} finally {
|
||||
git.close();
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> reviewed(RevisionResource resource)
|
||||
throws AuthException, OrmException {
|
||||
CurrentUser user = self.get();
|
||||
|
||||
@@ -24,6 +24,8 @@ import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Singleton
|
||||
@@ -44,12 +46,14 @@ public class GetContent implements RestReadView<FileResource> {
|
||||
OrmException {
|
||||
String path = rsrc.getPatchKey().get();
|
||||
if (Patch.COMMIT_MSG.equals(path)) {
|
||||
return BinaryResult.create(
|
||||
changeUtil.getMessage(rsrc.getRevision().getChange())).base64();
|
||||
String msg = changeUtil.getMessage(rsrc.getRevision().getChange());
|
||||
return BinaryResult.create(msg)
|
||||
.setContentType(FileContentUtil.TEXT_X_GERRIT_COMMIT_MESSAGE)
|
||||
.base64();
|
||||
}
|
||||
return fileContentUtil.getContent(
|
||||
rsrc.getRevision().getControl().getProject().getNameKey(),
|
||||
rsrc.getRevision().getPatchSet().getRevision().get(),
|
||||
rsrc.getRevision().getControl().getProjectControl().getProjectState(),
|
||||
ObjectId.fromString(rsrc.getRevision().getPatchSet().getRevision().get()),
|
||||
path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
// Copyright (C) 2014 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.change;
|
||||
|
||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||
import com.google.gerrit.extensions.restapi.RestReadView;
|
||||
import com.google.gerrit.reviewdb.client.Patch;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Singleton
|
||||
public class GetContentType implements RestReadView<FileResource> {
|
||||
private final FileContentUtil fileContentUtil;
|
||||
|
||||
@Inject
|
||||
GetContentType(FileContentUtil fileContentUtil) {
|
||||
this.fileContentUtil = fileContentUtil;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apply(FileResource rsrc)
|
||||
throws ResourceNotFoundException, IOException {
|
||||
String path = rsrc.getPatchKey().get();
|
||||
if (Patch.COMMIT_MSG.equals(path)) {
|
||||
return "text/plain";
|
||||
}
|
||||
return fileContentUtil.getContentType(
|
||||
rsrc.getRevision().getControl().getProject().getNameKey(),
|
||||
rsrc.getRevision().getPatchSet().getRevision().get(),
|
||||
path);
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@ import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gerrit.common.data.PatchScript;
|
||||
import com.google.gerrit.common.data.PatchScript.DisplayMethod;
|
||||
import com.google.gerrit.common.data.PatchScript.FileMode;
|
||||
import com.google.gerrit.extensions.common.ChangeType;
|
||||
import com.google.gerrit.extensions.common.DiffInfo;
|
||||
import com.google.gerrit.extensions.common.DiffInfo.ContentEntry;
|
||||
@@ -194,7 +193,8 @@ public class GetDiff implements RestReadView<FileResource> {
|
||||
result.metaA = new FileMeta();
|
||||
result.metaA.name = MoreObjects.firstNonNull(ps.getOldName(),
|
||||
ps.getNewName());
|
||||
setContentType(result.metaA, state, ps.getFileModeA(), ps.getMimeTypeA());
|
||||
result.metaA.contentType = FileContentUtil.resolveContentType(
|
||||
state, result.metaA.name, ps.getFileModeA(), ps.getMimeTypeA());
|
||||
result.metaA.lines = ps.getA().size();
|
||||
result.metaA.webLinks =
|
||||
getFileWebLinks(state.getProject(), revA, result.metaA.name);
|
||||
@@ -203,7 +203,8 @@ public class GetDiff implements RestReadView<FileResource> {
|
||||
if (ps.getDisplayMethodB() != DisplayMethod.NONE) {
|
||||
result.metaB = new FileMeta();
|
||||
result.metaB.name = ps.getNewName();
|
||||
setContentType(result.metaB, state, ps.getFileModeB(), ps.getMimeTypeB());
|
||||
result.metaB.contentType = FileContentUtil.resolveContentType(
|
||||
state, result.metaB.name, ps.getFileModeB(), ps.getMimeTypeB());
|
||||
result.metaB.lines = ps.getB().size();
|
||||
result.metaB.webLinks =
|
||||
getFileWebLinks(state.getProject(), revB, result.metaB.name);
|
||||
@@ -250,34 +251,6 @@ public class GetDiff implements RestReadView<FileResource> {
|
||||
return links.isEmpty() ? null : links.toList();
|
||||
}
|
||||
|
||||
private void setContentType(FileMeta meta, ProjectState project,
|
||||
FileMode fileMode, String mimeType) {
|
||||
switch (fileMode) {
|
||||
case FILE:
|
||||
if (Patch.COMMIT_MSG.equals(meta.name)) {
|
||||
mimeType = "text/x-gerrit-commit-message";
|
||||
} else if (project != null) {
|
||||
for (ProjectState p : project.tree()) {
|
||||
String t = p.getConfig().getMimeTypes().getMimeType(meta.name);
|
||||
if (t != null) {
|
||||
mimeType = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
meta.contentType = mimeType;
|
||||
break;
|
||||
case GITLINK:
|
||||
meta.contentType = "x-git/gitlink";
|
||||
break;
|
||||
case SYMLINK:
|
||||
meta.contentType = "x-git/symlink";
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("file mode: " + fileMode);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Content {
|
||||
final List<ContentEntry> lines;
|
||||
final SparseFileContent fileA;
|
||||
|
||||
@@ -103,7 +103,6 @@ public class Module extends RestApiModule {
|
||||
put(FILE_KIND, "reviewed").to(PutReviewed.class);
|
||||
delete(FILE_KIND, "reviewed").to(DeleteReviewed.class);
|
||||
get(FILE_KIND, "content").to(GetContent.class);
|
||||
get(FILE_KIND, "type").to(GetContentType.class);
|
||||
get(FILE_KIND, "diff").to(GetDiff.class);
|
||||
|
||||
child(CHANGE_KIND, "edit").to(ChangeEdits.class);
|
||||
@@ -115,7 +114,6 @@ public class Module extends RestApiModule {
|
||||
put(CHANGE_EDIT_KIND, "/").to(ChangeEdits.Put.class);
|
||||
delete(CHANGE_EDIT_KIND).to(ChangeEdits.DeleteContent.class);
|
||||
get(CHANGE_EDIT_KIND, "/").to(ChangeEdits.Get.class);
|
||||
get(CHANGE_EDIT_KIND, "type").to(ChangeEdits.GetType.class);
|
||||
|
||||
install(new FactoryModule() {
|
||||
@Override
|
||||
|
||||
@@ -41,4 +41,8 @@ public class BranchResource extends ProjectResource {
|
||||
public String getRef() {
|
||||
return branchInfo.ref;
|
||||
}
|
||||
|
||||
public String getRevision() {
|
||||
return branchInfo.revision;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package com.google.gerrit.server.project;
|
||||
|
||||
import com.google.gerrit.extensions.restapi.RestResource;
|
||||
import com.google.gerrit.extensions.restapi.RestView;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
@@ -33,8 +32,8 @@ public class CommitResource implements RestResource {
|
||||
this.commit = commit;
|
||||
}
|
||||
|
||||
public Project.NameKey getProject() {
|
||||
return project.getNameKey();
|
||||
public ProjectControl getProject() {
|
||||
return project.getControl();
|
||||
}
|
||||
|
||||
public RevCommit getCommit() {
|
||||
|
||||
@@ -16,28 +16,29 @@ package com.google.gerrit.server.project;
|
||||
|
||||
import com.google.gerrit.extensions.restapi.RestResource;
|
||||
import com.google.gerrit.extensions.restapi.RestView;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
|
||||
public class FileResource implements RestResource {
|
||||
public static final TypeLiteral<RestView<FileResource>> FILE_KIND =
|
||||
new TypeLiteral<RestView<FileResource>>() {};
|
||||
|
||||
private final Project.NameKey project;
|
||||
private final String rev;
|
||||
private final ProjectControl project;
|
||||
private final ObjectId rev;
|
||||
private final String path;
|
||||
|
||||
public FileResource(Project.NameKey project, String rev, String path) {
|
||||
public FileResource(ProjectControl project, ObjectId rev, String path) {
|
||||
this.project = project;
|
||||
this.rev = rev;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public Project.NameKey getProject() {
|
||||
public ProjectControl getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
public String getRev() {
|
||||
public ObjectId getRev() {
|
||||
return rev;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ import com.google.gerrit.extensions.restapi.RestView;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
|
||||
@Singleton
|
||||
public class FilesCollection implements
|
||||
ChildCollection<BranchResource, FileResource> {
|
||||
@@ -39,7 +41,10 @@ public class FilesCollection implements
|
||||
|
||||
@Override
|
||||
public FileResource parse(BranchResource parent, IdString id) {
|
||||
return new FileResource(parent.getNameKey(), parent.getRef(), id.get());
|
||||
return new FileResource(
|
||||
parent.getControl(),
|
||||
ObjectId.fromString(parent.getRevision()),
|
||||
id.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -40,8 +40,7 @@ public class FilesInCommitCollection implements
|
||||
@Override
|
||||
public FileResource parse(CommitResource parent, IdString id)
|
||||
throws ResourceNotFoundException {
|
||||
return new FileResource(parent.getProject(), parent.getCommit().getName(),
|
||||
id.get());
|
||||
return new FileResource(parent.getProject(), parent.getCommit(), id.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -35,7 +35,9 @@ public class GetContent implements RestReadView<FileResource> {
|
||||
@Override
|
||||
public BinaryResult apply(FileResource rsrc)
|
||||
throws ResourceNotFoundException, IOException {
|
||||
return fileContentUtil.getContent(rsrc.getProject(), rsrc.getRev(),
|
||||
return fileContentUtil.getContent(
|
||||
rsrc.getProject().getProjectState(),
|
||||
rsrc.getRev(),
|
||||
rsrc.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user