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