Dissolve top level gitiles-* directories
The current layout of having gitiles-* directories with separate java
source trees dates back to the bad era of Maven, when this specific
layout was necessary to decompose the build into separate pom.xml files.
Moreover, src/{main,test}/java are also Maven artifacts, so that we go
even further and create three top level directories:
* java
* javatests
* resources
Change-Id: I4421096428db1e3de019a9b6c1253217cf7e4fbe
diff --git a/resources/BUILD b/resources/BUILD
new file mode 100644
index 0000000..020f145
--- /dev/null
+++ b/resources/BUILD
@@ -0,0 +1,5 @@
+filegroup(
+ name = "web_xml",
+ srcs = ["web.xml"],
+ visibility = ["//visibility:public"],
+)
diff --git a/resources/com/google/gitiles/BUILD b/resources/com/google/gitiles/BUILD
new file mode 100644
index 0000000..c5df3e1
--- /dev/null
+++ b/resources/com/google/gitiles/BUILD
@@ -0,0 +1,27 @@
+load(
+ "@com_googlesource_gerrit_bazlets//tools:genrule2.bzl",
+ "genrule2",
+)
+
+filegroup(
+ name = "gitiles",
+ srcs = glob(
+ ["**/*"],
+ exclude = ["BUILD"],
+ ),
+ visibility = ["//visibility:public"],
+)
+
+genrule2(
+ name = "webassets",
+ srcs = [":gitiles"],
+ outs = ["webassets.zip"],
+ cmd = " && ".join([
+ "o=$$PWD/$@",
+ "tar cf - $(SRCS) | tar -C $$TMP/ --strip-components=1 -xf -",
+ "cd $$TMP/com/google/gitiles/",
+ "mv static +static",
+ "zip -qr $$o .",
+ ]),
+ visibility = ["//visibility:public"],
+)
diff --git a/resources/com/google/gitiles/mime-types.properties b/resources/com/google/gitiles/mime-types.properties
new file mode 100644
index 0000000..0b4bd26
--- /dev/null
+++ b/resources/com/google/gitiles/mime-types.properties
@@ -0,0 +1,16 @@
+bmp = image/bmp
+css = text/css
+csv = text/csv
+gif = image/gif
+htm = text/html
+html = text/html
+jpeg = image/jpeg
+jpg = image/jpeg
+js = application/javascript
+md = text/markdown
+pdf = application/pdf
+png = image/png
+svg = image/svg+xml
+tiff = image/tiff
+txt = text/plain
+xml = text/xml
diff --git a/resources/com/google/gitiles/static/base.css b/resources/com/google/gitiles/static/base.css
new file mode 100644
index 0000000..2a56084
--- /dev/null
+++ b/resources/com/google/gitiles/static/base.css
@@ -0,0 +1,517 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+/* Common styles and definitions. */
+
+@import "//fonts.googleapis.com/css?family=Open+Sans:300,400,700&subset=latin,cyrillic-ext,greek-ext,cyrillic,greek,vietnamese,latin-ext";
+@import "//fonts.googleapis.com/css?family=Source+Code+Pro";
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+}
+h1, h2, h3, h4, h5, h6 {
+ font-weight: normal;
+ margin: .25em 0 .5em;
+}
+h1 {
+ font-size: 2em;
+}
+h2 {
+ font-size: 1.5em;
+}
+h3 {
+ font-size: 1.3em;
+}
+h4, h5, h6 {
+ font-size: 14px;
+ font-style: italic;
+}
+ul, ol {
+ list-style: none;
+}
+
+/* Utility classes */
+
+.u-sha1 {
+ background-color: #f1f2f3;
+ color: #000;
+ font-size: 13px;
+}
+.u-pre {
+ font-size: 10pt;
+ font-weight: 500;
+ white-space: pre;
+}
+.u-lineNum {
+ border-right: 1px solid #f1f2f3;
+ color: #666;
+ display: inline-block;
+ min-width: 3em;
+ text-align: right;
+}
+.u-noSelect {
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.u-monospace {
+ font-family: 'Source Code Pro', monospace;
+}
+
+/* Common.soy */
+
+.Site {
+ background: #fff;
+ color: #000;
+ display: -ms-flexbox;
+ display: flex;
+ font: 14px/1.54 'Open Sans', sans-serif;
+ min-height: 100vh;
+ -ms-flex-direction: column;
+ flex-direction: column;
+}
+.Site-header,
+.Site-footer {
+ background: #eee;
+ -ms-flex: none;
+ flex: none;
+}
+.Site-header--withNavbar {
+ background: #fff;
+}
+.Site-content {
+ -ms-flex: 1 0 auto;
+ flex: 1 0 auto;
+ padding: 20px;
+}
+.Container {
+ margin: 0 auto;
+ max-width: 980px;
+}
+.Container--fullWidth {
+ max-width: none;
+}
+.Header,
+.Footer {
+ -ms-flex-align: center;
+ align-items: center;
+ display: -ms-flexbox;
+ display: flex;
+ padding: 20px;
+}
+.Site-header--withNavbar .Header {
+ max-width: 980px;
+ margin: 0 auto;
+ padding: 10px 0;
+}
+.Header-title,
+.Header-image {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex: 1;
+ flex: 1;
+}
+.Header-anchor {
+ color: #666;
+ font-size: 32px;
+ font-weight: 300;
+ text-decoration: none;
+}
+.Header-anchorLogo {
+ display: inline-block;
+ margin-right: 10px;
+ vertical-align: middle;
+}
+.Header-nav {
+ background: #eee;
+ padding: 15px 0;
+}
+.Header-menu {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-pack: end;
+ justify-content: flex-end;
+}
+.Header-menuItem {
+ color: #00e;
+ display: inline-block;
+ margin-left: 15px;
+}
+.Header-menuItem--noAction {
+ color: inherit;
+}
+.Breadcrumbs {
+ font-size: 18px;
+ margin-bottom: 20px;
+}
+.Breadcrumbs-crumb {
+ color: #00e;
+}
+.Breadcrumbs-crumb:last-child {
+ color: #000;
+ font-weight: bold;
+}
+.Footer {
+ color: #666;
+}
+.Footer-poweredBy {
+ -ms-flex: 1;
+ flex: 1;
+}
+.Footer-formats,
+.Footer-links {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-pack: end;
+ justify-content: flex-end;
+}
+.Footer-formatsItem {
+ display: inline-block;
+}
+.Footer-formatsItem:first-child {
+ margin-right: 20px;
+}
+.Footer-link {
+ display: inline-block;
+ margin-left: 10px;
+}
+.RepoList-item {
+ display: -ms-flexbox;
+ display: flex;
+ left: -10px;
+ padding: 5px 0 5px 10px;
+ position: relative;
+ white-space: nowrap;
+ width: calc(100% + 20px);
+}
+.RepoList-item:link,
+.RepoList-item:visited {
+ text-decoration: none;
+}
+.RepoList-item:hover {
+ background: #eee;
+}
+.RepoList-item--header {
+ font-weight: bold;
+ margin: 0;
+}
+.RepoList-item--header:hover {
+ background: #fff;
+}
+.RepoList-itemName,
+.RepoList-itemDescription {
+ display: inline-block;
+}
+.RepoList-itemName {
+ margin-right: 10px;
+ min-width: 25%;
+ text-decoration: underline;
+}
+.RepoList-item--header > .RepoList-itemName {
+ text-decoration: none;
+}
+.RepoList-itemDescription {
+ color: #000;
+ -ms-flex: 1;
+ flex: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+/* RepositoryIndex.soy */
+
+.RepoDescription {
+ margin: 10px 0;
+}
+.RepoMirroredFrom {
+ margin: 10px 0;
+ color: #666;
+}
+.CloneRepo {
+ background: #eee;
+ margin-bottom: 20px;
+ padding: 10px;
+}
+.CloneRepo-title {
+ margin-bottom: 2px;
+}
+.CloneRepo-command {
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ display: block;
+ font-size: inherit;
+ padding: 10px;
+ width: 100%;
+}
+.RepoShortlog {
+ display: -ms-flexbox;
+ display: flex;
+}
+.RepoShortlog-refs {
+ -ms-flex: none !important;
+ flex: none !important;
+ width: 20%;
+}
+.RepoShortlog-refs > .RefList:first-child {
+ margin: 0;
+}
+.RepoShortlog-log {
+ -ms-flex: 1;
+ flex: 1;
+ width: 80%;
+}
+.RepoIndexDoc {
+ border-top: 1px solid #ddd;
+ margin-top: 20px;
+ padding-top: 5px;
+}
+
+/* RefList.soy */
+
+.Refs {}
+.RefList {
+ margin: 15px 0;
+}
+.RefList-title {
+ margin: 0;
+}
+.RefList-items {}
+.RefList-item {
+ padding: 2px 0;
+}
+
+/* LogDetail.soy */
+
+.LogNav {
+ margin: 10px 0;
+ text-align: center;
+}
+.CommitLog {}
+.CommitLog-item {
+ padding: 2px 0;
+}
+.CommitLog-item--oneline:hover {
+ background: #eee;
+}
+.CommitLog-item--full {
+ margin-bottom: 20px;
+}
+.CommitLog-item--empty {
+ padding: 10px 0;
+ text-align: center;
+}
+.CommitLog-sha1 {
+ border-radius: 3px;
+ display: inline-block;
+ margin-right: 3px;
+ padding: 2px 4px;
+ text-align: center;
+}
+.CommitLog-time {
+ color: #666;
+}
+.CommitLog-branchLabel {
+ color: #dd4b39;
+}
+.CommitLog-tagLabel {
+ color: #093;
+}
+.CommitLog-rename {
+ font-size: 0.9em;
+ display: block;
+ padding-left: 5px;
+}
+
+/* ObjectDetail.soy */
+
+.Metadata {
+ margin-bottom: 15px;
+}
+.Metadata-title {
+ font-weight: bold;
+ padding-right: 10px;
+ text-align: right;
+}
+.MetadataMessage {
+ background-color: #fafafa;
+ border: 1px solid #ccc;
+ color: #000;
+ margin: 0;
+ padding: 12px;
+ white-space: pre-wrap;
+}
+.DiffTree {
+ margin: 10px 0 5px;
+}
+.DiffTree-action {
+ margin-left: .5em;
+}
+.DiffTree-action--add {
+ color: #060;
+}
+.DiffTree-action--delete {
+ color: #600;
+}
+.DiffTree-action--rename,
+.DiffTree-action--copy {
+ color: #006;
+}
+.DiffSummary {}
+.TreeDetail-sha1,
+.BlobSha1 {
+ margin: 10px 0;
+ padding: 5px 10px;
+}
+.FileList {
+ margin-left: 25px;
+}
+.FileList-item {
+ padding: 1px 0;
+ position: relative;
+}
+.FileList-item:hover {
+ background: #eee;
+}
+.FileList-item::before {
+ left: -22px;
+ position: absolute;
+ top: 4px;
+}
+.FileList-itemLink {
+ display: block;
+}
+/* Tree icons are taken from the public domain Tango icons:
+ * http://tango.freedesktop.org/Tango_Icon_Library
+ * Compressed with pngcrush -brute -rem tEXt -rem tIME -rem iTXt -rem zTXt */
+.FileList-item--gitTree::before {
+ /* places/folder.png */
+ content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAb5JREFUOMulkr1KA0EQgGdvTwwnYmER0gQsrFKmSy+pLESw9Qm0F/ICNnba+h6iEOuAEWslKJKTOyJJvIT72d1xZuOFC0giOLA77O7Mt/PnNptN+I+49Xr9GhH3f3mb0v1ht9vtLAUYYw5ItkgDL3KyD8PhcLvdbl/WarXT3DjLMnAcR/f7/YfxeKwtgC5RKQVhGILWeg4hQ6hUKjWyucmhLFEUuWR3QYBWAZABQ9i5CCmXy16pVALP80BKaaG+70MQBLvzFMjRKKXh8j6FSYKF7ITdEWLa4/ktokN74wiqjSMpnVcbQZqmEJHz+ckeCPFjWKwULpyspAqhdXVXdcnZcPjsIgn+2BsVA8jVYuWlgJ3yBj0icgq2uoK+lg4t+ZvLomSKamSQ4AI5BcMADtMhyNoSgNIISUaFNtwlazcDcBc4gjjVwCWid2usCWroYEhnaqbzFJLUzAHIXRDChXCcQP8zhkSZ5eNLgHAUzwDcRu4CoIRn/wsGUQIIy4Vr9TH6SYFCNzw4nALn5627K4vIttOUOwfa5YnrDYzt/9OLv9I5l8kk5hZ3XLO20b7tbR7zHLy/BX8G0IeBEM7ZN1NGIaFUaKLgAAAAAElFTkSuQmCC);
+}
+.FileList-item--symlink::before {
+ /* actions/edit-redo.png */
+ content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAABZUlEQVQ4y2NgIAL4zWL7D8TGDOQCqAEg7Ey2Aes+58AMcSSkmB2I3YB4HhCfh9kOMoCgIUAJMyDe2D+b58jKe553133M+r/uU/b/zV+L/y97n/i/+JIYbkOAAl5AfGLNTde/69+n/1/4MuD/gtsqKBhkALIh5S0M1jDN2kC8a+UNt/8b36f+X3JP5f/0u1pwjeuvS8E1g3DpZQm4ITAD5s09ZPBq49uE/0vvq4E1gPCJC5z/yy+IoGgG4a5HJqjeCJ3Pc2vjy+T/ux4Y/j99Rfz/7GtK/xfeUkbBN+8pY9cMAkFzuT5uepPy/+w1lf+TF3L/Q4p3OD5zRQ67Zlg873vk9n/mMlaQ5EcgLgZiA2R5nJphCjbfNP8LVeCBJyUa40xpO+5afQXS/8jKC0DJg+uPKx+bOJf1HDYXEJPW46JW8LcduKYzbdZMph4gn4ccQxSAOAuIo4FYdvsKFpYdK1iYCekDACq5JXDHGJhDAAAAAElFTkSuQmCC);
+}
+.FileList-item--regularFile::before {
+ /* mimetypes/text-x-generic.png */
+ content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAtElEQVQ4ja2TSw7CIBRFu0r3wyIYsAMHDl1CC92IDqC0wAbQi4Fo5VOMJGcAyT33vQEDY+xCCPGdnIZ48NB7kPkSLMvipZQBpVQC70Br7Y0xZQGC4zj6aZoCnPMPhBBtwb41NoN1XesCBHPNhyfI7fziFu6HJti3IgS0vrcFuZ3Btm2JpmC/M5jnOdEU5JoRstYmigKES80x7JyrC+IE7+1xAoSrgp//AqX02vsbn5nz8K/zAP9CzjbgFoHjAAAAAElFTkSuQmCC);
+}
+.FileList-item--executableFile::before {
+ /* mimetypes/text-x-script.png */
+ content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA7ADsAOwdIxY2AAAACXBIWXMAAAsTAAALEwEAmpwYAAABOklEQVQ4T5WTTYqDQBBGPdKcZnIJdy7EVRByBQPi0iwHAlGT0YBHcG82kkV2VnffoKar7FYzIQYLPtqffq+rEJ04jn/CMMSV+XZs0YO1RcyLoO/7MdAD9gAI8wiK+CyYA0IDFABhrmFBAHNYbwYTIxFyWN8KwAiEmIEaknqVUposCoBBGE8cIGUipUKp5IJAzOe2JxI0pG1b3Gw2+Hg8FjoQzy0rLVAavt0GuGkaXrfb7avAzs0CNcHtDD4ejwzTve/7X/9GGFqn2QmkDmzbBJ9OJ8yyDNM0Rdd1J8mzgDqQPDNJLFwUBZ7PZ7xcLizwPI9gfj+NYAX2k+kx7vc7byrLEquqwuv1ivv9HpMk4ec6Uwfvqus63lzXNeZ5zoIRpoqiKP/09wVBwNDhcOB1t9v9OmuLTnw62dQfVIHPYx/I/0kAAAAASUVORK5CYII=);
+}
+.FileList-item--gitlink::before {
+ /* emblems/emblem-symbolic-link.png */
+ content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAABO0lEQVQ4T7WT3U6EMBCF92m99yGMZuODGL01eueyXqjvwc+WUlooUPkfZxq3sQEvJLHJSQvlfDOnDbub/dUFCrZof3t9uaPF1kFeBwjD8E+apukfAVEUQRzHkCQJJKfEznES43tUGP0OIOMheIGn50e4f7izCo4H4GkKDEXPBIviCIZh8AFkfv94g5Qx4Jw7AOn4Grh1iqATdrUAEJmxFLIsgzzPQSnpQc4SIkMIh7ZtfQCjys6soNQlVFW1AEgpQWQCjDE+gHIKIaxZo7mu69UOiqJwRXxAxnFDQllS5XUzSeO+kmoJoOzUni41NE1tM9JBTdMII85d14FpjI2lihUA9wCNA8zzDOM4WkBjvgFqrQO8ulzmNgLl/8SPyTT0WL3vLLBGsNZ6HUBV1tT3vROd/Fk/AZt/Z/J+AUN8ayghXmezAAAAAElFTkSuQmCC);
+}
+.FileContents {
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px 0;
+}
+.FileContents-line {
+ border: none;
+}
+.FileContents-lineNum {
+ padding-right: 10px;
+ width: 1%;
+}
+/* Used to prevent copying the line number. */
+.FileContents-lineNum::before {
+ color: #aaa;
+ content: attr(data-line-number);
+ cursor: pointer;
+}
+.FileContents-lineContents {
+ line-height: 1.3em;
+ min-height: 1em;
+ padding-left: 10px;
+}
+.FileContents-lineContents:target {
+ background: #cfd8dc;
+}
+.InlineReadme {
+ border-top: 1px solid #ddd;
+ margin: 10px 0;
+ padding: 7px 0;
+}
+.InlineReadme-path {
+ color: #666;
+}
+
+/* BlameDetail.soy */
+
+.Blame {
+ border-collapse: collapse;
+ font-size: 8pt;
+ margin: 0 auto;
+}
+.Blame-region--bg1 {
+ background: #fff;
+}
+.Blame-region--bg2 {
+ background: #f1f2f3;
+}
+.Blame-sha1,
+.Blame-author,
+.Blame-time,
+.Blame-regionLink {
+ font-size: 8pt;
+ padding: 0 3px;
+ white-space: nowrap;
+}
+.Blame-regionLink {
+ text-align: right;
+}
+.Blame-lineNum .u-lineNum {
+ padding: 0 8px;
+ text-align: right;
+}
+.Blame-lineNum:hover {
+ text-decoration: underline;
+}
+.Blame-lineContent {
+ font-size: 9pt;
+ line-height: 1.3em;
+ padding: 0 8px;
+}
+
+/* DiffDetail.soy */
+
+.Diff {
+ margin: 10px 0;
+}
+.Diff-fileIndex {
+ color: #444;
+ font-weight: bold;
+}
+.Diff-unified {
+ border-bottom: 1px solid #ddd;
+ border-top: 1px solid #ddd;
+ padding: 10px 0;
+}
+.Diff-hunk {
+ color: #00c;
+}
+.Diff-delete {
+ color: #c00;
+}
+.Diff-insert {
+ color: #080;
+}
diff --git a/resources/com/google/gitiles/static/doc.css b/resources/com/google/gitiles/static/doc.css
new file mode 100644
index 0000000..a531087
--- /dev/null
+++ b/resources/com/google/gitiles/static/doc.css
@@ -0,0 +1,277 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+/* Markdown rendered in /+doc/ or tree view page . */
+
+.Site-Content--markdown {
+ padding-top: 0;
+}
+.Header-nav ul {
+ max-width: 980px;
+ margin: 0 auto;
+}
+.Header-nav li {
+ display: inline-block;
+ margin-right: 15px;
+}
+.doc h1, .doc h2, .doc h3, .doc h4, .doc h5, .doc h6 {
+ font-weight: normal;
+ margin: 1.236em 0 .618em;
+}
+.doc.RepoIndexDoc h1 {
+ margin-top: .25em;
+}
+.doc h1 {
+ font-size: 2em;
+}
+.doc h2 {
+ font-size: 1.5em;
+}
+.doc h3 {
+ font-size: 1.3em;
+}
+.doc h4 {
+ font-size: 1.3em;
+ font-weight: lighter;
+ font-style: italic;
+}
+.doc h5 {
+ font-size: 16px;
+ font-weight: lighter;
+ font-style: italic;
+}
+.doc h6 {
+ font-size: 14px;
+ font-style: italic;
+}
+.doc hr {
+ border: none;
+ border-top: 1px solid #aaa;
+ display: block;
+ margin-top: 25px;
+}
+.doc a {
+ text-decoration: none;
+}
+.doc a:link {
+ color: #245dc1;
+}
+.doc a:visited {
+ color: #7759ae;
+}
+.doc a:hover {
+ text-decoration: underline;
+}
+.doc a.h {
+ display: inline-block;
+ font-weight: normal;
+ width: 1.5em;
+ margin-left: -1.5em;
+ margin-top: -1em;
+ margin-bottom: -1em;
+}
+.doc a.h:link,
+.doc a.h:visited {
+ color: #444;
+}
+.doc a.h:focus {
+ outline: none;
+}
+.doc a.h:hover {
+ text-decoration: none;
+}
+.doc a.h span {
+ display: inline-block;
+ width: 1.5em;
+}
+.doc h1:hover a.h span:before,
+.doc h2:hover a.h span:before,
+.doc h3:hover a.h span:before,
+.doc h4:hover a.h span:before,
+.doc h5:hover a.h span:before,
+.doc h6:hover a.h span:before {
+ content: '#';
+ font-weight: normal;
+ color: #AAA;
+}
+.doc h1:hover a:hover.h span:before,
+.doc h2:hover a:hover.h span:before,
+.doc h3:hover a:hover.h span:before,
+.doc h4:hover a:hover.h span:before,
+.doc h5:hover a:hover.h span:before,
+.doc h6:hover a:hover.h span:before {
+ text-decoration: underline;
+}
+.doc h1:hover a:visited.h span:before,
+.doc h2:hover a:visited.h span:before,
+.doc h3:hover a:visited.h span:before,
+.doc h4:hover a:visited.h span:before,
+.doc h5:hover a:visited.h span:before,
+.doc h6:hover a:visited.h span:before {
+ color: #AAA;
+}
+.doc ul, .doc ol {
+ margin: 10px 10px 10px 30px;
+ padding: 0;
+}
+.doc ul {
+ list-style-type: disc;
+}
+.doc ol {
+ list-style-type: decimal;
+}
+.doc img {
+ border: 0;
+ max-width: 100%;
+}
+.doc iframe {
+ min-width: 100px;
+ min-height: 30px;
+}
+iframe.noborder {
+ border: 0;
+}
+.doc em {
+ font-weight: normal;
+ font-style: italic;
+}
+.doc strong {
+ font-weight: bold;
+ color: inherit;
+}
+.doc p {
+ margin: 10px 0;
+}
+.doc blockquote {
+ background-color: #fffde7;
+ border-left: 2px solid #fab700;
+ padding: 2px 10px 2px 10px;
+}
+.doc pre {
+ padding: 12px;
+ font-size: 10pt;
+ background-color: #fafafa;
+ border: 1px solid #ccc;
+ overflow-x: auto;
+}
+.doc code {
+ padding: 2px 4px;
+ background-color: #F5F5F5;
+ border: transparent;
+ border-radius: 4px;
+}
+.doc .code {
+ font-family: 'Source Code Pro', monospace;
+}
+.doc dl dt {
+ margin-top: 1em;
+}
+.doc table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+.doc th {
+ text-align: center;
+}
+.doc th,
+.doc td {
+ border: 1px solid #eee;
+ padding: 4px 12px;
+ vertical-align: top;
+}
+.doc th {
+ background-color: #f5f5f5;
+}
+.toc {
+ margin-top: 30px;
+}
+.toc-aux {
+ background: #f9f9f9;
+ border: 1px solid #f2f2f2;
+}
+.toc h2 {
+ margin: 0 0 5px 0;
+}
+.toc ul {
+ margin: 10px 10px 10px 30px;
+}
+.toc ul li {
+ margin-left: 0px;
+ list-style: disc;
+}
+.toc ul ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+.toc ul ul li {
+ list-style: circle;
+}
+.note,
+.promo,
+.aside {
+ border: 1px solid;
+ border-radius: 4px;
+ margin: 10px 0;
+ padding: 10px;
+}
+.note {
+ background: #fffbe4;
+ border-color: #f8f6e6;
+}
+.promo {
+ background: #f6f9ff;
+ border-color: #eff2f9;
+}
+.aside {
+ background: #f9f9f9;
+ border-color: #f2f2f2;
+}
+.note :first-child,
+.promo :first-child,
+.aside :first-child {
+ margin-top: 0;
+}
+.note p:last-child,
+.promo p:last-child,
+.aside p:last-child {
+ margin-bottom: 0;
+}
+.cols {
+ margin: 0 -1.533%;
+ width: 103.067%;
+}
+.col-1, .col-2, .col-3, .col-4, .col-5, .col-6,
+.col-7, .col-8, .col-9, .col-10, .col-11, .col-12 {
+ display: inline-block;
+ margin: 0 1.488% 20px;
+ vertical-align: top;
+}
+.cols h1, .cols h2, .cols h3, .cols h4, .cols h5, .cols h6 {
+ margin: .67em 0;
+}
+.col-1 { width: 5.357%; }
+.col-2 { width: 13.690%; }
+.col-3 { width: 22.024%; }
+.col-4 { width: 30.357%; }
+.col-5 { width: 38.690%; }
+.col-6 { width: 47.024%; }
+.col-7 { width: 55.357%; }
+.col-8 { width: 63.690%; }
+.col-9 { width: 72.024%; }
+.col-10 { width: 80.357%; }
+.col-11 { width: 88.690%; }
+.col-12 { width: 97.024%; }
+.cols hr { width: 80%; }
diff --git a/resources/com/google/gitiles/static/prettify/prettify.css b/resources/com/google/gitiles/static/prettify/prettify.css
new file mode 100644
index 0000000..d44b3a2
--- /dev/null
+++ b/resources/com/google/gitiles/static/prettify/prettify.css
@@ -0,0 +1 @@
+.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
\ No newline at end of file
diff --git a/resources/com/google/gitiles/templates/BlameDetail.soy b/resources/com/google/gitiles/templates/BlameDetail.soy
new file mode 100644
index 0000000..909ee0f
--- /dev/null
+++ b/resources/com/google/gitiles/templates/BlameDetail.soy
@@ -0,0 +1,88 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// 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.
+{namespace gitiles autoescape="strict"}
+
+/**
+ * Detail page showing blame info for a file.
+ *
+ * @param title human-readable revision name.
+ * @param repositoryName name of this repository.
+ * @param? menuEntries menu entries.
+ * @param? customVariant variant name for custom styling.
+ * @param breadcrumbs breadcrumbs for this page.
+ * @param data blob data, matching the params for .blobBox.
+ * @param? regions for non-binary files, list of regions, one per line, with the
+ * following keys:
+ * abbrevSha: abbreviated SHA-1 of revision for this line; if missing,
+ * assume blame info is missing.
+ * author: author information with at least "name" and "relativeTime"
+ * keys.
+ * time: time of the revision.
+ * blameUrl: URL for a blame of this file at this commit.
+ * commitUrl: URL for detail about the commit.
+ * diffUrl: URL for a diff of this file at this commit.
+ * class: class name for tr.
+ * All keys but "class" are optional.
+ */
+{template .blameDetail}
+{if $regions}
+ {call .header data="all"}
+ {param css: [gitiles.PRETTIFY_CSS_URL] /}
+ {param containerClass: 'Container--fullWidth' /}
+ {/call}
+
+ {call .blobHeader data="$data" /}
+
+ <table class="Blame">
+ {foreach $line in $data.lines}
+ {let $i: index($line) /}
+ {let $region: $regions[$i] /}
+ <tr class="Blame-region {$region.class}">
+ {if isNonnull($region.abbrevSha)}
+ <td class="Blame-author">{$region.author.name}</td>
+ <td class="Blame-sha1"><a class="u-sha1 u-monospace Blame-sha1" href="{$region.commitUrl}">{$region.abbrevSha}</a></td>
+ <td class="Blame-time">{$region.author.time}</span>
+ <td class="Blame-regionLink">
+ [<a href="{$region.diffUrl}">{msg desc="text for diff URL"}diff{/msg}</a>]
+ [<a href="{$region.blameUrl}">{msg desc="text for blame URL"}{$region.blameText}{/msg}</a>]
+ </td>
+ {else}
+ <td colspan="4"></td>
+ {/if}
+ {let $n: $i + 1 /}
+ <td class="Blame-lineNum">
+ <a class="u-monospace u-lineNum" href="#{$n}" name="{$n}">{$n}</a>
+ </td>
+ <td class="u-pre u-monospace Blame-lineContent">
+ {foreach $span in $line}
+ <span class="{$span.classes}">{$span.text}</span>
+ {/foreach}
+ </td>
+ </tr>
+ {/foreach}
+ </table>
+{else}
+ {call .header data="all" /}
+ {call .blobDetail data="$data" /}
+ <div class="FileContents-binary">
+ {msg desc="blame not available for binary file"}
+ No blame information available
+ {/msg}
+ </div>
+{/if}
+
+{call .footer}
+ {param customVariant: $customVariant /}
+{/call}
+{/template}
diff --git a/resources/com/google/gitiles/templates/Common.soy b/resources/com/google/gitiles/templates/Common.soy
new file mode 100644
index 0000000..ca3e21f
--- /dev/null
+++ b/resources/com/google/gitiles/templates/Common.soy
@@ -0,0 +1,169 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// 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.
+{namespace gitiles autoescape="strict"}
+
+/**
+ * Common header for Gitiles.
+ *
+ * @param title title for this page. Always suffixed with repository name and a
+ * sitewide title.
+ * @param? repositoryName repository name for this page, if applicable.
+ * @param? menuEntries optional list of menu entries with "text" and optional
+ * "url" keys.
+ * @param? customVariant variant name for custom styling.
+ * @param breadcrumbs navigation breadcrumbs for this page.
+ * @param? css optional list of CSS URLs to include.
+ * @param? containerClass optional class to append to the main container.
+ */
+{template .header}
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>
+ {$title}
+ {if $repositoryName}
+ {sp}- {$repositoryName}
+ {/if}
+ {sp}- {msg desc="name of the application"}{gitiles.SITE_TITLE}{/msg}
+ </title>
+
+ <link rel="stylesheet" type="text/css" href="{gitiles.BASE_CSS_URL}">
+ {if $css and length($css)}
+ {foreach $url in $css}
+ <link rel="stylesheet" type="text/css" href="{$url}">
+ {/foreach}
+ {/if}
+ {delcall gitiles.customHeadTagPart variant="$customVariant ?: ''" /}
+
+</head>
+<body class="Site">
+ <header class="Site-header">
+ <div class="Header">
+ {delcall gitiles.customHeader variant="$customVariant ?: ''" /}
+
+ {if $menuEntries and length($menuEntries)}
+ <div class="Header-menu">
+ {foreach $entry in $menuEntries}
+ {sp}
+ {if $entry.url}
+ <a class="Header-menuItem" href="{$entry.url}">{$entry.text}</a>
+ {else}
+ <span class="Header-menuItem Header-menuItem--noAction">{$entry.text}</span>
+ {/if}
+ {/foreach}
+ {sp}
+ </div>
+ {/if}
+ </div>
+ </header>
+
+ <div class="Site-content">
+ <div class="Container {if $containerClass}{$containerClass}{/if}">
+ {if $breadcrumbs and length($breadcrumbs)}
+ <div class="Breadcrumbs">
+ {foreach $entry in $breadcrumbs}
+ {if not isFirst($entry)}{sp}/{sp}{/if}
+ {if not isLast($entry)}
+ <a class="Breadcrumbs-crumb" href="{$entry.url}">{$entry.text}</a>
+ {else}
+ <span class="Breadcrumbs-crumb">{$entry.text}</span>
+ {/if}
+ {/foreach}
+ </div>
+ {/if}
+{/template}
+
+/**
+ * Default (empty) custom head tag part
+ *
+ * This can be used to include per-project CSS/JS by
+ * providing custom variants.
+ */
+{deltemplate gitiles.customHeadTagPart}
+ <!-- default customHeadTagPart -->
+{/deltemplate}
+
+/**
+ * Default custom header implementation for Gitiles.
+ */
+{deltemplate gitiles.customHeader}
+<!-- default customHeader -->
+<div class="Header-title">
+ {msg desc="short name of the application"}{gitiles.SITE_TITLE}{/msg}
+</div>
+{/deltemplate}
+
+/**
+ * Footer 'powered by' element
+ *
+ * Please call this in custom variants as well.
+ */
+{template .footerPoweredBy}
+<span class="Footer-poweredBy">
+ Powered by <a href="https://gerrit.googlesource.com/gitiles/">Gitiles</a>
+</span>
+{/template}
+
+/**
+ * Footer format badge
+ *
+ * You can use this in custom footers as well.
+ */
+{template .footerFormatBadge}
+<span class="Footer-formats">
+ <a class="u-monospace Footer-formatsItem" href="?format=TEXT">{msg desc="text format"}txt{/msg}</a>
+ {sp}
+ <a class="u-monospace Footer-formatsItem" href="?format=JSON">{msg desc="JSON format"}json{/msg}</a>
+</span>
+{/template}
+
+/**
+ * Default Footer
+ */
+{deltemplate gitiles.customFooter}
+<!-- default customFooter -->
+<footer class="Site-footer">
+ <div class="Footer">
+ {call gitiles.footerPoweredBy /}
+ {call gitiles.footerFormatBadge /}
+ </div>
+</footer>
+{/deltemplate}
+
+/**
+ * Main footer.
+ *
+ * The footer tag part can be customized by creating a customFooter
+ * variant template.
+ *
+ * @param? customVariant variant name for custom styling.
+ */
+{template .footer}
+ </div> <!-- Container -->
+ </div> <!-- Site-content -->
+ {delcall gitiles.customFooter variant="$customVariant ?: ''" /}
+</body>
+</html>
+{/template}
+
+/**
+ * Placeholder for streaming rendering.
+ *
+ * Insert this in a template to use with
+ * Renderer#renderStreaming(HttpServletResponse, String).
+ */
+{template .streamingPlaceholder}
+<div id="STREAMED_OUTPUT_BLOCK" />
+{/template}
diff --git a/resources/com/google/gitiles/templates/DiffDetail.soy b/resources/com/google/gitiles/templates/DiffDetail.soy
new file mode 100644
index 0000000..252ab7b
--- /dev/null
+++ b/resources/com/google/gitiles/templates/DiffDetail.soy
@@ -0,0 +1,61 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// 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.
+{namespace gitiles autoescape="strict"}
+
+/**
+ * Detail page showing diffs for a single commit.
+ *
+ * @param title human-readable revision name.
+ * @param repositoryName name of this repository.
+ * @param? menuEntries menu entries.
+ * @param? customVariant variant name for custom styling.
+ * @param breadcrumbs breadcrumbs for this page.
+ * @param? commit optional commit for which diffs are displayed, with keys
+ * corresponding to the gitiles.commitDetail template (minus "diffTree").
+ */
+{template .diffDetail}
+{call .header data="all" /}
+
+{if $commit}
+ {call .commitDetail data="$commit" /}
+{/if}
+{call .streamingPlaceholder /}
+
+{call .footer}
+ {param customVariant: $customVariant /}
+{/call}
+{/template}
+
+/**
+ * File header for a single unified diff patch.
+ *
+ * @param firstParts parts of the first line of the header, with "text" and
+ * optional "url" fields.
+ * @param rest remaining lines of the header, if any.
+ * @param fileIndex position of the file within the difference.
+ */
+{template .diffHeader}
+<pre class="u-pre u-monospace Diff">
+ <a name="F{$fileIndex}" class="Diff-fileIndex"></a>
+ {foreach $part in $firstParts}
+ {if not isFirst($part)}{sp}{/if}
+ {if $part.url}
+ <a href="{$part.url}">{$part.text}</a>
+ {else}
+ {$part.text}
+ {/if}
+ {/foreach}{\n}
+ {$rest}
+</pre>
+{/template}
diff --git a/resources/com/google/gitiles/templates/Doc.soy b/resources/com/google/gitiles/templates/Doc.soy
new file mode 100644
index 0000000..426ba15
--- /dev/null
+++ b/resources/com/google/gitiles/templates/Doc.soy
@@ -0,0 +1,90 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// 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.
+{namespace gitiles autoescape="strict"}
+
+/**
+ * Documentation page rendered from markdown.
+ *
+ * @param? siteTitle h1 title from navbar.md.
+ * @param pageTitle h1 title from specific page.
+ * @param? logoUrl url of image logo.
+ * @param? homeUrl url to jump to top of site.
+ * @param? analyticsId Google Analytics Property ID.
+ * @param? sourceUrl url for source view of the page.
+ * @param? logUrl url for log history of page.
+ * @param? blameUrl url for blame of page source.
+ * @param? navbarHtml navar.md converted to SafeHtml.
+ * @param? customVariant variant name for custom styling.
+ */
+{template .markdownDoc}
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>
+ {if $siteTitle}{$siteTitle} -{sp}{/if}
+ {$pageTitle}
+ </title>
+ <link rel="stylesheet" type="text/css" href="{gitiles.BASE_CSS_URL}" />
+ <link rel="stylesheet" type="text/css" href="{gitiles.DOC_CSS_URL}" />
+ <link rel="stylesheet" type="text/css" href="{gitiles.PRETTIFY_CSS_URL}" />
+ {delcall gitiles.customHeadTagPart variant="$customVariant ?: ''" /}
+</head>
+<body class="Site">
+ <header class="Site-header {if $navbarHtml}Site-header--withNavbar{/if}">
+ <div class="Header">
+ <div class="Header-title">
+ {if $homeUrl}<a class="Header-anchor" href="{$homeUrl}">{/if}
+ {if $logoUrl}<img class="Header-anchorLogo" src="{$logoUrl}" alt="project logo" />{/if}
+ {if $siteTitle}<span class="Header-anchorTitle">{$siteTitle}</span>{/if}
+ {if $homeUrl}</a>{/if}
+ </div>
+ </div>
+ {if $navbarHtml}
+ <nav class="Header-nav" role="navigation">
+ {$navbarHtml}
+ </div>
+ {/if}
+ </header>
+ <div class="Site-content Site-Content--markdown">
+ <div class="Container">
+ <div class="doc">
+ {call .streamingPlaceholder /}
+ </div>
+ </div>
+ </div>
+ <footer class="Site-footer">
+ <div class="Footer">
+ {call gitiles.footerPoweredBy /}
+ <div class="Footer-links">
+ {if $sourceUrl}<a class="Footer-link" href="{$sourceUrl}">{msg desc="text for the source link"}source{/msg}</a>{/if}
+ {if $logUrl}<a class="Footer-link" href="{$logUrl}">{msg desc="text for the log link"}log{/msg}</a>{/if}
+ {if $blameUrl}<a class="Footer-link" href="{$blameUrl}">{msg desc="text for the blame link"}blame{/msg}</a>{/if}
+ </div>
+ </footer>
+ {if $analyticsId}
+ /* From https://developers.google.com/analytics/devguides/collection/analyticsjs/ */
+ <script>
+ (function(i,s,o,g,r,a,m){lb}i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){lb}
+ (i[r].q=i[r].q||[]).push(arguments){rb},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ {rb})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+ ga('create', '{$analyticsId}', 'auto');
+ ga('send', 'pageview', {lb}title: '{$pageTitle}'{rb});
+ </script>
+ {/if}
+</body>
+</html>
+{/template}
diff --git a/resources/com/google/gitiles/templates/HostIndex.soy b/resources/com/google/gitiles/templates/HostIndex.soy
new file mode 100644
index 0000000..ab3b18c
--- /dev/null
+++ b/resources/com/google/gitiles/templates/HostIndex.soy
@@ -0,0 +1,69 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// 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.
+{namespace gitiles autoescape="strict"}
+
+/**
+ * HTML page for /.
+ *
+ * @param hostName host name.
+ * @param? menuEntries menu entries.
+ * @param? customVariant variant name for custom styling.
+ * @param? prefix prefix path for matching repositories.
+ * @param? breadcrumbs map of breadcrumbs for header.
+ * @param repositories list of repository description maps with name, cloneUrl,
+ * and optional description values.
+ */
+{template .hostIndex}
+{call .header}
+ {param title: $prefix ? $prefix : $hostName ? $hostName + ' Git repositories' : 'Git repositories' /}
+ {param menuEntries: $menuEntries /}
+ {param breadcrumbs: $breadcrumbs /}
+ {param customVariant: $customVariant /}
+{/call}
+
+{if length($repositories)}
+ {if not $breadcrumbs}
+ <h1>
+ {msg desc="Git repositories available on the host"}
+ Git repositories on {$hostName}
+ {/msg}
+ </h1>
+ {/if}
+
+ <div class="RepoList">
+ <div class="RepoList-item RepoList-item--header">
+ <span class="RepoList-itemName">
+ {msg desc="column header for repository name"}
+ Name
+ {/msg}
+ </span>
+ <span class="RepoList-itemDescription">
+ {msg desc="column header for repository description"}
+ Description
+ {/msg}
+ </span>
+ </div>
+ {foreach $repo in $repositories}
+ <a class="RepoList-item" href="{$repo.url}">
+ <span class="RepoList-itemName">{$repo.name}</span>
+ <span class="RepoList-itemDescription">{$repo.description}</span>
+ </a>
+ {/foreach}
+ </div>
+{/if}
+
+{call .footer}
+ {param customVariant: $customVariant /}
+{/call}
+{/template}
diff --git a/resources/com/google/gitiles/templates/LogDetail.soy b/resources/com/google/gitiles/templates/LogDetail.soy
new file mode 100644
index 0000000..be7c9b3
--- /dev/null
+++ b/resources/com/google/gitiles/templates/LogDetail.soy
@@ -0,0 +1,258 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// 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.
+{namespace gitiles autoescape="strict"}
+
+/**
+ * Detail page showing a shortlog for a commit.
+ *
+ * @param title human-readable revision name.
+ * @param repositoryName name of this repository.
+ * @param? menuEntries menu entries.
+ * @param? customVariant variant name for custom styling.
+ * @param breadcrumbs breadcrumbs for this page.
+ * @param? tags optional list of tags encountered when peeling this object, with
+ * keys corresponding to gitiles.tagDetail.
+ */
+{template .logDetail}
+{call .header data="all" /}
+
+{if $tags}
+ {foreach $tag in $tags}
+ {call gitiles.tagDetail data="$tag" /}
+ {/foreach}
+{/if}
+
+{call .streamingPlaceholder /}
+
+{call .footer}
+ {param customVariant: $customVariant /}
+{/call}
+{/template}
+
+
+/**
+ * Header for list of log entries.
+ *
+ * @param? previousUrl URL for the previous page of results.
+ */
+{template .logEntriesHeader}
+{if $previousUrl}
+ <nav class="LogNav">
+ <a class="LogNav-prev" href="{$previousUrl}">{msg desc="text for previous URL"}« Previous{/msg}</a>
+ </nav>
+{/if}
+
+<ol class="CommitLog">
+{/template}
+
+
+/**
+ * Wrapper for a single log entry with pretty format and variant.
+ *
+ * @param variant variant name for log entry template.
+ * @param entry log entry; see .logEntry.
+ */
+{template .logEntryWrapper}
+<li class="CommitLog-item CommitLog-item--{$variant}">
+ {delcall gitiles.logEntry variant="$variant ?: 'default'" data="$entry" /}
+</li>
+{/template}
+
+
+/**
+ * Footer for the list of log entries.
+ *
+ * @param? nextUrl URL for the next page of results.
+ */
+{template .logEntriesFooter}
+</ol>
+{if $nextUrl}
+ <nav class="LogNav">
+ <a class="LogNav-next" href="{$nextUrl}">{msg desc="text for next URL"}Next »{/msg}</a>
+ </nav>
+{/if}
+{/template}
+
+
+/**
+ * Single log entry indicating the full log is empty.
+ */
+{template .emptyLog}
+<li class="CommitLog-item CommitLog-item--empty">{msg desc="informational text for when the log is empty"}No commits.{/msg}</p>
+{/template}
+
+
+/**
+ * Single pretty log entry, similar to --pretty=oneline.
+ *
+ * @param abbrevSha abbreviated SHA-1.
+ * @param sha commit SHA-1.
+ * @param url URL to commit detail page.
+ * @param shortMessage short commit message.
+ * @param message list of commit message parts, where each part contains:
+ * text: raw text of the part.
+ * url: optional URL that should be linked to from the part.
+ * @param author author information with at least "name" and "relativeTime" keys.
+ * @param committer committer information with at least "time" and "relativeTime" keys.
+ * @param branches list of branches for this entry, with "name" and "url" keys.
+ * @param tags list of tags for this entry, with "name" and "url" keys.
+ * @param diffTree unused in this variant.
+ * @param rename if this entry was a rename or a copy of the path, an object containg:
+ * changeType: the change type, "RENAME" or "COPY".
+ * oldPath: the old path prior to the rename or copy.
+ * newPath: the new path after the rename or copy.
+ * score: the similarity score of the rename or copy.
+ */
+{deltemplate gitiles.logEntry variant="'oneline'"}
+<a class="u-sha1 u-monospace CommitLog-sha1" href="{$url}">{$abbrevSha}</a>
+{sp}<a href="{$url}">{$shortMessage}</a>
+{sp}<span class="CommitLog-author" title="{$author.email}">{msg desc="commit author name"}by {$author.name}{/msg}</span>
+{sp}<span class="CommitLog-time" title="{$author.time}">· {$author.relativeTime}</span>
+{if length($branches)}
+ {foreach $branch in $branches}
+ {sp}<a class="CommitLog-branchLabel" href="{$branch.url}">{$branch.name}</a>
+ {/foreach}
+{/if}
+{if length($tags)}
+ {foreach $tag in $tags}
+ {sp}<a class="CommitLog-tagLabel" href="{$tag.url}">{$tag.name}</a>
+ {/foreach}
+{/if}
+
+{if $rename}
+ <span class="CommitLog-rename">
+ [
+ {switch $rename.changeType}
+ {case 'RENAME'}
+ Renamed
+ {case 'COPY'}
+ Copied
+ {/switch}
+ {if $rename.score != 100}
+ {sp}({$rename.score}%)
+ {/if}
+ {sp}from {$rename.oldPath}]
+ </span>
+{/if}
+
+{/deltemplate}
+
+
+/**
+ * Default single log entry (oneline format).
+ *
+ * @param abbrevSha abbreviated SHA-1.
+ * @param sha commit SHA-1.
+ * @param url URL to commit detail page.
+ * @param shortMessage short commit message.
+ * @param message list of commit message parts, where each part contains:
+ * text: raw text of the part.
+ * url: optional URL that should be linked to from the part.
+ * @param author author information with at least "name" and "relativeTime" keys.
+ * @param committer committer information with at least "time" and "relativeTime" keys.
+ * @param branches list of branches for this entry, with "name" and "url" keys.
+ * @param tags list of tags for this entry, with "name" and "url" keys.
+ * @param diffTree unused in this variant.
+ * @param rename if this entry was a rename or a copy of the path, an object containg:
+ * changeType: the change type, "RENAME" or "COPY".
+ * oldPath: the old path prior to the rename or copy.
+ * newPath: the new path after the rename or copy.
+ * score: the similarity score of the rename or copy.
+ */
+{deltemplate gitiles.logEntry variant="'default'"}
+{delcall gitiles.logEntry variant="'oneline'" data="all" /}
+{/deltemplate}
+
+
+/**
+ * Single pretty log entry, similar to --pretty=full.
+ *
+ * @param abbrevSha abbreviated SHA-1.
+ * @param sha commit SHA-1.
+ * @param url URL to commit detail page.
+ * @param shortMessage short commit message.
+ * @param message list of commit message parts, where each part contains:
+ * text: raw text of the part.
+ * url: optional URL that should be linked to from the part.
+ * @param author author information with at least "name" and "relativeTime" keys.
+ * @param committer committer information with at least "time" and "relativeTime" keys.
+ * @param branches list of branches for this entry, with "name" and "url" keys.
+ * @param tags list of tags for this entry, with "name" and "url" keys.
+ * @param diffTree unused in this variant.
+ * @param rename if this entry was a rename or a copy of the path, an object containg:
+ * changeType: the change type, "RENAME" or "COPY".
+ * oldPath: the old path prior to the rename or copy.
+ * newPath: the new path after the rename or copy.
+ * score: the similarity score of the rename or copy.
+ */
+{deltemplate gitiles.logEntry variant="'full'"}
+<div class="u-monospace Metadata">
+<table>
+ <tr>
+ <th class="Metadata-title">{msg desc="Header for commit SHA entry"}commit{/msg}</th>
+ <td class="sha1">
+ <a href="{$url}">{$sha}</a>
+ </td>
+ <td>
+ {if length($branches)}
+ {foreach $branch in $branches}
+ {sp}<a href="{$branch.url}" class="branch-label">{$branch.name}</a>
+ {/foreach}
+ {/if}
+ {if length($tags)}
+ {foreach $tag in $tags}
+ {sp}<a href="{$tag.url}" class="tag-label">{$tag.name}</a>
+ {/foreach}
+ {else}
+ {sp}
+ {/if}
+ </td>
+ </tr>
+ <tr>
+ <th class="Metadata-title">{msg desc="Header for commit author"}author{/msg}</th>
+ <td>{call .person_ data="$author" /}</td>
+ <td>{$author.time}</td>
+ </tr>
+ <tr>
+ <th class="Metadata-title">{msg desc="Header for committer"}committer{/msg}</th>
+ <td>{call .person_ data="$committer" /}</td>
+ <td>{$committer.time}</td>
+ </tr>
+
+ {if $rename}
+ <tr>
+ <td colspan="3">
+ <span class="CommitLog-rename">
+ [
+ {switch $rename.changeType}
+ {case 'RENAME'}
+ Renamed
+ {case 'COPY'}
+ Copied
+ {/switch}
+ {if $rename.score != 100}
+ {sp}({$rename.score}%)
+ {/if}
+ {sp}from {$rename.oldPath}]
+ </span>
+ </td>
+ </tr>
+ {/if}
+
+</table>
+</div>
+<pre class="u-pre u-monospace MetadataMessage">
+ {$message}
+</pre>
+{/deltemplate}
diff --git a/resources/com/google/gitiles/templates/ObjectDetail.soy b/resources/com/google/gitiles/templates/ObjectDetail.soy
new file mode 100644
index 0000000..ea0e06e
--- /dev/null
+++ b/resources/com/google/gitiles/templates/ObjectDetail.soy
@@ -0,0 +1,345 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// 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.
+{namespace gitiles autoescape="strict"}
+
+/**
+ * Detailed listing of a commit.
+ *
+ * @param author map with "name", "email", and "time" keys for the commit author.
+ * @param committer map with "name", "email", and "time" keys for the committer.
+ * @param sha commit SHA-1.
+ * @param tree tree SHA-1.
+ * @param treeUrl tree URL.
+ * @param parents list of parent objects with the following keys:
+ * sha: SHA-1.
+ * url: URL to view the parent commit.
+ * diffUrl: URL to display diffs relative to this parent.
+ * blameUrl: optional URL to display blame of a file at this parent.
+ * @param message list of commit message parts, where each part contains:
+ * text: raw text of the part.
+ * url: optional URL that should be linked to from the part.
+ * @param diffTree list of changed tree entries with the following keys:
+ * changeType: string matching an org.eclipse.jgit.diff.DiffEntry.ChangeType
+ * constant.
+ * path: (new) path of the tree entry.
+ * oldPath: old path, only for renames and copies.
+ * url: URL to a detail page for the tree entry.
+ * diffUrl: URL to a diff page for the tree entry's diff in this commit.
+ * @param logUrl URL to a log page starting at this commit.
+ * @param archiveUrl URL to a download link of this commit as an archive.
+ * @param archiveType type of the archive to download.
+ */
+{template .commitDetail}
+<div class="u-monospace Metadata">
+ <table>
+ <tr>
+ <th class="Metadata-title">{msg desc="Header for commit SHA entry"}commit{/msg}</th>
+ <td>
+ {$sha}
+ </td>
+ <td>
+ <span>
+ [<a href="{$logUrl}">{msg desc="text for the log link"}log{/msg}</a>]
+ </span>
+ {sp}<span>[<a href="{$archiveUrl}">{$archiveType}</a>]</span>
+ </td>
+ </tr>
+ <tr>
+ <th class="Metadata-title">{msg desc="Header for commit author"}author{/msg}</th>
+ <td>{call .person_ data="$author" /}</td>
+ <td>{$author.time}</td>
+ </tr>
+ <tr>
+ <th class="Metadata-title">{msg desc="Header for committer"}committer{/msg}</th>
+ <td>{call .person_ data="$committer" /}</td>
+ <td>{$committer.time}</td>
+ </tr>
+ <tr>
+ <th class="Metadata-title">{msg desc="Header for tree SHA entry"}tree{/msg}</th>
+ <td><a href="{$treeUrl}">{$tree}</a></td>
+ </tr>
+ {foreach $parent in $parents}
+ <tr>
+ <th class="Metadata-title">{msg desc="Header for parent SHA"}parent{/msg}</th>
+ <td>
+ <a href="{$parent.url}">{$parent.sha}</a>
+ {sp}<span>
+ [<a href="{$parent.diffUrl}">{msg desc="text for the parent diff link"}diff{/msg}</a>]
+ {if isNonnull($parent.blameUrl)}
+ {sp}[<a href="{$parent.blameUrl}">{msg desc="text for the parent blame link"}blame{/msg}</a>]
+ {/if}
+ </span>
+ </td>
+ </tr>
+ {/foreach}
+ </table>
+</div>
+{call .message_}
+ {param className: 'u-pre u-monospace MetadataMessage' /}
+ {param message: $message /}
+{/call}
+
+{if $diffTree and length($diffTree)}
+ <ul class="DiffTree">
+ {foreach $entry in $diffTree}
+ <li>
+ <a href="{$entry.url}">{$entry.path}</a>
+ {switch $entry.changeType}
+ {case 'ADD'}
+ <span class="DiffTree-action DiffTree-action--add">
+ {msg desc="Text for a new tree entry"}
+ [Added - <a href="{$entry.diffUrl}">diff</a>]
+ {/msg}
+ </span>
+ {case 'MODIFY'}
+ <span class="DiffTree-action DiffTree-action--modify">
+ {msg desc="Text for a modified tree entry"}
+ [<a href="{$entry.diffUrl}">diff</a>]
+ {/msg}
+ </span>
+ {case 'DELETE'}
+ <span class="DiffTree-action DiffTree-action--delete">
+ {msg desc="Text for a deleted tree entry"}
+ [Deleted - <a href="{$entry.diffUrl}">diff</a>]
+ {/msg}
+ </span>
+ {case 'RENAME'}
+ <span class="DiffTree-action DiffTree-action--rename">
+ {msg desc="Text for a renamed tree entry"}
+ [Renamed from {$entry.oldPath} - <a href="{$entry.diffUrl}">diff</a>]
+ {/msg}
+ </span>
+ {case 'COPY'}
+ <span class="DiffTree-action DiffTree-action--copy">
+ {msg desc="Text for a copied tree entry"}
+ [Copied from {$entry.oldPath} - <a href="{$entry.diffUrl}">diff</a>]
+ {/msg}
+ </span>
+ {default}
+ {/switch}
+ </li>
+ {/foreach}
+ </ul>
+ <div class="DiffSummary">
+ {if length($diffTree) == 1}
+ {msg desc="1 file changed"}1 file changed{/msg}
+ {else}
+ {msg desc="number of files changed"}{length($diffTree)} files changed{/msg}
+ {/if}
+ </div>
+{/if}
+
+{/template}
+
+/**
+ * Detailed listing of a tree.
+ *
+ * @param sha SHA of this path's tree.
+ * @param? logUrl optional URL to a log for this path.
+ * @param? archiveUrl optional URL to a download link of this tree as an archive.
+ * @param? archiveType type of the archive to download, if archiveUrl is set.
+ * @param entries list of entries with the following keys:
+ * type: entry type, matching one of the constant names defined in
+ * org.eclipse.jgit.lib.FileMode.
+ * name: tree entry name.
+ * url: URL to link to.
+ * targetName: name of a symlink target, required only if type == 'SYMLINK'.
+ * targetUrl: optional url of a symlink target, required only if
+ * type == 'SYMLINK'.
+ * @param? readmePath optional path of the selected README.md file.
+ * @param? readmeHtml optional rendered README.md contents.
+ */
+{template .treeDetail}
+<div class="TreeDetail">
+ <div class="u-sha1 u-monospace TreeDetail-sha1">
+ {msg desc="SHA-1 for the path's tree"}tree: {$sha}{/msg}
+ {if $logUrl}{sp}[<a href="{$logUrl}">{msg desc="history for a path"}path history{/msg}</a>]{/if}
+ {if $archiveUrl}
+ {sp}<span>[<a href="{$archiveUrl}">{$archiveType}</a>]</span>
+ {/if}
+ </div>
+
+ {if length($entries)}
+ <ol class="FileList">
+ {foreach $entry in $entries}
+ <li class="FileList-item{sp}
+ {switch $entry.type}
+ {case 'TREE'}FileList-item--gitTree
+ {case 'SYMLINK'}FileList-item--symlink
+ {case 'REGULAR_FILE'}FileList-item--regularFile
+ {case 'EXECUTABLE_FILE'}FileList-item--executableFile
+ {case 'GITLINK'}gitlink
+ {default}regular-file
+ {/switch}
+ " title="
+ {switch $entry.type}
+ {case 'TREE'}{msg desc="Alt text for tree icon"}Tree{/msg}
+ {case 'SYMLINK'}{msg desc="Alt text for symlink icon"}Symlink{/msg}
+ {case 'REGULAR_FILE'}{msg desc="Alt text for regular file icon"}Regular file{/msg}
+ {case 'EXECUTABLE_FILE'}
+ {msg desc="Alt text for executable file icon"}Executable file{/msg}
+ {case 'GITLINK'}
+ {msg desc="Alt text for git submodule link icon"}Git submodule link{/msg}
+ {default}{msg desc="Alt text for other file icon"}Other{/msg}
+ {/switch}
+ {sp}- {$entry.name}">
+ <a class="FileList-itemLink" href="{$entry.url}">{$entry.name}</a>
+ {if $entry.type == 'SYMLINK'}
+ {sp}⇨{sp}
+ {if $entry.targetUrl}
+ <a href="{$entry.targetUrl}">{$entry.targetName}</a>
+ {else}
+ {$entry.targetName}
+ {/if}
+ {/if}
+ // TODO(dborowitz): Something reasonable for gitlinks.
+ </li>
+ {/foreach}
+ </ol>
+ {else}
+ <p>{msg desc="Informational text for when a tree is empty"}This tree is empty.{/msg}</p>
+ {/if}
+
+ {if $readmeHtml}
+ <div class="InlineReadme">
+ <div class="InlineReadme-path">{$readmePath}</div>
+ <div class="doc">{$readmeHtml}</div>
+ </div>
+ {/if}
+</div>
+{/template}
+
+/**
+ * Common header for a blob shared between detail, blame, etc. views.
+ *
+ * @param sha SHA of this file's blob.
+ * @param? fileUrl optional URL to a detail view of this file.
+ * @param? logUrl optional URL to a log for this file.
+ * @param? blameUrl optional URL to a blame for this file.
+ * @param? docUrl optional URL to view rendered file.
+ */
+{template .blobHeader}
+<div class="u-sha1 u-monospace BlobSha1">
+ {msg desc="SHA-1 for the file's blob"}blob: {$sha}{/msg}
+ {if $fileUrl}{sp}[<a href="{$fileUrl}">{msg desc="detail view of a file"}file{/msg}</a>]{/if}
+ {if $logUrl}{sp}[<a href="{$logUrl}">{msg desc="history for a file"}log{/msg}</a>]{/if}
+ {if $blameUrl}{sp}[<a href="{$blameUrl}">{msg desc="blame for a file"}blame{/msg}</a>]{/if}
+ {if $docUrl}{sp}[<a href="{$docUrl}">{msg desc="view rendered file"}view{/msg}</a>]{/if}
+</div>
+{/template}
+
+/**
+ * Detailed listing of a blob.
+ *
+ * @param sha SHA of this file's blob.
+ * @param? logUrl optional URL to a log for this file.
+ * @param? blameUrl optional URL to a blame for this file.
+ * @param lines lines (may be empty), or null for a binary file. Each line
+ * is a list of entries with "classes" and "text" fields for pretty-printed
+ * spans.
+ * @param? size for binary files only, size in bytes.
+ */
+{template .blobDetail}
+ {call .blobHeader data="all" /}
+
+ {if $lines != null}
+ {if $lines}
+ <table class="FileContents">
+ {foreach $line in $lines}
+ {let $n: index($line) + 1 /}
+ <tr class="u-pre u-monospace FileContents-line">
+ <td class="u-lineNum u-noSelect FileContents-lineNum"
+ data-line-number="{$n}" onclick="window.location.hash='#{$n}'"></td>
+ <td class="FileContents-lineContents" id="{$n}">
+ {foreach $span in $line}
+ <span class="{$span.classes}">{$span.text}</span>
+ {/foreach}
+ </td>
+ </tr>
+ {/foreach}
+ </table>
+ {else}
+ <div class="FileContents-empty">Empty file</div>
+ {/if}
+ {else}
+ <div class="FileContents-binary">
+ {msg desc="size of binary file in bytes"}{$size}-byte binary file{/msg}
+ </div>
+ {/if}
+{/template}
+
+/**
+ * Detailed listing of an annotated tag.
+ *
+ * @param sha SHA of this tag.
+ * @param? tagger optional map with "name", "email", and "time" keys for the
+ * tagger.
+ * @param object SHA of the object this tag points to.
+ * @param message tag message.
+ */
+{template .tagDetail}
+<div class="u-monospace Metadata">
+ <table>
+ <tr>
+ <th class="Metadata-title">{msg desc="Header for tag SHA entry"}tag{/msg}</th>
+ <td class="sha">{$sha}</td>
+ <td>{sp}</td>
+ </tr>
+ {if $tagger}
+ <tr>
+ <th class="Metadata-title">{msg desc="Header for tagger"}tagger{/msg}</th>
+ <td>{call .person_ data="$tagger" /}</td>
+ <td>{$tagger.time}</td>
+ </tr>
+ {/if}
+ <tr>
+ <th class="Metadata-title">{msg desc="Header for tagged object SHA"}object{/msg}</th>
+ <td class="sha">{$object}</td>
+ <td>{sp}</td>
+ </tr>
+ </table>
+</div>
+{if $message and length($message)}
+ {call .message_}
+ {param className: 'u-pre u-monospace MetadataMessage' /}
+ {param message: $message /}
+ {/call}
+{/if}
+{/template}
+
+/**
+ * Line about a git person identity.
+ *
+ * @param name name.
+ * @param email email.
+ */
+{template .person_}
+{$name}{if $email} <{$email}>{/if}
+{/template}
+
+/**
+ * Preformatted message, possibly containing hyperlinks.
+ *
+ * @param className CSS class name for <pre> block.
+ * @param message list of message parts, where each part contains:
+ * text: raw text of the part.
+ * url: optional URL that should be linked to from the part.
+ */
+{template .message_ visibility="private"}
+<pre class="{$className}">
+ {foreach $part in $message}
+ {if $part.url}<a href="{$part.url}">{$part.text}</a>{else}{$part.text}{/if}
+ {/foreach}
+</pre>
+{/template}
diff --git a/resources/com/google/gitiles/templates/PathDetail.soy b/resources/com/google/gitiles/templates/PathDetail.soy
new file mode 100644
index 0000000..c4c5d5f
--- /dev/null
+++ b/resources/com/google/gitiles/templates/PathDetail.soy
@@ -0,0 +1,89 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// 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.
+{namespace gitiles autoescape="strict"}
+
+/**
+ * Detail page for a path within a tree.
+ *
+ * @param title human-readable name of this path.
+ * @param repositoryName name of this repository.
+ * @param? menuEntries menu entries.
+ * @param? customVariant variant name for custom styling.
+ * @param breadcrumbs breadcrumbs for this page.
+ * @param type path type, matching one of the constant names defined in
+ * org.eclipse.jgit.lib.FileMode.
+ * @param data path data, matching the params for one of .treeDetail,
+ * .blobDetail, .symlinkDetail, or .gitlinkDetail as appropriate.
+ */
+{template .pathDetail}
+{if $type == 'REGULAR_FILE' or $type == 'EXECUTABLE_FILE'}
+ {call .header data="all"}
+ {param css: [gitiles.PRETTIFY_CSS_URL] /}
+ {/call}
+{elseif $data.readmeHtml}
+ {call .header data="all"}
+ {param css: [gitiles.DOC_CSS_URL, gitiles.PRETTIFY_CSS_URL] /}
+ {/call}
+{else}
+ {call .header data="all" /}
+{/if}
+
+{switch $type}
+ {case 'TREE'}{call .treeDetail data="$data" /}
+ {case 'SYMLINK'}{call .symlinkDetail data="$data" /}
+ {case 'REGULAR_FILE'}{call .blobDetail data="$data" /}
+ {case 'EXECUTABLE_FILE'}{call .blobDetail data="$data" /}
+ {case 'GITLINK'}{call .gitlinkDetail data="$data" /}
+ {default}
+ <div class="error">
+ {msg desc="Error message for an unknown object type"}Object has unknown type.{/msg}
+ </div>
+{/switch}
+
+{call .footer}
+ {param customVariant: $customVariant /}
+{/call}
+{/template}
+
+/**
+ * Detail for a symbolic link.
+ *
+ * @param target target of this symlink.
+ * @param? targetUrl optional URL for the target, if it is within this repo.
+ */
+{template .symlinkDetail}
+<div class="symlink-detail">
+ {msg desc="Lead-in text for the symbolic link target."}Symbolic link to{/msg}
+ {sp}{if $targetUrl}<a href="{$targetUrl}">{$target}</a>{else}{$target}{/if}
+</div>
+{/template}
+
+/**
+ * Detail for a git submodule link.
+ *
+ * @param sha submodule commit SHA.
+ * @param remoteUrl URL of the remote repository.
+ * @param? httpUrl optional HTTP URL pointing to a web-browser-compatible URL of
+ * the remote repository.
+ */
+{template .gitlinkDetail}
+<div class="gitlink-detail">
+ {msg desc="Lead-in text for the git link URL"}Submodule link to {$sha} of{/msg}
+ {if $remoteUrl}
+ {sp}{if $httpUrl}<a href="{$httpUrl}">{$remoteUrl}</a>{else}{$remoteUrl}{/if}
+ {else}
+ {sp}{msg desc="Text describing an unknown submodule URL"}a submodule with an unknown URL{/msg}
+ {/if}
+</div>
+{/template}
diff --git a/resources/com/google/gitiles/templates/RefList.soy b/resources/com/google/gitiles/templates/RefList.soy
new file mode 100644
index 0000000..be9c94a
--- /dev/null
+++ b/resources/com/google/gitiles/templates/RefList.soy
@@ -0,0 +1,72 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// 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.
+{namespace gitiles autoescape="strict"}
+
+
+/**
+ * List of all refs in a repository.
+ *
+ * @param repositoryName name of this repository.
+ * @param? menuEntries menu entries.
+ * @param? customVariant variant name for custom styling.
+ * @param breadcrumbs breadcrumbs for this page.
+ * @param branches list of branch objects with url, name, and isHead keys.
+ * @param tags list of tag objects with url and name keys.
+ */
+{template .refsDetail}
+{call .header}
+ {param title: 'Refs' /}
+ {param repositoryName: $repositoryName /}
+ {param menuEntries: $menuEntries /}
+ {param customVariant: $customVariant /}
+ {param breadcrumbs: $breadcrumbs /}
+{/call}
+
+<div class="Refs">
+ {if length($branches)}
+ {call .refList}
+ {param type: 'Branches' /}
+ {param refs: $branches /}
+ {/call}
+ {/if}
+
+ {if length($tags)}
+ {call .refList}
+ {param type: 'Tags' /}
+ {param refs: $tags /}
+ {/call}
+ {/if}
+</div>
+
+{call .footer}
+ {param customVariant: $customVariant /}
+{/call}
+{/template}
+
+/**
+ * List of a single type of refs
+ *
+ * @param type name of this type of refs, e.g. "Branches"
+ * @param refs list of branch objects with url, name, and optional isHead keys.
+ */
+{template .refList}
+ <div class="RefList">
+ <h3 class="RefList-title">{$type}</h3>
+ <ul class="RefList-items">
+ {foreach $ref in $refs}
+ <li class="RefList-item"><a href="{$ref.url}">{$ref.name}</a></li>
+ {/foreach}
+ </ul>
+ </div>
+{/template}
diff --git a/resources/com/google/gitiles/templates/RepositoryIndex.soy b/resources/com/google/gitiles/templates/RepositoryIndex.soy
new file mode 100644
index 0000000..78f5b79
--- /dev/null
+++ b/resources/com/google/gitiles/templates/RepositoryIndex.soy
@@ -0,0 +1,132 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// 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.
+{namespace gitiles autoescape="strict"}
+
+/**
+ * Index page for a repository.
+ *
+ * @param repositoryName name of this repository.
+ * @param? menuEntries menu entries.
+ * @param? customVariant variant name for custom styling.
+ * @param breadcrumbs breadcrumbs for this page.
+ * @param cloneUrl clone URL for this repository.
+ * @param description description text of the repository.
+ * @param? mirroredFromUrl URL this repository is mirrored from.
+ * @param branches list of branch objects with url, name, and isHead keys.
+ * @param? moreBranchesUrl URL to show more branches, if necessary.
+ * @param tags list of tag objects with url and name keys.
+ * @param? moreTagsUrl URL to show more branches, if necessary.
+ * @param hasLog whether a log should be shown for HEAD.
+ * @param? readmeHtml optional rendered README.md contents.
+ */
+{template .repositoryIndex}
+{if $readmeHtml}
+ {call .header data="all"}
+ {param title: $repositoryName /}
+ {param repositoryName: null /}
+ {param menuEntries: $menuEntries /}
+ {param customVariant: $customVariant /}
+ {param breadcrumbs: $breadcrumbs /}
+ {param css: [gitiles.DOC_CSS_URL] /}
+ {/call}
+{else}
+ {call .header}
+ {param title: $repositoryName /}
+ {param repositoryName: null /}
+ {param menuEntries: $menuEntries /}
+ {param customVariant: $customVariant /}
+ {param breadcrumbs: $breadcrumbs /}
+ {/call}
+{/if}
+
+{if $description}
+ <h2 class="RepoDescription">{$description}</h2>
+{/if}
+
+{if $mirroredFromUrl}
+ <div class="RepoMirroredFrom">
+ {msg desc="Informational text describing source of repository"}
+ Mirrored from <a href="{$mirroredFromUrl}">{$mirroredFromUrl}</a>
+ {/msg}
+ </div>
+{/if}
+
+<div class="CloneRepo">
+ <div class="CloneRepo-title">Clone this repo:</div>
+ <input type="text" class="u-monospace CloneRepo-command"
+ onclick="this.focus();if(this.selectionStart==this.selectionEnd){lb}this.select(){rb}"
+ readonly="readonly" value="git clone {$cloneUrl}">
+</div>
+
+{if $hasLog and (length($branches) or length($tags))}
+ <div class="RepoShortlog">
+ <div class="RepoShortlog-refs">
+ {call .branches_ data="all" /}
+ {call .tags_ data="all" /}
+ </div>
+ <div class="RepoShortlog-log">
+ {call .streamingPlaceholder /}
+ {if $readmeHtml}
+ <div class="doc RepoIndexDoc">{$readmeHtml}</div>
+ {/if}
+ </div>
+ </div>
+
+{elseif $hasLog}
+ {call .streamingPlaceholder /}
+{elseif length($branches) or length($tags)}
+ {call .branches_ data="all" /}
+ {call .tags_ data="all" /}
+{/if}
+
+{call .footer}
+ {param customVariant: $customVariant /}
+{/call}
+{/template}
+
+/**
+ * List of branches.
+ *
+ * @param? branches list of branch objects with url and name keys.
+ * @param? moreBranchesUrl URL to show more branches, if necessary.
+ */
+{template .branches_ visibility="private"}
+ {if length($branches)}
+ {call .refList}
+ {param type: 'Branches' /}
+ {param refs: $branches /}
+ {/call}
+ {if $moreBranchesUrl}
+ <a href="{$moreBranchesUrl}">{msg desc="link to view more branches"}More...{/msg}</a>
+ {/if}
+ {/if}
+{/template}
+
+/**
+ * List of tags.
+ *
+ * @param? tags list of branch objects with url and name keys.
+ * @param? moreTagsUrl URL to show more tags, if necessary.
+ */
+{template .tags_ visibility="private"}
+ {if length($tags)}
+ {call .refList}
+ {param type: 'Tags' /}
+ {param refs: $tags /}
+ {/call}
+ {if $moreTagsUrl}
+ <a href="{$moreTagsUrl}">{msg desc="link to view more tags"}More...{/msg}</a>
+ {/if}
+ {/if}
+{/template}
diff --git a/resources/com/google/gitiles/templates/RevisionDetail.soy b/resources/com/google/gitiles/templates/RevisionDetail.soy
new file mode 100644
index 0000000..2bfabe0
--- /dev/null
+++ b/resources/com/google/gitiles/templates/RevisionDetail.soy
@@ -0,0 +1,65 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// 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.
+{namespace gitiles autoescape="strict"}
+
+/**
+ * Detail page about a single revision.
+ *
+ * @param title human-readable revision name.
+ * @param repositoryName name of this repository.
+ * @param? menuEntries menu entries.
+ * @param? customVariant variant name for styling.
+ * @param breadcrumbs breadcrumbs for this page.
+ * @param? hasBlob set to true if the revision or its peeled value is a blob.
+ * @param? hasReadme set to true if the treeDetail has readmeHtml.
+ * @param objects list of objects encountered when peeling this object. Each
+ * object has a "type" key with one of the
+ * org.eclipse.jgit.lib.Contants.TYPE_* constant strings, and a "data" key
+ * with an object whose keys correspond to the appropriate object detail
+ * template from ObjectDetail.soy.
+ */
+{template .revisionDetail}
+{if $hasBlob}
+ {call .header data="all"}
+ {param css: [gitiles.PRETTIFY_CSS_URL] /}
+ {/call}
+{elseif $hasReadme}
+ {call .header data="all"}
+ {param css: [gitiles.DOC_CSS_URL, gitiles.PRETTIFY_CSS_URL] /}
+ {/call}
+{else}
+ {call .header data="all" /}
+{/if}
+
+{foreach $object in $objects}
+ {switch $object.type}
+ {case 'commit'}
+ {call .commitDetail data="$object.data" /}
+ {case 'tree'}
+ {call .treeDetail data="$object.data" /}
+ {case 'blob'}
+ {call .blobDetail data="$object.data" /}
+ {case 'tag'}
+ {call .tagDetail data="$object.data" /}
+ {default}
+ <div class="error">
+ {msg desc="Error message for an unknown object type"}Object has unknown type.{/msg}
+ </div>
+ {/switch}
+{/foreach}
+
+{call .footer}
+ {param customVariant: $customVariant /}
+{/call}
+{/template}
diff --git a/resources/web.xml b/resources/web.xml
new file mode 100644
index 0000000..bffacb5
--- /dev/null
+++ b/resources/web.xml
@@ -0,0 +1,40 @@
+<!DOCTYPE web-app PUBLIC
+ "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+ "http://java.sun.com/dtd/web-app_2_3.dtd" >
+<!--
+ Copyright 2012 Google Inc. All Rights Reserved.
+
+ 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.
+-->
+<web-app>
+ <display-name>Gitiles</display-name>
+
+ <servlet>
+ <servlet-name>gitiles</servlet-name>
+ <servlet-class>com.google.gitiles.GitilesServlet</servlet-class>
+ <init-param>
+ <param-name>configPath</param-name>
+ <param-value>gitiles.config</param-value>
+ </init-param>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>default</servlet-name>
+ <url-pattern>/+static/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>gitiles</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+</web-app>