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
|
GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/edit/foo HTTP/1.0
|
||||||
----
|
----
|
||||||
|
|
||||||
The content of the file is returned as text encoded inside base64. When
|
The content of the file is returned as text encoded inside base64.
|
||||||
specified file was deleted in the change edit "`204 No Content`" is returned.
|
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
|
.Response
|
||||||
----
|
----
|
||||||
@@ -1417,33 +1425,11 @@ specified file was deleted in the change edit "`204 No Content`" is returned.
|
|||||||
Content-Disposition: attachment
|
Content-Disposition: attachment
|
||||||
Content-Type: text/plain; charset=ISO-8859-1
|
Content-Type: text/plain; charset=ISO-8859-1
|
||||||
X-FYI-Content-Encoding: base64
|
X-FYI-Content-Encoding: base64
|
||||||
|
X-FYI-Content-Type: text/xml
|
||||||
|
|
||||||
RnJvbSA3ZGFkY2MxNTNmZGVhMTdhYTg0ZmYzMmE2ZTI0NWRiYjY...
|
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]]
|
[[get-edit-message]]
|
||||||
=== Retrieve commit message from Change Edit or current patch set of the change
|
=== 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
|
of the paths the caller has marked as reviewed. Clients that also
|
||||||
need the FileInfo should make two requests.
|
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
|
.Request
|
||||||
----
|
----
|
||||||
GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/674ac754f91e64a0efb8087e59a176484bd534d1/files/?reviewed HTTP/1.0
|
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
|
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
|
.Response
|
||||||
----
|
----
|
||||||
HTTP/1.1 200 OK
|
HTTP/1.1 200 OK
|
||||||
Content-Disposition: attachment
|
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...
|
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]]
|
||||||
=== 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.Base64;
|
||||||
import org.apache.commons.codec.binary.StringUtils;
|
import org.apache.commons.codec.binary.StringUtils;
|
||||||
import org.eclipse.jgit.api.Git;
|
import org.eclipse.jgit.api.Git;
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.PersonIdent;
|
import org.eclipse.jgit.lib.PersonIdent;
|
||||||
import org.eclipse.jgit.lib.RefUpdate;
|
import org.eclipse.jgit.lib.RefUpdate;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
@@ -194,10 +195,10 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
Date beforeRebase = edit.getEditCommit().getCommitterIdent().getWhen();
|
Date beforeRebase = edit.getEditCommit().getCommitterIdent().getWhen();
|
||||||
modifier.rebaseEdit(edit, current);
|
modifier.rebaseEdit(edit, current);
|
||||||
edit = editUtil.byChange(change).get();
|
edit = editUtil.byChange(change).get();
|
||||||
assertByteArray(fileUtil.getContent(edit.getChange().getProject(), edit
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()),
|
||||||
.getRevision().get(), FILE_NAME), CONTENT_NEW);
|
ObjectId.fromString(edit.getRevision().get()), FILE_NAME), CONTENT_NEW);
|
||||||
assertByteArray(fileUtil.getContent(edit.getChange().getProject(), edit
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()),
|
||||||
.getRevision().get(), FILE_NAME2), CONTENT_NEW2);
|
ObjectId.fromString(edit.getRevision().get()), FILE_NAME2), CONTENT_NEW2);
|
||||||
assertThat(edit.getBasePatchSet().getPatchSetId()).isEqualTo(
|
assertThat(edit.getBasePatchSet().getPatchSetId()).isEqualTo(
|
||||||
current.getPatchSetId());
|
current.getPatchSetId());
|
||||||
Date afterRebase = edit.getEditCommit().getCommitterIdent().getWhen();
|
Date afterRebase = edit.getEditCommit().getCommitterIdent().getWhen();
|
||||||
@@ -218,10 +219,10 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
RestResponse r = adminSession.post(urlRebase());
|
RestResponse r = adminSession.post(urlRebase());
|
||||||
assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT);
|
assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT);
|
||||||
edit = editUtil.byChange(change).get();
|
edit = editUtil.byChange(change).get();
|
||||||
assertByteArray(fileUtil.getContent(edit.getChange().getProject(), edit
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()),
|
||||||
.getRevision().get(), FILE_NAME), CONTENT_NEW);
|
ObjectId.fromString(edit.getRevision().get()), FILE_NAME), CONTENT_NEW);
|
||||||
assertByteArray(fileUtil.getContent(edit.getChange().getProject(), edit
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()),
|
||||||
.getRevision().get(), FILE_NAME2), CONTENT_NEW2);
|
ObjectId.fromString(edit.getRevision().get()), FILE_NAME2), CONTENT_NEW2);
|
||||||
assertThat(edit.getBasePatchSet().getPatchSetId()).isEqualTo(
|
assertThat(edit.getBasePatchSet().getPatchSetId()).isEqualTo(
|
||||||
current.getPatchSetId());
|
current.getPatchSetId());
|
||||||
Date afterRebase = edit.getEditCommit().getCommitterIdent().getWhen();
|
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)))
|
assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW)))
|
||||||
.isEqualTo(RefUpdate.Result.FORCED);
|
.isEqualTo(RefUpdate.Result.FORCED);
|
||||||
edit = editUtil.byChange(change);
|
edit = editUtil.byChange(change);
|
||||||
assertByteArray(
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW);
|
||||||
.getRevision().get(), FILE_NAME), CONTENT_NEW);
|
|
||||||
editUtil.delete(edit.get());
|
editUtil.delete(edit.get());
|
||||||
edit = editUtil.byChange(change);
|
edit = editUtil.byChange(change);
|
||||||
assertThat(edit.isPresent()).isFalse();
|
assertThat(edit.isPresent()).isFalse();
|
||||||
@@ -364,8 +364,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
RefUpdate.Result.FORCED);
|
RefUpdate.Result.FORCED);
|
||||||
edit = editUtil.byChange(change);
|
edit = editUtil.byChange(change);
|
||||||
try {
|
try {
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(),
|
fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
edit.get().getRevision().get(), FILE_NAME);
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME);
|
||||||
fail("ResourceNotFoundException expected");
|
fail("ResourceNotFoundException expected");
|
||||||
} catch (ResourceNotFoundException rnfe) {
|
} catch (ResourceNotFoundException rnfe) {
|
||||||
}
|
}
|
||||||
@@ -377,8 +377,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT);
|
assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT);
|
||||||
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
||||||
try {
|
try {
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(),
|
fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
edit.get().getRevision().get(), FILE_NAME);
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME);
|
||||||
fail("ResourceNotFoundException expected");
|
fail("ResourceNotFoundException expected");
|
||||||
} catch (ResourceNotFoundException rnfe) {
|
} catch (ResourceNotFoundException rnfe) {
|
||||||
}
|
}
|
||||||
@@ -397,8 +397,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
SC_NO_CONTENT);
|
SC_NO_CONTENT);
|
||||||
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
||||||
try {
|
try {
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(),
|
fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
edit.get().getRevision().get(), FILE_NAME);
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME);
|
||||||
fail("ResourceNotFoundException expected");
|
fail("ResourceNotFoundException expected");
|
||||||
} catch (ResourceNotFoundException rnfe) {
|
} catch (ResourceNotFoundException rnfe) {
|
||||||
}
|
}
|
||||||
@@ -412,9 +412,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
assertThat(modifier.restoreFile(edit.get(), FILE_NAME)).isEqualTo(
|
assertThat(modifier.restoreFile(edit.get(), FILE_NAME)).isEqualTo(
|
||||||
RefUpdate.Result.FORCED);
|
RefUpdate.Result.FORCED);
|
||||||
edit = editUtil.byChange(change2);
|
edit = editUtil.byChange(change2);
|
||||||
assertByteArray(
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD);
|
||||||
.getRevision().get(), FILE_NAME), CONTENT_OLD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -424,9 +423,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
assertThat(adminSession.post(urlEdit2(), in).getStatusCode()).isEqualTo(
|
assertThat(adminSession.post(urlEdit2(), in).getStatusCode()).isEqualTo(
|
||||||
SC_NO_CONTENT);
|
SC_NO_CONTENT);
|
||||||
Optional<ChangeEdit> edit = editUtil.byChange(change2);
|
Optional<ChangeEdit> edit = editUtil.byChange(change2);
|
||||||
assertByteArray(
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD);
|
||||||
.getRevision().get(), FILE_NAME), CONTENT_OLD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -436,15 +434,13 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW)))
|
assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW)))
|
||||||
.isEqualTo(RefUpdate.Result.FORCED);
|
.isEqualTo(RefUpdate.Result.FORCED);
|
||||||
edit = editUtil.byChange(change);
|
edit = editUtil.byChange(change);
|
||||||
assertByteArray(
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW);
|
||||||
.getRevision().get(), FILE_NAME), CONTENT_NEW);
|
|
||||||
assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW2)))
|
assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW2)))
|
||||||
.isEqualTo(RefUpdate.Result.FORCED);
|
.isEqualTo(RefUpdate.Result.FORCED);
|
||||||
edit = editUtil.byChange(change);
|
edit = editUtil.byChange(change);
|
||||||
assertByteArray(
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW2);
|
||||||
.getRevision().get(), FILE_NAME), CONTENT_NEW2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -454,16 +450,14 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode())
|
assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode())
|
||||||
.isEqualTo(SC_NO_CONTENT);
|
.isEqualTo(SC_NO_CONTENT);
|
||||||
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
||||||
assertByteArray(
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW);
|
||||||
.getRevision().get(), FILE_NAME), CONTENT_NEW);
|
|
||||||
in.content = RestSession.newRawInput(CONTENT_NEW2);
|
in.content = RestSession.newRawInput(CONTENT_NEW2);
|
||||||
assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode())
|
assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode())
|
||||||
.isEqualTo(SC_NO_CONTENT);
|
.isEqualTo(SC_NO_CONTENT);
|
||||||
edit = editUtil.byChange(change);
|
edit = editUtil.byChange(change);
|
||||||
assertByteArray(
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW2);
|
||||||
.getRevision().get(), FILE_NAME), CONTENT_NEW2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -474,9 +468,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode())
|
assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode())
|
||||||
.isEqualTo(SC_NO_CONTENT);
|
.isEqualTo(SC_NO_CONTENT);
|
||||||
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
||||||
assertByteArray(
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW);
|
||||||
.getRevision().get(), FILE_NAME), CONTENT_NEW);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -485,9 +478,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
assertThat(adminSession.put(urlEditFile()).getStatusCode()).isEqualTo(
|
assertThat(adminSession.put(urlEditFile()).getStatusCode()).isEqualTo(
|
||||||
SC_NO_CONTENT);
|
SC_NO_CONTENT);
|
||||||
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
||||||
assertByteArray(
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), "".getBytes());
|
||||||
.getRevision().get(), FILE_NAME), "".getBytes());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -495,9 +487,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
assertThat(adminSession.post(urlEdit()).getStatusCode()).isEqualTo(
|
assertThat(adminSession.post(urlEdit()).getStatusCode()).isEqualTo(
|
||||||
SC_NO_CONTENT);
|
SC_NO_CONTENT);
|
||||||
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
||||||
assertByteArray(
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD);
|
||||||
.getRevision().get(), FILE_NAME), CONTENT_OLD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -517,18 +508,6 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
.isEqualTo(StringUtils.newStringUtf8(CONTENT_NEW2));
|
.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
|
@Test
|
||||||
public void getFileNotFoundRest() throws Exception {
|
public void getFileNotFoundRest() throws Exception {
|
||||||
assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW);
|
assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW);
|
||||||
@@ -536,8 +515,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
SC_NO_CONTENT);
|
SC_NO_CONTENT);
|
||||||
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
Optional<ChangeEdit> edit = editUtil.byChange(change);
|
||||||
try {
|
try {
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(),
|
fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
edit.get().getRevision().get(), FILE_NAME);
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME);
|
||||||
fail("ResourceNotFoundException expected");
|
fail("ResourceNotFoundException expected");
|
||||||
} catch (ResourceNotFoundException rnfe) {
|
} catch (ResourceNotFoundException rnfe) {
|
||||||
}
|
}
|
||||||
@@ -552,9 +531,8 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
assertThat(modifier.modifyFile(edit.get(), FILE_NAME2, RestSession.newRawInput(CONTENT_NEW)))
|
assertThat(modifier.modifyFile(edit.get(), FILE_NAME2, RestSession.newRawInput(CONTENT_NEW)))
|
||||||
.isEqualTo(RefUpdate.Result.FORCED);
|
.isEqualTo(RefUpdate.Result.FORCED);
|
||||||
edit = editUtil.byChange(change);
|
edit = editUtil.byChange(change);
|
||||||
assertByteArray(
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME2), CONTENT_NEW);
|
||||||
.getRevision().get(), FILE_NAME2), CONTENT_NEW);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -564,15 +542,13 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
assertThat(modifier.modifyFile(edit.get(), FILE_NAME2, RestSession.newRawInput(CONTENT_NEW)))
|
assertThat(modifier.modifyFile(edit.get(), FILE_NAME2, RestSession.newRawInput(CONTENT_NEW)))
|
||||||
.isEqualTo(RefUpdate.Result.FORCED);
|
.isEqualTo(RefUpdate.Result.FORCED);
|
||||||
edit = editUtil.byChange(change);
|
edit = editUtil.byChange(change);
|
||||||
assertByteArray(
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME2), CONTENT_NEW);
|
||||||
.getRevision().get(), FILE_NAME2), CONTENT_NEW);
|
|
||||||
assertThat(modifier.modifyFile(edit.get(), FILE_NAME2, RestSession.newRawInput(CONTENT_NEW2)))
|
assertThat(modifier.modifyFile(edit.get(), FILE_NAME2, RestSession.newRawInput(CONTENT_NEW2)))
|
||||||
.isEqualTo(RefUpdate.Result.FORCED);
|
.isEqualTo(RefUpdate.Result.FORCED);
|
||||||
edit = editUtil.byChange(change);
|
edit = editUtil.byChange(change);
|
||||||
assertByteArray(
|
assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
|
||||||
fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
|
ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME2), CONTENT_NEW2);
|
||||||
.getRevision().get(), FILE_NAME2), CONTENT_NEW2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -684,13 +660,6 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
+ FILE_NAME;
|
+ FILE_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String urlEditFileContentType() {
|
|
||||||
return urlEdit()
|
|
||||||
+ "/"
|
|
||||||
+ FILE_NAME
|
|
||||||
+ "/type";
|
|
||||||
}
|
|
||||||
|
|
||||||
private String urlGetFiles() {
|
private String urlGetFiles() {
|
||||||
return urlEdit()
|
return urlEdit()
|
||||||
+ "?list";
|
+ "?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
|
<ui:UiBinder
|
||||||
xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||||
xmlns:c='urn:import:com.google.gwtexpui.globalkey.client'
|
xmlns:u='urn:import:com.google.gerrit.client.ui'
|
||||||
xmlns:f='urn:import:com.google.gerrit.client.change'
|
|
||||||
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
||||||
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
|
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
|
||||||
<ui:style>
|
<ui:style>
|
||||||
.fileContent {
|
|
||||||
background-color: white;
|
|
||||||
font-family: monospace;
|
|
||||||
}
|
|
||||||
.cancel { float: right; }
|
.cancel { float: right; }
|
||||||
</ui:style>
|
</ui:style>
|
||||||
<g:HTMLPanel>
|
<g:HTMLPanel>
|
||||||
<div class='{res.style.section}'>
|
<div class='{res.style.section}'>
|
||||||
<div>
|
<ui:msg>Path: <u:RemoteSuggestBox ui:field='path' visibleLength='86'/></ui:msg>
|
||||||
<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'/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class='{res.style.section}'>
|
<div class='{res.style.section}'>
|
||||||
<g:Button ui:field='save'
|
<g:Button ui:field='open'
|
||||||
title='Create new revision edit'
|
title='Open file in editor'
|
||||||
styleName='{res.style.button}'>
|
styleName='{res.style.button}'>
|
||||||
<ui:attribute name='title'/>
|
<ui:attribute name='title'/>
|
||||||
<div><ui:msg>Save</ui:msg></div>
|
<div><ui:msg>Open</ui:msg></div>
|
||||||
</g:Button>
|
</g:Button>
|
||||||
<g:Button ui:field='cancel'
|
<g:Button ui:field='cancel'
|
||||||
styleName='{res.style.button}'
|
styleName='{res.style.button}'
|
||||||
@@ -193,7 +193,7 @@ public class ChangeScreen2 extends Screen {
|
|||||||
private IncludedInAction includedInAction;
|
private IncludedInAction includedInAction;
|
||||||
private PatchSetsAction patchSetsAction;
|
private PatchSetsAction patchSetsAction;
|
||||||
private DownloadAction downloadAction;
|
private DownloadAction downloadAction;
|
||||||
private EditFileAction editFileAction;
|
private AddFileAction addFileAction;
|
||||||
|
|
||||||
public ChangeScreen2(Change.Id changeId, String base, String revision,
|
public ChangeScreen2(Change.Id changeId, String base, String revision,
|
||||||
boolean openReplyBox, FileTable.Mode mode) {
|
boolean openReplyBox, FileTable.Mode mode) {
|
||||||
@@ -215,11 +215,15 @@ public class ChangeScreen2 extends Screen {
|
|||||||
CallbackGroup group = new CallbackGroup();
|
CallbackGroup group = new CallbackGroup();
|
||||||
if (Gerrit.isSignedIn()) {
|
if (Gerrit.isSignedIn()) {
|
||||||
ChangeApi.editWithFiles(changeId.get(), group.add(
|
ChangeApi.editWithFiles(changeId.get(), group.add(
|
||||||
new GerritCallback<EditInfo>() {
|
new AsyncCallback<EditInfo>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(EditInfo result) {
|
public void onSuccess(EditInfo result) {
|
||||||
edit = result;
|
edit = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable caught) {
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
loadChangeInfo(true, group.addFinal(
|
loadChangeInfo(true, group.addFinal(
|
||||||
@@ -444,9 +448,9 @@ public class ChangeScreen2 extends Screen {
|
|||||||
editMode.setVisible(fileTableMode == FileTable.Mode.REVIEW);
|
editMode.setVisible(fileTableMode == FileTable.Mode.REVIEW);
|
||||||
addFile.setVisible(!editMode.isVisible());
|
addFile.setVisible(!editMode.isVisible());
|
||||||
reviewMode.setVisible(!editMode.isVisible());
|
reviewMode.setVisible(!editMode.isVisible());
|
||||||
editFileAction = new EditFileAction(
|
addFileAction = new AddFileAction(
|
||||||
new PatchSet.Id(changeId, edit == null ? rev._number() : 0),
|
changeId, info.revision(revision),
|
||||||
"", "", style, editMessage, reply);
|
style, addFile);
|
||||||
} else {
|
} else {
|
||||||
editMode.setVisible(false);
|
editMode.setVisible(false);
|
||||||
addFile.setVisible(false);
|
addFile.setVisible(false);
|
||||||
@@ -621,7 +625,7 @@ public class ChangeScreen2 extends Screen {
|
|||||||
|
|
||||||
@UiHandler("addFile")
|
@UiHandler("addFile")
|
||||||
void onAddFile(@SuppressWarnings("unused") ClickEvent e) {
|
void onAddFile(@SuppressWarnings("unused") ClickEvent e) {
|
||||||
editFileAction.onEdit();
|
addFileAction.onEdit();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshFileTable() {
|
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.Gerrit;
|
||||||
import com.google.gerrit.client.VoidResult;
|
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.rpc.GerritCallback;
|
||||||
import com.google.gerrit.client.ui.TextBoxChangeListener;
|
import com.google.gerrit.client.ui.TextBoxChangeListener;
|
||||||
import com.google.gerrit.common.PageLinks;
|
import com.google.gerrit.common.PageLinks;
|
||||||
@@ -79,7 +79,7 @@ class EditMessageBox extends Composite {
|
|||||||
@UiHandler("save")
|
@UiHandler("save")
|
||||||
void onSave(@SuppressWarnings("unused") ClickEvent e) {
|
void onSave(@SuppressWarnings("unused") ClickEvent e) {
|
||||||
save.setEnabled(false);
|
save.setEnabled(false);
|
||||||
ChangeFileApi.putMessage(changeId, message.getText().trim(),
|
ChangeEditApi.putMessage(changeId.get(), message.getText().trim(),
|
||||||
new GerritCallback<VoidResult>() {
|
new GerritCallback<VoidResult>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(VoidResult result) {
|
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.Gerrit;
|
||||||
import com.google.gerrit.client.VoidResult;
|
import com.google.gerrit.client.VoidResult;
|
||||||
import com.google.gerrit.client.changes.ChangeApi;
|
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.CommentInfo;
|
||||||
import com.google.gerrit.client.changes.ReviewInfo;
|
import com.google.gerrit.client.changes.ReviewInfo;
|
||||||
import com.google.gerrit.client.changes.Util;
|
import com.google.gerrit.client.changes.Util;
|
||||||
@@ -317,7 +317,7 @@ public class FileTable extends FlowPanel {
|
|||||||
|
|
||||||
void onDelete(int idx) {
|
void onDelete(int idx) {
|
||||||
String path = list.get(idx).path();
|
String path = list.get(idx).path();
|
||||||
ChangeFileApi.deleteContent(curr, path,
|
ChangeEditApi.delete(curr.getParentKey().get(), path,
|
||||||
new AsyncCallback<VoidResult>() {
|
new AsyncCallback<VoidResult>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(VoidResult result) {
|
public void onSuccess(VoidResult result) {
|
||||||
@@ -333,7 +333,7 @@ public class FileTable extends FlowPanel {
|
|||||||
|
|
||||||
void onRestore(int idx) {
|
void onRestore(int idx) {
|
||||||
String path = list.get(idx).path();
|
String path = list.get(idx).path();
|
||||||
ChangeFileApi.restoreContent(curr, path,
|
ChangeEditApi.restore(curr.getParentKey().get(), path,
|
||||||
new AsyncCallback<VoidResult>() {
|
new AsyncCallback<VoidResult>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(VoidResult result) {
|
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.CommentApi;
|
||||||
import com.google.gerrit.client.changes.CommentInfo;
|
import com.google.gerrit.client.changes.CommentInfo;
|
||||||
import com.google.gerrit.client.rpc.CallbackGroup;
|
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.NativeMap;
|
||||||
import com.google.gerrit.client.rpc.Natives;
|
import com.google.gerrit.client.rpc.Natives;
|
||||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||||
import com.google.gwt.core.client.JsArray;
|
import com.google.gwt.core.client.JsArray;
|
||||||
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@@ -53,39 +53,55 @@ class CommentsCollections {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private GerritCallback<NativeMap<JsArray<CommentInfo>>> publishedBase() {
|
private AsyncCallback<NativeMap<JsArray<CommentInfo>>> publishedBase() {
|
||||||
return new GerritCallback<NativeMap<JsArray<CommentInfo>>>() {
|
return new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
|
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
|
||||||
publishedBase = sort(result.get(path));
|
publishedBase = sort(result.get(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable caught) {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private GerritCallback<NativeMap<JsArray<CommentInfo>>> publishedRevision() {
|
private AsyncCallback<NativeMap<JsArray<CommentInfo>>> publishedRevision() {
|
||||||
return new GerritCallback<NativeMap<JsArray<CommentInfo>>>() {
|
return new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
|
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
|
||||||
publishedRevision = sort(result.get(path));
|
publishedRevision = sort(result.get(path));
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private GerritCallback<NativeMap<JsArray<CommentInfo>>> draftsBase() {
|
|
||||||
return new GerritCallback<NativeMap<JsArray<CommentInfo>>>() {
|
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
|
public void onFailure(Throwable caught) {
|
||||||
draftsBase = sort(result.get(path));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private GerritCallback<NativeMap<JsArray<CommentInfo>>> draftsRevision() {
|
private AsyncCallback<NativeMap<JsArray<CommentInfo>>> draftsBase() {
|
||||||
return new GerritCallback<NativeMap<JsArray<CommentInfo>>>() {
|
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
|
@Override
|
||||||
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
|
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
|
||||||
draftsRevision = sort(result.get(path));
|
draftsRevision = sort(result.get(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable caught) {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -167,26 +167,36 @@ public class SideBySide2 extends Screen {
|
|||||||
protected void onLoad() {
|
protected void onLoad() {
|
||||||
super.onLoad();
|
super.onLoad();
|
||||||
|
|
||||||
CallbackGroup cmGroup = new CallbackGroup();
|
CallbackGroup group1 = new CallbackGroup();
|
||||||
CodeMirror.initLibrary(cmGroup.<Void> addEmpty());
|
final CallbackGroup group2 = new CallbackGroup();
|
||||||
|
|
||||||
final CallbackGroup group = new CallbackGroup();
|
CodeMirror.initLibrary(group1.add(new AsyncCallback<Void>() {
|
||||||
final AsyncCallback<Void> themeCallback = group.addEmpty();
|
final AsyncCallback<Void> themeCallback = group2.addEmpty();
|
||||||
final AsyncCallback<Void> modeInjectorCb = group.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)
|
DiffApi.diff(revision, path)
|
||||||
.base(base)
|
.base(base)
|
||||||
.wholeFile()
|
.wholeFile()
|
||||||
.intraline(prefs.intralineDifference())
|
.intraline(prefs.intralineDifference())
|
||||||
.ignoreWhitespace(prefs.ignoreWhitespace())
|
.ignoreWhitespace(prefs.ignoreWhitespace())
|
||||||
.get(cmGroup.addFinal(new GerritCallback<DiffInfo>() {
|
.get(group1.addFinal(new GerritCallback<DiffInfo>() {
|
||||||
|
final AsyncCallback<Void> modeInjectorCb = group2.addEmpty();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(DiffInfo diffInfo) {
|
public void onSuccess(DiffInfo diffInfo) {
|
||||||
diff = diffInfo;
|
diff = diffInfo;
|
||||||
fileSize = bucketFileSize(diffInfo);
|
fileSize = bucketFileSize(diffInfo);
|
||||||
|
|
||||||
// Load theme after CM library to ensure theme can override CSS.
|
|
||||||
ThemeLoader.loadTheme(prefs.theme(), themeCallback);
|
|
||||||
if (prefs.syntaxHighlighting()) {
|
if (prefs.syntaxHighlighting()) {
|
||||||
if (fileSize.compareTo(FileSize.SMALL) > 0) {
|
if (fileSize.compareTo(FileSize.SMALL) > 0) {
|
||||||
modeInjectorCb.onSuccess(null);
|
modeInjectorCb.onSuccess(null);
|
||||||
@@ -200,22 +210,26 @@ public class SideBySide2 extends Screen {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
if (Gerrit.isSignedIn()) {
|
if (Gerrit.isSignedIn()) {
|
||||||
ChangeApi.edit(changeId.get(), group.add(
|
ChangeApi.edit(changeId.get(), group2.add(
|
||||||
new GerritCallback<EditInfo>() {
|
new AsyncCallback<EditInfo>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(EditInfo result) {
|
public void onSuccess(EditInfo result) {
|
||||||
edit = result;
|
edit = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable caught) {
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
final CommentsCollections comments = new CommentsCollections();
|
final CommentsCollections comments = new CommentsCollections();
|
||||||
comments.load(base, revision, path, group);
|
comments.load(base, revision, path, group2);
|
||||||
|
|
||||||
RestApi call = ChangeApi.detail(changeId.get());
|
RestApi call = ChangeApi.detail(changeId.get());
|
||||||
ChangeList.addOptions(call, EnumSet.of(
|
ChangeList.addOptions(call, EnumSet.of(
|
||||||
ListChangesOption.ALL_REVISIONS));
|
ListChangesOption.ALL_REVISIONS));
|
||||||
call.get(group.add(new GerritCallback<ChangeInfo>() {
|
call.get(group2.add(new AsyncCallback<ChangeInfo>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(ChangeInfo info) {
|
public void onSuccess(ChangeInfo info) {
|
||||||
info.revisions().copyKeysIntoChildren("name");
|
info.revisions().copyKeysIntoChildren("name");
|
||||||
@@ -230,9 +244,14 @@ public class SideBySide2 extends Screen {
|
|||||||
diffTable.set(prefs, list, diff, edit != null, currentPatchSet,
|
diffTable.set(prefs, list, diff, edit != null, currentPatchSet,
|
||||||
info.status().isOpen());
|
info.status().isOpen());
|
||||||
header.setChangeInfo(info);
|
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) {
|
new ScreenLoadCallback<ConfigInfoCache.Entry>(SideBySide2.this) {
|
||||||
@Override
|
@Override
|
||||||
protected void preDisplay(ConfigInfoCache.Entry result) {
|
protected void preDisplay(ConfigInfoCache.Entry result) {
|
||||||
|
|||||||
@@ -14,17 +14,23 @@
|
|||||||
|
|
||||||
package com.google.gerrit.client.editor;
|
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.Gerrit;
|
||||||
import com.google.gerrit.client.JumpKeys;
|
import com.google.gerrit.client.JumpKeys;
|
||||||
import com.google.gerrit.client.VoidResult;
|
import com.google.gerrit.client.VoidResult;
|
||||||
import com.google.gerrit.client.account.DiffPreferences;
|
import com.google.gerrit.client.account.DiffPreferences;
|
||||||
import com.google.gerrit.client.changes.ChangeApi;
|
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.changes.ChangeInfo;
|
||||||
import com.google.gerrit.client.diff.FileInfo;
|
import com.google.gerrit.client.diff.FileInfo;
|
||||||
import com.google.gerrit.client.diff.Header;
|
import com.google.gerrit.client.diff.Header;
|
||||||
import com.google.gerrit.client.rpc.CallbackGroup;
|
import com.google.gerrit.client.rpc.CallbackGroup;
|
||||||
import com.google.gerrit.client.rpc.GerritCallback;
|
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.rpc.ScreenLoadCallback;
|
||||||
import com.google.gerrit.client.ui.Screen;
|
import com.google.gerrit.client.ui.Screen;
|
||||||
import com.google.gerrit.common.PageLinks;
|
import com.google.gerrit.common.PageLinks;
|
||||||
@@ -68,11 +74,14 @@ public class EditScreen extends Screen {
|
|||||||
private final String path;
|
private final String path;
|
||||||
private DiffPreferences prefs;
|
private DiffPreferences prefs;
|
||||||
private CodeMirror cm;
|
private CodeMirror cm;
|
||||||
private String type;
|
private HttpResponse<NativeString> content;
|
||||||
|
|
||||||
@UiField Element header;
|
@UiField Element header;
|
||||||
@UiField Element project;
|
@UiField Element project;
|
||||||
@UiField Element filePath;
|
@UiField Element filePath;
|
||||||
|
@UiField Element cursLine;
|
||||||
|
@UiField Element cursCol;
|
||||||
|
@UiField Element dirty;
|
||||||
@UiField Button close;
|
@UiField Button close;
|
||||||
@UiField Button save;
|
@UiField Button save;
|
||||||
@UiField Element editor;
|
@UiField Element editor;
|
||||||
@@ -100,10 +109,11 @@ public class EditScreen extends Screen {
|
|||||||
protected void onLoad() {
|
protected void onLoad() {
|
||||||
super.onLoad();
|
super.onLoad();
|
||||||
|
|
||||||
CallbackGroup cmGroup = new CallbackGroup();
|
CallbackGroup group1 = new CallbackGroup();
|
||||||
final CallbackGroup group = new CallbackGroup();
|
final CallbackGroup group2 = new CallbackGroup();
|
||||||
CodeMirror.initLibrary(cmGroup.add(new AsyncCallback<Void>() {
|
|
||||||
final AsyncCallback<Void> themeCallback = group.addEmpty();
|
CodeMirror.initLibrary(group1.add(new AsyncCallback<Void>() {
|
||||||
|
final AsyncCallback<Void> themeCallback = group2.addEmpty();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Void result) {
|
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(),
|
ChangeApi.detail(revision.getParentKey().get(),
|
||||||
group.add(new GerritCallback<ChangeInfo>() {
|
group1.add(new AsyncCallback<ChangeInfo>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(ChangeInfo c) {
|
public void onSuccess(ChangeInfo c) {
|
||||||
project.setInnerText(c.project());
|
project.setInnerText(c.project());
|
||||||
SafeHtml.setInnerHTML(filePath, Header.formatPath(path, null, null));
|
SafeHtml.setInnerHTML(filePath, Header.formatPath(path, null, null));
|
||||||
}
|
}
|
||||||
}));
|
|
||||||
|
|
||||||
ChangeFileApi.getContentOrMessage(revision, path,
|
|
||||||
group.addFinal(new ScreenLoadCallback<String>(this) {
|
|
||||||
@Override
|
@Override
|
||||||
protected void preDisplay(String content) {
|
public void onFailure(Throwable caught) {
|
||||||
initEditor(content);
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
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
|
@Override
|
||||||
@@ -172,11 +194,11 @@ public class EditScreen extends Screen {
|
|||||||
});
|
});
|
||||||
|
|
||||||
generation = cm.changeGeneration(true);
|
generation = cm.changeGeneration(true);
|
||||||
save.setEnabled(false);
|
setClean(true);
|
||||||
cm.on(new ChangesHandler() {
|
cm.on(new ChangesHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void handle(CodeMirror cm) {
|
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()));
|
Gerrit.display(PageLinks.toChangeInEditMode(revision.getParentKey()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initEditor(String content) {
|
private void initEditor(HttpResponse<NativeString> file) {
|
||||||
ModeInfo mode = prefs.syntaxHighlighting()
|
ModeInfo mode = prefs.syntaxHighlighting()
|
||||||
? ModeInfo.findMode(type, path)
|
? ModeInfo.findMode(file.getContentType(), path)
|
||||||
: null;
|
: null;
|
||||||
cm = CodeMirror.create(editor, Configuration.create()
|
cm = CodeMirror.create(editor, Configuration.create()
|
||||||
.set("value", content)
|
.set("value", file.getResult().asString())
|
||||||
.set("readOnly", false)
|
.set("readOnly", false)
|
||||||
.set("cursorBlinkRate", 0)
|
.set("cursorBlinkRate", 0)
|
||||||
.set("cursorHeight", 0.85)
|
.set("cursorHeight", 0.85)
|
||||||
@@ -272,9 +294,16 @@ public class EditScreen extends Screen {
|
|||||||
|
|
||||||
private void updateActiveLine() {
|
private void updateActiveLine() {
|
||||||
Pos p = cm.getCursor("end");
|
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()));
|
cm.extras().activeLine(cm.getLineHandleVisualStart(p.line()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setClean(boolean clean) {
|
||||||
|
save.setEnabled(!clean);
|
||||||
|
dirty.getStyle().setVisibility(!clean ? VISIBLE : HIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
private Runnable save() {
|
private Runnable save() {
|
||||||
return new Runnable() {
|
return new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@@ -282,12 +311,12 @@ public class EditScreen extends Screen {
|
|||||||
if (!cm.isClean(generation)) {
|
if (!cm.isClean(generation)) {
|
||||||
String text = cm.getValue();
|
String text = cm.getValue();
|
||||||
final int g = cm.changeGeneration(false);
|
final int g = cm.changeGeneration(false);
|
||||||
ChangeFileApi.putContentOrMessage(revision, path, text,
|
ChangeEditApi.put(revision.getParentKey().get(), path, text,
|
||||||
new GerritCallback<VoidResult>() {
|
new GerritCallback<VoidResult>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(VoidResult result) {
|
public void onSuccess(VoidResult result) {
|
||||||
generation = g;
|
generation = g;
|
||||||
save.setEnabled(!cm.isClean(g));
|
setClean(cm.isClean(g));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,34 @@ limitations under the License.
|
|||||||
.path {
|
.path {
|
||||||
white-space: nowrap;
|
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>
|
</ui:style>
|
||||||
<g:HTMLPanel>
|
<g:HTMLPanel>
|
||||||
<div class='{style.headerLine}' ui:field='header'>
|
<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>
|
<span class='{style.path}'><span ui:field='project'/> / <span ui:field='filePath'/></span>
|
||||||
</div>
|
</div>
|
||||||
<div ui:field='editor' />
|
<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>
|
</g:HTMLPanel>
|
||||||
</ui:UiBinder>
|
</ui:UiBinder>
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ import java.util.Set;
|
|||||||
* processing it.
|
* processing it.
|
||||||
*/
|
*/
|
||||||
public class CallbackGroup {
|
public class CallbackGroup {
|
||||||
private final List<CallbackImpl<?>> callbacks;
|
private final List<CallbackGlue> callbacks;
|
||||||
private final Set<CallbackImpl<?>> remaining;
|
private final Set<CallbackGlue> remaining;
|
||||||
private boolean finalAdded;
|
private boolean finalAdded;
|
||||||
|
|
||||||
private boolean failed;
|
private boolean failed;
|
||||||
@@ -76,6 +76,27 @@ public class CallbackGroup {
|
|||||||
return handleAdd(cb);
|
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) {
|
public <T> Callback<T> addFinal(final AsyncCallback<T> cb) {
|
||||||
checkFinalAdded();
|
checkFinalAdded();
|
||||||
finalAdded = true;
|
finalAdded = true;
|
||||||
@@ -84,7 +105,7 @@ public class CallbackGroup {
|
|||||||
|
|
||||||
public void done() {
|
public void done() {
|
||||||
finalAdded = true;
|
finalAdded = true;
|
||||||
applyAllSuccess();
|
apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addListener(AsyncCallback<Void> cb) {
|
public void addListener(AsyncCallback<Void> cb) {
|
||||||
@@ -99,19 +120,30 @@ public class CallbackGroup {
|
|||||||
addListener(group.<Void> addEmpty());
|
addListener(group.<Void> addEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyAllSuccess() {
|
private void success(CallbackGlue cb) {
|
||||||
if (!failed && finalAdded && remaining.isEmpty()) {
|
remaining.remove(cb);
|
||||||
for (CallbackImpl<?> cb : callbacks) {
|
apply();
|
||||||
cb.applySuccess();
|
|
||||||
}
|
|
||||||
callbacks.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyAllFailed() {
|
private <T> void failure(CallbackGlue w, Throwable caught) {
|
||||||
if (failed && finalAdded && remaining.isEmpty()) {
|
if (!failed) {
|
||||||
for (CallbackImpl<?> cb : callbacks) {
|
failed = true;
|
||||||
cb.applyFailed();
|
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();
|
callbacks.clear();
|
||||||
}
|
}
|
||||||
@@ -139,7 +171,12 @@ public class CallbackGroup {
|
|||||||
extends AsyncCallback<T>, com.google.gwtjsonrpc.common.AsyncCallback<T> {
|
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;
|
AsyncCallback<T> delegate;
|
||||||
T result;
|
T result;
|
||||||
|
|
||||||
@@ -150,21 +187,16 @@ public class CallbackGroup {
|
|||||||
@Override
|
@Override
|
||||||
public void onSuccess(T value) {
|
public void onSuccess(T value) {
|
||||||
this.result = value;
|
this.result = value;
|
||||||
remaining.remove(this);
|
success(this);
|
||||||
CallbackGroup.this.applyAllSuccess();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Throwable caught) {
|
public void onFailure(Throwable caught) {
|
||||||
if (!failed) {
|
failure(this, caught);
|
||||||
failed = true;
|
|
||||||
failedThrowable = caught;
|
|
||||||
}
|
|
||||||
remaining.remove(this);
|
|
||||||
CallbackGroup.this.applyAllFailed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void applySuccess() {
|
@Override
|
||||||
|
public void applySuccess() {
|
||||||
AsyncCallback<T> cb = delegate;
|
AsyncCallback<T> cb = delegate;
|
||||||
if (cb != null) {
|
if (cb != null) {
|
||||||
delegate = null;
|
delegate = null;
|
||||||
@@ -173,7 +205,8 @@ public class CallbackGroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyFailed() {
|
@Override
|
||||||
|
public void applyFailed() {
|
||||||
AsyncCallback<T> cb = delegate;
|
AsyncCallback<T> cb = delegate;
|
||||||
if (cb != null) {
|
if (cb != null) {
|
||||||
delegate = 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.NoSuchEntityException;
|
||||||
import com.google.gerrit.common.errors.NoSuchGroupException;
|
import com.google.gerrit.common.errors.NoSuchGroupException;
|
||||||
import com.google.gerrit.common.errors.NotSignedInException;
|
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.gwt.user.client.rpc.InvocationException;
|
||||||
import com.google.gwtjsonrpc.client.RemoteJsonException;
|
import com.google.gwtjsonrpc.client.RemoteJsonException;
|
||||||
import com.google.gwtjsonrpc.client.ServerUnavailableException;
|
import com.google.gwtjsonrpc.client.ServerUnavailableException;
|
||||||
@@ -35,6 +34,10 @@ public abstract class GerritCallback<T> implements
|
|||||||
com.google.gwt.user.client.rpc.AsyncCallback<T> {
|
com.google.gwt.user.client.rpc.AsyncCallback<T> {
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(final Throwable caught) {
|
public void onFailure(final Throwable caught) {
|
||||||
|
showFailure(caught);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showFailure(Throwable caught) {
|
||||||
if (isNotSignedIn(caught) || isInvalidXSRF(caught)) {
|
if (isNotSignedIn(caught) || isInvalidXSRF(caught)) {
|
||||||
new NotSignedInDialog().center();
|
new NotSignedInDialog().center();
|
||||||
|
|
||||||
@@ -70,7 +73,6 @@ public abstract class GerritCallback<T> implements
|
|||||||
new ErrorDialog(RpcConstants.C.errorServerUnavailable()).center();
|
new ErrorDialog(RpcConstants.C.errorServerUnavailable()).center();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
GWT.log(getClass().getName() + " caught " + caught, caught);
|
|
||||||
new ErrorDialog(caught).center();
|
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 {
|
implements RequestCallback {
|
||||||
private final boolean background;
|
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.background = bg;
|
||||||
this.cb = cb;
|
this.cb = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResponseReceived(Request req, Response res) {
|
public void onResponseReceived(Request req, final Response res) {
|
||||||
int status = res.getStatusCode();
|
int status = res.getStatusCode();
|
||||||
if (status == Response.SC_NO_CONTENT) {
|
if (status == Response.SC_NO_CONTENT) {
|
||||||
cb.onSuccess(null);
|
cb.onSuccess(new HttpResponse<T>(res, null, null));
|
||||||
if (!background) {
|
if (!background) {
|
||||||
RpcStatus.INSTANCE.onRpcComplete();
|
RpcStatus.INSTANCE.onRpcComplete();
|
||||||
}
|
}
|
||||||
@@ -126,12 +126,12 @@ public class RestApi {
|
|||||||
} else if (200 <= status && status < 300) {
|
} else if (200 <= status && status < 300) {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
final T data;
|
final T data;
|
||||||
if (isTextBody(res)) {
|
final String type;
|
||||||
data = NativeString.wrap(res.getText()).cast();
|
if (isJsonBody(res)) {
|
||||||
} else if (isJsonBody(res)) {
|
|
||||||
try {
|
try {
|
||||||
// javac generics bug
|
// javac generics bug
|
||||||
data = RestApi.<T>cast(parseJson(res));
|
data = RestApi.<T> cast(parseJson(res));
|
||||||
|
type = JSON_TYPE;
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
if (!background) {
|
if (!background) {
|
||||||
RpcStatus.INSTANCE.onRpcComplete();
|
RpcStatus.INSTANCE.onRpcComplete();
|
||||||
@@ -140,6 +140,12 @@ public class RestApi {
|
|||||||
"Invalid JSON: " + e.getMessage()));
|
"Invalid JSON: " + e.getMessage()));
|
||||||
return;
|
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 {
|
} else {
|
||||||
if (!background) {
|
if (!background) {
|
||||||
RpcStatus.INSTANCE.onRpcComplete();
|
RpcStatus.INSTANCE.onRpcComplete();
|
||||||
@@ -154,7 +160,7 @@ public class RestApi {
|
|||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
try {
|
try {
|
||||||
cb.onSuccess(data);
|
cb.onSuccess(new HttpResponse<>(res, type, data));
|
||||||
} finally {
|
} finally {
|
||||||
if (!background) {
|
if (!background) {
|
||||||
RpcStatus.INSTANCE.onRpcComplete();
|
RpcStatus.INSTANCE.onRpcComplete();
|
||||||
@@ -318,21 +324,24 @@ public class RestApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <T extends JavaScriptObject> void get(AsyncCallback<T> cb) {
|
public <T extends JavaScriptObject> void get(AsyncCallback<T> cb) {
|
||||||
|
get(wrap(cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends JavaScriptObject> void get(HttpCallback<T> cb) {
|
||||||
send(GET, cb);
|
send(GET, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends JavaScriptObject> void delete(AsyncCallback<T> 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);
|
send(DELETE, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends JavaScriptObject> void delete(JavaScriptObject content,
|
private <T extends JavaScriptObject> void send(Method method,
|
||||||
AsyncCallback<T> cb) {
|
HttpCallback<T> cb) {
|
||||||
sendJSON(DELETE, content, cb);
|
HttpImpl<T> httpCallback = new HttpImpl<>(background, cb);
|
||||||
}
|
|
||||||
|
|
||||||
private <T extends JavaScriptObject> void send(
|
|
||||||
Method method, AsyncCallback<T> cb) {
|
|
||||||
HttpCallback<T> httpCallback = new HttpCallback<>(background, cb);
|
|
||||||
try {
|
try {
|
||||||
if (!background) {
|
if (!background) {
|
||||||
RpcStatus.INSTANCE.onRpcStart();
|
RpcStatus.INSTANCE.onRpcStart();
|
||||||
@@ -346,33 +355,59 @@ public class RestApi {
|
|||||||
public <T extends JavaScriptObject> void post(
|
public <T extends JavaScriptObject> void post(
|
||||||
JavaScriptObject content,
|
JavaScriptObject content,
|
||||||
AsyncCallback<T> cb) {
|
AsyncCallback<T> cb) {
|
||||||
|
post(content, wrap(cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends JavaScriptObject> void post(
|
||||||
|
JavaScriptObject content,
|
||||||
|
HttpCallback<T> cb) {
|
||||||
sendJSON(POST, content, cb);
|
sendJSON(POST, content, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends JavaScriptObject> void post(String content,
|
public <T extends JavaScriptObject> void post(String content,
|
||||||
AsyncCallback<T> cb) {
|
AsyncCallback<T> cb) {
|
||||||
|
post(content, wrap(cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends JavaScriptObject> void post(String content,
|
||||||
|
HttpCallback<T> cb) {
|
||||||
sendRaw(POST, content, cb);
|
sendRaw(POST, content, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends JavaScriptObject> void put(AsyncCallback<T> 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);
|
send(PUT, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends JavaScriptObject> void put(String content,
|
public <T extends JavaScriptObject> void put(String content,
|
||||||
AsyncCallback<T> cb) {
|
AsyncCallback<T> cb) {
|
||||||
|
put(content, wrap(cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends JavaScriptObject> void put(String content,
|
||||||
|
HttpCallback<T> cb) {
|
||||||
sendRaw(PUT, content, cb);
|
sendRaw(PUT, content, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends JavaScriptObject> void put(
|
public <T extends JavaScriptObject> void put(
|
||||||
JavaScriptObject content,
|
JavaScriptObject content,
|
||||||
AsyncCallback<T> cb) {
|
AsyncCallback<T> cb) {
|
||||||
|
put(content, wrap(cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends JavaScriptObject> void put(
|
||||||
|
JavaScriptObject content,
|
||||||
|
HttpCallback<T> cb) {
|
||||||
sendJSON(PUT, content, cb);
|
sendJSON(PUT, content, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends JavaScriptObject> void sendJSON(
|
private <T extends JavaScriptObject> void sendJSON(
|
||||||
Method method, JavaScriptObject content,
|
Method method, JavaScriptObject content,
|
||||||
AsyncCallback<T> cb) {
|
HttpCallback<T> cb) {
|
||||||
HttpCallback<T> httpCallback = new HttpCallback<>(background, cb);
|
HttpImpl<T> httpCallback = new HttpImpl<>(background, cb);
|
||||||
try {
|
try {
|
||||||
if (!background) {
|
if (!background) {
|
||||||
RpcStatus.INSTANCE.onRpcStart();
|
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,
|
private <T extends JavaScriptObject> void sendRaw(Method method, String body,
|
||||||
AsyncCallback<T> cb) {
|
HttpCallback<T> cb) {
|
||||||
HttpCallback<T> httpCallback = new HttpCallback<>(background, cb);
|
HttpImpl<T> httpCallback = new HttpImpl<>(background, cb);
|
||||||
try {
|
try {
|
||||||
if (!background) {
|
if (!background) {
|
||||||
RpcStatus.INSTANCE.onRpcStart();
|
RpcStatus.INSTANCE.onRpcStart();
|
||||||
@@ -422,16 +461,22 @@ public class RestApi {
|
|||||||
return isContentType(res, TEXT_TYPE);
|
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) {
|
private static boolean isContentType(Response res, String want) {
|
||||||
String type = res.getHeader("Content-Type");
|
String type = res.getHeader("Content-Type");
|
||||||
if (type == null) {
|
return type != null && want.equals(simpleType(type));
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
private static String simpleType(String type) {
|
||||||
int semi = type.indexOf(';');
|
int semi = type.indexOf(';');
|
||||||
if (semi >= 0) {
|
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)
|
private static JSONValue parseJson(Response res)
|
||||||
@@ -464,4 +509,19 @@ public class RestApi {
|
|||||||
throw new JSONException("unsupported JSON type");
|
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;
|
package net.codemirror.lib;
|
||||||
|
|
||||||
import com.google.gerrit.client.rpc.CallbackGroup;
|
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.Callback;
|
||||||
import com.google.gwt.core.client.ScriptInjector;
|
import com.google.gwt.core.client.ScriptInjector;
|
||||||
import com.google.gwt.dom.client.ScriptElement;
|
import com.google.gwt.dom.client.ScriptElement;
|
||||||
@@ -39,11 +38,15 @@ public class Loader {
|
|||||||
|
|
||||||
CallbackGroup group = new CallbackGroup();
|
CallbackGroup group = new CallbackGroup();
|
||||||
injectCss(Lib.I.css(), group.<Void> addEmpty());
|
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
|
@Override
|
||||||
public void onSuccess(Void result) {
|
public void onSuccess(Void result) {
|
||||||
Vim.initKeyMap();
|
Vim.initKeyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable caught) {
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
group.addListener(cb);
|
group.addListener(cb);
|
||||||
group.done();
|
group.done();
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ class RevisionApiImpl extends RevisionApi.NotImplemented implements RevisionApi
|
|||||||
return ImmutableSet.copyOf((Iterable<String>) listFiles
|
return ImmutableSet.copyOf((Iterable<String>) listFiles
|
||||||
.get().setReviewed(true)
|
.get().setReviewed(true)
|
||||||
.apply(revision).value());
|
.apply(revision).value());
|
||||||
} catch (OrmException e) {
|
} catch (OrmException | IOException e) {
|
||||||
throw new RestApiException("Cannot list reviewed files", 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.Singleton;
|
||||||
import com.google.inject.assistedinject.Assisted;
|
import com.google.inject.assistedinject.Assisted;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.kohsuke.args4j.Option;
|
import org.kohsuke.args4j.Option;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -433,8 +434,8 @@ public class ChangeEdits implements
|
|||||||
throws ResourceNotFoundException, IOException {
|
throws ResourceNotFoundException, IOException {
|
||||||
try {
|
try {
|
||||||
return Response.ok(fileContentUtil.getContent(
|
return Response.ok(fileContentUtil.getContent(
|
||||||
rsrc.getChangeEdit().getChange().getProject(),
|
rsrc.getControl().getProjectControl().getProjectState(),
|
||||||
rsrc.getChangeEdit().getRevision().get(),
|
ObjectId.fromString(rsrc.getChangeEdit().getRevision().get()),
|
||||||
rsrc.getPath()));
|
rsrc.getPath()));
|
||||||
} catch (ResourceNotFoundException rnfe) {
|
} catch (ResourceNotFoundException rnfe) {
|
||||||
return Response.none();
|
return Response.none();
|
||||||
@@ -502,29 +503,12 @@ public class ChangeEdits implements
|
|||||||
IOException, ResourceNotFoundException {
|
IOException, ResourceNotFoundException {
|
||||||
Optional<ChangeEdit> edit = editUtil.byChange(rsrc.getChange());
|
Optional<ChangeEdit> edit = editUtil.byChange(rsrc.getChange());
|
||||||
if (edit.isPresent()) {
|
if (edit.isPresent()) {
|
||||||
return BinaryResult.create(
|
String msg = edit.get().getEditCommit().getFullMessage();
|
||||||
edit.get().getEditCommit().getFullMessage()).base64();
|
return BinaryResult.create(msg)
|
||||||
|
.setContentType(FileContentUtil.TEXT_X_GERRIT_COMMIT_MESSAGE)
|
||||||
|
.base64();
|
||||||
}
|
}
|
||||||
throw new ResourceNotFoundException();
|
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 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.BinaryResult;
|
||||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
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.FileTypeRegistry;
|
||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
|
import com.google.gerrit.server.project.ProjectState;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
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.ObjectLoader;
|
||||||
import org.eclipse.jgit.lib.ObjectReader;
|
import org.eclipse.jgit.lib.ObjectReader;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
@@ -36,6 +41,11 @@ import java.io.OutputStream;
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class FileContentUtil {
|
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 GitRepositoryManager repoManager;
|
||||||
private final FileTypeRegistry registry;
|
private final FileTypeRegistry registry;
|
||||||
|
|
||||||
@@ -46,28 +56,50 @@ public class FileContentUtil {
|
|||||||
this.registry = ftr;
|
this.registry = ftr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BinaryResult getContent(Project.NameKey project, String revstr,
|
public BinaryResult getContent(ProjectState project, ObjectId revstr,
|
||||||
String path) throws ResourceNotFoundException, IOException {
|
String path) throws ResourceNotFoundException, IOException {
|
||||||
Repository repo = repoManager.openRepository(project);
|
Repository repo = openRepository(project);
|
||||||
try {
|
try {
|
||||||
RevWalk rw = new RevWalk(repo);
|
RevWalk rw = new RevWalk(repo);
|
||||||
try {
|
try {
|
||||||
RevCommit commit = rw.parseCommit(repo.resolve(revstr));
|
RevCommit commit = rw.parseCommit(revstr);
|
||||||
TreeWalk tw =
|
ObjectReader reader = rw.getObjectReader();
|
||||||
TreeWalk.forPath(rw.getObjectReader(), path,
|
TreeWalk tw = TreeWalk.forPath(reader, path, commit.getTree());
|
||||||
commit.getTree().getId());
|
|
||||||
if (tw == null) {
|
if (tw == null) {
|
||||||
throw new ResourceNotFoundException();
|
throw new ResourceNotFoundException();
|
||||||
}
|
}
|
||||||
final ObjectLoader object = repo.open(tw.getObjectId(0));
|
|
||||||
@SuppressWarnings("resource")
|
org.eclipse.jgit.lib.FileMode mode = tw.getFileMode(0);
|
||||||
BinaryResult result = new BinaryResult() {
|
ObjectId id = tw.getObjectId(0);
|
||||||
@Override
|
if (mode == org.eclipse.jgit.lib.FileMode.GITLINK) {
|
||||||
public void writeTo(OutputStream os) throws IOException {
|
return BinaryResult.create(id.name())
|
||||||
object.copyTo(os);
|
.setContentType(X_GIT_GITLINK)
|
||||||
}
|
.base64();
|
||||||
};
|
}
|
||||||
return result.setContentLength(object.getSize()).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 {
|
} finally {
|
||||||
rw.release();
|
rw.release();
|
||||||
}
|
}
|
||||||
@@ -76,31 +108,44 @@ public class FileContentUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getContentType(Project.NameKey project, String revstr,
|
private static BinaryResult asBinaryResult(final ObjectLoader obj) {
|
||||||
String path) throws ResourceNotFoundException, IOException {
|
@SuppressWarnings("resource")
|
||||||
Repository repo = repoManager.openRepository(project);
|
BinaryResult result = new BinaryResult() {
|
||||||
try {
|
@Override
|
||||||
RevWalk rw = new RevWalk(repo);
|
public void writeTo(OutputStream os) throws IOException {
|
||||||
ObjectReader reader = repo.newObjectReader();
|
obj.copyTo(os);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
} finally {
|
}.setContentLength(obj.getSize());
|
||||||
repo.close();
|
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.Provider;
|
||||||
import com.google.inject.Singleton;
|
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.ObjectReader;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
import org.eclipse.jgit.revwalk.RevWalk;
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
import org.eclipse.jgit.treewalk.TreeWalk;
|
import org.eclipse.jgit.treewalk.TreeWalk;
|
||||||
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
|
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
|
||||||
@@ -53,6 +56,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -96,6 +100,9 @@ public class Files implements ChildCollection<RevisionResource, FileResource> {
|
|||||||
@Option(name = "--reviewed")
|
@Option(name = "--reviewed")
|
||||||
boolean reviewed;
|
boolean reviewed;
|
||||||
|
|
||||||
|
@Option(name = "-q")
|
||||||
|
String query;
|
||||||
|
|
||||||
private final Provider<ReviewDb> db;
|
private final Provider<ReviewDb> db;
|
||||||
private final Provider<CurrentUser> self;
|
private final Provider<CurrentUser> self;
|
||||||
private final FileInfoJson fileInfoJson;
|
private final FileInfoJson fileInfoJson;
|
||||||
@@ -125,11 +132,13 @@ public class Files implements ChildCollection<RevisionResource, FileResource> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Response<?> apply(RevisionResource resource) throws AuthException,
|
public Response<?> apply(RevisionResource resource) throws AuthException,
|
||||||
BadRequestException, ResourceNotFoundException, OrmException {
|
BadRequestException, ResourceNotFoundException, OrmException,
|
||||||
if (base != null && reviewed) {
|
RepositoryNotFoundException, IOException {
|
||||||
throw new BadRequestException("cannot combine base and reviewed");
|
checkOptions();
|
||||||
} else if (reviewed) {
|
if (reviewed) {
|
||||||
return Response.ok(reviewed(resource));
|
return Response.ok(reviewed(resource));
|
||||||
|
} else if (query != null) {
|
||||||
|
return Response.ok(query(resource));
|
||||||
}
|
}
|
||||||
|
|
||||||
PatchSet basePatchSet = null;
|
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)
|
private List<String> reviewed(RevisionResource resource)
|
||||||
throws AuthException, OrmException {
|
throws AuthException, OrmException {
|
||||||
CurrentUser user = self.get();
|
CurrentUser user = self.get();
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ import com.google.gwtorm.server.OrmException;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@@ -44,12 +46,14 @@ public class GetContent implements RestReadView<FileResource> {
|
|||||||
OrmException {
|
OrmException {
|
||||||
String path = rsrc.getPatchKey().get();
|
String path = rsrc.getPatchKey().get();
|
||||||
if (Patch.COMMIT_MSG.equals(path)) {
|
if (Patch.COMMIT_MSG.equals(path)) {
|
||||||
return BinaryResult.create(
|
String msg = changeUtil.getMessage(rsrc.getRevision().getChange());
|
||||||
changeUtil.getMessage(rsrc.getRevision().getChange())).base64();
|
return BinaryResult.create(msg)
|
||||||
|
.setContentType(FileContentUtil.TEXT_X_GERRIT_COMMIT_MESSAGE)
|
||||||
|
.base64();
|
||||||
}
|
}
|
||||||
return fileContentUtil.getContent(
|
return fileContentUtil.getContent(
|
||||||
rsrc.getRevision().getControl().getProject().getNameKey(),
|
rsrc.getRevision().getControl().getProjectControl().getProjectState(),
|
||||||
rsrc.getRevision().getPatchSet().getRevision().get(),
|
ObjectId.fromString(rsrc.getRevision().getPatchSet().getRevision().get()),
|
||||||
path);
|
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.common.collect.Maps;
|
||||||
import com.google.gerrit.common.data.PatchScript;
|
import com.google.gerrit.common.data.PatchScript;
|
||||||
import com.google.gerrit.common.data.PatchScript.DisplayMethod;
|
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.ChangeType;
|
||||||
import com.google.gerrit.extensions.common.DiffInfo;
|
import com.google.gerrit.extensions.common.DiffInfo;
|
||||||
import com.google.gerrit.extensions.common.DiffInfo.ContentEntry;
|
import com.google.gerrit.extensions.common.DiffInfo.ContentEntry;
|
||||||
@@ -194,7 +193,8 @@ public class GetDiff implements RestReadView<FileResource> {
|
|||||||
result.metaA = new FileMeta();
|
result.metaA = new FileMeta();
|
||||||
result.metaA.name = MoreObjects.firstNonNull(ps.getOldName(),
|
result.metaA.name = MoreObjects.firstNonNull(ps.getOldName(),
|
||||||
ps.getNewName());
|
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.lines = ps.getA().size();
|
||||||
result.metaA.webLinks =
|
result.metaA.webLinks =
|
||||||
getFileWebLinks(state.getProject(), revA, result.metaA.name);
|
getFileWebLinks(state.getProject(), revA, result.metaA.name);
|
||||||
@@ -203,7 +203,8 @@ public class GetDiff implements RestReadView<FileResource> {
|
|||||||
if (ps.getDisplayMethodB() != DisplayMethod.NONE) {
|
if (ps.getDisplayMethodB() != DisplayMethod.NONE) {
|
||||||
result.metaB = new FileMeta();
|
result.metaB = new FileMeta();
|
||||||
result.metaB.name = ps.getNewName();
|
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.lines = ps.getB().size();
|
||||||
result.metaB.webLinks =
|
result.metaB.webLinks =
|
||||||
getFileWebLinks(state.getProject(), revB, result.metaB.name);
|
getFileWebLinks(state.getProject(), revB, result.metaB.name);
|
||||||
@@ -250,34 +251,6 @@ public class GetDiff implements RestReadView<FileResource> {
|
|||||||
return links.isEmpty() ? null : links.toList();
|
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 {
|
private static class Content {
|
||||||
final List<ContentEntry> lines;
|
final List<ContentEntry> lines;
|
||||||
final SparseFileContent fileA;
|
final SparseFileContent fileA;
|
||||||
|
|||||||
@@ -103,7 +103,6 @@ public class Module extends RestApiModule {
|
|||||||
put(FILE_KIND, "reviewed").to(PutReviewed.class);
|
put(FILE_KIND, "reviewed").to(PutReviewed.class);
|
||||||
delete(FILE_KIND, "reviewed").to(DeleteReviewed.class);
|
delete(FILE_KIND, "reviewed").to(DeleteReviewed.class);
|
||||||
get(FILE_KIND, "content").to(GetContent.class);
|
get(FILE_KIND, "content").to(GetContent.class);
|
||||||
get(FILE_KIND, "type").to(GetContentType.class);
|
|
||||||
get(FILE_KIND, "diff").to(GetDiff.class);
|
get(FILE_KIND, "diff").to(GetDiff.class);
|
||||||
|
|
||||||
child(CHANGE_KIND, "edit").to(ChangeEdits.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);
|
put(CHANGE_EDIT_KIND, "/").to(ChangeEdits.Put.class);
|
||||||
delete(CHANGE_EDIT_KIND).to(ChangeEdits.DeleteContent.class);
|
delete(CHANGE_EDIT_KIND).to(ChangeEdits.DeleteContent.class);
|
||||||
get(CHANGE_EDIT_KIND, "/").to(ChangeEdits.Get.class);
|
get(CHANGE_EDIT_KIND, "/").to(ChangeEdits.Get.class);
|
||||||
get(CHANGE_EDIT_KIND, "type").to(ChangeEdits.GetType.class);
|
|
||||||
|
|
||||||
install(new FactoryModule() {
|
install(new FactoryModule() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -41,4 +41,8 @@ public class BranchResource extends ProjectResource {
|
|||||||
public String getRef() {
|
public String getRef() {
|
||||||
return branchInfo.ref;
|
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.RestResource;
|
||||||
import com.google.gerrit.extensions.restapi.RestView;
|
import com.google.gerrit.extensions.restapi.RestView;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
|
||||||
import com.google.inject.TypeLiteral;
|
import com.google.inject.TypeLiteral;
|
||||||
|
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
@@ -33,8 +32,8 @@ public class CommitResource implements RestResource {
|
|||||||
this.commit = commit;
|
this.commit = commit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Project.NameKey getProject() {
|
public ProjectControl getProject() {
|
||||||
return project.getNameKey();
|
return project.getControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
public RevCommit getCommit() {
|
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.RestResource;
|
||||||
import com.google.gerrit.extensions.restapi.RestView;
|
import com.google.gerrit.extensions.restapi.RestView;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
|
||||||
import com.google.inject.TypeLiteral;
|
import com.google.inject.TypeLiteral;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
|
||||||
public class FileResource implements RestResource {
|
public class FileResource implements RestResource {
|
||||||
public static final TypeLiteral<RestView<FileResource>> FILE_KIND =
|
public static final TypeLiteral<RestView<FileResource>> FILE_KIND =
|
||||||
new TypeLiteral<RestView<FileResource>>() {};
|
new TypeLiteral<RestView<FileResource>>() {};
|
||||||
|
|
||||||
private final Project.NameKey project;
|
private final ProjectControl project;
|
||||||
private final String rev;
|
private final ObjectId rev;
|
||||||
private final String path;
|
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.project = project;
|
||||||
this.rev = rev;
|
this.rev = rev;
|
||||||
this.path = path;
|
this.path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Project.NameKey getProject() {
|
public ProjectControl getProject() {
|
||||||
return project;
|
return project;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRev() {
|
public ObjectId getRev() {
|
||||||
return rev;
|
return rev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import com.google.gerrit.extensions.restapi.RestView;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class FilesCollection implements
|
public class FilesCollection implements
|
||||||
ChildCollection<BranchResource, FileResource> {
|
ChildCollection<BranchResource, FileResource> {
|
||||||
@@ -39,7 +41,10 @@ public class FilesCollection implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FileResource parse(BranchResource parent, IdString id) {
|
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
|
@Override
|
||||||
|
|||||||
@@ -40,8 +40,7 @@ public class FilesInCommitCollection implements
|
|||||||
@Override
|
@Override
|
||||||
public FileResource parse(CommitResource parent, IdString id)
|
public FileResource parse(CommitResource parent, IdString id)
|
||||||
throws ResourceNotFoundException {
|
throws ResourceNotFoundException {
|
||||||
return new FileResource(parent.getProject(), parent.getCommit().getName(),
|
return new FileResource(parent.getProject(), parent.getCommit(), id.get());
|
||||||
id.get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ public class GetContent implements RestReadView<FileResource> {
|
|||||||
@Override
|
@Override
|
||||||
public BinaryResult apply(FileResource rsrc)
|
public BinaryResult apply(FileResource rsrc)
|
||||||
throws ResourceNotFoundException, IOException {
|
throws ResourceNotFoundException, IOException {
|
||||||
return fileContentUtil.getContent(rsrc.getProject(), rsrc.getRev(),
|
return fileContentUtil.getContent(
|
||||||
|
rsrc.getProject().getProjectState(),
|
||||||
|
rsrc.getRev(),
|
||||||
rsrc.getPath());
|
rsrc.getPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user