Merge "Add and fix copyright headers"
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/Module.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/Module.java
index 65be419..d822faf 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/Module.java
@@ -31,6 +31,7 @@
import com.googlesource.gerrit.plugins.xdocs.formatter.Formatter;
import com.googlesource.gerrit.plugins.xdocs.formatter.MarkdownFormatter;
import com.googlesource.gerrit.plugins.xdocs.formatter.PlainTextFormatter;
+import com.googlesource.gerrit.plugins.xdocs.formatter.ZipFormatter;
import java.util.List;
@@ -57,6 +58,9 @@
bind(Formatter.class)
.annotatedWith(Exports.named(PlainTextFormatter.NAME))
.to(PlainTextFormatter.class);
+ bind(Formatter.class)
+ .annotatedWith(Exports.named(ZipFormatter.NAME))
+ .to(ZipFormatter.class);
DynamicSet.bind(binder(), ProjectWebLink.class)
.to(XDocWebLink.class);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java
index e84e1e4..1f86e69 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java
@@ -17,9 +17,12 @@
import com.googlesource.gerrit.plugins.xdocs.formatter.AsciidoctorFormatter;
import com.googlesource.gerrit.plugins.xdocs.formatter.MarkdownFormatter;
import com.googlesource.gerrit.plugins.xdocs.formatter.PlainTextFormatter;
+import com.googlesource.gerrit.plugins.xdocs.formatter.ZipFormatter;
import org.eclipse.jgit.lib.Config;
+import java.util.Arrays;
+
public class XDocGlobalConfig {
public static final String SECTION_FORMATTER = "formatter";
public static final String KEY_ALLOW_HTML = "allowHtml";
@@ -49,5 +52,7 @@
"text/x-markdown");
cfg.setString(SECTION_FORMATTER, PlainTextFormatter.NAME, KEY_MIME_TYPE,
"text/plain");
+ cfg.setStringList(SECTION_FORMATTER, ZipFormatter.NAME, KEY_EXT,
+ Arrays.asList("jar", "war", "zip"));
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocs.gwt.xml b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocs.gwt.xml
index 7855c78..405a81f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocs.gwt.xml
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocs.gwt.xml
@@ -18,6 +18,7 @@
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name="com.google.gwt.user.User"/>
<!-- Other module inherits -->
+ <inherits name="com.google.gerrit.GerritGwtUICommon"/>
<inherits name="com.google.gerrit.Plugin"/>
<inherits name="com.google.gwt.http.HTTP"/>
<inherits name="com.google.gwt.json.JSON"/>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/ChangeApi.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/ChangeApi.java
index 69ecf7d..44d1d49 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/ChangeApi.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/ChangeApi.java
@@ -31,6 +31,10 @@
return call(id, "detail");
}
+ public static RestApi revision(String changeId, int patchSetId) {
+ return change(changeId).view("revisions").id(patchSetId);
+ }
+
private static RestApi call(String id, String action) {
return change(id).view(action);
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/ChangeInfo.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/ChangeInfo.java
index caad355..9f28d99 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/ChangeInfo.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/ChangeInfo.java
@@ -20,6 +20,7 @@
public class ChangeInfo extends JavaScriptObject {
public final native String project() /*-{ return this.project; }-*/;
public final native NativeMap<RevisionInfo> revisions() /*-{ return this.revisions; }-*/;
+ public final native int _number() /*-{ return this._number; }-*/;
protected ChangeInfo() {
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/DiffApi.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/DiffApi.java
new file mode 100644
index 0000000..7bd9b7f
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/DiffApi.java
@@ -0,0 +1,31 @@
+// 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.googlesource.gerrit.plugins.xdocs.client;
+
+import com.google.gerrit.client.rpc.NativeMap;
+import com.google.gerrit.plugin.client.rpc.RestApi;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+public class DiffApi {
+
+ public static void list(String changeId, int patchSetId, Integer basePatchSetId,
+ AsyncCallback<NativeMap<FileInfo>> cb) {
+ RestApi api = ChangeApi.revision(changeId, patchSetId).view("files");
+ if (basePatchSetId != null) {
+ api.addParameter("base", basePatchSetId);
+ }
+ api.get(NativeMap.copyKeysIntoChildren("path", cb));
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/FileInfo.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/FileInfo.java
new file mode 100644
index 0000000..8fff48b
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/FileInfo.java
@@ -0,0 +1,53 @@
+// 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.googlesource.gerrit.plugins.xdocs.client;
+
+import com.google.gerrit.client.rpc.Natives;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArray;
+
+import java.util.Collections;
+import java.util.Comparator;
+
+public class FileInfo extends JavaScriptObject {
+ public final native String path() /*-{ return this.path; }-*/;
+ public final native boolean binary() /*-{ return this.binary || false; }-*/;
+
+ public static void sortFileInfoByPath(JsArray<FileInfo> list) {
+ Collections.sort(Natives.asList(list), new Comparator<FileInfo>() {
+ @Override
+ public int compare(FileInfo a, FileInfo b) {
+ if (Patch.COMMIT_MSG.equals(a.path())) {
+ return -1;
+ } else if (Patch.COMMIT_MSG.equals(b.path())) {
+ return 1;
+ }
+ return a.path().compareTo(b.path());
+ }
+ });
+ }
+
+ public static String getFileName(String path) {
+ String fileName = Patch.COMMIT_MSG.equals(path)
+ ? "Commit Message"
+ : path;
+ int s = fileName.lastIndexOf('/');
+ return s >= 0 ? fileName.substring(s + 1) : fileName;
+ }
+
+ protected FileInfo() {
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/VoidResult.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/VoidResult.java
new file mode 100644
index 0000000..d381cd6
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/VoidResult.java
@@ -0,0 +1,26 @@
+// 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.googlesource.gerrit.plugins.xdocs.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+
+public final class VoidResult extends JavaScriptObject {
+ protected VoidResult() {
+ }
+
+ public static VoidResult create() {
+ return createObject().cast();
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocApi.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocApi.java
new file mode 100644
index 0000000..e8de4ab
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocApi.java
@@ -0,0 +1,66 @@
+// 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.googlesource.gerrit.plugins.xdocs.client;
+
+import com.google.gerrit.plugin.client.Plugin;
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestBuilder;
+import com.google.gwt.http.client.RequestCallback;
+import com.google.gwt.http.client.RequestException;
+import com.google.gwt.http.client.Response;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+public class XDocApi {
+ public static String getUrl(String projectName, String revision,
+ String path) {
+ StringBuilder url = new StringBuilder();
+ url.append("plugins/");
+ url.append(Plugin.get().getName());
+ url.append("/project/");
+ url.append(URL.encodeQueryString(projectName));
+ if (revision != null && !"HEAD".equals(revision)) {
+ url.append("/rev/");
+ url.append(URL.encodeQueryString(revision));
+ }
+ url.append("/");
+ url.append(URL.encodeQueryString(path));
+ return url.toString();
+ }
+
+ public static void checkHtml(String url,
+ final AsyncCallback<VoidResult> callback) {
+ RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
+ try {
+ builder.sendRequest(null, new RequestCallback() {
+ public void onResponseReceived(Request request, Response response) {
+ int status = response.getStatusCode();
+ if (200 <= status && status < 300) {
+ callback.onSuccess(VoidResult.create());
+ } else {
+ callback.onFailure(new RequestException(status + " "
+ + response.getStatusText()));
+ }
+ }
+
+ public void onError(Request request, Throwable caught) {
+ callback.onFailure(caught);
+ }
+ });
+ } catch (RequestException e) {
+ callback.onFailure(e);
+ }
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocDiffScreen.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocDiffScreen.java
index eb05e5a..12606b6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocDiffScreen.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocDiffScreen.java
@@ -14,37 +14,50 @@
package com.googlesource.gerrit.plugins.xdocs.client;
+import com.google.gerrit.client.rpc.NativeMap;
import com.google.gerrit.client.rpc.Natives;
+import com.google.gerrit.plugin.client.Plugin;
+import com.google.gwt.core.client.JsArray;
+import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.InlineHyperlink;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
import com.googlesource.gerrit.plugins.xdocs.client.ChangeInfo.RevisionInfo;
public abstract class XDocDiffScreen extends VerticalPanel {
+ private final String changeId;
private final String path;
private String revisionA;
private String revisionB;
+ private int patchSet;
+ private Integer base;
+ private FlowPanel iconPanel;
- XDocDiffScreen(final String change, final String patchSet, String path) {
+ XDocDiffScreen(String changeId, final String patchSet, String path) {
setStyleName("xdocs-panel");
+ this.changeId = changeId;
this.path = path;
- ChangeApi.getChangeInfo(change, new AsyncCallback<ChangeInfo>() {
+ ChangeApi.getChangeInfo(changeId, new AsyncCallback<ChangeInfo>() {
@Override
public void onSuccess(ChangeInfo change) {
- addPathHeader(change);
setRevisions(change, patchSet);
+ addHeader(change);
display(change);
}
@Override
public void onFailure(Throwable caught) {
- showError("Unable to load change " + change + ": " + caught.getMessage());
+ showError("Unable to load change " + XDocDiffScreen.this.changeId
+ + ": " + caught.getMessage());
}
});
}
@@ -63,41 +76,163 @@
return revisionB;
}
- private void setRevisions(ChangeInfo change, String patchSet) {
- int i = patchSet.indexOf("..");
+ private void setRevisions(ChangeInfo change, String patchSetString) {
+ int i = patchSetString.indexOf("..");
if (i > 0) {
- revisionA = getRevision(change, patchSet.substring(0, i));
- if (patchSet.length() > i + 2) {
- revisionB = getRevision(change, patchSet.substring(i + 2));
+ base = parsePatchSet(patchSetString.substring(0, i));
+ revisionA = getRevision(change, base);
+ if (patchSetString.length() > i + 2) {
+ patchSet = parsePatchSet(patchSetString.substring(i + 2));
+ revisionB = getRevision(change, patchSet);
} else {
- throw new IllegalArgumentException("Invalid patch set: " + patchSet);
+ throw new IllegalArgumentException("Invalid patch set: " + patchSetString);
}
} else {
+ patchSet = parsePatchSet(patchSetString);
revisionB = getRevision(change, patchSet);
revisionA = this.revisionB + "^1";
}
}
- private static String getRevision(ChangeInfo change, String patchSet) {
+ private static String getRevision(ChangeInfo change, int patchSet) {
for (RevisionInfo rev : Natives.asList(change.revisions().values())) {
- try {
- if (rev._number() == Integer.valueOf(patchSet)) {
- return rev.ref();
- }
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException("Invalid patch set: " + patchSet);
+ if (rev._number() == patchSet) {
+ return rev.ref();
}
}
throw new IllegalArgumentException("Patch set " + patchSet + " not found.");
}
- private void addPathHeader(ChangeInfo change) {
+ private static int parsePatchSet(String patchSet) {
+ try {
+ return Integer.valueOf(patchSet);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid patch set: " + patchSet);
+ }
+ }
+
+ private void addHeader(ChangeInfo change) {
HorizontalPanel p = new HorizontalPanel();
p.setStyleName("xdocs-header");
+ p.add(getPathHeader(change));
+
+ iconPanel = new FlowPanel();
+ iconPanel.setStyleName("xdocs-icon-panel");
+ p.add(iconPanel);
+ addNavigationButtons(change);
+
+ add(p);
+ }
+
+ private Widget getPathHeader(ChangeInfo change) {
+ HorizontalPanel p = new HorizontalPanel();
+ p.setStyleName("xdocs-file-header");
p.add(new InlineHyperlink(change.project(), "/admin/projects/" + change.project()));
p.add(new Label("/"));
p.add(new Label(path));
- add(p);
+ return p;
+ }
+
+ private void addNavigationButtons(final ChangeInfo change) {
+ DiffApi.list(changeId, patchSet, base,
+ new AsyncCallback<NativeMap<FileInfo>>() {
+ @Override
+ public void onSuccess(NativeMap<FileInfo> result) {
+ JsArray<FileInfo> files = result.values();
+ FileInfo.sortFileInfoByPath(files);
+ int index = 0;
+ for (int i = 0; i < files.length(); i++) {
+ if (path.equals(files.get(i).path())) {
+ index = i;
+ break;
+ }
+ }
+
+ FileInfo prevInfo = index == 0 ? null : files.get(index - 1);
+ if (prevInfo != null) {
+ iconPanel.add(createNavLink(XDocsPlugin.RESOURCES.goPrev(),
+ change, patchSet, base, prevInfo));
+ }
+
+ iconPanel.add(createIcon(XDocsPlugin.RESOURCES.goUp(),
+ "Up to change", toChange(change)));
+
+ FileInfo nextInfo = index == files.length() - 1
+ ? null
+ : files.get(index + 1);
+ if (nextInfo != null) {
+ iconPanel.add(createNavLink(XDocsPlugin.RESOURCES.goNext(),
+ change, patchSet, base, nextInfo));
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ showError("Unable to load files of change " + changeId + ": "
+ + caught.getMessage());
+ }
+ });
+ }
+
+ private InlineHyperlink createNavLink(ImageResource res,
+ final ChangeInfo change, final int patchSet, final Integer base,
+ final FileInfo file) {
+ final InlineHyperlink link = createIcon(
+ res, FileInfo.getFileName(file.path()),
+ toFile(change, patchSet, base, file));
+ XDocApi.checkHtml(XDocApi.getUrl(change.project(),
+ getRevision(change, patchSet), file.path()),
+ new AsyncCallback<VoidResult>() {
+ @Override
+ public void onSuccess(VoidResult result) {
+ link.setTargetHistoryToken(
+ toPreview(change, patchSet, base, file));
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ }
+ });
+ return link;
+ }
+
+ private static InlineHyperlink createIcon(ImageResource res, String tooltip, String target) {
+ InlineHyperlink l = new InlineHyperlink(
+ AbstractImagePrototype.create(res).getHTML(), true, target);
+ if (tooltip != null) {
+ l.setTitle(tooltip);
+ }
+ return l;
+ }
+
+ private String toPreview(ChangeInfo change, int patchSet,
+ Integer base, FileInfo file) {
+ String panel = getPanel();
+ return "/x/" + Plugin.get().getName()
+ + toPatchSet(change, patchSet, base)
+ + file.path()
+ + (panel != null ? "," + panel : "");
+ }
+
+ private String toFile(ChangeInfo change, int patchSet, Integer base,
+ FileInfo file) {
+ String panel = file.binary() ? "unified" : getPanel();
+ return toPatchSet(change, patchSet, base)
+ + file.path()
+ + (panel != null ? "," + panel : "");
+ }
+
+ protected String getPanel() {
+ return null;
+ }
+
+ private static String toPatchSet(ChangeInfo change, int patchSet, Integer base) {
+ return toChange(change)
+ + (base != null ? patchSet + ".." + base : patchSet) + "/";
+ }
+
+ private static String toChange(ChangeInfo change) {
+ return "/c/" + change._number() + "/";
}
protected void showError(String message) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocScreen.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocScreen.java
index 9c3439e..f60e140 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocScreen.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocScreen.java
@@ -14,15 +14,9 @@
package com.googlesource.gerrit.plugins.xdocs.client;
-import com.google.gerrit.plugin.client.Plugin;
import com.google.gerrit.plugin.client.screen.Screen;
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gwt.http.client.Request;
-import com.google.gwt.http.client.RequestBuilder;
-import com.google.gwt.http.client.RequestCallback;
-import com.google.gwt.http.client.RequestException;
-import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Frame;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.InlineHyperlink;
@@ -38,7 +32,7 @@
String revision = URL.decode(screen.getToken(2));
String path = URL.decode(screen.getToken(3));
screen.show(new XDocScreen(projectName, revision, path));
- screen.setWindowTitle(getFileName(path));
+ screen.setWindowTitle(FileInfo.getFileName(path));
}
}
@@ -48,7 +42,7 @@
String projectName = URL.decode(screen.getToken(1));
String path = URL.decode(screen.getToken(2));
screen.show(new XDocScreen(projectName, "HEAD", path));
- screen.setWindowTitle(getFileName(path));
+ screen.setWindowTitle(FileInfo.getFileName(path));
}
}
@@ -56,37 +50,29 @@
setStyleName("xdocs-panel");
HorizontalPanel p = new HorizontalPanel();
- p.setStyleName("xdocs-header");
+ p.setStyleName("xdocs-file-header");
p.add(new InlineHyperlink(projectName, "/admin/projects/" + projectName));
p.add(new Label("/"));
p.add(new Label(path));
p.add(new Label("(" + revision + ")"));
add(p);
- final String url = getUrl(projectName, revision, path);
- RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
- try {
- builder.sendRequest(null, new RequestCallback() {
- public void onResponseReceived(Request request, Response response) {
- int status = response.getStatusCode();
- if (200 <= status && status < 300) {
- String frameId = "xdoc_iframe";
- Frame frame = new Frame(url);
- frame.getElement().setId(frameId);
- resize(frame, frameId);
- add(frame);
- } else {
- showError(status + " " + response.getStatusText());
- }
- }
+ final String url = XDocApi.getUrl(projectName, revision, path);
+ XDocApi.checkHtml(url, new AsyncCallback<VoidResult>() {
+ @Override
+ public void onSuccess(VoidResult result) {
+ String frameId = "xdoc_iframe";
+ Frame frame = new Frame(url);
+ frame.getElement().setId(frameId);
+ resize(frame, frameId);
+ add(frame);
+ }
- public void onError(Request request, Throwable exception) {
- showError(exception.getMessage());
- }
- });
- } catch (RequestException e) {
- showError(e.getMessage());
- }
+ @Override
+ public void onFailure(Throwable caught) {
+ showError(caught.getMessage());
+ }
+ });
}
private void showError(String message) {
@@ -95,29 +81,6 @@
add(l);
}
- public static String getFileName(String path) {
- String fileName = Patch.COMMIT_MSG.equals(path)
- ? "Commit Message"
- : path;
- int s = fileName.lastIndexOf('/');
- return s >= 0 ? fileName.substring(s + 1) : fileName;
- }
-
- public static String getUrl(String projectName, String revision, String fileName) {
- StringBuilder url = new StringBuilder();
- url.append("plugins/");
- url.append(Plugin.get().getName());
- url.append("/project/");
- url.append(URL.encodeQueryString(projectName));
- if (revision != null && !"HEAD".equals(revision)) {
- url.append("/rev/");
- url.append(URL.encodeQueryString(revision));
- }
- url.append("/");
- url.append(URL.encodeQueryString(fileName));
- return url.toString();
- }
-
public static void resize(Widget w, String id) {
StringBuilder autoResizeScript = new StringBuilder();
autoResizeScript.append("if (document.getElementById) {");
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocSideBySideDiffScreen.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocSideBySideDiffScreen.java
index f46344e..9209a36 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocSideBySideDiffScreen.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocSideBySideDiffScreen.java
@@ -27,7 +27,7 @@
String patchSet = URL.decode(screen.getToken(2));
String path = URL.decode(screen.getToken(4));
screen.show(new XDocSideBySideDiffScreen(change, patchSet, path));
- screen.setWindowTitle(XDocScreen.getFileName(path));
+ screen.setWindowTitle(FileInfo.getFileName(path));
}
}
@@ -39,13 +39,13 @@
protected void display(ChangeInfo change) {
String frameIdA = "xdoc_sidebyside_diff_a_iframe";
Frame frameA =
- new Frame(XDocScreen.getUrl(change.project(), getRevisionSideA(), getPath()));
+ new Frame(XDocApi.getUrl(change.project(), getRevisionSideA(), getPath()));
frameA.getElement().setId(frameIdA);
XDocScreen.resize(frameA, frameIdA);
String frameIdB = "xdoc_sidebyside_diff_b_iframe";
Frame frameB =
- new Frame(XDocScreen.getUrl(change.project(), getRevisionSideB(), getPath()));
+ new Frame(XDocApi.getUrl(change.project(), getRevisionSideB(), getPath()));
frameB.getElement().setId(frameIdB);
XDocScreen.resize(frameB, frameIdB);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocUnifiedDiffScreen.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocUnifiedDiffScreen.java
index 57d6dcb..551d76e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocUnifiedDiffScreen.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocUnifiedDiffScreen.java
@@ -26,7 +26,7 @@
String patchSet = URL.decode(screen.getToken(2));
String path = URL.decode(screen.getToken(4));
screen.show(new XDocUnifiedDiffScreen(change, patchSet, path));
- screen.setWindowTitle(XDocScreen.getFileName(path));
+ screen.setWindowTitle(FileInfo.getFileName(path));
}
}
@@ -38,7 +38,7 @@
protected void display(ChangeInfo change) {
String frameId = "xdoc_unified_diff_iframe";
Frame frame =
- new Frame(XDocScreen.getUrl(change.project(), getRevision(), getPath()));
+ new Frame(XDocApi.getUrl(change.project(), getRevision(), getPath()));
frame.getElement().setId(frameId);
XDocScreen.resize(frame, frameId);
add(frame);
@@ -47,4 +47,9 @@
private String getRevision() {
return getRevisionA() + "<->" + getRevisionB();
}
+
+ @Override
+ protected String getPanel() {
+ return "unified";
+ }
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocsPlugin.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocsPlugin.java
index 08507c0..71c2714 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocsPlugin.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocsPlugin.java
@@ -14,10 +14,13 @@
package com.googlesource.gerrit.plugins.xdocs.client;
+import com.google.gerrit.client.Resources;
import com.google.gerrit.plugin.client.Plugin;
import com.google.gerrit.plugin.client.PluginEntryPoint;
+import com.google.gwt.core.client.GWT;
public class XDocsPlugin extends PluginEntryPoint {
+ public static final Resources RESOURCES = GWT.create(Resources.class);
@Override
public void onPluginLoad() {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/AsciidoctorFormatter.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/AsciidoctorFormatter.java
index 42c0456..2f9ae4d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/AsciidoctorFormatter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/AsciidoctorFormatter.java
@@ -15,12 +15,9 @@
package com.googlesource.gerrit.plugins.xdocs.formatter;
import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_ALLOW_HTML;
-import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_CSS_THEME;
import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_INCLUDE_TOC;
-import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_INHERIT_CSS;
import static java.nio.charset.StandardCharsets.UTF_8;
-import com.google.common.base.MoreObjects;
import com.google.common.io.ByteStreams;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.extensions.annotations.PluginData;
@@ -35,17 +32,14 @@
import org.asciidoctor.Options;
import org.asciidoctor.OptionsBuilder;
import org.asciidoctor.SafeMode;
-import org.eclipse.jgit.util.TemporaryBuffer;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
-import java.net.URL;
import java.util.Properties;
@Singleton
@@ -57,7 +51,6 @@
private static final String ERUBY = "erb";
private final File baseDir;
- private final String defaultCss;
private final Properties attributes;
private final FormatterUtil util;
private final Formatters formatters;
@@ -66,7 +59,6 @@
public AsciidoctorFormatter(@PluginData File baseDir,
FormatterUtil formatterUtil, Formatters formatters) throws IOException {
this.baseDir = baseDir;
- this.defaultCss = readCss();
this.attributes = readAttributes();
this.util = formatterUtil;
this.formatters = formatters;
@@ -92,18 +84,7 @@
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteStreams.copy(input, out);
String html = out.toString(UTF_8.name());
- String cssTheme = projectCfg.getString(KEY_CSS_THEME);
- String inheritedCss =
- util.getInheritedCss(projectName, NAME, "asciidoctor", cssTheme);
- String projectCss = util.getCss(projectName, "asciidoctor", cssTheme);
- if (projectCfg.getBoolean(KEY_INHERIT_CSS, true)) {
- return util.insertCss(html,
- MoreObjects.firstNonNull(inheritedCss, defaultCss), projectCss);
- } else {
- return util.insertCss(html,
- MoreObjects.firstNonNull(projectCss,
- MoreObjects.firstNonNull(inheritedCss, defaultCss)));
- }
+ return util.applyCss(html, NAME, projectName);
}
} finally {
if (!tmpFile.delete()) {
@@ -154,19 +135,6 @@
return ab.get();
}
- private static String readCss() throws IOException {
- String name = "asciidoctor.css";
- URL url = AsciidoctorFormatter.class.getResource(name);
- if (url == null) {
- throw new FileNotFoundException("Resource " + name);
- }
- try (InputStream in = url.openStream();
- TemporaryBuffer.Heap tmp = new TemporaryBuffer.Heap(128 * 1024)) {
- tmp.copy(in);
- return new String(tmp.toByteArray(), UTF_8);
- }
- }
-
private static Properties readAttributes() throws IOException {
Properties attributes = new Properties();
try (InputStream in = AsciidoctorFormatter.class
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/FormatterUtil.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/FormatterUtil.java
index 2c49704..5d62a7e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/FormatterUtil.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/FormatterUtil.java
@@ -14,11 +14,13 @@
package com.googlesource.gerrit.plugins.xdocs.formatter;
+import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_CSS_THEME;
import static com.googlesource.gerrit.plugins.xdocs.XDocGlobalConfig.KEY_INHERIT_CSS;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.commons.lang.StringEscapeUtils.escapeHtml;
import com.google.common.base.Joiner;
+import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.gerrit.extensions.annotations.PluginData;
import com.google.gerrit.extensions.annotations.PluginName;
@@ -40,20 +42,31 @@
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
+import org.eclipse.jgit.util.TemporaryBuffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
@Singleton
public class FormatterUtil {
+ private static final Logger log = LoggerFactory.getLogger(FormatterUtil.class);
+
private final String pluginName;
private final File baseDir;
private final GitRepositoryManager repoManager;
private final ProjectCache projectCache;
private final Formatters formatters;
+ private final Map<String, String> defaultCss;
@Inject
FormatterUtil(@PluginName String pluginName,
@@ -66,6 +79,7 @@
this.repoManager = repoManager;
this.projectCache = projectCache;
this.formatters = formatters;
+ this.defaultCss = new HashMap<>();
}
/**
@@ -191,6 +205,47 @@
return null;
}
+ public String applyCss(String html, String formatterName, String projectName)
+ throws IOException {
+ ConfigSection projectCfg =
+ formatters.getFormatterConfig(formatterName, projectName);
+ String cssName = formatterName.toLowerCase(Locale.US);
+ String cssTheme = projectCfg.getString(KEY_CSS_THEME);
+ String defaultCss = getDefaultCss(formatterName);
+ String inheritedCss =
+ getInheritedCss(projectName, formatterName, cssName, cssTheme);
+ String projectCss = getCss(projectName, cssName, cssTheme);
+ if (projectCfg.getBoolean(KEY_INHERIT_CSS, true)) {
+ return insertCss(html,
+ MoreObjects.firstNonNull(inheritedCss, defaultCss), projectCss);
+ } else {
+ return insertCss(html,
+ MoreObjects.firstNonNull(projectCss,
+ MoreObjects.firstNonNull(inheritedCss, defaultCss)));
+ }
+ }
+
+ private String getDefaultCss(String formatterName) throws IOException {
+ String css = defaultCss.get(formatterName) ;
+ if (css == null) {
+ URL url = FormatterUtil.class.getResource(
+ formatterName.toLowerCase(Locale.US) + ".css");
+ if (url != null) {
+ try (InputStream in = url.openStream();
+ TemporaryBuffer.Heap tmp = new TemporaryBuffer.Heap(128 * 1024)) {
+ tmp.copy(in);
+ css = new String(tmp.toByteArray(), UTF_8);
+ }
+ } else {
+ log.info(String.format("No default CSS for formatter '%s' found.",
+ formatterName));
+ css = "";
+ }
+ defaultCss.put(formatterName, css);
+ }
+ return css;
+ }
+
/**
* Inserts the given CSS into the given HTML.
*
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/HtmlBuilder.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/HtmlBuilder.java
new file mode 100644
index 0000000..c971df5
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/HtmlBuilder.java
@@ -0,0 +1,121 @@
+// 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.googlesource.gerrit.plugins.xdocs.formatter;
+
+import static org.apache.commons.lang.StringEscapeUtils.escapeHtml;
+
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.inject.Inject;
+
+import org.eclipse.jgit.lib.PersonIdent;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+public class HtmlBuilder {
+ private final DateFormat rfc2822DateFormatter;
+ private final StringBuilder html = new StringBuilder();
+
+ @Inject
+ HtmlBuilder(@GerritPersonIdent PersonIdent gerritIdent) {
+ rfc2822DateFormatter =
+ new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
+ rfc2822DateFormatter.setCalendar(Calendar.getInstance(
+ gerritIdent.getTimeZone(), Locale.US));
+ }
+
+ public HtmlBuilder startDocument() {
+ return open("html");
+ }
+
+ public HtmlBuilder endDocument() {
+ return close("html");
+ }
+
+ public HtmlBuilder openBody() {
+ return open("body");
+ }
+
+ public HtmlBuilder closeBody() {
+ return close("body");
+ }
+
+ public HtmlBuilder openHead() {
+ return open("head");
+ }
+
+ public HtmlBuilder closeHead() {
+ return close("head");
+ }
+
+ public HtmlBuilder openTable() {
+ return open("table");
+ }
+
+ public HtmlBuilder closeTable() {
+ return close("table");
+ }
+
+ public HtmlBuilder openRow() {
+ return open("tr");
+ }
+
+ public HtmlBuilder closeRow() {
+ return close("tr");
+ }
+
+ public HtmlBuilder appendCellHeader(String s) {
+ return open("th").append(s).close("th");
+ }
+
+ public HtmlBuilder appendCell(String s) {
+ return open("td").append(s).close("td");
+ }
+
+ public HtmlBuilder appendCell() {
+ return appendCell("");
+ }
+
+ public HtmlBuilder appendDateCell(long date) {
+ return open("td").appendDate(date).close("td");
+ }
+
+ public HtmlBuilder open(String tag) {
+ html.append("<").append(tag).append(">");
+ return this;
+ }
+
+ public HtmlBuilder close(String tag) {
+ html.append("</").append(tag).append(">");
+ return this;
+ }
+
+ public HtmlBuilder append(String s) {
+ html.append(escapeHtml(s));
+ return this;
+ }
+
+ public HtmlBuilder appendDate(long date) {
+ html.append(rfc2822DateFormatter.format(new Date(date)));
+ return this;
+ }
+
+ public String toString() {
+ return html.toString();
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/ZipFormatter.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/ZipFormatter.java
new file mode 100644
index 0000000..fcb9bd8
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/ZipFormatter.java
@@ -0,0 +1,77 @@
+// 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.googlesource.gerrit.plugins.xdocs.formatter;
+
+import com.google.inject.Inject;
+
+import com.googlesource.gerrit.plugins.xdocs.ConfigSection;
+
+import org.apache.commons.io.FileUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+public class ZipFormatter implements StreamFormatter {
+ public static final String NAME = "ZIP";
+
+ private final FormatterUtil util;
+ private final HtmlBuilder html;
+
+ @Inject
+ ZipFormatter(
+ Formatters formatters,
+ FormatterUtil formatterUtil,
+ HtmlBuilder html) {
+ this.util = formatterUtil;
+ this.html = html;
+ }
+
+ @Override
+ public String format(String projectName, String revision, ConfigSection globalCfg,
+ InputStream raw) throws IOException {
+ html.startDocument()
+ .openHead()
+ .closeHead()
+ .openBody()
+ .openTable()
+ .appendCellHeader("name")
+ .appendCellHeader("size")
+ .appendCellHeader("last modified");
+ try (ZipInputStream zip = new ZipInputStream(raw)) {
+ for (ZipEntry entry; (entry = zip.getNextEntry()) != null;) {
+ html.openRow()
+ .appendCell(entry.getName());
+ if (!entry.isDirectory()) {
+ if (entry.getSize() != -1) {
+ html.appendCell(FileUtils.byteCountToDisplaySize(entry.getSize()));
+ } else {
+ html.appendCell("n/a");
+ }
+ } else {
+ html.appendCell();
+ }
+ html.appendDateCell(entry.getTime())
+ .closeRow();
+ }
+ }
+ html.closeTable()
+ .closeBody()
+ .endDocument();
+
+ return util.applyCss(html.toString(), NAME, projectName);
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/public/xdocs.css b/src/main/java/com/googlesource/gerrit/plugins/xdocs/public/xdocs.css
index 8a83068..e7364b9 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/public/xdocs.css
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/public/xdocs.css
@@ -18,10 +18,21 @@
width: 100%;
}
-.xdocs-header td {
+.xdocs-file-header td {
padding-right: 5px;
}
+.xdocs-icon-panel {
+ position: absolute;
+ right: 10px;
+ height: 16px;
+ line-height: 16px;
+}
+
+.xdocs-icon-panel img {
+ padding-right: 3px;
+}
+
.xdocs-panel iframe {
width: 100%;
border-width: 1px;
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
index f7b2632..7477b6e 100644
--- a/src/main/resources/Documentation/about.md
+++ b/src/main/resources/Documentation/about.md
@@ -82,6 +82,13 @@
<td><a href="../../../Documentation/licenses.html#Apache2_0">Apache2.0</a></td>
<td><a href="http://commons.apache.org">http://commons.apache.org</a></td>
</tr>
+ <tr>
+ <td><tt>ZipFormatter</tt></td>
+ <td><tt>ZIP</tt></td>
+ <td>Formatter for zip files.</td>
+ <td></td>
+ <td></td>
+ </tr>
</table>
<a id="htmlDiff">
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 26d773e..2b12b55 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -96,7 +96,7 @@
Overrides the [global configuration of `inheritCss`](#formatterInheritCss)
for this formatter.
- Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`
+ Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`, `ZIP`
Default: `true` (CSS is inherited)
@@ -111,7 +111,7 @@
Overrides the [global configuration of `cssTheme`](#formatterCssTheme)
for this formatter.
- Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`
+ Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`, `ZIP`
By default not set.
@@ -137,6 +137,7 @@
* `ASCIIDOCTOR`: `@PLUGIN@/asciidoctor.css`
* `MARKDOWN`: `@PLUGIN@/markdown.css`
+* `ZIP`: `@PLUGIN@/zip.css`
If link:inheritCss[inheritCss] is set to true custom CSS files are
inherited from parent projects.
@@ -158,6 +159,10 @@
mimeType = text/x-markdown
[formatter "PLAIN_TEXT"]
mimeType = text/plain
+ [formatter "ZIP"]
+ ext = jar
+ ext = war
+ ext = zip
```
Supported formatters:
@@ -165,6 +170,7 @@
* `ASCIIDOCTOR`
* `MARKDOWN`
* `PLAIN_TEXT`
+* `ZIP`
<a id="formatterExt">
formatter.<formatter>.ext
@@ -243,7 +249,7 @@
Can be overridden on [project-level](#inheritCss).
- Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`
+ Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`, `ZIP`
Default: `true` (CSS is inherited)
@@ -256,7 +262,7 @@
Can be overridden on [project-level](#cssTheme).
- Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`
+ Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`, `ZIP`
By default not set.
@@ -295,3 +301,4 @@
* `ASCIIDOCTOR`: `asciidoctor.css`
* `MARKDOWN`: `markdown.css`
+* `ZIP`: `zip.css`