James Moger
2012-10-03 c25b9801899e86753dd6ba80ebc68102ee37a21c
src/com/gitblit/GitBlit.java
@@ -32,6 +32,7 @@
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -81,6 +82,7 @@
import com.gitblit.models.FederationModel;
import com.gitblit.models.FederationProposal;
import com.gitblit.models.FederationSet;
import com.gitblit.models.ForkModel;
import com.gitblit.models.Metric;
import com.gitblit.models.ProjectModel;
import com.gitblit.models.RepositoryModel;
@@ -1268,6 +1270,9 @@
               Constants.CONFIG_GITBLIT, null, "federationSets")));
         model.isFederated = getConfig(config, "isFederated", false);
         model.origin = config.getString("remote", "origin", "url");
         if (model.origin != null) {
            model.origin = model.origin.replace('\\', '/');
         }
         model.preReceiveScripts = new ArrayList<String>(Arrays.asList(config.getStringList(
               Constants.CONFIG_GITBLIT, null, "preReceiveScript")));
         model.postReceiveScripts = new ArrayList<String>(Arrays.asList(config.getStringList(
@@ -1324,6 +1329,113 @@
      }
      r.close();
      return true;
   }
   /**
    * Determines if the specified user has a fork of the specified origin
    * repository.
    *
    * @param username
    * @param origin
    * @return true the if the user has a fork
    */
   public boolean hasFork(String username, String origin) {
      return getFork(username, origin) != null;
   }
   /**
    * Gets the name of a user's fork of the specified origin
    * repository.
    *
    * @param username
    * @param origin
    * @return the name of the user's fork, null otherwise
    */
   public String getFork(String username, String origin) {
      String userProject = "~" + username.toLowerCase();
      if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
         String userPath = userProject + "/";
         // collect all origin nodes in fork network
         Set<String> roots = new HashSet<String>();
         roots.add(origin);
         RepositoryModel originModel = repositoryListCache.get(origin);
         while (originModel != null) {
            if (!ArrayUtils.isEmpty(originModel.forks)) {
               for (String fork : originModel.forks) {
                  if (!fork.startsWith(userPath)) {
                     roots.add(fork);
                  }
               }
            }
            if (originModel.originRepository != null) {
               roots.add(originModel.originRepository);
               originModel = repositoryListCache.get(originModel.originRepository);
            } else {
               // break
               originModel = null;
            }
         }
         for (String repository : repositoryListCache.keySet()) {
            if (repository.toLowerCase().startsWith(userPath)) {
               RepositoryModel model = repositoryListCache.get(repository);
               if (!StringUtils.isEmpty(model.originRepository)) {
                  if (roots.contains(model.originRepository)) {
                     // user has a fork in this graph
                     return model.name;
                  }
               }
            }
         }
      } else {
         // not caching
         ProjectModel project = getProjectModel(userProject);
         for (String repository : project.repositories) {
            if (repository.toLowerCase().startsWith(userProject)) {
               RepositoryModel model = repositoryListCache.get(repository);
               if (model.originRepository.equalsIgnoreCase(origin)) {
                  // user has a fork
                  return model.name;
               }
            }
         }
      }
      // user does not have a fork
      return null;
   }
   /**
    * Returns the fork network for a repository by traversing up the fork graph
    * to discover the root and then down through all children of the root node.
    *
    * @param repository
    * @return a ForkModel
    */
   public ForkModel getForkNetwork(String repository) {
      if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
         // find the root
         RepositoryModel model = repositoryListCache.get(repository);
         while (model.originRepository != null) {
            model = repositoryListCache.get(model.originRepository);
         }
         ForkModel root = getForkModel(model.name);
         return root;
      }
      return null;
   }
   private ForkModel getForkModel(String repository) {
      RepositoryModel model = repositoryListCache.get(repository);
      ForkModel fork = new ForkModel(model);
      if (!ArrayUtils.isEmpty(model.forks)) {
         for (String aFork : model.forks) {
            ForkModel fm = getForkModel(aFork);
            fork.forks.add(fm);
         }
      }
      return fork;
   }
   /**
@@ -2528,44 +2640,45 @@
    * 
    * @param repository
    * @param user
    * @return true, if successful
    * @return the repository model of the fork, if successful
    * @throws GitBlitException
    */
   public boolean fork(RepositoryModel repository, UserModel user) {
   public RepositoryModel fork(RepositoryModel repository, UserModel user) throws GitBlitException {
      String cloneName = MessageFormat.format("~{0}/{1}.git", user.username, StringUtils.stripDotGit(StringUtils.getLastPathElement(repository.name)));
      String fromUrl = MessageFormat.format("file://{0}/{1}", repositoriesFolder.getAbsolutePath(), repository.name);
      // clone the repository
      try {
         // clone the repository
         JGitUtils.cloneRepository(repositoriesFolder, cloneName, fromUrl, true, null);
         // create a Gitblit repository model for the clone
         RepositoryModel cloneModel = repository.cloneAs(cloneName);
         cloneModel.owner = user.username;
         updateRepositoryModel(cloneName, cloneModel, false);
         if (AuthorizationControl.NAMED.equals(cloneModel.authorizationControl)) {
            // add the owner of the source repository to the clone's access list
            if (!StringUtils.isEmpty(repository.owner)) {
               UserModel owner = getUserModel(repository.owner);
               if (owner != null) {
                  owner.repositories.add(cloneName);
                  updateUserModel(owner.username, owner, false);
               }
            }
            // inherit origin's access lists
            List<String> users = getRepositoryUsers(repository);
            setRepositoryUsers(cloneModel, users);
            List<String> teams = getRepositoryTeams(repository);
            setRepositoryTeams(cloneModel, teams);
         }
         // add this clone to the cached model
         addToCachedRepositoryList(cloneModel.name, cloneModel);
         return true;
      } catch (Exception e) {
         logger.error("failed to fork", e);
         throw new GitBlitException(e);
      }
      return false;
      // create a Gitblit repository model for the clone
      RepositoryModel cloneModel = repository.cloneAs(cloneName);
      cloneModel.owner = user.username;
      updateRepositoryModel(cloneName, cloneModel, false);
      if (AuthorizationControl.NAMED.equals(cloneModel.authorizationControl)) {
         // add the owner of the source repository to the clone's access list
         if (!StringUtils.isEmpty(repository.owner)) {
            UserModel owner = getUserModel(repository.owner);
            if (owner != null) {
               owner.repositories.add(cloneName);
               updateUserModel(owner.username, owner, false);
            }
         }
         // inherit origin's access lists
         List<String> users = getRepositoryUsers(repository);
         setRepositoryUsers(cloneModel, users);
         List<String> teams = getRepositoryTeams(repository);
         setRepositoryTeams(cloneModel, teams);
      }
      // add this clone to the cached model
      addToCachedRepositoryList(cloneModel.name, cloneModel);
      return cloneModel;
   }
}