Beispiel #1
0
 @Test
 public void testArbitraryCommitDiff() throws Exception {
   Repository repository = GitBlitSuite.getHelloworldRepository();
   RevCommit baseCommit =
       JGitUtils.getCommit(repository, "8baf6a833b5579384d9b9ceb8a16b5d0ea2ec4ca");
   RevCommit commit = JGitUtils.getCommit(repository, "1d0c2933a4ae69c362f76797d42d6bd182d05176");
   String diff = DiffUtils.getDiff(repository, baseCommit, commit, DiffOutputType.PLAIN).content;
   repository.close();
   assertTrue(diff != null && diff.length() > 0);
   String expected =
       "-		system.out.println(\"Hello World\");\n+		System.out.println(\"Hello World\"";
   assertTrue(diff.indexOf(expected) > -1);
 }
Beispiel #2
0
 @Test
 public void testArbitraryFilePatch() throws Exception {
   Repository repository = GitBlitSuite.getHelloworldRepository();
   RevCommit baseCommit =
       JGitUtils.getCommit(repository, "8baf6a833b5579384d9b9ceb8a16b5d0ea2ec4ca");
   RevCommit commit = JGitUtils.getCommit(repository, "1d0c2933a4ae69c362f76797d42d6bd182d05176");
   String patch = DiffUtils.getCommitPatch(repository, baseCommit, commit, "java.java");
   repository.close();
   assertTrue(patch != null && patch.length() > 0);
   String expected =
       "-		system.out.println(\"Hello World\");\n+		System.out.println(\"Hello World\"";
   assertTrue(patch.indexOf(expected) > -1);
 }
  /**
   * Retrieves the specified attachment from a ticket.
   *
   * @param repository
   * @param ticketId
   * @param filename
   * @return an attachment, if found, null otherwise
   */
  @Override
  public Attachment getAttachment(RepositoryModel repository, long ticketId, String filename) {
    if (ticketId <= 0L) {
      return null;
    }

    // deserialize the ticket model so that we have the attachment metadata
    TicketModel ticket = getTicket(repository, ticketId);
    Attachment attachment = ticket.getAttachment(filename);

    // attachment not found
    if (attachment == null) {
      return null;
    }

    // retrieve the attachment content
    Repository db = repositoryManager.getRepository(repository.name);
    try {
      String attachmentPath = toAttachmentPath(ticketId, attachment.name);
      RevTree tree = JGitUtils.getCommit(db, BRANCH).getTree();
      byte[] content = JGitUtils.getByteContent(db, tree, attachmentPath, false);
      attachment.content = content;
      attachment.size = content.length;
      return attachment;
    } finally {
      db.close();
    }
  }
Beispiel #4
0
 @Override
 public String getContent(String objectId, String blobPath) {
   objectId = defaultObjectId(objectId);
   Repository r = git.getRepository();
   RevCommit commit = JGitUtils.getCommit(r, objectId);
   return JGitUtils.getStringContent(r, commit.getTree(), blobPath, encodings);
 }
Beispiel #5
0
  @Override
  public String diff(String objectId, String baseObjectId, String blobPath) {
    Repository r = git.getRepository();
    objectId = defaultObjectId(objectId);
    RevCommit commit = JGitUtils.getCommit(r, objectId);

    DiffUtils.DiffOutputType diffType = DiffUtils.DiffOutputType.PLAIN;
    String diff;
    if (StringUtils.isEmpty(baseObjectId)) {
      // use first parent
      diff = DiffUtils.getDiff(r, commit, blobPath, diffType);
    } else {
      // base commit specified
      RevCommit baseCommit = JGitUtils.getCommit(r, baseObjectId);
      diff = DiffUtils.getDiff(r, baseCommit, commit, blobPath, diffType);
    }
    return diff;
  }
Beispiel #6
0
 private RevCommit getCommit(Repository r, String rev) {
   RevCommit otherCommit = JGitUtils.getCommit(r, rev);
   if (otherCommit == null) {
     error(
         MessageFormat.format(
             getString("gb.failedToFindCommit"), rev, repositoryName, getPageName()),
         true);
   }
   return otherCommit;
 }
Beispiel #7
0
 @Test
 public void testPlainFileDiff() throws Exception {
   Repository repository = GitBlitSuite.getHelloworldRepository();
   RevCommit commit = JGitUtils.getCommit(repository, "1d0c2933a4ae69c362f76797d42d6bd182d05176");
   String diff = DiffUtils.getDiff(repository, commit, "java.java", DiffOutputType.PLAIN).content;
   repository.close();
   assertTrue(diff != null && diff.length() > 0);
   String expected =
       "-		system.out.println(\"Hello World\");\n+		System.out.println(\"Hello World\"";
   assertTrue(diff.indexOf(expected) > -1);
 }
 /**
  * Ensures that we have a ticket for this ticket id.
  *
  * @param repository
  * @param ticketId
  * @return true if the ticket exists
  */
 @Override
 public boolean hasTicket(RepositoryModel repository, long ticketId) {
   boolean hasTicket = false;
   Repository db = repositoryManager.getRepository(repository.name);
   try {
     RefModel ticketsBranch = getTicketsBranch(db);
     if (ticketsBranch == null) {
       return false;
     }
     String ticketPath = toTicketPath(ticketId);
     RevCommit tip = JGitUtils.getCommit(db, BRANCH);
     hasTicket = !JGitUtils.getFilesInPath(db, ticketPath, tip).isEmpty();
   } finally {
     db.close();
   }
   return hasTicket;
 }
  public HistoryPanel(
      String wicketId,
      final String repositoryName,
      final String objectId,
      final String path,
      Repository r,
      int limit,
      int pageOffset,
      boolean showRemoteRefs) {
    super(wicketId);
    boolean pageResults = limit <= 0;
    int itemsPerPage = GitBlit.getInteger(Keys.web.itemsPerPage, 50);
    if (itemsPerPage <= 1) {
      itemsPerPage = 50;
    }

    RevCommit commit = JGitUtils.getCommit(r, objectId);
    List<PathChangeModel> paths = JGitUtils.getFilesInCommit(r, commit);

    Map<String, SubmoduleModel> submodules = new HashMap<String, SubmoduleModel>();
    for (SubmoduleModel model : JGitUtils.getSubmodules(r, commit.getTree())) {
      submodules.put(model.path, model);
    }

    PathModel matchingPath = null;
    for (PathModel p : paths) {
      if (p.path.equals(path)) {
        matchingPath = p;
        break;
      }
    }
    if (matchingPath == null) {
      // path not in commit
      // manually locate path in tree
      TreeWalk tw = new TreeWalk(r);
      tw.reset();
      tw.setRecursive(true);
      try {
        tw.addTree(commit.getTree());
        tw.setFilter(PathFilterGroup.createFromStrings(Collections.singleton(path)));
        while (tw.next()) {
          if (tw.getPathString().equals(path)) {
            matchingPath =
                new PathChangeModel(
                    tw.getPathString(),
                    tw.getPathString(),
                    0,
                    tw.getRawMode(0),
                    tw.getObjectId(0).getName(),
                    commit.getId().getName(),
                    ChangeType.MODIFY);
          }
        }
      } catch (Exception e) {
      } finally {
        tw.release();
      }
    }

    final boolean isTree = matchingPath == null ? true : matchingPath.isTree();
    final boolean isSubmodule = matchingPath == null ? true : matchingPath.isSubmodule();

    // submodule
    SubmoduleModel submodule = getSubmodule(submodules, repositoryName, matchingPath.path);
    final String submodulePath;
    final boolean hasSubmodule;
    if (submodule != null) {
      submodulePath = submodule.gitblitPath;
      hasSubmodule = submodule.hasSubmodule;
    } else {
      submodulePath = "";
      hasSubmodule = false;
    }

    final Map<ObjectId, List<RefModel>> allRefs = JGitUtils.getAllRefs(r, showRemoteRefs);
    List<RevCommit> commits;
    if (pageResults) {
      // Paging result set
      commits = JGitUtils.getRevLog(r, objectId, path, pageOffset * itemsPerPage, itemsPerPage);
    } else {
      // Fixed size result set
      commits = JGitUtils.getRevLog(r, objectId, path, 0, limit);
    }

    // inaccurate way to determine if there are more commits.
    // works unless commits.size() represents the exact end.
    hasMore = commits.size() >= itemsPerPage;

    add(new CommitHeaderPanel("commitHeader", repositoryName, commit));

    // breadcrumbs
    add(new PathBreadcrumbsPanel("breadcrumbs", repositoryName, path, objectId));

    final int hashLen = GitBlit.getInteger(Keys.web.shortCommitIdLength, 6);
    ListDataProvider<RevCommit> dp = new ListDataProvider<RevCommit>(commits);
    DataView<RevCommit> logView =
        new DataView<RevCommit>("commit", dp) {
          private static final long serialVersionUID = 1L;
          int counter;

          public void populateItem(final Item<RevCommit> item) {
            final RevCommit entry = item.getModelObject();
            final Date date = JGitUtils.getCommitDate(entry);

            item.add(
                WicketUtils.createDateLabel("commitDate", date, getTimeZone(), getTimeUtils()));

            // author search link
            String author = entry.getAuthorIdent().getName();
            LinkPanel authorLink =
                new LinkPanel(
                    "commitAuthor",
                    "list",
                    author,
                    GitSearchPage.class,
                    WicketUtils.newSearchParameter(
                        repositoryName, objectId, author, Constants.SearchType.AUTHOR));
            setPersonSearchTooltip(authorLink, author, Constants.SearchType.AUTHOR);
            item.add(authorLink);

            // merge icon
            if (entry.getParentCount() > 1) {
              item.add(WicketUtils.newImage("commitIcon", "commit_merge_16x16.png"));
            } else {
              item.add(WicketUtils.newBlankImage("commitIcon"));
            }

            String shortMessage = entry.getShortMessage();
            String trimmedMessage = shortMessage;
            if (allRefs.containsKey(entry.getId())) {
              trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG_REFS);
            } else {
              trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG);
            }
            LinkPanel shortlog =
                new LinkPanel(
                    "commitShortMessage",
                    "list subject",
                    trimmedMessage,
                    CommitPage.class,
                    WicketUtils.newObjectParameter(repositoryName, entry.getName()));
            if (!shortMessage.equals(trimmedMessage)) {
              WicketUtils.setHtmlTooltip(shortlog, shortMessage);
            }
            item.add(shortlog);

            item.add(new RefsPanel("commitRefs", repositoryName, entry, allRefs));

            if (isTree) {
              // tree
              item.add(new Label("hashLabel", getString("gb.tree") + "@"));
              LinkPanel commitHash =
                  new LinkPanel(
                      "hashLink",
                      null,
                      entry.getName().substring(0, hashLen),
                      TreePage.class,
                      WicketUtils.newObjectParameter(repositoryName, entry.getName()));
              WicketUtils.setCssClass(commitHash, "shortsha1");
              WicketUtils.setHtmlTooltip(commitHash, entry.getName());
              item.add(commitHash);

              Fragment links = new Fragment("historyLinks", "treeLinks", this);
              links.add(
                  new BookmarkablePageLink<Void>(
                      "commitdiff",
                      CommitDiffPage.class,
                      WicketUtils.newObjectParameter(repositoryName, entry.getName())));
              item.add(links);
            } else if (isSubmodule) {
              // submodule
              item.add(new Label("hashLabel", submodulePath + "@"));
              Repository repository = GitBlit.self().getRepository(repositoryName);
              String submoduleId = JGitUtils.getSubmoduleCommitId(repository, path, entry);
              repository.close();
              LinkPanel commitHash =
                  new LinkPanel(
                      "hashLink",
                      null,
                      submoduleId.substring(0, hashLen),
                      TreePage.class,
                      WicketUtils.newObjectParameter(submodulePath, submoduleId));
              WicketUtils.setCssClass(commitHash, "shortsha1");
              WicketUtils.setHtmlTooltip(commitHash, submoduleId);
              item.add(commitHash.setEnabled(hasSubmodule));

              Fragment links = new Fragment("historyLinks", "treeLinks", this);
              links.add(
                  new BookmarkablePageLink<Void>(
                      "commitdiff",
                      CommitDiffPage.class,
                      WicketUtils.newObjectParameter(repositoryName, entry.getName())));
              item.add(links);
            } else {
              // commit
              item.add(new Label("hashLabel", getString("gb.blob") + "@"));
              LinkPanel commitHash =
                  new LinkPanel(
                      "hashLink",
                      null,
                      entry.getName().substring(0, hashLen),
                      BlobPage.class,
                      WicketUtils.newPathParameter(repositoryName, entry.getName(), path));
              WicketUtils.setCssClass(commitHash, "sha1");
              WicketUtils.setHtmlTooltip(commitHash, entry.getName());
              item.add(commitHash);

              Fragment links = new Fragment("historyLinks", "blobLinks", this);
              links.add(
                  new BookmarkablePageLink<Void>(
                      "commitdiff",
                      CommitDiffPage.class,
                      WicketUtils.newObjectParameter(repositoryName, entry.getName())));
              links.add(
                  new BookmarkablePageLink<Void>(
                          "difftocurrent",
                          BlobDiffPage.class,
                          WicketUtils.newBlobDiffParameter(
                              repositoryName, entry.getName(), objectId, path))
                      .setEnabled(counter > 0));
              item.add(links);
            }

            WicketUtils.setAlternatingBackground(item, counter);
            counter++;
          }
        };
    add(logView);

    // determine to show pager, more, or neither
    if (limit <= 0) {
      // no display limit
      add(new Label("moreHistory", "").setVisible(false));
    } else {
      if (pageResults) {
        // paging
        add(new Label("moreHistory", "").setVisible(false));
      } else {
        // more
        if (commits.size() == limit) {
          // show more
          add(
              new LinkPanel(
                  "moreHistory",
                  "link",
                  new StringResourceModel("gb.moreHistory", this, null),
                  HistoryPage.class,
                  WicketUtils.newPathParameter(repositoryName, objectId, path)));
        } else {
          // no more
          add(new Label("moreHistory", "").setVisible(false));
        }
      }
    }
  }
Beispiel #10
0
  @Override
  public List<CommitInfo> history(
      String objectId,
      String path,
      int limit,
      int pageOffset,
      boolean showRemoteRefs,
      int itemsPerPage) {
    try {
      if (itemsPerPage <= 1) {
        itemsPerPage = 50;
      }
      boolean pageResults = limit <= 0;
      Repository r = git.getRepository();

      // TODO not sure if this is the right String we should use for the sub module stuff...
      String repositoryName = getConfigDirectory().getPath();

      objectId = defaultObjectId(objectId);
      RevCommit commit = JGitUtils.getCommit(r, objectId);
      List<PathModel.PathChangeModel> paths = JGitUtils.getFilesInCommit(r, commit);

      Map<String, SubmoduleModel> submodules = new HashMap<String, SubmoduleModel>();
      for (SubmoduleModel model : JGitUtils.getSubmodules(r, commit.getTree())) {
        submodules.put(model.path, model);
      }

      PathModel matchingPath = null;
      for (PathModel p : paths) {
        if (p.path.equals(path)) {
          matchingPath = p;
          break;
        }
      }
      if (matchingPath == null) {
        // path not in commit
        // manually locate path in tree
        TreeWalk tw = new TreeWalk(r);
        tw.reset();
        tw.setRecursive(true);
        try {
          tw.addTree(commit.getTree());
          tw.setFilter(PathFilterGroup.createFromStrings(Collections.singleton(path)));
          while (tw.next()) {
            if (tw.getPathString().equals(path)) {
              matchingPath =
                  new PathModel.PathChangeModel(
                      tw.getPathString(),
                      tw.getPathString(),
                      0,
                      tw.getRawMode(0),
                      tw.getObjectId(0).getName(),
                      commit.getId().getName(),
                      ChangeType.MODIFY);
            }
          }
        } catch (Exception e) {
        } finally {
          tw.release();
        }
      }

      final boolean isTree = matchingPath == null ? true : matchingPath.isTree();
      final boolean isSubmodule = matchingPath == null ? true : matchingPath.isSubmodule();

      // submodule
      SubmoduleModel submodule = null;
      if (matchingPath != null) {
        submodule = getSubmodule(submodules, repositoryName, matchingPath.path);
      }
      final String submodulePath;
      final boolean hasSubmodule;
      if (submodule != null) {
        submodulePath = submodule.gitblitPath;
        hasSubmodule = submodule.hasSubmodule;
      } else {
        submodulePath = "";
        hasSubmodule = false;
      }

      final Map<ObjectId, List<RefModel>> allRefs = JGitUtils.getAllRefs(r, showRemoteRefs);
      List<RevCommit> commits;
      if (pageResults) {
        // Paging result set
        commits = JGitUtils.getRevLog(r, objectId, path, pageOffset * itemsPerPage, itemsPerPage);
      } else {
        // Fixed size result set
        commits = JGitUtils.getRevLog(r, objectId, path, 0, limit);
      }

      // inaccurate way to determine if there are more commits.
      // works unless commits.size() represents the exact end.
      boolean hasMore = commits.size() >= itemsPerPage;

      List<CommitInfo> results = new ArrayList<CommitInfo>();
      for (RevCommit entry : commits) {
        final Date date = JGitUtils.getCommitDate(entry);
        String author = entry.getAuthorIdent().getName();
        boolean merge = entry.getParentCount() > 1;

        String shortMessage = entry.getShortMessage();
        String trimmedMessage = shortMessage;
        if (allRefs.containsKey(entry.getId())) {
          trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG_REFS);
        } else {
          trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG);
        }
        String name = entry.getName();
        String commitHashText = getShortCommitHash(name);

        String kind;
        if (isTree) {
          kind = "tree";
        } else if (isSubmodule) {
          kind = "submodule";
        } else kind = "file";

        results.add(
            new CommitInfo(
                commitHashText, name, kind, author, date, merge, trimmedMessage, shortMessage));
      }
      return results;
    } catch (Exception e) {
      throw new RuntimeIOException(e);
    }
  }
Beispiel #11
0
  public SummaryPage(PageParameters params) {
    super(params);

    int numberCommits = GitBlit.getInteger(Keys.web.summaryCommitCount, 20);
    if (numberCommits <= 0) {
      numberCommits = 20;
    }
    int numberRefs = GitBlit.getInteger(Keys.web.summaryRefsCount, 5);

    Repository r = getRepository();
    RepositoryModel model = getRepositoryModel();

    List<Metric> metrics = null;
    Metric metricsTotal = null;
    if (!model.skipSummaryMetrics && GitBlit.getBoolean(Keys.web.generateActivityGraph, true)) {
      metrics = GitBlit.self().getRepositoryDefaultMetrics(model, r);
      metricsTotal = metrics.remove(0);
    }

    addSyndicationDiscoveryLink();

    // repository description
    add(new Label("repositoryDescription", getRepositoryModel().description));
    add(new Label("repositoryOwner", getRepositoryModel().owner));

    add(
        WicketUtils.createTimestampLabel(
            "repositoryLastChange", JGitUtils.getLastChange(r), getTimeZone()));
    if (metricsTotal == null) {
      add(new Label("branchStats", ""));
    } else {
      add(
          new Label(
              "branchStats",
              MessageFormat.format(
                  "{0} commits and {1} tags in {2}",
                  metricsTotal.count,
                  metricsTotal.tag,
                  TimeUtils.duration(metricsTotal.duration))));
    }
    add(
        new BookmarkablePageLink<Void>(
            "metrics", MetricsPage.class, WicketUtils.newRepositoryParameter(repositoryName)));

    List<String> repositoryUrls = new ArrayList<String>();

    if (GitBlit.getBoolean(Keys.git.enableGitServlet, true)) {
      AccessRestrictionType accessRestriction = getRepositoryModel().accessRestriction;
      switch (accessRestriction) {
        case NONE:
          add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
          break;
        case PUSH:
          add(
              WicketUtils.newImage(
                  "accessRestrictionIcon",
                  "lock_go_16x16.png",
                  getAccessRestrictions().get(accessRestriction)));
          break;
        case CLONE:
          add(
              WicketUtils.newImage(
                  "accessRestrictionIcon",
                  "lock_pull_16x16.png",
                  getAccessRestrictions().get(accessRestriction)));
          break;
        case VIEW:
          add(
              WicketUtils.newImage(
                  "accessRestrictionIcon",
                  "shield_16x16.png",
                  getAccessRestrictions().get(accessRestriction)));
          break;
        default:
          add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
      }
      // add the Gitblit repository url
      repositoryUrls.add(getRepositoryUrl(getRepositoryModel()));
    } else {
      add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
    }
    repositoryUrls.addAll(GitBlit.self().getOtherCloneUrls(repositoryName));

    String primaryUrl = ArrayUtils.isEmpty(repositoryUrls) ? "" : repositoryUrls.remove(0);
    add(new RepositoryUrlPanel("repositoryCloneUrl", primaryUrl));

    add(
        new Label("otherUrls", StringUtils.flattenStrings(repositoryUrls, "<br/>"))
            .setEscapeModelStrings(false));

    add(
        new LogPanel(
            "commitsPanel", repositoryName, getRepositoryModel().HEAD, r, numberCommits, 0));
    add(new TagsPanel("tagsPanel", repositoryName, r, numberRefs).hideIfEmpty());
    add(new BranchesPanel("branchesPanel", getRepositoryModel(), r, numberRefs).hideIfEmpty());

    if (getRepositoryModel().showReadme) {
      String htmlText = null;
      String readme = null;
      try {
        RevCommit head = JGitUtils.getCommit(r, null);
        List<String> markdownExtensions = GitBlit.getStrings(Keys.web.markdownExtensions);
        List<PathModel> paths = JGitUtils.getFilesInPath(r, null, head);
        for (PathModel path : paths) {
          if (!path.isTree()) {
            String name = path.name.toLowerCase();

            if (name.startsWith("readme")) {
              if (name.indexOf('.') > -1) {
                String ext = name.substring(name.lastIndexOf('.') + 1);
                if (markdownExtensions.contains(ext)) {
                  readme = path.name;
                  break;
                }
              }
            }
          }
        }
        if (!StringUtils.isEmpty(readme)) {
          String markdownText = JGitUtils.getStringContent(r, head.getTree(), readme);
          htmlText = MarkdownUtils.transformMarkdown(markdownText);
        }
      } catch (ParseException p) {
        error(p.getMessage());
      }
      Fragment fragment = new Fragment("readme", "markdownPanel");
      fragment.add(new Label("readmeFile", readme));
      // Add the html to the page
      Component content = new Label("readmeContent", htmlText).setEscapeModelStrings(false);
      fragment.add(content.setVisible(!StringUtils.isEmpty(htmlText)));
      add(fragment);
    } else {
      add(new Label("readme").setVisible(false));
    }

    // Display an activity line graph
    insertActivityGraph(metrics);
  }
  /**
   * Mirrors a repository and, optionally, the server's users, and/or configuration settings from a
   * origin Gitblit instance.
   *
   * @param registration
   * @throws Exception
   */
  private void pull(FederationModel registration) throws Exception {
    Map<String, RepositoryModel> repositories = FederationUtils.getRepositories(registration, true);
    String registrationFolder = registration.folder.toLowerCase().trim();
    // confirm valid characters in server alias
    Character c = StringUtils.findInvalidCharacter(registrationFolder);
    if (c != null) {
      logger.error(
          MessageFormat.format(
              "Illegal character ''{0}'' in folder name ''{1}'' of federation registration {2}!",
              c, registrationFolder, registration.name));
      return;
    }
    File repositoriesFolder = new File(GitBlit.getString(Keys.git.repositoriesFolder, "git"));
    File registrationFolderFile = new File(repositoriesFolder, registrationFolder);
    registrationFolderFile.mkdirs();

    // Clone/Pull the repository
    for (Map.Entry<String, RepositoryModel> entry : repositories.entrySet()) {
      String cloneUrl = entry.getKey();
      RepositoryModel repository = entry.getValue();
      if (!repository.hasCommits) {
        logger.warn(
            MessageFormat.format(
                "Skipping federated repository {0} from {1} @ {2}. Repository is EMPTY.",
                repository.name, registration.name, registration.url));
        registration.updateStatus(repository, FederationPullStatus.SKIPPED);
        continue;
      }

      // Determine local repository name
      String repositoryName;
      if (StringUtils.isEmpty(registrationFolder)) {
        repositoryName = repository.name;
      } else {
        repositoryName = registrationFolder + "/" + repository.name;
      }

      if (registration.bare) {
        // bare repository, ensure .git suffix
        if (!repositoryName.toLowerCase().endsWith(DOT_GIT_EXT)) {
          repositoryName += DOT_GIT_EXT;
        }
      } else {
        // normal repository, strip .git suffix
        if (repositoryName.toLowerCase().endsWith(DOT_GIT_EXT)) {
          repositoryName = repositoryName.substring(0, repositoryName.indexOf(DOT_GIT_EXT));
        }
      }

      // confirm that the origin of any pre-existing repository matches
      // the clone url
      String fetchHead = null;
      Repository existingRepository = GitBlit.self().getRepository(repositoryName);

      if (existingRepository == null && GitBlit.self().isCollectingGarbage(repositoryName)) {
        logger.warn(
            MessageFormat.format(
                "Skipping local repository {0}, busy collecting garbage", repositoryName));
        continue;
      }

      if (existingRepository != null) {
        StoredConfig config = existingRepository.getConfig();
        config.load();
        String origin = config.getString("remote", "origin", "url");
        RevCommit commit =
            JGitUtils.getCommit(existingRepository, org.eclipse.jgit.lib.Constants.FETCH_HEAD);
        if (commit != null) {
          fetchHead = commit.getName();
        }
        existingRepository.close();
        if (!origin.startsWith(registration.url)) {
          logger.warn(
              MessageFormat.format(
                  "Skipping federated repository {0} from {1} @ {2}. Origin does not match, consider EXCLUDING.",
                  repository.name, registration.name, registration.url));
          registration.updateStatus(repository, FederationPullStatus.SKIPPED);
          continue;
        }
      }

      // clone/pull this repository
      CredentialsProvider credentials =
          new UsernamePasswordCredentialsProvider(Constants.FEDERATION_USER, registration.token);
      logger.info(
          MessageFormat.format(
              "Pulling federated repository {0} from {1} @ {2}",
              repository.name, registration.name, registration.url));

      CloneResult result =
          JGitUtils.cloneRepository(
              registrationFolderFile, repository.name, cloneUrl, registration.bare, credentials);
      Repository r = GitBlit.self().getRepository(repositoryName);
      RepositoryModel rm = GitBlit.self().getRepositoryModel(repositoryName);
      repository.isFrozen = registration.mirror;
      if (result.createdRepository) {
        // default local settings
        repository.federationStrategy = FederationStrategy.EXCLUDE;
        repository.isFrozen = registration.mirror;
        repository.showRemoteBranches = !registration.mirror;
        logger.info(MessageFormat.format("     cloning {0}", repository.name));
        registration.updateStatus(repository, FederationPullStatus.MIRRORED);
      } else {
        // fetch and update
        boolean fetched = false;
        RevCommit commit = JGitUtils.getCommit(r, org.eclipse.jgit.lib.Constants.FETCH_HEAD);
        String newFetchHead = commit.getName();
        fetched = fetchHead == null || !fetchHead.equals(newFetchHead);

        if (registration.mirror) {
          // mirror
          if (fetched) {
            // update local branches to match the remote tracking branches
            for (RefModel ref : JGitUtils.getRemoteBranches(r, false, -1)) {
              if (ref.displayName.startsWith("origin/")) {
                String branch =
                    org.eclipse.jgit.lib.Constants.R_HEADS
                        + ref.displayName.substring(ref.displayName.indexOf('/') + 1);
                String hash = ref.getReferencedObjectId().getName();

                JGitUtils.setBranchRef(r, branch, hash);
                logger.info(
                    MessageFormat.format(
                        "     resetting {0} of {1} to {2}", branch, repository.name, hash));
              }
            }

            String newHead;
            if (StringUtils.isEmpty(repository.HEAD)) {
              newHead = newFetchHead;
            } else {
              newHead = repository.HEAD;
            }
            JGitUtils.setHEADtoRef(r, newHead);
            logger.info(
                MessageFormat.format(
                    "     resetting HEAD of {0} to {1}", repository.name, newHead));
            registration.updateStatus(repository, FederationPullStatus.MIRRORED);
          } else {
            // indicate no commits pulled
            registration.updateStatus(repository, FederationPullStatus.NOCHANGE);
          }
        } else {
          // non-mirror
          if (fetched) {
            // indicate commits pulled to origin/master
            registration.updateStatus(repository, FederationPullStatus.PULLED);
          } else {
            // indicate no commits pulled
            registration.updateStatus(repository, FederationPullStatus.NOCHANGE);
          }
        }

        // preserve local settings
        repository.isFrozen = rm.isFrozen;
        repository.federationStrategy = rm.federationStrategy;

        // merge federation sets
        Set<String> federationSets = new HashSet<String>();
        if (rm.federationSets != null) {
          federationSets.addAll(rm.federationSets);
        }
        if (repository.federationSets != null) {
          federationSets.addAll(repository.federationSets);
        }
        repository.federationSets = new ArrayList<String>(federationSets);

        // merge indexed branches
        Set<String> indexedBranches = new HashSet<String>();
        if (rm.indexedBranches != null) {
          indexedBranches.addAll(rm.indexedBranches);
        }
        if (repository.indexedBranches != null) {
          indexedBranches.addAll(repository.indexedBranches);
        }
        repository.indexedBranches = new ArrayList<String>(indexedBranches);
      }
      // only repositories that are actually _cloned_ from the origin
      // Gitblit repository are marked as federated. If the origin
      // is from somewhere else, these repositories are not considered
      // "federated" repositories.
      repository.isFederated = cloneUrl.startsWith(registration.url);

      GitBlit.self().updateConfiguration(r, repository);
      r.close();
    }

    IUserService userService = null;

    try {
      // Pull USERS
      // TeamModels are automatically pulled because they are contained
      // within the UserModel. The UserService creates unknown teams
      // and updates existing teams.
      Collection<UserModel> users = FederationUtils.getUsers(registration);
      if (users != null && users.size() > 0) {
        File realmFile = new File(registrationFolderFile, registration.name + "_users.conf");
        realmFile.delete();
        userService = new ConfigUserService(realmFile);
        for (UserModel user : users) {
          userService.updateUserModel(user.username, user);

          // merge the origin permissions and origin accounts into
          // the user accounts of this Gitblit instance
          if (registration.mergeAccounts) {
            // reparent all repository permissions if the local
            // repositories are stored within subfolders
            if (!StringUtils.isEmpty(registrationFolder)) {
              if (user.permissions != null) {
                // pulling from >= 1.2 version
                Map<String, AccessPermission> copy =
                    new HashMap<String, AccessPermission>(user.permissions);
                user.permissions.clear();
                for (Map.Entry<String, AccessPermission> entry : copy.entrySet()) {
                  user.setRepositoryPermission(
                      registrationFolder + "/" + entry.getKey(), entry.getValue());
                }
              } else {
                // pulling from <= 1.1 version
                List<String> permissions = new ArrayList<String>(user.repositories);
                user.repositories.clear();
                for (String permission : permissions) {
                  user.addRepositoryPermission(registrationFolder + "/" + permission);
                }
              }
            }

            // insert new user or update local user
            UserModel localUser = GitBlit.self().getUserModel(user.username);
            if (localUser == null) {
              // create new local user
              GitBlit.self().updateUserModel(user.username, user, true);
            } else {
              // update repository permissions of local user
              if (user.permissions != null) {
                // pulling from >= 1.2 version
                Map<String, AccessPermission> copy =
                    new HashMap<String, AccessPermission>(user.permissions);
                for (Map.Entry<String, AccessPermission> entry : copy.entrySet()) {
                  localUser.setRepositoryPermission(entry.getKey(), entry.getValue());
                }
              } else {
                // pulling from <= 1.1 version
                for (String repository : user.repositories) {
                  localUser.addRepositoryPermission(repository);
                }
              }
              localUser.password = user.password;
              localUser.canAdmin = user.canAdmin;
              GitBlit.self().updateUserModel(localUser.username, localUser, false);
            }

            for (String teamname : GitBlit.self().getAllTeamnames()) {
              TeamModel team = GitBlit.self().getTeamModel(teamname);
              if (user.isTeamMember(teamname) && !team.hasUser(user.username)) {
                // new team member
                team.addUser(user.username);
                GitBlit.self().updateTeamModel(teamname, team, false);
              } else if (!user.isTeamMember(teamname) && team.hasUser(user.username)) {
                // remove team member
                team.removeUser(user.username);
                GitBlit.self().updateTeamModel(teamname, team, false);
              }

              // update team repositories
              TeamModel remoteTeam = user.getTeam(teamname);
              if (remoteTeam != null) {
                if (remoteTeam.permissions != null) {
                  // pulling from >= 1.2
                  for (Map.Entry<String, AccessPermission> entry :
                      remoteTeam.permissions.entrySet()) {
                    team.setRepositoryPermission(entry.getKey(), entry.getValue());
                  }
                  GitBlit.self().updateTeamModel(teamname, team, false);
                } else if (!ArrayUtils.isEmpty(remoteTeam.repositories)) {
                  // pulling from <= 1.1
                  team.addRepositoryPermissions(remoteTeam.repositories);
                  GitBlit.self().updateTeamModel(teamname, team, false);
                }
              }
            }
          }
        }
      }
    } catch (ForbiddenException e) {
      // ignore forbidden exceptions
    } catch (IOException e) {
      logger.warn(
          MessageFormat.format(
              "Failed to retrieve USERS from federated gitblit ({0} @ {1})",
              registration.name, registration.url),
          e);
    }

    try {
      // Pull TEAMS
      // We explicitly pull these even though they are embedded in
      // UserModels because it is possible to use teams to specify
      // mailing lists or push scripts without specifying users.
      if (userService != null) {
        Collection<TeamModel> teams = FederationUtils.getTeams(registration);
        if (teams != null && teams.size() > 0) {
          for (TeamModel team : teams) {
            userService.updateTeamModel(team);
          }
        }
      }
    } catch (ForbiddenException e) {
      // ignore forbidden exceptions
    } catch (IOException e) {
      logger.warn(
          MessageFormat.format(
              "Failed to retrieve TEAMS from federated gitblit ({0} @ {1})",
              registration.name, registration.url),
          e);
    }

    try {
      // Pull SETTINGS
      Map<String, String> settings = FederationUtils.getSettings(registration);
      if (settings != null && settings.size() > 0) {
        Properties properties = new Properties();
        properties.putAll(settings);
        FileOutputStream os =
            new FileOutputStream(
                new File(
                    registrationFolderFile, registration.name + "_" + Constants.PROPERTIES_FILE));
        properties.store(os, null);
        os.close();
      }
    } catch (ForbiddenException e) {
      // ignore forbidden exceptions
    } catch (IOException e) {
      logger.warn(
          MessageFormat.format(
              "Failed to retrieve SETTINGS from federated gitblit ({0} @ {1})",
              registration.name, registration.url),
          e);
    }

    try {
      // Pull SCRIPTS
      Map<String, String> scripts = FederationUtils.getScripts(registration);
      if (scripts != null && scripts.size() > 0) {
        for (Map.Entry<String, String> script : scripts.entrySet()) {
          String scriptName = script.getKey();
          if (scriptName.endsWith(".groovy")) {
            scriptName = scriptName.substring(0, scriptName.indexOf(".groovy"));
          }
          File file =
              new File(registrationFolderFile, registration.name + "_" + scriptName + ".groovy");
          FileUtils.writeContent(file, script.getValue());
        }
      }
    } catch (ForbiddenException e) {
      // ignore forbidden exceptions
    } catch (IOException e) {
      logger.warn(
          MessageFormat.format(
              "Failed to retrieve SCRIPTS from federated gitblit ({0} @ {1})",
              registration.name, registration.url),
          e);
    }
  }