| | |
| | | */ |
| | | package com.gitblit; |
| | | |
| | | import java.io.BufferedReader; |
| | | import java.io.File; |
| | | import java.io.FileInputStream; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.io.InputStreamReader; |
| | | import java.lang.reflect.Type; |
| | | import java.text.MessageFormat; |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | |
| | | import javax.servlet.http.HttpServletResponse; |
| | | |
| | | import org.eclipse.jgit.lib.Repository; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.Constants.AccessPermission; |
| | | import com.gitblit.Constants.AccessRestrictionType; |
| | | import com.gitblit.Constants.FederationRequest; |
| | | import com.gitblit.Constants.FederationToken; |
| | | import com.gitblit.manager.IAuthenticationManager; |
| | | import com.gitblit.manager.IFederationManager; |
| | | import com.gitblit.manager.IGitblitManager; |
| | | import com.gitblit.manager.IGitblit; |
| | | import com.gitblit.manager.INotificationManager; |
| | | 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.FederationModel; |
| | | import com.gitblit.models.FederationProposal; |
| | | import com.gitblit.models.FederationSet; |
| | |
| | | import com.gitblit.models.SearchResult; |
| | | import com.gitblit.models.ServerSettings; |
| | | import com.gitblit.models.ServerStatus; |
| | | import com.gitblit.models.SettingModel; |
| | | import com.gitblit.models.TeamModel; |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.utils.ArrayUtils; |
| | | import com.gitblit.utils.HttpUtils; |
| | | import com.gitblit.utils.JGitUtils; |
| | | import com.gitblit.utils.JsonUtils; |
| | | import com.gitblit.utils.ObjectCache; |
| | | import com.gitblit.utils.StringUtils; |
| | | import com.google.gson.Gson; |
| | | import com.google.gson.JsonIOException; |
| | | import com.google.gson.JsonSyntaxException; |
| | | import com.google.gson.reflect.TypeToken; |
| | | |
| | | /** |
| | | * GitBlit is an aggregate interface delegate. It implements all the manager |
| | |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | public class GitBlit implements IRuntimeManager, |
| | | INotificationManager, |
| | | IUserManager, |
| | | IAuthenticationManager, |
| | | IRepositoryManager, |
| | | IProjectManager, |
| | | IGitblitManager, |
| | | IFederationManager { |
| | | public class GitBlit implements IGitblit { |
| | | |
| | | private final Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | private final ObjectCache<Collection<GitClientApplication>> clientApplications = new ObjectCache<Collection<GitClientApplication>>(); |
| | | |
| | | private final IStoredSettings settings; |
| | | |
| | | private final IRuntimeManager runtimeManager; |
| | | |
| | |
| | | |
| | | private final IProjectManager projectManager; |
| | | |
| | | private final IGitblitManager gitblitManager; |
| | | |
| | | private final IFederationManager federationManager; |
| | | |
| | | private final ServicesManager servicesManager; |
| | | |
| | | public GitBlit( |
| | | IRuntimeManager runtimeManager, |
| | |
| | | IAuthenticationManager authenticationManager, |
| | | IRepositoryManager repositoryManager, |
| | | IProjectManager projectManager, |
| | | IGitblitManager gitblitManager, |
| | | IFederationManager federationManager) { |
| | | |
| | | this.settings = runtimeManager.getSettings(); |
| | | this.runtimeManager = runtimeManager; |
| | | this.notificationManager = notificationManager; |
| | | this.userManager = userManager; |
| | | this.authenticationManager = authenticationManager; |
| | | this.repositoryManager = repositoryManager; |
| | | this.projectManager = projectManager; |
| | | this.gitblitManager = gitblitManager; |
| | | this.federationManager = federationManager; |
| | | |
| | | this.servicesManager = new ServicesManager(this); |
| | | } |
| | | |
| | | @Override |
| | | public GitBlit start() { |
| | | loadSettingModels(runtimeManager.getSettingsModel()); |
| | | logger.info("Starting services manager..."); |
| | | servicesManager.start(); |
| | | return this; |
| | | } |
| | | |
| | | @Override |
| | | public GitBlit stop() { |
| | | servicesManager.stop(); |
| | | return this; |
| | | } |
| | | |
| | | /* |
| | | * IGITBLIT |
| | | */ |
| | | |
| | | /** |
| | | * Creates a personal fork of the specified repository. The clone is view |
| | | * restricted by default and the owner of the source repository is given |
| | | * access to the clone. |
| | | * |
| | | * @param repository |
| | | * @param user |
| | | * @return the repository model of the fork, if successful |
| | | * @throws GitBlitException |
| | | */ |
| | | @Override |
| | | public RepositoryModel fork(RepositoryModel repository, UserModel user) throws GitBlitException { |
| | | String cloneName = MessageFormat.format("{0}/{1}.git", user.getPersonalPath(), StringUtils.stripDotGit(StringUtils.getLastPathElement(repository.name))); |
| | | String fromUrl = MessageFormat.format("file://{0}/{1}", repositoryManager.getRepositoriesFolder().getAbsolutePath(), repository.name); |
| | | |
| | | // clone the repository |
| | | try { |
| | | JGitUtils.cloneRepository(repositoryManager.getRepositoriesFolder(), cloneName, fromUrl, true, null); |
| | | } catch (Exception e) { |
| | | throw new GitBlitException(e); |
| | | } |
| | | |
| | | // create a Gitblit repository model for the clone |
| | | RepositoryModel cloneModel = repository.cloneAs(cloneName); |
| | | // owner has REWIND/RW+ permissions |
| | | cloneModel.addOwner(user.username); |
| | | repositoryManager.updateRepositoryModel(cloneName, cloneModel, false); |
| | | |
| | | // add the owner of the source repository to the clone's access list |
| | | if (!ArrayUtils.isEmpty(repository.owners)) { |
| | | for (String owner : repository.owners) { |
| | | UserModel originOwner = userManager.getUserModel(owner); |
| | | if (originOwner != null) { |
| | | originOwner.setRepositoryPermission(cloneName, AccessPermission.CLONE); |
| | | updateUserModel(originOwner.username, originOwner, false); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // grant origin's user list clone permission to fork |
| | | List<String> users = repositoryManager.getRepositoryUsers(repository); |
| | | List<UserModel> cloneUsers = new ArrayList<UserModel>(); |
| | | for (String name : users) { |
| | | if (!name.equalsIgnoreCase(user.username)) { |
| | | UserModel cloneUser = userManager.getUserModel(name); |
| | | if (cloneUser.canClone(repository)) { |
| | | // origin user can clone origin, grant clone access to fork |
| | | cloneUser.setRepositoryPermission(cloneName, AccessPermission.CLONE); |
| | | } |
| | | cloneUsers.add(cloneUser); |
| | | } |
| | | } |
| | | userManager.updateUserModels(cloneUsers); |
| | | |
| | | // grant origin's team list clone permission to fork |
| | | List<String> teams = repositoryManager.getRepositoryTeams(repository); |
| | | List<TeamModel> cloneTeams = new ArrayList<TeamModel>(); |
| | | for (String name : teams) { |
| | | TeamModel cloneTeam = userManager.getTeamModel(name); |
| | | if (cloneTeam.canClone(repository)) { |
| | | // origin team can clone origin, grant clone access to fork |
| | | cloneTeam.setRepositoryPermission(cloneName, AccessPermission.CLONE); |
| | | } |
| | | cloneTeams.add(cloneTeam); |
| | | } |
| | | userManager.updateTeamModels(cloneTeams); |
| | | |
| | | // add this clone to the cached model |
| | | repositoryManager.addToCachedRepositoryList(cloneModel); |
| | | return cloneModel; |
| | | } |
| | | |
| | | /** |
| | | * Updates the TeamModel object for the specified name. |
| | | * |
| | | * @param teamname |
| | | * @param team |
| | | * @param isCreate |
| | | */ |
| | | @Override |
| | | public void updateTeamModel(String teamname, TeamModel team, boolean isCreate) |
| | | throws GitBlitException { |
| | | if (!teamname.equalsIgnoreCase(team.name)) { |
| | | if (userManager.getTeamModel(team.name) != null) { |
| | | throw new GitBlitException(MessageFormat.format( |
| | | "Failed to rename ''{0}'' because ''{1}'' already exists.", teamname, |
| | | team.name)); |
| | | } |
| | | } |
| | | if (!userManager.updateTeamModel(teamname, team)) { |
| | | throw new GitBlitException(isCreate ? "Failed to add team!" : "Failed to update team!"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Adds/updates a complete user object keyed by username. This method allows |
| | | * for renaming a user. |
| | | * |
| | | * @see IUserService.updateUserModel(String, UserModel) |
| | | * @param username |
| | | * @param user |
| | | * @param isCreate |
| | | * @throws GitBlitException |
| | | */ |
| | | @Override |
| | | public void updateUserModel(String username, UserModel user, boolean isCreate) |
| | | throws GitBlitException { |
| | | if (!username.equalsIgnoreCase(user.username)) { |
| | | if (userManager.getUserModel(user.username) != null) { |
| | | throw new GitBlitException(MessageFormat.format( |
| | | "Failed to rename ''{0}'' because ''{1}'' already exists.", username, |
| | | user.username)); |
| | | } |
| | | |
| | | // rename repositories and owner fields for all repositories |
| | | for (RepositoryModel model : repositoryManager.getRepositoryModels(user)) { |
| | | if (model.isUsersPersonalRepository(username)) { |
| | | // personal repository |
| | | model.addOwner(user.username); |
| | | String oldRepositoryName = model.name; |
| | | model.name = user.getPersonalPath() + model.name.substring(model.projectPath.length()); |
| | | model.projectPath = user.getPersonalPath(); |
| | | repositoryManager.updateRepositoryModel(oldRepositoryName, model, false); |
| | | } else if (model.isOwner(username)) { |
| | | // common/shared repo |
| | | model.addOwner(user.username); |
| | | repositoryManager.updateRepositoryModel(model.name, model, false); |
| | | } |
| | | } |
| | | } |
| | | if (!userManager.updateUserModel(username, user)) { |
| | | throw new GitBlitException(isCreate ? "Failed to add user!" : "Failed to update user!"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 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)); |
| | | } |
| | | } |
| | | |
| | | // 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)) { |
| | | 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)); |
| | | } |
| | | } |
| | | return list; |
| | | } |
| | | |
| | | protected String getRepositoryUrl(HttpServletRequest request, String username, RepositoryModel repository) { |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append(HttpUtils.getGitblitURL(request)); |
| | | 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; |
| | | * |
| | | * @return a collection of client applications |
| | | */ |
| | | @Override |
| | | public Collection<GitClientApplication> getClientApplications() { |
| | | // prefer user definitions, if they exist |
| | | File userDefs = new File(runtimeManager.getBaseFolder(), "clientapps.json"); |
| | | if (userDefs.exists()) { |
| | | Date lastModified = new Date(userDefs.lastModified()); |
| | | if (clientApplications.hasCurrent("user", lastModified)) { |
| | | return clientApplications.getObject("user"); |
| | | } else { |
| | | // (re)load user definitions |
| | | try { |
| | | InputStream is = new FileInputStream(userDefs); |
| | | Collection<GitClientApplication> clients = readClientApplications(is); |
| | | is.close(); |
| | | if (clients != null) { |
| | | clientApplications.updateObject("user", lastModified, clients); |
| | | return clients; |
| | | } |
| | | } catch (IOException e) { |
| | | logger.error("Failed to deserialize " + userDefs.getAbsolutePath(), e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // no user definitions, use system definitions |
| | | if (!clientApplications.hasCurrent("system", new Date(0))) { |
| | | try { |
| | | InputStream is = getClass().getResourceAsStream("/clientapps.json"); |
| | | Collection<GitClientApplication> clients = readClientApplications(is); |
| | | is.close(); |
| | | if (clients != null) { |
| | | clientApplications.updateObject("system", new Date(0), clients); |
| | | } |
| | | } catch (IOException e) { |
| | | logger.error("Failed to deserialize clientapps.json resource!", e); |
| | | } |
| | | } |
| | | |
| | | return clientApplications.getObject("system"); |
| | | } |
| | | |
| | | private Collection<GitClientApplication> readClientApplications(InputStream is) { |
| | | try { |
| | | Type type = new TypeToken<Collection<GitClientApplication>>() { |
| | | }.getType(); |
| | | InputStreamReader reader = new InputStreamReader(is); |
| | | Gson gson = JsonUtils.gson(); |
| | | Collection<GitClientApplication> links = gson.fromJson(reader, type); |
| | | return links; |
| | | } catch (JsonIOException e) { |
| | | logger.error("Error deserializing client applications!", e); |
| | | } catch (JsonSyntaxException e) { |
| | | logger.error("Error deserializing client applications!", e); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * Parse the properties file and aggregate all the comments by the setting |
| | | * key. A setting model tracks the current value, the default value, the |
| | | * description of the setting and and directives about the setting. |
| | | * |
| | | * @return Map<String, SettingModel> |
| | | */ |
| | | private void loadSettingModels(ServerSettings settingsModel) { |
| | | try { |
| | | // Read bundled Gitblit properties to extract setting descriptions. |
| | | // This copy is pristine and only used for populating the setting |
| | | // models map. |
| | | InputStream is = getClass().getResourceAsStream("/reference.properties"); |
| | | BufferedReader propertiesReader = new BufferedReader(new InputStreamReader(is)); |
| | | StringBuilder description = new StringBuilder(); |
| | | SettingModel setting = new SettingModel(); |
| | | String line = null; |
| | | while ((line = propertiesReader.readLine()) != null) { |
| | | if (line.length() == 0) { |
| | | description.setLength(0); |
| | | setting = new SettingModel(); |
| | | } else { |
| | | if (line.charAt(0) == '#') { |
| | | if (line.length() > 1) { |
| | | String text = line.substring(1).trim(); |
| | | if (SettingModel.CASE_SENSITIVE.equals(text)) { |
| | | setting.caseSensitive = true; |
| | | } else if (SettingModel.RESTART_REQUIRED.equals(text)) { |
| | | setting.restartRequired = true; |
| | | } else if (SettingModel.SPACE_DELIMITED.equals(text)) { |
| | | setting.spaceDelimited = true; |
| | | } else if (text.startsWith(SettingModel.SINCE)) { |
| | | try { |
| | | setting.since = text.split(" ")[1]; |
| | | } catch (Exception e) { |
| | | setting.since = text; |
| | | } |
| | | } else { |
| | | description.append(text); |
| | | description.append('\n'); |
| | | } |
| | | } |
| | | } else { |
| | | String[] kvp = line.split("=", 2); |
| | | String key = kvp[0].trim(); |
| | | setting.name = key; |
| | | setting.defaultValue = kvp[1].trim(); |
| | | setting.currentValue = setting.defaultValue; |
| | | setting.description = description.toString().trim(); |
| | | settingsModel.add(setting); |
| | | description.setLength(0); |
| | | setting = new SettingModel(); |
| | | } |
| | | } |
| | | } |
| | | propertiesReader.close(); |
| | | } catch (NullPointerException e) { |
| | | logger.error("Failed to find resource copy of gitblit.properties"); |
| | | } catch (IOException e) { |
| | | logger.error("Failed to load resource copy of gitblit.properties"); |
| | | } |
| | | } |
| | | |
| | | /* |
| | |
| | | @Override |
| | | public boolean deletePendingFederationProposal(FederationProposal proposal) { |
| | | return federationManager.deletePendingFederationProposal(proposal); |
| | | } |
| | | |
| | | /* |
| | | * GITBLIT MANAGER |
| | | */ |
| | | |
| | | @Override |
| | | public RepositoryModel fork(RepositoryModel repository, UserModel user) throws GitBlitException { |
| | | return gitblitManager.fork(repository, user); |
| | | } |
| | | |
| | | @Override |
| | | public void updateTeamModel(String teamname, TeamModel team, boolean isCreate) |
| | | throws GitBlitException { |
| | | gitblitManager.updateTeamModel(teamname, team, isCreate); |
| | | } |
| | | |
| | | @Override |
| | | public void updateUserModel(String username, UserModel user, boolean isCreate) |
| | | throws GitBlitException { |
| | | gitblitManager.updateUserModel(username, user, isCreate); |
| | | } |
| | | |
| | | @Override |
| | | public List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) { |
| | | return gitblitManager.getRepositoryUrls(request, user, repository); |
| | | } |
| | | |
| | | @Override |
| | | public Collection<GitClientApplication> getClientApplications() { |
| | | return gitblitManager.getClientApplications(); |
| | | } |
| | | } |