From fd8cea4761b5382f23d06ed52608d1f556c4dbe5 Mon Sep 17 00:00:00 2001 From: James Moger <james.moger@gitblit.com> Date: Thu, 22 May 2014 17:31:30 -0400 Subject: [PATCH] Render GFM links using Markdown, not direct HTML --- src/main/java/com/gitblit/manager/RepositoryManager.java | 155 +++++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 137 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/gitblit/manager/RepositoryManager.java b/src/main/java/com/gitblit/manager/RepositoryManager.java index 438d885..c141f08 100644 --- a/src/main/java/com/gitblit/manager/RepositoryManager.java +++ b/src/main/java/com/gitblit/manager/RepositoryManager.java @@ -157,6 +157,8 @@ configureJGit(); configureCommitCache(); + confirmWriteAccess(); + return this; } @@ -167,6 +169,7 @@ gcExecutor.close(); mirrorExecutor.close(); + closeAll(); return this; } @@ -418,8 +421,9 @@ // update the fork origin repository with this repository clone if (!StringUtils.isEmpty(model.originRepository)) { - if (repositoryListCache.containsKey(model.originRepository)) { - RepositoryModel origin = repositoryListCache.get(model.originRepository); + String originKey = model.originRepository.toLowerCase(); + if (repositoryListCache.containsKey(originKey)) { + RepositoryModel origin = repositoryListCache.get(originKey); origin.addFork(model.name); } } @@ -447,6 +451,19 @@ private void clearRepositoryMetadataCache(String repositoryName) { repositorySizeCache.remove(repositoryName); repositoryMetricsCache.remove(repositoryName); + CommitCache.instance().clear(repositoryName); + } + + /** + * Reset all caches for this repository. + * + * @param repositoryName + * @since 1.5.1 + */ + @Override + public void resetRepositoryCache(String repositoryName) { + removeFromCachedRepositoryList(repositoryName); + clearRepositoryMetadataCache(repositoryName); } /** @@ -457,6 +474,9 @@ public void resetRepositoryListCache() { logger.info("Repository cache manually reset"); repositoryListCache.clear(); + repositorySizeCache.clear(); + repositoryMetricsCache.clear(); + CommitCache.instance().clear(); } /** @@ -527,8 +547,9 @@ // rebuild fork networks for (RepositoryModel model : repositoryListCache.values()) { if (!StringUtils.isEmpty(model.originRepository)) { - if (repositoryListCache.containsKey(model.originRepository)) { - RepositoryModel origin = repositoryListCache.get(model.originRepository); + String originKey = model.originRepository.toLowerCase(); + if (repositoryListCache.containsKey(originKey)) { + RepositoryModel origin = repositoryListCache.get(originKey); origin.addFork(model.name); } } @@ -778,10 +799,11 @@ model.projectPath = StringUtils.getFirstPathElement(repositoryName); StoredConfig config = r.getConfig(); - boolean hasOrigin = !StringUtils.isEmpty(config.getString("remote", "origin", "url")); + boolean hasOrigin = false; if (config != null) { // Initialize description from description file + hasOrigin = !StringUtils.isEmpty(config.getString("remote", "origin", "url")); if (getConfig(config,"description", null) == null) { File descFile = new File(r.getDirectory(), "description"); if (descFile.exists()) { @@ -794,6 +816,10 @@ model.description = getConfig(config, "description", ""); model.originRepository = getConfig(config, "originRepository", null); model.addOwners(ArrayUtils.fromString(getConfig(config, "owner", ""))); + model.acceptNewPatchsets = getConfig(config, "acceptNewPatchsets", true); + model.acceptNewTickets = getConfig(config, "acceptNewTickets", true); + model.requireApproval = getConfig(config, "requireApproval", settings.getBoolean(Keys.tickets.requireApproval, false)); + model.mergeTo = getConfig(config, "mergeTo", null); model.useIncrementalPushTags = getConfig(config, "useIncrementalPushTags", false); model.incrementalPushTagPrefix = getConfig(config, "incrementalPushTagPrefix", null); model.allowForks = getConfig(config, "allowForks", true); @@ -844,6 +870,9 @@ } } model.HEAD = JGitUtils.getHEADRef(r); + if (StringUtils.isEmpty(model.mergeTo)) { + model.mergeTo = model.HEAD; + } model.availableRefs = JGitUtils.getAvailableHeadTargets(r); model.sparkleshareId = JGitUtils.getSparkleshareId(r); model.hasCommits = JGitUtils.hasCommits(r); @@ -928,26 +957,31 @@ */ @Override public String getFork(String username, String origin) { + if (StringUtils.isEmpty(origin)) { + return null; + } String userProject = ModelUtils.getPersonalPath(username); if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) { + String originKey = origin.toLowerCase(); String userPath = userProject + "/"; // collect all origin nodes in fork network Set<String> roots = new HashSet<String>(); - roots.add(origin); - RepositoryModel originModel = repositoryListCache.get(origin); + roots.add(originKey); + RepositoryModel originModel = repositoryListCache.get(originKey); while (originModel != null) { if (!ArrayUtils.isEmpty(originModel.forks)) { for (String fork : originModel.forks) { if (!fork.startsWith(userPath)) { - roots.add(fork); + roots.add(fork.toLowerCase()); } } } if (originModel.originRepository != null) { - roots.add(originModel.originRepository); - originModel = repositoryListCache.get(originModel.originRepository); + String ooKey = originModel.originRepository.toLowerCase(); + roots.add(ooKey); + originModel = repositoryListCache.get(ooKey); } else { // break originModel = null; @@ -958,7 +992,7 @@ if (repository.startsWith(userPath)) { RepositoryModel model = repositoryListCache.get(repository); if (!StringUtils.isEmpty(model.originRepository)) { - if (roots.contains(model.originRepository)) { + if (roots.contains(model.originRepository.toLowerCase())) { // user has a fork in this graph return model.name; } @@ -975,7 +1009,7 @@ settings.getStrings(Keys.git.searchExclusions)); for (String repository : repositories) { RepositoryModel model = getRepositoryModel(userProject + "/" + repository); - if (model.originRepository.equalsIgnoreCase(origin)) { + if (model.originRepository != null && model.originRepository.equalsIgnoreCase(origin)) { // user has a fork return model.name; } @@ -998,7 +1032,7 @@ // find the root, cached RepositoryModel model = repositoryListCache.get(repository.toLowerCase()); while (model.originRepository != null) { - model = repositoryListCache.get(model.originRepository); + model = repositoryListCache.get(model.originRepository.toLowerCase()); } ForkModel root = getForkModelFromCache(model.name); return root; @@ -1078,12 +1112,49 @@ } /** + * Returns true if the repository is idle (not being accessed). + * + * @param repository + * @return true if the repository is idle + */ + @Override + public boolean isIdle(Repository repository) { + try { + // Read the use count. + // An idle use count is 2: + // +1 for being in the cache + // +1 for the repository parameter in this method + Field useCnt = Repository.class.getDeclaredField("useCnt"); + useCnt.setAccessible(true); + int useCount = ((AtomicInteger) useCnt.get(repository)).get(); + return useCount == 2; + } catch (Exception e) { + logger.warn(MessageFormat + .format("Failed to reflectively determine use count for repository {0}", + repository.getDirectory().getPath()), e); + } + return false; + } + + /** + * Ensures that all cached repository are completely closed and their resources + * are properly released. + */ + @Override + public void closeAll() { + for (String repository : getRepositoryList()) { + close(repository); + } + } + + /** * Ensure that a cached repository is completely closed and its resources * are properly released. * * @param repositoryName */ - private void closeRepository(String repositoryName) { + @Override + public void close(String repositoryName) { Repository repository = getRepository(repositoryName); if (repository == null) { return; @@ -1108,7 +1179,7 @@ repositoryName), e); } if (uses > 0) { - logger.info(MessageFormat + logger.debug(MessageFormat .format("{0}.useCnt={1}, calling close() {2} time(s) to close object and ref databases", repositoryName, uses, uses)); for (int i = 0; i < uses; i++) { @@ -1246,7 +1317,7 @@ "Failed to rename ''{0}'' because ''{1}'' already exists.", repositoryName, repository.name)); } - closeRepository(repositoryName); + close(repositoryName); File folder = new File(repositoriesFolder, repositoryName); File destFolder = new File(repositoriesFolder, repository.name); if (destFolder.exists()) { @@ -1292,7 +1363,7 @@ // update this repository's origin's fork list if (!StringUtils.isEmpty(repository.originRepository)) { - RepositoryModel origin = repositoryListCache.get(repository.originRepository); + RepositoryModel origin = repositoryListCache.get(repository.originRepository.toLowerCase()); if (origin != null && !ArrayUtils.isEmpty(origin.forks)) { origin.forks.remove(repositoryName); origin.forks.add(repository.name); @@ -1362,6 +1433,18 @@ config.setString(Constants.CONFIG_GITBLIT, null, "description", repository.description); config.setString(Constants.CONFIG_GITBLIT, null, "originRepository", repository.originRepository); config.setString(Constants.CONFIG_GITBLIT, null, "owner", ArrayUtils.toString(repository.owners)); + config.setBoolean(Constants.CONFIG_GITBLIT, null, "acceptNewPatchsets", repository.acceptNewPatchsets); + config.setBoolean(Constants.CONFIG_GITBLIT, null, "acceptNewTickets", repository.acceptNewTickets); + if (settings.getBoolean(Keys.tickets.requireApproval, false) == repository.requireApproval) { + // use default + config.unset(Constants.CONFIG_GITBLIT, null, "requireApproval"); + } else { + // override default + config.setBoolean(Constants.CONFIG_GITBLIT, null, "requireApproval", repository.requireApproval); + } + if (!StringUtils.isEmpty(repository.mergeTo)) { + config.setString(Constants.CONFIG_GITBLIT, null, "mergeTo", repository.mergeTo); + } config.setBoolean(Constants.CONFIG_GITBLIT, null, "useIncrementalPushTags", repository.useIncrementalPushTags); if (StringUtils.isEmpty(repository.incrementalPushTagPrefix) || repository.incrementalPushTagPrefix.equals(settings.getString(Keys.git.defaultIncrementalPushTagPrefix, "r"))) { @@ -1450,6 +1533,17 @@ } /** + * Returns true if the repository can be deleted. + * + * @return true if the repository can be deleted + */ + @Override + public boolean canDelete(RepositoryModel repository) { + return settings.getBoolean(Keys.web.allowDeletingNonEmptyRepositories, true) + || !repository.hasCommits; + } + + /** * Deletes the repository from the file system and removes the repository * permission from all repository users. * @@ -1470,8 +1564,14 @@ */ @Override public boolean deleteRepository(String repositoryName) { + RepositoryModel repository = getRepositoryModel(repositoryName); + if (!canDelete(repository)) { + logger.warn("Attempt to delete {} rejected!", repositoryName); + return false; + } + try { - closeRepository(repositoryName); + close(repositoryName); // clear the repository cache clearRepositoryMetadataCache(repositoryName); @@ -1754,4 +1854,23 @@ daysToCache, commitCount, repoCount, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start))); } } + + 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(""); + } + } + } } -- Gitblit v1.9.1