3 files renamed
6 files deleted
64 files added
234 files modified
| | |
| | | <classpathentry kind="src" path="src/test/java" output="bin/test-classes" /> |
| | | <classpathentry kind="src" path="src/test/bugtraq" output="bin/test-classes" /> |
| | | <classpathentry kind="src" path="src/main/resources" /> |
| | | <classpathentry kind="lib" path="ext/dagger-1.1.0.jar" sourcepath="ext/src/dagger-1.1.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/guice-4.0.jar" sourcepath="ext/src/guice-4.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/javax.inject-1.jar" sourcepath="ext/src/javax.inject-1.jar" /> |
| | | <classpathentry kind="lib" path="ext/dagger-compiler-1.1.0.jar" sourcepath="ext/src/dagger-compiler-1.1.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/javawriter-2.1.1.jar" sourcepath="ext/src/javawriter-2.1.1.jar" /> |
| | | <classpathentry kind="lib" path="ext/aopalliance-1.0.jar" sourcepath="ext/src/aopalliance-1.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/guava-18.0.jar" sourcepath="ext/src/guava-18.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/guice-servlet-4.0-gb2.jar" sourcepath="ext/src/guice-servlet-4.0-gb2.jar" /> |
| | | <classpathentry kind="lib" path="ext/annotations-12.0.jar" sourcepath="ext/src/annotations-12.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/log4j-1.2.17.jar" sourcepath="ext/src/log4j-1.2.17.jar" /> |
| | | <classpathentry kind="lib" path="ext/slf4j-api-1.7.5.jar" sourcepath="ext/src/slf4j-api-1.7.5.jar" /> |
| | | <classpathentry kind="lib" path="ext/slf4j-log4j12-1.7.5.jar" sourcepath="ext/src/slf4j-log4j12-1.7.5.jar" /> |
| | | <classpathentry kind="lib" path="ext/slf4j-api-1.7.12.jar" sourcepath="ext/src/slf4j-api-1.7.12.jar" /> |
| | | <classpathentry kind="lib" path="ext/slf4j-log4j12-1.7.12.jar" sourcepath="ext/src/slf4j-log4j12-1.7.12.jar" /> |
| | | <classpathentry kind="lib" path="ext/javax.mail-1.5.1.jar" sourcepath="ext/src/javax.mail-1.5.1.jar" /> |
| | | <classpathentry kind="lib" path="ext/javax.servlet-api-3.1.0.jar" sourcepath="ext/src/javax.servlet-api-3.1.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/jetty-all-9.2.3.v20140905.jar" sourcepath="ext/src/jetty-all-9.2.3.v20140905.jar" /> |
| | | <classpathentry kind="lib" path="ext/wicket-1.4.21.jar" sourcepath="ext/src/wicket-1.4.21.jar" /> |
| | | <classpathentry kind="lib" path="ext/wicket-auth-roles-1.4.21.jar" sourcepath="ext/src/wicket-auth-roles-1.4.21.jar" /> |
| | | <classpathentry kind="lib" path="ext/wicket-extensions-1.4.21.jar" sourcepath="ext/src/wicket-extensions-1.4.21.jar" /> |
| | | <classpathentry kind="lib" path="ext/lucene-core-4.6.0.jar" sourcepath="ext/src/lucene-core-4.6.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/lucene-analyzers-common-4.6.0.jar" sourcepath="ext/src/lucene-analyzers-common-4.6.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/lucene-highlighter-4.6.0.jar" sourcepath="ext/src/lucene-highlighter-4.6.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/lucene-memory-4.6.0.jar" sourcepath="ext/src/lucene-memory-4.6.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/lucene-queries-4.6.0.jar" sourcepath="ext/src/lucene-queries-4.6.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/lucene-queryparser-4.6.0.jar" sourcepath="ext/src/lucene-queryparser-4.6.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/lucene-sandbox-4.6.0.jar" sourcepath="ext/src/lucene-sandbox-4.6.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/jetty-all-9.2.13.v20150730.jar" sourcepath="ext/src/jetty-all-9.2.13.v20150730.jar" /> |
| | | <classpathentry kind="lib" path="ext/wicket-1.4.22.jar" sourcepath="ext/src/wicket-1.4.22.jar" /> |
| | | <classpathentry kind="lib" path="ext/wicket-auth-roles-1.4.22.jar" sourcepath="ext/src/wicket-auth-roles-1.4.22.jar" /> |
| | | <classpathentry kind="lib" path="ext/wicket-extensions-1.4.22.jar" sourcepath="ext/src/wicket-extensions-1.4.22.jar" /> |
| | | <classpathentry kind="lib" path="ext/lucene-core-4.10.4.jar" sourcepath="ext/src/lucene-core-4.10.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/lucene-analyzers-common-4.10.4.jar" sourcepath="ext/src/lucene-analyzers-common-4.10.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/lucene-highlighter-4.10.4.jar" sourcepath="ext/src/lucene-highlighter-4.10.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/lucene-memory-4.10.4.jar" sourcepath="ext/src/lucene-memory-4.10.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/lucene-queries-4.10.4.jar" sourcepath="ext/src/lucene-queries-4.10.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/lucene-queryparser-4.10.4.jar" sourcepath="ext/src/lucene-queryparser-4.10.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/lucene-sandbox-4.10.4.jar" sourcepath="ext/src/lucene-sandbox-4.10.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/jakarta-regexp-1.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/pegdown-1.4.2.jar" sourcepath="ext/src/pegdown-1.4.2.jar" /> |
| | | <classpathentry kind="lib" path="ext/parboiled-java-1.1.6.jar" sourcepath="ext/src/parboiled-java-1.1.6.jar" /> |
| | | <classpathentry kind="lib" path="ext/parboiled-core-1.1.6.jar" sourcepath="ext/src/parboiled-core-1.1.6.jar" /> |
| | | <classpathentry kind="lib" path="ext/asm-4.1.jar" sourcepath="ext/src/asm-4.1.jar" /> |
| | | <classpathentry kind="lib" path="ext/asm-tree-4.1.jar" sourcepath="ext/src/asm-tree-4.1.jar" /> |
| | | <classpathentry kind="lib" path="ext/asm-analysis-4.1.jar" sourcepath="ext/src/asm-analysis-4.1.jar" /> |
| | | <classpathentry kind="lib" path="ext/asm-util-4.1.jar" sourcepath="ext/src/asm-util-4.1.jar" /> |
| | | <classpathentry kind="lib" path="ext/pegdown-1.5.0.jar" sourcepath="ext/src/pegdown-1.5.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/parboiled-java-1.1.7.jar" sourcepath="ext/src/parboiled-java-1.1.7.jar" /> |
| | | <classpathentry kind="lib" path="ext/parboiled-core-1.1.7.jar" sourcepath="ext/src/parboiled-core-1.1.7.jar" /> |
| | | <classpathentry kind="lib" path="ext/asm-5.0.3.jar" sourcepath="ext/src/asm-5.0.3.jar" /> |
| | | <classpathentry kind="lib" path="ext/asm-tree-5.0.3.jar" sourcepath="ext/src/asm-tree-5.0.3.jar" /> |
| | | <classpathentry kind="lib" path="ext/asm-analysis-5.0.3.jar" sourcepath="ext/src/asm-analysis-5.0.3.jar" /> |
| | | <classpathentry kind="lib" path="ext/asm-util-5.0.3.jar" sourcepath="ext/src/asm-util-5.0.3.jar" /> |
| | | <classpathentry kind="lib" path="ext/wikitext-core-1.4.jar" sourcepath="ext/src/wikitext-core-1.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/twiki-core-1.4.jar" sourcepath="ext/src/twiki-core-1.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/textile-core-1.4.jar" sourcepath="ext/src/textile-core-1.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/tracwiki-core-1.4.jar" sourcepath="ext/src/tracwiki-core-1.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/mediawiki-core-1.4.jar" sourcepath="ext/src/mediawiki-core-1.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/confluence-core-1.4.jar" sourcepath="ext/src/confluence-core-1.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/org.eclipse.jgit-3.5.1.201410131835-r.jar" sourcepath="ext/src/org.eclipse.jgit-3.5.1.201410131835-r.jar" /> |
| | | <classpathentry kind="lib" path="ext/jsch-0.1.50.jar" sourcepath="ext/src/jsch-0.1.50.jar" /> |
| | | <classpathentry kind="lib" path="ext/org.eclipse.jgit-4.1.1.201511131810-r.jar" sourcepath="ext/src/org.eclipse.jgit-4.1.1.201511131810-r.jar" /> |
| | | <classpathentry kind="lib" path="ext/jsch-0.1.53.jar" sourcepath="ext/src/jsch-0.1.53.jar" /> |
| | | <classpathentry kind="lib" path="ext/JavaEWAH-0.7.9.jar" sourcepath="ext/src/JavaEWAH-0.7.9.jar" /> |
| | | <classpathentry kind="lib" path="ext/httpclient-4.1.3.jar" sourcepath="ext/src/httpclient-4.1.3.jar" /> |
| | | <classpathentry kind="lib" path="ext/httpcore-4.1.4.jar" sourcepath="ext/src/httpcore-4.1.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/commons-logging-1.1.1.jar" sourcepath="ext/src/commons-logging-1.1.1.jar" /> |
| | | <classpathentry kind="lib" path="ext/httpclient-4.3.6.jar" sourcepath="ext/src/httpclient-4.3.6.jar" /> |
| | | <classpathentry kind="lib" path="ext/httpcore-4.3.3.jar" sourcepath="ext/src/httpcore-4.3.3.jar" /> |
| | | <classpathentry kind="lib" path="ext/commons-logging-1.1.3.jar" sourcepath="ext/src/commons-logging-1.1.3.jar" /> |
| | | <classpathentry kind="lib" path="ext/commons-codec-1.7.jar" sourcepath="ext/src/commons-codec-1.7.jar" /> |
| | | <classpathentry kind="lib" path="ext/org.eclipse.jgit.http.server-3.5.1.201410131835-r.jar" sourcepath="ext/src/org.eclipse.jgit.http.server-3.5.1.201410131835-r.jar" /> |
| | | <classpathentry kind="lib" path="ext/bcprov-jdk15on-1.49.jar" sourcepath="ext/src/bcprov-jdk15on-1.49.jar" /> |
| | | <classpathentry kind="lib" path="ext/bcmail-jdk15on-1.49.jar" sourcepath="ext/src/bcmail-jdk15on-1.49.jar" /> |
| | | <classpathentry kind="lib" path="ext/bcpkix-jdk15on-1.49.jar" sourcepath="ext/src/bcpkix-jdk15on-1.49.jar" /> |
| | | <classpathentry kind="lib" path="ext/sshd-core-0.12.0.jar" sourcepath="ext/src/sshd-core-0.12.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/mina-core-2.0.7.jar" sourcepath="ext/src/mina-core-2.0.7.jar" /> |
| | | <classpathentry kind="lib" path="ext/org.eclipse.jdt.annotation-1.1.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/org.eclipse.jgit.http.server-4.1.1.201511131810-r.jar" sourcepath="ext/src/org.eclipse.jgit.http.server-4.1.1.201511131810-r.jar" /> |
| | | <classpathentry kind="lib" path="ext/bcprov-jdk15on-1.52.jar" sourcepath="ext/src/bcprov-jdk15on-1.52.jar" /> |
| | | <classpathentry kind="lib" path="ext/bcmail-jdk15on-1.52.jar" sourcepath="ext/src/bcmail-jdk15on-1.52.jar" /> |
| | | <classpathentry kind="lib" path="ext/bcpkix-jdk15on-1.52.jar" sourcepath="ext/src/bcpkix-jdk15on-1.52.jar" /> |
| | | <classpathentry kind="lib" path="ext/sshd-core-1.0.0.jar" sourcepath="ext/src/sshd-core-1.0.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/mina-core-2.0.9.jar" sourcepath="ext/src/mina-core-2.0.9.jar" /> |
| | | <classpathentry kind="lib" path="ext/rome-0.9.jar" sourcepath="ext/src/rome-0.9.jar" /> |
| | | <classpathentry kind="lib" path="ext/jdom-1.0.jar" sourcepath="ext/src/jdom-1.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/gson-1.7.2.jar" sourcepath="ext/src/gson-1.7.2.jar" /> |
| | | <classpathentry kind="lib" path="ext/groovy-all-1.8.8.jar" sourcepath="ext/src/groovy-all-1.8.8.jar" /> |
| | | <classpathentry kind="lib" path="ext/unboundid-ldapsdk-2.3.0.jar" sourcepath="ext/src/unboundid-ldapsdk-2.3.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/gson-2.3.1.jar" sourcepath="ext/src/gson-2.3.1.jar" /> |
| | | <classpathentry kind="lib" path="ext/groovy-all-2.4.4.jar" sourcepath="ext/src/groovy-all-2.4.4.jar" /> |
| | | <classpathentry kind="lib" path="ext/unboundid-ldapsdk-2.3.8.jar" sourcepath="ext/src/unboundid-ldapsdk-2.3.8.jar" /> |
| | | <classpathentry kind="lib" path="ext/ivy-2.2.0.jar" sourcepath="ext/src/ivy-2.2.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/jcalendar-1.3.2.jar" /> |
| | | <classpathentry kind="lib" path="ext/commons-compress-1.4.1.jar" sourcepath="ext/src/commons-compress-1.4.1.jar" /> |
| | |
| | | <classpathentry kind="lib" path="ext/force-partner-api-24.0.0.jar" sourcepath="ext/src/force-partner-api-24.0.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/force-wsc-24.0.0.jar" sourcepath="ext/src/force-wsc-24.0.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/js-1.7R2.jar" sourcepath="ext/src/js-1.7R2.jar" /> |
| | | <classpathentry kind="lib" path="ext/freemarker-2.3.19.jar" sourcepath="ext/src/freemarker-2.3.19.jar" /> |
| | | <classpathentry kind="lib" path="ext/waffle-jna-1.5.jar" sourcepath="ext/src/waffle-jna-1.5.jar" /> |
| | | <classpathentry kind="lib" path="ext/platform-3.5.0.jar" sourcepath="ext/src/platform-3.5.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/jna-3.5.0.jar" sourcepath="ext/src/jna-3.5.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/guava-13.0.1.jar" sourcepath="ext/src/guava-13.0.1.jar" /> |
| | | <classpathentry kind="lib" path="ext/libpam4j-1.7.jar" sourcepath="ext/src/libpam4j-1.7.jar" /> |
| | | <classpathentry kind="lib" path="ext/args4j-2.0.26.jar" sourcepath="ext/src/args4j-2.0.26.jar" /> |
| | | <classpathentry kind="lib" path="ext/jedis-2.3.1.jar" sourcepath="ext/src/jedis-2.3.1.jar" /> |
| | | <classpathentry kind="lib" path="ext/freemarker-2.3.22.jar" sourcepath="ext/src/freemarker-2.3.22.jar" /> |
| | | <classpathentry kind="lib" path="ext/waffle-jna-1.7.3.jar" sourcepath="ext/src/waffle-jna-1.7.3.jar" /> |
| | | <classpathentry kind="lib" path="ext/jna-4.1.0.jar" sourcepath="ext/src/jna-4.1.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/jna-platform-4.1.0.jar" sourcepath="ext/src/jna-platform-4.1.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/libpam4j-1.8.jar" sourcepath="ext/src/libpam4j-1.8.jar" /> |
| | | <classpathentry kind="lib" path="ext/args4j-2.0.29.jar" sourcepath="ext/src/args4j-2.0.29.jar" /> |
| | | <classpathentry kind="lib" path="ext/jedis-2.6.2.jar" sourcepath="ext/src/jedis-2.6.2.jar" /> |
| | | <classpathentry kind="lib" path="ext/commons-pool2-2.0.jar" sourcepath="ext/src/commons-pool2-2.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/pf4j-0.8.0.jar" sourcepath="ext/src/pf4j-0.8.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/pf4j-0.9.0.jar" sourcepath="ext/src/pf4j-0.9.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/tika-core-1.5.jar" sourcepath="ext/src/tika-core-1.5.jar" /> |
| | | <classpathentry kind="lib" path="ext/jsoup-1.7.3.jar" sourcepath="ext/src/jsoup-1.7.3.jar" /> |
| | | <classpathentry kind="lib" path="ext/junit-4.11.jar" sourcepath="ext/src/junit-4.11.jar" /> |
| | |
| | | <classpathentry kind="lib" path="ext/json-20080701.jar" sourcepath="ext/src/json-20080701.jar" /> |
| | | <classpathentry kind="lib" path="ext/selenium-api-2.28.0.jar" sourcepath="ext/src/selenium-api-2.28.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/commons-exec-1.1.jar" sourcepath="ext/src/commons-exec-1.1.jar" /> |
| | | <classpathentry kind="lib" path="ext/platform-3.4.0.jar" sourcepath="ext/src/platform-3.4.0.jar" /> |
| | | <classpathentry kind="lib" path="ext/mockito-core-1.10.19.jar" sourcepath="ext/src/mockito-core-1.10.19.jar" /> |
| | | <classpathentry kind="lib" path="ext/objenesis-2.1.jar" sourcepath="ext/src/objenesis-2.1.jar" /> |
| | | <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER" /> |
| | | <classpathentry kind="src" path="src/main/dagger"> |
| | | <attributes> |
| | |
| | | tags |
| | | /temp |
| | | /lib |
| | | /ext |
| | | /build |
| | | /site |
| | | /git |
| | | /lucene |
| | | /build.properties |
| | | /federation.properties |
| | | /mailtest.properties |
| | |
| | | /**/.idea |
| | | /**/init.lua |
| | | /**/session |
| | | /nbproject/private |
| | |
| | | [submodule "src/main/distrib/data/gitignore"] |
| | | path = src/main/distrib/data/gitignore |
| | | url = https://github.com/github/gitignore.git |
| | | [submodule "src/main/js/prosemirror"] |
| | | path = src/main/js/prosemirror |
| | | url = https://github.com/ProseMirror/prosemirror.git |
New file |
| | |
| | | James Moger <james.moger@gitblit.com> James Moger <james.moger@gmail.com> |
| | | James Moger <james.moger@gitblit.com> James Moger <jmoger@vas.com> |
| | |
| | | [[src/site/setup_viewer.mkd]]
|
| | | [[src/site/administration.mkd]]
|
| | | [[src/site/setup_scaling.mkd]]
|
| | | [[src/site/setup_filestore.mkd]]
|
| | |
|
| | |
|
| | | ### Gitblit Tickets
|
| | |
|
| | |
| | | Apache License 2.0 |
| | | |
| | | https://github.com/decebals/pf4j |
| | | |
| | | --------------------------------------------------------------------------- |
| | | google-guice |
| | | --------------------------------------------------------------------------- |
| | | google-guice, release under the |
| | | Apache License 2.0 |
| | | |
| | | https://code.google.com/p/google-guice |
| | | |
| | |
| | | | Source | Location |
|
| | | | ------------- |--------------------------------------------------------|
|
| | | | Documentation | [Gitblit website](http://gitblit.com) |
|
| | | | Issues | [Google Code](http://code.google.com/p/gitblit) |
|
| | | | Forums | [Google Groups](https://groups.google.com/forum/#!forum/gitblit) |
|
| | | | Twitter | @gitblit or @jamesmoger |
|
| | | | Google+ | +gitblit or +jamesmoger |
|
| | |
| | | Contributing
|
| | | ------------
|
| | |
|
| | | GitHub pull requests or Gitblit Tickets are preferred. Any contributions must be distributed under the terms of the [Apache Software Foundation license, version 2.0](http://www.apache.org/licenses/LICENSE-2.0).
|
| | |
|
| | | **Workflow**
|
| | |
|
| | | Gitblit practices the [git-flow][1] branching model.
|
| | |
|
| | | - **master** is the current stable release + fixes accumulated since release.
|
| | | - **develop** is the integration branch for the next major release.
|
| | | - **ticket/N** are feature or hotfix branches to be merged to **master** or **develop**, as appropriate.
|
| | |
|
| | | **Feature Development**
|
| | |
|
| | | Development of new features is mostly done using [Gitblit Tickets][2] hosted at [dev.gitblit.com][3]. This allows continuous dogfooding and improvement of Gitbit's own issue-tracker and pull-request mechanism.
|
| | |
|
| | | **Release Planning**
|
| | |
|
| | | Release planning is mostly done using Gitblit Milestones and Gitblit Tickets hosted at [dev.gitblit.com][3].
|
| | |
|
| | | **Releasing**
|
| | |
|
| | | When Gitblit is preparing for a release, a **release-{milestone}** branch will be created, tested, & fixed until it is ready to be merged to **master** and tagged as the next major release. After the release is tagged, the **release-{milestone}** branch will also be merged back into **develop** and then the release branch will be removed.
|
| | | GitHub pull requests are preferred. Any contributions must be distributed under the terms of the [Apache Software Foundation license, version 2.0](http://www.apache.org/licenses/LICENSE-2.0).
|
| | |
|
| | | Building Gitblit
|
| | | ----------------
|
| | |
| | | 1. If you are running Ant from an ANSI-capable console, consider setting the `MX_COLOR` environment variable before executing Ant.<pre>set MX_COLOR=true</pre>
|
| | | 2. The build script will honor your Maven proxy settings. If you need to fine-tune this, please review the [settings.moxie](http://gitblit.github.io/moxie/settings.html) documentation.
|
| | |
|
| | | [1]: http://nvie.com/posts/a-successful-git-branching-model
|
| | | [2]: http://gitblit.com/tickets_overview.html
|
| | | [3]: https://dev.gitblit.com
|
| | |
| | | # |
| | | |
| | | # Specify minimum Moxie version required to build |
| | | requires: 0.9.3 |
| | | requires: 0.9.4 |
| | | |
| | | # Project Metadata |
| | | name: Gitblit |
| | | description: pure Java Git solution |
| | | groupId: com.gitblit |
| | | artifactId: gitblit |
| | | version: 1.6.3-SNAPSHOT |
| | | version: 1.7.2-SNAPSHOT |
| | | inceptionYear: 2011 |
| | | |
| | | # Current stable release |
| | | releaseVersion: 1.6.2 |
| | | releaseDate: 2014-10-28 |
| | | releaseVersion: 1.7.1 |
| | | releaseDate: 2015-11-23 |
| | | |
| | | # Project urls |
| | | url: 'http://gitblit.com' |
| | | issuesUrl: 'http://code.google.com/p/gitblit/issues/list' |
| | | issuesUrl: 'https://github.com/gitblit/gitblit' |
| | | socialNetworkUrl: 'https://plus.google.com/114464678392593421684' |
| | | forumUrl: 'http://groups.google.com/group/gitblit' |
| | | mavenUrl: 'http://gitblit.github.io/gitblit-maven' |
| | |
| | | sourceDirectories: |
| | | - compile 'src/main/java' |
| | | - compile 'src/main/bugtraq' |
| | | - compile 'src/main/dagger' apt |
| | | - compile 'src/main/gen' apt |
| | | - test 'src/test/java' |
| | | - test 'src/test/bugtraq' |
| | | # Moxie supports one site-scoped directory for mx:doc |
| | |
| | | registeredRepositories: |
| | | - { id: eclipse, url: 'http://repo.eclipse.org/content/groups/releases' } |
| | | - { id: eclipse-snapshots, url: 'http://repo.eclipse.org/content/groups/snapshots' } |
| | | - { id: atlassian-contrib, url: 'https://maven.atlassian.com/content/repositories/atlassian-3rdparty' } |
| | | - { id: gitblit, url: 'http://gitblit.github.io/gitblit-maven' } |
| | | |
| | | # Source all dependencies from the following repositories in the specified order |
| | | repositories: central, eclipse-snapshots, eclipse, atlassian-contrib |
| | | repositories: central, eclipse-snapshots, eclipse, gitblit |
| | | |
| | | # Convenience properties for dependencies |
| | | properties: { |
| | | jetty.version : 9.2.9.v20150224 |
| | | wicket.version : 1.4.21 |
| | | lucene.version : 4.6.0 |
| | | jgit.version : 3.5.1.201410131835-r |
| | | groovy.version : 1.8.8 |
| | | bouncycastle.version : 1.49 |
| | | jetty.version : 9.2.13.v20150730 |
| | | slf4j.version : 1.7.12 |
| | | wicket.version : 1.4.22 |
| | | lucene.version : 4.10.4 |
| | | jgit.version : 4.1.1.201511131810-r |
| | | groovy.version : 2.4.4 |
| | | bouncycastle.version : 1.52 |
| | | selenium.version : 2.28.0 |
| | | wikitext.version : 1.4 |
| | | sshd.version: 0.12.0 |
| | | mina.version: 2.0.7 |
| | | sshd.version: 1.0.0 |
| | | mina.version: 2.0.9 |
| | | guice.version : 4.0 |
| | | # Gitblit maintains a fork of guice-servlet |
| | | guice-servlet.version : 4.0-gb2 |
| | | } |
| | | |
| | | # Dependencies |
| | |
| | | # |
| | | |
| | | dependencies: |
| | | # Dagger dependency injection library (annotation processor) |
| | | - compile 'com.squareup.dagger:dagger:1.1.0' :war apt |
| | | - compile 'com.squareup.dagger:dagger-compiler:1.1.0' :war optional apt |
| | | # Standard dependencies |
| | | - compile 'com.google.inject:guice:${guice.version}' :war :fedclient |
| | | - compile 'com.google.inject.extensions:guice-servlet:${guice-servlet.version}' :war |
| | | - compile 'com.google.guava:guava:18.0' :war :fedclient |
| | | - compile 'com.intellij:annotations:12.0' :war |
| | | - compile 'log4j:log4j:1.2.17' :war :fedclient :authority |
| | | - compile 'org.slf4j:slf4j-api:1.7.5' :war :fedclient :authority |
| | | - compile 'org.slf4j:slf4j-log4j12:1.7.5' :war :fedclient :authority |
| | | - compile 'com.sun.mail:javax.mail:1.5.1' :war :authority |
| | | - compile 'log4j:log4j:1.2.17' :war :fedclient :manager |
| | | - compile 'org.slf4j:slf4j-api:${slf4j.version}' :war :fedclient :manager |
| | | - compile 'org.slf4j:slf4j-log4j12:${slf4j.version}' :war :fedclient :manager |
| | | - compile 'com.sun.mail:javax.mail:1.5.1' :war |
| | | - compile 'javax.servlet:javax.servlet-api:3.1.0' :fedclient |
| | | - compile 'org.eclipse.jetty.aggregate:jetty-all:${jetty.version}' @jar |
| | | - compile 'org.apache.wicket:wicket:${wicket.version}' :war !org.mockito |
| | |
| | | - compile 'org.apache.lucene:lucene-highlighter:${lucene.version}' :war :fedclient |
| | | - compile 'org.apache.lucene:lucene-memory:${lucene.version}' :war :fedclient |
| | | - compile 'org.apache.lucene:lucene-queryparser:${lucene.version}' :war :fedclient |
| | | - compile 'org.pegdown:pegdown:1.4.2' :war |
| | | - compile 'org.pegdown:pegdown:1.5.0' :war |
| | | - compile 'org.fusesource.wikitext:wikitext-core:${wikitext.version}' :war |
| | | - compile 'org.fusesource.wikitext:twiki-core:${wikitext.version}' :war |
| | | - compile 'org.fusesource.wikitext:textile-core:${wikitext.version}' :war |
| | | - compile 'org.fusesource.wikitext:tracwiki-core:${wikitext.version}' :war |
| | | - compile 'org.fusesource.wikitext:mediawiki-core:${wikitext.version}' :war |
| | | - compile 'org.fusesource.wikitext:confluence-core:${wikitext.version}' :war |
| | | - compile 'org.eclipse.jgit:org.eclipse.jgit:${jgit.version}' :war :fedclient :manager :authority !junit |
| | | - compile 'org.eclipse.jgit:org.eclipse.jgit.http.server:${jgit.version}' :war :manager :authority !junit |
| | | - compile 'org.bouncycastle:bcprov-jdk15on:${bouncycastle.version}' :war :authority |
| | | - compile 'org.bouncycastle:bcmail-jdk15on:${bouncycastle.version}' :war :authority |
| | | - compile 'org.bouncycastle:bcpkix-jdk15on:${bouncycastle.version}' :war :authority |
| | | - compile 'org.eclipse.jgit:org.eclipse.jgit:${jgit.version}' :war :fedclient :manager !junit |
| | | - compile 'org.eclipse.jgit:org.eclipse.jgit.http.server:${jgit.version}' :war :manager !junit |
| | | - compile 'org.bouncycastle:bcprov-jdk15on:${bouncycastle.version}' :war |
| | | - compile 'org.bouncycastle:bcmail-jdk15on:${bouncycastle.version}' :war |
| | | - compile 'org.bouncycastle:bcpkix-jdk15on:${bouncycastle.version}' :war |
| | | - compile 'org.apache.sshd:sshd-core:${sshd.version}' :war !org.easymock |
| | | - compile 'org.apache.mina:mina-core:${mina.version}' :war !org.easymock |
| | | - compile 'rome:rome:0.9' :war :manager :api |
| | | - compile 'com.google.code.gson:gson:1.7.2' :war :fedclient :manager :api |
| | | - compile 'com.google.code.gson:gson:2.3.1' :war :fedclient :manager :api |
| | | - compile 'org.codehaus.groovy:groovy-all:${groovy.version}' :war |
| | | - compile 'com.unboundid:unboundid-ldapsdk:2.3.0' :war |
| | | - compile 'com.unboundid:unboundid-ldapsdk:2.3.8' :war |
| | | - compile 'org.apache.ivy:ivy:2.2.0' :war |
| | | - compile 'com.toedter:jcalendar:1.3.2' :authority |
| | | - compile 'org.apache.commons:commons-compress:1.4.1' :war |
| | | - compile 'commons-io:commons-io:2.2' :war |
| | | - compile 'com.force.api:force-partner-api:24.0.0' :war |
| | | - compile 'org.freemarker:freemarker:2.3.19' :war |
| | | - compile 'com.github.dblock.waffle:waffle-jna:1.5' :war |
| | | - compile 'org.kohsuke:libpam4j:1.7' :war |
| | | - compile 'args4j:args4j:2.0.26' :war :fedclient :authority |
| | | - compile 'org.freemarker:freemarker:2.3.22' :war |
| | | - compile 'com.github.dblock.waffle:waffle-jna:1.7.3' :war |
| | | - compile 'org.kohsuke:libpam4j:1.8' :war |
| | | - compile 'args4j:args4j:2.0.29' :war :fedclient |
| | | - compile 'commons-codec:commons-codec:1.7' :war |
| | | - compile 'redis.clients:jedis:2.3.1' :war |
| | | - compile 'ro.fortsoft.pf4j:pf4j:0.8.0' :war |
| | | - compile 'redis.clients:jedis:2.6.2' :war |
| | | - compile 'ro.fortsoft.pf4j:pf4j:0.9.0' :war |
| | | - compile 'org.apache.tika:tika-core:1.5' :war |
| | | - compile 'org.jsoup:jsoup:1.7.3' :war |
| | | - test 'junit' |
| | |
| | | - test 'org.seleniumhq.selenium:selenium-java:${selenium.version}' @jar |
| | | - test 'org.seleniumhq.selenium:selenium-support:${selenium.version}' @jar |
| | | - test 'org.seleniumhq.selenium:selenium-firefox-driver:${selenium.version}' |
| | | - test 'org.mockito:mockito-core:1.10.19' |
| | | # Dependencies with the "build" scope are retrieved |
| | | # and injected into the Ant runtime classpath |
| | | - build 'jacoco' |
| | |
| | | documentation @ http://gitblit.github.io/moxie
|
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| | | -->
|
| | | <property name="moxie.version" value="0.9.3" />
|
| | | <property name="moxie.version" value="0.9.4" />
|
| | | <property name="moxie.url" value="http://gitblit.github.io/moxie/maven" />
|
| | | <property name="moxie.jar" value="moxie-toolkit-${moxie.version}.jar" />
|
| | | <property name="moxie.dir" value="${user.home}/.moxie" />
|
| | |
| | | <mx:init verbose="no" mxroot="${moxie.dir}" />
|
| | |
|
| | | <!-- Set Ant project properties -->
|
| | | <property name="distribution.zipfile" value="gitblit-${project.version}.zip" />
|
| | | <property name="distribution.tgzfile" value="gitblit-${project.version}.tar.gz" />
|
| | | <property name="distribution.warfile" value="gitblit-${project.version}.war" />
|
| | | <property name="release.name" value="gitblit-${project.version}"/>
|
| | | <property name="distribution.zipfile" value="${release.name}.zip" />
|
| | | <property name="distribution.tgzfile" value="${release.name}.tar.gz" />
|
| | | <property name="distribution.warfile" value="${release.name}.war" />
|
| | | <property name="fedclient.zipfile" value="fedclient-${project.version}.zip" />
|
| | | <property name="manager.zipfile" value="manager-${project.version}.zip" />
|
| | | <property name="authority.zipfile" value="authority-${project.version}.zip" />
|
| | |
| | | <fileset dir="${project.distrib.dir}/data" />
|
| | | </copy>
|
| | |
|
| | | <!-- copy gitblit.properties to the source directory.
|
| | | this file is only used for parsing setting descriptions. -->
|
| | | <copy tofile="${project.src.dir}/reference.properties" overwrite="true"
|
| | | file="${project.distrib.dir}/data/gitblit.properties" />
|
| | | <!-- copy defaults.properties to the source directory -->
|
| | | <copy tofile="${project.src.dir}/defaults.properties" overwrite="true"
|
| | | file="${project.distrib.dir}/data/defaults.properties" />
|
| | |
|
| | | <!-- copy clientapps.json to the source directory.
|
| | | this file is only used if a local file is not provided. -->
|
| | |
| | | -->
|
| | | <target name="compile" depends="setup" description="compiles Gitblit from source">
|
| | |
|
| | | <!-- Generate the Keys class from the properties file -->
|
| | | <mx:keys propertiesfile="${project.distrib.dir}/data/gitblit.properties"
|
| | | <!-- Generate the Keys class from the defaults.properties file -->
|
| | | <mx:keys propertiesfile="${project.distrib.dir}/data/defaults.properties"
|
| | | outputclass="com.gitblit.Keys"
|
| | | todir="${project.src.dir}" />
|
| | |
|
| | |
| | |
|
| | | <echo>Building Gitblit GO ${project.version}</echo>
|
| | |
|
| | | <local name="go.dir" />
|
| | | <property name="go.dir" value="${project.outputDirectory}/go" /> |
| | | <local name="go.dir"/>
|
| | | <property name="go.dir" value="${project.outputDirectory}/go"/>
|
| | | <delete dir="${go.dir}" />
|
| | | |
| | | <local name="go.release.dir" />
|
| | | <property name="go.release.dir" value="${go.dir}/${release.name}" /> |
| | |
|
| | | <local name="webinf" />
|
| | | <property name="webinf" value="${project.compileOutputDirectory}/WEB-INF" />
|
| | |
|
| | | <prepareDataDirectory toDir="${go.dir}/data" />
|
| | | <prepareDataDirectory toDir="${go.release.dir}/data" />
|
| | |
|
| | | <!-- Copy the web.xml from the prototype web.xml -->
|
| | | <copy todir="${webinf}" overwrite="true">
|
| | |
| | | </copy>
|
| | |
|
| | | <!-- Build jar -->
|
| | | <mx:jar destfile="${go.dir}/gitblit.jar" includeresources="true">
|
| | | <mx:jar destfile="${go.release.dir}/gitblit.jar" includeresources="true">
|
| | | <mainclass name="com.gitblit.GitBlitServer" />
|
| | | <launcher paths="ext" />
|
| | | </mx:jar>
|
| | |
|
| | | <!-- Generate the docs for the GO build -->
|
| | | <generateDocs toDir="${go.dir}/docs" />
|
| | | |
| | | <generateDocs toDir="${go.release.dir}/docs" />
|
| | |
|
| | | <!-- Create GO Windows Zip deployment -->
|
| | | <mx:zip basedir="${go.dir}">
|
| | | <!-- LICENSE and NOTICE -->
|
| | | <fileset dir="${basedir}" >
|
| | | <zipfileset dir="${basedir}" prefix="${release.name}">
|
| | | <include name="LICENSE" />
|
| | | <include name="NOTICE" />
|
| | | </fileset>
|
| | | </zipfileset>
|
| | | <!-- Windows distrib files -->
|
| | | <zipfileset dir="${project.distrib.dir}/win" />
|
| | | <zipfileset dir="${project.distrib.dir}/win" prefix="${release.name}"/>
|
| | | <!-- Gitblit Authority data -->
|
| | | <zipfileset dir="${project.distrib.dir}/data/certs" prefix="data/certs" />
|
| | | <zipfileset dir="${project.distrib.dir}/data/certs" prefix="${release.name}/data/certs" />
|
| | |
|
| | | <!-- include all dependencies -->
|
| | | <dependencies prefix="ext" />
|
| | | <dependencies prefix="${release.name}/ext" />
|
| | | </mx:zip>
|
| | |
|
| | | <!-- Create GO Linux/OSX tar.gz deployment -->
|
| | | <mx:tar basedir="${go.dir}" longfile="gnu" compression="gzip">
|
| | | <!-- LICENSE and NOTICE -->
|
| | | <fileset dir="${basedir}" >
|
| | | <zipfileset dir="${basedir}" prefix="${release.name}">
|
| | | <include name="LICENSE" />
|
| | | <include name="NOTICE" />
|
| | | </fileset>
|
| | | </zipfileset>
|
| | | <!-- Linux/OSX distrib files -->
|
| | | <tarfileset dir="${project.distrib.dir}/linux" filemode="755" />
|
| | | <tarfileset dir="${project.distrib.dir}/linux" filemode="755" prefix="${release.name}"/>
|
| | | <!-- Gitblit Authority data -->
|
| | | <zipfileset dir="${project.distrib.dir}/data/certs" prefix="data/certs" />
|
| | | <zipfileset dir="${project.distrib.dir}/data/certs" prefix="${release.name}/data/certs" />
|
| | | <!-- include all dependencies -->
|
| | | <dependencies prefix="ext" />
|
| | | <dependencies prefix="${release.name}/ext" />
|
| | | </mx:tar>
|
| | |
|
| | | </target>
|
| | |
| | | </mx:webxml>
|
| | |
|
| | | <!-- Gitblit jar -->
|
| | | <mx:jar destfile="${webinf}/lib/gitblit.jar" includeresources="false" />
|
| | | <mx:jar destfile="${webinf}/lib/gitblit-${project.version}.jar" includeresources="false" />
|
| | |
|
| | | <!-- Build the WAR file -->
|
| | | <mx:zip basedir="${war.dir}" destfile="${project.targetDirectory}/${distribution.warfile}" compress="true" >
|
| | |
| | | classes, exclude any classes in classpath jars -->
|
| | | <mx:genjar tag="" includeresources="false" excludeClasspathJars="true"
|
| | | destfile="${project.targetDirectory}/fedclient.jar"
|
| | | excludes="**/.class,**/*.java, **/Thumbs.db, **/*.mkd, com/gitblit/wicket/**">
|
| | | excludes="**/.class, **/*.java, **/Thumbs.db, **/*.mkd, **/*.md, **/*.css, com/gitblit/wicket/**">
|
| | | <mainclass name="com.gitblit.FederationClient" />
|
| | | <class name="com.gitblit.Keys" />
|
| | | <launcher paths="ext" />
|
| | |
| | | <!-- generate jar by traversing the class hierarchy of the specified
|
| | | classes, exclude any classes in classpath jars -->
|
| | | <mx:genjar tag="" includeResources="false" excludeClasspathJars="true"
|
| | | destfile="${project.targetDirectory}/manager.jar">
|
| | | destfile="${project.targetDirectory}/manager.jar"
|
| | | excludes="**/.class, **/*.java, **/Thumbs.db, **/*.mkd, **/*.md, **/*.css, com/gitblit/wicket/**">
|
| | | <resource file="${project.src.dir}/com/gitblit/client/splash.png" />
|
| | | <resource file="${project.resources.dir}/gitblt-favicon.png" />
|
| | | <resource file="${project.resources.dir}/gitweb-favicon.png" />
|
| | |
| | |
|
| | | <!-- Build API Library jar -->
|
| | | <mx:genjar tag="" includeResources="false" excludeClasspathJars="true"
|
| | | destfile="${project.targetDirectory}/gbapi-${project.version}.jar">
|
| | | destfile="${project.targetDirectory}/gbapi-${project.version}.jar"
|
| | | excludes="**/.class, **/*.java, **/Thumbs.db, **/*.mkd, **/*.md, **/*.css, com/gitblit/wicket/**">
|
| | | <mainclass name="com.gitblit.client.GitblitClient" />
|
| | | <class name="com.gitblit.Keys" />
|
| | | <class name="com.gitblit.client.GitblitClient" />
|
| | | <class name="com.gitblit.models.FederationModel" />
|
| | | <class name="com.gitblit.models.FederationProposal" />
|
| | | <class name="com.gitblit.models.FederationSet" />
|
| | |
| | | </zip>
|
| | |
|
| | | <!-- Build API JavaDoc jar -->
|
| | | <mx:javadoc destdir="${javadoc.dir}" redirect="true">
|
| | | <mx:javadoc destdir="${javadoc.dir}" charset="utf-8" encoding="utf-8" docencoding="utf-8" redirect="true">
|
| | | <fileset dir="${project.src.dir}" defaultexcludes="yes">
|
| | | <include name="com/gitblit/Constants.java"/>
|
| | | <include name="com/gitblit/GitBlitException.java"/>
|
| | |
| | | <page name="bugtraq" src="setup_bugtraq.mkd" />
|
| | | <page name="mirrors" src="setup_mirrors.mkd" />
|
| | | <page name="scaling" src="setup_scaling.mkd" />
|
| | | <page name="fail2ban" src="setup_fail2ban.mkd" />
|
| | | <page name="filestore (Git LFS)" src="setup_filestore.mkd" />
|
| | | <divider />
|
| | | <page name="Gitblit as a viewer" src="setup_viewer.mkd" />
|
| | | </menu>
|
| | |
| | | <page name="release history" out="releases.html">
|
| | | <template src="releasehistory.ftl" data="${releaselog}" />
|
| | | </page>
|
| | | <divider />
|
| | | <page name="roadmap" src="roadmap.mkd" /> |
| | | </menu>
|
| | |
|
| | | <menu name="downloads">
|
| | |
| | | <link name="Github" src="${project.scmUrl}" />
|
| | | <link name="Issues" src="${project.issuesUrl}" />
|
| | | <link name="Discussion" src="${project.forumUrl}" />
|
| | | <link name="Google+" src="${project.socialNetworkUrl}" />
|
| | | <link name="Twitter" src="https://twitter.com/gitblit" />
|
| | | <link name="Ohloh" src="http://www.ohloh.net/p/gitblit" />
|
| | | <divider />
|
| | |
| | | <link name="Gitblit SSH and Plugin Management asciicast" src="https://asciinema.org/a/9342" />
|
| | | <link name="GitMinutes #29: James Moger on Gitblit" src="http://episodes.gitminutes.com/2014/05/gitminutes-29-james-moger-on-gitblit.html" />
|
| | | <divider />
|
| | | <link name="+JamesMoger" src="https://plus.google.com/+JamesMoger" />
|
| | | <link name="@JamesMoger" src="https://twitter.com/JamesMoger" />
|
| | | </menu>
|
| | | <divider />
|
| | |
| | |
|
| | | <replace token="%GCURL%" value="${gc.url}" />
|
| | |
|
| | | <properties token="%PROPERTIES%" file="${project.distrib.dir}/data/gitblit.properties" />
|
| | | <properties token="%PROPERTIES%" file="${project.distrib.dir}/data/defaults.properties" />
|
| | |
|
| | | <regex searchPattern="\b(issue)(\s*[#]?|-){0,1}(\d+)\b" replacePattern="<a href='http://code.google.com/p/gitblit/issues/detail?id=$3'>issue $3</a>" />
|
| | | <regex searchPattern="\b(pr|pull request)(\s*[#]?|-){0,1}(\d+)\b" replacePattern="<a href='https://github.com/gitblit/gitblit/pull/$3'>pull request #$3</a>" />
|
| | |
| | | <link name="Github" src="${project.scmUrl}" />
|
| | | <link name="Issues" src="${project.issuesUrl}" />
|
| | | <link name="Discussion" src="${project.forumUrl}" />
|
| | | <link name="Google+" src="${project.socialNetworkUrl}" />
|
| | | <link name="Ohloh" src="http://www.ohloh.net/p/gitblit" />
|
| | | </menu>
|
| | | </structure>
|
| | |
|
| | | <properties token="%PROPERTIES%" file="${project.distrib.dir}/data/gitblit.properties" />
|
| | | <properties token="%PROPERTIES%" file="${project.distrib.dir}/data/defaults.properties" />
|
| | |
|
| | | <regex searchPattern="\b(issue)(\s*[#]?|-){0,1}(\d+)\b" replacePattern="<a href='http://code.google.com/p/gitblit/issues/detail?id=$3'>issue $3</a>" />
|
| | | <regex searchPattern="\b(pr|pull request)(\s*[#]?|-){0,1}(\d+)\b" replacePattern="<a href='https://github.com/gitblit/gitblit/pull/$3'>pull request #$3</a>" />
|
| | |
| | | <fileset dir="${project.distrib.dir}/data">
|
| | | <include name="users.conf" />
|
| | | <include name="projects.conf" />
|
| | | <include name="defaults.properties" />
|
| | | <include name="gitblit.properties" />
|
| | | </fileset>
|
| | | </copy>
|
| | |
| | | <mx:install />
|
| | | </target>
|
| | |
|
| | | |
| | | <!--
|
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| | | Build Gitblit UI via npm
|
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | -->
|
| | | <target name="buildUI" description="Build Gitblit UI via npm">
|
| | | <exec executable="npm" dir="src/main/js/" failonerror="true" vmlauncher="false" searchpath="true" >
|
| | | <arg value="install" />
|
| | | </exec>
|
| | | |
| | | <exec executable="npm" dir="src/main/js/" failonerror="true" vmlauncher="false" searchpath="true" >
|
| | | <arg value="run" />
|
| | | <arg value="build" />
|
| | | </exec>
|
| | | </target>
|
| | | |
| | | </project>
|
| | |
| | | <content url="file://$MODULE_DIR$"> |
| | | <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> |
| | | <sourceFolder url="file://$MODULE_DIR$/src/main/bugtraq" isTestSource="false" /> |
| | | <sourceFolder url="file://$MODULE_DIR$/src/main/dagger" isTestSource="false" /> |
| | | <sourceFolder url="file://$MODULE_DIR$/src/main/gen" isTestSource="false" /> |
| | | <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" /> |
| | | <sourceFolder url="file://$MODULE_DIR$/src/test/bugtraq" isTestSource="true" /> |
| | | <sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" /> |
| | | </content> |
| | | <orderEntry type="sourceFolder" forTests="false" /> |
| | | <orderEntry type="module-library"> |
| | | <library name="dagger-1.1.0.jar"> |
| | | <library name="guice-4.0.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/dagger-1.1.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/guice-4.0.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/dagger-1.1.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/guice-4.0.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="dagger-compiler-1.1.0.jar"> |
| | | <library name="aopalliance-1.0.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/dagger-compiler-1.1.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/aopalliance-1.0.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/dagger-compiler-1.1.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/aopalliance-1.0.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="javawriter-2.1.1.jar"> |
| | | <library name="guava-18.0.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/javawriter-2.1.1.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/guava-18.0.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/javawriter-2.1.1.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/guava-18.0.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="guice-servlet-4.0-gb2.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/guice-servlet-4.0-gb2.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/guice-servlet-4.0-gb2.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="slf4j-api-1.7.5.jar"> |
| | | <library name="slf4j-api-1.7.12.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/slf4j-api-1.7.5.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/slf4j-api-1.7.12.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/slf4j-api-1.7.5.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/slf4j-api-1.7.12.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="slf4j-log4j12-1.7.5.jar"> |
| | | <library name="slf4j-log4j12-1.7.12.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/slf4j-log4j12-1.7.5.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/slf4j-log4j12-1.7.12.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/slf4j-log4j12-1.7.5.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/slf4j-log4j12-1.7.12.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="jetty-all-9.2.3.v20140905.jar"> |
| | | <library name="jetty-all-9.2.13.v20150730.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/jetty-all-9.2.3.v20140905.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/jetty-all-9.2.13.v20150730.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/jetty-all-9.2.3.v20140905.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/jetty-all-9.2.13.v20150730.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="wicket-1.4.21.jar"> |
| | | <library name="wicket-1.4.22.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/wicket-1.4.21.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/wicket-1.4.22.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/wicket-1.4.21.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/wicket-1.4.22.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="wicket-auth-roles-1.4.21.jar"> |
| | | <library name="wicket-auth-roles-1.4.22.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/wicket-auth-roles-1.4.21.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/wicket-auth-roles-1.4.22.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/wicket-auth-roles-1.4.21.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/wicket-auth-roles-1.4.22.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="wicket-extensions-1.4.21.jar"> |
| | | <library name="wicket-extensions-1.4.22.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/wicket-extensions-1.4.21.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/wicket-extensions-1.4.22.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/wicket-extensions-1.4.21.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/wicket-extensions-1.4.22.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="lucene-core-4.6.0.jar"> |
| | | <library name="lucene-core-4.10.4.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/lucene-core-4.6.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/lucene-core-4.10.4.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/lucene-core-4.6.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/lucene-core-4.10.4.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="lucene-analyzers-common-4.6.0.jar"> |
| | | <library name="lucene-analyzers-common-4.10.4.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/lucene-analyzers-common-4.6.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/lucene-analyzers-common-4.10.4.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/lucene-analyzers-common-4.6.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/lucene-analyzers-common-4.10.4.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="lucene-highlighter-4.6.0.jar"> |
| | | <library name="lucene-highlighter-4.10.4.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/lucene-highlighter-4.6.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/lucene-highlighter-4.10.4.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/lucene-highlighter-4.6.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/lucene-highlighter-4.10.4.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="lucene-memory-4.6.0.jar"> |
| | | <library name="lucene-memory-4.10.4.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/lucene-memory-4.6.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/lucene-memory-4.10.4.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/lucene-memory-4.6.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/lucene-memory-4.10.4.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="lucene-queries-4.6.0.jar"> |
| | | <library name="lucene-queries-4.10.4.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/lucene-queries-4.6.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/lucene-queries-4.10.4.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/lucene-queries-4.6.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/lucene-queries-4.10.4.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="lucene-queryparser-4.6.0.jar"> |
| | | <library name="lucene-queryparser-4.10.4.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/lucene-queryparser-4.6.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/lucene-queryparser-4.10.4.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/lucene-queryparser-4.6.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/lucene-queryparser-4.10.4.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="lucene-sandbox-4.6.0.jar"> |
| | | <library name="lucene-sandbox-4.10.4.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/lucene-sandbox-4.6.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/lucene-sandbox-4.10.4.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/lucene-sandbox-4.6.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/lucene-sandbox-4.10.4.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="pegdown-1.4.2.jar"> |
| | | <library name="pegdown-1.5.0.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/pegdown-1.4.2.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/pegdown-1.5.0.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/pegdown-1.4.2.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/pegdown-1.5.0.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="parboiled-java-1.1.6.jar"> |
| | | <library name="parboiled-java-1.1.7.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/parboiled-java-1.1.6.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/parboiled-java-1.1.7.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/parboiled-java-1.1.6.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/parboiled-java-1.1.7.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="parboiled-core-1.1.6.jar"> |
| | | <library name="parboiled-core-1.1.7.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/parboiled-core-1.1.6.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/parboiled-core-1.1.7.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/parboiled-core-1.1.6.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/parboiled-core-1.1.7.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="asm-4.1.jar"> |
| | | <library name="asm-5.0.3.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/asm-4.1.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/asm-5.0.3.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/asm-4.1.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/asm-5.0.3.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="asm-tree-4.1.jar"> |
| | | <library name="asm-tree-5.0.3.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/asm-tree-4.1.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/asm-tree-5.0.3.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/asm-tree-4.1.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/asm-tree-5.0.3.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="asm-analysis-4.1.jar"> |
| | | <library name="asm-analysis-5.0.3.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/asm-analysis-4.1.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/asm-analysis-5.0.3.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/asm-analysis-4.1.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/asm-analysis-5.0.3.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="asm-util-4.1.jar"> |
| | | <library name="asm-util-5.0.3.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/asm-util-4.1.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/asm-util-5.0.3.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/asm-util-4.1.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/asm-util-5.0.3.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="org.eclipse.jgit-3.5.1.201410131835-r.jar"> |
| | | <library name="org.eclipse.jgit-4.1.1.201511131810-r.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/org.eclipse.jgit-3.5.1.201410131835-r.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/org.eclipse.jgit-4.1.1.201511131810-r.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/org.eclipse.jgit-3.5.1.201410131835-r.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/org.eclipse.jgit-4.1.1.201511131810-r.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="jsch-0.1.50.jar"> |
| | | <library name="jsch-0.1.53.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/jsch-0.1.50.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/jsch-0.1.53.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/jsch-0.1.50.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/jsch-0.1.53.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="httpclient-4.1.3.jar"> |
| | | <library name="httpclient-4.3.6.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/httpclient-4.1.3.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/httpclient-4.3.6.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/httpclient-4.1.3.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/httpclient-4.3.6.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="httpcore-4.1.4.jar"> |
| | | <library name="httpcore-4.3.3.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/httpcore-4.1.4.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/httpcore-4.3.3.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/httpcore-4.1.4.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/httpcore-4.3.3.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="commons-logging-1.1.1.jar"> |
| | | <library name="commons-logging-1.1.3.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/commons-logging-1.1.1.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/commons-logging-1.1.3.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/commons-logging-1.1.1.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/commons-logging-1.1.3.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="org.eclipse.jgit.http.server-3.5.1.201410131835-r.jar"> |
| | | <library name="org.eclipse.jdt.annotation-1.1.0.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/org.eclipse.jgit.http.server-3.5.1.201410131835-r.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/org.eclipse.jdt.annotation-1.1.0.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES /> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="org.eclipse.jgit.http.server-4.1.1.201511131810-r.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/org.eclipse.jgit.http.server-4.1.1.201511131810-r.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/org.eclipse.jgit.http.server-3.5.1.201410131835-r.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/org.eclipse.jgit.http.server-4.1.1.201511131810-r.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="bcprov-jdk15on-1.49.jar"> |
| | | <library name="bcprov-jdk15on-1.52.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/bcprov-jdk15on-1.49.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/bcprov-jdk15on-1.52.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/bcprov-jdk15on-1.49.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/bcprov-jdk15on-1.52.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="bcmail-jdk15on-1.49.jar"> |
| | | <library name="bcmail-jdk15on-1.52.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/bcmail-jdk15on-1.49.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/bcmail-jdk15on-1.52.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/bcmail-jdk15on-1.49.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/bcmail-jdk15on-1.52.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="bcpkix-jdk15on-1.49.jar"> |
| | | <library name="bcpkix-jdk15on-1.52.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/bcpkix-jdk15on-1.49.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/bcpkix-jdk15on-1.52.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/bcpkix-jdk15on-1.49.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/bcpkix-jdk15on-1.52.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="sshd-core-0.12.0.jar"> |
| | | <library name="sshd-core-1.0.0.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/sshd-core-0.12.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/sshd-core-1.0.0.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/sshd-core-0.12.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/sshd-core-1.0.0.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="mina-core-2.0.7.jar"> |
| | | <library name="mina-core-2.0.9.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/mina-core-2.0.7.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/mina-core-2.0.9.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/mina-core-2.0.7.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/mina-core-2.0.9.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="gson-1.7.2.jar"> |
| | | <library name="gson-2.3.1.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/gson-1.7.2.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/gson-2.3.1.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/gson-1.7.2.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/gson-2.3.1.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="groovy-all-1.8.8.jar"> |
| | | <library name="groovy-all-2.4.4.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/groovy-all-1.8.8.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/groovy-all-2.4.4.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/groovy-all-1.8.8.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/groovy-all-2.4.4.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="unboundid-ldapsdk-2.3.0.jar"> |
| | | <library name="unboundid-ldapsdk-2.3.8.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/unboundid-ldapsdk-2.3.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/unboundid-ldapsdk-2.3.8.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/unboundid-ldapsdk-2.3.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/unboundid-ldapsdk-2.3.8.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="freemarker-2.3.19.jar"> |
| | | <library name="freemarker-2.3.22.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/freemarker-2.3.19.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/freemarker-2.3.22.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/freemarker-2.3.19.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/freemarker-2.3.22.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="waffle-jna-1.5.jar"> |
| | | <library name="waffle-jna-1.7.3.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/waffle-jna-1.5.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/waffle-jna-1.7.3.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/waffle-jna-1.5.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/waffle-jna-1.7.3.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="platform-3.5.0.jar"> |
| | | <library name="jna-4.1.0.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/platform-3.5.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/jna-4.1.0.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/platform-3.5.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/jna-4.1.0.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="jna-3.5.0.jar"> |
| | | <library name="jna-platform-4.1.0.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/jna-3.5.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/jna-platform-4.1.0.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/jna-3.5.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/jna-platform-4.1.0.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="guava-13.0.1.jar"> |
| | | <library name="libpam4j-1.8.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/guava-13.0.1.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/libpam4j-1.8.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/guava-13.0.1.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/libpam4j-1.8.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="libpam4j-1.7.jar"> |
| | | <library name="args4j-2.0.29.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/libpam4j-1.7.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/args4j-2.0.29.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/libpam4j-1.7.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/args4j-2.0.29.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="args4j-2.0.26.jar"> |
| | | <library name="jedis-2.6.2.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/args4j-2.0.26.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/jedis-2.6.2.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/args4j-2.0.26.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="jedis-2.3.1.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/jedis-2.3.1.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/jedis-2.3.1.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/jedis-2.6.2.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library"> |
| | | <library name="pf4j-0.8.0.jar"> |
| | | <library name="pf4j-0.9.0.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/pf4j-0.8.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/pf4j-0.9.0.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/pf4j-0.8.0.jar!/" /> |
| | | <root url="jar://$MODULE_DIR$/ext/src/pf4j-0.9.0.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library" scope="TEST"> |
| | | <library name="platform-3.4.0.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/platform-3.4.0.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/platform-3.4.0.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library" scope="TEST"> |
| | | <library name="mockito-core-1.10.19.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/mockito-core-1.10.19.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/mockito-core-1.10.19.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="module-library" scope="TEST"> |
| | | <library name="objenesis-2.1.jar"> |
| | | <CLASSES> |
| | | <root url="jar://$MODULE_DIR$/ext/objenesis-2.1.jar!/" /> |
| | | </CLASSES> |
| | | <JAVADOC /> |
| | | <SOURCES> |
| | | <root url="jar://$MODULE_DIR$/ext/src/objenesis-2.1.jar!/" /> |
| | | </SOURCES> |
| | | </library> |
| | | </orderEntry> |
| | | <orderEntry type="inheritedJdk" /> |
| | | </component> |
| | | </module> |
| | |
| | | # merge to master |
| | | echo "" |
| | | echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" |
| | | echo "Merging release ${project.version} to master" |
| | | echo "Updating build identifier for next release cycle" |
| | | echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" |
| | | echo "" |
| | | git checkout master |
| | | git merge --no-ff -m "Merge release ${project.version}" ${project.commitId} |
| | | ant nextPointReleaseCycle |
| | | |
| | | # merge to develop |
| | | echo "" |
| | | echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" |
| | | echo "Merging release ${project.version} to develop" |
| | | echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" |
| | | echo "" |
| | | git checkout develop |
| | | git merge --no-ff -m "Merge release ${project.version}" ${project.commitId} |
| | | ant nextMinorReleaseCycle |
| | | |
| | | # push Maven repository to origin |
| | | echo "" |
| | |
| | | # push project branches |
| | | echo "" |
| | | echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" |
| | | echo "Pushing master, develop, gh-pages, and tag ${project.tag}" |
| | | echo "Pushing master, gh-pages, and tag ${project.tag}" |
| | | echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" |
| | | echo "" |
| | | git push origin master develop gh-pages ${project.tag} |
| | | git push origin master gh-pages ${project.tag} |
| | |
| | | # |
| | | # ${project.version} release |
| | | # |
| | | r27: { |
| | | r29: { |
| | | title: ${project.name} ${project.version} released |
| | | id: ${project.version} |
| | | date: ${project.buildDate} |
| | |
| | | html: ~ |
| | | text: ~ |
| | | security: ~ |
| | | fixes: ~ |
| | | changes: ~ |
| | | additions: ~ |
| | | dependencyChanges: ~ |
| | | contributors: ~ |
| | | fixes: |
| | | - Fix exception when viewing a ticket with a patchset where the integration branch does not exist (issue-521, ticket-212) |
| | | - Fix exception when deleting a repository using the FileTicketService (issue-522, ticket-213) |
| | | - Do not inject team repository permissions as explicit user permissions when editing a user (issue-462, ticket-214) |
| | | - Whitelist the target link attribute in the XSS filter (ticket-216) |
| | | - Strip line breaks from pasted SSH keys (ticket-245) |
| | | - Fix project sorting (pr-287) |
| | | - Fix Lucene indexing of tags (pr-291) |
| | | - Prevent session fixation for external authentication (pr-908) |
| | | - Encode email subject as UTF-8 (pr-929) |
| | | - Do not automatically trim passwords (pr-932) |
| | | - Fix nested repository detection in raw servlet (pr-950, pr-957) |
| | | - Raw servlet will now assume text/plain for dot files (pr-956) |
| | | changes: |
| | | - Replaced Dagger with Guice (ticket-80) |
| | | - Use release name as root directory in Gitblit GO artifacts (ticket-109) |
| | | - Split gitblit.properties into gitblit.properties & defaults.properties (ticket-110) |
| | | - Show team type in teams page (pr-217, ticket-168) |
| | | - Relocate the repository Delete button (ticket-225) |
| | | - Improve diff performance by gracefully limiting large diffs (pr-226) |
| | | - Add granular settings to disable display of git transport urls (pr-274) |
| | | - Use author date to be consistent with other tools (pr-919) |
| | | additions: |
| | | - Add GitHub Octicons (ticket-106) |
| | | - Support for chain-loading properties files (ticket-110) |
| | | - Add Priority & Severity fields for tickets (pr-220, ticket-157) |
| | | - Add Maintenance ticket type (pr-223, ticket-206) |
| | | - Add commitdiff option to ignore whitespace (ticket-233) |
| | | - Add configurable tab length for blob views (ticket-253) |
| | | - Implement image diffs (pr-229) |
| | | - Add support for configurable HTTP proxy host/port in PluginManager (pr-235) |
| | | - Implement collapsed empty folder navigation (pr-241) |
| | | - Implement hashing to detect usermodel changes and reduce users.conf file I/O (pr-246) |
| | | - Add support for Kerberos5/GSS authentication to SSH (pr-254) |
| | | - Allow extraction of additional user metadata in request headers when using external or container authentication (pr-255) |
| | | - Allow custom host & port specification for advertised SSH urls (pr-268) |
| | | - Improve logging for fail2ban usage (pr-296) |
| | | - Initial implementation of Git-LFS (pr-921) |
| | | - Add "all" repositories parameter to Search page (pr-935) |
| | | dependencyChanges: |
| | | - Guice 4.0 (ticket-80, ticket-219) |
| | | - SLF4j 1.7.12 |
| | | - gson 2.3.1 |
| | | - Freemarker 2.3.22 |
| | | - Lucene 4.10.0 (ticket-159) |
| | | - SSHD 1.0.0 |
| | | - JGit 4.1.1 |
| | | - Groovy 2.4.4 |
| | | - Wicket 1.4.22 |
| | | - BouncyCastle 1.52 |
| | | - Pegdown 1.5.0 |
| | | - Jetty 9.2.13 |
| | | settings: |
| | | - { name: web.displayUserPanel, defaultValue: 'true' } |
| | | - { name: web.tabLength, defaultValue: 4 } |
| | | - { name: web.avatarClass, defaultValue: '' } |
| | | - { name: web.showHttpServletUrls, defaultValue: 'true' } |
| | | - { name: web.showGitDaemonUrls, defaultValue: 'true' } |
| | | - { name: web.showSshDaemonUrls, defaultValue: 'true' } |
| | | - { name: web.advertiseAccessPermissionForOtherUrls, defaultValue: 'false' } |
| | | - { name: web.maxDiffLinesPerFile, defaultValue: '4000' } |
| | | - { name: web.maxDiffLines, defaultValue: '20000' } |
| | | - { name: ssh.advertisedHost, defaultValue: '' } |
| | | - { name: ssh.advertisedPort, defaultValue: '' } |
| | | - { name: git.sshWithKrb5, defaultValue: '' } |
| | | - { name: git.sshKrb5Keytab, defaultValue: '' } |
| | | - { name: git.sshKrb5ServicePrincipalName, defaultValue: '' } |
| | | - { name: git.sshKrb5StripDomain, defaultValue: 'true' } |
| | | - { name: filestore.storageFolder, defaultValue: '${baseFolder}/lfs' } |
| | | - { name: filestore.maxUploadSize, defaultValue: '-1' } |
| | | - { name: plugins.httpProxyHost, defaultValue: '' } |
| | | - { name: plugins.httpProxyPort, defaultValue: '' } |
| | | - { name: plugins.httpProxyAuthorization, defaultValue: '' } |
| | | - { name: realm.container.autoAccounts.displayName, defaultValue: '' } |
| | | - { name: realm.container.autoAccounts.emailAddress, defaultValue: '' } |
| | | - { name: realm.container.autoAccounts.locale, defaultValue: '' } |
| | | - { name: realm.container.autoAccounts.adminRole, defaultValue: '' } |
| | | |
| | | contributors: |
| | | - James Moger |
| | | - David Ostrovsky |
| | | - Alex Lewis |
| | | - Florian Zschocke |
| | | - Paul Martin |
| | | - razzard |
| | | - Alexander Zabluda |
| | | - Marcin Cieślak |
| | | - Rainer W |
| | | - Vitaliy Filippov |
| | | - willyann |
| | | - enrico204 |
| | | - mrjoel |
| | | - Fabrice Bacchella |
| | | - Milos Cubrilo |
| | | - Thomas Wolf |
| | | - Morten Bøgeskov |
| | | - Steven Oliver |
| | | - Dariusz Bywalec |
| | | - Jan Å mucr |
| | | -paladox |
| | | } |
| | | |
| | | # |
| | | # 1.7.1 release |
| | | # |
| | | r28: { |
| | | title: Gitblit 1.7.1 released |
| | | id: 1.7.1 |
| | | date: 2015-11-23 |
| | | note: This is a re-build of 1.7.0 with a fix for failed WAR deployments. |
| | | html: ~ |
| | | text: ~ |
| | | security: ~ |
| | | fixes: |
| | | - Fix exception when viewing a ticket with a patchset where the integration branch does not exist (issue-521, ticket-212) |
| | | - Fix exception when deleting a repository using the FileTicketService (issue-522, ticket-213) |
| | | - Do not inject team repository permissions as explicit user permissions when editing a user (issue-462, ticket-214) |
| | | - Whitelist the target link attribute in the XSS filter (ticket-216) |
| | | - Strip line breaks from pasted SSH keys (ticket-245) |
| | | - Fix project sorting (pr-287) |
| | | - Fix Lucene indexing of tags (pr-291) |
| | | - Prevent session fixation for external authentication (pr-908) |
| | | - Encode email subject as UTF-8 (pr-929) |
| | | - Do not automatically trim passwords (pr-932) |
| | | - Fix nested repository detection in raw servlet (pr-950) |
| | | changes: |
| | | - Replaced Dagger with Guice (ticket-80) |
| | | - Use release name as root directory in Gitblit GO artifacts (ticket-109) |
| | | - Split gitblit.properties into gitblit.properties & defaults.properties (ticket-110) |
| | | - Show team type in teams page (pr-217, ticket-168) |
| | | - Relocate the repository Delete button (ticket-225) |
| | | - Improve diff performance by gracefully limiting large diffs (pr-226) |
| | | - Add granular settings to disable display of git transport urls (pr-274) |
| | | - Use author date to be consistent with other tools (pr-919) |
| | | additions: |
| | | - Add GitHub Octicons (ticket-106) |
| | | - Support for chain-loading properties files (ticket-110) |
| | | - Add Priority & Severity fields for tickets (pr-220, ticket-157) |
| | | - Add Maintenance ticket type (pr-223, ticket-206) |
| | | - Add commitdiff option to ignore whitespace (ticket-233) |
| | | - Add configurable tab length for blob views (ticket-253) |
| | | - Implement image diffs (pr-229) |
| | | - Add support for configurable HTTP proxy host/port in PluginManager (pr-235) |
| | | - Implement collapsed empty folder navigation (pr-241) |
| | | - Implement hashing to detect usermodel changes and reduce users.conf file I/O (pr-246) |
| | | - Add support for Kerberos5/GSS authentication to SSH (pr-254) |
| | | - Allow extraction of additional user metadata in request headers when using external or container authentication (pr-255) |
| | | - Allow custom host & port specification for advertised SSH urls (pr-268) |
| | | - Improve logging for fail2ban usage (pr-296) |
| | | - Initial implementation of Git-LFS (pr-921) |
| | | - Add "all" repositories parameter to Search page (pr-935) |
| | | dependencyChanges: |
| | | - Guice 4.0 (ticket-80, ticket-219) |
| | | - SLF4j 1.7.12 |
| | | - gson 2.3.1 |
| | | - Freemarker 2.3.22 |
| | | - Lucene 4.10.0 (ticket-159) |
| | | - SSHD 1.0.0 |
| | | - JGit 4.1.1 |
| | | - Groovy 2.4.4 |
| | | - Wicket 1.4.22 |
| | | - BouncyCastle 1.52 |
| | | - Pegdown 1.5.0 |
| | | - Jetty 9.2.13 |
| | | settings: |
| | | - { name: web.displayUserPanel, defaultValue: 'true' } |
| | | - { name: web.tabLength, defaultValue: 4 } |
| | | - { name: web.avatarClass, defaultValue: '' } |
| | | - { name: web.showHttpServletUrls, defaultValue: 'true' } |
| | | - { name: web.showGitDaemonUrls, defaultValue: 'true' } |
| | | - { name: web.showSshDaemonUrls, defaultValue: 'true' } |
| | | - { name: web.advertiseAccessPermissionForOtherUrls, defaultValue: 'false' } |
| | | - { name: web.maxDiffLinesPerFile, defaultValue: '4000' } |
| | | - { name: web.maxDiffLines, defaultValue: '20000' } |
| | | - { name: ssh.advertisedHost, defaultValue: '' } |
| | | - { name: ssh.advertisedPort, defaultValue: '' } |
| | | - { name: git.sshWithKrb5, defaultValue: '' } |
| | | - { name: git.sshKrb5Keytab, defaultValue: '' } |
| | | - { name: git.sshKrb5ServicePrincipalName, defaultValue: '' } |
| | | - { name: git.sshKrb5StripDomain, defaultValue: 'true' } |
| | | - { name: filestore.storageFolder, defaultValue: '${baseFolder}/lfs' } |
| | | - { name: filestore.maxUploadSize, defaultValue: '-1' } |
| | | - { name: plugins.httpProxyHost, defaultValue: '' } |
| | | - { name: plugins.httpProxyPort, defaultValue: '' } |
| | | - { name: plugins.httpProxyAuthorization, defaultValue: '' } |
| | | - { name: realm.container.autoAccounts.displayName, defaultValue: '' } |
| | | - { name: realm.container.autoAccounts.emailAddress, defaultValue: '' } |
| | | - { name: realm.container.autoAccounts.locale, defaultValue: '' } |
| | | - { name: realm.container.autoAccounts.adminRole, defaultValue: '' } |
| | | |
| | | contributors: |
| | | - James Moger |
| | | - David Ostrovsky |
| | | - Alex Lewis |
| | | - Florian Zschocke |
| | | - Paul Martin |
| | | - razzard |
| | | - Alexander Zabluda |
| | | - Marcin Cieślak |
| | | - Rainer W |
| | | - Vitaliy Filippov |
| | | - willyann |
| | | - enrico204 |
| | | - mrjoel |
| | | - Fabrice Bacchella |
| | | - Milos Cubrilo |
| | | - Thomas Wolf |
| | | - Morten Bøgeskov |
| | | - Steven Oliver |
| | | - Dariusz Bywalec |
| | | - Jan Å mucr |
| | | } |
| | | |
| | | # |
| | | # 1.7.0 release |
| | | # |
| | | r27: { |
| | | title: Gitblit 1.7.0 released |
| | | id: 1.7.0 |
| | | date: 2015-11-22 |
| | | note: ~ |
| | | html: ~ |
| | | text: ~ |
| | | security: ~ |
| | | fixes: |
| | | - Fix exception when viewing a ticket with a patchset where the integration branch does not exist (issue-521, ticket-212) |
| | | - Fix exception when deleting a repository using the FileTicketService (issue-522, ticket-213) |
| | | - Do not inject team repository permissions as explicit user permissions when editing a user (issue-462, ticket-214) |
| | | - Whitelist the target link attribute in the XSS filter (ticket-216) |
| | | - Strip line breaks from pasted SSH keys (ticket-245) |
| | | - Fix project sorting (pr-287) |
| | | - Fix Lucene indexing of tags (pr-291) |
| | | - Prevent session fixation for external authentication (pr-908) |
| | | - Encode email subject as UTF-8 (pr-929) |
| | | - Do not automatically trim passwords (pr-932) |
| | | - Fix nested repository detection in raw servlet (pr-950) |
| | | changes: |
| | | - Replaced Dagger with Guice (ticket-80) |
| | | - Use release name as root directory in Gitblit GO artifacts (ticket-109) |
| | | - Split gitblit.properties into gitblit.properties & defaults.properties (ticket-110) |
| | | - Show team type in teams page (pr-217, ticket-168) |
| | | - Relocate the repository Delete button (ticket-225) |
| | | - Improve diff performance by gracefully limiting large diffs (pr-226) |
| | | - Add granular settings to disable display of git transport urls (pr-274) |
| | | - Use author date to be consistent with other tools (pr-919) |
| | | additions: |
| | | - Add GitHub Octicons (ticket-106) |
| | | - Support for chain-loading properties files (ticket-110) |
| | | - Add Priority & Severity fields for tickets (pr-220, ticket-157) |
| | | - Add Maintenance ticket type (pr-223, ticket-206) |
| | | - Add commitdiff option to ignore whitespace (ticket-233) |
| | | - Add configurable tab length for blob views (ticket-253) |
| | | - Implement image diffs (pr-229) |
| | | - Add support for configurable HTTP proxy host/port in PluginManager (pr-235) |
| | | - Implement collapsed empty folder navigation (pr-241) |
| | | - Implement hashing to detect usermodel changes and reduce users.conf file I/O (pr-246) |
| | | - Add support for Kerberos5/GSS authentication to SSH (pr-254) |
| | | - Allow extraction of additional user metadata in request headers when using external or container authentication (pr-255) |
| | | - Allow custom host & port specification for advertised SSH urls (pr-268) |
| | | - Improve logging for fail2ban usage (pr-296) |
| | | - Initial implementation of Git-LFS (pr-921) |
| | | - Add "all" repositories parameter to Search page (pr-935) |
| | | dependencyChanges: |
| | | - Guice 4.0 (ticket-80, ticket-219) |
| | | - SLF4j 1.7.12 |
| | | - gson 2.3.1 |
| | | - Freemarker 2.3.22 |
| | | - Lucene 4.10.0 (ticket-159) |
| | | - SSHD 1.0.0 |
| | | - JGit 4.1.1 |
| | | - Groovy 2.4.4 |
| | | - Wicket 1.4.22 |
| | | - BouncyCastle 1.52 |
| | | - Pegdown 1.5.0 |
| | | - Jetty 9.2.13 |
| | | settings: |
| | | - { name: web.displayUserPanel, defaultValue: 'true' } |
| | | - { name: web.tabLength, defaultValue: 4 } |
| | | - { name: web.avatarClass, defaultValue: '' } |
| | | - { name: web.showHttpServletUrls, defaultValue: 'true' } |
| | | - { name: web.showGitDaemonUrls, defaultValue: 'true' } |
| | | - { name: web.showSshDaemonUrls, defaultValue: 'true' } |
| | | - { name: web.advertiseAccessPermissionForOtherUrls, defaultValue: 'false' } |
| | | - { name: web.maxDiffLinesPerFile, defaultValue: '4000' } |
| | | - { name: web.maxDiffLines, defaultValue: '20000' } |
| | | - { name: ssh.advertisedHost, defaultValue: '' } |
| | | - { name: ssh.advertisedPort, defaultValue: '' } |
| | | - { name: git.sshWithKrb5, defaultValue: '' } |
| | | - { name: git.sshKrb5Keytab, defaultValue: '' } |
| | | - { name: git.sshKrb5ServicePrincipalName, defaultValue: '' } |
| | | - { name: git.sshKrb5StripDomain, defaultValue: 'true' } |
| | | - { name: filestore.storageFolder, defaultValue: '${baseFolder}/lfs' } |
| | | - { name: filestore.maxUploadSize, defaultValue: '-1' } |
| | | - { name: plugins.httpProxyHost, defaultValue: '' } |
| | | - { name: plugins.httpProxyPort, defaultValue: '' } |
| | | - { name: plugins.httpProxyAuthorization, defaultValue: '' } |
| | | - { name: realm.container.autoAccounts.displayName, defaultValue: '' } |
| | | - { name: realm.container.autoAccounts.emailAddress, defaultValue: '' } |
| | | - { name: realm.container.autoAccounts.locale, defaultValue: '' } |
| | | - { name: realm.container.autoAccounts.adminRole, defaultValue: '' } |
| | | |
| | | contributors: |
| | | - James Moger |
| | | - David Ostrovsky |
| | | - Alex Lewis |
| | | - Florian Zschocke |
| | | - Paul Martin |
| | | - razzard |
| | | - Alexander Zabluda |
| | | - Marcin Cieślak |
| | | - Rainer W |
| | | - Vitaliy Filippov |
| | | - willyann |
| | | - enrico204 |
| | | - mrjoel |
| | | - Fabrice Bacchella |
| | | - Milos Cubrilo |
| | | - Thomas Wolf |
| | | - Morten Bøgeskov |
| | | - Steven Oliver |
| | | - Dariusz Bywalec |
| | | - Jan Å mucr |
| | | } |
| | | |
| | | # |
| | |
| | | - James Moger |
| | | } |
| | | |
| | | snapshot: &r27 |
| | | release: &r26 |
| | | releases: &r[1..26] |
| | | snapshot: &r29 |
| | | release: &r28 |
| | | releases: &r[1..28] |
| | |
| | | } |
| | | finally { |
| | | rw.dispose(); |
| | | tw.release(); |
| | | tw.close(); |
| | | } |
| | | |
| | | if (content == null) { |
New file |
| | |
| | | # |
| | | # DEFAULTS.PROPERTIES |
| | | # |
| | | # The default Gitblit settings. |
| | | # |
| | | |
| | | # This settings file supports parameterization from the command-line for the |
| | | # following command-line parameters: |
| | | # |
| | | # --baseFolder ${baseFolder} SINCE 1.2.1 |
| | | # |
| | | # Settings that support ${baseFolder} parameter substitution are indicated with the |
| | | # BASEFOLDER attribute. If the --baseFolder argument is unspecified, ${baseFolder} |
| | | # and it's trailing / will be discarded from the setting value leaving a relative |
| | | # path that is equivalent to pre-1.2.1 releases. |
| | | # |
| | | # e.g. "${baseFolder}/git" becomes "git", if --baseFolder is unspecified |
| | | # |
| | | # Git Servlet Settings |
| | | # |
| | | |
| | | # Base folder for repositories. |
| | | # This folder may contain bare and non-bare repositories but Gitblit will only |
| | | # allow you to push to bare repositories. |
| | | # Use forward slashes even on Windows!! |
| | | # e.g. c:/gitrepos |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | # BASEFOLDER |
| | | git.repositoriesFolder = ${baseFolder}/git |
| | | |
| | | # Build the available repository list at startup and cache this list for reuse. |
| | | # This reduces disk io when presenting the repositories page, responding to rpcs, |
| | | # etc, but it means that Gitblit will not automatically identify repositories |
| | | # added or deleted by external tools. |
| | | # |
| | | # For this case you can use curl, wget, etc to issue an rpc request to clear the |
| | | # cache (e.g. https://localhost/rpc?req=CLEAR_REPOSITORY_CACHE) |
| | | # |
| | | # SINCE 1.1.0 |
| | | git.cacheRepositoryList = true |
| | | |
| | | # Search the repositories folder subfolders for other repositories. |
| | | # Repositories MAY NOT be nested (i.e. one repository within another) |
| | | # but they may be grouped together in subfolders. |
| | | # e.g. c:/gitrepos/libraries/mylibrary.git |
| | | # c:/gitrepos/libraries/myotherlibrary.git |
| | | # |
| | | # SINCE 0.5.0 |
| | | git.searchRepositoriesSubfolders = true |
| | | |
| | | # Maximum number of folders to recurse into when searching for repositories. |
| | | # The default value, -1, disables depth limits. |
| | | # |
| | | # SINCE 1.1.0 |
| | | git.searchRecursionDepth = -1 |
| | | |
| | | # List of regex exclusion patterns to match against folders found in |
| | | # *git.repositoriesFolder*. |
| | | # Use forward slashes even on Windows!! |
| | | # e.g. test/jgit\.git |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 1.1.0 |
| | | git.searchExclusions = |
| | | |
| | | # List of regex url patterns for extracting a repository name when locating |
| | | # submodules. |
| | | # e.g. git.submoduleUrlPatterns = .*?://github.com/(.*) will extract |
| | | # *gitblit/gitblit.git* from *git://github.com/gitblit/gitblit.git* |
| | | # If no matches are found then the submodule repository name is assumed to be |
| | | # whatever trails the last / character. (e.g. gitblit.git). |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 1.1.0 |
| | | git.submoduleUrlPatterns = .*?://github.com/(.*) |
| | | |
| | | # Specify the interface for Git Daemon to bind it's service. |
| | | # You may specify an ip or an empty value to bind to all interfaces. |
| | | # Specifying localhost will result in Gitblit ONLY listening to requests to |
| | | # localhost. |
| | | # |
| | | # SINCE 1.3.0 |
| | | # RESTART REQUIRED |
| | | git.daemonBindInterface = |
| | | |
| | | # port for serving the Git Daemon service. <= 0 disables this service. |
| | | # On Unix/Linux systems, ports < 1024 require root permissions. |
| | | # Recommended value: 9418 |
| | | # |
| | | # SINCE 1.3.0 |
| | | # RESTART REQUIRED |
| | | git.daemonPort = 9418 |
| | | |
| | | # The port for serving the SSH service. <= 0 disables this service. |
| | | # On Unix/Linux systems, ports < 1024 require root permissions. |
| | | # Recommended value: 29418 |
| | | # |
| | | # SINCE 1.5.0 |
| | | # RESTART REQUIRED |
| | | git.sshPort = 29418 |
| | | |
| | | # Specify the interface for the SSH daemon to bind its service. |
| | | # You may specify an ip or an empty value to bind to all interfaces. |
| | | # Specifying localhost will result in Gitblit ONLY listening to requests to |
| | | # localhost. |
| | | # |
| | | # SINCE 1.5.0 |
| | | # RESTART REQUIRED |
| | | git.sshBindInterface = |
| | | |
| | | # Manually specify the hostname to use in advertised SSH repository urls. |
| | | # This may be useful in complex forwarding setups. |
| | | # |
| | | # SINCE 1.7.0 |
| | | git.sshAdvertisedHost = |
| | | |
| | | # Manually specify the port to use in advertised SSH repository urls. |
| | | # This may be useful in complex forwarding setups. |
| | | # |
| | | # SINCE 1.7.0 |
| | | git.sshAdvertisedPort = |
| | | |
| | | # Specify the SSH key manager to use for retrieving, storing, and removing |
| | | # SSH keys. |
| | | # |
| | | # Valid key managers are: |
| | | # com.gitblit.transport.ssh.FileKeyManager |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.sshKeysManager = com.gitblit.transport.ssh.FileKeyManager |
| | | |
| | | # Directory for storing user SSH keys when using the FileKeyManager. |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.sshKeysFolder= ${baseFolder}/ssh |
| | | |
| | | # Use Kerberos5 (GSS) authentication |
| | | # |
| | | # SINCE 1.7.0 |
| | | git.sshWithKrb5 = false |
| | | |
| | | # The path to a Kerberos 5 keytab. |
| | | # |
| | | # SINCE 1.7.0 |
| | | git.sshKrb5Keytab = |
| | | |
| | | # The service principal name to be used for Kerberos5. |
| | | # The default is host/hostname. |
| | | # |
| | | # SINCE 1.7.0 |
| | | git.sshKrb5ServicePrincipalName = |
| | | |
| | | # Strip the domain suffix from a kerberos username. |
| | | # e.g. james@bigbox would be "james" |
| | | # |
| | | # SINCE 1.7.0 |
| | | git.sshKrb5StripDomain = true |
| | | |
| | | # SSH backend NIO2|MINA. |
| | | # |
| | | # The Apache Mina project recommends using the NIO2 backend. |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.sshBackend = NIO2 |
| | | |
| | | # Number of threads used to parse a command line submitted by a client over SSH |
| | | # for execution, create the internal data structures used by that command, |
| | | # and schedule it for execution on another thread. |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.sshCommandStartThreads = 2 |
| | | |
| | | |
| | | # Allow push/pull over http/https with JGit servlet. |
| | | # If you do NOT want to allow Git clients to clone/push to Gitblit set this |
| | | # to false. You might want to do this if you are only using ssh:// or git://. |
| | | # If you set this false, consider changing the *web.otherUrls* setting to |
| | | # indicate your clone/push urls. |
| | | # |
| | | # SINCE 0.5.0 |
| | | git.enableGitServlet = true |
| | | |
| | | # If you want to restrict all git servlet access to those with valid X509 client |
| | | # certificates then set this value to true. |
| | | # |
| | | # SINCE 1.2.0 |
| | | git.requiresClientCertificate = false |
| | | |
| | | # Enforce date checks on client certificates to ensure that they are not being |
| | | # used prematurely and that they have not expired. |
| | | # |
| | | # SINCE 1.2.0 |
| | | git.enforceCertificateValidity = true |
| | | |
| | | # List of OIDs to extract from a client certificate DN to map a certificate to |
| | | # an account username. |
| | | # |
| | | # e.g. git.certificateUsernameOIDs = CN |
| | | # e.g. git.certificateUsernameOIDs = FirstName LastName |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.2.0 |
| | | git.certificateUsernameOIDs = CN |
| | | |
| | | # Only serve/display bare repositories. |
| | | # If there are non-bare repositories in git.repositoriesFolder and this setting |
| | | # is true, they will be excluded from the ui. |
| | | # |
| | | # SINCE 0.9.0 |
| | | git.onlyAccessBareRepositories = false |
| | | |
| | | |
| | | # Specify the list of acceptable transports for pushes. |
| | | # If this setting is empty, all transports are acceptable. |
| | | # |
| | | # Valid choices are: GIT HTTP HTTPS SSH |
| | | # |
| | | # SINCE 1.5.0 |
| | | # SPACE-DELIMITED |
| | | git.acceptedPushTransports = HTTP HTTPS SSH |
| | | |
| | | # Allow an authenticated user to create a destination repository on a push if |
| | | # the repository does not already exist. |
| | | # |
| | | # Administrator accounts can create a repository in any project. |
| | | # These repositories are created with the default access restriction and authorization |
| | | # control values. The pushing account is set as the owner. |
| | | # |
| | | # Non-administrator accounts with the CREATE role may create personal repositories. |
| | | # These repositories are created as VIEW restricted for NAMED users. |
| | | # The pushing account is set as the owner. |
| | | # |
| | | # SINCE 1.2.0 |
| | | git.allowCreateOnPush = true |
| | | |
| | | # Global setting to control anonymous pushes. |
| | | # |
| | | # This setting allows/rejects anonymous pushes at the level of the receive pack. |
| | | # This trumps all repository config settings. While anonymous pushes are convenient |
| | | # on your own box when you are a lone developer, they are not recommended for |
| | | # any multi-user installation where accountability is required. Since Gitblit |
| | | # tracks pushes and user accounts, allowing anonymous pushes compromises that |
| | | # information. |
| | | # |
| | | # SINCE 1.4.0 |
| | | git.allowAnonymousPushes = false |
| | | |
| | | # The default access restriction for new repositories. |
| | | # Valid values are NONE, PUSH, CLONE, VIEW |
| | | # NONE = anonymous view, clone, & push |
| | | # PUSH = anonymous view & clone and authenticated push |
| | | # CLONE = anonymous view, authenticated clone & push |
| | | # VIEW = authenticated view, clone, & push |
| | | # |
| | | # SINCE 1.0.0 |
| | | git.defaultAccessRestriction = PUSH |
| | | |
| | | # The default authorization control for new repositories. |
| | | # Valid values are AUTHENTICATED and NAMED |
| | | # AUTHENTICATED = any authenticated user is granted restricted access |
| | | # NAMED = only named users/teams are granted restricted access |
| | | # |
| | | # SINCE 1.1.0 |
| | | git.defaultAuthorizationControl = NAMED |
| | | |
| | | # The prefix for a users personal repository directory. |
| | | # |
| | | # Personal user repositories are created in this directory, named by the user name |
| | | # prefixed with the userRepositoryPrefix. For eaxmple, a user 'john' would have his |
| | | # personal repositories in the directory '~john'. |
| | | # |
| | | # Cannot be an empty string. Also, absolute paths are changed to relative paths by |
| | | # removing the first directory separator. |
| | | # |
| | | # It is not recommended to change this value AFTER your user's have created |
| | | # personal repositories because it will break all permissions, ownership, and |
| | | # repository push/pull operations. |
| | | # |
| | | # RESTART REQUIRED |
| | | # SINCE 1.4.0 |
| | | git.userRepositoryPrefix = ~ |
| | | |
| | | # The default incremental push tag prefix. Tag prefix applied to a repository |
| | | # that has automatic push tags enabled and does not specify a custom tag prefix. |
| | | # |
| | | # If incremental push tags are enabled, the tips of each branch in the push will |
| | | # be tagged with an increasing revision integer. |
| | | # |
| | | # e.g. refs/tags/r2345 or refs/tags/rev_2345 |
| | | # |
| | | # SINCE 1.3.0 |
| | | git.defaultIncrementalPushTagPrefix = r |
| | | |
| | | # Controls creating a repository as --shared on Unix servers. |
| | | # |
| | | # In an Unix environment where mixed access methods exist for shared repositories, |
| | | # the repository should be created with 'git init --shared' to make sure that |
| | | # it can be accessed e.g. via ssh (user git) and http (user www-data). |
| | | # |
| | | # Valid values are the values available for the '--shared' option. The the manual |
| | | # page for 'git init' for more information on shared repositories. |
| | | # |
| | | # SINCE 1.4.0 |
| | | git.createRepositoriesShared = false |
| | | |
| | | # Directory for gitignore templates used during repository creation. |
| | | # |
| | | # SINCE 1.6.0 |
| | | git.gitignoreFolder = ${baseFolder}/gitignore |
| | | |
| | | # Enable JGit-based garbage collection. (!!EXPERIMENTAL!!) |
| | | # |
| | | # USE AT YOUR OWN RISK! |
| | | # |
| | | # If enabled, the garbage collection executor scans all repositories once a day |
| | | # at the hour of your choosing. The GC executor will take each repository "offline", |
| | | # one-at-a-time, to check if the repository satisfies it's GC trigger requirements. |
| | | # |
| | | # While the repository is offline it will be inaccessible from the web UI or from |
| | | # any of the other services (git, rpc, rss, etc). |
| | | # |
| | | # Gitblit's GC Executor MAY NOT PLAY NICE with the other Git kids on the block, |
| | | # especially on Windows systems, so if you are using other tools please coordinate |
| | | # their usage with your GC Executor schedule or do not use this feature. |
| | | # |
| | | # The GC algorithm complex and the JGit team advises caution when using their |
| | | # young implementation of GC. |
| | | # |
| | | # http://wiki.eclipse.org/EGit/New_and_Noteworthy/2.1#Garbage_Collector_and_Repository_Storage_Statistics |
| | | # |
| | | # EXPERIMENTAL |
| | | # SINCE 1.2.0 |
| | | # RESTART REQUIRED |
| | | git.enableGarbageCollection = false |
| | | |
| | | # Hour of the day for the GC Executor to scan repositories. |
| | | # This value is in 24-hour time. |
| | | # |
| | | # SINCE 1.2.0 |
| | | git.garbageCollectionHour = 0 |
| | | |
| | | # The default minimum total filesize of loose objects to trigger early garbage |
| | | # collection. |
| | | # |
| | | # You may specify a custom threshold for a repository in the repository's settings. |
| | | # Common unit suffixes of k, m, or g are supported. |
| | | # |
| | | # SINCE 1.2.0 |
| | | git.defaultGarbageCollectionThreshold = 500k |
| | | |
| | | # The default period, in days, between GCs for a repository. If the total filesize |
| | | # of the loose object exceeds *git.garbageCollectionThreshold* or the repository's |
| | | # custom threshold, this period will be short-circuited. |
| | | # |
| | | # e.g. if a repository collects 100KB of loose objects every day with a 500KB |
| | | # threshold and a period of 7 days, it will take 5 days for the loose objects to |
| | | # be collected, packed, and pruned. |
| | | # |
| | | # OR |
| | | # |
| | | # if a repository collects 10KB of loose objects every day with a 500KB threshold |
| | | # and a period of 7 days, it will take the full 7 days for the loose objects to be |
| | | # collected, packed, and pruned. |
| | | # |
| | | # You may specify a custom period for a repository in the repository's settings. |
| | | # |
| | | # The minimum value is 1 day since the GC Executor only runs once a day. |
| | | # |
| | | # SINCE 1.2.0 |
| | | git.defaultGarbageCollectionPeriod = 7 |
| | | |
| | | # Gitblit can automatically fetch ref updates for a properly configured mirror |
| | | # repository. |
| | | # |
| | | # Requirements: |
| | | # 1. you must manually clone the repository using native git |
| | | # git clone --mirror git://somewhere.com/myrepo.git |
| | | # 2. the "origin" remote must be the mirror source |
| | | # 3. the "origin" repository must be accessible without authentication OR the |
| | | # credentials must be embedded in the origin url (not recommended) |
| | | # |
| | | # Notes: |
| | | # 1. "origin" SSH urls are untested and not likely to work |
| | | # 2. mirrors cloned while Gitblit is running are likely to require clearing the |
| | | # gitblit cache (link on the repositories page of an administrator account) |
| | | # 3. Gitblit will automatically repair any invalid fetch refspecs with a "//" |
| | | # sequence. |
| | | # |
| | | # SINCE 1.4.0 |
| | | # RESTART REQUIRED |
| | | git.enableMirroring = false |
| | | |
| | | # Specify the period between update checks for mirrored repositories. |
| | | # The shortest period you may specify between mirror update checks is 5 mins. |
| | | # |
| | | # SINCE 1.4.0 |
| | | # RESTART REQUIRED |
| | | git.mirrorPeriod = 30 mins |
| | | |
| | | # Number of bytes of a pack file to load into memory in a single read operation. |
| | | # This is the "page size" of the JGit buffer cache, used for all pack access |
| | | # operations. All disk IO occurs as single window reads. Setting this too large |
| | | # may cause the process to load more data than is required; setting this too small |
| | | # may increase the frequency of read() system calls. |
| | | # |
| | | # Default on JGit is 8 KiB on all platforms. |
| | | # |
| | | # Common unit suffixes of k, m, or g are supported. |
| | | # Documentation courtesy of the Gerrit project. |
| | | # |
| | | # SINCE 1.0.0 |
| | | # RESTART REQUIRED |
| | | git.packedGitWindowSize = 8k |
| | | |
| | | # Maximum number of bytes to load and cache in memory from pack files. If JGit |
| | | # needs to access more than this many bytes it will unload less frequently used |
| | | # windows to reclaim memory space within the process. As this buffer must be shared |
| | | # with the rest of the JVM heap, it should be a fraction of the total memory available. |
| | | # |
| | | # The JGit team recommends setting this value larger than the size of your biggest |
| | | # repository. This ensures you can serve most requests from memory. |
| | | # |
| | | # Default on JGit is 10 MiB on all platforms. |
| | | # |
| | | # Common unit suffixes of k, m, or g are supported. |
| | | # Documentation courtesy of the Gerrit project. |
| | | # |
| | | # SINCE 1.0.0 |
| | | # RESTART REQUIRED |
| | | git.packedGitLimit = 10m |
| | | |
| | | # Maximum number of bytes to reserve for caching base objects that multiple deltafied |
| | | # objects reference. By storing the entire decompressed base object in a cache Git |
| | | # is able to avoid unpacking and decompressing frequently used base objects multiple times. |
| | | # |
| | | # Default on JGit is 10 MiB on all platforms. You probably do not need to adjust |
| | | # this value. |
| | | # |
| | | # Common unit suffixes of k, m, or g are supported. |
| | | # Documentation courtesy of the Gerrit project. |
| | | # |
| | | # SINCE 1.0.0 |
| | | # RESTART REQUIRED |
| | | git.deltaBaseCacheLimit = 10m |
| | | |
| | | # Maximum number of pack files to have open at once. A pack file must be opened |
| | | # in order for any of its data to be available in a cached window. |
| | | # |
| | | # If you increase this to a larger setting you may need to also adjust the ulimit |
| | | # on file descriptors for the host JVM, as Gitblit needs additional file descriptors |
| | | # available for network sockets and other repository data manipulation. |
| | | # |
| | | # Default on JGit is 128 file descriptors on all platforms. |
| | | # Documentation courtesy of the Gerrit project. |
| | | # |
| | | # SINCE 1.0.0 |
| | | # RESTART REQUIRED |
| | | git.packedGitOpenFiles = 128 |
| | | |
| | | # When true, JGit will use mmap() rather than malloc()+read() to load data from |
| | | # pack files. The use of mmap can be problematic on some JVMs as the garbage |
| | | # collector must deduce that a memory mapped segment is no longer in use before |
| | | # a call to munmap() can be made by the JVM native code. |
| | | # |
| | | # In server applications (such as Gitblit) that need to access many pack files, |
| | | # setting this to true risks artificially running out of virtual address space, |
| | | # as the garbage collector cannot reclaim unused mapped spaces fast enough. |
| | | # |
| | | # Default on JGit is false. Although potentially slower, it yields much more |
| | | # predictable behavior. |
| | | # Documentation courtesy of the Gerrit project. |
| | | # |
| | | # SINCE 1.0.0 |
| | | # RESTART REQUIRED |
| | | git.packedGitMmap = false |
| | | |
| | | # Validate all received (pushed) objects are valid. |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.checkReceivedObjects = true |
| | | |
| | | # Validate all referenced but not supplied objects are reachable. |
| | | # |
| | | # If enabled, Gitblit will verify that references to objects not contained |
| | | # within the received pack are already reachable through at least one other |
| | | # reference advertised to clients. |
| | | # |
| | | # This feature is useful when Gitblit doesn't trust the client to not provide a |
| | | # forged SHA-1 reference to an object, in an attempt to access parts of the DAG |
| | | # that they aren't allowed to see and which have been hidden from them via the |
| | | # configured AdvertiseRefsHook or RefFilter. |
| | | # |
| | | # Enabling this feature may imply at least some, if not all, of the same functionality |
| | | # performed by git.checkReceivedObjects. |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.checkReferencedObjectsAreReachable = true |
| | | |
| | | # Set the maximum allowed Git object size. |
| | | # |
| | | # If an object is larger than the given size the pack-parsing will throw an exception |
| | | # aborting the receive-pack operation. The default value, 0, disables maximum |
| | | # object size checking. |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.maxObjectSizeLimit = 0 |
| | | |
| | | # Set the maximum allowed pack size. |
| | | # |
| | | # A pack exceeding this size will be rejected. The default value, -1, disables |
| | | # maximum pack size checking. |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.maxPackSizeLimit = -1 |
| | | |
| | | # Use the Gitblit patch receive pack for processing contributions and tickets. |
| | | # This allows the user to push a patch using the familiar Gerrit syntax: |
| | | # |
| | | # git push <remote> HEAD:refs/for/<targetBranch> |
| | | # |
| | | # NOTE: |
| | | # This requires git.enableGitServlet = true AND it requires an authenticated |
| | | # git transport connection (http/https) when pushing from a client. |
| | | # |
| | | # Valid services include: |
| | | # com.gitblit.tickets.FileTicketService |
| | | # com.gitblit.tickets.BranchTicketService |
| | | # com.gitblit.tickets.RedisTicketService |
| | | # |
| | | # SINCE 1.4.0 |
| | | # RESTART REQUIRED |
| | | tickets.service = |
| | | |
| | | # Globally enable or disable creation of new bug, enhancement, task, etc tickets |
| | | # for all repositories. |
| | | # |
| | | # If false, no tickets can be created through the ui for any repositories. |
| | | # If true, each repository can control if they allow new tickets to be created. |
| | | # |
| | | # NOTE: |
| | | # If a repository is accepting patchsets, new proposal tickets can be created |
| | | # regardless of this setting. |
| | | # |
| | | # SINCE 1.4.0 |
| | | tickets.acceptNewTickets = true |
| | | |
| | | # Globally enable or disable pushing patchsets to all repositories. |
| | | # |
| | | # If false, no patchsets will be accepted for any repositories. |
| | | # If true, each repository can control if they accept new patchsets. |
| | | # |
| | | # NOTE: |
| | | # If a repository is accepting patchsets, new proposal tickets can be created |
| | | # regardless of the acceptNewTickets setting. |
| | | # |
| | | # SINCE 1.4.0 |
| | | tickets.acceptNewPatchsets = true |
| | | |
| | | # Default setting to control patchset merge through the web ui. If true, patchsets |
| | | # must have an approval score to enable the merge button. This setting can be |
| | | # overriden per-repository. |
| | | # |
| | | # SINCE 1.4.0 |
| | | tickets.requireApproval = false |
| | | |
| | | # The case-insensitive regular expression used to identify and close tickets on |
| | | # push to the integration branch for commits that are NOT already referenced as |
| | | # a patchset tip. |
| | | # |
| | | # SINCE 1.5.0 |
| | | tickets.closeOnPushCommitMessageRegex = (?:fixes|closes)[\\s-]+#?(\\d+) |
| | | |
| | | # Specify the location of the Lucene Ticket index |
| | | # |
| | | # SINCE 1.4.0 |
| | | # RESTART REQUIRED |
| | | tickets.indexFolder = ${baseFolder}/tickets/lucene |
| | | |
| | | # Define the url for the Redis server. |
| | | # |
| | | # e.g. redis://localhost:6379 |
| | | # redis://:foobared@localhost:6379/2 |
| | | # |
| | | # SINCE 1.4.0 |
| | | # RESTART REQUIRED |
| | | tickets.redis.url = |
| | | |
| | | # The number of tickets to display on a page. |
| | | # |
| | | # SINCE 1.4.0 |
| | | tickets.perPage = 25 |
| | | |
| | | # The folder where plugins are loaded from. |
| | | # |
| | | # SINCE 1.5.0 |
| | | # RESTART REQUIRED |
| | | # BASEFOLDER |
| | | plugins.folder = ${baseFolder}/plugins |
| | | |
| | | # The registry of available plugins. |
| | | # |
| | | # SINCE 1.5.0 |
| | | plugins.registry = http://plugins.gitblit.com/plugins.json |
| | | |
| | | # The HTTP proxy host for plugin manager. |
| | | # |
| | | # SINCE 1.7.0 |
| | | plugins.httpProxyHost = |
| | | |
| | | # The HTTP proxy port for plugin manager. |
| | | # |
| | | # SINCE 1.7.0 |
| | | plugins.httpProxyPort = |
| | | |
| | | # The HTTP proxy authorization header for plugin manager. |
| | | # |
| | | # SINCE 1.7.0 |
| | | plugins.httpProxyAuthorization = |
| | | |
| | | # Number of threads used to handle miscellaneous tasks in the background. |
| | | # |
| | | # SINCE 1.6.0 |
| | | # RESTART REQUIRED |
| | | execution.defaultThreadPoolSize = 1 |
| | | |
| | | # |
| | | # Groovy Integration |
| | | # |
| | | |
| | | # Location of Groovy scripts to use for Pre and Post receive hooks. |
| | | # Use forward slashes even on Windows!! |
| | | # e.g. c:/groovy |
| | | # |
| | | # RESTART REQUIRED |
| | | # SINCE 0.8.0 |
| | | # BASEFOLDER |
| | | groovy.scriptsFolder = ${baseFolder}/groovy |
| | | |
| | | # Specify the directory Grape uses for downloading libraries. |
| | | # http://groovy.codehaus.org/Grape |
| | | # |
| | | # RESTART REQUIRED |
| | | # SINCE 1.0.0 |
| | | # BASEFOLDER |
| | | groovy.grapeFolder = ${baseFolder}/groovy/grape |
| | | |
| | | # Scripts to execute on Pre-Receive. |
| | | # |
| | | # These scripts execute after an incoming push has been parsed and validated |
| | | # but BEFORE the changes are applied to the repository. You might reject a |
| | | # push in this script based on the repository and branch the push is attempting |
| | | # to change. |
| | | # |
| | | # Script names are case-sensitive on case-sensitive file systems. You may omit |
| | | # the traditional ".groovy" from this list if your file extension is ".groovy" |
| | | # |
| | | # NOTE: |
| | | # These scripts are only executed when pushing to *Gitblit*, not to other Git |
| | | # tooling you may be using. Also note that these scripts are shared between |
| | | # repositories. These are NOT repository-specific scripts! Within the script |
| | | # you may customize the control-flow for a specific repository by checking the |
| | | # *repository* variable. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 0.8.0 |
| | | groovy.preReceiveScripts = |
| | | |
| | | # Scripts to execute on Post-Receive. |
| | | # |
| | | # These scripts execute AFTER an incoming push has been applied to a repository. |
| | | # You might trigger a continuous-integration build here or send a notification. |
| | | # |
| | | # Script names are case-sensitive on case-sensitive file systems. You may omit |
| | | # the traditional ".groovy" from this list if your file extension is ".groovy" |
| | | # |
| | | # NOTE: |
| | | # These scripts are only executed when pushing to *Gitblit*, not to other Git |
| | | # tooling you may be using. Also note that these scripts are shared between |
| | | # repositories. These are NOT repository-specific scripts! Within the script |
| | | # you may customize the control-flow for a specific repository by checking the |
| | | # *repository* variable. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 0.8.0 |
| | | groovy.postReceiveScripts = |
| | | |
| | | # Repository custom fields for Groovy Hook mechanism |
| | | # |
| | | # List of key=label pairs of custom fields to prompt for in the Edit Repository |
| | | # page. These keys are stored in the repository's git config file in the |
| | | # section [gitblit "customFields"]. Key names are alphanumeric only. These |
| | | # fields are intended to be used for the Groovy hook mechanism where a script |
| | | # can adjust it's execution based on the custom fields stored in the repository |
| | | # config. |
| | | # |
| | | # e.g. "commitMsgRegex=Commit Message Regular Expression" anotherProperty=Another |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.0.0 |
| | | groovy.customFields = |
| | | |
| | | # |
| | | # Fanout Settings |
| | | # |
| | | |
| | | # Fanout is a PubSub notification service that can be used by Sparkleshare |
| | | # to eliminate repository change polling. The fanout service runs in a separate |
| | | # thread on a separate port from the Gitblit http/https application. |
| | | # This service is provided so that Sparkleshare may be used with Gitblit in |
| | | # firewalled environments or where reliance on Sparkleshare's default notifications |
| | | # server (notifications.sparkleshare.org) is unwanted. |
| | | # |
| | | # This service maintains an open socket connection from the client to the |
| | | # Fanout PubSub service. This service may not work properly behind a proxy server. |
| | | |
| | | # Specify the interface for Fanout to bind it's service. |
| | | # You may specify an ip or an empty value to bind to all interfaces. |
| | | # Specifying localhost will result in Gitblit ONLY listening to requests to |
| | | # localhost. |
| | | # |
| | | # SINCE 1.2.1 |
| | | # RESTART REQUIRED |
| | | fanout.bindInterface = |
| | | |
| | | # port for serving the Fanout PubSub service. <= 0 disables this service. |
| | | # On Unix/Linux systems, ports < 1024 require root permissions. |
| | | # Recommended value: 17000 |
| | | # |
| | | # SINCE 1.2.1 |
| | | # RESTART REQUIRED |
| | | fanout.port = 0 |
| | | |
| | | # Use Fanout NIO service. If false, a multi-threaded socket service will be used. |
| | | # Be advised, the socket implementation spawns a thread per connection plus the |
| | | # connection acceptor thread. The NIO implementation is completely single-threaded. |
| | | # |
| | | # SINCE 1.2.1 |
| | | # RESTART REQUIRED |
| | | fanout.useNio = true |
| | | |
| | | # Concurrent connection limit. <= 0 disables concurrent connection throttling. |
| | | # If > 0, only the specified number of concurrent connections will be allowed |
| | | # and all other connections will be rejected. |
| | | # |
| | | # SINCE 1.2.1 |
| | | # RESTART REQUIRED |
| | | fanout.connectionLimit = 0 |
| | | |
| | | # |
| | | # Authentication Settings |
| | | # |
| | | |
| | | # Require authentication to see everything but the admin pages |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | web.authenticateViewPages = false |
| | | |
| | | # If web.authenticateViewPages=true you may optionally require a client-side |
| | | # basic authentication prompt instead of the standard form-based login. |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.enforceHttpBasicAuthentication = false |
| | | |
| | | # Require admin authentication for the admin functions and pages |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | web.authenticateAdminPages = true |
| | | |
| | | # Allow Gitblit to store a cookie in the user's browser for automatic |
| | | # authentication. The cookie is generated by the user service. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.allowCookieAuthentication = true |
| | | |
| | | # Allow deletion of non-empty repositories. This is enforced for all delete vectors. |
| | | # |
| | | # SINCE 1.6.0 |
| | | web.allowDeletingNonEmptyRepositories = true |
| | | |
| | | # Setting to include personal repositories in the main repositories list. |
| | | # |
| | | # SINCE 1.6.0 |
| | | web.includePersonalRepositories = false |
| | | |
| | | # Config file for storing project metadata |
| | | # |
| | | # SINCE 1.2.0 |
| | | # BASEFOLDER |
| | | web.projectsFile = ${baseFolder}/projects.conf |
| | | |
| | | # Defines the tab length for all blob views |
| | | # |
| | | # SINCE 1.7.0 |
| | | web.tabLength = 4 |
| | | |
| | | # Either the full path to a user config file (users.conf) |
| | | # OR a fully qualified class name that implements the IUserService interface. |
| | | # |
| | | # Any custom user service implementation must have a public default constructor. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | # BASEFOLDER |
| | | realm.userService = ${baseFolder}/users.conf |
| | | |
| | | # Ordered list of external authentication providers which will be used if |
| | | # authentication against the local user service fails. |
| | | # |
| | | # Valid providers are: |
| | | # |
| | | # htpasswd |
| | | # httpheader |
| | | # ldap |
| | | # pam |
| | | # redmine |
| | | # salesforce |
| | | # windows |
| | | |
| | | # e.g. realm.authenticationProviders = htpasswd windows |
| | | # |
| | | # SINCE 1.4.0 |
| | | # RESTART REQUIRED |
| | | # SPACE-DELIMITED |
| | | realm.authenticationProviders = |
| | | |
| | | # How to store passwords. |
| | | # Valid values are plain, md5, or combined-md5. md5 is the hash of password. |
| | | # combined-md5 is the hash of username.toLowerCase()+password. |
| | | # Default is md5. |
| | | # |
| | | # SINCE 0.5.0 |
| | | realm.passwordStorage = md5 |
| | | |
| | | # Minimum valid length for a plain text password. |
| | | # Default value is 5. Absolute minimum is 4. |
| | | # |
| | | # SINCE 0.5.0 |
| | | realm.minPasswordLength = 5 |
| | | |
| | | # |
| | | # Gitblit Web Settings |
| | | # |
| | | # If blank Gitblit is displayed. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.siteName = |
| | | |
| | | # The canonical url of your Gitblit server to be used in repository url generation, |
| | | # RSS feeds, and all embedded links in email and plugin-based notifications. |
| | | # |
| | | # If you are running Gitblit on a non-standard http port (i.e. not 80 and not 443) |
| | | # then you must specify that port in this url otherwise your generated urls will be |
| | | # incorrect. |
| | | # |
| | | # The hostname of this url will be extracted for SSH and GIT protocol repository |
| | | # url generation. |
| | | # |
| | | # e.g. web.canonicalUrl = https://dev.gitblit.com |
| | | # web.canonicalUrl = https://dev.gitblit.com:8443 |
| | | # |
| | | # SINCE 1.4.0 |
| | | web.canonicalUrl = |
| | | |
| | | # You may specify a different logo image for the header but it must be 120x45px. |
| | | # If the specified file does not exist, the default Gitblit logo will be used. |
| | | # |
| | | # SINCE 1.3.0 |
| | | # BASEFOLDER |
| | | web.headerLogo = ${baseFolder}/logo.png |
| | | |
| | | # You may specify a different link URL for the logo image anchor. |
| | | # If blank the Gitblit main page URL is used. |
| | | # |
| | | # SINCE 1.3.0 |
| | | # BASEFOLDER |
| | | web.rootLink = |
| | | |
| | | # You may specify a custom header background CSS color. If unspecified, the |
| | | # default color will be used. |
| | | # |
| | | # e.g. web.headerBackgroundColor = #002060 |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.headerBackgroundColor = |
| | | |
| | | # You may specify a custom header foreground CSS color. If unspecified, the |
| | | # default color will be used. |
| | | # |
| | | # e.g. web.headerForegroundColor = white |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.headerForegroundColor = |
| | | |
| | | # You may specify a custom header foreground hover CSS color. If unspecified, the |
| | | # default color will be used. |
| | | # |
| | | # e.g. web.headerHoverColor = white |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.headerHoverColor = |
| | | |
| | | # You may specify a custom header border CSS color. If unspecified, the default |
| | | # color will be used. |
| | | # |
| | | # e.g. web.headerBorderColor = #002060 |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.headerBorderColor = |
| | | |
| | | # You may specify a custom header border CSS color. If unspecified, the default |
| | | # color will be used. |
| | | # |
| | | # e.g. web.headerBorderFocusColor = #ff9900 |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.headerBorderFocusColor = |
| | | |
| | | # If *web.authenticateAdminPages*=true, users with "admin" role can create |
| | | # repositories, create users, and edit repository metadata. |
| | | # |
| | | # If *web.authenticateAdminPages*=false, any user can execute the aforementioned |
| | | # functions. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.allowAdministration = true |
| | | |
| | | # Setting to disable rendering the top-level navigation header which includes |
| | | # the login form, top-level links like dashboard, repositories, search, etc. |
| | | # This setting is only useful if you plan to embed Gitblit within another page |
| | | # or system. |
| | | # |
| | | # SINCE 1.4.0 |
| | | web.hideHeader = false |
| | | |
| | | # Allows rpc clients to list repositories and possibly manage or administer the |
| | | # Gitblit server, if the authenticated account has administrator permissions. |
| | | # See *web.enableRpcManagement* and *web.enableRpcAdministration*. |
| | | # |
| | | # SINCE 0.7.0 |
| | | web.enableRpcServlet = true |
| | | |
| | | # Allows rpc clients to manage repositories and users of the Gitblit instance, |
| | | # if the authenticated account has administrator permissions. |
| | | # Requires *web.enableRpcServlet=true*. |
| | | # |
| | | # SINCE 0.7.0 |
| | | web.enableRpcManagement = false |
| | | |
| | | # Allows rpc clients to control the server settings and monitor the health of this |
| | | # this Gitblit instance, if the authenticated account has administrator permissions. |
| | | # Requires *web.enableRpcServlet=true* and *web.enableRpcManagement*. |
| | | # |
| | | # SINCE 0.7.0 |
| | | web.enableRpcAdministration = false |
| | | |
| | | # Full path to a configurable robots.txt file. With this file you can control |
| | | # what parts of your Gitblit server respectable robots are allowed to traverse. |
| | | # http://googlewebmastercentral.blogspot.com/2008/06/improving-on-robots-exclusion-protocol.html |
| | | # |
| | | # SINCE 1.0.0 |
| | | # BASEFOLDER |
| | | web.robots.txt = ${baseFolder}/robots.txt |
| | | |
| | | # The number of minutes to cache a page in the browser since the last request. |
| | | # The default value is 0 minutes. A value <= 0 disables all page caching which |
| | | # is the default behavior for Gitblit <= 1.3.0. |
| | | # |
| | | # SINCE 1.3.1 |
| | | web.pageCacheExpires = 0 |
| | | |
| | | # If true, the web ui layout will respond and adapt to the browser's dimensions. |
| | | # if false, the web ui will use a 940px fixed-width layout. |
| | | # http://twitter.github.com/bootstrap/scaffolding.html#responsive |
| | | # |
| | | # SINCE 1.0.0 |
| | | web.useResponsiveLayout = true |
| | | |
| | | # Allow Gravatar images to be displayed in Gitblit pages. |
| | | # |
| | | # SINCE 0.8.0 |
| | | web.allowGravatar = true |
| | | |
| | | # Define which class will generate the avatar URL. |
| | | # |
| | | # SINCE 1.7.0 |
| | | web.avatarClass = com.gitblit.GravatarGenerator |
| | | |
| | | # Allow dynamic zip downloads. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.allowZipDownloads = true |
| | | |
| | | # If *web.allowZipDownloads=true* the following formats will be displayed for |
| | | # download compressed archive links: |
| | | # |
| | | # zip = standard .zip |
| | | # tar = standard tar format (preserves *nix permissions and symlinks) |
| | | # gz = gz-compressed tar |
| | | # xz = xz-compressed tar |
| | | # bzip2 = bzip2-compressed tar |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.2.0 |
| | | web.compressedDownloads = zip gz |
| | | |
| | | # Allow optional Lucene integration. Lucene indexing is an opt-in feature. |
| | | # A repository may specify branches to index with Lucene instead of using Git |
| | | # commit traversal. There are scenarios where you may want to completely disable |
| | | # Lucene indexing despite a repository specifying indexed branches. One such |
| | | # scenario is on a resource-constrained federated Gitblit mirror. |
| | | # |
| | | # SINCE 0.9.0 |
| | | web.allowLuceneIndexing = true |
| | | |
| | | # Control the frequency of Lucene repository indexing. |
| | | # The default setting is to check for updated refs every 2 mins. |
| | | # |
| | | # SINCE 1.6.1 |
| | | web.luceneFrequency = 2 mins |
| | | |
| | | # Allows an authenticated user to create forks of a repository |
| | | # |
| | | # set this to false if you want to disable all fork controls on the web site |
| | | # |
| | | web.allowForking = true |
| | | |
| | | # Controls the length of shortened commit hash ids |
| | | # |
| | | # SINCE 1.2.0 |
| | | web.shortCommitIdLength = 6 |
| | | |
| | | # Use Clippy (Flash solution) to provide a copy-to-clipboard button. |
| | | # If false, a button with a more primitive JavaScript-based prompt box will |
| | | # offer a 3-step (click, ctrl+c, enter) copy-to-clipboard alternative. |
| | | # |
| | | # SINCE 0.8.0 |
| | | web.allowFlashCopyToClipboard = true |
| | | |
| | | # Default maximum number of commits that a repository may contribute to the |
| | | # activity page, regardless of the selected duration. This setting may be valuable |
| | | # for an extremely busy server. This value may also be configed per-repository |
| | | # in Edit Repository. 0 disables this throttle. |
| | | # |
| | | # SINCE 1.2.0 |
| | | web.maxActivityCommits = 0 |
| | | |
| | | # Default number of entries to include in RSS Syndication links |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.syndicationEntries = 25 |
| | | |
| | | # Show the size of each repository on the repositories page. |
| | | # This requires recursive traversal of each repository folder. This may be |
| | | # non-performant on some operating systems and/or filesystems. |
| | | # |
| | | # SINCE 0.5.2 |
| | | web.showRepositorySizes = true |
| | | |
| | | # List of custom regex expressions that can be displayed in the Filters menu |
| | | # of the Repositories and Activity pages. Keep them very simple because you |
| | | # are likely to run into encoding issues if they are too complex. |
| | | # |
| | | # Use !!! to separate the filters |
| | | # |
| | | # SINCE 0.8.0 |
| | | web.customFilters = |
| | | |
| | | # Show federation registrations (without token) and the current pull status |
| | | # to non-administrator users. |
| | | # |
| | | # SINCE 0.6.0 |
| | | web.showFederationRegistrations = false |
| | | |
| | | # This is the message displayed when *web.authenticateViewPages=true*. |
| | | # This can point to a file with Markdown content. |
| | | # Specifying "gitblit" uses the internal login message. |
| | | # |
| | | # SINCE 0.7.0 |
| | | # BASEFOLDER |
| | | web.loginMessage = gitblit |
| | | |
| | | # This is the message displayed above the repositories table. |
| | | # This can point to a file with Markdown content. |
| | | # Specifying "gitblit" uses the internal welcome message. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # BASEFOLDER |
| | | web.repositoriesMessage = gitblit |
| | | |
| | | # Ordered list of charsets/encodings to use when trying to display a blob. |
| | | # If empty, UTF-8 and ISO-8859-1 are used. The server's default charset |
| | | # is always appended to the encoding list. If all encodings fail to cleanly |
| | | # decode the blob content, UTF-8 will be used with the standard malformed |
| | | # input/unmappable character replacement strings. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.0.0 |
| | | web.blobEncodings = UTF-8 ISO-8859-1 |
| | | |
| | | # Manually set the default timezone to be used by Gitblit for display in the |
| | | # web ui. This value is independent of the JVM timezone. Specifying a blank |
| | | # value will default to the JVM timezone. |
| | | # e.g. America/New_York, US/Pacific, UTC, Europe/Berlin |
| | | # |
| | | # SINCE 0.9.0 |
| | | # RESTART REQUIRED |
| | | web.timezone = |
| | | |
| | | # Use the client timezone when formatting dates. |
| | | # This uses AJAX to determine the browser's timezone and may require more |
| | | # server overhead because a Wicket session is created. All Gitblit pages |
| | | # attempt to be stateless, if possible. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | web.useClientTimezone = false |
| | | |
| | | # Time format |
| | | # <http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html> |
| | | # |
| | | # SINCE 0.8.0 |
| | | web.timeFormat = HH:mm |
| | | |
| | | # Short date format |
| | | # <http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html> |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.datestampShortFormat = yyyy-MM-dd |
| | | |
| | | # Long date format |
| | | # |
| | | # SINCE 0.8.0 |
| | | web.datestampLongFormat = EEEE, MMMM d, yyyy |
| | | |
| | | # Long timestamp format |
| | | # <http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html> |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.datetimestampLongFormat = EEEE, MMMM d, yyyy HH:mm Z |
| | | |
| | | # Mount URL parameters |
| | | # This setting controls if pretty or parameter URLs are used. |
| | | # i.e. |
| | | # if true: |
| | | # http://localhost/commit/myrepo/abcdef |
| | | # if false: |
| | | # http://localhost/commit/?r=myrepo&h=abcdef |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | web.mountParameters = true |
| | | |
| | | # Some servlet containers (e.g. Tomcat >= 6.0.10) disallow '/' (%2F) encoding |
| | | # in URLs as a security precaution for proxies. This setting tells Gitblit |
| | | # to preemptively replace '/' with '*' or '!' for url string parameters. |
| | | # |
| | | # <https://issues.apache.org/jira/browse/WICKET-1303> |
| | | # <http://tomcat.apache.org/security-6.html#Fixed_in_Apache_Tomcat_6.0.10> |
| | | # Add *-Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true* to your |
| | | # *CATALINA_OPTS* or to your JVM launch parameters |
| | | # |
| | | # SINCE 0.5.2 |
| | | web.forwardSlashCharacter = / |
| | | |
| | | # Show other URLs on the summary page for accessing your git repositories |
| | | # Use spaces to separate urls. |
| | | # |
| | | # {0} is the token for the repository name |
| | | # {1} is the token for the username |
| | | # |
| | | # The username is only practical if you have setup your other git serving |
| | | # solutions accounts to have the same username as the Gitblit account. |
| | | # |
| | | # e.g. |
| | | # web.otherUrls = ssh://localhost/git/{0} git://localhost/git/{0} https://{1}@localhost/r/{0} |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 0.5.0 |
| | | web.otherUrls = |
| | | |
| | | # Should HTTP/HTTPS URLs be displayed if the git servlet is enabled? |
| | | # default: true |
| | | # |
| | | # SINCE 1.7.0 |
| | | web.showHttpServletUrls = true |
| | | |
| | | # Should git URLs be displayed if the git daemon is enabled? |
| | | # default: true |
| | | # |
| | | # SINCE 1.7.0 |
| | | web.showGitDaemonUrls = true |
| | | |
| | | # Should SSH URLs be displayed if the SSH daemon is enabled? |
| | | # default: true |
| | | # |
| | | # SINCE 1.7.0 |
| | | web.showSshDaemonUrls = true |
| | | |
| | | # Should effective permissions be advertised for access paths defined in web.otherUrls? |
| | | # If false, gitblit will indicate unknown permissions for the external link. If true, |
| | | # gitblit will indicate permissions as defined within gitblit (including limiting to clone |
| | | # permission is the transport type is not a valid push mechaism in git.acceptedPushTransports). |
| | | # |
| | | # Configure with caution: Note that gitblit has no way of knowing if further restrictions |
| | | # are imposed by an external forwarding agent, so this may cause user confusion due to |
| | | # more rights being advertised than are available through the URL. It will NOT grant |
| | | # additional rights, but may incorrectly offer actions that are unavailable externally. |
| | | # default: false |
| | | # |
| | | # SINCE 1.7.0 |
| | | web.advertiseAccessPermissionForOtherUrls = false |
| | | |
| | | # Should app-specific clone links be displayed for SourceTree, SparkleShare, etc? |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.allowAppCloneLinks = true |
| | | |
| | | # Choose how to present the repositories list. |
| | | # grouped = group nested/subfolder repositories together (no sorting) |
| | | # flat = flat list of repositories (sorting allowed) |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.repositoryListType = grouped |
| | | |
| | | # If using a grouped repository list and there are repositories at the |
| | | # root level of your repositories folder, you may specify the displayed |
| | | # group name with this setting. This value is only used for web presentation. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.repositoryRootGroupName = main |
| | | |
| | | # Display the repository swatch color next to the repository name link in the |
| | | # repositories list. |
| | | # |
| | | # SINCE 0.8.0 |
| | | web.repositoryListSwatches = true |
| | | |
| | | # Defines the default commit message renderer. This can be configured |
| | | # per-repository. |
| | | # |
| | | # Valid values are: plain, markdown |
| | | # |
| | | # SINCE 1.4.0 |
| | | web.commitMessageRenderer = plain |
| | | |
| | | # Control if email addresses are shown in web ui |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.showEmailAddresses = true |
| | | |
| | | # Shows a combobox in the page links header with commit, committer, and author |
| | | # search selection. Default search is commit. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.showSearchTypeSelection = false |
| | | |
| | | # Controls display of activity graphs on the dashboard, activity, and summary |
| | | # pages. Charts are generated using Flotr2; an open source HTML5 library. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.generateActivityGraph = true |
| | | |
| | | # Displays the commits branch graph in the summary page and commits/log page. |
| | | # |
| | | # SINCE 1.4.0 |
| | | web.showBranchGraph = true |
| | | |
| | | # The default number of days to show on the activity page. |
| | | # Value must exceed 0 else default of 7 is used |
| | | # |
| | | # SINCE 0.8.0 |
| | | web.activityDuration = 7 |
| | | |
| | | # Choices for days of activity to display. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.3.0 |
| | | web.activityDurationChoices = 1 3 7 14 21 28 |
| | | |
| | | # Maximum number of days of activity that may be displayed on the activity page. |
| | | # |
| | | # SINCE 1.3.2 |
| | | web.activityDurationMaximum = 30 |
| | | |
| | | # The number of days of commits to cache in memory for the dashboard, activity, |
| | | # and project pages. A value of 0 will disable all caching and will parse commits |
| | | # in each repository per-request. If the value > 0 these pages will try to fulfill |
| | | # requests using the commit cache. If the request specifies a period which falls |
| | | # outside the commit cache window, then the cache will be ignored and the request |
| | | # will be fulfilled by brute-force parsing all relevant commits per-repository. |
| | | # |
| | | # Consider the values specified for *web.activityDurationChoices* when setting |
| | | # the cache size AND consider adjusting the JVM -Xmx heap parameter appropriately. |
| | | # |
| | | # SINCE 1.3.0 |
| | | # RESTART REQUIRED |
| | | web.activityCacheDays = 14 |
| | | |
| | | # Case-insensitive list of authors to exclude from metrics. Useful for |
| | | # eliminating bots. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.3.0 |
| | | web.metricAuthorExclusions = |
| | | |
| | | # The number of commits to display on the summary page |
| | | # Value must exceed 0 else default of 20 is used |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.summaryCommitCount = 16 |
| | | |
| | | # The number of tags/branches to display on the summary page. |
| | | # -1 = all tags/branches |
| | | # 0 = hide tags/branches |
| | | # N = N tags/branches |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.summaryRefsCount = 5 |
| | | |
| | | # Show a README file, if available, on the summary page. |
| | | # |
| | | # SINCE 1.4.0 |
| | | web.summaryShowReadme = false |
| | | |
| | | # The number of items to show on a page before showing the first, prev, next |
| | | # pagination links. A default of 50 is used for any invalid value. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.itemsPerPage = 50 |
| | | |
| | | # The number of reflog changes to display on the overview page |
| | | # Value must exceed 0 else default of 5 is used |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.overviewReflogCount = 5 |
| | | |
| | | # The number of reflog changes to show on a reflog page before show the first, |
| | | # prev, next pagination links. A default of 10 is used for any invalid value. |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.reflogChangesPerPage = 10 |
| | | |
| | | # Specify the names of documents in the root of your repository to be displayed |
| | | # in tabs on your repository docs page. If the name is not found in the root |
| | | # then no tab is added. The order specified is the order displayed. Do not |
| | | # specify a file extension as the aggregation of markup extensions + txt are used |
| | | # in the search algorithm. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.4.0 |
| | | web.documents = readme home index changelog contributing submitting_patches copying license notice authors |
| | | |
| | | # Registered file extensions to ignore during Lucene indexing |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 0.9.0 |
| | | web.luceneIgnoreExtensions = 7z arc arj bin bmp dll doc docx exe gif gz jar jpg lib lzh odg odf odt pdf ppt pptx png so swf tar xcf xls xlsx zip |
| | | |
| | | # Registered extensions for google-code-prettify |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 0.5.0 |
| | | web.prettyPrintExtensions = aea agc basic bat c cbm cl clj cmd cpp cs css dart el erl erlang frm fs go groovy h hpp hs htm html java js latex lisp ll llvm lsp lua ml moxie mumps n nemerle pascal php pl pm prefs properties proto py r R rb rd Rd rkt s S scala scm sh Splus sql ss tcl tex vb vbs vhd vhdl wiki xml xq xquery yaml yml ymlapollo |
| | | |
| | | # Registered extensions for markdown transformation |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 0.5.0 |
| | | web.markdownExtensions = md mkd markdown MD MKD |
| | | |
| | | # Registered extensions for mediawiki transformation |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 1.4.0 |
| | | web.mediawikiExtensions = mw mediawiki |
| | | |
| | | # Registered extensions for twiki transformation |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 1.4.0 |
| | | web.twikiExtensions = twiki |
| | | |
| | | # Registered extensions for textile transformation |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 1.4.0 |
| | | web.textileExtensions = textile |
| | | |
| | | # Registered extensions for confluence transformation |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 1.4.0 |
| | | web.confluenceExtensions = confluence |
| | | |
| | | # Registered extensions for tracwiki transformation |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 1.4.0 |
| | | web.tracwikiExtensions = tracwiki |
| | | |
| | | # Image extensions |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 0.5.0 |
| | | web.imageExtensions = bmp ico gif jpg jpeg png svg |
| | | |
| | | # Registered extensions for binary blobs |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 0.5.0 |
| | | web.binaryExtensions = 7z arc arj bin dll doc docx exe gz jar lib lzh odg odf odt pdf ppt pptx so tar xls xlsx zip |
| | | |
| | | # Aggressive heap management will run the garbage collector on every generated |
| | | # page. This slows down page generation a little but improves heap consumption. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.aggressiveHeapManagement = false |
| | | |
| | | # Run the webapp in debug mode |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | web.debugMode = false |
| | | |
| | | # Allows to hide the user logon form or dropdown menu from the top pane |
| | | # if it's not needed. |
| | | # |
| | | # SINCE 1.7.0 |
| | | web.displayUserPanel = true |
| | | |
| | | # Force a default locale for all users, ignoring the browser's settings. |
| | | # An empty value allows Gitblit to use the translation preferred by the browser. |
| | | # |
| | | # Changing this value while the server is running will only affect new sessions. |
| | | # |
| | | # e.g. web.forceDefaultLocale = en |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.forceDefaultLocale = |
| | | |
| | | # The following two settings serve to avoid browser overload when trying to |
| | | # render very large diffs. Both limits apply to commitdiffs, not to single-file |
| | | # diffs. |
| | | |
| | | # Maximum number of diff lines to display for a single file diff in a commitdiff. |
| | | # Defaults to 4000; can be adjusted in the range [500 .. 4000]. Smaller values |
| | | # set the limit to 500, larger values to 4000. The count includes context lines |
| | | # in the diff. |
| | | # |
| | | # If a file diff in a commitdiff produces more lines, the diff for that file is |
| | | # not shown in the commitdiff. |
| | | # |
| | | # SINCE 1.7.0 |
| | | web.maxDiffLinesPerFile = 4000 |
| | | |
| | | # Total maximum number of diff lines to show in a commitdiff. Defaults to 20000; |
| | | # can be adjusted in the range [1000 .. 20000]. Smaller values set the limit to |
| | | # 1000, larger values to 20000. The count includes context lines in diffs. |
| | | # |
| | | # If a commitdiff produces more lines, it is truncated after the first file |
| | | # that exceeds the limit. Diffs for subsequent files in the commit are not shown |
| | | # at all in the commitdiff. Omitted files are listed, though. |
| | | # |
| | | # SINCE 1.7.0 |
| | | web.maxDiffLines = 20000 |
| | | |
| | | # Enable/disable global regex substitutions (i.e. shared across repositories) |
| | | # |
| | | # SINCE 0.5.0 |
| | | # DEPRECATED 1.4.0 (migrate to bugtraq instead) |
| | | regex.global = true |
| | | |
| | | # Example global regex substitutions |
| | | # Use !!! to separate the search pattern and the replace pattern |
| | | # searchpattern!!!replacepattern |
| | | # SINCE 0.5.0 |
| | | |
| | | # regex.global.bug = \\b(Bug:)(\\s*[#]?|-){0,1}(\\d+)\\b!!!Bug: <a href="http://somehost/bug/$3">$3</a> |
| | | # SINCE 0.5.0 |
| | | |
| | | # Example Gerrit links |
| | | # regex.global.changeid = \\b(Change-Id:\\s*)([A-Za-z0-9]*)\\b!!!Change-Id: <a href="http://somehost/r/#q,$2,n,z">$2</a> |
| | | # regex.global.reviewedon = \\b(Reviewed-on:\\s*)([A-Za-z0-9:/\\.]*)\\b!!!Reviewed-on: <a href="$2">$2</a> |
| | | |
| | | # Example per-repository regex substitutions overrides global |
| | | # SINCE 0.5.0 |
| | | # regex.myrepository.bug = \\b(Bug:)(\\s*[#]?|-){0,1}(\\d+)\\b!!!Bug: <a href="http://elsewhere/bug/$3">$3</a> |
| | | |
| | | # |
| | | # Mail Settings |
| | | # SINCE 0.6.0 |
| | | # |
| | | # Mail settings are used to notify administrators of received federation proposals |
| | | # |
| | | |
| | | # ip or hostname of smtp server |
| | | # |
| | | # SINCE 0.6.0 |
| | | mail.server = |
| | | |
| | | # port to use for smtp requests |
| | | # |
| | | # SINCE 0.6.0 |
| | | mail.port = 25 |
| | | |
| | | # debug the mail executor |
| | | # |
| | | # SINCE 0.6.0 |
| | | mail.debug = false |
| | | |
| | | # use SMTPs flag |
| | | mail.smtps = false |
| | | |
| | | # use STARTTLS flag |
| | | # |
| | | # SINCE 1.6.0 |
| | | mail.starttls = false |
| | | |
| | | # if your smtp server requires authentication, supply the credentials here |
| | | # |
| | | # SINCE 0.6.0 |
| | | mail.username = |
| | | # SINCE 0.6.0 |
| | | mail.password = |
| | | |
| | | # from address for generated emails |
| | | # |
| | | # SINCE 0.6.0 |
| | | mail.fromAddress = |
| | | |
| | | # List of email addresses for the Gitblit administrators |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 0.6.0 |
| | | mail.adminAddresses = |
| | | |
| | | # List of email addresses for sending push email notifications. |
| | | # |
| | | # This key currently requires use of the sendemail.groovy hook script. |
| | | # If you set sendemail.groovy in *groovy.postReceiveScripts* then email |
| | | # notifications for all repositories (regardless of access restrictions!) |
| | | # will be sent to these addresses. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 0.8.0 |
| | | mail.mailingLists = |
| | | |
| | | # |
| | | # Federation Settings |
| | | # SINCE 0.6.0 |
| | | # |
| | | # A Gitblit federation is a way to backup one Gitblit instance to another. |
| | | # |
| | | # *git.enableGitServlet* must be true to use this feature. |
| | | |
| | | # Your federation name is used for federation status acknowledgments. If it is |
| | | # unset, and you elect to send a status acknowledgment, your Gitblit instance |
| | | # will be identified by its hostname, if available, else your internal ip address. |
| | | # The source Gitblit instance will also append your external IP address to your |
| | | # identification to differentiate multiple pulling systems behind a single proxy. |
| | | # |
| | | # SINCE 0.6.0 |
| | | federation.name = |
| | | |
| | | # Specify the passphrase of this Gitblit instance. |
| | | # |
| | | # An unspecified (empty) passphrase disables processing federation requests. |
| | | # |
| | | # This value can be anything you want: an integer, a sentence, an haiku, etc. |
| | | # Keep the value simple, though, to avoid Java properties file encoding issues. |
| | | # |
| | | # Changing your passphrase will break any registrations you have established with other |
| | | # Gitblit instances. |
| | | # |
| | | # CASE-SENSITIVE |
| | | # SINCE 0.6.0 |
| | | # RESTART REQUIRED *(only to enable or disable federation)* |
| | | federation.passphrase = |
| | | |
| | | # Control whether or not this Gitblit instance can receive federation proposals |
| | | # from another Gitblit instance. Registering a federated Gitblit is a manual |
| | | # process. Proposals help to simplify that process by allowing a remote Gitblit |
| | | # instance to send your Gitblit instance the federation pull data. |
| | | # |
| | | # SINCE 0.6.0 |
| | | federation.allowProposals = false |
| | | |
| | | # The destination folder for cached federation proposals. |
| | | # Use forward slashes even on Windows!! |
| | | # |
| | | # SINCE 0.6.0 |
| | | # BASEFOLDER |
| | | federation.proposalsFolder = ${baseFolder}/proposals |
| | | |
| | | # The default pull frequency if frequency is unspecified on a registration |
| | | # |
| | | # SINCE 0.6.0 |
| | | federation.defaultFrequency = 60 mins |
| | | |
| | | # Federation Sets are named groups of repositories. The Federation Sets are |
| | | # available for selection in the repository settings page. You can assign a |
| | | # repository to one or more sets and then distribute the token for the set. |
| | | # This allows you to grant federation pull access to a subset of your available |
| | | # repositories. Tokens for federation sets only grant repository pull access. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 0.6.0 |
| | | federation.sets = |
| | | |
| | | # Federation pull registrations |
| | | # Registrations are read once, at startup. |
| | | # |
| | | # RESTART REQUIRED |
| | | # |
| | | # frequency: |
| | | # The shortest frequency allowed is every 5 minutes |
| | | # Decimal frequency values are cast to integers |
| | | # Frequency values may be specified in mins, hours, or days |
| | | # Values that can not be parsed or are unspecified default to *federation.defaultFrequency* |
| | | # |
| | | # folder: |
| | | # if unspecified, the folder is *git.repositoriesFolder* |
| | | # if specified, the folder is relative to *git.repositoriesFolder* |
| | | # |
| | | # bare: |
| | | # if true, each repository will be created as a *bare* repository and will not |
| | | # have a working directory. |
| | | # |
| | | # if false, each repository will be created as a normal repository suitable |
| | | # for local work. |
| | | # |
| | | # mirror: |
| | | # if true, each repository HEAD is reset to *origin/master* after each pull. |
| | | # The repository will be flagged *isFrozen* after the initial clone. |
| | | # |
| | | # if false, each repository HEAD will point to the FETCH_HEAD of the initial |
| | | # clone from the origin until pushed to or otherwise manipulated. |
| | | # |
| | | # mergeAccounts: |
| | | # if true, remote accounts and their permissions are merged into your |
| | | # users.properties file |
| | | # |
| | | # notifyOnError: |
| | | # if true and the mail configuration is properly set, administrators will be |
| | | # notified by email of pull failures |
| | | # |
| | | # include and exclude: |
| | | # Space-delimited list of repositories to include or exclude from pull |
| | | # may be * wildcard to include or exclude all |
| | | # may use fuzzy match (e.g. org.eclipse.*) |
| | | |
| | | # |
| | | # (Nearly) Perfect Mirror example |
| | | # |
| | | |
| | | #federation.example1.url = https://go.gitblit.com |
| | | #federation.example1.token = 6f3b8a24bf970f17289b234284c94f43eb42f0e4 |
| | | #federation.example1.frequency = 120 mins |
| | | #federation.example1.folder = |
| | | #federation.example1.bare = true |
| | | #federation.example1.mirror = true |
| | | #federation.example1.mergeAccounts = true |
| | | |
| | | # |
| | | # Advanced Realm Settings |
| | | # |
| | | |
| | | # Auto-creates user accounts based on the servlet container principal. This |
| | | # assumes that your Gitblit install is a protected resource and your container's |
| | | # authentication process intercepts all Gitblit requests. |
| | | # |
| | | # SINCE 1.3.0 |
| | | realm.container.autoCreateAccounts = false |
| | | |
| | | # A set of mapping used to map HTTP session attributes to user informations |
| | | # They are used if realm.container.autoCreateAccounts is set to true and |
| | | # the webapp container used can fill the session with user informations |
| | | # |
| | | # SINCE 1.7.0 |
| | | realm.container.autoAccounts.displayName = |
| | | realm.container.autoAccounts.emailAddress = |
| | | realm.container.autoAccounts.locale = |
| | | |
| | | # If the user's created by the webapp container is given this role, |
| | | # the user created will be a admin user. |
| | | # |
| | | # SINCE 1.7.0 |
| | | realm.container.autoAccounts.adminRole = |
| | | |
| | | |
| | | # Allow or prohibit Windows guest account logins |
| | | # |
| | | # SINCE 1.3.0 |
| | | realm.windows.allowGuests = false |
| | | |
| | | # Allow user accounts belonging to the BUILTIN\Administrators group to be |
| | | # Gitblit administrators. |
| | | # |
| | | # SINCE 1.4.0 |
| | | realm.windows.permitBuiltInAdministrators = true |
| | | |
| | | # The default domain for authentication. |
| | | # |
| | | # If specified, this domain will be used for authentication UNLESS the supplied |
| | | # login name manually specifies a domain (.e.g. mydomain\james or james@mydomain) |
| | | # |
| | | # If unspecified, the username must be specified in UPN format (name@domain). |
| | | # |
| | | # if "." (dot) is specified, ONLY the local account database will be used. |
| | | # |
| | | # SINCE 1.3.0 |
| | | realm.windows.defaultDomain = |
| | | |
| | | # The PAM service name for authentication. |
| | | # default: system-auth |
| | | # |
| | | # SINCE 1.3.1 |
| | | realm.pam.serviceName = system-auth |
| | | |
| | | # The Apache htpasswd file that contains the users and passwords. |
| | | # default: ${baseFolder}/htpasswd |
| | | # |
| | | # RESTART REQUIRED |
| | | # BASEFOLDER |
| | | # SINCE 1.3.2 |
| | | realm.htpasswd.userfile = ${baseFolder}/htpasswd |
| | | |
| | | # The name of the HTTP header containing the user name to trust as authenticated |
| | | # default: none |
| | | # |
| | | # WARNING: only use this mechanism if your requests are coming from a trusted |
| | | # and secure source such as a self managed reverse proxy! |
| | | # |
| | | # RESTART REQUIRED |
| | | # SINCE 1.7.2 |
| | | realm.httpheader.userheader = |
| | | |
| | | # The name of the HTTP header containing the team names of which the user is a member. |
| | | # If this is defined, then only groups from the headers will be available, whereas |
| | | # if this remains undefined, then local groups will be used. |
| | | # |
| | | # This setting requires that you have configured realm.httpheader.userheader. |
| | | # |
| | | # default: none |
| | | # |
| | | # RESTART REQUIRED |
| | | # SINCE 1.7.2 |
| | | realm.httpheader.teamheader = |
| | | |
| | | # The regular expression pattern used to separate team names in the team header value |
| | | # default: , |
| | | # |
| | | # This setting requires that you have configured realm.httpheader.teamheader |
| | | # |
| | | # RESTART REQUIRED |
| | | # SINCE 1.7.2 |
| | | realm.httpheader.teamseparator = , |
| | | |
| | | # Auto-creates user accounts when successfully authenticated based on HTTP headers. |
| | | # |
| | | # SINCE 1.7.2 |
| | | realm.httpheader.autoCreateAccounts = false |
| | | |
| | | # Restrict the Salesforce user to members of this org. |
| | | # default: 0 (i.e. do not check the Org ID) |
| | | # |
| | | # SINCE 1.3.0 |
| | | realm.salesforce.orgId = 0 |
| | | |
| | | # URL of the LDAP server. |
| | | # To use encrypted transport, use either ldaps:// URL for SSL or ldap+tls:// to |
| | | # send StartTLS command. |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.server = ldap://localhost |
| | | |
| | | # Login username for LDAP searches. |
| | | # If this value is unspecified, anonymous LDAP login will be used. |
| | | # |
| | | # e.g. mydomain\\username |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.username = cn=Directory Manager |
| | | |
| | | # Login password for LDAP searches. |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.password = password |
| | | |
| | | # Bind pattern for Authentication. |
| | | # Allow to directly authenticate an user without LDAP Searches. |
| | | # |
| | | # e.g. CN=${username},OU=Users,OU=UserControl,OU=MyOrganization,DC=MyDomain |
| | | # |
| | | # SINCE 1.5.0 |
| | | realm.ldap.bindpattern = |
| | | |
| | | |
| | | # Delegate team membership control to LDAP. |
| | | # |
| | | # If true, team user memberships will be specified by LDAP groups. This will |
| | | # disable team selection in Edit User and user selection in Edit Team. |
| | | # |
| | | # If false, LDAP will only be used for authentication and Gitblit will maintain |
| | | # team memberships with the *realm.ldap.backingUserService*. |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.maintainTeams = false |
| | | |
| | | # Root node for all LDAP users |
| | | # |
| | | # This is the root node from which subtree user searches will begin. |
| | | # If blank, Gitblit will search ALL nodes. |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.accountBase = OU=Users,OU=UserControl,OU=MyOrganization,DC=MyDomain |
| | | |
| | | # Filter criteria for LDAP users |
| | | # |
| | | # Query pattern to use when searching for a user account. This may be any valid |
| | | # LDAP query expression, including the standard (&) and (|) operators. |
| | | # |
| | | # Variables may be injected via the ${variableName} syntax. |
| | | # Recognized variables are: |
| | | # ${username} - The text entered as the user name |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.accountPattern = (&(objectClass=person)(sAMAccountName=${username})) |
| | | |
| | | # Root node for all LDAP groups to be used as Gitblit Teams |
| | | # |
| | | # This is the root node from which subtree team searches will begin. |
| | | # If blank, Gitblit will search ALL nodes. |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.groupBase = OU=Groups,OU=UserControl,OU=MyOrganization,DC=MyDomain |
| | | |
| | | # Filter criteria for LDAP groups |
| | | # |
| | | # Query pattern to use when searching for a team. This may be any valid |
| | | # LDAP query expression, including the standard (&) and (|) operators. |
| | | # |
| | | # Variables may be injected via the ${variableName} syntax. |
| | | # Recognized variables are: |
| | | # ${username} - The text entered as the user name |
| | | # ${dn} - The Distinguished Name of the user logged in |
| | | # |
| | | # All attributes from the LDAP User record are available. For example, if a user |
| | | # has an attribute "fullName" set to "John", "(fn=${fullName})" will be |
| | | # translated to "(fn=John)". |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.groupMemberPattern = (&(objectClass=group)(member=${dn})) |
| | | |
| | | # Filter criteria for empty LDAP groups |
| | | # |
| | | # Query pattern to use when searching for an empty team. This may be any valid |
| | | # LDAP query expression, including the standard (&) and (|) operators. |
| | | # |
| | | # default: (&(objectClass=group)(!(member=*))) |
| | | # SINCE 1.4.0 |
| | | realm.ldap.groupEmptyMemberPattern = (&(objectClass=group)(!(member=*))) |
| | | |
| | | # LDAP users or groups that should be given administrator privileges. |
| | | # |
| | | # Teams are specified with a leading '@' character. Groups with spaces in the |
| | | # name can be entered as "@team name". This setting only applies when using |
| | | # LDAP to maintain team memberships. |
| | | # |
| | | # e.g. realm.ldap.admins = john @git_admins "@git admins" |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.0.0 |
| | | realm.ldap.admins = @Git_Admins |
| | | |
| | | # Attribute(s) on the USER record that indicate their display (or full) name. |
| | | # Leave blank for no mapping available in LDAP. |
| | | # |
| | | # This may be a single attribute, or a string of multiple attributes. Examples: |
| | | # displayName - Uses the attribute 'displayName' on the user record |
| | | # ${personalTitle}. ${givenName} ${surname} - Will concatenate the 3 |
| | | # attributes together, with a '.' after personalTitle |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.displayName = displayName |
| | | |
| | | # Attribute(s) on the USER record that indicate their email address. |
| | | # Leave blank for no mapping available in LDAP. |
| | | # |
| | | # This may be a single attribute, or a string of multiple attributes. Examples: |
| | | # email - Uses the attribute 'email' on the user record |
| | | # ${givenName}.${surname}@gitblit.com -Will concatenate the 2 attributes |
| | | # together with a '.' and '@' creating something like first.last@gitblit.com |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.email = email |
| | | |
| | | # Attribute on the USER record that indicate their username to be used in gitblit |
| | | # when synchronizing users from LDAP |
| | | # if blank, Gitblit will use uid |
| | | # For MS Active Directory this may be sAMAccountName |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.uid = uid |
| | | |
| | | # Defines whether to synchronize all LDAP users and teams into the user service |
| | | # |
| | | # Valid values: true, false |
| | | # If left blank, false is assumed |
| | | # |
| | | # SINCE 1.4.0 |
| | | realm.ldap.synchronize = false |
| | | |
| | | # Defines the period to be used when synchronizing users and teams from ldap. |
| | | # |
| | | # Must be of the form '<long> <TimeUnit>' where <TimeUnit> is one of 'MILLISECONDS', 'SECONDS', 'MINUTES', 'HOURS', 'DAYS' |
| | | |
| | | # default: 5 MINUTES |
| | | # |
| | | # RESTART REQUIRED |
| | | # SINCE 1.4.0 |
| | | realm.ldap.syncPeriod = 5 MINUTES |
| | | |
| | | # Defines whether to delete non-existent LDAP users from the user service |
| | | # during synchronization. depends on realm.ldap.synchronize = true |
| | | # |
| | | # Valid values: true, false |
| | | # If left blank, true is assumed |
| | | # |
| | | # SINCE 1.4.0 |
| | | realm.ldap.removeDeletedUsers = true |
| | | |
| | | # URL of the Redmine. |
| | | # |
| | | # SINCE 1.2.0 |
| | | realm.redmine.url = http://example.com/redmine |
| | | |
| | | # |
| | | # Gitblit GO Server Settings |
| | | # The following settings only affect the integrated GO variant. |
| | | # |
| | | |
| | | # The temporary folder to decompress the embedded gitblit webapp. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | # BASEFOLDER |
| | | server.tempFolder = ${baseFolder}/temp |
| | | |
| | | # Specify the maximum number of concurrent http/https Jetty worker |
| | | # threads to allow. This setting does not affect other threaded |
| | | # daemons and components of Gitblit. |
| | | # |
| | | # SINCE 1.3.0 |
| | | # RESTART REQUIRED |
| | | server.threadPoolSize = 50 |
| | | |
| | | # Context path for the GO application. You might want to change the context |
| | | # path if running Gitblit behind a proxy layer such as mod_proxy. |
| | | # |
| | | # SINCE 0.7.0 |
| | | # RESTART REQUIRED |
| | | server.contextPath = / |
| | | |
| | | # Standard http port to serve. <= 0 disables this connector. |
| | | # On Unix/Linux systems, ports < 1024 require root permissions. |
| | | # Recommended value: 80 or 8080 |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | server.httpPort = 0 |
| | | |
| | | # Secure/SSL https port to serve. <= 0 disables this connector. |
| | | # On Unix/Linux systems, ports < 1024 require root permissions. |
| | | # Recommended value: 443 or 8443 |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | server.httpsPort = 8443 |
| | | |
| | | # Automatically redirect http requests to the secure https connector. |
| | | # |
| | | # This setting requires that you have configured server.httpPort and server.httpsPort. |
| | | # Unless you are on a private LAN where you trust all client connections, it is |
| | | # recommended to use https for all communications. |
| | | # |
| | | # SINCE 1.4.0 |
| | | # RESTART REQUIRED |
| | | server.redirectToHttpsPort = false |
| | | |
| | | # Specify the interface for Jetty to bind the standard connector. |
| | | # You may specify an ip or an empty value to bind to all interfaces. |
| | | # Specifying localhost will result in Gitblit ONLY listening to requests to |
| | | # localhost. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | server.httpBindInterface = |
| | | |
| | | # Specify the interface for Jetty to bind the secure connector. |
| | | # You may specify an ip or an empty value to bind to all interfaces. |
| | | # Specifying localhost will result in Gitblit ONLY listening to requests to |
| | | # localhost. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | server.httpsBindInterface = |
| | | |
| | | # Alias of certificate to use for https/SSL serving. If blank the first |
| | | # certificate found in the keystore will be used. |
| | | # |
| | | # SINCE 1.2.0 |
| | | # RESTART REQUIRED |
| | | server.certificateAlias = localhost |
| | | |
| | | # Password for SSL keystore. |
| | | # Keystore password and certificate password must match. |
| | | # This is provided for convenience, its probably more secure to set this value |
| | | # using the --storePassword command line parameter. |
| | | # |
| | | # If you are using the official JRE or JDK from Oracle you may not have the |
| | | # JCE Unlimited Strength Jurisdiction Policy files bundled with your JVM. Because |
| | | # of this, your store/key password can not exceed 7 characters. If you require |
| | | # longer passwords you may need to install the JCE Unlimited Strength Jurisdiction |
| | | # Policy files from Oracle. |
| | | # |
| | | # http://www.oracle.com/technetwork/java/javase/downloads/index.html |
| | | # |
| | | # Gitblit and the Gitblit Certificate Authority will both indicate if Unlimited |
| | | # Strength encryption is available. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | server.storePassword = gitblit |
| | | |
| | | # If serving over https (recommended) you might consider requiring clients to |
| | | # authenticate with ssl certificates. If enabled, only https clients with the |
| | | # a valid client certificate will be able to access Gitblit. |
| | | # |
| | | # If disabled, client certificate authentication is optional and will be tried |
| | | # first before falling-back to form authentication or basic authentication. |
| | | # |
| | | # Requiring client certificates to access any of Gitblit may be too extreme, |
| | | # consider this carefully. |
| | | # |
| | | # SINCE 1.2.0 |
| | | # RESTART REQUIRED |
| | | server.requireClientCertificates = false |
| | | |
| | | # Port for shutdown monitor to listen on. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | server.shutdownPort = 8081 |
| | | |
| | | # |
| | | # Gitblit Filestore Settings |
| | | # |
| | | # The location to save the filestore blobs |
| | | # |
| | | # SINCE 1.7.0 |
| | | filestore.storageFolder = ${baseFolder}/lfs |
| | | |
| | | # Maximum allowable upload size |
| | | # The default value, -1, disables upload limits. |
| | | # Common unit suffixes of k, m, or g are supported. |
| | | # SINCE 1.7.0 |
| | | filestore.maxUploadSize = -1 |
| | |
| | | # |
| | | # Gitblit Settings |
| | | # GITBLIT.PROPERTIES |
| | | # |
| | | |
| | | # This settings file supports parameterization from the command-line for the |
| | | # following command-line parameters: |
| | | # |
| | | # --baseFolder ${baseFolder} SINCE 1.2.1 |
| | | # |
| | | # Settings that support ${baseFolder} parameter substitution are indicated with the |
| | | # BASEFOLDER attribute. If the --baseFolder argument is unspecified, ${baseFolder} |
| | | # and it's trailing / will be discarded from the setting value leaving a relative |
| | | # path that is equivalent to pre-1.2.1 releases. |
| | | # |
| | | # e.g. "${baseFolder}/git" becomes "git", if --baseFolder is unspecified |
| | | # |
| | | # Git Servlet Settings |
| | | # Define your custom settings in this file and/or include settings defined in |
| | | # other properties files. |
| | | # |
| | | |
| | | # Base folder for repositories. |
| | | # This folder may contain bare and non-bare repositories but Gitblit will only |
| | | # allow you to push to bare repositories. |
| | | # Use forward slashes even on Windows!! |
| | | # e.g. c:/gitrepos |
| | | # Include Gitblit's 'defaults.properties' within your configuration. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | # BASEFOLDER |
| | | git.repositoriesFolder = ${baseFolder}/git |
| | | |
| | | # Build the available repository list at startup and cache this list for reuse. |
| | | # This reduces disk io when presenting the repositories page, responding to rpcs, |
| | | # etc, but it means that Gitblit will not automatically identify repositories |
| | | # added or deleted by external tools. |
| | | # NOTE: Gitblit will not automatically reload "included" properties. Gitblit |
| | | # only watches the 'gitblit.properties' file for modifications. |
| | | # |
| | | # For this case you can use curl, wget, etc to issue an rpc request to clear the |
| | | # cache (e.g. https://localhost/rpc?req=CLEAR_REPOSITORY_CACHE) |
| | | # Paths may be relative to the ${baseFolder} or they may be absolute. |
| | | # |
| | | # SINCE 1.1.0 |
| | | git.cacheRepositoryList = true |
| | | # COMMA-DELIMITED |
| | | # SINCE 1.7.0 |
| | | include = defaults.properties |
| | | |
| | | # Search the repositories folder subfolders for other repositories. |
| | | # Repositories MAY NOT be nested (i.e. one repository within another) |
| | | # but they may be grouped together in subfolders. |
| | | # e.g. c:/gitrepos/libraries/mylibrary.git |
| | | # c:/gitrepos/libraries/myotherlibrary.git |
| | | # |
| | | # SINCE 0.5.0 |
| | | git.searchRepositoriesSubfolders = true |
| | | |
| | | # Maximum number of folders to recurse into when searching for repositories. |
| | | # The default value, -1, disables depth limits. |
| | | # |
| | | # SINCE 1.1.0 |
| | | git.searchRecursionDepth = -1 |
| | | |
| | | # List of regex exclusion patterns to match against folders found in |
| | | # *git.repositoriesFolder*. |
| | | # Use forward slashes even on Windows!! |
| | | # e.g. test/jgit\.git |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 1.1.0 |
| | | git.searchExclusions = |
| | | |
| | | # List of regex url patterns for extracting a repository name when locating |
| | | # submodules. |
| | | # e.g. git.submoduleUrlPatterns = .*?://github.com/(.*) will extract |
| | | # *gitblit/gitblit.git* from *git://github.com/gitblit/gitblit.git* |
| | | # If no matches are found then the submodule repository name is assumed to be |
| | | # whatever trails the last / character. (e.g. gitblit.git). |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 1.1.0 |
| | | git.submoduleUrlPatterns = .*?://github.com/(.*) |
| | | |
| | | # Specify the interface for Git Daemon to bind it's service. |
| | | # You may specify an ip or an empty value to bind to all interfaces. |
| | | # Specifying localhost will result in Gitblit ONLY listening to requests to |
| | | # localhost. |
| | | # |
| | | # SINCE 1.3.0 |
| | | # RESTART REQUIRED |
| | | git.daemonBindInterface = |
| | | |
| | | # port for serving the Git Daemon service. <= 0 disables this service. |
| | | # On Unix/Linux systems, ports < 1024 require root permissions. |
| | | # Recommended value: 9418 |
| | | # |
| | | # SINCE 1.3.0 |
| | | # RESTART REQUIRED |
| | | git.daemonPort = 9418 |
| | | |
| | | # The port for serving the SSH service. <= 0 disables this service. |
| | | # On Unix/Linux systems, ports < 1024 require root permissions. |
| | | # Recommended value: 29418 |
| | | # |
| | | # SINCE 1.5.0 |
| | | # RESTART REQUIRED |
| | | git.sshPort = 29418 |
| | | |
| | | # Specify the interface for the SSH daemon to bind its service. |
| | | # You may specify an ip or an empty value to bind to all interfaces. |
| | | # Specifying localhost will result in Gitblit ONLY listening to requests to |
| | | # localhost. |
| | | # |
| | | # SINCE 1.5.0 |
| | | # RESTART REQUIRED |
| | | git.sshBindInterface = |
| | | |
| | | # Specify the SSH key manager to use for retrieving, storing, and removing |
| | | # SSH keys. |
| | | # |
| | | # Valid key managers are: |
| | | # com.gitblit.transport.ssh.FileKeyManager |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.sshKeysManager = com.gitblit.transport.ssh.FileKeyManager |
| | | |
| | | # Directory for storing user SSH keys when using the FileKeyManager. |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.sshKeysFolder= ${baseFolder}/ssh |
| | | |
| | | # SSH backend NIO2|MINA. |
| | | # |
| | | # The Apache Mina project recommends using the NIO2 backend. |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.sshBackend = NIO2 |
| | | |
| | | # Number of threads used to parse a command line submitted by a client over SSH |
| | | # for execution, create the internal data structures used by that command, |
| | | # and schedule it for execution on another thread. |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.sshCommandStartThreads = 2 |
| | | |
| | | |
| | | # Allow push/pull over http/https with JGit servlet. |
| | | # If you do NOT want to allow Git clients to clone/push to Gitblit set this |
| | | # to false. You might want to do this if you are only using ssh:// or git://. |
| | | # If you set this false, consider changing the *web.otherUrls* setting to |
| | | # indicate your clone/push urls. |
| | | # |
| | | # SINCE 0.5.0 |
| | | git.enableGitServlet = true |
| | | |
| | | # If you want to restrict all git servlet access to those with valid X509 client |
| | | # certificates then set this value to true. |
| | | # |
| | | # SINCE 1.2.0 |
| | | git.requiresClientCertificate = false |
| | | |
| | | # Enforce date checks on client certificates to ensure that they are not being |
| | | # used prematurely and that they have not expired. |
| | | # |
| | | # SINCE 1.2.0 |
| | | git.enforceCertificateValidity = true |
| | | |
| | | # List of OIDs to extract from a client certificate DN to map a certificate to |
| | | # an account username. |
| | | # |
| | | # e.g. git.certificateUsernameOIDs = CN |
| | | # e.g. git.certificateUsernameOIDs = FirstName LastName |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.2.0 |
| | | git.certificateUsernameOIDs = CN |
| | | |
| | | # Only serve/display bare repositories. |
| | | # If there are non-bare repositories in git.repositoriesFolder and this setting |
| | | # is true, they will be excluded from the ui. |
| | | # |
| | | # SINCE 0.9.0 |
| | | git.onlyAccessBareRepositories = false |
| | | |
| | | |
| | | # Specify the list of acceptable transports for pushes. |
| | | # If this setting is empty, all transports are acceptable. |
| | | # |
| | | # Valid choices are: GIT HTTP HTTPS SSH |
| | | # |
| | | # SINCE 1.5.0 |
| | | # SPACE-DELIMITED |
| | | git.acceptedPushTransports = HTTP HTTPS SSH |
| | | |
| | | # Allow an authenticated user to create a destination repository on a push if |
| | | # the repository does not already exist. |
| | | # |
| | | # Administrator accounts can create a repository in any project. |
| | | # These repositories are created with the default access restriction and authorization |
| | | # control values. The pushing account is set as the owner. |
| | | # |
| | | # Non-administrator accounts with the CREATE role may create personal repositories. |
| | | # These repositories are created as VIEW restricted for NAMED users. |
| | | # The pushing account is set as the owner. |
| | | # |
| | | # SINCE 1.2.0 |
| | | git.allowCreateOnPush = true |
| | | |
| | | # Global setting to control anonymous pushes. |
| | | # |
| | | # This setting allows/rejects anonymous pushes at the level of the receive pack. |
| | | # This trumps all repository config settings. While anonymous pushes are convenient |
| | | # on your own box when you are a lone developer, they are not recommended for |
| | | # any multi-user installation where accountability is required. Since Gitblit |
| | | # tracks pushes and user accounts, allowing anonymous pushes compromises that |
| | | # information. |
| | | # |
| | | # SINCE 1.4.0 |
| | | git.allowAnonymousPushes = false |
| | | |
| | | # The default access restriction for new repositories. |
| | | # Valid values are NONE, PUSH, CLONE, VIEW |
| | | # NONE = anonymous view, clone, & push |
| | | # PUSH = anonymous view & clone and authenticated push |
| | | # CLONE = anonymous view, authenticated clone & push |
| | | # VIEW = authenticated view, clone, & push |
| | | # |
| | | # SINCE 1.0.0 |
| | | git.defaultAccessRestriction = PUSH |
| | | |
| | | # The default authorization control for new repositories. |
| | | # Valid values are AUTHENTICATED and NAMED |
| | | # AUTHENTICATED = any authenticated user is granted restricted access |
| | | # NAMED = only named users/teams are granted restricted access |
| | | # |
| | | # SINCE 1.1.0 |
| | | git.defaultAuthorizationControl = NAMED |
| | | |
| | | # The prefix for a users personal repository directory. |
| | | # |
| | | # Personal user repositories are created in this directory, named by the user name |
| | | # prefixed with the userRepositoryPrefix. For eaxmple, a user 'john' would have his |
| | | # personal repositories in the directory '~john'. |
| | | # |
| | | # Cannot be an empty string. Also, absolute paths are changed to relative paths by |
| | | # removing the first directory separator. |
| | | # |
| | | # It is not recommended to change this value AFTER your user's have created |
| | | # personal repositories because it will break all permissions, ownership, and |
| | | # repository push/pull operations. |
| | | # |
| | | # RESTART REQUIRED |
| | | # SINCE 1.4.0 |
| | | git.userRepositoryPrefix = ~ |
| | | |
| | | # The default incremental push tag prefix. Tag prefix applied to a repository |
| | | # that has automatic push tags enabled and does not specify a custom tag prefix. |
| | | # |
| | | # If incremental push tags are enabled, the tips of each branch in the push will |
| | | # be tagged with an increasing revision integer. |
| | | # |
| | | # e.g. refs/tags/r2345 or refs/tags/rev_2345 |
| | | # |
| | | # SINCE 1.3.0 |
| | | git.defaultIncrementalPushTagPrefix = r |
| | | |
| | | # Controls creating a repository as --shared on Unix servers. |
| | | # |
| | | # In an Unix environment where mixed access methods exist for shared repositories, |
| | | # the repository should be created with 'git init --shared' to make sure that |
| | | # it can be accessed e.g. via ssh (user git) and http (user www-data). |
| | | # |
| | | # Valid values are the values available for the '--shared' option. The the manual |
| | | # page for 'git init' for more information on shared repositories. |
| | | # |
| | | # SINCE 1.4.0 |
| | | git.createRepositoriesShared = false |
| | | |
| | | # Directory for gitignore templates used during repository creation. |
| | | # |
| | | # SINCE 1.6.0 |
| | | git.gitignoreFolder = ${baseFolder}/gitignore |
| | | |
| | | # Enable JGit-based garbage collection. (!!EXPERIMENTAL!!) |
| | | # |
| | | # USE AT YOUR OWN RISK! |
| | | # |
| | | # If enabled, the garbage collection executor scans all repositories once a day |
| | | # at the hour of your choosing. The GC executor will take each repository "offline", |
| | | # one-at-a-time, to check if the repository satisfies it's GC trigger requirements. |
| | | # |
| | | # While the repository is offline it will be inaccessible from the web UI or from |
| | | # any of the other services (git, rpc, rss, etc). |
| | | # |
| | | # Gitblit's GC Executor MAY NOT PLAY NICE with the other Git kids on the block, |
| | | # especially on Windows systems, so if you are using other tools please coordinate |
| | | # their usage with your GC Executor schedule or do not use this feature. |
| | | # |
| | | # The GC algorithm complex and the JGit team advises caution when using their |
| | | # young implementation of GC. |
| | | # |
| | | # http://wiki.eclipse.org/EGit/New_and_Noteworthy/2.1#Garbage_Collector_and_Repository_Storage_Statistics |
| | | # |
| | | # EXPERIMENTAL |
| | | # SINCE 1.2.0 |
| | | # RESTART REQUIRED |
| | | git.enableGarbageCollection = false |
| | | |
| | | # Hour of the day for the GC Executor to scan repositories. |
| | | # This value is in 24-hour time. |
| | | # |
| | | # SINCE 1.2.0 |
| | | git.garbageCollectionHour = 0 |
| | | |
| | | # The default minimum total filesize of loose objects to trigger early garbage |
| | | # collection. |
| | | # |
| | | # You may specify a custom threshold for a repository in the repository's settings. |
| | | # Common unit suffixes of k, m, or g are supported. |
| | | # |
| | | # SINCE 1.2.0 |
| | | git.defaultGarbageCollectionThreshold = 500k |
| | | |
| | | # The default period, in days, between GCs for a repository. If the total filesize |
| | | # of the loose object exceeds *git.garbageCollectionThreshold* or the repository's |
| | | # custom threshold, this period will be short-circuited. |
| | | # |
| | | # e.g. if a repository collects 100KB of loose objects every day with a 500KB |
| | | # threshold and a period of 7 days, it will take 5 days for the loose objects to |
| | | # be collected, packed, and pruned. |
| | | # |
| | | # OR |
| | | # |
| | | # if a repository collects 10KB of loose objects every day with a 500KB threshold |
| | | # and a period of 7 days, it will take the full 7 days for the loose objects to be |
| | | # collected, packed, and pruned. |
| | | # |
| | | # You may specify a custom period for a repository in the repository's settings. |
| | | # |
| | | # The minimum value is 1 day since the GC Executor only runs once a day. |
| | | # |
| | | # SINCE 1.2.0 |
| | | git.defaultGarbageCollectionPeriod = 7 |
| | | |
| | | # Gitblit can automatically fetch ref updates for a properly configured mirror |
| | | # repository. |
| | | # |
| | | # Requirements: |
| | | # 1. you must manually clone the repository using native git |
| | | # git clone --mirror git://somewhere.com/myrepo.git |
| | | # 2. the "origin" remote must be the mirror source |
| | | # 3. the "origin" repository must be accessible without authentication OR the |
| | | # credentials must be embedded in the origin url (not recommended) |
| | | # |
| | | # Notes: |
| | | # 1. "origin" SSH urls are untested and not likely to work |
| | | # 2. mirrors cloned while Gitblit is running are likely to require clearing the |
| | | # gitblit cache (link on the repositories page of an administrator account) |
| | | # 3. Gitblit will automatically repair any invalid fetch refspecs with a "//" |
| | | # sequence. |
| | | # |
| | | # SINCE 1.4.0 |
| | | # RESTART REQUIRED |
| | | git.enableMirroring = false |
| | | |
| | | # Specify the period between update checks for mirrored repositories. |
| | | # The shortest period you may specify between mirror update checks is 5 mins. |
| | | # |
| | | # SINCE 1.4.0 |
| | | # RESTART REQUIRED |
| | | git.mirrorPeriod = 30 mins |
| | | |
| | | # Number of bytes of a pack file to load into memory in a single read operation. |
| | | # This is the "page size" of the JGit buffer cache, used for all pack access |
| | | # operations. All disk IO occurs as single window reads. Setting this too large |
| | | # may cause the process to load more data than is required; setting this too small |
| | | # may increase the frequency of read() system calls. |
| | | # |
| | | # Default on JGit is 8 KiB on all platforms. |
| | | # |
| | | # Common unit suffixes of k, m, or g are supported. |
| | | # Documentation courtesy of the Gerrit project. |
| | | # |
| | | # SINCE 1.0.0 |
| | | # RESTART REQUIRED |
| | | git.packedGitWindowSize = 8k |
| | | |
| | | # Maximum number of bytes to load and cache in memory from pack files. If JGit |
| | | # needs to access more than this many bytes it will unload less frequently used |
| | | # windows to reclaim memory space within the process. As this buffer must be shared |
| | | # with the rest of the JVM heap, it should be a fraction of the total memory available. |
| | | # |
| | | # The JGit team recommends setting this value larger than the size of your biggest |
| | | # repository. This ensures you can serve most requests from memory. |
| | | # |
| | | # Default on JGit is 10 MiB on all platforms. |
| | | # |
| | | # Common unit suffixes of k, m, or g are supported. |
| | | # Documentation courtesy of the Gerrit project. |
| | | # |
| | | # SINCE 1.0.0 |
| | | # RESTART REQUIRED |
| | | git.packedGitLimit = 10m |
| | | |
| | | # Maximum number of bytes to reserve for caching base objects that multiple deltafied |
| | | # objects reference. By storing the entire decompressed base object in a cache Git |
| | | # is able to avoid unpacking and decompressing frequently used base objects multiple times. |
| | | # |
| | | # Default on JGit is 10 MiB on all platforms. You probably do not need to adjust |
| | | # this value. |
| | | # |
| | | # Common unit suffixes of k, m, or g are supported. |
| | | # Documentation courtesy of the Gerrit project. |
| | | # |
| | | # SINCE 1.0.0 |
| | | # RESTART REQUIRED |
| | | git.deltaBaseCacheLimit = 10m |
| | | |
| | | # Maximum number of pack files to have open at once. A pack file must be opened |
| | | # in order for any of its data to be available in a cached window. |
| | | # |
| | | # If you increase this to a larger setting you may need to also adjust the ulimit |
| | | # on file descriptors for the host JVM, as Gitblit needs additional file descriptors |
| | | # available for network sockets and other repository data manipulation. |
| | | # |
| | | # Default on JGit is 128 file descriptors on all platforms. |
| | | # Documentation courtesy of the Gerrit project. |
| | | # |
| | | # SINCE 1.0.0 |
| | | # RESTART REQUIRED |
| | | git.packedGitOpenFiles = 128 |
| | | |
| | | # When true, JGit will use mmap() rather than malloc()+read() to load data from |
| | | # pack files. The use of mmap can be problematic on some JVMs as the garbage |
| | | # collector must deduce that a memory mapped segment is no longer in use before |
| | | # a call to munmap() can be made by the JVM native code. |
| | | # |
| | | # In server applications (such as Gitblit) that need to access many pack files, |
| | | # setting this to true risks artificially running out of virtual address space, |
| | | # as the garbage collector cannot reclaim unused mapped spaces fast enough. |
| | | # |
| | | # Default on JGit is false. Although potentially slower, it yields much more |
| | | # predictable behavior. |
| | | # Documentation courtesy of the Gerrit project. |
| | | # |
| | | # SINCE 1.0.0 |
| | | # RESTART REQUIRED |
| | | git.packedGitMmap = false |
| | | |
| | | # Validate all received (pushed) objects are valid. |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.checkReceivedObjects = true |
| | | |
| | | # Validate all referenced but not supplied objects are reachable. |
| | | # |
| | | # If enabled, Gitblit will verify that references to objects not contained |
| | | # within the received pack are already reachable through at least one other |
| | | # reference advertised to clients. |
| | | # |
| | | # This feature is useful when Gitblit doesn't trust the client to not provide a |
| | | # forged SHA-1 reference to an object, in an attempt to access parts of the DAG |
| | | # that they aren't allowed to see and which have been hidden from them via the |
| | | # configured AdvertiseRefsHook or RefFilter. |
| | | # |
| | | # Enabling this feature may imply at least some, if not all, of the same functionality |
| | | # performed by git.checkReceivedObjects. |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.checkReferencedObjectsAreReachable = true |
| | | |
| | | # Set the maximum allowed Git object size. |
| | | # |
| | | # If an object is larger than the given size the pack-parsing will throw an exception |
| | | # aborting the receive-pack operation. The default value, 0, disables maximum |
| | | # object size checking. |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.maxObjectSizeLimit = 0 |
| | | |
| | | # Set the maximum allowed pack size. |
| | | # |
| | | # A pack exceeding this size will be rejected. The default value, -1, disables |
| | | # maximum pack size checking. |
| | | # |
| | | # SINCE 1.5.0 |
| | | git.maxPackSizeLimit = -1 |
| | | |
| | | # Use the Gitblit patch receive pack for processing contributions and tickets. |
| | | # This allows the user to push a patch using the familiar Gerrit syntax: |
| | | # |
| | | # git push <remote> HEAD:refs/for/<targetBranch> |
| | | # |
| | | # NOTE: |
| | | # This requires git.enableGitServlet = true AND it requires an authenticated |
| | | # git transport connection (http/https) when pushing from a client. |
| | | # |
| | | # Valid services include: |
| | | # com.gitblit.tickets.FileTicketService |
| | | # com.gitblit.tickets.BranchTicketService |
| | | # com.gitblit.tickets.RedisTicketService |
| | | # |
| | | # SINCE 1.4.0 |
| | | # RESTART REQUIRED |
| | | tickets.service = |
| | | |
| | | # Globally enable or disable creation of new bug, enhancement, task, etc tickets |
| | | # for all repositories. |
| | | # |
| | | # If false, no tickets can be created through the ui for any repositories. |
| | | # If true, each repository can control if they allow new tickets to be created. |
| | | # |
| | | # NOTE: |
| | | # If a repository is accepting patchsets, new proposal tickets can be created |
| | | # regardless of this setting. |
| | | # |
| | | # SINCE 1.4.0 |
| | | tickets.acceptNewTickets = true |
| | | |
| | | # Globally enable or disable pushing patchsets to all repositories. |
| | | # |
| | | # If false, no patchsets will be accepted for any repositories. |
| | | # If true, each repository can control if they accept new patchsets. |
| | | # |
| | | # NOTE: |
| | | # If a repository is accepting patchsets, new proposal tickets can be created |
| | | # regardless of the acceptNewTickets setting. |
| | | # |
| | | # SINCE 1.4.0 |
| | | tickets.acceptNewPatchsets = true |
| | | |
| | | # Default setting to control patchset merge through the web ui. If true, patchsets |
| | | # must have an approval score to enable the merge button. This setting can be |
| | | # overriden per-repository. |
| | | # |
| | | # SINCE 1.4.0 |
| | | tickets.requireApproval = false |
| | | |
| | | # The case-insensitive regular expression used to identify and close tickets on |
| | | # push to the integration branch for commits that are NOT already referenced as |
| | | # a patchset tip. |
| | | # |
| | | # SINCE 1.5.0 |
| | | tickets.closeOnPushCommitMessageRegex = (?:fixes|closes)[\\s-]+#?(\\d+) |
| | | |
| | | # Specify the location of the Lucene Ticket index |
| | | # |
| | | # SINCE 1.4.0 |
| | | # RESTART REQUIRED |
| | | tickets.indexFolder = ${baseFolder}/tickets/lucene |
| | | |
| | | # Define the url for the Redis server. |
| | | # |
| | | # e.g. redis://localhost:6379 |
| | | # redis://:foobared@localhost:6379/2 |
| | | # |
| | | # SINCE 1.4.0 |
| | | # RESTART REQUIRED |
| | | tickets.redis.url = |
| | | |
| | | # The number of tickets to display on a page. |
| | | # |
| | | # SINCE 1.4.0 |
| | | tickets.perPage = 25 |
| | | |
| | | # The folder where plugins are loaded from. |
| | | # |
| | | # SINCE 1.5.0 |
| | | # RESTART REQUIRED |
| | | # BASEFOLDER |
| | | plugins.folder = ${baseFolder}/plugins |
| | | |
| | | # The registry of available plugins. |
| | | # |
| | | # SINCE 1.5.0 |
| | | plugins.registry = http://plugins.gitblit.com/plugins.json |
| | | |
| | | # Number of threads used to handle miscellaneous tasks in the background. |
| | | # |
| | | # SINCE 1.6.0 |
| | | # RESTART REQUIRED |
| | | execution.defaultThreadPoolSize = 1 |
| | | |
| | | # |
| | | # Groovy Integration |
| | | # |
| | | |
| | | # Location of Groovy scripts to use for Pre and Post receive hooks. |
| | | # Use forward slashes even on Windows!! |
| | | # e.g. c:/groovy |
| | | # |
| | | # RESTART REQUIRED |
| | | # SINCE 0.8.0 |
| | | # BASEFOLDER |
| | | groovy.scriptsFolder = ${baseFolder}/groovy |
| | | |
| | | # Specify the directory Grape uses for downloading libraries. |
| | | # http://groovy.codehaus.org/Grape |
| | | # |
| | | # RESTART REQUIRED |
| | | # SINCE 1.0.0 |
| | | # BASEFOLDER |
| | | groovy.grapeFolder = ${baseFolder}/groovy/grape |
| | | |
| | | # Scripts to execute on Pre-Receive. |
| | | # |
| | | # These scripts execute after an incoming push has been parsed and validated |
| | | # but BEFORE the changes are applied to the repository. You might reject a |
| | | # push in this script based on the repository and branch the push is attempting |
| | | # to change. |
| | | # |
| | | # Script names are case-sensitive on case-sensitive file systems. You may omit |
| | | # the traditional ".groovy" from this list if your file extension is ".groovy" |
| | | # |
| | | # NOTE: |
| | | # These scripts are only executed when pushing to *Gitblit*, not to other Git |
| | | # tooling you may be using. Also note that these scripts are shared between |
| | | # repositories. These are NOT repository-specific scripts! Within the script |
| | | # you may customize the control-flow for a specific repository by checking the |
| | | # *repository* variable. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 0.8.0 |
| | | groovy.preReceiveScripts = |
| | | |
| | | # Scripts to execute on Post-Receive. |
| | | # |
| | | # These scripts execute AFTER an incoming push has been applied to a repository. |
| | | # You might trigger a continuous-integration build here or send a notification. |
| | | # |
| | | # Script names are case-sensitive on case-sensitive file systems. You may omit |
| | | # the traditional ".groovy" from this list if your file extension is ".groovy" |
| | | # |
| | | # NOTE: |
| | | # These scripts are only executed when pushing to *Gitblit*, not to other Git |
| | | # tooling you may be using. Also note that these scripts are shared between |
| | | # repositories. These are NOT repository-specific scripts! Within the script |
| | | # you may customize the control-flow for a specific repository by checking the |
| | | # *repository* variable. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 0.8.0 |
| | | groovy.postReceiveScripts = |
| | | |
| | | # Repository custom fields for Groovy Hook mechanism |
| | | # |
| | | # List of key=label pairs of custom fields to prompt for in the Edit Repository |
| | | # page. These keys are stored in the repository's git config file in the |
| | | # section [gitblit "customFields"]. Key names are alphanumeric only. These |
| | | # fields are intended to be used for the Groovy hook mechanism where a script |
| | | # can adjust it's execution based on the custom fields stored in the repository |
| | | # config. |
| | | # |
| | | # e.g. "commitMsgRegex=Commit Message Regular Expression" anotherProperty=Another |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.0.0 |
| | | groovy.customFields = |
| | | |
| | | # |
| | | # Fanout Settings |
| | | # |
| | | |
| | | # Fanout is a PubSub notification service that can be used by Sparkleshare |
| | | # to eliminate repository change polling. The fanout service runs in a separate |
| | | # thread on a separate port from the Gitblit http/https application. |
| | | # This service is provided so that Sparkleshare may be used with Gitblit in |
| | | # firewalled environments or where reliance on Sparkleshare's default notifications |
| | | # server (notifications.sparkleshare.org) is unwanted. |
| | | # |
| | | # This service maintains an open socket connection from the client to the |
| | | # Fanout PubSub service. This service may not work properly behind a proxy server. |
| | | |
| | | # Specify the interface for Fanout to bind it's service. |
| | | # You may specify an ip or an empty value to bind to all interfaces. |
| | | # Specifying localhost will result in Gitblit ONLY listening to requests to |
| | | # localhost. |
| | | # |
| | | # SINCE 1.2.1 |
| | | # RESTART REQUIRED |
| | | fanout.bindInterface = |
| | | |
| | | # port for serving the Fanout PubSub service. <= 0 disables this service. |
| | | # On Unix/Linux systems, ports < 1024 require root permissions. |
| | | # Recommended value: 17000 |
| | | # |
| | | # SINCE 1.2.1 |
| | | # RESTART REQUIRED |
| | | fanout.port = 0 |
| | | |
| | | # Use Fanout NIO service. If false, a multi-threaded socket service will be used. |
| | | # Be advised, the socket implementation spawns a thread per connection plus the |
| | | # connection acceptor thread. The NIO implementation is completely single-threaded. |
| | | # |
| | | # SINCE 1.2.1 |
| | | # RESTART REQUIRED |
| | | fanout.useNio = true |
| | | |
| | | # Concurrent connection limit. <= 0 disables concurrent connection throttling. |
| | | # If > 0, only the specified number of concurrent connections will be allowed |
| | | # and all other connections will be rejected. |
| | | # |
| | | # SINCE 1.2.1 |
| | | # RESTART REQUIRED |
| | | fanout.connectionLimit = 0 |
| | | |
| | | # |
| | | # Authentication Settings |
| | | # |
| | | |
| | | # Require authentication to see everything but the admin pages |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | web.authenticateViewPages = false |
| | | |
| | | # If web.authenticateViewPages=true you may optionally require a client-side |
| | | # basic authentication prompt instead of the standard form-based login. |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.enforceHttpBasicAuthentication = false |
| | | |
| | | # Require admin authentication for the admin functions and pages |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | web.authenticateAdminPages = true |
| | | |
| | | # Allow Gitblit to store a cookie in the user's browser for automatic |
| | | # authentication. The cookie is generated by the user service. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.allowCookieAuthentication = true |
| | | |
| | | # Allow deletion of non-empty repositories. This is enforced for all delete vectors. |
| | | # |
| | | # SINCE 1.6.0 |
| | | web.allowDeletingNonEmptyRepositories = true |
| | | |
| | | # Setting to include personal repositories in the main repositories list. |
| | | # |
| | | # SINCE 1.6.0 |
| | | web.includePersonalRepositories = false |
| | | |
| | | # Config file for storing project metadata |
| | | # |
| | | # SINCE 1.2.0 |
| | | # BASEFOLDER |
| | | web.projectsFile = ${baseFolder}/projects.conf |
| | | |
| | | # Either the full path to a user config file (users.conf) |
| | | # OR a fully qualified class name that implements the IUserService interface. |
| | | # |
| | | # Any custom user service implementation must have a public default constructor. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | # BASEFOLDER |
| | | realm.userService = ${baseFolder}/users.conf |
| | | |
| | | # Ordered list of external authentication providers which will be used if |
| | | # authentication against the local user service fails. |
| | | # |
| | | # Valid providers are: |
| | | # |
| | | # htpasswd |
| | | # ldap |
| | | # pam |
| | | # redmine |
| | | # salesforce |
| | | # windows |
| | | |
| | | # e.g. realm.authenticationProviders = htpasswd windows |
| | | # |
| | | # SINCE 1.4.0 |
| | | # RESTART REQUIRED |
| | | # SPACE-DELIMITED |
| | | realm.authenticationProviders = |
| | | |
| | | # How to store passwords. |
| | | # Valid values are plain, md5, or combined-md5. md5 is the hash of password. |
| | | # combined-md5 is the hash of username.toLowerCase()+password. |
| | | # Default is md5. |
| | | # |
| | | # SINCE 0.5.0 |
| | | realm.passwordStorage = md5 |
| | | |
| | | # Minimum valid length for a plain text password. |
| | | # Default value is 5. Absolute minimum is 4. |
| | | # |
| | | # SINCE 0.5.0 |
| | | realm.minPasswordLength = 5 |
| | | |
| | | # |
| | | # Gitblit Web Settings |
| | | # |
| | | # If blank Gitblit is displayed. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.siteName = |
| | | |
| | | # The canonical url of your Gitblit server to be used in repository url generation, |
| | | # RSS feeds, and all embedded links in email and plugin-based notifications. |
| | | # |
| | | # If you are running Gitblit on a non-standard http port (i.e. not 80 and not 443) |
| | | # then you must specify that port in this url otherwise your generated urls will be |
| | | # incorrect. |
| | | # |
| | | # The hostname of this url will be extracted for SSH and GIT protocol repository |
| | | # url generation. |
| | | # |
| | | # e.g. web.canonicalUrl = https://dev.gitblit.com |
| | | # web.canonicalUrl = https://dev.gitblit.com:8443 |
| | | # |
| | | # SINCE 1.4.0 |
| | | web.canonicalUrl = |
| | | |
| | | # You may specify a different logo image for the header but it must be 120x45px. |
| | | # If the specified file does not exist, the default Gitblit logo will be used. |
| | | # |
| | | # SINCE 1.3.0 |
| | | # BASEFOLDER |
| | | web.headerLogo = ${baseFolder}/logo.png |
| | | |
| | | # You may specify a different link URL for the logo image anchor. |
| | | # If blank the Gitblit main page URL is used. |
| | | # |
| | | # SINCE 1.3.0 |
| | | # BASEFOLDER |
| | | web.rootLink = |
| | | |
| | | # You may specify a custom header background CSS color. If unspecified, the |
| | | # default color will be used. |
| | | # |
| | | # e.g. web.headerBackgroundColor = #002060 |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.headerBackgroundColor = |
| | | |
| | | # You may specify a custom header foreground CSS color. If unspecified, the |
| | | # default color will be used. |
| | | # |
| | | # e.g. web.headerForegroundColor = white |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.headerForegroundColor = |
| | | |
| | | # You may specify a custom header foreground hover CSS color. If unspecified, the |
| | | # default color will be used. |
| | | # |
| | | # e.g. web.headerHoverColor = white |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.headerHoverColor = |
| | | |
| | | # You may specify a custom header border CSS color. If unspecified, the default |
| | | # color will be used. |
| | | # |
| | | # e.g. web.headerBorderColor = #002060 |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.headerBorderColor = |
| | | |
| | | # You may specify a custom header border CSS color. If unspecified, the default |
| | | # color will be used. |
| | | # |
| | | # e.g. web.headerBorderFocusColor = #ff9900 |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.headerBorderFocusColor = |
| | | |
| | | # If *web.authenticateAdminPages*=true, users with "admin" role can create |
| | | # repositories, create users, and edit repository metadata. |
| | | # |
| | | # If *web.authenticateAdminPages*=false, any user can execute the aforementioned |
| | | # functions. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.allowAdministration = true |
| | | |
| | | # Setting to disable rendering the top-level navigation header which includes |
| | | # the login form, top-level links like dashboard, repositories, search, etc. |
| | | # This setting is only useful if you plan to embed Gitblit within another page |
| | | # or system. |
| | | # |
| | | # SINCE 1.4.0 |
| | | web.hideHeader = false |
| | | |
| | | # Allows rpc clients to list repositories and possibly manage or administer the |
| | | # Gitblit server, if the authenticated account has administrator permissions. |
| | | # See *web.enableRpcManagement* and *web.enableRpcAdministration*. |
| | | # |
| | | # SINCE 0.7.0 |
| | | web.enableRpcServlet = true |
| | | |
| | | # Allows rpc clients to manage repositories and users of the Gitblit instance, |
| | | # if the authenticated account has administrator permissions. |
| | | # Requires *web.enableRpcServlet=true*. |
| | | # |
| | | # SINCE 0.7.0 |
| | | web.enableRpcManagement = false |
| | | |
| | | # Allows rpc clients to control the server settings and monitor the health of this |
| | | # this Gitblit instance, if the authenticated account has administrator permissions. |
| | | # Requires *web.enableRpcServlet=true* and *web.enableRpcManagement*. |
| | | # |
| | | # SINCE 0.7.0 |
| | | web.enableRpcAdministration = false |
| | | |
| | | # Full path to a configurable robots.txt file. With this file you can control |
| | | # what parts of your Gitblit server respectable robots are allowed to traverse. |
| | | # http://googlewebmastercentral.blogspot.com/2008/06/improving-on-robots-exclusion-protocol.html |
| | | # |
| | | # SINCE 1.0.0 |
| | | # BASEFOLDER |
| | | web.robots.txt = ${baseFolder}/robots.txt |
| | | |
| | | # The number of minutes to cache a page in the browser since the last request. |
| | | # The default value is 0 minutes. A value <= 0 disables all page caching which |
| | | # is the default behavior for Gitblit <= 1.3.0. |
| | | # |
| | | # SINCE 1.3.1 |
| | | web.pageCacheExpires = 0 |
| | | |
| | | # If true, the web ui layout will respond and adapt to the browser's dimensions. |
| | | # if false, the web ui will use a 940px fixed-width layout. |
| | | # http://twitter.github.com/bootstrap/scaffolding.html#responsive |
| | | # |
| | | # SINCE 1.0.0 |
| | | web.useResponsiveLayout = true |
| | | |
| | | # Allow Gravatar images to be displayed in Gitblit pages. |
| | | # |
| | | # SINCE 0.8.0 |
| | | web.allowGravatar = true |
| | | |
| | | # Allow dynamic zip downloads. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.allowZipDownloads = true |
| | | |
| | | # If *web.allowZipDownloads=true* the following formats will be displayed for |
| | | # download compressed archive links: |
| | | # |
| | | # zip = standard .zip |
| | | # tar = standard tar format (preserves *nix permissions and symlinks) |
| | | # gz = gz-compressed tar |
| | | # xz = xz-compressed tar |
| | | # bzip2 = bzip2-compressed tar |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.2.0 |
| | | web.compressedDownloads = zip gz |
| | | |
| | | # Allow optional Lucene integration. Lucene indexing is an opt-in feature. |
| | | # A repository may specify branches to index with Lucene instead of using Git |
| | | # commit traversal. There are scenarios where you may want to completely disable |
| | | # Lucene indexing despite a repository specifying indexed branches. One such |
| | | # scenario is on a resource-constrained federated Gitblit mirror. |
| | | # |
| | | # SINCE 0.9.0 |
| | | web.allowLuceneIndexing = true |
| | | |
| | | # Control the frequency of Lucene repository indexing. |
| | | # The default setting is to check for updated refs every 2 mins. |
| | | # |
| | | # SINCE 1.6.1 |
| | | web.luceneFrequency = 2 mins |
| | | |
| | | # Allows an authenticated user to create forks of a repository |
| | | # |
| | | # set this to false if you want to disable all fork controls on the web site |
| | | # |
| | | web.allowForking = true |
| | | |
| | | # Controls the length of shortened commit hash ids |
| | | # |
| | | # SINCE 1.2.0 |
| | | web.shortCommitIdLength = 6 |
| | | |
| | | # Use Clippy (Flash solution) to provide a copy-to-clipboard button. |
| | | # If false, a button with a more primitive JavaScript-based prompt box will |
| | | # offer a 3-step (click, ctrl+c, enter) copy-to-clipboard alternative. |
| | | # |
| | | # SINCE 0.8.0 |
| | | web.allowFlashCopyToClipboard = true |
| | | |
| | | # Default maximum number of commits that a repository may contribute to the |
| | | # activity page, regardless of the selected duration. This setting may be valuable |
| | | # for an extremely busy server. This value may also be configed per-repository |
| | | # in Edit Repository. 0 disables this throttle. |
| | | # |
| | | # SINCE 1.2.0 |
| | | web.maxActivityCommits = 0 |
| | | |
| | | # Default number of entries to include in RSS Syndication links |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.syndicationEntries = 25 |
| | | |
| | | # Show the size of each repository on the repositories page. |
| | | # This requires recursive traversal of each repository folder. This may be |
| | | # non-performant on some operating systems and/or filesystems. |
| | | # |
| | | # SINCE 0.5.2 |
| | | web.showRepositorySizes = true |
| | | |
| | | # List of custom regex expressions that can be displayed in the Filters menu |
| | | # of the Repositories and Activity pages. Keep them very simple because you |
| | | # are likely to run into encoding issues if they are too complex. |
| | | # |
| | | # Use !!! to separate the filters |
| | | # |
| | | # SINCE 0.8.0 |
| | | web.customFilters = |
| | | |
| | | # Show federation registrations (without token) and the current pull status |
| | | # to non-administrator users. |
| | | # |
| | | # SINCE 0.6.0 |
| | | web.showFederationRegistrations = false |
| | | |
| | | # This is the message displayed when *web.authenticateViewPages=true*. |
| | | # This can point to a file with Markdown content. |
| | | # Specifying "gitblit" uses the internal login message. |
| | | # |
| | | # SINCE 0.7.0 |
| | | # BASEFOLDER |
| | | web.loginMessage = gitblit |
| | | |
| | | # This is the message displayed above the repositories table. |
| | | # This can point to a file with Markdown content. |
| | | # Specifying "gitblit" uses the internal welcome message. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # BASEFOLDER |
| | | web.repositoriesMessage = gitblit |
| | | |
| | | # Ordered list of charsets/encodings to use when trying to display a blob. |
| | | # If empty, UTF-8 and ISO-8859-1 are used. The server's default charset |
| | | # is always appended to the encoding list. If all encodings fail to cleanly |
| | | # decode the blob content, UTF-8 will be used with the standard malformed |
| | | # input/unmappable character replacement strings. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.0.0 |
| | | web.blobEncodings = UTF-8 ISO-8859-1 |
| | | |
| | | # Manually set the default timezone to be used by Gitblit for display in the |
| | | # web ui. This value is independent of the JVM timezone. Specifying a blank |
| | | # value will default to the JVM timezone. |
| | | # e.g. America/New_York, US/Pacific, UTC, Europe/Berlin |
| | | # |
| | | # SINCE 0.9.0 |
| | | # RESTART REQUIRED |
| | | web.timezone = |
| | | |
| | | # Use the client timezone when formatting dates. |
| | | # This uses AJAX to determine the browser's timezone and may require more |
| | | # server overhead because a Wicket session is created. All Gitblit pages |
| | | # attempt to be stateless, if possible. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | web.useClientTimezone = false |
| | | |
| | | # Time format |
| | | # <http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html> |
| | | # |
| | | # SINCE 0.8.0 |
| | | web.timeFormat = HH:mm |
| | | |
| | | # Short date format |
| | | # <http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html> |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.datestampShortFormat = yyyy-MM-dd |
| | | |
| | | # Long date format |
| | | # |
| | | # SINCE 0.8.0 |
| | | web.datestampLongFormat = EEEE, MMMM d, yyyy |
| | | |
| | | # Long timestamp format |
| | | # <http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html> |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.datetimestampLongFormat = EEEE, MMMM d, yyyy HH:mm Z |
| | | |
| | | # Mount URL parameters |
| | | # This setting controls if pretty or parameter URLs are used. |
| | | # i.e. |
| | | # if true: |
| | | # http://localhost/commit/myrepo/abcdef |
| | | # if false: |
| | | # http://localhost/commit/?r=myrepo&h=abcdef |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | web.mountParameters = true |
| | | |
| | | # Some servlet containers (e.g. Tomcat >= 6.0.10) disallow '/' (%2F) encoding |
| | | # in URLs as a security precaution for proxies. This setting tells Gitblit |
| | | # to preemptively replace '/' with '*' or '!' for url string parameters. |
| | | # |
| | | # <https://issues.apache.org/jira/browse/WICKET-1303> |
| | | # <http://tomcat.apache.org/security-6.html#Fixed_in_Apache_Tomcat_6.0.10> |
| | | # Add *-Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true* to your |
| | | # *CATALINA_OPTS* or to your JVM launch parameters |
| | | # |
| | | # SINCE 0.5.2 |
| | | web.forwardSlashCharacter = / |
| | | |
| | | # Show other URLs on the summary page for accessing your git repositories |
| | | # Use spaces to separate urls. |
| | | # |
| | | # {0} is the token for the repository name |
| | | # {1} is the token for the username |
| | | # |
| | | # The username is only practical if you have setup your other git serving |
| | | # solutions accounts to have the same username as the Gitblit account. |
| | | # |
| | | # e.g. |
| | | # web.otherUrls = ssh://localhost/git/{0} git://localhost/git/{0} https://{1}@localhost/r/{0} |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 0.5.0 |
| | | web.otherUrls = |
| | | |
| | | # Should app-specific clone links be displayed for SourceTree, SparkleShare, etc? |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.allowAppCloneLinks = true |
| | | |
| | | # Choose how to present the repositories list. |
| | | # grouped = group nested/subfolder repositories together (no sorting) |
| | | # flat = flat list of repositories (sorting allowed) |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.repositoryListType = grouped |
| | | |
| | | # If using a grouped repository list and there are repositories at the |
| | | # root level of your repositories folder, you may specify the displayed |
| | | # group name with this setting. This value is only used for web presentation. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.repositoryRootGroupName = main |
| | | |
| | | # Display the repository swatch color next to the repository name link in the |
| | | # repositories list. |
| | | # |
| | | # SINCE 0.8.0 |
| | | web.repositoryListSwatches = true |
| | | |
| | | # Defines the default commit message renderer. This can be configured |
| | | # per-repository. |
| | | # |
| | | # Valid values are: plain, markdown |
| | | # |
| | | # SINCE 1.4.0 |
| | | web.commitMessageRenderer = plain |
| | | |
| | | # Control if email addresses are shown in web ui |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.showEmailAddresses = true |
| | | |
| | | # Shows a combobox in the page links header with commit, committer, and author |
| | | # search selection. Default search is commit. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.showSearchTypeSelection = false |
| | | |
| | | # Controls display of activity graphs on the dashboard, activity, and summary |
| | | # pages. Charting makes use of the external Google Charts API. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.generateActivityGraph = true |
| | | |
| | | # Displays the commits branch graph in the summary page and commits/log page. |
| | | # |
| | | # SINCE 1.4.0 |
| | | web.showBranchGraph = true |
| | | |
| | | # The default number of days to show on the activity page. |
| | | # Value must exceed 0 else default of 7 is used |
| | | # |
| | | # SINCE 0.8.0 |
| | | web.activityDuration = 7 |
| | | |
| | | # Choices for days of activity to display. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.3.0 |
| | | web.activityDurationChoices = 1 3 7 14 21 28 |
| | | |
| | | # Maximum number of days of activity that may be displayed on the activity page. |
| | | # |
| | | # SINCE 1.3.2 |
| | | web.activityDurationMaximum = 30 |
| | | |
| | | # The number of days of commits to cache in memory for the dashboard, activity, |
| | | # and project pages. A value of 0 will disable all caching and will parse commits |
| | | # in each repository per-request. If the value > 0 these pages will try to fulfill |
| | | # requests using the commit cache. If the request specifies a period which falls |
| | | # outside the commit cache window, then the cache will be ignored and the request |
| | | # will be fulfilled by brute-force parsing all relevant commits per-repository. |
| | | # |
| | | # Consider the values specified for *web.activityDurationChoices* when setting |
| | | # the cache size AND consider adjusting the JVM -Xmx heap parameter appropriately. |
| | | # |
| | | # SINCE 1.3.0 |
| | | # RESTART REQUIRED |
| | | web.activityCacheDays = 14 |
| | | |
| | | # Case-insensitive list of authors to exclude from metrics. Useful for |
| | | # eliminating bots. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.3.0 |
| | | web.metricAuthorExclusions = |
| | | |
| | | # The number of commits to display on the summary page |
| | | # Value must exceed 0 else default of 20 is used |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.summaryCommitCount = 16 |
| | | |
| | | # The number of tags/branches to display on the summary page. |
| | | # -1 = all tags/branches |
| | | # 0 = hide tags/branches |
| | | # N = N tags/branches |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.summaryRefsCount = 5 |
| | | |
| | | # Show a README file, if available, on the summary page. |
| | | # |
| | | # SINCE 1.4.0 |
| | | web.summaryShowReadme = false |
| | | |
| | | # The number of items to show on a page before showing the first, prev, next |
| | | # pagination links. A default of 50 is used for any invalid value. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.itemsPerPage = 50 |
| | | |
| | | # The number of reflog changes to display on the overview page |
| | | # Value must exceed 0 else default of 5 is used |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.overviewReflogCount = 5 |
| | | |
| | | # The number of reflog changes to show on a reflog page before show the first, |
| | | # prev, next pagination links. A default of 10 is used for any invalid value. |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.reflogChangesPerPage = 10 |
| | | |
| | | # Specify the names of documents in the root of your repository to be displayed |
| | | # in tabs on your repository docs page. If the name is not found in the root |
| | | # then no tab is added. The order specified is the order displayed. Do not |
| | | # specify a file extension as the aggregation of markup extensions + txt are used |
| | | # in the search algorithm. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.4.0 |
| | | web.documents = readme home index changelog contributing submitting_patches copying license notice authors |
| | | |
| | | # Registered file extensions to ignore during Lucene indexing |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 0.9.0 |
| | | web.luceneIgnoreExtensions = 7z arc arj bin bmp dll doc docx exe gif gz jar jpg lib lzh odg odf odt pdf ppt pptx png so swf tar xcf xls xlsx zip |
| | | |
| | | # Registered extensions for google-code-prettify |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 0.5.0 |
| | | web.prettyPrintExtensions = aea agc basic c cbm cl clj cpp cs css dart el erl erlang frm fs go groovy h hpp hs htm html java js latex lisp ll llvm lsp lua ml moxie mumps n nemerle pascal php pl pm prefs properties proto py r R rb rd Rd rkt s S scala scm sh Splus sql ss tcl tex vb vbs vhd vhdl wiki xml xq xquery yaml yml ymlapollo |
| | | |
| | | # Registered extensions for markdown transformation |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 0.5.0 |
| | | web.markdownExtensions = md mkd markdown MD MKD |
| | | |
| | | # Registered extensions for mediawiki transformation |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 1.4.0 |
| | | web.mediawikiExtensions = mw mediawiki |
| | | |
| | | # Registered extensions for twiki transformation |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 1.4.0 |
| | | web.twikiExtensions = twiki |
| | | |
| | | # Registered extensions for textile transformation |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 1.4.0 |
| | | web.textileExtensions = textile |
| | | |
| | | # Registered extensions for confluence transformation |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 1.4.0 |
| | | web.confluenceExtensions = confluence |
| | | |
| | | # Registered extensions for tracwiki transformation |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 1.4.0 |
| | | web.tracwikiExtensions = tracwiki |
| | | |
| | | # Image extensions |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 0.5.0 |
| | | web.imageExtensions = bmp jpg jpeg gif png ico |
| | | |
| | | # Registered extensions for binary blobs |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 0.5.0 |
| | | web.binaryExtensions = 7z arc arj bin dll doc docx exe gz jar lib lzh odg odf odt pdf ppt pptx so tar xls xlsx zip |
| | | |
| | | # Aggressive heap management will run the garbage collector on every generated |
| | | # page. This slows down page generation a little but improves heap consumption. |
| | | # |
| | | # SINCE 0.5.0 |
| | | web.aggressiveHeapManagement = false |
| | | |
| | | # Run the webapp in debug mode |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | web.debugMode = false |
| | | |
| | | # Force a default locale for all users, ignoring the browser's settings. |
| | | # An empty value allows Gitblit to use the translation preferred by the browser. |
| | | # |
| | | # Changing this value while the server is running will only affect new sessions. |
| | | # |
| | | # e.g. web.forceDefaultLocale = en |
| | | # |
| | | # SINCE 1.3.0 |
| | | web.forceDefaultLocale = |
| | | |
| | | # Enable/disable global regex substitutions (i.e. shared across repositories) |
| | | # |
| | | # SINCE 0.5.0 |
| | | # DEPRECATED 1.4.0 (migrate to bugtraq instead) |
| | | regex.global = true |
| | | |
| | | # Example global regex substitutions |
| | | # Use !!! to separate the search pattern and the replace pattern |
| | | # searchpattern!!!replacepattern |
| | | # SINCE 0.5.0 |
| | | |
| | | # regex.global.bug = \\b(Bug:)(\\s*[#]?|-){0,1}(\\d+)\\b!!!Bug: <a href="http://somehost/bug/$3">$3</a> |
| | | # SINCE 0.5.0 |
| | | |
| | | # Example Gerrit links |
| | | # regex.global.changeid = \\b(Change-Id:\\s*)([A-Za-z0-9]*)\\b!!!Change-Id: <a href="http://somehost/r/#q,$2,n,z">$2</a> |
| | | # regex.global.reviewedon = \\b(Reviewed-on:\\s*)([A-Za-z0-9:/\\.]*)\\b!!!Reviewed-on: <a href="$2">$2</a> |
| | | |
| | | # Example per-repository regex substitutions overrides global |
| | | # SINCE 0.5.0 |
| | | # regex.myrepository.bug = \\b(Bug:)(\\s*[#]?|-){0,1}(\\d+)\\b!!!Bug: <a href="http://elsewhere/bug/$3">$3</a> |
| | | |
| | | # |
| | | # Mail Settings |
| | | # SINCE 0.6.0 |
| | | # |
| | | # Mail settings are used to notify administrators of received federation proposals |
| | | # |
| | | |
| | | # ip or hostname of smtp server |
| | | # |
| | | # SINCE 0.6.0 |
| | | mail.server = |
| | | |
| | | # port to use for smtp requests |
| | | # |
| | | # SINCE 0.6.0 |
| | | mail.port = 25 |
| | | |
| | | # debug the mail executor |
| | | # |
| | | # SINCE 0.6.0 |
| | | mail.debug = false |
| | | |
| | | # use SMTPs flag |
| | | mail.smtps = false |
| | | |
| | | # use STARTTLS flag |
| | | # |
| | | # SINCE 1.6.0 |
| | | mail.starttls = false |
| | | |
| | | # if your smtp server requires authentication, supply the credentials here |
| | | # |
| | | # SINCE 0.6.0 |
| | | mail.username = |
| | | # SINCE 0.6.0 |
| | | mail.password = |
| | | |
| | | # from address for generated emails |
| | | # |
| | | # SINCE 0.6.0 |
| | | mail.fromAddress = |
| | | |
| | | # List of email addresses for the Gitblit administrators |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 0.6.0 |
| | | mail.adminAddresses = |
| | | |
| | | # List of email addresses for sending push email notifications. |
| | | # |
| | | # This key currently requires use of the sendemail.groovy hook script. |
| | | # If you set sendemail.groovy in *groovy.postReceiveScripts* then email |
| | | # notifications for all repositories (regardless of access restrictions!) |
| | | # will be sent to these addresses. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 0.8.0 |
| | | mail.mailingLists = |
| | | |
| | | # |
| | | # Federation Settings |
| | | # SINCE 0.6.0 |
| | | # |
| | | # A Gitblit federation is a way to backup one Gitblit instance to another. |
| | | # |
| | | # *git.enableGitServlet* must be true to use this feature. |
| | | |
| | | # Your federation name is used for federation status acknowledgments. If it is |
| | | # unset, and you elect to send a status acknowledgment, your Gitblit instance |
| | | # will be identified by its hostname, if available, else your internal ip address. |
| | | # The source Gitblit instance will also append your external IP address to your |
| | | # identification to differentiate multiple pulling systems behind a single proxy. |
| | | # |
| | | # SINCE 0.6.0 |
| | | federation.name = |
| | | |
| | | # Specify the passphrase of this Gitblit instance. |
| | | # |
| | | # An unspecified (empty) passphrase disables processing federation requests. |
| | | # |
| | | # This value can be anything you want: an integer, a sentence, an haiku, etc. |
| | | # Keep the value simple, though, to avoid Java properties file encoding issues. |
| | | # |
| | | # Changing your passphrase will break any registrations you have established with other |
| | | # Gitblit instances. |
| | | # |
| | | # CASE-SENSITIVE |
| | | # SINCE 0.6.0 |
| | | # RESTART REQUIRED *(only to enable or disable federation)* |
| | | federation.passphrase = |
| | | |
| | | # Control whether or not this Gitblit instance can receive federation proposals |
| | | # from another Gitblit instance. Registering a federated Gitblit is a manual |
| | | # process. Proposals help to simplify that process by allowing a remote Gitblit |
| | | # instance to send your Gitblit instance the federation pull data. |
| | | # |
| | | # SINCE 0.6.0 |
| | | federation.allowProposals = false |
| | | |
| | | # The destination folder for cached federation proposals. |
| | | # Use forward slashes even on Windows!! |
| | | # |
| | | # SINCE 0.6.0 |
| | | # BASEFOLDER |
| | | federation.proposalsFolder = ${baseFolder}/proposals |
| | | |
| | | # The default pull frequency if frequency is unspecified on a registration |
| | | # |
| | | # SINCE 0.6.0 |
| | | federation.defaultFrequency = 60 mins |
| | | |
| | | # Federation Sets are named groups of repositories. The Federation Sets are |
| | | # available for selection in the repository settings page. You can assign a |
| | | # repository to one or more sets and then distribute the token for the set. |
| | | # This allows you to grant federation pull access to a subset of your available |
| | | # repositories. Tokens for federation sets only grant repository pull access. |
| | | # |
| | | # SPACE-DELIMITED |
| | | # CASE-SENSITIVE |
| | | # SINCE 0.6.0 |
| | | federation.sets = |
| | | |
| | | # Federation pull registrations |
| | | # Registrations are read once, at startup. |
| | | # |
| | | # RESTART REQUIRED |
| | | # |
| | | # frequency: |
| | | # The shortest frequency allowed is every 5 minutes |
| | | # Decimal frequency values are cast to integers |
| | | # Frequency values may be specified in mins, hours, or days |
| | | # Values that can not be parsed or are unspecified default to *federation.defaultFrequency* |
| | | # |
| | | # folder: |
| | | # if unspecified, the folder is *git.repositoriesFolder* |
| | | # if specified, the folder is relative to *git.repositoriesFolder* |
| | | # |
| | | # bare: |
| | | # if true, each repository will be created as a *bare* repository and will not |
| | | # have a working directory. |
| | | # |
| | | # if false, each repository will be created as a normal repository suitable |
| | | # for local work. |
| | | # |
| | | # mirror: |
| | | # if true, each repository HEAD is reset to *origin/master* after each pull. |
| | | # The repository will be flagged *isFrozen* after the initial clone. |
| | | # |
| | | # if false, each repository HEAD will point to the FETCH_HEAD of the initial |
| | | # clone from the origin until pushed to or otherwise manipulated. |
| | | # |
| | | # mergeAccounts: |
| | | # if true, remote accounts and their permissions are merged into your |
| | | # users.properties file |
| | | # |
| | | # notifyOnError: |
| | | # if true and the mail configuration is properly set, administrators will be |
| | | # notified by email of pull failures |
| | | # |
| | | # include and exclude: |
| | | # Space-delimited list of repositories to include or exclude from pull |
| | | # may be * wildcard to include or exclude all |
| | | # may use fuzzy match (e.g. org.eclipse.*) |
| | | |
| | | # |
| | | # (Nearly) Perfect Mirror example |
| | | # |
| | | |
| | | #federation.example1.url = https://go.gitblit.com |
| | | #federation.example1.token = 6f3b8a24bf970f17289b234284c94f43eb42f0e4 |
| | | #federation.example1.frequency = 120 mins |
| | | #federation.example1.folder = |
| | | #federation.example1.bare = true |
| | | #federation.example1.mirror = true |
| | | #federation.example1.mergeAccounts = true |
| | | |
| | | # |
| | | # Advanced Realm Settings |
| | | # |
| | | |
| | | # Auto-creates user accounts based on the servlet container principal. This |
| | | # assumes that your Gitblit install is a protected resource and your container's |
| | | # authentication process intercepts all Gitblit requests. |
| | | # |
| | | # SINCE 1.3.0 |
| | | realm.container.autoCreateAccounts = false |
| | | |
| | | # Allow or prohibit Windows guest account logins |
| | | # |
| | | # SINCE 1.3.0 |
| | | realm.windows.allowGuests = false |
| | | |
| | | # Allow user accounts belonging to the BUILTIN\Administrators group to be |
| | | # Gitblit administrators. |
| | | # |
| | | # SINCE 1.4.0 |
| | | realm.windows.permitBuiltInAdministrators = true |
| | | |
| | | # The default domain for authentication. |
| | | # |
| | | # If specified, this domain will be used for authentication UNLESS the supplied |
| | | # login name manually specifies a domain (.e.g. mydomain\james or james@mydomain) |
| | | # |
| | | # If unspecified, the username must be specified in UPN format (name@domain). |
| | | # |
| | | # if "." (dot) is specified, ONLY the local account database will be used. |
| | | # |
| | | # SINCE 1.3.0 |
| | | realm.windows.defaultDomain = |
| | | |
| | | # The PAM service name for authentication. |
| | | # default: system-auth |
| | | # |
| | | # SINCE 1.3.1 |
| | | realm.pam.serviceName = system-auth |
| | | |
| | | # The Apache htpasswd file that contains the users and passwords. |
| | | # default: ${baseFolder}/htpasswd |
| | | # |
| | | # RESTART REQUIRED |
| | | # BASEFOLDER |
| | | # SINCE 1.3.2 |
| | | realm.htpasswd.userfile = ${baseFolder}/htpasswd |
| | | |
| | | # Restrict the Salesforce user to members of this org. |
| | | # default: 0 (i.e. do not check the Org ID) |
| | | # |
| | | # SINCE 1.3.0 |
| | | realm.salesforce.orgId = 0 |
| | | |
| | | # URL of the LDAP server. |
| | | # To use encrypted transport, use either ldaps:// URL for SSL or ldap+tls:// to |
| | | # send StartTLS command. |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.server = ldap://localhost |
| | | |
| | | # Login username for LDAP searches. |
| | | # If this value is unspecified, anonymous LDAP login will be used. |
| | | # |
| | | # e.g. mydomain\\username |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.username = cn=Directory Manager |
| | | |
| | | # Login password for LDAP searches. |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.password = password |
| | | |
| | | # Bind pattern for Authentication. |
| | | # Allow to directly authenticate an user without LDAP Searches. |
| | | # |
| | | # e.g. CN=${username},OU=Users,OU=UserControl,OU=MyOrganization,DC=MyDomain |
| | | # |
| | | # SINCE 1.5.0 |
| | | realm.ldap.bindpattern = |
| | | |
| | | |
| | | # Delegate team membership control to LDAP. |
| | | # |
| | | # If true, team user memberships will be specified by LDAP groups. This will |
| | | # disable team selection in Edit User and user selection in Edit Team. |
| | | # |
| | | # If false, LDAP will only be used for authentication and Gitblit will maintain |
| | | # team memberships with the *realm.ldap.backingUserService*. |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.maintainTeams = false |
| | | |
| | | # Root node for all LDAP users |
| | | # |
| | | # This is the root node from which subtree user searches will begin. |
| | | # If blank, Gitblit will search ALL nodes. |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.accountBase = OU=Users,OU=UserControl,OU=MyOrganization,DC=MyDomain |
| | | |
| | | # Filter criteria for LDAP users |
| | | # |
| | | # Query pattern to use when searching for a user account. This may be any valid |
| | | # LDAP query expression, including the standard (&) and (|) operators. |
| | | # |
| | | # Variables may be injected via the ${variableName} syntax. |
| | | # Recognized variables are: |
| | | # ${username} - The text entered as the user name |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.accountPattern = (&(objectClass=person)(sAMAccountName=${username})) |
| | | |
| | | # Root node for all LDAP groups to be used as Gitblit Teams |
| | | # |
| | | # This is the root node from which subtree team searches will begin. |
| | | # If blank, Gitblit will search ALL nodes. |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.groupBase = OU=Groups,OU=UserControl,OU=MyOrganization,DC=MyDomain |
| | | |
| | | # Filter criteria for LDAP groups |
| | | # |
| | | # Query pattern to use when searching for a team. This may be any valid |
| | | # LDAP query expression, including the standard (&) and (|) operators. |
| | | # |
| | | # Variables may be injected via the ${variableName} syntax. |
| | | # Recognized variables are: |
| | | # ${username} - The text entered as the user name |
| | | # ${dn} - The Distinguished Name of the user logged in |
| | | # |
| | | # All attributes from the LDAP User record are available. For example, if a user |
| | | # has an attribute "fullName" set to "John", "(fn=${fullName})" will be |
| | | # translated to "(fn=John)". |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.groupMemberPattern = (&(objectClass=group)(member=${dn})) |
| | | |
| | | # Filter criteria for empty LDAP groups |
| | | # |
| | | # Query pattern to use when searching for an empty team. This may be any valid |
| | | # LDAP query expression, including the standard (&) and (|) operators. |
| | | # |
| | | # default: (&(objectClass=group)(!(member=*))) |
| | | # SINCE 1.4.0 |
| | | realm.ldap.groupEmptyMemberPattern = (&(objectClass=group)(!(member=*))) |
| | | |
| | | # LDAP users or groups that should be given administrator privileges. |
| | | # |
| | | # Teams are specified with a leading '@' character. Groups with spaces in the |
| | | # name can be entered as "@team name". This setting only applies when using |
| | | # LDAP to maintain team memberships. |
| | | # |
| | | # e.g. realm.ldap.admins = john @git_admins "@git admins" |
| | | # |
| | | # SPACE-DELIMITED |
| | | # SINCE 1.0.0 |
| | | realm.ldap.admins = @Git_Admins |
| | | |
| | | # Attribute(s) on the USER record that indicate their display (or full) name. |
| | | # Leave blank for no mapping available in LDAP. |
| | | # |
| | | # This may be a single attribute, or a string of multiple attributes. Examples: |
| | | # displayName - Uses the attribute 'displayName' on the user record |
| | | # ${personalTitle}. ${givenName} ${surname} - Will concatenate the 3 |
| | | # attributes together, with a '.' after personalTitle |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.displayName = displayName |
| | | |
| | | # Attribute(s) on the USER record that indicate their email address. |
| | | # Leave blank for no mapping available in LDAP. |
| | | # |
| | | # This may be a single attribute, or a string of multiple attributes. Examples: |
| | | # email - Uses the attribute 'email' on the user record |
| | | # ${givenName}.${surname}@gitblit.com -Will concatenate the 2 attributes |
| | | # together with a '.' and '@' creating something like first.last@gitblit.com |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.email = email |
| | | |
| | | # Attribute on the USER record that indicate their username to be used in gitblit |
| | | # when synchronizing users from LDAP |
| | | # if blank, Gitblit will use uid |
| | | # For MS Active Directory this may be sAMAccountName |
| | | # |
| | | # SINCE 1.0.0 |
| | | realm.ldap.uid = uid |
| | | |
| | | # Defines whether to synchronize all LDAP users and teams into the user service |
| | | # |
| | | # Valid values: true, false |
| | | # If left blank, false is assumed |
| | | # |
| | | # SINCE 1.4.0 |
| | | realm.ldap.synchronize = false |
| | | |
| | | # Defines the period to be used when synchronizing users and teams from ldap. |
| | | # |
| | | # Must be of the form '<long> <TimeUnit>' where <TimeUnit> is one of 'MILLISECONDS', 'SECONDS', 'MINUTES', 'HOURS', 'DAYS' |
| | | |
| | | # default: 5 MINUTES |
| | | # |
| | | # RESTART REQUIRED |
| | | # SINCE 1.4.0 |
| | | realm.ldap.syncPeriod = 5 MINUTES |
| | | |
| | | # Defines whether to delete non-existent LDAP users from the user service |
| | | # during synchronization. depends on realm.ldap.synchronize = true |
| | | # |
| | | # Valid values: true, false |
| | | # If left blank, true is assumed |
| | | # |
| | | # SINCE 1.4.0 |
| | | realm.ldap.removeDeletedUsers = true |
| | | |
| | | # URL of the Redmine. |
| | | # |
| | | # SINCE 1.2.0 |
| | | realm.redmine.url = http://example.com/redmine |
| | | |
| | | # |
| | | # Gitblit GO Server Settings |
| | | # The following settings only affect the integrated GO variant. |
| | | # |
| | | |
| | | # The temporary folder to decompress the embedded gitblit webapp. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | # BASEFOLDER |
| | | server.tempFolder = ${baseFolder}/temp |
| | | |
| | | # Specify the maximum number of concurrent http/https Jetty worker |
| | | # threads to allow. This setting does not affect other threaded |
| | | # daemons and components of Gitblit. |
| | | # |
| | | # SINCE 1.3.0 |
| | | # RESTART REQUIRED |
| | | server.threadPoolSize = 50 |
| | | |
| | | # Context path for the GO application. You might want to change the context |
| | | # path if running Gitblit behind a proxy layer such as mod_proxy. |
| | | # |
| | | # SINCE 0.7.0 |
| | | # RESTART REQUIRED |
| | | server.contextPath = / |
| | | |
| | | # Standard http port to serve. <= 0 disables this connector. |
| | | # On Unix/Linux systems, ports < 1024 require root permissions. |
| | | # Recommended value: 80 or 8080 |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | server.httpPort = 0 |
| | | |
| | | # Secure/SSL https port to serve. <= 0 disables this connector. |
| | | # On Unix/Linux systems, ports < 1024 require root permissions. |
| | | # Recommended value: 443 or 8443 |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | server.httpsPort = 8443 |
| | | |
| | | # Automatically redirect http requests to the secure https connector. |
| | | # |
| | | # This setting requires that you have configured server.httpPort and server.httpsPort. |
| | | # Unless you are on a private LAN where you trust all client connections, it is |
| | | # recommended to use https for all communications. |
| | | # |
| | | # SINCE 1.4.0 |
| | | # RESTART REQUIRED |
| | | server.redirectToHttpsPort = false |
| | | |
| | | # Specify the interface for Jetty to bind the standard connector. |
| | | # You may specify an ip or an empty value to bind to all interfaces. |
| | | # Specifying localhost will result in Gitblit ONLY listening to requests to |
| | | # localhost. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | server.httpBindInterface = |
| | | |
| | | # Specify the interface for Jetty to bind the secure connector. |
| | | # You may specify an ip or an empty value to bind to all interfaces. |
| | | # Specifying localhost will result in Gitblit ONLY listening to requests to |
| | | # localhost. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | server.httpsBindInterface = |
| | | |
| | | # Alias of certificate to use for https/SSL serving. If blank the first |
| | | # certificate found in the keystore will be used. |
| | | # |
| | | # SINCE 1.2.0 |
| | | # RESTART REQUIRED |
| | | server.certificateAlias = localhost |
| | | |
| | | # Password for SSL keystore. |
| | | # Keystore password and certificate password must match. |
| | | # This is provided for convenience, its probably more secure to set this value |
| | | # using the --storePassword command line parameter. |
| | | # |
| | | # If you are using the official JRE or JDK from Oracle you may not have the |
| | | # JCE Unlimited Strength Jurisdiction Policy files bundled with your JVM. Because |
| | | # of this, your store/key password can not exceed 7 characters. If you require |
| | | # longer passwords you may need to install the JCE Unlimited Strength Jurisdiction |
| | | # Policy files from Oracle. |
| | | # |
| | | # http://www.oracle.com/technetwork/java/javase/downloads/index.html |
| | | # |
| | | # Gitblit and the Gitblit Certificate Authority will both indicate if Unlimited |
| | | # Strength encryption is available. |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | server.storePassword = gitblit |
| | | |
| | | # If serving over https (recommended) you might consider requiring clients to |
| | | # authenticate with ssl certificates. If enabled, only https clients with the |
| | | # a valid client certificate will be able to access Gitblit. |
| | | # |
| | | # If disabled, client certificate authentication is optional and will be tried |
| | | # first before falling-back to form authentication or basic authentication. |
| | | # |
| | | # Requiring client certificates to access any of Gitblit may be too extreme, |
| | | # consider this carefully. |
| | | # |
| | | # SINCE 1.2.0 |
| | | # RESTART REQUIRED |
| | | server.requireClientCertificates = false |
| | | |
| | | # Port for shutdown monitor to listen on. |
| | | # Define your overrides or custom settings below |
| | | # |
| | | # SINCE 0.5.0 |
| | | # RESTART REQUIRED |
| | | server.shutdownPort = 8081 |
| | |
| | | // gitblit.properties or web.xml
|
| | | def jenkinsUrl = gitblit.getString('groovy.jenkinsServer', 'http://yourserver/jenkins')
|
| | |
|
| | | // define the repository base url
|
| | | def jenkinsGitbaseurl = gitblit.getString('groovy.jenkinsGitbaseurl', "${url}/r")
|
| | |
|
| | | // define the trigger url
|
| | | def triggerUrl = jenkinsUrl + "/git/notifyCommit?url=${url}/r/${repository.name}"
|
| | | def triggerUrl = jenkinsUrl + "/git/notifyCommit?url=" + jenkinsGitbaseurl + "/${repository.name}"
|
| | |
|
| | | // trigger the build
|
| | | new URL(triggerUrl).getContent()
|
| | |
| | | #!/bin/bash -x |
| | | # This script installes gitblit on a system running under systemd. |
| | | # This script installs Gitblit on a system running under systemd. |
| | | # The script assumes the server is running as user giblit |
| | | |
| | | # First create a file with the default settings |
| | |
| | | GITBLIT_BASE_FOLDER=/opt/gitblit/data |
| | | GITBLIT_HTTP_PORT=0 |
| | | GITBLIT_HTTPS_PORT=8443 |
| | | GITBLIT_LOG=/var/log/gitblit.log |
| | | EOF |
| | | # Create a systemd service file |
| | | cat > /tmp/gitblit.service << EOF |
| | |
| | | EOF |
| | | |
| | | # Finally copy the files to the destination and register the systemd unit. |
| | | sudo su -c "cp /tmp/gitblit.defaults /etc/sysconfig/gitblit && cp /tmp/gitblit.service /usr/lib/systemd/system/" |
| | | sudo su -c "cp /tmp/gitblit.defaults /etc/sysconfig/gitblit && cp /tmp/gitblit.service /etc/systemd/system/" |
| | | sudo su -c "systemctl daemon-reload && systemctl enable gitblit.service && systemctl start gitblit.service" |
| | | # Prepare the logfile |
| | | sudo su -c "touch /var/log/gitblit.log && chown gitblit:gitblit /var/log/gitblit.log" |
| | |
| | | /clientapps.json |
| | | /defaults.properties |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?>
|
| | | <web-app version="2.4"
|
| | | xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
| | | xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
|
| | |
|
| | | <!-- The base folder is used to specify the root location of your Gitblit data.
|
| | | |
| | | ${baseFolder}/gitblit.properties
|
| | | ${baseFolder}/users.conf
|
| | | ${baseFolder}/projects.conf
|
| | | ${baseFolder}/robots.txt
|
| | | ${baseFolder}/git
|
| | | ${baseFolder}/groovy
|
| | | ${baseFolder}/groovy/grape
|
| | | ${baseFolder}/proposals
|
| | |
|
| | | By default, this location is WEB-INF/data. It is recommended to set this
|
| | | path to a location outside your webapps folder that is writable by your
|
| | | servlet container. Gitblit will copy the WEB-INF/data files to that
|
| | | location for you when it restarts. This approach makes upgrading simpler.
|
| | | All you have to do is set this parameter for the new release and then
|
| | | review the defaults for any new settings. Settings are always versioned
|
| | | with a SINCE x.y.z attribute and also noted in the release changelog.
|
| | | -->
|
| | | <env-entry>
|
| | | <description>The base folder is used to specify the root location of your Gitblit data.</description>
|
| | | <env-entry-name>baseFolder</env-entry-name>
|
| | | <env-entry-type>java.lang.String</env-entry-type>
|
| | | <env-entry-value>${contextFolder}/WEB-INF/data</env-entry-value>
|
| | | </env-entry>
|
| | | |
| | | <!-- Gitblit Displayname -->
|
| | | <display-name>Gitblit - @gb.version@</display-name>
|
| | |
|
| | | |
| | | <!-- Gitblit Context Listener --><!-- STRIP |
| | | <listener>
|
| | | <listener-class>com.gitblit.servlet.GitblitContext</listener-class>
|
| | | </listener>STRIP --> |
| | | |
| | | |
| | | <!-- Git Servlet
|
| | | <url-pattern> MUST match: |
| | | * GitFilter
|
| | | * com.gitblit.Constants.GIT_PATH
|
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <servlet>
|
| | | <servlet-name>GitServlet</servlet-name>
|
| | | <servlet-class>com.gitblit.servlet.GitServlet</servlet-class>
|
| | | </servlet>
|
| | | <servlet-mapping>
|
| | | <servlet-name>GitServlet</servlet-name> |
| | | <url-pattern>/git/*</url-pattern>
|
| | | </servlet-mapping>
|
| | | <servlet-mapping>
|
| | | <servlet-name>GitServlet</servlet-name> |
| | | <url-pattern>/r/*</url-pattern>
|
| | | </servlet-mapping>
|
| | |
|
| | | |
| | | <!-- SparkleShare Invite Servlet
|
| | | <url-pattern> MUST match: |
| | | * com.gitblit.Constants.SPARKLESHARE_INVITE_PATH
|
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <servlet>
|
| | | <servlet-name>SparkleShareInviteServlet</servlet-name>
|
| | | <servlet-class>com.gitblit.servlet.SparkleShareInviteServlet</servlet-class>
|
| | | </servlet>
|
| | | <servlet-mapping>
|
| | | <servlet-name>SparkleShareInviteServlet</servlet-name> |
| | | <url-pattern>/sparkleshare/*</url-pattern>
|
| | | </servlet-mapping>
|
| | |
|
| | | |
| | | <!-- Syndication Servlet
|
| | | <url-pattern> MUST match: |
| | | * SyndicationFilter
|
| | | * com.gitblit.Constants.SYNDICATION_PATH
|
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <servlet>
|
| | | <servlet-name>SyndicationServlet</servlet-name>
|
| | | <servlet-class>com.gitblit.servlet.SyndicationServlet</servlet-class> |
| | | </servlet>
|
| | | <servlet-mapping>
|
| | | <servlet-name>SyndicationServlet</servlet-name>
|
| | | <url-pattern>/feed/*</url-pattern>
|
| | | </servlet-mapping>
|
| | | |
| | | |
| | | <!-- Zip Servlet
|
| | | <url-pattern> MUST match: |
| | | * ZipServlet
|
| | | * com.gitblit.Constants.ZIP_PATH
|
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <servlet>
|
| | | <servlet-name>ZipServlet</servlet-name>
|
| | | <servlet-class>com.gitblit.servlet.DownloadZipServlet</servlet-class> |
| | | </servlet>
|
| | | <servlet-mapping>
|
| | | <servlet-name>ZipServlet</servlet-name>
|
| | | <url-pattern>/zip/*</url-pattern>
|
| | | </servlet-mapping>
|
| | | |
| | | |
| | | <!-- Federation Servlet
|
| | | <url-pattern> MUST match: |
| | | * com.gitblit.Constants.FEDERATION_PATH |
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <servlet>
|
| | | <servlet-name>FederationServlet</servlet-name>
|
| | | <servlet-class>com.gitblit.servlet.FederationServlet</servlet-class> |
| | | </servlet>
|
| | | <servlet-mapping>
|
| | | <servlet-name>FederationServlet</servlet-name>
|
| | | <url-pattern>/federation/*</url-pattern>
|
| | | </servlet-mapping> |
| | | |
| | | |
| | | <!-- Rpc Servlet
|
| | | <url-pattern> MUST match: |
| | | * com.gitblit.Constants.RPC_PATH |
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <servlet>
|
| | | <servlet-name>RpcServlet</servlet-name>
|
| | | <servlet-class>com.gitblit.servlet.RpcServlet</servlet-class> |
| | | </servlet>
|
| | | <servlet-mapping>
|
| | | <servlet-name>RpcServlet</servlet-name>
|
| | | <url-pattern>/rpc/*</url-pattern>
|
| | | </servlet-mapping> |
| | |
|
| | |
|
| | | <!-- Raw Servlet
|
| | | <url-pattern> MUST match: |
| | | * RawFilter
|
| | | * com.gitblit.Constants.RAW_PATH
|
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <servlet>
|
| | | <servlet-name>RawServlet</servlet-name>
|
| | | <servlet-class>com.gitblit.servlet.RawServlet</servlet-class>
|
| | | </servlet>
|
| | | <servlet-mapping>
|
| | | <servlet-name>RawServlet</servlet-name> |
| | | <url-pattern>/raw/*</url-pattern>
|
| | | </servlet-mapping> |
| | |
|
| | |
|
| | | <!-- Pages Servlet
|
| | | <url-pattern> MUST match: |
| | | * PagesFilter
|
| | | * com.gitblit.Constants.PAGES_PATH
|
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <servlet>
|
| | | <servlet-name>PagesServlet</servlet-name>
|
| | | <servlet-class>com.gitblit.servlet.PagesServlet</servlet-class>
|
| | | </servlet>
|
| | | <servlet-mapping>
|
| | | <servlet-name>PagesServlet</servlet-name> |
| | | <url-pattern>/pages/*</url-pattern>
|
| | | </servlet-mapping> |
| | |
|
| | | |
| | | <!-- Logo Servlet
|
| | | <url-pattern> MUST match: |
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <servlet>
|
| | | <servlet-name>LogoServlet</servlet-name>
|
| | | <servlet-class>com.gitblit.servlet.LogoServlet</servlet-class>
|
| | | </servlet>
|
| | | <servlet-mapping>
|
| | | <servlet-name>LogoServlet</servlet-name> |
| | | <url-pattern>/logo.png</url-pattern>
|
| | | </servlet-mapping>
|
| | |
|
| | |
|
| | | <!-- PT Servlet
|
| | | <url-pattern> MUST match: |
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <servlet>
|
| | | <servlet-name>PtServlet</servlet-name>
|
| | | <servlet-class>com.gitblit.servlet.PtServlet</servlet-class>
|
| | | </servlet>
|
| | | <servlet-mapping>
|
| | | <servlet-name>PtServlet</servlet-name> |
| | | <url-pattern>/pt</url-pattern>
|
| | | </servlet-mapping>
|
| | |
|
| | |
|
| | | <!-- Branch Graph Servlet
|
| | | <url-pattern> MUST match: |
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <servlet>
|
| | | <servlet-name>BranchGraphServlet</servlet-name>
|
| | | <servlet-class>com.gitblit.servlet.BranchGraphServlet</servlet-class>
|
| | | </servlet>
|
| | | <servlet-mapping>
|
| | | <servlet-name>BranchGraphServlet</servlet-name> |
| | | <url-pattern>/graph/*</url-pattern>
|
| | | </servlet-mapping>
|
| | |
|
| | | <!-- Robots.txt Servlet
|
| | | <url-pattern> MUST match: |
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <servlet>
|
| | | <servlet-name>RobotsTxtServlet</servlet-name>
|
| | | <servlet-class>com.gitblit.servlet.RobotsTxtServlet</servlet-class>
|
| | | </servlet>
|
| | | <servlet-mapping>
|
| | | <servlet-name>RobotsTxtServlet</servlet-name> |
| | | <url-pattern>/robots.txt</url-pattern>
|
| | | </servlet-mapping>
|
| | |
|
| | | <filter>
|
| | | <filter-name>ProxyFilter</filter-name>
|
| | | <filter-class>com.gitblit.servlet.ProxyFilter</filter-class>
|
| | | </filter>
|
| | | <filter-mapping>
|
| | | <filter-name>ProxyFilter</filter-name>
|
| | | <url-pattern>/*</url-pattern>
|
| | | </filter-mapping>
|
| | | |
| | | <!-- Git Access Restriction Filter
|
| | | <url-pattern> MUST match: |
| | | * GitServlet
|
| | | * com.gitblit.Constants.GIT_PATH
|
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <filter>
|
| | | <filter-name>GitFilter</filter-name>
|
| | | <filter-class>com.gitblit.servlet.GitFilter</filter-class>
|
| | | </filter>
|
| | | <filter-mapping>
|
| | | <filter-name>GitFilter</filter-name>
|
| | | <url-pattern>/git/*</url-pattern>
|
| | | </filter-mapping>
|
| | | <filter-mapping>
|
| | | <filter-name>GitFilter</filter-name>
|
| | | <url-pattern>/r/*</url-pattern>
|
| | | </filter-mapping>
|
| | | |
| | | |
| | | <!-- Syndication Restriction Filter
|
| | | <url-pattern> MUST match: |
| | | * SyndicationServlet
|
| | | * com.gitblit.Constants.SYNDICATION_PATH
|
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <filter>
|
| | | <filter-name>SyndicationFilter</filter-name>
|
| | | <filter-class>com.gitblit.servlet.SyndicationFilter</filter-class>
|
| | | </filter>
|
| | | <filter-mapping>
|
| | | <filter-name>SyndicationFilter</filter-name>
|
| | | <url-pattern>/feed/*</url-pattern>
|
| | | </filter-mapping>
|
| | | |
| | | |
| | | <!-- Download Zip Restriction Filter
|
| | | <url-pattern> MUST match: |
| | | * DownloadZipServlet
|
| | | * com.gitblit.Constants.ZIP_PATH
|
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <filter>
|
| | | <filter-name>ZipFilter</filter-name>
|
| | | <filter-class>com.gitblit.servlet.DownloadZipFilter</filter-class>
|
| | | </filter>
|
| | | <filter-mapping>
|
| | | <filter-name>ZipFilter</filter-name>
|
| | | <url-pattern>/zip/*</url-pattern>
|
| | | </filter-mapping>
|
| | |
|
| | | |
| | | <!-- Rpc Restriction Filter
|
| | | <url-pattern> MUST match: |
| | | * RpcServlet
|
| | | * com.gitblit.Constants.RPC_PATH
|
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <filter>
|
| | | <filter-name>RpcFilter</filter-name>
|
| | | <filter-class>com.gitblit.servlet.RpcFilter</filter-class>
|
| | | </filter>
|
| | | <filter-mapping>
|
| | | <filter-name>RpcFilter</filter-name>
|
| | | <url-pattern>/rpc/*</url-pattern>
|
| | | </filter-mapping>
|
| | |
|
| | |
|
| | | <!-- Branch Restriction Filter
|
| | | <url-pattern> MUST match: |
| | | * RawServlet
|
| | | * com.gitblit.Constants.BRANCH_PATH
|
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <filter>
|
| | | <filter-name>RawFilter</filter-name>
|
| | | <filter-class>com.gitblit.servlet.RawFilter</filter-class>
|
| | | </filter>
|
| | | <filter-mapping>
|
| | | <filter-name>RawFilter</filter-name>
|
| | | <url-pattern>/raw/*</url-pattern>
|
| | | </filter-mapping>
|
| | | |
| | |
|
| | | <!-- Pages Restriction Filter
|
| | | <url-pattern> MUST match: |
| | | * PagesServlet
|
| | | * com.gitblit.Constants.PAGES_PATH
|
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <filter>
|
| | | <filter-name>PagesFilter</filter-name>
|
| | | <filter-class>com.gitblit.servlet.PagesFilter</filter-class>
|
| | | </filter>
|
| | | <filter-mapping>
|
| | | <filter-name>PagesFilter</filter-name>
|
| | | <url-pattern>/pages/*</url-pattern>
|
| | | </filter-mapping>
|
| | | |
| | | <filter>
|
| | | <filter-name>EnforceAuthenticationFilter</filter-name>
|
| | | <filter-class>com.gitblit.servlet.EnforceAuthenticationFilter</filter-class>
|
| | | </filter>
|
| | | <filter-mapping>
|
| | | <filter-name>EnforceAuthenticationFilter</filter-name>
|
| | | <url-pattern>/*</url-pattern>
|
| | | </filter-mapping>
|
| | |
|
| | |
|
| | | <!-- Wicket Filter -->
|
| | | <filter>
|
| | | <filter-name>wicketFilter</filter-name>
|
| | | <filter-class>
|
| | | com.gitblit.wicket.GitblitWicketFilter
|
| | | </filter-class> |
| | | <init-param>
|
| | | <param-name>ignorePaths</param-name>
|
| | | <!-- Paths should match |
| | | * SyndicationFilter <url-pattern>
|
| | | * SyndicationServlet <url-pattern>
|
| | | * com.gitblit.Constants.SYNDICATION_PATH
|
| | | * GitFilter <url-pattern>
|
| | | * GitServlet <url-pattern>
|
| | | * com.gitblit.Constants.GIT_PATH
|
| | | * SparkleshareInviteServlet <url-pattern>
|
| | | * com.gitblit.Constants.SPARKLESHARE_INVITE_PATH
|
| | | * Zipfilter <url-pattern>
|
| | | * ZipServlet <url-pattern>
|
| | | * com.gitblit.Constants.ZIP_PATH
|
| | | * FederationServlet <url-pattern>
|
| | | * RpcFilter <url-pattern>
|
| | | * RpcServlet <url-pattern>
|
| | | * RawFilter <url-pattern>
|
| | | * RawServlet <url-pattern>
|
| | | * PagesFilter <url-pattern>
|
| | | * PagesServlet <url-pattern>
|
| | | * com.gitblit.Constants.PAGES_PATH -->
|
| | | <param-value>r/,git/,pt,feed/,zip/,federation/,rpc/,raw/,pages/,robots.txt,logo.png,graph/,sparkleshare/</param-value>
|
| | | </init-param>
|
| | | </filter>
|
| | | <filter-mapping>
|
| | | <filter-name>wicketFilter</filter-name>
|
| | | <url-pattern>/*</url-pattern>
|
| | | </filter-mapping>
|
| | | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <web-app version="2.4" |
| | | xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_3_0.xsd"> |
| | | |
| | | <!-- The base folder is used to specify the root location of your Gitblit data. |
| | | |
| | | ${baseFolder}/gitblit.properties |
| | | ${baseFolder}/users.conf |
| | | ${baseFolder}/projects.conf |
| | | ${baseFolder}/robots.txt |
| | | ${baseFolder}/git |
| | | ${baseFolder}/groovy |
| | | ${baseFolder}/groovy/grape |
| | | ${baseFolder}/proposals |
| | | |
| | | By default, this location is WEB-INF/data. It is recommended to set this |
| | | path to a location outside your webapps folder that is writable by your |
| | | servlet container. Gitblit will copy the WEB-INF/data files to that |
| | | location for you when it restarts. This approach makes upgrading simpler. |
| | | All you have to do is set this parameter for the new release and then |
| | | review the defaults for any new settings. Settings are always versioned |
| | | with a SINCE x.y.z attribute and also noted in the release changelog. |
| | | --> |
| | | <env-entry> |
| | | <description>The base folder is used to specify the root location of your Gitblit data.</description> |
| | | <env-entry-name>baseFolder</env-entry-name> |
| | | <env-entry-type>java.lang.String</env-entry-type> |
| | | <env-entry-value>${contextFolder}/WEB-INF/data</env-entry-value> |
| | | </env-entry> |
| | | |
| | | <!-- Gitblit Displayname --> |
| | | <display-name>Gitblit - @gb.version@</display-name> |
| | | |
| | | <listener> |
| | | <listener-class>com.gitblit.servlet.GitblitContext</listener-class> |
| | | </listener> |
| | | |
| | | <filter> |
| | | <filter-name>guiceFilter</filter-name> |
| | | <filter-class>com.google.inject.servlet.GuiceFilter</filter-class> |
| | | </filter> |
| | | |
| | | <filter-mapping> |
| | | <filter-name>guiceFilter</filter-name> |
| | | <url-pattern>/*</url-pattern> |
| | | </filter-mapping> |
| | | |
| | | <session-config> |
| | | <tracking-mode>COOKIE</tracking-mode> |
| | | </session-config> |
| | | </web-app> |
New file |
| | |
| | | /* |
| | | * Copyright 2015 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; |
| | | |
| | | public interface AvatarGenerator { |
| | | |
| | | String getURL(String username, String emailaddress, boolean identicon, int width); |
| | | |
| | | } |
| | |
| | |
|
| | | import com.gitblit.Constants.AccessPermission;
|
| | | import com.gitblit.Constants.AccountType;
|
| | | import com.gitblit.Constants.Role;
|
| | | import com.gitblit.Constants.Transport;
|
| | | import com.gitblit.manager.IRuntimeManager;
|
| | | import com.gitblit.models.TeamModel;
|
| | |
| | | // user roles
|
| | | List<String> roles = new ArrayList<String>();
|
| | | if (model.canAdmin) {
|
| | | roles.add(Constants.ADMIN_ROLE);
|
| | | roles.add(Role.ADMIN.getRole());
|
| | | }
|
| | | if (model.canFork) {
|
| | | roles.add(Constants.FORK_ROLE);
|
| | | roles.add(Role.FORK.getRole());
|
| | | }
|
| | | if (model.canCreate) {
|
| | | roles.add(Constants.CREATE_ROLE);
|
| | | roles.add(Role.CREATE.getRole());
|
| | | }
|
| | | if (model.excludeFromFederation) {
|
| | | roles.add(Constants.NOT_FEDERATED_ROLE);
|
| | | roles.add(Role.NOT_FEDERATED.getRole());
|
| | | }
|
| | | if (roles.size() == 0) {
|
| | | // we do this to ensure that user record with no password
|
| | | // is written. otherwise, StoredConfig optimizes that account
|
| | | // away. :(
|
| | | roles.add(Constants.NO_ROLE);
|
| | | roles.add(Role.NONE.getRole());
|
| | | }
|
| | | config.setStringList(USER, model.username, ROLE, roles);
|
| | |
|
| | |
| | | // team roles
|
| | | List<String> roles = new ArrayList<String>();
|
| | | if (model.canAdmin) {
|
| | | roles.add(Constants.ADMIN_ROLE);
|
| | | roles.add(Role.ADMIN.getRole());
|
| | | }
|
| | | if (model.canFork) {
|
| | | roles.add(Constants.FORK_ROLE);
|
| | | roles.add(Role.FORK.getRole());
|
| | | }
|
| | | if (model.canCreate) {
|
| | | roles.add(Constants.CREATE_ROLE);
|
| | | roles.add(Role.CREATE.getRole());
|
| | | }
|
| | | if (roles.size() == 0) {
|
| | | // we do this to ensure that team record is written.
|
| | | // Otherwise, StoredConfig might optimizes that record away.
|
| | | roles.add(Constants.NO_ROLE);
|
| | | roles.add(Role.NONE.getRole());
|
| | | }
|
| | | config.setStringList(TEAM, model.name, ROLE, roles);
|
| | | if (model.accountType != null) {
|
| | |
| | | user.displayName = config.getString(USER, username, DISPLAYNAME);
|
| | | user.emailAddress = config.getString(USER, username, EMAILADDRESS);
|
| | | user.accountType = AccountType.fromString(config.getString(USER, username, ACCOUNTTYPE));
|
| | | if (Constants.EXTERNAL_ACCOUNT.equals(user.password) && user.accountType.isLocal()) {
|
| | | user.accountType = AccountType.EXTERNAL;
|
| | | }
|
| | | user.disabled = config.getBoolean(USER, username, DISABLED, false);
|
| | | user.organizationalUnit = config.getString(USER, username, ORGANIZATIONALUNIT);
|
| | | user.organization = config.getString(USER, username, ORGANIZATION);
|
| | |
| | | // user roles
|
| | | Set<String> roles = new HashSet<String>(Arrays.asList(config.getStringList(
|
| | | USER, username, ROLE)));
|
| | | user.canAdmin = roles.contains(Constants.ADMIN_ROLE);
|
| | | user.canFork = roles.contains(Constants.FORK_ROLE);
|
| | | user.canCreate = roles.contains(Constants.CREATE_ROLE);
|
| | | user.excludeFromFederation = roles.contains(Constants.NOT_FEDERATED_ROLE);
|
| | | user.canAdmin = roles.contains(Role.ADMIN.getRole());
|
| | | user.canFork = roles.contains(Role.FORK.getRole());
|
| | | user.canCreate = roles.contains(Role.CREATE.getRole());
|
| | | user.excludeFromFederation = roles.contains(Role.NOT_FEDERATED.getRole());
|
| | |
|
| | | // repository memberships
|
| | | if (!user.canAdmin) {
|
| | |
| | | TeamModel team = new TeamModel(teamname);
|
| | | Set<String> roles = new HashSet<String>(Arrays.asList(config.getStringList(
|
| | | TEAM, teamname, ROLE)));
|
| | | team.canAdmin = roles.contains(Constants.ADMIN_ROLE);
|
| | | team.canFork = roles.contains(Constants.FORK_ROLE);
|
| | | team.canCreate = roles.contains(Constants.CREATE_ROLE);
|
| | | team.canAdmin = roles.contains(Role.ADMIN.getRole());
|
| | | team.canFork = roles.contains(Role.FORK.getRole());
|
| | | team.canCreate = roles.contains(Role.CREATE.getRole());
|
| | | team.accountType = AccountType.fromString(config.getString(TEAM, teamname, ACCOUNTTYPE));
|
| | |
|
| | | if (!team.canAdmin) {
|
| | |
| | |
|
| | | public static final String FULL_NAME = "Gitblit - a pure Java Git solution";
|
| | |
|
| | | @Deprecated
|
| | | public static final String ADMIN_ROLE = "#admin";
|
| | |
|
| | | @Deprecated
|
| | | public static final String FORK_ROLE = "#fork";
|
| | |
|
| | | @Deprecated
|
| | | public static final String CREATE_ROLE = "#create";
|
| | |
|
| | | @Deprecated
|
| | | public static final String NOT_FEDERATED_ROLE = "#notfederated";
|
| | |
|
| | | @Deprecated
|
| | | public static final String NO_ROLE = "#none";
|
| | |
|
| | | public static final String EXTERNAL_ACCOUNT = "#externalAccount";
|
| | |
| | | public static final String R_PATH = "/r/";
|
| | |
|
| | | public static final String GIT_PATH = "/git/";
|
| | | |
| | | public static final String REGEX_SHA256 = "[a-fA-F0-9]{64}";
|
| | |
|
| | | public static final String ZIP_PATH = "/zip/";
|
| | |
|
| | |
| | | public static final String SPARKLESHARE_INVITE_PATH = "/sparkleshare/";
|
| | |
|
| | | public static final String RAW_PATH = "/raw/";
|
| | |
|
| | | public static final String PT_PATH = "/pt";
|
| | |
|
| | | public static final String BRANCH_GRAPH_PATH = "/graph/";
|
| | |
|
| | |
| | | public static final int LEN_SHORTLOG = 78;
|
| | |
|
| | | public static final int LEN_SHORTLOG_REFS = 60;
|
| | | |
| | | public static final int LEN_FILESTORE_META_MIN = 125;
|
| | | |
| | | public static final int LEN_FILESTORE_META_MAX = 146;
|
| | |
|
| | | public static final String DEFAULT_BRANCH = "default";
|
| | |
|
| | |
| | |
|
| | | public static final String DEVELOP = "develop";
|
| | |
|
| | | public static final String AUTHENTICATION_TYPE = "authentication-type";
|
| | | public static final String ATTRIB_AUTHTYPE = NAME + ":authentication-type";
|
| | |
|
| | | public static final String ATTRIB_AUTHUSER = NAME + ":authenticated-user";
|
| | | |
| | | public static final String R_LFS = "info/lfs/";
|
| | |
|
| | | public static String getVersion() {
|
| | | String v = Constants.class.getPackage().getImplementationVersion();
|
| | |
| | |
|
| | | public static String getBuildDate() {
|
| | | return getManifestValue("build-date", "PENDING");
|
| | | }
|
| | |
|
| | | public static String getASCIIArt() {
|
| | | StringBuilder sb = new StringBuilder();
|
| | | sb.append(" _____ _ _ _ _ _ _").append('\n');
|
| | | sb.append(" | __ \\(_)| | | | | |(_)| |").append('\n');
|
| | | sb.append(" | | \\/ _ | |_ | |__ | | _ | |_").append('\n');
|
| | | sb.append(" | | __ | || __|| '_ \\ | || || __|").append(" ").append("http://gitblit.com").append('\n');
|
| | | sb.append(" | |_\\ \\| || |_ | |_) || || || |_").append(" ").append("@gitblit").append('\n');
|
| | | sb.append(" \\____/|_| \\__||_.__/ |_||_| \\__|").append(" ").append(Constants.getVersion()).append('\n');
|
| | | return sb.toString();
|
| | | }
|
| | |
|
| | | private static String getManifestValue(String attrib, String defaultValue) {
|
| | |
| | | } catch (Exception e) {
|
| | | }
|
| | | return defaultValue;
|
| | | }
|
| | |
|
| | | public static enum Role {
|
| | | NONE, ADMIN, CREATE, FORK, NOT_FEDERATED;
|
| | |
|
| | | public String getRole() {
|
| | | return "#" + name().replace("_", "").toLowerCase();
|
| | | }
|
| | |
|
| | | @Override
|
| | | public String toString() {
|
| | | return getRole();
|
| | | }
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | }
|
| | |
|
| | | public static enum AuthenticationType {
|
| | | PUBLIC_KEY, CREDENTIALS, COOKIE, CERTIFICATE, CONTAINER;
|
| | | PUBLIC_KEY, CREDENTIALS, COOKIE, CERTIFICATE, CONTAINER, HTTPHEADER;
|
| | |
|
| | | public boolean isStandard() {
|
| | | return ordinal() <= COOKIE.ordinal();
|
| | |
| | | }
|
| | |
|
| | | public static enum AccountType {
|
| | | LOCAL, EXTERNAL, CONTAINER, LDAP, REDMINE, SALESFORCE, WINDOWS, PAM, HTPASSWD;
|
| | | LOCAL, CONTAINER, LDAP, REDMINE, SALESFORCE, WINDOWS, PAM, HTPASSWD, HTTPHEADER;
|
| | |
|
| | | public static AccountType fromString(String value) {
|
| | | for (AccountType type : AccountType.values()) {
|
| | |
| | | /*
|
| | | * 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.io.File;
|
| | | import java.util.ArrayList;
|
| | | import java.util.Collection;
|
| | | import java.util.List;
|
| | |
|
| | | import org.kohsuke.args4j.CmdLineException;
|
| | | import org.kohsuke.args4j.CmdLineParser;
|
| | | import org.kohsuke.args4j.Option;
|
| | |
|
| | | import com.gitblit.manager.FederationManager;
|
| | | import com.gitblit.manager.GitblitManager;
|
| | | import com.gitblit.manager.IGitblit;
|
| | | import com.gitblit.manager.INotificationManager;
|
| | | import com.gitblit.manager.RepositoryManager;
|
| | | import com.gitblit.manager.RuntimeManager;
|
| | | import com.gitblit.manager.UserManager;
|
| | | import com.gitblit.models.FederationModel;
|
| | | import com.gitblit.models.Mailing;
|
| | | import com.gitblit.service.FederationPullService;
|
| | | import com.gitblit.utils.FederationUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | | import com.gitblit.utils.XssFilter;
|
| | | import com.gitblit.utils.XssFilter.AllowXssFilter;
|
| | |
|
| | | /**
|
| | | * Command-line client to pull federated Gitblit repositories.
|
| | | *
|
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | public class FederationClient {
|
| | |
|
| | | public static void main(String[] args) {
|
| | | Params params = new Params();
|
| | | CmdLineParser parser = new CmdLineParser(params);
|
| | | try {
|
| | | parser.parseArgument(args);
|
| | | } catch (CmdLineException t) {
|
| | | usage(parser, t);
|
| | | }
|
| | |
|
| | | System.out.println("Gitblit Federation Client v" + Constants.getVersion() + " (" + Constants.getBuildDate() + ")");
|
| | |
|
| | | // command-line specified base folder
|
| | | File baseFolder = new File(System.getProperty("user.dir"));
|
| | | if (!StringUtils.isEmpty(params.baseFolder)) {
|
| | | baseFolder = new File(params.baseFolder);
|
| | | }
|
| | |
|
| | | File regFile = com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$, baseFolder, params.registrationsFile);
|
| | | FileSettings settings = new FileSettings(regFile.getAbsolutePath());
|
| | | List<FederationModel> registrations = new ArrayList<FederationModel>();
|
| | | if (StringUtils.isEmpty(params.url)) {
|
| | | registrations.addAll(FederationUtils.getFederationRegistrations(settings));
|
| | | } else {
|
| | | if (StringUtils.isEmpty(params.token)) {
|
| | | System.out.println("Must specify --token parameter!");
|
| | | System.exit(0);
|
| | | }
|
| | | FederationModel model = new FederationModel("Gitblit");
|
| | | model.url = params.url;
|
| | | model.token = params.token;
|
| | | model.mirror = params.mirror;
|
| | | model.bare = params.bare;
|
| | | model.folder = "";
|
| | | registrations.add(model);
|
| | | }
|
| | | if (registrations.size() == 0) {
|
| | | System.out.println("No Federation Registrations! Nothing to do.");
|
| | | System.exit(0);
|
| | | }
|
| | |
|
| | | // command-line specified repositories folder
|
| | | if (!StringUtils.isEmpty(params.repositoriesFolder)) {
|
| | | settings.overrideSetting(Keys.git.repositoriesFolder, new File(
|
| | | params.repositoriesFolder).getAbsolutePath());
|
| | | }
|
| | |
|
| | | // configure the Gitblit singleton for minimal, non-server operation
|
| | | XssFilter xssFilter = new AllowXssFilter();
|
| | | RuntimeManager runtime = new RuntimeManager(settings, xssFilter, baseFolder).start();
|
| | | NoopNotificationManager notifications = new NoopNotificationManager().start();
|
| | | UserManager users = new UserManager(runtime, null).start();
|
| | | RepositoryManager repositories = new RepositoryManager(runtime, null, users).start();
|
| | | FederationManager federation = new FederationManager(runtime, notifications, repositories).start();
|
| | | IGitblit gitblit = new GitblitManager(runtime, null, notifications, users, null, null, repositories, null, federation);
|
| | |
|
| | | FederationPullService puller = new FederationPullService(gitblit, federation.getFederationRegistrations()) {
|
| | | @Override
|
| | | public void reschedule(FederationModel registration) {
|
| | | // NOOP
|
| | | }
|
| | | };
|
| | | puller.run();
|
| | |
|
| | | System.out.println("Finished.");
|
| | | System.exit(0);
|
| | | }
|
| | |
|
| | | private static void usage(CmdLineParser parser, CmdLineException t) {
|
| | | System.out.println(Constants.getGitBlitVersion());
|
| | | System.out.println();
|
| | | if (t != null) {
|
| | | System.out.println(t.getMessage());
|
| | | System.out.println();
|
| | | }
|
| | |
|
| | | if (parser != null) {
|
| | | parser.printUsage(System.out);
|
| | | }
|
| | | System.exit(0);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Parameters class for FederationClient.
|
| | | */
|
| | | private static class Params {
|
| | |
|
| | | @Option(name = "--registrations", usage = "Gitblit Federation Registrations File", metaVar = "FILE")
|
| | | public String registrationsFile = "${baseFolder}/federation.properties";
|
| | |
|
| | | @Option(name = "--url", usage = "URL of Gitblit instance to mirror from", metaVar = "URL")
|
| | | public String url;
|
| | |
|
| | | @Option(name = "--mirror", usage = "Mirror repositories")
|
| | | public boolean mirror;
|
| | |
|
| | | @Option(name = "--bare", usage = "Create bare repositories")
|
| | | public boolean bare;
|
| | |
|
| | | @Option(name = "--token", usage = "Federation Token", metaVar = "TOKEN")
|
| | | public String token;
|
| | |
|
| | | @Option(name = "--baseFolder", usage = "Base folder for received data", metaVar = "PATH")
|
| | | public String baseFolder;
|
| | |
|
| | | @Option(name = "--repositoriesFolder", usage = "Destination folder for cloned repositories", metaVar = "PATH")
|
| | | public String repositoriesFolder;
|
| | |
|
| | | }
|
| | |
|
| | | private static class NoopNotificationManager implements INotificationManager {
|
| | |
|
| | | @Override
|
| | | public NoopNotificationManager start() {
|
| | | return this;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public NoopNotificationManager stop() {
|
| | | return this;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public boolean isSendingMail() {
|
| | | return false;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public void sendMailToAdministrators(String subject, String message) {
|
| | | }
|
| | |
|
| | | @Override
|
| | | public void sendMail(String subject, String message, Collection<String> toAddresses) {
|
| | | }
|
| | |
|
| | | @Override
|
| | | public void sendHtmlMail(String subject, String message, Collection<String> toAddresses) {
|
| | | }
|
| | |
|
| | | @Override
|
| | | public void send(Mailing mailing) {
|
| | | }
|
| | | }
|
| | | }
|
| | | /* |
| | | * 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.io.File; |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | import org.kohsuke.args4j.CmdLineException; |
| | | import org.kohsuke.args4j.CmdLineParser; |
| | | import org.kohsuke.args4j.Option; |
| | | |
| | | import com.gitblit.manager.FederationManager; |
| | | import com.gitblit.manager.GitblitManager; |
| | | import com.gitblit.manager.IGitblit; |
| | | import com.gitblit.manager.INotificationManager; |
| | | import com.gitblit.manager.RepositoryManager; |
| | | import com.gitblit.manager.RuntimeManager; |
| | | import com.gitblit.manager.UserManager; |
| | | import com.gitblit.models.FederationModel; |
| | | import com.gitblit.models.Mailing; |
| | | import com.gitblit.service.FederationPullService; |
| | | import com.gitblit.utils.FederationUtils; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.gitblit.utils.XssFilter; |
| | | import com.gitblit.utils.XssFilter.AllowXssFilter; |
| | | |
| | | /** |
| | | * Command-line client to pull federated Gitblit repositories. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | public class FederationClient { |
| | | |
| | | public static void main(String[] args) { |
| | | Params params = new Params(); |
| | | CmdLineParser parser = new CmdLineParser(params); |
| | | try { |
| | | parser.parseArgument(args); |
| | | } catch (CmdLineException t) { |
| | | usage(parser, t); |
| | | } |
| | | |
| | | System.out.println("Gitblit Federation Client v" + Constants.getVersion() + " (" + Constants.getBuildDate() + ")"); |
| | | |
| | | // command-line specified base folder |
| | | File baseFolder = new File(System.getProperty("user.dir")); |
| | | if (!StringUtils.isEmpty(params.baseFolder)) { |
| | | baseFolder = new File(params.baseFolder); |
| | | } |
| | | |
| | | File regFile = com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$, baseFolder, params.registrationsFile); |
| | | FileSettings settings = new FileSettings(regFile.getAbsolutePath()); |
| | | List<FederationModel> registrations = new ArrayList<FederationModel>(); |
| | | if (StringUtils.isEmpty(params.url)) { |
| | | registrations.addAll(FederationUtils.getFederationRegistrations(settings)); |
| | | } else { |
| | | if (StringUtils.isEmpty(params.token)) { |
| | | System.out.println("Must specify --token parameter!"); |
| | | System.exit(0); |
| | | } |
| | | FederationModel model = new FederationModel("Gitblit"); |
| | | model.url = params.url; |
| | | model.token = params.token; |
| | | model.mirror = params.mirror; |
| | | model.bare = params.bare; |
| | | model.folder = ""; |
| | | registrations.add(model); |
| | | } |
| | | if (registrations.size() == 0) { |
| | | System.out.println("No Federation Registrations! Nothing to do."); |
| | | System.exit(0); |
| | | } |
| | | |
| | | // command-line specified repositories folder |
| | | if (!StringUtils.isEmpty(params.repositoriesFolder)) { |
| | | settings.overrideSetting(Keys.git.repositoriesFolder, new File( |
| | | params.repositoriesFolder).getAbsolutePath()); |
| | | } |
| | | |
| | | // configure the Gitblit singleton for minimal, non-server operation |
| | | XssFilter xssFilter = new AllowXssFilter(); |
| | | RuntimeManager runtime = new RuntimeManager(settings, xssFilter, baseFolder).start(); |
| | | NoopNotificationManager notifications = new NoopNotificationManager().start(); |
| | | UserManager users = new UserManager(runtime, null).start(); |
| | | RepositoryManager repositories = new RepositoryManager(runtime, null, users).start(); |
| | | FederationManager federation = new FederationManager(runtime, notifications, repositories).start(); |
| | | IGitblit gitblit = new GitblitManager(null, null, runtime, null, notifications, users, null, repositories, null, federation, null); |
| | | |
| | | FederationPullService puller = new FederationPullService(gitblit, federation.getFederationRegistrations()) { |
| | | @Override |
| | | public void reschedule(FederationModel registration) { |
| | | // NOOP |
| | | } |
| | | }; |
| | | puller.run(); |
| | | |
| | | System.out.println("Finished."); |
| | | System.exit(0); |
| | | } |
| | | |
| | | private static void usage(CmdLineParser parser, CmdLineException t) { |
| | | System.out.println(Constants.getGitBlitVersion()); |
| | | System.out.println(); |
| | | if (t != null) { |
| | | System.out.println(t.getMessage()); |
| | | System.out.println(); |
| | | } |
| | | |
| | | if (parser != null) { |
| | | parser.printUsage(System.out); |
| | | } |
| | | System.exit(0); |
| | | } |
| | | |
| | | /** |
| | | * Parameters class for FederationClient. |
| | | */ |
| | | private static class Params { |
| | | |
| | | @Option(name = "--registrations", usage = "Gitblit Federation Registrations File", metaVar = "FILE") |
| | | public String registrationsFile = "${baseFolder}/federation.properties"; |
| | | |
| | | @Option(name = "--url", usage = "URL of Gitblit instance to mirror from", metaVar = "URL") |
| | | public String url; |
| | | |
| | | @Option(name = "--mirror", usage = "Mirror repositories") |
| | | public boolean mirror; |
| | | |
| | | @Option(name = "--bare", usage = "Create bare repositories") |
| | | public boolean bare; |
| | | |
| | | @Option(name = "--token", usage = "Federation Token", metaVar = "TOKEN") |
| | | public String token; |
| | | |
| | | @Option(name = "--baseFolder", usage = "Base folder for received data", metaVar = "PATH") |
| | | public String baseFolder; |
| | | |
| | | @Option(name = "--repositoriesFolder", usage = "Destination folder for cloned repositories", metaVar = "PATH") |
| | | public String repositoriesFolder; |
| | | |
| | | } |
| | | |
| | | private static class NoopNotificationManager implements INotificationManager { |
| | | |
| | | @Override |
| | | public NoopNotificationManager start() { |
| | | return this; |
| | | } |
| | | |
| | | @Override |
| | | public NoopNotificationManager stop() { |
| | | return this; |
| | | } |
| | | |
| | | @Override |
| | | public boolean isSendingMail() { |
| | | return false; |
| | | } |
| | | |
| | | @Override |
| | | public void sendMailToAdministrators(String subject, String message) { |
| | | } |
| | | |
| | | @Override |
| | | public void sendMail(String subject, String message, Collection<String> toAddresses) { |
| | | } |
| | | |
| | | @Override |
| | | public void sendHtmlMail(String subject, String message, Collection<String> toAddresses) { |
| | | } |
| | | |
| | | @Override |
| | | public void send(Mailing mailing) { |
| | | } |
| | | } |
| | | } |
| | |
| | | import java.io.File;
|
| | | import java.io.FileInputStream;
|
| | | import java.io.FileNotFoundException;
|
| | | import java.io.IOException;
|
| | | import java.util.List;
|
| | | import java.util.Map;
|
| | | import java.util.Properties;
|
| | |
|
| | | import com.gitblit.utils.FileUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | |
|
| | | /**
|
| | | * Dynamically loads and reloads a properties file by keeping track of the last
|
| | |
| | | if (propertiesFile != null && propertiesFile.exists() && (forceReload || (propertiesFile.lastModified() > lastModified))) {
|
| | | FileInputStream is = null;
|
| | | try {
|
| | | logger.debug("loading {}", propertiesFile);
|
| | | Properties props = new Properties();
|
| | | is = new FileInputStream(propertiesFile);
|
| | | props.load(is);
|
| | |
|
| | | // ticket-110
|
| | | props = readIncludes(props);
|
| | |
|
| | | // load properties after we have successfully read file
|
| | | properties.clear();
|
| | |
| | | return properties;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Recursively read "include" properties files.
|
| | | *
|
| | | * @param properties
|
| | | * @return
|
| | | * @throws IOException
|
| | | */
|
| | | private Properties readIncludes(Properties properties) throws IOException {
|
| | |
|
| | | Properties baseProperties = new Properties();
|
| | |
|
| | | String include = (String) properties.remove("include");
|
| | | if (!StringUtils.isEmpty(include)) {
|
| | |
|
| | | // allow for multiples
|
| | | List<String> names = StringUtils.getStringsFromValue(include, ",");
|
| | | for (String name : names) {
|
| | |
|
| | | if (StringUtils.isEmpty(name)) {
|
| | | continue;
|
| | | }
|
| | |
|
| | | // try co-located
|
| | | File file = new File(propertiesFile.getParentFile(), name.trim());
|
| | | if (!file.exists()) {
|
| | | // try absolute path
|
| | | file = new File(name.trim());
|
| | | }
|
| | |
|
| | | if (!file.exists()) {
|
| | | logger.warn("failed to locate {}", file);
|
| | | continue;
|
| | | }
|
| | |
|
| | | // load properties
|
| | | logger.debug("loading {}", file);
|
| | | try (FileInputStream iis = new FileInputStream(file)) {
|
| | | baseProperties.load(iis);
|
| | | }
|
| | |
|
| | | // read nested includes
|
| | | baseProperties = readIncludes(baseProperties);
|
| | |
|
| | | }
|
| | |
|
| | | }
|
| | |
|
| | | // includes are "default" properties, they must be set first and the
|
| | | // props which specified the "includes" must override
|
| | | Properties merged = new Properties();
|
| | | merged.putAll(baseProperties);
|
| | | merged.putAll(properties);
|
| | |
|
| | | return merged;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public boolean saveSettings() {
|
| | | String content = FileUtils.readContent(propertiesFile, "\n");
|
| | | for (String key : removals) {
|
| | | String regex = "(?m)^(" + regExEscape(key) + "\\s*+=\\s*+)"
|
| | | + "(?:[^\r\n\\\\]++|\\\\(?:\r?\n|\r|.))*+$";
|
| | | + "(?:[^\r\n\\\\]++|\\\\(?:\r?\n|\r|.))*+$";
|
| | | content = content.replaceAll(regex, "");
|
| | | }
|
| | | removals.clear();
|
| | |
| | | String content = FileUtils.readContent(propertiesFile, "\n");
|
| | | for (Map.Entry<String, String> setting:settings.entrySet()) {
|
| | | String regex = "(?m)^(" + regExEscape(setting.getKey()) + "\\s*+=\\s*+)"
|
| | | + "(?:[^\r\n\\\\]++|\\\\(?:\r?\n|\r|.))*+$";
|
| | | + "(?:[^\r\n\\\\]++|\\\\(?:\r?\n|\r|.))*+$";
|
| | | String oldContent = content;
|
| | | content = content.replaceAll(regex, setting.getKey() + " = " + setting.getValue());
|
| | | if (content.equals(oldContent)) {
|
| | |
| | | */ |
| | | package com.gitblit; |
| | | |
| | | import java.text.MessageFormat; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.Comparator; |
| | | import java.util.HashSet; |
| | | import java.util.Iterator; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | | import javax.inject.Singleton; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | |
| | | import com.gitblit.Constants.AccessPermission; |
| | | import com.gitblit.Constants.Transport; |
| | | import com.gitblit.manager.GitblitManager; |
| | | import com.gitblit.manager.IAuthenticationManager; |
| | | import com.gitblit.manager.IFederationManager; |
| | | import com.gitblit.manager.IGitblit; |
| | | import com.gitblit.manager.IFilestoreManager; |
| | | import com.gitblit.manager.INotificationManager; |
| | | import com.gitblit.manager.IPluginManager; |
| | | import com.gitblit.manager.IProjectManager; |
| | | import com.gitblit.manager.IRepositoryManager; |
| | | import com.gitblit.manager.IRuntimeManager; |
| | | import com.gitblit.manager.IUserManager; |
| | | import com.gitblit.manager.ServicesManager; |
| | | import com.gitblit.models.RepositoryModel; |
| | | import com.gitblit.models.RepositoryUrl; |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.tickets.BranchTicketService; |
| | | import com.gitblit.tickets.FileTicketService; |
| | | import com.gitblit.tickets.ITicketService; |
| | | import com.gitblit.tickets.NullTicketService; |
| | | import com.gitblit.tickets.RedisTicketService; |
| | | import com.gitblit.transport.ssh.IPublicKeyManager; |
| | | import com.gitblit.utils.StringUtils; |
| | | |
| | | import dagger.Module; |
| | | import dagger.ObjectGraph; |
| | | import dagger.Provides; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Provider; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * GitBlit is the aggregate manager for the Gitblit webapp. It provides all |
| | | * management functions and also manages some long-running services. |
| | | * GitBlit is the aggregate manager for the Gitblit webapp. The parent class provides all |
| | | * functionality. This class exists to not break existing Groovy push hooks. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | @Deprecated |
| | | public class GitBlit extends GitblitManager { |
| | | |
| | | private final ObjectGraph injector; |
| | | |
| | | private final ServicesManager servicesManager; |
| | | |
| | | private ITicketService ticketService; |
| | | |
| | | @Inject |
| | | public GitBlit( |
| | | Provider<IPublicKeyManager> publicKeyManagerProvider, |
| | | Provider<ITicketService> ticketServiceProvider, |
| | | IRuntimeManager runtimeManager, |
| | | IPluginManager pluginManager, |
| | | INotificationManager notificationManager, |
| | | IUserManager userManager, |
| | | IAuthenticationManager authenticationManager, |
| | | IPublicKeyManager publicKeyManager, |
| | | IRepositoryManager repositoryManager, |
| | | IProjectManager projectManager, |
| | | IFederationManager federationManager) { |
| | | IFederationManager federationManager, |
| | | IFilestoreManager filestoreManager) { |
| | | |
| | | super(runtimeManager, |
| | | super( |
| | | publicKeyManagerProvider, |
| | | ticketServiceProvider, |
| | | runtimeManager, |
| | | pluginManager, |
| | | notificationManager, |
| | | userManager, |
| | | authenticationManager, |
| | | publicKeyManager, |
| | | repositoryManager, |
| | | projectManager, |
| | | federationManager); |
| | | |
| | | this.injector = ObjectGraph.create(getModules()); |
| | | |
| | | this.servicesManager = new ServicesManager(this); |
| | | } |
| | | |
| | | @Override |
| | | public GitBlit start() { |
| | | super.start(); |
| | | logger.info("Starting services manager..."); |
| | | servicesManager.start(); |
| | | configureTicketService(); |
| | | return this; |
| | | } |
| | | |
| | | @Override |
| | | public GitBlit stop() { |
| | | super.stop(); |
| | | servicesManager.stop(); |
| | | ticketService.stop(); |
| | | return this; |
| | | } |
| | | |
| | | @Override |
| | | public boolean isServingRepositories() { |
| | | return servicesManager.isServingRepositories(); |
| | | } |
| | | |
| | | @Override |
| | | public boolean isServingHTTP() { |
| | | return servicesManager.isServingHTTP(); |
| | | } |
| | | |
| | | @Override |
| | | public boolean isServingGIT() { |
| | | return servicesManager.isServingGIT(); |
| | | } |
| | | |
| | | @Override |
| | | public boolean isServingSSH() { |
| | | return servicesManager.isServingSSH(); |
| | | } |
| | | |
| | | protected Object [] getModules() { |
| | | return new Object [] { new GitBlitModule()}; |
| | | } |
| | | |
| | | protected boolean acceptPush(Transport byTransport) { |
| | | if (byTransport == null) { |
| | | logger.info("Unknown transport, push rejected!"); |
| | | return false; |
| | | } |
| | | |
| | | Set<Transport> transports = new HashSet<Transport>(); |
| | | for (String value : getSettings().getStrings(Keys.git.acceptedPushTransports)) { |
| | | Transport transport = Transport.fromString(value); |
| | | if (transport == null) { |
| | | logger.info(String.format("Ignoring unknown registered transport %s", value)); |
| | | continue; |
| | | } |
| | | |
| | | transports.add(transport); |
| | | } |
| | | |
| | | if (transports.isEmpty()) { |
| | | // no transports are explicitly specified, all are acceptable |
| | | return true; |
| | | } |
| | | |
| | | // verify that the transport is permitted |
| | | return transports.contains(byTransport); |
| | | } |
| | | |
| | | /** |
| | | * Returns a list of repository URLs and the user access permission. |
| | | * |
| | | * @param request |
| | | * @param user |
| | | * @param repository |
| | | * @return a list of repository urls |
| | | */ |
| | | @Override |
| | | public List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) { |
| | | if (user == null) { |
| | | user = UserModel.ANONYMOUS; |
| | | } |
| | | String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username); |
| | | |
| | | List<RepositoryUrl> list = new ArrayList<RepositoryUrl>(); |
| | | |
| | | // http/https url |
| | | if (settings.getBoolean(Keys.git.enableGitServlet, true)) { |
| | | AccessPermission permission = user.getRepositoryPermission(repository).permission; |
| | | if (permission.exceeds(AccessPermission.NONE)) { |
| | | Transport transport = Transport.fromString(request.getScheme()); |
| | | if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(transport)) { |
| | | // downgrade the repo permission for this transport |
| | | // because it is not an acceptable PUSH transport |
| | | permission = AccessPermission.CLONE; |
| | | } |
| | | list.add(new RepositoryUrl(getRepositoryUrl(request, username, repository), permission)); |
| | | } |
| | | } |
| | | |
| | | // ssh daemon url |
| | | String sshDaemonUrl = servicesManager.getSshDaemonUrl(request, user, repository); |
| | | if (!StringUtils.isEmpty(sshDaemonUrl)) { |
| | | AccessPermission permission = user.getRepositoryPermission(repository).permission; |
| | | if (permission.exceeds(AccessPermission.NONE)) { |
| | | if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.SSH)) { |
| | | // downgrade the repo permission for this transport |
| | | // because it is not an acceptable PUSH transport |
| | | permission = AccessPermission.CLONE; |
| | | } |
| | | |
| | | list.add(new RepositoryUrl(sshDaemonUrl, permission)); |
| | | } |
| | | } |
| | | |
| | | // git daemon url |
| | | String gitDaemonUrl = servicesManager.getGitDaemonUrl(request, user, repository); |
| | | if (!StringUtils.isEmpty(gitDaemonUrl)) { |
| | | AccessPermission permission = servicesManager.getGitDaemonAccessPermission(user, repository); |
| | | if (permission.exceeds(AccessPermission.NONE)) { |
| | | if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.GIT)) { |
| | | // downgrade the repo permission for this transport |
| | | // because it is not an acceptable PUSH transport |
| | | permission = AccessPermission.CLONE; |
| | | } |
| | | list.add(new RepositoryUrl(gitDaemonUrl, permission)); |
| | | } |
| | | } |
| | | |
| | | // add all other urls |
| | | // {0} = repository |
| | | // {1} = username |
| | | for (String url : settings.getStrings(Keys.web.otherUrls)) { |
| | | if (url.contains("{1}")) { |
| | | // external url requires username, only add url IF we have one |
| | | if (!StringUtils.isEmpty(username)) { |
| | | list.add(new RepositoryUrl(MessageFormat.format(url, repository.name, username), null)); |
| | | } |
| | | } else { |
| | | // external url does not require username |
| | | list.add(new RepositoryUrl(MessageFormat.format(url, repository.name), null)); |
| | | } |
| | | } |
| | | |
| | | // sort transports by highest permission and then by transport security |
| | | Collections.sort(list, new Comparator<RepositoryUrl>() { |
| | | |
| | | @Override |
| | | public int compare(RepositoryUrl o1, RepositoryUrl o2) { |
| | | if (!o1.isExternal() && o2.isExternal()) { |
| | | // prefer Gitblit over external |
| | | return -1; |
| | | } else if (o1.isExternal() && !o2.isExternal()) { |
| | | // prefer Gitblit over external |
| | | return 1; |
| | | } else if (o1.isExternal() && o2.isExternal()) { |
| | | // sort by Transport ordinal |
| | | return o1.transport.compareTo(o2.transport); |
| | | } else if (o1.permission.exceeds(o2.permission)) { |
| | | // prefer highest permission |
| | | return -1; |
| | | } else if (o2.permission.exceeds(o1.permission)) { |
| | | // prefer highest permission |
| | | return 1; |
| | | } |
| | | |
| | | // prefer more secure transports |
| | | return o1.transport.compareTo(o2.transport); |
| | | } |
| | | }); |
| | | |
| | | // consider the user's transport preference |
| | | RepositoryUrl preferredUrl = null; |
| | | Transport preferredTransport = user.getPreferences().getTransport(); |
| | | if (preferredTransport != null) { |
| | | Iterator<RepositoryUrl> itr = list.iterator(); |
| | | while (itr.hasNext()) { |
| | | RepositoryUrl url = itr.next(); |
| | | if (url.transport.equals(preferredTransport)) { |
| | | itr.remove(); |
| | | preferredUrl = url; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | if (preferredUrl != null) { |
| | | list.add(0, preferredUrl); |
| | | } |
| | | |
| | | return list; |
| | | } |
| | | |
| | | /** |
| | | * Detect renames and reindex as appropriate. |
| | | */ |
| | | @Override |
| | | public void updateRepositoryModel(String repositoryName, RepositoryModel repository, |
| | | boolean isCreate) throws GitBlitException { |
| | | RepositoryModel oldModel = null; |
| | | boolean isRename = !isCreate && !repositoryName.equalsIgnoreCase(repository.name); |
| | | if (isRename) { |
| | | oldModel = repositoryManager.getRepositoryModel(repositoryName); |
| | | } |
| | | |
| | | super.updateRepositoryModel(repositoryName, repository, isCreate); |
| | | |
| | | if (isRename && ticketService != null) { |
| | | ticketService.rename(oldModel, repository); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Delete the user and all associated public ssh keys. |
| | | */ |
| | | @Override |
| | | public boolean deleteUser(String username) { |
| | | UserModel user = userManager.getUserModel(username); |
| | | return deleteUserModel(user); |
| | | } |
| | | |
| | | @Override |
| | | public boolean deleteUserModel(UserModel model) { |
| | | boolean success = userManager.deleteUserModel(model); |
| | | if (success) { |
| | | getPublicKeyManager().removeAllKeys(model.username); |
| | | } |
| | | return success; |
| | | } |
| | | |
| | | /** |
| | | * Delete the repository and all associated tickets. |
| | | */ |
| | | @Override |
| | | public boolean deleteRepository(String repositoryName) { |
| | | RepositoryModel repository = repositoryManager.getRepositoryModel(repositoryName); |
| | | return deleteRepositoryModel(repository); |
| | | } |
| | | |
| | | @Override |
| | | public boolean deleteRepositoryModel(RepositoryModel model) { |
| | | boolean success = repositoryManager.deleteRepositoryModel(model); |
| | | if (success && ticketService != null) { |
| | | ticketService.deleteAll(model); |
| | | } |
| | | return success; |
| | | } |
| | | |
| | | /** |
| | | * Returns the configured ticket service. |
| | | * |
| | | * @return a ticket service |
| | | */ |
| | | @Override |
| | | public ITicketService getTicketService() { |
| | | return ticketService; |
| | | } |
| | | |
| | | protected void configureTicketService() { |
| | | String clazz = settings.getString(Keys.tickets.service, NullTicketService.class.getName()); |
| | | if (StringUtils.isEmpty(clazz)) { |
| | | clazz = NullTicketService.class.getName(); |
| | | } |
| | | try { |
| | | Class<? extends ITicketService> serviceClass = (Class<? extends ITicketService>) Class.forName(clazz); |
| | | ticketService = injector.get(serviceClass).start(); |
| | | if (ticketService instanceof NullTicketService) { |
| | | logger.warn("No ticket service configured."); |
| | | } else if (ticketService.isReady()) { |
| | | logger.info("{} is ready.", ticketService); |
| | | } else { |
| | | logger.warn("{} is disabled.", ticketService); |
| | | } |
| | | } catch (Exception e) { |
| | | logger.error("failed to create ticket service " + clazz, e); |
| | | ticketService = injector.get(NullTicketService.class).start(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * A nested Dagger graph is used for constructor dependency injection of |
| | | * complex classes. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Module( |
| | | library = true, |
| | | injects = { |
| | | IStoredSettings.class, |
| | | |
| | | // core managers |
| | | IRuntimeManager.class, |
| | | IPluginManager.class, |
| | | INotificationManager.class, |
| | | IUserManager.class, |
| | | IAuthenticationManager.class, |
| | | IRepositoryManager.class, |
| | | IProjectManager.class, |
| | | IFederationManager.class, |
| | | |
| | | // the monolithic manager |
| | | IGitblit.class, |
| | | |
| | | // ticket services |
| | | NullTicketService.class, |
| | | FileTicketService.class, |
| | | BranchTicketService.class, |
| | | RedisTicketService.class |
| | | } |
| | | ) |
| | | class GitBlitModule { |
| | | |
| | | @Provides @Singleton IStoredSettings provideSettings() { |
| | | return settings; |
| | | } |
| | | |
| | | @Provides @Singleton IRuntimeManager provideRuntimeManager() { |
| | | return runtimeManager; |
| | | } |
| | | |
| | | @Provides @Singleton IPluginManager providePluginManager() { |
| | | return pluginManager; |
| | | } |
| | | |
| | | @Provides @Singleton INotificationManager provideNotificationManager() { |
| | | return notificationManager; |
| | | } |
| | | |
| | | @Provides @Singleton IUserManager provideUserManager() { |
| | | return userManager; |
| | | } |
| | | |
| | | @Provides @Singleton IAuthenticationManager provideAuthenticationManager() { |
| | | return authenticationManager; |
| | | } |
| | | |
| | | @Provides @Singleton IRepositoryManager provideRepositoryManager() { |
| | | return repositoryManager; |
| | | } |
| | | |
| | | @Provides @Singleton IProjectManager provideProjectManager() { |
| | | return projectManager; |
| | | } |
| | | |
| | | @Provides @Singleton IFederationManager provideFederationManager() { |
| | | return federationManager; |
| | | } |
| | | |
| | | @Provides @Singleton IGitblit provideGitblit() { |
| | | return GitBlit.this; |
| | | } |
| | | |
| | | @Provides @Singleton NullTicketService provideNullTicketService() { |
| | | return new NullTicketService( |
| | | runtimeManager, |
| | | pluginManager, |
| | | notificationManager, |
| | | userManager, |
| | | repositoryManager); |
| | | } |
| | | |
| | | @Provides @Singleton FileTicketService provideFileTicketService() { |
| | | return new FileTicketService( |
| | | runtimeManager, |
| | | pluginManager, |
| | | notificationManager, |
| | | userManager, |
| | | repositoryManager); |
| | | } |
| | | |
| | | @Provides @Singleton BranchTicketService provideBranchTicketService() { |
| | | return new BranchTicketService( |
| | | runtimeManager, |
| | | pluginManager, |
| | | notificationManager, |
| | | userManager, |
| | | repositoryManager); |
| | | } |
| | | |
| | | @Provides @Singleton RedisTicketService provideRedisTicketService() { |
| | | return new RedisTicketService( |
| | | runtimeManager, |
| | | pluginManager, |
| | | notificationManager, |
| | | userManager, |
| | | repositoryManager); |
| | | } |
| | | federationManager, |
| | | filestoreManager); |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | logger = LoggerFactory.getLogger(GitBlitServer.class); |
| | | logger.info(Constants.BORDER); |
| | | logger.info(" _____ _ _ _ _ _ _"); |
| | | logger.info(" | __ \\(_)| | | | | |(_)| |"); |
| | | logger.info(" | | \\/ _ | |_ | |__ | | _ | |_"); |
| | | logger.info(" | | __ | || __|| '_ \\ | || || __|"); |
| | | logger.info(" | |_\\ \\| || |_ | |_) || || || |_"); |
| | | logger.info(" \\____/|_| \\__||_.__/ |_||_| \\__|"); |
| | | int spacing = (Constants.BORDER.length() - Constants.getGitBlitVersion().length()) / 2; |
| | | StringBuilder sb = new StringBuilder(); |
| | | while (spacing > 0) { |
| | | spacing--; |
| | | sb.append(' '); |
| | | } |
| | | logger.info(sb.toString() + Constants.getGitBlitVersion()); |
| | | logger.info(""); |
| | | logger.info(Constants.BORDER); |
| | | logger.info("\n" + Constants.getASCIIArt()); |
| | | |
| | | System.setProperty("java.awt.headless", "true"); |
| | | |
| | |
| | | |
| | | @Override |
| | | public void run() { |
| | | logger.info("Shutdown Monitor listening on port " + socket.getLocalPort()); |
| | | Socket accept; |
| | | try { |
| | | accept = socket.accept(); |
| | | BufferedReader reader = new BufferedReader(new InputStreamReader( |
| | | accept.getInputStream())); |
| | | reader.readLine(); |
| | | logger.info(Constants.BORDER); |
| | | logger.info("Stopping " + Constants.NAME); |
| | | logger.info(Constants.BORDER); |
| | | server.stop(); |
| | | server.setStopAtShutdown(false); |
| | | accept.close(); |
| | | socket.close(); |
| | | } catch (Exception e) { |
| | | logger.warn("Failed to shutdown Jetty", e); |
| | | // Only run if the socket was able to be created (not already in use, failed to bind, etc.) |
| | | if (null != socket) { |
| | | logger.info("Shutdown Monitor listening on port " + socket.getLocalPort()); |
| | | Socket accept; |
| | | try { |
| | | accept = socket.accept(); |
| | | BufferedReader reader = new BufferedReader(new InputStreamReader( |
| | | accept.getInputStream())); |
| | | reader.readLine(); |
| | | logger.info(Constants.BORDER); |
| | | logger.info("Stopping " + Constants.NAME); |
| | | logger.info(Constants.BORDER); |
| | | server.stop(); |
| | | server.setStopAtShutdown(false); |
| | | accept.close(); |
| | | socket.close(); |
| | | } catch (Exception e) { |
| | | logger.warn("Failed to shutdown Jetty", e); |
| | | } |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2015 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 com.gitblit.utils.ActivityUtils; |
| | | import com.google.inject.Singleton; |
| | | |
| | | @Singleton |
| | | public class GravatarGenerator implements AvatarGenerator { |
| | | |
| | | @Override |
| | | public String getURL(String username, String emailaddress, boolean identicon, int width) { |
| | | String email = emailaddress == null ? username : emailaddress; |
| | | if (identicon) { |
| | | return ActivityUtils.getGravatarIdenticonUrl(email, width); |
| | | } else { |
| | | return ActivityUtils.getGravatarThumbnailUrl(email, width); |
| | | } |
| | | } |
| | | |
| | | } |
| | |
| | | import java.io.File; |
| | | import java.math.BigInteger; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.Constants.AccountType; |
| | | import com.gitblit.Constants.Role; |
| | | import com.gitblit.Constants.AuthenticationType; |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.manager.IRuntimeManager; |
| | | import com.gitblit.manager.IUserManager; |
| | |
| | | return serviceName; |
| | | } |
| | | |
| | | public abstract AuthenticationType getAuthenticationType(); |
| | | |
| | | protected void setCookie(UserModel user, char [] password) { |
| | | // create a user cookie |
| | | if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) { |
| | |
| | | |
| | | public abstract void stop(); |
| | | |
| | | /** |
| | | * Used to handle requests for requests for pages requiring authentication. |
| | | * This allows authentication to occur based on the contents of the request |
| | | * itself. |
| | | * |
| | | * @param httpRequest |
| | | * @return |
| | | */ |
| | | public abstract UserModel authenticate(HttpServletRequest httpRequest); |
| | | |
| | | /** |
| | | * Used to authentication user/password credentials, both for login form |
| | | * and HTTP Basic authentication processing. |
| | | * |
| | | * @param username |
| | | * @param password |
| | | * @return |
| | | */ |
| | | public abstract UserModel authenticate(String username, char[] password); |
| | | |
| | | public abstract AccountType getAccountType(); |
| | | |
| | | /** |
| | | * Does the user service support changes to credentials? |
| | | * Returns true if the users's credentials can be changed. |
| | | * |
| | | * @return true or false |
| | | * @return true if the authentication provider supports credential changes |
| | | * @since 1.0.0 |
| | | */ |
| | | public abstract boolean supportsCredentialChanges(); |
| | |
| | | * Returns true if the user's display name can be changed. |
| | | * |
| | | * @param user |
| | | * @return true if the user service supports display name changes |
| | | * @return true if the authentication provider supports display name changes |
| | | */ |
| | | public abstract boolean supportsDisplayNameChanges(); |
| | | |
| | |
| | | * Returns true if the user's email address can be changed. |
| | | * |
| | | * @param user |
| | | * @return true if the user service supports email address changes |
| | | * @return true if the authentication provider supports email address changes |
| | | */ |
| | | public abstract boolean supportsEmailAddressChanges(); |
| | | |
| | |
| | | * Returns true if the user's team memberships can be changed. |
| | | * |
| | | * @param user |
| | | * @return true if the user service supports team membership changes |
| | | * @return true if the authentication provider supports team membership changes |
| | | */ |
| | | public abstract boolean supportsTeamMembershipChanges(); |
| | | |
| | | /** |
| | | * Returns true if the user's role can be changed. |
| | | * |
| | | * @param user |
| | | * @param role |
| | | * @return true if the user's role can be changed |
| | | */ |
| | | public abstract boolean supportsRoleChanges(UserModel user, Role role); |
| | | |
| | | /** |
| | | * Returns true if the team's role can be changed. |
| | | * |
| | | * @param user |
| | | * @param role |
| | | * @return true if the team's role can be changed |
| | | */ |
| | | public abstract boolean supportsRoleChanges(TeamModel team, Role role); |
| | | |
| | | @Override |
| | | public String toString() { |
| | |
| | | protected UsernamePasswordAuthenticationProvider(String serviceName) { |
| | | super(serviceName); |
| | | } |
| | | |
| | | @Override |
| | | public UserModel authenticate(HttpServletRequest httpRequest) { |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public AuthenticationType getAuthenticationType() { |
| | | return AuthenticationType.CREDENTIALS; |
| | | } |
| | | |
| | | @Override |
| | | public void stop() { |
| | |
| | | } |
| | | |
| | | @Override |
| | | public UserModel authenticate(HttpServletRequest httpRequest) { |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public UserModel authenticate(String username, char[] password) { |
| | | return null; |
| | | } |
| | |
| | | @Override |
| | | public AccountType getAccountType() { |
| | | return AccountType.LOCAL; |
| | | } |
| | | |
| | | @Override |
| | | public AuthenticationType getAuthenticationType() { |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | |
| | | public boolean supportsTeamMembershipChanges() { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(UserModel user, Role role) { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(TeamModel team, Role role) { |
| | | return true; |
| | | } |
| | | |
| | | } |
| | | } |
| | |
| | | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.Constants.AccountType; |
| | | import com.gitblit.Constants.Role; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider; |
| | | import com.gitblit.models.TeamModel; |
| | | import com.gitblit.models.UserModel; |
| | | |
| | | |
| | |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(UserModel user, Role role) { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(TeamModel team, Role role) { |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Authenticate a user based on a username and password. |
| | | * |
New file |
| | |
| | | /* |
| | | * Copyright 2015 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.auth; |
| | | |
| | | import java.util.HashSet; |
| | | import java.util.Set; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.Constants.AccountType; |
| | | import com.gitblit.Constants.AuthenticationType; |
| | | import com.gitblit.Constants.Role; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.models.TeamModel; |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.utils.StringUtils; |
| | | |
| | | public class HttpHeaderAuthProvider extends AuthenticationProvider { |
| | | |
| | | protected final Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | protected String userHeaderName; |
| | | protected String teamHeaderName; |
| | | protected String teamHeaderSeparator; |
| | | |
| | | public HttpHeaderAuthProvider() { |
| | | super("httpheader"); |
| | | } |
| | | |
| | | @Override |
| | | public void setup() { |
| | | // Load HTTP header configuration |
| | | userHeaderName = settings.getString(Keys.realm.httpheader.userheader, null); |
| | | teamHeaderName = settings.getString(Keys.realm.httpheader.teamheader, null); |
| | | teamHeaderSeparator = settings.getString(Keys.realm.httpheader.teamseparator, ","); |
| | | |
| | | if (StringUtils.isEmpty(userHeaderName)) { |
| | | logger.warn("HTTP Header authentication is enabled, but no header is not defined in " + Keys.realm.httpheader.userheader); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void stop() {} |
| | | |
| | | |
| | | @Override |
| | | public UserModel authenticate(HttpServletRequest httpRequest) { |
| | | // Try to authenticate using custom HTTP header if user header is defined |
| | | if (!StringUtils.isEmpty(userHeaderName)) { |
| | | String headerUserName = httpRequest.getHeader(userHeaderName); |
| | | if (!StringUtils.isEmpty(headerUserName) && !userManager.isInternalAccount(headerUserName)) { |
| | | // We have a user, try to load team names as well |
| | | Set<TeamModel> userTeams = new HashSet<>(); |
| | | if (!StringUtils.isEmpty(teamHeaderName)) { |
| | | String headerTeamValue = httpRequest.getHeader(teamHeaderName); |
| | | if (!StringUtils.isEmpty(headerTeamValue)) { |
| | | String[] headerTeamNames = headerTeamValue.split(teamHeaderSeparator); |
| | | for (String teamName : headerTeamNames) { |
| | | teamName = teamName.trim(); |
| | | if (!StringUtils.isEmpty(teamName)) { |
| | | TeamModel team = userManager.getTeamModel(teamName); |
| | | if (null == team) { |
| | | // Create teams here so they can marked with the correct AccountType |
| | | team = new TeamModel(teamName); |
| | | team.accountType = AccountType.HTTPHEADER; |
| | | updateTeam(team); |
| | | } |
| | | userTeams.add(team); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | UserModel user = userManager.getUserModel(headerUserName); |
| | | if (user != null) { |
| | | // If team header is provided in request, reset all team memberships, even if resetting to empty set |
| | | if (!StringUtils.isEmpty(teamHeaderName)) { |
| | | user.teams.clear(); |
| | | user.teams.addAll(userTeams); |
| | | } |
| | | updateUser(user); |
| | | return user; |
| | | } else if (settings.getBoolean(Keys.realm.httpheader.autoCreateAccounts, false)) { |
| | | // auto-create user from HTTP header |
| | | user = new UserModel(headerUserName.toLowerCase()); |
| | | user.displayName = headerUserName; |
| | | user.password = Constants.EXTERNAL_ACCOUNT; |
| | | user.accountType = AccountType.HTTPHEADER; |
| | | user.teams.addAll(userTeams); |
| | | updateUser(user); |
| | | return user; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public UserModel authenticate(String username, char[] password){ |
| | | // Username/password is not supported for HTTP header authentication |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public AccountType getAccountType() { |
| | | return AccountType.HTTPHEADER; |
| | | } |
| | | |
| | | @Override |
| | | public AuthenticationType getAuthenticationType() { |
| | | return AuthenticationType.HTTPHEADER; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsCredentialChanges() { |
| | | return false; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsDisplayNameChanges() { |
| | | return false; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsEmailAddressChanges() { |
| | | return false; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsTeamMembershipChanges() { |
| | | return StringUtils.isEmpty(teamHeaderName); |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(UserModel user, Role role) { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(TeamModel team, Role role) { |
| | | return true; |
| | | } |
| | | } |
| | |
| | | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.Constants.AccountType; |
| | | import com.gitblit.Constants.Role; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider; |
| | | import com.gitblit.models.TeamModel; |
| | |
| | | return StringUtils.isEmpty(settings.getString(Keys.realm.ldap.email, "")); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * If the LDAP server will maintain team memberships then LdapUserService |
| | | * will not allow team membership changes. In this scenario all team |
| | |
| | | @Override |
| | | public boolean supportsTeamMembershipChanges() { |
| | | return !settings.getBoolean(Keys.realm.ldap.maintainTeams, false); |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(UserModel user, Role role) { |
| | | if (Role.ADMIN == role) { |
| | | if (!supportsTeamMembershipChanges()) { |
| | | List<String> admins = settings.getStrings(Keys.realm.ldap.admins); |
| | | if (admins.contains(user.username)) { |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(TeamModel team, Role role) { |
| | | if (Role.ADMIN == role) { |
| | | if (!supportsTeamMembershipChanges()) { |
| | | List<String> admins = settings.getStrings(Keys.realm.ldap.admins); |
| | | if (admins.contains("@" + team.name)) { |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (ldapSyncService.isReady()) { |
| | | long ldapSyncPeriod = getSynchronizationPeriodInMilliseconds(); |
| | | int delay = 1; |
| | | logger.info("Ldap sync service will update users and groups every {} minutes.", ldapSyncPeriod); |
| | | logger.info("Ldap sync service will update users and groups every {} minutes.", |
| | | TimeUnit.MILLISECONDS.toMinutes(ldapSyncPeriod)); |
| | | scheduledExecutorService.scheduleAtFixedRate(ldapSyncService, delay, ldapSyncPeriod, TimeUnit.MILLISECONDS); |
| | | } else { |
| | | logger.info("Ldap sync service is disabled."); |
| | |
| | | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.Constants.AccountType; |
| | | import com.gitblit.Constants.Role; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider; |
| | | import com.gitblit.models.TeamModel; |
| | | import com.gitblit.models.UserModel; |
| | | |
| | | /** |
| | |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(UserModel user, Role role) { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(TeamModel team, Role role) { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public AccountType getAccountType() { |
| | | return AccountType.PAM; |
| | |
| | | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.Constants.AccountType; |
| | | import com.gitblit.Constants.Role; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider; |
| | | import com.gitblit.models.TeamModel; |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.utils.ConnectionUtils; |
| | | import com.gitblit.utils.StringUtils; |
| | |
| | | public boolean supportsTeamMembershipChanges() { |
| | | return false; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(UserModel user, Role role) { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(TeamModel team, Role role) { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public AccountType getAccountType() { |
| | |
| | | url = url.concat("/"); |
| | | } |
| | | String apiUrl = url + "users/current.json"; |
| | | |
| | | |
| | | HttpURLConnection http; |
| | | if (username == null) { |
| | | // apikey authentication |
| | |
| | | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.Constants.AccountType; |
| | | import com.gitblit.Constants.Role; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider; |
| | | import com.gitblit.models.TeamModel; |
| | | import com.gitblit.models.UserModel; |
| | | import com.sforce.soap.partner.Connector; |
| | | import com.sforce.soap.partner.GetUserInfoResult; |
| | |
| | | public boolean supportsTeamMembershipChanges() { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(UserModel user, Role role) { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(TeamModel team, Role role) { |
| | | return true; |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.Constants.AccountType; |
| | | import com.gitblit.Constants.Role; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider; |
| | | import com.gitblit.models.TeamModel; |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.sun.jna.platform.win32.Win32Exception; |
| | |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(UserModel user, Role role) { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(TeamModel team, Role role) { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public AccountType getAccountType() { |
| | | return AccountType.WINDOWS; |
| | |
| | | import com.gitblit.Constants.AuthorizationControl;
|
| | | import com.gitblit.Constants.PermissionType;
|
| | | import com.gitblit.Constants.RegistrantType;
|
| | | import com.gitblit.GitBlitException.ForbiddenException;
|
| | | import com.gitblit.GitBlitException.NotAllowedException;
|
| | | import com.gitblit.GitBlitException.UnauthorizedException;
|
| | | import com.gitblit.GitBlitException.UnknownRequestException;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.models.FederationModel;
|
| | | import com.gitblit.models.FeedEntryModel;
|
| | |
| | | refreshRepositories();
|
| | | refreshSubscribedFeeds(0);
|
| | |
|
| | | try {
|
| | | // credentials may not have administrator access
|
| | | // or server may have disabled rpc management
|
| | | refreshUsers();
|
| | | if (protocolVersion > 1) {
|
| | | refreshTeams();
|
| | | }
|
| | | allowManagement = true;
|
| | | } catch (UnauthorizedException e) {
|
| | | } catch (ForbiddenException e) {
|
| | | } catch (NotAllowedException e) {
|
| | | } catch (UnknownRequestException e) {
|
| | | } catch (IOException e) {
|
| | | e.printStackTrace();
|
| | | // credentials may not have administrator access
|
| | | // or server may have disabled rpc management
|
| | | refreshUsers();
|
| | | if (protocolVersion > 1) {
|
| | | refreshTeams();
|
| | | }
|
| | | allowManagement = true;
|
| | |
|
| | | try {
|
| | | // credentials may not have administrator access
|
| | | // or server may have disabled rpc administration
|
| | | refreshStatus();
|
| | | allowAdministration = true;
|
| | | } catch (UnauthorizedException e) {
|
| | | } catch (ForbiddenException e) {
|
| | | } catch (NotAllowedException e) {
|
| | | } catch (UnknownRequestException e) {
|
| | | } catch (IOException e) {
|
| | | e.printStackTrace();
|
| | | }
|
| | | // credentials may not have administrator access
|
| | | // or server may have disabled rpc administration
|
| | | refreshStatus();
|
| | | allowAdministration = true;
|
| | |
|
| | | }
|
| | |
|
| | | public int getProtocolVersion() {
|
| | |
| | | public abstract void onCreation(RepositoryModel repository); |
| | | |
| | | /** |
| | | * Called after a repository has been forked. |
| | | * |
| | | * @param origin |
| | | * @param fork |
| | | * @since 1.7.0 |
| | | */ |
| | | public abstract void onFork(RepositoryModel origin, RepositoryModel fork); |
| | | |
| | | /** |
| | | * Called after a repository has been renamed. |
| | | * |
| | | * @param oldName |
| | | * @param repository |
| | | * @since 1.7.0 |
| | | */ |
| | | public abstract void onRename(String oldName, RepositoryModel repository); |
| | | |
| | | /** |
| | | * Called after a repository has been deleted. |
| | | * |
| | | * @param repository |
| | |
| | | // identified the missing object earlier before we got control.
|
| | | LOGGER.error("failed to get commit count", e);
|
| | | } finally {
|
| | | walk.release();
|
| | | walk.close();
|
| | | }
|
| | |
|
| | | sendError("");
|
| | |
| | | LOGGER.error("failed to get commit count", e);
|
| | | return 0;
|
| | | } finally {
|
| | | walk.release();
|
| | | walk.close();
|
| | | }
|
| | | return count;
|
| | | }
|
New file |
| | |
| | | /* |
| | | * Copyright 2015 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.guice; |
| | | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.AvatarGenerator; |
| | | import com.gitblit.GravatarGenerator; |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.manager.IRuntimeManager; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Provider; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Provides a lazily-instantiated AvatarGenerator configured from IStoredSettings. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class AvatarGeneratorProvider implements Provider<AvatarGenerator> { |
| | | |
| | | private final Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | private final IRuntimeManager runtimeManager; |
| | | |
| | | private volatile AvatarGenerator avatarGenerator; |
| | | |
| | | @Inject |
| | | public AvatarGeneratorProvider(IRuntimeManager runtimeManager) { |
| | | this.runtimeManager = runtimeManager; |
| | | } |
| | | |
| | | @Override |
| | | public synchronized AvatarGenerator get() { |
| | | if (avatarGenerator != null) { |
| | | return avatarGenerator; |
| | | } |
| | | |
| | | IStoredSettings settings = runtimeManager.getSettings(); |
| | | String clazz = settings.getString(Keys.web.avatarClass, GravatarGenerator.class.getName()); |
| | | if (StringUtils.isEmpty(clazz)) { |
| | | clazz = GravatarGenerator.class.getName(); |
| | | } |
| | | try { |
| | | Class<? extends AvatarGenerator> generatorClass = (Class<? extends AvatarGenerator>) Class.forName(clazz); |
| | | avatarGenerator = runtimeManager.getInjector().getInstance(generatorClass); |
| | | } catch (Exception e) { |
| | | logger.error("failed to create avatar generator", e); |
| | | avatarGenerator = new GravatarGenerator(); |
| | | } |
| | | return avatarGenerator; |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2014 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.guice; |
| | | |
| | | import com.gitblit.FileSettings; |
| | | import com.gitblit.GitBlit; |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.manager.AuthenticationManager; |
| | | import com.gitblit.manager.FederationManager; |
| | | import com.gitblit.manager.FilestoreManager; |
| | | import com.gitblit.manager.IAuthenticationManager; |
| | | import com.gitblit.manager.IFederationManager; |
| | | import com.gitblit.manager.IFilestoreManager; |
| | | import com.gitblit.manager.IGitblit; |
| | | import com.gitblit.manager.INotificationManager; |
| | | import com.gitblit.manager.IPluginManager; |
| | | import com.gitblit.manager.IProjectManager; |
| | | import com.gitblit.manager.IRepositoryManager; |
| | | import com.gitblit.manager.IRuntimeManager; |
| | | import com.gitblit.manager.IServicesManager; |
| | | import com.gitblit.manager.IUserManager; |
| | | import com.gitblit.manager.NotificationManager; |
| | | import com.gitblit.manager.PluginManager; |
| | | import com.gitblit.manager.ProjectManager; |
| | | import com.gitblit.manager.RepositoryManager; |
| | | import com.gitblit.manager.RuntimeManager; |
| | | import com.gitblit.manager.ServicesManager; |
| | | import com.gitblit.manager.UserManager; |
| | | import com.gitblit.tickets.ITicketService; |
| | | import com.gitblit.transport.ssh.IPublicKeyManager; |
| | | import com.gitblit.utils.JSoupXssFilter; |
| | | import com.gitblit.utils.WorkQueue; |
| | | import com.gitblit.utils.XssFilter; |
| | | import com.google.inject.AbstractModule; |
| | | |
| | | /** |
| | | * CoreModule references all the core business objects. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | public class CoreModule extends AbstractModule { |
| | | |
| | | @Override |
| | | protected void configure() { |
| | | |
| | | bind(IStoredSettings.class).toInstance(new FileSettings()); |
| | | bind(XssFilter.class).to(JSoupXssFilter.class); |
| | | |
| | | // bind complex providers |
| | | bind(IPublicKeyManager.class).toProvider(IPublicKeyManagerProvider.class); |
| | | bind(ITicketService.class).toProvider(ITicketServiceProvider.class); |
| | | bind(WorkQueue.class).toProvider(WorkQueueProvider.class); |
| | | |
| | | // core managers |
| | | bind(IRuntimeManager.class).to(RuntimeManager.class); |
| | | bind(IPluginManager.class).to(PluginManager.class); |
| | | bind(INotificationManager.class).to(NotificationManager.class); |
| | | bind(IUserManager.class).to(UserManager.class); |
| | | bind(IAuthenticationManager.class).to(AuthenticationManager.class); |
| | | bind(IRepositoryManager.class).to(RepositoryManager.class); |
| | | bind(IProjectManager.class).to(ProjectManager.class); |
| | | bind(IFederationManager.class).to(FederationManager.class); |
| | | bind(IFilestoreManager.class).to(FilestoreManager.class); |
| | | |
| | | // the monolithic manager |
| | | bind(IGitblit.class).to(GitBlit.class); |
| | | |
| | | // manager for long-running daemons and services |
| | | bind(IServicesManager.class).to(ServicesManager.class); |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2014 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.guice; |
| | | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.manager.IRuntimeManager; |
| | | import com.gitblit.transport.ssh.FileKeyManager; |
| | | import com.gitblit.transport.ssh.IPublicKeyManager; |
| | | import com.gitblit.transport.ssh.NullKeyManager; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Provider; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Provides a lazily-instantiated IPublicKeyManager configured from IStoredSettings. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class IPublicKeyManagerProvider implements Provider<IPublicKeyManager> { |
| | | |
| | | private final Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | private final IRuntimeManager runtimeManager; |
| | | |
| | | private volatile IPublicKeyManager manager; |
| | | |
| | | @Inject |
| | | public IPublicKeyManagerProvider(IRuntimeManager runtimeManager) { |
| | | this.runtimeManager = runtimeManager; |
| | | } |
| | | |
| | | @Override |
| | | public synchronized IPublicKeyManager get() { |
| | | if (manager != null) { |
| | | return manager; |
| | | } |
| | | |
| | | IStoredSettings settings = runtimeManager.getSettings(); |
| | | String clazz = settings.getString(Keys.git.sshKeysManager, FileKeyManager.class.getName()); |
| | | if (StringUtils.isEmpty(clazz)) { |
| | | clazz = FileKeyManager.class.getName(); |
| | | } |
| | | try { |
| | | Class<? extends IPublicKeyManager> mgrClass = (Class<? extends IPublicKeyManager>) Class.forName(clazz); |
| | | manager = runtimeManager.getInjector().getInstance(mgrClass); |
| | | } catch (Exception e) { |
| | | logger.error("failed to create public key manager", e); |
| | | manager = new NullKeyManager(); |
| | | } |
| | | return manager; |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2014 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.guice; |
| | | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.manager.IRuntimeManager; |
| | | import com.gitblit.tickets.ITicketService; |
| | | import com.gitblit.tickets.NullTicketService; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Provider; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Provides a lazily-instantiated ITicketService configured from IStoredSettings. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class ITicketServiceProvider implements Provider<ITicketService> { |
| | | |
| | | private final Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | private final IRuntimeManager runtimeManager; |
| | | |
| | | private volatile ITicketService service; |
| | | |
| | | @Inject |
| | | public ITicketServiceProvider(IRuntimeManager runtimeManager) { |
| | | this.runtimeManager = runtimeManager; |
| | | } |
| | | |
| | | @Override |
| | | public synchronized ITicketService get() { |
| | | if (service != null) { |
| | | return service; |
| | | } |
| | | |
| | | IStoredSettings settings = runtimeManager.getSettings(); |
| | | String clazz = settings.getString(Keys.tickets.service, NullTicketService.class.getName()); |
| | | if (StringUtils.isEmpty(clazz)) { |
| | | clazz = NullTicketService.class.getName(); |
| | | } |
| | | |
| | | try { |
| | | Class<? extends ITicketService> serviceClass = (Class<? extends ITicketService>) Class.forName(clazz); |
| | | service = runtimeManager.getInjector().getInstance(serviceClass); |
| | | } catch (Exception e) { |
| | | logger.error("failed to create ticket service", e); |
| | | service = runtimeManager.getInjector().getInstance(NullTicketService.class); |
| | | } |
| | | |
| | | return service; |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2014 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.guice; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | import com.gitblit.AvatarGenerator; |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.servlet.AccessDeniedServlet; |
| | | import com.gitblit.servlet.BranchGraphServlet; |
| | | import com.gitblit.servlet.DownloadZipFilter; |
| | | import com.gitblit.servlet.DownloadZipServlet; |
| | | import com.gitblit.servlet.EnforceAuthenticationFilter; |
| | | import com.gitblit.servlet.FederationServlet; |
| | | import com.gitblit.servlet.FilestoreServlet; |
| | | import com.gitblit.servlet.GitFilter; |
| | | import com.gitblit.servlet.GitServlet; |
| | | import com.gitblit.servlet.LogoServlet; |
| | | import com.gitblit.servlet.PagesFilter; |
| | | import com.gitblit.servlet.PagesServlet; |
| | | import com.gitblit.servlet.ProxyFilter; |
| | | import com.gitblit.servlet.PtServlet; |
| | | import com.gitblit.servlet.RawFilter; |
| | | import com.gitblit.servlet.RawServlet; |
| | | import com.gitblit.servlet.RobotsTxtServlet; |
| | | import com.gitblit.servlet.RpcFilter; |
| | | import com.gitblit.servlet.RpcServlet; |
| | | import com.gitblit.servlet.SparkleShareInviteServlet; |
| | | import com.gitblit.servlet.SyndicationFilter; |
| | | import com.gitblit.servlet.SyndicationServlet; |
| | | import com.gitblit.wicket.GitblitWicketFilter; |
| | | import com.google.common.base.Joiner; |
| | | import com.google.inject.servlet.ServletModule; |
| | | |
| | | /** |
| | | * Defines all the web servlets & filters. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | public class WebModule extends ServletModule { |
| | | |
| | | final static String ALL = "/*"; |
| | | |
| | | @Override |
| | | protected void configureServlets() { |
| | | |
| | | // bind web component providers |
| | | bind(AvatarGenerator.class).toProvider(AvatarGeneratorProvider.class); |
| | | |
| | | // servlets |
| | | serveRegex(FilestoreServlet.REGEX_PATH).with(FilestoreServlet.class); |
| | | serve(fuzzy(Constants.R_PATH), fuzzy(Constants.GIT_PATH)).with(GitServlet.class); |
| | | serve(fuzzy(Constants.RAW_PATH)).with(RawServlet.class); |
| | | serve(fuzzy(Constants.PAGES)).with(PagesServlet.class); |
| | | serve(fuzzy(Constants.RPC_PATH)).with(RpcServlet.class); |
| | | serve(fuzzy(Constants.ZIP_PATH)).with(DownloadZipServlet.class); |
| | | serve(fuzzy(Constants.SYNDICATION_PATH)).with(SyndicationServlet.class); |
| | | |
| | | |
| | | serve(fuzzy(Constants.FEDERATION_PATH)).with(FederationServlet.class); |
| | | serve(fuzzy(Constants.SPARKLESHARE_INVITE_PATH)).with(SparkleShareInviteServlet.class); |
| | | serve(fuzzy(Constants.BRANCH_GRAPH_PATH)).with(BranchGraphServlet.class); |
| | | serve(Constants.PT_PATH).with(PtServlet.class); |
| | | serve("/robots.txt").with(RobotsTxtServlet.class); |
| | | serve("/logo.png").with(LogoServlet.class); |
| | | |
| | | /* Prevent accidental access to 'resources' such as GitBlit java classes |
| | | * |
| | | * In the GO setup the JAR containing the application and the WAR injected |
| | | * into Jetty are the same file. However Jetty expects to serve the entire WAR |
| | | * contents, except the WEB-INF folder. Thus, all java binary classes in the |
| | | * JAR are served by default as is they were legitimate resources. |
| | | * |
| | | * The below servlet mappings prevent that behavior |
| | | */ |
| | | serve(fuzzy("/com/")).with(AccessDeniedServlet.class); |
| | | |
| | | // global filters |
| | | filter(ALL).through(ProxyFilter.class); |
| | | filter(ALL).through(EnforceAuthenticationFilter.class); |
| | | |
| | | // security filters |
| | | filter(fuzzy(Constants.R_PATH), fuzzy(Constants.GIT_PATH)).through(GitFilter.class); |
| | | filter(fuzzy(Constants.RAW_PATH)).through(RawFilter.class); |
| | | filter(fuzzy(Constants.PAGES)).through(PagesFilter.class); |
| | | filter(fuzzy(Constants.RPC_PATH)).through(RpcFilter.class); |
| | | filter(fuzzy(Constants.ZIP_PATH)).through(DownloadZipFilter.class); |
| | | filter(fuzzy(Constants.SYNDICATION_PATH)).through(SyndicationFilter.class); |
| | | |
| | | |
| | | // Wicket |
| | | String toIgnore = Joiner.on(",").join(Constants.R_PATH, Constants.GIT_PATH, Constants.RAW_PATH, |
| | | Constants.PAGES, Constants.RPC_PATH, Constants.ZIP_PATH, Constants.SYNDICATION_PATH, |
| | | Constants.FEDERATION_PATH, Constants.SPARKLESHARE_INVITE_PATH, Constants.BRANCH_GRAPH_PATH, |
| | | Constants.PT_PATH, "/robots.txt", "/logo.png"); |
| | | |
| | | Map<String, String> params = new HashMap<String, String>(); |
| | | params.put(GitblitWicketFilter.FILTER_MAPPING_PARAM, ALL); |
| | | params.put(GitblitWicketFilter.IGNORE_PATHS_PARAM, toIgnore); |
| | | filter(ALL).through(GitblitWicketFilter.class, params); |
| | | } |
| | | |
| | | private String fuzzy(String path) { |
| | | if (path.endsWith(ALL)) { |
| | | return path; |
| | | } else if (path.endsWith("/")) { |
| | | return path + "*"; |
| | | } |
| | | return path + ALL; |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2014 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.guice; |
| | | |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.manager.IRuntimeManager; |
| | | import com.gitblit.utils.IdGenerator; |
| | | import com.gitblit.utils.WorkQueue; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Provider; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Provides a lazily-instantiated WorkQueue configured from IStoredSettings. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class WorkQueueProvider implements Provider<WorkQueue> { |
| | | |
| | | private final IRuntimeManager runtimeManager; |
| | | |
| | | private volatile WorkQueue workQueue; |
| | | |
| | | @Inject |
| | | public WorkQueueProvider(IRuntimeManager runtimeManager) { |
| | | this.runtimeManager = runtimeManager; |
| | | } |
| | | |
| | | @Override |
| | | public synchronized WorkQueue get() { |
| | | if (workQueue != null) { |
| | | return workQueue; |
| | | } |
| | | |
| | | IStoredSettings settings = runtimeManager.getSettings(); |
| | | int defaultThreadPoolSize = settings.getInteger(Keys.execution.defaultThreadPoolSize, 1); |
| | | IdGenerator idGenerator = new IdGenerator(); |
| | | workQueue = new WorkQueue(idGenerator, defaultThreadPoolSize); |
| | | return workQueue; |
| | | } |
| | | } |
| | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.Constants.AccountType; |
| | | import com.gitblit.Constants.AuthenticationType; |
| | | import com.gitblit.Constants.Role; |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.auth.AuthenticationProvider; |
| | | import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider; |
| | | import com.gitblit.auth.HtpasswdAuthProvider; |
| | | import com.gitblit.auth.HttpHeaderAuthProvider; |
| | | import com.gitblit.auth.LdapAuthProvider; |
| | | import com.gitblit.auth.PAMAuthProvider; |
| | | import com.gitblit.auth.RedmineAuthProvider; |
| | |
| | | import com.gitblit.utils.HttpUtils; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.gitblit.utils.X509Utils.X509Metadata; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * The authentication manager handles user login & logout. |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class AuthenticationManager implements IAuthenticationManager { |
| | | |
| | | private final Logger logger = LoggerFactory.getLogger(getClass()); |
| | |
| | | |
| | | private final Map<String, String> legacyRedirects; |
| | | |
| | | @Inject |
| | | public AuthenticationManager( |
| | | IRuntimeManager runtimeManager, |
| | | IUserManager userManager) { |
| | |
| | | // map of shortcut provider names |
| | | providerNames = new HashMap<String, Class<? extends AuthenticationProvider>>(); |
| | | providerNames.put("htpasswd", HtpasswdAuthProvider.class); |
| | | providerNames.put("httpheader", HttpHeaderAuthProvider.class); |
| | | providerNames.put("ldap", LdapAuthProvider.class); |
| | | providerNames.put("pam", PAMAuthProvider.class); |
| | | providerNames.put("redmine", RedmineAuthProvider.class); |
| | |
| | | } |
| | | |
| | | /** |
| | | * Authenticate a user based on HTTP request parameters. |
| | | * Used to handle authentication for page requests. |
| | | * |
| | | * This allows authentication to occur based on the contents of the request |
| | | * itself. If no configured @{AuthenticationProvider}s authenticate succesffully, |
| | | * a request for login will be shown. |
| | | * |
| | | * Authentication by X509Certificate is tried first and then by cookie. |
| | | * |
| | |
| | | /** |
| | | * Authenticate a user based on HTTP request parameters. |
| | | * |
| | | * Authentication by servlet container principal, X509Certificate, cookie, |
| | | * Authentication by custom HTTP header, servlet container principal, X509Certificate, cookie, |
| | | * and finally BASIC header. |
| | | * |
| | | * @param httpRequest |
| | |
| | | */ |
| | | @Override |
| | | public UserModel authenticate(HttpServletRequest httpRequest, boolean requiresCertificate) { |
| | | |
| | | // Check if this request has already been authenticated, and trust that instead of re-processing |
| | | String reqAuthUser = (String) httpRequest.getAttribute(Constants.ATTRIB_AUTHUSER); |
| | | if (!StringUtils.isEmpty(reqAuthUser)) { |
| | | logger.debug("Called servlet authenticate when request is already authenticated."); |
| | | return userManager.getUserModel(reqAuthUser); |
| | | } |
| | | |
| | | // try to authenticate by servlet container principal |
| | | if (!requiresCertificate) { |
| | | Principal principal = httpRequest.getUserPrincipal(); |
| | |
| | | UserModel user = userManager.getUserModel(username); |
| | | if (user != null) { |
| | | // existing user |
| | | flagSession(httpRequest, AuthenticationType.CONTAINER); |
| | | flagRequest(httpRequest, AuthenticationType.CONTAINER, user.username); |
| | | logger.debug(MessageFormat.format("{0} authenticated by servlet container principal from {1}", |
| | | user.username, httpRequest.getRemoteAddr())); |
| | | return validateAuthentication(user, AuthenticationType.CONTAINER); |
| | |
| | | user.displayName = username; |
| | | user.password = Constants.EXTERNAL_ACCOUNT; |
| | | user.accountType = AccountType.CONTAINER; |
| | | |
| | | // Try to extract user's informations for the session |
| | | // it uses "realm.container.autoAccounts.*" as the attribute name to look for |
| | | HttpSession session = httpRequest.getSession(); |
| | | String emailAddress = resolveAttribute(session, Keys.realm.container.autoAccounts.emailAddress); |
| | | if(emailAddress != null) { |
| | | user.emailAddress = emailAddress; |
| | | } |
| | | String displayName = resolveAttribute(session, Keys.realm.container.autoAccounts.displayName); |
| | | if(displayName != null) { |
| | | user.displayName = displayName; |
| | | } |
| | | String userLocale = resolveAttribute(session, Keys.realm.container.autoAccounts.locale); |
| | | if(userLocale != null) { |
| | | user.getPreferences().setLocale(userLocale); |
| | | } |
| | | String adminRole = settings.getString(Keys.realm.container.autoAccounts.adminRole, null); |
| | | if(adminRole != null && ! adminRole.isEmpty()) { |
| | | if(httpRequest.isUserInRole(adminRole)) { |
| | | user.canAdmin = true; |
| | | } |
| | | } |
| | | |
| | | userManager.updateUserModel(user); |
| | | flagSession(httpRequest, AuthenticationType.CONTAINER); |
| | | flagRequest(httpRequest, AuthenticationType.CONTAINER, user.username); |
| | | logger.debug(MessageFormat.format("{0} authenticated and created by servlet container principal from {1}", |
| | | user.username, httpRequest.getRemoteAddr())); |
| | | return validateAuthentication(user, AuthenticationType.CONTAINER); |
| | |
| | | UserModel user = userManager.getUserModel(model.username); |
| | | X509Metadata metadata = HttpUtils.getCertificateMetadata(httpRequest); |
| | | if (user != null) { |
| | | flagSession(httpRequest, AuthenticationType.CERTIFICATE); |
| | | flagRequest(httpRequest, AuthenticationType.CERTIFICATE, user.username); |
| | | logger.debug(MessageFormat.format("{0} authenticated by client certificate {1} from {2}", |
| | | user.username, metadata.serialNumber, httpRequest.getRemoteAddr())); |
| | | return validateAuthentication(user, AuthenticationType.CERTIFICATE); |
| | |
| | | if (!StringUtils.isEmpty(cookie)) { |
| | | user = userManager.getUserModel(cookie.toCharArray()); |
| | | if (user != null) { |
| | | flagSession(httpRequest, AuthenticationType.COOKIE); |
| | | flagRequest(httpRequest, AuthenticationType.COOKIE, user.username); |
| | | logger.debug(MessageFormat.format("{0} authenticated by cookie from {1}", |
| | | user.username, httpRequest.getRemoteAddr())); |
| | | return validateAuthentication(user, AuthenticationType.COOKIE); |
| | |
| | | if (values.length == 2) { |
| | | String username = values[0]; |
| | | char[] password = values[1].toCharArray(); |
| | | user = authenticate(username, password); |
| | | user = authenticate(username, password, httpRequest.getRemoteAddr()); |
| | | if (user != null) { |
| | | flagSession(httpRequest, AuthenticationType.CREDENTIALS); |
| | | flagRequest(httpRequest, AuthenticationType.CREDENTIALS, user.username); |
| | | logger.debug(MessageFormat.format("{0} authenticated by BASIC request header from {1}", |
| | | user.username, httpRequest.getRemoteAddr())); |
| | | return validateAuthentication(user, AuthenticationType.CREDENTIALS); |
| | | } else { |
| | | logger.warn(MessageFormat.format("Failed login attempt for {0}, invalid credentials from {1}", |
| | | username, httpRequest.getRemoteAddr())); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Check each configured AuthenticationProvider |
| | | for (AuthenticationProvider ap : authenticationProviders) { |
| | | UserModel authedUser = ap.authenticate(httpRequest); |
| | | if (null != authedUser) { |
| | | flagRequest(httpRequest, ap.getAuthenticationType(), authedUser.username); |
| | | logger.debug(MessageFormat.format("{0} authenticated by {1} from {2} for {3}", |
| | | authedUser.username, ap.getServiceName(), httpRequest.getRemoteAddr(), |
| | | httpRequest.getPathInfo())); |
| | | return validateAuthentication(authedUser, ap.getAuthenticationType()); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * Extract given attribute from the session and return it's content |
| | | * it return null if attributeMapping is empty, or if the value is |
| | | * empty |
| | | * |
| | | * @param session The user session |
| | | * @param attributeMapping |
| | | * @return |
| | | */ |
| | | private String resolveAttribute(HttpSession session, String attributeMapping) { |
| | | String attributeName = settings.getString(attributeMapping, null); |
| | | if(StringUtils.isEmpty(attributeName)) { |
| | | return null; |
| | | } |
| | | Object attributeValue = session.getAttribute(attributeName); |
| | | if(attributeValue == null) { |
| | | return null; |
| | | } |
| | | String value = attributeValue.toString(); |
| | | if(value.isEmpty()) { |
| | | return null; |
| | | } |
| | | return value; |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | |
| | | /** |
| | | * Return the UserModel for already authenticated user. |
| | | * |
| | | * This implementation assumes that the authentication has already take place |
| | | * (e.g. SSHDaemon) and that this is a validation/verification of the user. |
| | | * |
| | | * @param username |
| | | * @return a user object or null |
| | | */ |
| | | @Override |
| | | public UserModel authenticate(String username) { |
| | | if (username != null) { |
| | | if (!StringUtils.isEmpty(username)) { |
| | | UserModel user = userManager.getUserModel(username); |
| | | if (user != null) { |
| | | // existing user |
| | | logger.debug(MessageFormat.format("{0} authenticated externally", user.username)); |
| | | return validateAuthentication(user, AuthenticationType.CONTAINER); |
| | | } |
| | | logger.warn(MessageFormat.format("Failed to find UserModel for {0} during external authentication", |
| | | username)); |
| | | } |
| | | } else { |
| | | logger.warn("Empty user passed to AuthenticationManager.authenticate!"); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * This method allows the authentication manager to reject authentication |
| | | * attempts. It is called after the username/secret have been verified to |
| | | * ensure that the authentication technique has been logged. |
| | |
| | | return user; |
| | | } |
| | | |
| | | protected void flagSession(HttpServletRequest httpRequest, AuthenticationType authenticationType) { |
| | | httpRequest.getSession().setAttribute(Constants.AUTHENTICATION_TYPE, authenticationType); |
| | | protected void flagRequest(HttpServletRequest httpRequest, AuthenticationType authenticationType, String authedUsername) { |
| | | httpRequest.setAttribute(Constants.ATTRIB_AUTHUSER, authedUsername); |
| | | httpRequest.setAttribute(Constants.ATTRIB_AUTHTYPE, authenticationType); |
| | | } |
| | | |
| | | /** |
| | |
| | | * @return a user object or null |
| | | */ |
| | | @Override |
| | | public UserModel authenticate(String username, char[] password) { |
| | | public UserModel authenticate(String username, char[] password, String remoteIP) { |
| | | if (StringUtils.isEmpty(username)) { |
| | | // can not authenticate empty username |
| | | return null; |
| | | } |
| | | |
| | | if (username.equalsIgnoreCase(Constants.FEDERATION_USER)) { |
| | | // can not authenticate internal FEDERATION_USER at this point |
| | | // it must be routed to FederationManager |
| | | return null; |
| | | } |
| | | |
| | | String usernameDecoded = StringUtils.decodeUsername(username); |
| | | String pw = new String(password); |
| | | if (StringUtils.isEmpty(pw)) { |
| | |
| | | |
| | | // try local authentication |
| | | if (user != null && user.isLocalAccount()) { |
| | | return authenticateLocal(user, password); |
| | | } |
| | | |
| | | // try registered external authentication providers |
| | | for (AuthenticationProvider provider : authenticationProviders) { |
| | | if (provider instanceof UsernamePasswordAuthenticationProvider) { |
| | | UserModel returnedUser = provider.authenticate(usernameDecoded, password); |
| | | if (returnedUser != null) { |
| | | // user authenticated |
| | | returnedUser.accountType = provider.getAccountType(); |
| | | return validateAuthentication(returnedUser, AuthenticationType.CREDENTIALS); |
| | | UserModel returnedUser = authenticateLocal(user, password); |
| | | if (returnedUser != null) { |
| | | // user authenticated |
| | | return returnedUser; |
| | | } |
| | | } else { |
| | | // try registered external authentication providers |
| | | for (AuthenticationProvider provider : authenticationProviders) { |
| | | if (provider instanceof UsernamePasswordAuthenticationProvider) { |
| | | UserModel returnedUser = provider.authenticate(usernameDecoded, password); |
| | | if (returnedUser != null) { |
| | | // user authenticated |
| | | returnedUser.accountType = provider.getAccountType(); |
| | | return validateAuthentication(returnedUser, AuthenticationType.CREDENTIALS); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // could not authenticate locally or with a provider |
| | | logger.warn(MessageFormat.format("Failed login attempt for {0}, invalid credentials from {1}", username, |
| | | remoteIP != null ? remoteIP : "unknown")); |
| | | |
| | | return null; |
| | | } |
| | | |
| | |
| | | @Override |
| | | public void setCookie(HttpServletRequest request, HttpServletResponse response, UserModel user) { |
| | | if (settings.getBoolean(Keys.web.allowCookieAuthentication, true)) { |
| | | HttpSession session = request.getSession(); |
| | | AuthenticationType authenticationType = (AuthenticationType) session.getAttribute(Constants.AUTHENTICATION_TYPE); |
| | | boolean standardLogin = authenticationType.isStandard(); |
| | | boolean standardLogin = true; |
| | | |
| | | if (null != request) { |
| | | // Pull the auth type from the request, it is set there if container managed |
| | | AuthenticationType authenticationType = (AuthenticationType) request.getAttribute(Constants.ATTRIB_AUTHTYPE); |
| | | |
| | | if (null != authenticationType) |
| | | standardLogin = authenticationType.isStandard(); |
| | | } |
| | | |
| | | if (standardLogin) { |
| | | Cookie userCookie; |
| | |
| | | return (team != null && team.isLocalTeam()) || findProvider(team).supportsTeamMembershipChanges(); |
| | | } |
| | | |
| | | /** |
| | | * Returns true if the user's role can be changed. |
| | | * |
| | | * @param user |
| | | * @return true if the user's role can be changed |
| | | */ |
| | | @Override |
| | | public boolean supportsRoleChanges(UserModel user, Role role) { |
| | | return (user != null && user.isLocalAccount()) || findProvider(user).supportsRoleChanges(user, role); |
| | | } |
| | | |
| | | /** |
| | | * Returns true if the team's role can be changed. |
| | | * |
| | | * @param user |
| | | * @return true if the team's role can be changed |
| | | */ |
| | | @Override |
| | | public boolean supportsRoleChanges(TeamModel team, Role role) { |
| | | return (team != null && team.isLocalTeam()) || findProvider(team).supportsRoleChanges(team, role); |
| | | } |
| | | |
| | | protected AuthenticationProvider findProvider(UserModel user) { |
| | | for (AuthenticationProvider provider : authenticationProviders) { |
| | | if (provider.getAccountType().equals(user.accountType)) { |
| | |
| | | import com.gitblit.utils.FederationUtils; |
| | | import com.gitblit.utils.JsonUtils; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Federation manager controls all aspects of handling federation sets, tokens, |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class FederationManager implements IFederationManager { |
| | | |
| | | private final Logger logger = LoggerFactory.getLogger(getClass()); |
| | |
| | | |
| | | private final IRepositoryManager repositoryManager; |
| | | |
| | | @Inject |
| | | public FederationManager( |
| | | IRuntimeManager runtimeManager, |
| | | INotificationManager notificationManager, |
| | |
| | | && file.getName().toLowerCase().endsWith(Constants.PROPOSAL_EXT); |
| | | } |
| | | }); |
| | | if (files == null) { |
| | | return list; |
| | | } |
| | | |
| | | for (File file : files) { |
| | | String json = com.gitblit.utils.FileUtils.readContent(file, null); |
| | | FederationProposal proposal = JsonUtils.fromJsonString(json, |
New file |
| | |
| | | /* |
| | | * Copyright 2015 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.manager; |
| | | |
| | | import java.io.EOFException; |
| | | import java.io.File; |
| | | import java.io.FileInputStream; |
| | | import java.io.FileOutputStream; |
| | | import java.io.FileReader; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.io.OutputStream; |
| | | import java.io.RandomAccessFile; |
| | | import java.lang.reflect.Type; |
| | | import java.nio.file.Files; |
| | | import java.text.MessageFormat; |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.Date; |
| | | import java.util.Iterator; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.regex.Pattern; |
| | | |
| | | import org.apache.commons.codec.digest.DigestUtils; |
| | | import org.apache.commons.io.FileUtils; |
| | | import org.apache.commons.io.IOUtils; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.models.FilestoreModel; |
| | | import com.gitblit.models.FilestoreModel.Status; |
| | | import com.gitblit.models.RepositoryModel; |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.utils.ArrayUtils; |
| | | import com.gitblit.utils.JsonUtils.GmtDateTypeAdapter; |
| | | import com.google.gson.ExclusionStrategy; |
| | | import com.google.gson.Gson; |
| | | import com.google.gson.GsonBuilder; |
| | | import com.google.gson.reflect.TypeToken; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * FilestoreManager handles files uploaded via: |
| | | * + git-lfs |
| | | * + ticket attachment (TBD) |
| | | * |
| | | * Files are stored using their SHA256 hash (as per git-lfs) |
| | | * If the same file is uploaded through different repositories no additional space is used |
| | | * Access is controlled through the current repository permissions. |
| | | * |
| | | * TODO: Identify what and how the actual BLOBs should work with federation |
| | | * |
| | | * @author Paul Martin |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class FilestoreManager implements IFilestoreManager { |
| | | |
| | | private final Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | private final IRuntimeManager runtimeManager; |
| | | |
| | | private final IRepositoryManager repositoryManager; |
| | | |
| | | private final IStoredSettings settings; |
| | | |
| | | public static final int UNDEFINED_SIZE = -1; |
| | | |
| | | private static final String METAFILE = "filestore.json"; |
| | | |
| | | private static final String METAFILE_TMP = "filestore.json.tmp"; |
| | | |
| | | protected static final Type METAFILE_TYPE = new TypeToken<Collection<FilestoreModel>>() {}.getType(); |
| | | |
| | | private Map<String, FilestoreModel > fileCache = new ConcurrentHashMap<String, FilestoreModel>(); |
| | | |
| | | |
| | | @Inject |
| | | FilestoreManager( |
| | | IRuntimeManager runtimeManager, |
| | | IRepositoryManager repositoryManager) { |
| | | this.runtimeManager = runtimeManager; |
| | | this.repositoryManager = repositoryManager; |
| | | this.settings = runtimeManager.getSettings(); |
| | | } |
| | | |
| | | @Override |
| | | public IManager start() { |
| | | |
| | | // Try to load any existing metadata |
| | | File dir = getStorageFolder(); |
| | | dir.mkdirs(); |
| | | File metadata = new File(dir, METAFILE); |
| | | |
| | | if (metadata.exists()) { |
| | | Collection<FilestoreModel> items = null; |
| | | |
| | | Gson gson = gson(); |
| | | try (FileReader file = new FileReader(metadata)) { |
| | | items = gson.fromJson(file, METAFILE_TYPE); |
| | | file.close(); |
| | | |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | |
| | | for(Iterator<FilestoreModel> itr = items.iterator(); itr.hasNext(); ) { |
| | | FilestoreModel model = itr.next(); |
| | | fileCache.put(model.oid, model); |
| | | } |
| | | |
| | | logger.info("Loaded {} items from filestore metadata file", fileCache.size()); |
| | | } |
| | | else |
| | | { |
| | | logger.info("No filestore metadata file found"); |
| | | } |
| | | |
| | | return this; |
| | | } |
| | | |
| | | @Override |
| | | public IManager stop() { |
| | | return this; |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public boolean isValidOid(String oid) { |
| | | //NOTE: Assuming SHA256 support only as per git-lfs |
| | | return Pattern.matches("[a-fA-F0-9]{64}", oid); |
| | | } |
| | | |
| | | @Override |
| | | public FilestoreModel.Status addObject(String oid, long size, UserModel user, RepositoryModel repo) { |
| | | |
| | | //Handle access control |
| | | if (!user.canPush(repo)) { |
| | | if (user == UserModel.ANONYMOUS) { |
| | | return Status.AuthenticationRequired; |
| | | } else { |
| | | return Status.Error_Unauthorized; |
| | | } |
| | | } |
| | | |
| | | //Handle object details |
| | | if (!isValidOid(oid)) { return Status.Error_Invalid_Oid; } |
| | | |
| | | if (fileCache.containsKey(oid)) { |
| | | FilestoreModel item = fileCache.get(oid); |
| | | |
| | | if (!item.isInErrorState() && (size != UNDEFINED_SIZE) && (item.getSize() != size)) { |
| | | return Status.Error_Size_Mismatch; |
| | | } |
| | | |
| | | item.addRepository(repo.name); |
| | | |
| | | if (item.isInErrorState()) { |
| | | item.reset(user, size); |
| | | } |
| | | } else { |
| | | |
| | | if (size < 0) {return Status.Error_Invalid_Size; } |
| | | if ((getMaxUploadSize() != UNDEFINED_SIZE) && (size > getMaxUploadSize())) { return Status.Error_Exceeds_Size_Limit; } |
| | | |
| | | FilestoreModel model = new FilestoreModel(oid, size, user, repo.name); |
| | | fileCache.put(oid, model); |
| | | saveFilestoreModel(model); |
| | | } |
| | | |
| | | return fileCache.get(oid).getStatus(); |
| | | } |
| | | |
| | | @Override |
| | | public FilestoreModel.Status uploadBlob(String oid, long size, UserModel user, RepositoryModel repo, InputStream streamIn) { |
| | | |
| | | //Access control and object logic |
| | | Status state = addObject(oid, size, user, repo); |
| | | |
| | | if (state != Status.Upload_Pending) { |
| | | return state; |
| | | } |
| | | |
| | | FilestoreModel model = fileCache.get(oid); |
| | | |
| | | if (!model.actionUpload(user)) { |
| | | return Status.Upload_In_Progress; |
| | | } else { |
| | | long actualSize = 0; |
| | | File file = getStoragePath(oid); |
| | | |
| | | try { |
| | | file.getParentFile().mkdirs(); |
| | | file.createNewFile(); |
| | | |
| | | try (FileOutputStream streamOut = new FileOutputStream(file)) { |
| | | |
| | | actualSize = IOUtils.copyLarge(streamIn, streamOut); |
| | | |
| | | streamOut.flush(); |
| | | streamOut.close(); |
| | | |
| | | if (model.getSize() != actualSize) { |
| | | model.setStatus(Status.Error_Size_Mismatch, user); |
| | | |
| | | logger.warn(MessageFormat.format("Failed to upload blob {0} due to size mismatch, expected {1} got {2}", |
| | | oid, model.getSize(), actualSize)); |
| | | } else { |
| | | String actualOid = ""; |
| | | |
| | | try (FileInputStream fileForHash = new FileInputStream(file)) { |
| | | actualOid = DigestUtils.sha256Hex(fileForHash); |
| | | fileForHash.close(); |
| | | } |
| | | |
| | | if (oid.equalsIgnoreCase(actualOid)) { |
| | | model.setStatus(Status.Available, user); |
| | | } else { |
| | | model.setStatus(Status.Error_Hash_Mismatch, user); |
| | | |
| | | logger.warn(MessageFormat.format("Failed to upload blob {0} due to hash mismatch, got {1}", oid, actualOid)); |
| | | } |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | |
| | | model.setStatus(Status.Error_Unknown, user); |
| | | logger.warn(MessageFormat.format("Failed to upload blob {0}", oid), e); |
| | | } finally { |
| | | saveFilestoreModel(model); |
| | | } |
| | | |
| | | if (model.isInErrorState()) { |
| | | file.delete(); |
| | | model.removeRepository(repo.name); |
| | | } |
| | | } |
| | | |
| | | return model.getStatus(); |
| | | } |
| | | |
| | | private FilestoreModel.Status canGetObject(String oid, UserModel user, RepositoryModel repo) { |
| | | |
| | | //Access Control |
| | | if (!user.canView(repo)) { |
| | | if (user == UserModel.ANONYMOUS) { |
| | | return Status.AuthenticationRequired; |
| | | } else { |
| | | return Status.Error_Unauthorized; |
| | | } |
| | | } |
| | | |
| | | //Object Logic |
| | | if (!isValidOid(oid)) { |
| | | return Status.Error_Invalid_Oid; |
| | | } |
| | | |
| | | if (!fileCache.containsKey(oid)) { |
| | | return Status.Unavailable; |
| | | } |
| | | |
| | | FilestoreModel item = fileCache.get(oid); |
| | | |
| | | if (item.getStatus() == Status.Available) { |
| | | return Status.Available; |
| | | } |
| | | |
| | | return Status.Unavailable; |
| | | } |
| | | |
| | | @Override |
| | | public FilestoreModel getObject(String oid, UserModel user, RepositoryModel repo) { |
| | | |
| | | if (canGetObject(oid, user, repo) == Status.Available) { |
| | | return fileCache.get(oid); |
| | | } |
| | | |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public FilestoreModel.Status downloadBlob(String oid, UserModel user, RepositoryModel repo, OutputStream streamOut) { |
| | | |
| | | //Access control and object logic |
| | | Status status = canGetObject(oid, user, repo); |
| | | |
| | | if (status != Status.Available) { |
| | | return status; |
| | | } |
| | | |
| | | FilestoreModel item = fileCache.get(oid); |
| | | |
| | | if (streamOut != null) { |
| | | try (FileInputStream streamIn = new FileInputStream(getStoragePath(oid))) { |
| | | |
| | | IOUtils.copyLarge(streamIn, streamOut); |
| | | |
| | | streamOut.flush(); |
| | | streamIn.close(); |
| | | } catch (EOFException e) { |
| | | logger.error(MessageFormat.format("Client aborted connection for {0}", oid), e); |
| | | return Status.Error_Unexpected_Stream_End; |
| | | } catch (Exception e) { |
| | | logger.error(MessageFormat.format("Failed to download blob {0}", oid), e); |
| | | return Status.Error_Unknown; |
| | | } |
| | | } |
| | | |
| | | return item.getStatus(); |
| | | } |
| | | |
| | | @Override |
| | | public List<FilestoreModel> getAllObjects(UserModel user) { |
| | | |
| | | final List<RepositoryModel> viewableRepositories = repositoryManager.getRepositoryModels(user); |
| | | List<String> viewableRepositoryNames = new ArrayList<String>(viewableRepositories.size()); |
| | | |
| | | for (RepositoryModel repository : viewableRepositories) { |
| | | viewableRepositoryNames.add(repository.name); |
| | | } |
| | | |
| | | if (viewableRepositoryNames.size() == 0) { |
| | | return null; |
| | | } |
| | | |
| | | final Collection<FilestoreModel> allFiles = fileCache.values(); |
| | | List<FilestoreModel> userViewableFiles = new ArrayList<FilestoreModel>(allFiles.size()); |
| | | |
| | | for (FilestoreModel file : allFiles) { |
| | | if (file.isInRepositoryList(viewableRepositoryNames)) { |
| | | userViewableFiles.add(file); |
| | | } |
| | | } |
| | | |
| | | return userViewableFiles; |
| | | } |
| | | |
| | | @Override |
| | | public File getStorageFolder() { |
| | | return runtimeManager.getFileOrFolder(Keys.filestore.storageFolder, "${baseFolder}/lfs"); |
| | | } |
| | | |
| | | @Override |
| | | public File getStoragePath(String oid) { |
| | | return new File(getStorageFolder(), oid.substring(0, 2).concat("/").concat(oid.substring(2))); |
| | | } |
| | | |
| | | @Override |
| | | public long getMaxUploadSize() { |
| | | return settings.getLong(Keys.filestore.maxUploadSize, -1); |
| | | } |
| | | |
| | | @Override |
| | | public long getFilestoreUsedByteCount() { |
| | | Iterator<FilestoreModel> iterator = fileCache.values().iterator(); |
| | | long total = 0; |
| | | |
| | | while (iterator.hasNext()) { |
| | | |
| | | FilestoreModel item = iterator.next(); |
| | | if (item.getStatus() == Status.Available) { |
| | | total += item.getSize(); |
| | | } |
| | | } |
| | | |
| | | return total; |
| | | } |
| | | |
| | | @Override |
| | | public long getFilestoreAvailableByteCount() { |
| | | |
| | | try { |
| | | return Files.getFileStore(getStorageFolder().toPath()).getUsableSpace(); |
| | | } catch (IOException e) { |
| | | logger.error(MessageFormat.format("Failed to retrive available space in Filestore {0}", e)); |
| | | } |
| | | |
| | | return UNDEFINED_SIZE; |
| | | }; |
| | | |
| | | private synchronized void saveFilestoreModel(FilestoreModel model) { |
| | | |
| | | File metaFile = new File(getStorageFolder(), METAFILE); |
| | | File metaFileTmp = new File(getStorageFolder(), METAFILE_TMP); |
| | | boolean isNewFile = false; |
| | | |
| | | try { |
| | | if (!metaFile.exists()) { |
| | | metaFile.getParentFile().mkdirs(); |
| | | metaFile.createNewFile(); |
| | | isNewFile = true; |
| | | } |
| | | FileUtils.copyFile(metaFile, metaFileTmp); |
| | | |
| | | } catch (IOException e) { |
| | | logger.error("Writing filestore model to file {0}, {1}", METAFILE, e); |
| | | } |
| | | |
| | | try (RandomAccessFile fs = new RandomAccessFile(metaFileTmp, "rw")) { |
| | | |
| | | if (isNewFile) { |
| | | fs.writeBytes("["); |
| | | } else { |
| | | fs.seek(fs.length() - 1); |
| | | fs.writeBytes(","); |
| | | } |
| | | |
| | | fs.writeBytes(gson().toJson(model)); |
| | | fs.writeBytes("]"); |
| | | |
| | | fs.close(); |
| | | |
| | | } catch (IOException e) { |
| | | logger.error("Writing filestore model to file {0}, {1}", METAFILE_TMP, e); |
| | | } |
| | | |
| | | try { |
| | | if (metaFileTmp.exists()) { |
| | | FileUtils.copyFile(metaFileTmp, metaFile); |
| | | |
| | | metaFileTmp.delete(); |
| | | } else { |
| | | logger.error("Writing filestore model to file {0}", METAFILE); |
| | | } |
| | | } |
| | | catch (IOException e) { |
| | | logger.error("Writing filestore model to file {0}, {1}", METAFILE, e); |
| | | } |
| | | } |
| | | |
| | | /* |
| | | * Intended for testing purposes only |
| | | */ |
| | | @Override |
| | | public void clearFilestoreCache() { |
| | | fileCache.clear(); |
| | | } |
| | | |
| | | private static Gson gson(ExclusionStrategy... strategies) { |
| | | GsonBuilder builder = new GsonBuilder(); |
| | | builder.registerTypeAdapter(Date.class, new GmtDateTypeAdapter()); |
| | | if (!ArrayUtils.isEmpty(strategies)) { |
| | | builder.setExclusionStrategies(strategies); |
| | | } |
| | | return builder.create(); |
| | | } |
| | | |
| | | } |
| | |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.io.InputStreamReader; |
| | | import java.io.OutputStream; |
| | | import java.lang.reflect.Type; |
| | | import java.text.MessageFormat; |
| | | import java.util.ArrayList; |
| | |
| | | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.Constants.AccessPermission; |
| | | import com.gitblit.Constants.AccessRestrictionType; |
| | | import com.gitblit.Constants.FederationRequest; |
| | | import com.gitblit.Constants.FederationToken; |
| | | import com.gitblit.Constants.Role; |
| | | import com.gitblit.GitBlitException; |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.extensions.RepositoryLifeCycleListener; |
| | | import com.gitblit.models.FederationModel; |
| | | import com.gitblit.models.FederationProposal; |
| | | import com.gitblit.models.FederationSet; |
| | | import com.gitblit.models.FilestoreModel; |
| | | import com.gitblit.models.ForkModel; |
| | | import com.gitblit.models.GitClientApplication; |
| | | import com.gitblit.models.Mailing; |
| | |
| | | import com.gitblit.models.ProjectModel; |
| | | import com.gitblit.models.RegistrantAccessPermission; |
| | | import com.gitblit.models.RepositoryModel; |
| | | import com.gitblit.models.RepositoryUrl; |
| | | import com.gitblit.models.SearchResult; |
| | | import com.gitblit.models.ServerSettings; |
| | | import com.gitblit.models.ServerStatus; |
| | |
| | | import com.gitblit.transport.ssh.IPublicKeyManager; |
| | | import com.gitblit.transport.ssh.SshKey; |
| | | import com.gitblit.utils.ArrayUtils; |
| | | import com.gitblit.utils.HttpUtils; |
| | | import com.gitblit.utils.JsonUtils; |
| | | import com.gitblit.utils.ObjectCache; |
| | | import com.gitblit.utils.StringUtils; |
| | |
| | | import com.google.gson.JsonIOException; |
| | | import com.google.gson.JsonSyntaxException; |
| | | import com.google.gson.reflect.TypeToken; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Injector; |
| | | import com.google.inject.Provider; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * GitblitManager is an aggregate interface delegate. It implements all the manager |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class GitblitManager implements IGitblit { |
| | | |
| | | protected final Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | protected final ObjectCache<Collection<GitClientApplication>> clientApplications = new ObjectCache<Collection<GitClientApplication>>(); |
| | | |
| | | protected final Provider<IPublicKeyManager> publicKeyManagerProvider; |
| | | |
| | | protected final Provider<ITicketService> ticketServiceProvider; |
| | | |
| | | protected final IStoredSettings settings; |
| | | |
| | |
| | | |
| | | protected final IAuthenticationManager authenticationManager; |
| | | |
| | | protected final IPublicKeyManager publicKeyManager; |
| | | |
| | | protected final IRepositoryManager repositoryManager; |
| | | |
| | | protected final IProjectManager projectManager; |
| | | |
| | | protected final IFederationManager federationManager; |
| | | |
| | | protected final IFilestoreManager filestoreManager; |
| | | |
| | | @Inject |
| | | public GitblitManager( |
| | | Provider<IPublicKeyManager> publicKeyManagerProvider, |
| | | Provider<ITicketService> ticketServiceProvider, |
| | | IRuntimeManager runtimeManager, |
| | | IPluginManager pluginManager, |
| | | INotificationManager notificationManager, |
| | | IUserManager userManager, |
| | | IAuthenticationManager authenticationManager, |
| | | IPublicKeyManager publicKeyManager, |
| | | IRepositoryManager repositoryManager, |
| | | IProjectManager projectManager, |
| | | IFederationManager federationManager) { |
| | | IFederationManager federationManager, |
| | | IFilestoreManager filestoreManager) { |
| | | |
| | | this.publicKeyManagerProvider = publicKeyManagerProvider; |
| | | this.ticketServiceProvider = ticketServiceProvider; |
| | | |
| | | this.settings = runtimeManager.getSettings(); |
| | | this.runtimeManager = runtimeManager; |
| | |
| | | this.notificationManager = notificationManager; |
| | | this.userManager = userManager; |
| | | this.authenticationManager = authenticationManager; |
| | | this.publicKeyManager = publicKeyManager; |
| | | this.repositoryManager = repositoryManager; |
| | | this.projectManager = projectManager; |
| | | this.federationManager = federationManager; |
| | | this.filestoreManager = filestoreManager; |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | // add this clone to the cached model |
| | | repositoryManager.addToCachedRepositoryList(cloneModel); |
| | | |
| | | if (pluginManager != null) { |
| | | for (RepositoryLifeCycleListener listener : pluginManager.getExtensions(RepositoryLifeCycleListener.class)) { |
| | | try { |
| | | listener.onFork(repository, cloneModel); |
| | | } catch (Throwable t) { |
| | | logger.error(String.format("failed to call plugin onFork %s", repository.name), t); |
| | | } |
| | | } |
| | | } |
| | | return cloneModel; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns a list of repository URLs and the user access permission. |
| | | * |
| | | * @param request |
| | | * @param user |
| | | * @param repository |
| | | * @return a list of repository urls |
| | | */ |
| | | @Override |
| | | public List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) { |
| | | if (user == null) { |
| | | user = UserModel.ANONYMOUS; |
| | | } |
| | | String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username); |
| | | |
| | | List<RepositoryUrl> list = new ArrayList<RepositoryUrl>(); |
| | | // http/https url |
| | | if (settings.getBoolean(Keys.git.enableGitServlet, true)) { |
| | | AccessPermission permission = user.getRepositoryPermission(repository).permission; |
| | | if (permission.exceeds(AccessPermission.NONE)) { |
| | | list.add(new RepositoryUrl(getRepositoryUrl(request, username, repository), permission)); |
| | | } |
| | | } |
| | | |
| | | // add all other urls |
| | | // {0} = repository |
| | | // {1} = username |
| | | for (String url : settings.getStrings(Keys.web.otherUrls)) { |
| | | if (url.contains("{1}")) { |
| | | // external url requires username, only add url IF we have one |
| | | if (!StringUtils.isEmpty(username)) { |
| | | list.add(new RepositoryUrl(MessageFormat.format(url, repository.name, username), null)); |
| | | } |
| | | } else { |
| | | // external url does not require username |
| | | list.add(new RepositoryUrl(MessageFormat.format(url, repository.name), null)); |
| | | } |
| | | } |
| | | return list; |
| | | } |
| | | |
| | | protected String getRepositoryUrl(HttpServletRequest request, String username, RepositoryModel repository) { |
| | | String gitblitUrl = settings.getString(Keys.web.canonicalUrl, null); |
| | | if (StringUtils.isEmpty(gitblitUrl)) { |
| | | gitblitUrl = HttpUtils.getGitblitURL(request); |
| | | } |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append(gitblitUrl); |
| | | sb.append(Constants.R_PATH); |
| | | sb.append(repository.name); |
| | | |
| | | // inject username into repository url if authentication is required |
| | | if (repository.accessRestriction.exceeds(AccessRestrictionType.NONE) |
| | | && !StringUtils.isEmpty(username)) { |
| | | sb.insert(sb.indexOf("://") + 3, username + "@"); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns the list of custom client applications to be used for the |
| | | * repository url panel; |
| | | * |
| | |
| | | // Read bundled Gitblit properties to extract setting descriptions. |
| | | // This copy is pristine and only used for populating the setting |
| | | // models map. |
| | | InputStream is = GitblitManager.class.getResourceAsStream("/reference.properties"); |
| | | InputStream is = GitblitManager.class.getResourceAsStream("/defaults.properties"); |
| | | BufferedReader propertiesReader = new BufferedReader(new InputStreamReader(is)); |
| | | StringBuilder description = new StringBuilder(); |
| | | SettingModel setting = new SettingModel(); |
| | |
| | | } |
| | | propertiesReader.close(); |
| | | } catch (NullPointerException e) { |
| | | logger.error("Failed to find resource copy of gitblit.properties"); |
| | | logger.error("Failed to find classpath resource 'defaults.properties'"); |
| | | } catch (IOException e) { |
| | | logger.error("Failed to load resource copy of gitblit.properties"); |
| | | logger.error("Failed to load classpath resource 'defaults.properties'"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Throws an exception if trying to get a ticket service. |
| | | * |
| | | */ |
| | | @Override |
| | | public ITicketService getTicketService() { |
| | | throw new RuntimeException("This class does not have a ticket service!"); |
| | | return ticketServiceProvider.get(); |
| | | } |
| | | |
| | | @Override |
| | | public IPublicKeyManager getPublicKeyManager() { |
| | | return publicKeyManager; |
| | | return publicKeyManagerProvider.get(); |
| | | } |
| | | |
| | | /* |
| | |
| | | } |
| | | |
| | | @Override |
| | | public boolean isServingRepositories() { |
| | | return runtimeManager.isServingRepositories(); |
| | | } |
| | | |
| | | @Override |
| | | public boolean isServingHTTP() { |
| | | return runtimeManager.isServingHTTP(); |
| | | } |
| | | |
| | | @Override |
| | | public boolean isServingGIT() { |
| | | return runtimeManager.isServingGIT(); |
| | | } |
| | | |
| | | @Override |
| | | public boolean isServingSSH() { |
| | | return runtimeManager.isServingSSH(); |
| | | } |
| | | |
| | | @Override |
| | | public TimeZone getTimezone() { |
| | | return runtimeManager.getTimezone(); |
| | | } |
| | |
| | | @Override |
| | | public ServerStatus getStatus() { |
| | | return runtimeManager.getStatus(); |
| | | } |
| | | |
| | | @Override |
| | | public Injector getInjector() { |
| | | return runtimeManager.getInjector(); |
| | | } |
| | | |
| | | @Override |
| | |
| | | */ |
| | | |
| | | @Override |
| | | public UserModel authenticate(String username, char[] password) { |
| | | return authenticationManager.authenticate(username, password); |
| | | public UserModel authenticate(String username, char[] password, String remoteIP) { |
| | | return authenticationManager.authenticate(username, password, remoteIP); |
| | | } |
| | | |
| | | @Override |
| | |
| | | @Override |
| | | public UserModel authenticate(String username, SshKey key) { |
| | | return authenticationManager.authenticate(username, key); |
| | | } |
| | | |
| | | @Override |
| | | public UserModel authenticate(String username) { |
| | | return authenticationManager.authenticate(username); |
| | | } |
| | | |
| | | @Override |
| | |
| | | return authenticationManager.supportsTeamMembershipChanges(team); |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(UserModel user, Role role) { |
| | | return authenticationManager.supportsRoleChanges(user, role); |
| | | } |
| | | |
| | | @Override |
| | | public boolean supportsRoleChanges(TeamModel team, Role role) { |
| | | return authenticationManager.supportsRoleChanges(team, role); |
| | | } |
| | | |
| | | /* |
| | | * USER MANAGER |
| | | */ |
| | |
| | | @Override |
| | | public List<UserModel> getAllUsers() { |
| | | return userManager.getAllUsers(); |
| | | } |
| | | |
| | | @Override |
| | | public boolean deleteUser(String username) { |
| | | return userManager.deleteUser(username); |
| | | } |
| | | |
| | | @Override |
| | |
| | | } |
| | | |
| | | @Override |
| | | public boolean deleteUser(String username) { |
| | | // delegate to deleteUserModel() to delete public ssh keys |
| | | UserModel user = userManager.getUserModel(username); |
| | | return deleteUserModel(user); |
| | | } |
| | | |
| | | /** |
| | | * Delete the user and all associated public ssh keys. |
| | | */ |
| | | @Override |
| | | public boolean deleteUserModel(UserModel model) { |
| | | return userManager.deleteUserModel(model); |
| | | boolean success = userManager.deleteUserModel(model); |
| | | if (success) { |
| | | getPublicKeyManager().removeAllKeys(model.username); |
| | | } |
| | | return success; |
| | | } |
| | | |
| | | @Override |
| | |
| | | return repositoryManager.getRepositoryDefaultMetrics(model, repository); |
| | | } |
| | | |
| | | /** |
| | | * Detect renames and reindex as appropriate. |
| | | */ |
| | | @Override |
| | | public void updateRepositoryModel(String repositoryName, RepositoryModel repository, |
| | | boolean isCreate) throws GitBlitException { |
| | | RepositoryModel oldModel = null; |
| | | boolean isRename = !isCreate && !repositoryName.equalsIgnoreCase(repository.name); |
| | | if (isRename) { |
| | | oldModel = repositoryManager.getRepositoryModel(repositoryName); |
| | | } |
| | | |
| | | repositoryManager.updateRepositoryModel(repositoryName, repository, isCreate); |
| | | |
| | | if (isRename && ticketServiceProvider.get() != null) { |
| | | ticketServiceProvider.get().rename(oldModel, repository); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | return repositoryManager.canDelete(model); |
| | | } |
| | | |
| | | /** |
| | | * Delete the repository and all associated tickets. |
| | | */ |
| | | @Override |
| | | public boolean deleteRepositoryModel(RepositoryModel model) { |
| | | return repositoryManager.deleteRepositoryModel(model); |
| | | boolean success = repositoryManager.deleteRepositoryModel(model); |
| | | if (success && ticketServiceProvider.get() != null) { |
| | | ticketServiceProvider.get().deleteAll(model); |
| | | } |
| | | return success; |
| | | } |
| | | |
| | | @Override |
| | | public boolean deleteRepository(String repositoryName) { |
| | | return repositoryManager.deleteRepository(repositoryName); |
| | | // delegate to deleteRepositoryModel() to destroy indexed tickets |
| | | RepositoryModel repository = repositoryManager.getRepositoryModel(repositoryName); |
| | | return deleteRepositoryModel(repository); |
| | | } |
| | | |
| | | @Override |
| | |
| | | } |
| | | |
| | | /* |
| | | * FILE STORAGE MANAGER |
| | | */ |
| | | |
| | | @Override |
| | | public boolean isValidOid(String oid) { |
| | | return filestoreManager.isValidOid(oid); |
| | | } |
| | | |
| | | @Override |
| | | public FilestoreModel.Status addObject(String oid, long size, UserModel user, RepositoryModel repo) { |
| | | return filestoreManager.addObject(oid, size, user, repo); |
| | | } |
| | | |
| | | @Override |
| | | public FilestoreModel getObject(String oid, UserModel user, RepositoryModel repo) { |
| | | return filestoreManager.getObject(oid, user, repo); |
| | | }; |
| | | |
| | | @Override |
| | | public FilestoreModel.Status uploadBlob(String oid, long size, UserModel user, RepositoryModel repo, InputStream streamIn ) { |
| | | return filestoreManager.uploadBlob(oid, size, user, repo, streamIn); |
| | | } |
| | | |
| | | @Override |
| | | public FilestoreModel.Status downloadBlob(String oid, UserModel user, RepositoryModel repo, OutputStream streamOut ) { |
| | | return filestoreManager.downloadBlob(oid, user, repo, streamOut); |
| | | } |
| | | |
| | | @Override |
| | | public List<FilestoreModel> getAllObjects(UserModel user) { |
| | | return filestoreManager.getAllObjects(user); |
| | | } |
| | | |
| | | @Override |
| | | public File getStorageFolder() { |
| | | return filestoreManager.getStorageFolder(); |
| | | } |
| | | |
| | | @Override |
| | | public File getStoragePath(String oid) { |
| | | return filestoreManager.getStoragePath(oid); |
| | | } |
| | | |
| | | @Override |
| | | public long getMaxUploadSize() { |
| | | return filestoreManager.getMaxUploadSize(); |
| | | }; |
| | | |
| | | @Override |
| | | public void clearFilestoreCache() { |
| | | filestoreManager.clearFilestoreCache(); |
| | | }; |
| | | |
| | | @Override |
| | | public long getFilestoreUsedByteCount() { |
| | | return filestoreManager.getFilestoreUsedByteCount(); |
| | | }; |
| | | |
| | | @Override |
| | | public long getFilestoreAvailableByteCount() { |
| | | return filestoreManager.getFilestoreAvailableByteCount(); |
| | | }; |
| | | |
| | | /* |
| | | * PLUGIN MANAGER |
| | | */ |
| | | |
| | |
| | | public PluginRelease lookupRelease(String pluginId, String version) { |
| | | return pluginManager.lookupRelease(pluginId, version); |
| | | } |
| | | |
| | | } |
| | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | |
| | | import com.gitblit.Constants.Role; |
| | | import com.gitblit.models.TeamModel; |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.transport.ssh.SshKey; |
| | |
| | | * @see IUserService.authenticate(String, char[]) |
| | | * @param username |
| | | * @param password |
| | | * @param remoteIP |
| | | * @return a user object or null |
| | | * @since 1.4.0 |
| | | */ |
| | | UserModel authenticate(String username, char[] password); |
| | | UserModel authenticate(String username, char[] password, String remoteIP); |
| | | |
| | | /** |
| | | * Return the UserModel for already authenticated user. |
| | | * |
| | | * @see IUserService.authenticate(String, char[]) |
| | | * @param username |
| | | * @return a user object or null |
| | | * @since 1.7.0 |
| | | */ |
| | | UserModel authenticate(String username); |
| | | |
| | | /** |
| | | * Returns the Gitlbit cookie in the request. |
| | |
| | | */ |
| | | boolean supportsTeamMembershipChanges(TeamModel team); |
| | | |
| | | /** |
| | | * Returns true if the specified role can be changed. |
| | | * |
| | | * @param user |
| | | * @return true if the specified role can be changed |
| | | * @since 1.6.1 |
| | | */ |
| | | boolean supportsRoleChanges(UserModel user, Role role); |
| | | |
| | | /** |
| | | * Returns true if the specified role can be changed. |
| | | * |
| | | * @param team |
| | | * @return true if the specified role can be changed |
| | | * @since 1.6.1 |
| | | */ |
| | | boolean supportsRoleChanges(TeamModel team, Role role); |
| | | |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2015 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.manager; |
| | | |
| | | import java.io.File; |
| | | import java.io.InputStream; |
| | | import java.io.OutputStream; |
| | | import java.util.List; |
| | | |
| | | import com.gitblit.models.FilestoreModel; |
| | | import com.gitblit.models.RepositoryModel; |
| | | import com.gitblit.models.UserModel; |
| | | |
| | | |
| | | public interface IFilestoreManager extends IManager { |
| | | |
| | | boolean isValidOid(String oid); |
| | | |
| | | FilestoreModel.Status addObject(String oid, long size, UserModel user, RepositoryModel repo); |
| | | |
| | | FilestoreModel getObject(String oid, UserModel user, RepositoryModel repo); |
| | | |
| | | FilestoreModel.Status uploadBlob(String oid, long size, UserModel user, RepositoryModel repo, InputStream streamIn ); |
| | | |
| | | FilestoreModel.Status downloadBlob(String oid, UserModel user, RepositoryModel repo, OutputStream streamOut ); |
| | | |
| | | List<FilestoreModel> getAllObjects(UserModel user); |
| | | |
| | | File getStorageFolder(); |
| | | |
| | | File getStoragePath(String oid); |
| | | |
| | | long getMaxUploadSize(); |
| | | |
| | | void clearFilestoreCache(); |
| | | |
| | | long getFilestoreUsedByteCount(); |
| | | |
| | | long getFilestoreAvailableByteCount(); |
| | | |
| | | } |
| | |
| | | package com.gitblit.manager; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | |
| | | import com.gitblit.GitBlitException; |
| | | import com.gitblit.models.GitClientApplication; |
| | | import com.gitblit.models.RepositoryModel; |
| | | import com.gitblit.models.RepositoryUrl; |
| | | import com.gitblit.models.TeamModel; |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.tickets.ITicketService; |
| | |
| | | IAuthenticationManager, |
| | | IRepositoryManager, |
| | | IProjectManager, |
| | | IFederationManager { |
| | | |
| | | /** |
| | | * Returns a list of repository URLs and the user access permission. |
| | | * |
| | | * @param request |
| | | * @param user |
| | | * @param repository |
| | | * @return a list of repository urls |
| | | * @since 1.4.0 |
| | | */ |
| | | List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository); |
| | | IFederationManager, |
| | | IFilestoreManager { |
| | | |
| | | /** |
| | | * Creates a complete user object. |
| | |
| | | import com.gitblit.models.ServerSettings; |
| | | import com.gitblit.models.ServerStatus; |
| | | import com.gitblit.utils.XssFilter; |
| | | import com.google.inject.Injector; |
| | | |
| | | public interface IRuntimeManager extends IManager { |
| | | |
| | | Injector getInjector(); |
| | | |
| | | void setBaseFolder(File folder); |
| | | |
| | |
| | | * @since 1.5.1 |
| | | */ |
| | | Locale getLocale(); |
| | | |
| | | /** |
| | | * Determine if this Gitblit instance is actively serving git repositories |
| | | * or if it is merely a repository viewer. |
| | | * |
| | | * @return true if Gitblit is serving repositories |
| | | * @since 1.4.0 |
| | | */ |
| | | boolean isServingRepositories(); |
| | | |
| | | /** |
| | | * Determine if this Gitblit instance is actively serving git repositories |
| | | * over HTTP. |
| | | * |
| | | * @return true if Gitblit is serving repositories over HTTP |
| | | * @since 1.6.0 |
| | | */ |
| | | boolean isServingHTTP(); |
| | | |
| | | /** |
| | | * Determine if this Gitblit instance is actively serving git repositories |
| | | * over the GIT Daemon protocol. |
| | | * |
| | | * @return true if Gitblit is serving repositories over the GIT Daemon protocol |
| | | * @since 1.6.0 |
| | | */ |
| | | boolean isServingGIT(); |
| | | |
| | | /** |
| | | * Determine if this Gitblit instance is actively serving git repositories |
| | | * over the SSH protocol. |
| | | * |
| | | * @return true if Gitblit is serving repositories over the SSH protocol |
| | | * @since 1.6.0 |
| | | */ |
| | | boolean isServingSSH(); |
| | | |
| | | /** |
| | | * Determine if this Gitblit instance is running in debug mode |
New file |
| | |
| | | /* |
| | | * Copyright 2014 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.manager; |
| | | |
| | | import java.util.List; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | |
| | | import com.gitblit.Constants.Transport; |
| | | import com.gitblit.models.RepositoryModel; |
| | | import com.gitblit.models.RepositoryUrl; |
| | | import com.gitblit.models.UserModel; |
| | | |
| | | public interface IServicesManager extends IManager { |
| | | |
| | | /** |
| | | * Determine if this Gitblit instance is actively serving git repositories |
| | | * or if it is merely a repository viewer. |
| | | * |
| | | * @return true if Gitblit is serving repositories |
| | | * @since 1.7.0 |
| | | */ |
| | | boolean isServingRepositories(); |
| | | |
| | | /** |
| | | * Determine if this Gitblit instance is actively serving git repositories |
| | | * over HTTP. |
| | | * |
| | | * @return true if Gitblit is serving repositories over HTTP |
| | | * @since 1.7.0 |
| | | */ |
| | | boolean isServingHTTP(); |
| | | |
| | | /** |
| | | * Determine if this Gitblit instance is actively serving git repositories |
| | | * over HTTP. |
| | | * |
| | | * @return true if Gitblit is serving repositories over HTTPS |
| | | * @since 1.7.0 |
| | | */ |
| | | boolean isServingHTTPS(); |
| | | |
| | | /** |
| | | * Determine if this Gitblit instance is actively serving git repositories |
| | | * over the GIT Daemon protocol. |
| | | * |
| | | * @return true if Gitblit is serving repositories over the GIT Daemon protocol |
| | | * @since 1.7.0 |
| | | */ |
| | | boolean isServingGIT(); |
| | | |
| | | /** |
| | | * Determine if this Gitblit instance is actively serving git repositories |
| | | * over the SSH protocol. |
| | | * |
| | | * @return true if Gitblit is serving repositories over the SSH protocol |
| | | * @since 1.7.0 |
| | | */ |
| | | boolean isServingSSH(); |
| | | |
| | | /** |
| | | * Returns a list of repository URLs and the user access permission. |
| | | * |
| | | * @param request |
| | | * @param user |
| | | * @param repository |
| | | * @return a list of repository urls |
| | | * @since 1.7.0 |
| | | */ |
| | | List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository); |
| | | |
| | | /** |
| | | * Returns true if the transport may be used for pushing. |
| | | * |
| | | * @param byTransport |
| | | * @return true if the transport can be used for pushes. |
| | | * @since 1.7.0 |
| | | */ |
| | | boolean acceptsPush(Transport byTransport); |
| | | |
| | | } |
| | |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.models.Mailing; |
| | | import com.gitblit.service.MailService; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * The notification manager dispatches notifications. Currently, email is the |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class NotificationManager implements INotificationManager { |
| | | |
| | | private final Logger logger = LoggerFactory.getLogger(getClass()); |
| | |
| | | |
| | | private final MailService mailService; |
| | | |
| | | @Inject |
| | | public NotificationManager(IStoredSettings settings) { |
| | | this.settings = settings; |
| | | this.mailService = new MailService(settings); |
| | |
| | | */ |
| | | package com.gitblit.manager; |
| | | |
| | | import java.io.BufferedInputStream; |
| | | import java.io.File; |
| | | import java.io.FileFilter; |
| | | import java.io.FileInputStream; |
| | | import java.io.FileOutputStream; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.io.OutputStream; |
| | | import java.net.HttpURLConnection; |
| | | import java.net.InetSocketAddress; |
| | | import java.net.Proxy; |
| | | import java.net.URL; |
| | | import java.net.URLConnection; |
| | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import ro.fortsoft.pf4j.DefaultPluginFactory; |
| | | import ro.fortsoft.pf4j.DefaultPluginManager; |
| | | import ro.fortsoft.pf4j.ExtensionFactory; |
| | | import ro.fortsoft.pf4j.Plugin; |
| | | import ro.fortsoft.pf4j.PluginClassLoader; |
| | | import ro.fortsoft.pf4j.PluginFactory; |
| | | import ro.fortsoft.pf4j.PluginState; |
| | | import ro.fortsoft.pf4j.PluginStateEvent; |
| | | import ro.fortsoft.pf4j.PluginStateListener; |
| | |
| | | import com.gitblit.utils.FileUtils; |
| | | import com.gitblit.utils.JsonUtils; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.google.common.io.Files; |
| | | import com.google.common.io.InputSupplier; |
| | | import com.google.common.io.ByteStreams; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * The plugin manager maintains the lifecycle of plugins. It is exposed as |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class PluginManager implements IPluginManager, PluginStateListener { |
| | | |
| | | private final Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | private final DefaultPluginManager pf4j; |
| | | |
| | | private final IRuntimeManager runtimeManager; |
| | | |
| | | private DefaultPluginManager pf4j; |
| | | |
| | | // timeout defaults of Maven 3.0.4 in seconds |
| | | private int connectTimeout = 20; |
| | | |
| | | private int readTimeout = 12800; |
| | | |
| | | @Inject |
| | | public PluginManager(IRuntimeManager runtimeManager) { |
| | | File dir = runtimeManager.getFileOrFolder(Keys.plugins.folder, "${baseFolder}/plugins"); |
| | | dir.mkdirs(); |
| | | this.runtimeManager = runtimeManager; |
| | | |
| | | this.pf4j = new DefaultPluginManager(dir); |
| | | |
| | | try { |
| | | Version systemVersion = Version.createVersion(Constants.getVersion()); |
| | | pf4j.setSystemVersion(systemVersion); |
| | | } catch (Exception e) { |
| | | logger.error(null, e); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | @Override |
| | | public PluginManager start() { |
| | | File dir = runtimeManager.getFileOrFolder(Keys.plugins.folder, "${baseFolder}/plugins"); |
| | | dir.mkdirs(); |
| | | |
| | | pf4j = new DefaultPluginManager(dir) { |
| | | |
| | | @Override |
| | | protected PluginFactory createPluginFactory() { |
| | | return new GuicePluginFactory(); |
| | | } |
| | | |
| | | @Override |
| | | protected ExtensionFactory createExtensionFactory() { |
| | | return new GuiceExtensionFactory(); |
| | | } |
| | | }; |
| | | |
| | | try { |
| | | Version systemVersion = Version.createVersion(Constants.getVersion()); |
| | | pf4j.setSystemVersion(systemVersion); |
| | | } catch (Exception e) { |
| | | logger.error(null, e); |
| | | } |
| | | pf4j.loadPlugins(); |
| | | logger.debug("Starting plugins"); |
| | | pf4j.startPlugins(); |
| | |
| | | |
| | | } |
| | | |
| | | if (sha1File == null && md5File == null && verifyChecksum) { |
| | | if (sha1File == null && md5File == null) { |
| | | throw new IOException("Missing SHA1 and MD5 checksums for " + url); |
| | | } |
| | | |
| | |
| | | // try to get the server-specified last-modified date of this artifact |
| | | long lastModified = conn.getHeaderFieldDate("Last-Modified", System.currentTimeMillis()); |
| | | |
| | | Files.copy(new InputSupplier<InputStream>() { |
| | | @Override |
| | | public InputStream getInput() throws IOException { |
| | | return new BufferedInputStream(conn.getInputStream()); |
| | | } |
| | | }, tmpFile); |
| | | try (InputStream is = conn.getInputStream(); OutputStream os = new FileOutputStream(tmpFile);) { |
| | | ByteStreams.copy(is, os); |
| | | } |
| | | |
| | | File destFile = new File(pFolder, StringUtils.getLastPathElement(u.getPath())); |
| | | if (destFile.exists()) { |
| | |
| | | } |
| | | |
| | | protected Proxy getProxy(URL url) { |
| | | return java.net.Proxy.NO_PROXY; |
| | | String proxyHost = runtimeManager.getSettings().getString(Keys.plugins.httpProxyHost, ""); |
| | | String proxyPort = runtimeManager.getSettings().getString(Keys.plugins.httpProxyPort, ""); |
| | | |
| | | if (!StringUtils.isEmpty(proxyHost) && !StringUtils.isEmpty(proxyPort)) { |
| | | return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, Integer.parseInt(proxyPort))); |
| | | } else { |
| | | return java.net.Proxy.NO_PROXY; |
| | | } |
| | | } |
| | | |
| | | protected String getProxyAuthorization(URL url) { |
| | | return ""; |
| | | String proxyAuth = runtimeManager.getSettings().getString(Keys.plugins.httpProxyAuthorization, ""); |
| | | return proxyAuth; |
| | | } |
| | | |
| | | /** |
| | | * Instantiates a plugin using pf4j but injects member fields |
| | | * with Guice. |
| | | */ |
| | | private class GuicePluginFactory extends DefaultPluginFactory { |
| | | |
| | | @Override |
| | | public Plugin create(PluginWrapper pluginWrapper) { |
| | | // use pf4j to create the plugin |
| | | Plugin plugin = super.create(pluginWrapper); |
| | | |
| | | if (plugin != null) { |
| | | // allow Guice to inject member fields |
| | | runtimeManager.getInjector().injectMembers(plugin); |
| | | } |
| | | |
| | | return plugin; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Instantiates an extension using Guice. |
| | | */ |
| | | private class GuiceExtensionFactory implements ExtensionFactory { |
| | | @Override |
| | | public Object create(Class<?> extensionClass) { |
| | | // instantiate && inject the extension |
| | | logger.debug("Create instance for extension '{}'", extensionClass.getName()); |
| | | try { |
| | | return runtimeManager.getInjector().getInstance(extensionClass); |
| | | } catch (Exception e) { |
| | | logger.error(e.getMessage(), e); |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | } |
| | |
| | | import com.gitblit.utils.ModelUtils; |
| | | import com.gitblit.utils.ObjectCache; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Project manager handles project-related functions. |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class ProjectManager implements IProjectManager { |
| | | |
| | | private final Logger logger = LoggerFactory.getLogger(getClass()); |
| | |
| | | |
| | | private FileBasedConfig projectConfigs; |
| | | |
| | | @Inject |
| | | public ProjectManager( |
| | | IRuntimeManager runtimeManager, |
| | | IUserManager userManager, |
| | |
| | | import com.gitblit.utils.ObjectCache; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.gitblit.utils.TimeUtils; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Repository manager creates, updates, deletes and caches git repositories. It |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class RepositoryManager implements IRepositoryManager { |
| | | |
| | | private final Logger logger = LoggerFactory.getLogger(getClass()); |
| | |
| | | |
| | | private final IUserManager userManager; |
| | | |
| | | private final File repositoriesFolder; |
| | | private File repositoriesFolder; |
| | | |
| | | private LuceneService luceneExecutor; |
| | | |
| | |
| | | |
| | | private MirrorService mirrorExecutor; |
| | | |
| | | @Inject |
| | | public RepositoryManager( |
| | | IRuntimeManager runtimeManager, |
| | | IPluginManager pluginManager, |
| | |
| | | this.runtimeManager = runtimeManager; |
| | | this.pluginManager = pluginManager; |
| | | this.userManager = userManager; |
| | | this.repositoriesFolder = runtimeManager.getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git"); |
| | | } |
| | | |
| | | @Override |
| | | public RepositoryManager start() { |
| | | repositoriesFolder = runtimeManager.getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git"); |
| | | logger.info("Repositories folder : {}", repositoriesFolder.getAbsolutePath()); |
| | | |
| | | // initialize utilities |
| | |
| | | // find the root, cached |
| | | String key = getRepositoryKey(repository); |
| | | RepositoryModel model = repositoryListCache.get(key); |
| | | if (model == null) { |
| | | return null; |
| | | } |
| | | |
| | | while (model.originRepository != null) { |
| | | String originKey = getRepositoryKey(model.originRepository); |
| | | model = repositoryListCache.get(originKey); |
| | | if (model == null) { |
| | | return null; |
| | | } |
| | | } |
| | | ForkModel root = getForkModelFromCache(model.name); |
| | | return root; |
| | |
| | | } |
| | | |
| | | /** |
| | | * Creates/updates the repository model keyed by reopsitoryName. Saves all |
| | | * Creates/updates the repository model keyed by repositoryName. Saves all |
| | | * repository settings in .git/config. This method allows for renaming |
| | | * repositories and will update user access permissions accordingly. |
| | | * |
| | |
| | | repository.name = repository.name.substring(projectPath.length() + 1); |
| | | } |
| | | } |
| | | boolean isRename = false; |
| | | if (isCreate) { |
| | | // ensure created repository name ends with .git |
| | | if (!repository.name.toLowerCase().endsWith(org.eclipse.jgit.lib.Constants.DOT_GIT_EXT)) { |
| | |
| | | r = JGitUtils.createRepository(repositoriesFolder, repository.name, shared); |
| | | } else { |
| | | // rename repository |
| | | if (!repositoryName.equalsIgnoreCase(repository.name)) { |
| | | isRename = !repositoryName.equalsIgnoreCase(repository.name); |
| | | if (isRename) { |
| | | if (!repository.name.toLowerCase().endsWith( |
| | | org.eclipse.jgit.lib.Constants.DOT_GIT_EXT)) { |
| | | repository.name += org.eclipse.jgit.lib.Constants.DOT_GIT_EXT; |
| | |
| | | listener.onCreation(repository); |
| | | } catch (Throwable t) { |
| | | logger.error(String.format("failed to call plugin onCreation %s", repositoryName), t); |
| | | } |
| | | } |
| | | } else if (isRename && pluginManager != null) { |
| | | for (RepositoryLifeCycleListener listener : pluginManager.getExtensions(RepositoryLifeCycleListener.class)) { |
| | | try { |
| | | listener.onRename(repositoryName, repository); |
| | | } catch (Throwable t) { |
| | | logger.error(String.format("failed to call plugin onRename %s", repositoryName), t); |
| | | } |
| | | } |
| | | } |
| | |
| | | cfg.setPackedGitWindowSize(settings.getFilesize(Keys.git.packedGitWindowSize, cfg.getPackedGitWindowSize())); |
| | | cfg.setPackedGitLimit(settings.getFilesize(Keys.git.packedGitLimit, cfg.getPackedGitLimit())); |
| | | cfg.setDeltaBaseCacheLimit(settings.getFilesize(Keys.git.deltaBaseCacheLimit, cfg.getDeltaBaseCacheLimit())); |
| | | cfg.setPackedGitOpenFiles(settings.getFilesize(Keys.git.packedGitOpenFiles, cfg.getPackedGitOpenFiles())); |
| | | cfg.setPackedGitOpenFiles(settings.getInteger(Keys.git.packedGitOpenFiles, cfg.getPackedGitOpenFiles())); |
| | | cfg.setPackedGitMMAP(settings.getBoolean(Keys.git.packedGitMmap, cfg.isPackedGitMMAP())); |
| | | |
| | | try { |
| | |
| | | } |
| | | |
| | | protected void confirmWriteAccess() { |
| | | if (runtimeManager.isServingRepositories()) { |
| | | try { |
| | | if (!getRepositoriesFolder().exists()) { |
| | | getRepositoriesFolder().mkdirs(); |
| | | } |
| | | File file = File.createTempFile(".test-", ".txt", getRepositoriesFolder()); |
| | | file.delete(); |
| | | } catch (Exception e) { |
| | | logger.error(""); |
| | | logger.error(Constants.BORDER2); |
| | | logger.error("Please check filesystem permissions!"); |
| | | logger.error("FAILED TO WRITE TO REPOSITORIES FOLDER!!", e); |
| | | logger.error(Constants.BORDER2); |
| | | logger.error(""); |
| | | try { |
| | | if (!getRepositoriesFolder().exists()) { |
| | | getRepositoriesFolder().mkdirs(); |
| | | } |
| | | File file = File.createTempFile(".test-", ".txt", getRepositoriesFolder()); |
| | | file.delete(); |
| | | } catch (Exception e) { |
| | | logger.error(""); |
| | | logger.error(Constants.BORDER2); |
| | | logger.error("Please check filesystem permissions!"); |
| | | logger.error("FAILED TO WRITE TO REPOSITORIES FOLDER!!", e); |
| | | logger.error(Constants.BORDER2); |
| | | logger.error(""); |
| | | } |
| | | } |
| | | } |
| | |
| | | import com.gitblit.models.SettingModel; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.gitblit.utils.XssFilter; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Injector; |
| | | import com.google.inject.Singleton; |
| | | |
| | | @Singleton |
| | | public class RuntimeManager implements IRuntimeManager { |
| | | |
| | | private final Logger logger = LoggerFactory.getLogger(getClass()); |
| | |
| | | |
| | | private TimeZone timezone; |
| | | |
| | | @Inject |
| | | private Injector injector; |
| | | |
| | | @Inject |
| | | public RuntimeManager(IStoredSettings settings, XssFilter xssFilter) { |
| | | this(settings, xssFilter, null); |
| | | } |
| | |
| | | @Override |
| | | public RuntimeManager stop() { |
| | | return this; |
| | | } |
| | | |
| | | @Override |
| | | public Injector getInjector() { |
| | | return injector; |
| | | } |
| | | |
| | | @Override |
| | |
| | | } |
| | | // settingsModel.pushScripts = getAllScripts(); |
| | | return settingsModel; |
| | | } |
| | | |
| | | /** |
| | | * Determine if this Gitblit instance is actively serving git repositories |
| | | * or if it is merely a repository viewer. |
| | | * |
| | | * @return true if Gitblit is serving repositories |
| | | */ |
| | | @Override |
| | | public boolean isServingRepositories() { |
| | | return isServingHTTP() |
| | | || isServingGIT() |
| | | || isServingSSH(); |
| | | } |
| | | |
| | | /** |
| | | * Determine if this Gitblit instance is actively serving git repositories |
| | | * over the HTTP protocol. |
| | | * |
| | | * @return true if Gitblit is serving repositories over the HTTP protocol |
| | | */ |
| | | @Override |
| | | public boolean isServingHTTP() { |
| | | return settings.getBoolean(Keys.git.enableGitServlet, true); |
| | | } |
| | | |
| | | /** |
| | | * Determine if this Gitblit instance is actively serving git repositories |
| | | * over the Git Daemon protocol. |
| | | * |
| | | * @return true if Gitblit is serving repositories over the Git Daemon protocol |
| | | */ |
| | | @Override |
| | | public boolean isServingGIT() { |
| | | return settings.getInteger(Keys.git.daemonPort, 0) > 0; |
| | | } |
| | | |
| | | /** |
| | | * Determine if this Gitblit instance is actively serving git repositories |
| | | * over the SSH protocol. |
| | | * |
| | | * @return true if Gitblit is serving repositories over the SSH protocol |
| | | */ |
| | | @Override |
| | | public boolean isServingSSH() { |
| | | return settings.getInteger(Keys.git.sshPort, 0) > 0; |
| | | } |
| | | |
| | | /** |
| | |
| | | import java.io.IOException; |
| | | import java.net.URI; |
| | | import java.text.MessageFormat; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Collections; |
| | | import java.util.Comparator; |
| | | import java.util.Date; |
| | | import java.util.HashSet; |
| | | import java.util.Iterator; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | import java.util.concurrent.Executors; |
| | | import java.util.concurrent.ScheduledExecutorService; |
| | | import java.util.concurrent.TimeUnit; |
| | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.Constants.AccessPermission; |
| | | import com.gitblit.Constants.AccessRestrictionType; |
| | | import com.gitblit.Constants.FederationToken; |
| | | import com.gitblit.Constants.Transport; |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.fanout.FanoutNioService; |
| | |
| | | import com.gitblit.fanout.FanoutSocketService; |
| | | import com.gitblit.models.FederationModel; |
| | | import com.gitblit.models.RepositoryModel; |
| | | import com.gitblit.models.RepositoryUrl; |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.service.FederationPullService; |
| | | import com.gitblit.transport.git.GitDaemon; |
| | | import com.gitblit.transport.ssh.SshDaemon; |
| | | import com.gitblit.utils.IdGenerator; |
| | | import com.gitblit.utils.HttpUtils; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.gitblit.utils.TimeUtils; |
| | | import com.gitblit.utils.WorkQueue; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Provider; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Services manager manages long-running services/processes that either have no |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | public class ServicesManager implements IManager { |
| | | @Singleton |
| | | public class ServicesManager implements IServicesManager { |
| | | |
| | | private final Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | private final ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(5); |
| | | |
| | | private final Provider<WorkQueue> workQueueProvider; |
| | | |
| | | private final IStoredSettings settings; |
| | | |
| | | private final IGitblit gitblit; |
| | | |
| | | private final IdGenerator idGenerator; |
| | | |
| | | private final WorkQueue workQueue; |
| | | |
| | | private FanoutService fanoutService; |
| | | |
| | |
| | | |
| | | private SshDaemon sshDaemon; |
| | | |
| | | public ServicesManager(IGitblit gitblit) { |
| | | this.settings = gitblit.getSettings(); |
| | | @Inject |
| | | public ServicesManager( |
| | | Provider<WorkQueue> workQueueProvider, |
| | | IStoredSettings settings, |
| | | IGitblit gitblit) { |
| | | |
| | | this.workQueueProvider = workQueueProvider; |
| | | |
| | | this.settings = settings; |
| | | this.gitblit = gitblit; |
| | | int defaultThreadPoolSize = settings.getInteger(Keys.execution.defaultThreadPoolSize, 1); |
| | | this.idGenerator = new IdGenerator(); |
| | | this.workQueue = new WorkQueue(idGenerator, defaultThreadPoolSize); |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (sshDaemon != null) { |
| | | sshDaemon.stop(); |
| | | } |
| | | workQueue.stop(); |
| | | workQueueProvider.get().stop(); |
| | | return this; |
| | | } |
| | | |
| | | protected String getRepositoryUrl(HttpServletRequest request, String username, RepositoryModel repository) { |
| | | String gitblitUrl = settings.getString(Keys.web.canonicalUrl, null); |
| | | if (StringUtils.isEmpty(gitblitUrl)) { |
| | | gitblitUrl = HttpUtils.getGitblitURL(request); |
| | | } |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append(gitblitUrl); |
| | | sb.append(Constants.R_PATH); |
| | | sb.append(repository.name); |
| | | |
| | | // inject username into repository url if authentication is required |
| | | if (repository.accessRestriction.exceeds(AccessRestrictionType.NONE) |
| | | && !StringUtils.isEmpty(username)) { |
| | | sb.insert(sb.indexOf("://") + 3, username + "@"); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * Returns a list of repository URLs and the user access permission. |
| | | * |
| | | * @param request |
| | | * @param user |
| | | * @param repository |
| | | * @return a list of repository urls |
| | | */ |
| | | @Override |
| | | public List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) { |
| | | if (user == null) { |
| | | user = UserModel.ANONYMOUS; |
| | | } |
| | | String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username); |
| | | |
| | | List<RepositoryUrl> list = new ArrayList<RepositoryUrl>(); |
| | | |
| | | // http/https url |
| | | if (settings.getBoolean(Keys.git.enableGitServlet, true) && |
| | | settings.getBoolean(Keys.web.showHttpServletUrls, true)) { |
| | | AccessPermission permission = user.getRepositoryPermission(repository).permission; |
| | | if (permission.exceeds(AccessPermission.NONE)) { |
| | | String repoUrl = getRepositoryUrl(request, username, repository); |
| | | Transport transport = Transport.fromUrl(repoUrl); |
| | | if (permission.atLeast(AccessPermission.PUSH) && !acceptsPush(transport)) { |
| | | // downgrade the repo permission for this transport |
| | | // because it is not an acceptable PUSH transport |
| | | permission = AccessPermission.CLONE; |
| | | } |
| | | list.add(new RepositoryUrl(repoUrl, permission)); |
| | | } |
| | | } |
| | | |
| | | // ssh daemon url |
| | | String sshDaemonUrl = getSshDaemonUrl(request, user, repository); |
| | | if (!StringUtils.isEmpty(sshDaemonUrl) && |
| | | settings.getBoolean(Keys.web.showSshDaemonUrls, true)) { |
| | | AccessPermission permission = user.getRepositoryPermission(repository).permission; |
| | | if (permission.exceeds(AccessPermission.NONE)) { |
| | | if (permission.atLeast(AccessPermission.PUSH) && !acceptsPush(Transport.SSH)) { |
| | | // downgrade the repo permission for this transport |
| | | // because it is not an acceptable PUSH transport |
| | | permission = AccessPermission.CLONE; |
| | | } |
| | | |
| | | list.add(new RepositoryUrl(sshDaemonUrl, permission)); |
| | | } |
| | | } |
| | | |
| | | // git daemon url |
| | | String gitDaemonUrl = getGitDaemonUrl(request, user, repository); |
| | | if (!StringUtils.isEmpty(gitDaemonUrl) && |
| | | settings.getBoolean(Keys.web.showGitDaemonUrls, true)) { |
| | | AccessPermission permission = getGitDaemonAccessPermission(user, repository); |
| | | if (permission.exceeds(AccessPermission.NONE)) { |
| | | if (permission.atLeast(AccessPermission.PUSH) && !acceptsPush(Transport.GIT)) { |
| | | // downgrade the repo permission for this transport |
| | | // because it is not an acceptable PUSH transport |
| | | permission = AccessPermission.CLONE; |
| | | } |
| | | list.add(new RepositoryUrl(gitDaemonUrl, permission)); |
| | | } |
| | | } |
| | | |
| | | // add all other urls |
| | | // {0} = repository |
| | | // {1} = username |
| | | boolean advertisePermsForOther = settings.getBoolean(Keys.web.advertiseAccessPermissionForOtherUrls, false); |
| | | for (String url : settings.getStrings(Keys.web.otherUrls)) { |
| | | String externalUrl = null; |
| | | |
| | | if (url.contains("{1}")) { |
| | | // external url requires username, only add url IF we have one |
| | | if (StringUtils.isEmpty(username)) { |
| | | continue; |
| | | } else { |
| | | externalUrl = MessageFormat.format(url, repository.name, username); |
| | | } |
| | | } else { |
| | | // external url does not require username, just do repo name formatting |
| | | externalUrl = MessageFormat.format(url, repository.name); |
| | | } |
| | | |
| | | AccessPermission permission = null; |
| | | if (advertisePermsForOther) { |
| | | permission = user.getRepositoryPermission(repository).permission; |
| | | if (permission.exceeds(AccessPermission.NONE)) { |
| | | Transport transport = Transport.fromUrl(externalUrl); |
| | | if (permission.atLeast(AccessPermission.PUSH) && !acceptsPush(transport)) { |
| | | // downgrade the repo permission for this transport |
| | | // because it is not an acceptable PUSH transport |
| | | permission = AccessPermission.CLONE; |
| | | } |
| | | } |
| | | } |
| | | list.add(new RepositoryUrl(externalUrl, permission)); |
| | | } |
| | | |
| | | // sort transports by highest permission and then by transport security |
| | | Collections.sort(list, new Comparator<RepositoryUrl>() { |
| | | |
| | | @Override |
| | | public int compare(RepositoryUrl o1, RepositoryUrl o2) { |
| | | if (o1.hasPermission() && !o2.hasPermission()) { |
| | | // prefer known permission items over unknown |
| | | return -1; |
| | | } else if (!o1.hasPermission() && o2.hasPermission()) { |
| | | // prefer known permission items over unknown |
| | | return 1; |
| | | } else if (!o1.hasPermission() && !o2.hasPermission()) { |
| | | // sort by Transport ordinal |
| | | return o1.transport.compareTo(o2.transport); |
| | | } else if (o1.permission.exceeds(o2.permission)) { |
| | | // prefer highest permission |
| | | return -1; |
| | | } else if (o2.permission.exceeds(o1.permission)) { |
| | | // prefer highest permission |
| | | return 1; |
| | | } |
| | | |
| | | // prefer more secure transports |
| | | return o1.transport.compareTo(o2.transport); |
| | | } |
| | | }); |
| | | |
| | | // consider the user's transport preference |
| | | RepositoryUrl preferredUrl = null; |
| | | Transport preferredTransport = user.getPreferences().getTransport(); |
| | | if (preferredTransport != null) { |
| | | Iterator<RepositoryUrl> itr = list.iterator(); |
| | | while (itr.hasNext()) { |
| | | RepositoryUrl url = itr.next(); |
| | | if (url.transport.equals(preferredTransport)) { |
| | | itr.remove(); |
| | | preferredUrl = url; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | if (preferredUrl != null) { |
| | | list.add(0, preferredUrl); |
| | | } |
| | | |
| | | return list; |
| | | } |
| | | |
| | | /* (non-Javadoc) |
| | | * @see com.gitblit.manager.IServicesManager#isServingRepositories() |
| | | */ |
| | | @Override |
| | | public boolean isServingRepositories() { |
| | | return isServingHTTP() |
| | | return isServingHTTPS() |
| | | || isServingHTTP() |
| | | || isServingGIT() |
| | | || isServingSSH(); |
| | | } |
| | | |
| | | /* (non-Javadoc) |
| | | * @see com.gitblit.manager.IServicesManager#isServingHTTP() |
| | | */ |
| | | @Override |
| | | public boolean isServingHTTP() { |
| | | return settings.getBoolean(Keys.git.enableGitServlet, true); |
| | | return settings.getBoolean(Keys.git.enableGitServlet, true) |
| | | && ((gitblit.getStatus().isGO && settings.getInteger(Keys.server.httpPort, 0) > 0) |
| | | || !gitblit.getStatus().isGO); |
| | | } |
| | | |
| | | /* (non-Javadoc) |
| | | * @see com.gitblit.manager.IServicesManager#isServingHTTPS() |
| | | */ |
| | | @Override |
| | | public boolean isServingHTTPS() { |
| | | return settings.getBoolean(Keys.git.enableGitServlet, true) |
| | | && ((gitblit.getStatus().isGO && settings.getInteger(Keys.server.httpsPort, 0) > 0) |
| | | || !gitblit.getStatus().isGO); |
| | | } |
| | | |
| | | /* (non-Javadoc) |
| | | * @see com.gitblit.manager.IServicesManager#isServingGIT() |
| | | */ |
| | | @Override |
| | | public boolean isServingGIT() { |
| | | return gitDaemon != null && gitDaemon.isRunning(); |
| | | } |
| | | |
| | | /* (non-Javadoc) |
| | | * @see com.gitblit.manager.IServicesManager#isServingSSH() |
| | | */ |
| | | @Override |
| | | public boolean isServingSSH() { |
| | | return sshDaemon != null && sshDaemon.isRunning(); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public boolean acceptsPush(Transport byTransport) { |
| | | if (byTransport == null) { |
| | | logger.info("Unknown transport, push rejected!"); |
| | | return false; |
| | | } |
| | | |
| | | Set<Transport> transports = new HashSet<Transport>(); |
| | | for (String value : settings.getStrings(Keys.git.acceptedPushTransports)) { |
| | | Transport transport = Transport.fromString(value); |
| | | if (transport == null) { |
| | | logger.info(String.format("Ignoring unknown registered transport %s", value)); |
| | | continue; |
| | | } |
| | | |
| | | transports.add(transport); |
| | | } |
| | | |
| | | if (transports.isEmpty()) { |
| | | // no transports are explicitly specified, all are acceptable |
| | | return true; |
| | | } |
| | | |
| | | // verify that the transport is permitted |
| | | return transports.contains(byTransport); |
| | | } |
| | | |
| | | protected void configureGitDaemon() { |
| | | int port = settings.getInteger(Keys.git.daemonPort, 0); |
| | | String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost"); |
| | |
| | | String bindInterface = settings.getString(Keys.git.sshBindInterface, "localhost"); |
| | | if (port > 0) { |
| | | try { |
| | | sshDaemon = new SshDaemon(gitblit, workQueue); |
| | | sshDaemon = new SshDaemon(gitblit, workQueueProvider.get()); |
| | | sshDaemon.start(); |
| | | } catch (IOException e) { |
| | | sshDaemon = null; |
| | |
| | | */ |
| | | protected String getHostname(HttpServletRequest request) { |
| | | String hostname = request.getServerName(); |
| | | String canonicalUrl = gitblit.getSettings().getString(Keys.web.canonicalUrl, null); |
| | | String canonicalUrl = settings.getString(Keys.web.canonicalUrl, null); |
| | | if (!StringUtils.isEmpty(canonicalUrl)) { |
| | | try { |
| | | URI uri = new URI(canonicalUrl); |
| | |
| | | import com.gitblit.models.TeamModel; |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * The user manager manages persistence and retrieval of users and teams. |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class UserManager implements IUserManager { |
| | | |
| | | private final Logger logger = LoggerFactory.getLogger(getClass()); |
| | |
| | | |
| | | private IUserService userService; |
| | | |
| | | @Inject |
| | | public UserManager(IRuntimeManager runtimeManager, IPluginManager pluginManager) { |
| | | this.settings = runtimeManager.getSettings(); |
| | | this.runtimeManager = runtimeManager; |
| | |
| | | * @param userService |
| | | */ |
| | | public void setUserService(IUserService userService) { |
| | | logger.info(userService.toString()); |
| | | this.userService = userService; |
| | | this.userService.setup(runtimeManager); |
| | | logger.info(userService.toString()); |
| | | } |
| | | |
| | | @Override |
| | |
| | | // check to see if this "file" is a custom user service class |
| | | Class<?> realmClass = Class.forName(realm); |
| | | service = (IUserService) realmClass.newInstance(); |
| | | } catch (Throwable t) { |
| | | } catch (ClassNotFoundException t) { |
| | | // typical file path configuration |
| | | File realmFile = runtimeManager.getFileOrFolder(Keys.realm.userService, "${baseFolder}/users.conf"); |
| | | service = createUserService(realmFile); |
| | | } catch (InstantiationException | IllegalAccessException e) { |
| | | logger.error("failed to instantiate user service {}: {}", realm, e.getMessage()); |
| | | } |
| | | } |
| | | setUserService(service); |
New file |
| | |
| | | /* |
| | | * Copyright 2015 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.models; |
| | | |
| | | import java.io.Serializable; |
| | | import java.util.ArrayList; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.NoSuchElementException; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | |
| | | import com.gitblit.Constants; |
| | | |
| | | /** |
| | | * A FilestoreModel represents a file stored outside a repository but referenced by the repository using a unique objectID |
| | | * |
| | | * @author Paul Martin |
| | | * |
| | | */ |
| | | public class FilestoreModel implements Serializable, Comparable<FilestoreModel> { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private static final String metaRegexText = new StringBuilder() |
| | | .append("version\\shttps://git-lfs.github.com/spec/v1\\s+") |
| | | .append("oid\\ssha256:(" + Constants.REGEX_SHA256 + ")\\s+") |
| | | .append("size\\s([0-9]+)") |
| | | .toString(); |
| | | |
| | | private static final Pattern metaRegex = Pattern.compile(metaRegexText); |
| | | |
| | | private static final int metaRegexIndexSHA = 1; |
| | | |
| | | private static final int metaRegexIndexSize = 2; |
| | | |
| | | public final String oid; |
| | | |
| | | private Long size; |
| | | private Status status; |
| | | |
| | | //Audit |
| | | private String stateChangedBy; |
| | | private Date stateChangedOn; |
| | | |
| | | //Access Control |
| | | private List<String> repositories; |
| | | |
| | | public FilestoreModel(String id, long definedSize) { |
| | | oid = id; |
| | | size = definedSize; |
| | | status = Status.ReferenceOnly; |
| | | } |
| | | |
| | | public FilestoreModel(String id, long expectedSize, UserModel user, String repo) { |
| | | oid = id; |
| | | size = expectedSize; |
| | | status = Status.Upload_Pending; |
| | | stateChangedBy = user.getName(); |
| | | stateChangedOn = new Date(); |
| | | repositories = new ArrayList<String>(); |
| | | repositories.add(repo); |
| | | } |
| | | |
| | | /* |
| | | * Attempts to create a FilestoreModel from the given meta string |
| | | * |
| | | * @return A valid FilestoreModel if successful, otherwise null |
| | | */ |
| | | public static FilestoreModel fromMetaString(String meta) { |
| | | |
| | | Matcher m = metaRegex.matcher(meta); |
| | | |
| | | if (m.find()) { |
| | | try |
| | | { |
| | | final Long size = Long.parseLong(m.group(metaRegexIndexSize)); |
| | | final String sha = m.group(metaRegexIndexSHA); |
| | | return new FilestoreModel(sha, size); |
| | | } catch (Exception e) { |
| | | //Fail silent - it is not a valid filestore item |
| | | } |
| | | } |
| | | |
| | | return null; |
| | | } |
| | | |
| | | public synchronized long getSize() { |
| | | return size; |
| | | } |
| | | |
| | | public synchronized Status getStatus() { |
| | | return status; |
| | | } |
| | | |
| | | public synchronized String getChangedBy() { |
| | | return stateChangedBy; |
| | | } |
| | | |
| | | public synchronized Date getChangedOn() { |
| | | return stateChangedOn; |
| | | } |
| | | |
| | | public synchronized void setStatus(Status status, UserModel user) { |
| | | this.status = status; |
| | | stateChangedBy = user.getName(); |
| | | stateChangedOn = new Date(); |
| | | } |
| | | |
| | | public synchronized void reset(UserModel user, long size) { |
| | | status = Status.Upload_Pending; |
| | | stateChangedBy = user.getName(); |
| | | stateChangedOn = new Date(); |
| | | this.size = size; |
| | | } |
| | | |
| | | /* |
| | | * Handles possible race condition with concurrent connections |
| | | * @return true if action can proceed, false otherwise |
| | | */ |
| | | public synchronized boolean actionUpload(UserModel user) { |
| | | if (status == Status.Upload_Pending) { |
| | | status = Status.Upload_In_Progress; |
| | | stateChangedBy = user.getName(); |
| | | stateChangedOn = new Date(); |
| | | return true; |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | public synchronized boolean isInErrorState() { |
| | | return (this.status.value < 0); |
| | | } |
| | | |
| | | public synchronized void addRepository(String repo) { |
| | | if (status != Status.ReferenceOnly) { |
| | | if (!repositories.contains(repo)) { |
| | | repositories.add(repo); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public synchronized void removeRepository(String repo) { |
| | | if (status != Status.ReferenceOnly) { |
| | | repositories.remove(repo); |
| | | } |
| | | } |
| | | |
| | | public synchronized boolean isInRepositoryList(List<String> repoList) { |
| | | if (status != Status.ReferenceOnly) { |
| | | for (String name : repositories) { |
| | | if (repoList.contains(name)) { |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | public static enum Status { |
| | | |
| | | ReferenceOnly(-42), |
| | | |
| | | Deleted(-30), |
| | | AuthenticationRequired(-20), |
| | | |
| | | Error_Unknown(-8), |
| | | Error_Unexpected_Stream_End(-7), |
| | | Error_Invalid_Oid(-6), |
| | | Error_Invalid_Size(-5), |
| | | Error_Hash_Mismatch(-4), |
| | | Error_Size_Mismatch(-3), |
| | | Error_Exceeds_Size_Limit(-2), |
| | | Error_Unauthorized(-1), |
| | | //Negative values provide additional information and may be treated as 0 when not required |
| | | Unavailable(0), |
| | | Upload_Pending(1), |
| | | Upload_In_Progress(2), |
| | | Available(3); |
| | | |
| | | final int value; |
| | | |
| | | Status(int value) { |
| | | this.value = value; |
| | | } |
| | | |
| | | public int getValue() { |
| | | return value; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return name().toLowerCase().replace('_', ' '); |
| | | } |
| | | |
| | | public static Status fromState(int state) { |
| | | for (Status s : values()) { |
| | | if (s.getValue() == state) { |
| | | return s; |
| | | } |
| | | } |
| | | throw new NoSuchElementException(String.valueOf(state)); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public int compareTo(FilestoreModel o) { |
| | | return this.oid.compareTo(o.oid); |
| | | } |
| | | |
| | | } |
| | | |
| | |
| | | */
|
| | | package com.gitblit.models;
|
| | |
|
| | | import java.io.IOException;
|
| | | import java.io.Serializable;
|
| | |
|
| | | import org.eclipse.jgit.diff.DiffEntry;
|
| | | import org.eclipse.jgit.diff.DiffEntry.ChangeType;
|
| | | import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
| | | import org.eclipse.jgit.errors.MissingObjectException;
|
| | | import org.eclipse.jgit.lib.Constants;
|
| | | import org.eclipse.jgit.lib.FileMode;
|
| | | import org.eclipse.jgit.lib.Repository;
|
| | | import org.eclipse.jgit.revwalk.RevWalk;
|
| | |
|
| | | import com.gitblit.manager.FilestoreManager;
|
| | | import com.gitblit.utils.JGitUtils;
|
| | |
|
| | | /**
|
| | | * PathModel is a serializable model class that represents a file or a folder,
|
| | |
| | |
|
| | | public final String name;
|
| | | public final String path;
|
| | | private final FilestoreModel filestoreItem;
|
| | | public final long size;
|
| | | public final int mode;
|
| | | public final String objectId;
|
| | | public final String commitId;
|
| | | public boolean isParentPath;
|
| | |
|
| | | public PathModel(String name, String path, long size, int mode, String objectId, String commitId) {
|
| | | |
| | | public PathModel(String name, String path, FilestoreModel filestoreItem, long size, int mode, String objectId, String commitId) {
|
| | | this.name = name;
|
| | | this.path = path;
|
| | | this.size = size;
|
| | | this.filestoreItem = filestoreItem;
|
| | | this.size = (filestoreItem == null) ? size : filestoreItem.getSize();
|
| | | this.mode = mode;
|
| | | this.objectId = objectId;
|
| | | this.commitId = commitId;
|
| | |
| | | return FileMode.REGULAR_FILE.equals(mode)
|
| | | || FileMode.EXECUTABLE_FILE.equals(mode)
|
| | | || (FileMode.MISSING.equals(mode) && !isSymlink() && !isSubmodule() && !isTree());
|
| | | }
|
| | | |
| | | public boolean isFilestoreItem() {
|
| | | return filestoreItem != null;
|
| | | }
|
| | | |
| | | public String getFilestoreOid() {
|
| | | if (filestoreItem != null) {
|
| | | return filestoreItem.oid;
|
| | | }
|
| | | |
| | | return null;
|
| | | }
|
| | |
|
| | | @Override
|
| | |
| | |
|
| | | public int deletions;
|
| | |
|
| | | public PathChangeModel(String name, String path, long size, int mode, String objectId,
|
| | | public PathChangeModel(String name, String path, FilestoreModel filestoreItem, long size, int mode, String objectId,
|
| | | String commitId, ChangeType type) {
|
| | | super(name, path, size, mode, objectId, commitId);
|
| | | super(name, path, filestoreItem, size, mode, objectId, commitId);
|
| | | this.changeType = type;
|
| | | }
|
| | |
|
| | |
| | | return super.equals(o);
|
| | | }
|
| | |
|
| | | public static PathChangeModel from(DiffEntry diff, String commitId) {
|
| | | public static PathChangeModel from(DiffEntry diff, String commitId, Repository repository) {
|
| | | PathChangeModel pcm;
|
| | | FilestoreModel filestoreItem = null;
|
| | | long size = 0;
|
| | |
|
| | | if (repository != null) {
|
| | | try (RevWalk revWalk = new RevWalk(repository)) {
|
| | | size = revWalk.getObjectReader().getObjectSize(diff.getNewId().toObjectId(), Constants.OBJ_BLOB);
|
| | | |
| | | if (JGitUtils.isPossibleFilestoreItem(size)) {
|
| | | filestoreItem = JGitUtils.getFilestoreItem(revWalk.getObjectReader().open(diff.getNewId().toObjectId()));
|
| | | }
|
| | | } catch (Exception e) {
|
| | | e.printStackTrace();
|
| | | }
|
| | | }
|
| | | |
| | | if (diff.getChangeType().equals(ChangeType.DELETE)) {
|
| | | pcm = new PathChangeModel(diff.getOldPath(), diff.getOldPath(), 0, diff
|
| | | pcm = new PathChangeModel(diff.getOldPath(), diff.getOldPath(), filestoreItem, size, diff
|
| | | .getNewMode().getBits(), diff.getOldId().name(), commitId, diff
|
| | | .getChangeType());
|
| | | } else if (diff.getChangeType().equals(ChangeType.RENAME)) {
|
| | | pcm = new PathChangeModel(diff.getOldPath(), diff.getNewPath(), 0, diff
|
| | | pcm = new PathChangeModel(diff.getOldPath(), diff.getNewPath(), filestoreItem, size, diff
|
| | | .getNewMode().getBits(), diff.getNewId().name(), commitId, diff
|
| | | .getChangeType());
|
| | | } else {
|
| | | pcm = new PathChangeModel(diff.getNewPath(), diff.getNewPath(), 0, diff
|
| | | pcm = new PathChangeModel(diff.getNewPath(), diff.getNewPath(), filestoreItem, size, diff
|
| | | .getNewMode().getBits(), diff.getNewId().name(), commitId, diff
|
| | | .getChangeType());
|
| | | }
|
| | |
| | | }
|
| | | } else if (referencedObject instanceof RevCommit) {
|
| | | RevCommit commit = (RevCommit) referencedObject;
|
| | | PersonIdent committer = commit.getCommitterIdent();
|
| | | if (committer != null) {
|
| | | date = committer.getWhen();
|
| | | } else {
|
| | | date = JGitUtils.getCommitDate(commit);
|
| | | }
|
| | | date = JGitUtils.getAuthorDate(commit);
|
| | | }
|
| | | }
|
| | | return date;
|
| | |
| | | this.permission = permission;
|
| | | }
|
| | |
|
| | | public boolean isExternal() {
|
| | | return permission == null;
|
| | | public boolean hasPermission() {
|
| | | return permission != null;
|
| | | }
|
| | |
|
| | | @Override
|
| | |
| | | |
| | | public Integer deletions; |
| | | |
| | | public Priority priority; |
| | | |
| | | public Severity severity; |
| | | |
| | | /** |
| | | * Builds an effective ticket from the collection of changes. A change may |
| | | * Add or Subtract information from a ticket, but the collection of changes |
| | |
| | | TicketModel ticket; |
| | | List<Change> effectiveChanges = new ArrayList<Change>(); |
| | | Map<String, Change> comments = new HashMap<String, Change>(); |
| | | Map<Integer, Integer> latestRevisions = new HashMap<Integer, Integer>(); |
| | | |
| | | int latestPatchsetNumber = -1; |
| | | |
| | | List<Integer> deletedPatchsets = new ArrayList<Integer>(); |
| | | |
| | | for (Change change : changes) { |
| | | if (change.patchset != null) { |
| | | if (change.patchset.isDeleted()) { |
| | | deletedPatchsets.add(change.patchset.number); |
| | | } else { |
| | | Integer latestRev = latestRevisions.get(change.patchset.number); |
| | | |
| | | if (latestRev == null || change.patchset.rev > latestRev) { |
| | | latestRevisions.put(change.patchset.number, change.patchset.rev); |
| | | } |
| | | |
| | | if (change.patchset.number > latestPatchsetNumber) { |
| | | latestPatchsetNumber = change.patchset.number; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | for (Change change : changes) { |
| | | if (change.comment != null) { |
| | | if (comments.containsKey(change.comment.id)) { |
| | |
| | | } else { |
| | | effectiveChanges.add(change); |
| | | comments.put(change.comment.id, change); |
| | | } |
| | | } else if (change.patchset != null) { |
| | | //All revisions of a deleted patchset are not displayed |
| | | if (!deletedPatchsets.contains(change.patchset.number)) { |
| | | |
| | | Integer latestRev = latestRevisions.get(change.patchset.number); |
| | | |
| | | if ( (change.patchset.number < latestPatchsetNumber) |
| | | && (change.patchset.rev == latestRev)) { |
| | | change.patchset.canDelete = true; |
| | | } |
| | | |
| | | effectiveChanges.add(change); |
| | | } |
| | | } else { |
| | | effectiveChanges.add(change); |
| | |
| | | changes = new ArrayList<Change>(); |
| | | status = Status.New; |
| | | type = Type.defaultType; |
| | | priority = Priority.defaultPriority; |
| | | severity = Severity.defaultSeverity; |
| | | } |
| | | |
| | | public boolean isOpen() { |
| | |
| | | break; |
| | | case mergeSha: |
| | | mergeSha = toString(value); |
| | | break; |
| | | case priority: |
| | | priority = TicketModel.Priority.fromObject(value, priority); |
| | | break; |
| | | case severity: |
| | | severity = TicketModel.Severity.fromObject(value, severity); |
| | | break; |
| | | default: |
| | | // unknown |
| | |
| | | public int added; |
| | | public PatchsetType type; |
| | | |
| | | public transient boolean canDelete = false; |
| | | |
| | | public boolean isFF() { |
| | | return PatchsetType.FastForward == type; |
| | | } |
| | | |
| | | public boolean isDeleted() { |
| | | return PatchsetType.Delete == type; |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | public static enum Field { |
| | | title, body, responsible, type, status, milestone, mergeSha, mergeTo, |
| | | topic, labels, watchers, reviewers, voters, mentions; |
| | | topic, labels, watchers, reviewers, voters, mentions, priority, severity; |
| | | } |
| | | |
| | | public static enum Type { |
| | | Enhancement, Task, Bug, Proposal, Question; |
| | | Enhancement, Task, Bug, Proposal, Question, Maintenance; |
| | | |
| | | public static Type defaultType = Task; |
| | | |
| | | public static Type [] choices() { |
| | | return new Type [] { Enhancement, Task, Bug, Question }; |
| | | return new Type [] { Enhancement, Task, Bug, Question, Maintenance }; |
| | | } |
| | | |
| | | @Override |
| | |
| | | } |
| | | |
| | | public static enum PatchsetType { |
| | | Proposal, FastForward, Rebase, Squash, Rebase_Squash, Amend; |
| | | Proposal, FastForward, Rebase, Squash, Rebase_Squash, Amend, Delete; |
| | | |
| | | public boolean isRewrite() { |
| | | return (this != FastForward) && (this != Proposal); |
| | |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | public static enum Priority { |
| | | Low(-1), Normal(0), High(1), Urgent(2); |
| | | |
| | | public static Priority defaultPriority = Normal; |
| | | |
| | | final int value; |
| | | |
| | | Priority(int value) { |
| | | this.value = value; |
| | | } |
| | | |
| | | public int getValue() { |
| | | return value; |
| | | } |
| | | |
| | | public static Priority [] choices() { |
| | | return new Priority [] { Urgent, High, Normal, Low }; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return name().toLowerCase().replace('_', ' '); |
| | | } |
| | | |
| | | public static Priority fromObject(Object o, Priority defaultPriority) { |
| | | if (o instanceof Priority) { |
| | | // cast and return |
| | | return (Priority) o; |
| | | } else if (o instanceof String) { |
| | | // find by name |
| | | for (Priority priority : values()) { |
| | | String str = o.toString(); |
| | | if (priority.name().equalsIgnoreCase(str) |
| | | || priority.toString().equalsIgnoreCase(str)) { |
| | | return priority; |
| | | } |
| | | } |
| | | } else if (o instanceof Number) { |
| | | |
| | | switch (((Number) o).intValue()) { |
| | | case -1: return Priority.Low; |
| | | case 0: return Priority.Normal; |
| | | case 1: return Priority.High; |
| | | case 2: return Priority.Urgent; |
| | | default: return Priority.Normal; |
| | | } |
| | | } |
| | | |
| | | return defaultPriority; |
| | | } |
| | | } |
| | | |
| | | public static enum Severity { |
| | | Unrated(-1), Negligible(1), Minor(2), Serious(3), Critical(4), Catastrophic(5); |
| | | |
| | | public static Severity defaultSeverity = Unrated; |
| | | |
| | | final int value; |
| | | |
| | | Severity(int value) { |
| | | this.value = value; |
| | | } |
| | | |
| | | public int getValue() { |
| | | return value; |
| | | } |
| | | |
| | | public static Severity [] choices() { |
| | | return new Severity [] { Unrated, Negligible, Minor, Serious, Critical, Catastrophic }; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return name().toLowerCase().replace('_', ' '); |
| | | } |
| | | |
| | | public static Severity fromObject(Object o, Severity defaultSeverity) { |
| | | if (o instanceof Severity) { |
| | | // cast and return |
| | | return (Severity) o; |
| | | } else if (o instanceof String) { |
| | | // find by name |
| | | for (Severity severity : values()) { |
| | | String str = o.toString(); |
| | | if (severity.name().equalsIgnoreCase(str) |
| | | || severity.toString().equalsIgnoreCase(str)) { |
| | | return severity; |
| | | } |
| | | } |
| | | } else if (o instanceof Number) { |
| | | |
| | | switch (((Number) o).intValue()) { |
| | | case -1: return Severity.Unrated; |
| | | case 1: return Severity.Negligible; |
| | | case 2: return Severity.Minor; |
| | | case 3: return Severity.Serious; |
| | | case 4: return Severity.Critical; |
| | | case 5: return Severity.Catastrophic; |
| | | default: return Severity.Unrated; |
| | | } |
| | | } |
| | | |
| | | return defaultSeverity; |
| | | } |
| | | } |
| | | } |
| | |
| | | public class LuceneService implements Runnable {
|
| | |
|
| | |
|
| | | private static final int INDEX_VERSION = 5;
|
| | | private static final int INDEX_VERSION = 6;
|
| | |
|
| | | private static final String FIELD_OBJECT_TYPE = "type";
|
| | | private static final String FIELD_PATH = "path";
|
| | |
| | | private static final String CONF_ALIAS = "aliases";
|
| | | private static final String CONF_BRANCH = "branches";
|
| | |
|
| | | private static final Version LUCENE_VERSION = Version.LUCENE_46;
|
| | | private static final Version LUCENE_VERSION = Version.LUCENE_4_10_0;
|
| | |
|
| | | private final Logger logger = LoggerFactory.getLogger(LuceneService.class);
|
| | |
|
| | |
| | | // skip non-annotated tags
|
| | | continue;
|
| | | }
|
| | | if (!tags.containsKey(tag.getObjectId().getName())) {
|
| | | if (!tags.containsKey(tag.getReferencedObjectId().getName())) {
|
| | | tags.put(tag.getReferencedObjectId().getName(), new ArrayList<String>());
|
| | | }
|
| | | tags.get(tag.getReferencedObjectId().getName()).add(tag.displayName);
|
| | |
| | | }
|
| | |
|
| | | // finished
|
| | | reader.release();
|
| | | reader.close();
|
| | |
|
| | | // commit all changes and reset the searcher
|
| | | config.setInt(CONF_INDEX, null, CONF_VERSION, INDEX_VERSION);
|
| | |
| | | content = "";
|
| | | }
|
| | |
|
| | | int tabLength = storedSettings.getInteger(Keys.web.tabLength, 4);
|
| | | int fragmentLength = SearchObjectType.commit == result.type ? 512 : 150;
|
| | |
|
| | | QueryScorer scorer = new QueryScorer(query, "content");
|
| | |
| | | if (fragment.length() > fragmentLength) {
|
| | | fragment = fragment.substring(0, fragmentLength) + "...";
|
| | | }
|
| | | return "<pre class=\"text\">" + StringUtils.escapeForHtml(fragment, true) + "</pre>";
|
| | | return "<pre class=\"text\">" + StringUtils.escapeForHtml(fragment, true, tabLength) + "</pre>";
|
| | | }
|
| | |
|
| | | // make sure we have unique fragments
|
| | |
| | | import javax.mail.internet.MimeBodyPart;
|
| | | import javax.mail.internet.MimeMessage;
|
| | | import javax.mail.internet.MimeMultipart;
|
| | | import javax.mail.internet.MimeUtility;
|
| | |
|
| | | import org.slf4j.Logger;
|
| | | import org.slf4j.LoggerFactory;
|
| | |
| | | }
|
| | |
|
| | | message.setSentDate(new Date());
|
| | | message.setSubject(mailing.subject);
|
| | | // UTF-8 encode
|
| | | message.setSubject(MimeUtility.encodeText(mailing.subject, "utf-8", "B"));
|
| | |
|
| | | MimeBodyPart messagePart = new MimeBodyPart();
|
| | | messagePart.setText(mailing.content, "utf-8");
|
New file |
| | |
| | | /* |
| | | * Copyright 2015 Jean-Baptiste Mayer |
| | | * |
| | | * 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.servlet; |
| | | |
| | | import java.io.IOException; |
| | | |
| | | import javax.servlet.ServletException; |
| | | import javax.servlet.http.HttpServlet; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Access-denied Servlet. |
| | | * |
| | | * This servlet serves only 404 Not Found error replies. |
| | | * |
| | | * This servlet is used to override the container's default behavior to serve |
| | | * all contents of the application's WAR. We can selectively prevent access to |
| | | * a specific path simply by mapping this servlet onto specific paths. |
| | | * |
| | | * |
| | | * @author Jean-Baptiste Mayer |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class AccessDeniedServlet extends HttpServlet { |
| | | /** |
| | | * |
| | | */ |
| | | private static final long serialVersionUID = -3239463647917811122L; |
| | | |
| | | @Override |
| | | protected void doPost(HttpServletRequest request, HttpServletResponse response) |
| | | throws ServletException, java.io.IOException { |
| | | processRequest(request, response); |
| | | } |
| | | |
| | | @Override |
| | | protected void doGet(HttpServletRequest request, HttpServletResponse response) |
| | | throws ServletException, IOException { |
| | | processRequest(request, response); |
| | | } |
| | | |
| | | private void processRequest(HttpServletRequest request, |
| | | HttpServletResponse response) { |
| | | response.setStatus(HttpServletResponse.SC_NOT_FOUND); |
| | | } |
| | | } |
| | |
| | |
|
| | | import java.io.IOException;
|
| | | import java.text.MessageFormat;
|
| | | import java.util.Collections;
|
| | | import java.util.Iterator;
|
| | |
|
| | | import javax.servlet.FilterChain;
|
| | | import javax.servlet.FilterConfig;
|
| | | import javax.servlet.ServletException;
|
| | | import javax.servlet.ServletRequest;
|
| | | import javax.servlet.ServletResponse;
|
| | | import javax.servlet.http.HttpServletRequest;
|
| | | import javax.servlet.http.HttpServletResponse;
|
| | |
|
| | | import com.gitblit.manager.IAuthenticationManager;
|
| | | import com.gitblit.manager.IRepositoryManager;
|
| | | import com.gitblit.manager.IRuntimeManager;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.models.UserModel;
|
| | | import com.gitblit.utils.StringUtils;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | |
|
| | | /**
|
| | | * The AccessRestrictionFilter is an AuthenticationFilter that confirms that the
|
| | |
| | |
|
| | | protected IRepositoryManager repositoryManager;
|
| | |
|
| | | @Override
|
| | | protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
|
| | | super.inject(dagger, filterConfig);
|
| | | this.runtimeManager = dagger.get(IRuntimeManager.class);
|
| | | this.repositoryManager = dagger.get(IRepositoryManager.class);
|
| | | protected AccessRestrictionFilter(
|
| | | IRuntimeManager runtimeManager,
|
| | | IAuthenticationManager authenticationManager,
|
| | | IRepositoryManager repositoryManager) {
|
| | |
|
| | | super(authenticationManager);
|
| | |
|
| | | this.runtimeManager = runtimeManager;
|
| | | this.repositoryManager = repositoryManager;
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | *
|
| | | * @return true if the filter allows repository creation
|
| | | */
|
| | | protected abstract boolean isCreationAllowed();
|
| | | protected abstract boolean isCreationAllowed(String action);
|
| | |
|
| | | /**
|
| | | * Determine if the action may be executed on the repository.
|
| | | *
|
| | | * @param repository
|
| | | * @param action
|
| | | * @param method
|
| | | * @return true if the action may be performed
|
| | | */
|
| | | protected abstract boolean isActionAllowed(RepositoryModel repository, String action);
|
| | | protected abstract boolean isActionAllowed(RepositoryModel repository, String action, String method);
|
| | |
|
| | | /**
|
| | | * Determine if the repository requires authentication.
|
| | |
| | | * @param action
|
| | | * @return true if authentication required
|
| | | */
|
| | | protected abstract boolean requiresAuthentication(RepositoryModel repository, String action);
|
| | | protected abstract boolean requiresAuthentication(RepositoryModel repository, String action, String method);
|
| | |
|
| | | /**
|
| | | * Determine if the user can access the repository and perform the specified
|
| | |
| | | protected RepositoryModel createRepository(UserModel user, String repository, String action) {
|
| | | return null;
|
| | | }
|
| | |
|
| | | |
| | | /**
|
| | | * Allows authentication header to be altered based on the action requested
|
| | | * Default is WWW-Authenticate
|
| | | * @param httpRequest
|
| | | * @param action
|
| | | * @return authentication type header
|
| | | */
|
| | | protected String getAuthenticationHeader(HttpServletRequest httpRequest, String action) {
|
| | | return "WWW-Authenticate";
|
| | | }
|
| | | |
| | | /**
|
| | | * Allows request headers to be used as part of filtering
|
| | | * @param request
|
| | | * @return true (default) if headers are valid, false otherwise
|
| | | */
|
| | | protected boolean hasValidRequestHeader(String action, HttpServletRequest request) {
|
| | | return true;
|
| | | }
|
| | | |
| | | /**
|
| | | * doFilter does the actual work of preprocessing the request to ensure that
|
| | | * the user may proceed.
|
| | |
| | | // Load the repository model
|
| | | RepositoryModel model = repositoryManager.getRepositoryModel(repository);
|
| | | if (model == null) {
|
| | | if (isCreationAllowed()) {
|
| | | if (isCreationAllowed(urlRequestType)) {
|
| | | if (user == null) {
|
| | | // challenge client to provide credentials for creation. send 401.
|
| | | if (runtimeManager.isDebugMode()) {
|
| | | logger.info(MessageFormat.format("ARF: CREATE CHALLENGE {0}", fullUrl));
|
| | | }
|
| | | httpResponse.setHeader("WWW-Authenticate", CHALLENGE);
|
| | | |
| | | httpResponse.setHeader(getAuthenticationHeader(httpRequest, urlRequestType), CHALLENGE);
|
| | | httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
| | | return;
|
| | | } else {
|
| | |
| | | }
|
| | |
|
| | | // Confirm that the action may be executed on the repository
|
| | | if (!isActionAllowed(model, urlRequestType)) {
|
| | | if (!isActionAllowed(model, urlRequestType, httpRequest.getMethod())) {
|
| | | logger.info(MessageFormat.format("ARF: action {0} on {1} forbidden ({2})",
|
| | | urlRequestType, model, HttpServletResponse.SC_FORBIDDEN));
|
| | | httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
|
| | |
| | | }
|
| | |
|
| | | // BASIC authentication challenge and response processing
|
| | | if (!StringUtils.isEmpty(urlRequestType) && requiresAuthentication(model, urlRequestType)) {
|
| | | if (!StringUtils.isEmpty(urlRequestType) && requiresAuthentication(model, urlRequestType, httpRequest.getMethod())) {
|
| | | if (user == null) {
|
| | | // challenge client to provide credentials. send 401.
|
| | | if (runtimeManager.isDebugMode()) {
|
| | | logger.info(MessageFormat.format("ARF: CHALLENGE {0}", fullUrl));
|
| | | }
|
| | | httpResponse.setHeader("WWW-Authenticate", CHALLENGE);
|
| | | httpResponse.setHeader(getAuthenticationHeader(httpRequest, urlRequestType), CHALLENGE);
|
| | | httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
| | | return;
|
| | | } else {
|
| | |
| | | // authenticated request permitted.
|
| | | // pass processing to the restricted servlet.
|
| | | newSession(authenticatedRequest, httpResponse);
|
| | | logger.info(MessageFormat.format("ARF: {0} ({1}) authenticated", fullUrl,
|
| | | HttpServletResponse.SC_CONTINUE));
|
| | | logger.info(MessageFormat.format("ARF: authenticated {0} to {1} ({2})", user.username,
|
| | | fullUrl, HttpServletResponse.SC_CONTINUE));
|
| | | chain.doFilter(authenticatedRequest, httpResponse);
|
| | | return;
|
| | | }
|
| | |
| | | // pass processing to the restricted servlet.
|
| | | chain.doFilter(authenticatedRequest, httpResponse);
|
| | | }
|
| | | |
| | | public static boolean hasContentInRequestHeader(HttpServletRequest request, String headerName, String content)
|
| | | {
|
| | | Iterator<String> headerItr = Collections.list(request.getHeaders(headerName)).iterator();
|
| | | |
| | | while (headerItr.hasNext()) {
|
| | | if (headerItr.next().contains(content)) {
|
| | | return true;
|
| | | }
|
| | | }
|
| | |
|
| | | return false;
|
| | | }
|
| | | } |
| | |
| | | /*
|
| | | * 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.servlet;
|
| | |
|
| | | import java.io.IOException;
|
| | | import java.security.Principal;
|
| | | import java.util.Enumeration;
|
| | | import java.util.HashMap;
|
| | | import java.util.Map;
|
| | |
|
| | | import javax.servlet.FilterChain;
|
| | | import javax.servlet.FilterConfig;
|
| | | import javax.servlet.ServletException;
|
| | | import javax.servlet.ServletRequest;
|
| | | import javax.servlet.ServletResponse;
|
| | | import javax.servlet.http.HttpServletRequest;
|
| | | import javax.servlet.http.HttpServletRequestWrapper;
|
| | | import javax.servlet.http.HttpServletResponse;
|
| | | import javax.servlet.http.HttpSession;
|
| | |
|
| | | import org.slf4j.Logger;
|
| | | import org.slf4j.LoggerFactory;
|
| | |
|
| | | import com.gitblit.Constants;
|
| | | import com.gitblit.dagger.DaggerFilter;
|
| | | import com.gitblit.manager.IAuthenticationManager;
|
| | | import com.gitblit.models.UserModel;
|
| | | import com.gitblit.utils.DeepCopier;
|
| | | import com.gitblit.utils.StringUtils;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | |
|
| | | /**
|
| | | * The AuthenticationFilter is a servlet filter that preprocesses requests that
|
| | | * match its url pattern definition in the web.xml file.
|
| | | *
|
| | | * http://en.wikipedia.org/wiki/Basic_access_authentication
|
| | | *
|
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | public abstract class AuthenticationFilter extends DaggerFilter {
|
| | |
|
| | | protected static final String CHALLENGE = "Basic realm=\"" + Constants.NAME + "\"";
|
| | |
|
| | | protected static final String SESSION_SECURED = "com.gitblit.secured";
|
| | |
|
| | | protected transient Logger logger = LoggerFactory.getLogger(getClass());
|
| | |
|
| | | protected IAuthenticationManager authenticationManager;
|
| | |
|
| | | @Override
|
| | | protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
|
| | | this.authenticationManager = dagger.get(IAuthenticationManager.class);
|
| | | }
|
| | |
|
| | | /**
|
| | | * doFilter does the actual work of preprocessing the request to ensure that
|
| | | * the user may proceed.
|
| | | *
|
| | | * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
|
| | | * javax.servlet.ServletResponse, javax.servlet.FilterChain)
|
| | | */
|
| | | @Override
|
| | | public abstract void doFilter(final ServletRequest request, final ServletResponse response,
|
| | | final FilterChain chain) throws IOException, ServletException;
|
| | |
|
| | | /**
|
| | | * Allow the filter to require a client certificate to continue processing.
|
| | | *
|
| | | * @return true, if a client certificate is required
|
| | | */
|
| | | protected boolean requiresClientCertificate() {
|
| | | return false;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the full relative url of the request.
|
| | | *
|
| | | * @param httpRequest
|
| | | * @return url
|
| | | */
|
| | | protected String getFullUrl(HttpServletRequest httpRequest) {
|
| | | String servletUrl = httpRequest.getContextPath() + httpRequest.getServletPath();
|
| | | String url = httpRequest.getRequestURI().substring(servletUrl.length());
|
| | | String params = httpRequest.getQueryString();
|
| | | if (url.length() > 0 && url.charAt(0) == '/') {
|
| | | url = url.substring(1);
|
| | | }
|
| | | String fullUrl = url + (StringUtils.isEmpty(params) ? "" : ("?" + params));
|
| | | return fullUrl;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the user making the request, if the user has authenticated.
|
| | | *
|
| | | * @param httpRequest
|
| | | * @return user
|
| | | */
|
| | | protected UserModel getUser(HttpServletRequest httpRequest) {
|
| | | UserModel user = authenticationManager.authenticate(httpRequest, requiresClientCertificate());
|
| | | return user;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Taken from Jetty's LoginAuthenticator.renewSessionOnAuthentication()
|
| | | */
|
| | | protected void newSession(HttpServletRequest request, HttpServletResponse response) {
|
| | | HttpSession oldSession = request.getSession(false);
|
| | | if (oldSession != null && oldSession.getAttribute(SESSION_SECURED) == null) {
|
| | | synchronized (this) {
|
| | | Map<String, Object> attributes = new HashMap<String, Object>();
|
| | | Enumeration<String> e = oldSession.getAttributeNames();
|
| | | while (e.hasMoreElements()) {
|
| | | String name = e.nextElement();
|
| | | attributes.put(name, oldSession.getAttribute(name));
|
| | | oldSession.removeAttribute(name);
|
| | | }
|
| | | oldSession.invalidate();
|
| | |
|
| | | HttpSession newSession = request.getSession(true);
|
| | | newSession.setAttribute(SESSION_SECURED, Boolean.TRUE);
|
| | | for (Map.Entry<String, Object> entry : attributes.entrySet()) {
|
| | | newSession.setAttribute(entry.getKey(), entry.getValue());
|
| | | }
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | /**
|
| | | * Wraps a standard HttpServletRequest and overrides user principal methods.
|
| | | */
|
| | | public static class AuthenticatedRequest extends HttpServletRequestWrapper {
|
| | |
|
| | | private UserModel user;
|
| | |
|
| | | public AuthenticatedRequest(HttpServletRequest req) {
|
| | | super(req);
|
| | | user = DeepCopier.copy(UserModel.ANONYMOUS);
|
| | | }
|
| | |
|
| | | UserModel getUser() {
|
| | | return user;
|
| | | }
|
| | |
|
| | | void setUser(UserModel user) {
|
| | | this.user = user;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public String getRemoteUser() {
|
| | | return user.username;
|
| | | }
|
| | |
|
| | | @Override
|
| | | public boolean isUserInRole(String role) {
|
| | | if (role.equals(Constants.ADMIN_ROLE)) {
|
| | | return user.canAdmin();
|
| | | }
|
| | | // Gitblit does not currently use actual roles in the traditional
|
| | | // servlet container sense. That is the reason this is marked
|
| | | // deprecated, but I may want to revisit this.
|
| | | return user.hasRepositoryPermission(role);
|
| | | }
|
| | |
|
| | | @Override
|
| | | public Principal getUserPrincipal() {
|
| | | return user;
|
| | | }
|
| | | }
|
| | | }
|
| | | /* |
| | | * 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.servlet; |
| | | |
| | | import java.io.IOException; |
| | | import java.security.Principal; |
| | | import java.util.Enumeration; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | import javax.servlet.Filter; |
| | | import javax.servlet.FilterChain; |
| | | import javax.servlet.FilterConfig; |
| | | import javax.servlet.ServletException; |
| | | import javax.servlet.ServletRequest; |
| | | import javax.servlet.ServletResponse; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletRequestWrapper; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import javax.servlet.http.HttpSession; |
| | | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.Constants.Role; |
| | | import com.gitblit.manager.IAuthenticationManager; |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.utils.DeepCopier; |
| | | import com.gitblit.utils.StringUtils; |
| | | |
| | | /** |
| | | * The AuthenticationFilter is a servlet filter that preprocesses requests that |
| | | * match its url pattern definition in the web.xml file. |
| | | * |
| | | * http://en.wikipedia.org/wiki/Basic_access_authentication |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | public abstract class AuthenticationFilter implements Filter { |
| | | |
| | | protected static final String CHALLENGE = "Basic realm=\"" + Constants.NAME + "\""; |
| | | |
| | | protected static final String SESSION_SECURED = "com.gitblit.secured"; |
| | | |
| | | protected transient Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | protected IAuthenticationManager authenticationManager; |
| | | |
| | | protected AuthenticationFilter(IAuthenticationManager authenticationManager) { |
| | | this.authenticationManager = authenticationManager; |
| | | } |
| | | |
| | | @Override |
| | | public void init(FilterConfig filterConfig) throws ServletException { |
| | | } |
| | | |
| | | @Override |
| | | public void destroy() { |
| | | } |
| | | |
| | | /** |
| | | * doFilter does the actual work of preprocessing the request to ensure that |
| | | * the user may proceed. |
| | | * |
| | | * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, |
| | | * javax.servlet.ServletResponse, javax.servlet.FilterChain) |
| | | */ |
| | | @Override |
| | | public abstract void doFilter(final ServletRequest request, final ServletResponse response, |
| | | final FilterChain chain) throws IOException, ServletException; |
| | | |
| | | /** |
| | | * Allow the filter to require a client certificate to continue processing. |
| | | * |
| | | * @return true, if a client certificate is required |
| | | */ |
| | | protected boolean requiresClientCertificate() { |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * Returns the full relative url of the request. |
| | | * |
| | | * @param httpRequest |
| | | * @return url |
| | | */ |
| | | protected String getFullUrl(HttpServletRequest httpRequest) { |
| | | String servletUrl = httpRequest.getContextPath() + httpRequest.getServletPath(); |
| | | String url = httpRequest.getRequestURI().substring(servletUrl.length()); |
| | | String params = httpRequest.getQueryString(); |
| | | if (url.length() > 0 && url.charAt(0) == '/') { |
| | | url = url.substring(1); |
| | | } |
| | | String fullUrl = url + (StringUtils.isEmpty(params) ? "" : ("?" + params)); |
| | | return fullUrl; |
| | | } |
| | | |
| | | /** |
| | | * Returns the user making the request, if the user has authenticated. |
| | | * |
| | | * @param httpRequest |
| | | * @return user |
| | | */ |
| | | protected UserModel getUser(HttpServletRequest httpRequest) { |
| | | UserModel user = authenticationManager.authenticate(httpRequest, requiresClientCertificate()); |
| | | return user; |
| | | } |
| | | |
| | | /** |
| | | * Taken from Jetty's LoginAuthenticator.renewSessionOnAuthentication() |
| | | */ |
| | | protected void newSession(HttpServletRequest request, HttpServletResponse response) { |
| | | HttpSession oldSession = request.getSession(false); |
| | | if (oldSession != null && oldSession.getAttribute(SESSION_SECURED) == null) { |
| | | synchronized (this) { |
| | | Map<String, Object> attributes = new HashMap<String, Object>(); |
| | | Enumeration<String> e = oldSession.getAttributeNames(); |
| | | while (e.hasMoreElements()) { |
| | | String name = e.nextElement(); |
| | | attributes.put(name, oldSession.getAttribute(name)); |
| | | oldSession.removeAttribute(name); |
| | | } |
| | | oldSession.invalidate(); |
| | | |
| | | HttpSession newSession = request.getSession(true); |
| | | newSession.setAttribute(SESSION_SECURED, Boolean.TRUE); |
| | | for (Map.Entry<String, Object> entry : attributes.entrySet()) { |
| | | newSession.setAttribute(entry.getKey(), entry.getValue()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Wraps a standard HttpServletRequest and overrides user principal methods. |
| | | */ |
| | | public static class AuthenticatedRequest extends HttpServletRequestWrapper { |
| | | |
| | | private UserModel user; |
| | | |
| | | public AuthenticatedRequest(HttpServletRequest req) { |
| | | super(req); |
| | | user = DeepCopier.copy(UserModel.ANONYMOUS); |
| | | } |
| | | |
| | | UserModel getUser() { |
| | | return user; |
| | | } |
| | | |
| | | void setUser(UserModel user) { |
| | | this.user = user; |
| | | } |
| | | |
| | | @Override |
| | | public String getRemoteUser() { |
| | | return user.username; |
| | | } |
| | | |
| | | @Override |
| | | public boolean isUserInRole(String role) { |
| | | if (role.equals(Role.ADMIN.getRole())) { |
| | | return user.canAdmin(); |
| | | } |
| | | // Gitblit does not currently use actual roles in the traditional |
| | | // servlet container sense. That is the reason this is marked |
| | | // deprecated, but I may want to revisit this. |
| | | return user.hasRepositoryPermission(role); |
| | | } |
| | | |
| | | @Override |
| | | public Principal getUserPrincipal() { |
| | | return user; |
| | | } |
| | | } |
| | | } |
| | |
| | | import java.util.TreeSet;
|
| | |
|
| | | import javax.imageio.ImageIO;
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | | import javax.servlet.ServletException;
|
| | | import javax.servlet.http.HttpServlet;
|
| | | import javax.servlet.http.HttpServletRequest;
|
| | | import javax.servlet.http.HttpServletResponse;
|
| | |
|
| | |
| | | import com.gitblit.Constants;
|
| | | import com.gitblit.IStoredSettings;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.dagger.DaggerServlet;
|
| | | import com.gitblit.manager.IRepositoryManager;
|
| | | import com.gitblit.utils.JGitUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | |
|
| | | /**
|
| | | * Handles requests for branch graphs
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | public class BranchGraphServlet extends DaggerServlet {
|
| | | @Singleton
|
| | | public class BranchGraphServlet extends HttpServlet {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | |
| | |
|
| | | private IRepositoryManager repositoryManager;
|
| | |
|
| | | public BranchGraphServlet() {
|
| | | super();
|
| | | @Inject
|
| | | public BranchGraphServlet(
|
| | | IStoredSettings settings,
|
| | | IRepositoryManager repositoryManager) {
|
| | |
|
| | | this.settings = settings;
|
| | | this.repositoryManager = repositoryManager;
|
| | |
|
| | | strokeCache = new Stroke[4];
|
| | | for (int i = 1; i < strokeCache.length; i++) {
|
| | | strokeCache[i] = new BasicStroke(i);
|
| | | }
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected void inject(ObjectGraph dagger) {
|
| | | this.settings = dagger.get(IStoredSettings.class);
|
| | | this.repositoryManager = dagger.get(IRepositoryManager.class);
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | */
|
| | | package com.gitblit.servlet;
|
| | |
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | |
|
| | | import com.gitblit.Constants.AccessRestrictionType;
|
| | | import com.gitblit.manager.IAuthenticationManager;
|
| | | import com.gitblit.manager.IRepositoryManager;
|
| | | import com.gitblit.manager.IRuntimeManager;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.models.UserModel;
|
| | |
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | @Singleton
|
| | | public class DownloadZipFilter extends AccessRestrictionFilter {
|
| | |
|
| | | @Inject
|
| | | public DownloadZipFilter(
|
| | | IRuntimeManager runtimeManager,
|
| | | IAuthenticationManager authenticationManager,
|
| | | IRepositoryManager repositoryManager) {
|
| | |
|
| | | super(runtimeManager, authenticationManager, repositoryManager);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Extract the repository name from the url.
|
| | |
| | | * @return true if the filter allows repository creation
|
| | | */
|
| | | @Override
|
| | | protected boolean isCreationAllowed() {
|
| | | protected boolean isCreationAllowed(String action) {
|
| | | return false;
|
| | | }
|
| | |
|
| | |
| | | *
|
| | | * @param repository
|
| | | * @param action
|
| | | * @param method
|
| | | * @return true if the action may be performed
|
| | | */
|
| | | @Override
|
| | | protected boolean isActionAllowed(RepositoryModel repository, String action) {
|
| | | protected boolean isActionAllowed(RepositoryModel repository, String action, String method) {
|
| | | return true;
|
| | | }
|
| | |
|
| | |
| | | *
|
| | | * @param repository
|
| | | * @param action
|
| | | * @param method
|
| | | * @return true if authentication required
|
| | | */
|
| | | @Override
|
| | | protected boolean requiresAuthentication(RepositoryModel repository, String action) {
|
| | | protected boolean requiresAuthentication(RepositoryModel repository, String action, String method) {
|
| | | return repository.accessRestriction.atLeast(AccessRestrictionType.VIEW);
|
| | | }
|
| | |
|
| | |
| | | import java.text.ParseException;
|
| | | import java.util.Date;
|
| | |
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | |
|
| | | import javax.servlet.ServletException;
|
| | | import javax.servlet.http.HttpServlet;
|
| | | import javax.servlet.http.HttpServletResponse;
|
| | |
|
| | | import org.eclipse.jgit.lib.Repository;
|
| | |
| | | import com.gitblit.Constants;
|
| | | import com.gitblit.IStoredSettings;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.dagger.DaggerServlet;
|
| | | import com.gitblit.manager.IFilestoreManager;
|
| | | import com.gitblit.manager.IRepositoryManager;
|
| | | import com.gitblit.utils.CompressionUtils;
|
| | | import com.gitblit.utils.JGitUtils;
|
| | | import com.gitblit.utils.MarkdownUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | |
|
| | | /**
|
| | | * Streams out a zip file from the specified repository for any tree path at any
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | public class DownloadZipServlet extends DaggerServlet {
|
| | | @Singleton
|
| | | public class DownloadZipServlet extends HttpServlet {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | |
| | | private IStoredSettings settings;
|
| | |
|
| | | private IRepositoryManager repositoryManager;
|
| | | |
| | | private IFilestoreManager filestoreManager;
|
| | |
|
| | | public static enum Format {
|
| | | zip(".zip"), tar(".tar"), gz(".tar.gz"), xz(".tar.xz"), bzip2(".tar.bzip2");
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected void inject(ObjectGraph dagger) {
|
| | | this.settings = dagger.get(IStoredSettings.class);
|
| | | this.repositoryManager = dagger.get(IRepositoryManager.class);
|
| | | @Inject
|
| | | public DownloadZipServlet(IStoredSettings settings, IRepositoryManager repositoryManager, IFilestoreManager filestoreManager) {
|
| | | this.settings = settings;
|
| | | this.repositoryManager = repositoryManager;
|
| | | this.filestoreManager = filestoreManager;
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | response.setHeader("Pragma", "no-cache");
|
| | | response.setDateHeader("Expires", 0);
|
| | |
|
| | | |
| | | try {
|
| | | switch (format) {
|
| | | case zip:
|
| | | CompressionUtils.zip(r, basePath, objectId, response.getOutputStream());
|
| | | CompressionUtils.zip(r, filestoreManager, basePath, objectId, response.getOutputStream());
|
| | | break;
|
| | | case tar:
|
| | | CompressionUtils.tar(r, basePath, objectId, response.getOutputStream());
|
| | | CompressionUtils.tar(r, filestoreManager, basePath, objectId, response.getOutputStream());
|
| | | break;
|
| | | case gz:
|
| | | CompressionUtils.gz(r, basePath, objectId, response.getOutputStream());
|
| | | CompressionUtils.gz(r, filestoreManager, basePath, objectId, response.getOutputStream());
|
| | | break;
|
| | | case xz:
|
| | | CompressionUtils.xz(r, basePath, objectId, response.getOutputStream());
|
| | | CompressionUtils.xz(r, filestoreManager, basePath, objectId, response.getOutputStream());
|
| | | break;
|
| | | case bzip2:
|
| | | CompressionUtils.bzip2(r, basePath, objectId, response.getOutputStream());
|
| | | CompressionUtils.bzip2(r, filestoreManager, basePath, objectId, response.getOutputStream());
|
| | | break;
|
| | | }
|
| | |
|
| | |
| | | import java.io.IOException; |
| | | import java.text.MessageFormat; |
| | | |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | import javax.servlet.Filter; |
| | | import javax.servlet.FilterChain; |
| | | import javax.servlet.FilterConfig; |
| | | import javax.servlet.ServletException; |
| | |
| | | |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.dagger.DaggerFilter; |
| | | import com.gitblit.manager.IAuthenticationManager; |
| | | import com.gitblit.models.UserModel; |
| | | |
| | | import dagger.ObjectGraph; |
| | | |
| | | /** |
| | | * This filter enforces authentication via HTTP Basic Authentication, if the settings indicate so. |
| | |
| | | * @author Laurens Vrijnsen |
| | | * |
| | | */ |
| | | public class EnforceAuthenticationFilter extends DaggerFilter { |
| | | @Singleton |
| | | public class EnforceAuthenticationFilter implements Filter { |
| | | |
| | | protected transient Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | |
| | | |
| | | private IAuthenticationManager authenticationManager; |
| | | |
| | | @Inject |
| | | public EnforceAuthenticationFilter( |
| | | IStoredSettings settings, |
| | | IAuthenticationManager authenticationManager) { |
| | | |
| | | this.settings = settings; |
| | | this.authenticationManager = authenticationManager; |
| | | } |
| | | |
| | | @Override |
| | | protected void inject(ObjectGraph dagger, FilterConfig filterConfig) { |
| | | this.settings = dagger.get(IStoredSettings.class); |
| | | this.authenticationManager = dagger.get(IAuthenticationManager.class); |
| | | public void init(FilterConfig config) { |
| | | } |
| | | |
| | | @Override |
| | | public void destroy() { |
| | | } |
| | | |
| | | /* |
| | |
| | | // user is authenticated, or don't care, continue handling |
| | | chain.doFilter(request, response); |
| | | } |
| | | } |
| | | |
| | | |
| | | /* |
| | | * @see javax.servlet.Filter#destroy() |
| | | */ |
| | | @Override |
| | | public void destroy() { |
| | | } |
| | | } |
| | |
| | | import java.util.Map;
|
| | | import java.util.Set;
|
| | |
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | | import javax.servlet.http.HttpServletResponse;
|
| | |
|
| | | import com.gitblit.Constants.FederationRequest;
|
| | |
| | | import com.gitblit.utils.StringUtils;
|
| | | import com.gitblit.utils.TimeUtils;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | |
|
| | | /**
|
| | | * Handles federation requests.
|
| | | *
|
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | @Singleton
|
| | | public class FederationServlet extends JsonServlet {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
| | |
|
| | | private IFederationManager federationManager;
|
| | |
|
| | | @Override
|
| | | protected void inject(ObjectGraph dagger) {
|
| | | this.settings = dagger.get(IStoredSettings.class);
|
| | | this.userManager = dagger.get(IUserManager.class);
|
| | | this.repositoryManager = dagger.get(IRepositoryManager.class);
|
| | | this.federationManager = dagger.get(IFederationManager.class);
|
| | | @Inject
|
| | | public FederationServlet(
|
| | | IStoredSettings settings,
|
| | | IUserManager userManager,
|
| | | IRepositoryManager repositoryManager,
|
| | | IFederationManager federationManager) {
|
| | |
|
| | | this.settings = settings;
|
| | | this.userManager = userManager;
|
| | | this.repositoryManager = repositoryManager;
|
| | | this.federationManager = federationManager;
|
| | | }
|
| | |
|
| | | /**
|
New file |
| | |
| | | /* |
| | | * Copyright 2015 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.servlet; |
| | | |
| | | import java.io.BufferedReader; |
| | | import java.io.IOException; |
| | | import java.io.Serializable; |
| | | import java.text.MessageFormat; |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | import javax.servlet.ServletException; |
| | | import javax.servlet.http.HttpServlet; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.models.FilestoreModel; |
| | | import com.gitblit.models.RepositoryModel; |
| | | import com.gitblit.models.FilestoreModel.Status; |
| | | import com.gitblit.manager.FilestoreManager; |
| | | import com.gitblit.manager.IGitblit; |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.utils.JsonUtils; |
| | | |
| | | |
| | | /** |
| | | * Handles large file storage as per the Git LFS v1 Batch API |
| | | * |
| | | * Further details can be found at https://github.com/github/git-lfs |
| | | * |
| | | * @author Paul Martin |
| | | */ |
| | | @Singleton |
| | | public class FilestoreServlet extends HttpServlet { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | public static final int PROTOCOL_VERSION = 1; |
| | | |
| | | public static final String GIT_LFS_META_MIME = "application/vnd.git-lfs+json"; |
| | | |
| | | public static final String REGEX_PATH = "^(.*?)/(r)/(.*?)/info/lfs/objects/(batch|" + Constants.REGEX_SHA256 + ")"; |
| | | public static final int REGEX_GROUP_BASE_URI = 1; |
| | | public static final int REGEX_GROUP_PREFIX = 2; |
| | | public static final int REGEX_GROUP_REPOSITORY = 3; |
| | | public static final int REGEX_GROUP_ENDPOINT = 4; |
| | | |
| | | protected final Logger logger; |
| | | |
| | | private static IGitblit gitblit; |
| | | |
| | | @Inject |
| | | public FilestoreServlet(IStoredSettings settings, IGitblit gitblit) { |
| | | |
| | | super(); |
| | | logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | FilestoreServlet.gitblit = gitblit; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Handles batch upload request (metadata) |
| | | * |
| | | * @param request |
| | | * @param response |
| | | * @throws javax.servlet.ServletException |
| | | * @throws java.io.IOException |
| | | */ |
| | | @Override |
| | | protected void doPost(HttpServletRequest request, |
| | | HttpServletResponse response) throws ServletException ,IOException { |
| | | |
| | | UrlInfo info = getInfoFromRequest(request); |
| | | if (info == null) { |
| | | sendError(response, HttpServletResponse.SC_NOT_FOUND); |
| | | return; |
| | | } |
| | | |
| | | //Post is for batch operations so no oid should be defined |
| | | if (info.oid != null) { |
| | | sendError(response, HttpServletResponse.SC_BAD_REQUEST); |
| | | return; |
| | | } |
| | | |
| | | IGitLFS.Batch batch = deserialize(request, response, IGitLFS.Batch.class); |
| | | |
| | | if (batch == null) { |
| | | sendError(response, HttpServletResponse.SC_BAD_REQUEST); |
| | | return; |
| | | } |
| | | |
| | | UserModel user = getUserOrAnonymous(request); |
| | | |
| | | IGitLFS.BatchResponse batchResponse = new IGitLFS.BatchResponse(); |
| | | |
| | | if (batch.operation.equalsIgnoreCase("upload")) { |
| | | for (IGitLFS.Request item : batch.objects) { |
| | | |
| | | Status state = gitblit.addObject(item.oid, item.size, user, info.repository); |
| | | |
| | | batchResponse.objects.add(getResponseForUpload(info.baseUrl, item.oid, item.size, user.getName(), info.repository.name, state)); |
| | | } |
| | | } else if (batch.operation.equalsIgnoreCase("download")) { |
| | | for (IGitLFS.Request item : batch.objects) { |
| | | |
| | | Status state = gitblit.downloadBlob(item.oid, user, info.repository, null); |
| | | batchResponse.objects.add(getResponseForDownload(info.baseUrl, item.oid, item.size, user.getName(), info.repository.name, state)); |
| | | } |
| | | } else { |
| | | sendError(response, HttpServletResponse.SC_NOT_IMPLEMENTED); |
| | | return; |
| | | } |
| | | |
| | | response.setStatus(HttpServletResponse.SC_OK); |
| | | serialize(response, batchResponse); |
| | | } |
| | | |
| | | /** |
| | | * Handles the actual upload (BLOB) |
| | | * |
| | | * @param request |
| | | * @param response |
| | | * @throws javax.servlet.ServletException |
| | | * @throws java.io.IOException |
| | | */ |
| | | @Override |
| | | protected void doPut(HttpServletRequest request, |
| | | HttpServletResponse response) throws ServletException ,IOException { |
| | | |
| | | UrlInfo info = getInfoFromRequest(request); |
| | | |
| | | if (info == null) { |
| | | sendError(response, HttpServletResponse.SC_NOT_FOUND); |
| | | return; |
| | | } |
| | | |
| | | //Put is a singular operation so must have oid |
| | | if (info.oid == null) { |
| | | sendError(response, HttpServletResponse.SC_BAD_REQUEST); |
| | | return; |
| | | } |
| | | |
| | | UserModel user = getUserOrAnonymous(request); |
| | | long size = FilestoreManager.UNDEFINED_SIZE; |
| | | |
| | | |
| | | |
| | | FilestoreModel.Status status = gitblit.uploadBlob(info.oid, size, user, info.repository, request.getInputStream()); |
| | | IGitLFS.Response responseObject = getResponseForUpload(info.baseUrl, info.oid, size, user.getName(), info.repository.name, status); |
| | | |
| | | logger.info(MessageFormat.format("FILESTORE-AUDIT {0}:{4} {1} {2}@{3}", |
| | | "PUT", info.oid, user.getName(), info.repository.name, status.toString() )); |
| | | |
| | | if (responseObject.error == null) { |
| | | response.setStatus(responseObject.successCode); |
| | | } else { |
| | | serialize(response, responseObject.error); |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * Handles a download |
| | | * Treated as hypermedia request if accept header contains Git-LFS MIME |
| | | * otherwise treated as a download of the blob |
| | | * @param request |
| | | * @param response |
| | | * @throws javax.servlet.ServletException |
| | | * @throws java.io.IOException |
| | | */ |
| | | @Override |
| | | protected void doGet(HttpServletRequest request, |
| | | HttpServletResponse response) throws ServletException ,IOException { |
| | | |
| | | UrlInfo info = getInfoFromRequest(request); |
| | | |
| | | if (info == null || info.oid == null) { |
| | | sendError(response, HttpServletResponse.SC_NOT_FOUND); |
| | | return; |
| | | } |
| | | |
| | | UserModel user = getUserOrAnonymous(request); |
| | | |
| | | FilestoreModel model = gitblit.getObject(info.oid, user, info.repository); |
| | | long size = FilestoreManager.UNDEFINED_SIZE; |
| | | |
| | | boolean isMetaRequest = AccessRestrictionFilter.hasContentInRequestHeader(request, "Accept", GIT_LFS_META_MIME); |
| | | FilestoreModel.Status status = Status.Unavailable; |
| | | |
| | | if (model != null) { |
| | | size = model.getSize(); |
| | | status = model.getStatus(); |
| | | } |
| | | |
| | | if (!isMetaRequest) { |
| | | status = gitblit.downloadBlob(info.oid, user, info.repository, response.getOutputStream()); |
| | | |
| | | logger.info(MessageFormat.format("FILESTORE-AUDIT {0}:{4} {1} {2}@{3}", |
| | | "GET", info.oid, user.getName(), info.repository.name, status.toString() )); |
| | | } |
| | | |
| | | if (status == Status.Error_Unexpected_Stream_End) { |
| | | return; |
| | | } |
| | | |
| | | IGitLFS.Response responseObject = getResponseForDownload(info.baseUrl, |
| | | info.oid, size, user.getName(), info.repository.name, status); |
| | | |
| | | if (responseObject.error == null) { |
| | | response.setStatus(responseObject.successCode); |
| | | |
| | | if (isMetaRequest) { |
| | | serialize(response, responseObject); |
| | | } |
| | | } else { |
| | | response.setStatus(responseObject.error.code); |
| | | |
| | | if (isMetaRequest) { |
| | | serialize(response, responseObject.error); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | private void sendError(HttpServletResponse response, int code) throws IOException { |
| | | |
| | | String msg = ""; |
| | | |
| | | switch (code) |
| | | { |
| | | case HttpServletResponse.SC_NOT_FOUND: msg = "Not Found"; break; |
| | | case HttpServletResponse.SC_NOT_IMPLEMENTED: msg = "Not Implemented"; break; |
| | | case HttpServletResponse.SC_BAD_REQUEST: msg = "Malformed Git-LFS request"; break; |
| | | |
| | | default: msg = "Unknown Error"; |
| | | } |
| | | |
| | | response.setStatus(code); |
| | | serialize(response, new IGitLFS.ObjectError(code, msg)); |
| | | } |
| | | |
| | | @SuppressWarnings("incomplete-switch") |
| | | private IGitLFS.Response getResponseForUpload(String baseUrl, String oid, long size, String user, String repo, FilestoreModel.Status state) { |
| | | |
| | | switch (state) { |
| | | case AuthenticationRequired: |
| | | return new IGitLFS.Response(oid, size, 401, MessageFormat.format("Authentication required to write to repository {0}", repo)); |
| | | case Error_Unauthorized: |
| | | return new IGitLFS.Response(oid, size, 403, MessageFormat.format("User {0}, does not have write permissions to repository {1}", user, repo)); |
| | | case Error_Exceeds_Size_Limit: |
| | | return new IGitLFS.Response(oid, size, 509, MessageFormat.format("Object is larger than allowed limit of {1}", gitblit.getMaxUploadSize())); |
| | | case Error_Hash_Mismatch: |
| | | return new IGitLFS.Response(oid, size, 422, "Hash mismatch"); |
| | | case Error_Invalid_Oid: |
| | | return new IGitLFS.Response(oid, size, 422, MessageFormat.format("{0} is not a valid oid", oid)); |
| | | case Error_Invalid_Size: |
| | | return new IGitLFS.Response(oid, size, 422, MessageFormat.format("{0} is not a valid size", size)); |
| | | case Error_Size_Mismatch: |
| | | return new IGitLFS.Response(oid, size, 422, "Object size mismatch"); |
| | | case Deleted: |
| | | return new IGitLFS.Response(oid, size, 410, "Object was deleted : ".concat("TBD Reason") ); |
| | | case Upload_In_Progress: |
| | | return new IGitLFS.Response(oid, size, 503, "File currently being uploaded by another user"); |
| | | case Unavailable: |
| | | return new IGitLFS.Response(oid, size, 404, MessageFormat.format("Repository {0}, does not exist for user {1}", repo, user)); |
| | | case Upload_Pending: |
| | | return new IGitLFS.Response(oid, size, 202, "upload", getObjectUri(baseUrl, repo, oid) ); |
| | | case Available: |
| | | return new IGitLFS.Response(oid, size, 200, "upload", getObjectUri(baseUrl, repo, oid) ); |
| | | } |
| | | |
| | | return new IGitLFS.Response(oid, size, 500, "Unknown Error"); |
| | | } |
| | | |
| | | @SuppressWarnings("incomplete-switch") |
| | | private IGitLFS.Response getResponseForDownload(String baseUrl, String oid, long size, String user, String repo, FilestoreModel.Status state) { |
| | | |
| | | switch (state) { |
| | | case Error_Unauthorized: |
| | | return new IGitLFS.Response(oid, size, 403, MessageFormat.format("User {0}, does not have read permissions to repository {1}", user, repo)); |
| | | case Error_Invalid_Oid: |
| | | return new IGitLFS.Response(oid, size, 422, MessageFormat.format("{0} is not a valid oid", oid)); |
| | | case Error_Unknown: |
| | | return new IGitLFS.Response(oid, size, 500, "Unknown Error"); |
| | | case Deleted: |
| | | return new IGitLFS.Response(oid, size, 410, "Object was deleted : ".concat("TBD Reason") ); |
| | | case Available: |
| | | return new IGitLFS.Response(oid, size, 200, "download", getObjectUri(baseUrl, repo, oid) ); |
| | | } |
| | | |
| | | return new IGitLFS.Response(oid, size, 404, "Object not available"); |
| | | } |
| | | |
| | | |
| | | private String getObjectUri(String baseUrl, String repo, String oid) { |
| | | return baseUrl + "/" + repo + "/" + Constants.R_LFS + "objects/" + oid; |
| | | } |
| | | |
| | | |
| | | protected void serialize(HttpServletResponse response, Object o) throws IOException { |
| | | if (o != null) { |
| | | // Send JSON response |
| | | String json = JsonUtils.toJsonString(o); |
| | | response.setCharacterEncoding(Constants.ENCODING); |
| | | response.setContentType(GIT_LFS_META_MIME); |
| | | response.getWriter().append(json); |
| | | } |
| | | } |
| | | |
| | | protected <X> X deserialize(HttpServletRequest request, HttpServletResponse response, |
| | | Class<X> clazz) { |
| | | |
| | | String json = ""; |
| | | try { |
| | | |
| | | json = readJson(request, response); |
| | | |
| | | return JsonUtils.fromJsonString(json.toString(), clazz); |
| | | |
| | | } catch (Exception e) { |
| | | //Intentional silent fail |
| | | } |
| | | |
| | | return null; |
| | | } |
| | | |
| | | private String readJson(HttpServletRequest request, HttpServletResponse response) |
| | | throws IOException { |
| | | BufferedReader reader = request.getReader(); |
| | | StringBuilder json = new StringBuilder(); |
| | | String line = null; |
| | | while ((line = reader.readLine()) != null) { |
| | | json.append(line); |
| | | } |
| | | reader.close(); |
| | | |
| | | if (json.length() == 0) { |
| | | logger.error(MessageFormat.format("Failed to receive json data from {0}", |
| | | request.getRemoteAddr())); |
| | | response.setStatus(HttpServletResponse.SC_BAD_REQUEST); |
| | | return null; |
| | | } |
| | | return json.toString(); |
| | | } |
| | | |
| | | private UserModel getUserOrAnonymous(HttpServletRequest r) { |
| | | UserModel user = (UserModel) r.getUserPrincipal(); |
| | | if (user != null) { return user; } |
| | | return UserModel.ANONYMOUS; |
| | | } |
| | | |
| | | private static class UrlInfo { |
| | | public RepositoryModel repository; |
| | | public String oid; |
| | | public String baseUrl; |
| | | |
| | | public UrlInfo(RepositoryModel repo, String oid, String baseUrl) { |
| | | this.repository = repo; |
| | | this.oid = oid; |
| | | this.baseUrl = baseUrl; |
| | | } |
| | | } |
| | | |
| | | public static UrlInfo getInfoFromRequest(HttpServletRequest httpRequest) { |
| | | |
| | | String url = httpRequest.getRequestURL().toString(); |
| | | Pattern p = Pattern.compile(REGEX_PATH); |
| | | Matcher m = p.matcher(url); |
| | | |
| | | |
| | | if (m.find()) { |
| | | RepositoryModel repo = gitblit.getRepositoryModel(m.group(REGEX_GROUP_REPOSITORY)); |
| | | String baseUrl = m.group(REGEX_GROUP_BASE_URI) + "/" + m.group(REGEX_GROUP_PREFIX); |
| | | |
| | | if (m.group(REGEX_GROUP_ENDPOINT).equals("batch")) { |
| | | return new UrlInfo(repo, null, baseUrl); |
| | | } else { |
| | | return new UrlInfo(repo, m.group(REGEX_GROUP_ENDPOINT), baseUrl); |
| | | } |
| | | } |
| | | |
| | | return null; |
| | | } |
| | | |
| | | |
| | | public interface IGitLFS { |
| | | |
| | | @SuppressWarnings("serial") |
| | | public class Request implements Serializable |
| | | { |
| | | public String oid; |
| | | public long size; |
| | | } |
| | | |
| | | |
| | | @SuppressWarnings("serial") |
| | | public class Batch implements Serializable |
| | | { |
| | | public String operation; |
| | | public List<Request> objects; |
| | | } |
| | | |
| | | |
| | | @SuppressWarnings("serial") |
| | | public class Response implements Serializable |
| | | { |
| | | public String oid; |
| | | public long size; |
| | | public Map<String, HyperMediaLink> actions; |
| | | public ObjectError error; |
| | | public transient int successCode; |
| | | |
| | | public Response(String id, long itemSize, int errorCode, String errorText) { |
| | | oid = id; |
| | | size = itemSize; |
| | | actions = null; |
| | | successCode = 0; |
| | | error = new ObjectError(errorCode, errorText); |
| | | } |
| | | |
| | | public Response(String id, long itemSize, int actionCode, String action, String uri) { |
| | | oid = id; |
| | | size = itemSize; |
| | | error = null; |
| | | successCode = actionCode; |
| | | actions = new HashMap<String, HyperMediaLink>(); |
| | | actions.put(action, new HyperMediaLink(action, uri)); |
| | | } |
| | | |
| | | } |
| | | |
| | | @SuppressWarnings("serial") |
| | | public class BatchResponse implements Serializable { |
| | | public List<Response> objects; |
| | | |
| | | public BatchResponse() { |
| | | objects = new ArrayList<Response>(); |
| | | } |
| | | } |
| | | |
| | | |
| | | @SuppressWarnings("serial") |
| | | public class ObjectError implements Serializable |
| | | { |
| | | public String message; |
| | | public int code; |
| | | public String documentation_url; |
| | | public Integer request_id; |
| | | |
| | | public ObjectError(int errorCode, String errorText) { |
| | | code = errorCode; |
| | | message = errorText; |
| | | request_id = null; |
| | | } |
| | | } |
| | | |
| | | @SuppressWarnings("serial") |
| | | public class HyperMediaLink implements Serializable |
| | | { |
| | | public String href; |
| | | public transient String header; |
| | | //public Date expires_at; |
| | | |
| | | public HyperMediaLink(String action, String uri) { |
| | | header = action; |
| | | href = uri; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | } |
| | |
| | |
|
| | | import java.text.MessageFormat;
|
| | |
|
| | | import javax.servlet.FilterConfig;
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | |
|
| | | import javax.servlet.http.HttpServletRequest;
|
| | |
|
| | | import com.gitblit.Constants.AccessRestrictionType;
|
| | |
| | | import com.gitblit.GitBlitException;
|
| | | import com.gitblit.IStoredSettings;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.manager.IAuthenticationManager;
|
| | | import com.gitblit.manager.IFederationManager;
|
| | | import com.gitblit.manager.IRepositoryManager;
|
| | | import com.gitblit.manager.IRuntimeManager;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.models.UserModel;
|
| | | import com.gitblit.utils.StringUtils;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | |
|
| | | /**
|
| | | * The GitFilter is an AccessRestrictionFilter which ensures that Git client
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | @Singleton
|
| | | public class GitFilter extends AccessRestrictionFilter {
|
| | |
|
| | | protected static final String gitReceivePack = "/git-receive-pack";
|
| | |
|
| | | protected static final String gitUploadPack = "/git-upload-pack";
|
| | |
|
| | | |
| | | protected static final String gitLfs = "/info/lfs";
|
| | | |
| | | protected static final String[] suffixes = { gitReceivePack, gitUploadPack, "/info/refs", "/HEAD",
|
| | | "/objects" };
|
| | | "/objects", gitLfs };
|
| | |
|
| | | private IStoredSettings settings;
|
| | |
|
| | | private IFederationManager federationManager;
|
| | |
|
| | | @Override
|
| | | protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
|
| | | super.inject(dagger, filterConfig);
|
| | | this.settings = dagger.get(IStoredSettings.class);
|
| | | this.federationManager = dagger.get(IFederationManager.class);
|
| | | @Inject
|
| | | public GitFilter(
|
| | | IStoredSettings settings,
|
| | | IRuntimeManager runtimeManager,
|
| | | IAuthenticationManager authenticationManager,
|
| | | IRepositoryManager repositoryManager,
|
| | | IFederationManager federationManager) {
|
| | |
|
| | | super(runtimeManager, authenticationManager, repositoryManager);
|
| | |
|
| | | this.settings = settings;
|
| | | this.federationManager = federationManager;
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | }
|
| | |
|
| | | /**
|
| | | * Analyze the url and returns the action of the request. Return values are
|
| | | * either "/git-receive-pack" or "/git-upload-pack".
|
| | | * Analyze the url and returns the action of the request. Return values are:
|
| | | * "/git-receive-pack", "/git-upload-pack" or "/info/lfs".
|
| | | *
|
| | | * @param serverUrl
|
| | | * @return action of the request
|
| | |
| | | return gitReceivePack;
|
| | | } else if (suffix.contains("?service=git-upload-pack")) {
|
| | | return gitUploadPack;
|
| | | } else if (suffix.startsWith(gitLfs)) {
|
| | | return gitLfs;
|
| | | } else {
|
| | | return gitUploadPack;
|
| | | }
|
| | |
| | | * @return true if the server allows repository creation on-push
|
| | | */
|
| | | @Override
|
| | | protected boolean isCreationAllowed() {
|
| | | protected boolean isCreationAllowed(String action) {
|
| | | |
| | | //Repository must already exist before large files can be deposited
|
| | | if (action.equals(gitLfs)) {
|
| | | return false;
|
| | | }
|
| | | |
| | | return settings.getBoolean(Keys.git.allowCreateOnPush, true);
|
| | | }
|
| | |
|
| | |
| | | * @return true if the action may be performed
|
| | | */
|
| | | @Override
|
| | | protected boolean isActionAllowed(RepositoryModel repository, String action) {
|
| | | protected boolean isActionAllowed(RepositoryModel repository, String action, String method) {
|
| | | // the log here has been moved into ReceiveHook to provide clients with
|
| | | // error messages
|
| | | if (gitLfs.equals(action)) {
|
| | | if (!method.matches("GET|POST|PUT|HEAD")) {
|
| | | return false;
|
| | | }
|
| | | }
|
| | | |
| | | return true;
|
| | | }
|
| | |
|
| | |
| | | *
|
| | | * @param repository
|
| | | * @param action
|
| | | * @param method
|
| | | * @return true if authentication required
|
| | | */
|
| | | @Override
|
| | | protected boolean requiresAuthentication(RepositoryModel repository, String action) {
|
| | | protected boolean requiresAuthentication(RepositoryModel repository, String action, String method) {
|
| | | if (gitUploadPack.equals(action)) {
|
| | | // send to client
|
| | | return repository.accessRestriction.atLeast(AccessRestrictionType.CLONE);
|
| | | } else if (gitReceivePack.equals(action)) {
|
| | | // receive from client
|
| | | return repository.accessRestriction.atLeast(AccessRestrictionType.PUSH);
|
| | | } else if (gitLfs.equals(action)) {
|
| | | |
| | | if (method.matches("GET|HEAD")) {
|
| | | return repository.accessRestriction.atLeast(AccessRestrictionType.CLONE);
|
| | | } else {
|
| | | //NOTE: Treat POST as PUT as as without reading message type cannot determine |
| | | return repository.accessRestriction.atLeast(AccessRestrictionType.PUSH);
|
| | | }
|
| | | }
|
| | | return false;
|
| | | }
|
| | |
| | | @Override
|
| | | protected RepositoryModel createRepository(UserModel user, String repository, String action) {
|
| | | boolean isPush = !StringUtils.isEmpty(action) && gitReceivePack.equals(action);
|
| | | |
| | | if (action.equals(gitLfs)) {
|
| | | //Repository must already exist for any filestore actions
|
| | | return null;
|
| | | }
|
| | | |
| | | if (isPush) {
|
| | | if (user.canCreate(repository)) {
|
| | | // user is pushing to a new repository
|
| | |
| | | // repository could not be created or action was not a push
|
| | | return null;
|
| | | }
|
| | | |
| | | /**
|
| | | * Git lfs action uses an alternative authentication header, |
| | | * dependent on the viewing method.
|
| | | * |
| | | * @param httpRequest
|
| | | * @param action
|
| | | * @return
|
| | | */
|
| | | @Override
|
| | | protected String getAuthenticationHeader(HttpServletRequest httpRequest, String action) {
|
| | |
|
| | | if (action.equals(gitLfs)) {
|
| | | if (hasContentInRequestHeader(httpRequest, "Accept", FilestoreServlet.GIT_LFS_META_MIME)) {
|
| | | return "LFS-Authenticate";
|
| | | }
|
| | | }
|
| | | |
| | | return super.getAuthenticationHeader(httpRequest, action);
|
| | | }
|
| | | |
| | | /**
|
| | | * Interrogates the request headers based on the action
|
| | | * @param action
|
| | | * @param request
|
| | | * @return
|
| | | */
|
| | | @Override
|
| | | protected boolean hasValidRequestHeader(String action,
|
| | | HttpServletRequest request) {
|
| | |
|
| | | if (action.equals(gitLfs) && request.getMethod().equals("POST")) {
|
| | | if ( !hasContentInRequestHeader(request, "Accept", FilestoreServlet.GIT_LFS_META_MIME)
|
| | | || !hasContentInRequestHeader(request, "Content-Type", FilestoreServlet.GIT_LFS_META_MIME)) {
|
| | | return false;
|
| | | } |
| | | }
|
| | | |
| | | return super.hasValidRequestHeader(action, request);
|
| | | }
|
| | | }
|
| | |
| | | import java.io.IOException;
|
| | | import java.util.Enumeration;
|
| | |
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | | import javax.servlet.FilterChain;
|
| | | import javax.servlet.FilterConfig;
|
| | | import javax.servlet.ServletConfig;
|
| | |
| | |
|
| | | import org.eclipse.jgit.http.server.GitFilter;
|
| | |
|
| | | import com.gitblit.dagger.DaggerContext;
|
| | | import com.gitblit.git.GitblitReceivePackFactory;
|
| | | import com.gitblit.git.GitblitUploadPackFactory;
|
| | | import com.gitblit.git.RepositoryResolver;
|
| | | import com.gitblit.manager.IGitblit;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | |
|
| | | /**
|
| | | * The GitServlet provides http/https access to Git repositories.
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | @Singleton
|
| | | public class GitServlet extends HttpServlet {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | private final GitFilter gitFilter;
|
| | |
|
| | | public GitServlet() {
|
| | | @Inject
|
| | | public GitServlet(IGitblit gitblit) {
|
| | | gitFilter = new GitFilter();
|
| | | gitFilter.setRepositoryResolver(new RepositoryResolver<HttpServletRequest>(gitblit));
|
| | | gitFilter.setUploadPackFactory(new GitblitUploadPackFactory<HttpServletRequest>(gitblit));
|
| | | gitFilter.setReceivePackFactory(new GitblitReceivePackFactory<HttpServletRequest>(gitblit));
|
| | | }
|
| | |
|
| | | @Override
|
| | | public void init(final ServletConfig config) throws ServletException {
|
| | | ServletContext context = config.getServletContext();
|
| | | ObjectGraph dagger = (ObjectGraph) context.getAttribute(DaggerContext.INJECTOR_NAME);
|
| | | IGitblit gitblit = dagger.get(IGitblit.class);
|
| | | gitFilter.setRepositoryResolver(new RepositoryResolver<HttpServletRequest>(gitblit));
|
| | | gitFilter.setUploadPackFactory(new GitblitUploadPackFactory<HttpServletRequest>(gitblit));
|
| | | gitFilter.setReceivePackFactory(new GitblitReceivePackFactory<HttpServletRequest>(gitblit));
|
| | |
|
| | | gitFilter.init(new FilterConfig() {
|
| | | @Override
|
| | |
| | | import java.text.MessageFormat; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | | import javax.naming.Context; |
| | | import javax.naming.InitialContext; |
| | |
| | | import javax.servlet.ServletContext; |
| | | import javax.servlet.ServletContextEvent; |
| | | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.DaggerModule; |
| | | import com.gitblit.FileSettings; |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.WebXmlSettings; |
| | | import com.gitblit.dagger.DaggerContext; |
| | | import com.gitblit.extensions.LifeCycleListener; |
| | | import com.gitblit.guice.CoreModule; |
| | | import com.gitblit.guice.WebModule; |
| | | import com.gitblit.manager.IAuthenticationManager; |
| | | import com.gitblit.manager.IFederationManager; |
| | | import com.gitblit.manager.IFilestoreManager; |
| | | import com.gitblit.manager.IGitblit; |
| | | import com.gitblit.manager.IManager; |
| | | import com.gitblit.manager.INotificationManager; |
| | |
| | | import com.gitblit.manager.IProjectManager; |
| | | import com.gitblit.manager.IRepositoryManager; |
| | | import com.gitblit.manager.IRuntimeManager; |
| | | import com.gitblit.manager.IServicesManager; |
| | | import com.gitblit.manager.IUserManager; |
| | | import com.gitblit.tickets.ITicketService; |
| | | import com.gitblit.transport.ssh.IPublicKeyManager; |
| | | import com.gitblit.utils.ContainerUtils; |
| | | import com.gitblit.utils.StringUtils; |
| | | |
| | | import dagger.ObjectGraph; |
| | | import com.google.inject.AbstractModule; |
| | | import com.google.inject.Guice; |
| | | import com.google.inject.Injector; |
| | | import com.google.inject.servlet.GuiceServletContextListener; |
| | | |
| | | /** |
| | | * This class is the main entry point for the entire webapp. It is a singleton |
| | | * created manually by Gitblit GO or dynamically by the WAR/Express servlet |
| | | * container. This class instantiates and starts all managers. Servlets and |
| | | * filters are instantiated defined in web.xml and instantiated by the servlet |
| | | * container, but those servlets and filters use Dagger to manually inject their |
| | | * dependencies. |
| | | * container. This class instantiates and starts all managers. |
| | | * |
| | | * Servlets and filters are injected which allows Gitblit to be completely |
| | | * code-driven. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | public class GitblitContext extends DaggerContext { |
| | | public class GitblitContext extends GuiceServletContextListener { |
| | | |
| | | private static GitblitContext gitblit; |
| | | |
| | | protected final Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | private final List<IManager> managers = new ArrayList<IManager>(); |
| | | |
| | |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * Returns Gitblit's Dagger injection modules. |
| | | */ |
| | | @Override |
| | | protected Object [] getModules() { |
| | | return new Object [] { new DaggerModule() }; |
| | | protected Injector getInjector() { |
| | | return Guice.createInjector(getModules()); |
| | | } |
| | | |
| | | /** |
| | | * Returns Gitblit's Guice injection modules. |
| | | */ |
| | | protected AbstractModule [] getModules() { |
| | | return new AbstractModule [] { new CoreModule(), new WebModule() }; |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | @Override |
| | | public final void contextInitialized(ServletContextEvent contextEvent) { |
| | | super.contextInitialized(contextEvent); |
| | | |
| | | ServletContext context = contextEvent.getServletContext(); |
| | | configureContext(context); |
| | | startCore(context); |
| | | } |
| | | |
| | | /** |
| | | * Prepare runtime settings and start all manager instances. |
| | | */ |
| | | protected void configureContext(ServletContext context) { |
| | | ObjectGraph injector = getInjector(context); |
| | | protected void startCore(ServletContext context) { |
| | | Injector injector = (Injector) context.getAttribute(Injector.class.getName()); |
| | | |
| | | // create the runtime settings object |
| | | IStoredSettings runtimeSettings = injector.get(IStoredSettings.class); |
| | | IStoredSettings runtimeSettings = injector.getInstance(IStoredSettings.class); |
| | | final File baseFolder; |
| | | |
| | | if (goSettings != null) { |
| | |
| | | |
| | | // Manually configure IRuntimeManager |
| | | logManager(IRuntimeManager.class); |
| | | IRuntimeManager runtime = injector.get(IRuntimeManager.class); |
| | | IRuntimeManager runtime = injector.getInstance(IRuntimeManager.class); |
| | | runtime.setBaseFolder(baseFolder); |
| | | runtime.getStatus().isGO = goSettings != null; |
| | | runtime.getStatus().servletContainer = context.getServerInfo(); |
| | |
| | | startManager(injector, IRepositoryManager.class); |
| | | startManager(injector, IProjectManager.class); |
| | | startManager(injector, IFederationManager.class); |
| | | startManager(injector, ITicketService.class); |
| | | startManager(injector, IGitblit.class); |
| | | startManager(injector, IServicesManager.class); |
| | | startManager(injector, IFilestoreManager.class); |
| | | |
| | | // start the plugin manager last so that plugins can depend on |
| | | // deterministic access to all other managers in their start() methods |
| | |
| | | logger.info("All managers started."); |
| | | logger.info(""); |
| | | |
| | | IPluginManager pluginManager = injector.get(IPluginManager.class); |
| | | IPluginManager pluginManager = injector.getInstance(IPluginManager.class); |
| | | for (LifeCycleListener listener : pluginManager.getExtensions(LifeCycleListener.class)) { |
| | | try { |
| | | listener.onStartup(); |
| | |
| | | return defaultBaseFolder; |
| | | } |
| | | |
| | | protected <X extends IManager> X loadManager(ObjectGraph injector, Class<X> clazz) { |
| | | X x = injector.get(clazz); |
| | | protected <X extends IManager> X loadManager(Injector injector, Class<X> clazz) { |
| | | X x = injector.getInstance(clazz); |
| | | return x; |
| | | } |
| | | |
| | | protected <X extends IManager> X startManager(ObjectGraph injector, Class<X> clazz) { |
| | | protected <X extends IManager> X startManager(Injector injector, Class<X> clazz) { |
| | | X x = loadManager(injector, clazz); |
| | | logManager(clazz); |
| | | x.start(); |
| | | managers.add(x); |
| | | return x; |
| | | return startManager(x); |
| | | } |
| | | |
| | | protected <X extends IManager> X startManager(X x) { |
| | | x.start(); |
| | | managers.add(x); |
| | | return x; |
| | | } |
| | | |
| | | protected void logManager(Class<? extends IManager> clazz) { |
| | |
| | | logger.info("----[{}]----", clazz.getName()); |
| | | } |
| | | |
| | | @Override |
| | | public final void contextDestroyed(ServletContextEvent contextEvent) { |
| | | super.contextDestroyed(contextEvent); |
| | | ServletContext context = contextEvent.getServletContext(); |
| | | destroyContext(context); |
| | | } |
| | | |
| | | /** |
| | | * Gitblit is being shutdown either because the servlet container is |
| | | * shutting down or because the servlet container is re-deploying Gitblit. |
| | | */ |
| | | @Override |
| | | protected void destroyContext(ServletContext context) { |
| | | logger.info("Gitblit context destroyed by servlet container."); |
| | | |
| | |
| | | baseFolder.mkdirs(); |
| | | |
| | | // try to extract the data folder resource to the baseFolder |
| | | File localSettings = new File(baseFolder, "gitblit.properties"); |
| | | if (!localSettings.exists()) { |
| | | extractResources(context, "/WEB-INF/data/", baseFolder); |
| | | } |
| | | extractResources(context, "/WEB-INF/data/", baseFolder); |
| | | |
| | | // delegate all config to baseFolder/gitblit.properties file |
| | | File localSettings = new File(baseFolder, "gitblit.properties"); |
| | | FileSettings fileSettings = new FileSettings(localSettings.getAbsolutePath()); |
| | | |
| | | // merge the stored settings into the runtime settings |
| | |
| | | } |
| | | |
| | | protected void extractResources(ServletContext context, String path, File toDir) { |
| | | for (String resource : context.getResourcePaths(path)) { |
| | | Set<String> resources = context.getResourcePaths(path); |
| | | if (resources == null) { |
| | | logger.warn("There are no WAR resources to extract from {}", path); |
| | | return; |
| | | } |
| | | for (String resource : resources) { |
| | | // extract the resource to the directory if it does not exist |
| | | File f = new File(toDir, resource.substring(path.length())); |
| | | if (!f.exists()) { |
| | |
| | | import java.text.MessageFormat;
|
| | |
|
| | | import javax.servlet.ServletException;
|
| | | import javax.servlet.http.HttpServlet;
|
| | | import javax.servlet.http.HttpServletRequest;
|
| | | import javax.servlet.http.HttpServletResponse;
|
| | |
|
| | |
| | | import org.slf4j.LoggerFactory;
|
| | |
|
| | | import com.gitblit.Constants;
|
| | | import com.gitblit.dagger.DaggerServlet;
|
| | | import com.gitblit.utils.JsonUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | |
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | public abstract class JsonServlet extends DaggerServlet {
|
| | | public abstract class JsonServlet extends HttpServlet {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | |
| | | import java.io.InputStream;
|
| | | import java.io.OutputStream;
|
| | |
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | | import javax.servlet.ServletContext;
|
| | | import javax.servlet.ServletException;
|
| | | import javax.servlet.http.HttpServlet;
|
| | | import javax.servlet.http.HttpServletRequest;
|
| | | import javax.servlet.http.HttpServletResponse;
|
| | |
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.dagger.DaggerServlet;
|
| | | import com.gitblit.manager.IRuntimeManager;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | |
|
| | | /**
|
| | | * Handles requests for logo.png
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | public class LogoServlet extends DaggerServlet {
|
| | | @Singleton
|
| | | public class LogoServlet extends HttpServlet {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | |
| | |
|
| | | private IRuntimeManager runtimeManager;
|
| | |
|
| | | @Override
|
| | | protected void inject(ObjectGraph dagger) {
|
| | | this.runtimeManager = dagger.get(IRuntimeManager.class);
|
| | | @Inject
|
| | | public LogoServlet(IRuntimeManager runtimeManager) {
|
| | | this.runtimeManager = runtimeManager;
|
| | | }
|
| | |
|
| | | @Override
|
| | |
| | | */
|
| | | package com.gitblit.servlet;
|
| | |
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | |
|
| | | import com.gitblit.manager.IAuthenticationManager;
|
| | | import com.gitblit.manager.IRepositoryManager;
|
| | | import com.gitblit.manager.IRuntimeManager;
|
| | |
|
| | |
|
| | | /**
|
| | | * The PagesFilter is an AccessRestrictionFilter which ensures the gh-pages
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | |
|
| | | @Singleton
|
| | | public class PagesFilter extends RawFilter {
|
| | |
|
| | | @Inject
|
| | | public PagesFilter(
|
| | | IRuntimeManager runtimeManager,
|
| | | IAuthenticationManager authenticationManager,
|
| | | IRepositoryManager repositoryManager) {
|
| | |
|
| | | super(runtimeManager, authenticationManager, repositoryManager);
|
| | | }
|
| | |
|
| | | }
|
| | |
| | | /*
|
| | | * Copyright 2012 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.servlet;
|
| | |
|
| | | import java.io.IOException;
|
| | | import java.io.InputStream;
|
| | | import java.util.Date;
|
| | |
|
| | | import javax.servlet.ServletException;
|
| | | import javax.servlet.http.HttpServletRequest;
|
| | | import javax.servlet.http.HttpServletResponse;
|
| | |
|
| | | import org.eclipse.jgit.lib.Repository;
|
| | | import org.eclipse.jgit.revwalk.RevCommit;
|
| | |
|
| | | import com.gitblit.Constants;
|
| | | import com.gitblit.utils.JGitUtils;
|
| | |
|
| | | /**
|
| | | * Serves the content of a gh-pages branch.
|
| | | *
|
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | public class PagesServlet extends RawServlet {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | |
|
| | | /**
|
| | | * Returns an url to this servlet for the specified parameters.
|
| | | *
|
| | | * @param baseURL
|
| | | * @param repository
|
| | | * @param path
|
| | | * @return an url
|
| | | */
|
| | | public static String asLink(String baseURL, String repository, String path) {
|
| | | if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') {
|
| | | baseURL = baseURL.substring(0, baseURL.length() - 1);
|
| | | }
|
| | | return baseURL + Constants.PAGES + repository + "/" + (path == null ? "" : ("/" + path));
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected String getBranch(String repository, HttpServletRequest request) {
|
| | | return "gh-pages";
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected String getPath(String repository, String branch, HttpServletRequest request) {
|
| | | String pi = request.getPathInfo().substring(1);
|
| | | if (pi.equals(repository)) {
|
| | | return "";
|
| | | }
|
| | | String path = pi.substring(pi.indexOf(repository) + repository.length() + 1);
|
| | | if (path.endsWith("/")) {
|
| | | path = path.substring(0, path.length() - 1);
|
| | | }
|
| | | return path;
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected boolean renderIndex() {
|
| | | return true;
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected void setContentType(HttpServletResponse response, String contentType) {
|
| | | response.setContentType(contentType);;
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected boolean streamFromRepo(HttpServletRequest request, HttpServletResponse response, Repository repository,
|
| | | RevCommit commit, String requestedPath) throws IOException {
|
| | |
|
| | | response.setDateHeader("Last-Modified", JGitUtils.getCommitDate(commit).getTime());
|
| | | response.setHeader("Cache-Control", "public, max-age=3600, must-revalidate");
|
| | |
|
| | | return super.streamFromRepo(request, response, repository, commit, requestedPath);
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected void sendContent(HttpServletResponse response, Date date, InputStream is) throws ServletException, IOException {
|
| | | response.setDateHeader("Last-Modified", date.getTime());
|
| | | response.setHeader("Cache-Control", "public, max-age=3600, must-revalidate");
|
| | |
|
| | | super.sendContent(response, date, is);
|
| | | }
|
| | | }
|
| | | /* |
| | | * Copyright 2012 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.servlet; |
| | | |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.util.Date; |
| | | |
| | | import javax.servlet.ServletException; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | |
| | | import org.eclipse.jgit.lib.Repository; |
| | | import org.eclipse.jgit.revwalk.RevCommit; |
| | | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.manager.IRepositoryManager; |
| | | import com.gitblit.manager.IRuntimeManager; |
| | | import com.gitblit.utils.JGitUtils; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Serves the content of a gh-pages branch. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class PagesServlet extends RawServlet { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | |
| | | /** |
| | | * Returns an url to this servlet for the specified parameters. |
| | | * |
| | | * @param baseURL |
| | | * @param repository |
| | | * @param path |
| | | * @return an url |
| | | */ |
| | | public static String asLink(String baseURL, String repository, String path) { |
| | | if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') { |
| | | baseURL = baseURL.substring(0, baseURL.length() - 1); |
| | | } |
| | | return baseURL + Constants.PAGES + repository + "/" + (path == null ? "" : ("/" + path)); |
| | | } |
| | | |
| | | @Inject |
| | | public PagesServlet( |
| | | IRuntimeManager runtimeManager, |
| | | IRepositoryManager repositoryManager) { |
| | | |
| | | super(runtimeManager, repositoryManager); |
| | | } |
| | | |
| | | @Override |
| | | protected String getBranch(String repository, HttpServletRequest request) { |
| | | return "gh-pages"; |
| | | } |
| | | |
| | | @Override |
| | | protected String getPath(String repository, String branch, HttpServletRequest request) { |
| | | String pi = request.getPathInfo().substring(1); |
| | | if (pi.equals(repository)) { |
| | | return ""; |
| | | } |
| | | String path = pi.substring(pi.indexOf(repository) + repository.length() + 1); |
| | | if (path.endsWith("/")) { |
| | | path = path.substring(0, path.length() - 1); |
| | | } |
| | | return path; |
| | | } |
| | | |
| | | @Override |
| | | protected boolean renderIndex() { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | protected void setContentType(HttpServletResponse response, String contentType) { |
| | | response.setContentType(contentType);; |
| | | } |
| | | |
| | | @Override |
| | | protected boolean streamFromRepo(HttpServletRequest request, HttpServletResponse response, Repository repository, |
| | | RevCommit commit, String requestedPath) throws IOException { |
| | | |
| | | response.setDateHeader("Last-Modified", JGitUtils.getCommitDate(commit).getTime()); |
| | | response.setHeader("Cache-Control", "public, max-age=3600, must-revalidate"); |
| | | |
| | | return super.streamFromRepo(request, response, repository, commit, requestedPath); |
| | | } |
| | | |
| | | @Override |
| | | protected void sendContent(HttpServletResponse response, Date date, InputStream is) throws ServletException, IOException { |
| | | response.setDateHeader("Last-Modified", date.getTime()); |
| | | response.setHeader("Cache-Control", "public, max-age=3600, must-revalidate"); |
| | | |
| | | super.sendContent(response, date, is); |
| | | } |
| | | } |
| | |
| | | package com.gitblit.servlet; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.ArrayList; |
| | | import java.util.Iterator; |
| | | import java.util.List; |
| | | |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | import javax.servlet.Filter; |
| | | import javax.servlet.FilterChain; |
| | | import javax.servlet.FilterConfig; |
| | | import javax.servlet.ServletException; |
| | |
| | | |
| | | import ro.fortsoft.pf4j.PluginWrapper; |
| | | |
| | | import com.gitblit.dagger.DaggerFilter; |
| | | import com.gitblit.extensions.HttpRequestFilter; |
| | | import com.gitblit.manager.IPluginManager; |
| | | import com.gitblit.manager.IRuntimeManager; |
| | | |
| | | import dagger.ObjectGraph; |
| | | |
| | | /** |
| | | * A request filter than allows registered extension request filters to access |
| | |
| | | * @author David Ostrovsky |
| | | * @since 1.6.0 |
| | | */ |
| | | public class ProxyFilter extends DaggerFilter { |
| | | private List<HttpRequestFilter> filters; |
| | | @Singleton |
| | | public class ProxyFilter implements Filter { |
| | | private final IRuntimeManager runtimeManager; |
| | | |
| | | private final IPluginManager pluginManager; |
| | | |
| | | private final List<HttpRequestFilter> filters; |
| | | |
| | | @Inject |
| | | public ProxyFilter( |
| | | IRuntimeManager runtimeManager, |
| | | IPluginManager pluginManager) { |
| | | |
| | | this.runtimeManager = runtimeManager; |
| | | this.pluginManager = pluginManager; |
| | | this.filters = new ArrayList<>(); |
| | | |
| | | } |
| | | |
| | | @Override |
| | | protected void inject(ObjectGraph dagger, FilterConfig filterConfig) throws ServletException { |
| | | IRuntimeManager runtimeManager = dagger.get(IRuntimeManager.class); |
| | | IPluginManager pluginManager = dagger.get(IPluginManager.class); |
| | | public void init(FilterConfig filterConfig) throws ServletException { |
| | | |
| | | filters = pluginManager.getExtensions(HttpRequestFilter.class); |
| | | filters.addAll(pluginManager.getExtensions(HttpRequestFilter.class)); |
| | | for (HttpRequestFilter f : filters) { |
| | | // wrap the filter config for Gitblit settings retrieval |
| | | PluginWrapper pluginWrapper = pluginManager.whichPlugin(f.getClass()); |
| | |
| | | import java.io.InputStream;
|
| | | import java.io.OutputStream;
|
| | |
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | | import javax.servlet.ServletException;
|
| | | import javax.servlet.http.HttpServlet;
|
| | | import javax.servlet.http.HttpServletRequest;
|
| | | import javax.servlet.http.HttpServletResponse;
|
| | |
|
| | |
| | | import org.apache.commons.compress.compressors.CompressorStreamFactory;
|
| | | import org.eclipse.jgit.lib.FileMode;
|
| | |
|
| | | import com.gitblit.dagger.DaggerServlet;
|
| | | import com.gitblit.manager.IRuntimeManager;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | |
|
| | | /**
|
| | | * Handles requests for the Barnum pt (patchset tool).
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | public class PtServlet extends DaggerServlet {
|
| | | @Singleton
|
| | | public class PtServlet extends HttpServlet {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | |
| | |
|
| | | private IRuntimeManager runtimeManager;
|
| | |
|
| | | @Override
|
| | | protected void inject(ObjectGraph dagger) {
|
| | | this.runtimeManager = dagger.get(IRuntimeManager.class);
|
| | | @Inject
|
| | | public PtServlet(IRuntimeManager runtimeManager) {
|
| | | this.runtimeManager = runtimeManager;
|
| | | }
|
| | |
|
| | | @Override
|
| | |
| | | */
|
| | | package com.gitblit.servlet;
|
| | |
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | |
|
| | | import org.eclipse.jgit.lib.Repository;
|
| | |
|
| | | import com.gitblit.Constants.AccessRestrictionType;
|
| | | import com.gitblit.manager.IAuthenticationManager;
|
| | | import com.gitblit.manager.IRepositoryManager;
|
| | | import com.gitblit.manager.IRuntimeManager;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.models.UserModel;
|
| | |
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | @Singleton
|
| | | public class RawFilter extends AccessRestrictionFilter {
|
| | |
|
| | | @Inject
|
| | | public RawFilter(
|
| | | IRuntimeManager runtimeManager,
|
| | | IAuthenticationManager authenticationManager,
|
| | | IRepositoryManager repositoryManager) {
|
| | |
|
| | | super(runtimeManager, authenticationManager, repositoryManager);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Extract the repository name from the url.
|
| | |
| | | * @return true if the filter allows repository creation
|
| | | */
|
| | | @Override
|
| | | protected boolean isCreationAllowed() {
|
| | | protected boolean isCreationAllowed(String action) {
|
| | | return false;
|
| | | }
|
| | |
|
| | |
| | | *
|
| | | * @param repository
|
| | | * @param action
|
| | | * @param method
|
| | | * @return true if the action may be performed
|
| | | */
|
| | | @Override
|
| | | protected boolean isActionAllowed(RepositoryModel repository, String action) {
|
| | | protected boolean isActionAllowed(RepositoryModel repository, String action, String method) {
|
| | | return true;
|
| | | }
|
| | |
|
| | |
| | | *
|
| | | * @param repository
|
| | | * @param action
|
| | | * @param method
|
| | | * @return true if authentication required
|
| | | */
|
| | | @Override
|
| | | protected boolean requiresAuthentication(RepositoryModel repository, String action) {
|
| | | protected boolean requiresAuthentication(RepositoryModel repository, String action, String method) {
|
| | | return repository.accessRestriction.atLeast(AccessRestrictionType.VIEW);
|
| | | }
|
| | |
|
| | |
| | | import java.text.ParseException; |
| | | import java.util.ArrayList; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.TreeMap; |
| | | |
| | | import javax.servlet.ServletContext; |
| | | import javax.servlet.ServletException; |
| | | import javax.servlet.http.HttpServlet; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | |
| | |
| | | |
| | | import com.gitblit.Constants; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.dagger.DaggerServlet; |
| | | import com.gitblit.manager.IRepositoryManager; |
| | | import com.gitblit.manager.IRuntimeManager; |
| | | import com.gitblit.models.PathModel; |
| | |
| | | import com.gitblit.utils.JGitUtils; |
| | | import com.gitblit.utils.MarkdownUtils; |
| | | import com.gitblit.utils.StringUtils; |
| | | |
| | | import dagger.ObjectGraph; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Serves the content of a branch. |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | public class RawServlet extends DaggerServlet { |
| | | @Singleton |
| | | public class RawServlet extends HttpServlet { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private transient Logger logger = LoggerFactory.getLogger(RawServlet.class); |
| | | |
| | | private IRuntimeManager runtimeManager; |
| | | private final IRuntimeManager runtimeManager; |
| | | |
| | | private IRepositoryManager repositoryManager; |
| | | private final IRepositoryManager repositoryManager; |
| | | |
| | | @Override |
| | | protected void inject(ObjectGraph dagger) { |
| | | this.runtimeManager = dagger.get(IRuntimeManager.class); |
| | | this.repositoryManager = dagger.get(IRepositoryManager.class); |
| | | @Inject |
| | | public RawServlet( |
| | | IRuntimeManager runtimeManager, |
| | | IRepositoryManager repositoryManager) { |
| | | |
| | | this.runtimeManager = runtimeManager; |
| | | this.repositoryManager = repositoryManager; |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | // determine repository and resource from url |
| | | String repository = ""; |
| | | String repository = path; |
| | | Repository r = null; |
| | | int offset = 0; |
| | | while (r == null) { |
| | | int slash = path.indexOf('/', offset); |
| | | if (slash == -1) { |
| | | repository = path; |
| | | } else { |
| | | repository = path.substring(0, slash); |
| | | } |
| | | offset = ( slash + 1 ); |
| | | int terminator = repository.length(); |
| | | do { |
| | | repository = repository.substring(0, terminator); |
| | | r = repositoryManager.getRepository(repository, false); |
| | | if (repository.equals(path)) { |
| | | // either only repository in url or no repository found |
| | | break; |
| | | } |
| | | } |
| | | terminator = repository.lastIndexOf('/'); |
| | | } while (r == null && terminator > -1 ); |
| | | |
| | | ServletContext context = request.getSession().getServletContext(); |
| | | |
| | |
| | | return; |
| | | } |
| | | |
| | | Map<String, String> quickContentTypes = new HashMap<>(); |
| | | quickContentTypes.put("html", "text/html"); |
| | | quickContentTypes.put("htm", "text/html"); |
| | | quickContentTypes.put("xml", "application/xml"); |
| | | quickContentTypes.put("json", "application/json"); |
| | | |
| | | List<PathModel> pathEntries = JGitUtils.getFilesInPath(r, requestedPath, commit); |
| | | if (pathEntries.isEmpty()) { |
| | | // requested a specific resource |
| | | String file = StringUtils.getLastPathElement(requestedPath); |
| | | try { |
| | | // query Tika for the content type |
| | | Tika tika = new Tika(); |
| | | String contentType = tika.detect(file); |
| | | |
| | | String ext = StringUtils.getFileExtension(file).toLowerCase(); |
| | | // We can't parse out an extension for classic "dotfiles", so make a general assumption that |
| | | // they're text files to allow presenting them in browser instead of only for download. |
| | | // |
| | | // However, that only holds for files with no other extension included, for files that happen |
| | | // to start with a dot but also include an extension, process the extension normally. |
| | | // This logic covers .gitattributes, .gitignore, .zshrc, etc., but does not cover .mongorc.js, .zshrc.bak |
| | | boolean isExtensionlessDotfile = file.charAt(0) == '.' && (file.length() == 1 || file.indexOf('.', 1) < 0); |
| | | String contentType = isExtensionlessDotfile ? "text/plain" : quickContentTypes.get(ext); |
| | | |
| | | if (contentType == null) { |
| | | List<String> exts = runtimeManager.getSettings().getStrings(Keys.web.prettyPrintExtensions); |
| | | if (exts.contains(ext)) { |
| | | // extension is a registered text type for pretty printing |
| | | contentType = "text/plain"; |
| | | } else { |
| | | // query Tika for the content type |
| | | Tika tika = new Tika(); |
| | | contentType = tika.detect(file); |
| | | } |
| | | } |
| | | |
| | | if (contentType == null) { |
| | | // ask the container for the content type |
| | |
| | | } |
| | | } |
| | | |
| | | if (isTextType(contentType)) { |
| | | if (isTextType(contentType) || isTextDataType(contentType)) { |
| | | |
| | | // load, interpret, and serve text content as UTF-8 |
| | | String [] encodings = runtimeManager.getSettings().getStrings(Keys.web.blobEncodings).toArray(new String[0]); |
| | |
| | | if (pathEntries.get(0).path.indexOf('/') > -1) { |
| | | // we are in a subdirectory, add parent directory link |
| | | String pp = URLEncoder.encode(requestedPath, Constants.ENCODING); |
| | | pathEntries.add(0, new PathModel("..", pp + "/..", 0, FileMode.TREE.getBits(), null, null)); |
| | | pathEntries.add(0, new PathModel("..", pp + "/..", null, 0, FileMode.TREE.getBits(), null, null)); |
| | | } |
| | | } |
| | | |
| | |
| | | if (contentType.startsWith("text/") |
| | | || "application/json".equals(contentType) |
| | | || "application/xml".equals(contentType)) { |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | protected boolean isTextDataType(String contentType) { |
| | | if ("image/svg+xml".equals(contentType)) { |
| | | return true; |
| | | } |
| | | return false; |
| | |
| | | served = true; |
| | | } |
| | | } finally { |
| | | tw.release(); |
| | | tw.close(); |
| | | rw.dispose(); |
| | | } |
| | | |
| | |
| | | import java.io.File;
|
| | | import java.io.IOException;
|
| | |
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | | import javax.servlet.ServletException;
|
| | | import javax.servlet.http.HttpServlet;
|
| | | import javax.servlet.http.HttpServletRequest;
|
| | | import javax.servlet.http.HttpServletResponse;
|
| | |
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.dagger.DaggerServlet;
|
| | | import com.gitblit.manager.IRuntimeManager;
|
| | | import com.gitblit.utils.FileUtils;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | |
|
| | | /**
|
| | | * Handles requests for robots.txt
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | public class RobotsTxtServlet extends DaggerServlet {
|
| | | @Singleton
|
| | | public class RobotsTxtServlet extends HttpServlet {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | private IRuntimeManager runtimeManager;
|
| | |
|
| | | @Override
|
| | | protected void inject(ObjectGraph dagger) {
|
| | | this.runtimeManager = dagger.get(IRuntimeManager.class);
|
| | | @Inject
|
| | | public RobotsTxtServlet(IRuntimeManager runtimeManager) {
|
| | | this.runtimeManager = runtimeManager;
|
| | | }
|
| | |
|
| | | @Override
|
| | |
| | | import java.io.IOException;
|
| | | import java.text.MessageFormat;
|
| | |
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | | import javax.servlet.FilterChain;
|
| | | import javax.servlet.FilterConfig;
|
| | | import javax.servlet.ServletException;
|
| | | import javax.servlet.ServletRequest;
|
| | | import javax.servlet.ServletResponse;
|
| | |
| | | import com.gitblit.Constants.RpcRequest;
|
| | | import com.gitblit.IStoredSettings;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.manager.IAuthenticationManager;
|
| | | import com.gitblit.manager.IRuntimeManager;
|
| | | import com.gitblit.models.UserModel;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | |
|
| | | /**
|
| | | * The RpcFilter is a servlet filter that secures the RpcServlet.
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | @Singleton
|
| | | public class RpcFilter extends AuthenticationFilter {
|
| | |
|
| | | private IStoredSettings settings;
|
| | |
|
| | | private IRuntimeManager runtimeManager;
|
| | |
|
| | | @Override
|
| | | protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
|
| | | super.inject(dagger, filterConfig);
|
| | | this.settings = dagger.get(IStoredSettings.class);
|
| | | this.runtimeManager = dagger.get(IRuntimeManager.class);
|
| | | @Inject
|
| | | public RpcFilter(
|
| | | IStoredSettings settings,
|
| | | IRuntimeManager runtimeManager,
|
| | | IAuthenticationManager authenticationManager) {
|
| | |
|
| | | super(authenticationManager);
|
| | |
|
| | | this.settings = settings;
|
| | | this.runtimeManager = runtimeManager;
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | return;
|
| | | } else {
|
| | | // check user access for request
|
| | | if (user.canAdmin() || canAccess(user, requestType)) {
|
| | | if (user.canAdmin() || !adminRequest) {
|
| | | // authenticated request permitted.
|
| | | // pass processing to the restricted servlet.
|
| | | newSession(authenticatedRequest, httpResponse);
|
| | |
| | | // pass processing to the restricted servlet.
|
| | | chain.doFilter(authenticatedRequest, httpResponse);
|
| | | }
|
| | |
|
| | | private boolean canAccess(UserModel user, RpcRequest requestType) {
|
| | | switch (requestType) {
|
| | | case GET_PROTOCOL:
|
| | | return true;
|
| | | case LIST_REPOSITORIES:
|
| | | return true;
|
| | | default:
|
| | | return user.canAdmin();
|
| | | }
|
| | | }
|
| | | } |
| | | }
|
| | |
| | | import java.util.List;
|
| | | import java.util.Map;
|
| | |
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | | import javax.servlet.ServletException;
|
| | | import javax.servlet.http.HttpServletRequest;
|
| | | import javax.servlet.http.HttpServletResponse;
|
| | |
| | | import com.gitblit.utils.RpcUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | |
|
| | | /**
|
| | | * Handles remote procedure calls.
|
| | | *
|
| | | * @author James Moger
|
| | | */
|
| | | @Singleton
|
| | | public class RpcServlet extends JsonServlet {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
| | |
|
| | | private IGitblit gitblit;
|
| | |
|
| | | @Override
|
| | | protected void inject(ObjectGraph dagger) {
|
| | | this.settings = dagger.get(IStoredSettings.class);
|
| | | this.gitblit = dagger.get(IGitblit.class);
|
| | | @Inject
|
| | | public RpcServlet(IStoredSettings settings, IGitblit gitblit) {
|
| | | this.settings = settings;
|
| | | this.gitblit = gitblit;
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | import java.text.MessageFormat;
|
| | |
|
| | | import javax.servlet.ServletException;
|
| | | import javax.servlet.http.HttpServlet;
|
| | | import javax.servlet.http.HttpServletRequest;
|
| | | import javax.servlet.http.HttpServletResponse;
|
| | |
|
| | | import com.gitblit.IStoredSettings;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.dagger.DaggerServlet;
|
| | | import com.gitblit.manager.IAuthenticationManager;
|
| | | import com.gitblit.manager.IRepositoryManager;
|
| | | import com.gitblit.manager.IUserManager;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.models.UserModel;
|
| | | import com.gitblit.utils.StringUtils;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | |
|
| | | /**
|
| | | * Handles requests for Sparkleshare Invites
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | public class SparkleShareInviteServlet extends DaggerServlet {
|
| | | @Singleton
|
| | | public class SparkleShareInviteServlet extends HttpServlet {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | |
| | |
|
| | | private IRepositoryManager repositoryManager;
|
| | |
|
| | | @Override
|
| | | protected void inject(ObjectGraph dagger) {
|
| | | this.settings = dagger.get(IStoredSettings.class);
|
| | | this.userManager = dagger.get(IUserManager.class);
|
| | | this.authenticationManager = dagger.get(IAuthenticationManager.class);
|
| | | this.repositoryManager = dagger.get(IRepositoryManager.class);
|
| | | @Inject
|
| | | public SparkleShareInviteServlet(
|
| | | IStoredSettings settings,
|
| | | IUserManager userManager,
|
| | | IAuthenticationManager authenticationManager,
|
| | | IRepositoryManager repositoryManager) {
|
| | |
|
| | | this.settings = settings;
|
| | | this.userManager = userManager;
|
| | | this.authenticationManager = authenticationManager;
|
| | | this.repositoryManager = repositoryManager;
|
| | | }
|
| | |
|
| | | @Override
|
| | |
| | | response.getWriter().append("SSH is not active on this server!");
|
| | | return;
|
| | | }
|
| | | int sshDisplayPort = settings.getInteger(Keys.git.sshAdvertisedPort, sshPort);
|
| | |
|
| | | // extract repo name from request
|
| | | String repoUrl = request.getPathInfo().substring(1);
|
| | |
|
| | |
| | | String url = settings.getString(Keys.web.canonicalUrl, "https://localhost:8443");
|
| | | if (!StringUtils.isEmpty(url) && url.indexOf("localhost") == -1) {
|
| | | host = new URL(url).getHost();
|
| | | }
|
| | | String sshDisplayHost = settings.getString(Keys.git.sshAdvertisedHost, "");
|
| | | if(sshDisplayHost.isEmpty()) {
|
| | | sshDisplayHost = host;
|
| | | }
|
| | |
|
| | | UserModel user;
|
| | |
| | | StringBuilder sb = new StringBuilder();
|
| | | sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
| | | sb.append("<sparkleshare><invite>\n");
|
| | | sb.append(MessageFormat.format("<address>ssh://{0}@{1}:{2,number,0}/</address>\n", user.username, host, sshPort));
|
| | | sb.append(MessageFormat.format("<address>ssh://{0}@{1}:{2,number,0}/</address>\n", user.username, sshDisplayHost, sshDisplayPort));
|
| | | sb.append(MessageFormat.format("<remote_path>/{0}</remote_path>\n", model.name));
|
| | | int fanoutPort = settings.getInteger(Keys.fanout.port, 0);
|
| | | if (fanoutPort > 0) {
|
| | |
| | | import java.io.IOException;
|
| | | import java.text.MessageFormat;
|
| | |
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | | import javax.servlet.FilterChain;
|
| | | import javax.servlet.FilterConfig;
|
| | | import javax.servlet.ServletException;
|
| | | import javax.servlet.ServletRequest;
|
| | | import javax.servlet.ServletResponse;
|
| | |
| | | import javax.servlet.http.HttpServletResponse;
|
| | |
|
| | | import com.gitblit.Constants.AccessRestrictionType;
|
| | | import com.gitblit.manager.IAuthenticationManager;
|
| | | import com.gitblit.manager.IProjectManager;
|
| | | import com.gitblit.manager.IRepositoryManager;
|
| | | import com.gitblit.manager.IRuntimeManager;
|
| | | import com.gitblit.models.ProjectModel;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.models.UserModel;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | |
|
| | | /**
|
| | | * The SyndicationFilter is an AuthenticationFilter which ensures that feed
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | @Singleton
|
| | | public class SyndicationFilter extends AuthenticationFilter {
|
| | |
|
| | | private IRuntimeManager runtimeManager;
|
| | | private IRepositoryManager repositoryManager;
|
| | | private IProjectManager projectManager;
|
| | |
|
| | | @Override
|
| | | protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
|
| | | super.inject(dagger, filterConfig);
|
| | | this.runtimeManager = dagger.get(IRuntimeManager.class);
|
| | | this.repositoryManager = dagger.get(IRepositoryManager.class);
|
| | | this.projectManager = dagger.get(IProjectManager.class);
|
| | | @Inject
|
| | | public SyndicationFilter(
|
| | | IRuntimeManager runtimeManager,
|
| | | IAuthenticationManager authenticationManager,
|
| | | IRepositoryManager repositoryManager,
|
| | | IProjectManager projectManager) {
|
| | | super(authenticationManager);
|
| | |
|
| | | this.runtimeManager = runtimeManager;
|
| | | this.repositoryManager = repositoryManager;
|
| | | this.projectManager = projectManager;
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | import java.util.List;
|
| | | import java.util.Map;
|
| | |
|
| | | import javax.servlet.http.HttpServlet;
|
| | |
|
| | | import org.eclipse.jgit.lib.ObjectId;
|
| | | import org.eclipse.jgit.lib.Repository;
|
| | | import org.eclipse.jgit.revwalk.RevCommit;
|
| | |
| | | import com.gitblit.Constants;
|
| | | import com.gitblit.IStoredSettings;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.dagger.DaggerServlet;
|
| | | import com.gitblit.manager.IProjectManager;
|
| | | import com.gitblit.manager.IRepositoryManager;
|
| | | import com.gitblit.models.FeedEntryModel;
|
| | |
| | | import com.gitblit.utils.JGitUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | | import com.gitblit.utils.SyndicationUtils;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | |
|
| | | /**
|
| | | * SyndicationServlet generates RSS 2.0 feeds and feed links.
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | public class SyndicationServlet extends DaggerServlet {
|
| | | @Singleton
|
| | | public class SyndicationServlet extends HttpServlet {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | |
| | |
|
| | | private IProjectManager projectManager;
|
| | |
|
| | | @Override
|
| | | protected void inject(ObjectGraph dagger) {
|
| | | this.settings = dagger.get(IStoredSettings.class);
|
| | | this.repositoryManager = dagger.get(IRepositoryManager.class);
|
| | | this.projectManager = dagger.get(IProjectManager.class);
|
| | | @Inject
|
| | | public SyndicationServlet(
|
| | | IStoredSettings settings,
|
| | | IRepositoryManager repositoryManager,
|
| | | IProjectManager projectManager) {
|
| | |
|
| | | this.settings = settings;
|
| | | this.repositoryManager = repositoryManager;
|
| | | this.projectManager = projectManager;
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | if (mountParameters) {
|
| | | // mounted url
|
| | | feedLink = MessageFormat.format("{0}/summary/{1}", gitblitUrl,
|
| | | StringUtils.encodeURL(feedName));
|
| | | StringUtils.encodeURL(feedName.replace('/', fsc)));
|
| | | } else {
|
| | | // parameterized url
|
| | | feedLink = MessageFormat.format("{0}/summary/?r={1}", gitblitUrl,
|
| | |
| | | import java.text.MessageFormat; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | |
| | | import java.util.concurrent.atomic.AtomicLong; |
| | | |
| | | import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException; |
| | | import org.eclipse.jgit.api.errors.JGitInternalException; |
| | | import org.eclipse.jgit.dircache.DirCache; |
| | | import org.eclipse.jgit.dircache.DirCacheBuilder; |
| | | import org.eclipse.jgit.dircache.DirCacheEntry; |
| | | import org.eclipse.jgit.events.RefsChangedEvent; |
| | | import org.eclipse.jgit.events.RefsChangedListener; |
| | | import org.eclipse.jgit.internal.JGitText; |
| | | import org.eclipse.jgit.lib.CommitBuilder; |
| | | import org.eclipse.jgit.lib.FileMode; |
| | | import org.eclipse.jgit.lib.ObjectId; |
| | | import org.eclipse.jgit.lib.ObjectInserter; |
| | | import org.eclipse.jgit.lib.PersonIdent; |
| | | import org.eclipse.jgit.lib.Ref; |
| | | import org.eclipse.jgit.lib.RefRename; |
| | | import org.eclipse.jgit.lib.RefUpdate; |
| | | import org.eclipse.jgit.lib.RefUpdate.Result; |
| | | import org.eclipse.jgit.lib.Repository; |
| | | import org.eclipse.jgit.revwalk.RevCommit; |
| | |
| | | import com.gitblit.utils.ArrayUtils; |
| | | import com.gitblit.utils.JGitUtils; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Implementation of a ticket service based on an orphan branch. All tickets |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class BranchTicketService extends ITicketService implements RefsChangedListener { |
| | | |
| | | public static final String BRANCH = "refs/meta/gitblit/tickets"; |
| | |
| | | |
| | | private final Map<String, AtomicLong> lastAssignedId; |
| | | |
| | | @Inject |
| | | public BranchTicketService( |
| | | IRuntimeManager runtimeManager, |
| | | IPluginManager pluginManager, |
| | |
| | | |
| | | @Override |
| | | public BranchTicketService start() { |
| | | log.info("{} started", getClass().getSimpleName()); |
| | | return this; |
| | | } |
| | | |
| | |
| | | log.error("failed to read " + file, e); |
| | | } finally { |
| | | if (rw != null) { |
| | | rw.release(); |
| | | rw.close(); |
| | | } |
| | | } |
| | | return null; |
| | |
| | | Set<String> ignorePaths = new HashSet<String>(); |
| | | ignorePaths.add(file); |
| | | |
| | | for (DirCacheEntry entry : getTreeEntries(db, ignorePaths)) { |
| | | for (DirCacheEntry entry : JGitUtils.getTreeEntries(db, BRANCH, ignorePaths)) { |
| | | builder.add(entry); |
| | | } |
| | | |
| | |
| | | } catch (IOException e) { |
| | | log.error("", e); |
| | | } finally { |
| | | inserter.release(); |
| | | inserter.close(); |
| | | } |
| | | } |
| | | |
| | |
| | | } finally { |
| | | // release the treewalk |
| | | if (treeWalk != null) { |
| | | treeWalk.release(); |
| | | treeWalk.close(); |
| | | } |
| | | } |
| | | } finally { |
| | |
| | | } |
| | | } |
| | | |
| | | for (DirCacheEntry entry : getTreeEntries(db, ignorePaths)) { |
| | | for (DirCacheEntry entry : JGitUtils.getTreeEntries(db, BRANCH, ignorePaths)) { |
| | | builder.add(entry); |
| | | } |
| | | |
| | | // finish the index |
| | | builder.finish(); |
| | | } finally { |
| | | inserter.release(); |
| | | inserter.close(); |
| | | } |
| | | return newIndex; |
| | | } |
| | | |
| | | /** |
| | | * Returns all tree entries that do not match the ignore paths. |
| | | * |
| | | * @param db |
| | | * @param ignorePaths |
| | | * @param dcBuilder |
| | | * @throws IOException |
| | | */ |
| | | private List<DirCacheEntry> getTreeEntries(Repository db, Collection<String> ignorePaths) throws IOException { |
| | | List<DirCacheEntry> list = new ArrayList<DirCacheEntry>(); |
| | | TreeWalk tw = null; |
| | | try { |
| | | ObjectId treeId = db.resolve(BRANCH + "^{tree}"); |
| | | if (treeId == null) { |
| | | // branch does not exist yet, could be migrating tickets |
| | | return list; |
| | | } |
| | | tw = new TreeWalk(db); |
| | | int hIdx = tw.addTree(treeId); |
| | | tw.setRecursive(true); |
| | | |
| | | while (tw.next()) { |
| | | String path = tw.getPathString(); |
| | | CanonicalTreeParser hTree = null; |
| | | if (hIdx != -1) { |
| | | hTree = tw.getTree(hIdx, CanonicalTreeParser.class); |
| | | } |
| | | if (!ignorePaths.contains(path)) { |
| | | // add all other tree entries |
| | | if (hTree != null) { |
| | | final DirCacheEntry entry = new DirCacheEntry(path); |
| | | entry.setObjectId(hTree.getEntryObjectId()); |
| | | entry.setFileMode(hTree.getEntryFileMode()); |
| | | list.add(entry); |
| | | } |
| | | } |
| | | } |
| | | } finally { |
| | | if (tw != null) { |
| | | tw.release(); |
| | | } |
| | | } |
| | | return list; |
| | | } |
| | | |
| | | private boolean commitIndex(Repository db, DirCache index, String author, String message) throws IOException, ConcurrentRefUpdateException { |
| | | final boolean forceCommit = true; |
| | | boolean success = false; |
| | | |
| | | |
| | | ObjectId headId = db.resolve(BRANCH + "^{commit}"); |
| | | if (headId == null) { |
| | | // create the branch |
| | | createTicketsBranch(db); |
| | | headId = db.resolve(BRANCH + "^{commit}"); |
| | | } |
| | | ObjectInserter odi = db.newObjectInserter(); |
| | | try { |
| | | // Create the in-memory index of the new/updated ticket |
| | | ObjectId indexTreeId = index.writeTree(odi); |
| | | |
| | | // Create a commit object |
| | | PersonIdent ident = new PersonIdent(author, "gitblit@localhost"); |
| | | CommitBuilder commit = new CommitBuilder(); |
| | | commit.setAuthor(ident); |
| | | commit.setCommitter(ident); |
| | | commit.setEncoding(Constants.ENCODING); |
| | | commit.setMessage(message); |
| | | commit.setParentId(headId); |
| | | commit.setTreeId(indexTreeId); |
| | | |
| | | // Insert the commit into the repository |
| | | ObjectId commitId = odi.insert(commit); |
| | | odi.flush(); |
| | | |
| | | RevWalk revWalk = new RevWalk(db); |
| | | try { |
| | | RevCommit revCommit = revWalk.parseCommit(commitId); |
| | | RefUpdate ru = db.updateRef(BRANCH); |
| | | ru.setNewObjectId(commitId); |
| | | ru.setExpectedOldObjectId(headId); |
| | | ru.setRefLogMessage("commit: " + revCommit.getShortMessage(), false); |
| | | Result rc = ru.forceUpdate(); |
| | | switch (rc) { |
| | | case NEW: |
| | | case FORCED: |
| | | case FAST_FORWARD: |
| | | success = true; |
| | | break; |
| | | case REJECTED: |
| | | case LOCK_FAILURE: |
| | | throw new ConcurrentRefUpdateException(JGitText.get().couldNotLockHEAD, |
| | | ru.getRef(), rc); |
| | | default: |
| | | throw new JGitInternalException(MessageFormat.format( |
| | | JGitText.get().updatingRefFailed, BRANCH, commitId.toString(), |
| | | rc)); |
| | | } |
| | | } finally { |
| | | revWalk.release(); |
| | | } |
| | | } finally { |
| | | odi.release(); |
| | | } |
| | | |
| | | success = JGitUtils.commitIndex(db, BRANCH, index, headId, forceCommit, author, "gitblit@localhost", message); |
| | | |
| | | return success; |
| | | } |
| | | |
| | |
| | | import com.gitblit.utils.ArrayUtils; |
| | | import com.gitblit.utils.FileUtils; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Implementation of a ticket service based on a directory within the repository. |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class FileTicketService extends ITicketService { |
| | | |
| | | private static final String JOURNAL = "journal.json"; |
| | |
| | | |
| | | private final Map<String, AtomicLong> lastAssignedId; |
| | | |
| | | @Inject |
| | | public FileTicketService( |
| | | IRuntimeManager runtimeManager, |
| | | IPluginManager pluginManager, |
| | |
| | | |
| | | @Override |
| | | public FileTicketService start() { |
| | | log.info("{} started", getClass().getSimpleName()); |
| | | return this; |
| | | } |
| | | |
| | |
| | | @Override |
| | | protected boolean deleteAllImpl(RepositoryModel repository) { |
| | | Repository db = repositoryManager.getRepository(repository.name); |
| | | if (db == null) { |
| | | // the tickets no longer exist because the db no longer exists |
| | | return true; |
| | | } |
| | | try { |
| | | File dir = new File(db.getDirectory(), TICKETS_PATH); |
| | | return FileUtils.delete(dir); |
| | |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.extensions.TicketHook; |
| | | import com.gitblit.manager.IManager; |
| | | import com.gitblit.manager.INotificationManager; |
| | | import com.gitblit.manager.IPluginManager; |
| | | import com.gitblit.manager.IRepositoryManager; |
| | |
| | | import com.gitblit.models.TicketModel.Change; |
| | | import com.gitblit.models.TicketModel.Field; |
| | | import com.gitblit.models.TicketModel.Patchset; |
| | | import com.gitblit.models.TicketModel.PatchsetType; |
| | | import com.gitblit.models.TicketModel.Status; |
| | | import com.gitblit.tickets.TicketIndexer.Lucene; |
| | | import com.gitblit.utils.DeepCopier; |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | public abstract class ITicketService { |
| | | public abstract class ITicketService implements IManager { |
| | | |
| | | public static final String SETTING_UPDATE_DIFFSTATS = "migration.updateDiffstats"; |
| | | |
| | |
| | | * Start the service. |
| | | * @since 1.4.0 |
| | | */ |
| | | @Override |
| | | public abstract ITicketService start(); |
| | | |
| | | /** |
| | | * Stop the service. |
| | | * @since 1.4.0 |
| | | */ |
| | | @Override |
| | | public final ITicketService stop() { |
| | | indexer.close(); |
| | | ticketsCache.invalidateAll(); |
| | |
| | | TicketModel revisedTicket = updateTicket(repository, ticket.number, deletion); |
| | | return revisedTicket; |
| | | } |
| | | |
| | | /** |
| | | * Deletes a patchset from a ticket. |
| | | * |
| | | * @param ticket |
| | | * @param patchset |
| | | * the patchset to delete (should be the highest revision) |
| | | * @param userName |
| | | * the user deleting the commit |
| | | * @return the revised ticket if the deletion was successful |
| | | * @since 1.8.0 |
| | | */ |
| | | public final TicketModel deletePatchset(TicketModel ticket, Patchset patchset, String userName) { |
| | | Change deletion = new Change(userName); |
| | | deletion.patchset = new Patchset(); |
| | | deletion.patchset.number = patchset.number; |
| | | deletion.patchset.rev = patchset.rev; |
| | | deletion.patchset.type = PatchsetType.Delete; |
| | | |
| | | RepositoryModel repository = repositoryManager.getRepositoryModel(ticket.repository); |
| | | TicketModel revisedTicket = updateTicket(repository, ticket.number, deletion); |
| | | |
| | | return revisedTicket; |
| | | } |
| | | |
| | | /** |
| | | * Commit a ticket change to the repository. |
| | |
| | | import com.gitblit.models.TicketModel; |
| | | import com.gitblit.models.TicketModel.Attachment; |
| | | import com.gitblit.models.TicketModel.Change; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Implementation of a ticket service that rejects everything. |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class NullTicketService extends ITicketService { |
| | | |
| | | @Inject |
| | | public NullTicketService( |
| | | IRuntimeManager runtimeManager, |
| | | IPluginManager pluginManager, |
| | |
| | | |
| | | @Override |
| | | public NullTicketService start() { |
| | | log.info("{} started", getClass().getSimpleName()); |
| | | return this; |
| | | } |
| | | |
| | |
| | | import com.gitblit.models.TicketModel.Patchset; |
| | | import com.gitblit.models.TicketModel.Status; |
| | | import com.gitblit.models.TicketModel.Type; |
| | | import com.gitblit.models.TicketModel.Priority; |
| | | import com.gitblit.models.TicketModel.Severity; |
| | | import com.gitblit.utils.StringUtils; |
| | | |
| | | /** |
| | |
| | | public int commentsCount; |
| | | public int votesCount; |
| | | public int approvalsCount; |
| | | public Priority priority; |
| | | public Severity severity; |
| | | |
| | | public int docId; |
| | | public int totalResults; |
| | |
| | | import com.gitblit.models.TicketModel.Change; |
| | | import com.gitblit.utils.ArrayUtils; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Implementation of a ticket service based on a Redis key-value store. All |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class RedisTicketService extends ITicketService { |
| | | |
| | | private final JedisPool pool; |
| | |
| | | journal, ticket, counter |
| | | } |
| | | |
| | | @Inject |
| | | public RedisTicketService( |
| | | IRuntimeManager runtimeManager, |
| | | IPluginManager pluginManager, |
| | |
| | | |
| | | @Override |
| | | public RedisTicketService start() { |
| | | log.info("{} started", getClass().getSimpleName()); |
| | | if (!isReady()) { |
| | | log.warn("{} is not ready!", getClass().getSimpleName()); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | |
| | | mergesha(Type.STRING), |
| | | mergeto(Type.STRING), |
| | | patchsets(Type.INT), |
| | | votes(Type.INT); |
| | | votes(Type.INT), |
| | | //NOTE: Indexing on the underlying value to allow flexibility on naming |
| | | priority(Type.INT), |
| | | severity(Type.INT); |
| | | |
| | | final Type fieldType; |
| | | |
| | |
| | | toDocField(doc, Lucene.watchedby, StringUtils.flattenStrings(ticket.getWatchers(), ";").toLowerCase()); |
| | | toDocField(doc, Lucene.mentions, StringUtils.flattenStrings(ticket.getMentions(), ";").toLowerCase()); |
| | | toDocField(doc, Lucene.votes, ticket.getVoters().size()); |
| | | toDocField(doc, Lucene.priority, ticket.priority.getValue()); |
| | | toDocField(doc, Lucene.severity, ticket.severity.getValue()); |
| | | |
| | | List<String> attachments = new ArrayList<String>(); |
| | | for (Attachment attachment : ticket.getAttachments()) { |
| | |
| | | result.participants = unpackStrings(doc, Lucene.participants); |
| | | result.watchedby = unpackStrings(doc, Lucene.watchedby); |
| | | result.mentions = unpackStrings(doc, Lucene.mentions); |
| | | result.priority = TicketModel.Priority.fromObject(unpackInt(doc, Lucene.priority), TicketModel.Priority.defaultPriority); |
| | | result.severity = TicketModel.Severity.fromObject(unpackInt(doc, Lucene.severity), TicketModel.Severity.defaultSeverity); |
| | | |
| | | if (!StringUtils.isEmpty(doc.get(Lucene.patchset.name()))) { |
| | | // unpack most recent patchset |
| | |
| | | StringBuilder html = new StringBuilder(); |
| | | html.append("<head>"); |
| | | html.append(readStyle()); |
| | | html.append(readViewTicketAction(ticket)); |
| | | html.append("</head>"); |
| | | html.append("<body>"); |
| | | html.append(MarkdownUtils.transformGFM(settings, markdown, ticket.repository)); |
| | |
| | | return sb.toString(); |
| | | } |
| | | |
| | | protected String readViewTicketAction(TicketModel ticket) { |
| | | String action = readResource("viewTicket.html"); |
| | | action = action.replace("${url}", ticketService.getTicketUrl(ticket)); |
| | | return action; |
| | | } |
| | | |
| | | protected String readResource(String resource) { |
| | | StringBuilder sb = new StringBuilder(); |
| | | InputStream is = null; |
New file |
| | |
| | | <script type="application/ld+json"> |
| | | { |
| | | "@context": "http://schema.org", |
| | | "@type": "EmailMessage", |
| | | "description": "View this Ticket in Gitblit", |
| | | "action": { |
| | | "@type": "ViewAction", |
| | | "url": "${url}", |
| | | "name": "View Ticket" |
| | | } |
| | | } |
| | | </script> |
| | |
| | | package com.gitblit.transport.ssh; |
| | | |
| | | import java.io.IOException; |
| | | import java.nio.file.FileSystem; |
| | | |
| | | import org.apache.sshd.common.Session; |
| | | import org.apache.sshd.common.file.FileSystemFactory; |
| | | import org.apache.sshd.common.file.FileSystemView; |
| | | import org.apache.sshd.common.file.SshFile; |
| | | import org.apache.sshd.common.session.Session; |
| | | |
| | | public class DisabledFilesystemFactory implements FileSystemFactory { |
| | | |
| | | @Override |
| | | public FileSystemView createFileSystemView(Session session) throws IOException { |
| | | return new FileSystemView() { |
| | | @Override |
| | | public SshFile getFile(SshFile baseDir, String file) { |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public SshFile getFile(String file) { |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public FileSystemView getNormalizedView() { |
| | | return null; |
| | | } |
| | | }; |
| | | } |
| | | /** |
| | | * Create user specific file system. |
| | | * |
| | | * @param session The session created for the user |
| | | * @return The current {@link FileSystem} for the provided session |
| | | * @throws java.io.IOException when the filesystem can not be created |
| | | */ |
| | | @Override |
| | | public FileSystem createFileSystem(Session session) throws IOException { |
| | | return null; |
| | | } |
| | | } |
| | |
| | | import com.google.common.base.Charsets; |
| | | import com.google.common.base.Joiner; |
| | | import com.google.common.io.Files; |
| | | import com.google.inject.Inject; |
| | | |
| | | /** |
| | | * Manages public keys on the filesystem. |
| | |
| | | |
| | | protected final Map<File, Long> lastModifieds; |
| | | |
| | | @Inject |
| | | public FileKeyManager(IRuntimeManager runtimeManager) { |
| | | this.runtimeManager = runtimeManager; |
| | | this.lastModifieds = new ConcurrentHashMap<File, Long>(); |
New file |
| | |
| | | /* |
| | | * Licensed to the Apache Software Foundation (ASF) under one |
| | | * or more contributor license agreements. See the NOTICE file |
| | | * distributed with this work for additional information |
| | | * regarding copyright ownership. The ASF licenses this file |
| | | * to you 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.transport.ssh; |
| | | |
| | | import java.io.FileInputStream; |
| | | import java.io.InputStreamReader; |
| | | import java.security.KeyPair; |
| | | import java.util.Arrays; |
| | | import java.util.Iterator; |
| | | import java.util.NoSuchElementException; |
| | | |
| | | import org.apache.sshd.common.keyprovider.AbstractKeyPairProvider; |
| | | import org.apache.sshd.common.util.SecurityUtils; |
| | | import org.bouncycastle.openssl.PEMDecryptorProvider; |
| | | import org.bouncycastle.openssl.PEMEncryptedKeyPair; |
| | | import org.bouncycastle.openssl.PEMKeyPair; |
| | | import org.bouncycastle.openssl.PEMParser; |
| | | import org.bouncycastle.openssl.PasswordFinder; |
| | | import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; |
| | | import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; |
| | | |
| | | /** |
| | | * This host key provider loads private keys from the specified files. |
| | | * |
| | | * Note that this class has a direct dependency on BouncyCastle and won't work |
| | | * unless it has been correctly registered as a security provider. |
| | | * |
| | | * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a> |
| | | */ |
| | | public class FileKeyPairProvider extends AbstractKeyPairProvider { |
| | | |
| | | private String[] files; |
| | | private PasswordFinder passwordFinder; |
| | | |
| | | public FileKeyPairProvider() { |
| | | } |
| | | |
| | | public FileKeyPairProvider(String[] files) { |
| | | this.files = files; |
| | | } |
| | | |
| | | public FileKeyPairProvider(String[] files, PasswordFinder passwordFinder) { |
| | | this.files = files; |
| | | this.passwordFinder = passwordFinder; |
| | | } |
| | | |
| | | public String[] getFiles() { |
| | | return files; |
| | | } |
| | | |
| | | public void setFiles(String[] files) { |
| | | this.files = files; |
| | | } |
| | | |
| | | public PasswordFinder getPasswordFinder() { |
| | | return passwordFinder; |
| | | } |
| | | |
| | | public void setPasswordFinder(PasswordFinder passwordFinder) { |
| | | this.passwordFinder = passwordFinder; |
| | | } |
| | | |
| | | public Iterable<KeyPair> loadKeys() { |
| | | if (!SecurityUtils.isBouncyCastleRegistered()) { |
| | | throw new IllegalStateException("BouncyCastle must be registered as a JCE provider"); |
| | | } |
| | | return new Iterable<KeyPair>() { |
| | | @Override |
| | | public Iterator<KeyPair> iterator() { |
| | | return new Iterator<KeyPair>() { |
| | | private final Iterator<String> iterator = Arrays.asList(files).iterator(); |
| | | private KeyPair nextKeyPair; |
| | | private boolean nextKeyPairSet = false; |
| | | @Override |
| | | public boolean hasNext() { |
| | | return nextKeyPairSet || setNextObject(); |
| | | } |
| | | @Override |
| | | public KeyPair next() { |
| | | if (!nextKeyPairSet) { |
| | | if (!setNextObject()) { |
| | | throw new NoSuchElementException(); |
| | | } |
| | | } |
| | | nextKeyPairSet = false; |
| | | return nextKeyPair; |
| | | } |
| | | @Override |
| | | public void remove() { |
| | | throw new UnsupportedOperationException(); |
| | | } |
| | | private boolean setNextObject() { |
| | | while (iterator.hasNext()) { |
| | | String file = iterator.next(); |
| | | nextKeyPair = doLoadKey(file); |
| | | if (nextKeyPair != null) { |
| | | nextKeyPairSet = true; |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | }; |
| | | } |
| | | }; |
| | | } |
| | | |
| | | protected KeyPair doLoadKey(String file) { |
| | | try { |
| | | PEMParser r = new PEMParser(new InputStreamReader(new FileInputStream(file))); |
| | | try { |
| | | Object o = r.readObject(); |
| | | |
| | | JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter(); |
| | | pemConverter.setProvider("BC"); |
| | | if (passwordFinder != null && o instanceof PEMEncryptedKeyPair) { |
| | | JcePEMDecryptorProviderBuilder decryptorBuilder = new JcePEMDecryptorProviderBuilder(); |
| | | PEMDecryptorProvider pemDecryptor = decryptorBuilder.build(passwordFinder.getPassword()); |
| | | o = pemConverter.getKeyPair(((PEMEncryptedKeyPair) o).decryptKeyPair(pemDecryptor)); |
| | | } |
| | | |
| | | if (o instanceof PEMKeyPair) { |
| | | o = pemConverter.getKeyPair((PEMKeyPair)o); |
| | | return (KeyPair) o; |
| | | } else if (o instanceof KeyPair) { |
| | | return (KeyPair) o; |
| | | } |
| | | } finally { |
| | | r.close(); |
| | | } |
| | | } catch (Exception e) { |
| | | log.warn("Unable to read key " + file, e); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | } |
| | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | import com.google.inject.Inject; |
| | | |
| | | /** |
| | | * Memory public key manager. |
| | | * |
| | |
| | | |
| | | final Map<String, List<SshKey>> keys; |
| | | |
| | | @Inject |
| | | public MemoryKeyManager() { |
| | | keys = new HashMap<String, List<SshKey>>(); |
| | | } |
| | |
| | | */ |
| | | package com.gitblit.transport.ssh; |
| | | |
| | | import org.apache.sshd.common.ForwardingFilter; |
| | | import org.apache.sshd.common.Session; |
| | | import org.apache.sshd.common.SshdSocketAddress; |
| | | import org.apache.sshd.common.session.Session; |
| | | import org.apache.sshd.server.forward.ForwardingFilter; |
| | | |
| | | public class NonForwardingFilter implements ForwardingFilter { |
| | | |
| | | @Override |
| | | public boolean canConnect(SshdSocketAddress address, Session session) { |
| | | public boolean canConnect(Type type, SshdSocketAddress address, Session session) { |
| | | return false; |
| | | } |
| | | |
| | |
| | | |
| | | import java.util.List; |
| | | |
| | | import com.google.inject.Inject; |
| | | |
| | | /** |
| | | * Rejects all public key management requests. |
| | | * |
| | |
| | | */ |
| | | public class NullKeyManager extends IPublicKeyManager { |
| | | |
| | | @Inject |
| | | public NullKeyManager() { |
| | | } |
| | | |
| | |
| | | import java.text.MessageFormat; |
| | | import java.util.concurrent.atomic.AtomicBoolean; |
| | | |
| | | import org.apache.sshd.SshServer; |
| | | import org.apache.sshd.common.io.IoServiceFactoryFactory; |
| | | import org.apache.sshd.common.io.mina.MinaServiceFactoryFactory; |
| | | import org.apache.sshd.common.io.nio2.Nio2ServiceFactoryFactory; |
| | | import org.apache.sshd.common.keyprovider.FileKeyPairProvider; |
| | | import org.apache.sshd.common.util.SecurityUtils; |
| | | import org.apache.sshd.server.SshServer; |
| | | import org.apache.sshd.server.auth.CachingPublicKeyAuthenticator; |
| | | import org.bouncycastle.openssl.PEMWriter; |
| | | import org.eclipse.jgit.internal.JGitText; |
| | | import org.slf4j.Logger; |
| | |
| | | hostKeyPairProvider.setFiles(new String [] { rsaKeyStore.getPath(), dsaKeyStore.getPath(), dsaKeyStore.getPath() }); |
| | | |
| | | // Client public key authenticator |
| | | CachingPublicKeyAuthenticator keyAuthenticator = |
| | | new CachingPublicKeyAuthenticator(gitblit.getPublicKeyManager(), gitblit); |
| | | SshKeyAuthenticator keyAuthenticator = |
| | | new SshKeyAuthenticator(gitblit.getPublicKeyManager(), gitblit); |
| | | |
| | | // Configure the preferred SSHD backend |
| | | String sshBackendStr = settings.getString(Keys.git.sshBackend, |
| | |
| | | sshd.setPort(addr.getPort()); |
| | | sshd.setHost(addr.getHostName()); |
| | | sshd.setKeyPairProvider(hostKeyPairProvider); |
| | | sshd.setPublickeyAuthenticator(keyAuthenticator); |
| | | sshd.setPublickeyAuthenticator(new CachingPublicKeyAuthenticator(keyAuthenticator)); |
| | | sshd.setPasswordAuthenticator(new UsernamePasswordAuthenticator(gitblit)); |
| | | if (settings.getBoolean(Keys.git.sshWithKrb5, false)) { |
| | | sshd.setGSSAuthenticator(new SshKrbAuthenticator(settings, gitblit)); |
| | | } |
| | | sshd.setSessionFactory(new SshServerSessionFactory()); |
| | | sshd.setFileSystemFactory(new DisabledFilesystemFactory()); |
| | | sshd.setTcpipForwardingFilter(new NonForwardingFilter()); |
| | |
| | | } |
| | | |
| | | public String formatUrl(String gituser, String servername, String repository) { |
| | | if (sshd.getPort() == DEFAULT_PORT) { |
| | | IStoredSettings settings = gitblit.getSettings(); |
| | | |
| | | int port = sshd.getPort(); |
| | | int displayPort = settings.getInteger(Keys.git.sshAdvertisedPort, port); |
| | | String displayServername = settings.getString(Keys.git.sshAdvertisedHost, ""); |
| | | if(displayServername.isEmpty()) { |
| | | displayServername = servername; |
| | | } |
| | | if (displayPort == DEFAULT_PORT) { |
| | | // standard port |
| | | return MessageFormat.format("ssh://{0}@{1}/{2}", gituser, servername, |
| | | return MessageFormat.format("ssh://{0}@{1}/{2}", gituser, displayServername, |
| | | repository); |
| | | } else { |
| | | // non-standard port |
| | | return MessageFormat.format("ssh://{0}@{1}:{2,number,0}/{3}", |
| | | gituser, servername, sshd.getPort(), repository); |
| | | gituser, displayServername, displayPort, repository); |
| | | } |
| | | } |
| | | |
| | |
| | | try { |
| | | ((SshCommandFactory) sshd.getCommandFactory()).stop(); |
| | | sshd.stop(); |
| | | } catch (InterruptedException e) { |
| | | } catch (IOException e) { |
| | | log.error("SSH Daemon stop interrupted", e); |
| | | } |
| | | } |
| | |
| | | |
| | | import java.net.SocketAddress; |
| | | |
| | | import org.apache.sshd.common.Session.AttributeKey; |
| | | import org.apache.sshd.common.session.Session.AttributeKey; |
| | | |
| | | import com.gitblit.models.UserModel; |
| | | |
| | |
| | | |
| | | import org.apache.commons.codec.binary.Base64; |
| | | import org.apache.sshd.common.SshException; |
| | | import org.apache.sshd.common.util.Buffer; |
| | | import org.apache.sshd.common.util.buffer.Buffer; |
| | | import org.apache.sshd.common.util.buffer.ByteArrayBuffer; |
| | | import org.eclipse.jgit.lib.Constants; |
| | | |
| | | import com.gitblit.Constants.AccessPermission; |
| | |
| | | } |
| | | final byte[] bin = Base64.decodeBase64(Constants.encodeASCII(parts[1])); |
| | | try { |
| | | publicKey = new Buffer(bin).getRawPublicKey(); |
| | | publicKey = new ByteArrayBuffer(bin).getRawPublicKey(); |
| | | } catch (SshException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | |
| | | public String getRawData() { |
| | | if (rawData == null && publicKey != null) { |
| | | // build the raw data manually from the public key |
| | | Buffer buf = new Buffer(); |
| | | Buffer buf = new ByteArrayBuffer(); |
| | | |
| | | // 1: identify the algorithm |
| | | buf.putRawPublicKey(publicKey); |
File was renamed from src/main/java/com/gitblit/transport/ssh/CachingPublicKeyAuthenticator.java |
| | |
| | | package com.gitblit.transport.ssh; |
| | | |
| | | import java.security.PublicKey; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Locale; |
| | | import java.util.Map; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | | import org.apache.sshd.common.Session; |
| | | import org.apache.sshd.common.SessionListener; |
| | | import org.apache.sshd.server.PublickeyAuthenticator; |
| | | import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator; |
| | | import org.apache.sshd.server.session.ServerSession; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | |
| | | * Authenticates an SSH session against a public key. |
| | | * |
| | | */ |
| | | public class CachingPublicKeyAuthenticator implements PublickeyAuthenticator, SessionListener { |
| | | public class SshKeyAuthenticator implements PublickeyAuthenticator { |
| | | |
| | | protected final Logger log = LoggerFactory.getLogger(getClass()); |
| | | |
| | |
| | | |
| | | protected final IAuthenticationManager authManager; |
| | | |
| | | private final Map<ServerSession, Map<PublicKey, Boolean>> cache = new ConcurrentHashMap<ServerSession, Map<PublicKey, Boolean>>(); |
| | | |
| | | public CachingPublicKeyAuthenticator(IPublicKeyManager keyManager, IAuthenticationManager authManager) { |
| | | public SshKeyAuthenticator(IPublicKeyManager keyManager, IAuthenticationManager authManager) { |
| | | this.keyManager = keyManager; |
| | | this.authManager = authManager; |
| | | } |
| | | |
| | | @Override |
| | | public boolean authenticate(String username, PublicKey key, ServerSession session) { |
| | | Map<PublicKey, Boolean> map = cache.get(session); |
| | | if (map == null) { |
| | | map = new HashMap<PublicKey, Boolean>(); |
| | | cache.put(session, map); |
| | | session.addListener(this); |
| | | } |
| | | if (map.containsKey(key)) { |
| | | return map.get(key); |
| | | } |
| | | boolean result = doAuthenticate(username, key, session); |
| | | map.put(key, result); |
| | | return result; |
| | | } |
| | | |
| | | private boolean doAuthenticate(String username, PublicKey suppliedKey, ServerSession session) { |
| | | public boolean authenticate(String username, PublicKey suppliedKey, ServerSession session) { |
| | | SshDaemonClient client = session.getAttribute(SshDaemonClient.KEY); |
| | | Preconditions.checkState(client.getUser() == null); |
| | | username = username.toLowerCase(Locale.US); |
| | |
| | | |
| | | log.warn("could not authenticate {} for SSH using the supplied public key", username); |
| | | return false; |
| | | } |
| | | |
| | | @Override |
| | | public void sessionCreated(Session session) { |
| | | } |
| | | |
| | | @Override |
| | | public void sessionEvent(Session sesssion, Event event) { |
| | | } |
| | | |
| | | @Override |
| | | public void sessionClosed(Session session) { |
| | | cache.remove(session); |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2015 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.transport.ssh; |
| | | |
| | | import java.util.Locale; |
| | | |
| | | import org.apache.sshd.server.auth.gss.GSSAuthenticator; |
| | | import org.apache.sshd.server.session.ServerSession; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.manager.IAuthenticationManager; |
| | | import com.gitblit.models.UserModel; |
| | | |
| | | public class SshKrbAuthenticator extends GSSAuthenticator { |
| | | |
| | | protected final Logger log = LoggerFactory.getLogger(getClass()); |
| | | protected final IAuthenticationManager authManager; |
| | | protected final boolean stripDomain; |
| | | |
| | | |
| | | public SshKrbAuthenticator(IStoredSettings settings, IAuthenticationManager authManager) { |
| | | this.authManager = authManager; |
| | | |
| | | String keytabString = settings.getString(Keys.git.sshKrb5Keytab, ""); |
| | | if(! keytabString.isEmpty()) { |
| | | setKeytabFile(keytabString); |
| | | } |
| | | |
| | | String servicePrincipalName = settings.getString(Keys.git.sshKrb5ServicePrincipalName, ""); |
| | | if(! servicePrincipalName.isEmpty()) { |
| | | setServicePrincipalName(servicePrincipalName); |
| | | } |
| | | |
| | | this.stripDomain = settings.getBoolean(Keys.git.sshKrb5StripDomain, false); |
| | | } |
| | | |
| | | @Override |
| | | public boolean validateIdentity(ServerSession session, String identity) { |
| | | log.info("identify with kerberos {}", identity); |
| | | SshDaemonClient client = session.getAttribute(SshDaemonClient.KEY); |
| | | if (client.getUser() != null) { |
| | | log.info("{} has already authenticated!", identity); |
| | | return true; |
| | | } |
| | | String username = identity.toLowerCase(Locale.US); |
| | | if (stripDomain) { |
| | | int p = username.indexOf('@'); |
| | | if (p > 0) { |
| | | username = username.substring(0, p); |
| | | } |
| | | } |
| | | UserModel user = authManager.authenticate(username); |
| | | if (user != null) { |
| | | client.setUser(user); |
| | | return true; |
| | | } |
| | | log.warn("could not authenticate {} for SSH", username); |
| | | return false; |
| | | } |
| | | } |
| | |
| | | import org.apache.sshd.common.future.SshFutureListener; |
| | | import org.apache.sshd.common.io.IoSession; |
| | | import org.apache.sshd.server.ServerFactoryManager; |
| | | import org.apache.sshd.server.session.ServerSession; |
| | | import org.apache.sshd.server.session.ServerSessionImpl; |
| | | |
| | | // Expose addition of close session listeners |
| | | class SshServerSession extends ServerSession { |
| | | class SshServerSession extends ServerSessionImpl { |
| | | |
| | | SshServerSession(ServerFactoryManager server, IoSession ioSession) throws Exception { |
| | | super(server, ioSession); |
| | |
| | | |
| | | @Override |
| | | protected AbstractSession doCreateSession(IoSession ioSession) throws Exception { |
| | | return new SshServerSession(server, ioSession); |
| | | return new SshServerSession(getServer(), ioSession); |
| | | } |
| | | } |
| | |
| | | |
| | | import java.util.Locale; |
| | | |
| | | import org.apache.sshd.server.PasswordAuthenticator; |
| | | import org.apache.sshd.server.auth.password.PasswordAuthenticator; |
| | | import org.apache.sshd.server.session.ServerSession; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | |
| | | } |
| | | |
| | | username = username.toLowerCase(Locale.US); |
| | | UserModel user = authManager.authenticate(username, password.toCharArray()); |
| | | UserModel user = authManager.authenticate(username, password.toCharArray(), null); |
| | | if (user != null) { |
| | | client.setUser(user); |
| | | return true; |
| | | } |
| | | |
| | | log.warn("could not authenticate {} for SSH using the supplied password", username); |
| | | log.warn("could not authenticate {} ({}) for SSH using the supplied password", username, client.getRemoteAddress()); |
| | | return false; |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | private String formatUrl(String hostname, int port, String username) { |
| | | if (port == 22) { |
| | | int displayPort = settings.getInteger(Keys.git.sshAdvertisedPort, port); |
| | | String displayHostname = settings.getString(Keys.git.sshAdvertisedHost, ""); |
| | | if(displayHostname.isEmpty()) { |
| | | displayHostname = hostname; |
| | | } |
| | | if (displayPort == 22) { |
| | | // standard port |
| | | return MessageFormat.format("{0}@{1}/REPOSITORY.git", username, hostname); |
| | | return MessageFormat.format("{0}@{1}/REPOSITORY.git", username, displayHostname); |
| | | } else { |
| | | // non-standard port |
| | | return MessageFormat.format("ssh://{0}@{1}:{2,number,0}/REPOSITORY.git", |
| | | username, hostname, port); |
| | | username, displayHostname, displayPort); |
| | | } |
| | | } |
| | | } |
| | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.Keys; |
| | | import com.gitblit.manager.IGitblit; |
| | | import com.gitblit.utils.StringUtils; |
| | |
| | | |
| | | protected String getRepositoryUrl(String repository) { |
| | | String username = getContext().getClient().getUsername(); |
| | | String hostname = getHostname(); |
| | | int port = getContext().getGitblit().getSettings().getInteger(Keys.git.sshPort, 0); |
| | | if (port == 22) { |
| | | IStoredSettings settings = getContext().getGitblit().getSettings(); |
| | | String displayHostname = settings.getString(Keys.git.sshAdvertisedHost, ""); |
| | | if(displayHostname.isEmpty()) { |
| | | displayHostname = getHostname(); |
| | | } |
| | | int port = settings.getInteger(Keys.git.sshPort, 0); |
| | | int displayPort = settings.getInteger(Keys.git.sshAdvertisedPort, port); |
| | | if (displayPort == 22) { |
| | | // standard port |
| | | return MessageFormat.format("{0}@{1}/{2}.git", username, hostname, repository); |
| | | return MessageFormat.format("{0}@{1}/{2}.git", username, displayHostname, repository); |
| | | } else { |
| | | // non-standard port |
| | | return MessageFormat.format("ssh://{0}@{1}:{2,number,0}/{3}", |
| | | username, hostname, port, repository); |
| | | username, displayHostname, displayPort, repository); |
| | | } |
| | | } |
| | | |
| | |
| | | if (width <= 0) {
|
| | | width = 50;
|
| | | }
|
| | | String emailHash = StringUtils.getMD5(email);
|
| | | String emailHash = StringUtils.getMD5(email.toLowerCase());
|
| | | String url = MessageFormat.format(
|
| | | "https://www.gravatar.com/avatar/{0}?s={1,number,0}&d=identicon", emailHash, width);
|
| | | return url;
|
| | |
| | | if (width <= 0) {
|
| | | width = 50;
|
| | | }
|
| | | String emailHash = StringUtils.getMD5(email);
|
| | | String emailHash = StringUtils.getMD5(email.toLowerCase());
|
| | | String url = MessageFormat.format(
|
| | | "https://www.gravatar.com/avatar/{0}?s={1,number,0}&d=mm", emailHash, width);
|
| | | return url;
|
| | |
| | | package com.gitblit.utils;
|
| | |
|
| | | import java.io.ByteArrayOutputStream;
|
| | | import java.io.EOFException;
|
| | | import java.io.File;
|
| | | import java.io.FileInputStream;
|
| | | import java.io.IOException;
|
| | | import java.io.OutputStream;
|
| | | import java.text.MessageFormat;
|
| | |
| | | import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
|
| | | import org.apache.commons.compress.compressors.CompressorException;
|
| | | import org.apache.commons.compress.compressors.CompressorStreamFactory;
|
| | | import org.apache.commons.io.IOUtils;
|
| | | import org.eclipse.jgit.lib.Constants;
|
| | | import org.eclipse.jgit.lib.FileMode;
|
| | | import org.eclipse.jgit.lib.MutableObjectId;
|
| | | import org.eclipse.jgit.lib.ObjectId;
|
| | | import org.eclipse.jgit.lib.ObjectLoader;
|
| | | import org.eclipse.jgit.lib.ObjectReader;
|
| | | import org.eclipse.jgit.lib.Repository;
|
| | |
| | | import org.eclipse.jgit.treewalk.filter.PathFilter;
|
| | | import org.slf4j.Logger;
|
| | | import org.slf4j.LoggerFactory;
|
| | |
|
| | | import com.gitblit.GitBlit;
|
| | | import com.gitblit.manager.IFilestoreManager;
|
| | | import com.gitblit.models.FilestoreModel;
|
| | | import com.gitblit.models.FilestoreModel.Status;
|
| | |
|
| | | /**
|
| | | * Collection of static methods for retrieving information from a repository.
|
| | |
| | | * @return true if repository was successfully zipped to supplied output
|
| | | * stream
|
| | | */
|
| | | public static boolean zip(Repository repository, String basePath, String objectId,
|
| | | public static boolean zip(Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId,
|
| | | OutputStream os) {
|
| | | RevCommit commit = JGitUtils.getCommit(repository, objectId);
|
| | | if (commit == null) {
|
| | |
| | | continue;
|
| | | }
|
| | | tw.getObjectId(id, 0);
|
| | |
|
| | | |
| | | ObjectLoader loader = repository.open(id);
|
| | | |
| | | ZipArchiveEntry entry = new ZipArchiveEntry(tw.getPathString());
|
| | | entry.setSize(reader.getObjectSize(id, Constants.OBJ_BLOB));
|
| | |
|
| | | FilestoreModel filestoreItem = null;
|
| | | |
| | | if (JGitUtils.isPossibleFilestoreItem(loader.getSize())) {
|
| | | filestoreItem = JGitUtils.getFilestoreItem(tw.getObjectReader().open(id));
|
| | | }
|
| | |
|
| | | final long size = (filestoreItem == null) ? loader.getSize() : filestoreItem.getSize(); |
| | |
|
| | | entry.setSize(size);
|
| | | entry.setComment(commit.getName());
|
| | | entry.setUnixMode(mode.getBits());
|
| | | entry.setTime(modified);
|
| | | zos.putArchiveEntry(entry);
|
| | | |
| | | if (filestoreItem == null) {
|
| | | //Copy repository stored file
|
| | | loader.copyTo(zos);
|
| | | } else {
|
| | | //Copy filestore file
|
| | | try (FileInputStream streamIn = new FileInputStream(filestoreManager.getStoragePath(filestoreItem.oid))) {
|
| | | IOUtils.copyLarge(streamIn, zos);
|
| | | } catch (Throwable e) {
|
| | | LOGGER.error(MessageFormat.format("Failed to archive filestore item {0}", filestoreItem.oid), e);
|
| | |
|
| | | ObjectLoader ldr = repository.open(id);
|
| | | ldr.copyTo(zos);
|
| | | //Handle as per other errors |
| | | throw e; |
| | | }
|
| | | }
|
| | |
|
| | | zos.closeArchiveEntry();
|
| | | }
|
| | | zos.finish();
|
| | |
| | | } catch (IOException e) {
|
| | | error(e, repository, "{0} failed to zip files from commit {1}", commit.getName());
|
| | | } finally {
|
| | | tw.release();
|
| | | tw.close();
|
| | | rw.dispose();
|
| | | }
|
| | | return success;
|
| | |
| | | * @return true if repository was successfully zipped to supplied output
|
| | | * stream
|
| | | */
|
| | | public static boolean tar(Repository repository, String basePath, String objectId,
|
| | | public static boolean tar(Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId,
|
| | | OutputStream os) {
|
| | | return tar(null, repository, basePath, objectId, os);
|
| | | return tar(null, repository, filestoreManager, basePath, objectId, os);
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | * @return true if repository was successfully zipped to supplied output
|
| | | * stream
|
| | | */
|
| | | public static boolean gz(Repository repository, String basePath, String objectId,
|
| | | public static boolean gz(Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId,
|
| | | OutputStream os) {
|
| | | return tar(CompressorStreamFactory.GZIP, repository, basePath, objectId, os);
|
| | | return tar(CompressorStreamFactory.GZIP, repository, filestoreManager, basePath, objectId, os);
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | * @return true if repository was successfully zipped to supplied output
|
| | | * stream
|
| | | */
|
| | | public static boolean xz(Repository repository, String basePath, String objectId,
|
| | | public static boolean xz(Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId,
|
| | | OutputStream os) {
|
| | | return tar(CompressorStreamFactory.XZ, repository, basePath, objectId, os);
|
| | | return tar(CompressorStreamFactory.XZ, repository, filestoreManager, basePath, objectId, os);
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | * @return true if repository was successfully zipped to supplied output
|
| | | * stream
|
| | | */
|
| | | public static boolean bzip2(Repository repository, String basePath, String objectId,
|
| | | public static boolean bzip2(Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId,
|
| | | OutputStream os) {
|
| | |
|
| | | return tar(CompressorStreamFactory.BZIP2, repository, basePath, objectId, os);
|
| | | return tar(CompressorStreamFactory.BZIP2, repository, filestoreManager, basePath, objectId, os);
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | * @return true if repository was successfully zipped to supplied output
|
| | | * stream
|
| | | */
|
| | | private static boolean tar(String algorithm, Repository repository, String basePath, String objectId,
|
| | | private static boolean tar(String algorithm, Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId,
|
| | | OutputStream os) {
|
| | | RevCommit commit = JGitUtils.getCommit(repository, objectId);
|
| | | if (commit == null) {
|
| | |
| | | if (mode == FileMode.GITLINK || mode == FileMode.TREE) {
|
| | | continue;
|
| | | }
|
| | | |
| | | tw.getObjectId(id, 0);
|
| | |
|
| | | ObjectLoader loader = repository.open(id);
|
| | |
| | | TarArchiveEntry entry = new TarArchiveEntry(tw.getPathString());
|
| | | entry.setMode(mode.getBits());
|
| | | entry.setModTime(modified);
|
| | | entry.setSize(loader.getSize());
|
| | |
|
| | | FilestoreModel filestoreItem = null;
|
| | | |
| | | if (JGitUtils.isPossibleFilestoreItem(loader.getSize())) {
|
| | | filestoreItem = JGitUtils.getFilestoreItem(tw.getObjectReader().open(id));
|
| | | }
|
| | |
|
| | | final long size = (filestoreItem == null) ? loader.getSize() : filestoreItem.getSize(); |
| | |
|
| | | entry.setSize(size);
|
| | | tos.putArchiveEntry(entry);
|
| | | loader.copyTo(tos);
|
| | | |
| | | if (filestoreItem == null) {
|
| | | //Copy repository stored file
|
| | | loader.copyTo(tos);
|
| | | } else {
|
| | | //Copy filestore file
|
| | | try (FileInputStream streamIn = new FileInputStream(filestoreManager.getStoragePath(filestoreItem.oid))) {
|
| | |
|
| | | IOUtils.copyLarge(streamIn, tos);
|
| | | } catch (Throwable e) {
|
| | | LOGGER.error(MessageFormat.format("Failed to archive filestore item {0}", filestoreItem.oid), e);
|
| | |
|
| | | //Handle as per other errors |
| | | throw e; |
| | | }
|
| | | }
|
| | | |
| | | tos.closeArchiveEntry();
|
| | | }
|
| | | }
|
| | |
| | | } catch (IOException e) {
|
| | | error(e, repository, "{0} failed to {1} stream files from commit {2}", algorithm, commit.getName());
|
| | | } finally {
|
| | | tw.release();
|
| | | tw.close();
|
| | | rw.dispose();
|
| | | }
|
| | | return success;
|
| | |
| | | import org.eclipse.jgit.diff.DiffEntry;
|
| | | import org.eclipse.jgit.diff.DiffFormatter;
|
| | | import org.eclipse.jgit.diff.RawText;
|
| | | import org.eclipse.jgit.lib.Repository;
|
| | | import org.eclipse.jgit.util.io.NullOutputStream;
|
| | |
|
| | | import com.gitblit.models.PathModel.PathChangeModel;
|
| | |
| | |
|
| | | private PathChangeModel path;
|
| | |
|
| | | public DiffStatFormatter(String commitId) {
|
| | | public DiffStatFormatter(String commitId, Repository repository) {
|
| | | super(NullOutputStream.INSTANCE);
|
| | | diffStat = new DiffStat(commitId);
|
| | | diffStat = new DiffStat(commitId, repository);
|
| | | }
|
| | |
|
| | | @Override
|
| | |
| | | private static final Logger LOGGER = LoggerFactory.getLogger(DiffUtils.class);
|
| | |
|
| | | /**
|
| | | * Callback interface for binary diffs. All the getDiff methods here take an optional handler;
|
| | | * if given and the {@link DiffOutputType} is {@link DiffOutputType#HTML HTML}, it is responsible
|
| | | * for displaying a binary diff.
|
| | | */
|
| | | public interface BinaryDiffHandler {
|
| | |
|
| | | /**
|
| | | * Renders a binary diff. The result must be valid HTML, it will be inserted into an HTML table cell.
|
| | | * May return {@code null} if the default behavior (which is typically just a textual note "Bnary
|
| | | * files differ") is desired.
|
| | | *
|
| | | * @param diffEntry
|
| | | * current diff entry
|
| | | *
|
| | | * @return the rendered diff as HTML, or {@code null} if the default is desired.
|
| | | */
|
| | | public String renderBinaryDiff(final DiffEntry diffEntry);
|
| | |
|
| | | }
|
| | |
|
| | | /**
|
| | | * Enumeration for the diff output types.
|
| | | */
|
| | | public static enum DiffOutputType {
|
| | |
| | |
|
| | | public static DiffOutputType forName(String name) {
|
| | | for (DiffOutputType type : values()) {
|
| | | if (type.name().equalsIgnoreCase(name)) {
|
| | | return type;
|
| | | }
|
| | | }
|
| | | return null;
|
| | | }
|
| | | }
|
| | |
|
| | | /**
|
| | | * Enumeration for the diff comparator types.
|
| | | */
|
| | | public static enum DiffComparator {
|
| | | SHOW_WHITESPACE(RawTextComparator.DEFAULT),
|
| | | IGNORE_WHITESPACE(RawTextComparator.WS_IGNORE_ALL),
|
| | | IGNORE_LEADING(RawTextComparator.WS_IGNORE_LEADING),
|
| | | IGNORE_TRAILING(RawTextComparator.WS_IGNORE_TRAILING),
|
| | | IGNORE_CHANGES(RawTextComparator.WS_IGNORE_CHANGE);
|
| | |
|
| | | public final RawTextComparator textComparator;
|
| | |
|
| | | DiffComparator(RawTextComparator textComparator) {
|
| | | this.textComparator = textComparator;
|
| | | }
|
| | |
|
| | | public DiffComparator getOpposite() {
|
| | | return this == SHOW_WHITESPACE ? IGNORE_WHITESPACE : SHOW_WHITESPACE;
|
| | | }
|
| | |
|
| | | public String getTranslationKey() {
|
| | | return "gb." + name().toLowerCase();
|
| | | }
|
| | |
|
| | | public static DiffComparator forName(String name) {
|
| | | for (DiffComparator type : values()) {
|
| | | if (type.name().equalsIgnoreCase(name)) {
|
| | | return type;
|
| | | }
|
| | |
| | | public final List<PathChangeModel> paths = new ArrayList<PathChangeModel>();
|
| | |
|
| | | private final String commitId;
|
| | | |
| | | private final Repository repository;
|
| | |
|
| | | public DiffStat(String commitId) {
|
| | | public DiffStat(String commitId, Repository repository) {
|
| | | this.commitId = commitId;
|
| | | this.repository = repository;
|
| | | }
|
| | |
|
| | | public PathChangeModel addPath(DiffEntry entry) {
|
| | | PathChangeModel pcm = PathChangeModel.from(entry, commitId);
|
| | | PathChangeModel pcm = PathChangeModel.from(entry, commitId, repository);
|
| | | paths.add(pcm);
|
| | | return pcm;
|
| | | }
|
| | |
| | | *
|
| | | * @param repository
|
| | | * @param commit
|
| | | * @param comparator
|
| | | * @param outputType
|
| | | * @param tabLength
|
| | | * @return the diff
|
| | | */
|
| | | public static DiffOutput getCommitDiff(Repository repository, RevCommit commit,
|
| | | DiffOutputType outputType) {
|
| | | return getDiff(repository, null, commit, null, outputType);
|
| | | DiffComparator comparator, DiffOutputType outputType, int tabLength) {
|
| | | return getDiff(repository, null, commit, null, comparator, outputType, tabLength);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the complete diff of the specified commit compared to its primary parent.
|
| | | *
|
| | | * @param repository
|
| | | * @param commit
|
| | | * @param comparator
|
| | | * @param outputType
|
| | | * @param handler
|
| | | * to use for rendering binary diffs if {@code outputType} is {@link DiffOutputType#HTML HTML}.
|
| | | * May be {@code null}, resulting in the default behavior.
|
| | | * @param tabLength
|
| | | * @return the diff
|
| | | */
|
| | | public static DiffOutput getCommitDiff(Repository repository, RevCommit commit,
|
| | | DiffComparator comparator, DiffOutputType outputType, BinaryDiffHandler handler, int tabLength) {
|
| | | return getDiff(repository, null, commit, null, comparator, outputType, handler, tabLength);
|
| | | }
|
| | |
|
| | |
|
| | | /**
|
| | | * Returns the diff for the specified file or folder from the specified
|
| | | * commit compared to its primary parent.
|
| | | *
|
| | | * @param repository
|
| | | * @param commit
|
| | | * @param path
|
| | | * @param comparator
|
| | | * @param outputType
|
| | | * @param tabLength
|
| | | * @return the diff
|
| | | */
|
| | | public static DiffOutput getDiff(Repository repository, RevCommit commit, String path,
|
| | | DiffComparator comparator, DiffOutputType outputType, int tabLength) {
|
| | | return getDiff(repository, null, commit, path, comparator, outputType, tabLength);
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | * @param repository
|
| | | * @param commit
|
| | | * @param path
|
| | | * @param comparator
|
| | | * @param outputType
|
| | | * @param handler
|
| | | * to use for rendering binary diffs if {@code outputType} is {@link DiffOutputType#HTML HTML}.
|
| | | * May be {@code null}, resulting in the default behavior.
|
| | | * @param tabLength
|
| | | * @return the diff
|
| | | */
|
| | | public static DiffOutput getDiff(Repository repository, RevCommit commit, String path,
|
| | | DiffOutputType outputType) {
|
| | | return getDiff(repository, null, commit, path, outputType);
|
| | | DiffComparator comparator, DiffOutputType outputType, BinaryDiffHandler handler, int tabLength) {
|
| | | return getDiff(repository, null, commit, path, comparator, outputType, handler, tabLength);
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | * @param repository
|
| | | * @param baseCommit
|
| | | * @param commit
|
| | | * @param comparator
|
| | | * @param outputType
|
| | | * @param tabLength
|
| | | *
|
| | | * @return the diff
|
| | | */
|
| | | public static DiffOutput getDiff(Repository repository, RevCommit baseCommit, RevCommit commit,
|
| | | DiffOutputType outputType) {
|
| | | return getDiff(repository, baseCommit, commit, null, outputType);
|
| | | DiffComparator comparator, DiffOutputType outputType, int tabLength) {
|
| | | return getDiff(repository, baseCommit, commit, null, comparator, outputType, tabLength);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the complete diff between the two specified commits.
|
| | | *
|
| | | * @param repository
|
| | | * @param baseCommit
|
| | | * @param commit
|
| | | * @param comparator
|
| | | * @param outputType
|
| | | * @param handler
|
| | | * to use for rendering binary diffs if {@code outputType} is {@link DiffOutputType#HTML HTML}.
|
| | | * May be {@code null}, resulting in the default behavior.
|
| | | * @param tabLength
|
| | | * @return the diff
|
| | | */
|
| | | public static DiffOutput getDiff(Repository repository, RevCommit baseCommit, RevCommit commit,
|
| | | DiffComparator comparator, DiffOutputType outputType, BinaryDiffHandler handler, int tabLength) {
|
| | | return getDiff(repository, baseCommit, commit, null, comparator, outputType, handler, tabLength);
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | * if the path is specified, the diff is restricted to that file
|
| | | * or folder. if unspecified, the diff is for the entire commit.
|
| | | * @param outputType
|
| | | * @param diffComparator
|
| | | * @param tabLength
|
| | | * @return the diff
|
| | | */
|
| | | public static DiffOutput getDiff(Repository repository, RevCommit baseCommit, RevCommit commit,
|
| | | String path, DiffOutputType outputType) {
|
| | | String path, DiffComparator diffComparator, DiffOutputType outputType, int tabLength) {
|
| | | return getDiff(repository, baseCommit, commit, path, diffComparator, outputType, null, tabLength);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the diff between two commits for the specified file.
|
| | | *
|
| | | * @param repository
|
| | | * @param baseCommit
|
| | | * if base commit is null the diff is to the primary parent of
|
| | | * the commit.
|
| | | * @param commit
|
| | | * @param path
|
| | | * if the path is specified, the diff is restricted to that file
|
| | | * or folder. if unspecified, the diff is for the entire commit.
|
| | | * @param comparator
|
| | | * @param outputType
|
| | | * @param handler
|
| | | * to use for rendering binary diffs if {@code outputType} is {@link DiffOutputType#HTML HTML}.
|
| | | * May be {@code null}, resulting in the default behavior.
|
| | | * @param tabLength
|
| | | * @return the diff
|
| | | */
|
| | | public static DiffOutput getDiff(Repository repository, RevCommit baseCommit, RevCommit commit, String path,
|
| | | DiffComparator comparator, DiffOutputType outputType, final BinaryDiffHandler handler, int tabLength) {
|
| | | DiffStat stat = null;
|
| | | String diff = null;
|
| | | try {
|
| | | final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
| | | RawTextComparator cmp = RawTextComparator.DEFAULT;
|
| | | ByteArrayOutputStream os = null;
|
| | |
|
| | | DiffFormatter df;
|
| | | switch (outputType) {
|
| | | case HTML:
|
| | | df = new GitBlitDiffFormatter(os, commit.getName());
|
| | | df = new GitBlitDiffFormatter(commit.getName(), repository, path, handler, tabLength);
|
| | | break;
|
| | | case PLAIN:
|
| | | default:
|
| | | os = new ByteArrayOutputStream();
|
| | | df = new DiffFormatter(os);
|
| | | break;
|
| | | }
|
| | | df.setRepository(repository);
|
| | | df.setDiffComparator(cmp);
|
| | | df.setDiffComparator((comparator == null ? DiffComparator.SHOW_WHITESPACE : comparator).textComparator);
|
| | | df.setDetectRenames(true);
|
| | |
|
| | | RevTree commitTree = commit.getTree();
|
| | |
| | | } else {
|
| | | df.format(diffEntries);
|
| | | }
|
| | | df.flush();
|
| | | if (df instanceof GitBlitDiffFormatter) {
|
| | | // workaround for complex private methods in DiffFormatter
|
| | | diff = ((GitBlitDiffFormatter) df).getHtml();
|
| | |
| | | } else {
|
| | | diff = os.toString();
|
| | | }
|
| | | df.flush();
|
| | | } catch (Throwable t) {
|
| | | LOGGER.error("failed to generate commit diff!", t);
|
| | | }
|
| | |
| | | DiffStat stat = null;
|
| | | try {
|
| | | RawTextComparator cmp = RawTextComparator.DEFAULT;
|
| | | DiffStatFormatter df = new DiffStatFormatter(commit.getName());
|
| | | DiffStatFormatter df = new DiffStatFormatter(commit.getName(), repository);
|
| | | df.setRepository(repository);
|
| | | df.setDiffComparator(cmp);
|
| | | df.setDetectRenames(true);
|
| | |
| | | public static String readContent(File file, String lineEnding) {
|
| | | StringBuilder sb = new StringBuilder();
|
| | | InputStreamReader is = null;
|
| | | BufferedReader reader = null;
|
| | | try {
|
| | | is = new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8"));
|
| | | BufferedReader reader = new BufferedReader(is);
|
| | | reader = new BufferedReader(is);
|
| | | String line = null;
|
| | | while ((line = reader.readLine()) != null) {
|
| | | sb.append(line);
|
| | |
| | | System.err.println("Failed to read content of " + file.getAbsolutePath());
|
| | | t.printStackTrace();
|
| | | } finally {
|
| | | if (reader != null){
|
| | | try {
|
| | | reader.close();
|
| | | } catch (IOException ioe) {
|
| | | System.err.println("Failed to close file " + file.getAbsolutePath());
|
| | | ioe.printStackTrace();
|
| | | }
|
| | | }
|
| | | if (is != null) {
|
| | | try {
|
| | | is.close();
|
| | |
| | | /*
|
| | | * 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 static org.eclipse.jgit.lib.Constants.encode;
|
| | | import static org.eclipse.jgit.lib.Constants.encodeASCII;
|
| | |
|
| | | import java.io.ByteArrayOutputStream;
|
| | | import java.io.IOException;
|
| | | import java.io.OutputStream;
|
| | | import java.text.MessageFormat;
|
| | |
|
| | | import org.eclipse.jgit.diff.DiffEntry;
|
| | | import org.eclipse.jgit.diff.DiffFormatter;
|
| | | import org.eclipse.jgit.diff.RawText;
|
| | | import org.eclipse.jgit.util.RawParseUtils;
|
| | |
|
| | | import com.gitblit.models.PathModel.PathChangeModel;
|
| | | import com.gitblit.utils.DiffUtils.DiffStat;
|
| | |
|
| | | /**
|
| | | * Generates an html snippet of a diff in Gitblit's style, tracks changed paths,
|
| | | * and calculates diff stats.
|
| | | *
|
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | public class GitBlitDiffFormatter extends DiffFormatter {
|
| | |
|
| | | private final OutputStream os;
|
| | |
|
| | | private final DiffStat diffStat;
|
| | |
|
| | | private PathChangeModel currentPath;
|
| | |
|
| | | private int left, right;
|
| | |
|
| | | public GitBlitDiffFormatter(OutputStream os, String commitId) {
|
| | | super(os);
|
| | | this.os = os;
|
| | | this.diffStat = new DiffStat(commitId);
|
| | | }
|
| | |
|
| | | @Override
|
| | | public void format(DiffEntry ent) throws IOException {
|
| | | currentPath = diffStat.addPath(ent);
|
| | | super.format(ent);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Output a hunk header
|
| | | *
|
| | | * @param aStartLine
|
| | | * within first source
|
| | | * @param aEndLine
|
| | | * within first source
|
| | | * @param bStartLine
|
| | | * within second source
|
| | | * @param bEndLine
|
| | | * within second source
|
| | | * @throws IOException
|
| | | */
|
| | | @Override
|
| | | protected void writeHunkHeader(int aStartLine, int aEndLine, int bStartLine, int bEndLine)
|
| | | throws IOException {
|
| | | os.write("<tr><th>..</th><th>..</th><td class='hunk_header'>".getBytes());
|
| | | os.write('@');
|
| | | os.write('@');
|
| | | writeRange('-', aStartLine + 1, aEndLine - aStartLine);
|
| | | writeRange('+', bStartLine + 1, bEndLine - bStartLine);
|
| | | os.write(' ');
|
| | | os.write('@');
|
| | | os.write('@');
|
| | | os.write("</td></tr>\n".getBytes());
|
| | | left = aStartLine + 1;
|
| | | right = bStartLine + 1;
|
| | | }
|
| | |
|
| | | protected void writeRange(final char prefix, final int begin, final int cnt) throws IOException {
|
| | | os.write(' ');
|
| | | os.write(prefix);
|
| | | switch (cnt) {
|
| | | case 0:
|
| | | // If the range is empty, its beginning number must
|
| | | // be the
|
| | | // line just before the range, or 0 if the range is
|
| | | // at the
|
| | | // start of the file stream. Here, begin is always 1
|
| | | // based,
|
| | | // so an empty file would produce "0,0".
|
| | | //
|
| | | os.write(encodeASCII(begin - 1));
|
| | | os.write(',');
|
| | | os.write('0');
|
| | | break;
|
| | |
|
| | | case 1:
|
| | | // If the range is exactly one line, produce only
|
| | | // the number.
|
| | | //
|
| | | os.write(encodeASCII(begin));
|
| | | break;
|
| | |
|
| | | default:
|
| | | os.write(encodeASCII(begin));
|
| | | os.write(',');
|
| | | os.write(encodeASCII(cnt));
|
| | | break;
|
| | | }
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected void writeLine(final char prefix, final RawText text, final int cur)
|
| | | throws IOException {
|
| | | // update entry diffstat
|
| | | currentPath.update(prefix);
|
| | |
|
| | | // output diff
|
| | | os.write("<tr>".getBytes());
|
| | | switch (prefix) {
|
| | | case '+':
|
| | | os.write(("<th></th><th>" + (right++) + "</th>").getBytes());
|
| | | os.write("<td><div class=\"diff add2\">".getBytes());
|
| | | break;
|
| | | case '-':
|
| | | os.write(("<th>" + (left++) + "</th><th></th>").getBytes());
|
| | | os.write("<td><div class=\"diff remove2\">".getBytes());
|
| | | break;
|
| | | default:
|
| | | os.write(("<th>" + (left++) + "</th><th>" + (right++) + "</th>").getBytes());
|
| | | os.write("<td>".getBytes());
|
| | | break;
|
| | | }
|
| | | os.write(prefix);
|
| | | String line = text.getString(cur);
|
| | | line = StringUtils.escapeForHtml(line, false);
|
| | | os.write(encode(line));
|
| | | switch (prefix) {
|
| | | case '+':
|
| | | case '-':
|
| | | os.write("</div>".getBytes());
|
| | | break;
|
| | | default:
|
| | | os.write("</td>".getBytes());
|
| | | }
|
| | | os.write("</tr>\n".getBytes());
|
| | | }
|
| | |
|
| | | /**
|
| | | * Workaround function for complex private methods in DiffFormatter. This
|
| | | * sets the html for the diff headers.
|
| | | *
|
| | | * @return
|
| | | */
|
| | | public String getHtml() {
|
| | | ByteArrayOutputStream bos = (ByteArrayOutputStream) os;
|
| | | String html = RawParseUtils.decode(bos.toByteArray());
|
| | | String[] lines = html.split("\n");
|
| | | StringBuilder sb = new StringBuilder();
|
| | | boolean inFile = false;
|
| | | String oldnull = "a/dev/null";
|
| | | for (String line : lines) {
|
| | | if (line.startsWith("index")) {
|
| | | // skip index lines
|
| | | } else if (line.startsWith("new file")) {
|
| | | // skip new file lines
|
| | | } else if (line.startsWith("\\ No newline")) {
|
| | | // skip no new line
|
| | | } else if (line.startsWith("---") || line.startsWith("+++")) {
|
| | | // skip --- +++ lines
|
| | | } else if (line.startsWith("diff")) {
|
| | | line = StringUtils.convertOctal(line);
|
| | | if (line.indexOf(oldnull) > -1) {
|
| | | // a is null, use b
|
| | | line = line.substring(("diff --git " + oldnull).length()).trim();
|
| | | // trim b/
|
| | | line = line.substring(2).trim();
|
| | | } else {
|
| | | // use a
|
| | | line = line.substring("diff --git ".length()).trim();
|
| | | line = line.substring(line.startsWith("\"a/") ? 3 : 2);
|
| | | line = line.substring(0, line.indexOf(" b/") > -1 ? line.indexOf(" b/") : line.indexOf("\"b/")).trim();
|
| | | }
|
| | |
|
| | | if (line.charAt(0) == '"') {
|
| | | line = line.substring(1);
|
| | | }
|
| | | if (line.charAt(line.length() - 1) == '"') {
|
| | | line = line.substring(0, line.length() - 1);
|
| | | }
|
| | | if (inFile) {
|
| | | sb.append("</tbody></table></div>\n");
|
| | | inFile = false;
|
| | | }
|
| | |
|
| | | sb.append(MessageFormat.format("<div class='header'><div class=\"diffHeader\" id=\"{0}\"><i class=\"icon-file\"></i> ", line)).append(line).append("</div></div>");
|
| | | sb.append("<div class=\"diff\">");
|
| | | sb.append("<table><tbody>");
|
| | | inFile = true;
|
| | | } else {
|
| | | boolean gitLinkDiff = line.length() > 0 && line.substring(1).startsWith("Subproject commit");
|
| | | if (gitLinkDiff) {
|
| | | sb.append("<tr><th></th><th></th>");
|
| | | if (line.charAt(0) == '+') {
|
| | | sb.append("<td><div class=\"diff add2\">");
|
| | | } else {
|
| | | sb.append("<td><div class=\"diff remove2\">");
|
| | | }
|
| | | }
|
| | | sb.append(line);
|
| | | if (gitLinkDiff) {
|
| | | sb.append("</div></td></tr>");
|
| | | }
|
| | | }
|
| | | }
|
| | | sb.append("</table></div>");
|
| | | return sb.toString();
|
| | | }
|
| | |
|
| | | public DiffStat getDiffStat() {
|
| | | return diffStat;
|
| | | }
|
| | | }
|
| | | /* |
| | | * 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 static org.eclipse.jgit.lib.Constants.encode; |
| | | import static org.eclipse.jgit.lib.Constants.encodeASCII; |
| | | |
| | | import java.io.IOException; |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.text.MessageFormat; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | |
| | | import org.apache.wicket.Application; |
| | | import org.apache.wicket.Localizer; |
| | | import org.eclipse.jgit.diff.DiffEntry; |
| | | import org.eclipse.jgit.diff.DiffEntry.ChangeType; |
| | | import org.eclipse.jgit.diff.DiffFormatter; |
| | | import org.eclipse.jgit.diff.RawText; |
| | | import org.eclipse.jgit.lib.Repository; |
| | | import org.eclipse.jgit.util.RawParseUtils; |
| | | |
| | | import com.gitblit.models.PathModel.PathChangeModel; |
| | | import com.gitblit.utils.DiffUtils.BinaryDiffHandler; |
| | | import com.gitblit.utils.DiffUtils.DiffStat; |
| | | import com.gitblit.wicket.GitBlitWebApp; |
| | | |
| | | /** |
| | | * Generates an html snippet of a diff in Gitblit's style, tracks changed paths, and calculates diff stats. |
| | | * |
| | | * @author James Moger |
| | | * @author Tom <tw201207@gmail.com> |
| | | * |
| | | */ |
| | | public class GitBlitDiffFormatter extends DiffFormatter { |
| | | |
| | | /** Regex pattern identifying trailing whitespace. */ |
| | | private static final Pattern trailingWhitespace = Pattern.compile("(\\s+?)\r?\n?$"); |
| | | |
| | | /** |
| | | * gitblit.properties key for the per-file limit on the number of diff lines. |
| | | */ |
| | | private static final String DIFF_LIMIT_PER_FILE_KEY = "web.maxDiffLinesPerFile"; |
| | | |
| | | /** |
| | | * gitblit.properties key for the global limit on the number of diff lines in a commitdiff. |
| | | */ |
| | | private static final String GLOBAL_DIFF_LIMIT_KEY = "web.maxDiffLines"; |
| | | |
| | | /** |
| | | * Diffs with more lines are not shown in commitdiffs. (Similar to what GitHub does.) Can be reduced |
| | | * (but not increased) through gitblit.properties key {@link #DIFF_LIMIT_PER_FILE_KEY}. |
| | | */ |
| | | private static final int DIFF_LIMIT_PER_FILE = 4000; |
| | | |
| | | /** |
| | | * Global diff limit. Commitdiffs with more lines are truncated. Can be reduced (but not increased) |
| | | * through gitblit.properties key {@link #GLOBAL_DIFF_LIMIT_KEY}. |
| | | */ |
| | | private static final int GLOBAL_DIFF_LIMIT = 20000; |
| | | |
| | | private static final boolean CONVERT_TABS = true; |
| | | |
| | | private final DiffOutputStream os; |
| | | |
| | | private final DiffStat diffStat; |
| | | |
| | | private PathChangeModel currentPath; |
| | | |
| | | private int left, right; |
| | | |
| | | /** |
| | | * If a single file diff in a commitdiff produces more than this number of lines, we don't display |
| | | * the diff. First, it's too taxing on the browser: it'll spend an awful lot of time applying the |
| | | * CSS rules (despite my having optimized them). And second, no human can read a diff with thousands |
| | | * of lines and make sense of it. |
| | | * <p> |
| | | * Set to {@link #DIFF_LIMIT_PER_FILE} for commitdiffs, and to -1 (switches off the limit) for |
| | | * single-file diffs. |
| | | * </p> |
| | | */ |
| | | private final int maxDiffLinesPerFile; |
| | | |
| | | /** |
| | | * Global limit on the number of diff lines. Set to {@link #GLOBAL_DIFF_LIMIT} for commitdiffs, and |
| | | * to -1 (switched off the limit) for single-file diffs. |
| | | */ |
| | | private final int globalDiffLimit; |
| | | |
| | | /** Number of lines for the current file diff. Set to zero when a new DiffEntry is started. */ |
| | | private int nofLinesCurrent; |
| | | /** |
| | | * Position in the stream when we try to write the first line. Used to rewind when we detect that |
| | | * the diff is too large. |
| | | */ |
| | | private int startCurrent; |
| | | /** Flag set to true when we rewind. Reset to false when we start a new DiffEntry. */ |
| | | private boolean isOff; |
| | | /** The current diff entry. */ |
| | | private DiffEntry entry; |
| | | |
| | | // Global limit stuff. |
| | | |
| | | /** Total number of lines written before the current diff entry. */ |
| | | private int totalNofLinesPrevious; |
| | | /** Running total of the number of diff lines written. Updated until we exceed the global limit. */ |
| | | private int totalNofLinesCurrent; |
| | | /** Stream position to reset to if we decided to truncate the commitdiff. */ |
| | | private int truncateTo; |
| | | /** Whether we decided to truncate the commitdiff. */ |
| | | private boolean truncated; |
| | | /** If {@link #truncated}, contains all entries skipped. */ |
| | | private final List<DiffEntry> skipped = new ArrayList<DiffEntry>(); |
| | | |
| | | private int tabLength; |
| | | |
| | | /** |
| | | * A {@link ResettableByteArrayOutputStream} that intercept the "Binary files differ" message produced |
| | | * by the super implementation. Unfortunately the super implementation has far too many things private; |
| | | * otherwise we'd just have re-implemented {@link GitBlitDiffFormatter#format(DiffEntry) format(DiffEntry)} |
| | | * completely without ever calling the super implementation. |
| | | */ |
| | | private static class DiffOutputStream extends ResettableByteArrayOutputStream { |
| | | |
| | | private static final String BINARY_DIFFERENCE = "Binary files differ\n"; |
| | | |
| | | private GitBlitDiffFormatter formatter; |
| | | private BinaryDiffHandler binaryDiffHandler; |
| | | |
| | | public void setFormatter(GitBlitDiffFormatter formatter, BinaryDiffHandler handler) { |
| | | this.formatter = formatter; |
| | | this.binaryDiffHandler = handler; |
| | | } |
| | | |
| | | @Override |
| | | public void write(byte[] b, int offset, int length) { |
| | | if (binaryDiffHandler != null |
| | | && RawParseUtils.decode(Arrays.copyOfRange(b, offset, offset + length)).contains(BINARY_DIFFERENCE)) |
| | | { |
| | | String binaryDiff = binaryDiffHandler.renderBinaryDiff(formatter.entry); |
| | | if (binaryDiff != null) { |
| | | byte[] bb = ("<tr><td colspan='4' align='center'>" + binaryDiff + "</td></tr>").getBytes(StandardCharsets.UTF_8); |
| | | super.write(bb, 0, bb.length); |
| | | return; |
| | | } |
| | | } |
| | | super.write(b, offset, length); |
| | | } |
| | | |
| | | } |
| | | |
| | | public GitBlitDiffFormatter(String commitId, Repository repository, String path, BinaryDiffHandler handler, int tabLength) { |
| | | super(new DiffOutputStream()); |
| | | this.os = (DiffOutputStream) getOutputStream(); |
| | | this.os.setFormatter(this, handler); |
| | | this.diffStat = new DiffStat(commitId, repository); |
| | | this.tabLength = tabLength; |
| | | // If we have a full commitdiff, install maxima to avoid generating a super-long diff listing that |
| | | // will only tax the browser too much. |
| | | maxDiffLinesPerFile = path != null ? -1 : getLimit(DIFF_LIMIT_PER_FILE_KEY, 500, DIFF_LIMIT_PER_FILE); |
| | | globalDiffLimit = path != null ? -1 : getLimit(GLOBAL_DIFF_LIMIT_KEY, 1000, GLOBAL_DIFF_LIMIT); |
| | | } |
| | | |
| | | /** |
| | | * Determines a limit to use for HTML diff output. |
| | | * |
| | | * @param key |
| | | * to use to read the value from the GitBlit settings, if available. |
| | | * @param minimum |
| | | * minimum value to enforce |
| | | * @param maximum |
| | | * maximum (and default) value to enforce |
| | | * @return the limit |
| | | */ |
| | | private int getLimit(String key, int minimum, int maximum) { |
| | | if (Application.exists()) { |
| | | Application application = Application.get(); |
| | | if (application instanceof GitBlitWebApp) { |
| | | GitBlitWebApp webApp = (GitBlitWebApp) application; |
| | | int configValue = webApp.settings().getInteger(key, maximum); |
| | | if (configValue < minimum) { |
| | | return minimum; |
| | | } else if (configValue < maximum) { |
| | | return configValue; |
| | | } |
| | | } |
| | | } |
| | | return maximum; |
| | | } |
| | | |
| | | /** |
| | | * Returns a localized message string, if there is a localization; otherwise the given default value. |
| | | * |
| | | * @param key |
| | | * message key for the message |
| | | * @param defaultValue |
| | | * to use if no localization for the message can be found |
| | | * @return the possibly localized message |
| | | */ |
| | | private String getMsg(String key, String defaultValue) { |
| | | if (Application.exists()) { |
| | | Localizer localizer = Application.get().getResourceSettings().getLocalizer(); |
| | | if (localizer != null) { |
| | | // Use getStringIgnoreSettings because we don't want exceptions here if the key is missing! |
| | | return localizer.getStringIgnoreSettings(key, null, null, defaultValue); |
| | | } |
| | | } |
| | | return defaultValue; |
| | | } |
| | | |
| | | @Override |
| | | public void format(DiffEntry ent) throws IOException { |
| | | currentPath = diffStat.addPath(ent); |
| | | nofLinesCurrent = 0; |
| | | isOff = false; |
| | | entry = ent; |
| | | if (!truncated) { |
| | | totalNofLinesPrevious = totalNofLinesCurrent; |
| | | if (globalDiffLimit > 0 && totalNofLinesPrevious > globalDiffLimit) { |
| | | truncated = true; |
| | | isOff = true; |
| | | } |
| | | truncateTo = os.size(); |
| | | } else { |
| | | isOff = true; |
| | | } |
| | | if (truncated) { |
| | | skipped.add(ent); |
| | | } else { |
| | | // Produce a header here and now |
| | | String path; |
| | | String id; |
| | | if (ChangeType.DELETE.equals(ent.getChangeType())) { |
| | | path = ent.getOldPath(); |
| | | id = ent.getOldId().name(); |
| | | } else { |
| | | path = ent.getNewPath(); |
| | | id = ent.getNewId().name(); |
| | | } |
| | | StringBuilder sb = new StringBuilder(MessageFormat.format("<div class='header'><div class=\"diffHeader\" id=\"n{0}\"><i class=\"icon-file\"></i> ", id)); |
| | | sb.append(StringUtils.escapeForHtml(path, false)).append("</div></div>"); |
| | | sb.append("<div class=\"diff\"><table cellpadding='0'><tbody>\n"); |
| | | os.write(sb.toString().getBytes()); |
| | | } |
| | | // Keep formatting, but if off, don't produce anything anymore. We just keep on counting. |
| | | super.format(ent); |
| | | if (!truncated) { |
| | | // Close the table |
| | | os.write("</tbody></table></div>\n".getBytes()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void flush() throws IOException { |
| | | if (truncated) { |
| | | os.resetTo(truncateTo); |
| | | } |
| | | super.flush(); |
| | | } |
| | | |
| | | /** |
| | | * Rewind and issue a message that the diff is too large. |
| | | */ |
| | | private void reset() { |
| | | if (!isOff) { |
| | | os.resetTo(startCurrent); |
| | | writeFullWidthLine(getMsg("gb.diffFileDiffTooLarge", "Diff too large")); |
| | | totalNofLinesCurrent = totalNofLinesPrevious; |
| | | isOff = true; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Writes an initial table row containing information about added/removed/renamed/copied files. In case |
| | | * of a deletion, we also suppress generating the diff; it's not interesting. (All lines removed.) |
| | | */ |
| | | private void handleChange() { |
| | | // XXX Would be nice if we could generate blob links for the cases handled here. Alas, we lack the repo |
| | | // name, and cannot reliably determine it here. We could get the .git directory of a Repository, if we |
| | | // passed in the repo, and then take the name of the parent directory, but that'd fail for repos nested |
| | | // in GitBlit projects. And we don't know if the repo is inside a project or is a top-level repo. |
| | | // |
| | | // That's certainly solvable (just pass along more information), but would require a larger rewrite than |
| | | // I'm prepared to do now. |
| | | String message; |
| | | switch (entry.getChangeType()) { |
| | | case ADD: |
| | | message = getMsg("gb.diffNewFile", "New file"); |
| | | break; |
| | | case DELETE: |
| | | message = getMsg("gb.diffDeletedFile", "File was deleted"); |
| | | isOff = true; |
| | | break; |
| | | case RENAME: |
| | | message = MessageFormat.format(getMsg("gb.diffRenamedFile", "File was renamed from {0}"), entry.getOldPath()); |
| | | break; |
| | | case COPY: |
| | | message = MessageFormat.format(getMsg("gb.diffCopiedFile", "File was copied from {0}"), entry.getOldPath()); |
| | | break; |
| | | default: |
| | | return; |
| | | } |
| | | writeFullWidthLine(message); |
| | | } |
| | | |
| | | /** |
| | | * Output a hunk header |
| | | * |
| | | * @param aStartLine |
| | | * within first source |
| | | * @param aEndLine |
| | | * within first source |
| | | * @param bStartLine |
| | | * within second source |
| | | * @param bEndLine |
| | | * within second source |
| | | * @throws IOException |
| | | */ |
| | | @Override |
| | | protected void writeHunkHeader(int aStartLine, int aEndLine, int bStartLine, int bEndLine) throws IOException { |
| | | if (nofLinesCurrent++ == 0) { |
| | | handleChange(); |
| | | startCurrent = os.size(); |
| | | } |
| | | if (!isOff) { |
| | | totalNofLinesCurrent++; |
| | | if (nofLinesCurrent > maxDiffLinesPerFile && maxDiffLinesPerFile > 0) { |
| | | reset(); |
| | | } else { |
| | | os.write("<tr><th class='diff-line' data-lineno='..'></th><th class='diff-line' data-lineno='..'></th><th class='diff-state'></th><td class='hunk_header'>" |
| | | .getBytes()); |
| | | os.write('@'); |
| | | os.write('@'); |
| | | writeRange('-', aStartLine + 1, aEndLine - aStartLine); |
| | | writeRange('+', bStartLine + 1, bEndLine - bStartLine); |
| | | os.write(' '); |
| | | os.write('@'); |
| | | os.write('@'); |
| | | os.write("</td></tr>\n".getBytes()); |
| | | } |
| | | } |
| | | left = aStartLine + 1; |
| | | right = bStartLine + 1; |
| | | } |
| | | |
| | | protected void writeRange(final char prefix, final int begin, final int cnt) throws IOException { |
| | | os.write(' '); |
| | | os.write(prefix); |
| | | switch (cnt) { |
| | | case 0: |
| | | // If the range is empty, its beginning number must be the |
| | | // line just before the range, or 0 if the range is at the |
| | | // start of the file stream. Here, begin is always 1 based, |
| | | // so an empty file would produce "0,0". |
| | | // |
| | | os.write(encodeASCII(begin - 1)); |
| | | os.write(','); |
| | | os.write('0'); |
| | | break; |
| | | |
| | | case 1: |
| | | // If the range is exactly one line, produce only the number. |
| | | // |
| | | os.write(encodeASCII(begin)); |
| | | break; |
| | | |
| | | default: |
| | | os.write(encodeASCII(begin)); |
| | | os.write(','); |
| | | os.write(encodeASCII(cnt)); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Writes a line spanning the full width of the code view, including the gutter. |
| | | * |
| | | * @param text |
| | | * to put on that line; will be HTML-escaped. |
| | | */ |
| | | private void writeFullWidthLine(String text) { |
| | | try { |
| | | os.write("<tr><td class='diff-cell' colspan='4'>".getBytes()); |
| | | os.write(StringUtils.escapeForHtml(text, false).getBytes()); |
| | | os.write("</td></tr>\n".getBytes()); |
| | | } catch (IOException ex) { |
| | | // Cannot happen with a ByteArrayOutputStream |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | protected void writeLine(final char prefix, final RawText text, final int cur) throws IOException { |
| | | if (nofLinesCurrent++ == 0) { |
| | | handleChange(); |
| | | startCurrent = os.size(); |
| | | } |
| | | // update entry diffstat |
| | | currentPath.update(prefix); |
| | | if (isOff) { |
| | | return; |
| | | } |
| | | totalNofLinesCurrent++; |
| | | if (nofLinesCurrent > maxDiffLinesPerFile && maxDiffLinesPerFile > 0) { |
| | | reset(); |
| | | } else { |
| | | // output diff |
| | | os.write("<tr>".getBytes()); |
| | | switch (prefix) { |
| | | case '+': |
| | | os.write(("<th class='diff-line'></th><th class='diff-line' data-lineno='" + (right++) + "'></th>").getBytes()); |
| | | os.write("<th class='diff-state diff-state-add'></th>".getBytes()); |
| | | os.write("<td class='diff-cell add2'>".getBytes()); |
| | | break; |
| | | case '-': |
| | | os.write(("<th class='diff-line' data-lineno='" + (left++) + "'></th><th class='diff-line'></th>").getBytes()); |
| | | os.write("<th class='diff-state diff-state-sub'></th>".getBytes()); |
| | | os.write("<td class='diff-cell remove2'>".getBytes()); |
| | | break; |
| | | default: |
| | | os.write(("<th class='diff-line' data-lineno='" + (left++) + "'></th><th class='diff-line' data-lineno='" + (right++) + "'></th>").getBytes()); |
| | | os.write("<th class='diff-state'></th>".getBytes()); |
| | | os.write("<td class='diff-cell context2'>".getBytes()); |
| | | break; |
| | | } |
| | | os.write(encode(codeLineToHtml(prefix, text.getString(cur)))); |
| | | os.write("</td></tr>\n".getBytes()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Convert the given code line to HTML. |
| | | * |
| | | * @param prefix |
| | | * the diff prefix (+/-) indicating whether the line was added or removed. |
| | | * @param line |
| | | * the line to format as HTML |
| | | * @return the HTML-formatted line, safe for inserting as is into HTML. |
| | | */ |
| | | private String codeLineToHtml(final char prefix, final String line) { |
| | | if ((prefix == '+' || prefix == '-')) { |
| | | // Highlight trailing whitespace on deleted/added lines. |
| | | Matcher matcher = trailingWhitespace.matcher(line); |
| | | if (matcher.find()) { |
| | | StringBuilder result = new StringBuilder(StringUtils.escapeForHtml(line.substring(0, matcher.start()), CONVERT_TABS, tabLength)); |
| | | result.append("<span class='trailingws-").append(prefix == '+' ? "add" : "sub").append("'>"); |
| | | result.append(StringUtils.escapeForHtml(matcher.group(1), false)); |
| | | result.append("</span>"); |
| | | return result.toString(); |
| | | } |
| | | } |
| | | return StringUtils.escapeForHtml(line, CONVERT_TABS, tabLength); |
| | | } |
| | | |
| | | /** |
| | | * Workaround function for complex private methods in DiffFormatter. This sets the html for the diff headers. |
| | | * |
| | | * @return |
| | | */ |
| | | public String getHtml() { |
| | | String html = RawParseUtils.decode(os.toByteArray()); |
| | | String[] lines = html.split("\n"); |
| | | StringBuilder sb = new StringBuilder(); |
| | | for (String line : lines) { |
| | | if (line.startsWith("index") || line.startsWith("similarity") |
| | | || line.startsWith("rename from ") || line.startsWith("rename to ")) { |
| | | // skip index lines |
| | | } else if (line.startsWith("new file") || line.startsWith("deleted file")) { |
| | | // skip new file lines |
| | | } else if (line.startsWith("\\ No newline")) { |
| | | // skip no new line |
| | | } else if (line.startsWith("---") || line.startsWith("+++")) { |
| | | // skip --- +++ lines |
| | | } else if (line.startsWith("diff")) { |
| | | // skip diff lines |
| | | } else { |
| | | boolean gitLinkDiff = line.length() > 0 && line.substring(1).startsWith("Subproject commit"); |
| | | if (gitLinkDiff) { |
| | | sb.append("<tr><th class='diff-line'></th><th class='diff-line'></th>"); |
| | | if (line.charAt(0) == '+') { |
| | | sb.append("<th class='diff-state diff-state-add'></th><td class=\"diff-cell add2\">"); |
| | | } else { |
| | | sb.append("<th class='diff-state diff-state-sub'></th><td class=\"diff-cell remove2\">"); |
| | | } |
| | | line = StringUtils.escapeForHtml(line.substring(1), CONVERT_TABS, tabLength); |
| | | } |
| | | sb.append(line); |
| | | if (gitLinkDiff) { |
| | | sb.append("</td></tr>"); |
| | | } |
| | | sb.append('\n'); |
| | | } |
| | | } |
| | | if (truncated) { |
| | | sb.append(MessageFormat.format("<div class='header'><div class='diffHeader'>{0}</div></div>", |
| | | StringUtils.escapeForHtml(getMsg("gb.diffTruncated", "Diff truncated after the above file"), false))); |
| | | // List all files not shown. We can be sure we do have at least one path in skipped. |
| | | sb.append("<div class='diff'><table cellpadding='0'><tbody><tr><td class='diff-cell' colspan='4'>"); |
| | | String deletedSuffix = StringUtils.escapeForHtml(getMsg("gb.diffDeletedFileSkipped", "(deleted)"), false); |
| | | boolean first = true; |
| | | for (DiffEntry entry : skipped) { |
| | | if (!first) { |
| | | sb.append('\n'); |
| | | } |
| | | if (ChangeType.DELETE.equals(entry.getChangeType())) { |
| | | sb.append("<span id=\"n" + entry.getOldId().name() + "\">" + StringUtils.escapeForHtml(entry.getOldPath(), false) + ' ' + deletedSuffix + "</span>"); |
| | | } else { |
| | | sb.append("<span id=\"n" + entry.getNewId().name() + "\">" + StringUtils.escapeForHtml(entry.getNewPath(), false) + "</span>"); |
| | | } |
| | | first = false; |
| | | } |
| | | skipped.clear(); |
| | | sb.append("</td></tr></tbody></table></div>"); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | public DiffStat getDiffStat() { |
| | | return diffStat; |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2014 Tom <tw201207@gmail.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 org.jsoup.nodes.Document; |
| | | import org.jsoup.nodes.Element; |
| | | import org.jsoup.parser.Tag; |
| | | |
| | | /** |
| | | * Simple helper class to hide some common setup needed to use JSoup as an HTML generator. |
| | | * A {@link HtmlBuilder} has a root element that can be manipulated in all the usual JSoup |
| | | * ways (but not added to some {@link Document}); to generate HTML for that root element, |
| | | * the builder's {@link #toString()} method can be used. (Or one can invoke toString() |
| | | * directly on the root element.) By default, a HTML builder does not pretty-print the HTML. |
| | | * |
| | | * @author Tom <tw201207@gmail.com> |
| | | */ |
| | | public class HtmlBuilder { |
| | | |
| | | private final Document shell; |
| | | private final Element root; |
| | | |
| | | /** |
| | | * Creates a new HTML builder with a root element with the given {@code tagName}. |
| | | * |
| | | * @param tagName |
| | | * of the {@link Element} to set as the root element. |
| | | */ |
| | | public HtmlBuilder(String tagName) { |
| | | this(new Element(Tag.valueOf(tagName), "")); |
| | | } |
| | | |
| | | /** |
| | | * Creates a new HTML builder for the given element. |
| | | * |
| | | * @param element |
| | | * to set as the root element of this HTML builder. |
| | | */ |
| | | public HtmlBuilder(Element element) { |
| | | shell = Document.createShell(""); |
| | | shell.outputSettings().prettyPrint(false); |
| | | shell.body().appendChild(element); |
| | | root = element; |
| | | } |
| | | |
| | | /** @return the root element of this HTML builder */ |
| | | public Element getRoot() { |
| | | return root; |
| | | } |
| | | |
| | | /** @return the root element of this HTML builder */ |
| | | public Element root() { |
| | | return root; |
| | | } |
| | | |
| | | /** @return whether this HTML builder will pretty-print the HTML generated by {@link #toString()} */ |
| | | public boolean prettyPrint() { |
| | | return shell.outputSettings().prettyPrint(); |
| | | } |
| | | |
| | | /** |
| | | * Sets whether this HTML builder will produce pretty-printed HTML in its {@link #toString()} method. |
| | | * |
| | | * @param pretty |
| | | * whether to pretty-print |
| | | * @return the HTML builder itself |
| | | */ |
| | | public HtmlBuilder prettyPrint(boolean pretty) { |
| | | shell.outputSettings().prettyPrint(pretty); |
| | | return this; |
| | | } |
| | | |
| | | /** @return the HTML for the root element. */ |
| | | @Override |
| | | public String toString() { |
| | | return root.toString(); |
| | | } |
| | | |
| | | /** @return the {@link Document} used as generation shell. */ |
| | | protected Document getShell() { |
| | | return shell; |
| | | } |
| | | } |
| | |
| | | import java.text.MessageFormat;
|
| | | import java.util.ArrayList;
|
| | | import java.util.Arrays;
|
| | | import java.util.Collection;
|
| | | import java.util.Collections;
|
| | | import java.util.Date;
|
| | | import java.util.HashMap;
|
| | |
| | | import java.util.List;
|
| | | import java.util.Map;
|
| | | import java.util.Map.Entry;
|
| | | import java.util.regex.Matcher;
|
| | | import java.util.regex.Pattern;
|
| | |
|
| | | import org.apache.commons.io.filefilter.TrueFileFilter;
|
| | |
| | | import org.eclipse.jgit.api.FetchCommand;
|
| | | import org.eclipse.jgit.api.Git;
|
| | | import org.eclipse.jgit.api.TagCommand;
|
| | | import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
|
| | | import org.eclipse.jgit.api.errors.GitAPIException;
|
| | | import org.eclipse.jgit.api.errors.JGitInternalException;
|
| | | import org.eclipse.jgit.diff.DiffEntry;
|
| | | import org.eclipse.jgit.diff.DiffEntry.ChangeType;
|
| | | import org.eclipse.jgit.diff.DiffFormatter;
|
| | | import org.eclipse.jgit.diff.RawTextComparator;
|
| | | import org.eclipse.jgit.dircache.DirCache;
|
| | | import org.eclipse.jgit.dircache.DirCacheEntry;
|
| | | import org.eclipse.jgit.errors.ConfigInvalidException;
|
| | | import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
| | | import org.eclipse.jgit.errors.LargeObjectException;
|
| | | import org.eclipse.jgit.errors.MissingObjectException;
|
| | | import org.eclipse.jgit.errors.StopWalkException;
|
| | | import org.eclipse.jgit.internal.JGitText;
|
| | | import org.eclipse.jgit.lib.BlobBasedConfig;
|
| | | import org.eclipse.jgit.lib.CommitBuilder;
|
| | | import org.eclipse.jgit.lib.Constants;
|
| | |
| | | import org.eclipse.jgit.lib.TreeFormatter;
|
| | | import org.eclipse.jgit.merge.MergeStrategy;
|
| | | import org.eclipse.jgit.merge.RecursiveMerger;
|
| | | import org.eclipse.jgit.merge.ThreeWayMerger;
|
| | | import org.eclipse.jgit.revwalk.RevBlob;
|
| | | import org.eclipse.jgit.revwalk.RevCommit;
|
| | | import org.eclipse.jgit.revwalk.RevObject;
|
| | |
| | | import org.eclipse.jgit.transport.CredentialsProvider;
|
| | | import org.eclipse.jgit.transport.FetchResult;
|
| | | import org.eclipse.jgit.transport.RefSpec;
|
| | | import org.eclipse.jgit.treewalk.CanonicalTreeParser;
|
| | | import org.eclipse.jgit.treewalk.TreeWalk;
|
| | | import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
|
| | | import org.eclipse.jgit.treewalk.filter.OrTreeFilter;
|
| | |
| | | import org.slf4j.Logger;
|
| | | import org.slf4j.LoggerFactory;
|
| | |
|
| | | import com.gitblit.GitBlit;
|
| | | import com.gitblit.GitBlitException;
|
| | | import com.gitblit.manager.GitblitManager;
|
| | | import com.gitblit.models.FilestoreModel;
|
| | | import com.gitblit.models.GitNote;
|
| | | import com.gitblit.models.PathModel;
|
| | | import com.gitblit.models.PathModel.PathChangeModel;
|
| | | import com.gitblit.models.RefModel;
|
| | | import com.gitblit.models.SubmoduleModel;
|
| | | import com.gitblit.servlet.FilestoreServlet;
|
| | | import com.google.common.base.Strings;
|
| | |
|
| | | /**
|
| | | * Collection of static methods for retrieving information from a repository.
|
| | |
| | | if (commit == null) {
|
| | | return new Date(0);
|
| | | }
|
| | | return commit.getAuthorIdent().getWhen();
|
| | | if (commit.getAuthorIdent() != null) {
|
| | | return commit.getAuthorIdent().getWhen();
|
| | | }
|
| | | return getCommitDate(commit);
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | }
|
| | | } finally {
|
| | | rw.dispose();
|
| | | tw.release();
|
| | | tw.close();
|
| | | }
|
| | | return content;
|
| | | }
|
| | |
| | | } catch (IOException e) {
|
| | | error(e, repository, "{0} failed to get files for commit {1}", commit.getName());
|
| | | } finally {
|
| | | tw.release();
|
| | | tw.close();
|
| | | }
|
| | | Collections.sort(list);
|
| | | return list;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the list of files in the specified folder at the specified
|
| | | * commit. If the repository does not exist or is empty, an empty list is
|
| | | * returned.
|
| | | *
|
| | | * This is modified version that implements path compression feature.
|
| | | *
|
| | | * @param repository
|
| | | * @param path
|
| | | * if unspecified, root folder is assumed.
|
| | | * @param commit
|
| | | * if null, HEAD is assumed.
|
| | | * @return list of files in specified path
|
| | | */
|
| | | public static List<PathModel> getFilesInPath2(Repository repository, String path, RevCommit commit) {
|
| | |
|
| | | List<PathModel> list = new ArrayList<PathModel>();
|
| | | if (!hasCommits(repository)) {
|
| | | return list;
|
| | | }
|
| | | if (commit == null) {
|
| | | commit = getCommit(repository, null);
|
| | | }
|
| | | final TreeWalk tw = new TreeWalk(repository);
|
| | | try {
|
| | |
|
| | | tw.addTree(commit.getTree());
|
| | | final boolean isPathEmpty = Strings.isNullOrEmpty(path);
|
| | |
|
| | | if (!isPathEmpty) {
|
| | | PathFilter f = PathFilter.create(path);
|
| | | tw.setFilter(f);
|
| | | }
|
| | |
|
| | | tw.setRecursive(true);
|
| | | List<String> paths = new ArrayList<>();
|
| | |
|
| | | while (tw.next()) {
|
| | | String child = isPathEmpty ? tw.getPathString()
|
| | | : tw.getPathString().replaceFirst(String.format("%s/", path), "");
|
| | | paths.add(child);
|
| | | }
|
| | |
|
| | | for(String p: PathUtils.compressPaths(paths)) {
|
| | | String pathString = isPathEmpty ? p : String.format("%s/%s", path, p);
|
| | | list.add(getPathModel(repository, pathString, path, commit));
|
| | | }
|
| | |
|
| | | } catch (IOException e) {
|
| | | error(e, repository, "{0} failed to get files for commit {1}", commit.getName());
|
| | | } finally {
|
| | | tw.close();
|
| | | }
|
| | | Collections.sort(list);
|
| | | return list;
|
| | |
| | | tw.setRecursive(true);
|
| | | tw.addTree(commit.getTree());
|
| | | while (tw.next()) {
|
| | | list.add(new PathChangeModel(tw.getPathString(), tw.getPathString(), 0, tw
|
| | | .getRawMode(0), tw.getObjectId(0).getName(), commit.getId().getName(),
|
| | | long size = 0;
|
| | | FilestoreModel filestoreItem = null;
|
| | | ObjectId objectId = tw.getObjectId(0);
|
| | | |
| | | try {
|
| | | if (!tw.isSubtree() && (tw.getFileMode(0) != FileMode.GITLINK)) {
|
| | |
|
| | | size = tw.getObjectReader().getObjectSize(objectId, Constants.OBJ_BLOB);
|
| | |
|
| | | if (isPossibleFilestoreItem(size)) {
|
| | | filestoreItem = getFilestoreItem(tw.getObjectReader().open(objectId));
|
| | | }
|
| | | }
|
| | | } catch (Throwable t) {
|
| | | error(t, null, "failed to retrieve blob size for " + tw.getPathString());
|
| | | }
|
| | | |
| | | list.add(new PathChangeModel(tw.getPathString(), tw.getPathString(),filestoreItem, size, tw
|
| | | .getRawMode(0), objectId.getName(), commit.getId().getName(),
|
| | | ChangeType.ADD));
|
| | | }
|
| | | tw.release();
|
| | | tw.close();
|
| | | } else {
|
| | | RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
|
| | | DiffStatFormatter df = new DiffStatFormatter(commit.getName());
|
| | | DiffStatFormatter df = new DiffStatFormatter(commit.getName(), repository);
|
| | | df.setRepository(repository);
|
| | | df.setDiffComparator(RawTextComparator.DEFAULT);
|
| | | df.setDetectRenames(true);
|
| | | List<DiffEntry> diffs = df.scan(parent.getTree(), commit.getTree());
|
| | | for (DiffEntry diff : diffs) {
|
| | | // create the path change model
|
| | | PathChangeModel pcm = PathChangeModel.from(diff, commit.getName());
|
| | |
|
| | | if (calculateDiffStat) {
|
| | | PathChangeModel pcm = PathChangeModel.from(diff, commit.getName(), repository);
|
| | | |
| | | if (calculateDiffStat) {
|
| | | // update file diffstats
|
| | | df.format(diff);
|
| | | PathChangeModel pathStat = df.getDiffStat().getPath(pcm.path);
|
| | |
| | | RevCommit start = rw.parseCommit(startRange);
|
| | | RevCommit end = rw.parseCommit(endRange);
|
| | | list.addAll(getFilesInRange(repository, start, end));
|
| | | rw.release();
|
| | | rw.close();
|
| | | } catch (Throwable t) {
|
| | | error(t, repository, "{0} failed to determine files in range {1}..{2}!", startCommit, endCommit);
|
| | | }
|
| | |
| | |
|
| | | List<DiffEntry> diffEntries = df.scan(startCommit.getTree(), endCommit.getTree());
|
| | | for (DiffEntry diff : diffEntries) {
|
| | | PathChangeModel pcm = PathChangeModel.from(diff, endCommit.getName());
|
| | | PathChangeModel pcm = PathChangeModel.from(diff, endCommit.getName(), repository);
|
| | | list.add(pcm);
|
| | | }
|
| | | Collections.sort(list);
|
| | |
| | | } catch (IOException e) {
|
| | | error(e, repository, "{0} failed to get documents for commit {1}", commit.getName());
|
| | | } finally {
|
| | | tw.release();
|
| | | tw.close();
|
| | | }
|
| | | Collections.sort(list);
|
| | | return list;
|
| | |
| | | private static PathModel getPathModel(TreeWalk tw, String basePath, RevCommit commit) {
|
| | | String name;
|
| | | long size = 0;
|
| | | |
| | | if (StringUtils.isEmpty(basePath)) {
|
| | | name = tw.getPathString();
|
| | | } else {
|
| | | name = tw.getPathString().substring(basePath.length() + 1);
|
| | | }
|
| | | ObjectId objectId = tw.getObjectId(0);
|
| | | FilestoreModel filestoreItem = null;
|
| | | |
| | | try {
|
| | | if (!tw.isSubtree() && (tw.getFileMode(0) != FileMode.GITLINK)) {
|
| | |
|
| | | size = tw.getObjectReader().getObjectSize(objectId, Constants.OBJ_BLOB);
|
| | |
|
| | | if (isPossibleFilestoreItem(size)) {
|
| | | filestoreItem = getFilestoreItem(tw.getObjectReader().open(objectId));
|
| | | }
|
| | | }
|
| | | } catch (Throwable t) {
|
| | | error(t, null, "failed to retrieve blob size for " + tw.getPathString());
|
| | | }
|
| | | return new PathModel(name, tw.getPathString(), size, tw.getFileMode(0).getBits(),
|
| | | return new PathModel(name, tw.getPathString(), filestoreItem, size, tw.getFileMode(0).getBits(),
|
| | | objectId.getName(), commit.getName());
|
| | | }
|
| | | |
| | | public static boolean isPossibleFilestoreItem(long size) {
|
| | | return ( (size >= com.gitblit.Constants.LEN_FILESTORE_META_MIN) |
| | | && (size <= com.gitblit.Constants.LEN_FILESTORE_META_MAX));
|
| | | }
|
| | | |
| | | /**
|
| | | * |
| | | * @return Representative FilestoreModel if valid, otherwise null
|
| | | */
|
| | | public static FilestoreModel getFilestoreItem(ObjectLoader obj){
|
| | | try {
|
| | | final byte[] blob = obj.getCachedBytes(com.gitblit.Constants.LEN_FILESTORE_META_MAX);
|
| | | final String meta = new String(blob, "UTF-8");
|
| | | |
| | | return FilestoreModel.fromMetaString(meta);
|
| | |
|
| | | } catch (LargeObjectException e) {
|
| | | //Intentionally failing silent
|
| | | } catch (Exception e) {
|
| | | error(e, null, "failed to retrieve filestoreItem " + obj.toString());
|
| | | }
|
| | | |
| | | return null;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns a path model by path string
|
| | | *
|
| | | * @param repo
|
| | | * @param path
|
| | | * @param filter
|
| | | * @param commit
|
| | | * @return a path model of the specified object
|
| | | */
|
| | | private static PathModel getPathModel(Repository repo, String path, String filter, RevCommit commit)
|
| | | throws IOException {
|
| | |
|
| | | long size = 0;
|
| | | FilestoreModel filestoreItem = null;
|
| | | TreeWalk tw = TreeWalk.forPath(repo, path, commit.getTree());
|
| | | String pathString = path;
|
| | |
|
| | | if (!tw.isSubtree() && (tw.getFileMode(0) != FileMode.GITLINK)) {
|
| | |
|
| | | pathString = PathUtils.getLastPathComponent(pathString);
|
| | | |
| | | size = tw.getObjectReader().getObjectSize(tw.getObjectId(0), Constants.OBJ_BLOB);
|
| | | |
| | | if (isPossibleFilestoreItem(size)) {
|
| | | filestoreItem = getFilestoreItem(tw.getObjectReader().open(tw.getObjectId(0)));
|
| | | }
|
| | | } else if (tw.isSubtree()) {
|
| | |
|
| | | // do not display dirs that are behind in the path
|
| | | if (!Strings.isNullOrEmpty(filter)) {
|
| | | pathString = path.replaceFirst(filter + "/", "");
|
| | | }
|
| | |
|
| | | // remove the last slash from path in displayed link
|
| | | if (pathString != null && pathString.charAt(pathString.length()-1) == '/') {
|
| | | pathString = pathString.substring(0, pathString.length()-1);
|
| | | }
|
| | | }
|
| | |
|
| | | return new PathModel(pathString, tw.getPathString(), filestoreItem, size, tw.getFileMode(0).getBits(),
|
| | | tw.getObjectId(0).getName(), commit.getName());
|
| | |
|
| | | }
|
| | |
|
| | |
|
| | | /**
|
| | | * Returns a permissions representation of the mode bits.
|
| | |
| | | * @return true if successful
|
| | | */
|
| | | public static boolean deleteBranchRef(Repository repository, String branch) {
|
| | | String branchName = branch;
|
| | | if (!branchName.startsWith(Constants.R_HEADS)) {
|
| | | branchName = Constants.R_HEADS + branch;
|
| | | }
|
| | |
|
| | | try {
|
| | | RefUpdate refUpdate = repository.updateRef(branchName, false);
|
| | | RefUpdate refUpdate = repository.updateRef(branch, false);
|
| | | refUpdate.setForceUpdate(true);
|
| | | RefUpdate.Result result = refUpdate.delete();
|
| | | switch (result) {
|
| | |
| | | return true;
|
| | | default:
|
| | | LOGGER.error(MessageFormat.format("{0} failed to delete to {1} returned result {2}",
|
| | | repository.getDirectory().getAbsolutePath(), branchName, result));
|
| | | repository.getDirectory().getAbsolutePath(), branch, result));
|
| | | }
|
| | | } catch (Throwable t) {
|
| | | error(t, repository, "{0} failed to delete {1}", branchName);
|
| | | error(t, repository, "{0} failed to delete {1}", branch);
|
| | | }
|
| | | return false;
|
| | | }
|
| | |
| | | error(t, repository, "{0} can't find {1} in commit {2}", path, commit.name());
|
| | | } finally {
|
| | | rw.dispose();
|
| | | tw.release();
|
| | | tw.close();
|
| | | }
|
| | | return commitId;
|
| | | }
|
| | |
| | | success = false;
|
| | | }
|
| | | } finally {
|
| | | revWalk.release();
|
| | | revWalk.close();
|
| | | }
|
| | | } finally {
|
| | | odi.release();
|
| | | odi.close();
|
| | | }
|
| | | } catch (Throwable t) {
|
| | | error(t, repository, "Failed to create orphan branch {1} in repository {0}", branchName);
|
| | |
| | | }
|
| | | return false;
|
| | | }
|
| | | |
| | | /** |
| | | * Returns true if the commit identified by commitId is an ancestor or the |
| | | * the commit identified by tipId. |
| | | * |
| | | * @param repository |
| | | * @param commitId |
| | | * @param tipId |
| | | * @return true if there is the commit is an ancestor of the tip |
| | | */ |
| | | public static boolean isMergedInto(Repository repository, String commitId, String tipId) { |
| | | try { |
| | | return isMergedInto(repository, repository.resolve(commitId), repository.resolve(tipId)); |
| | | } catch (Exception e) { |
| | | LOGGER.error("Failed to determine isMergedInto", e); |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * Returns true if the commit identified by commitId is an ancestor or the |
| | | * the commit identified by tipId. |
| | | * |
| | | * @param repository |
| | | * @param commitId |
| | | * @param tipId |
| | | * @return true if there is the commit is an ancestor of the tip |
| | | */ |
| | | public static boolean isMergedInto(Repository repository, ObjectId commitId, ObjectId tipCommitId) { |
| | | // traverse the revlog looking for a commit chain between the endpoints |
| | | RevWalk rw = new RevWalk(repository); |
| | | try { |
| | | // must re-lookup RevCommits to workaround undocumented RevWalk bug |
| | | RevCommit tip = rw.lookupCommit(tipCommitId); |
| | | RevCommit commit = rw.lookupCommit(commitId); |
| | | return rw.isMergedInto(commit, tip); |
| | | } catch (Exception e) { |
| | | LOGGER.error("Failed to determine isMergedInto", e); |
| | | } finally { |
| | | rw.dispose(); |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * Returns the merge base of two commits or null if there is no common |
| | | * ancestry. |
| | | * |
| | | * @param repository |
| | | * @param commitIdA |
| | | * @param commitIdB |
| | | * @return the commit id of the merge base or null if there is no common base |
| | | */ |
| | | public static String getMergeBase(Repository repository, ObjectId commitIdA, ObjectId commitIdB) { |
| | | RevWalk rw = new RevWalk(repository); |
| | | try { |
| | | RevCommit a = rw.lookupCommit(commitIdA); |
| | | RevCommit b = rw.lookupCommit(commitIdB); |
| | | |
| | | rw.setRevFilter(RevFilter.MERGE_BASE); |
| | | rw.markStart(a); |
| | | rw.markStart(b); |
| | | RevCommit mergeBase = rw.next(); |
| | | if (mergeBase == null) { |
| | | return null; |
| | | } |
| | | return mergeBase.getName(); |
| | | } catch (Exception e) { |
| | | LOGGER.error("Failed to determine merge base", e); |
| | | } finally { |
| | | rw.dispose(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | public static enum MergeStatus { |
| | | NOT_MERGEABLE, FAILED, ALREADY_MERGED, MERGEABLE, MERGED; |
| | | } |
| | | |
| | | /** |
| | | * Determines if we can cleanly merge one branch into another. Returns true |
| | | * if we can merge without conflict, otherwise returns false. |
| | | * |
| | | * @param repository |
| | | * @param src |
| | | * @param toBranch |
| | | * @return true if we can merge without conflict |
| | | */ |
| | | public static MergeStatus canMerge(Repository repository, String src, String toBranch) { |
| | | RevWalk revWalk = null; |
| | | try { |
| | | revWalk = new RevWalk(repository); |
| | | RevCommit branchTip = revWalk.lookupCommit(repository.resolve(toBranch)); |
| | | RevCommit srcTip = revWalk.lookupCommit(repository.resolve(src)); |
| | | if (revWalk.isMergedInto(srcTip, branchTip)) { |
| | | // already merged |
| | | return MergeStatus.ALREADY_MERGED; |
| | | } else if (revWalk.isMergedInto(branchTip, srcTip)) { |
| | | // fast-forward |
| | | return MergeStatus.MERGEABLE; |
| | | } |
| | | RecursiveMerger merger = (RecursiveMerger) MergeStrategy.RECURSIVE.newMerger(repository, true); |
| | | boolean canMerge = merger.merge(branchTip, srcTip); |
| | | if (canMerge) { |
| | | return MergeStatus.MERGEABLE; |
| | | } |
| | | } catch (IOException e) { |
| | | LOGGER.error("Failed to determine canMerge", e); |
| | |
|
| | | /**
|
| | | * Returns true if the commit identified by commitId is an ancestor or the
|
| | | * the commit identified by tipId.
|
| | | *
|
| | | * @param repository
|
| | | * @param commitId
|
| | | * @param tipId
|
| | | * @return true if there is the commit is an ancestor of the tip
|
| | | */
|
| | | public static boolean isMergedInto(Repository repository, String commitId, String tipId) {
|
| | | try {
|
| | | return isMergedInto(repository, repository.resolve(commitId), repository.resolve(tipId));
|
| | | } catch (Exception e) {
|
| | | LOGGER.error("Failed to determine isMergedInto", e);
|
| | | }
|
| | | return false;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns true if the commit identified by commitId is an ancestor or the
|
| | | * the commit identified by tipId.
|
| | | *
|
| | | * @param repository
|
| | | * @param commitId
|
| | | * @param tipId
|
| | | * @return true if there is the commit is an ancestor of the tip
|
| | | */
|
| | | public static boolean isMergedInto(Repository repository, ObjectId commitId, ObjectId tipCommitId) {
|
| | | // traverse the revlog looking for a commit chain between the endpoints
|
| | | RevWalk rw = new RevWalk(repository);
|
| | | try {
|
| | | // must re-lookup RevCommits to workaround undocumented RevWalk bug
|
| | | RevCommit tip = rw.lookupCommit(tipCommitId);
|
| | | RevCommit commit = rw.lookupCommit(commitId);
|
| | | return rw.isMergedInto(commit, tip);
|
| | | } catch (Exception e) {
|
| | | LOGGER.error("Failed to determine isMergedInto", e);
|
| | | } finally {
|
| | | if (revWalk != null) { |
| | | revWalk.release();
|
| | | } |
| | | } |
| | | return MergeStatus.NOT_MERGEABLE; |
| | | } |
| | | |
| | | |
| | | public static class MergeResult { |
| | | public final MergeStatus status; |
| | | public final String sha; |
| | | |
| | | MergeResult(MergeStatus status, String sha) { |
| | | this.status = status; |
| | | this.sha = sha; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Tries to merge a commit into a branch. If there are conflicts, the merge |
| | | * will fail. |
| | | * |
| | | * @param repository |
| | | * @param src |
| | | * @param toBranch |
| | | * @param committer |
| | | * @param message |
| | | * @return the merge result |
| | | */ |
| | | public static MergeResult merge(Repository repository, String src, String toBranch, |
| | | PersonIdent committer, String message) { |
| | | |
| | | if (!toBranch.startsWith(Constants.R_REFS)) { |
| | | // branch ref doesn't start with ref, assume this is a branch head |
| | | toBranch = Constants.R_HEADS + toBranch; |
| | | } |
| | | |
| | | RevWalk revWalk = null; |
| | | try { |
| | | revWalk = new RevWalk(repository); |
| | | RevCommit branchTip = revWalk.lookupCommit(repository.resolve(toBranch)); |
| | | RevCommit srcTip = revWalk.lookupCommit(repository.resolve(src)); |
| | | if (revWalk.isMergedInto(srcTip, branchTip)) { |
| | | // already merged |
| | | return new MergeResult(MergeStatus.ALREADY_MERGED, null); |
| | | } |
| | | RecursiveMerger merger = (RecursiveMerger) MergeStrategy.RECURSIVE.newMerger(repository, true); |
| | | boolean merged = merger.merge(branchTip, srcTip); |
| | | if (merged) { |
| | | // create a merge commit and a reference to track the merge commit |
| | | ObjectId treeId = merger.getResultTreeId(); |
| | | ObjectInserter odi = repository.newObjectInserter(); |
| | | try { |
| | | // Create a commit object |
| | | CommitBuilder commitBuilder = new CommitBuilder(); |
| | | commitBuilder.setCommitter(committer); |
| | | commitBuilder.setAuthor(committer); |
| | | commitBuilder.setEncoding(Constants.CHARSET); |
| | | if (StringUtils.isEmpty(message)) { |
| | | message = MessageFormat.format("merge {0} into {1}", srcTip.getName(), branchTip.getName()); |
| | | } |
| | | commitBuilder.setMessage(message); |
| | | commitBuilder.setParentIds(branchTip.getId(), srcTip.getId()); |
| | | commitBuilder.setTreeId(treeId); |
| | | |
| | | // Insert the merge commit into the repository |
| | | ObjectId mergeCommitId = odi.insert(commitBuilder); |
| | | odi.flush(); |
| | | |
| | | // set the merge ref to the merge commit |
| | | RevCommit mergeCommit = revWalk.parseCommit(mergeCommitId); |
| | | RefUpdate mergeRefUpdate = repository.updateRef(toBranch); |
| | | mergeRefUpdate.setNewObjectId(mergeCommitId); |
| | | mergeRefUpdate.setRefLogMessage("commit: " + mergeCommit.getShortMessage(), false); |
| | | RefUpdate.Result rc = mergeRefUpdate.update(); |
| | | switch (rc) { |
| | | case FAST_FORWARD: |
| | | // successful, clean merge |
| | | rw.dispose();
|
| | | }
|
| | | return false;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the merge base of two commits or null if there is no common
|
| | | * ancestry.
|
| | | *
|
| | | * @param repository
|
| | | * @param commitIdA
|
| | | * @param commitIdB
|
| | | * @return the commit id of the merge base or null if there is no common base
|
| | | */
|
| | | public static String getMergeBase(Repository repository, ObjectId commitIdA, ObjectId commitIdB) {
|
| | | RevWalk rw = new RevWalk(repository);
|
| | | try {
|
| | | RevCommit a = rw.lookupCommit(commitIdA);
|
| | | RevCommit b = rw.lookupCommit(commitIdB);
|
| | |
|
| | | rw.setRevFilter(RevFilter.MERGE_BASE);
|
| | | rw.markStart(a);
|
| | | rw.markStart(b);
|
| | | RevCommit mergeBase = rw.next();
|
| | | if (mergeBase == null) {
|
| | | return null;
|
| | | }
|
| | | return mergeBase.getName();
|
| | | } catch (Exception e) {
|
| | | LOGGER.error("Failed to determine merge base", e);
|
| | | } finally {
|
| | | rw.dispose();
|
| | | }
|
| | | return null;
|
| | | }
|
| | |
|
| | | public static enum MergeStatus {
|
| | | MISSING_INTEGRATION_BRANCH, MISSING_SRC_BRANCH, NOT_MERGEABLE, FAILED, ALREADY_MERGED, MERGEABLE, MERGED;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Determines if we can cleanly merge one branch into another. Returns true
|
| | | * if we can merge without conflict, otherwise returns false.
|
| | | *
|
| | | * @param repository
|
| | | * @param src
|
| | | * @param toBranch
|
| | | * @return true if we can merge without conflict
|
| | | */
|
| | | public static MergeStatus canMerge(Repository repository, String src, String toBranch) {
|
| | | RevWalk revWalk = null;
|
| | | try {
|
| | | revWalk = new RevWalk(repository);
|
| | | ObjectId branchId = repository.resolve(toBranch);
|
| | | if (branchId == null) {
|
| | | return MergeStatus.MISSING_INTEGRATION_BRANCH;
|
| | | }
|
| | | ObjectId srcId = repository.resolve(src);
|
| | | if (srcId == null) {
|
| | | return MergeStatus.MISSING_SRC_BRANCH;
|
| | | }
|
| | | RevCommit branchTip = revWalk.lookupCommit(branchId);
|
| | | RevCommit srcTip = revWalk.lookupCommit(srcId);
|
| | | if (revWalk.isMergedInto(srcTip, branchTip)) {
|
| | | // already merged
|
| | | return MergeStatus.ALREADY_MERGED;
|
| | | } else if (revWalk.isMergedInto(branchTip, srcTip)) {
|
| | | // fast-forward
|
| | | return MergeStatus.MERGEABLE;
|
| | | }
|
| | | RecursiveMerger merger = (RecursiveMerger) MergeStrategy.RECURSIVE.newMerger(repository, true);
|
| | | boolean canMerge = merger.merge(branchTip, srcTip);
|
| | | if (canMerge) {
|
| | | return MergeStatus.MERGEABLE;
|
| | | }
|
| | | } catch (NullPointerException e) {
|
| | | LOGGER.error("Failed to determine canMerge", e);
|
| | | } catch (IOException e) {
|
| | | LOGGER.error("Failed to determine canMerge", e);
|
| | | } finally {
|
| | | if (revWalk != null) {
|
| | | revWalk.close();
|
| | | }
|
| | | }
|
| | | return MergeStatus.NOT_MERGEABLE;
|
| | | }
|
| | |
|
| | |
|
| | | public static class MergeResult {
|
| | | public final MergeStatus status;
|
| | | public final String sha;
|
| | |
|
| | | MergeResult(MergeStatus status, String sha) {
|
| | | this.status = status;
|
| | | this.sha = sha;
|
| | | }
|
| | | }
|
| | |
|
| | | /**
|
| | | * Tries to merge a commit into a branch. If there are conflicts, the merge
|
| | | * will fail.
|
| | | *
|
| | | * @param repository
|
| | | * @param src
|
| | | * @param toBranch
|
| | | * @param committer
|
| | | * @param message
|
| | | * @return the merge result
|
| | | */
|
| | | public static MergeResult merge(Repository repository, String src, String toBranch,
|
| | | PersonIdent committer, String message) {
|
| | |
|
| | | if (!toBranch.startsWith(Constants.R_REFS)) {
|
| | | // branch ref doesn't start with ref, assume this is a branch head
|
| | | toBranch = Constants.R_HEADS + toBranch;
|
| | | }
|
| | |
|
| | | RevWalk revWalk = null;
|
| | | try {
|
| | | revWalk = new RevWalk(repository);
|
| | | RevCommit branchTip = revWalk.lookupCommit(repository.resolve(toBranch));
|
| | | RevCommit srcTip = revWalk.lookupCommit(repository.resolve(src));
|
| | | if (revWalk.isMergedInto(srcTip, branchTip)) {
|
| | | // already merged
|
| | | return new MergeResult(MergeStatus.ALREADY_MERGED, null);
|
| | | }
|
| | | RecursiveMerger merger = (RecursiveMerger) MergeStrategy.RECURSIVE.newMerger(repository, true);
|
| | | boolean merged = merger.merge(branchTip, srcTip);
|
| | | if (merged) {
|
| | | // create a merge commit and a reference to track the merge commit
|
| | | ObjectId treeId = merger.getResultTreeId();
|
| | | ObjectInserter odi = repository.newObjectInserter();
|
| | | try {
|
| | | // Create a commit object
|
| | | CommitBuilder commitBuilder = new CommitBuilder();
|
| | | commitBuilder.setCommitter(committer);
|
| | | commitBuilder.setAuthor(committer);
|
| | | commitBuilder.setEncoding(Constants.CHARSET);
|
| | | if (StringUtils.isEmpty(message)) {
|
| | | message = MessageFormat.format("merge {0} into {1}", srcTip.getName(), branchTip.getName());
|
| | | }
|
| | | commitBuilder.setMessage(message);
|
| | | commitBuilder.setParentIds(branchTip.getId(), srcTip.getId());
|
| | | commitBuilder.setTreeId(treeId);
|
| | |
|
| | | // Insert the merge commit into the repository
|
| | | ObjectId mergeCommitId = odi.insert(commitBuilder);
|
| | | odi.flush();
|
| | |
|
| | | // set the merge ref to the merge commit
|
| | | RevCommit mergeCommit = revWalk.parseCommit(mergeCommitId);
|
| | | RefUpdate mergeRefUpdate = repository.updateRef(toBranch);
|
| | | mergeRefUpdate.setNewObjectId(mergeCommitId);
|
| | | mergeRefUpdate.setRefLogMessage("commit: " + mergeCommit.getShortMessage(), false);
|
| | | RefUpdate.Result rc = mergeRefUpdate.update();
|
| | | switch (rc) {
|
| | | case FAST_FORWARD:
|
| | | // successful, clean merge
|
| | | break;
|
| | | default: |
| | | throw new GitBlitException(MessageFormat.format("Unexpected result \"{0}\" when merging commit {1} into {2} in {3}", |
| | | rc.name(), srcTip.getName(), branchTip.getName(), repository.getDirectory())); |
| | | } |
| | | |
| | | // return the merge commit id |
| | | return new MergeResult(MergeStatus.MERGED, mergeCommitId.getName()); |
| | | } finally { |
| | | odi.release(); |
| | | } |
| | | } |
| | | } catch (IOException e) { |
| | | LOGGER.error("Failed to merge", e); |
| | | default:
|
| | | throw new GitBlitException(MessageFormat.format("Unexpected result \"{0}\" when merging commit {1} into {2} in {3}",
|
| | | rc.name(), srcTip.getName(), branchTip.getName(), repository.getDirectory()));
|
| | | }
|
| | |
|
| | | // return the merge commit id
|
| | | return new MergeResult(MergeStatus.MERGED, mergeCommitId.getName());
|
| | | } finally {
|
| | | odi.close();
|
| | | }
|
| | | }
|
| | | } catch (IOException e) {
|
| | | LOGGER.error("Failed to merge", e);
|
| | | } finally {
|
| | | if (revWalk != null) { |
| | | revWalk.release();
|
| | | } |
| | | } |
| | | return new MergeResult(MergeStatus.FAILED, null); |
| | | } |
| | | if (revWalk != null) {
|
| | | revWalk.close();
|
| | | }
|
| | | }
|
| | | return new MergeResult(MergeStatus.FAILED, null);
|
| | | }
|
| | | |
| | | |
| | | /**
|
| | | * Returns the LFS URL for the given oid |
| | | * Currently assumes that the Gitblit Filestore is used |
| | | *
|
| | | * @param baseURL
|
| | | * @param repository name
|
| | | * @param oid of lfs item
|
| | | * @return the lfs item URL
|
| | | */
|
| | | public static String getLfsRepositoryUrl(String baseURL, String repositoryName, String oid) {
|
| | | |
| | | if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') {
|
| | | baseURL = baseURL.substring(0, baseURL.length() - 1);
|
| | | }
|
| | | |
| | | return baseURL + com.gitblit.Constants.R_PATH |
| | | + repositoryName + "/" |
| | | + com.gitblit.Constants.R_LFS |
| | | + "objects/" + oid;
|
| | | |
| | | }
|
| | | |
| | | /**
|
| | | * Returns all tree entries that do not match the ignore paths.
|
| | | *
|
| | | * @param db
|
| | | * @param ignorePaths
|
| | | * @param dcBuilder
|
| | | * @throws IOException
|
| | | */
|
| | | public static List<DirCacheEntry> getTreeEntries(Repository db, String branch, Collection<String> ignorePaths) throws IOException {
|
| | | List<DirCacheEntry> list = new ArrayList<DirCacheEntry>();
|
| | | TreeWalk tw = null;
|
| | | try {
|
| | | ObjectId treeId = db.resolve(branch + "^{tree}");
|
| | | if (treeId == null) {
|
| | | // branch does not exist yet
|
| | | return list;
|
| | | }
|
| | | tw = new TreeWalk(db);
|
| | | int hIdx = tw.addTree(treeId);
|
| | | tw.setRecursive(true);
|
| | |
|
| | | while (tw.next()) {
|
| | | String path = tw.getPathString();
|
| | | CanonicalTreeParser hTree = null;
|
| | | if (hIdx != -1) {
|
| | | hTree = tw.getTree(hIdx, CanonicalTreeParser.class);
|
| | | }
|
| | | if (!ignorePaths.contains(path)) {
|
| | | // add all other tree entries
|
| | | if (hTree != null) {
|
| | | final DirCacheEntry entry = new DirCacheEntry(path);
|
| | | entry.setObjectId(hTree.getEntryObjectId());
|
| | | entry.setFileMode(hTree.getEntryFileMode());
|
| | | list.add(entry);
|
| | | }
|
| | | }
|
| | | }
|
| | | } finally {
|
| | | if (tw != null) {
|
| | | tw.close();
|
| | | }
|
| | | }
|
| | | return list;
|
| | | }
|
| | | |
| | | public static boolean commitIndex(Repository db, String branch, DirCache index,
|
| | | ObjectId parentId, boolean forceCommit,
|
| | | String author, String authorEmail, String message) throws IOException, ConcurrentRefUpdateException {
|
| | | boolean success = false;
|
| | |
|
| | | ObjectId headId = db.resolve(branch + "^{commit}");
|
| | | ObjectId baseId = parentId;
|
| | | if (baseId == null || headId == null) { return false; }
|
| | | |
| | | ObjectInserter odi = db.newObjectInserter();
|
| | | try {
|
| | | // Create the in-memory index of the new/updated ticket
|
| | | ObjectId indexTreeId = index.writeTree(odi);
|
| | |
|
| | | // Create a commit object
|
| | | PersonIdent ident = new PersonIdent(author, authorEmail);
|
| | | |
| | | if (forceCommit == false) {
|
| | | ThreeWayMerger merger = MergeStrategy.RECURSIVE.newMerger(db, true);
|
| | | merger.setObjectInserter(odi);
|
| | | merger.setBase(baseId);
|
| | | boolean mergeSuccess = merger.merge(indexTreeId, headId);
|
| | | |
| | | if (mergeSuccess) {
|
| | | indexTreeId = merger.getResultTreeId();
|
| | | } else {
|
| | | //Manual merge required
|
| | | return false; |
| | | }
|
| | | }
|
| | | |
| | | CommitBuilder commit = new CommitBuilder();
|
| | | commit.setAuthor(ident);
|
| | | commit.setCommitter(ident);
|
| | | commit.setEncoding(com.gitblit.Constants.ENCODING);
|
| | | commit.setMessage(message);
|
| | | commit.setParentId(headId);
|
| | | commit.setTreeId(indexTreeId);
|
| | |
|
| | | // Insert the commit into the repository
|
| | | ObjectId commitId = odi.insert(commit);
|
| | | odi.flush();
|
| | |
|
| | | RevWalk revWalk = new RevWalk(db);
|
| | | try {
|
| | | RevCommit revCommit = revWalk.parseCommit(commitId);
|
| | | RefUpdate ru = db.updateRef(branch);
|
| | | ru.setForceUpdate(forceCommit);
|
| | | ru.setNewObjectId(commitId);
|
| | | ru.setExpectedOldObjectId(headId);
|
| | | ru.setRefLogMessage("commit: " + revCommit.getShortMessage(), false);
|
| | | Result rc = ru.update();
|
| | |
|
| | | switch (rc) {
|
| | | case NEW:
|
| | | case FORCED:
|
| | | case FAST_FORWARD:
|
| | | success = true;
|
| | | break;
|
| | | case REJECTED:
|
| | | case LOCK_FAILURE:
|
| | | throw new ConcurrentRefUpdateException(JGitText.get().couldNotLockHEAD,
|
| | | ru.getRef(), rc);
|
| | | default:
|
| | | throw new JGitInternalException(MessageFormat.format(
|
| | | JGitText.get().updatingRefFailed, branch, commitId.toString(),
|
| | | rc));
|
| | | }
|
| | | } finally {
|
| | | revWalk.close();
|
| | | }
|
| | | } finally {
|
| | | odi.close();
|
| | | }
|
| | | return success;
|
| | | }
|
| | | |
| | | /**
|
| | | * Returns true if the commit identified by commitId is at the tip of it's branch.
|
| | | *
|
| | | * @param repository
|
| | | * @param commitId
|
| | | * @return true if the given commit is the tip
|
| | | */
|
| | | public static boolean isTip(Repository repository, String commitId) {
|
| | | try {
|
| | | RefModel tip = getBranch(repository, commitId);
|
| | | return (tip != null); |
| | | } catch (Exception e) {
|
| | | LOGGER.error("Failed to determine isTip", e);
|
| | | }
|
| | | return false;
|
| | | }
|
| | |
|
| | | }
|
| | |
| | | import org.jsoup.safety.Cleaner; |
| | | import org.jsoup.safety.Whitelist; |
| | | |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Singleton; |
| | | |
| | | /** |
| | | * Implementation of an XSS filter based on JSoup. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | @Singleton |
| | | public class JSoupXssFilter implements XssFilter { |
| | | |
| | | private final Cleaner none; |
| | | |
| | | private final Cleaner relaxed; |
| | | |
| | | @Inject |
| | | public JSoupXssFilter() { |
| | | none = new Cleaner(Whitelist.none()); |
| | | relaxed = new Cleaner(getRelaxedWhiteList()); |
| | |
| | | import com.google.gson.JsonDeserializationContext;
|
| | | import com.google.gson.JsonDeserializer;
|
| | | import com.google.gson.JsonElement;
|
| | | import com.google.gson.JsonParseException;
|
| | | import com.google.gson.JsonPrimitive;
|
| | | import com.google.gson.JsonSerializationContext;
|
| | | import com.google.gson.JsonSerializer;
|
| | |
| | |
|
| | | /**
|
| | | * Convert a json string to an object of the specified type.
|
| | | *
|
| | | * |
| | | * @param json
|
| | | * @param clazz
|
| | | * @return an object
|
| | | * @return the deserialized object
|
| | | * @throws JsonParseException
|
| | | * @throws JsonSyntaxException
|
| | | */
|
| | | public static <X> X fromJsonString(String json, Class<X> clazz) {
|
| | | public static <X> X fromJsonString(String json, Class<X> clazz) throws JsonParseException,
|
| | | JsonSyntaxException {
|
| | | return gson().fromJson(json, clazz);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Convert a json string to an object of the specified type.
|
| | | *
|
| | | * |
| | | * @param json
|
| | | * @param clazz
|
| | | * @return an object
|
| | | * @param type
|
| | | * @return the deserialized object
|
| | | * @throws JsonParseException
|
| | | * @throws JsonSyntaxException
|
| | | */
|
| | | public static <X> X fromJsonString(String json, Type type) {
|
| | | public static <X> X fromJsonString(String json, Type type) throws JsonParseException,
|
| | | JsonSyntaxException {
|
| | | return gson().fromJson(json, type);
|
| | | }
|
| | |
|
| | |
| | | package com.gitblit.utils;
|
| | |
|
| | | import static org.pegdown.Extensions.ALL;
|
| | | import static org.pegdown.Extensions.ANCHORLINKS;
|
| | | import static org.pegdown.Extensions.SMARTYPANTS;
|
| | |
|
| | | import java.io.IOException;
|
| | |
| | | */
|
| | | public static String transformMarkdown(String markdown, LinkRenderer linkRenderer) {
|
| | | try {
|
| | | PegDownProcessor pd = new PegDownProcessor(ALL & ~SMARTYPANTS);
|
| | | PegDownProcessor pd = new PegDownProcessor(ALL & ~SMARTYPANTS & ~ANCHORLINKS);
|
| | | RootNode astRoot = pd.parseMarkdown(markdown.toCharArray());
|
| | | return new WorkaroundHtmlSerializer(linkRenderer == null ? new LinkRenderer() : linkRenderer).toHtml(astRoot);
|
| | | } catch (ParsingTimeoutException e) {
|
| | |
| | |
|
| | | Iterable<RevCommit> revlog = revWalk;
|
| | | for (RevCommit rev : revlog) {
|
| | | Date d = JGitUtils.getCommitDate(rev);
|
| | | Date d = JGitUtils.getAuthorDate(rev);
|
| | | String p = df.format(d);
|
| | | if (!metricMap.containsKey(p)) {
|
| | | metricMap.put(p, new Metric(p));
|
New file |
| | |
| | | package com.gitblit.utils; |
| | | |
| | | import com.google.common.base.Joiner; |
| | | import com.google.common.base.Splitter; |
| | | import com.google.common.collect.Iterables; |
| | | |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * Utils for handling path strings |
| | | * |
| | | */ |
| | | public class PathUtils { |
| | | |
| | | private PathUtils() {} |
| | | |
| | | /** |
| | | * Compress paths containing no files |
| | | * |
| | | * @param paths lines from `git ls-tree -r --name-only ${branch}` |
| | | * @return compressed paths |
| | | */ |
| | | public static List<String> compressPaths(final Iterable<String> paths) { |
| | | |
| | | ArrayList<String> pathList = new ArrayList<>(); |
| | | Map<String, List<String[]>> folderRoots = new LinkedHashMap<>(); |
| | | |
| | | for (String s: paths) { |
| | | String[] components = s.split("/"); |
| | | |
| | | // File in current directory |
| | | if (components.length == 1) { |
| | | pathList.add(components[0]); |
| | | |
| | | // Directory path |
| | | } else { |
| | | List<String[]> rootedPaths = folderRoots.get(components[0]); |
| | | if (rootedPaths == null) { |
| | | rootedPaths = new ArrayList<>(); |
| | | } |
| | | rootedPaths.add(components); |
| | | folderRoots.put(components[0], rootedPaths); |
| | | } |
| | | } |
| | | |
| | | for (String folder: folderRoots.keySet()) { |
| | | List<String[]> matchingPaths = folderRoots.get(folder); |
| | | |
| | | if (matchingPaths.size() == 1) { |
| | | pathList.add(toStringPath(matchingPaths.get(0))); |
| | | } else { |
| | | pathList.add(longestCommonSequence(matchingPaths)); |
| | | } |
| | | } |
| | | return pathList; |
| | | } |
| | | |
| | | /** |
| | | * Get last path component |
| | | * |
| | | * |
| | | * @param path string path separated by slashes |
| | | * @return rightmost entry |
| | | */ |
| | | public static String getLastPathComponent(final String path) { |
| | | return Iterables.getLast(Splitter.on("/").omitEmptyStrings().split(path), path); |
| | | } |
| | | |
| | | private static String toStringPath(final String[] pathComponents) { |
| | | List<String> tmp = Arrays.asList(pathComponents); |
| | | return Joiner.on('/').join(tmp.subList(0,tmp.size()-1)) + '/'; |
| | | } |
| | | |
| | | |
| | | private static String longestCommonSequence(final List<String[]> paths) { |
| | | |
| | | StringBuilder path = new StringBuilder(); |
| | | |
| | | for (int i = 0; i < paths.get(0).length; i++) { |
| | | String current = paths.get(0)[i]; |
| | | for (int j = 1; j < paths.size(); j++) { |
| | | if (!current.equals(paths.get(j)[i])) { |
| | | return path.toString(); |
| | | } |
| | | } |
| | | path.append(current); |
| | | path.append('/'); |
| | | } |
| | | return path.toString(); |
| | | } |
| | | |
| | | } |
| | |
| | | rc)); |
| | | } |
| | | } finally { |
| | | revWalk.release(); |
| | | revWalk.close(); |
| | | } |
| | | } finally { |
| | | odi.release(); |
| | | odi.close(); |
| | | } |
| | | } catch (Throwable t) { |
| | | error(t, repository, "Failed to commit reflog entry to {0}"); |
| | |
| | | } |
| | | |
| | | // release the treewalk |
| | | treeWalk.release(); |
| | | treeWalk.close(); |
| | | |
| | | // finish temporary in-core index used for this commit |
| | | dcBuilder.finish(); |
| | | } finally { |
| | | inserter.release(); |
| | | inserter.close(); |
| | | } |
| | | return inCoreIndex; |
| | | } |
New file |
| | |
| | | // Copyright (C) 2014 Tom <tw201207@gmail.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.ByteArrayOutputStream; |
| | | |
| | | /** |
| | | * A {@link ByteArrayOutputStream} that can be reset to a specified position. |
| | | * |
| | | * @author Tom <tw201207@gmail.com> |
| | | */ |
| | | public class ResettableByteArrayOutputStream extends ByteArrayOutputStream { |
| | | |
| | | /** |
| | | * Reset the stream to the given position. If {@code mark} is <= 0, see {@link #reset()}. |
| | | * A no-op if the stream contains less than {@code mark} bytes. Otherwise, resets the |
| | | * current writing position to {@code mark}. Previously allocated buffer space will be |
| | | * reused in subsequent writes. |
| | | * |
| | | * @param mark |
| | | * to set the current writing position to. |
| | | */ |
| | | public synchronized void resetTo(int mark) { |
| | | if (mark <= 0) { |
| | | reset(); |
| | | } else if (mark < count) { |
| | | count = mark; |
| | | } |
| | | } |
| | | |
| | | } |
| | |
| | | * @return plain text escaped for html
|
| | | */
|
| | | public static String escapeForHtml(String inStr, boolean changeSpace) {
|
| | | return escapeForHtml(inStr, changeSpace, 4);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Prepare text for html presentation. Replace sensitive characters with
|
| | | * html entities.
|
| | | *
|
| | | * @param inStr
|
| | | * @param changeSpace
|
| | | * @param tabLength
|
| | | * @return plain text escaped for html
|
| | | */
|
| | | public static String escapeForHtml(String inStr, boolean changeSpace, int tabLength) {
|
| | | StringBuilder retStr = new StringBuilder();
|
| | | int i = 0;
|
| | | while (i < inStr.length()) {
|
| | |
| | | } else if (changeSpace && inStr.charAt(i) == ' ') {
|
| | | retStr.append(" ");
|
| | | } else if (changeSpace && inStr.charAt(i) == '\t') {
|
| | | retStr.append(" ");
|
| | | for (int j = 0; j < tabLength; j++) {
|
| | | retStr.append(" ");
|
| | | }
|
| | | } else {
|
| | | retStr.append(inStr.charAt(i));
|
| | | }
|
| | |
| | | import java.util.zip.ZipOutputStream;
|
| | |
|
| | | import javax.crypto.Cipher;
|
| | | import javax.naming.ldap.LdapName;
|
| | |
|
| | | import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
| | | import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
|
| | |
| | | import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
|
| | | import org.bouncycastle.jce.PrincipalUtil;
|
| | | import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
|
| | | import org.bouncycastle.openssl.PEMEncryptor;
|
| | | import org.bouncycastle.openssl.PEMWriter;
|
| | | import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
|
| | | import org.bouncycastle.openssl.jcajce.JcePEMEncryptorBuilder;
|
| | | import org.bouncycastle.operator.ContentSigner;
|
| | | import org.bouncycastle.operator.OperatorCreationException;
|
| | | import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
| | |
| | | if (pemFile.exists()) {
|
| | | pemFile.delete();
|
| | | }
|
| | | PEMWriter pemWriter = new PEMWriter(new FileWriter(pemFile));
|
| | | pemWriter.writeObject(pair.getPrivate(), "DES-EDE3-CBC", clientMetadata.password.toCharArray(), new SecureRandom());
|
| | | JcePEMEncryptorBuilder builder = new JcePEMEncryptorBuilder("DES-EDE3-CBC");
|
| | | builder.setSecureRandom(new SecureRandom());
|
| | | PEMEncryptor pemEncryptor = builder.build(clientMetadata.password.toCharArray());
|
| | | JcaPEMWriter pemWriter = new JcaPEMWriter(new FileWriter(pemFile));
|
| | | pemWriter.writeObject(pair.getPrivate(), pemEncryptor);
|
| | | pemWriter.writeObject(userCert);
|
| | | pemWriter.writeObject(caCert);
|
| | | pemWriter.flush();
|
| | |
| | | }
|
| | |
|
| | | public static X509Metadata getMetadata(X509Certificate cert) {
|
| | | // manually split DN into OID components
|
| | | // this is instead of parsing with LdapName which:
|
| | | // (1) I don't trust the order of values
|
| | | // (2) it filters out values like EMAILADDRESS
|
| | | String dn = cert.getSubjectDN().getName();
|
| | | Map<String, String> oids = new HashMap<String, String>();
|
| | | for (String kvp : dn.split(",")) {
|
| | | String [] val = kvp.trim().split("=");
|
| | | String oid = val[0].toUpperCase().trim();
|
| | | String data = val[1].trim();
|
| | | oids.put(oid, data);
|
| | | try {
|
| | | String dn = cert.getSubjectDN().getName();
|
| | | LdapName ldapName = new LdapName(dn);
|
| | | for (int i = 0; i < ldapName.size(); i++) {
|
| | | String [] val = ldapName.get(i).trim().split("=", 2);
|
| | | String oid = val[0].toUpperCase().trim();
|
| | | String data = val[1].trim();
|
| | | oids.put(oid, data);
|
| | | }
|
| | | } catch (Exception e) {
|
| | | throw new RuntimeException(e);
|
| | | }
|
| | |
|
| | | X509Metadata metadata = new X509Metadata(oids.get("CN"), "whocares");
|
| | |
| | | public boolean isMultiValued() { |
| | | return false; |
| | | } |
| | | |
| | | @Override |
| | | public boolean help() { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public String[] forbids() { |
| | | return new String [0]; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2015 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.wicket; |
| | | |
| | | import org.apache.wicket.markup.html.basic.Label; |
| | | |
| | | import com.gitblit.models.FilestoreModel; |
| | | import com.gitblit.models.FilestoreModel.Status; |
| | | |
| | | /** |
| | | * Common filestore ui methods and classes. |
| | | * |
| | | * @author Paul Martin |
| | | * |
| | | */ |
| | | public class FilestoreUI { |
| | | |
| | | public static Label getStatusIcon(String wicketId, FilestoreModel item) { |
| | | return getStatusIcon(wicketId, item.getStatus()); |
| | | } |
| | | |
| | | public static Label getStatusIcon(String wicketId, Status status) { |
| | | Label label = new Label(wicketId); |
| | | |
| | | switch (status) { |
| | | case Upload_Pending: |
| | | WicketUtils.setCssClass(label, "fa fa-spinner fa-fw file-negative"); |
| | | break; |
| | | case Upload_In_Progress: |
| | | WicketUtils.setCssClass(label, "fa fa-spinner fa-spin fa-fw file-positive"); |
| | | break; |
| | | case Available: |
| | | WicketUtils.setCssClass(label, "fa fa-check fa-fw file-positive"); |
| | | break; |
| | | case Deleted: |
| | | WicketUtils.setCssClass(label, "fa fa-ban fa-fw file-negative"); |
| | | break; |
| | | case Unavailable: |
| | | WicketUtils.setCssClass(label, "fa fa-times fa-fw file-negative"); |
| | | break; |
| | | default: |
| | | WicketUtils.setCssClass(label, "fa fa-exclamation-triangle fa-fw file-negative"); |
| | | } |
| | | WicketUtils.setHtmlTooltip(label, status.toString()); |
| | | |
| | | return label; |
| | | } |
| | | |
| | | } |
| | |
| | | import com.gitblit.extensions.GitblitWicketPlugin; |
| | | import com.gitblit.manager.IAuthenticationManager; |
| | | import com.gitblit.manager.IFederationManager; |
| | | import com.gitblit.manager.IFilestoreManager; |
| | | import com.gitblit.manager.IGitblit; |
| | | import com.gitblit.manager.INotificationManager; |
| | | import com.gitblit.manager.IPluginManager; |
| | | import com.gitblit.manager.IProjectManager; |
| | | import com.gitblit.manager.IRepositoryManager; |
| | | import com.gitblit.manager.IRuntimeManager; |
| | | import com.gitblit.manager.IServicesManager; |
| | | import com.gitblit.manager.IUserManager; |
| | | import com.gitblit.tickets.ITicketService; |
| | | import com.gitblit.transport.ssh.IPublicKeyManager; |
| | |
| | | import com.gitblit.wicket.pages.ComparePage; |
| | | import com.gitblit.wicket.pages.DocPage; |
| | | import com.gitblit.wicket.pages.DocsPage; |
| | | import com.gitblit.wicket.pages.EditFilePage; |
| | | import com.gitblit.wicket.pages.EditMilestonePage; |
| | | import com.gitblit.wicket.pages.EditRepositoryPage; |
| | | import com.gitblit.wicket.pages.EditTicketPage; |
| | | import com.gitblit.wicket.pages.ExportTicketPage; |
| | | import com.gitblit.wicket.pages.FederationRegistrationPage; |
| | | import com.gitblit.wicket.pages.FilestorePage; |
| | | import com.gitblit.wicket.pages.ForkPage; |
| | | import com.gitblit.wicket.pages.ForksPage; |
| | | import com.gitblit.wicket.pages.GitSearchPage; |
| | |
| | | import com.gitblit.wicket.pages.TreePage; |
| | | import com.gitblit.wicket.pages.UserPage; |
| | | import com.gitblit.wicket.pages.UsersPage; |
| | | import com.google.inject.Inject; |
| | | import com.google.inject.Provider; |
| | | import com.google.inject.Singleton; |
| | | |
| | | @Singleton |
| | | public class GitBlitWebApp extends WebApplication implements GitblitWicketApp { |
| | | |
| | | private final Class<? extends WebPage> homePageClass = MyDashboardPage.class; |
| | |
| | | private final Class<? extends WebPage> newRepositoryPageClass = NewRepositoryPage.class; |
| | | |
| | | private final Map<String, CacheControl> cacheablePages = new HashMap<String, CacheControl>(); |
| | | |
| | | private final Provider<IPublicKeyManager> publicKeyManagerProvider; |
| | | |
| | | private final Provider<ITicketService> ticketServiceProvider; |
| | | |
| | | private final IStoredSettings settings; |
| | | |
| | |
| | | |
| | | private final IAuthenticationManager authenticationManager; |
| | | |
| | | private final IPublicKeyManager publicKeyManager; |
| | | |
| | | private final IRepositoryManager repositoryManager; |
| | | |
| | | private final IProjectManager projectManager; |
| | |
| | | |
| | | private final IGitblit gitblit; |
| | | |
| | | private final IServicesManager services; |
| | | |
| | | private final IFilestoreManager filestoreManager; |
| | | |
| | | @Inject |
| | | public GitBlitWebApp( |
| | | Provider<IPublicKeyManager> publicKeyManagerProvider, |
| | | Provider<ITicketService> ticketServiceProvider, |
| | | IRuntimeManager runtimeManager, |
| | | IPluginManager pluginManager, |
| | | INotificationManager notificationManager, |
| | | IUserManager userManager, |
| | | IAuthenticationManager authenticationManager, |
| | | IPublicKeyManager publicKeyManager, |
| | | IRepositoryManager repositoryManager, |
| | | IProjectManager projectManager, |
| | | IFederationManager federationManager, |
| | | IGitblit gitblit) { |
| | | IGitblit gitblit, |
| | | IServicesManager services, |
| | | IFilestoreManager filestoreManager) { |
| | | |
| | | super(); |
| | | this.publicKeyManagerProvider = publicKeyManagerProvider; |
| | | this.ticketServiceProvider = ticketServiceProvider; |
| | | this.settings = runtimeManager.getSettings(); |
| | | this.xssFilter = runtimeManager.getXssFilter(); |
| | | this.runtimeManager = runtimeManager; |
| | |
| | | this.notificationManager = notificationManager; |
| | | this.userManager = userManager; |
| | | this.authenticationManager = authenticationManager; |
| | | this.publicKeyManager = publicKeyManager; |
| | | this.repositoryManager = repositoryManager; |
| | | this.projectManager = projectManager; |
| | | this.federationManager = federationManager; |
| | | this.gitblit = gitblit; |
| | | this.services = services; |
| | | this.filestoreManager = filestoreManager; |
| | | } |
| | | |
| | | @Override |
| | |
| | | // setup the markup document urls |
| | | mount("/docs", DocsPage.class, "r", "h"); |
| | | mount("/doc", DocPage.class, "r", "h", "f"); |
| | | mount("/editfile", EditFilePage.class, "r", "h", "f"); |
| | | |
| | | // federation urls |
| | | mount("/proposal", ReviewProposalPage.class, "t"); |
| | |
| | | mount("/user", UserPage.class, "user"); |
| | | mount("/forks", ForksPage.class, "r"); |
| | | mount("/fork", ForkPage.class, "r"); |
| | | |
| | | // filestore URL |
| | | mount("/filestore", FilestorePage.class); |
| | | |
| | | // allow started Wicket plugins to initialize |
| | | for (PluginWrapper pluginWrapper : pluginManager.getPlugins()) { |
| | |
| | | */ |
| | | @Override |
| | | public IPublicKeyManager keys() { |
| | | return publicKeyManager; |
| | | return publicKeyManagerProvider.get(); |
| | | } |
| | | |
| | | /* (non-Javadoc) |
| | |
| | | } |
| | | |
| | | /* (non-Javadoc) |
| | | * @see com.gitblit.wicket.Webapp#services() |
| | | */ |
| | | @Override |
| | | public IServicesManager services() { |
| | | return services; |
| | | } |
| | | |
| | | /* (non-Javadoc) |
| | | * @see com.gitblit.wicket.Webapp#tickets() |
| | | */ |
| | | @Override |
| | | public ITicketService tickets() { |
| | | return gitblit.getTicketService(); |
| | | return ticketServiceProvider.get(); |
| | | } |
| | | |
| | | /* (non-Javadoc) |
| | |
| | | public static GitBlitWebApp get() { |
| | | return (GitBlitWebApp) WebApplication.get(); |
| | | } |
| | | |
| | | @Override |
| | | public IFilestoreManager filestore() { |
| | | return filestoreManager; |
| | | } |
| | | } |
| | |
| | | gb.enhancementTickets = enhancements |
| | | gb.taskTickets = tasks |
| | | gb.questionTickets = questions |
| | | gb.maintenanceTickets = maintenance |
| | | gb.requestTickets = enhancements & tasks |
| | | gb.yourCreatedTickets = created by you |
| | | gb.yourWatchedTickets = watched by you |
| | |
| | | gb.permission = Permission |
| | | gb.sshKeyPermissionDescription = Specify the access permission for the SSH key |
| | | gb.transportPreference = Transport Preference |
| | | gb.transportPreferenceDescription = Set the transport that you prefer to use for cloning |
| | | gb.transportPreferenceDescription = Set the transport that you prefer to use for cloning |
| | | gb.priority = priority |
| | | gb.severity = severity |
| | | gb.sortHighestPriority = highest priority |
| | | gb.sortLowestPriority = lowest priority |
| | | gb.sortHighestSeverity = highest severity |
| | | gb.sortLowestSeverity = lowest severity |
| | | gb.missingIntegrationBranchMore = The target integration branch does not exist in the repository! |
| | | gb.diffDeletedFileSkipped = (deleted) |
| | | gb.diffFileDiffTooLarge = Diff too large |
| | | gb.diffNewFile = New file |
| | | gb.diffDeletedFile = File was deleted |
| | | gb.diffRenamedFile = File was renamed from {0} |
| | | gb.diffCopiedFile = File was copied from {0} |
| | | gb.diffTruncated = Diff truncated after the above file |
| | | gb.opacityAdjust = Adjust opacity |
| | | gb.blinkComparator = Blink comparator |
| | | gb.imgdiffSubtract = Subtract (black = identical) |
| | | gb.deleteRepositoryHeader = Delete Repository |
| | | gb.deleteRepositoryDescription = Deleted repositories will be unrecoverable. |
| | | gb.show_whitespace = show whitespace |
| | | gb.ignore_whitespace = ignore whitespace |
| | | gb.allRepositories = All Repositories |
| | | gb.oid = object id |
| | | gb.filestore = filestore |
| | | gb.filestoreStats = Filestore contains {0} files with a total size of {1}. ({2} remaining) |
| | | gb.statusChangedOn = status changed on |
| | | gb.statusChangedBy = status changed by |
| | | gb.filestoreHelp = How to use the Filestore? |
| | | gb.editFile = edit file |
| | | gb.continueEditing = Continue Editing |
| | | gb.commitChanges = Commit Changes |
| | | gb.fileNotMergeable = Unable to commit {0}. This file can not be automatically merged. |
| | | gb.fileCommitted = Successfully committed {0}. |
| | | gb.deletePatchset = Delete Patchset {0} |
| | | gb.deletePatchsetSuccess = Deleted Patchset {0}. |
| | | gb.deletePatchsetFailure = Error deleting Patchset {0}. |
| | |
| | | gb.sshKeyPermissionDescription = Geben Sie die Zugriffberechtigung f\u00fcr den SSH Key an |
| | | gb.transportPreference = \u00dcbertragungseinstellungen |
| | | gb.transportPreferenceDescription = Geben Sie die \u00dcbertragungsart an, die Sie f\u00fcr das Klonen bevorzugen |
| | | gb.diffDeletedFileSkipped = (gel\u00f6scht) |
| | | gb.diffFileDiffTooLarge = Zu viele \u00c4nderungen; Diff wird nicht angezeigt |
| | | gb.diffNewFile = Neue Datei |
| | | gb.diffDeletedFile = Datei wurde gel\u00f6scht |
| | | gb.diffRenamedFile = Datei umbenannt von {0} |
| | | gb.diffCopiedFile = Datei kopiert von {0} |
| | | gb.diffTruncated = Diff nach obiger Datei abgeschnitten |
| | | gb.opacityAdjust = Transparenz |
| | | gb.blinkComparator = Blinkkomparator |
| | | gb.imgdiffSubtract = Pixeldifferenz (schwarz = identisch) |
| | |
| | | gb.mergeToDescription = branche d'int\u00e9gration par d\u00e9faut pour fusionner les correctifs li\u00e9s aux tickets |
| | | gb.myTickets = mes tickets |
| | | gb.yourAssignedTickets = dont vous \u00eates responsable |
| | | gb.diffDeletedFileSkipped = (effac\u00e9) |
| | | gb.diffFileDiffTooLarge = Trop de diff\u00e9rences, affichage supprim\u00e9e |
| | | gb.diffNewFile = Nouveau fichier |
| | | gb.diffDeletedFile = Fichier a \u00e9t\u00e9 effac\u00e9 |
| | | gb.diffRenamedFile = Fichier renomm\u00e9 de {0} |
| | | gb.diffCopiedFile = Fichier copi\u00e9 de {0} |
| | | gb.diffTruncated = Affichage de diff\u00e9rences supprim\u00e9e apr\u00e8s le fichier ci-dessus |
| | | gb.opacityAdjust = ajuster l'opacit\u00e9 |
| | | gb.blinkComparator = Comparateur \u00e0 clignotement |
| | | gb.imgdiffSubtract = Diff\u00e9rence (noir = identique) |
New file |
| | |
| | | #! |
| | | #! created/edited by Popeye version 0.54 (popeye.sourceforge.net) |
| | | #! encoding:ISO-8859-1 |
| | | gb.about = \u95dc\u65bc |
| | | gb.acceptNewPatchsets = \u5141\u8a31\u88dc\u4e01 |
| | | gb.acceptNewPatchsetsDescription = \u63a5\u53d7\u5230\u7248\u672c\u5009\u9032\u884c\u4fee\u88dc\u52d5\u4f5c |
| | | gb.acceptNewTickets = \u5141\u8a31\u5efa\u7acb\u4efb\u52d9\u55ae |
| | | gb.acceptNewTicketsDescription = \u5141\u8a31\u65b0\u589e"\u81ed\u87f2","\u512a\u5316","\u4efb\u52d9"\u5404\u985e\u578b\u4efb\u52d9\u55ae |
| | | gb.accessDenied = \u62d2\u7d55\u5b58\u53d6 |
| | | gb.accessLevel = \u5b58\u53d6\u7b49\u7d1a |
| | | gb.accessPermissions = \u5b58\u53d6\u6b0a\u9650 |
| | | gb.accessPermissionsDescription = restrict access by users and teams |
| | | gb.accessPermissionsForTeamDescription = set team members and grant access to specific restricted repositories |
| | | gb.accessPermissionsForUserDescription = set team memberships or grant access to specific restricted repositories |
| | | gb.accessPolicy = \u5b58\u53d6\u653f\u7b56 |
| | | gb.accessPolicyDescription = \u9078\u64c7\u7528\u4f86\u63a7\u5236\u6587\u4ef6\u5eab\u7684\u5b58\u53d6\u653f\u7b56\u4ee5\u53ca\u6b0a\u9650\u8a2d\u5b9a |
| | | gb.accessRestriction = \u9650\u5236\u5b58\u53d6 |
| | | gb.accountPreferences = \u5e33\u865f\u8a2d\u5b9a |
| | | gb.accountPreferencesDescription = \u8a2d\u5b9a\u5e33\u865f\u9810\u8a2d\u503c |
| | | gb.action = \u52d5\u4f5c |
| | | gb.active = \u6d3b\u52d5 |
| | | gb.activeAuthors = \u6d3b\u8e8d\u7528\u6236 |
| | | gb.activeRepositories = \u6d3b\u8e8d\u7248\u672c\u5eab |
| | | gb.activity = \u6d3b\u52d5 |
| | | gb.add = \u65b0\u589e |
| | | gb.addComment = \u65b0\u589e\u8a3b\u89e3 |
| | | gb.addedNCommits = {0}\u500b\u6a94\u6848\u63d0\u4ea4\u5b8c\u7562 |
| | | gb.addedOneCommit = \u63d0\u4ea41\u500b\u6a94\u6848 |
| | | gb.addition = addition |
| | | gb.addSshKey = \u65b0\u589e SSH Key |
| | | gb.administration = \u7ba1\u7406\u6b0a\u9650 |
| | | gb.administrator = \u7ba1\u7406\u54e1 |
| | | gb.administratorPermission = Gitblit \u7ba1\u7406\u54e1 |
| | | gb.affiliationChanged = affiliation changed |
| | | gb.age = \u6642\u9593 |
| | | gb.all = \u5168\u90e8 |
| | | gb.allBranches = \u6240\u6709\u5206\u652f |
| | | gb.allowAuthenticatedDescription = \u6279\u51c6 RW+ \u6b0a\u9650\u7d66\u4e88\u5c08\u6848\u6210\u54e1 |
| | | gb.allowForks = \u5141\u8a31\u5efa\u7acb\u5206\u652f(forks) |
| | | gb.allowForksDescription = \u5141\u8a31\u5df2\u6388\u6b0a\u7684\u4f7f\u7528\u8005\u5f9e\u6587\u4ef6\u5eab\u5efa\u7acb\u5206\u652f(fork) |
| | | gb.allowNamedDescription = grant fine-grained permissions to named users or teams |
| | | gb.allProjects = \u5168\u90e8\u7fa4\u7d44 |
| | | gb.allTags = \u6240\u6709\u6a19\u7c64 |
| | | gb.anonymousCanNotPropose = \u533f\u540d\u8005\u4e0d\u80fd\u63d0\u4f9b\u88dc\u4e01 |
| | | gb.anonymousPolicy = \u533f\u540d\u72c0\u614b\u53ef\u4ee5View, Clone\u8207Push |
| | | gb.anonymousPolicyDescription = \u4efb\u4f55\u4eba\u53ef\u6aa2\u8996,\u8907\u88fd(clone)\u8207\u63a8\u9001(push)\u6587\u4ef6\u5230\u6587\u4ef6\u5eab |
| | | gb.anonymousUser= \u533f\u540d\u72c0\u614b |
| | | gb.any = \u4efb\u4f55 |
| | | gb.approve = \u901a\u904e |
| | | gb.at = at |
| | | gb.attributes = \u5c6c\u6027 |
| | | gb.authenticatedPushPolicy = Restrict Push (Authenticated) |
| | | gb.authenticatedPushPolicyDescription = \u4efb\u4f55\u4eba\u53ef\u4ee5\u6aa2\u8996\u8207\u8907\u88fd(clone).\u6240\u6709\u6587\u4ef6\u5eab\u6210\u54e1\u7686\u6709RW+\u8207\u63a8\u9001(push)\u529f\u80fd. |
| | | gb.author = \u4f5c\u8005 |
| | | gb.authored = \u5df2\u6388\u6b0a |
| | | gb.authorizationControl = \u6388\u6b0a\u7ba1\u63a7 |
| | | gb.available = \u53ef\u7528 |
| | | gb.blame = \u7a76\u67e5 |
| | | gb.blinkComparator = Blink comparator |
| | | gb.blob = \u5340\u584a |
| | | gb.body = body |
| | | gb.bootDate = \u555f\u52d5\u65e5 |
| | | gb.branch = \u5206\u652f |
| | | gb.branches = \u5206\u652f |
| | | gb.branchStats = \u9019\u500b\u5206\u652f{2}\u6709{0}\u500b\u63d0\u4ea4\u4ee5\u53ca{1}\u500b\u6a19\u7c64 |
| | | gb.browse = \u700f\u89bd |
| | | gb.bugTickets = \u81ed\u87f2 |
| | | gb.busyCollectingGarbage = \u62b1\u6b49,Gitblit\u6b63\u5728\u56de\u6536\u7cfb\u7d71\u8cc7\u6e90\u4e2d:{0} |
| | | gb.byNAuthors = \u7d93\u7531{0}\u500b\u4f5c\u8005 |
| | | gb.byOneAuthor = \u7d93\u7531{0} |
| | | gb.caCompromise = CA compromise |
| | | gb.canAdmin = \u53ef\u7ba1\u7406 |
| | | gb.canAdminDescription = \u53ef\u7ba1\u7406Gitblit\u4f3a\u670d\u5668 |
| | | gb.cancel = \u53d6\u6d88 |
| | | gb.canCreate = \u53ef\u5efa\u7acb |
| | | gb.canCreateDescription = \u80fd\u5920\u5efa\u7acb\u79c1\u4eba\u6587\u4ef6\u5eab |
| | | gb.canFork = \u53ef\u5efa\u7acb\u5206\u652f(fork) |
| | | gb.canForkDescription = \u53ef\u4ee5\u5efa\u7acb\u6587\u4ef6\u5eab\u5206\u652f(fork),\u4e26\u4e14\u8907\u88fd\u5230\u79c1\u4eba\u6587\u4ef6\u5eab\u4e2d |
| | | gb.canNotLoadRepository = \u7121\u6cd5\u8f09\u5165\u7248\u672c\u5eab |
| | | gb.canNotProposePatchset = \u4e0d\u80fd\u63d0\u4f9b\u88dc\u4e01 |
| | | gb.certificate = \u8b49\u66f8 |
| | | gb.certificateRevoked = \u8b49\u66f8{0,number,0} \u5df2\u7d93\u88ab\u53d6\u6d88 |
| | | gb.certificates = \u8b49\u66f8 |
| | | gb.cessationOfOperation = cessation of operation |
| | | gb.changedFiles = \u5df2\u8b8a\u66f4\u904e\u7684\u6a94\u6848 |
| | | gb.changedStatus = changed the status |
| | | gb.changePassword = \u4fee\u6539\u5bc6\u78bc |
| | | gb.checkout = \u6aa2\u51fa(checkout) |
| | | gb.checkoutStep1 = Fetch the current patchset \u2014 run this from your project directory |
| | | gb.checkoutStep2 = \u5c07\u8a72\u88dc\u4e01\u8f49\u51fa\u5230\u65b0\u7684\u5206\u652f\u7136\u5f8c\u7528\u4f86\u6aa2\u8996 |
| | | gb.checkoutViaCommandLine = \u4f7f\u7528\u6307\u4ee4Checkout |
| | | gb.checkoutViaCommandLineNote = \u4f60\u53ef\u4ee5\u5f9e\u4f60\u6587\u4ef6\u5eab\u4e2dcheckout\u4e00\u4efd,\u7136\u5f8c\u9032\u884c\u6e2c\u8a66 |
| | | gb.clearCache = \u6e05\u9664\u5feb\u53d6 |
| | | gb.clientCertificateBundleSent = {0}\u7684\u7528\u6236\u8b49\u66f8\u5df2\u5bc4\u767c |
| | | gb.clientCertificateGenerated = \u6210\u529f\u7522\u751f{0}\u7684\u65b0\u8b49\u66f8 |
| | | gb.clone = \u8907\u88fd(clone) |
| | | gb.clonePermission = {0} \u8907\u88fd(clone) |
| | | gb.clonePolicy = Restrict Clone & Push |
| | | gb.clonePolicyDescription = \u4efb\u4f55\u4eba\u53ef\u4ee5\u770b\u6587\u4ef6\u5eab. \u4f46\u4f60\u80fd\u5920\u8907\u88fd(clone)\u8207\u63a8\u9001(push) |
| | | gb.cloneRestricted = authenticated clone & push |
| | | gb.closeBrowser = \u8acb\u95dc\u9589\u700f\u89bd\u5668\u7d50\u675f\u6b64\u767b\u5165\u968e\u6bb5 |
| | | gb.closed = \u95dc\u9589 |
| | | gb.closedMilestones = \u5df2\u95dc\u9589\u7684\u91cc\u7a0b\u7891(milestones) |
| | | gb.combinedMd5Rename = Gitblit\u4f7f\u7528md5\u65b9\u5f0f\u5c07\u5bc6\u78bc\u7de8\u78bc(\u7121\u6cd5\u9084\u539f).\u4f60\u5fc5\u9808\u8f38\u5165\u65b0\u5bc6\u78bc. |
| | | gb.comment = \u8a3b\u89e3 |
| | | gb.commented = \u5df2\u8a3b\u89e3 |
| | | gb.comments = \u8a3b\u89e3 |
| | | gb.commit = \u63d0\u4ea4 |
| | | gb.commitActivityAuthors = \u63d0\u4ea4\u6d3b\u8e8d\u7387(\u4f7f\u7528\u8005) |
| | | gb.commitActivityDOW = \u6bcf(\u65e5)\u9031\u63d0\u4ea4 |
| | | gb.commitActivityTrend = \u63d0\u4ea4\u8da8\u52e2\u5716 |
| | | gb.commitdiff = \u63d0\u4ea4\u5dee\u7570 |
| | | gb.commitIsNull = \u63d0\u4ea4\u5167\u5bb9\u662f\u7a7a\u7684 |
| | | gb.commitMessageRenderer = \u63d0\u4ea4\u8a0a\u606f\u5448\u73fe\u65b9\u5f0f |
| | | gb.commitMessageRendererDescription = \u63d0\u4ea4\u8a0a\u606f\u53ef\u4ee5\u4f7f\u7528\u6587\u5b57\u6216\u662f\u6a19\u8a18\u8a9e\u8a00(markup)\u5448\u73fe |
| | | gb.commits = \u63d0\u4ea4 |
| | | gb.commitsInPatchsetN = \u88dc\u4e01 {0} \u7684\u63d0\u4ea4 |
| | | gb.commitsTo = {0} commits to |
| | | gb.committed = \u5df2\u63d0\u4ea4 |
| | | gb.committer = \u78ba\u8a8d\u63d0\u4ea4\u8005 |
| | | gb.compare = \u6bd4\u5c0d |
| | | gb.compareToMergeBase = \u6bd4\u5c0d\u5f8c,\u5408\u4f75\u5230\u4e3b\u8981\u5de5\u4f5c\u5340 |
| | | gb.compareToN = \u8207{0}\u9032\u884c\u6bd4\u5c0d |
| | | gb.completeGravatarProfile = \u5b8c\u6210Gravator.com\u4e0a\u7684\u57fa\u672c\u8cc7\u6599\u8a2d\u5b9a |
| | | gb.confirmPassword = \u78ba\u8a8d\u5bc6\u78bc |
| | | gb.content = \u5167\u5bb9 |
| | | gb.copyToClipboard = \u8907\u88fd\u5230\u526a\u8cbc\u677f |
| | | gb.couldNotCreateFederationProposal = \u7121\u6cd5\u5efa\u7acb\u4e32\u9023\u7684\u5408\u4f5c\u63d0\u6848 |
| | | gb.couldNotFindFederationProposal = \u641c\u5c0b\u4e0d\u5230\u8981\u6c42\u4e32\u9023\u7684\u63d0\u6848 |
| | | gb.couldNotFindFederationRegistration = \u627e\u4e0d\u5230\u4e32\u9023\u8a3b\u518a\u55ae |
| | | gb.couldNotFindTag = \u627e\u4e0d\u5230\u6a19\u7c64{0} |
| | | gb.countryCode = \u570b\u5bb6\u4ee3\u78bc |
| | | gb.create = \u5efa\u7acb |
| | | gb.createdBy = created by |
| | | gb.createdNewBranch = \u5efa\u7acb\u65b0\u5206\u652f |
| | | gb.createdNewPullRequest = created pull request |
| | | gb.createdNewTag = \u5efa\u7acb\u65b0\u6a19\u7c64 |
| | | gb.createdThisTicket = \u5df2\u958b\u7acb\u7684\u4efb\u52d9\u55ae |
| | | gb.createFirstTicket = \u6309\u6b64\u9996\u767c\u4efb\u52d9\u55ae |
| | | gb.createPermission = {0} (push, ref creation) |
| | | gb.createReadme = \u5efa\u7acbREADME\u6a94\u6848 |
| | | gb.customFields = custom fields |
| | | gb.customFieldsDescription = custom fields available to Groovy hooks |
| | | gb.dailyActivity = \u6bcf\u65e5\u6d3b\u52d5 |
| | | gb.dashboard = \u5100\u8868\u677f |
| | | gb.date = \u65e5\u671f |
| | | gb.default = \u9810\u8a2d |
| | | gb.delete = \u522a\u9664 |
| | | gb.deletedBranch = deleted branch |
| | | gb.deletedTag = \u522a\u9664\u6a19\u7c64 |
| | | gb.deleteMilestone = \u522a\u9664\u91cc\u7a0b\u7891"{0}"? |
| | | gb.deletePermission = {0} (push, ref creation+deletion) |
| | | gb.deleteRepository = \u522a\u9664\u7248\u672c\u5eab"{0}"? |
| | | gb.deleteRepositoryDescription = \u7248\u672c\u5eab\u522a\u9664\u5c07\u7121\u6cd5\u9084\u539f |
| | | gb.deleteRepositoryHeader = \u522a\u9664\u7248\u672c\u5eab |
| | | gb.deleteUser = \u522a\u9664\u4f7f\u7528\u8005"{0}"? |
| | | gb.deletion = \u522a\u9664 |
| | | gb.description = \u6982\u8ff0 |
| | | gb.destinationUrl = \u50b3\u9001 |
| | | gb.destinationUrlDescription = \u50b3\u9001Gitblit\u9023\u7d50\u5230\u4f60\u7684\u5c08\u6848(proposal) |
| | | gb.diff = \u5dee\u7570 |
| | | gb.diffCopiedFile = File was copied from {0} |
| | | gb.diffDeletedFile = \u6a94\u6848\u5df2\u522a\u9664 |
| | | gb.diffDeletedFileSkipped = (\u522a\u9664) |
| | | gb.diffFileDiffTooLarge = \u6a94\u6848\u592a\u5927 |
| | | gb.diffNewFile = \u6bd4\u5c0d\u65b0\u6a94\u6848 |
| | | gb.diffRenamedFile = File was renamed from {0} |
| | | gb.diffStat = \u65b0\u589e{0}\u5217\u8207\u522a\u9664{1}\u5217 |
| | | gb.difftocurrent = \u6bd4\u5c0d\u5dee\u7570 |
| | | gb.diffTruncated = Diff truncated after the above file |
| | | gb.disableUser = \u505c\u7528\u5e33\u6236 |
| | | gb.disableUserDescription = \u8a72\u5e33\u6236\u7121\u6cd5\u4f7f\u7528 |
| | | gb.discussion = \u8a0e\u8ad6 |
| | | gb.displayName = \u986f\u793a\u7684\u540d\u7a31 |
| | | gb.displayNameDescription = \u5e0c\u671b\u986f\u793a\u7684\u540d\u7a31 |
| | | gb.docs = \u6a94\u6848\u5340 |
| | | gb.docsWelcome1 = \u4f60\u53ef\u4ee5\u4f7f\u7528\u6a94\u6848\u5340\u5efa\u7acb\u6587\u4ef6\u5eab\u7684\u6559\u5b78\u6a94\u6848 |
| | | gb.docsWelcome2 = \u63d0\u4ea4README.md \u6216 HOME.md\u5f8c,\u518d\u958b\u59cb\u65b0\u7684\u6587\u4ef6\u5eab |
| | | gb.doesNotExistInTree = {0}\u4e26\u6c92\u6709\u5728\u76ee\u9304{1}\u88e1\u9762 |
| | | gb.download = \u4e0b\u8f09 |
| | | gb.downloading = \u4e0b\u8f09ing |
| | | gb.due = due |
| | | gb.duration = \u9031\u671f |
| | | gb.duration.days = {0}\u5929 |
| | | gb.duration.months = {0}\u6708 |
| | | gb.duration.oneDay = 1\u5929 |
| | | gb.duration.oneMonth = 1\u6708 |
| | | gb.duration.oneYear = 1\u5e74 |
| | | gb.duration.years = {0}\u5e74 |
| | | gb.edit = \u7de8\u8f2f |
| | | gb.editMilestone = \u4fee\u6539milestone |
| | | gb.editTicket = \u4fee\u6539\u4efb\u52d9\u55ae |
| | | gb.editUsers = \u4fee\u6539\u5e33\u865f |
| | | gb.effective = \u6240\u6709\u6b0a\u9650 |
| | | gb.emailAddress = \u96fb\u5b50\u90f5\u4ef6 |
| | | gb.emailAddressDescription = \u7528\u4f86\u63a5\u6536\u901a\u77e5\u7684\u4e3b\u8981\u96fb\u5b50\u90f5\u4ef6 |
| | | gb.emailCertificateBundle = \u5bc4\u767c\u7528\u6236\u7aef\u8b49\u66f8 |
| | | gb.emailMeOnMyTicketChanges = \u6211\u7684\u4efb\u52d9\u55ae\u82e5\u6709\u8b8a\u66f4,\u8acb800\u91cc\u52a0\u6025(email)\u901a\u77e5\u6211 |
| | | gb.emailMeOnMyTicketChangesDescription = \u6211\u8655\u7406\u904e\u7684\u4efb\u52d9\u55ae\u8acbemail\u901a\u77e5\u6211 |
| | | gb.empty = \u7a7a\u7684 |
| | | gb.emptyRepository = \u7a7a\u7684\u7248\u672c\u5eab |
| | | gb.enableDocs = \u555f\u7528\u6a94\u6848\u5340 |
| | | gb.enableIncrementalPushTags = \u555f\u7528\u81ea\u52d5\u65b0\u589e\u6a19\u7c64\u529f\u80fd |
| | | gb.enableTickets = \u555f\u7528\u4efb\u52d9\u55ae\u7cfb\u7d71 |
| | | gb.enhancementTickets = \u512a\u5316 |
| | | gb.enterKeystorePassword = \u8acb\u8f38\u5165Gitblit\u7684keystore\u5c08\u7528\u5bc6\u78bc |
| | | gb.error = \u932f\u8aa4 |
| | | gb.errorAdministrationDisabled = \u7ba1\u7406\u6b0a\u9650\u5df2\u53d6\u6d88 |
| | | gb.errorAdminLoginRequired = \u767b\u5165\u9700\u6709\u7ba1\u7406\u6b0a\u9650 |
| | | gb.errorOnlyAdminMayCreateRepository = \u53ea\u6709\u7ba1\u7406\u8005\u80fd\u5efa\u7acb\u7248\u672c\u5eab |
| | | gb.errorOnlyAdminOrOwnerMayEditRepository = \u53ea\u6709\u7ba1\u7406\u8005\u8207\u7248\u672c\u5eab\u64c1\u6709\u8005\u80fd\u4fee\u6539\u7248\u672c\u5eab\u5c6c\u6027 |
| | | gb.excludeFromActivity = exclude from activity page |
| | | gb.excludeFromFederation = \u6392\u9664\u4e32\u9023 |
| | | gb.excludeFromFederationDescription = \u963b\u64cb\u5df2\u4e32\u9023\u7684Gitblit\u4f3a\u670d\u5668 |
| | | gb.excludePermission = {0} (\u6392\u9664) |
| | | gb.exclusions = \u6392\u9664 |
| | | gb.expired = \u904e\u671f |
| | | gb.expires = \u5230\u671f |
| | | gb.expiring = \u5c07\u8981\u904e\u671f |
| | | gb.export = \u532f\u51fa |
| | | gb.extensions = \u64f4\u5145 |
| | | gb.externalPermissions = {0} access permissions are externally maintained |
| | | gb.failedToFindAccount = \u7121\u6cd5\u641c\u5c0b\u5230\u5e33\u865f"{0}" |
| | | gb.failedToFindCommit = Failed to find commit "{0}" in {1}\! |
| | | gb.failedToFindGravatarProfile = \u7121\u6cd5\u627e\u5230\u5e33\u865f{0}\u7684Gravator\u8cc7\u6599 |
| | | gb.failedtoRead = \u8b80\u53d6\u5931\u6557 |
| | | gb.failedToReadMessage = Failed to read default message from {0}\! |
| | | gb.failedToSendProposal = \u63d0\u6848\u767c\u9001\u5931\u6557\! |
| | | gb.failedToUpdateUser = \u7121\u6cd5\u66f4\u65b0\u4f7f\u7528\u8005\u5e33\u865f |
| | | gb.federatedRepositoryDefinitions = \u7248\u672c\u5eab\u5b9a\u7fa9 |
| | | gb.federatedSettingDefinitions = setting definitions |
| | | gb.federatedUserDefinitions = user definitions |
| | | gb.federateOrigin = federate the origin |
| | | gb.federateThis = \u8207\u672c\u6587\u4ef6\u5eab\u4e32\u9023 |
| | | gb.federation = \u4e32\u9023 |
| | | gb.federationRegistration = federation registration |
| | | gb.federationRepositoryDescription = \u8207\u5176\u4ed6gitblit\u4f3a\u670d\u5668\u5206\u4eab\u4e00\u8d77\u4f7f\u7528\u9019\u500b\u7248\u672c\u5eab |
| | | gb.federationResults = federation pull results |
| | | gb.federationSets = \u4e32\u9023\u7d44\u5408 |
| | | gb.federationSetsDescription = \u6b64\u6587\u4ef6\u5eab\u5c07\u5305\u542b\u65bc\u6307\u5b9a\u7684\u4e32\u9023\u7fa4\u7d44(federation sets) |
| | | gb.federationStrategy = \u4e32\u9023\u7b56\u7565 |
| | | gb.federationStrategyDescription = \u63a7\u5236\u5982\u4f55\u5c07\u6587\u4ef6\u5eab\u8207\u5176\u4ed6Gitblit\u7248\u63a7\u4f3a\u670d\u5668\u4e32\u9023 |
| | | gb.feed = \u8cc7\u6599\u8a02\u95b1 |
| | | gb.filesAdded = \u65b0\u589e{0}\u500b\u6a94\u6848 |
| | | gb.filesCopied = \u8907\u88fd{0}\u500b\u6a94\u6848 |
| | | gb.filesDeleted = \u522a\u9664{0}\u500b\u6a94\u6848 |
| | | gb.filesModified = \u4fee\u6539{0}\u500b\u6a94\u6848 |
| | | gb.filesRenamed = \u4fee\u6539{0}\u500b\u6a94\u6848\u540d\u7a31 |
| | | gb.filter = \u689d\u4ef6\u904e\u6ffe |
| | | gb.filters = \u67e5\u8a62\u689d\u4ef6 |
| | | gb.findSomeRepositories = \u641c\u5c0b\u6587\u4ef6\u5eab |
| | | gb.folder = \u76ee\u9304 |
| | | gb.fork = \u5efa\u7acb\u5206\u652f(fork) |
| | | gb.forkedFrom = forked from |
| | | gb.forkInProgress = fork in progress |
| | | gb.forkNotAuthorized = \u5f88\u62b1\u6b49, \u4f60\u7121\u5efa\u7acb\u6587\u4ef6\u5eab{0}\u5206\u652f(fork)\u7684\u6b0a\u9650 |
| | | gb.forkRepository = \u7248\u672c\u5eab{0}\u5efa\u7acb\u5206\u652f(fork)? |
| | | gb.forks = \u5206\u652f(forks) |
| | | gb.forksProhibited = \u7981\u6b62\u5efa\u7acb\u5206\u652f(forks) |
| | | gb.forksProhibitedWarning = \u672c\u6587\u4ef6\u5eab\u7981\u6b62\u5206\u652f(fork) |
| | | gb.free = \u91cb\u653e |
| | | gb.frequency = \u983b\u7387 |
| | | gb.from = from |
| | | gb.garbageCollection = \u56de\u6536\u7cfb\u7d71\u8cc7\u6e90 |
| | | gb.garbageCollectionDescription = \u7cfb\u7d71\u8cc7\u6e90\u56de\u6536\u529f\u80fd\u5c07\u6703\u6574\u9813\u9b06\u6563\u7528\u6236\u7aef\u63a8\u9001(push)\u7684\u7269\u4ef6, \u4e5f\u6703\u79fb\u9664\u6587\u4ef6\u5eab\u4e0a\u7121\u7528\u7684\u7269\u4ef6 |
| | | gb.gc = \u7cfb\u7d71\u8cc7\u6e90\u56de\u6536\u5668 |
| | | gb.gcPeriod = \u7cfb\u7d71\u8cc7\u6e90\u56de\u6536\u968e\u6bb5 |
| | | gb.gcPeriodDescription = \u56de\u6536\u9031\u671f |
| | | gb.gcThreshold = GC \u57fa\u6578(threshold) |
| | | gb.gcThresholdDescription = \u89f8\u767c\u7cfb\u7d71\u8cc7\u6e90\u56de\u6536\u7684\u6700\u5c0f\u7269\u4ef6\u5bb9\u91cf |
| | | gb.general = \u4e00\u822c |
| | | gb.generalDescription = \u4e00\u822c\u8a2d\u5b9a |
| | | gb.hasNotReviewed = \u5c1a\u672a\u6aa2\u6838\u904e |
| | | gb.head = HEAD |
| | | gb.headRef = \u9810\u8a2d\u5206\u652f(HEAD) |
| | | gb.headRefDescription = \u9810\u8a2d\u5206\u652f\u5c07\u6703\u8907\u88fd\u4ee5\u53ca\u986f\u793a\u5230\u532f\u7e3d\u9801\u9762 |
| | | gb.heapAllocated = \u5df2\u4f7f\u7528\u5806\u7a4d(Heap) |
| | | gb.heapMaximum = \u6700\u5927\u5806\u7a4d(heap) |
| | | gb.heapUsed = \u5df2\u4f7f\u7528\u7684\u5806\u7a4d(heap) |
| | | gb.history = \u6b77\u7a0b |
| | | gb.home = \u9996\u9801 |
| | | gb.hookScripts = hook\u7684\u8173\u672c |
| | | gb.hookScriptsDescription = \u7576\u63a8\u9001(push)\u81f3\u6b64Gitblit\u7248\u63a7\u4f3a\u670d\u5668\u6642, \u57f7\u884cGroovy\u8173\u672c |
| | | gb.hostname = \u4e3b\u6a5f\u540d\u7a31 |
| | | gb.hostnameRequired = \u8acb\u8f38\u5165\u4e3b\u6a5f\u540d\u7a31 |
| | | gb.ignore_whitespace =\u5ffd\u7565\u7a7a\u767d |
| | | gb.illegalCharacterRepositoryName = \u7248\u672c\u5eab\u540d\u7a31\u6709\u4e0d\u5408\u6cd5\u7684\u5b57\u5143"{0}" |
| | | gb.illegalLeadingSlash = \u7981\u6b62\u6839\u76ee\u9304(/) |
| | | gb.illegalPersonalRepositoryLocation = \u4f60\u79c1\u4eba\u7248\u672c\u5eab\u5fc5\u9808\u653e\u5728"{0}" |
| | | gb.illegalRelativeSlash = \u7981\u6b62\u76f8\u5c0d\u76ee\u9304(../) |
| | | gb.imgdiffSubtract = Subtract (black = identical) |
| | | gb.in = in |
| | | gb.inclusions = inclusions |
| | | gb.incrementalPushTagMessage = \u7576[{0}]\u5206\u652f\u63a8\u9001\u5f8c,\u81ea\u52d5\u7d66\u4e88\u6a19\u7c64\u865f. |
| | | gb.indexedBranches = \u5206\u652f\u7d22\u5f15 |
| | | gb.indexedBranchesDescription = \u9078\u5b9a\u6b32\u57f7\u884cLucene\u7d22\u5f15\u529f\u80fd\u7684\u5206\u652f |
| | | gb.inherited = \u7e7c\u627f |
| | | gb.initialCommit = \u521d\u6b21\u63d0\u4ea4 |
| | | gb.initialCommitDescription = \u4ee5\u4e0b\u6b65\u9a5f\u5c07\u6703\u8b93\u4f60\u99ac\u4e0a\u57f7\u884c<code>git clone</code>.\u5982\u679c\u4f60\u672c\u6a5f\u5df2\u6709\u6b64\u6587\u4ef6\u5eab\u4e14\u57f7\u884c\u904e<code>git init</code>,\u8acb\u8df3\u904e\u6b64\u6b65\u9a5f. |
| | | gb.initWithGitignore = \u5305\u542b .gitignore \u6a94\u6848 |
| | | gb.initWithGitignoreDescription = \u65b0\u589e\u4e00\u500b\u8a2d\u5b9a\u6a94\u7528\u4f86\u6307\u5b9a\u54ea\u4e9b\u6a94\u6848\u6216\u76ee\u9304\u9700\u8981\u5ffd\u7565 |
| | | gb.initWithReadme = \u5305\u542bREADME\u6587\u4ef6 |
| | | gb.initWithReadmeDescription = \u6587\u4ef6\u5eab\u5c07\u7522\u751f\u7c21\u55aeREADME\u6587\u4ef6 |
| | | gb.invalidExpirationDate = \u4e0d\u6b63\u78ba\u7684\u5230\u671f\u65e5 |
| | | gb.invalidUsernameOrPassword = \u932f\u8aa4\u7684\u4f7f\u7528\u8005\u540d\u7a31\u6216\u5bc6\u78bc! |
| | | gb.isFederated = \u5df2\u7d93\u4e32\u9023 |
| | | gb.isFork = \u662f\u5206\u652f\u985e\u578b(fork) |
| | | gb.isFrozen = \u51cd\u7d50\u63a5\u6536 |
| | | gb.isFrozenDescription = \u7981\u6b62\u63a8\u9001(push) |
| | | gb.isMirror = \u8a72\u6587\u4ef6\u5eab\u70ba\u93e1\u50cf(mirror) |
| | | gb.isNotValidFile = \u4e0d\u662f\u6b63\u5e38\u6a94\u6848 |
| | | gb.isSparkleshared = \u8a72\u6587\u4ef6\u5eab\u5df2\u70baSparkleshared (http://sparkleshare.org) |
| | | gb.issued = \u767c\u51fa |
| | | gb.issuer = issuer |
| | | gb.jceWarning = Your Java Runtime Environment does not have the "JCE Unlimited Strength Jurisdiction Policy" files.\nThis will limit the length of passwords you may use to encrypt your keystores to 7 characters.\nThese policy files are an optional download from Oracle.\n\nWould you like to continue and generate the certificate infrastructure anyway?\n\nAnswering No will direct your browser to Oracle's download page so that you may download the policy files. |
| | | gb.key = \u91d1\u9470 |
| | | gb.keyCompromise = \u91d1\u9470\u5bc6\u78bc\u5916\u6d29 |
| | | gb.labels = \u6a19\u8a18 |
| | | gb.languagePreference = \u5e38\u7528\u8a9e\u8a00 |
| | | gb.languagePreferenceDescription = \u9078\u64c7\u4f60\u60f3\u8981\u7684Gitblit\u7ffb\u8b6f |
| | | gb.lastChange = \u6700\u8fd1\u4fee\u6539 |
| | | gb.lastLogin = \u6700\u8fd1\u767b\u5165 |
| | | gb.lastNDays = \u6700\u8fd1{0}\u5929 |
| | | gb.lastPull = \u4e0a\u6b21\u4e0b\u8f09(pull) |
| | | gb.leaveComment = \u7559\u4e0b\u8a3b\u89e3 |
| | | gb.line = \u884c |
| | | gb.loading = \u8f09\u5165 |
| | | gb.local = \u672c\u5730\u7aef |
| | | gb.locality = \u4f4d\u7f6e |
| | | gb.log = \u65e5\u8a8c |
| | | gb.login = \u767b\u5165 |
| | | gb.logout = \u767b\u51fa |
| | | gb.looksGood = \u770b\u8d77\u4f86\u5f88\u597d |
| | | gb.luceneDisabled = \u505c\u7528Lucene\u7d22\u5f15\u529f\u80fd |
| | | gb.mailingLists = \u90f5\u4ef6\u540d\u55ae |
| | | gb.maintenanceTickets = \u7dad\u8b77 |
| | | gb.manage = \u7ba1\u7406 |
| | | gb.manual = \u81ea\u884c\u8f38\u5165 |
| | | gb.markdown = markdown |
| | | gb.markdownFailure = \u89e3\u6790Markdown\u5931\u6557 |
| | | gb.maxActivityCommits = \u6700\u5927\u63d0\u4ea4\u6d3b\u8e8d\u7387 |
| | | gb.maxActivityCommitsDescription = \u6700\u5927\u63d0\u4ea4\u6d3b\u8e8d\u6578\u91cf |
| | | gb.maxHits = \u6700\u5927\u9ede\u64ca |
| | | gb.md5FingerPrint = MD5 Fingerprint |
| | | gb.mentions = \u63d0\u5230 |
| | | gb.mentionsMeTickets = \u63d0\u5230\u4f60 |
| | | gb.merge = \u5408\u4f75 |
| | | gb.mergeBase = \u57fa\u672c\u5408\u4f75 |
| | | gb.merged = \u5df2\u5408\u4f75 |
| | | gb.mergedPatchset = \u5c07\u88dc\u4e01\u5408\u4f75 |
| | | gb.mergedPullRequest = \u5408\u4f75\u63a8\u9001\u8981\u6c42 |
| | | gb.mergeSha = mergeSha |
| | | gb.mergeStep1 = Check out a new branch to review the changes \u2014 run this from your project directory |
| | | gb.mergeStep2 = Bring in the proposed changes and review |
| | | gb.mergeStep3 = \u5c07\u63d0\u6848\u4fee\u6539\u5167\u5bb9\u5408\u4f75\u5230\u4f3a\u670d\u5668\u4e0a |
| | | gb.mergeTo = \u5408\u4f75\u5230 |
| | | gb.mergeToDescription = \u9810\u8a2d\u5c07\u6587\u4ef6\u76f8\u95dc\u88dc\u4e01\u5305\u8207\u6307\u5b9a\u5206\u652f(branch)\u5408\u4f75 |
| | | gb.mergingViaCommandLine = \u7d93\u7531\u6307\u4ee4\u57f7\u884c\u5408\u4f75 |
| | | gb.mergingViaCommandLineNote = \u5982\u679c\u4f60\u4e0d\u60f3\u8981\u4f7f\u7528\u81ea\u52d5\u5408\u4f75\u529f\u80fd,\u6216\u662f\u6309\u4e0b\u5408\u4f75\u6309\u9215, \u4f60\u53ef\u4ee5\u4e0b\u6307\u4ee4\u624b\u52d5\u5408\u4f75 |
| | | gb.message = \u8a0a\u606f |
| | | gb.metricAuthorExclusions = \u91cf\u5316\u7d71\u8a08\u6642\u6392\u9664\u6d3b\u8e8d\u5e33\u6236 |
| | | gb.metrics = \u91cf\u5316\u7d71\u8a08 |
| | | gb.milestone = \u91cc\u7a0b\u7891 |
| | | gb.milestoneDeleteFailed = \u522a\u9664\u91cc\u7a0b\u7891"{0}"\u5931\u6557 |
| | | gb.milestoneProgress = {0}\u958b\u555f,{1}\u7d50\u675f |
| | | gb.milestones = \u91cc\u7a0b\u7891 |
| | | gb.mirrorOf = {0}\u7684\u93e1\u50cf |
| | | gb.mirrorWarning = \u8a72\u6587\u4ef6\u5eab\u5c6c\u65bc\u93e1\u50cf, \u4e0d\u80fd\u5920\u63a5\u6536\u63a8\u9001(push) |
| | | gb.miscellaneous = \u5176\u4ed6 |
| | | gb.missing = \u5931\u8aa4! |
| | | gb.missingIntegrationBranchMore = \u76ee\u6a19\u5206\u652f\u4e0d\u5728\u6b64\u7248\u672c\u5eab |
| | | gb.missingPermission = the repository for this permission is missing\! |
| | | gb.missingUsername = \u7f3a\u5c11\u4f7f\u7528\u8005\u540d\u7a31 |
| | | gb.modification = \u4fee\u6539 |
| | | gb.monthlyActivity = \u6708\u6d3b\u52d5 |
| | | gb.moreChanges = \u6240\u6709\u8b8a\u66f4... |
| | | gb.moreHistory = \u66f4\u591a\u6b77\u53f2\u7d00\u9304... |
| | | gb.moreLogs = \u66f4\u591a\u63d0\u4ea4 ... |
| | | gb.mutable = \u52d5\u614b\u7d66\u4e88 |
| | | gb.myDashboard = \u6211\u7684\u5100\u8868\u677f |
| | | gb.myFork = \u6aa2\u8996\u6211\u5efa\u7acb\u7684\u5206\u652f(fork) |
| | | gb.myProfile = \u6211\u7684\u57fa\u672c\u8cc7\u6599 |
| | | gb.myRepositories = \u6211\u7684\u7248\u672c\u5eab |
| | | gb.myTickets = \u6211\u7684\u4efb\u52d9\u55ae |
| | | gb.myUrlDescription = \u4f60Gitblit\u4f3a\u670d\u5668\u7684\u516c\u958bURL |
| | | gb.name = \u540d\u5b57 |
| | | gb.nameDescription = \u4f7f\u7528"/"\u505a\u70ba\u6587\u4ef6\u5eab\u7fa4\u7d44\u5206\u985e. \u5982: library/mycoolib.git |
| | | gb.namedPushPolicy = Restrict Push (Named) |
| | | gb.namedPushPolicyDescription = \u4efb\u4f55\u4eba\u7686\u53ef\u6aa2\u8996\u8207\u8907\u88fd(clone)\u6587\u4ef6\u5eab. \u4f60\u53ef\u53e6\u5916\u6307\u5b9a\u8ab0\u80fd\u5920\u6709\u63a8\u9001\u529f\u80fd(push) |
| | | gb.nAttachments = {0}\u500b\u9644\u4ef6 |
| | | gb.nClosedTickets = {0}\u9805\u7d50\u675f |
| | | gb.nComments = {0}\u500b\u8a3b\u89e3 |
| | | gb.nCommits = {0}\u4efd\u63d0\u4ea4 |
| | | gb.needsImprovement = \u9700\u8981\u512a\u5316 |
| | | gb.new = \u5efa\u7acb |
| | | gb.newCertificate = \u5efa\u7acb\u8b49\u66f8 |
| | | gb.newCertificateDefaults = \u65b0\u8b49\u66f8\u9810\u8a2d\u503c |
| | | gb.newClientCertificateMessage = \u6ce8\u610f:\n'password'\u5bc6\u78bc\u4e26\u4e0d\u662f\u4f7f\u7528\u8005\u5bc6\u78bc, \u800c\u662f\u7528\u4f86\u4fdd\u8b77\u4f7f\u7528\u8005\u500b\u4eba\u7684keystore.\u8a72\u5bc6\u78bc\u4e26\u4e0d\u6703\u5132\u5b58, \u56e0\u6b64\u5fc5\u9808\u8a2d\u5b9a\u63d0\u793a(hint), \u8a72\u63d0\u793a\u5c07\u6703\u5beb\u5728\u4f7f\u7528\u8005\u7684README\u6587\u4ef6\u88e1\u9762. |
| | | gb.newMilestone = \u5efa\u7acb\u91cc\u7a0b\u7891 |
| | | gb.newRepository = \u5efa\u7acb\u7248\u672c\u5eab |
| | | gb.newSSLCertificate = \u65b0\u7684\u4f3a\u670d\u5668SSL\u8b49\u66f8 |
| | | gb.newTeam = \u5efa\u7acb\u5718\u968a |
| | | gb.newTicket = \u65b0\u589e\u4efb\u52d9\u55ae |
| | | gb.newUser = \u5efa\u7acb\u4f7f\u7528\u8005 |
| | | gb.nextPull = next pull |
| | | gb.nFederationProposalsToReview = \u7e3d\u5171\u6709{0}\u500b\u4e32\u9023\u8a08\u756b\u7b49\u5f85\u5be9\u8996 |
| | | gb.nMoreCommits = \u9084\u6709{0}\u4efd\u63d0\u4ea4 \u00bb |
| | | gb.noActivity = \u904e\u53bb{0}\u5929\u4f86,\u4e26\u6c92\u6709\u6d3b\u52d5\u7d00\u9304 |
| | | gb.noActivityToday = \u4eca\u5929\u6c92\u6709\u6d3b\u52d5\u7d00\u9304 |
| | | gb.noComments = \u6c92\u6709\u5099\u8a3b |
| | | gb.noDescriptionGiven = \u6c92\u6709\u7d66\u4e88\u7c21\u8ff0 |
| | | gb.noFederation = Sorry, {0} is not configured to federate with any Gitblit instances. |
| | | gb.noForks = {0}\u6c92\u6709\u5206\u652f(fork) |
| | | gb.noGitblitFound = Sorry, {0} could not find a Gitblit instance at {1}. |
| | | gb.noHits = \u7121\u9ede\u64ca |
| | | gb.noIndexedRepositoriesWarning = \u8ddf\u4f60\u76f8\u95dc\u7684\u6587\u4ef6\u5eab\u4e26\u6c92\u6709\u505aLucene\u7d22\u5f15 |
| | | gb.noMaximum = \u7121\u6700\u5927\u503c |
| | | gb.noMilestoneSelected = \u672a\u9078\u53d6\u91cc\u7a0b\u7891 |
| | | gb.none = \u7121 |
| | | gb.nOpenTickets = {0}\u9805\u958b\u555f\u4e2d |
| | | gb.noPermission = \u522a\u9664\u9019\u500b\u6b0a\u9650 |
| | | gb.noProposals = \u62b1\u6b49, {0}\u6b64\u6642\u4e26\u4e0d\u662f\u53ef\u63a5\u53d7\u7684\u8a08\u756b |
| | | gb.noSelectedRepositoriesWarning = \u8acb\u81f3\u5c11\u9078\u64c7\u4e00\u500b\u6587\u4ef6\u5eab |
| | | gb.notifyChangedOpenTickets = \u5df2\u958b\u555f\u7684\u4efb\u52d9\u55ae\u6709\u7570\u52d5\u8acb\u767c\u9001\u901a\u77e5 |
| | | gb.notRestricted = \u533f\u540d\u72c0\u614b\u53ef\u4ee5View, Clone\u8207Push |
| | | gb.notSpecified = \u7121\u6307\u5b9a |
| | | gb.nParticipants = {0}\u500b\u53c3\u8207 |
| | | gb.nTotalTickets = \u7e3d\u5171{0}\u9805 |
| | | gb.object = \u7269\u4ef6 |
| | | gb.of = \u7684 |
| | | gb.ok = ok |
| | | gb.oneAttachment = {0}\u500b\u9644\u4ef6 |
| | | gb.oneComment = {0}\u500b\u8a3b\u89e3 |
| | | gb.oneCommit = 1\u500b\u63d0\u4ea4 |
| | | gb.oneCommitTo = 1\u500b\u63d0\u4ea4\u5230 |
| | | gb.oneMoreCommit = \u9084\u6709\u4e00\u500b\u63d0\u4ea4 \u00bb |
| | | gb.oneParticipant = {0}\u53c3\u8207 |
| | | gb.OneProposalToReview = \u6709\u4e00\u500b\u4e32\u9023\u7684\u63d0\u6848\u7b49\u5f85\u5be9\u67e5 |
| | | gb.opacityAdjust = Adjust opacity |
| | | gb.open = \u958b\u555f |
| | | gb.openMilestones = \u6253\u958b\u91cc\u7a0b\u7891 |
| | | gb.organization = \u7d44\u7e54 |
| | | gb.organizationalUnit = \u7d44\u7e54\u55ae\u4f4d |
| | | gb.origin = origin |
| | | gb.originDescription = \u6b64\u6587\u4ef6\u5eabURL\u5df2\u7d93\u88ab\u8907\u88fd(cloned)\u4e86 |
| | | gb.overdue = \u904e\u671f |
| | | gb.overview = \u6982\u89c0 |
| | | gb.owned = \u64c1\u6709\u7684 |
| | | gb.owner = \u64c1\u6709\u8005 |
| | | gb.ownerDescription = \u64c1\u6709\u8005\u53ef\u4fee\u6539\u6587\u4ef6\u5eab\u8a2d\u5b9a\u503c |
| | | gb.ownerPermission = \u6587\u4ef6\u5eab\u6240\u6709\u8005 |
| | | gb.owners = \u6240\u6709\u8005 |
| | | gb.ownersDescription = \u6240\u6709\u8005\u53ef\u4ee5\u7ba1\u7406\u6587\u4ef6\u5eab,\u4f46\u662f\u4e0d\u5141\u8a31\u4fee\u6539\u540d\u7a31(\u79c1\u4eba\u6587\u4ef6\u5eab\u4f8b\u5916) |
| | | gb.pageFirst = \u7b2c\u4e00\u7b46 |
| | | gb.pageNext = \u4e0b\u4e00\u9801 |
| | | gb.pagePrevious = \u4e0a\u4e00\u9801 |
| | | gb.pages = \u6587\u4ef6 |
| | | gb.parent = \u4e0a\u500b\u7248\u672c |
| | | gb.password = \u5bc6\u78bc |
| | | gb.passwordChangeAborted = \u53d6\u6d88\u5bc6\u78bc\u8b8a\u66f4 |
| | | gb.passwordChanged = \u5bc6\u78bc\u8b8a\u66f4\u6210\u529f |
| | | gb.passwordHint = \u5bc6\u78bc\u63d0\u793a |
| | | gb.passwordHintRequired = \u5bc6\u78bc\u63d0\u793a(\u5fc5\u8981) |
| | | gb.passwordsDoNotMatch = \u5bc6\u78bc\u4e0d\u76f8\u7b26 |
| | | gb.passwordTooShort = \u5bc6\u78bc\u904e\u77ed, \u6700\u5c11{0}\u500b\u5b57\u5143 |
| | | gb.patch = \u4fee\u88dc\u6a94 |
| | | gb.patchset = \u88dc\u4e01 |
| | | gb.patchsetAlreadyMerged = \u8a72\u88dc\u4e01\u5df2\u7d93\u5408\u4f75\u5230{0} |
| | | gb.patchsetMergeable = \u8a72\u88dc\u4e01\u53ef\u4ee5\u81ea\u52d5\u8207{0}\u5408\u4f75 |
| | | gb.patchsetMergeableMore = \u4f7f\u7528\u547d\u4ee4\u529f\u80fd,\u8b93\u6b64\u88dc\u4e01\u53ef\u4ee5\u8207{0}\u5408\u4f75 |
| | | gb.patchsetN = \u88dc\u4e01{0} |
| | | gb.patchsetNotApproved = \u8a72\u88dc\u4e01\u7248\u672c\u4e26\u6c92\u6709\u88ab\u6279\u51c6\u8207{0}\u5408\u4f75 |
| | | gb.patchsetNotApprovedMore = \u8a72\u88dc\u4e01\u5fc5\u9808\u7531\u5be9\u67e5\u8005\u6279\u51c6 |
| | | gb.patchsetNotMergeable = \u8a72\u88dc\u4e01\u4e0d\u80fd\u81ea\u52d5\u8207{0}\u5408\u4f75 |
| | | gb.patchsetNotMergeableMore = \u5fc5\u9808\u4ee5rebased\u6216\u662f\u624b\u52d5\u8207{0}\u5408\u4f75\u7684\u65b9\u5f0f\u624d\u80fd\u89e3\u6c7a\u8a72\u88dc\u4e01\u9020\u6210\u7684\u885d\u7a81 |
| | | gb.patchsetVetoedMore = \u5be9\u8996\u8005\u5df2\u7d93\u5c0d\u6b64\u88dc\u4e01\u6295\u7968 |
| | | gb.permission = \u6b0a\u9650 |
| | | gb.permissions = \u6b0a\u9650 |
| | | gb.permittedTeams = permitted teams |
| | | gb.permittedUsers = permitted users |
| | | gb.personalRepositories = \u500b\u4eba\u6587\u4ef6\u5eab |
| | | gb.pleaseGenerateClientCertificate = \u8acb\u7522\u751f\u7d66{0}\u4f7f\u7528\u7684\u7528\u6236\u7aef\u8b49\u66f8 |
| | | gb.pleaseSelectGitIgnore = \u8acb\u9078\u64c7\u4e00\u500b.gitignore\u6a94\u6848 |
| | | gb.pleaseSelectProject = \u8acb\u9078\u64c7\u5c08\u6848! |
| | | gb.pleaseSetDestinationUrl = Please enter a destination url for your proposal\! |
| | | gb.pleaseSetGitblitUrl = \u8acb\u8f38\u5165Gitblit URL ! |
| | | gb.pleaseSetRepositoryName = \u8acb\u8a2d\u5b9a\u7248\u672c\u5eab\u540d\u7a31 |
| | | gb.pleaseSetTeamName = \u8acb\u8f38\u5165\u5718\u968a\u540d\u7a31 |
| | | gb.pleaseSetUsername = \u8acb\u8f38\u5165\u4f7f\u7528\u8005\u540d\u7a31 |
| | | gb.plugins = \u63d2\u4ef6 |
| | | gb.postReceiveDescription = \u63a5\u5230\u63d0\u4ea4\u7533\u8acb\u5f8c,<em>\u4e26\u4e14\u5728refs\u5b8c\u7562\u5f8c</em>, \u5c07\u6703\u57f7\u884cPost-receive hook..<p>This is the appropriate hook for notifications, build triggers, etc.</p> |
| | | gb.postReceiveScripts = post-receive\u8173\u672c |
| | | gb.preferences = \u9810\u8a2d\u5e38\u7528\u503c |
| | | gb.preparingFork = \u6b63\u5728\u6e96\u5099\u8907\u88fd\u4e2d(fork)... |
| | | gb.preReceiveDescription = \u63a5\u5230\u63d0\u4ea4\u7533\u8acb\u5f8c,<em>\u4f46\u5728\u9084\u6c92\u6709\u66f4\u65b0refs\u524d</em>, \u5c07\u6703\u57f7\u884cPre-receive hook. <p>This is the appropriate hook for rejecting a push.</p> |
| | | gb.preReceiveScripts = pre-receive \u8173\u672c |
| | | gb.preview = \u9810\u89bd |
| | | gb.priority = \u512a\u5148 |
| | | gb.privilegeWithdrawn = \u53d6\u6d88\u6b0a\u9650 |
| | | gb.project = \u7fa4\u7d44 |
| | | gb.projects = \u7fa4\u7d44 |
| | | gb.properties = \u5c6c\u6027 |
| | | gb.proposal = \u63d0\u6848 |
| | | gb.proposalError = \u62b1\u6b49, {0} \u4efd\u5831\u544a\u767c\u751f\u9810\u671f\u5916\u7684\u932f\u8aa4! |
| | | gb.proposalFailed = Sorry, {0} did not receive any proposal data\! |
| | | gb.proposalReceived = Proposal successfully received by {0}. |
| | | gb.proposals = \u8981\u6c42\u806f\u5408\u7684\u63d0\u6848 |
| | | gb.proposalTickets = \u63d0\u6848\u4fee\u6539 |
| | | gb.proposedThisChange = proposed this change |
| | | gb.proposeInstructions = To start, craft a patchset and upload it with Git. Gitblit will link your patchset to this ticket by the id. |
| | | gb.proposePatchset = \u63d0\u51fa\u88dc\u4e01 |
| | | gb.proposePatchsetNote = \u6b61\u8fce\u5c0d\u6b64\u4efb\u52d9\u55ae\u63d0\u4f9b\u88dc\u4e01 |
| | | gb.proposeWith = propose a patchset with {0} |
| | | gb.ptCheckout = Fetch & checkout the current patchset to a review branch |
| | | gb.ptDescription = the Gitblit patchset tool |
| | | gb.ptDescription1 = Barnum is a command-line companion for Git that simplifies the syntax for working with Gitblit Tickets and Patchsets. |
| | | gb.ptDescription2 = Barnum requires Python 3 and native Git. It runs on Windows, Linux, and Mac OS X. |
| | | gb.ptMerge = \u53d6\u5f97\u76ee\u524d\u88dc\u4e01,\u7136\u5f8c\u8207\u4f60\u672c\u6a5f\u7aef\u7684\u5206\u652f\u5408\u4f75 |
| | | gb.ptSimplifiedCollaboration = simplified collaboration syntax |
| | | gb.ptSimplifiedMerge = simplified merge syntax |
| | | gb.publicKey = \u516c\u958b\u91d1\u9470 |
| | | gb.pushedNCommitsTo = {0}\u500b\u63d0\u4ea4\u5df2\u63a8\u9001\u81f3 |
| | | gb.pushedNewBranch = \u65b0\u5206\u652f\u5df2\u63a8\u9001(pushed) |
| | | gb.pushedNewTag = \u65b0\u6a19\u7c64\u5df2\u63a8\u9001(pushed) |
| | | gb.pushedOneCommitTo = 1\u500b\u63d0\u4ea4\u5df2\u63a8\u9001\u81f3 |
| | | gb.pushPermission = {0}(\u63a8\u9001) |
| | | gb.pushRestricted = authenticated push |
| | | gb.queries = \u67e5\u8a62\u7d50\u679c |
| | | gb.query = \u67e5\u8a62 |
| | | gb.queryHelp = \u652f\u63f4\u6a19\u6e96\u67e5\u8a62\u8a9e\u6cd5.<p/><p/>\u8a73\u60c5\u8acb\u53c3\u8003 <a target\ = "_new" href\ = "http\://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> |
| | | gb.queryResults = results {0} - {1} ({2} hits) |
| | | gb.questionTickets = \u63d0\u554f |
| | | gb.raw = \u539f\u59cb |
| | | gb.reason = \u539f\u56e0 |
| | | gb.receive = \u63a5\u6536 |
| | | gb.received = \u5df2\u63a5\u6536 |
| | | gb.receiveSettings = \u8a2d\u5b9a\u63a5\u6536\u65b9\u5f0f |
| | | gb.receiveSettingsDescription = \u63a7\u7ba1\u63a8\u9001\u5230\u6587\u4ef6\u5eab\u7684\u63a5\u6536\u65b9\u5f0f |
| | | gb.recent = \u6700\u8fd1 |
| | | gb.recentActivity = \u6700\u8fd1\u6d3b\u8e8d\u72c0\u6cc1 |
| | | gb.recentActivityNone = \u904e\u53bb{0}\u5929/\u7121 |
| | | gb.recentActivityStats = \u904e\u53bb{0}\u5929,\u4e00\u5171\u6709{2}\u4eba\u57f7\u884c{1}\u4efd\u63d0\u4ea4 |
| | | gb.reflog = \u76f8\u95dc\u65e5\u8a8c |
| | | gb.refresh = \u5237\u65b0 |
| | | gb.refs = \u5f15\u7528 |
| | | gb.regexPermission = \u5df2\u7d93\u4f7f\u7528\u6b63\u898f\u8868\u793a\u5f0f(regular expression)"{0}" \u8a2d\u5b9a\u6b0a\u9650\u5b8c\u7562 |
| | | gb.registration = \u8a3b\u518a |
| | | gb.registrations = federation registrations |
| | | gb.releaseDate = \u767c\u8868\u65e5 |
| | | gb.remote = \u9060\u7aef |
| | | gb.removeVote = \u79fb\u9664\u6295\u7968 |
| | | gb.rename = \u6539\u540d\u7a31 |
| | | gb.repositories = \u6587\u4ef6\u5eab |
| | | gb.repository = \u7248\u672c\u5eab |
| | | gb.repositoryDeleted = \u7248\u672c\u5eab"{0}"\u5df2\u522a\u9664 |
| | | gb.repositoryDeleteFailed = \u522a\u9664\u7248\u672c\u5eab"{0}"\u5931\u6557! |
| | | gb.repositoryDoesNotAcceptPatchsets = \u8a72\u7248\u672c\u5eab\u4e0d\u63a5\u53d7\u88dc\u4e01 |
| | | gb.repositoryForked = \u7248\u672c\u5eab{0}\u5df2\u7d93\u5efa\u7acb\u5206\u652f(fork) |
| | | gb.repositoryForkFailed= \u5efa\u7acb\u5206\u652f(fork)\u5931\u6557 |
| | | gb.repositoryIsFrozen = \u8a72\u7248\u672c\u5eab\u5df2\u51cd\u7d50 |
| | | gb.repositoryIsMirror = \u8a72\u7248\u672c\u5eab\u70ba\u552f\u8b80\u8907\u672c |
| | | gb.repositoryNotSpecified = \u672a\u6307\u5b9a\u7248\u672c\u5eab! |
| | | gb.repositoryNotSpecifiedFor = \u7248\u672c\u5eab\u4e26\u6c92\u6709\u6307\u5b9a\u7d66 {0}\! |
| | | gb.repositoryPermissions = \u7248\u672c\u5eab\u6b0a\u9650 |
| | | gb.repositoryUrl = \u7248\u672c\u5eab url |
| | | gb.requestTickets = \u512a\u5316 & \u4efb\u52d9 |
| | | gb.requireApproval = \u9700\u6279\u51c6 |
| | | gb.requireApprovalDescription = \u5408\u4f75\u6309\u9215\u555f\u7528\u524d,\u88dc\u4e01\u5305\u5fc5\u9808\u5148\u6279\u51c6 |
| | | gb.reset = \u6e05\u9664 |
| | | gb.responsible = \u8ca0\u8cac\u4eba\u54e1 |
| | | gb.restrictedRepositories = restricted repositories |
| | | gb.review = \u8907\u67e5(review) |
| | | gb.reviewedPatchsetRev = reviewed patchset {0} revision {1}\: {2} |
| | | gb.reviewers = \u5be9\u67e5\u8005 |
| | | gb.reviewPatchset = review {0} patchset {1} |
| | | gb.reviews = reviews |
| | | gb.revisionHistory = \u4fee\u6539\u7d00\u9304 |
| | | gb.revokeCertificate = \u64a4\u56de\u8b49\u66f8 |
| | | gb.revokeCertificateReason = \u8acb\u8f38\u5165\u64a4\u56de\u8b49\u66f8\u7406\u7531 |
| | | gb.revoked = \u5df2\u64a4\u92b7 |
| | | gb.rewind = REWIND |
| | | gb.rewindPermission = {0} (push, ref creation+deletion+rewind) |
| | | gb.save = \u5132\u5b58 |
| | | gb.search = \u641c\u5c0b |
| | | gb.searchForAuthor = Search for commits authored by |
| | | gb.searchForCommitter = Search for commits committed by |
| | | gb.searchTickets = \u641c\u5c0b\u4efb\u52d9\u55ae |
| | | gb.searchTicketsTooltip = \u627e\u5230{0}\u4efd\u4efb\u52d9\u55ae |
| | | gb.searchTooltip = \u641c\u5c0b{0} |
| | | gb.searchTypeTooltip = \u9078\u64c7\u641c\u5c0b\u985e\u578b |
| | | gb.selectAccessRestriction = Please select access restriction\! |
| | | gb.selected = \u9078\u5b9a |
| | | gb.selectFederationStrategy = Please select federation strategy\! |
| | | gb.sendEmail = \u767cemail |
| | | gb.sendProposal = \u63d0\u6848 |
| | | gb.serialNumber = \u5e8f\u865f |
| | | gb.serveCertificate = \u555f\u7528\u4f7f\u7528\u6b64\u8b49\u66f8\u7684https\u529f\u80fd |
| | | gb.serverDoesNotAcceptPatchsets = \u672c\u4f3a\u670d\u5668\u4e0d\u63a5\u53d7\u88dc\u4e01 |
| | | gb.servers = \u4f3a\u670d\u5668 |
| | | gb.servletContainer = servlet\u5bb9\u5668 |
| | | gb.sessionEnded = session\u5df2\u7d93\u53d6\u6d88 |
| | | gb.setDefault = \u8a2d\u70ba\u9810\u8a2d\u503c |
| | | gb.settings = \u8a2d\u5b9a |
| | | gb.severity = \u91cd\u8981 |
| | | gb.sha1FingerPrint = SHA-1 Fingerprint |
| | | gb.show_whitespace = \u986f\u793a\u7a7a\u767d |
| | | gb.showHideDetails = \u986f\u793a/\u96b1\u85cf \u8a73\u89e3\u5167\u5bb9 |
| | | gb.showReadme = \u986f\u793areadme\u6587\u4ef6 |
| | | gb.showReadmeDescription = \u5728\u532f\u7e3d\u9801\u9762\u4e2d\u986f\u793a"readme"(markdown\u683c\u5f0f) |
| | | gb.showRemoteBranches = \u986f\u793a\u9060\u7aef\u5206\u652f |
| | | gb.showRemoteBranchesDescription = \u986f\u793a\u9060\u7aef\u5206\u652f(branches) |
| | | gb.signatureAlgorithm = \u7c3d\u7ae0\u6f14\u7b97\u6cd5 |
| | | gb.since = \u5f9e |
| | | gb.siteName = \u7ad9\u53f0\u540d\u7a31 |
| | | gb.siteNameDescription = \u4f3a\u670d\u5668\u7c21\u7a31 |
| | | gb.size = \u5bb9\u91cf |
| | | gb.skipSizeCalculation = \u7565\u904e\u5bb9\u91cf\u8a08\u7b97 |
| | | gb.skipSizeCalculationDescription = \u4e0d\u8a08\u7b97\u6587\u4ef6\u5eab\u5bb9\u91cf(\u52a0\u5feb\u7db2\u9801\u8f09\u5165\u901f\u5ea6) |
| | | gb.skipSummaryMetrics = \u7565\u904e\u91cf\u5316\u532f\u7e3d |
| | | gb.skipSummaryMetricsDescription = \u4e0d\u8981\u8a08\u7b97\u91cf\u5316\u4e26\u4e14\u986f\u793a\u5728\u532f\u7e3d\u9801\u9762\u4e0a(\u52a0\u5feb\u901f\u5ea6) |
| | | gb.sort = \u6392\u5e8f |
| | | gb.sortHighestPriority = \u6700\u9ad8\u512a\u5148 |
| | | gb.sortHighestSeverity = \u6700\u91cd\u8981 |
| | | gb.sortLeastComments = \u6700\u5c11\u5099\u8a3b |
| | | gb.sortLeastPatchsetRevisions = \u6700\u5c11\u88dc\u4e01\u4fee\u6539 |
| | | gb.sortLeastRecentlyUpdated = \u6700\u8fd1\u6700\u5c11\u8b8a\u52d5 |
| | | gb.sortLeastVotes = \u6700\u5c11\u6295\u7968 |
| | | gb.sortLowestPriority = \u6700\u4f4e\u512a\u5148 |
| | | gb.sortLowestSeverity = \u6700\u4e0d\u91cd\u8981 |
| | | gb.sortMostComments = \u6700\u591a\u5099\u8a3b |
| | | gb.sortMostPatchsetRevisions = \u6700\u591a\u88dc\u4e01\u4fee\u6b63 |
| | | gb.sortMostRecentlyUpdated = \u6700\u8fd1\u66f4\u65b0 |
| | | gb.sortMostVotes = \u6700\u591a\u6295\u7968 |
| | | gb.sortNewest = \u6700\u65b0 |
| | | gb.sortOldest = \u6700\u820a |
| | | gb.specified = \u6307\u5b9a\u7d66\u4e88(\u542b\u7cfb\u7d71\u9810\u8a2d) |
| | | gb.sshKeyCommentDescription = \u8acb\u8f38\u5165\u5099\u8a3b, \u82e5\u7121\u5099\u8a3b, \u5c07\u81ea\u8a02\u586b\u5165key data |
| | | gb.sshKeyPermissionDescription = \u6307\u5b9a\u8a72SSH key\u6240\u64c1\u6709\u7684\u5b58\u53d6\u6b0a\u9650 |
| | | gb.sshKeys = SSH Keys |
| | | gb.sshKeysDescription = SSH \u516c\u958b\u91d1\u9470\u662f\u5bc6\u78bc\u8a8d\u8b49\u5916\u66f4\u5b89\u5168\u7684\u9078\u9805 |
| | | gb.sslCertificateGenerated = \u6210\u529f\u7522\u751f\u7d66{0}\u7684\u670d\u5668SSL\u8b49\u66f8 |
| | | gb.sslCertificateGeneratedRestart = \u6210\u529f\u7522\u751f\u7d66{0}\u4f7f\u7528\u7684SSL\u8b49\u66f8\n\u4f60\u5fc5\u9808\u91cd\u65b0\u555f\u52d5Gitblit\u7248\u63a7\u4f3a\u670d\u5668\u624d\u80fd\u555f\u7528\u65b0\u7684\u8b49\u66f8\n\nf you are launching with the '--alias' parameter you will have to set that to ''--alias {0}''. |
| | | gb.star = \u91cd\u8981 |
| | | gb.stargazers = stargazers |
| | | gb.starred = \u91cd\u8981 |
| | | gb.starredAndOwned = \u91cd\u8981\u7684 & \u64c1\u6709\u7684 |
| | | gb.starredRepositories = \u91cd\u8981\u7684\u6587\u4ef6\u5eab |
| | | gb.starting = \u555f\u52d5\u4e2d |
| | | gb.stateProvince = \u5dde\u6216\u7701 |
| | | gb.stats = \u7d71\u8a08 |
| | | gb.status = \u72c0\u614b |
| | | gb.stepN = \u6b65\u9a5f{0} |
| | | gb.stopWatching = \u505c\u6b62\u8ffd\u8e64(watching) |
| | | gb.subject = \u6a19\u984c |
| | | gb.subscribe = \u8a02\u95b1 |
| | | gb.summary = \u532f\u7e3d |
| | | gb.superseded = \u5df2\u88ab\u66ff\u4ee3 |
| | | gb.tag = \u6a19\u7c64 |
| | | gb.tagger = tagger |
| | | gb.tags = \u6a19\u7c64 |
| | | gb.taskTickets = \u4efb\u52d9 |
| | | gb.team = \u5718\u968a |
| | | gb.teamCreated = \u5718\u968a"{0}"\u65b0\u589e\u6210\u529f. |
| | | gb.teamMembers = \u5718\u968a\u6210\u54e1 |
| | | gb.teamMemberships = \u5718\u968a\u6210\u54e1(memberships) |
| | | gb.teamMustSpecifyRepository = \u5718\u968a\u6700\u5c11\u8981\u6307\u5b9a\u4e00\u500b\u7248\u672c\u5eab |
| | | gb.teamName = \u5718\u968a\u540d\u7a31 |
| | | gb.teamNameUnavailable = \u5718\u968a"{0}"\u4e0d\u5b58\u5728. |
| | | gb.teamPermission = "{0}" \u5718\u968a\u6210\u54e1\u7684\u6b0a\u9650 |
| | | gb.teamPermissions = \u5718\u968a\u6b0a\u9650 |
| | | gb.teamPermissionsDescription = \u4f60\u53ef\u4ee5\u6307\u5b9a\u5718\u968a\u6b0a\u9650.\u9019\u4e9b\u8a2d\u5b9a\u5c07\u6703\u53d6\u4ee3\u539f\u672c\u5718\u968a\u9810\u8a2d\u6b0a\u9650 |
| | | gb.teams = \u53c3\u8207\u7684\u5718\u968a |
| | | gb.ticket = \u4efb\u52d9\u55ae |
| | | gb.ticketAssigned = \u5df2\u6307\u5b9a |
| | | gb.ticketComments = \u8a3b\u89e3 |
| | | gb.ticketId = \u4efb\u52d9\u55aeID |
| | | gb.ticketIsClosed = \u8a72\u4efb\u52d9\u55ae\u5df2\u7d93\u7d50\u6848 |
| | | gb.ticketN = \u4efb\u52d9\u55ae\u865f#{0} |
| | | gb.ticketOpenDate = \u767c\u884c\u65e5 |
| | | gb.ticketPatchset = {0}\u4efb\u52d9\u55ae,{1}\u88dc\u4e01 |
| | | gb.tickets = \u4efb\u52d9\u55ae |
| | | gb.ticketSettings = \u4efb\u52d9\u55ae\u5167\u5bb9\u8a2d\u5b9a |
| | | gb.ticketStatus = \u72c0\u614b |
| | | gb.ticketsWelcome = \u4f60\u53ef\u4ee5\u5229\u7528\u4efb\u52d9\u55ae\u7cfb\u7d71\u5efa\u69cb\u51fa\u5f85\u8fa6\u4e8b\u9805, \u81ed\u87f2\u56de\u5831\u5340\u4ee5\u53ca\u88dc\u4e01\u5305\u7684\u5354\u540c\u5408\u4f5c |
| | | gb.time.daysAgo = {0}\u5929\u524d |
| | | gb.time.hoursAgo = {0}\u5c0f\u6642\u524d |
| | | gb.time.inDays = {0}\u5929\u5167 |
| | | gb.time.inHours = {0}\u5c0f\u6642\u5167 |
| | | gb.time.inMinutes = {0}\u5206\u9418\u5167 |
| | | gb.time.justNow = \u525b\u525b |
| | | gb.time.minsAgo = {0}\u5206\u9418\u524d |
| | | gb.time.monthsAgo = {0}\u6708\u524d |
| | | gb.time.oneYearAgo = 1\u5e74\u524d |
| | | gb.time.today = \u4eca\u5929 |
| | | gb.time.weeksAgo = {0}\u5468\u524d |
| | | gb.time.yearsAgo = {0}\u5e74\u524d |
| | | gb.time.yesterday = \u6628\u5929 |
| | | gb.title = \u6a19\u984c |
| | | gb.to = to |
| | | gb.toBranch = to {0} |
| | | gb.todaysActivityNone = \u4eca\u5929/\u7121 |
| | | gb.todaysActivityStats = \u4eca\u5929/\u6709{2}\u500b\u4f5c\u8005\u5b8c\u6210{1}\u500b\u63d0\u4ea4 |
| | | gb.token = token |
| | | gb.tokenAllDescription = \u6240\u6709\u7248\u672c\u5eab,\u4f7f\u7528\u8005\u8207\u8a2d\u5b9a |
| | | gb.tokenJurDescription = \u6240\u6709\u7248\u672c\u5eab |
| | | gb.tokens = federation tokens |
| | | gb.tokenUnrDescription = \u6240\u6709\u7248\u672c\u5eab\u8207\u4f7f\u7528\u8005 |
| | | gb.topic = \u8a71\u984c |
| | | gb.topicsAndLabels = \u8a71\u984c\u8207\u6a19\u8a18 |
| | | gb.transportPreference = \u9810\u8a2d\u901a\u8a0a\u5354\u5b9a |
| | | gb.transportPreferenceDescription = \u8a2d\u5b9a\u4f60\u5e38\u7528\u7684\u9023\u7dda\u901a\u8a0a\u5354\u5b9a\u4ee5\u7528\u4f86\u8907\u88fd(clone) |
| | | gb.tree = \u76ee\u9304 |
| | | gb.type = \u985e\u578b |
| | | gb.unauthorizedAccessForRepository = \u7248\u672c\u5eab\u672a\u6388\u6b0a\u5b58\u53d6 |
| | | gb.undefinedQueryWarning = \u672a\u8a2d\u5b9a\u67e5\u8a62\u689d\u4ef6 |
| | | gb.unspecified = \u672a\u6307\u5b9a |
| | | gb.unstar = \u53d6\u6d88 |
| | | gb.updated = \u5df2\u66f4\u65b0 |
| | | gb.updatedBy = updated by |
| | | gb.uploadedPatchsetN = \u88dc\u4e01{0}\u5df2\u4e0a\u50b3 |
| | | gb.uploadedPatchsetNRevisionN = \u88dc\u4e01{0}\u4fee\u6539\u7248\u672c{1}\u5df2\u4e0a\u50b3 |
| | | gb.url = URL |
| | | gb.useDocsDescription = \u8a08\u7b97\u6587\u4ef6\u5eab\u88e1\u9762\u7684Markdown\u6a94\u6848 |
| | | gb.useIncrementalPushTagsDescription = \u63a8\u9001\u6642\u5c07\u81ea\u52d5\u65b0\u589e\u6a19\u7c64\u865f\u78bc |
| | | gb.userCreated = \u6210\u529f\u5efa\u7acb\u65b0\u4f7f\u7528\u8005"{0}" |
| | | gb.userDeleted = \u4f7f\u7528\u8005"{0}"\u5df2\u522a\u9664 |
| | | gb.userDeleteFailed = \u4f7f\u7528\u8005"{0}"\u522a\u9664\u5931\u6557 |
| | | gb.username = \u4f7f\u7528\u8005\u540d\u7a31 |
| | | gb.usernameUnavailable = \u4f7f\u7528\u8005\u540d\u7a31"{0}"\u4e0d\u53ef\u7528 |
| | | gb.userPermissions = \u4f7f\u7528\u8005\u6b0a\u9650 |
| | | gb.userPermissionsDescription = \u4f60\u53ef\u4ee5\u91dd\u5c0d\u5e33\u865f\u8a2d\u5b9a\u6b0a\u9650(\u9019\u4e9b\u8a2d\u5b9a\u5c07\u8986\u84cb\u5718\u968a\u6216\u5176\u4ed6\u6b0a\u9650) |
| | | gb.users = \u4f7f\u7528\u8005 |
| | | gb.userServiceDoesNotPermitAddUser = {0}\u4e0d\u5141\u8a31\u65b0\u589e\u4f7f\u7528\u8005\u5e33\u865f |
| | | gb.userServiceDoesNotPermitPasswordChanges = {0}\u4e0d\u5141\u8a31\u4fee\u6539\u5bc6\u78bc |
| | | gb.useTicketsDescription = readonly, distributed Ticgit issues |
| | | gb.validFrom = valid from |
| | | gb.validity = validity |
| | | gb.validUntil = valid until |
| | | gb.verifyCommitter = \u63d0\u4ea4\u8005\u9700\u9a57\u8b49 |
| | | gb.verifyCommitterDescription = \u9700\u8981\u63d0\u4ea4\u8005\u7b26\u5408\u63a8\u9001\u5e33\u865f |
| | | gb.verifyCommitterNote = \u6240\u6709\u5408\u4f75\u52d5\u4f5c\u7686\u9808\u5f37\u5236\u4f7f\u7528"--no-ff"\u53c3\u6578 |
| | | gb.version = \u7248\u672c |
| | | gb.veto = veto |
| | | gb.view = \u6aa2\u8996 |
| | | gb.viewAccess = \u4f60\u6c92\u6709Gitblit\u8b80\u53d6\u6216\u662f\u4fee\u6539\u6b0a\u9650 |
| | | gb.viewCertificate = \u6aa2\u8996\u8b49\u66f8 |
| | | gb.viewComparison = \u6bd4\u8f03\u9019{0}\u500b\u63d0\u4ea4 \u00bb |
| | | gb.viewPermission = {0} (\u6aa2\u8996) |
| | | gb.viewPolicy = Restrict View, Clone, & Push |
| | | gb.viewPolicyDescription = \u9078\u64c7\u53ef\u4ee5\u5728\u6587\u4ef6\u5eab\u6aa2\u8996,\u8907\u88fd(clone)\u8207\u63a8\u9001(push)\u7684\u4f7f\u7528\u8005, \u9664\u6b64\u4e4b\u5916\u5176\u4ed6\u4eba\u7686\u7121\u6b0a\u9650 |
| | | gb.viewRestricted = authenticated view, clone, & push |
| | | gb.vote = \u5c0d{0}\u6295\u7968 |
| | | gb.voters = votes |
| | | gb.votes = votes |
| | | gb.warning = \u8b66\u544a |
| | | gb.watch = \u76e3\u770b{0} |
| | | gb.watchers = \u76e3\u770b\u8005 |
| | | gb.watching = \u76e3\u770b\u4e2d |
| | | gb.workingCopy = \u5de5\u4f5c\u8907\u672c |
| | | gb.workingCopyWarning = \u8a72\u6587\u4ef6\u5eab\u4ecd\u6709\u5de5\u4f5c\u8907\u672c,\u56e0\u6b64\u7121\u6cd5\u63a5\u53d7\u63a8\u9001(push) |
| | | gb.write = write |
| | | gb.youDoNotHaveClonePermission = \u4f60\u4e0d\u5141\u8a31\u8907\u88fd(clone)\u6b64\u6587\u4ef6\u5eab |
| | | gb.yourAssignedTickets = \u6307\u6d3e\u7d66\u4f60\u7684 |
| | | gb.yourCreatedTickets = \u7531\u4f60\u65b0\u589e\u7684 |
| | | gb.yourWatchedTickets = \u4f60\u60f3\u770b\u7684 |
| | | gb.zip = zip\u58d3\u7e2e\u6a94 |
| | | gb.ticketState = |
| | | gb.repositoryForkFailed = |
| | | gb.anonymousUser = |
| | | gb.oneAttachment = |
| | | gb.viewPolicy = |
| | | gb.emailMeOnMyTicketChangesDescription = |
| | |
| | | import com.gitblit.IStoredSettings; |
| | | import com.gitblit.manager.IAuthenticationManager; |
| | | import com.gitblit.manager.IFederationManager; |
| | | import com.gitblit.manager.IFilestoreManager; |
| | | import com.gitblit.manager.IGitblit; |
| | | import com.gitblit.manager.INotificationManager; |
| | | import com.gitblit.manager.IPluginManager; |
| | | import com.gitblit.manager.IProjectManager; |
| | | import com.gitblit.manager.IRepositoryManager; |
| | | import com.gitblit.manager.IRuntimeManager; |
| | | import com.gitblit.manager.IServicesManager; |
| | | import com.gitblit.manager.IUserManager; |
| | | import com.gitblit.tickets.ITicketService; |
| | | import com.gitblit.transport.ssh.IPublicKeyManager; |
| | |
| | | |
| | | public abstract IGitblit gitblit(); |
| | | |
| | | public abstract IServicesManager services(); |
| | | |
| | | public abstract ITicketService tickets(); |
| | | |
| | | public abstract TimeZone getTimezone(); |
| | | |
| | | public abstract IFilestoreManager filestore(); |
| | | |
| | | } |
| | |
| | |
|
| | | import java.util.Date;
|
| | |
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | | import javax.servlet.http.HttpServletRequest;
|
| | |
|
| | | import org.apache.wicket.protocol.http.IWebApplicationFactory;
|
| | |
| | |
|
| | | import com.gitblit.IStoredSettings;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.dagger.DaggerWicketFilter;
|
| | | import com.gitblit.manager.IProjectManager;
|
| | | import com.gitblit.manager.IRepositoryManager;
|
| | | import com.gitblit.manager.IRuntimeManager;
|
| | |
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.utils.JGitUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | |
|
| | | import dagger.ObjectGraph;
|
| | |
|
| | | /**
|
| | | *
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | public class GitblitWicketFilter extends DaggerWicketFilter {
|
| | | @Singleton
|
| | | public class GitblitWicketFilter extends WicketFilter {
|
| | |
|
| | | private IStoredSettings settings;
|
| | |
|
| | |
| | |
|
| | | private GitBlitWebApp webapp;
|
| | |
|
| | | @Override
|
| | | protected void inject(ObjectGraph dagger) {
|
| | | this.settings = dagger.get(IStoredSettings.class);
|
| | | this.runtimeManager = dagger.get(IRuntimeManager.class);
|
| | | this.repositoryManager = dagger.get(IRepositoryManager.class);
|
| | | this.projectManager = dagger.get(IProjectManager.class);
|
| | | this.webapp = dagger.get(GitBlitWebApp.class);
|
| | | @Inject
|
| | | public GitblitWicketFilter(
|
| | | IStoredSettings settings,
|
| | | IRuntimeManager runtimeManager,
|
| | | IRepositoryManager repositoryManager,
|
| | | IProjectManager projectManager,
|
| | | GitBlitWebApp webapp) {
|
| | |
|
| | | this.settings = settings;
|
| | | this.runtimeManager = runtimeManager;
|
| | | this.repositoryManager = repositoryManager;
|
| | | this.projectManager = projectManager;
|
| | | this.webapp = webapp;
|
| | | }
|
| | |
|
| | | @Override
|
New file |
| | |
| | | package com.gitblit.wicket; |
| | | |
| | | import java.text.DateFormat; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Date; |
| | | import java.util.Locale; |
| | | |
| | | import org.apache.wicket.Session; |
| | | import org.apache.wicket.markup.html.form.TextField; |
| | | import org.apache.wicket.markup.html.form.AbstractTextComponent.ITextFormatProvider; |
| | | import org.apache.wicket.model.IModel; |
| | | import org.apache.wicket.util.convert.IConverter; |
| | | import org.apache.wicket.util.convert.converters.DateConverter; |
| | | |
| | | public class Html5DateField extends TextField<Date> implements ITextFormatProvider { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private static final String DEFAULT_PATTERN = "MM/dd/yyyy"; |
| | | |
| | | private String datePattern = null; |
| | | |
| | | private IConverter converter = null; |
| | | |
| | | /** |
| | | * Creates a new Html5DateField, without a specified pattern. This is the same as calling |
| | | * <code>new Html5DateField(id, Date.class)</code> |
| | | * |
| | | * @param id |
| | | * The id of the date field |
| | | */ |
| | | public Html5DateField(String id) |
| | | { |
| | | this(id, null, defaultDatePattern()); |
| | | } |
| | | |
| | | /** |
| | | * Creates a new Html5DateField, without a specified pattern. This is the same as calling |
| | | * <code>new Html5DateField(id, object, Date.class)</code> |
| | | * |
| | | * @param id |
| | | * The id of the date field |
| | | * @param model |
| | | * The model |
| | | */ |
| | | public Html5DateField(String id, IModel<Date> model) |
| | | { |
| | | this(id, model, defaultDatePattern()); |
| | | } |
| | | |
| | | /** |
| | | * Creates a new Html5DateField bound with a specific <code>SimpleDateFormat</code> pattern. |
| | | * |
| | | * @param id |
| | | * The id of the date field |
| | | * @param datePattern |
| | | * A <code>SimpleDateFormat</code> pattern |
| | | * |
| | | */ |
| | | public Html5DateField(String id, String datePattern) |
| | | { |
| | | this(id, null, datePattern); |
| | | } |
| | | |
| | | /** |
| | | * Creates a new DateTextField bound with a specific <code>SimpleDateFormat</code> pattern. |
| | | * |
| | | * @param id |
| | | * The id of the date field |
| | | * @param model |
| | | * The model |
| | | * @param datePattern |
| | | * A <code>SimpleDateFormat</code> pattern |
| | | */ |
| | | public Html5DateField(String id, IModel<Date> model, String datePattern) |
| | | { |
| | | super(id, model, Date.class); |
| | | this.datePattern = datePattern; |
| | | converter = new DateConverter() |
| | | { |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * @see org.apache.wicket.util.convert.converters.DateConverter#getDateFormat(java.util.Locale) |
| | | */ |
| | | @Override |
| | | public DateFormat getDateFormat(Locale locale) |
| | | { |
| | | if (locale == null) |
| | | { |
| | | locale = Locale.getDefault(); |
| | | } |
| | | return new SimpleDateFormat(Html5DateField.this.datePattern, locale); |
| | | } |
| | | }; |
| | | } |
| | | |
| | | /** |
| | | * Returns the default converter if created without pattern; otherwise it returns a |
| | | * pattern-specific converter. |
| | | * |
| | | * @param type |
| | | * The type for which the converter should work |
| | | * |
| | | * @return A pattern-specific converter |
| | | */ |
| | | @Override |
| | | public IConverter getConverter(Class<?> type) |
| | | { |
| | | if (converter == null) |
| | | { |
| | | return super.getConverter(type); |
| | | } |
| | | else |
| | | { |
| | | return converter; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Returns the date pattern. |
| | | * |
| | | * @see org.apache.wicket.markup.html.form.AbstractTextComponent.ITextFormatProvider#getTextFormat() |
| | | */ |
| | | public String getTextFormat() |
| | | { |
| | | return datePattern; |
| | | } |
| | | |
| | | /** |
| | | * Try to get datePattern from user session locale. If it is not possible, it will return |
| | | * {@link #DEFAULT_PATTERN} |
| | | * |
| | | * @return date pattern |
| | | */ |
| | | private static String defaultDatePattern() |
| | | { |
| | | Locale locale = Session.get().getLocale(); |
| | | if (locale != null) |
| | | { |
| | | DateFormat format = DateFormat.getDateInstance(DateFormat.SHORT, locale); |
| | | if (format instanceof SimpleDateFormat) |
| | | { |
| | | return ((SimpleDateFormat)format).toPattern(); |
| | | } |
| | | } |
| | | return DEFAULT_PATTERN; |
| | | } |
| | | |
| | | @Override |
| | | protected String getInputType() |
| | | { |
| | | return "date"; |
| | | } |
| | | |
| | | } |
src/main/java/com/gitblit/wicket/NonTrimmedPasswordTextField.java
src/main/java/com/gitblit/wicket/TicketsUI.java
src/main/java/com/gitblit/wicket/WicketUtils.java
src/main/java/com/gitblit/wicket/freemarker/templates/FilterableRepositoryList.fm
src/main/java/com/gitblit/wicket/pages/BasePage.html
src/main/java/com/gitblit/wicket/pages/BasePage.java
src/main/java/com/gitblit/wicket/pages/BlamePage.java
src/main/java/com/gitblit/wicket/pages/BlobDiffPage.html
src/main/java/com/gitblit/wicket/pages/BlobDiffPage.java
src/main/java/com/gitblit/wicket/pages/BlobPage.html
src/main/java/com/gitblit/wicket/pages/BlobPage.java
src/main/java/com/gitblit/wicket/pages/ChangePasswordPage.java
src/main/java/com/gitblit/wicket/pages/CommitDiffPage.html
src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java
src/main/java/com/gitblit/wicket/pages/CommitPage.html
src/main/java/com/gitblit/wicket/pages/CommitPage.java
src/main/java/com/gitblit/wicket/pages/ComparePage.html
src/main/java/com/gitblit/wicket/pages/ComparePage.java
src/main/java/com/gitblit/wicket/pages/DocPage.html
src/main/java/com/gitblit/wicket/pages/DocPage.java
src/main/java/com/gitblit/wicket/pages/DocsPage.html
src/main/java/com/gitblit/wicket/pages/DocsPage.java
src/main/java/com/gitblit/wicket/pages/EditFilePage.html
src/main/java/com/gitblit/wicket/pages/EditFilePage.java
src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html
src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java
src/main/java/com/gitblit/wicket/pages/EditTeamPage.java
src/main/java/com/gitblit/wicket/pages/EditTicketPage.html
src/main/java/com/gitblit/wicket/pages/EditTicketPage.java
src/main/java/com/gitblit/wicket/pages/EditUserPage.java
src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java
src/main/java/com/gitblit/wicket/pages/FilestorePage.html
src/main/java/com/gitblit/wicket/pages/FilestorePage.java
src/main/java/com/gitblit/wicket/pages/FilestoreUsage.html
src/main/java/com/gitblit/wicket/pages/FilestoreUsage.java
src/main/java/com/gitblit/wicket/pages/ForksPage.java
src/main/java/com/gitblit/wicket/pages/ImageDiffHandler.java
src/main/java/com/gitblit/wicket/pages/LogoutPage.html
src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.html
src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.java
src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html
src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java
src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html
src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java
src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java
src/main/java/com/gitblit/wicket/pages/NewTicketPage.html
src/main/java/com/gitblit/wicket/pages/NewTicketPage.java
src/main/java/com/gitblit/wicket/pages/ProjectsPage.html
src/main/java/com/gitblit/wicket/pages/ProjectsPage.java
src/main/java/com/gitblit/wicket/pages/ReflogPage.html
src/main/java/com/gitblit/wicket/pages/ReflogPage.java
src/main/java/com/gitblit/wicket/pages/RepositoryPage.html
src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
src/main/java/com/gitblit/wicket/pages/ReviewProposalPage.java
src/main/java/com/gitblit/wicket/pages/RootPage.html
src/main/java/com/gitblit/wicket/pages/RootPage.java
src/main/java/com/gitblit/wicket/pages/SessionPage.java
src/main/java/com/gitblit/wicket/pages/TagPage.java
src/main/java/com/gitblit/wicket/pages/TicketPage.html
src/main/java/com/gitblit/wicket/pages/TicketPage.java
src/main/java/com/gitblit/wicket/pages/TicketsPage.html
src/main/java/com/gitblit/wicket/pages/TicketsPage.java
src/main/java/com/gitblit/wicket/pages/TreePage.html
src/main/java/com/gitblit/wicket/pages/TreePage.java
src/main/java/com/gitblit/wicket/pages/UserPage.java
src/main/java/com/gitblit/wicket/pages/scripts/imgdiff.js
src/main/java/com/gitblit/wicket/pages/scripts/wicketHtml5Patch.js
src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java
src/main/java/com/gitblit/wicket/panels/ActivityPanel.java
src/main/java/com/gitblit/wicket/panels/AvatarImage.html
src/main/java/com/gitblit/wicket/panels/AvatarImage.java
src/main/java/com/gitblit/wicket/panels/BranchesPanel.java
src/main/java/com/gitblit/wicket/panels/CommitHeaderPanel.java
src/main/java/com/gitblit/wicket/panels/DigestsPanel.java
src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java
src/main/java/com/gitblit/wicket/panels/HistoryPanel.java
src/main/java/com/gitblit/wicket/panels/LinkPanel.java
src/main/java/com/gitblit/wicket/panels/LogPanel.java
src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html
src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java
src/main/java/com/gitblit/wicket/panels/ReflogPanel.java
src/main/java/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java
src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.html
src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java
src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java
src/main/java/com/gitblit/wicket/panels/SearchPanel.java
src/main/java/com/gitblit/wicket/panels/TeamsPanel.html
src/main/java/com/gitblit/wicket/panels/TeamsPanel.java
src/main/java/com/gitblit/wicket/panels/TicketListPanel.html
src/main/java/com/gitblit/wicket/panels/TicketListPanel.java
src/main/java/com/gitblit/wicket/panels/UserTitlePanel.java
src/main/java/login_zh_TW.mkd
src/main/java/welcome_zh_TW.mkd
src/main/js/.gitignore
src/main/js/editor.dev.css
src/main/js/editor.dev.js
src/main/js/package.json
src/main/js/prosemirror
src/main/resources/blink32.png
src/main/resources/fontawesome/css/font-awesome.min.css
src/main/resources/fontawesome/fonts/FontAwesome.otf
src/main/resources/fontawesome/fonts/fontawesome-webfont.eot
src/main/resources/fontawesome/fonts/fontawesome-webfont.svg
src/main/resources/fontawesome/fonts/fontawesome-webfont.ttf
src/main/resources/fontawesome/fonts/fontawesome-webfont.woff
src/main/resources/fontawesome/fonts/fontawesome-webfont.woff2
src/main/resources/gitblit-editor.min.css
src/main/resources/gitblit-editor.min.js
src/main/resources/gitblit.css
src/main/resources/octicons/octicons-local.ttf
src/main/resources/octicons/octicons.css
src/main/resources/octicons/octicons.eot
src/main/resources/octicons/octicons.less
src/main/resources/octicons/octicons.svg
src/main/resources/octicons/octicons.ttf
src/main/resources/octicons/octicons.woff
src/main/resources/octicons/sprockets-octicons.scss
src/main/resources/sub32.png
src/site/design.mkd
src/site/plugins_extensions.mkd
src/site/roadmap.mkd (deleted)
src/site/rpc.mkd
src/site/setup_authentication.mkd
src/site/setup_bugtraq.mkd
src/site/setup_fail2ban.mkd
src/site/setup_filestore.mkd
src/site/setup_go.mkd
src/site/setup_proxy.mkd
src/site/setup_transport_http.mkd
src/site/setup_war.mkd
src/site/siteindex.mkd
src/site/tickets_overview.mkd
src/site/upgrade_go.mkd
src/site/upgrade_war.mkd
src/test/java/com/gitblit/tests/AuthenticationManagerTest.java
src/test/java/com/gitblit/tests/DiffUtilsTest.java
src/test/java/com/gitblit/tests/FilestoreManagerTest.java
src/test/java/com/gitblit/tests/FilestoreServletTest.java
src/test/java/com/gitblit/tests/GitBlitSuite.java
src/test/java/com/gitblit/tests/GitBlitTest.java
src/test/java/com/gitblit/tests/GitblitUnitTest.java
src/test/java/com/gitblit/tests/GravatarTest.java
src/test/java/com/gitblit/tests/HtpasswdAuthenticationTest.java
src/test/java/com/gitblit/tests/JGitUtilsTest.java
src/test/java/com/gitblit/tests/LdapAuthenticationTest.java
src/test/java/com/gitblit/tests/PathUtilsTest.java
src/test/java/com/gitblit/tests/RedmineAuthenticationTest.java
src/test/java/com/gitblit/tests/SshDaemonTest.java
src/test/java/com/gitblit/tests/SshKerberosAuthenticationTest.java
src/test/java/com/gitblit/tests/SshUnitTest.java
src/test/java/com/gitblit/tests/StringUtilsTest.java
src/test/java/com/gitblit/tests/TicketServiceTest.java
src/test/java/com/gitblit/tests/UITicketTest.java
src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java |