/**
   * 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();
    }
  }
示例#2
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);
 }
示例#3
0
  @Override
  public List<CommitInfo> log(
      String objectId,
      final 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);

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

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

        // short message
        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 commitHash = getShortCommitHash(name);
        answer.add(
            new CommitInfo(
                commitHash, name, "log", author, date, merge, trimmedMessage, shortMessage));
      }
      return answer;
    } catch (Exception e) {
      throw new RuntimeIOException(e);
    }
  }
示例#4
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);
 }
示例#5
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);
 }
 /**
  * Returns the assigned ticket ids.
  *
  * @return the assigned ticket ids
  */
 @Override
 public synchronized Set<Long> getIds(RepositoryModel repository) {
   Repository db = repositoryManager.getRepository(repository.name);
   try {
     if (getTicketsBranch(db) == null) {
       return Collections.emptySet();
     }
     Set<Long> ids = new TreeSet<Long>();
     List<PathModel> paths = JGitUtils.getDocuments(db, Arrays.asList("json"), BRANCH);
     for (PathModel path : paths) {
       String name = path.name.substring(path.name.lastIndexOf('/') + 1);
       if (!JOURNAL.equals(name)) {
         continue;
       }
       String tid = path.path.split("/")[2];
       long ticketId = Long.parseLong(tid);
       ids.add(ticketId);
     }
     return ids;
   } finally {
     if (db != null) {
       db.close();
     }
   }
 }
 /**
  * Returns a RefModel for the refs/meta/gitblit/tickets branch in the repository. If the branch
  * can not be found, null is returned.
  *
  * @return a refmodel for the gitblit tickets branch or null
  */
 private RefModel getTicketsBranch(Repository db) {
   List<RefModel> refs = JGitUtils.getRefs(db, "refs/");
   Ref oldRef = null;
   for (RefModel ref : refs) {
     if (ref.reference.getName().equals(BRANCH)) {
       return ref;
     } else if (ref.reference.getName().equals("refs/gitblit/tickets")) {
       oldRef = ref.reference;
     }
   }
   if (oldRef != null) {
     // rename old ref to refs/meta/gitblit/tickets
     RefRename cmd;
     try {
       cmd = db.renameRef(oldRef.getName(), BRANCH);
       cmd.setRefLogIdent(new PersonIdent("Gitblit", "gitblit@localhost"));
       cmd.setRefLogMessage("renamed " + oldRef.getName() + " => " + BRANCH);
       Result res = cmd.rename();
       switch (res) {
         case RENAMED:
           log.info(db.getDirectory() + " " + cmd.getRefLogMessage());
           return getTicketsBranch(db);
         default:
           log.error(
               "failed to rename " + oldRef.getName() + " => " + BRANCH + " (" + res.name() + ")");
       }
     } catch (IOException e) {
       log.error("failed to rename tickets branch", e);
     }
   }
   return null;
 }
 /**
  * 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;
 }
示例#9
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;
  }
示例#10
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;
 }
示例#11
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);
 }
  private File cloneDatasourceViewsGit(String datasourceName) throws Exception {
    File targetDir = getDatasourceViewsGit(datasourceName);

    // Create datasource views bare git repo
    Repository newRepo = new FileRepository(targetDir);
    if (!targetDir.exists()) {
      newRepo.create(true);
    }

    String remoteUrl = "file://" + targetDir.getAbsolutePath();
    File tmp = getTmpDirectory();
    File localRepo = new File(tmp, "opal-" + Long.toString(System.nanoTime()));
    JGitUtils.cloneRepository(
        localRepo.getParentFile(), localRepo.getName(), remoteUrl, false, null);
    return localRepo;
  }
 /**
  * Reads a file from the tickets branch.
  *
  * @param db
  * @param file
  * @return the file content or null
  */
 private String readTicketsFile(Repository db, String file) {
   try {
     ObjectId treeId = db.resolve(BRANCH + "^{tree}");
     if (treeId == null) {
       return null;
     }
     try (RevWalk rw = new RevWalk(db)) {
       RevTree tree = rw.lookupTree(treeId);
       if (tree != null) {
         return JGitUtils.getStringContent(db, tree, file, Constants.ENCODING);
       }
     }
   } catch (IOException e) {
     log.error("failed to read " + file, e);
   }
   return null;
 }
 @Override
 protected boolean deleteAllImpl(RepositoryModel repository) {
   Repository db = repositoryManager.getRepository(repository.name);
   try {
     RefModel branch = getTicketsBranch(db);
     if (branch != null) {
       return JGitUtils.deleteBranchRef(db, BRANCH);
     }
     return true;
   } catch (Exception e) {
     log.error(null, e);
   } finally {
     if (db != null) {
       db.close();
     }
   }
   return false;
 }
示例#15
0
  public OverviewPage(PageParameters params) {
    super(params);

    int numberRefs = GitBlit.getInteger(Keys.web.summaryRefsCount, 5);

    Repository r = getRepository();
    final RepositoryModel model = getRepositoryModel();
    UserModel user = GitBlitWebSession.get().getUser();
    if (user == null) {
      user = UserModel.ANONYMOUS;
    }

    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));

    // owner links
    final List<String> owners = new ArrayList<String>(getRepositoryModel().owners);
    ListDataProvider<String> ownersDp = new ListDataProvider<String>(owners);
    DataView<String> ownersView =
        new DataView<String>("repositoryOwners", ownersDp) {
          private static final long serialVersionUID = 1L;
          int counter = 0;

          public void populateItem(final Item<String> item) {
            String ownername = item.getModelObject();
            UserModel ownerModel = GitBlit.self().getUserModel(ownername);
            if (ownerModel != null) {
              item.add(
                  new LinkPanel(
                          "owner",
                          null,
                          ownerModel.getDisplayName(),
                          UserPage.class,
                          WicketUtils.newUsernameParameter(ownerModel.username))
                      .setRenderBodyOnly(true));
            } else {
              Label owner = new Label("owner", ownername);
              WicketUtils.setCssStyle(owner, "text-decoration: line-through;");
              WicketUtils.setHtmlTooltip(
                  owner, MessageFormat.format(getString("gb.failedToFindAccount"), ownername));
              item.add(owner);
            }
            counter++;
            item.add(new Label("comma", ",").setVisible(counter < owners.size()));
            item.setRenderBodyOnly(true);
          }
        };
    ownersView.setRenderBodyOnly(true);
    add(ownersView);

    add(
        WicketUtils.createTimestampLabel(
            "repositoryLastChange",
            JGitUtils.getLastChange(r).when,
            getTimeZone(),
            getTimeUtils()));
    add(new Label("repositorySize", model.size));

    if (metricsTotal == null) {
      add(new Label("branchStats", ""));
    } else {
      add(
          new Label(
              "branchStats",
              MessageFormat.format(
                  getString("gb.branchStats"),
                  metricsTotal.count,
                  metricsTotal.tag,
                  getTimeUtils().duration(metricsTotal.duration))));
    }
    add(
        new BookmarkablePageLink<Void>(
            "metrics", MetricsPage.class, WicketUtils.newRepositoryParameter(repositoryName)));

    add(new RepositoryUrlPanel("repositoryUrlPanel", false, user, model));

    int reflogCount = GitBlit.getInteger(Keys.web.overviewReflogCount, 5);
    ReflogPanel reflog = new ReflogPanel("reflogPanel", getRepositoryModel(), r, reflogCount, 0);
    add(reflog);
    add(new TagsPanel("tagsPanel", repositoryName, r, numberRefs).hideIfEmpty());
    add(
        new BranchesPanel("branchesPanel", getRepositoryModel(), r, numberRefs, false)
            .hideIfEmpty());

    // Display an activity line graph
    insertActivityGraph(metrics);
  }
示例#16
0
  /**
   * Processes an rpc request.
   *
   * @param request
   * @param response
   * @throws javax.servlet.ServletException
   * @throws java.io.IOException
   */
  @Override
  protected void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    RpcRequest reqType = RpcRequest.fromName(request.getParameter("req"));
    String objectName = request.getParameter("name");
    logger.info(MessageFormat.format("Rpc {0} request from {1}", reqType, request.getRemoteAddr()));

    UserModel user = (UserModel) request.getUserPrincipal();

    boolean allowManagement =
        user != null && user.canAdmin && GitBlit.getBoolean(Keys.web.enableRpcManagement, false);

    boolean allowAdmin =
        user != null
            && user.canAdmin
            && GitBlit.getBoolean(Keys.web.enableRpcAdministration, false);

    Object result = null;
    if (RpcRequest.LIST_REPOSITORIES.equals(reqType)) {
      // Determine the Gitblit clone url
      String gitblitUrl = HttpUtils.getGitblitURL(request);
      StringBuilder sb = new StringBuilder();
      sb.append(gitblitUrl);
      sb.append(Constants.GIT_PATH);
      sb.append("{0}");
      String cloneUrl = sb.toString();

      // list repositories
      List<RepositoryModel> list = GitBlit.self().getRepositoryModels(user);
      Map<String, RepositoryModel> repositories = new HashMap<String, RepositoryModel>();
      for (RepositoryModel model : list) {
        String url = MessageFormat.format(cloneUrl, model.name);
        repositories.put(url, model);
      }
      result = repositories;
    } else if (RpcRequest.LIST_BRANCHES.equals(reqType)) {
      // list all local branches in all repositories accessible to user
      Map<String, List<String>> localBranches = new HashMap<String, List<String>>();
      List<RepositoryModel> models = GitBlit.self().getRepositoryModels(user);
      for (RepositoryModel model : models) {
        if (!model.hasCommits) {
          // skip empty repository
          continue;
        }
        // get local branches
        Repository repository = GitBlit.self().getRepository(model.name);
        List<RefModel> refs = JGitUtils.getLocalBranches(repository, false, -1);
        if (model.showRemoteBranches) {
          // add remote branches if repository displays them
          refs.addAll(JGitUtils.getRemoteBranches(repository, false, -1));
        }
        if (refs.size() > 0) {
          List<String> branches = new ArrayList<String>();
          for (RefModel ref : refs) {
            branches.add(ref.getName());
          }
          localBranches.put(model.name, branches);
        }
        repository.close();
      }
      result = localBranches;
    } else if (RpcRequest.LIST_USERS.equals(reqType)) {
      // list users
      List<String> names = GitBlit.self().getAllUsernames();
      List<UserModel> users = new ArrayList<UserModel>();
      for (String name : names) {
        users.add(GitBlit.self().getUserModel(name));
      }
      result = users;
    } else if (RpcRequest.CREATE_REPOSITORY.equals(reqType)) {
      // create repository
      RepositoryModel model = deserialize(request, response, RepositoryModel.class);
      try {
        GitBlit.self().updateRepositoryModel(model.name, model, true);
      } catch (GitBlitException e) {
        response.setStatus(failureCode);
      }
    } else if (RpcRequest.EDIT_REPOSITORY.equals(reqType)) {
      // edit repository
      RepositoryModel model = deserialize(request, response, RepositoryModel.class);
      // name specifies original repository name in event of rename
      String repoName = objectName;
      if (repoName == null) {
        repoName = model.name;
      }
      try {
        GitBlit.self().updateRepositoryModel(repoName, model, false);
      } catch (GitBlitException e) {
        response.setStatus(failureCode);
      }
    } else if (RpcRequest.DELETE_REPOSITORY.equals(reqType)) {
      // delete repository
      RepositoryModel model = deserialize(request, response, RepositoryModel.class);
      GitBlit.self().deleteRepositoryModel(model);
    } else if (RpcRequest.CREATE_USER.equals(reqType)) {
      // create user
      UserModel model = deserialize(request, response, UserModel.class);
      try {
        GitBlit.self().updateUserModel(model.username, model, true);
      } catch (GitBlitException e) {
        response.setStatus(failureCode);
      }
    } else if (RpcRequest.EDIT_USER.equals(reqType)) {
      // edit user
      UserModel model = deserialize(request, response, UserModel.class);
      // name parameter specifies original user name in event of rename
      String username = objectName;
      if (username == null) {
        username = model.username;
      }
      try {
        GitBlit.self().updateUserModel(username, model, false);
      } catch (GitBlitException e) {
        response.setStatus(failureCode);
      }
    } else if (RpcRequest.DELETE_USER.equals(reqType)) {
      // delete user
      UserModel model = deserialize(request, response, UserModel.class);
      if (!GitBlit.self().deleteUser(model.username)) {
        response.setStatus(failureCode);
      }
    } else if (RpcRequest.LIST_REPOSITORY_MEMBERS.equals(reqType)) {
      // get repository members
      RepositoryModel model = GitBlit.self().getRepositoryModel(objectName);
      result = GitBlit.self().getRepositoryUsers(model);
    } else if (RpcRequest.SET_REPOSITORY_MEMBERS.equals(reqType)) {
      // update repository access list
      RepositoryModel model = GitBlit.self().getRepositoryModel(objectName);
      Collection<String> names = deserialize(request, response, RpcUtils.NAMES_TYPE);
      List<String> users = new ArrayList<String>(names);
      if (!GitBlit.self().setRepositoryUsers(model, users)) {
        response.setStatus(failureCode);
      }
    } else if (RpcRequest.LIST_FEDERATION_REGISTRATIONS.equals(reqType)) {
      // return the list of federation registrations
      if (allowAdmin) {
        result = GitBlit.self().getFederationRegistrations();
      } else {
        response.sendError(notAllowedCode);
      }
    } else if (RpcRequest.LIST_FEDERATION_RESULTS.equals(reqType)) {
      // return the list of federation result registrations
      if (allowAdmin && GitBlit.canFederate()) {
        result = GitBlit.self().getFederationResultRegistrations();
      } else {
        response.sendError(notAllowedCode);
      }
    } else if (RpcRequest.LIST_FEDERATION_PROPOSALS.equals(reqType)) {
      // return the list of federation proposals
      if (allowAdmin && GitBlit.canFederate()) {
        result = GitBlit.self().getPendingFederationProposals();
      } else {
        response.sendError(notAllowedCode);
      }
    } else if (RpcRequest.LIST_FEDERATION_SETS.equals(reqType)) {
      // return the list of federation sets
      if (allowAdmin && GitBlit.canFederate()) {
        String gitblitUrl = HttpUtils.getGitblitURL(request);
        result = GitBlit.self().getFederationSets(gitblitUrl);
      } else {
        response.sendError(notAllowedCode);
      }
    } else if (RpcRequest.LIST_SETTINGS.equals(reqType)) {
      // return the server's settings
      ServerSettings settings = GitBlit.self().getSettingsModel();
      if (allowAdmin) {
        // return all settings
        result = settings;
      } else {
        // anonymous users get a few settings to allow browser launching
        List<String> keys = new ArrayList<String>();
        keys.add(Keys.web.siteName);
        keys.add(Keys.web.mountParameters);
        keys.add(Keys.web.syndicationEntries);

        if (allowManagement) {
          // keys necessary for repository and/or user management
          keys.add(Keys.realm.minPasswordLength);
          keys.add(Keys.realm.passwordStorage);
          keys.add(Keys.federation.sets);
        }
        // build the settings
        ServerSettings managementSettings = new ServerSettings();
        for (String key : keys) {
          managementSettings.add(settings.get(key));
        }
        result = managementSettings;
      }
    } else if (RpcRequest.EDIT_SETTINGS.equals(reqType)) {
      // update settings on the server
      if (allowAdmin) {
        Map<String, String> settings = deserialize(request, response, RpcUtils.SETTINGS_TYPE);
        GitBlit.self().updateSettings(settings);
      } else {
        response.sendError(notAllowedCode);
      }
    } else if (RpcRequest.LIST_STATUS.equals(reqType)) {
      // return the server's status information
      if (allowAdmin) {
        result = GitBlit.self().getStatus();
      } else {
        response.sendError(notAllowedCode);
      }
    }

    // send the result of the request
    serialize(response, result);
  }
示例#17
0
  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));
        }
      }
    }
  }
  /**
   * 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);
    }
  }
  /** Listen for tickets branch changes and (re)index tickets, as appropriate */
  @Override
  public synchronized void onRefsChanged(RefsChangedEvent event) {
    if (!(event instanceof ReceiveCommandEvent)) {
      return;
    }

    ReceiveCommandEvent branchUpdate = (ReceiveCommandEvent) event;
    RepositoryModel repository = branchUpdate.model;
    ReceiveCommand cmd = branchUpdate.cmd;
    try {
      switch (cmd.getType()) {
        case CREATE:
        case UPDATE_NONFASTFORWARD:
          // reindex everything
          reindex(repository);
          break;
        case UPDATE:
          // incrementally index ticket updates
          resetCaches(repository);
          long start = System.nanoTime();
          log.info(
              "incrementally indexing {} ticket branch due to received ref update",
              repository.name);
          Repository db = repositoryManager.getRepository(repository.name);
          try {
            Set<Long> ids = new HashSet<Long>();
            List<PathChangeModel> paths =
                JGitUtils.getFilesInRange(db, cmd.getOldId().getName(), cmd.getNewId().getName());
            for (PathChangeModel path : paths) {
              String name = path.name.substring(path.name.lastIndexOf('/') + 1);
              if (!JOURNAL.equals(name)) {
                continue;
              }
              String tid = path.path.split("/")[2];
              long ticketId = Long.parseLong(tid);
              if (!ids.contains(ticketId)) {
                ids.add(ticketId);
                TicketModel ticket = getTicket(repository, ticketId);
                log.info(
                    MessageFormat.format(
                        "indexing ticket #{0,number,0}: {1}", ticketId, ticket.title));
                indexer.index(ticket);
              }
            }
            long end = System.nanoTime();
            log.info(
                "incremental indexing of {0} ticket(s) completed in {1} msecs",
                ids.size(), TimeUnit.NANOSECONDS.toMillis(end - start));
          } finally {
            db.close();
          }
          break;
        default:
          log.warn(
              "Unexpected receive type {} in BranchTicketService.onRefsChanged" + cmd.getType());
          break;
      }
    } catch (Exception e) {
      log.error("failed to reindex " + repository.name, e);
    }
  }
示例#20
0
  public BranchesPanel(
      String wicketId, final RepositoryModel model, Repository r, final int maxCount) {
    super(wicketId);

    // branches
    List<RefModel> branches = new ArrayList<RefModel>();
    branches.addAll(JGitUtils.getLocalBranches(r, false, maxCount));
    if (model.showRemoteBranches) {
      branches.addAll(JGitUtils.getRemoteBranches(r, false, maxCount));
    }
    Collections.sort(branches);
    Collections.reverse(branches);
    if (maxCount > 0 && branches.size() > maxCount) {
      branches = new ArrayList<RefModel>(branches.subList(0, maxCount));
    }

    if (maxCount > 0) {
      // summary page
      // show branches page link
      add(
          new LinkPanel(
              "branches",
              "title",
              new StringResourceModel("gb.branches", this, null),
              BranchesPage.class,
              WicketUtils.newRepositoryParameter(model.name)));
    } else {
      // branches page
      // show repository summary page link
      add(
          new LinkPanel(
              "branches",
              "title",
              model.name,
              SummaryPage.class,
              WicketUtils.newRepositoryParameter(model.name)));
    }

    ListDataProvider<RefModel> branchesDp = new ListDataProvider<RefModel>(branches);
    DataView<RefModel> branchesView =
        new DataView<RefModel>("branch", branchesDp) {
          private static final long serialVersionUID = 1L;
          int counter;

          public void populateItem(final Item<RefModel> item) {
            final RefModel entry = item.getModelObject();

            item.add(WicketUtils.createDateLabel("branchDate", entry.getDate(), getTimeZone()));

            item.add(
                new LinkPanel(
                    "branchName",
                    "list name",
                    StringUtils.trimString(entry.displayName, 28),
                    LogPage.class,
                    WicketUtils.newObjectParameter(model.name, entry.getName())));

            String author = entry.getAuthorIdent().getName();
            LinkPanel authorLink =
                new LinkPanel(
                    "branchAuthor",
                    "list",
                    author,
                    SearchPage.class,
                    WicketUtils.newSearchParameter(
                        model.name, entry.getName(), author, SearchType.AUTHOR));
            setPersonSearchTooltip(authorLink, author, SearchType.AUTHOR);
            item.add(authorLink);

            // short message
            String shortMessage = entry.getShortMessage();
            String trimmedMessage = StringUtils.trimShortLog(shortMessage);
            LinkPanel shortlog =
                new LinkPanel(
                    "branchLog",
                    "list subject",
                    trimmedMessage,
                    CommitPage.class,
                    WicketUtils.newObjectParameter(model.name, entry.getName()));
            if (!shortMessage.equals(trimmedMessage)) {
              WicketUtils.setHtmlTooltip(shortlog, shortMessage);
            }
            item.add(shortlog);

            if (maxCount <= 0) {
              Fragment fragment = new Fragment("branchLinks", "branchPageLinks", this);
              fragment.add(
                  new BookmarkablePageLink<Void>(
                      "log",
                      LogPage.class,
                      WicketUtils.newObjectParameter(model.name, entry.getName())));
              fragment.add(
                  new BookmarkablePageLink<Void>(
                      "tree",
                      TreePage.class,
                      WicketUtils.newObjectParameter(model.name, entry.getName())));
              fragment.add(
                  new BookmarkablePageLink<Void>(
                      "metrics",
                      MetricsPage.class,
                      WicketUtils.newObjectParameter(model.name, entry.getName())));
              fragment.add(
                  new ExternalLink(
                      "syndication",
                      SyndicationServlet.asLink(
                          getRequest().getRelativePathPrefixToContextRoot(),
                          model.name,
                          entry.getName(),
                          0)));
              item.add(fragment);
            } else {
              Fragment fragment = new Fragment("branchLinks", "branchPanelLinks", this);
              fragment.add(
                  new BookmarkablePageLink<Void>(
                      "log",
                      LogPage.class,
                      WicketUtils.newObjectParameter(model.name, entry.getName())));
              fragment.add(
                  new BookmarkablePageLink<Void>(
                      "tree",
                      TreePage.class,
                      WicketUtils.newObjectParameter(model.name, entry.getName())));
              item.add(fragment);
            }
            WicketUtils.setAlternatingBackground(item, counter);
            counter++;
          }
        };
    add(branchesView);
    if (branches.size() < maxCount || maxCount <= 0) {
      add(new Label("allBranches", "").setVisible(false));
    } else {
      add(
          new LinkPanel(
              "allBranches",
              "link",
              new StringResourceModel("gb.allBranches", this, null),
              BranchesPage.class,
              WicketUtils.newRepositoryParameter(model.name)));
    }
    // We always have 1 branch
    hasBranches =
        (branches.size() > 1)
            || ((branches.size() == 1) && !branches.get(0).displayName.equalsIgnoreCase("master"));
  }
 /**
  * Creates the refs/meta/gitblit/tickets branch.
  *
  * @param db
  */
 private void createTicketsBranch(Repository db) {
   JGitUtils.createOrphanBranch(db, BRANCH, null);
 }
  /**
   * Returns all the tickets in the repository. Querying tickets from the repository requires
   * deserializing all tickets. This is an expensive process and not recommended. Tickets are
   * indexed by Lucene and queries should be executed against that index.
   *
   * @param repository
   * @param filter optional filter to only return matching results
   * @return a list of tickets
   */
  @Override
  public List<TicketModel> getTickets(RepositoryModel repository, TicketFilter filter) {
    List<TicketModel> list = new ArrayList<TicketModel>();

    Repository db = repositoryManager.getRepository(repository.name);
    try {
      RefModel ticketsBranch = getTicketsBranch(db);
      if (ticketsBranch == null) {
        return list;
      }

      // Collect the set of all json files
      List<PathModel> paths = JGitUtils.getDocuments(db, Arrays.asList("json"), BRANCH);

      // Deserialize each ticket and optionally filter out unwanted tickets
      for (PathModel path : paths) {
        String name = path.name.substring(path.name.lastIndexOf('/') + 1);
        if (!JOURNAL.equals(name)) {
          continue;
        }
        String json = readTicketsFile(db, path.path);
        if (StringUtils.isEmpty(json)) {
          // journal was touched but no changes were written
          continue;
        }
        try {
          // Reconstruct ticketId from the path
          // id/26/326/journal.json
          String tid = path.path.split("/")[2];
          long ticketId = Long.parseLong(tid);
          List<Change> changes = TicketSerializer.deserializeJournal(json);
          if (ArrayUtils.isEmpty(changes)) {
            log.warn("Empty journal for {}:{}", repository, path.path);
            continue;
          }
          TicketModel ticket = TicketModel.buildTicket(changes);
          ticket.project = repository.projectPath;
          ticket.repository = repository.name;
          ticket.number = ticketId;

          // add the ticket, conditionally, to the list
          if (filter == null) {
            list.add(ticket);
          } else {
            if (filter.accept(ticket)) {
              list.add(ticket);
            }
          }
        } catch (Exception e) {
          log.error(
              "failed to deserialize {}/{}\n{}",
              new Object[] {repository, path.path, e.getMessage()});
          log.error(null, e);
        }
      }

      // sort the tickets by creation
      Collections.sort(list);
      return list;
    } finally {
      db.close();
    }
  }
示例#23
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);
    }
  }
示例#24
0
 @Override
 public String getHEAD() {
   return JGitUtils.getHEADRef(git.getRepository());
 }
示例#25
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);
  }
示例#26
0
  public ComparePage(PageParameters params) {
    super(params);
    Repository r = getRepository();
    RepositoryModel repository = getRepositoryModel();

    if (StringUtils.isEmpty(objectId)) {
      // seleciton form
      add(new Label("comparison").setVisible(false));
    } else {
      // active comparison
      Fragment comparison = new Fragment("comparison", "comparisonFragment", this);
      add(comparison);

      RevCommit fromCommit;
      RevCommit toCommit;

      String[] parts = objectId.split("\\.\\.");
      if (parts[0].startsWith("refs/") && parts[1].startsWith("refs/")) {
        // set the ref models
        fromRefId.setObject(parts[0]);
        toRefId.setObject(parts[1]);

        fromCommit = getCommit(r, fromRefId.getObject());
        toCommit = getCommit(r, toRefId.getObject());
      } else {
        // set the id models
        fromCommitId.setObject(parts[0]);
        toCommitId.setObject(parts[1]);

        fromCommit = getCommit(r, fromCommitId.getObject());
        toCommit = getCommit(r, toCommitId.getObject());
      }

      // prepare submodules
      getSubmodules(toCommit);

      final String startId = fromCommit.getId().getName();
      final String endId = toCommit.getId().getName();

      // commit ids
      fromCommitId.setObject(startId);
      toCommitId.setObject(endId);

      final DiffOutput diff = DiffUtils.getDiff(r, fromCommit, toCommit, DiffOutputType.HTML);

      // add compare diffstat
      int insertions = 0;
      int deletions = 0;
      for (PathChangeModel pcm : diff.stat.paths) {
        insertions += pcm.insertions;
        deletions += pcm.deletions;
      }
      comparison.add(new DiffStatPanel("diffStat", insertions, deletions));

      // compare page links
      //			comparison.add(new BookmarkablePageLink<Void>("patchLink", PatchPage.class,
      //					WicketUtils.newRangeParameter(repositoryName, fromCommitId.toString(),
      // toCommitId.getObject())));

      // display list of commits
      comparison.add(
          new LogPanel(
              "commitList", repositoryName, objectId, r, 0, 0, repository.showRemoteBranches));

      // changed paths list
      comparison.add(new CommitLegendPanel("commitLegend", diff.stat.paths));
      ListDataProvider<PathChangeModel> pathsDp =
          new ListDataProvider<PathChangeModel>(diff.stat.paths);
      DataView<PathChangeModel> pathsView =
          new DataView<PathChangeModel>("changedPath", pathsDp) {
            private static final long serialVersionUID = 1L;
            int counter;

            @Override
            public void populateItem(final Item<PathChangeModel> item) {
              final PathChangeModel entry = item.getModelObject();
              Label changeType = new Label("changeType", "");
              WicketUtils.setChangeTypeCssClass(changeType, entry.changeType);
              setChangeTypeTooltip(changeType, entry.changeType);
              item.add(changeType);
              item.add(new DiffStatPanel("diffStat", entry.insertions, entry.deletions, true));

              boolean hasSubmodule = false;
              String submodulePath = null;
              if (entry.isTree()) {
                // tree
                item.add(
                    new LinkPanel(
                        "pathName",
                        null,
                        entry.path,
                        TreePage.class,
                        WicketUtils.newPathParameter(repositoryName, endId, entry.path)));
              } else if (entry.isSubmodule()) {
                // submodule
                String submoduleId = entry.objectId;
                SubmoduleModel submodule = getSubmodule(entry.path);
                submodulePath = submodule.gitblitPath;
                hasSubmodule = submodule.hasSubmodule;

                // add relative link
                item.add(
                    new LinkPanel(
                        "pathName",
                        "list",
                        entry.path + " @ " + getShortObjectId(submoduleId),
                        "#" + entry.path));
              } else {
                // add relative link
                item.add(new LinkPanel("pathName", "list", entry.path, "#" + entry.path));
              }

              // quick links
              if (entry.isSubmodule()) {
                // submodule
                item.add(new ExternalLink("patch", "").setEnabled(false));
                item.add(
                    new BookmarkablePageLink<Void>(
                            "view",
                            CommitPage.class,
                            WicketUtils.newObjectParameter(submodulePath, entry.objectId))
                        .setEnabled(hasSubmodule));
                item.add(new ExternalLink("blame", "").setEnabled(false));
                item.add(
                    new BookmarkablePageLink<Void>(
                            "history",
                            HistoryPage.class,
                            WicketUtils.newPathParameter(repositoryName, endId, entry.path))
                        .setEnabled(!entry.changeType.equals(ChangeType.ADD)));
              } else {
                // tree or blob
                item.add(
                    new BookmarkablePageLink<Void>(
                            "patch",
                            PatchPage.class,
                            WicketUtils.newBlobDiffParameter(
                                repositoryName, startId, endId, entry.path))
                        .setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
                item.add(
                    new BookmarkablePageLink<Void>(
                            "view",
                            BlobPage.class,
                            WicketUtils.newPathParameter(repositoryName, endId, entry.path))
                        .setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
                item.add(
                    new BookmarkablePageLink<Void>(
                            "raw",
                            RawPage.class,
                            WicketUtils.newPathParameter(repositoryName, endId, entry.path))
                        .setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
                item.add(
                    new BookmarkablePageLink<Void>(
                            "blame",
                            BlamePage.class,
                            WicketUtils.newPathParameter(repositoryName, endId, entry.path))
                        .setEnabled(
                            !entry.changeType.equals(ChangeType.ADD)
                                && !entry.changeType.equals(ChangeType.DELETE)));
                item.add(
                    new BookmarkablePageLink<Void>(
                            "history",
                            HistoryPage.class,
                            WicketUtils.newPathParameter(repositoryName, endId, entry.path))
                        .setEnabled(!entry.changeType.equals(ChangeType.ADD)));
              }
              WicketUtils.setAlternatingBackground(item, counter);
              counter++;
            }
          };
      comparison.add(pathsView);
      comparison.add(new Label("diffText", diff.content).setEscapeModelStrings(false));
    }

    //
    // ref selection form
    //
    SessionlessForm<Void> refsForm =
        new SessionlessForm<Void>("compareRefsForm", getClass(), getPageParameters()) {

          private static final long serialVersionUID = 1L;

          @Override
          public void onSubmit() {
            String from = ComparePage.this.fromRefId.getObject();
            String to = ComparePage.this.toRefId.getObject();

            PageParameters params = WicketUtils.newRangeParameter(repositoryName, from, to);
            String relativeUrl = urlFor(ComparePage.class, params).toString();
            String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl);
            getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));
          }
        };

    List<String> refs = new ArrayList<String>();
    for (RefModel ref : JGitUtils.getLocalBranches(r, true, -1)) {
      refs.add(ref.getName());
    }
    if (repository.showRemoteBranches) {
      for (RefModel ref : JGitUtils.getRemoteBranches(r, true, -1)) {
        refs.add(ref.getName());
      }
    }
    for (RefModel ref : JGitUtils.getTags(r, true, -1)) {
      refs.add(ref.getName());
    }
    refsForm.add(
        new DropDownChoice<String>("fromRef", fromRefId, refs).setEnabled(refs.size() > 0));
    refsForm.add(new DropDownChoice<String>("toRef", toRefId, refs).setEnabled(refs.size() > 0));
    add(refsForm);

    //
    // manual ids form
    //
    SessionlessForm<Void> idsForm =
        new SessionlessForm<Void>("compareIdsForm", getClass(), getPageParameters()) {

          private static final long serialVersionUID = 1L;

          @Override
          public void onSubmit() {
            String from = ComparePage.this.fromCommitId.getObject();
            String to = ComparePage.this.toCommitId.getObject();

            PageParameters params = WicketUtils.newRangeParameter(repositoryName, from, to);
            String relativeUrl = urlFor(ComparePage.class, params).toString();
            String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl);
            getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));
          }
        };

    TextField<String> fromIdField = new TextField<String>("fromId", fromCommitId);
    WicketUtils.setInputPlaceholder(fromIdField, getString("gb.from") + "...");
    idsForm.add(fromIdField);

    TextField<String> toIdField = new TextField<String>("toId", toCommitId);
    WicketUtils.setInputPlaceholder(toIdField, getString("gb.to") + "...");
    idsForm.add(toIdField);
    add(idsForm);

    r.close();
  }
  public CommitDiffPage(PageParameters params) {
    super(params);

    Repository r = getRepository();

    final RevCommit commit = getCommit();

    final List<String> parents = new ArrayList<String>();
    if (commit.getParentCount() > 0) {
      for (RevCommit parent : commit.getParents()) {
        parents.add(parent.name());
      }
    }

    // commit page links
    if (parents.size() == 0) {
      add(new Label("parentLink", getString("gb.none")));
    } else {
      add(
          new LinkPanel(
              "parentLink",
              null,
              parents.get(0).substring(0, 8),
              CommitDiffPage.class,
              newCommitParameter(parents.get(0))));
    }
    add(
        new BookmarkablePageLink<Void>(
            "patchLink",
            PatchPage.class,
            WicketUtils.newObjectParameter(repositoryName, objectId)));
    add(
        new BookmarkablePageLink<Void>(
            "commitLink",
            CommitPage.class,
            WicketUtils.newObjectParameter(repositoryName, objectId)));

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

    final List<String> imageExtensions = app().settings().getStrings(Keys.web.imageExtensions);
    final ImageDiffHandler handler =
        new ImageDiffHandler(
            this,
            repositoryName,
            parents.isEmpty() ? null : parents.get(0),
            commit.getName(),
            imageExtensions);
    final DiffOutput diff = DiffUtils.getCommitDiff(r, commit, DiffOutputType.HTML, handler);
    if (handler.getImgDiffCount() > 0) {
      addBottomScript("scripts/imgdiff.js"); // Tiny support script for image diffs
    }

    // add commit diffstat
    int insertions = 0;
    int deletions = 0;
    for (PathChangeModel pcm : diff.stat.paths) {
      insertions += pcm.insertions;
      deletions += pcm.deletions;
    }
    add(new DiffStatPanel("diffStat", insertions, deletions));

    addFullText("fullMessage", commit.getFullMessage());

    // git notes
    List<GitNote> notes = JGitUtils.getNotesOnCommit(r, commit);
    ListDataProvider<GitNote> notesDp = new ListDataProvider<GitNote>(notes);
    DataView<GitNote> notesView =
        new DataView<GitNote>("notes", notesDp) {
          private static final long serialVersionUID = 1L;

          @Override
          public void populateItem(final Item<GitNote> item) {
            GitNote entry = item.getModelObject();
            item.add(new RefsPanel("refName", repositoryName, Arrays.asList(entry.notesRef)));
            item.add(
                createPersonPanel(
                    "authorName", entry.notesRef.getAuthorIdent(), Constants.SearchType.AUTHOR));
            item.add(new GravatarImage("noteAuthorAvatar", entry.notesRef.getAuthorIdent()));
            item.add(
                WicketUtils.createTimestampLabel(
                    "authorDate",
                    entry.notesRef.getAuthorIdent().getWhen(),
                    getTimeZone(),
                    getTimeUtils()));
            item.add(
                new Label(
                        "noteContent",
                        bugtraqProcessor()
                            .processPlainCommitMessage(
                                getRepository(), repositoryName, entry.content))
                    .setEscapeModelStrings(false));
          }
        };
    add(notesView.setVisible(notes.size() > 0));

    // changed paths list
    add(new CommitLegendPanel("commitLegend", diff.stat.paths));
    ListDataProvider<PathChangeModel> pathsDp =
        new ListDataProvider<PathChangeModel>(diff.stat.paths);
    DataView<PathChangeModel> pathsView =
        new DataView<PathChangeModel>("changedPath", pathsDp) {
          private static final long serialVersionUID = 1L;
          int counter;

          @Override
          public void populateItem(final Item<PathChangeModel> item) {
            final PathChangeModel entry = item.getModelObject();
            Label changeType = new Label("changeType", "");
            WicketUtils.setChangeTypeCssClass(changeType, entry.changeType);
            setChangeTypeTooltip(changeType, entry.changeType);
            item.add(changeType);
            item.add(new DiffStatPanel("diffStat", entry.insertions, entry.deletions, true));

            boolean hasSubmodule = false;
            String submodulePath = null;
            if (entry.isTree()) {
              // tree
              item.add(
                  new LinkPanel(
                      "pathName",
                      null,
                      entry.path,
                      TreePage.class,
                      WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path)));
            } else if (entry.isSubmodule()) {
              // submodule
              String submoduleId = entry.objectId;
              SubmoduleModel submodule = getSubmodule(entry.path);
              submodulePath = submodule.gitblitPath;
              hasSubmodule = submodule.hasSubmodule;

              // add relative link
              item.add(
                  new LinkPanel(
                      "pathName",
                      "list",
                      entry.path + " @ " + getShortObjectId(submoduleId),
                      "#n" + entry.objectId));
            } else {
              // add relative link
              item.add(new LinkPanel("pathName", "list", entry.path, "#n" + entry.objectId));
            }

            // quick links
            if (entry.isSubmodule()) {
              item.add(new ExternalLink("raw", "").setEnabled(false));
              // submodule
              item.add(new ExternalLink("patch", "").setEnabled(false));
              item.add(
                  new BookmarkablePageLink<Void>(
                          "view",
                          CommitPage.class,
                          WicketUtils.newObjectParameter(submodulePath, entry.objectId))
                      .setEnabled(hasSubmodule));
              item.add(new ExternalLink("blame", "").setEnabled(false));
              item.add(
                  new BookmarkablePageLink<Void>(
                          "history",
                          HistoryPage.class,
                          WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path))
                      .setEnabled(!entry.changeType.equals(ChangeType.ADD)));
            } else {
              // tree or blob
              item.add(
                  new BookmarkablePageLink<Void>(
                          "patch",
                          PatchPage.class,
                          WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path))
                      .setEnabled(
                          !entry.changeType.equals(ChangeType.ADD)
                              && !entry.changeType.equals(ChangeType.DELETE)));
              item.add(
                  new BookmarkablePageLink<Void>(
                          "view",
                          BlobPage.class,
                          WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path))
                      .setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
              String rawUrl =
                  RawServlet.asLink(getContextUrl(), repositoryName, entry.commitId, entry.path);
              item.add(
                  new ExternalLink("raw", rawUrl)
                      .setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
              item.add(
                  new BookmarkablePageLink<Void>(
                          "blame",
                          BlamePage.class,
                          WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path))
                      .setEnabled(
                          !entry.changeType.equals(ChangeType.ADD)
                              && !entry.changeType.equals(ChangeType.DELETE)));
              item.add(
                  new BookmarkablePageLink<Void>(
                          "history",
                          HistoryPage.class,
                          WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path))
                      .setEnabled(!entry.changeType.equals(ChangeType.ADD)));
            }

            WicketUtils.setAlternatingBackground(item, counter);
            counter++;
          }
        };
    add(pathsView);
    add(new Label("diffText", diff.content).setEscapeModelStrings(false));
  }