From 06ae63123c94038b90153f4847de2c57c0193db8 Mon Sep 17 00:00:00 2001 From: Rafael Cavazin <rafaelcavazin@gmail.com> Date: Sun, 27 Jan 2013 09:46:50 -0500 Subject: [PATCH] updating current development --- src/com/gitblit/GitBlit.java | 247 ++++++++++++++++++++++++++++++++++++------------- 1 files changed, 181 insertions(+), 66 deletions(-) diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java index 96333a0..6bf75d7 100644 --- a/src/com/gitblit/GitBlit.java +++ b/src/com/gitblit/GitBlit.java @@ -85,6 +85,9 @@ import com.gitblit.Constants.FederationToken; import com.gitblit.Constants.PermissionType; import com.gitblit.Constants.RegistrantType; +import com.gitblit.fanout.FanoutNioService; +import com.gitblit.fanout.FanoutService; +import com.gitblit.fanout.FanoutSocketService; import com.gitblit.models.FederationModel; import com.gitblit.models.FederationProposal; import com.gitblit.models.FederationSet; @@ -154,8 +157,14 @@ private final Map<String, ProjectModel> projectCache = new ConcurrentHashMap<String, ProjectModel>(); private final AtomicReference<String> repositoryListSettingsChecksum = new AtomicReference<String>(""); + + private final ObjectCache<String> projectMarkdownCache = new ObjectCache<String>(); + + private final ObjectCache<String> projectRepositoriesMarkdownCache = new ObjectCache<String>(); private ServletContext servletContext; + + private File baseFolder; private File repositoriesFolder; @@ -176,6 +185,8 @@ private TimeZone timezone; private FileBasedConfig projectConfigs; + + private FanoutService fanoutService; public GitBlit() { if (gitblit == null) { @@ -385,12 +396,8 @@ * @return the file */ public static File getFileOrFolder(String fileOrFolder) { - String openShift = System.getenv("OPENSHIFT_DATA_DIR"); - if (!StringUtils.isEmpty(openShift)) { - // running on RedHat OpenShift - return new File(openShift, fileOrFolder); - } - return new File(fileOrFolder); + return com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$, + self().baseFolder, fileOrFolder); } /** @@ -400,7 +407,7 @@ * @return the repositories folder path */ public static File getRepositoriesFolder() { - return getFileOrFolder(Keys.git.repositoriesFolder, "git"); + return getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git"); } /** @@ -410,7 +417,7 @@ * @return the proposals folder path */ public static File getProposalsFolder() { - return getFileOrFolder(Keys.federation.proposalsFolder, "proposals"); + return getFileOrFolder(Keys.federation.proposalsFolder, "${baseFolder}/proposals"); } /** @@ -420,9 +427,9 @@ * @return the Groovy scripts folder path */ public static File getGroovyScriptsFolder() { - return getFileOrFolder(Keys.groovy.scriptsFolder, "groovy"); + return getFileOrFolder(Keys.groovy.scriptsFolder, "${baseFolder}/groovy"); } - + /** * Updates the list of server settings. * @@ -467,36 +474,48 @@ this.userService.setup(settings); } + public boolean supportsAddUser() { + return supportsCredentialChanges(new UserModel("")); + } + /** + * Returns true if the user's credentials can be changed. * + * @param user * @return true if the user service supports credential changes */ - public boolean supportsCredentialChanges() { - return userService.supportsCredentialChanges(); + public boolean supportsCredentialChanges(UserModel user) { + return (user != null && user.isLocalAccount()) || userService.supportsCredentialChanges(); } /** + * Returns true if the user's display name can be changed. * + * @param user * @return true if the user service supports display name changes */ - public boolean supportsDisplayNameChanges() { - return userService.supportsDisplayNameChanges(); + public boolean supportsDisplayNameChanges(UserModel user) { + return (user != null && user.isLocalAccount()) || userService.supportsDisplayNameChanges(); } /** + * Returns true if the user's email address can be changed. * + * @param user * @return true if the user service supports email address changes */ - public boolean supportsEmailAddressChanges() { - return userService.supportsEmailAddressChanges(); + public boolean supportsEmailAddressChanges(UserModel user) { + return (user != null && user.isLocalAccount()) || userService.supportsEmailAddressChanges(); } /** + * Returns true if the user's team memberships can be changed. * + * @param user * @return true if the user service supports team membership changes */ - public boolean supportsTeamMembershipChanges() { - return userService.supportsTeamMembershipChanges(); + public boolean supportsTeamMembershipChanges(UserModel user) { + return (user != null && user.isLocalAccount()) || userService.supportsTeamMembershipChanges(); } /** @@ -785,6 +804,10 @@ * @return the effective list of permissions for the user */ public List<RegistrantAccessPermission> getUserAccessPermissions(UserModel user) { + if (StringUtils.isEmpty(user.username)) { + // new user + return new ArrayList<RegistrantAccessPermission>(); + } Set<RegistrantAccessPermission> set = new LinkedHashSet<RegistrantAccessPermission>(); set.addAll(user.getRepositoryPermissions()); // Flag missing repositories @@ -916,14 +939,14 @@ for (RepositoryModel model : getRepositoryModels(user)) { if (model.isUsersPersonalRepository(username)) { // personal repository - model.owner = user.username; + model.addOwner(user.username); String oldRepositoryName = model.name; model.name = "~" + user.username + model.name.substring(model.projectPath.length()); model.projectPath = "~" + user.username; updateRepositoryModel(oldRepositoryName, model, false); } else if (model.isOwner(username)) { // common/shared repo - model.owner = user.username; + model.addOwner(user.username); updateRepositoryModel(model.name, model, false); } } @@ -1351,8 +1374,8 @@ if (config.isOutdated()) { // reload model logger.info(MessageFormat.format("Config for \"{0}\" has changed. Reloading model and updating cache.", repositoryName)); - model = loadRepositoryModel(repositoryName); - removeFromCachedRepositoryList(repositoryName); + model = loadRepositoryModel(model.name); + removeFromCachedRepositoryList(model.name); addToCachedRepositoryList(model); } else { // update a few repository parameters @@ -1402,7 +1425,30 @@ } project.title = projectConfigs.getString("project", name, "title"); project.description = projectConfigs.getString("project", name, "description"); - configs.put(name.toLowerCase(), project); + + // project markdown + File pmkd = new File(getRepositoriesFolder(), (project.isRoot ? "" : name) + "/project.mkd"); + if (pmkd.exists()) { + Date lm = new Date(pmkd.lastModified()); + if (!projectMarkdownCache.hasCurrent(name, lm)) { + String mkd = com.gitblit.utils.FileUtils.readContent(pmkd, "\n"); + projectMarkdownCache.updateObject(name, lm, mkd); + } + project.projectMarkdown = projectMarkdownCache.getObject(name); + } + + // project repositories markdown + File rmkd = new File(getRepositoriesFolder(), (project.isRoot ? "" : name) + "/repositories.mkd"); + if (rmkd.exists()) { + Date lm = new Date(rmkd.lastModified()); + if (!projectRepositoriesMarkdownCache.hasCurrent(name, lm)) { + String mkd = com.gitblit.utils.FileUtils.readContent(rmkd, "\n"); + projectRepositoriesMarkdownCache.updateObject(name, lm, mkd); + } + project.repositoriesMarkdown = projectRepositoriesMarkdownCache.getObject(name); + } + + configs.put(name.toLowerCase(), project); } projectCache.clear(); projectCache.putAll(configs); @@ -1604,7 +1650,7 @@ } RepositoryModel model = new RepositoryModel(); model.isBare = r.isBare(); - File basePath = getFileOrFolder(Keys.git.repositoriesFolder, "git"); + File basePath = getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git"); if (model.isBare) { model.name = com.gitblit.utils.FileUtils.getRelativePath(basePath, r.getDirectory()); } else { @@ -1619,7 +1665,7 @@ if (config != null) { model.description = getConfig(config, "description", ""); - model.owner = getConfig(config, "owner", ""); + model.addOwners(ArrayUtils.fromString(getConfig(config, "owner", ""))); model.useTickets = getConfig(config, "useTickets", false); model.useDocs = getConfig(config, "useDocs", false); model.allowForks = getConfig(config, "allowForks", true); @@ -1667,6 +1713,7 @@ } model.HEAD = JGitUtils.getHEADRef(r); model.availableRefs = JGitUtils.getAvailableHeadTargets(r); + model.sparkleshareId = JGitUtils.getSparkleshareId(r); r.close(); if (model.origin != null && model.origin.startsWith("file://")) { @@ -1823,11 +1870,16 @@ private ForkModel getForkModelFromCache(String repository) { RepositoryModel model = repositoryListCache.get(repository.toLowerCase()); + if (model == null) { + return null; + } ForkModel fork = new ForkModel(model); if (!ArrayUtils.isEmpty(model.forks)) { for (String aFork : model.forks) { ForkModel fm = getForkModelFromCache(aFork); - fork.forks.add(fm); + if (fm != null) { + fork.forks.add(fm); + } } } return fork; @@ -1835,11 +1887,16 @@ private ForkModel getForkModel(String repository) { RepositoryModel model = getRepositoryModel(repository.toLowerCase()); + if (model == null) { + return null; + } ForkModel fork = new ForkModel(model); if (!ArrayUtils.isEmpty(model.forks)) { for (String aFork : model.forks) { ForkModel fm = getForkModel(aFork); - fork.forks.add(fm); + if (fm != null) { + fork.forks.add(fm); + } } } return fork; @@ -2126,7 +2183,7 @@ public void updateConfiguration(Repository r, RepositoryModel repository) { StoredConfig config = r.getConfig(); config.setString(Constants.CONFIG_GITBLIT, null, "description", repository.description); - config.setString(Constants.CONFIG_GITBLIT, null, "owner", repository.owner); + config.setString(Constants.CONFIG_GITBLIT, null, "owner", ArrayUtils.toString(repository.owners)); config.setBoolean(Constants.CONFIG_GITBLIT, null, "useTickets", repository.useTickets); config.setBoolean(Constants.CONFIG_GITBLIT, null, "useDocs", repository.useDocs); config.setBoolean(Constants.CONFIG_GITBLIT, null, "allowForks", repository.allowForks); @@ -2984,12 +3041,15 @@ * * @param settings */ - public void configureContext(IStoredSettings settings, boolean startFederation) { - logger.info("Reading configuration from " + settings.toString()); + public void configureContext(IStoredSettings settings, File folder, boolean startFederation) { this.settings = settings; + this.baseFolder = folder; repositoriesFolder = getRepositoriesFolder(); - logger.info("Git repositories folder " + repositoriesFolder.getAbsolutePath()); + + logger.info("Gitblit base folder = " + folder.getAbsolutePath()); + logger.info("Git repositories folder = " + repositoriesFolder.getAbsolutePath()); + logger.info("Gitblit settings = " + settings.toString()); // prepare service executors mailExecutor = new MailExecutor(settings); @@ -3011,7 +3071,7 @@ serverStatus = new ServerStatus(isGO()); if (this.userService == null) { - String realm = settings.getString(Keys.realm.userService, "users.properties"); + String realm = settings.getString(Keys.realm.userService, "${baseFolder}/users.properties"); IUserService loginService = null; try { // check to see if this "file" is a login service class @@ -3024,7 +3084,7 @@ } // load and cache the project metadata - projectConfigs = new FileBasedConfig(getFileOrFolder(Keys.web.projectsFile, "projects.conf"), FS.detect()); + projectConfigs = new FileBasedConfig(getFileOrFolder(Keys.web.projectsFile, "${baseFolder}/projects.conf"), FS.detect()); getProjectConfigs(); // schedule mail engine @@ -3090,6 +3150,32 @@ } ContainerUtils.CVE_2007_0450.test(); + + // startup Fanout PubSub service + if (settings.getInteger(Keys.fanout.port, 0) > 0) { + String bindInterface = settings.getString(Keys.fanout.bindInterface, null); + int port = settings.getInteger(Keys.fanout.port, FanoutService.DEFAULT_PORT); + boolean useNio = settings.getBoolean(Keys.fanout.useNio, true); + int limit = settings.getInteger(Keys.fanout.connectionLimit, 0); + + if (useNio) { + if (StringUtils.isEmpty(bindInterface)) { + fanoutService = new FanoutNioService(port); + } else { + fanoutService = new FanoutNioService(bindInterface, port); + } + } else { + if (StringUtils.isEmpty(bindInterface)) { + fanoutService = new FanoutSocketService(port); + } else { + fanoutService = new FanoutSocketService(bindInterface, port); + } + } + + fanoutService.setConcurrentConnectionLimit(limit); + fanoutService.setAllowAllChannelAnnouncements(false); + fanoutService.start(); + } } private void logTimezone(String type, TimeZone zone) { @@ -3113,39 +3199,63 @@ public void contextInitialized(ServletContextEvent contextEvent, InputStream referencePropertiesInputStream) { servletContext = contextEvent.getServletContext(); if (settings == null) { - // Gitblit WAR is running in a servlet container + // Gitblit is running in a servlet container ServletContext context = contextEvent.getServletContext(); WebXmlSettings webxmlSettings = new WebXmlSettings(context); - - // gitblit.properties file located within the webapp - String webProps = context.getRealPath("/WEB-INF/gitblit.properties"); - if (!StringUtils.isEmpty(webProps)) { - File overrideFile = new File(webProps); - webxmlSettings.applyOverrides(overrideFile); - } + File contextFolder = new File(context.getRealPath("/")); + String openShift = System.getenv("OPENSHIFT_DATA_DIR"); - // gitblit.properties file located outside the deployed war - // folder lie, for example, on RedHat OpenShift. - File overrideFile = getFileOrFolder("gitblit.properties"); - if (!overrideFile.getPath().equals("gitblit.properties")) { - webxmlSettings.applyOverrides(overrideFile); - } - - configureContext(webxmlSettings, true); + if (!StringUtils.isEmpty(openShift)) { + // Gitblit is running in OpenShift/JBoss + File base = new File(openShift); - // Copy the included scripts to the configured groovy folder - File localScripts = getFileOrFolder(Keys.groovy.scriptsFolder, "groovy"); - if (!localScripts.exists()) { - File includedScripts = new File(context.getRealPath("/WEB-INF/groovy")); - if (!includedScripts.equals(localScripts)) { - try { - com.gitblit.utils.FileUtils.copy(localScripts, includedScripts.listFiles()); - } catch (IOException e) { - logger.error(MessageFormat.format( - "Failed to copy included Groovy scripts from {0} to {1}", - includedScripts, localScripts)); + // gitblit.properties setting overrides + File overrideFile = new File(base, "gitblit.properties"); + webxmlSettings.applyOverrides(overrideFile); + + // Copy the included scripts to the configured groovy folder + File localScripts = new File(base, webxmlSettings.getString(Keys.groovy.scriptsFolder, "groovy")); + if (!localScripts.exists()) { + File warScripts = new File(contextFolder, "/WEB-INF/data/groovy"); + if (!warScripts.equals(localScripts)) { + try { + com.gitblit.utils.FileUtils.copy(localScripts, warScripts.listFiles()); + } catch (IOException e) { + logger.error(MessageFormat.format( + "Failed to copy included Groovy scripts from {0} to {1}", + warScripts, localScripts)); + } } } + + // configure context using the web.xml + configureContext(webxmlSettings, base, true); + } else { + // Gitblit is running in a standard servlet container + logger.info("WAR contextFolder is " + contextFolder.getAbsolutePath()); + + String path = webxmlSettings.getString(Constants.baseFolder, Constants.contextFolder$ + "/WEB-INF/data"); + File base = com.gitblit.utils.FileUtils.resolveParameter(Constants.contextFolder$, contextFolder, path); + base.mkdirs(); + + // try to copy the data folder contents to the baseFolder + File localSettings = new File(base, "gitblit.properties"); + if (!localSettings.exists()) { + File contextData = new File(contextFolder, "/WEB-INF/data"); + if (!base.equals(contextData)) { + try { + com.gitblit.utils.FileUtils.copy(base, contextData.listFiles()); + } catch (IOException e) { + logger.error(MessageFormat.format( + "Failed to copy included data from {0} to {1}", + contextData, base)); + } + } + } + + // delegate all config to baseFolder/gitblit.properties file + FileSettings settings = new FileSettings(localSettings.getAbsolutePath()); + configureContext(settings, base, true); } } @@ -3163,6 +3273,9 @@ scheduledExecutor.shutdownNow(); luceneExecutor.close(); gcExecutor.close(); + if (fanoutService != null) { + fanoutService.stop(); + } } /** @@ -3207,15 +3320,17 @@ // create a Gitblit repository model for the clone RepositoryModel cloneModel = repository.cloneAs(cloneName); // owner has REWIND/RW+ permissions - cloneModel.owner = user.username; + cloneModel.addOwner(user.username); updateRepositoryModel(cloneName, cloneModel, false); // add the owner of the source repository to the clone's access list - if (!StringUtils.isEmpty(repository.owner)) { - UserModel originOwner = getUserModel(repository.owner); - if (originOwner != null) { - originOwner.setRepositoryPermission(cloneName, AccessPermission.CLONE); - updateUserModel(originOwner.username, originOwner, false); + if (!ArrayUtils.isEmpty(repository.owners)) { + for (String owner : repository.owners) { + UserModel originOwner = getUserModel(owner); + if (originOwner != null) { + originOwner.setRepositoryPermission(cloneName, AccessPermission.CLONE); + updateUserModel(originOwner.username, originOwner, false); + } } } -- Gitblit v1.9.1