\r
http://www.jcraft.com/jsch\r
\r
+---------------------------------------------------------------------------\r
+Rome\r
+---------------------------------------------------------------------------\r
+ Rome RSS and Atom Java Utilities, released under the\r
+ Apache Software License, Version 1.1.\r
+\r
+ http://rome.dev.java.net\r
+\r
+---------------------------------------------------------------------------\r
+jdom\r
+---------------------------------------------------------------------------\r
+ jdom xml library, released under the\r
+ Apache-style Software License.\r
+\r
+ http://www.jdom.org\r
+\r
---------------------------------------------------------------------------\r
JUnit\r
---------------------------------------------------------------------------\r
# Allow dyanamic zip downloads. \r
web.allowZipDownloads = true\r
\r
+# Default number of entries to include in RSS/Atom Syndication links\r
+web.syndicationEntries = 25\r
+\r
# This is the message display above the repositories table.\r
# This can point to a file with Markdown content.\r
# Specifying "gitblit" uses the internal welcome message.\r
- Automatically generates a self-signed certificate for https communications\r
- Git-notes support\r
- Branch metrics (uses Google Charts)\r
+- HEAD and branch RSS feeds\r
- Blame annotations view\r
- Dates can optionally be displayed using the browser's reported timezone\r
- Display of Author and Committer email addresses can be disabled\r
- Gitblit may have security holes. Patches welcome. :)\r
\r
### Todo List\r
+- Custom BASIC authentication servlet or servlet filter\r
- Code documentation\r
- Unit testing\r
- Update Build.java to JGit 1.0.0, when its released\r
- [JCommander](http://jcommander.org) (Apache 2.0)\r
- [BouncyCastle](http://www.bouncycastle.org) (MIT/X11)\r
- [JSch - Java Secure Channel](http://www.jcraft.com/jsch) (BSD)\r
+- [Rome](http://rome.dev.java.net) (Apache 1.1)\r
+- [jdom](http://www.jdom.org) (Apache-style JDOM license)\r
\r
### Other Build Dependencies\r
- [Fancybox image viewer](http://fancybox.net) (MIT and GPL dual-licensed)\r
3. <pre>Key = *http.sslVerify* \r
Value = *false*</pre>\r
- Command-line Git ([Git-Config Manual Page](http://www.kernel.org/pub/software/scm/git/docs/git-config.html))\r
- <pre>git-config --global --bool --add http.sslVerify false</pre>\r
+ <pre>git config --global --bool --add http.sslVerify false</pre>\r
\r
### Cloning an Access Restricted Repository \r
- Eclipse/Egit<br/>Nothing special to configure, EGit figures out everything.\r
[jgit]: http://eclipse.org/jgit "Eclipse JGit Site"\r
[git]: http://git-scm.com "Official Git Site"\r
[mina]: http://mina.apache.org "Apache Mina"\r
-[bouncycastle]: http://bouncycastle.org "The Legion of the Bouncy Castle"\r
-[hg4j]: http://code.google.com/p/hg4j/ "hg4j"
\ No newline at end of file
+[bouncycastle]: http://bouncycastle.org "The Legion of the Bouncy Castle"
\ No newline at end of file
downloadFromApache(MavenObject.BOUNCYCASTLE, BuildType.RUNTIME);\r
downloadFromApache(MavenObject.BOUNCYCASTLE_MAIL, BuildType.RUNTIME);\r
downloadFromApache(MavenObject.JSCH, BuildType.RUNTIME);\r
+ downloadFromApache(MavenObject.ROME, BuildType.RUNTIME);\r
+ downloadFromApache(MavenObject.JDOM, BuildType.RUNTIME);\r
\r
downloadFromEclipse(MavenObject.JGIT, BuildType.RUNTIME);\r
downloadFromEclipse(MavenObject.JGIT_HTTP, BuildType.RUNTIME);\r
downloadFromApache(MavenObject.BOUNCYCASTLE, BuildType.COMPILETIME);\r
downloadFromApache(MavenObject.BOUNCYCASTLE_MAIL, BuildType.COMPILETIME);\r
downloadFromApache(MavenObject.JSCH, BuildType.COMPILETIME);\r
-\r
+ downloadFromApache(MavenObject.ROME, BuildType.COMPILETIME);\r
+ downloadFromApache(MavenObject.JDOM, BuildType.COMPILETIME);\r
+ \r
downloadFromEclipse(MavenObject.JGIT, BuildType.COMPILETIME);\r
downloadFromEclipse(MavenObject.JGIT_HTTP, BuildType.COMPILETIME);\r
\r
"1.4.0", 181000, 0, 0, "eb47e8cad2dd7f92fd7e77df1d1529cae87361f7",\r
"",\r
"");\r
+ \r
+ public static final MavenObject ROME = new MavenObject("rome", "rome", "rome",\r
+ "0.9", 208000, 196000, 407000, "dee2705dd01e79a5a96a17225f5a1ae30470bb18",\r
+ "226f851dc44fd94fe70b9c471881b71f88949cbf",\r
+ "8d7d867b97eeb3a9196c3926da550ad042941c1b");\r
+\r
+ public static final MavenObject JDOM = new MavenObject("jdom", "org/jdom", "jdom",\r
+ "1.1", 153000, 235000, 445000, "1d04c0f321ea337f3661cf7ede8f4c6f653a8fdd",\r
+ "a7ed425c4c46605b8f2bf2ee118c1609682f4f2c",\r
+ "f3df91edccba2f07a0fced70887c2f7b7836cb75");\r
\r
public final String name;\r
public final String group;\r
public static final String GIT_SERVLET_PATH = "/git/";\r
\r
public static final String ZIP_SERVLET_PATH = "/zip/";\r
+ \r
+ public static final String SYNDICATION_SERVLET_PATH = "/feed/";\r
\r
public static final String BORDER = "***********************************************************";\r
\r
}\r
\r
public static String asLink(String baseURL, String repository, String objectId, String path) {\r
- return baseURL + (baseURL.endsWith("/") ? "" : "/") + "zip?r=" + repository\r
+ if (baseURL.charAt(baseURL.length() - 1) == '/') {\r
+ baseURL = baseURL.substring(0, baseURL.length() - 1);\r
+ }\r
+ return baseURL + Constants.ZIP_SERVLET_PATH + "?r=" + repository\r
+ (path == null ? "" : ("&p=" + path))\r
+ (objectId == null ? "" : ("&h=" + objectId));\r
}\r
// Zip Servlet\r
rootContext.addServlet(DownloadZipServlet.class, Constants.ZIP_SERVLET_PATH + "*");\r
\r
+ // Syndication Servlet\r
+ rootContext.addServlet(SyndicationServlet.class, Constants.SYNDICATION_SERVLET_PATH + "*");\r
+\r
// Git Servlet\r
ServletHolder gitServlet = null;\r
String gitServletPathSpec = Constants.GIT_SERVLET_PATH + "*";\r
FileWriter writer = new FileWriter(realmFileCopy);\r
properties\r
.store(writer,\r
- "# Git:Blit realm file format: username=password,\\#permission,repository1,repository2...");\r
+ "# Gitblit realm file format: username=password,\\#permission,repository1,repository2...");\r
writer.close();\r
if (realmFileCopy.exists() && realmFileCopy.length() > 0) {\r
if (realmFile.delete()) {\r
--- /dev/null
+/*\r
+ * Copyright 2011 gitblit.com.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package com.gitblit;\r
+\r
+import java.util.List;\r
+\r
+import javax.servlet.http.HttpServlet;\r
+\r
+import org.eclipse.jgit.lib.Repository;\r
+import org.eclipse.jgit.revwalk.RevCommit;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+import com.gitblit.models.RepositoryModel;\r
+import com.gitblit.utils.JGitUtils;\r
+import com.gitblit.utils.StringUtils;\r
+import com.gitblit.utils.SyndicationUtils;\r
+\r
+public class SyndicationServlet extends HttpServlet {\r
+\r
+ private static final long serialVersionUID = 1L;\r
+\r
+ private transient Logger logger = LoggerFactory.getLogger(SyndicationServlet.class);\r
+\r
+ public static String asLink(String baseURL, String repository, String objectId, int length) {\r
+ if (baseURL.charAt(baseURL.length() - 1) == '/') {\r
+ baseURL = baseURL.substring(0, baseURL.length() - 1);\r
+ }\r
+ return baseURL + Constants.SYNDICATION_SERVLET_PATH + "?r=" + repository\r
+ + (objectId == null ? "" : ("&h=" + objectId)) + (length > 0 ? "&l=" + length : "");\r
+ }\r
+\r
+ private void processRequest(javax.servlet.http.HttpServletRequest request,\r
+ javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,\r
+ java.io.IOException {\r
+ String hostUrl = request.getRequestURL().toString();\r
+ String servlet = request.getServletPath();\r
+ hostUrl = hostUrl.substring(0, hostUrl.indexOf(servlet));\r
+ String repositoryName = request.getParameter("r");\r
+ String objectId = request.getParameter("h");\r
+ String l = request.getParameter("l");\r
+ int length = GitBlit.getInteger(Keys.web.syndicationEntries, 25);\r
+ if (StringUtils.isEmpty(objectId)) {\r
+ objectId = org.eclipse.jgit.lib.Constants.HEAD;\r
+ }\r
+ if (!StringUtils.isEmpty(l)) {\r
+ try {\r
+ length = Integer.parseInt(l);\r
+ } catch (NumberFormatException x) {\r
+ }\r
+ }\r
+ \r
+ // TODO confirm repository is accessible!!\r
+\r
+ Repository repository = GitBlit.self().getRepository(repositoryName);\r
+ RepositoryModel model = GitBlit.self().getRepositoryModel(repositoryName);\r
+ List<RevCommit> commits = JGitUtils.getRevLog(repository, objectId, 0, length);\r
+ try {\r
+ SyndicationUtils.toRSS(hostUrl, model.name + " " + objectId, model.description, model.name, commits, response.getOutputStream());\r
+ } catch (Exception e) {\r
+ logger.error("An error occurred during feed generation", e);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ protected void doPost(javax.servlet.http.HttpServletRequest request,\r
+ javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,\r
+ java.io.IOException {\r
+ processRequest(request, response);\r
+ }\r
+\r
+ @Override\r
+ protected void doGet(javax.servlet.http.HttpServletRequest request,\r
+ javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,\r
+ java.io.IOException {\r
+ processRequest(request, response);\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * Copyright 2011 gitblit.com.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package com.gitblit.utils;\r
+\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+import java.io.OutputStreamWriter;\r
+import java.text.MessageFormat;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.eclipse.jgit.revwalk.RevCommit;\r
+\r
+import com.sun.syndication.feed.synd.SyndContent;\r
+import com.sun.syndication.feed.synd.SyndContentImpl;\r
+import com.sun.syndication.feed.synd.SyndEntry;\r
+import com.sun.syndication.feed.synd.SyndEntryImpl;\r
+import com.sun.syndication.feed.synd.SyndFeed;\r
+import com.sun.syndication.feed.synd.SyndFeedImpl;\r
+import com.sun.syndication.io.FeedException;\r
+import com.sun.syndication.io.SyndFeedOutput;\r
+\r
+public class SyndicationUtils {\r
+\r
+ public static void toRSS(String hostUrl, String title, String description, String repository, List<RevCommit> commits, OutputStream os)\r
+ throws IOException, FeedException {\r
+\r
+ SyndFeed feed = new SyndFeedImpl();\r
+ feed.setFeedType("rss_1.0");\r
+ feed.setTitle(title);\r
+ feed.setLink(MessageFormat.format("{0}/summary/{1}", hostUrl, repository));\r
+ feed.setDescription(description);\r
+\r
+ List<SyndEntry> entries = new ArrayList<SyndEntry>();\r
+ for (RevCommit commit : commits) {\r
+ SyndEntry entry = new SyndEntryImpl();\r
+ entry.setTitle(commit.getShortMessage());\r
+ entry.setAuthor(commit.getAuthorIdent().getName());\r
+ entry.setLink(MessageFormat.format("{0}/commit/{1}/{2}", hostUrl, repository, commit.getName()));\r
+ entry.setPublishedDate(commit.getCommitterIdent().getWhen());\r
+\r
+ SyndContent content = new SyndContentImpl();\r
+ content.setType("text/html");\r
+ String html = StringUtils.escapeForHtml(commit.getFullMessage(), false);\r
+ content.setValue(StringUtils.breakLinesForHtml(html));\r
+ entry.setDescription(content);\r
+ entries.add(entry);\r
+ }\r
+ feed.setEntries(entries);\r
+\r
+ OutputStreamWriter writer = new OutputStreamWriter(os);\r
+ SyndFeedOutput output = new SyndFeedOutput();\r
+ output.output(feed, writer);\r
+ writer.close();\r
+ }\r
+}\r
gb.blob = blob\r
gb.commitActivityTrend = commit activity trend\r
gb.commitActivityDOW = commit activity by day of week\r
-gb.commitActivityAuthors = primary authors by commit activity
\ No newline at end of file
+gb.commitActivityAuthors = primary authors by commit activity\r
+gb.feed = feed
\ No newline at end of file
SimpleDateFormat sdf = new SimpleDateFormat("E");\r
Calendar cal = Calendar.getInstance();\r
\r
- List<Metric> sorted = new ArrayList<Metric>(7);\r
+ List<Metric> sorted = new ArrayList<Metric>();\r
int firstDayOfWeek = cal.getFirstDayOfWeek();\r
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);\r
\r
String day = sdf.format(cal.getTime());\r
for (Metric metric : list) {\r
if (metric.name.equals(day)) {\r
- sorted.add(i, metric);\r
+ sorted.add(metric);\r
list.remove(metric);\r
break;\r
}\r
<!-- page header bar --> \r
<div>\r
<!-- floating search form on right -->\r
- <form wicket:id="searchForm">\r
- <div class="search">\r
+ <div class="search">\r
+ <form wicket:id="searchForm">\r
<select wicket:id="searchType"/> \r
<input type="text" id="searchBox" wicket:id="searchBox" size="25" value=""/>\r
- </div>\r
- </form>\r
+ </form>\r
+ </div>\r
\r
<!-- page nav links -->\r
- <div class="page_nav"> \r
+ <div class="page_nav">\r
+ <a style="text-decoration: none;" wicket:id="syndication">\r
+ <img style="border:0px;vertical-align:middle;" src="/com/gitblit/wicket/resources/feed_16x16.png"></img>\r
+ </a> \r
<a wicket:id="summary"><wicket:message key="gb.summary"></wicket:message></a> | <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a> | <a wicket:id="branches"><wicket:message key="gb.branches"></wicket:message></a> | <a wicket:id="tags"><wicket:message key="gb.tags"></wicket:message></a> | <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> <span wicket:id="extra"><span wicket:id="extraSeparator"></span><span wicket:id="extraLink"></span></span>\r
</div>\r
</div>\r
import org.apache.wicket.markup.html.form.StatelessForm;\r
import org.apache.wicket.markup.html.form.TextField;\r
import org.apache.wicket.markup.html.link.BookmarkablePageLink;\r
+import org.apache.wicket.markup.html.link.ExternalLink;\r
import org.apache.wicket.markup.html.panel.Fragment;\r
import org.apache.wicket.markup.repeater.Item;\r
import org.apache.wicket.markup.repeater.data.DataView;\r
\r
import com.gitblit.GitBlit;\r
import com.gitblit.Keys;\r
+import com.gitblit.SyndicationServlet;\r
import com.gitblit.models.RepositoryModel;\r
import com.gitblit.utils.JGitUtils;\r
import com.gitblit.utils.JGitUtils.SearchType;\r
}\r
};\r
add(extrasView);\r
+ \r
+ add(new ExternalLink("syndication", SyndicationServlet.asLink(getRequest()\r
+ .getRelativePathPrefixToContextRoot(), repositoryName, null, 0)));\r
\r
// disable current page\r
disablePageLink(getPageName());\r
<!-- branch page links -->\r
<wicket:fragment wicket:id="branchPageLinks">\r
<span class="link">\r
- <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a> | <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> | <a wicket:id="metrics"><wicket:message key="gb.metrics"></wicket:message></a>\r
+ <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a> | <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> | <a wicket:id="metrics"><wicket:message key="gb.metrics"></wicket:message></a> | <a wicket:id="syndication"><wicket:message key="gb.feed"></wicket:message></a>\r
</span>\r
</wicket:fragment>\r
\r
\r
import org.apache.wicket.markup.html.basic.Label;\r
import org.apache.wicket.markup.html.link.BookmarkablePageLink;\r
+import org.apache.wicket.markup.html.link.ExternalLink;\r
import org.apache.wicket.markup.html.panel.Fragment;\r
import org.apache.wicket.markup.repeater.Item;\r
import org.apache.wicket.markup.repeater.data.DataView;\r
import org.eclipse.jgit.lib.Constants;\r
import org.eclipse.jgit.lib.Repository;\r
\r
+import com.gitblit.SyndicationServlet;\r
import com.gitblit.models.RefModel;\r
import com.gitblit.models.RepositoryModel;\r
import com.gitblit.utils.JGitUtils;\r
.newObjectParameter(model.name, entry.getName())));\r
fragment.add(new BookmarkablePageLink<Void>("metrics", MetricsPage.class,\r
WicketUtils.newObjectParameter(model.name, entry.getName())));\r
+ fragment.add(new ExternalLink("syndication", SyndicationServlet.asLink(getRequest()\r
+ .getRelativePathPrefixToContextRoot(), model.name, entry.getName(), 0)));\r
item.add(fragment);\r
} else {\r
Fragment fragment = new Fragment("branchLinks", "branchPanelLinks", this);\r
padding: 8px;\r
}\r
\r
+table.plain td {\r
+ white-space: nowrap;\r
+}\r
+\r
table.plain td.edit { \r
padding: 3px;\r
}\r