summaryrefslogtreecommitdiffstats
path: root/src/main/java/com/gitblit
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/gitblit')
-rw-r--r--src/main/java/com/gitblit/ConfigUserService.java33
-rw-r--r--src/main/java/com/gitblit/Constants.java31
-rw-r--r--src/main/java/com/gitblit/DaggerModule.java222
-rw-r--r--src/main/java/com/gitblit/FederationClient.java384
-rw-r--r--src/main/java/com/gitblit/FileSettings.java67
-rw-r--r--src/main/java/com/gitblit/GitBlit.java444
-rw-r--r--src/main/java/com/gitblit/GitBlitServer.java17
-rw-r--r--src/main/java/com/gitblit/auth/AuthenticationProvider.java30
-rw-r--r--src/main/java/com/gitblit/auth/HtpasswdAuthProvider.java12
-rw-r--r--src/main/java/com/gitblit/auth/LdapAuthProvider.java31
-rw-r--r--src/main/java/com/gitblit/auth/PAMAuthProvider.java12
-rw-r--r--src/main/java/com/gitblit/auth/RedmineAuthProvider.java14
-rw-r--r--src/main/java/com/gitblit/auth/SalesforceAuthProvider.java13
-rw-r--r--src/main/java/com/gitblit/auth/WindowsAuthProvider.java12
-rw-r--r--src/main/java/com/gitblit/dagger/DaggerContext.java67
-rw-r--r--src/main/java/com/gitblit/dagger/DaggerFilter.java47
-rw-r--r--src/main/java/com/gitblit/dagger/DaggerServlet.java44
-rw-r--r--src/main/java/com/gitblit/dagger/DaggerWicketFilter.java45
-rw-r--r--src/main/java/com/gitblit/guice/CoreModule.java82
-rw-r--r--src/main/java/com/gitblit/guice/IPublicKeyManagerProvider.java72
-rw-r--r--src/main/java/com/gitblit/guice/ITicketServiceProvider.java73
-rw-r--r--src/main/java/com/gitblit/guice/WebModule.java105
-rw-r--r--src/main/java/com/gitblit/guice/WorkQueueProvider.java57
-rw-r--r--src/main/java/com/gitblit/manager/AuthenticationManager.java27
-rw-r--r--src/main/java/com/gitblit/manager/FederationManager.java4
-rw-r--r--src/main/java/com/gitblit/manager/GitblitManager.java180
-rw-r--r--src/main/java/com/gitblit/manager/IAuthenticationManager.java19
-rw-r--r--src/main/java/com/gitblit/manager/IGitblit.java15
-rw-r--r--src/main/java/com/gitblit/manager/IRuntimeManager.java39
-rw-r--r--src/main/java/com/gitblit/manager/IServicesManager.java94
-rw-r--r--src/main/java/com/gitblit/manager/NotificationManager.java4
-rw-r--r--src/main/java/com/gitblit/manager/PluginManager.java97
-rw-r--r--src/main/java/com/gitblit/manager/ProjectManager.java4
-rw-r--r--src/main/java/com/gitblit/manager/RepositoryManager.java34
-rw-r--r--src/main/java/com/gitblit/manager/RuntimeManager.java59
-rw-r--r--src/main/java/com/gitblit/manager/ServicesManager.java244
-rw-r--r--src/main/java/com/gitblit/manager/UserManager.java4
-rw-r--r--src/main/java/com/gitblit/models/TicketModel.java124
-rw-r--r--src/main/java/com/gitblit/service/LuceneService.java4
-rw-r--r--src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java18
-rw-r--r--src/main/java/com/gitblit/servlet/AuthenticationFilter.java374
-rw-r--r--src/main/java/com/gitblit/servlet/BranchGraphServlet.java25
-rw-r--r--src/main/java/com/gitblit/servlet/DownloadZipFilter.java16
-rw-r--r--src/main/java/com/gitblit/servlet/DownloadZipServlet.java17
-rw-r--r--src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java34
-rw-r--r--src/main/java/com/gitblit/servlet/FederationServlet.java22
-rw-r--r--src/main/java/com/gitblit/servlet/GitFilter.java26
-rw-r--r--src/main/java/com/gitblit/servlet/GitServlet.java18
-rw-r--r--src/main/java/com/gitblit/servlet/GitblitContext.java85
-rw-r--r--src/main/java/com/gitblit/servlet/JsonServlet.java4
-rw-r--r--src/main/java/com/gitblit/servlet/LogoServlet.java15
-rw-r--r--src/main/java/com/gitblit/servlet/PagesFilter.java17
-rw-r--r--src/main/java/com/gitblit/servlet/PagesServlet.java219
-rw-r--r--src/main/java/com/gitblit/servlet/ProxyFilter.java33
-rw-r--r--src/main/java/com/gitblit/servlet/PtServlet.java15
-rw-r--r--src/main/java/com/gitblit/servlet/RawFilter.java16
-rw-r--r--src/main/java/com/gitblit/servlet/RawServlet.java48
-rw-r--r--src/main/java/com/gitblit/servlet/RobotsTxtServlet.java15
-rw-r--r--src/main/java/com/gitblit/servlet/RpcFilter.java22
-rw-r--r--src/main/java/com/gitblit/servlet/RpcServlet.java13
-rw-r--r--src/main/java/com/gitblit/servlet/SparkleShareInviteServlet.java26
-rw-r--r--src/main/java/com/gitblit/servlet/SyndicationFilter.java24
-rw-r--r--src/main/java/com/gitblit/servlet/SyndicationServlet.java24
-rw-r--r--src/main/java/com/gitblit/tickets/BranchTicketService.java5
-rw-r--r--src/main/java/com/gitblit/tickets/FileTicketService.java9
-rw-r--r--src/main/java/com/gitblit/tickets/ITicketService.java5
-rw-r--r--src/main/java/com/gitblit/tickets/NullTicketService.java5
-rw-r--r--src/main/java/com/gitblit/tickets/QueryResult.java4
-rw-r--r--src/main/java/com/gitblit/tickets/RedisTicketService.java8
-rw-r--r--src/main/java/com/gitblit/tickets/TicketIndexer.java9
-rw-r--r--src/main/java/com/gitblit/tickets/TicketNotifier.java7
-rw-r--r--src/main/java/com/gitblit/tickets/viewTicket.html12
-rw-r--r--src/main/java/com/gitblit/transport/ssh/FileKeyManager.java2
-rw-r--r--src/main/java/com/gitblit/transport/ssh/MemoryKeyManager.java3
-rw-r--r--src/main/java/com/gitblit/transport/ssh/NullKeyManager.java3
-rw-r--r--src/main/java/com/gitblit/transport/ssh/SshDaemon.java7
-rw-r--r--src/main/java/com/gitblit/transport/ssh/SshKeyAuthenticator.java (renamed from src/main/java/com/gitblit/transport/ssh/CachingPublicKeyAuthenticator.java)41
-rw-r--r--src/main/java/com/gitblit/utils/DiffUtils.java102
-rw-r--r--src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java765
-rw-r--r--src/main/java/com/gitblit/utils/HtmlBuilder.java96
-rw-r--r--src/main/java/com/gitblit/utils/JGitUtils.java514
-rw-r--r--src/main/java/com/gitblit/utils/JSoupXssFilter.java5
-rw-r--r--src/main/java/com/gitblit/utils/PathUtils.java92
-rw-r--r--src/main/java/com/gitblit/utils/ResettableByteArrayOutputStream.java42
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp.java36
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp.properties20
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties10
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties10
-rw-r--r--src/main/java/com/gitblit/wicket/GitblitWicketApp.java3
-rw-r--r--src/main/java/com/gitblit/wicket/GitblitWicketFilter.java28
-rw-r--r--src/main/java/com/gitblit/wicket/TicketsUI.java59
-rw-r--r--src/main/java/com/gitblit/wicket/WicketUtils.java6
-rw-r--r--src/main/java/com/gitblit/wicket/freemarker/templates/FilterableRepositoryList.fm8
-rw-r--r--src/main/java/com/gitblit/wicket/pages/BasePage.html2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/BasePage.java40
-rw-r--r--src/main/java/com/gitblit/wicket/pages/BlobDiffPage.java20
-rw-r--r--src/main/java/com/gitblit/wicket/pages/BlobPage.html5
-rw-r--r--src/main/java/com/gitblit/wicket/pages/BlobPage.java2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java15
-rw-r--r--src/main/java/com/gitblit/wicket/pages/ComparePage.java14
-rw-r--r--src/main/java/com/gitblit/wicket/pages/EditTeamPage.java18
-rw-r--r--src/main/java/com/gitblit/wicket/pages/EditTicketPage.html6
-rw-r--r--src/main/java/com/gitblit/wicket/pages/EditTicketPage.java30
-rw-r--r--src/main/java/com/gitblit/wicket/pages/EditUserPage.java28
-rw-r--r--src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/ImageDiffHandler.java170
-rw-r--r--src/main/java/com/gitblit/wicket/pages/LogoutPage.html2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html21
-rw-r--r--src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java14
-rw-r--r--src/main/java/com/gitblit/wicket/pages/NewTicketPage.html6
-rw-r--r--src/main/java/com/gitblit/wicket/pages/NewTicketPage.java27
-rw-r--r--src/main/java/com/gitblit/wicket/pages/RepositoryPage.html35
-rw-r--r--src/main/java/com/gitblit/wicket/pages/RepositoryPage.java20
-rw-r--r--src/main/java/com/gitblit/wicket/pages/RootPage.html2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/RootPage.java3
-rw-r--r--src/main/java/com/gitblit/wicket/pages/TicketPage.html3
-rw-r--r--src/main/java/com/gitblit/wicket/pages/TicketPage.java14
-rw-r--r--src/main/java/com/gitblit/wicket/pages/TicketsPage.html19
-rw-r--r--src/main/java/com/gitblit/wicket/pages/TicketsPage.java16
-rw-r--r--src/main/java/com/gitblit/wicket/pages/TreePage.java2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/UserPage.java12
-rw-r--r--src/main/java/com/gitblit/wicket/pages/scripts/imgdiff.js263
-rw-r--r--src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java12
-rw-r--r--src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html31
-rw-r--r--src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java35
-rw-r--r--src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.html20
-rw-r--r--src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java87
-rw-r--r--src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java4
-rw-r--r--src/main/java/com/gitblit/wicket/panels/TeamsPanel.html6
-rw-r--r--src/main/java/com/gitblit/wicket/panels/TeamsPanel.java1
-rw-r--r--src/main/java/com/gitblit/wicket/panels/TicketListPanel.html3
-rw-r--r--src/main/java/com/gitblit/wicket/panels/TicketListPanel.java10
132 files changed, 4453 insertions, 2475 deletions
diff --git a/src/main/java/com/gitblit/ConfigUserService.java b/src/main/java/com/gitblit/ConfigUserService.java
index d7d6c14f..200ec8a6 100644
--- a/src/main/java/com/gitblit/ConfigUserService.java
+++ b/src/main/java/com/gitblit/ConfigUserService.java
@@ -37,6 +37,7 @@ import org.slf4j.LoggerFactory;
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;
@@ -734,22 +735,22 @@ public class ConfigUserService implements IUserService {
// 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);
@@ -778,18 +779,18 @@ public class ConfigUserService implements IUserService {
// 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) {
@@ -911,10 +912,10 @@ public class ConfigUserService implements IUserService {
// 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) {
@@ -947,9 +948,9 @@ public class ConfigUserService implements IUserService {
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) {
diff --git a/src/main/java/com/gitblit/Constants.java b/src/main/java/com/gitblit/Constants.java
index fa8af25f..8b05f895 100644
--- a/src/main/java/com/gitblit/Constants.java
+++ b/src/main/java/com/gitblit/Constants.java
@@ -36,14 +36,19 @@ public class Constants {
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";
@@ -70,6 +75,8 @@ public class Constants {
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 String BORDER = "*****************************************************************";
@@ -148,6 +155,17 @@ public class Constants {
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) {
Class<?> clazz = Constants.class;
String className = clazz.getSimpleName() + ".class";
@@ -167,6 +185,19 @@ public class Constants {
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();
+ }
+ }
+
/**
* Enumeration representing the four access restriction levels.
*/
diff --git a/src/main/java/com/gitblit/DaggerModule.java b/src/main/java/com/gitblit/DaggerModule.java
deleted file mode 100644
index dd7e1b2b..00000000
--- a/src/main/java/com/gitblit/DaggerModule.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright 2013 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 javax.inject.Singleton;
-
-import com.gitblit.manager.AuthenticationManager;
-import com.gitblit.manager.FederationManager;
-import com.gitblit.manager.IAuthenticationManager;
-import com.gitblit.manager.IFederationManager;
-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.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.UserManager;
-import com.gitblit.transport.ssh.FileKeyManager;
-import com.gitblit.transport.ssh.IPublicKeyManager;
-import com.gitblit.transport.ssh.MemoryKeyManager;
-import com.gitblit.transport.ssh.NullKeyManager;
-import com.gitblit.utils.JSoupXssFilter;
-import com.gitblit.utils.StringUtils;
-import com.gitblit.utils.XssFilter;
-import com.gitblit.wicket.GitBlitWebApp;
-
-import dagger.Module;
-import dagger.Provides;
-
-/**
- * DaggerModule references all injectable objects.
- *
- * @author James Moger
- *
- */
-@Module(
- library = true,
- injects = {
- IStoredSettings.class,
- XssFilter.class,
-
- // core managers
- IRuntimeManager.class,
- IPluginManager.class,
- INotificationManager.class,
- IUserManager.class,
- IAuthenticationManager.class,
- IPublicKeyManager.class,
- IRepositoryManager.class,
- IProjectManager.class,
- IFederationManager.class,
-
- // the monolithic manager
- IGitblit.class,
-
- // the Gitblit Wicket app
- GitBlitWebApp.class
- }
-)
-public class DaggerModule {
-
- @Provides @Singleton IStoredSettings provideSettings() {
- return new FileSettings();
- }
-
- @Provides @Singleton XssFilter provideXssFilter() {
- return new JSoupXssFilter();
- }
-
- @Provides @Singleton IRuntimeManager provideRuntimeManager(IStoredSettings settings, XssFilter xssFilter) {
- return new RuntimeManager(settings, xssFilter);
- }
-
- @Provides @Singleton IPluginManager providePluginManager(IRuntimeManager runtimeManager) {
- return new PluginManager(runtimeManager);
- }
-
- @Provides @Singleton INotificationManager provideNotificationManager(IStoredSettings settings) {
- return new NotificationManager(settings);
- }
-
- @Provides @Singleton IUserManager provideUserManager(
- IRuntimeManager runtimeManager,
- IPluginManager pluginManager) {
-
- return new UserManager(runtimeManager, pluginManager);
- }
-
- @Provides @Singleton IAuthenticationManager provideAuthenticationManager(
- IRuntimeManager runtimeManager,
- IUserManager userManager) {
-
- return new AuthenticationManager(
- runtimeManager,
- userManager);
- }
-
- @Provides @Singleton IPublicKeyManager providePublicKeyManager(
- IStoredSettings settings,
- IRuntimeManager runtimeManager) {
-
- String clazz = settings.getString(Keys.git.sshKeysManager, FileKeyManager.class.getName());
- if (StringUtils.isEmpty(clazz)) {
- clazz = FileKeyManager.class.getName();
- }
- if (FileKeyManager.class.getName().equals(clazz)) {
- return new FileKeyManager(runtimeManager);
- } else if (NullKeyManager.class.getName().equals(clazz)) {
- return new NullKeyManager();
- } else if (MemoryKeyManager.class.getName().equals(clazz)) {
- return new MemoryKeyManager();
- } else {
- try {
- Class<?> mgrClass = Class.forName(clazz);
- return (IPublicKeyManager) mgrClass.newInstance();
- } catch (Exception e) {
-
- }
- return null;
- }
- }
-
- @Provides @Singleton IRepositoryManager provideRepositoryManager(
- IRuntimeManager runtimeManager,
- IPluginManager pluginManager,
- IUserManager userManager) {
-
- return new RepositoryManager(
- runtimeManager,
- pluginManager,
- userManager);
- }
-
- @Provides @Singleton IProjectManager provideProjectManager(
- IRuntimeManager runtimeManager,
- IUserManager userManager,
- IRepositoryManager repositoryManager) {
-
- return new ProjectManager(
- runtimeManager,
- userManager,
- repositoryManager);
- }
-
- @Provides @Singleton IFederationManager provideFederationManager(
- IRuntimeManager runtimeManager,
- INotificationManager notificationManager,
- IRepositoryManager repositoryManager) {
-
- return new FederationManager(
- runtimeManager,
- notificationManager,
- repositoryManager);
- }
-
- @Provides @Singleton IGitblit provideGitblit(
- IRuntimeManager runtimeManager,
- IPluginManager pluginManager,
- INotificationManager notificationManager,
- IUserManager userManager,
- IAuthenticationManager authenticationManager,
- IPublicKeyManager publicKeyManager,
- IRepositoryManager repositoryManager,
- IProjectManager projectManager,
- IFederationManager federationManager) {
-
- return new GitBlit(
- runtimeManager,
- pluginManager,
- notificationManager,
- userManager,
- authenticationManager,
- publicKeyManager,
- repositoryManager,
- projectManager,
- federationManager);
- }
-
- @Provides @Singleton GitBlitWebApp provideWebApplication(
- IRuntimeManager runtimeManager,
- IPluginManager pluginManager,
- INotificationManager notificationManager,
- IUserManager userManager,
- IAuthenticationManager authenticationManager,
- IPublicKeyManager publicKeyManager,
- IRepositoryManager repositoryManager,
- IProjectManager projectManager,
- IFederationManager federationManager,
- IGitblit gitblit) {
-
- return new GitBlitWebApp(
- runtimeManager,
- pluginManager,
- notificationManager,
- userManager,
- authenticationManager,
- publicKeyManager,
- repositoryManager,
- projectManager,
- federationManager,
- gitblit);
- }
-} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/FederationClient.java b/src/main/java/com/gitblit/FederationClient.java
index 079355ef..487080e5 100644
--- a/src/main/java/com/gitblit/FederationClient.java
+++ b/src/main/java/com/gitblit/FederationClient.java
@@ -1,192 +1,192 @@
-/*
- * 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);
+
+ 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) {
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/FileSettings.java b/src/main/java/com/gitblit/FileSettings.java
index 21a20435..3caf966b 100644
--- a/src/main/java/com/gitblit/FileSettings.java
+++ b/src/main/java/com/gitblit/FileSettings.java
@@ -18,10 +18,13 @@ package com.gitblit;
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
@@ -77,10 +80,14 @@ public class FileSettings extends IStoredSettings {
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();
properties.putAll(props);
@@ -103,12 +110,68 @@ public class FileSettings extends IStoredSettings {
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();
@@ -128,7 +191,7 @@ public class FileSettings extends IStoredSettings {
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)) {
diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java
index f9d9be9f..68a91bb5 100644
--- a/src/main/java/com/gitblit/GitBlit.java
+++ b/src/main/java/com/gitblit/GitBlit.java
@@ -15,471 +15,55 @@
*/
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.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) {
- 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);
- }
}
}
diff --git a/src/main/java/com/gitblit/GitBlitServer.java b/src/main/java/com/gitblit/GitBlitServer.java
index c79b1720..a1fd071f 100644
--- a/src/main/java/com/gitblit/GitBlitServer.java
+++ b/src/main/java/com/gitblit/GitBlitServer.java
@@ -217,22 +217,7 @@ public class GitBlitServer {
}
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");
diff --git a/src/main/java/com/gitblit/auth/AuthenticationProvider.java b/src/main/java/com/gitblit/auth/AuthenticationProvider.java
index 29051df8..da9a7af7 100644
--- a/src/main/java/com/gitblit/auth/AuthenticationProvider.java
+++ b/src/main/java/com/gitblit/auth/AuthenticationProvider.java
@@ -21,6 +21,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitblit.Constants.AccountType;
+import com.gitblit.Constants.Role;
import com.gitblit.IStoredSettings;
import com.gitblit.manager.IRuntimeManager;
import com.gitblit.manager.IUserManager;
@@ -138,6 +139,24 @@ public abstract class AuthenticationProvider {
*/
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() {
return getServiceName() + " (" + getClass().getName() + ")";
@@ -199,5 +218,16 @@ public abstract class AuthenticationProvider {
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;
+ }
+
}
}
diff --git a/src/main/java/com/gitblit/auth/HtpasswdAuthProvider.java b/src/main/java/com/gitblit/auth/HtpasswdAuthProvider.java
index 5ffb6930..2cdabf6f 100644
--- a/src/main/java/com/gitblit/auth/HtpasswdAuthProvider.java
+++ b/src/main/java/com/gitblit/auth/HtpasswdAuthProvider.java
@@ -32,8 +32,10 @@ import org.apache.commons.codec.digest.Md5Crypt;
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;
@@ -124,6 +126,16 @@ public class HtpasswdAuthProvider extends UsernamePasswordAuthenticationProvider
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.
*
diff --git a/src/main/java/com/gitblit/auth/LdapAuthProvider.java b/src/main/java/com/gitblit/auth/LdapAuthProvider.java
index 5690073a..cc772e7b 100644
--- a/src/main/java/com/gitblit/auth/LdapAuthProvider.java
+++ b/src/main/java/com/gitblit/auth/LdapAuthProvider.java
@@ -30,6 +30,7 @@ import java.util.concurrent.TimeUnit;
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;
@@ -272,7 +273,6 @@ public class LdapAuthProvider extends UsernamePasswordAuthenticationProvider {
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
@@ -286,6 +286,32 @@ public class LdapAuthProvider extends UsernamePasswordAuthenticationProvider {
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
public AccountType getAccountType() {
return AccountType.LDAP;
@@ -591,7 +617,8 @@ public class LdapAuthProvider extends UsernamePasswordAuthenticationProvider {
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.");
diff --git a/src/main/java/com/gitblit/auth/PAMAuthProvider.java b/src/main/java/com/gitblit/auth/PAMAuthProvider.java
index 5d441b84..46f4dd6a 100644
--- a/src/main/java/com/gitblit/auth/PAMAuthProvider.java
+++ b/src/main/java/com/gitblit/auth/PAMAuthProvider.java
@@ -23,8 +23,10 @@ import org.jvnet.libpam.impl.CLibrary;
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;
/**
@@ -77,6 +79,16 @@ public class PAMAuthProvider extends UsernamePasswordAuthenticationProvider {
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;
diff --git a/src/main/java/com/gitblit/auth/RedmineAuthProvider.java b/src/main/java/com/gitblit/auth/RedmineAuthProvider.java
index ae4f28ed..27cece29 100644
--- a/src/main/java/com/gitblit/auth/RedmineAuthProvider.java
+++ b/src/main/java/com/gitblit/auth/RedmineAuthProvider.java
@@ -23,8 +23,10 @@ import org.apache.commons.io.IOUtils;
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;
@@ -77,6 +79,16 @@ public class RedmineAuthProvider extends UsernamePasswordAuthenticationProvider
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() {
return AccountType.REDMINE;
@@ -154,7 +166,7 @@ public class RedmineAuthProvider extends UsernamePasswordAuthenticationProvider
url = url.concat("/");
}
String apiUrl = url + "users/current.json";
-
+
HttpURLConnection http;
if (username == null) {
// apikey authentication
diff --git a/src/main/java/com/gitblit/auth/SalesforceAuthProvider.java b/src/main/java/com/gitblit/auth/SalesforceAuthProvider.java
index e4273ff6..df033c27 100644
--- a/src/main/java/com/gitblit/auth/SalesforceAuthProvider.java
+++ b/src/main/java/com/gitblit/auth/SalesforceAuthProvider.java
@@ -2,8 +2,10 @@ package com.gitblit.auth;
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;
@@ -119,4 +121,15 @@ public class SalesforceAuthProvider extends UsernamePasswordAuthenticationProvid
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;
+ }
+
}
diff --git a/src/main/java/com/gitblit/auth/WindowsAuthProvider.java b/src/main/java/com/gitblit/auth/WindowsAuthProvider.java
index ac15b28f..aee51008 100644
--- a/src/main/java/com/gitblit/auth/WindowsAuthProvider.java
+++ b/src/main/java/com/gitblit/auth/WindowsAuthProvider.java
@@ -26,8 +26,10 @@ import waffle.windows.auth.impl.WindowsAuthProviderImpl;
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;
@@ -90,6 +92,16 @@ public class WindowsAuthProvider extends UsernamePasswordAuthenticationProvider
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;
diff --git a/src/main/java/com/gitblit/dagger/DaggerContext.java b/src/main/java/com/gitblit/dagger/DaggerContext.java
deleted file mode 100644
index 0e6a3fc4..00000000
--- a/src/main/java/com/gitblit/dagger/DaggerContext.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2013 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.dagger;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import dagger.ObjectGraph;
-
-/**
- * Dagger servlet context listener is a context listener that uses Dagger to
- * instantiate and inject servlets, filters, and anything else you might want.
- *
- * @author James Moger
- *
- */
-public abstract class DaggerContext implements ServletContextListener {
-
- public static final String INJECTOR_NAME = ObjectGraph.class.getName();
-
- protected final Logger logger = LoggerFactory.getLogger(getClass());
-
- protected abstract Object [] getModules();
-
- protected abstract void destroyContext(ServletContext context);
-
- protected ObjectGraph getInjector(ServletContext context) {
- Object o = context.getAttribute(INJECTOR_NAME);
- if (o == null) {
- logger.debug("instantiating Dagger modules");
- Object [] modules = getModules();
- logger.debug("getting Dagger injector");
- try {
- o = ObjectGraph.create(modules);
- logger.debug("setting Dagger injector into {} attribute", INJECTOR_NAME);
- context.setAttribute(INJECTOR_NAME, o);
- } catch (Throwable t) {
- logger.error("an error occurred creating the Dagger injector", t);
- }
- }
- return (ObjectGraph) o;
- }
-
- @Override
- public final void contextDestroyed(ServletContextEvent contextEvent) {
- ServletContext context = contextEvent.getServletContext();
- context.removeAttribute(INJECTOR_NAME);
- destroyContext(context);
- }
-}
diff --git a/src/main/java/com/gitblit/dagger/DaggerFilter.java b/src/main/java/com/gitblit/dagger/DaggerFilter.java
deleted file mode 100644
index 01c07a4a..00000000
--- a/src/main/java/com/gitblit/dagger/DaggerFilter.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2013 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.dagger;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-
-import dagger.ObjectGraph;
-
-/**
- * Uses Dagger to manually inject dependencies into a servlet filter.
- * This class is useful for servlet containers that offer CDI and are
- * confused by Dagger.
- *
- * @author James Moger
- *
- */
-public abstract class DaggerFilter implements Filter {
-
- @Override
- public final void init(FilterConfig filterConfig) throws ServletException {
- ServletContext context = filterConfig.getServletContext();
- ObjectGraph objectGraph = (ObjectGraph) context.getAttribute(DaggerContext.INJECTOR_NAME);
- inject(objectGraph, filterConfig);
- }
-
- protected abstract void inject(ObjectGraph dagger, FilterConfig filterConfig) throws ServletException;
-
- @Override
- public void destroy() {
- }
-}
diff --git a/src/main/java/com/gitblit/dagger/DaggerServlet.java b/src/main/java/com/gitblit/dagger/DaggerServlet.java
deleted file mode 100644
index 88331a43..00000000
--- a/src/main/java/com/gitblit/dagger/DaggerServlet.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2013 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.dagger;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-
-import dagger.ObjectGraph;
-
-/**
- * Uses Dagger to manually inject dependencies into a servlet.
- * This class is useful for servlet containers that offer CDI and are
- * confused by Dagger.
- *
- * @author James Moger
- *
- */
-public abstract class DaggerServlet extends HttpServlet {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- public final void init() throws ServletException {
- ServletContext context = getServletContext();
- ObjectGraph objectGraph = (ObjectGraph) context.getAttribute(DaggerContext.INJECTOR_NAME);
- inject(objectGraph);
- }
-
- protected abstract void inject(ObjectGraph dagger);
-}
diff --git a/src/main/java/com/gitblit/dagger/DaggerWicketFilter.java b/src/main/java/com/gitblit/dagger/DaggerWicketFilter.java
deleted file mode 100644
index c2fd4d67..00000000
--- a/src/main/java/com/gitblit/dagger/DaggerWicketFilter.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2013 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.dagger;
-
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-
-import org.apache.wicket.protocol.http.WicketFilter;
-
-import dagger.ObjectGraph;
-
-/**
- * Uses Dagger to manually inject dependencies into a Wicket filter.
- * This class is useful for servlet containers that offer CDI and are
- * confused by Dagger.
- *
- * @author James Moger
- *
- */
-public abstract class DaggerWicketFilter extends WicketFilter {
-
- @Override
- public final void init(FilterConfig filterConfig) throws ServletException {
- ServletContext context = filterConfig.getServletContext();
- ObjectGraph objectGraph = (ObjectGraph) context.getAttribute(DaggerContext.INJECTOR_NAME);
- inject(objectGraph);
- super.init(filterConfig);
- }
-
- protected abstract void inject(ObjectGraph dagger);
-}
diff --git a/src/main/java/com/gitblit/guice/CoreModule.java b/src/main/java/com/gitblit/guice/CoreModule.java
new file mode 100644
index 00000000..a942b2ec
--- /dev/null
+++ b/src/main/java/com/gitblit/guice/CoreModule.java
@@ -0,0 +1,82 @@
+/*
+ * 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.IAuthenticationManager;
+import com.gitblit.manager.IFederationManager;
+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);
+
+ // the monolithic manager
+ bind(IGitblit.class).to(GitBlit.class);
+
+ // manager for long-running daemons and services
+ bind(IServicesManager.class).to(ServicesManager.class);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/guice/IPublicKeyManagerProvider.java b/src/main/java/com/gitblit/guice/IPublicKeyManagerProvider.java
new file mode 100644
index 00000000..8075aa94
--- /dev/null
+++ b/src/main/java/com/gitblit/guice/IPublicKeyManagerProvider.java
@@ -0,0 +1,72 @@
+/*
+ * 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;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/guice/ITicketServiceProvider.java b/src/main/java/com/gitblit/guice/ITicketServiceProvider.java
new file mode 100644
index 00000000..fd39955d
--- /dev/null
+++ b/src/main/java/com/gitblit/guice/ITicketServiceProvider.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/guice/WebModule.java b/src/main/java/com/gitblit/guice/WebModule.java
new file mode 100644
index 00000000..5b569182
--- /dev/null
+++ b/src/main/java/com/gitblit/guice/WebModule.java
@@ -0,0 +1,105 @@
+/*
+ * 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.Constants;
+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.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() {
+ // servlets
+ 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);
+
+ // 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;
+ }
+}
diff --git a/src/main/java/com/gitblit/guice/WorkQueueProvider.java b/src/main/java/com/gitblit/guice/WorkQueueProvider.java
new file mode 100644
index 00000000..cde27ea9
--- /dev/null
+++ b/src/main/java/com/gitblit/guice/WorkQueueProvider.java
@@ -0,0 +1,57 @@
+/*
+ * 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;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/manager/AuthenticationManager.java b/src/main/java/com/gitblit/manager/AuthenticationManager.java
index f98f7b64..29221e6f 100644
--- a/src/main/java/com/gitblit/manager/AuthenticationManager.java
+++ b/src/main/java/com/gitblit/manager/AuthenticationManager.java
@@ -35,6 +35,7 @@ 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.IStoredSettings;
import com.gitblit.Keys;
import com.gitblit.auth.AuthenticationProvider;
@@ -52,6 +53,8 @@ import com.gitblit.utils.Base64;
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.
@@ -59,6 +62,7 @@ import com.gitblit.utils.X509Utils.X509Metadata;
* @author James Moger
*
*/
+@Singleton
public class AuthenticationManager implements IAuthenticationManager {
private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -75,6 +79,7 @@ public class AuthenticationManager implements IAuthenticationManager {
private final Map<String, String> legacyRedirects;
+ @Inject
public AuthenticationManager(
IRuntimeManager runtimeManager,
IUserManager userManager) {
@@ -576,6 +581,28 @@ public class AuthenticationManager implements IAuthenticationManager {
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)) {
diff --git a/src/main/java/com/gitblit/manager/FederationManager.java b/src/main/java/com/gitblit/manager/FederationManager.java
index 95d38af1..f009c1c8 100644
--- a/src/main/java/com/gitblit/manager/FederationManager.java
+++ b/src/main/java/com/gitblit/manager/FederationManager.java
@@ -45,6 +45,8 @@ import com.gitblit.utils.Base64;
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,
@@ -53,6 +55,7 @@ import com.gitblit.utils.StringUtils;
* @author James Moger
*
*/
+@Singleton
public class FederationManager implements IFederationManager {
private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -70,6 +73,7 @@ public class FederationManager implements IFederationManager {
private final IRepositoryManager repositoryManager;
+ @Inject
public FederationManager(
IRuntimeManager runtimeManager,
INotificationManager notificationManager,
diff --git a/src/main/java/com/gitblit/manager/GitblitManager.java b/src/main/java/com/gitblit/manager/GitblitManager.java
index 88fa804e..9692e654 100644
--- a/src/main/java/com/gitblit/manager/GitblitManager.java
+++ b/src/main/java/com/gitblit/manager/GitblitManager.java
@@ -49,12 +49,11 @@ import ro.fortsoft.pf4j.Version;
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.models.FederationModel;
import com.gitblit.models.FederationProposal;
import com.gitblit.models.FederationSet;
@@ -68,7 +67,6 @@ import com.gitblit.models.PluginRegistry.PluginRelease;
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;
@@ -79,7 +77,6 @@ import com.gitblit.tickets.ITicketService;
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;
@@ -88,6 +85,10 @@ import com.google.gson.Gson;
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
@@ -101,12 +102,17 @@ import com.google.gson.reflect.TypeToken;
* @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 IRuntimeManager runtimeManager;
@@ -119,32 +125,34 @@ public class GitblitManager implements IGitblit {
protected final IAuthenticationManager authenticationManager;
- protected final IPublicKeyManager publicKeyManager;
-
protected final IRepositoryManager repositoryManager;
protected final IProjectManager projectManager;
protected final IFederationManager federationManager;
+ @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) {
+ this.publicKeyManagerProvider = publicKeyManagerProvider;
+ this.ticketServiceProvider = ticketServiceProvider;
+
this.settings = runtimeManager.getSettings();
this.runtimeManager = runtimeManager;
this.pluginManager = pluginManager;
this.notificationManager = notificationManager;
this.userManager = userManager;
this.authenticationManager = authenticationManager;
- this.publicKeyManager = publicKeyManager;
this.repositoryManager = repositoryManager;
this.projectManager = projectManager;
this.federationManager = federationManager;
@@ -358,66 +366,6 @@ public class GitblitManager implements IGitblit {
}
/**
- * 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;
*
@@ -492,7 +440,7 @@ public class GitblitManager implements IGitblit {
// 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();
@@ -537,24 +485,20 @@ public class GitblitManager implements IGitblit {
}
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();
}
/*
@@ -605,26 +549,6 @@ public class GitblitManager implements IGitblit {
}
@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();
}
@@ -665,6 +589,11 @@ public class GitblitManager implements IGitblit {
}
@Override
+ public Injector getInjector() {
+ return runtimeManager.getInjector();
+ }
+
+ @Override
public XssFilter getXssFilter() {
return runtimeManager.getXssFilter();
}
@@ -782,6 +711,16 @@ public class GitblitManager implements IGitblit {
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
*/
@@ -806,11 +745,6 @@ public class GitblitManager implements IGitblit {
}
@Override
- public boolean deleteUser(String username) {
- return userManager.deleteUser(username);
- }
-
- @Override
public UserModel getUserModel(String username) {
return userManager.getUserModel(username);
}
@@ -851,8 +785,22 @@ public class GitblitManager implements IGitblit {
}
@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
@@ -1053,10 +1001,23 @@ public class GitblitManager implements IGitblit {
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
@@ -1069,14 +1030,23 @@ public class GitblitManager implements IGitblit {
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
diff --git a/src/main/java/com/gitblit/manager/IAuthenticationManager.java b/src/main/java/com/gitblit/manager/IAuthenticationManager.java
index 3600b325..d48ec534 100644
--- a/src/main/java/com/gitblit/manager/IAuthenticationManager.java
+++ b/src/main/java/com/gitblit/manager/IAuthenticationManager.java
@@ -18,6 +18,7 @@ package com.gitblit.manager;
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;
@@ -161,4 +162,22 @@ public interface IAuthenticationManager extends IManager {
*/
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);
+
} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/manager/IGitblit.java b/src/main/java/com/gitblit/manager/IGitblit.java
index 50ec8b1f..6c5b374c 100644
--- a/src/main/java/com/gitblit/manager/IGitblit.java
+++ b/src/main/java/com/gitblit/manager/IGitblit.java
@@ -16,14 +16,10 @@
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;
@@ -40,17 +36,6 @@ public interface IGitblit extends IManager,
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);
-
- /**
* Creates a complete user object.
*
* @param user
diff --git a/src/main/java/com/gitblit/manager/IRuntimeManager.java b/src/main/java/com/gitblit/manager/IRuntimeManager.java
index 132534c3..2203b7ff 100644
--- a/src/main/java/com/gitblit/manager/IRuntimeManager.java
+++ b/src/main/java/com/gitblit/manager/IRuntimeManager.java
@@ -25,9 +25,12 @@ import com.gitblit.IStoredSettings;
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);
File getBaseFolder();
@@ -49,42 +52,6 @@ public interface IRuntimeManager extends IManager {
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
*
* @return true if Gitblit is running in debug mode
diff --git a/src/main/java/com/gitblit/manager/IServicesManager.java b/src/main/java/com/gitblit/manager/IServicesManager.java
new file mode 100644
index 00000000..b3a973b3
--- /dev/null
+++ b/src/main/java/com/gitblit/manager/IServicesManager.java
@@ -0,0 +1,94 @@
+/*
+ * 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);
+
+} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/manager/NotificationManager.java b/src/main/java/com/gitblit/manager/NotificationManager.java
index 69a611bb..4bbc2abf 100644
--- a/src/main/java/com/gitblit/manager/NotificationManager.java
+++ b/src/main/java/com/gitblit/manager/NotificationManager.java
@@ -29,6 +29,8 @@ import com.gitblit.IStoredSettings;
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
@@ -38,6 +40,7 @@ import com.gitblit.service.MailService;
* @author James Moger
*
*/
+@Singleton
public class NotificationManager implements INotificationManager {
private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -48,6 +51,7 @@ public class NotificationManager implements INotificationManager {
private final MailService mailService;
+ @Inject
public NotificationManager(IStoredSettings settings) {
this.settings = settings;
this.mailService = new MailService(settings);
diff --git a/src/main/java/com/gitblit/manager/PluginManager.java b/src/main/java/com/gitblit/manager/PluginManager.java
index 5e25caa1..bc3be52f 100644
--- a/src/main/java/com/gitblit/manager/PluginManager.java
+++ b/src/main/java/com/gitblit/manager/PluginManager.java
@@ -22,6 +22,7 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
@@ -37,8 +38,12 @@ import java.util.TreeMap;
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;
@@ -58,6 +63,8 @@ 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.inject.Inject;
+import com.google.inject.Singleton;
/**
* The plugin manager maintains the lifecycle of plugins. It is exposed as
@@ -68,32 +75,23 @@ import com.google.common.io.InputSupplier;
* @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
@@ -108,6 +106,28 @@ public class PluginManager implements IPluginManager, PluginStateListener {
@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();
@@ -438,7 +458,7 @@ public class PluginManager implements IPluginManager, PluginStateListener {
}
- if (sha1File == null && md5File == null && verifyChecksum) {
+ if (sha1File == null && md5File == null) {
throw new IOException("Missing SHA1 and MD5 checksums for " + url);
}
@@ -567,10 +587,55 @@ public class PluginManager implements IPluginManager, PluginStateListener {
}
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;
+ }
}
}
diff --git a/src/main/java/com/gitblit/manager/ProjectManager.java b/src/main/java/com/gitblit/manager/ProjectManager.java
index 666f5210..ae46bdfc 100644
--- a/src/main/java/com/gitblit/manager/ProjectManager.java
+++ b/src/main/java/com/gitblit/manager/ProjectManager.java
@@ -41,6 +41,8 @@ import com.gitblit.utils.DeepCopier;
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.
@@ -48,6 +50,7 @@ import com.gitblit.utils.StringUtils;
* @author James Moger
*
*/
+@Singleton
public class ProjectManager implements IProjectManager {
private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -68,6 +71,7 @@ public class ProjectManager implements IProjectManager {
private FileBasedConfig projectConfigs;
+ @Inject
public ProjectManager(
IRuntimeManager runtimeManager,
IUserManager userManager,
diff --git a/src/main/java/com/gitblit/manager/RepositoryManager.java b/src/main/java/com/gitblit/manager/RepositoryManager.java
index 2db41323..c2c6088e 100644
--- a/src/main/java/com/gitblit/manager/RepositoryManager.java
+++ b/src/main/java/com/gitblit/manager/RepositoryManager.java
@@ -91,6 +91,8 @@ import com.gitblit.utils.ModelUtils;
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
@@ -99,6 +101,7 @@ import com.gitblit.utils.TimeUtils;
* @author James Moger
*
*/
+@Singleton
public class RepositoryManager implements IRepositoryManager {
private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -121,7 +124,7 @@ public class RepositoryManager implements IRepositoryManager {
private final IUserManager userManager;
- private final File repositoriesFolder;
+ private File repositoriesFolder;
private LuceneService luceneExecutor;
@@ -129,6 +132,7 @@ public class RepositoryManager implements IRepositoryManager {
private MirrorService mirrorExecutor;
+ @Inject
public RepositoryManager(
IRuntimeManager runtimeManager,
IPluginManager pluginManager,
@@ -138,11 +142,11 @@ public class RepositoryManager implements IRepositoryManager {
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
@@ -1967,21 +1971,19 @@ public class RepositoryManager implements IRepositoryManager {
}
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("");
}
}
}
diff --git a/src/main/java/com/gitblit/manager/RuntimeManager.java b/src/main/java/com/gitblit/manager/RuntimeManager.java
index 219bf801..18d6b9c2 100644
--- a/src/main/java/com/gitblit/manager/RuntimeManager.java
+++ b/src/main/java/com/gitblit/manager/RuntimeManager.java
@@ -33,7 +33,11 @@ import com.gitblit.models.ServerStatus;
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());
@@ -50,6 +54,10 @@ public class RuntimeManager implements IRuntimeManager {
private TimeZone timezone;
+ @Inject
+ private Injector injector;
+
+ @Inject
public RuntimeManager(IStoredSettings settings, XssFilter xssFilter) {
this(settings, xssFilter, null);
}
@@ -79,6 +87,11 @@ public class RuntimeManager implements IRuntimeManager {
}
@Override
+ public Injector getInjector() {
+ return injector;
+ }
+
+ @Override
public File getBaseFolder() {
return baseFolder;
}
@@ -116,52 +129,6 @@ public class RuntimeManager implements IRuntimeManager {
}
/**
- * 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;
- }
-
- /**
* Returns the preferred timezone for the Gitblit instance.
*
* @return a timezone
diff --git a/src/main/java/com/gitblit/manager/ServicesManager.java b/src/main/java/com/gitblit/manager/ServicesManager.java
index 437fd106..69e5e408 100644
--- a/src/main/java/com/gitblit/manager/ServicesManager.java
+++ b/src/main/java/com/gitblit/manager/ServicesManager.java
@@ -18,9 +18,15 @@ package com.gitblit.manager;
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;
@@ -30,9 +36,11 @@ import javax.servlet.http.HttpServletRequest;
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;
@@ -40,14 +48,18 @@ import com.gitblit.fanout.FanoutService;
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
@@ -57,32 +69,35 @@ import com.gitblit.utils.WorkQueue;
* @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 GitDaemon gitDaemon;
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
@@ -107,24 +122,194 @@ public class ServicesManager implements IManager {
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)) {
+ AccessPermission permission = user.getRepositoryPermission(repository).permission;
+ if (permission.exceeds(AccessPermission.NONE)) {
+ Transport transport = Transport.fromString(request.getScheme());
+ 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(getRepositoryUrl(request, username, repository), permission));
+ }
+ }
+
+ // ssh daemon url
+ String sshDaemonUrl = getSshDaemonUrl(request, user, repository);
+ if (!StringUtils.isEmpty(sshDaemonUrl)) {
+ 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)) {
+ 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
+ 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;
+ }
+
+ /* (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();
}
@@ -158,6 +343,33 @@ public class ServicesManager implements IManager {
}
}
+ @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");
@@ -179,7 +391,7 @@ public class ServicesManager implements IManager {
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;
@@ -285,7 +497,7 @@ public class ServicesManager implements IManager {
*/
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);
diff --git a/src/main/java/com/gitblit/manager/UserManager.java b/src/main/java/com/gitblit/manager/UserManager.java
index 2b82ffb6..86be8bcd 100644
--- a/src/main/java/com/gitblit/manager/UserManager.java
+++ b/src/main/java/com/gitblit/manager/UserManager.java
@@ -36,6 +36,8 @@ import com.gitblit.extensions.UserTeamLifeCycleListener;
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.
@@ -43,6 +45,7 @@ import com.gitblit.utils.StringUtils;
* @author James Moger
*
*/
+@Singleton
public class UserManager implements IUserManager {
private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -57,6 +60,7 @@ public class UserManager implements IUserManager {
private IUserService userService;
+ @Inject
public UserManager(IRuntimeManager runtimeManager, IPluginManager pluginManager) {
this.settings = runtimeManager.getSettings();
this.runtimeManager = runtimeManager;
diff --git a/src/main/java/com/gitblit/models/TicketModel.java b/src/main/java/com/gitblit/models/TicketModel.java
index a4880ead..fd0b09eb 100644
--- a/src/main/java/com/gitblit/models/TicketModel.java
+++ b/src/main/java/com/gitblit/models/TicketModel.java
@@ -91,6 +91,10 @@ public class TicketModel implements Serializable, Comparable<TicketModel> {
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
@@ -141,6 +145,8 @@ public class TicketModel implements Serializable, Comparable<TicketModel> {
changes = new ArrayList<Change>();
status = Status.New;
type = Type.defaultType;
+ priority = Priority.defaultPriority;
+ severity = Severity.defaultSeverity;
}
public boolean isOpen() {
@@ -517,6 +523,12 @@ public class TicketModel implements Serializable, Comparable<TicketModel> {
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
break;
@@ -1183,16 +1195,16 @@ public class TicketModel implements Serializable, Comparable<TicketModel> {
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
@@ -1310,4 +1322,110 @@ public class TicketModel implements Serializable, Comparable<TicketModel> {
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;
+ }
+ }
}
diff --git a/src/main/java/com/gitblit/service/LuceneService.java b/src/main/java/com/gitblit/service/LuceneService.java
index 482be5c6..3f7635f4 100644
--- a/src/main/java/com/gitblit/service/LuceneService.java
+++ b/src/main/java/com/gitblit/service/LuceneService.java
@@ -105,7 +105,7 @@ import com.gitblit.utils.StringUtils;
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";
@@ -125,7 +125,7 @@ public class LuceneService implements Runnable {
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);
diff --git a/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java b/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java
index 7f691196..ee4a91aa 100644
--- a/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java
+++ b/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java
@@ -19,21 +19,19 @@ import java.io.IOException;
import java.text.MessageFormat;
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
* requested repository can be accessed by the anonymous or named user.
@@ -54,11 +52,15 @@ public abstract class AccessRestrictionFilter extends AuthenticationFilter {
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;
}
/**
diff --git a/src/main/java/com/gitblit/servlet/AuthenticationFilter.java b/src/main/java/com/gitblit/servlet/AuthenticationFilter.java
index c21f8692..3093e635 100644
--- a/src/main/java/com/gitblit/servlet/AuthenticationFilter.java
+++ b/src/main/java/com/gitblit/servlet/AuthenticationFilter.java
@@ -1,184 +1,190 @@
-/*
- * 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;
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/servlet/BranchGraphServlet.java b/src/main/java/com/gitblit/servlet/BranchGraphServlet.java
index fa2152c6..85fbb745 100644
--- a/src/main/java/com/gitblit/servlet/BranchGraphServlet.java
+++ b/src/main/java/com/gitblit/servlet/BranchGraphServlet.java
@@ -36,7 +36,10 @@ import java.util.Set;
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;
@@ -55,20 +58,18 @@ import org.slf4j.LoggerFactory;
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;
@@ -87,20 +88,20 @@ public class BranchGraphServlet extends DaggerServlet {
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);
- }
-
/**
* Returns an url to this servlet for the specified parameters.
*
diff --git a/src/main/java/com/gitblit/servlet/DownloadZipFilter.java b/src/main/java/com/gitblit/servlet/DownloadZipFilter.java
index 42257a23..de471482 100644
--- a/src/main/java/com/gitblit/servlet/DownloadZipFilter.java
+++ b/src/main/java/com/gitblit/servlet/DownloadZipFilter.java
@@ -15,7 +15,13 @@
*/
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;
@@ -27,8 +33,18 @@ 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.
*
diff --git a/src/main/java/com/gitblit/servlet/DownloadZipServlet.java b/src/main/java/com/gitblit/servlet/DownloadZipServlet.java
index 6a64778c..07562561 100644
--- a/src/main/java/com/gitblit/servlet/DownloadZipServlet.java
+++ b/src/main/java/com/gitblit/servlet/DownloadZipServlet.java
@@ -20,7 +20,10 @@ import java.text.MessageFormat;
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;
@@ -31,15 +34,12 @@ import org.slf4j.LoggerFactory;
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.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
* revision.
@@ -47,7 +47,8 @@ import dagger.ObjectGraph;
* @author James Moger
*
*/
-public class DownloadZipServlet extends DaggerServlet {
+@Singleton
+public class DownloadZipServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@@ -76,10 +77,10 @@ public class DownloadZipServlet extends DaggerServlet {
}
}
- @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) {
+ this.settings = settings;
+ this.repositoryManager = repositoryManager;
}
/**
diff --git a/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java b/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java
index c015021d..8a3f782a 100644
--- a/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java
+++ b/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java
@@ -18,6 +18,9 @@
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;
@@ -31,12 +34,9 @@ import org.slf4j.LoggerFactory;
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.
* It looks at the settings "web.authenticateViewPages" and "web.enforceHttpBasicAuthentication"; if
@@ -45,7 +45,8 @@ import dagger.ObjectGraph;
* @author Laurens Vrijnsen
*
*/
-public class EnforceAuthenticationFilter extends DaggerFilter {
+@Singleton
+public class EnforceAuthenticationFilter implements Filter {
protected transient Logger logger = LoggerFactory.getLogger(getClass());
@@ -53,10 +54,21 @@ public class EnforceAuthenticationFilter extends DaggerFilter {
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() {
}
/*
@@ -87,12 +99,4 @@ public class EnforceAuthenticationFilter extends DaggerFilter {
chain.doFilter(request, response);
}
}
-
-
- /*
- * @see javax.servlet.Filter#destroy()
- */
- @Override
- public void destroy() {
- }
}
diff --git a/src/main/java/com/gitblit/servlet/FederationServlet.java b/src/main/java/com/gitblit/servlet/FederationServlet.java
index acbc0021..78709c9c 100644
--- a/src/main/java/com/gitblit/servlet/FederationServlet.java
+++ b/src/main/java/com/gitblit/servlet/FederationServlet.java
@@ -25,6 +25,8 @@ import java.util.List;
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;
@@ -43,14 +45,13 @@ import com.gitblit.utils.HttpUtils;
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;
@@ -63,12 +64,17 @@ public class FederationServlet extends JsonServlet {
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;
}
/**
diff --git a/src/main/java/com/gitblit/servlet/GitFilter.java b/src/main/java/com/gitblit/servlet/GitFilter.java
index bb3d3216..b29fdb6a 100644
--- a/src/main/java/com/gitblit/servlet/GitFilter.java
+++ b/src/main/java/com/gitblit/servlet/GitFilter.java
@@ -17,7 +17,8 @@ package com.gitblit.servlet;
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;
@@ -25,13 +26,14 @@ import com.gitblit.Constants.AuthorizationControl;
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
* requests for push, clone, or view restricted repositories are authenticated
@@ -40,6 +42,7 @@ import dagger.ObjectGraph;
* @author James Moger
*
*/
+@Singleton
public class GitFilter extends AccessRestrictionFilter {
protected static final String gitReceivePack = "/git-receive-pack";
@@ -53,11 +56,18 @@ public class GitFilter extends AccessRestrictionFilter {
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;
}
/**
diff --git a/src/main/java/com/gitblit/servlet/GitServlet.java b/src/main/java/com/gitblit/servlet/GitServlet.java
index 93fe31d0..941b4c5e 100644
--- a/src/main/java/com/gitblit/servlet/GitServlet.java
+++ b/src/main/java/com/gitblit/servlet/GitServlet.java
@@ -20,6 +20,8 @@ import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
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;
@@ -33,14 +35,11 @@ import javax.servlet.http.HttpServletResponse;
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.
* Access to this servlet is protected by the GitFilter.
@@ -48,24 +47,23 @@ import dagger.ObjectGraph;
* @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
diff --git a/src/main/java/com/gitblit/servlet/GitblitContext.java b/src/main/java/com/gitblit/servlet/GitblitContext.java
index e5c59bd0..077624c2 100644
--- a/src/main/java/com/gitblit/servlet/GitblitContext.java
+++ b/src/main/java/com/gitblit/servlet/GitblitContext.java
@@ -31,14 +31,17 @@ import javax.naming.NamingException;
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.IGitblit;
@@ -48,28 +51,34 @@ 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.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>();
private final IStoredSettings goSettings;
@@ -111,12 +120,16 @@ public class GitblitContext extends DaggerContext {
return null;
}
+ @Override
+ protected Injector getInjector() {
+ return Guice.createInjector(getModules());
+ }
+
/**
- * Returns Gitblit's Dagger injection modules.
+ * Returns Gitblit's Guice injection modules.
*/
- @Override
- protected Object [] getModules() {
- return new Object [] { new DaggerModule() };
+ protected AbstractModule [] getModules() {
+ return new AbstractModule [] { new CoreModule(), new WebModule() };
}
/**
@@ -127,18 +140,20 @@ public class GitblitContext extends DaggerContext {
*/
@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) {
@@ -168,7 +183,7 @@ public class GitblitContext extends DaggerContext {
// 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();
@@ -186,7 +201,9 @@ public class GitblitContext extends DaggerContext {
startManager(injector, IRepositoryManager.class);
startManager(injector, IProjectManager.class);
startManager(injector, IFederationManager.class);
+ startManager(injector, ITicketService.class);
startManager(injector, IGitblit.class);
+ startManager(injector, IServicesManager.class);
// start the plugin manager last so that plugins can depend on
// deterministic access to all other managers in their start() methods
@@ -196,7 +213,7 @@ public class GitblitContext extends DaggerContext {
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();
@@ -236,17 +253,21 @@ public class GitblitContext extends DaggerContext {
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) {
@@ -254,11 +275,17 @@ public class GitblitContext extends DaggerContext {
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.");
@@ -341,12 +368,10 @@ public class GitblitContext extends DaggerContext {
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
diff --git a/src/main/java/com/gitblit/servlet/JsonServlet.java b/src/main/java/com/gitblit/servlet/JsonServlet.java
index 4378c8a6..abc0f292 100644
--- a/src/main/java/com/gitblit/servlet/JsonServlet.java
+++ b/src/main/java/com/gitblit/servlet/JsonServlet.java
@@ -21,6 +21,7 @@ import java.lang.reflect.Type;
import java.text.MessageFormat;
import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -28,7 +29,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitblit.Constants;
-import com.gitblit.dagger.DaggerServlet;
import com.gitblit.utils.JsonUtils;
import com.gitblit.utils.StringUtils;
@@ -38,7 +38,7 @@ 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;
diff --git a/src/main/java/com/gitblit/servlet/LogoServlet.java b/src/main/java/com/gitblit/servlet/LogoServlet.java
index 96f34afd..d5d298b1 100644
--- a/src/main/java/com/gitblit/servlet/LogoServlet.java
+++ b/src/main/java/com/gitblit/servlet/LogoServlet.java
@@ -21,24 +21,25 @@ import java.io.IOException;
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;
@@ -46,9 +47,9 @@ public class LogoServlet extends DaggerServlet {
private IRuntimeManager runtimeManager;
- @Override
- protected void inject(ObjectGraph dagger) {
- this.runtimeManager = dagger.get(IRuntimeManager.class);
+ @Inject
+ public LogoServlet(IRuntimeManager runtimeManager) {
+ this.runtimeManager = runtimeManager;
}
@Override
diff --git a/src/main/java/com/gitblit/servlet/PagesFilter.java b/src/main/java/com/gitblit/servlet/PagesFilter.java
index e07d9b3b..1d6c3db9 100644
--- a/src/main/java/com/gitblit/servlet/PagesFilter.java
+++ b/src/main/java/com/gitblit/servlet/PagesFilter.java
@@ -15,6 +15,13 @@
*/
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
@@ -23,7 +30,17 @@ package com.gitblit.servlet;
* @author James Moger
*
*/
+
+@Singleton
public class PagesFilter extends RawFilter {
+ @Inject
+ public PagesFilter(
+ IRuntimeManager runtimeManager,
+ IAuthenticationManager authenticationManager,
+ IRepositoryManager repositoryManager) {
+
+ super(runtimeManager, authenticationManager, repositoryManager);
+ }
}
diff --git a/src/main/java/com/gitblit/servlet/PagesServlet.java b/src/main/java/com/gitblit/servlet/PagesServlet.java
index defd9e63..1473e966 100644
--- a/src/main/java/com/gitblit/servlet/PagesServlet.java
+++ b/src/main/java/com/gitblit/servlet/PagesServlet.java
@@ -1,103 +1,116 @@
-/*
- * 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);
+ }
+}
diff --git a/src/main/java/com/gitblit/servlet/ProxyFilter.java b/src/main/java/com/gitblit/servlet/ProxyFilter.java
index 46f59de9..d7f096ac 100644
--- a/src/main/java/com/gitblit/servlet/ProxyFilter.java
+++ b/src/main/java/com/gitblit/servlet/ProxyFilter.java
@@ -16,9 +16,13 @@
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;
@@ -27,13 +31,10 @@ import javax.servlet.ServletResponse;
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
* request data. The intended purpose is for server monitoring plugins.
@@ -41,15 +42,29 @@ import dagger.ObjectGraph;
* @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());
diff --git a/src/main/java/com/gitblit/servlet/PtServlet.java b/src/main/java/com/gitblit/servlet/PtServlet.java
index f69b444d..5f577f85 100644
--- a/src/main/java/com/gitblit/servlet/PtServlet.java
+++ b/src/main/java/com/gitblit/servlet/PtServlet.java
@@ -22,7 +22,10 @@ import java.io.IOException;
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;
@@ -34,11 +37,8 @@ import org.apache.commons.compress.compressors.CompressorOutputStream;
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).
*
@@ -47,7 +47,8 @@ import dagger.ObjectGraph;
* @author James Moger
*
*/
-public class PtServlet extends DaggerServlet {
+@Singleton
+public class PtServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@@ -55,9 +56,9 @@ public class PtServlet extends DaggerServlet {
private IRuntimeManager runtimeManager;
- @Override
- protected void inject(ObjectGraph dagger) {
- this.runtimeManager = dagger.get(IRuntimeManager.class);
+ @Inject
+ public PtServlet(IRuntimeManager runtimeManager) {
+ this.runtimeManager = runtimeManager;
}
@Override
diff --git a/src/main/java/com/gitblit/servlet/RawFilter.java b/src/main/java/com/gitblit/servlet/RawFilter.java
index 34989c98..fe4af040 100644
--- a/src/main/java/com/gitblit/servlet/RawFilter.java
+++ b/src/main/java/com/gitblit/servlet/RawFilter.java
@@ -15,9 +15,15 @@
*/
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;
@@ -28,8 +34,18 @@ 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.
*
diff --git a/src/main/java/com/gitblit/servlet/RawServlet.java b/src/main/java/com/gitblit/servlet/RawServlet.java
index ca41d0ab..16d1a977 100644
--- a/src/main/java/com/gitblit/servlet/RawServlet.java
+++ b/src/main/java/com/gitblit/servlet/RawServlet.java
@@ -30,6 +30,7 @@ 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;
@@ -48,7 +49,6 @@ import org.slf4j.LoggerFactory;
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;
@@ -56,8 +56,8 @@ import com.gitblit.utils.ByteFormat;
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.
@@ -65,20 +65,24 @@ import dagger.ObjectGraph;
* @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;
}
/**
@@ -230,9 +234,18 @@ public class RawServlet extends DaggerServlet {
// 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 contentType;
+
+ List<String> exts = runtimeManager.getSettings().getStrings(Keys.web.prettyPrintExtensions);
+ String ext = StringUtils.getFileExtension(file).toLowerCase();
+ 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
@@ -244,7 +257,7 @@ public class RawServlet extends DaggerServlet {
}
}
- 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]);
@@ -378,6 +391,13 @@ public class RawServlet extends DaggerServlet {
return false;
}
+ protected boolean isTextDataType(String contentType) {
+ if ("image/svg+xml".equals(contentType)) {
+ return true;
+ }
+ return false;
+ }
+
/**
* Override all text types to be plain text.
*
diff --git a/src/main/java/com/gitblit/servlet/RobotsTxtServlet.java b/src/main/java/com/gitblit/servlet/RobotsTxtServlet.java
index 9bd3b3c3..4e58d4de 100644
--- a/src/main/java/com/gitblit/servlet/RobotsTxtServlet.java
+++ b/src/main/java/com/gitblit/servlet/RobotsTxtServlet.java
@@ -18,32 +18,33 @@ package com.gitblit.servlet;
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
diff --git a/src/main/java/com/gitblit/servlet/RpcFilter.java b/src/main/java/com/gitblit/servlet/RpcFilter.java
index 23bf956e..34474d55 100644
--- a/src/main/java/com/gitblit/servlet/RpcFilter.java
+++ b/src/main/java/com/gitblit/servlet/RpcFilter.java
@@ -18,8 +18,9 @@ package com.gitblit.servlet;
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;
@@ -29,11 +30,10 @@ import javax.servlet.http.HttpServletResponse;
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.
*
@@ -47,17 +47,23 @@ import dagger.ObjectGraph;
* @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;
}
/**
diff --git a/src/main/java/com/gitblit/servlet/RpcServlet.java b/src/main/java/com/gitblit/servlet/RpcServlet.java
index b8cdfb04..9809a252 100644
--- a/src/main/java/com/gitblit/servlet/RpcServlet.java
+++ b/src/main/java/com/gitblit/servlet/RpcServlet.java
@@ -23,6 +23,8 @@ import java.util.HashMap;
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;
@@ -47,13 +49,12 @@ import com.gitblit.utils.JGitUtils;
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;
@@ -64,10 +65,10 @@ public class RpcServlet extends JsonServlet {
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;
}
/**
diff --git a/src/main/java/com/gitblit/servlet/SparkleShareInviteServlet.java b/src/main/java/com/gitblit/servlet/SparkleShareInviteServlet.java
index 150dd68a..69c254cb 100644
--- a/src/main/java/com/gitblit/servlet/SparkleShareInviteServlet.java
+++ b/src/main/java/com/gitblit/servlet/SparkleShareInviteServlet.java
@@ -19,13 +19,15 @@ import java.io.IOException;
import java.net.URL;
import java.text.MessageFormat;
+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.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;
@@ -33,15 +35,14 @@ import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.StringUtils;
-import dagger.ObjectGraph;
-
/**
* 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;
@@ -53,12 +54,17 @@ public class SparkleShareInviteServlet extends DaggerServlet {
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
diff --git a/src/main/java/com/gitblit/servlet/SyndicationFilter.java b/src/main/java/com/gitblit/servlet/SyndicationFilter.java
index 78da47e9..49348d0d 100644
--- a/src/main/java/com/gitblit/servlet/SyndicationFilter.java
+++ b/src/main/java/com/gitblit/servlet/SyndicationFilter.java
@@ -18,8 +18,9 @@ package com.gitblit.servlet;
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;
@@ -27,6 +28,7 @@ import javax.servlet.http.HttpServletRequest;
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;
@@ -34,8 +36,6 @@ 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
* requests for projects or view-restricted repositories have proper authentication
@@ -44,18 +44,24 @@ import dagger.ObjectGraph;
* @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;
}
/**
diff --git a/src/main/java/com/gitblit/servlet/SyndicationServlet.java b/src/main/java/com/gitblit/servlet/SyndicationServlet.java
index e3c25967..c6343d9f 100644
--- a/src/main/java/com/gitblit/servlet/SyndicationServlet.java
+++ b/src/main/java/com/gitblit/servlet/SyndicationServlet.java
@@ -22,6 +22,10 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import javax.servlet.http.HttpServlet;
+
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -31,7 +35,6 @@ import org.slf4j.LoggerFactory;
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;
@@ -46,8 +49,6 @@ import com.gitblit.utils.JGitUtils;
import com.gitblit.utils.StringUtils;
import com.gitblit.utils.SyndicationUtils;
-import dagger.ObjectGraph;
-
/**
* SyndicationServlet generates RSS 2.0 feeds and feed links.
*
@@ -56,7 +57,8 @@ import dagger.ObjectGraph;
* @author James Moger
*
*/
-public class SyndicationServlet extends DaggerServlet {
+@Singleton
+public class SyndicationServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@@ -68,11 +70,15 @@ public class SyndicationServlet extends DaggerServlet {
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;
}
/**
diff --git a/src/main/java/com/gitblit/tickets/BranchTicketService.java b/src/main/java/com/gitblit/tickets/BranchTicketService.java
index 5a42c6a7..42189bfd 100644
--- a/src/main/java/com/gitblit/tickets/BranchTicketService.java
+++ b/src/main/java/com/gitblit/tickets/BranchTicketService.java
@@ -72,6 +72,8 @@ import com.gitblit.models.TicketModel.Change;
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
@@ -81,6 +83,7 @@ import com.gitblit.utils.StringUtils;
* @author James Moger
*
*/
+@Singleton
public class BranchTicketService extends ITicketService implements RefsChangedListener {
public static final String BRANCH = "refs/meta/gitblit/tickets";
@@ -91,6 +94,7 @@ public class BranchTicketService extends ITicketService implements RefsChangedLi
private final Map<String, AtomicLong> lastAssignedId;
+ @Inject
public BranchTicketService(
IRuntimeManager runtimeManager,
IPluginManager pluginManager,
@@ -112,6 +116,7 @@ public class BranchTicketService extends ITicketService implements RefsChangedLi
@Override
public BranchTicketService start() {
+ log.info("{} started", getClass().getSimpleName());
return this;
}
diff --git a/src/main/java/com/gitblit/tickets/FileTicketService.java b/src/main/java/com/gitblit/tickets/FileTicketService.java
index b3d8838e..1e82f0de 100644
--- a/src/main/java/com/gitblit/tickets/FileTicketService.java
+++ b/src/main/java/com/gitblit/tickets/FileTicketService.java
@@ -42,6 +42,8 @@ import com.gitblit.models.TicketModel.Change;
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.
@@ -51,6 +53,7 @@ import com.gitblit.utils.StringUtils;
* @author James Moger
*
*/
+@Singleton
public class FileTicketService extends ITicketService {
private static final String JOURNAL = "journal.json";
@@ -59,6 +62,7 @@ public class FileTicketService extends ITicketService {
private final Map<String, AtomicLong> lastAssignedId;
+ @Inject
public FileTicketService(
IRuntimeManager runtimeManager,
IPluginManager pluginManager,
@@ -77,6 +81,7 @@ public class FileTicketService extends ITicketService {
@Override
public FileTicketService start() {
+ log.info("{} started", getClass().getSimpleName());
return this;
}
@@ -488,6 +493,10 @@ public class FileTicketService extends ITicketService {
@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);
diff --git a/src/main/java/com/gitblit/tickets/ITicketService.java b/src/main/java/com/gitblit/tickets/ITicketService.java
index 4cf099ff..5e3e372a 100644
--- a/src/main/java/com/gitblit/tickets/ITicketService.java
+++ b/src/main/java/com/gitblit/tickets/ITicketService.java
@@ -36,6 +36,7 @@ import org.slf4j.LoggerFactory;
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;
@@ -63,7 +64,7 @@ import com.google.common.cache.CacheBuilder;
* @author James Moger
*
*/
-public abstract class ITicketService {
+public abstract class ITicketService implements IManager {
public static final String SETTING_UPDATE_DIFFSTATS = "migration.updateDiffstats";
@@ -176,12 +177,14 @@ public abstract class ITicketService {
* 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();
diff --git a/src/main/java/com/gitblit/tickets/NullTicketService.java b/src/main/java/com/gitblit/tickets/NullTicketService.java
index d410cdd0..3947b945 100644
--- a/src/main/java/com/gitblit/tickets/NullTicketService.java
+++ b/src/main/java/com/gitblit/tickets/NullTicketService.java
@@ -28,6 +28,8 @@ import com.gitblit.models.RepositoryModel;
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.
@@ -35,8 +37,10 @@ import com.gitblit.models.TicketModel.Change;
* @author James Moger
*
*/
+@Singleton
public class NullTicketService extends ITicketService {
+ @Inject
public NullTicketService(
IRuntimeManager runtimeManager,
IPluginManager pluginManager,
@@ -58,6 +62,7 @@ public class NullTicketService extends ITicketService {
@Override
public NullTicketService start() {
+ log.info("{} started", getClass().getSimpleName());
return this;
}
diff --git a/src/main/java/com/gitblit/tickets/QueryResult.java b/src/main/java/com/gitblit/tickets/QueryResult.java
index 7a2b1abe..f8d6d123 100644
--- a/src/main/java/com/gitblit/tickets/QueryResult.java
+++ b/src/main/java/com/gitblit/tickets/QueryResult.java
@@ -24,6 +24,8 @@ import java.util.List;
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;
/**
@@ -62,6 +64,8 @@ public class QueryResult implements Serializable {
public int commentsCount;
public int votesCount;
public int approvalsCount;
+ public Priority priority;
+ public Severity severity;
public int docId;
public int totalResults;
diff --git a/src/main/java/com/gitblit/tickets/RedisTicketService.java b/src/main/java/com/gitblit/tickets/RedisTicketService.java
index d773b0bd..0f9ad174 100644
--- a/src/main/java/com/gitblit/tickets/RedisTicketService.java
+++ b/src/main/java/com/gitblit/tickets/RedisTicketService.java
@@ -43,6 +43,8 @@ import com.gitblit.models.TicketModel.Attachment;
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
@@ -53,6 +55,7 @@ import com.gitblit.utils.StringUtils;
* @author James Moger
*
*/
+@Singleton
public class RedisTicketService extends ITicketService {
private final JedisPool pool;
@@ -61,6 +64,7 @@ public class RedisTicketService extends ITicketService {
journal, ticket, counter
}
+ @Inject
public RedisTicketService(
IRuntimeManager runtimeManager,
IPluginManager pluginManager,
@@ -80,6 +84,10 @@ public class RedisTicketService extends ITicketService {
@Override
public RedisTicketService start() {
+ log.info("{} started", getClass().getSimpleName());
+ if (!isReady()) {
+ log.warn("{} is not ready!", getClass().getSimpleName());
+ }
return this;
}
diff --git a/src/main/java/com/gitblit/tickets/TicketIndexer.java b/src/main/java/com/gitblit/tickets/TicketIndexer.java
index 11ea3a73..e2d53af7 100644
--- a/src/main/java/com/gitblit/tickets/TicketIndexer.java
+++ b/src/main/java/com/gitblit/tickets/TicketIndexer.java
@@ -103,7 +103,10 @@ public class TicketIndexer {
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;
@@ -519,6 +522,8 @@ public class TicketIndexer {
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()) {
@@ -600,6 +605,8 @@ public class TicketIndexer {
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
diff --git a/src/main/java/com/gitblit/tickets/TicketNotifier.java b/src/main/java/com/gitblit/tickets/TicketNotifier.java
index d6217b35..5979cf26 100644
--- a/src/main/java/com/gitblit/tickets/TicketNotifier.java
+++ b/src/main/java/com/gitblit/tickets/TicketNotifier.java
@@ -135,6 +135,7 @@ public class TicketNotifier {
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));
@@ -613,6 +614,12 @@ public class TicketNotifier {
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;
diff --git a/src/main/java/com/gitblit/tickets/viewTicket.html b/src/main/java/com/gitblit/tickets/viewTicket.html
new file mode 100644
index 00000000..54e091ca
--- /dev/null
+++ b/src/main/java/com/gitblit/tickets/viewTicket.html
@@ -0,0 +1,12 @@
+<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>
diff --git a/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java b/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java
index a063dc7d..1a2cd682 100644
--- a/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java
+++ b/src/main/java/com/gitblit/transport/ssh/FileKeyManager.java
@@ -29,6 +29,7 @@ import com.gitblit.manager.IRuntimeManager;
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.
@@ -42,6 +43,7 @@ public class FileKeyManager extends IPublicKeyManager {
protected final Map<File, Long> lastModifieds;
+ @Inject
public FileKeyManager(IRuntimeManager runtimeManager) {
this.runtimeManager = runtimeManager;
this.lastModifieds = new ConcurrentHashMap<File, Long>();
diff --git a/src/main/java/com/gitblit/transport/ssh/MemoryKeyManager.java b/src/main/java/com/gitblit/transport/ssh/MemoryKeyManager.java
index 357b34a2..bf783786 100644
--- a/src/main/java/com/gitblit/transport/ssh/MemoryKeyManager.java
+++ b/src/main/java/com/gitblit/transport/ssh/MemoryKeyManager.java
@@ -20,6 +20,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import com.google.inject.Inject;
+
/**
* Memory public key manager.
*
@@ -30,6 +32,7 @@ public class MemoryKeyManager extends IPublicKeyManager {
final Map<String, List<SshKey>> keys;
+ @Inject
public MemoryKeyManager() {
keys = new HashMap<String, List<SshKey>>();
}
diff --git a/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java b/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java
index 0761d842..fcd3e197 100644
--- a/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java
+++ b/src/main/java/com/gitblit/transport/ssh/NullKeyManager.java
@@ -17,6 +17,8 @@ package com.gitblit.transport.ssh;
import java.util.List;
+import com.google.inject.Inject;
+
/**
* Rejects all public key management requests.
*
@@ -25,6 +27,7 @@ import java.util.List;
*/
public class NullKeyManager extends IPublicKeyManager {
+ @Inject
public NullKeyManager() {
}
diff --git a/src/main/java/com/gitblit/transport/ssh/SshDaemon.java b/src/main/java/com/gitblit/transport/ssh/SshDaemon.java
index 6bcc0390..9667154f 100644
--- a/src/main/java/com/gitblit/transport/ssh/SshDaemon.java
+++ b/src/main/java/com/gitblit/transport/ssh/SshDaemon.java
@@ -31,6 +31,7 @@ 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.auth.CachingPublicKeyAuthenticator;
import org.bouncycastle.openssl.PEMWriter;
import org.eclipse.jgit.internal.JGitText;
import org.slf4j.Logger;
@@ -98,8 +99,8 @@ public class SshDaemon {
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,
@@ -125,7 +126,7 @@ public class SshDaemon {
sshd.setPort(addr.getPort());
sshd.setHost(addr.getHostName());
sshd.setKeyPairProvider(hostKeyPairProvider);
- sshd.setPublickeyAuthenticator(keyAuthenticator);
+ sshd.setPublickeyAuthenticator(new CachingPublicKeyAuthenticator(keyAuthenticator));
sshd.setPasswordAuthenticator(new UsernamePasswordAuthenticator(gitblit));
sshd.setSessionFactory(new SshServerSessionFactory());
sshd.setFileSystemFactory(new DisabledFilesystemFactory());
diff --git a/src/main/java/com/gitblit/transport/ssh/CachingPublicKeyAuthenticator.java b/src/main/java/com/gitblit/transport/ssh/SshKeyAuthenticator.java
index e804a0da..c28a2ed6 100644
--- a/src/main/java/com/gitblit/transport/ssh/CachingPublicKeyAuthenticator.java
+++ b/src/main/java/com/gitblit/transport/ssh/SshKeyAuthenticator.java
@@ -16,14 +16,9 @@
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.session.ServerSession;
import org.slf4j.Logger;
@@ -37,7 +32,7 @@ import com.google.common.base.Preconditions;
* 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());
@@ -45,30 +40,13 @@ public class CachingPublicKeyAuthenticator implements PublickeyAuthenticator, Se
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);
@@ -96,17 +74,4 @@ public class CachingPublicKeyAuthenticator implements PublickeyAuthenticator, Se
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);
- }
}
diff --git a/src/main/java/com/gitblit/utils/DiffUtils.java b/src/main/java/com/gitblit/utils/DiffUtils.java
index dd2a7807..b30a203d 100644
--- a/src/main/java/com/gitblit/utils/DiffUtils.java
+++ b/src/main/java/com/gitblit/utils/DiffUtils.java
@@ -52,6 +52,27 @@ public class DiffUtils {
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 {
@@ -181,6 +202,23 @@ public class DiffUtils {
}
/**
+ * Returns the complete diff of the specified commit compared to its primary parent.
+ *
+ * @param repository
+ * @param commit
+ * @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.
+ * @return the diff
+ */
+ public static DiffOutput getCommitDiff(Repository repository, RevCommit commit,
+ DiffOutputType outputType, BinaryDiffHandler handler) {
+ return getDiff(repository, null, commit, null, outputType, handler);
+ }
+
+
+ /**
* Returns the diff for the specified file or folder from the specified
* commit compared to its primary parent.
*
@@ -196,6 +234,24 @@ public class DiffUtils {
}
/**
+ * 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 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.
+ * @return the diff
+ */
+ public static DiffOutput getDiff(Repository repository, RevCommit commit, String path,
+ DiffOutputType outputType, BinaryDiffHandler handler) {
+ return getDiff(repository, null, commit, path, outputType, handler);
+ }
+
+ /**
* Returns the complete diff between the two specified commits.
*
* @param repository
@@ -210,6 +266,23 @@ public class DiffUtils {
}
/**
+ * Returns the complete diff between the two specified commits.
+ *
+ * @param repository
+ * @param baseCommit
+ * @param commit
+ * @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.
+ * @return the diff
+ */
+ public static DiffOutput getDiff(Repository repository, RevCommit baseCommit, RevCommit commit,
+ DiffOutputType outputType, BinaryDiffHandler handler) {
+ return getDiff(repository, baseCommit, commit, null, outputType, handler);
+ }
+
+ /**
* Returns the diff between two commits for the specified file.
*
* @param repository
@@ -225,18 +298,41 @@ public class DiffUtils {
*/
public static DiffOutput getDiff(Repository repository, RevCommit baseCommit, RevCommit commit,
String path, DiffOutputType outputType) {
+ return getDiff(repository, baseCommit, commit, path, outputType, null);
+ }
+
+ /**
+ * 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 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.
+ * @return the diff
+ */
+ public static DiffOutput getDiff(Repository repository, RevCommit baseCommit, RevCommit commit, String path, DiffOutputType outputType,
+ final BinaryDiffHandler handler) {
DiffStat stat = null;
String diff = null;
try {
- final ByteArrayOutputStream os = new ByteArrayOutputStream();
+ ByteArrayOutputStream os = null;
RawTextComparator cmp = RawTextComparator.DEFAULT;
DiffFormatter df;
switch (outputType) {
case HTML:
- df = new GitBlitDiffFormatter(os, commit.getName());
+ df = new GitBlitDiffFormatter(commit.getName(), path, handler);
break;
case PLAIN:
default:
+ os = new ByteArrayOutputStream();
df = new DiffFormatter(os);
break;
}
@@ -271,6 +367,7 @@ public class DiffUtils {
} else {
df.format(diffEntries);
}
+ df.flush();
if (df instanceof GitBlitDiffFormatter) {
// workaround for complex private methods in DiffFormatter
diff = ((GitBlitDiffFormatter) df).getHtml();
@@ -278,7 +375,6 @@ public class DiffUtils {
} else {
diff = os.toString();
}
- df.flush();
} catch (Throwable t) {
LOGGER.error("failed to generate commit diff!", t);
}
diff --git a/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java b/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java
index 47ff143a..3c65267b 100644
--- a/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java
+++ b/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java
@@ -1,236 +1,529 @@
-/*
- * 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.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 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>();
+
+ /**
+ * 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, String path, BinaryDiffHandler handler) {
+ super(new DiffOutputStream());
+ this.os = (DiffOutputStream) getOutputStream();
+ this.os.setFormatter(this, handler);
+ this.diffStat = new DiffStat(commitId);
+ // 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()), false));
+ 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, false);
+ }
+
+ /**
+ * 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")) {
+ // 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), false);
+ }
+ 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;
+ }
+}
diff --git a/src/main/java/com/gitblit/utils/HtmlBuilder.java b/src/main/java/com/gitblit/utils/HtmlBuilder.java
new file mode 100644
index 00000000..6208ea82
--- /dev/null
+++ b/src/main/java/com/gitblit/utils/HtmlBuilder.java
@@ -0,0 +1,96 @@
+/*
+ * 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;
+ }
+}
diff --git a/src/main/java/com/gitblit/utils/JGitUtils.java b/src/main/java/com/gitblit/utils/JGitUtils.java
index da51ea98..69084ca1 100644
--- a/src/main/java/com/gitblit/utils/JGitUtils.java
+++ b/src/main/java/com/gitblit/utils/JGitUtils.java
@@ -30,6 +30,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
+import com.google.common.base.Strings;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.FetchCommand;
@@ -891,6 +892,63 @@ public class JGitUtils {
}
/**
+ * 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.release();
+ }
+ Collections.sort(list);
+ return list;
+ }
+
+ /**
* Returns the list of files changed in a specified commit. If the
* repository does not exist or is empty, an empty list is returned.
*
@@ -1124,6 +1182,46 @@ public class JGitUtils {
}
/**
+ * 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;
+ TreeWalk tw = TreeWalk.forPath(repo, path, commit.getTree());
+ String pathString = path;
+
+ if (!tw.isSubtree() && (tw.getFileMode(0) != FileMode.GITLINK)) {
+ size = tw.getObjectReader().getObjectSize(tw.getObjectId(0), Constants.OBJ_BLOB);
+ pathString = PathUtils.getLastPathComponent(pathString);
+
+ } 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(), size, tw.getFileMode(0).getBits(),
+ tw.getObjectId(0).getName(), commit.getName());
+
+
+ }
+
+
+ /**
* Returns a permissions representation of the mode bits.
*
* @param mode
@@ -2194,212 +2292,222 @@ public class JGitUtils {
}
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 {
+ 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) {
+ 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
+ }
+ }
+ 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.release();
+ }
+ }
+ } catch (IOException e) {
+ LOGGER.error("Failed to merge", e);
} finally {
- if (revWalk != null) {
+ if (revWalk != null) {
revWalk.release();
- }
- }
- return new MergeResult(MergeStatus.FAILED, null);
- }
+ }
+ }
+ return new MergeResult(MergeStatus.FAILED, null);
+ }
}
diff --git a/src/main/java/com/gitblit/utils/JSoupXssFilter.java b/src/main/java/com/gitblit/utils/JSoupXssFilter.java
index 5ab7953a..aec22411 100644
--- a/src/main/java/com/gitblit/utils/JSoupXssFilter.java
+++ b/src/main/java/com/gitblit/utils/JSoupXssFilter.java
@@ -20,18 +20,23 @@ import org.jsoup.nodes.Document;
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());
diff --git a/src/main/java/com/gitblit/utils/PathUtils.java b/src/main/java/com/gitblit/utils/PathUtils.java
new file mode 100644
index 00000000..a3c7d8d6
--- /dev/null
+++ b/src/main/java/com/gitblit/utils/PathUtils.java
@@ -0,0 +1,92 @@
+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();
+ }
+
+}
diff --git a/src/main/java/com/gitblit/utils/ResettableByteArrayOutputStream.java b/src/main/java/com/gitblit/utils/ResettableByteArrayOutputStream.java
new file mode 100644
index 00000000..7df0693f
--- /dev/null
+++ b/src/main/java/com/gitblit/utils/ResettableByteArrayOutputStream.java
@@ -0,0 +1,42 @@
+// 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;
+ }
+ }
+
+}
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
index d19630c2..359040b5 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
@@ -43,6 +43,7 @@ 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;
@@ -90,7 +91,11 @@ import com.gitblit.wicket.pages.TicketsPage;
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;
@@ -99,6 +104,10 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp {
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 XssFilter xssFilter;
@@ -113,8 +122,6 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp {
private final IAuthenticationManager authenticationManager;
- private final IPublicKeyManager publicKeyManager;
-
private final IRepositoryManager repositoryManager;
private final IProjectManager projectManager;
@@ -123,19 +130,26 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp {
private final IGitblit gitblit;
+ private final IServicesManager services;
+
+ @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) {
super();
+ this.publicKeyManagerProvider = publicKeyManagerProvider;
+ this.ticketServiceProvider = ticketServiceProvider;
this.settings = runtimeManager.getSettings();
this.xssFilter = runtimeManager.getXssFilter();
this.runtimeManager = runtimeManager;
@@ -143,11 +157,11 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp {
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;
}
@Override
@@ -392,7 +406,7 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp {
*/
@Override
public IPublicKeyManager keys() {
- return publicKeyManager;
+ return publicKeyManagerProvider.get();
}
/* (non-Javadoc)
@@ -428,11 +442,19 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp {
}
/* (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)
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
index eb92e2d2..648ac2a5 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
@@ -561,6 +561,7 @@ gb.bugTickets = bugs
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
@@ -741,4 +742,21 @@ gb.sshKeyCommentDescription = Enter an optional comment. If blank, the comment w
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 \ No newline at end of file
+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) \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties
index 3ec330b7..eca3fd2a 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties
@@ -743,3 +743,13 @@ gb.permission = Berechtigung
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) \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties
index b888beee..d479b3d6 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties
@@ -672,3 +672,13 @@ gb.ticketIsClosed = Ce ticket est clos.
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) \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/GitblitWicketApp.java b/src/main/java/com/gitblit/wicket/GitblitWicketApp.java
index 8d3d598d..3041c5da 100644
--- a/src/main/java/com/gitblit/wicket/GitblitWicketApp.java
+++ b/src/main/java/com/gitblit/wicket/GitblitWicketApp.java
@@ -14,6 +14,7 @@ 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;
@@ -68,6 +69,8 @@ public interface GitblitWicketApp {
public abstract IGitblit gitblit();
+ public abstract IServicesManager services();
+
public abstract ITicketService tickets();
public abstract TimeZone getTimezone();
diff --git a/src/main/java/com/gitblit/wicket/GitblitWicketFilter.java b/src/main/java/com/gitblit/wicket/GitblitWicketFilter.java
index 7865fb3b..68ad84a5 100644
--- a/src/main/java/com/gitblit/wicket/GitblitWicketFilter.java
+++ b/src/main/java/com/gitblit/wicket/GitblitWicketFilter.java
@@ -17,6 +17,8 @@ package com.gitblit.wicket;
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;
@@ -28,7 +30,6 @@ import org.eclipse.jgit.revwalk.RevCommit;
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;
@@ -37,8 +38,6 @@ import com.gitblit.models.RepositoryModel;
import com.gitblit.utils.JGitUtils;
import com.gitblit.utils.StringUtils;
-import dagger.ObjectGraph;
-
/**
*
* Customization of the WicketFilter to allow smart browser-side caching of
@@ -47,7 +46,8 @@ import dagger.ObjectGraph;
* @author James Moger
*
*/
-public class GitblitWicketFilter extends DaggerWicketFilter {
+@Singleton
+public class GitblitWicketFilter extends WicketFilter {
private IStoredSettings settings;
@@ -59,13 +59,19 @@ public class GitblitWicketFilter extends DaggerWicketFilter {
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
diff --git a/src/main/java/com/gitblit/wicket/TicketsUI.java b/src/main/java/com/gitblit/wicket/TicketsUI.java
index 0eff4cff..8d599523 100644
--- a/src/main/java/com/gitblit/wicket/TicketsUI.java
+++ b/src/main/java/com/gitblit/wicket/TicketsUI.java
@@ -21,6 +21,8 @@ import java.text.MessageFormat;
import org.apache.wicket.markup.html.basic.Label;
import com.gitblit.models.TicketModel;
+import com.gitblit.models.TicketModel.Priority;
+import com.gitblit.models.TicketModel.Severity;
import com.gitblit.models.TicketModel.Status;
import com.gitblit.models.TicketModel.Type;
import com.gitblit.utils.StringUtils;
@@ -38,37 +40,74 @@ public class TicketsUI {
public static final String [] closedStatii = new String [] { "!" + Status.New.name().toLowerCase(), "!" + Status.Open.name().toLowerCase() };
public static Label getStateIcon(String wicketId, TicketModel ticket) {
- return getStateIcon(wicketId, ticket.type, ticket.status);
+ return getStateIcon(wicketId, ticket.type, ticket.status, ticket.severity);
}
- public static Label getStateIcon(String wicketId, Type type, Status state) {
+ public static Label getStateIcon(String wicketId, Type type, Status state, Severity severity) {
Label label = new Label(wicketId);
if (type == null) {
type = Type.defaultType;
}
switch (type) {
case Proposal:
- WicketUtils.setCssClass(label, "fa fa-code-fork");
+ WicketUtils.setCssClass(label, "fa fa-code-fork fa-fw");
break;
case Bug:
- WicketUtils.setCssClass(label, "fa fa-bug");
+ WicketUtils.setCssClass(label, "fa fa-bug fa-fw");
break;
case Enhancement:
- WicketUtils.setCssClass(label, "fa fa-magic");
+ WicketUtils.setCssClass(label, "fa fa-magic fa-fw");
break;
case Question:
- WicketUtils.setCssClass(label, "fa fa-question");
+ WicketUtils.setCssClass(label, "fa fa-question fa-fw");
+ break;
+ case Maintenance:
+ WicketUtils.setCssClass(label, "fa fa-cogs fa-fw");
break;
default:
// standard ticket
- WicketUtils.setCssClass(label, "fa fa-ticket");
+ WicketUtils.setCssClass(label, "fa fa-ticket fa-fw");
+ }
+ WicketUtils.setHtmlTooltip(label, getTypeState(type, state, severity));
+
+ return label;
+ }
+
+ public static Label getPriorityIcon(String wicketId, Priority priority) {
+ Label label = new Label(wicketId);
+ if (priority == null) {
+ priority = Priority.defaultPriority;
+ }
+ switch (priority) {
+ case Urgent:
+ WicketUtils.setCssClass(label, "fa fa-step-forward fa-rotate-270");
+ break;
+ case High:
+ WicketUtils.setCssClass(label, "fa fa-caret-up fa-lg");
+ break;
+ case Low:
+ WicketUtils.setCssClass(label, "fa fa-caret-down fa-lg");
+ break;
+ default:
}
- WicketUtils.setHtmlTooltip(label, getTypeState(type, state));
+ WicketUtils.setHtmlTooltip(label, priority.toString());
+
return label;
}
- public static String getTypeState(Type type, Status state) {
- return state.toString() + " " + type.toString();
+ public static String getPriorityClass(Priority priority) {
+ return String.format("priority-%s", priority);
+ }
+
+ public static String getSeverityClass(Severity severity) {
+ return String.format("severity-%s", severity);
+ }
+
+ public static String getTypeState(Type type, Status state, Severity severity) {
+ if (Severity.Unrated == severity) {
+ return state.toString() + " " + type.toString();
+ }
+ return state.toString() + " " + type.toString() + ", " + severity.toString();
}
public static String getLozengeClass(Status status, boolean subtle) {
diff --git a/src/main/java/com/gitblit/wicket/WicketUtils.java b/src/main/java/com/gitblit/wicket/WicketUtils.java
index d47390d4..9a40931d 100644
--- a/src/main/java/com/gitblit/wicket/WicketUtils.java
+++ b/src/main/java/com/gitblit/wicket/WicketUtils.java
@@ -29,12 +29,14 @@ import javax.servlet.http.HttpServletRequest;
import org.apache.wicket.Component;
import org.apache.wicket.PageParameters;
import org.apache.wicket.Request;
+import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.behavior.HeaderContributor;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.html.IHeaderContributor;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.image.ContextImage;
+import org.apache.wicket.model.Model;
import org.apache.wicket.protocol.http.WebRequest;
import org.apache.wicket.resource.ContextRelativeResource;
import org.eclipse.jgit.diff.DiffEntry.ChangeType;
@@ -56,6 +58,10 @@ public class WicketUtils {
container.add(new SimpleAttributeModifier("class", value));
}
+ public static void addCssClass(Component container, String value) {
+ container.add(new AttributeAppender("class", new Model<String>(value), " "));
+ }
+
public static void setCssStyle(Component container, String value) {
container.add(new SimpleAttributeModifier("style", value));
}
diff --git a/src/main/java/com/gitblit/wicket/freemarker/templates/FilterableRepositoryList.fm b/src/main/java/com/gitblit/wicket/freemarker/templates/FilterableRepositoryList.fm
index 1512adab..43816cf7 100644
--- a/src/main/java/com/gitblit/wicket/freemarker/templates/FilterableRepositoryList.fm
+++ b/src/main/java/com/gitblit/wicket/freemarker/templates/FilterableRepositoryList.fm
@@ -9,7 +9,13 @@
</div>
<div ng-repeat="item in ${ngList} | filter:query" style="padding: 3px;border-top: 1px solid #ddd;">
- <b><span class="repositorySwatch" style="background-color:{{item.c}};"><span ng-show="item.wc">!</span><span ng-show="!item.wc">&nbsp;</span></span></b>
+ <span style="color:{{item.c}};padding-right:2px;">
+ <span ng-show="item.y == 0" class="octicon octicon-centered octicon-repo"></span>
+ <span ng-show="item.y == 1" class="octicon octicon-centered octicon-repo-forked"></span>
+ <span ng-show="item.y == 2" class="octicon octicon-centered octicon-mirror"></span>
+ <span ng-show="item.y == 3" class="octicon octicon-centered octicon-repo-push"></span>
+ </span>
+
<a href="summary/?r={{item.r}}" title="{{item.i}}">{{item.p}}<b>{{item.n}}</b></a>
<span class="link hidden-tablet hidden-phone" style="color: #bbb;" title="{{item.d}}">{{item.t}}</span>
<span ng-show="item.s" class="pull-right">
diff --git a/src/main/java/com/gitblit/wicket/pages/BasePage.html b/src/main/java/com/gitblit/wicket/pages/BasePage.html
index 89a28b80..b998428c 100644
--- a/src/main/java/com/gitblit/wicket/pages/BasePage.html
+++ b/src/main/java/com/gitblit/wicket/pages/BasePage.html
@@ -15,6 +15,7 @@
<link rel="stylesheet" href="bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="bootstrap/css/iconic.css"/>
<link rel="stylesheet" href="fontawesome/css/font-awesome.min.css"/>
+ <link rel="stylesheet" href="octicons/octicons.css"/>
<link rel="stylesheet" type="text/css" href="gitblit.css"/>
</wicket:head>
@@ -50,5 +51,6 @@
<!-- Include scripts at end for faster page loading -->
<script type="text/javascript" src="bootstrap/js/jquery.js"></script>
<script type="text/javascript" src="bootstrap/js/bootstrap.js"></script>
+ <wicket:container wicket:id="bottomScripts"></wicket:container>
</body>
</html> \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/pages/BasePage.java b/src/main/java/com/gitblit/wicket/pages/BasePage.java
index b6967003..0d99f5e5 100644
--- a/src/main/java/com/gitblit/wicket/pages/BasePage.java
+++ b/src/main/java/com/gitblit/wicket/pages/BasePage.java
@@ -42,6 +42,8 @@ import org.apache.wicket.markup.html.CSSPackageResource;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.ExternalLink;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
+import org.apache.wicket.markup.html.resources.JavascriptResourceReference;
+import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.protocol.http.RequestUtils;
import org.apache.wicket.protocol.http.WebResponse;
import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
@@ -242,7 +244,7 @@ public abstract class BasePage extends SessionPage {
protected void setupPage(String repositoryName, String pageName) {
add(new Label("title", getPageTitle(repositoryName)));
-
+ getBottomScriptContainer();
String rootLinkUrl = app().settings().getString(Keys.web.rootLink, urlFor(GitBlitWebApp.get().getHomePage(), null).toString());
ExternalLink rootLink = new ExternalLink("rootLink", rootLinkUrl);
WicketUtils.setHtmlTooltip(rootLink, app().settings().getString(Keys.web.siteName, Constants.NAME));
@@ -506,4 +508,40 @@ public abstract class BasePage extends SessionPage {
return sb.toString();
}
+ private RepeatingView getBottomScriptContainer() {
+ RepeatingView bottomScriptContainer = (RepeatingView) get("bottomScripts");
+ if (bottomScriptContainer == null) {
+ bottomScriptContainer = new RepeatingView("bottomScripts");
+ bottomScriptContainer.setRenderBodyOnly(true);
+ add(bottomScriptContainer);
+ }
+ return bottomScriptContainer;
+ }
+
+ /**
+ * Adds a HTML script element loading the javascript designated by the given path.
+ *
+ * @param scriptPath
+ * page-relative path to the Javascript resource; normally starts with "scripts/"
+ */
+ protected void addBottomScript(String scriptPath) {
+ RepeatingView bottomScripts = getBottomScriptContainer();
+ Label script = new Label(bottomScripts.newChildId(), "<script type='text/javascript' src='"
+ + urlFor(new JavascriptResourceReference(this.getClass(), scriptPath)) + "'></script>\n");
+ bottomScripts.add(script.setEscapeModelStrings(false).setRenderBodyOnly(true));
+ }
+
+ /**
+ * Adds a HTML script element containing the given code.
+ *
+ * @param code
+ * inline script code
+ */
+ protected void addBottomScriptInline(String code) {
+ RepeatingView bottomScripts = getBottomScriptContainer();
+ Label script = new Label(bottomScripts.newChildId(),
+ "<script type='text/javascript'>/*<![CDATA[*/\n" + code + "\n//]]>\n</script>\n");
+ bottomScripts.add(script.setEscapeModelStrings(false).setRenderBodyOnly(true));
+ }
+
}
diff --git a/src/main/java/com/gitblit/wicket/pages/BlobDiffPage.java b/src/main/java/com/gitblit/wicket/pages/BlobDiffPage.java
index 9cc3eae1..ae737a53 100644
--- a/src/main/java/com/gitblit/wicket/pages/BlobDiffPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/BlobDiffPage.java
@@ -15,12 +15,15 @@
*/
package com.gitblit.wicket.pages;
+import java.util.List;
+
import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
+import com.gitblit.Keys;
import com.gitblit.utils.DiffUtils;
import com.gitblit.utils.DiffUtils.DiffOutputType;
import com.gitblit.utils.JGitUtils;
@@ -43,16 +46,29 @@ public class BlobDiffPage extends RepositoryPage {
Repository r = getRepository();
RevCommit commit = getCommit();
+ final List<String> imageExtensions = app().settings().getStrings(Keys.web.imageExtensions);
+
String diff;
if (StringUtils.isEmpty(baseObjectId)) {
// use first parent
- diff = DiffUtils.getDiff(r, commit, blobPath, DiffOutputType.HTML).content;
+ RevCommit parent = commit.getParentCount() == 0 ? null : commit.getParent(0);
+ ImageDiffHandler handler = new ImageDiffHandler(this, repositoryName,
+ parent.getName(), commit.getName(), imageExtensions);
+ diff = DiffUtils.getDiff(r, commit, blobPath, DiffOutputType.HTML, handler).content;
+ if (handler.getImgDiffCount() > 0) {
+ addBottomScript("scripts/imgdiff.js"); // Tiny support script for image diffs
+ }
add(new BookmarkablePageLink<Void>("patchLink", PatchPage.class,
WicketUtils.newPathParameter(repositoryName, objectId, blobPath)));
} else {
// base commit specified
RevCommit baseCommit = JGitUtils.getCommit(r, baseObjectId);
- diff = DiffUtils.getDiff(r, baseCommit, commit, blobPath, DiffOutputType.HTML).content;
+ ImageDiffHandler handler = new ImageDiffHandler(this, repositoryName,
+ baseCommit.getName(), commit.getName(), imageExtensions);
+ diff = DiffUtils.getDiff(r, baseCommit, commit, blobPath, DiffOutputType.HTML, handler).content;
+ if (handler.getImgDiffCount() > 0) {
+ addBottomScript("scripts/imgdiff.js"); // Tiny support script for image diffs
+ }
add(new BookmarkablePageLink<Void>("patchLink", PatchPage.class,
WicketUtils.newBlobDiffParameter(repositoryName, baseObjectId, objectId,
blobPath)));
diff --git a/src/main/java/com/gitblit/wicket/pages/BlobPage.html b/src/main/java/com/gitblit/wicket/pages/BlobPage.html
index 3f9a959a..289c1498 100644
--- a/src/main/java/com/gitblit/wicket/pages/BlobPage.html
+++ b/src/main/java/com/gitblit/wicket/pages/BlobPage.html
@@ -40,9 +40,8 @@
</wicket:link>
</wicket:head>
+<body>
<wicket:extend>
-<!-- need to specify body.onload -->
-<body onload="prettyPrint()">
<!-- blob nav links -->
<div class="page_nav2">
@@ -61,6 +60,6 @@
<!-- blob image -->
<img wicket:id="blobImage" style="padding-top:5px;"></img>
-</body>
</wicket:extend>
+</body>
</html> \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/pages/BlobPage.java b/src/main/java/com/gitblit/wicket/pages/BlobPage.java
index 3c244f9a..df30e4cc 100644
--- a/src/main/java/com/gitblit/wicket/pages/BlobPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/BlobPage.java
@@ -137,6 +137,7 @@ public class BlobPage extends RepositoryPage {
table = missingBlob(blobPath, commit);
} else {
table = generateSourceView(source, extension, type == 1);
+ addBottomScriptInline("jQuery(prettyPrint);");
}
add(new Label("blobText", table).setEscapeModelStrings(false));
add(new Image("blobImage").setVisible(false));
@@ -150,6 +151,7 @@ public class BlobPage extends RepositoryPage {
table = missingBlob(blobPath, commit);
} else {
table = generateSourceView(source, null, false);
+ addBottomScriptInline("jQuery(prettyPrint);");
}
add(new Label("blobText", table).setEscapeModelStrings(false));
add(new Image("blobImage").setVisible(false));
diff --git a/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java
index d827c449..c838dab5 100644
--- a/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java
@@ -31,6 +31,7 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import com.gitblit.Constants;
+import com.gitblit.Keys;
import com.gitblit.models.GitNote;
import com.gitblit.models.PathModel.PathChangeModel;
import com.gitblit.models.SubmoduleModel;
@@ -59,8 +60,6 @@ public class CommitDiffPage extends RepositoryPage {
RevCommit commit = getCommit();
- final DiffOutput diff = DiffUtils.getCommitDiff(r, commit, DiffOutputType.HTML);
-
List<String> parents = new ArrayList<String>();
if (commit.getParentCount() > 0) {
for (RevCommit parent : commit.getParents()) {
@@ -82,6 +81,14 @@ public class CommitDiffPage extends RepositoryPage {
add(new CommitHeaderPanel("commitHeader", repositoryName, commit));
+ final List<String> imageExtensions = app().settings().getStrings(Keys.web.imageExtensions);
+ final ImageDiffHandler handler = new ImageDiffHandler(this, repositoryName,
+ parents.isEmpty() ? null : parents.get(0), commit.getName(), imageExtensions);
+ final DiffOutput diff = DiffUtils.getCommitDiff(r, commit, DiffOutputType.HTML, handler);
+ if (handler.getImgDiffCount() > 0) {
+ addBottomScript("scripts/imgdiff.js"); // Tiny support script for image diffs
+ }
+
// add commit diffstat
int insertions = 0;
int deletions = 0;
@@ -145,10 +152,10 @@ public class CommitDiffPage extends RepositoryPage {
hasSubmodule = submodule.hasSubmodule;
// add relative link
- item.add(new LinkPanel("pathName", "list", entry.path + " @ " + getShortObjectId(submoduleId), "#" + entry.path));
+ item.add(new LinkPanel("pathName", "list", entry.path + " @ " + getShortObjectId(submoduleId), "#n" + entry.objectId));
} else {
// add relative link
- item.add(new LinkPanel("pathName", "list", entry.path, "#" + entry.path));
+ item.add(new LinkPanel("pathName", "list", entry.path, "#n" + entry.objectId));
}
// quick links
diff --git a/src/main/java/com/gitblit/wicket/pages/ComparePage.java b/src/main/java/com/gitblit/wicket/pages/ComparePage.java
index 1ec66133..62ae7c25 100644
--- a/src/main/java/com/gitblit/wicket/pages/ComparePage.java
+++ b/src/main/java/com/gitblit/wicket/pages/ComparePage.java
@@ -37,6 +37,7 @@ import org.eclipse.jgit.diff.DiffEntry.ChangeType;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
+import com.gitblit.Keys;
import com.gitblit.models.PathModel.PathChangeModel;
import com.gitblit.models.RefModel;
import com.gitblit.models.RepositoryModel;
@@ -111,7 +112,14 @@ public class ComparePage extends RepositoryPage {
fromCommitId.setObject(startId);
toCommitId.setObject(endId);
- final DiffOutput diff = DiffUtils.getDiff(r, fromCommit, toCommit, DiffOutputType.HTML);
+ final List<String> imageExtensions = app().settings().getStrings(Keys.web.imageExtensions);
+ final ImageDiffHandler handler = new ImageDiffHandler(this, repositoryName,
+ fromCommit.getName(), toCommit.getName(), imageExtensions);
+
+ final DiffOutput diff = DiffUtils.getDiff(r, fromCommit, toCommit, DiffOutputType.HTML, handler);
+ if (handler.getImgDiffCount() > 0) {
+ addBottomScript("scripts/imgdiff.js"); // Tiny support script for image diffs
+ }
// add compare diffstat
int insertions = 0;
@@ -160,10 +168,10 @@ public class ComparePage extends RepositoryPage {
hasSubmodule = submodule.hasSubmodule;
// add relative link
- item.add(new LinkPanel("pathName", "list", entry.path + " @ " + getShortObjectId(submoduleId), "#" + entry.path));
+ item.add(new LinkPanel("pathName", "list", entry.path + " @ " + getShortObjectId(submoduleId), "#n" + entry.objectId));
} else {
// add relative link
- item.add(new LinkPanel("pathName", "list", entry.path, "#" + entry.path));
+ item.add(new LinkPanel("pathName", "list", entry.path, "#n" + entry.objectId));
}
// quick links
diff --git a/src/main/java/com/gitblit/wicket/pages/EditTeamPage.java b/src/main/java/com/gitblit/wicket/pages/EditTeamPage.java
index f537f33d..a43d8db0 100644
--- a/src/main/java/com/gitblit/wicket/pages/EditTeamPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/EditTeamPage.java
@@ -39,6 +39,7 @@ import org.apache.wicket.model.util.CollectionModel;
import org.apache.wicket.model.util.ListModel;
import com.gitblit.Constants.RegistrantType;
+import com.gitblit.Constants.Role;
import com.gitblit.GitBlitException;
import com.gitblit.Keys;
import com.gitblit.models.RegistrantAccessPermission;
@@ -221,14 +222,23 @@ public class EditTeamPage extends RootSubPage {
// do not let the browser pre-populate these fields
form.add(new SimpleAttributeModifier("autocomplete", "off"));
- // not all user services support manipulating team memberships
+ // not all user providers support manipulating team memberships
boolean editMemberships = app().authentication().supportsTeamMembershipChanges(teamModel);
+ // not all user providers support manipulating the admin role
+ boolean changeAdminRole = app().authentication().supportsRoleChanges(teamModel, Role.ADMIN);
+
+ // not all user providers support manipulating the create role
+ boolean changeCreateRole = app().authentication().supportsRoleChanges(teamModel, Role.CREATE);
+
+ // not all user providers support manipulating the fork role
+ boolean changeForkRole = app().authentication().supportsRoleChanges(teamModel, Role.FORK);
+
// field names reflective match TeamModel fields
form.add(new TextField<String>("name"));
- form.add(new CheckBox("canAdmin"));
- form.add(new CheckBox("canFork").setEnabled(app().settings().getBoolean(Keys.web.allowForking, true)));
- form.add(new CheckBox("canCreate"));
+ form.add(new CheckBox("canAdmin").setEnabled(changeAdminRole));
+ form.add(new CheckBox("canFork").setEnabled(app().settings().getBoolean(Keys.web.allowForking, true) && changeForkRole));
+ form.add(new CheckBox("canCreate").setEnabled(changeCreateRole));
form.add(users.setEnabled(editMemberships));
mailingLists = new Model<String>(teamModel.mailingLists == null ? ""
: StringUtils.flattenStrings(teamModel.mailingLists, " "));
diff --git a/src/main/java/com/gitblit/wicket/pages/EditTicketPage.html b/src/main/java/com/gitblit/wicket/pages/EditTicketPage.html
index b5fe0ae5..b12d0c77 100644
--- a/src/main/java/com/gitblit/wicket/pages/EditTicketPage.html
+++ b/src/main/java/com/gitblit/wicket/pages/EditTicketPage.html
@@ -39,6 +39,8 @@
</div>
</td></tr>
<tr wicket:id="status"></tr>
+ <tr><th><wicket:message key="gb.severity"></wicket:message></th><td class="edit"><select class="input-large" wicket:id="severity"></select></td></tr>
+ <tr wicket:id="priority"></tr>
<tr wicket:id="responsible"></tr>
<tr wicket:id="milestone"></tr>
<tr wicket:id="mergeto"></tr>
@@ -71,5 +73,9 @@
<th><wicket:message key="gb.mergeTo"></wicket:message></th><td class="edit"><select class="input-large" wicket:id="mergeto"></select></td>
</wicket:fragment>
+<wicket:fragment wicket:id="priorityFragment">
+ <th><wicket:message key="gb.priority"></wicket:message></th><td class="edit"><select class="input-large" wicket:id="priority"></select></td>
+</wicket:fragment>
+
</wicket:extend>
</html> \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/pages/EditTicketPage.java b/src/main/java/com/gitblit/wicket/pages/EditTicketPage.java
index c3d405bc..192b48ca 100644
--- a/src/main/java/com/gitblit/wicket/pages/EditTicketPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/EditTicketPage.java
@@ -84,6 +84,10 @@ public class EditTicketPage extends RepositoryPage {
private Label descriptionPreview;
+ private IModel<TicketModel.Priority> priorityModel;
+
+ private IModel<TicketModel.Severity> severityModel;
+
public EditTicketPage(PageParameters params) {
super(params);
@@ -117,6 +121,8 @@ public class EditTicketPage extends RepositoryPage {
milestoneModel = Model.of();
mergeToModel = Model.of(ticket.mergeTo == null ? getRepositoryModel().mergeTo : ticket.mergeTo);
statusModel = Model.of(ticket.status);
+ priorityModel = Model.of(ticket.priority);
+ severityModel = Model.of(ticket.severity);
setStatelessHint(false);
setOutputMarkupId(true);
@@ -161,6 +167,9 @@ public class EditTicketPage extends RepositoryPage {
status.add(new DropDownChoice<TicketModel.Status>("status", statusModel, statusChoices));
form.add(status);
+ List<TicketModel.Severity> severityChoices = Arrays.asList(TicketModel.Severity.choices());
+ form.add(new DropDownChoice<TicketModel.Severity>("severity", severityModel, severityChoices));
+
if (currentUser.canAdmin(ticket, getRepositoryModel())) {
// responsible
Set<String> userlist = new TreeSet<String>(ticket.getParticipants());
@@ -214,11 +223,17 @@ public class EditTicketPage extends RepositoryPage {
milestones.add(new TicketMilestone(NIL));
}
+ // milestone
Fragment milestone = new Fragment("milestone", "milestoneFragment", this);
-
milestone.add(new DropDownChoice<TicketMilestone>("milestone", milestoneModel, milestones));
form.add(milestone.setVisible(!milestones.isEmpty()));
+ // priority
+ Fragment priority = new Fragment("priority", "priorityFragment", this);
+ List<TicketModel.Priority> priorityChoices = Arrays.asList(TicketModel.Priority.choices());
+ priority.add(new DropDownChoice<TicketModel.Priority>("priority", priorityModel, priorityChoices));
+ form.add(priority);
+
// mergeTo (integration branch)
List<String> branches = new ArrayList<String>();
for (String branch : getRepositoryModel().getLocalBranches()) {
@@ -238,6 +253,7 @@ public class EditTicketPage extends RepositoryPage {
form.add(new Label("responsible").setVisible(false));
form.add(new Label("milestone").setVisible(false));
form.add(new Label("mergeto").setVisible(false));
+ form.add(new Label("priority").setVisible(false));
}
form.add(new AjaxButton("update") {
@@ -316,6 +332,18 @@ public class EditTicketPage extends RepositoryPage {
}
}
+ TicketModel.Priority priority = priorityModel.getObject();
+ if (!ticket.priority.equals(priority))
+ {
+ change.setField(Field.priority, priority);
+ }
+
+ TicketModel.Severity severity = severityModel.getObject();
+ if (!ticket.severity.equals(severity))
+ {
+ change.setField(Field.severity, severity);
+ }
+
String mergeTo = mergeToModel.getObject();
if ((StringUtils.isEmpty(ticket.mergeTo) && !StringUtils.isEmpty(mergeTo))
|| (!StringUtils.isEmpty(mergeTo) && !mergeTo.equals(ticket.mergeTo))) {
diff --git a/src/main/java/com/gitblit/wicket/pages/EditUserPage.java b/src/main/java/com/gitblit/wicket/pages/EditUserPage.java
index 454aa619..c6b5c3c7 100644
--- a/src/main/java/com/gitblit/wicket/pages/EditUserPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/EditUserPage.java
@@ -35,6 +35,7 @@ import org.apache.wicket.model.util.CollectionModel;
import org.apache.wicket.model.util.ListModel;
import com.gitblit.Constants.RegistrantType;
+import com.gitblit.Constants.Role;
import com.gitblit.GitBlitException;
import com.gitblit.Keys;
import com.gitblit.models.RegistrantAccessPermission;
@@ -177,7 +178,9 @@ public class EditUserPage extends RootSubPage {
// update user permissions
for (RegistrantAccessPermission repositoryPermission : permissions) {
- userModel.setRepositoryPermission(repositoryPermission.registrant, repositoryPermission.permission);
+ if (repositoryPermission.mutable) {
+ userModel.setRepositoryPermission(repositoryPermission.registrant, repositoryPermission.permission);
+ }
}
Iterator<String> selectedTeams = teams.getSelectedChoices();
@@ -216,18 +219,27 @@ public class EditUserPage extends RootSubPage {
// do not let the browser pre-populate these fields
form.add(new SimpleAttributeModifier("autocomplete", "off"));
- // not all user services support manipulating username and password
+ // not all user providers support manipulating username and password
boolean editCredentials = app().authentication().supportsCredentialChanges(userModel);
- // not all user services support manipulating display name
+ // not all user providers support manipulating display name
boolean editDisplayName = app().authentication().supportsDisplayNameChanges(userModel);
- // not all user services support manipulating email address
+ // not all user providers support manipulating email address
boolean editEmailAddress = app().authentication().supportsEmailAddressChanges(userModel);
- // not all user services support manipulating team memberships
+ // not all user providers support manipulating team memberships
boolean editTeams = app().authentication().supportsTeamMembershipChanges(userModel);
+ // not all user providers support manipulating the admin role
+ boolean changeAdminRole = app().authentication().supportsRoleChanges(userModel, Role.ADMIN);
+
+ // not all user providers support manipulating the create role
+ boolean changeCreateRole = app().authentication().supportsRoleChanges(userModel, Role.CREATE);
+
+ // not all user providers support manipulating the fork role
+ boolean changeForkRole = app().authentication().supportsRoleChanges(userModel, Role.FORK);
+
// field names reflective match UserModel fields
form.add(new TextField<String>("username").setEnabled(editCredentials));
PasswordTextField passwordField = new PasswordTextField("password");
@@ -245,7 +257,7 @@ public class EditUserPage extends RootSubPage {
// display a disabled-yet-checked checkbox
form.add(new CheckBox("canAdmin", Model.of(true)).setEnabled(false));
} else {
- form.add(new CheckBox("canAdmin"));
+ form.add(new CheckBox("canAdmin").setEnabled(changeAdminRole));
}
if (userModel.canFork() && !userModel.canFork) {
@@ -254,7 +266,7 @@ public class EditUserPage extends RootSubPage {
form.add(new CheckBox("canFork", Model.of(true)).setEnabled(false));
} else {
final boolean forkingAllowed = app().settings().getBoolean(Keys.web.allowForking, true);
- form.add(new CheckBox("canFork").setEnabled(forkingAllowed));
+ form.add(new CheckBox("canFork").setEnabled(forkingAllowed && changeForkRole));
}
if (userModel.canCreate() && !userModel.canCreate) {
@@ -262,7 +274,7 @@ public class EditUserPage extends RootSubPage {
// display a disabled-yet-checked checkbox
form.add(new CheckBox("canCreate", Model.of(true)).setEnabled(false));
} else {
- form.add(new CheckBox("canCreate"));
+ form.add(new CheckBox("canCreate").setEnabled(changeCreateRole));
}
form.add(new CheckBox("excludeFromFederation"));
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java
index b3c52436..72d1e1a4 100644
--- a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java
@@ -55,7 +55,7 @@ public class EmptyRepositoryPage extends RepositoryPage {
}
HttpServletRequest req = ((WebRequest) getRequest()).getHttpServletRequest();
- List<RepositoryUrl> repositoryUrls = app().gitblit().getRepositoryUrls(req, user, repository);
+ List<RepositoryUrl> repositoryUrls = app().services().getRepositoryUrls(req, user, repository);
RepositoryUrl primaryUrl = repositoryUrls.size() == 0 ? null : repositoryUrls.get(0);
String url = primaryUrl != null ? primaryUrl.url : "";
diff --git a/src/main/java/com/gitblit/wicket/pages/ImageDiffHandler.java b/src/main/java/com/gitblit/wicket/pages/ImageDiffHandler.java
new file mode 100644
index 00000000..dc0c5ae8
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/pages/ImageDiffHandler.java
@@ -0,0 +1,170 @@
+/*
+ * 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.wicket.pages;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.protocol.http.WicketURLEncoder;
+import org.eclipse.jgit.diff.DiffEntry;
+import org.eclipse.jgit.diff.DiffEntry.Side;
+import org.jsoup.nodes.Element;
+
+import com.gitblit.servlet.RawServlet;
+import com.gitblit.utils.DiffUtils;
+import com.gitblit.utils.HtmlBuilder;
+
+/**
+ * A {@link DiffUtils.BinaryDiffHandler BinaryDiffHandler} for images.
+ *
+ * @author Tom <tw201207@gmail.com>
+ */
+public class ImageDiffHandler implements DiffUtils.BinaryDiffHandler {
+
+ private final String oldCommitId;
+ private final String newCommitId;
+ private final String repositoryName;
+ private final BasePage page;
+ private final List<String> imageExtensions;
+
+ private int imgDiffCount = 0;
+
+ public ImageDiffHandler(final BasePage page, final String repositoryName, final String oldCommitId, final String newCommitId,
+ final List<String> imageExtensions) {
+ this.page = page;
+ this.repositoryName = repositoryName;
+ this.oldCommitId = oldCommitId;
+ this.newCommitId = newCommitId;
+ this.imageExtensions = imageExtensions;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String renderBinaryDiff(DiffEntry diffEntry) {
+ switch (diffEntry.getChangeType()) {
+ case MODIFY:
+ case RENAME:
+ case COPY:
+ // TODO: for very small images such as icons, the slider doesn't really help. Two possible
+ // approaches: either upscale them for display (may show blurry upscaled images), or show
+ // them side by side (may still be too small to really make out the differences).
+ String oldUrl = getImageUrl(diffEntry, Side.OLD);
+ String newUrl = getImageUrl(diffEntry, Side.NEW);
+ if (oldUrl != null && newUrl != null) {
+ imgDiffCount++;
+ String id = "imgdiff" + imgDiffCount;
+ HtmlBuilder builder = new HtmlBuilder("div");
+ Element wrapper = builder.root().attr("class", "imgdiff-container").attr("id", "imgdiff-" + id);
+ Element container = wrapper.appendElement("div").attr("class", "imgdiff-ovr-slider").appendElement("div").attr("class", "imgdiff");
+ Element old = container.appendElement("div").attr("class", "imgdiff-left");
+ // style='max-width:640px;' is necessary for ensuring that the browser limits large images
+ // to some reasonable width, and to override the "img { max-width: 100%; }" from bootstrap.css,
+ // which would scale the left image to the width of its resizeable container, which isn't what
+ // we want here. Note that the max-width must be defined directly as inline style on the element,
+ // otherwise browsers ignore it if the image is larger, and we end up with an image display that
+ // is too wide.
+ // XXX: Maybe add a max-height, too, to limit portrait-oriented images to some reasonable height?
+ // (Like a 300x10000px image...)
+ old.appendElement("img").attr("class", "imgdiff-old").attr("id", id).attr("style", "max-width:640px;").attr("src", oldUrl);
+ container.appendElement("img").attr("class", "imgdiff").attr("style", "max-width:640px;").attr("src", newUrl);
+ wrapper.appendElement("br");
+ Element controls = wrapper.appendElement("div");
+ // Opacity slider
+ controls.appendElement("div").attr("class", "imgdiff-opa-container").appendElement("a").attr("class", "imgdiff-opa-slider")
+ .attr("href", "#").attr("title", page.getString("gb.opacityAdjust"));
+ // Blink comparator: find Pluto!
+ controls.appendElement("a").attr("class", "imgdiff-link imgdiff-blink").attr("href", "#")
+ .attr("title", page.getString("gb.blinkComparator"))
+ .appendElement("img").attr("src", getStaticResourceUrl("blink32.png")).attr("width", "20");
+ // Pixel subtraction, initially not displayed, will be shown by imgdiff.js depending on feature test.
+ // (Uses CSS mix-blend-mode, which isn't supported on all browsers yet).
+ controls.appendElement("a").attr("class", "imgdiff-link imgdiff-subtract").attr("href", "#")
+ .attr("title", page.getString("gb.imgdiffSubtract")).attr("style", "display:none;")
+ .appendElement("img").attr("src", getStaticResourceUrl("sub32.png")).attr("width", "20");
+ return builder.toString();
+ }
+ break;
+ case ADD:
+ String url = getImageUrl(diffEntry, Side.NEW);
+ if (url != null) {
+ return new HtmlBuilder("img").root().attr("class", "diff-img").attr("src", url).toString();
+ }
+ break;
+ default:
+ break;
+ }
+ return null;
+ }
+
+ /** Returns the number of image diffs generated so far by this {@link ImageDiffHandler}. */
+ public int getImgDiffCount() {
+ return imgDiffCount;
+ }
+
+ /**
+ * Constructs a URL that will fetch the designated resource in the git repository. The returned string will
+ * contain the URL fully URL-escaped, but note that it may still contain unescaped ampersands, so the result
+ * must still be run through HTML escaping if it is to be used in HTML.
+ *
+ * @return the URL to the image, if the given {@link DiffEntry} and {@link Side} refers to an image, or {@code null} otherwise.
+ */
+ protected String getImageUrl(DiffEntry entry, Side side) {
+ String path = entry.getPath(side);
+ int i = path.lastIndexOf('.');
+ if (i > 0) {
+ String extension = path.substring(i + 1);
+ for (String ext : imageExtensions) {
+ if (ext.equalsIgnoreCase(extension)) {
+ String commitId = Side.NEW.equals(side) ? newCommitId : oldCommitId;
+ if (commitId != null) {
+ return RawServlet.asLink(page.getContextUrl(), urlencode(repositoryName), commitId, urlencode(path));
+ } else {
+ return null;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns a URL that will fetch the designated static resource from within GitBlit.
+ */
+ protected String getStaticResourceUrl(String contextRelativePath) {
+ return WebApplication.get().getRequestCycleProcessor().getRequestCodingStrategy().rewriteStaticRelativeUrl(contextRelativePath);
+ }
+
+ /**
+ * Encode a URL component of a {@link RawServlet} URL in the special way that the servlet expects it. Note that
+ * the %-encoding used does not encode '&amp;' or '&lt;'. Slashes are not encoded in the result.
+ *
+ * @param component
+ * to encode using %-encoding
+ * @return the encoded component
+ */
+ protected String urlencode(final String component) {
+ // RawServlet handles slashes itself. Note that only the PATH_INSTANCE fits the bill here: it encodes
+ // spaces as %20, and we just have to correct for encoded slashes. Java's standard URLEncoder would
+ // encode spaces as '+', and I don't know what effects that would have on other parts of GitBlit. It
+ // would also be wrong for path components (but fine for a query part), so we'd have to correct it, too.
+ //
+ // Actually, this should be done in RawServlet.asLink(). As it is now, this may be incorrect if that
+ // operation ever uses query parameters instead of paths, or if it is fixed to urlencode its path
+ // components. But I don't want to touch that static method in RawServlet.
+ return WicketURLEncoder.PATH_INSTANCE.encode(component, StandardCharsets.UTF_8.name()).replaceAll("%2[fF]", "/");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/LogoutPage.html b/src/main/java/com/gitblit/wicket/pages/LogoutPage.html
index d4077830..ab3c0dae 100644
--- a/src/main/java/com/gitblit/wicket/pages/LogoutPage.html
+++ b/src/main/java/com/gitblit/wicket/pages/LogoutPage.html
@@ -14,7 +14,7 @@
<span class="icon-bar"></span>
</a>
<a class="brand" wicket:id="rootLink">
- <img src="gitblt_25_white.png" width="79" height="25" alt="gitblit" class="logo"/>
+ <img src="gitblt_25_white.png" width="79" alt="gitblit" class="logo"/>
</a>
</div>
diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html
index b0bc1949..cf94f3ca 100644
--- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html
+++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html
@@ -25,18 +25,19 @@
<!-- query list -->
<ul class="nav nav-list">
<li class="nav-header"><wicket:message key="gb.queries"></wicket:message></li>
- <li><a wicket:id="changesQuery"><i class="fa fa-code-fork"></i> <wicket:message key="gb.proposalTickets"></wicket:message></a></li>
- <li><a wicket:id="bugsQuery"><i class="fa fa-bug"></i> <wicket:message key="gb.bugTickets"></wicket:message></a></li>
- <li><a wicket:id="enhancementsQuery"><i class="fa fa-magic"></i> <wicket:message key="gb.enhancementTickets"></wicket:message></a></li>
- <li><a wicket:id="tasksQuery"><i class="fa fa-ticket"></i> <wicket:message key="gb.taskTickets"></wicket:message></a></li>
- <li><a wicket:id="questionsQuery"><i class="fa fa-question"></i> <wicket:message key="gb.questionTickets"></wicket:message></a></li>
+ <li><a wicket:id="changesQuery"><i class="fa fa-code-fork fa-fw"></i> <wicket:message key="gb.proposalTickets"></wicket:message></a></li>
+ <li><a wicket:id="bugsQuery"><i class="fa fa-bug fa-fw"></i> <wicket:message key="gb.bugTickets"></wicket:message></a></li>
+ <li><a wicket:id="enhancementsQuery"><i class="fa fa-magic fa-fw"></i> <wicket:message key="gb.enhancementTickets"></wicket:message></a></li>
+ <li><a wicket:id="tasksQuery"><i class="fa fa-ticket fa-fw"></i> <wicket:message key="gb.taskTickets"></wicket:message></a></li>
+ <li><a wicket:id="questionsQuery"><i class="fa fa-question fa-fw"></i> <wicket:message key="gb.questionTickets"></wicket:message></a></li>
+ <li><a wicket:id="maintenanceQuery"><i class="fa fa-cogs fa-fw"></i> <wicket:message key="gb.maintenanceTickets"></wicket:message></a></li>
<li wicket:id="userDivider" class="divider"></li>
- <li><a wicket:id="createdQuery"><i class="fa fa-user"></i> <wicket:message key="gb.yourCreatedTickets"></wicket:message></a></li>
- <li><a wicket:id="responsibleQuery"><i class="fa fa-user"></i> <wicket:message key="gb.yourAssignedTickets"></wicket:message></a></li>
- <li><a wicket:id="watchedQuery"><i class="fa fa-eye"></i> <wicket:message key="gb.yourWatchedTickets"></wicket:message></a></li>
- <li><a wicket:id="mentionsQuery"><i class="fa fa-comment"></i> <wicket:message key="gb.mentionsMeTickets"></wicket:message></a></li>
+ <li><a wicket:id="createdQuery"><i class="fa fa-user fa-fw"></i> <wicket:message key="gb.yourCreatedTickets"></wicket:message></a></li>
+ <li><a wicket:id="responsibleQuery"><i class="fa fa-user fa-fw"></i> <wicket:message key="gb.yourAssignedTickets"></wicket:message></a></li>
+ <li><a wicket:id="watchedQuery"><i class="fa fa-eye fa-fw"></i> <wicket:message key="gb.yourWatchedTickets"></wicket:message></a></li>
+ <li><a wicket:id="mentionsQuery"><i class="fa fa-comment fa-fw"></i> <wicket:message key="gb.mentionsMeTickets"></wicket:message></a></li>
<li class="divider"></li>
- <li><a wicket:id="resetQuery"><i class="fa fa-bolt"></i> <wicket:message key="gb.reset"></wicket:message></a></li>
+ <li><a wicket:id="resetQuery"><i class="fa fa-bolt fa-fw"></i> <wicket:message key="gb.reset"></wicket:message></a></li>
</ul>
</div>
diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java
index c207d561..187302f5 100644
--- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java
@@ -132,6 +132,16 @@ public class MyTicketsPage extends RootPage {
sortBy,
desc,
1)));
+
+ add(new BookmarkablePageLink<Void>("maintenanceQuery", MyTicketsPage.class,
+ queryParameters(
+ Lucene.type.matches(TicketModel.Type.Maintenance.name()),
+ milestoneParam,
+ statiiParam,
+ assignedToParam,
+ sortBy,
+ desc,
+ 1)));
add(new BookmarkablePageLink<Void>("resetQuery", MyTicketsPage.class,
queryParameters(
@@ -220,6 +230,10 @@ public class MyTicketsPage extends RootPage {
sortChoices.add(new TicketSort(getString("gb.sortLeastPatchsetRevisions"), Lucene.patchsets.name(), false));
sortChoices.add(new TicketSort(getString("gb.sortMostVotes"), Lucene.votes.name(), true));
sortChoices.add(new TicketSort(getString("gb.sortLeastVotes"), Lucene.votes.name(), false));
+ sortChoices.add(new TicketSort(getString("gb.sortHighestPriority"), Lucene.priority.name(), true));
+ sortChoices.add(new TicketSort(getString("gb.sortLowestPriority"), Lucene.priority.name(), false));
+ sortChoices.add(new TicketSort(getString("gb.sortHighestSeverity"), Lucene.severity.name(), true));
+ sortChoices.add(new TicketSort(getString("gb.sortLowestSeverity"), Lucene.severity.name(), false));
TicketSort currentSort = sortChoices.get(0);
for (TicketSort ts : sortChoices) {
diff --git a/src/main/java/com/gitblit/wicket/pages/NewTicketPage.html b/src/main/java/com/gitblit/wicket/pages/NewTicketPage.html
index 447c6aa4..9b5af023 100644
--- a/src/main/java/com/gitblit/wicket/pages/NewTicketPage.html
+++ b/src/main/java/com/gitblit/wicket/pages/NewTicketPage.html
@@ -39,6 +39,8 @@
</div>
</td></tr>
<tr><th><wicket:message key="gb.type"></wicket:message><span style="color:red;">*</span></th><td class="edit"><select class="input-large" wicket:id="type"></select></td></tr>
+ <tr><th><wicket:message key="gb.severity"></wicket:message></th><td class="edit"><select class="input-large" wicket:id="severity"></select></td></tr>
+ <tr wicket:id="priority"></tr>
<tr wicket:id="responsible"></tr>
<tr wicket:id="milestone"></tr>
<tr wicket:id="mergeto"></tr>
@@ -67,5 +69,9 @@
<th><wicket:message key="gb.mergeTo"></wicket:message></th><td class="edit"><select class="input-large" wicket:id="mergeto"></select></td>
</wicket:fragment>
+<wicket:fragment wicket:id="priorityFragment">
+ <th><wicket:message key="gb.priority"></wicket:message></th><td class="edit"><select class="input-large" wicket:id="priority"></select></td>
+</wicket:fragment>
+
</wicket:extend>
</html> \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/pages/NewTicketPage.java b/src/main/java/com/gitblit/wicket/pages/NewTicketPage.java
index 8f28055a..0c52505c 100644
--- a/src/main/java/com/gitblit/wicket/pages/NewTicketPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/NewTicketPage.java
@@ -76,6 +76,10 @@ public class NewTicketPage extends RepositoryPage {
private Label descriptionPreview;
+ private IModel<TicketModel.Priority> priorityModel;
+
+ private IModel<TicketModel.Severity> severityModel;
+
public NewTicketPage(PageParameters params) {
super(params);
@@ -95,6 +99,8 @@ public class NewTicketPage extends RepositoryPage {
mergeToModel = Model.of(Repository.shortenRefName(getRepositoryModel().mergeTo));
responsibleModel = Model.of();
milestoneModel = Model.of();
+ severityModel = Model.of(TicketModel.Severity.defaultSeverity);
+ priorityModel = Model.of(TicketModel.Priority.defaultPriority);
setStatelessHint(false);
setOutputMarkupId(true);
@@ -105,6 +111,7 @@ public class NewTicketPage extends RepositoryPage {
form.add(new DropDownChoice<TicketModel.Type>("type", typeModel, Arrays.asList(TicketModel.Type.choices())));
form.add(new TextField<String>("title", titleModel));
form.add(new TextField<String>("topic", topicModel));
+ form.add(new DropDownChoice<TicketModel.Severity>("severity", severityModel, Arrays.asList(TicketModel.Severity.choices())));
final IModel<String> markdownPreviewModel = Model.of();
descriptionPreview = new Label("descriptionPreview", markdownPreviewModel);
@@ -152,6 +159,11 @@ public class NewTicketPage extends RepositoryPage {
milestone.add(new DropDownChoice<TicketMilestone>("milestone", milestoneModel, milestones));
form.add(milestone.setVisible(!milestones.isEmpty()));
+ // priority
+ Fragment priority = new Fragment("priority", "priorityFragment", this);
+ priority.add(new DropDownChoice<TicketModel.Priority>("priority", priorityModel, Arrays.asList(TicketModel.Priority.choices())));
+ form.add(priority);
+
// integration branch
List<String> branches = new ArrayList<String>();
for (String branch : getRepositoryModel().getLocalBranches()) {
@@ -171,6 +183,7 @@ public class NewTicketPage extends RepositoryPage {
form.add(new Label("responsible").setVisible(false));
form.add(new Label("milestone").setVisible(false));
form.add(new Label("mergeto").setVisible(false));
+ form.add(new Label("priority").setVisible(false));
}
form.add(new AjaxButton("create") {
@@ -212,6 +225,20 @@ public class NewTicketPage extends RepositoryPage {
change.setField(Field.milestone, milestone.name);
}
+ // severity
+ TicketModel.Severity severity = TicketModel.Severity.defaultSeverity;
+ if (severityModel.getObject() != null) {
+ severity = severityModel.getObject();
+ }
+ change.setField(Field.severity, severity);
+
+ // priority
+ TicketModel.Priority priority = TicketModel.Priority.defaultPriority;
+ if (priorityModel.getObject() != null) {
+ priority = priorityModel.getObject();
+ }
+ change.setField(Field.priority, priority);
+
// integration branch
String mergeTo = mergeToModel.getObject();
if (!StringUtils.isEmpty(mergeTo)) {
diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.html
index 22544bc8..d4132421 100644
--- a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.html
+++ b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.html
@@ -24,13 +24,20 @@
</div>
<div class="span7">
- <div>
- <span class="project" wicket:id="projectTitle">[project title]</span>/<span class="repository" wicket:id="repositoryName">[repository name]</span>
- <a class="hidden-phone hidden-tablet" style="text-decoration: none;" wicket:id="syndication" wicket:message="title:gb.feed">
- <img style="border:0px;vertical-align:baseline;" src="feed_16x16.png"></img>
- </a>
+ <div style="display:inline-block;vertical-align:top;padding-right:5px;">
+ <span wicket:id="repoIcon"></span>
+ </div>
+ <div style="display:inline-block;">
+ <div>
+ <span class="project" wicket:id="projectTitle">[project title]</span>/<span class="repository" wicket:id="repositoryName">[repository name]</span>
+ <a class="hidden-phone hidden-tablet" style="text-decoration: none;" wicket:id="syndication" wicket:message="title:gb.feed">
+ <img style="border:0px;vertical-align:baseline;" src="feed_16x16.png"></img>
+ </a>
+ </div>
+ <div>
+ <span class="gray" wicket:id="originRepository">[origin repository]</span>
+ </div>
</div>
- <span wicket:id="originRepository">[origin repository]</span>
</div>
</div>
</div>
@@ -60,6 +67,22 @@
<i wicket:id="icon" style="padding-right:3px;"></i><span wicket:id="label"></span>
</wicket:fragment>
+ <wicket:fragment wicket:id="repoIconFragment">
+ <span class="gray mega-octicon octicon-repo"></span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="mirrorIconFragment">
+ <span class="gray mega-octicon octicon-mirror"></span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="forkIconFragment">
+ <span class="gray mega-octicon octicon-repo-forked"></span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="cloneIconFragment">
+ <span class="gray mega-octicon octicon-repo-push" wicket:message="title:gb.workingCopyWarning"></span>
+ </wicket:fragment>
+
<wicket:fragment wicket:id="originFragment">
<p class="originRepository"><wicket:message key="gb.forkedFrom">[forked from]</wicket:message> <span wicket:id="originRepository">[origin repository]</span></p>
</wicket:fragment>
diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
index 134ee044..9639a0c1 100644
--- a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
@@ -73,6 +73,7 @@ import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.panels.LinkPanel;
import com.gitblit.wicket.panels.NavigationPanel;
import com.gitblit.wicket.panels.RefsPanel;
+import com.google.common.base.Optional;
public abstract class RepositoryPage extends RootPage {
@@ -295,25 +296,38 @@ public abstract class RepositoryPage extends RootPage {
RepositoryModel model = getRepositoryModel();
if (StringUtils.isEmpty(model.originRepository)) {
if (model.isMirror) {
+ add(new Fragment("repoIcon", "mirrorIconFragment", this));
Fragment mirrorFrag = new Fragment("originRepository", "mirrorFragment", this);
Label lbl = new Label("originRepository", MessageFormat.format(getString("gb.mirrorOf"), "<b>" + model.origin + "</b>"));
mirrorFrag.add(lbl.setEscapeModelStrings(false));
add(mirrorFrag);
} else {
- add(new Label("originRepository").setVisible(false));
+ if (model.isBare) {
+ add(new Fragment("repoIcon", "repoIconFragment", this));
+ } else {
+ add(new Fragment("repoIcon", "cloneIconFragment", this));
+ }
+ add(new Label("originRepository", Optional.of(model.description).or("")));
}
} else {
RepositoryModel origin = app().repositories().getRepositoryModel(model.originRepository);
if (origin == null) {
- // no origin repository
- add(new Label("originRepository").setVisible(false));
+ // no origin repository, show description if available
+ if (model.isBare) {
+ add(new Fragment("repoIcon", "repoIconFragment", this));
+ } else {
+ add(new Fragment("repoIcon", "cloneIconFragment", this));
+ }
+ add(new Label("originRepository", Optional.of(model.description).or("")));
} else if (!user.canView(origin)) {
// show origin repository without link
+ add(new Fragment("repoIcon", "forkIconFragment", this));
Fragment forkFrag = new Fragment("originRepository", "originFragment", this);
forkFrag.add(new Label("originRepository", StringUtils.stripDotGit(model.originRepository)));
add(forkFrag);
} else {
// link to origin repository
+ add(new Fragment("repoIcon", "forkIconFragment", this));
Fragment forkFrag = new Fragment("originRepository", "originFragment", this);
forkFrag.add(new LinkPanel("originRepository", null, StringUtils.stripDotGit(model.originRepository),
SummaryPage.class, WicketUtils.newRepositoryParameter(model.originRepository)));
diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.html b/src/main/java/com/gitblit/wicket/pages/RootPage.html
index 2ff305f2..c51db819 100644
--- a/src/main/java/com/gitblit/wicket/pages/RootPage.html
+++ b/src/main/java/com/gitblit/wicket/pages/RootPage.html
@@ -14,7 +14,7 @@
<span class="icon-bar"></span>
</a>
<a class="brand" wicket:id="rootLink">
- <img src="logo.png" height="45" width="120" class="logo"/>
+ <img src="logo.png" width="120" class="logo"/>
</a>
<div class="nav-collapse">
diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java
index c4d4dd11..37e98702 100644
--- a/src/main/java/com/gitblit/wicket/pages/RootPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java
@@ -151,6 +151,7 @@ public abstract class RootPage extends BasePage {
boolean authenticateAdmin = app().settings().getBoolean(Keys.web.authenticateAdminPages, true);
boolean allowAdmin = app().settings().getBoolean(Keys.web.allowAdministration, true);
boolean allowLucene = app().settings().getBoolean(Keys.web.allowLuceneIndexing, true);
+ boolean displayUserPanel = app().settings().getBoolean(Keys.web.displayUserPanel, true);
boolean isLoggedIn = GitBlitWebSession.get().isLoggedIn();
if (authenticateAdmin) {
@@ -168,7 +169,7 @@ public abstract class RootPage extends BasePage {
}
}
- if (authenticateView || authenticateAdmin) {
+ if (displayUserPanel && (authenticateView || authenticateAdmin)) {
if (isLoggedIn) {
UserMenu userFragment = new UserMenu("userPanel", "userMenuFragment", RootPage.this);
add(userFragment);
diff --git a/src/main/java/com/gitblit/wicket/pages/TicketPage.html b/src/main/java/com/gitblit/wicket/pages/TicketPage.html
index f3f38ec3..5ae005eb 100644
--- a/src/main/java/com/gitblit/wicket/pages/TicketPage.html
+++ b/src/main/java/com/gitblit/wicket/pages/TicketPage.html
@@ -67,6 +67,8 @@
<div style="border: 1px solid #ccc;padding: 10px;margin: 5px 0px;">
<table class="summary" style="width: 100%">
<tr><th><wicket:message key="gb.type"></wicket:message></th><td><span wicket:id="ticketType">[type]</span></td></tr>
+ <tr><th><wicket:message key="gb.priority"></wicket:message></th><td><span wicket:id="priority">[priority]</span></td></tr>
+ <tr><th><wicket:message key="gb.severity"></wicket:message></th><td><span wicket:id="severity">[severity]</span></td></tr>
<tr><th><wicket:message key="gb.topic"></wicket:message></th><td><span wicket:id="ticketTopic">[topic]</span></td></tr>
<tr><th><wicket:message key="gb.responsible"></wicket:message></th><td><span wicket:id="responsible">[responsible]</span></td></tr>
<tr><th><wicket:message key="gb.milestone"></wicket:message></th><td><span wicket:id="milestone">[milestone]</span></td></tr>
@@ -555,7 +557,6 @@ pt push</pre>
</div>
</wicket:fragment>
-
<!-- VETOED PATCHSET FRAGMENT -->
<wicket:fragment wicket:id="vetoedFragment">
<div class="alert alert-error submit-info" style="padding:4px;">
diff --git a/src/main/java/com/gitblit/wicket/pages/TicketPage.java b/src/main/java/com/gitblit/wicket/pages/TicketPage.java
index b690e4c0..4890874a 100644
--- a/src/main/java/com/gitblit/wicket/pages/TicketPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/TicketPage.java
@@ -519,6 +519,10 @@ public class TicketPage extends RepositoryPage {
* TICKET METADATA
*/
add(new Label("ticketType", ticket.type.toString()));
+
+ add(new Label("priority", ticket.priority.toString()));
+ add(new Label("severity", ticket.severity.toString()));
+
if (StringUtils.isEmpty(ticket.topic)) {
add(new Label("ticketTopic").setVisible(false));
} else {
@@ -529,6 +533,8 @@ public class TicketPage extends RepositoryPage {
}
+
+
/*
* VOTERS
*/
@@ -1425,6 +1431,12 @@ public class TicketPage extends RepositoryPage {
Fragment mergePanel = new Fragment("mergePanel", "alreadyMergedFragment", this);
mergePanel.add(new Label("mergeTitle", MessageFormat.format(getString("gb.patchsetAlreadyMerged"), ticket.mergeTo)));
return mergePanel;
+ } else if (MergeStatus.MISSING_INTEGRATION_BRANCH == mergeStatus) {
+ // target/integration branch is missing
+ Fragment mergePanel = new Fragment("mergePanel", "notMergeableFragment", this);
+ mergePanel.add(new Label("mergeTitle", MessageFormat.format(getString("gb.patchsetNotMergeable"), ticket.mergeTo)));
+ mergePanel.add(new Label("mergeMore", MessageFormat.format(getString("gb.missingIntegrationBranchMore"), ticket.mergeTo)));
+ return mergePanel;
} else {
// patchset can not be cleanly merged
Fragment mergePanel = new Fragment("mergePanel", "notMergeableFragment", this);
@@ -1503,7 +1515,7 @@ public class TicketPage extends RepositoryPage {
*/
protected RepositoryUrl getRepositoryUrl(UserModel user, RepositoryModel repository) {
HttpServletRequest req = ((WebRequest) getRequest()).getHttpServletRequest();
- List<RepositoryUrl> urls = app().gitblit().getRepositoryUrls(req, user, repository);
+ List<RepositoryUrl> urls = app().services().getRepositoryUrls(req, user, repository);
if (ArrayUtils.isEmpty(urls)) {
return null;
}
diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.html b/src/main/java/com/gitblit/wicket/pages/TicketsPage.html
index 3a3d977a..c686d1ff 100644
--- a/src/main/java/com/gitblit/wicket/pages/TicketsPage.html
+++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.html
@@ -31,17 +31,18 @@
<div class="hidden-phone">
<ul class="nav nav-list">
<li class="nav-header"><wicket:message key="gb.queries"></wicket:message></li>
- <li><a wicket:id="changesQuery"><i class="fa fa-code-fork"></i> <wicket:message key="gb.proposalTickets"></wicket:message></a></li>
- <li><a wicket:id="bugsQuery"><i class="fa fa-bug"></i> <wicket:message key="gb.bugTickets"></wicket:message></a></li>
- <li><a wicket:id="enhancementsQuery"><i class="fa fa-magic"></i> <wicket:message key="gb.enhancementTickets"></wicket:message></a></li>
- <li><a wicket:id="tasksQuery"><i class="fa fa-ticket"></i> <wicket:message key="gb.taskTickets"></wicket:message></a></li>
- <li><a wicket:id="questionsQuery"><i class="fa fa-question"></i> <wicket:message key="gb.questionTickets"></wicket:message></a></li>
+ <li><a wicket:id="changesQuery"><i class="fa fa-code-fork fa-fw"></i> <wicket:message key="gb.proposalTickets"></wicket:message></a></li>
+ <li><a wicket:id="bugsQuery"><i class="fa fa-bug fa-fw"></i> <wicket:message key="gb.bugTickets"></wicket:message></a></li>
+ <li><a wicket:id="enhancementsQuery"><i class="fa fa-magic fa-fw"></i> <wicket:message key="gb.enhancementTickets"></wicket:message></a></li>
+ <li><a wicket:id="tasksQuery"><i class="fa fa-ticket fa-fw"></i> <wicket:message key="gb.taskTickets"></wicket:message></a></li>
+ <li><a wicket:id="questionsQuery"><i class="fa fa-question fa-fw"></i> <wicket:message key="gb.questionTickets"></wicket:message></a></li>
+ <li><a wicket:id="maintenanceQuery"><i class="fa fa-cogs fa-fw"></i> <wicket:message key="gb.maintenanceTickets"></wicket:message></a></li>
<li wicket:id="userDivider" class="divider"></li>
- <li><a wicket:id="createdQuery"><i class="fa fa-user"></i> <wicket:message key="gb.yourCreatedTickets"></wicket:message></a></li>
- <li><a wicket:id="watchedQuery"><i class="fa fa-eye"></i> <wicket:message key="gb.yourWatchedTickets"></wicket:message></a></li>
- <li><a wicket:id="mentionsQuery"><i class="fa fa-comment"></i> <wicket:message key="gb.mentionsMeTickets"></wicket:message></a></li>
+ <li><a wicket:id="createdQuery"><i class="fa fa-user fa-fw"></i> <wicket:message key="gb.yourCreatedTickets"></wicket:message></a></li>
+ <li><a wicket:id="watchedQuery"><i class="fa fa-eye fa-fw"></i> <wicket:message key="gb.yourWatchedTickets"></wicket:message></a></li>
+ <li><a wicket:id="mentionsQuery"><i class="fa fa-comment fa-fw"></i> <wicket:message key="gb.mentionsMeTickets"></wicket:message></a></li>
<li class="divider"></li>
- <li><a wicket:id="resetQuery"><i class="fa fa-bolt"></i> <wicket:message key="gb.reset"></wicket:message></a></li>
+ <li><a wicket:id="resetQuery"><i class="fa fa-bolt fa-fw"></i> <wicket:message key="gb.reset"></wicket:message></a></li>
</ul>
</div>
<div wicket:id="dynamicQueries" class="hidden-phone"></div>
diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java
index 658cddec..ecfed250 100644
--- a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java
@@ -272,6 +272,16 @@ public class TicketsPage extends RepositoryPage {
sortBy,
desc,
1)));
+
+ add(new BookmarkablePageLink<Void>("maintenanceQuery", TicketsPage.class,
+ queryParameters(
+ Lucene.type.matches(TicketModel.Type.Maintenance.name()),
+ milestoneParam,
+ statiiParam,
+ assignedToParam,
+ sortBy,
+ desc,
+ 1)));
add(new BookmarkablePageLink<Void>("resetQuery", TicketsPage.class,
queryParameters(
@@ -454,7 +464,11 @@ public class TicketsPage extends RepositoryPage {
sortChoices.add(new TicketSort(getString("gb.sortLeastPatchsetRevisions"), Lucene.patchsets.name(), false));
sortChoices.add(new TicketSort(getString("gb.sortMostVotes"), Lucene.votes.name(), true));
sortChoices.add(new TicketSort(getString("gb.sortLeastVotes"), Lucene.votes.name(), false));
-
+ sortChoices.add(new TicketSort(getString("gb.sortHighestPriority"), Lucene.priority.name(), true));
+ sortChoices.add(new TicketSort(getString("gb.sortLowestPriority"), Lucene.priority.name(), false));
+ sortChoices.add(new TicketSort(getString("gb.sortHighestSeverity"), Lucene.severity.name(), true));
+ sortChoices.add(new TicketSort(getString("gb.sortLowestSeverity"), Lucene.severity.name(), false));
+
TicketSort currentSort = sortChoices.get(0);
for (TicketSort ts : sortChoices) {
if (ts.sortBy.equals(sortBy) && desc == ts.desc) {
diff --git a/src/main/java/com/gitblit/wicket/pages/TreePage.java b/src/main/java/com/gitblit/wicket/pages/TreePage.java
index 9ddbecf6..d7899dcb 100644
--- a/src/main/java/com/gitblit/wicket/pages/TreePage.java
+++ b/src/main/java/com/gitblit/wicket/pages/TreePage.java
@@ -52,7 +52,7 @@ public class TreePage extends RepositoryPage {
Repository r = getRepository();
RevCommit commit = getCommit();
- List<PathModel> paths = JGitUtils.getFilesInPath(r, path, commit);
+ List<PathModel> paths = JGitUtils.getFilesInPath2(r, path, commit);
// tree page links
add(new BookmarkablePageLink<Void>("historyLink", HistoryPage.class,
diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java
index 8931d5e3..6e7e7a76 100644
--- a/src/main/java/com/gitblit/wicket/pages/UserPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java
@@ -104,7 +104,7 @@ public class UserPage extends RootPage {
if (isMyProfile) {
addPreferences(user);
- if (app().gitblit().isServingSSH()) {
+ if (app().services().isServingSSH()) {
// show the SSH key management tab
addSshKeys(user);
} else {
@@ -248,14 +248,16 @@ public class UserPage extends RootPage {
emailMeOnMyTicketChanges).setVisible(app().notifier().isSendingMail()));
List<Transport> availableTransports = new ArrayList<>();
- if (app().gitblit().isServingSSH()) {
+ if (app().services().isServingSSH()) {
availableTransports.add(Transport.SSH);
}
- if (app().gitblit().isServingHTTP()) {
- availableTransports.add(Transport.HTTPS);
+ if (app().services().isServingHTTP()) {
availableTransports.add(Transport.HTTP);
}
- if (app().gitblit().isServingGIT()) {
+ if (app().services().isServingHTTPS()) {
+ availableTransports.add(Transport.HTTPS);
+ }
+ if (app().services().isServingGIT()) {
availableTransports.add(Transport.GIT);
}
diff --git a/src/main/java/com/gitblit/wicket/pages/scripts/imgdiff.js b/src/main/java/com/gitblit/wicket/pages/scripts/imgdiff.js
new file mode 100644
index 00000000..61575132
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/pages/scripts/imgdiff.js
@@ -0,0 +1,263 @@
+/*
+ * 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.
+ */
+(function($) {
+
+/**
+ * Sets up elem as a slider; returns an access object. Elem must be positioned!
+ * Note that the element may contain other elements; this is used for instance
+ * for the image diff overlay slider.
+ *
+ * The styling of the slider is to be done in CSS. Currently recognized options:
+ * - initial: <float> clipped to [0..1], default 0
+ * - handleClass: <string> to assign to the handle span element created.
+ * If no handleClass is specified, a very plain default style is assigned.
+ */
+function rangeSlider(elem, options) {
+ options = $.extend({ initial : 0 }, options || {});
+ options.initial = Math.min(1.0, Math.max(0, options.initial));
+
+ var $elem = $(elem);
+ var $handle = $('<span></span>').css({ position: 'absolute', left: 0, cursor: 'ew-resize' });
+ var $root = $(document.documentElement);
+ var $doc = $(document);
+ var lastRatio = options.initial;
+
+ /** Mousemove event handler to track the mouse and move the slider. Generates slider:pos events. */
+ function track(e) {
+ var pos = $elem.offset().left;
+ var width = $elem.innerWidth();
+ var handleWidth = $handle.outerWidth(false);
+ var range = width - handleWidth;
+ if (range <= 0) return;
+ var delta = Math.min(range, Math.max (0, e.pageX - pos - handleWidth / 2));
+ lastRatio = delta / range;
+ $handle.css('left', "" + (delta * 100 / width) + '%');
+ $elem.trigger('slider:pos', { ratio: lastRatio, handle: $handle[0] });
+ }
+
+ /** Mouseup event handler to stop mouse tracking. */
+ function end(e) {
+ $doc.off('mousemove', track);
+ $doc.off('mouseup', end);
+ $root.removeClass('no-select');
+ }
+
+ /** Snaps the slider to the given ratio and generates a slider:pos event with the new ratio. */
+ function setTo(ratio) {
+ var w = $elem.innerWidth();
+ if (w <= 0 || $elem.is(':hidden')) return;
+ lastRatio = Math.min( 1.0, Math.max(0, ratio));
+ $handle.css('left', "" + Math.max(0, 100 * (lastRatio * (w - $handle.outerWidth(false))) / w) + '%');
+ $elem.trigger('slider:pos', { ratio: lastRatio, handle: $handle[0] });
+ }
+
+ /**
+ * Moves the slider to the given ratio, clipped to [0..1], in duration milliseconds.
+ * Generates slider:pos events during the animation. If duration <= 30, same as setTo.
+ * Default duration is 500ms. If a callback is given, it's called once the animation
+ * has completed.
+ */
+ function moveTo(ratio, duration, callback) {
+ ratio = Math.min(1.0, Math.max(0, ratio));
+ if (ratio === lastRatio) {
+ if (typeof callback == 'function') callback();
+ return;
+ }
+ if (typeof duration == 'undefined') duration = 500;
+ if (duration <= 30) {
+ // Cinema is 24 or 48 frames/sec, so 20-40ms per frame. Makes no sense to animate for such a short duration.
+ setTo(ratio);
+ if (typeof callback == 'function') callback();
+ } else {
+ var target = ratio * ($elem.innerWidth() - $handle.outerWidth(false));
+ if (ratio > lastRatio) target--; else target++;
+ $handle.stop().animate({left: target},
+ { 'duration' : duration,
+ 'step' : function() {
+ lastRatio = Math.min(1.0, Math.max(0, $handle.position().left / ($elem.innerWidth() - $handle.outerWidth(false))));
+ $elem.trigger('slider:pos', { ratio : lastRatio, handle : $handle[0] });
+ },
+ 'complete' : function() { setTo(ratio); if (typeof callback == 'function') callback(); } // Ensure we have again a % value
+ }
+ );
+ }
+ }
+
+ /**
+ * As moveTo, but determines an appropriate duration in the range [0..maxDuration] on its own,
+ * depending on the distance the handle would move. If no maxDuration is given it defaults
+ * to 1500ms.
+ */
+ function moveAuto(ratio, maxDuration, callback) {
+ if (typeof maxDuration == 'undefined') maxDuration = 1500;
+ var delta = ratio - lastRatio;
+ if (delta < 0) delta = -delta;
+ var speed = $elem.innerWidth() * delta * 2;
+ if (speed > maxDuration) speed = maxDuration;
+ moveTo(ratio, speed, callback);
+ }
+
+ /** Returns the current ratio. */
+ function getValue() {
+ return lastRatio;
+ }
+
+ $elem.append($handle);
+ if (options.handleClass) {
+ $handle.addClass(options.handleClass);
+ } else { // Provide a default style so that it is at least visible
+ $handle.css({ width: '10px', height: '10px', background: 'white', border: '1px solid black' });
+ }
+ if (options.initial) setTo(options.initial);
+
+ /** Install mousedown handler to start mouse tracking. */
+ $handle.on('mousedown', function(e) {
+ $root.addClass('no-select');
+ $doc.on('mousemove', track);
+ $doc.on('mouseup', end);
+ e.stopPropagation();
+ e.preventDefault();
+ });
+
+ return { setRatio: setTo, moveRatio: moveTo, 'moveAuto': moveAuto, getRatio: getValue, handle: $handle[0] };
+}
+
+function setup() {
+ $('.imgdiff-container').each(function() {
+ var $this = $(this);
+ var $overlaySlider = $this.find('.imgdiff-ovr-slider').first();
+ var $opacitySlider = $this.find('.imgdiff-opa-slider').first();
+ var overlayAccess = rangeSlider($overlaySlider, {handleClass: 'imgdiff-ovr-handle'});
+ var opacityAccess = rangeSlider($opacitySlider, {handleClass: 'imgdiff-opa-handle'});
+ var $img = $('#' + this.id.substr(this.id.indexOf('-')+1)); // Here we change opacity
+ var $div = $img.parent(); // This controls visibility: here we change width.
+ var blinking = false;
+
+ $overlaySlider.on('slider:pos', function(e, data) {
+ var pos = $(data.handle).offset().left;
+ var imgLeft = $img.offset().left; // Global
+ var imgW = $img.outerWidth(true);
+ var imgOff = $img.position().left; // From left edge of $div
+ if (pos <= imgLeft) {
+ $div.width(0);
+ } else if (pos <= imgLeft + imgW) {
+ $div.width(pos - imgLeft + imgOff);
+ } else if ($div.width() < imgW + imgOff) {
+ $div.width(imgW + imgOff);
+ }
+ });
+ $overlaySlider.css('cursor', 'pointer');
+ $overlaySlider.on('mousedown', function(e) {
+ var newRatio = (e.pageX - $overlaySlider.offset().left) / $overlaySlider.innerWidth();
+ var oldRatio = overlayAccess.getRatio();
+ if (newRatio !== oldRatio) {
+ overlayAccess.moveAuto(newRatio);
+ }
+ });
+
+ var autoShowing = false;
+ $opacitySlider.on('slider:pos', function(e, data) {
+ if ($div.width() <= 0 && !blinking) {
+ // Make old image visible in a nice way, *then* adjust opacity
+ autoShowing = true;
+ overlayAccess.moveAuto(1.0, 500, function() {
+ $img.stop().animate(
+ {opacity: 1.0 - opacityAccess.getRatio()},
+ {duration: 400,
+ complete: function () {
+ // In case the opacity handle was moved while we were trying to catch up
+ $img.css('opacity', 1.0 - opacityAccess.getRatio());
+ autoShowing = false;
+ }
+ }
+ );
+ });
+ } else if (!autoShowing) {
+ $img.css('opacity', 1.0 - data.ratio);
+ }
+ });
+ $opacitySlider.on('click', function(e) {
+ var newRatio = (e.pageX - $opacitySlider.offset().left) / $opacitySlider.innerWidth();
+ var oldRatio = opacityAccess.getRatio();
+ if (newRatio !== oldRatio) {
+ if ($div.width() <= 0) {
+ overlayAccess.moveRatio(1.0, 500, function() {opacityAccess.moveAuto(newRatio);}); // Make old image visible in a nice way
+ } else {
+ opacityAccess.moveAuto(newRatio)
+ }
+ }
+ e.preventDefault();
+ });
+
+ // Blinking before and after images is a good way for the human eye to catch differences.
+ var $blinker = $this.find('.imgdiff-blink');
+ var initialOpacity = null;
+ $blinker.on('click', function(e) {
+ if (blinking) {
+ window.clearTimeout(blinking);
+ $blinker.children('img').first().css('border', '1px solid transparent');
+ opacityAccess.setRatio(initialOpacity);
+ blinking = null;
+ } else {
+ $blinker.children('img').first().css('border', '1px solid #AAA');
+ initialOpacity = opacityAccess.getRatio();
+ var currentOpacity = 1.0;
+ function blink() {
+ opacityAccess.setRatio(currentOpacity);
+ currentOpacity = 1.0 - currentOpacity;
+ // Keep frequeny below 2Hz (i.e., delay above 500ms)
+ blinking = window.setTimeout(blink, 600);
+ }
+ if ($div.width() <= 0) {
+ overlayAccess.moveRatio(1.0, 500, blink);
+ } else {
+ blink();
+ }
+ }
+ e.preventDefault();
+ });
+
+ // Subtracting before and after images is another good way to detect differences. Result will be
+ // black where identical.
+ if (typeof $img[0].style.mixBlendMode != 'undefined') {
+ // Feature test: does the browser support the mix-blend-mode CSS property from the Compositing
+ // and Blending Level 1 spec (http://dev.w3.org/fxtf/compositing-1/#mix-blend-mode )?
+ // As of 2014-11, only Firefox >= 32 and Safari >= 7.1 support this. Other browsers will have to
+ // make do with the blink comparator only.
+ var $sub = $this.find('.imgdiff-subtract');
+ $sub.css('display', 'inline-block');
+ $sub.on('click', function (e) {
+ var curr = $img.css('mix-blend-mode');
+ if (curr != 'difference') {
+ curr = 'difference';
+ $sub.children('img').first().css('border', '1px solid #AAA');
+ if ($div.width() <= 0) overlayAccess.moveRatio(1.0, 500);
+ opacityAccess.setRatio(0);
+ } else {
+ curr = 'normal';
+ $sub.children('img').first().css('border', '1px solid transparent');
+
+ }
+ $img.css('mix-blend-mode', curr);
+ e.preventDefault();
+ });
+ }
+ });
+}
+
+$(setup); // Run on jQuery's dom-ready
+
+})(jQuery); \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java b/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java
index 4433b043..e4ce5ced 100644
--- a/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java
+++ b/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java
@@ -125,7 +125,15 @@ public class FilterableRepositoryList extends BasePanel {
item.t = getTimeUtils().timeAgo(repo.lastChange);
item.d = df.format(repo.lastChange);
item.c = StringUtils.getColor(StringUtils.stripDotGit(repo.name));
- item.wc = repo.isBare ? 0 : 1;
+ if (!repo.isBare) {
+ item.y = 3;
+ } else if (repo.isMirror) {
+ item.y = 2;
+ } else if (repo.isFork()) {
+ item.y = 1;
+ } else {
+ item.y = 0;
+ }
list.add(item);
}
@@ -147,6 +155,6 @@ public class FilterableRepositoryList extends BasePanel {
String i; // information/description
long s; // stars
String c; // html color
- int wc; // working copy: 1 = true, 0 = false
+ int y; // type: 0 = normal, 1 = fork, 2 = mirror, 3 = clone
}
} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html
index 33345a0a..88de3b4c 100644
--- a/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html
+++ b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html
@@ -24,13 +24,28 @@
<p class="originRepository" style="margin-left:20px;" ><wicket:message key="gb.forkedFrom">[forked from]</wicket:message> <span wicket:id="originRepository">[origin repository]</span></p>
</wicket:fragment>
+ <wicket:fragment wicket:id="repoIconFragment">
+ <span class="mega-octicon octicon-repo"></span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="mirrorIconFragment">
+ <span class="mega-octicon octicon-mirror"></span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="forkIconFragment">
+ <span class="mega-octicon octicon-repo-forked"></span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="cloneIconFragment">
+ <span class="mega-octicon octicon-repo-push" wicket:message="title:gb.workingCopyWarning"></span>
+ </wicket:fragment>
+
<div>
<div style="padding-top:15px;padding-bottom:15px;margin-right:15px;">
<div class="pull-right" style="text-align:right;padding-right:15px;">
<span wicket:id="repositoryLinks"></span>
<div>
<img class="inlineIcon" wicket:id="sparkleshareIcon" />
- <img class="inlineIcon" wicket:id="mirrorIcon" />
<img class="inlineIcon" wicket:id="frozenIcon" />
<img class="inlineIcon" wicket:id="federatedIcon" />
@@ -42,11 +57,15 @@
</div>
<div class="pageTitle" style="border:0px;">
- <div>
- <span class="repositorySwatch" wicket:id="repositorySwatch"></span>
- <span class="repository" style="padding-left:3px;color:black;" wicket:id="repositoryName">[repository name]</span>
- </div>
- <span wicket:id="originRepository">[origin repository]</span>
+ <div style="display:inline-block;vertical-align:top;padding-right:5px;">
+ <span wicket:id="repoIcon"></span>
+ </div>
+ <div style="display:inline-block;">
+ <div>
+ <span class="repository" style="padding-left:3px;color:black;" wicket:id="repositoryName">[repository name]</span>
+ </div>
+ <span wicket:id="originRepository">[origin repository]</span>
+ </div>
</div>
<div style="padding-left:20px;">
diff --git a/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java
index 8630d201..91ce9864 100644
--- a/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java
@@ -51,24 +51,27 @@ public class ProjectRepositoryPanel extends BasePanel {
final boolean showSwatch = app().settings().getBoolean(Keys.web.repositoryListSwatches, true);
final boolean showSize = app().settings().getBoolean(Keys.web.showRepositorySizes, true);
- // repository swatch
- Component swatch;
- if (entry.isBare) {
- swatch = new Label("repositorySwatch", "&nbsp;").setEscapeModelStrings(false);
- } else {
- swatch = new Label("repositorySwatch", "!");
- WicketUtils.setHtmlTooltip(swatch, localizer.getString("gb.workingCopyWarning", parent));
- }
- WicketUtils.setCssBackground(swatch, entry.toString());
- add(swatch);
- swatch.setVisible(showSwatch);
-
PageParameters pp = WicketUtils.newRepositoryParameter(entry.name);
add(new LinkPanel("repositoryName", "list", StringUtils.getRelativePath(entry.projectPath,
StringUtils.stripDotGit(entry.name)), SummaryPage.class, pp));
add(new Label("repositoryDescription", entry.description).setVisible(!StringUtils
.isEmpty(entry.description)));
+ Fragment iconFragment;
+ if (entry.isMirror) {
+ iconFragment = new Fragment("repoIcon", "mirrorIconFragment", this);
+ } else if (entry.isFork()) {
+ iconFragment = new Fragment("repoIcon", "forkIconFragment", this);
+ } else if (entry.isBare) {
+ iconFragment = new Fragment("repoIcon", "repoIconFragment", this);
+ } else {
+ iconFragment = new Fragment("repoIcon", "cloneIconFragment", this);
+ }
+ if (showSwatch) {
+ WicketUtils.setCssStyle(iconFragment, "color:" + StringUtils.getColor(entry.toString()));
+ }
+ add(iconFragment);
+
if (StringUtils.isEmpty(entry.originRepository)) {
add(new Label("originRepository").setVisible(false));
} else {
@@ -84,13 +87,7 @@ public class ProjectRepositoryPanel extends BasePanel {
add(WicketUtils.newClearPixel("sparkleshareIcon").setVisible(false));
}
- if (entry.isMirror) {
- add(WicketUtils.newImage("mirrorIcon", "mirror_16x16.png", localizer.getString("gb.isMirror", parent)));
- } else {
- add(WicketUtils.newClearPixel("mirrorIcon").setVisible(false));
- }
-
- if (entry.isFrozen) {
+ if (!entry.isMirror && entry.isFrozen) {
add(WicketUtils.newImage("frozenIcon", "cold_16x16.png", localizer.getString("gb.isFrozen", parent)));
} else {
add(WicketUtils.newClearPixel("frozenIcon").setVisible(false));
diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.html b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.html
index e2e7b72b..2de52b09 100644
--- a/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.html
+++ b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.html
@@ -17,6 +17,22 @@
</tr>
</tbody>
</table>
+
+ <wicket:fragment wicket:id="repoIconFragment">
+ <span class="octicon octicon-centered octicon-repo"></span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="mirrorIconFragment">
+ <span class="octicon octicon-centered octicon-mirror"></span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="forkIconFragment">
+ <span class="octicon octicon-centered octicon-repo-forked"></span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="cloneIconFragment">
+ <span class="octicon octicon-centered octicon-repo-push" wicket:message="title:gb.workingCopyWarning"></span>
+ </wicket:fragment>
<wicket:fragment wicket:id="adminLinks">
<!-- page nav links -->
@@ -76,10 +92,10 @@
</wicket:fragment>
<wicket:fragment wicket:id="repositoryRow">
- <td class="left" style="padding-left:3px;" ><b><span class="repositorySwatch" wicket:id="repositorySwatch"></span></b> <span style="padding-left:3px;" wicket:id="repositoryName">[repository name]</span></td>
+ <td class="left" style="padding-left:3px;" ><span wicket:id="repoIcon"></span><span style="padding-left:3px;" wicket:id="repositoryName">[repository name]</span></td>
<td class="hidden-phone"><span class="list" wicket:id="repositoryDescription">[repository description]</span></td>
<td class="hidden-tablet hidden-phone author"><span wicket:id="repositoryOwner">[repository owner]</span></td>
- <td class="hidden-phone" style="text-align: right;padding-right:10px;"><img class="inlineIcon" wicket:id="sparkleshareIcon" /><img class="inlineIcon" wicket:id="mirrorIcon" /><img class="inlineIcon" wicket:id="forkIcon" /><img class="inlineIcon" wicket:id="frozenIcon" /><img class="inlineIcon" wicket:id="federatedIcon" /><img class="inlineIcon" wicket:id="accessRestrictionIcon" /></td>
+ <td class="hidden-phone" style="text-align: right;padding-right:10px;"><img class="inlineIcon" wicket:id="sparkleshareIcon" /><img class="inlineIcon" wicket:id="frozenIcon" /><img class="inlineIcon" wicket:id="federatedIcon" /><img class="inlineIcon" wicket:id="accessRestrictionIcon" /></td>
<td><span wicket:id="repositoryLastChange">[last change]</span></td>
<td class="rightAlign hidden-phone" style="text-align: right;padding-right:15px;"><span style="font-size:0.8em;" wicket:id="repositorySize">[repository size]</span></td>
</wicket:fragment>
diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java
index 8573e1a6..c3f07099 100644
--- a/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java
@@ -24,7 +24,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import org.apache.wicket.Component;
import org.apache.wicket.PageParameters;
import org.apache.wicket.extensions.markup.html.repeater.data.sort.OrderByBorder;
import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
@@ -183,24 +182,28 @@ public class RepositoriesPanel extends BasePanel {
Fragment row = new Fragment("rowContent", "repositoryRow", this);
item.add(row);
+ // show colored repository type icon
+ Fragment iconFragment;
+ if (entry.isMirror) {
+ iconFragment = new Fragment("repoIcon", "mirrorIconFragment", this);
+ } else if (entry.isFork()) {
+ iconFragment = new Fragment("repoIcon", "forkIconFragment", this);
+ } else if (entry.isBare) {
+ iconFragment = new Fragment("repoIcon", "repoIconFragment", this);
+ } else {
+ iconFragment = new Fragment("repoIcon", "cloneIconFragment", this);
+ }
+ if (showSwatch) {
+ WicketUtils.setCssStyle(iconFragment, "color:" + StringUtils.getColor(entry.toString()));
+ }
+ row.add(iconFragment);
+
// try to strip group name for less cluttered list
String repoName = entry.toString();
if (!StringUtils.isEmpty(currGroupName) && (repoName.indexOf('/') > -1)) {
repoName = repoName.substring(currGroupName.length() + 1);
}
- // repository swatch
- Component swatch;
- if (entry.isBare){
- swatch = new Label("repositorySwatch", "&nbsp;").setEscapeModelStrings(false);
- } else {
- swatch = new Label("repositorySwatch", "!");
- WicketUtils.setHtmlTooltip(swatch, getString("gb.workingCopyWarning"));
- }
- WicketUtils.setCssBackground(swatch, entry.toString());
- row.add(swatch);
- swatch.setVisible(showSwatch);
-
if (linksActive) {
Class<? extends BasePage> linkPage = SummaryPage.class;
PageParameters pp = WicketUtils.newRepositoryParameter(entry.name);
@@ -228,21 +231,7 @@ public class RepositoriesPanel extends BasePanel {
row.add(WicketUtils.newClearPixel("sparkleshareIcon").setVisible(false));
}
- if (entry.isMirror) {
- row.add(WicketUtils.newImage("mirrorIcon", "mirror_16x16.png",
- getString("gb.isMirror")));
- } else {
- row.add(WicketUtils.newClearPixel("mirrorIcon").setVisible(false));
- }
-
- if (entry.isFork()) {
- row.add(WicketUtils.newImage("forkIcon", "commit_divide_16x16.png",
- getString("gb.isFork")));
- } else {
- row.add(WicketUtils.newClearPixel("forkIcon").setVisible(false));
- }
-
- if (entry.isFrozen) {
+ if (!entry.isMirror && entry.isFrozen) {
row.add(WicketUtils.newImage("frozenIcon", "cold_16x16.png",
getString("gb.isFrozen")));
} else {
@@ -255,24 +244,30 @@ public class RepositoriesPanel extends BasePanel {
} else {
row.add(WicketUtils.newClearPixel("federatedIcon").setVisible(false));
}
- switch (entry.accessRestriction) {
- case NONE:
- row.add(WicketUtils.newBlankImage("accessRestrictionIcon"));
- break;
- case PUSH:
- row.add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png",
- accessRestrictionTranslations.get(entry.accessRestriction)));
- break;
- case CLONE:
- row.add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png",
- accessRestrictionTranslations.get(entry.accessRestriction)));
- break;
- case VIEW:
- row.add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png",
- accessRestrictionTranslations.get(entry.accessRestriction)));
- break;
- default:
- row.add(WicketUtils.newBlankImage("accessRestrictionIcon"));
+
+ if (entry.isMirror) {
+ row.add(WicketUtils.newImage("accessRestrictionIcon", "mirror_16x16.png",
+ getString("gb.isMirror")));
+ } else {
+ switch (entry.accessRestriction) {
+ case NONE:
+ row.add(WicketUtils.newBlankImage("accessRestrictionIcon"));
+ break;
+ case PUSH:
+ row.add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png",
+ accessRestrictionTranslations.get(entry.accessRestriction)));
+ break;
+ case CLONE:
+ row.add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png",
+ accessRestrictionTranslations.get(entry.accessRestriction)));
+ break;
+ case VIEW:
+ row.add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png",
+ accessRestrictionTranslations.get(entry.accessRestriction)));
+ break;
+ default:
+ row.add(WicketUtils.newBlankImage("accessRestrictionIcon"));
+ }
}
String owner = "";
diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java
index 938226a6..0666fcd8 100644
--- a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java
@@ -80,7 +80,7 @@ public class RepositoryUrlPanel extends BasePanel {
HttpServletRequest req = ((WebRequest) getRequest()).getHttpServletRequest();
- List<RepositoryUrl> repositoryUrls = app().gitblit().getRepositoryUrls(req, user, repository);
+ List<RepositoryUrl> repositoryUrls = app().services().getRepositoryUrls(req, user, repository);
// grab primary url from the top of the list
primaryUrl = repositoryUrls.size() == 0 ? null : repositoryUrls.get(0);
@@ -165,7 +165,7 @@ public class RepositoryUrlPanel extends BasePanel {
if (repository.isMirror) {
urlPanel.add(WicketUtils.newImage("accessRestrictionIcon", "mirror_16x16.png",
getString("gb.isMirror")));
- } else if (app().gitblit().isServingRepositories()) {
+ } else if (app().services().isServingRepositories()) {
switch (repository.accessRestriction) {
case NONE:
urlPanel.add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
diff --git a/src/main/java/com/gitblit/wicket/panels/TeamsPanel.html b/src/main/java/com/gitblit/wicket/panels/TeamsPanel.html
index ff689292..2cce7b18 100644
--- a/src/main/java/com/gitblit/wicket/panels/TeamsPanel.html
+++ b/src/main/java/com/gitblit/wicket/panels/TeamsPanel.html
@@ -15,16 +15,18 @@
<img style="vertical-align: middle; border: 1px solid #888; background-color: white;" src="users_16x16.png"/>
<wicket:message key="gb.teams">[teams]</wicket:message>
</th>
+ <th class="hidden-phone" style="width:140px;"><wicket:message key="gb.type">[type]</wicket:message></th>
<th class="hidden-phone" style="width:140px;"><wicket:message key="gb.teamMembers">[team members]</wicket:message></th>
<th class="hidden-phone" style="width:100px;"><wicket:message key="gb.repositories">[repositories]</wicket:message></th>
<th style="width:80px;" class="right"></th>
</tr>
- <tbody>
+ <tbody>
<tr wicket:id="teamRow">
<td class="left" ><div class="list" wicket:id="teamname">[teamname]</div></td>
+ <td class="hidden-phone left" ><span style="font-size: 0.8em;" wicket:id="accountType">[account type]</span></td>
<td class="hidden-phone left" ><div class="list" wicket:id="members">[members]</div></td>
<td class="hidden-phone left" ><div class="list" wicket:id="repositories">[repositories]</div></td>
- <td class="rightAlign"><span wicket:id="teamLinks"></span></td>
+ <td class="rightAlign"><span wicket:id="teamLinks"></span></td>
</tr>
</tbody>
</table>
diff --git a/src/main/java/com/gitblit/wicket/panels/TeamsPanel.java b/src/main/java/com/gitblit/wicket/panels/TeamsPanel.java
index c1e1a43d..7f3fd9a2 100644
--- a/src/main/java/com/gitblit/wicket/panels/TeamsPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/TeamsPanel.java
@@ -60,6 +60,7 @@ public class TeamsPanel extends BasePanel {
EditTeamPage.class, WicketUtils.newTeamnameParameter(entry.name));
WicketUtils.setHtmlTooltip(editLink, getString("gb.edit") + " " + entry.name);
item.add(editLink);
+ item.add(new Label("accountType", entry.accountType.name()));
item.add(new Label("members", entry.users.size() > 0 ? ("" + entry.users.size())
: ""));
item.add(new Label("repositories",
diff --git a/src/main/java/com/gitblit/wicket/panels/TicketListPanel.html b/src/main/java/com/gitblit/wicket/panels/TicketListPanel.html
index 30f50367..659baeac 100644
--- a/src/main/java/com/gitblit/wicket/panels/TicketListPanel.html
+++ b/src/main/java/com/gitblit/wicket/panels/TicketListPanel.html
@@ -30,6 +30,9 @@
<td class="hidden-phone ticket-list-state">
<i wicket:message="title:gb.watching" style="color:#888;" class="fa fa-eye" wicket:id="watching"></i>
</td>
+ <td class="ticket-list-priority">
+ <div wicket:id="priority"></div>
+ </td>
<td class="ticket-list-state">
<div wicket:id="status"></div>
</td>
diff --git a/src/main/java/com/gitblit/wicket/panels/TicketListPanel.java b/src/main/java/com/gitblit/wicket/panels/TicketListPanel.java
index cc0b57a8..2ac33d53 100644
--- a/src/main/java/com/gitblit/wicket/panels/TicketListPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/TicketListPanel.java
@@ -83,7 +83,10 @@ public class TicketListPanel extends BasePanel {
item.add(new Label("ticketsLink").setVisible(false));
}
- item.add(TicketsUI.getStateIcon("state", ticket.type, ticket.status));
+ Label icon = TicketsUI.getStateIcon("state", ticket.type, ticket.status, ticket.severity);
+ WicketUtils.addCssClass(icon, TicketsUI.getSeverityClass(ticket.severity));
+ item.add(icon);
+
item.add(new Label("id", "" + ticket.number));
UserModel creator = app().users().getUserModel(ticket.createdBy);
if (creator != null) {
@@ -167,6 +170,11 @@ public class TicketListPanel extends BasePanel {
// watching indicator
item.add(new Label("watching").setVisible(ticket.isWatching(GitBlitWebSession.get().getUsername())));
+ // priority indicator
+ Label priorityIcon = TicketsUI.getPriorityIcon("priority", ticket.priority);
+ WicketUtils.addCssClass(priorityIcon, TicketsUI.getPriorityClass(ticket.priority));
+ item.add(priorityIcon.setVisible(true));
+
// status indicator
String css = TicketsUI.getLozengeClass(ticket.status, true);
Label l = new Label("status", ticket.status.toString());