James Moger
2013-01-05 9e186eedf1a09ca7ac4fbdea32b00e7e5331f7eb
src/com/gitblit/GitBlit.java
@@ -154,6 +154,10 @@
   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;
@@ -467,36 +471,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 +801,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
@@ -1339,7 +1359,7 @@
      }
      // check for updates
      Repository r = getRepository(repositoryName);
      Repository r = getRepository(model.name);
      if (r == null) {
         // repository is missing
         removeFromCachedRepositoryList(repositoryName);
@@ -1351,8 +1371,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 +1422,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);
@@ -1526,6 +1569,49 @@
   }
   
   /**
    * Returns the list of project models that are referenced by the supplied
    * repository model   list.  This is an alternative method exists to ensure
    * Gitblit does not call getRepositoryModels(UserModel) twice in a request.
    *
    * @param repositoryModels
    * @param includeUsers
    * @return a list of project models
    */
   public List<ProjectModel> getProjectModels(List<RepositoryModel> repositoryModels, boolean includeUsers) {
      Map<String, ProjectModel> projects = new LinkedHashMap<String, ProjectModel>();
      for (RepositoryModel repository : repositoryModels) {
         if (!includeUsers && repository.isPersonalRepository()) {
            // exclude personal repositories
            continue;
         }
         if (!projects.containsKey(repository.projectPath)) {
            ProjectModel project = getProjectModel(repository.projectPath);
            if (project == null) {
               logger.warn(MessageFormat.format("excluding project \"{0}\" from project list because it is empty!",
                     repository.projectPath));
               continue;
            }
            projects.put(repository.projectPath, project);
            // clear the repo list in the project because that is the system
            // list, not the user-accessible list and start building the
            // user-accessible list
            project.repositories.clear();
            project.repositories.add(repository.name);
            project.lastChange = repository.lastChange;
         } else {
            // update the user-accessible list
            // this is used for repository count
            ProjectModel project = projects.get(repository.projectPath);
            project.repositories.add(repository.name);
            if (project.lastChange.before(repository.lastChange)) {
               project.lastChange = repository.lastChange;
            }
         }
      }
      return new ArrayList<ProjectModel>(projects.values());
   }
   /**
    * Workaround JGit.  I need to access the raw config object directly in order
    * to see if the config is dirty so that I can reload a repository model.
    * If I use the stock JGit method to get the config it already reloads the
@@ -1602,6 +1688,7 @@
         } catch (Exception e) {
            model.lastGC = new Date(0);
         }
         model.maxActivityCommits = getConfig(config, "maxActivityCommits", settings.getInteger(Keys.web.maxActivityCommits, 0));
         model.origin = config.getString("remote", "origin", "url");
         if (model.origin != null) {
            model.origin = model.origin.replace('\\', '/');
@@ -1651,7 +1738,18 @@
    * @return true if the repository exists
    */
   public boolean hasRepository(String repositoryName) {
      if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
      return hasRepository(repositoryName, false);
   }
   /**
    * Determines if this server has the requested repository.
    *
    * @param name
    * @param caseInsensitive
    * @return true if the repository exists
    */
   public boolean hasRepository(String repositoryName, boolean caseSensitiveCheck) {
      if (!caseSensitiveCheck && settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
         // if we are caching use the cache to determine availability
         // otherwise we end up adding a phantom repository to the cache
         return repositoryListCache.containsKey(repositoryName.toLowerCase());
@@ -1727,7 +1825,7 @@
         ProjectModel project = getProjectModel(userProject);
         for (String repository : project.repositories) {
            if (repository.startsWith(userProject)) {
               RepositoryModel model = repositoryListCache.get(repository);
               RepositoryModel model = getRepositoryModel(repository);
               if (model.originRepository.equalsIgnoreCase(origin)) {
                  // user has a fork
                  return model.name;
@@ -1748,19 +1846,38 @@
    */
   public ForkModel getForkNetwork(String repository) {
      if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
         // find the root
         // find the root, cached
         RepositoryModel model = repositoryListCache.get(repository.toLowerCase());
         while (model.originRepository != null) {
            model = repositoryListCache.get(model.originRepository);
         }
         ForkModel root = getForkModelFromCache(model.name);
         return root;
      } else {
         // find the root, non-cached
         RepositoryModel model = getRepositoryModel(repository.toLowerCase());
         while (model.originRepository != null) {
            model = getRepositoryModel(model.originRepository);
         }
         ForkModel root = getForkModel(model.name);
         return root;
      }
      return null;
   }
   private ForkModel getForkModelFromCache(String repository) {
      RepositoryModel model = repositoryListCache.get(repository.toLowerCase());
      ForkModel fork = new ForkModel(model);
      if (!ArrayUtils.isEmpty(model.forks)) {
         for (String aFork : model.forks) {
            ForkModel fm = getForkModelFromCache(aFork);
            fork.forks.add(fm);
         }
      }
      return fork;
   }
   
   private ForkModel getForkModel(String repository) {
      RepositoryModel model = repositoryListCache.get(repository.toLowerCase());
      RepositoryModel model = getRepositoryModel(repository.toLowerCase());
      ForkModel fork = new ForkModel(model);
      if (!ArrayUtils.isEmpty(model.forks)) {
         for (String aFork : model.forks) {
@@ -1936,7 +2053,7 @@
         if (!repository.name.toLowerCase().endsWith(org.eclipse.jgit.lib.Constants.DOT_GIT_EXT)) {
            repository.name += org.eclipse.jgit.lib.Constants.DOT_GIT_EXT;
         }
         if (new File(repositoriesFolder, repository.name).exists()) {
         if (hasRepository(repository.name)) {
            throw new GitBlitException(MessageFormat.format(
                  "Can not create repository ''{0}'' because it already exists.",
                  repository.name));
@@ -2068,9 +2185,20 @@
            repository.federationStrategy.name());
      config.setBoolean(Constants.CONFIG_GITBLIT, null, "isFederated", repository.isFederated);
      config.setString(Constants.CONFIG_GITBLIT, null, "gcThreshold", repository.gcThreshold);
      config.setInt(Constants.CONFIG_GITBLIT, null, "gcPeriod", repository.gcPeriod);
      if (repository.gcPeriod == settings.getInteger(Keys.git.defaultGarbageCollectionPeriod, 7)) {
         // use default from config
         config.unset(Constants.CONFIG_GITBLIT, null, "gcPeriod");
      } else {
         config.setInt(Constants.CONFIG_GITBLIT, null, "gcPeriod", repository.gcPeriod);
      }
      if (repository.lastGC != null) {
         config.setString(Constants.CONFIG_GITBLIT, null, "lastGC", new SimpleDateFormat(Constants.ISO8601).format(repository.lastGC));
      }
      if (repository.maxActivityCommits == settings.getInteger(Keys.web.maxActivityCommits, 0)) {
         // use default from config
         config.unset(Constants.CONFIG_GITBLIT, null, "maxActivityCommits");
      } else {
         config.setInt(Constants.CONFIG_GITBLIT, null, "maxActivityCommits", repository.maxActivityCommits);
      }
      updateList(config, "federationSets", repository.federationSets);
@@ -3032,22 +3160,20 @@
         ServletContext context = contextEvent.getServletContext();
         WebXmlSettings webxmlSettings = new WebXmlSettings(context);
         // 0.7.0 web.properties in the deployed war folder
         String webProps = context.getRealPath("/WEB-INF/web.properties");
         // gitblit.properties file located within the webapp
         String webProps = context.getRealPath("/WEB-INF/gitblit.properties");
         if (!StringUtils.isEmpty(webProps)) {
            File overrideFile = new File(webProps);
            if (overrideFile.exists()) {
               webxmlSettings.applyOverrides(overrideFile);
            }
            webxmlSettings.applyOverrides(overrideFile);
         }
         
         // 0.8.0 gitblit.properties file located outside the deployed war
         // 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);
         // Copy the included scripts to the configured groovy folder