From ff7d3cffc7af1f24a1db8d42758943cc05bcbaa0 Mon Sep 17 00:00:00 2001 From: James Moger Date: Tue, 18 Jun 2013 22:22:31 -0400 Subject: Reflogs, Digests, and Dashboards Renamed pushlog to reflog to better match it's current and future purpose. Split PushesPanel into ReflogPanel and DigestsPanel. Overhauled project pages and gave them a coherent purpose from the dashboard. --- src/main/java/com/gitblit/git/ReceiveHook.java | 4 +- .../java/com/gitblit/models/DailyLogEntry.java | 2 +- src/main/java/com/gitblit/models/PushLogEntry.java | 340 ----------- src/main/java/com/gitblit/models/RefLogEntry.java | 340 +++++++++++ src/main/java/com/gitblit/utils/PushLogUtils.java | 636 -------------------- src/main/java/com/gitblit/utils/RefLogUtils.java | 659 +++++++++++++++++++++ .../java/com/gitblit/wicket/GitBlitWebApp.java | 8 +- .../com/gitblit/wicket/GitBlitWebApp.properties | 11 +- .../com/gitblit/wicket/pages/DashboardPage.html | 100 ---- .../com/gitblit/wicket/pages/DashboardPage.java | 249 ++------ .../com/gitblit/wicket/pages/MyDashboardPage.html | 158 +++++ .../com/gitblit/wicket/pages/MyDashboardPage.java | 311 ++++++++++ .../com/gitblit/wicket/pages/OverviewPage.html | 2 +- .../com/gitblit/wicket/pages/OverviewPage.java | 8 +- .../java/com/gitblit/wicket/pages/ProjectPage.html | 106 ++-- .../java/com/gitblit/wicket/pages/ProjectPage.java | 189 +----- .../com/gitblit/wicket/pages/ProjectsPage.html | 1 - .../com/gitblit/wicket/pages/ProjectsPage.java | 109 +--- .../java/com/gitblit/wicket/pages/PushesPage.html | 25 - .../java/com/gitblit/wicket/pages/PushesPage.java | 55 -- .../java/com/gitblit/wicket/pages/ReflogPage.html | 25 + .../java/com/gitblit/wicket/pages/ReflogPage.java | 55 ++ .../com/gitblit/wicket/pages/RepositoryPage.java | 6 +- .../java/com/gitblit/wicket/pages/RootPage.java | 2 +- .../com/gitblit/wicket/panels/DigestsPanel.html | 42 ++ .../com/gitblit/wicket/panels/DigestsPanel.java | 273 +++++++++ .../wicket/panels/ProjectRepositoryPanel.html | 2 - .../wicket/panels/ProjectRepositoryPanel.java | 2 - .../com/gitblit/wicket/panels/PushesPanel.html | 43 -- .../com/gitblit/wicket/panels/PushesPanel.java | 381 ------------ .../com/gitblit/wicket/panels/ReflogPanel.html | 43 ++ .../com/gitblit/wicket/panels/ReflogPanel.java | 305 ++++++++++ 32 files changed, 2363 insertions(+), 2129 deletions(-) delete mode 100644 src/main/java/com/gitblit/models/PushLogEntry.java create mode 100644 src/main/java/com/gitblit/models/RefLogEntry.java delete mode 100644 src/main/java/com/gitblit/utils/PushLogUtils.java create mode 100644 src/main/java/com/gitblit/utils/RefLogUtils.java delete mode 100644 src/main/java/com/gitblit/wicket/pages/DashboardPage.html create mode 100644 src/main/java/com/gitblit/wicket/pages/MyDashboardPage.html create mode 100644 src/main/java/com/gitblit/wicket/pages/MyDashboardPage.java delete mode 100644 src/main/java/com/gitblit/wicket/pages/PushesPage.html delete mode 100644 src/main/java/com/gitblit/wicket/pages/PushesPage.java create mode 100644 src/main/java/com/gitblit/wicket/pages/ReflogPage.html create mode 100644 src/main/java/com/gitblit/wicket/pages/ReflogPage.java create mode 100644 src/main/java/com/gitblit/wicket/panels/DigestsPanel.html create mode 100644 src/main/java/com/gitblit/wicket/panels/DigestsPanel.java delete mode 100644 src/main/java/com/gitblit/wicket/panels/PushesPanel.html delete mode 100644 src/main/java/com/gitblit/wicket/panels/PushesPanel.java create mode 100644 src/main/java/com/gitblit/wicket/panels/ReflogPanel.html create mode 100644 src/main/java/com/gitblit/wicket/panels/ReflogPanel.java (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/git/ReceiveHook.java b/src/main/java/com/gitblit/git/ReceiveHook.java index 3e00b381..e3435ffb 100644 --- a/src/main/java/com/gitblit/git/ReceiveHook.java +++ b/src/main/java/com/gitblit/git/ReceiveHook.java @@ -45,7 +45,7 @@ import com.gitblit.models.UserModel; import com.gitblit.utils.ArrayUtils; import com.gitblit.utils.ClientLogger; import com.gitblit.utils.JGitUtils; -import com.gitblit.utils.PushLogUtils; +import com.gitblit.utils.RefLogUtils; import com.gitblit.utils.StringUtils; /** @@ -256,7 +256,7 @@ public class ReceiveHook implements PreReceiveHook, PostReceiveHook { // update push log try { - PushLogUtils.updatePushLog(user, rp.getRepository(), commands); + RefLogUtils.updateRefLog(user, rp.getRepository(), commands); logger.debug(MessageFormat.format("{0} push log updated", repository.name)); } catch (Exception e) { logger.error(MessageFormat.format("Failed to update {0} pushlog", repository.name), e); diff --git a/src/main/java/com/gitblit/models/DailyLogEntry.java b/src/main/java/com/gitblit/models/DailyLogEntry.java index a459d76f..41f13818 100644 --- a/src/main/java/com/gitblit/models/DailyLogEntry.java +++ b/src/main/java/com/gitblit/models/DailyLogEntry.java @@ -28,7 +28,7 @@ import org.eclipse.jgit.transport.ReceiveCommand; * * @author James Moger */ -public class DailyLogEntry extends PushLogEntry implements Serializable { +public class DailyLogEntry extends RefLogEntry implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/com/gitblit/models/PushLogEntry.java b/src/main/java/com/gitblit/models/PushLogEntry.java deleted file mode 100644 index 77bed386..00000000 --- a/src/main/java/com/gitblit/models/PushLogEntry.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright 2013 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.gitblit.models; - -import java.io.Serializable; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.PersonIdent; -import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.transport.ReceiveCommand; - -import com.gitblit.utils.StringUtils; - -/** - * Model class to represent a push into a repository. - * - * @author James Moger - */ -public class PushLogEntry implements Serializable, Comparable { - - private static final long serialVersionUID = 1L; - - public final String repository; - - public final Date date; - - public final UserModel user; - - private final Set commits; - - protected final Map refUpdates; - - protected final Map refIdChanges; - - private int authorCount; - - /** - * Constructor for specified duration of push from start date. - * - * @param repository - * the repository that received the push - * @param date - * the date of the push - * @param user - * the user who pushed - */ - public PushLogEntry(String repository, Date date, UserModel user) { - this.repository = repository; - this.date = date; - this.user = user; - this.commits = new LinkedHashSet(); - this.refUpdates = new HashMap(); - this.refIdChanges = new HashMap(); - this.authorCount = -1; - } - - /** - * Tracks the change type for the specified ref. - * - * @param ref - * @param type - */ - public void updateRef(String ref, ReceiveCommand.Type type) { - if (!refUpdates.containsKey(ref)) { - refUpdates.put(ref, type); - } - } - - /** - * Tracks the change type for the specified ref. - * - * @param ref - * @param type - * @param oldId - * @param newId - */ - public void updateRef(String ref, ReceiveCommand.Type type, String oldId, String newId) { - if (!refUpdates.containsKey(ref)) { - refUpdates.put(ref, type); - refIdChanges.put(ref, oldId + "-" + newId); - } - } - - /** - * Returns the old id of a ref. - * - * @param ref - * @return the old id - */ - public String getOldId(String ref) { - String change = refIdChanges.get(ref); - if (StringUtils.isEmpty(change)) { - return null; - } - return change.split("-")[0]; - } - - /** - * Returns the new id of a ref - * - * @param ref - * @return the new id - */ - public String getNewId(String ref) { - String change = refIdChanges.get(ref); - if (StringUtils.isEmpty(change)) { - return null; - } - return change.split("-")[1]; - } - - /** - * Returns the change type of the ref change. - * - * @param ref - * @return the change type for the ref - */ - public ReceiveCommand.Type getChangeType(String ref) { - ReceiveCommand.Type type = refUpdates.get(ref); - return type; - } - - /** - * Adds a commit to the push entry object as long as the commit is not a - * duplicate. - * - * @param branch - * @param commit - * @return a RepositoryCommit, if one was added. Null if this is duplicate - * commit - */ - public RepositoryCommit addCommit(String branch, RevCommit commit) { - RepositoryCommit commitModel = new RepositoryCommit(repository, branch, commit); - if (commits.add(commitModel)) { - authorCount = -1; - return commitModel; - } - return null; - } - - /** - * Adds a a list of repository commits. This is used to construct discrete - * ref push log entries - * - * @param commits - */ - public void addCommits(List list) { - commits.addAll(list); - authorCount = -1; - } - - /** - * Returns true if this push contains a non-fastforward ref update. - * - * @return true if this is a non-fastforward push - */ - public boolean isNonFastForward() { - for (Map.Entry entry : refUpdates.entrySet()) { - if (ReceiveCommand.Type.UPDATE_NONFASTFORWARD.equals(entry.getValue())) { - return true; - } - } - return false; - } - - /** - * Returns true if this ref has been rewound. - * - * @param ref - * @return true if this is a non-fastforward ref update - */ - public boolean isNonFastForward(String ref) { - ReceiveCommand.Type type = refUpdates.get(ref); - if (type == null) { - return false; - } - return ReceiveCommand.Type.UPDATE_NONFASTFORWARD.equals(type); - } - - /** - * Returns true if this ref has been deleted. - * - * @param ref - * @return true if this is a delete ref update - */ - public boolean isDelete(String ref) { - ReceiveCommand.Type type = refUpdates.get(ref); - if (type == null) { - return false; - } - return ReceiveCommand.Type.DELETE.equals(type); - } - - /** - * Returns the list of refs changed by the push. - * - * @return a list of refs - */ - public List getChangedRefs() { - return new ArrayList(refUpdates.keySet()); - } - - /** - * Returns the list of branches changed by the push. - * - * @return a list of branches - */ - public List getChangedBranches() { - return getChangedRefs(Constants.R_HEADS); - } - - /** - * Returns the list of tags changed by the push. - * - * @return a list of tags - */ - public List getChangedTags() { - return getChangedRefs(Constants.R_TAGS); - } - - /** - * Gets the changed refs in the push. - * - * @param baseRef - * @return the changed refs - */ - protected List getChangedRefs(String baseRef) { - Set refs = new HashSet(); - for (String ref : refUpdates.keySet()) { - if (baseRef == null || ref.startsWith(baseRef)) { - refs.add(ref); - } - } - List list = new ArrayList(refs); - Collections.sort(list); - return list; - } - - public int getAuthorCount() { - if (authorCount == -1) { - Set authors = new HashSet(); - for (RepositoryCommit commit : commits) { - String name = commit.getAuthorIdent().getName(); - authors.add(name); - } - authorCount = authors.size(); - } - return authorCount; - } - - /** - * The total number of commits in the push. - * - * @return the number of commits in the push - */ - public int getCommitCount() { - return commits.size(); - } - - /** - * Returns all commits in the push. - * - * @return a list of commits - */ - public List getCommits() { - List list = new ArrayList(commits); - Collections.sort(list); - return list; - } - - /** - * Returns all commits that belong to a particular ref - * - * @param ref - * @return a list of commits - */ - public List getCommits(String ref) { - List list = new ArrayList(); - for (RepositoryCommit commit : commits) { - if (commit.branch.equals(ref)) { - list.add(commit); - } - } - Collections.sort(list); - return list; - } - - public PersonIdent getCommitterIdent() { - return new PersonIdent(user.getDisplayName(), user.emailAddress == null ? user.username : user.emailAddress); - } - - public PersonIdent getAuthorIdent() { - return getCommitterIdent(); - } - - @Override - public int compareTo(PushLogEntry o) { - // reverse chronological order - return o.date.compareTo(date); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(MessageFormat.format("{0,date,yyyy-MM-dd HH:mm}: {1} pushed {2,number,0} commit{3} to {4} ", - date, user.getDisplayName(), commits.size(), commits.size() == 1 ? "":"s", repository)); - for (Map.Entry entry : refUpdates.entrySet()) { - String ref = entry.getKey(); - ReceiveCommand.Type type = entry.getValue(); - sb.append("\n ").append(ref).append(' ').append(type.name()).append('\n'); - for (RepositoryCommit commit : getCommits(ref)) { - sb.append(" ").append(commit.toString()).append('\n'); - } - } - return sb.toString(); - } -} diff --git a/src/main/java/com/gitblit/models/RefLogEntry.java b/src/main/java/com/gitblit/models/RefLogEntry.java new file mode 100644 index 00000000..54d17771 --- /dev/null +++ b/src/main/java/com/gitblit/models/RefLogEntry.java @@ -0,0 +1,340 @@ +/* + * Copyright 2013 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.models; + +import java.io.Serializable; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.transport.ReceiveCommand; + +import com.gitblit.utils.StringUtils; + +/** + * Model class to represent a push into a repository. + * + * @author James Moger + */ +public class RefLogEntry implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public final String repository; + + public final Date date; + + public final UserModel user; + + private final Set commits; + + protected final Map refUpdates; + + protected final Map refIdChanges; + + private int authorCount; + + /** + * Constructor for specified duration of push from start date. + * + * @param repository + * the repository that received the push + * @param date + * the date of the push + * @param user + * the user who pushed + */ + public RefLogEntry(String repository, Date date, UserModel user) { + this.repository = repository; + this.date = date; + this.user = user; + this.commits = new LinkedHashSet(); + this.refUpdates = new HashMap(); + this.refIdChanges = new HashMap(); + this.authorCount = -1; + } + + /** + * Tracks the change type for the specified ref. + * + * @param ref + * @param type + */ + public void updateRef(String ref, ReceiveCommand.Type type) { + if (!refUpdates.containsKey(ref)) { + refUpdates.put(ref, type); + } + } + + /** + * Tracks the change type for the specified ref. + * + * @param ref + * @param type + * @param oldId + * @param newId + */ + public void updateRef(String ref, ReceiveCommand.Type type, String oldId, String newId) { + if (!refUpdates.containsKey(ref)) { + refUpdates.put(ref, type); + refIdChanges.put(ref, oldId + "-" + newId); + } + } + + /** + * Returns the old id of a ref. + * + * @param ref + * @return the old id + */ + public String getOldId(String ref) { + String change = refIdChanges.get(ref); + if (StringUtils.isEmpty(change)) { + return null; + } + return change.split("-")[0]; + } + + /** + * Returns the new id of a ref + * + * @param ref + * @return the new id + */ + public String getNewId(String ref) { + String change = refIdChanges.get(ref); + if (StringUtils.isEmpty(change)) { + return null; + } + return change.split("-")[1]; + } + + /** + * Returns the change type of the ref change. + * + * @param ref + * @return the change type for the ref + */ + public ReceiveCommand.Type getChangeType(String ref) { + ReceiveCommand.Type type = refUpdates.get(ref); + return type; + } + + /** + * Adds a commit to the push entry object as long as the commit is not a + * duplicate. + * + * @param branch + * @param commit + * @return a RepositoryCommit, if one was added. Null if this is duplicate + * commit + */ + public RepositoryCommit addCommit(String branch, RevCommit commit) { + RepositoryCommit commitModel = new RepositoryCommit(repository, branch, commit); + if (commits.add(commitModel)) { + authorCount = -1; + return commitModel; + } + return null; + } + + /** + * Adds a a list of repository commits. This is used to construct discrete + * ref push log entries + * + * @param commits + */ + public void addCommits(List list) { + commits.addAll(list); + authorCount = -1; + } + + /** + * Returns true if this push contains a non-fastforward ref update. + * + * @return true if this is a non-fastforward push + */ + public boolean isNonFastForward() { + for (Map.Entry entry : refUpdates.entrySet()) { + if (ReceiveCommand.Type.UPDATE_NONFASTFORWARD.equals(entry.getValue())) { + return true; + } + } + return false; + } + + /** + * Returns true if this ref has been rewound. + * + * @param ref + * @return true if this is a non-fastforward ref update + */ + public boolean isNonFastForward(String ref) { + ReceiveCommand.Type type = refUpdates.get(ref); + if (type == null) { + return false; + } + return ReceiveCommand.Type.UPDATE_NONFASTFORWARD.equals(type); + } + + /** + * Returns true if this ref has been deleted. + * + * @param ref + * @return true if this is a delete ref update + */ + public boolean isDelete(String ref) { + ReceiveCommand.Type type = refUpdates.get(ref); + if (type == null) { + return false; + } + return ReceiveCommand.Type.DELETE.equals(type); + } + + /** + * Returns the list of refs changed by the push. + * + * @return a list of refs + */ + public List getChangedRefs() { + return new ArrayList(refUpdates.keySet()); + } + + /** + * Returns the list of branches changed by the push. + * + * @return a list of branches + */ + public List getChangedBranches() { + return getChangedRefs(Constants.R_HEADS); + } + + /** + * Returns the list of tags changed by the push. + * + * @return a list of tags + */ + public List getChangedTags() { + return getChangedRefs(Constants.R_TAGS); + } + + /** + * Gets the changed refs in the push. + * + * @param baseRef + * @return the changed refs + */ + protected List getChangedRefs(String baseRef) { + Set refs = new HashSet(); + for (String ref : refUpdates.keySet()) { + if (baseRef == null || ref.startsWith(baseRef)) { + refs.add(ref); + } + } + List list = new ArrayList(refs); + Collections.sort(list); + return list; + } + + public int getAuthorCount() { + if (authorCount == -1) { + Set authors = new HashSet(); + for (RepositoryCommit commit : commits) { + String name = commit.getAuthorIdent().getName(); + authors.add(name); + } + authorCount = authors.size(); + } + return authorCount; + } + + /** + * The total number of commits in the push. + * + * @return the number of commits in the push + */ + public int getCommitCount() { + return commits.size(); + } + + /** + * Returns all commits in the push. + * + * @return a list of commits + */ + public List getCommits() { + List list = new ArrayList(commits); + Collections.sort(list); + return list; + } + + /** + * Returns all commits that belong to a particular ref + * + * @param ref + * @return a list of commits + */ + public List getCommits(String ref) { + List list = new ArrayList(); + for (RepositoryCommit commit : commits) { + if (commit.branch.equals(ref)) { + list.add(commit); + } + } + Collections.sort(list); + return list; + } + + public PersonIdent getCommitterIdent() { + return new PersonIdent(user.getDisplayName(), user.emailAddress == null ? user.username : user.emailAddress); + } + + public PersonIdent getAuthorIdent() { + return getCommitterIdent(); + } + + @Override + public int compareTo(RefLogEntry o) { + // reverse chronological order + return o.date.compareTo(date); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(MessageFormat.format("{0,date,yyyy-MM-dd HH:mm}: {1} pushed {2,number,0} commit{3} to {4} ", + date, user.getDisplayName(), commits.size(), commits.size() == 1 ? "":"s", repository)); + for (Map.Entry entry : refUpdates.entrySet()) { + String ref = entry.getKey(); + ReceiveCommand.Type type = entry.getValue(); + sb.append("\n ").append(ref).append(' ').append(type.name()).append('\n'); + for (RepositoryCommit commit : getCommits(ref)) { + sb.append(" ").append(commit.toString()).append('\n'); + } + } + return sb.toString(); + } +} diff --git a/src/main/java/com/gitblit/utils/PushLogUtils.java b/src/main/java/com/gitblit/utils/PushLogUtils.java deleted file mode 100644 index fed5b195..00000000 --- a/src/main/java/com/gitblit/utils/PushLogUtils.java +++ /dev/null @@ -1,636 +0,0 @@ -/* - * Copyright 2013 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.gitblit.utils; - -import java.io.IOException; -import java.text.DateFormat; -import java.text.MessageFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TimeZone; -import java.util.TreeSet; - -import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException; -import org.eclipse.jgit.api.errors.JGitInternalException; -import org.eclipse.jgit.dircache.DirCache; -import org.eclipse.jgit.dircache.DirCacheBuilder; -import org.eclipse.jgit.dircache.DirCacheEntry; -import org.eclipse.jgit.internal.JGitText; -import org.eclipse.jgit.lib.CommitBuilder; -import org.eclipse.jgit.lib.FileMode; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectInserter; -import org.eclipse.jgit.lib.PersonIdent; -import org.eclipse.jgit.lib.RefUpdate; -import org.eclipse.jgit.lib.RefUpdate.Result; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.revwalk.RevWalk; -import org.eclipse.jgit.transport.ReceiveCommand; -import org.eclipse.jgit.treewalk.CanonicalTreeParser; -import org.eclipse.jgit.treewalk.TreeWalk; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.gitblit.Constants; -import com.gitblit.models.DailyLogEntry; -import com.gitblit.models.PathModel.PathChangeModel; -import com.gitblit.models.PushLogEntry; -import com.gitblit.models.RefModel; -import com.gitblit.models.RepositoryCommit; -import com.gitblit.models.UserModel; - -/** - * Utility class for maintaining a pushlog within a git repository on an - * orphan branch. - * - * @author James Moger - * - */ -public class PushLogUtils { - - public static final String GB_PUSHES = "refs/gitblit/pushes"; - - static final Logger LOGGER = LoggerFactory.getLogger(PushLogUtils.class); - - /** - * Log an error message and exception. - * - * @param t - * @param repository - * if repository is not null it MUST be the {0} parameter in the - * pattern. - * @param pattern - * @param objects - */ - private static void error(Throwable t, Repository repository, String pattern, Object... objects) { - List parameters = new ArrayList(); - if (objects != null && objects.length > 0) { - for (Object o : objects) { - parameters.add(o); - } - } - if (repository != null) { - parameters.add(0, repository.getDirectory().getAbsolutePath()); - } - LOGGER.error(MessageFormat.format(pattern, parameters.toArray()), t); - } - - /** - * Returns a RefModel for the gb-pushes branch in the repository. If the - * branch can not be found, null is returned. - * - * @param repository - * @return a refmodel for the gb-pushes branch or null - */ - public static RefModel getPushLogBranch(Repository repository) { - List refs = JGitUtils.getRefs(repository, com.gitblit.Constants.R_GITBLIT); - for (RefModel ref : refs) { - if (ref.reference.getName().equals(GB_PUSHES)) { - return ref; - } - } - return null; - } - - private static UserModel newUserModelFrom(PersonIdent ident) { - String name = ident.getName(); - String username; - String displayname; - if (name.indexOf('/') > -1) { - int slash = name.indexOf('/'); - displayname = name.substring(0, slash); - username = name.substring(slash + 1); - } else { - displayname = name; - username = ident.getEmailAddress(); - } - - UserModel user = new UserModel(username); - user.displayName = displayname; - user.emailAddress = ident.getEmailAddress(); - return user; - } - - /** - * Updates a push log. - * - * @param user - * @param repository - * @param commands - * @return true, if the update was successful - */ - public static boolean updatePushLog(UserModel user, Repository repository, - Collection commands) { - RefModel pushlogBranch = getPushLogBranch(repository); - if (pushlogBranch == null) { - JGitUtils.createOrphanBranch(repository, GB_PUSHES, null); - } - - boolean success = false; - String message = "push"; - - try { - ObjectId headId = repository.resolve(GB_PUSHES + "^{commit}"); - ObjectInserter odi = repository.newObjectInserter(); - try { - // Create the in-memory index of the push log entry - DirCache index = createIndex(repository, headId, commands); - ObjectId indexTreeId = index.writeTree(odi); - - PersonIdent ident; - if (UserModel.ANONYMOUS.equals(user)) { - // anonymous push - ident = new PersonIdent("anonymous", "anonymous"); - } else { - // construct real pushing account - ident = new PersonIdent(MessageFormat.format("{0}/{1}", user.getDisplayName(), user.username), - user.emailAddress == null ? user.username : user.emailAddress); - } - - // Create a commit object - CommitBuilder commit = new CommitBuilder(); - commit.setAuthor(ident); - commit.setCommitter(ident); - commit.setEncoding(Constants.ENCODING); - commit.setMessage(message); - commit.setParentId(headId); - commit.setTreeId(indexTreeId); - - // Insert the commit into the repository - ObjectId commitId = odi.insert(commit); - odi.flush(); - - RevWalk revWalk = new RevWalk(repository); - try { - RevCommit revCommit = revWalk.parseCommit(commitId); - RefUpdate ru = repository.updateRef(GB_PUSHES); - ru.setNewObjectId(commitId); - ru.setExpectedOldObjectId(headId); - ru.setRefLogMessage("commit: " + revCommit.getShortMessage(), false); - Result rc = ru.forceUpdate(); - switch (rc) { - case NEW: - case FORCED: - case FAST_FORWARD: - success = true; - break; - case REJECTED: - case LOCK_FAILURE: - throw new ConcurrentRefUpdateException(JGitText.get().couldNotLockHEAD, - ru.getRef(), rc); - default: - throw new JGitInternalException(MessageFormat.format( - JGitText.get().updatingRefFailed, GB_PUSHES, commitId.toString(), - rc)); - } - } finally { - revWalk.release(); - } - } finally { - odi.release(); - } - } catch (Throwable t) { - error(t, repository, "Failed to commit pushlog entry to {0}"); - } - return success; - } - - /** - * Creates an in-memory index of the push log entry. - * - * @param repo - * @param headId - * @param commands - * @return an in-memory index - * @throws IOException - */ - private static DirCache createIndex(Repository repo, ObjectId headId, - Collection commands) throws IOException { - - DirCache inCoreIndex = DirCache.newInCore(); - DirCacheBuilder dcBuilder = inCoreIndex.builder(); - ObjectInserter inserter = repo.newObjectInserter(); - - long now = System.currentTimeMillis(); - Set ignorePaths = new TreeSet(); - try { - // add receive commands to the temporary index - for (ReceiveCommand command : commands) { - // use the ref names as the path names - String path = command.getRefName(); - ignorePaths.add(path); - - StringBuilder change = new StringBuilder(); - change.append(command.getType().name()).append(' '); - switch (command.getType()) { - case CREATE: - change.append(ObjectId.zeroId().getName()); - change.append(' '); - change.append(command.getNewId().getName()); - break; - case UPDATE: - case UPDATE_NONFASTFORWARD: - change.append(command.getOldId().getName()); - change.append(' '); - change.append(command.getNewId().getName()); - break; - case DELETE: - change = null; - break; - } - if (change == null) { - // ref deleted - continue; - } - String content = change.toString(); - - // create an index entry for this attachment - final DirCacheEntry dcEntry = new DirCacheEntry(path); - dcEntry.setLength(content.length()); - dcEntry.setLastModified(now); - dcEntry.setFileMode(FileMode.REGULAR_FILE); - - // insert object - dcEntry.setObjectId(inserter.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, content.getBytes("UTF-8"))); - - // add to temporary in-core index - dcBuilder.add(dcEntry); - } - - // Traverse HEAD to add all other paths - TreeWalk treeWalk = new TreeWalk(repo); - int hIdx = -1; - if (headId != null) - hIdx = treeWalk.addTree(new RevWalk(repo).parseTree(headId)); - treeWalk.setRecursive(true); - - while (treeWalk.next()) { - String path = treeWalk.getPathString(); - CanonicalTreeParser hTree = null; - if (hIdx != -1) - hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class); - if (!ignorePaths.contains(path)) { - // add entries from HEAD for all other paths - if (hTree != null) { - // create a new DirCacheEntry with data retrieved from - // HEAD - final DirCacheEntry dcEntry = new DirCacheEntry(path); - dcEntry.setObjectId(hTree.getEntryObjectId()); - dcEntry.setFileMode(hTree.getEntryFileMode()); - - // add to temporary in-core index - dcBuilder.add(dcEntry); - } - } - } - - // release the treewalk - treeWalk.release(); - - // finish temporary in-core index used for this commit - dcBuilder.finish(); - } finally { - inserter.release(); - } - return inCoreIndex; - } - - public static List getPushLog(String repositoryName, Repository repository) { - return getPushLog(repositoryName, repository, null, 0, -1); - } - - public static List getPushLog(String repositoryName, Repository repository, int maxCount) { - return getPushLog(repositoryName, repository, null, 0, maxCount); - } - - public static List getPushLog(String repositoryName, Repository repository, int offset, int maxCount) { - return getPushLog(repositoryName, repository, null, offset, maxCount); - } - - public static List getPushLog(String repositoryName, Repository repository, Date minimumDate) { - return getPushLog(repositoryName, repository, minimumDate, 0, -1); - } - - /** - * Returns the list of push log entries as they were recorded by Gitblit. - * Each PushLogEntry may represent multiple ref updates. - * - * @param repositoryName - * @param repository - * @param minimumDate - * @param offset - * @param maxCount - * if < 0, all pushes are returned. - * @return a list of push log entries - */ - public static List getPushLog(String repositoryName, Repository repository, - Date minimumDate, int offset, int maxCount) { - List list = new ArrayList(); - RefModel ref = getPushLogBranch(repository); - if (ref == null) { - return list; - } - if (maxCount == 0) { - return list; - } - - Map> allRefs = JGitUtils.getAllRefs(repository); - List pushes; - if (minimumDate == null) { - pushes = JGitUtils.getRevLog(repository, GB_PUSHES, offset, maxCount); - } else { - pushes = JGitUtils.getRevLog(repository, GB_PUSHES, minimumDate); - } - for (RevCommit push : pushes) { - if (push.getAuthorIdent().getName().equalsIgnoreCase("gitblit")) { - // skip gitblit/internal commits - continue; - } - - UserModel user = newUserModelFrom(push.getAuthorIdent()); - Date date = push.getAuthorIdent().getWhen(); - - PushLogEntry log = new PushLogEntry(repositoryName, date, user); - list.add(log); - List changedRefs = JGitUtils.getFilesInCommit(repository, push); - for (PathChangeModel change : changedRefs) { - switch (change.changeType) { - case DELETE: - log.updateRef(change.path, ReceiveCommand.Type.DELETE); - break; - case ADD: - log.updateRef(change.path, ReceiveCommand.Type.CREATE); - default: - String content = JGitUtils.getStringContent(repository, push.getTree(), change.path); - String [] fields = content.split(" "); - String oldId = fields[1]; - String newId = fields[2]; - log.updateRef(change.path, ReceiveCommand.Type.valueOf(fields[0]), oldId, newId); - List pushedCommits = JGitUtils.getRevLog(repository, oldId, newId); - for (RevCommit pushedCommit : pushedCommits) { - RepositoryCommit repoCommit = log.addCommit(change.path, pushedCommit); - if (repoCommit != null) { - repoCommit.setRefs(allRefs.get(pushedCommit.getId())); - } - } - } - } - } - Collections.sort(list); - return list; - } - - /** - * Returns the list of pushes separated by ref (e.g. each ref has it's own - * PushLogEntry object). - * - * @param repositoryName - * @param repository - * @param maxCount - * @return a list of push log entries separated by ref - */ - public static List getPushLogByRef(String repositoryName, Repository repository, int maxCount) { - return getPushLogByRef(repositoryName, repository, 0, maxCount); - } - - /** - * Returns the list of pushes separated by ref (e.g. each ref has it's own - * PushLogEntry object). - * - * @param repositoryName - * @param repository - * @param offset - * @param maxCount - * @return a list of push log entries separated by ref - */ - public static List getPushLogByRef(String repositoryName, Repository repository, int offset, - int maxCount) { - // break the push log into ref push logs and then merge them back into a list - Map> refMap = new HashMap>(); - List pushes = getPushLog(repositoryName, repository, offset, maxCount); - for (PushLogEntry push : pushes) { - for (String ref : push.getChangedRefs()) { - if (!refMap.containsKey(ref)) { - refMap.put(ref, new ArrayList()); - } - - // construct new ref-specific push log entry - PushLogEntry refPush; - if (push instanceof DailyLogEntry) { - // simulated push log from commits grouped by date - refPush = new DailyLogEntry(push.repository, push.date); - } else { - // real push log entry - refPush = new PushLogEntry(push.repository, push.date, push.user); - } - refPush.updateRef(ref, push.getChangeType(ref), push.getOldId(ref), push.getNewId(ref)); - refPush.addCommits(push.getCommits(ref)); - refMap.get(ref).add(refPush); - } - } - - // merge individual ref pushes into master list - List refPushLog = new ArrayList(); - for (List refPush : refMap.values()) { - refPushLog.addAll(refPush); - } - - // sort ref push log - Collections.sort(refPushLog); - - return refPushLog; - } - - /** - * Returns the list of pushes separated by ref (e.g. each ref has it's own - * PushLogEntry object). - * - * @param repositoryName - * @param repository - * @param minimumDate - * @return a list of push log entries separated by ref - */ - public static List getPushLogByRef(String repositoryName, Repository repository, Date minimumDate) { - // break the push log into ref push logs and then merge them back into a list - Map> refMap = new HashMap>(); - List pushes = getPushLog(repositoryName, repository, minimumDate); - for (PushLogEntry push : pushes) { - for (String ref : push.getChangedRefs()) { - if (!refMap.containsKey(ref)) { - refMap.put(ref, new ArrayList()); - } - - // construct new ref-specific push log entry - PushLogEntry refPush = new PushLogEntry(push.repository, push.date, push.user); - refPush.updateRef(ref, push.getChangeType(ref), push.getOldId(ref), push.getNewId(ref)); - refPush.addCommits(push.getCommits(ref)); - refMap.get(ref).add(refPush); - } - } - - // merge individual ref pushes into master list - List refPushLog = new ArrayList(); - for (List refPush : refMap.values()) { - refPushLog.addAll(refPush); - } - - // sort ref push log - Collections.sort(refPushLog); - - return refPushLog; - } - - /** - * Returns a commit log grouped by day. - * - * @param repositoryName - * @param repository - * @param minimumDate - * @param offset - * @param maxCount - * if < 0, all pushes are returned. - * @param the timezone to use when aggregating commits by date - * @return a list of grouped commit log entries - */ - public static List getDailyLog(String repositoryName, Repository repository, - Date minimumDate, int offset, int maxCount, - TimeZone timezone) { - DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); - df.setTimeZone(timezone); - - Map> allRefs = JGitUtils.getAllRefs(repository); - Map tags = new HashMap(); - Map pulls = new HashMap(); - Map dailydigests = new HashMap(); - String linearParent = null; - for (RefModel local : JGitUtils.getLocalBranches(repository, true, -1)) { - String branch = local.getName(); - List commits = JGitUtils.getRevLog(repository, branch, minimumDate); - for (RevCommit commit : commits) { - if (linearParent != null) { - if (!commit.getName().equals(linearParent)) { - // only follow linear branch commits - continue; - } - } - Date date = JGitUtils.getCommitDate(commit); - String dateStr = df.format(date); - if (!dailydigests.containsKey(dateStr)) { - dailydigests.put(dateStr, new DailyLogEntry(repositoryName, date)); - } - DailyLogEntry digest = dailydigests.get(dateStr); - if (commit.getParentCount() == 0) { - linearParent = null; - digest.updateRef(branch, ReceiveCommand.Type.CREATE); - } else { - linearParent = commit.getParents()[0].getId().getName(); - digest.updateRef(branch, ReceiveCommand.Type.UPDATE, linearParent, commit.getName()); - } - - RepositoryCommit repoCommit = digest.addCommit(branch, commit); - if (repoCommit != null) { - List matchedRefs = allRefs.get(commit.getId()); - repoCommit.setRefs(matchedRefs); - - if (!ArrayUtils.isEmpty(matchedRefs)) { - for (RefModel ref : matchedRefs) { - if (ref.getName().startsWith(Constants.R_TAGS)) { - // treat tags as special events in the log - if (!tags.containsKey(dateStr)) { - UserModel tagUser = newUserModelFrom(commit.getAuthorIdent()); - Date tagDate = commit.getAuthorIdent().getWhen(); - tags.put(dateStr, new DailyLogEntry(repositoryName, tagDate, tagUser)); - } - PushLogEntry tagEntry = tags.get(dateStr); - tagEntry.updateRef(ref.getName(), ReceiveCommand.Type.CREATE); - tagEntry.addCommit(ref.getName(), commit); - } else if (ref.getName().startsWith(Constants.R_PULL)) { - // treat pull requests as special events in the log - if (!pulls.containsKey(dateStr)) { - UserModel commitUser = newUserModelFrom(commit.getAuthorIdent()); - Date commitDate = commit.getAuthorIdent().getWhen(); - pulls.put(dateStr, new DailyLogEntry(repositoryName, commitDate, commitUser)); - } - PushLogEntry pullEntry = pulls.get(dateStr); - pullEntry.updateRef(ref.getName(), ReceiveCommand.Type.CREATE); - pullEntry.addCommit(ref.getName(), commit); - } - } - } - } - } - } - - List list = new ArrayList(dailydigests.values()); - list.addAll(tags.values()); - //list.addAll(pulls.values()); - Collections.sort(list); - return list; - } - - /** - * Returns the list of commits separated by ref (e.g. each ref has it's own - * PushLogEntry object for each day). - * - * @param repositoryName - * @param repository - * @param minimumDate - * @param the timezone to use when aggregating commits by date - * @return a list of push log entries separated by ref and date - */ - public static List getDailyLogByRef(String repositoryName, Repository repository, - Date minimumDate, TimeZone timezone) { - // break the push log into ref push logs and then merge them back into a list - Map> refMap = new HashMap>(); - List pushes = getDailyLog(repositoryName, repository, minimumDate, 0, -1, timezone); - for (DailyLogEntry push : pushes) { - for (String ref : push.getChangedRefs()) { - if (!refMap.containsKey(ref)) { - refMap.put(ref, new ArrayList()); - } - - // construct new ref-specific push log entry - DailyLogEntry refPush = new DailyLogEntry(push.repository, push.date, push.user); - refPush.updateRef(ref, push.getChangeType(ref), push.getOldId(ref), push.getNewId(ref)); - refPush.addCommits(push.getCommits(ref)); - refMap.get(ref).add(refPush); - } - } - - // merge individual ref pushes into master list - List refPushLog = new ArrayList(); - for (List refPush : refMap.values()) { - for (DailyLogEntry entry : refPush) { - if (entry.getCommitCount() > 0) { - refPushLog.add(entry); - } - } - } - - // sort ref push log - Collections.sort(refPushLog); - - return refPushLog; - } -} diff --git a/src/main/java/com/gitblit/utils/RefLogUtils.java b/src/main/java/com/gitblit/utils/RefLogUtils.java new file mode 100644 index 00000000..ce03a163 --- /dev/null +++ b/src/main/java/com/gitblit/utils/RefLogUtils.java @@ -0,0 +1,659 @@ +/* + * Copyright 2013 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.utils; + +import java.io.IOException; +import java.text.DateFormat; +import java.text.MessageFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TimeZone; +import java.util.TreeSet; + +import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException; +import org.eclipse.jgit.api.errors.JGitInternalException; +import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheBuilder; +import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.lib.CommitBuilder; +import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.RefRename; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.RefUpdate.Result; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.ReceiveCommand; +import org.eclipse.jgit.treewalk.CanonicalTreeParser; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.gitblit.Constants; +import com.gitblit.models.DailyLogEntry; +import com.gitblit.models.PathModel.PathChangeModel; +import com.gitblit.models.RefLogEntry; +import com.gitblit.models.RefModel; +import com.gitblit.models.RepositoryCommit; +import com.gitblit.models.UserModel; + +/** + * Utility class for maintaining a reflog within a git repository on an + * orphan branch. + * + * @author James Moger + * + */ +public class RefLogUtils { + + private static final String GB_REFLOG = "refs/gitblit/reflog"; + + private static final Logger LOGGER = LoggerFactory.getLogger(RefLogUtils.class); + + /** + * Log an error message and exception. + * + * @param t + * @param repository + * if repository is not null it MUST be the {0} parameter in the + * pattern. + * @param pattern + * @param objects + */ + private static void error(Throwable t, Repository repository, String pattern, Object... objects) { + List parameters = new ArrayList(); + if (objects != null && objects.length > 0) { + for (Object o : objects) { + parameters.add(o); + } + } + if (repository != null) { + parameters.add(0, repository.getDirectory().getAbsolutePath()); + } + LOGGER.error(MessageFormat.format(pattern, parameters.toArray()), t); + } + + /** + * Returns a RefModel for the reflog branch in the repository. If the + * branch can not be found, null is returned. + * + * @param repository + * @return a refmodel for the reflog branch or null + */ + public static RefModel getRefLogBranch(Repository repository) { + List refs = JGitUtils.getRefs(repository, com.gitblit.Constants.R_GITBLIT); + RefModel pushLog = null; + final String GB_PUSHES = "refs/gitblit/pushes"; + for (RefModel ref : refs) { + if (ref.reference.getName().equals(GB_REFLOG)) { + return ref; + } else if (ref.reference.getName().equals(GB_PUSHES)) { + pushLog = ref; + } + } + if (pushLog != null) { + // rename refs/gitblit/pushes to refs/gitblit/reflog + RefRename cmd; + try { + cmd = repository.renameRef(GB_PUSHES, GB_REFLOG); + cmd.setRefLogIdent(new PersonIdent("Gitblit", "gitblit@localhost")); + cmd.setRefLogMessage("renamed " + GB_PUSHES + " => " + GB_REFLOG); + Result res = cmd.rename(); + switch (res) { + case RENAMED: + return getRefLogBranch(repository); + default: + LOGGER.error("failed to rename " + GB_PUSHES + " => " + GB_REFLOG + " (" + res.name() + ")"); + } + } catch (IOException e) { + LOGGER.error("failed to rename pushlog", e); + } + } + return null; + } + + private static UserModel newUserModelFrom(PersonIdent ident) { + String name = ident.getName(); + String username; + String displayname; + if (name.indexOf('/') > -1) { + int slash = name.indexOf('/'); + displayname = name.substring(0, slash); + username = name.substring(slash + 1); + } else { + displayname = name; + username = ident.getEmailAddress(); + } + + UserModel user = new UserModel(username); + user.displayName = displayname; + user.emailAddress = ident.getEmailAddress(); + return user; + } + + /** + * Updates the reflog with the received commands. + * + * @param user + * @param repository + * @param commands + * @return true, if the update was successful + */ + public static boolean updateRefLog(UserModel user, Repository repository, + Collection commands) { + RefModel reflogBranch = getRefLogBranch(repository); + if (reflogBranch == null) { + JGitUtils.createOrphanBranch(repository, GB_REFLOG, null); + } + + boolean success = false; + String message = "push"; + + try { + ObjectId headId = repository.resolve(GB_REFLOG + "^{commit}"); + ObjectInserter odi = repository.newObjectInserter(); + try { + // Create the in-memory index of the push log entry + DirCache index = createIndex(repository, headId, commands); + ObjectId indexTreeId = index.writeTree(odi); + + PersonIdent ident; + if (UserModel.ANONYMOUS.equals(user)) { + // anonymous push + ident = new PersonIdent("anonymous", "anonymous"); + } else { + // construct real pushing account + ident = new PersonIdent(MessageFormat.format("{0}/{1}", user.getDisplayName(), user.username), + user.emailAddress == null ? user.username : user.emailAddress); + } + + // Create a commit object + CommitBuilder commit = new CommitBuilder(); + commit.setAuthor(ident); + commit.setCommitter(ident); + commit.setEncoding(Constants.ENCODING); + commit.setMessage(message); + commit.setParentId(headId); + commit.setTreeId(indexTreeId); + + // Insert the commit into the repository + ObjectId commitId = odi.insert(commit); + odi.flush(); + + RevWalk revWalk = new RevWalk(repository); + try { + RevCommit revCommit = revWalk.parseCommit(commitId); + RefUpdate ru = repository.updateRef(GB_REFLOG); + ru.setNewObjectId(commitId); + ru.setExpectedOldObjectId(headId); + ru.setRefLogMessage("commit: " + revCommit.getShortMessage(), false); + Result rc = ru.forceUpdate(); + switch (rc) { + case NEW: + case FORCED: + case FAST_FORWARD: + success = true; + break; + case REJECTED: + case LOCK_FAILURE: + throw new ConcurrentRefUpdateException(JGitText.get().couldNotLockHEAD, + ru.getRef(), rc); + default: + throw new JGitInternalException(MessageFormat.format( + JGitText.get().updatingRefFailed, GB_REFLOG, commitId.toString(), + rc)); + } + } finally { + revWalk.release(); + } + } finally { + odi.release(); + } + } catch (Throwable t) { + error(t, repository, "Failed to commit reflog entry to {0}"); + } + return success; + } + + /** + * Creates an in-memory index of the push log entry. + * + * @param repo + * @param headId + * @param commands + * @return an in-memory index + * @throws IOException + */ + private static DirCache createIndex(Repository repo, ObjectId headId, + Collection commands) throws IOException { + + DirCache inCoreIndex = DirCache.newInCore(); + DirCacheBuilder dcBuilder = inCoreIndex.builder(); + ObjectInserter inserter = repo.newObjectInserter(); + + long now = System.currentTimeMillis(); + Set ignorePaths = new TreeSet(); + try { + // add receive commands to the temporary index + for (ReceiveCommand command : commands) { + // use the ref names as the path names + String path = command.getRefName(); + ignorePaths.add(path); + + StringBuilder change = new StringBuilder(); + change.append(command.getType().name()).append(' '); + switch (command.getType()) { + case CREATE: + change.append(ObjectId.zeroId().getName()); + change.append(' '); + change.append(command.getNewId().getName()); + break; + case UPDATE: + case UPDATE_NONFASTFORWARD: + change.append(command.getOldId().getName()); + change.append(' '); + change.append(command.getNewId().getName()); + break; + case DELETE: + change = null; + break; + } + if (change == null) { + // ref deleted + continue; + } + String content = change.toString(); + + // create an index entry for this attachment + final DirCacheEntry dcEntry = new DirCacheEntry(path); + dcEntry.setLength(content.length()); + dcEntry.setLastModified(now); + dcEntry.setFileMode(FileMode.REGULAR_FILE); + + // insert object + dcEntry.setObjectId(inserter.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, content.getBytes("UTF-8"))); + + // add to temporary in-core index + dcBuilder.add(dcEntry); + } + + // Traverse HEAD to add all other paths + TreeWalk treeWalk = new TreeWalk(repo); + int hIdx = -1; + if (headId != null) + hIdx = treeWalk.addTree(new RevWalk(repo).parseTree(headId)); + treeWalk.setRecursive(true); + + while (treeWalk.next()) { + String path = treeWalk.getPathString(); + CanonicalTreeParser hTree = null; + if (hIdx != -1) + hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class); + if (!ignorePaths.contains(path)) { + // add entries from HEAD for all other paths + if (hTree != null) { + // create a new DirCacheEntry with data retrieved from + // HEAD + final DirCacheEntry dcEntry = new DirCacheEntry(path); + dcEntry.setObjectId(hTree.getEntryObjectId()); + dcEntry.setFileMode(hTree.getEntryFileMode()); + + // add to temporary in-core index + dcBuilder.add(dcEntry); + } + } + } + + // release the treewalk + treeWalk.release(); + + // finish temporary in-core index used for this commit + dcBuilder.finish(); + } finally { + inserter.release(); + } + return inCoreIndex; + } + + public static List getRefLog(String repositoryName, Repository repository) { + return getRefLog(repositoryName, repository, null, 0, -1); + } + + public static List getRefLog(String repositoryName, Repository repository, int maxCount) { + return getRefLog(repositoryName, repository, null, 0, maxCount); + } + + public static List getRefLog(String repositoryName, Repository repository, int offset, int maxCount) { + return getRefLog(repositoryName, repository, null, offset, maxCount); + } + + public static List getRefLog(String repositoryName, Repository repository, Date minimumDate) { + return getRefLog(repositoryName, repository, minimumDate, 0, -1); + } + + /** + * Returns the list of reflog entries as they were recorded by Gitblit. + * Each RefLogEntry may represent multiple ref updates. + * + * @param repositoryName + * @param repository + * @param minimumDate + * @param offset + * @param maxCount + * if < 0, all pushes are returned. + * @return a list of push log entries + */ + public static List getRefLog(String repositoryName, Repository repository, + Date minimumDate, int offset, int maxCount) { + List list = new ArrayList(); + RefModel ref = getRefLogBranch(repository); + if (ref == null) { + return list; + } + if (maxCount == 0) { + return list; + } + + Map> allRefs = JGitUtils.getAllRefs(repository); + List pushes; + if (minimumDate == null) { + pushes = JGitUtils.getRevLog(repository, GB_REFLOG, offset, maxCount); + } else { + pushes = JGitUtils.getRevLog(repository, GB_REFLOG, minimumDate); + } + for (RevCommit push : pushes) { + if (push.getAuthorIdent().getName().equalsIgnoreCase("gitblit")) { + // skip gitblit/internal commits + continue; + } + + UserModel user = newUserModelFrom(push.getAuthorIdent()); + Date date = push.getAuthorIdent().getWhen(); + + RefLogEntry log = new RefLogEntry(repositoryName, date, user); + list.add(log); + List changedRefs = JGitUtils.getFilesInCommit(repository, push); + for (PathChangeModel change : changedRefs) { + switch (change.changeType) { + case DELETE: + log.updateRef(change.path, ReceiveCommand.Type.DELETE); + break; + case ADD: + log.updateRef(change.path, ReceiveCommand.Type.CREATE); + default: + String content = JGitUtils.getStringContent(repository, push.getTree(), change.path); + String [] fields = content.split(" "); + String oldId = fields[1]; + String newId = fields[2]; + log.updateRef(change.path, ReceiveCommand.Type.valueOf(fields[0]), oldId, newId); + List pushedCommits = JGitUtils.getRevLog(repository, oldId, newId); + for (RevCommit pushedCommit : pushedCommits) { + RepositoryCommit repoCommit = log.addCommit(change.path, pushedCommit); + if (repoCommit != null) { + repoCommit.setRefs(allRefs.get(pushedCommit.getId())); + } + } + } + } + } + Collections.sort(list); + return list; + } + + /** + * Returns the list of pushes separated by ref (e.g. each ref has it's own + * PushLogEntry object). + * + * @param repositoryName + * @param repository + * @param maxCount + * @return a list of push log entries separated by ref + */ + public static List getLogByRef(String repositoryName, Repository repository, int maxCount) { + return getLogByRef(repositoryName, repository, 0, maxCount); + } + + /** + * Returns the list of pushes separated by ref (e.g. each ref has it's own + * PushLogEntry object). + * + * @param repositoryName + * @param repository + * @param offset + * @param maxCount + * @return a list of push log entries separated by ref + */ + public static List getLogByRef(String repositoryName, Repository repository, int offset, + int maxCount) { + // break the push log into ref push logs and then merge them back into a list + Map> refMap = new HashMap>(); + List refLog = getRefLog(repositoryName, repository, offset, maxCount); + for (RefLogEntry entry : refLog) { + for (String ref : entry.getChangedRefs()) { + if (!refMap.containsKey(ref)) { + refMap.put(ref, new ArrayList()); + } + + // construct new ref-specific ref change entry + RefLogEntry refChange; + if (entry instanceof DailyLogEntry) { + // simulated push log from commits grouped by date + refChange = new DailyLogEntry(entry.repository, entry.date); + } else { + // real push log entry + refChange = new RefLogEntry(entry.repository, entry.date, entry.user); + } + refChange.updateRef(ref, entry.getChangeType(ref), entry.getOldId(ref), entry.getNewId(ref)); + refChange.addCommits(entry.getCommits(ref)); + refMap.get(ref).add(refChange); + } + } + + // merge individual ref changes into master list + List mergedRefLog = new ArrayList(); + for (List refPush : refMap.values()) { + mergedRefLog.addAll(refPush); + } + + // sort ref log + Collections.sort(mergedRefLog); + + return mergedRefLog; + } + + /** + * Returns the list of ref changes separated by ref (e.g. each ref has it's own + * RefLogEntry object). + * + * @param repositoryName + * @param repository + * @param minimumDate + * @return a list of ref log entries separated by ref + */ + public static List getLogByRef(String repositoryName, Repository repository, Date minimumDate) { + // break the push log into ref push logs and then merge them back into a list + Map> refMap = new HashMap>(); + List pushes = getRefLog(repositoryName, repository, minimumDate); + for (RefLogEntry push : pushes) { + for (String ref : push.getChangedRefs()) { + if (!refMap.containsKey(ref)) { + refMap.put(ref, new ArrayList()); + } + + // construct new ref-specific push log entry + RefLogEntry refPush = new RefLogEntry(push.repository, push.date, push.user); + refPush.updateRef(ref, push.getChangeType(ref), push.getOldId(ref), push.getNewId(ref)); + refPush.addCommits(push.getCommits(ref)); + refMap.get(ref).add(refPush); + } + } + + // merge individual ref pushes into master list + List refPushLog = new ArrayList(); + for (List refPush : refMap.values()) { + refPushLog.addAll(refPush); + } + + // sort ref push log + Collections.sort(refPushLog); + + return refPushLog; + } + + /** + * Returns a commit log grouped by day. + * + * @param repositoryName + * @param repository + * @param minimumDate + * @param offset + * @param maxCount + * if < 0, all pushes are returned. + * @param the timezone to use when aggregating commits by date + * @return a list of grouped commit log entries + */ + public static List getDailyLog(String repositoryName, Repository repository, + Date minimumDate, int offset, int maxCount, + TimeZone timezone) { + DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + df.setTimeZone(timezone); + + Map> allRefs = JGitUtils.getAllRefs(repository); + Map tags = new HashMap(); + Map pulls = new HashMap(); + Map dailydigests = new HashMap(); + String linearParent = null; + for (RefModel local : JGitUtils.getLocalBranches(repository, true, -1)) { + String branch = local.getName(); + List commits = JGitUtils.getRevLog(repository, branch, minimumDate); + for (RevCommit commit : commits) { + if (linearParent != null) { + if (!commit.getName().equals(linearParent)) { + // only follow linear branch commits + continue; + } + } + Date date = JGitUtils.getCommitDate(commit); + String dateStr = df.format(date); + if (!dailydigests.containsKey(dateStr)) { + dailydigests.put(dateStr, new DailyLogEntry(repositoryName, date)); + } + DailyLogEntry digest = dailydigests.get(dateStr); + if (commit.getParentCount() == 0) { + linearParent = null; + digest.updateRef(branch, ReceiveCommand.Type.CREATE); + } else { + linearParent = commit.getParents()[0].getId().getName(); + digest.updateRef(branch, ReceiveCommand.Type.UPDATE, linearParent, commit.getName()); + } + + RepositoryCommit repoCommit = digest.addCommit(branch, commit); + if (repoCommit != null) { + List matchedRefs = allRefs.get(commit.getId()); + repoCommit.setRefs(matchedRefs); + + if (!ArrayUtils.isEmpty(matchedRefs)) { + for (RefModel ref : matchedRefs) { + if (ref.getName().startsWith(Constants.R_TAGS)) { + // treat tags as special events in the log + if (!tags.containsKey(dateStr)) { + UserModel tagUser = newUserModelFrom(commit.getAuthorIdent()); + Date tagDate = commit.getAuthorIdent().getWhen(); + tags.put(dateStr, new DailyLogEntry(repositoryName, tagDate, tagUser)); + } + RefLogEntry tagEntry = tags.get(dateStr); + tagEntry.updateRef(ref.getName(), ReceiveCommand.Type.CREATE); + tagEntry.addCommit(ref.getName(), commit); + } else if (ref.getName().startsWith(Constants.R_PULL)) { + // treat pull requests as special events in the log + if (!pulls.containsKey(dateStr)) { + UserModel commitUser = newUserModelFrom(commit.getAuthorIdent()); + Date commitDate = commit.getAuthorIdent().getWhen(); + pulls.put(dateStr, new DailyLogEntry(repositoryName, commitDate, commitUser)); + } + RefLogEntry pullEntry = pulls.get(dateStr); + pullEntry.updateRef(ref.getName(), ReceiveCommand.Type.CREATE); + pullEntry.addCommit(ref.getName(), commit); + } + } + } + } + } + } + + List list = new ArrayList(dailydigests.values()); + list.addAll(tags.values()); + //list.addAll(pulls.values()); + Collections.sort(list); + return list; + } + + /** + * Returns the list of commits separated by ref (e.g. each ref has it's own + * PushLogEntry object for each day). + * + * @param repositoryName + * @param repository + * @param minimumDate + * @param the timezone to use when aggregating commits by date + * @return a list of push log entries separated by ref and date + */ + public static List getDailyLogByRef(String repositoryName, Repository repository, + Date minimumDate, TimeZone timezone) { + // break the push log into ref push logs and then merge them back into a list + Map> refMap = new HashMap>(); + List pushes = getDailyLog(repositoryName, repository, minimumDate, 0, -1, timezone); + for (DailyLogEntry push : pushes) { + for (String ref : push.getChangedRefs()) { + if (!refMap.containsKey(ref)) { + refMap.put(ref, new ArrayList()); + } + + // construct new ref-specific push log entry + DailyLogEntry refPush = new DailyLogEntry(push.repository, push.date, push.user); + refPush.updateRef(ref, push.getChangeType(ref), push.getOldId(ref), push.getNewId(ref)); + refPush.addCommits(push.getCommits(ref)); + refMap.get(ref).add(refPush); + } + } + + // merge individual ref pushes into master list + List refPushLog = new ArrayList(); + for (List refPush : refMap.values()) { + for (DailyLogEntry entry : refPush) { + if (entry.getCommitCount() > 0) { + refPushLog.add(entry); + } + } + } + + // sort ref push log + Collections.sort(refPushLog); + + return refPushLog; + } +} diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java index f4180faa..cdae0931 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java @@ -44,18 +44,18 @@ import com.gitblit.wicket.pages.ForksPage; import com.gitblit.wicket.pages.GitSearchPage; import com.gitblit.wicket.pages.GravatarProfilePage; import com.gitblit.wicket.pages.HistoryPage; -import com.gitblit.wicket.pages.DashboardPage; import com.gitblit.wicket.pages.LogPage; import com.gitblit.wicket.pages.LogoutPage; import com.gitblit.wicket.pages.LuceneSearchPage; import com.gitblit.wicket.pages.MarkdownPage; import com.gitblit.wicket.pages.MetricsPage; +import com.gitblit.wicket.pages.MyDashboardPage; import com.gitblit.wicket.pages.OverviewPage; import com.gitblit.wicket.pages.PatchPage; import com.gitblit.wicket.pages.ProjectPage; import com.gitblit.wicket.pages.ProjectsPage; -import com.gitblit.wicket.pages.PushesPage; import com.gitblit.wicket.pages.RawPage; +import com.gitblit.wicket.pages.ReflogPage; import com.gitblit.wicket.pages.RepositoriesPage; import com.gitblit.wicket.pages.ReviewProposalPage; import com.gitblit.wicket.pages.SummaryPage; @@ -69,7 +69,7 @@ import com.gitblit.wicket.pages.UsersPage; public class GitBlitWebApp extends WebApplication { - public final static Class HOME_PAGE_CLASS = DashboardPage.class; + public final static Class HOME_PAGE_CLASS = MyDashboardPage.class; @Override public void init() { @@ -98,7 +98,7 @@ public class GitBlitWebApp extends WebApplication { mount("/repositories", RepositoriesPage.class); mount("/overview", OverviewPage.class, "r", "h"); mount("/summary", SummaryPage.class, "r"); - mount("/pushes", PushesPage.class, "r", "h"); + mount("/reflog", ReflogPage.class, "r", "h"); mount("/commits", LogPage.class, "r", "h"); mount("/log", LogPage.class, "r", "h"); mount("/tags", TagsPage.class, "r"); diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index 2e17e605..f7e72ca9 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -462,8 +462,7 @@ gb.to = to gb.at = at gb.of = of gb.in = in -gb.morePushes = all pushes... -gb.pushes = pushes +gb.moreChanges = all changes... gb.pushedNCommitsTo = pushed {0} commits to gb.pushedOneCommitTo = pushed 1 commit to gb.commitsTo = {0} commits to @@ -488,8 +487,12 @@ gb.stargazers = stargazers gb.starredRepositories = starred repositories gb.failedToUpdateUser = Failed to update user account! gb.myRepositories = my repositories -gb.noActivity = there has been no recent commit activity +gb.noActivity = there has been no activity in the last {0} days gb.findSomeRepositories = find some repositories gb.metricAuthorExclusions = author metric exclusions gb.myDashboard = my dashboard -gb.failedToFindAccount = failed to find user account ''{0}'' \ No newline at end of file +gb.failedToFindAccount = failed to find user account ''{0}'' +gb.reflog = reflog +gb.active = active +gb.starred = starred +gb.owned = owned \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/DashboardPage.html b/src/main/java/com/gitblit/wicket/pages/DashboardPage.html deleted file mode 100644 index 1da7ef41..00000000 --- a/src/main/java/com/gitblit/wicket/pages/DashboardPage.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - -
-
[repositories message]
- -
-
-
-
- - - - - -
-
-
-
-
-
[active]
-
[starred]
-
[owned]
-
- -
-
- - -
-
({{starred.length}}) -
- more -
-
- -
-
- -
- !  - {{item.p}}{{item.n}} - {{item.t}} - - {{item.s | number}} - -
- -
-
- - -
-
({{owned.length}}) -
- -
-
- -
-
- -
- !  - {{item.p}}{{item.n}} - {{item.t}} - - {{item.s | number}} - -
-
-
- - -
-
({{active.length}}) -
- -
-
- -
- !  - {{item.p}}{{item.n}} - {{item.t}} - - {{item.s | number}} - -
-
-
- -
- - \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/DashboardPage.java b/src/main/java/com/gitblit/wicket/pages/DashboardPage.java index 6c328b10..1c45b64a 100644 --- a/src/main/java/com/gitblit/wicket/pages/DashboardPage.java +++ b/src/main/java/com/gitblit/wicket/pages/DashboardPage.java @@ -15,49 +15,40 @@ */ package com.gitblit.wicket.pages; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.io.InputStreamReader; import java.io.Serializable; import java.text.DateFormat; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.Date; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TimeZone; import java.util.TreeSet; -import org.apache.wicket.Component; import org.apache.wicket.PageParameters; import org.apache.wicket.behavior.HeaderContributor; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.panel.Fragment; -import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; import com.gitblit.GitBlit; import com.gitblit.Keys; import com.gitblit.models.DailyLogEntry; import com.gitblit.models.Metric; -import com.gitblit.models.PushLogEntry; +import com.gitblit.models.RefLogEntry; import com.gitblit.models.RepositoryCommit; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; import com.gitblit.utils.ArrayUtils; -import com.gitblit.utils.MarkdownUtils; -import com.gitblit.utils.PushLogUtils; +import com.gitblit.utils.RefLogUtils; import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebApp; -import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.PageRegistration; import com.gitblit.wicket.PageRegistration.DropDownMenuItem; import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration; @@ -66,19 +57,17 @@ import com.gitblit.wicket.charting.GoogleChart; import com.gitblit.wicket.charting.GoogleCharts; import com.gitblit.wicket.charting.GooglePieChart; import com.gitblit.wicket.ng.NgController; +import com.gitblit.wicket.panels.DigestsPanel; import com.gitblit.wicket.panels.LinkPanel; -import com.gitblit.wicket.panels.PushesPanel; -public class DashboardPage extends RootPage { +public abstract class DashboardPage extends RootPage { public DashboardPage() { super(); - setup(null); } public DashboardPage(PageParameters params) { super(params); - setup(params); } @Override @@ -86,115 +75,50 @@ public class DashboardPage extends RootPage { return true; } - private void setup(PageParameters params) { - setupPage("", ""); - // check to see if we should display a login message - boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, true); - if (authenticateView && !GitBlitWebSession.get().isLoggedIn()) { - String messageSource = GitBlit.getString(Keys.web.loginMessage, "gitblit"); - String message = readMarkdown(messageSource, "login.mkd"); - Component repositoriesMessage = new Label("repositoriesMessage", message); - add(repositoriesMessage.setEscapeModelStrings(false)); - add(new Label("digests")); - add(new Label("active").setVisible(false)); - add(new Label("starred").setVisible(false)); - add(new Label("owned").setVisible(false)); - add(new Label("feedheader").setVisible(false)); - return; - } - - // Load the markdown welcome message - String messageSource = GitBlit.getString(Keys.web.repositoriesMessage, "gitblit"); - String message = readMarkdown(messageSource, "welcome.mkd"); - Component repositoriesMessage = new Label("repositoriesMessage", message) - .setEscapeModelStrings(false).setVisible(message.length() > 0); - add(repositoriesMessage); - - UserModel user = GitBlitWebSession.get().getUser(); - if (user == null) { - user = UserModel.ANONYMOUS; - } - - Comparator lastUpdateSort = new Comparator() { - @Override - public int compare(RepositoryModel o1, RepositoryModel o2) { - return o2.lastChange.compareTo(o1.lastChange); - } - }; - - // parameters - int daysBack = params == null ? 0 : WicketUtils.getDaysBack(params); - if (daysBack < 1) { - daysBack = 7; - } + protected void addActivity(UserModel user, Collection repositories, int daysBack) { Calendar c = Calendar.getInstance(); c.add(Calendar.DATE, -1*daysBack); Date minimumDate = c.getTime(); TimeZone timezone = getTimeZone(); - // build repo lists - List starred = new ArrayList(); - List owned = new ArrayList(); - List active = new ArrayList(); - - for (RepositoryModel model : getRepositoryModels()) { - if (model.isUsersPersonalRepository(user.username) || model.isOwner(user.username)) { - owned.add(model); - } - - if (user.getPreferences().isStarredRepository(model.name)) { - starred.add(model); - } - - if (model.isShowActivity() && model.lastChange.after(minimumDate)) { - active.add(model); - } - } - - Collections.sort(owned, lastUpdateSort); - Collections.sort(starred, lastUpdateSort); - Collections.sort(active, lastUpdateSort); - - Set feedSources = new HashSet(); - feedSources.addAll(starred); - if (feedSources.isEmpty()) { - feedSources.addAll(active); - } - // create daily commit digest feed - List pushes = new ArrayList(); - for (RepositoryModel model : feedSources) { + List digests = new ArrayList(); + for (RepositoryModel model : repositories) { Repository repository = GitBlit.self().getRepository(model.name); - List entries = PushLogUtils.getDailyLogByRef(model.name, repository, minimumDate, timezone); - pushes.addAll(entries); + List entries = RefLogUtils.getDailyLogByRef(model.name, repository, minimumDate, timezone); + digests.addAll(entries); repository.close(); } - if (pushes.size() == 0) { + Fragment activityFragment = new Fragment("activity", "activityFragment", this); + add(activityFragment); + if (digests.size() == 0) { // quiet or no starred repositories - if (feedSources.size() == 0) { + if (repositories.size() == 0) { if (UserModel.ANONYMOUS.equals(user)) { - add(new Label("digests", getString("gb.noActivity"))); + activityFragment.add(new Label("digests", MessageFormat.format(getString("gb.noActivity"), daysBack))); } else { - add(new LinkPanel("digests", null, getString("gb.findSomeRepositories"), RepositoriesPage.class)); + activityFragment.add(new LinkPanel("digests", null, getString("gb.findSomeRepositories"), RepositoriesPage.class)); } } else { - add(new Label("digests", getString("gb.noActivity"))); + activityFragment.add(new Label("digests", MessageFormat.format(getString("gb.noActivity"), daysBack))); } } else { // show daily commit digest feed - Collections.sort(pushes); - add(new PushesPanel("digests", pushes)); + Collections.sort(digests); + DigestsPanel digestsPanel = new DigestsPanel("digests", digests); + WicketUtils.setCssStyle(digestsPanel, "margin-top:-20px"); + activityFragment.add(digestsPanel); } // add the nifty charts - if (!ArrayUtils.isEmpty(pushes)) { + if (!ArrayUtils.isEmpty(digests)) { // aggregate author exclusions Set authorExclusions = new TreeSet(); for (String author : GitBlit.getStrings(Keys.web.metricAuthorExclusions)) { authorExclusions.add(author.toLowerCase()); } - for (RepositoryModel model : feedSources) { + for (RepositoryModel model : repositories) { if (!ArrayUtils.isEmpty(model.metricAuthorExclusions)) { for (String author : model.metricAuthorExclusions) { authorExclusions.add(author.toLowerCase()); @@ -202,40 +126,10 @@ public class DashboardPage extends RootPage { } } - addCharts(pushes, authorExclusions, daysBack); - } else { - add(new Label("feedheader").setVisible(false)); - } - - // active repository list - if (starred.isEmpty()) { - Fragment activeView = createNgList("active", "activeListFragment", "activeCtrl", active); - add(activeView); + addCharts(activityFragment, digests, authorExclusions, daysBack); } else { - add(new Label("active").setVisible(false)); - } - - // starred repository list - if (ArrayUtils.isEmpty(starred)) { - add(new Label("starred").setVisible(false)); - } else { - Fragment starredView = createNgList("starred", "starredListFragment", "starredCtrl", starred); - add(starredView); - } - - // owned repository list - if (ArrayUtils.isEmpty(owned)) { - add(new Label("owned").setVisible(false)); - } else { - Fragment ownedView = createNgList("owned", "ownedListFragment", "ownedCtrl", owned); - if (user.canCreate) { - // create button - ownedView.add(new LinkPanel("create", "btn btn-mini", getString("gb.newRepository"), EditRepositoryPage.class)); - } else { - // no button - ownedView.add(new Label("create").setVisible(false)); - } - add(ownedView); + activityFragment.add(new Label("charts").setVisible(false)); + activityFragment.add(new Label("feedheader").setVisible(false)); } } @@ -259,6 +153,7 @@ public class DashboardPage extends RootPage { item.n = name; item.p = path; item.r = repo.name; + item.i = repo.description; item.s = GitBlit.self().getStarCount(repo); item.t = getTimeUtils().timeAgo(repo.lastChange); item.d = df.format(repo.lastChange); @@ -295,104 +190,32 @@ public class DashboardPage extends RootPage { pages.add(menu); } - private String readMarkdown(String messageSource, String resource) { - String message = ""; - if (messageSource.equalsIgnoreCase("gitblit")) { - // Read default message - message = readDefaultMarkdown(resource); - } else { - // Read user-supplied message - if (!StringUtils.isEmpty(messageSource)) { - File file = GitBlit.getFileOrFolder(messageSource); - if (file.exists()) { - try { - FileInputStream fis = new FileInputStream(file); - InputStreamReader reader = new InputStreamReader(fis, - Constants.CHARACTER_ENCODING); - message = MarkdownUtils.transformMarkdown(reader); - reader.close(); - } catch (Throwable t) { - message = getString("gb.failedToRead") + " " + file; - warn(message, t); - } - } else { - message = messageSource + " " + getString("gb.isNotValidFile"); - } - } - } - return message; - } - - private String readDefaultMarkdown(String file) { - String base = file.substring(0, file.lastIndexOf('.')); - String ext = file.substring(file.lastIndexOf('.')); - String lc = getLanguageCode(); - String cc = getCountryCode(); - - // try to read file_en-us.ext, file_en.ext, file.ext - List files = new ArrayList(); - if (!StringUtils.isEmpty(lc)) { - if (!StringUtils.isEmpty(cc)) { - files.add(base + "_" + lc + "-" + cc + ext); - files.add(base + "_" + lc + "_" + cc + ext); - } - files.add(base + "_" + lc + ext); - } - files.add(file); - for (String name : files) { - String message; - InputStreamReader reader = null; - try { - InputStream is = getClass().getResourceAsStream("/" + name); - if (is == null) { - continue; - } - reader = new InputStreamReader(is, Constants.CHARACTER_ENCODING); - message = MarkdownUtils.transformMarkdown(reader); - reader.close(); - return message; - } catch (Throwable t) { - message = MessageFormat.format(getString("gb.failedToReadMessage"), file); - error(message, t, false); - return message; - } finally { - if (reader != null) { - try { - reader.close(); - } catch (Exception e) { - } - } - } - } - return MessageFormat.format(getString("gb.failedToReadMessage"), file); - } - /** * Creates the daily activity line chart, the active repositories pie chart, * and the active authors pie chart * - * @param recentPushes + * @param recentChanges * @param authorExclusions * @param daysBack */ - private void addCharts(List recentPushes, Set authorExclusions, int daysBack) { + protected void addCharts(Fragment frag, List recentChanges, Set authorExclusions, int daysBack) { // activity metrics Map repositoryMetrics = new HashMap(); Map authorMetrics = new HashMap(); // aggregate repository and author metrics int totalCommits = 0; - for (PushLogEntry push : recentPushes) { + for (RefLogEntry change : recentChanges) { // aggregate repository metrics - String repository = StringUtils.stripDotGit(push.repository); + String repository = StringUtils.stripDotGit(change.repository); if (!repositoryMetrics.containsKey(repository)) { repositoryMetrics.put(repository, new Metric(repository)); } repositoryMetrics.get(repository).count += 1; - for (RepositoryCommit commit : push.getCommits()) { + for (RepositoryCommit commit : change.getCommits()) { totalCommits++; String author = StringUtils.removeNewlines(commit.getAuthorIdent().getName()); String authorName = author.toLowerCase(); @@ -406,7 +229,7 @@ public class DashboardPage extends RootPage { } } - add(new Label("feedheader", MessageFormat.format(getString("gb.recentActivityStats"), + frag.add(new Label("feedheader", MessageFormat.format(getString("gb.recentActivityStats"), daysBack, totalCommits, authorMetrics.size()))); // build google charts @@ -430,10 +253,11 @@ public class DashboardPage extends RootPage { chart.setShowLegend(false); charts.addChart(chart); - add(new HeaderContributor(charts)); + add(new HeaderContributor(charts)); + frag.add(new Fragment("charts", "chartsFragment", this)); } - class RepoListItem implements Serializable { + protected class RepoListItem implements Serializable { private static final long serialVersionUID = 1L; @@ -442,6 +266,7 @@ public class DashboardPage extends RootPage { String p; // project/path String t; // time ago String d; // last updated + String i; // information/description long s; // stars String c; // html color int wc; // working copy, 1 = true diff --git a/src/main/java/com/gitblit/wicket/pages/MyDashboardPage.html b/src/main/java/com/gitblit/wicket/pages/MyDashboardPage.html new file mode 100644 index 00000000..6b78b140 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/MyDashboardPage.html @@ -0,0 +1,158 @@ + + + + + +
+ +
+
+
[repositories message]
+
+
+
+
+
+
+
+ + + +
+
+
[recently active]
+
+
+
[all projects]
+
+
+
+ + + +
+
+
[starred repositories]
+
+
+
[my repositories]
+
+
+
[recently active]
+
+
+
[all projects]
+
+
+
+ + +
+
+
+
+
+
+ + + + + + + +
+
+ + +
+
({{starred.length}}) +
+ +
+
+ +
+ !  + {{item.p}}{{item.n}} + {{item.t}} + + {{item.s | number}} + +
+ +
+
+ + +
+
({{owned.length}}) +
+ +
+
+ +
+
+ +
+ !  + {{item.p}}{{item.n}} + {{item.t}} + + {{item.s | number}} + +
+
+
+ + +
+
({{active.length}}) +
+ +
+
+ +
+ !  + {{item.p}}{{item.n}} + {{item.t}} + + {{item.s | number}} + +
+
+
+ + +
+
({{projectList.length}}) +
+ +
+
+ +
+ {{item.n}} + {{item.t}} + + {{item.c | number}} + +
+
+
+ +
+ + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/MyDashboardPage.java b/src/main/java/com/gitblit/wicket/pages/MyDashboardPage.java new file mode 100644 index 00000000..b0c89b72 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/MyDashboardPage.java @@ -0,0 +1,311 @@ +/* + * Copyright 2013 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.pages; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Serializable; +import java.text.DateFormat; +import java.text.MessageFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.wicket.Component; +import org.apache.wicket.PageParameters; +import org.apache.wicket.behavior.HeaderContributor; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.panel.Fragment; +import org.eclipse.jgit.lib.Constants; + +import com.gitblit.GitBlit; +import com.gitblit.Keys; +import com.gitblit.models.ProjectModel; +import com.gitblit.models.RepositoryModel; +import com.gitblit.models.UserModel; +import com.gitblit.utils.ArrayUtils; +import com.gitblit.utils.MarkdownUtils; +import com.gitblit.utils.StringUtils; +import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.ng.NgController; +import com.gitblit.wicket.panels.LinkPanel; + +public class MyDashboardPage extends DashboardPage { + + public MyDashboardPage() { + super(); + setup(null); + } + + public MyDashboardPage(PageParameters params) { + super(params); + setup(params); + } + + @Override + protected boolean reusePageParameters() { + return true; + } + + private void setup(PageParameters params) { + setupPage("", ""); + // check to see if we should display a login message + boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, true); + if (authenticateView && !GitBlitWebSession.get().isLoggedIn()) { + String messageSource = GitBlit.getString(Keys.web.loginMessage, "gitblit"); + String message = readMarkdown(messageSource, "login.mkd"); + Component repositoriesMessage = new Label("repositoriesMessage", message); + add(repositoriesMessage.setEscapeModelStrings(false)); + add(new Label("activity").setVisible(false)); + add(new Label("repositoryTabs").setVisible(false)); + return; + } + + // Load the markdown welcome message + String messageSource = GitBlit.getString(Keys.web.repositoriesMessage, "gitblit"); + String message = readMarkdown(messageSource, "welcome.mkd"); + Component repositoriesMessage = new Label("repositoriesMessage", message) + .setEscapeModelStrings(false).setVisible(message.length() > 0); + add(repositoriesMessage); + + UserModel user = GitBlitWebSession.get().getUser(); + if (user == null) { + user = UserModel.ANONYMOUS; + } + + // parameters + int daysBack = params == null ? 0 : WicketUtils.getDaysBack(params); + if (daysBack < 1) { + daysBack = 7; + } + Calendar c = Calendar.getInstance(); + c.add(Calendar.DATE, -1*daysBack); + Date minimumDate = c.getTime(); + + // build repo lists + List starred = new ArrayList(); + List owned = new ArrayList(); + List active = new ArrayList(); + + for (RepositoryModel model : getRepositoryModels()) { + if (model.isUsersPersonalRepository(user.username) || model.isOwner(user.username)) { + owned.add(model); + } + + if (user.getPreferences().isStarredRepository(model.name)) { + starred.add(model); + } + + if (model.isShowActivity() && model.lastChange.after(minimumDate)) { + active.add(model); + } + } + + Comparator lastUpdateSort = new Comparator() { + @Override + public int compare(RepositoryModel o1, RepositoryModel o2) { + return o2.lastChange.compareTo(o1.lastChange); + } + }; + + Collections.sort(owned, lastUpdateSort); + Collections.sort(starred, lastUpdateSort); + Collections.sort(active, lastUpdateSort); + + Set feed = new HashSet(); + feed.addAll(starred); + feed.addAll(owned); + if (feed.isEmpty()) { + feed.addAll(active); + } + + addActivity(user, feed, daysBack); + + Fragment repositoryTabs; + if (UserModel.ANONYMOUS.equals(user)) { + repositoryTabs = new Fragment("repositoryTabs", "anonymousTabsFragment", this); + } else { + repositoryTabs = new Fragment("repositoryTabs", "authenticatedTabsFragment", this); + } + + add(repositoryTabs); + + Fragment projectList = createProjectList(); + repositoryTabs.add(projectList); + + // active repository list + if (active.isEmpty()) { + repositoryTabs.add(new Label("active").setVisible(false)); + } else { + Fragment activeView = createNgList("active", "activeListFragment", "activeCtrl", active); + repositoryTabs.add(activeView); + } + + // starred repository list + if (ArrayUtils.isEmpty(starred)) { + repositoryTabs.add(new Label("starred").setVisible(false)); + } else { + Fragment starredView = createNgList("starred", "starredListFragment", "starredCtrl", starred); + repositoryTabs.add(starredView); + } + + // owned repository list + if (ArrayUtils.isEmpty(owned)) { + repositoryTabs.add(new Label("owned").setVisible(false)); + } else { + Fragment ownedView = createNgList("owned", "ownedListFragment", "ownedCtrl", owned); + if (user.canCreate) { + // create button + ownedView.add(new LinkPanel("create", "btn btn-mini", getString("gb.newRepository"), EditRepositoryPage.class)); + } else { + // no button + ownedView.add(new Label("create").setVisible(false)); + } + repositoryTabs.add(ownedView); + } + } + + private String readMarkdown(String messageSource, String resource) { + String message = ""; + if (messageSource.equalsIgnoreCase("gitblit")) { + // Read default message + message = readDefaultMarkdown(resource); + } else { + // Read user-supplied message + if (!StringUtils.isEmpty(messageSource)) { + File file = GitBlit.getFileOrFolder(messageSource); + if (file.exists()) { + try { + FileInputStream fis = new FileInputStream(file); + InputStreamReader reader = new InputStreamReader(fis, + Constants.CHARACTER_ENCODING); + message = MarkdownUtils.transformMarkdown(reader); + reader.close(); + } catch (Throwable t) { + message = getString("gb.failedToRead") + " " + file; + warn(message, t); + } + } else { + message = messageSource + " " + getString("gb.isNotValidFile"); + } + } + } + return message; + } + + private String readDefaultMarkdown(String file) { + String base = file.substring(0, file.lastIndexOf('.')); + String ext = file.substring(file.lastIndexOf('.')); + String lc = getLanguageCode(); + String cc = getCountryCode(); + + // try to read file_en-us.ext, file_en.ext, file.ext + List files = new ArrayList(); + if (!StringUtils.isEmpty(lc)) { + if (!StringUtils.isEmpty(cc)) { + files.add(base + "_" + lc + "-" + cc + ext); + files.add(base + "_" + lc + "_" + cc + ext); + } + files.add(base + "_" + lc + ext); + } + files.add(file); + + for (String name : files) { + String message; + InputStreamReader reader = null; + try { + InputStream is = getClass().getResourceAsStream("/" + name); + if (is == null) { + continue; + } + reader = new InputStreamReader(is, Constants.CHARACTER_ENCODING); + message = MarkdownUtils.transformMarkdown(reader); + reader.close(); + return message; + } catch (Throwable t) { + message = MessageFormat.format(getString("gb.failedToReadMessage"), file); + error(message, t, false); + return message; + } finally { + if (reader != null) { + try { + reader.close(); + } catch (Exception e) { + } + } + } + } + return MessageFormat.format(getString("gb.failedToReadMessage"), file); + } + + protected Fragment createProjectList() { + String format = GitBlit.getString(Keys.web.datestampShortFormat, "MM/dd/yy"); + final DateFormat df = new SimpleDateFormat(format); + df.setTimeZone(getTimeZone()); + List projects = GitBlit.self().getProjectModels(getRepositoryModels(), false); + Collections.sort(projects, new Comparator() { + @Override + public int compare(ProjectModel o1, ProjectModel o2) { + return o2.lastChange.compareTo(o1.lastChange); + } + }); + + List list = new ArrayList(); + for (ProjectModel proj : projects) { + if (proj.isUserProject() || proj.repositories.isEmpty()) { + // exclude user projects from list + continue; + } + ProjectListItem item = new ProjectListItem(); + item.p = proj.name; + item.n = StringUtils.isEmpty(proj.title) ? proj.name : proj.title; + item.i = proj.description; + item.t = getTimeUtils().timeAgo(proj.lastChange); + item.d = df.format(proj.lastChange); + item.c = proj.repositories.size(); + list.add(item); + } + + // inject an AngularJS controller with static data + NgController ctrl = new NgController("projectListCtrl"); + ctrl.addVariable("projectList", list); + add(new HeaderContributor(ctrl)); + + Fragment fragment = new Fragment("projectList", "projectListFragment", this); + return fragment; + } + + protected class ProjectListItem implements Serializable { + + private static final long serialVersionUID = 1L; + + String p; // path + String n; // name + String t; // time ago + String d; // last updated + String i; // information/description + long c; // repository count + } +} diff --git a/src/main/java/com/gitblit/wicket/pages/OverviewPage.html b/src/main/java/com/gitblit/wicket/pages/OverviewPage.html index 3340e318..995f8df6 100644 --- a/src/main/java/com/gitblit/wicket/pages/OverviewPage.html +++ b/src/main/java/com/gitblit/wicket/pages/OverviewPage.html @@ -48,7 +48,7 @@
[repository url panel]
-
[pushes panel]
+
[reflog panel]
diff --git a/src/main/java/com/gitblit/wicket/pages/OverviewPage.java b/src/main/java/com/gitblit/wicket/pages/OverviewPage.java index 42d20c5b..88487670 100644 --- a/src/main/java/com/gitblit/wicket/pages/OverviewPage.java +++ b/src/main/java/com/gitblit/wicket/pages/OverviewPage.java @@ -41,7 +41,7 @@ import com.gitblit.wicket.charting.GoogleCharts; import com.gitblit.wicket.charting.GoogleLineChart; import com.gitblit.wicket.panels.BranchesPanel; import com.gitblit.wicket.panels.LinkPanel; -import com.gitblit.wicket.panels.PushesPanel; +import com.gitblit.wicket.panels.ReflogPanel; import com.gitblit.wicket.panels.RepositoryUrlPanel; import com.gitblit.wicket.panels.TagsPanel; @@ -113,9 +113,9 @@ public class OverviewPage extends RepositoryPage { add(new RepositoryUrlPanel("repositoryUrlPanel", false, user, model)); - int pushCount = GitBlit.getInteger(Keys.web.overviewPushCount, 5); - PushesPanel pushes = new PushesPanel("pushesPanel", getRepositoryModel(), r, pushCount, 0, false); - add(pushes); + 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()); diff --git a/src/main/java/com/gitblit/wicket/pages/ProjectPage.html b/src/main/java/com/gitblit/wicket/pages/ProjectPage.html index 3b5d4e6a..9fbe1b2d 100644 --- a/src/main/java/com/gitblit/wicket/pages/ProjectPage.html +++ b/src/main/java/com/gitblit/wicket/pages/ProjectPage.html @@ -6,66 +6,70 @@ - -
-
-
-

- - - -

-
[project message]
-
-
- -
- - - - -
- - -
- -
-
-
[repositories message]
+
+
+
+
+ + + + +
-
-
- -
-
- -
-
-

/ [days back]

+
+
+
[project message]
+
[activity panel]
- -
- - - - - - -
+
+
[repositories message]
+
[repository list]
- -
[activity panel]
-
+ + +
+
+
+
+
+ + + + + + + +
+
+ + +
+
({{repositoryList.length}}) +
+ +
+
+ +
+ !  + {{item.p}}{{item.n}} + {{item.t}} + + {{item.s | number}} + +
- +
+ \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/ProjectPage.java b/src/main/java/com/gitblit/wicket/pages/ProjectPage.java index 7eba0331..c64e900a 100644 --- a/src/main/java/com/gitblit/wicket/pages/ProjectPage.java +++ b/src/main/java/com/gitblit/wicket/pages/ProjectPage.java @@ -15,34 +15,23 @@ */ package com.gitblit.wicket.pages; -import java.text.MessageFormat; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; -import java.util.Map; -import java.util.Set; import org.apache.wicket.Component; import org.apache.wicket.PageParameters; -import org.apache.wicket.behavior.HeaderContributor; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.link.ExternalLink; -import org.apache.wicket.markup.repeater.Item; -import org.apache.wicket.markup.repeater.data.DataView; -import org.apache.wicket.markup.repeater.data.ListDataProvider; +import org.apache.wicket.markup.html.panel.Fragment; import com.gitblit.GitBlit; import com.gitblit.Keys; import com.gitblit.SyndicationServlet; -import com.gitblit.models.Activity; -import com.gitblit.models.Metric; import com.gitblit.models.ProjectModel; import com.gitblit.models.RepositoryModel; -import com.gitblit.utils.ActivityUtils; +import com.gitblit.models.UserModel; import com.gitblit.utils.MarkdownUtils; import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebApp; @@ -52,14 +41,8 @@ import com.gitblit.wicket.PageRegistration; import com.gitblit.wicket.PageRegistration.DropDownMenuItem; import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration; import com.gitblit.wicket.WicketUtils; -import com.gitblit.wicket.charting.GoogleChart; -import com.gitblit.wicket.charting.GoogleCharts; -import com.gitblit.wicket.charting.GoogleLineChart; -import com.gitblit.wicket.charting.GooglePieChart; -import com.gitblit.wicket.panels.ActivityPanel; -import com.gitblit.wicket.panels.ProjectRepositoryPanel; -public class ProjectPage extends RootPage { +public class ProjectPage extends DashboardPage { List projectModels = new ArrayList(); @@ -72,10 +55,9 @@ public class ProjectPage extends RootPage { super(params); setup(params); } - - @Override - protected boolean reusePageParameters() { - return true; + + protected Class getRootNavPageClass() { + return RepositoriesPage.class; } private void setup(PageParameters params) { @@ -118,8 +100,20 @@ public class ProjectPage extends RootPage { .setEscapeModelStrings(false).setVisible(rmessage.length() > 0); add(repositoriesMessage); - List repositories = getRepositories(params); + UserModel user = GitBlitWebSession.get().getUser(); + if (user == null) { + user = UserModel.ANONYMOUS; + } + int daysBack = params == null ? 0 : WicketUtils.getDaysBack(params); + if (daysBack < 1) { + daysBack = 7; + } + // reset the daysback parameter so that we have a complete project + // repository list. the recent activity will be built up by the + // reflog utils. + params.put("db", 0); + List repositories = getRepositories(params); Collections.sort(repositories, new Comparator() { @Override public int compare(RepositoryModel o1, RepositoryModel o2) { @@ -128,145 +122,21 @@ public class ProjectPage extends RootPage { } }); - final ListDataProvider dp = new ListDataProvider(repositories); - DataView dataView = new DataView("repositoryList", dp) { - private static final long serialVersionUID = 1L; - - public void populateItem(final Item item) { - final RepositoryModel entry = item.getModelObject(); - - ProjectRepositoryPanel row = new ProjectRepositoryPanel("repository", - getLocalizer(), this, showAdmin, entry, getAccessRestrictions()); - item.add(row); - } - }; - add(dataView); - - // project activity - // parameters - int daysBack = WicketUtils.getDaysBack(params); - if (daysBack < 1) { - daysBack = 14; - } - String objectId = WicketUtils.getObject(params); - - List recentActivity = ActivityUtils.getRecentActivity(repositories, - daysBack, objectId, getTimeZone()); - if (recentActivity.size() == 0) { - // no activity, skip graphs and activity panel - add(new Label("subheader", MessageFormat.format(getString("gb.recentActivityNone"), - daysBack))); - add(new Label("activityPanel")); + + addActivity(user, repositories, daysBack); + + if (repositories.isEmpty()) { + add(new Label("repositoryList").setVisible(false)); } else { - // calculate total commits and total authors - int totalCommits = 0; - Set uniqueAuthors = new HashSet(); - for (Activity activity : recentActivity) { - totalCommits += activity.getCommitCount(); - uniqueAuthors.addAll(activity.getAuthorMetrics().keySet()); - } - int totalAuthors = uniqueAuthors.size(); - - // add the subheader with stat numbers - add(new Label("subheader", MessageFormat.format(getString("gb.recentActivityStats"), - daysBack, totalCommits, totalAuthors))); - - // create the activity charts - GoogleCharts charts = createCharts(recentActivity); - add(new HeaderContributor(charts)); - - // add activity panel - add(new ActivityPanel("activityPanel", recentActivity)); + Fragment activeView = createNgList("repositoryList", "repositoryListFragment", "repositoryListCtrl", repositories); + add(activeView); } } - /** - * Creates the daily activity line chart, the active repositories pie chart, - * and the active authors pie chart - * - * @param recentActivity - * @return - */ - private GoogleCharts createCharts(List recentActivity) { - // activity metrics - Map repositoryMetrics = new HashMap(); - Map authorMetrics = new HashMap(); - - // aggregate repository and author metrics - for (Activity activity : recentActivity) { - - // aggregate author metrics - for (Map.Entry entry : activity.getAuthorMetrics().entrySet()) { - String author = entry.getKey(); - if (!authorMetrics.containsKey(author)) { - authorMetrics.put(author, new Metric(author)); - } - authorMetrics.get(author).count += entry.getValue().count; - } - - // aggregate repository metrics - for (Map.Entry entry : activity.getRepositoryMetrics().entrySet()) { - String repository = StringUtils.stripDotGit(entry.getKey()); - if (!repositoryMetrics.containsKey(repository)) { - repositoryMetrics.put(repository, new Metric(repository)); - } - repositoryMetrics.get(repository).count += entry.getValue().count; - } - } - - // build google charts - int w = 310; - int h = 150; - GoogleCharts charts = new GoogleCharts(); - - // sort in reverse-chronological order and then reverse that - Collections.sort(recentActivity); - Collections.reverse(recentActivity); - - // daily line chart - GoogleChart chart = new GoogleLineChart("chartDaily", getString("gb.dailyActivity"), "day", - getString("gb.commits")); - SimpleDateFormat df = new SimpleDateFormat("MMM dd"); - df.setTimeZone(getTimeZone()); - for (Activity metric : recentActivity) { - chart.addValue(df.format(metric.startDate), metric.getCommitCount()); - } - chart.setWidth(w); - chart.setHeight(h); - charts.addChart(chart); - - // active repositories pie chart - chart = new GooglePieChart("chartRepositories", getString("gb.activeRepositories"), - getString("gb.repository"), getString("gb.commits")); - for (Metric metric : repositoryMetrics.values()) { - chart.addValue(metric.name, metric.count); - } - chart.setWidth(w); - chart.setHeight(h); - charts.addChart(chart); - - // active authors pie chart - chart = new GooglePieChart("chartAuthors", getString("gb.activeAuthors"), - getString("gb.author"), getString("gb.commits")); - for (Metric metric : authorMetrics.values()) { - chart.addValue(metric.name, metric.count); - } - chart.setWidth(w); - chart.setHeight(h); - charts.addChart(chart); - - return charts; - } - @Override protected void addDropDownMenus(List pages) { PageParameters params = getPageParameters(); - DropDownMenuRegistration projects = new DropDownMenuRegistration("gb.projects", - ProjectPage.class); - projects.menuItems.addAll(getProjectsMenu()); - pages.add(0, projects); - DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters", ProjectPage.class); // preserve time filter option on repository choices @@ -277,10 +147,15 @@ public class ProjectPage extends RootPage { if (menu.menuItems.size() > 0) { // Reset Filter - menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), null, null)); + menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), "p", WicketUtils.getProjectName(params))); } pages.add(menu); + + DropDownMenuRegistration projects = new DropDownMenuRegistration("gb.projects", + ProjectPage.class); + projects.menuItems.addAll(getProjectsMenu()); + pages.add(projects); } @Override diff --git a/src/main/java/com/gitblit/wicket/pages/ProjectsPage.html b/src/main/java/com/gitblit/wicket/pages/ProjectsPage.html index caa0f819..2d446ecc 100644 --- a/src/main/java/com/gitblit/wicket/pages/ProjectsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/ProjectsPage.html @@ -7,7 +7,6 @@
-
[projects message]
diff --git a/src/main/java/com/gitblit/wicket/pages/ProjectsPage.java b/src/main/java/com/gitblit/wicket/pages/ProjectsPage.java index 7f0b002e..d0001ecb 100644 --- a/src/main/java/com/gitblit/wicket/pages/ProjectsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/ProjectsPage.java @@ -15,29 +15,17 @@ */ package com.gitblit.wicket.pages; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.text.MessageFormat; -import java.util.ArrayList; import java.util.List; -import org.apache.wicket.Component; import org.apache.wicket.PageParameters; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.markup.repeater.data.DataView; import org.apache.wicket.markup.repeater.data.ListDataProvider; -import org.apache.wicket.resource.ContextRelativeResource; -import org.apache.wicket.util.resource.ResourceStreamNotFoundException; -import org.eclipse.jgit.lib.Constants; import com.gitblit.GitBlit; import com.gitblit.Keys; import com.gitblit.models.ProjectModel; -import com.gitblit.utils.MarkdownUtils; -import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.PageRegistration; import com.gitblit.wicket.PageRegistration.DropDownMenuItem; @@ -62,6 +50,11 @@ public class ProjectsPage extends RootPage { return true; } + @Override + protected Class getRootNavPageClass() { + return RepositoriesPage.class; + } + @Override protected List getProjectModels() { return GitBlit.self().getProjectModels(getRepositoryModels(), false); @@ -72,21 +65,10 @@ public class ProjectsPage extends RootPage { // check to see if we should display a login message boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, true); if (authenticateView && !GitBlitWebSession.get().isLoggedIn()) { - String messageSource = GitBlit.getString(Keys.web.loginMessage, "gitblit"); - String message = readMarkdown(messageSource, "login.mkd"); - Component repositoriesMessage = new Label("projectsMessage", message); - add(repositoriesMessage.setEscapeModelStrings(false)); add(new Label("projectsPanel")); return; } - // Load the markdown welcome message - String messageSource = GitBlit.getString(Keys.web.repositoriesMessage, "gitblit"); - String message = readMarkdown(messageSource, "welcome.mkd"); - Component projectsMessage = new Label("projectsMessage", message).setEscapeModelStrings( - false).setVisible(message.length() > 0); - add(projectsMessage); - List projects = getProjects(params); ListDataProvider dp = new ListDataProvider(projects); @@ -130,20 +112,12 @@ public class ProjectsPage extends RootPage { } }; add(dataView); - - // push the panel down if we are hiding the admin controls and the - // welcome message - if (!showAdmin && !projectsMessage.isVisible()) { - WicketUtils.setCssStyle(dataView, "padding-top:5px;"); - } } @Override protected void addDropDownMenus(List pages) { PageParameters params = getPageParameters(); - pages.add(0, new PageRegistration("gb.projects", ProjectsPage.class, params)); - DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters", ProjectsPage.class); // preserve time filter option on repository choices @@ -159,77 +133,4 @@ public class ProjectsPage extends RootPage { pages.add(menu); } - - private String readMarkdown(String messageSource, String resource) { - String message = ""; - if (messageSource.equalsIgnoreCase("gitblit")) { - // Read default message - message = readDefaultMarkdown(resource); - } else { - // Read user-supplied message - if (!StringUtils.isEmpty(messageSource)) { - File file = new File(messageSource); - if (file.exists()) { - try { - FileInputStream fis = new FileInputStream(file); - InputStreamReader reader = new InputStreamReader(fis, - Constants.CHARACTER_ENCODING); - message = MarkdownUtils.transformMarkdown(reader); - reader.close(); - } catch (Throwable t) { - message = getString("gb.failedToRead") + " " + file; - warn(message, t); - } - } else { - message = messageSource + " " + getString("gb.isNotValidFile"); - } - } - } - return message; - } - - private String readDefaultMarkdown(String file) { - String base = file.substring(0, file.lastIndexOf('.')); - String ext = file.substring(file.lastIndexOf('.')); - String lc = getLanguageCode(); - String cc = getCountryCode(); - - // try to read file_en-us.ext, file_en.ext, file.ext - List files = new ArrayList(); - if (!StringUtils.isEmpty(lc)) { - if (!StringUtils.isEmpty(cc)) { - files.add(base + "_" + lc + "-" + cc + ext); - files.add(base + "_" + lc + "_" + cc + ext); - } - files.add(base + "_" + lc + ext); - } - files.add(file); - - for (String name : files) { - String message; - InputStreamReader reader = null; - try { - ContextRelativeResource res = WicketUtils.getResource(name); - InputStream is = res.getResourceStream().getInputStream(); - reader = new InputStreamReader(is, Constants.CHARACTER_ENCODING); - message = MarkdownUtils.transformMarkdown(reader); - reader.close(); - return message; - } catch (ResourceStreamNotFoundException t) { - continue; - } catch (Throwable t) { - message = MessageFormat.format(getString("gb.failedToReadMessage"), file); - error(message, t, false); - return message; - } finally { - if (reader != null) { - try { - reader.close(); - } catch (Exception e) { - } - } - } - } - return MessageFormat.format(getString("gb.failedToReadMessage"), file); - } } diff --git a/src/main/java/com/gitblit/wicket/pages/PushesPage.html b/src/main/java/com/gitblit/wicket/pages/PushesPage.html deleted file mode 100644 index 145db6f5..00000000 --- a/src/main/java/com/gitblit/wicket/pages/PushesPage.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - -
[push log panel]
- - -
- | « | » -
- -
- - \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/PushesPage.java b/src/main/java/com/gitblit/wicket/pages/PushesPage.java deleted file mode 100644 index 866964ac..00000000 --- a/src/main/java/com/gitblit/wicket/pages/PushesPage.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2013 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.gitblit.wicket.pages; - -import org.apache.wicket.PageParameters; -import org.apache.wicket.markup.html.link.BookmarkablePageLink; - -import com.gitblit.wicket.WicketUtils; -import com.gitblit.wicket.panels.PushesPanel; - -public class PushesPage extends RepositoryPage { - - public PushesPage(PageParameters params) { - super(params); - - addSyndicationDiscoveryLink(); - - int pageNumber = WicketUtils.getPage(params); - int prevPage = Math.max(0, pageNumber - 1); - int nextPage = pageNumber + 1; - - PushesPanel pushesPanel = new PushesPanel("pushesPanel", getRepositoryModel(), getRepository(), -1, - pageNumber - 1, false); - boolean hasMore = pushesPanel.hasMore(); - add(pushesPanel); - - add(new BookmarkablePageLink("firstPage", PushesPage.class, - WicketUtils.newObjectParameter(repositoryName, objectId)) - .setEnabled(pageNumber > 1)); - add(new BookmarkablePageLink("prevPage", PushesPage.class, - WicketUtils.newLogPageParameter(repositoryName, objectId, prevPage)) - .setEnabled(pageNumber > 1)); - add(new BookmarkablePageLink("nextPage", PushesPage.class, - WicketUtils.newLogPageParameter(repositoryName, objectId, nextPage)) - .setEnabled(hasMore)); - } - - @Override - protected String getPageName() { - return getString("gb.pushes"); - } -} diff --git a/src/main/java/com/gitblit/wicket/pages/ReflogPage.html b/src/main/java/com/gitblit/wicket/pages/ReflogPage.html new file mode 100644 index 00000000..c0ac7eb7 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ReflogPage.html @@ -0,0 +1,25 @@ + + + + + + + + + + +
[reflog panel]
+ + +
+ | « | » +
+ +
+ + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/ReflogPage.java b/src/main/java/com/gitblit/wicket/pages/ReflogPage.java new file mode 100644 index 00000000..884f6167 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ReflogPage.java @@ -0,0 +1,55 @@ +/* + * Copyright 2013 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.pages; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.markup.html.link.BookmarkablePageLink; + +import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.panels.ReflogPanel; + +public class ReflogPage extends RepositoryPage { + + public ReflogPage(PageParameters params) { + super(params); + + addSyndicationDiscoveryLink(); + + int pageNumber = WicketUtils.getPage(params); + int prevPage = Math.max(0, pageNumber - 1); + int nextPage = pageNumber + 1; + + ReflogPanel reflogPanel = new ReflogPanel("reflogPanel", getRepositoryModel(), getRepository(), -1, + pageNumber - 1); + boolean hasMore = reflogPanel.hasMore(); + add(reflogPanel); + + add(new BookmarkablePageLink("firstPage", ReflogPage.class, + WicketUtils.newObjectParameter(repositoryName, objectId)) + .setEnabled(pageNumber > 1)); + add(new BookmarkablePageLink("prevPage", ReflogPage.class, + WicketUtils.newLogPageParameter(repositoryName, objectId, prevPage)) + .setEnabled(pageNumber > 1)); + add(new BookmarkablePageLink("nextPage", ReflogPage.class, + WicketUtils.newLogPageParameter(repositoryName, objectId, nextPage)) + .setEnabled(hasMore)); + } + + @Override + protected String getPageName() { + return getString("gb.reflog"); + } +} diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java index a15dd91b..96573012 100644 --- a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java @@ -60,7 +60,7 @@ import com.gitblit.models.UserRepositoryPreferences; import com.gitblit.utils.ArrayUtils; import com.gitblit.utils.DeepCopier; import com.gitblit.utils.JGitUtils; -import com.gitblit.utils.PushLogUtils; +import com.gitblit.utils.RefLogUtils; import com.gitblit.utils.StringUtils; import com.gitblit.utils.TicgitUtils; import com.gitblit.wicket.GitBlitWebSession; @@ -187,12 +187,12 @@ public abstract class RepositoryPage extends RootPage { RepositoryModel model = getRepositoryModel(); // standard links - if (PushLogUtils.getPushLogBranch(r) == null) { + if (RefLogUtils.getRefLogBranch(r) == null) { pages.put("summary", new PageRegistration("gb.summary", SummaryPage.class, params)); } else { pages.put("summary", new PageRegistration("gb.summary", SummaryPage.class, params)); // pages.put("overview", new PageRegistration("gb.overview", OverviewPage.class, params)); - pages.put("pushes", new PageRegistration("gb.pushes", PushesPage.class, params)); + pages.put("reflog", new PageRegistration("gb.reflog", ReflogPage.class, params)); } pages.put("commits", new PageRegistration("gb.commits", LogPage.class, params)); pages.put("tree", new PageRegistration("gb.tree", TreePage.class, params)); diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java index d21be366..8c1a5685 100644 --- a/src/main/java/com/gitblit/wicket/pages/RootPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java @@ -119,7 +119,7 @@ public abstract class RootPage extends BasePage { // navigation links List pages = new ArrayList(); if (!authenticateView || (authenticateView && GitBlitWebSession.get().isLoggedIn())) { - pages.add(new PageRegistration(GitBlitWebSession.get().isLoggedIn() ? "gb.myDashboard" : "gb.dashboard", DashboardPage.class, + pages.add(new PageRegistration(GitBlitWebSession.get().isLoggedIn() ? "gb.myDashboard" : "gb.dashboard", MyDashboardPage.class, getRootPageParameters())); pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class, getRootPageParameters())); diff --git a/src/main/java/com/gitblit/wicket/panels/DigestsPanel.html b/src/main/java/com/gitblit/wicket/panels/DigestsPanel.html new file mode 100644 index 00000000..53a81042 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/DigestsPanel.html @@ -0,0 +1,42 @@ + + + + + +
+
+ + + + + + + + +
+
+ +
+
[who changed]
+
+
+ + + + + + + +
[hash link] + [commit short message] +
+ +
+
+
+ + + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/DigestsPanel.java b/src/main/java/com/gitblit/wicket/panels/DigestsPanel.java new file mode 100644 index 00000000..0f380a49 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/DigestsPanel.java @@ -0,0 +1,273 @@ +/* + * Copyright 2013 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.panels; + +import java.text.DateFormat; +import java.text.MessageFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; + +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.markup.repeater.data.DataView; +import org.apache.wicket.markup.repeater.data.ListDataProvider; + +import com.gitblit.Constants; +import com.gitblit.GitBlit; +import com.gitblit.Keys; +import com.gitblit.models.DailyLogEntry; +import com.gitblit.models.RepositoryCommit; +import com.gitblit.utils.StringUtils; +import com.gitblit.utils.TimeUtils; +import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.pages.CommitPage; +import com.gitblit.wicket.pages.ComparePage; +import com.gitblit.wicket.pages.SummaryPage; +import com.gitblit.wicket.pages.TagPage; +import com.gitblit.wicket.pages.TreePage; +import com.gitblit.wicket.pages.UserPage; + +public class DigestsPanel extends BasePanel { + + private static final long serialVersionUID = 1L; + + private final boolean hasChanges; + + private boolean hasMore; + + public DigestsPanel(String wicketId, List digests) { + super(wicketId); + hasChanges = digests.size() > 0; + + final int hashLen = GitBlit.getInteger(Keys.web.shortCommitIdLength, 6); + + String dateFormat = GitBlit.getString(Keys.web.datestampLongFormat, "EEEE, MMMM d, yyyy"); + final TimeZone timezone = getTimeZone(); + final DateFormat df = new SimpleDateFormat(dateFormat); + df.setTimeZone(timezone); + final Calendar cal = Calendar.getInstance(timezone); + + ListDataProvider dp = new ListDataProvider(digests); + DataView pushView = new DataView("change", dp) { + private static final long serialVersionUID = 1L; + + public void populateItem(final Item logItem) { + final DailyLogEntry change = logItem.getModelObject(); + String fullRefName = change.getChangedRefs().get(0); + String shortRefName = fullRefName; + boolean isTag = false; + if (shortRefName.startsWith(Constants.R_HEADS)) { + shortRefName = shortRefName.substring(Constants.R_HEADS.length()); + } else if (shortRefName.startsWith(Constants.R_TAGS)) { + shortRefName = shortRefName.substring(Constants.R_TAGS.length()); + isTag = true; + } + + String fuzzydate; + TimeUtils tu = getTimeUtils(); + Date pushDate = change.date; + if (TimeUtils.isToday(pushDate, timezone)) { + fuzzydate = tu.today(); + } else if (TimeUtils.isYesterday(pushDate, timezone)) { + fuzzydate = tu.yesterday(); + } else { + // calculate a fuzzy time ago date + cal.setTime(pushDate); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + pushDate = cal.getTime(); + fuzzydate = getTimeUtils().timeAgo(pushDate); + } + logItem.add(new Label("whenChanged", fuzzydate + ", " + df.format(pushDate))); + + Label changeIcon = new Label("changeIcon"); + // use the repository hash color to differentiate the icon. + String color = StringUtils.getColor(StringUtils.stripDotGit(change.repository)); + WicketUtils.setCssStyle(changeIcon, "color: " + color); + + if (isTag) { + WicketUtils.setCssClass(changeIcon, "iconic-tag"); + } else { + WicketUtils.setCssClass(changeIcon, "iconic-loop"); + } + logItem.add(changeIcon); + + if (!isTag) { + logItem.add(new Label("whoChanged").setVisible(false)); + } else { + if (change.user.username.equals(change.user.emailAddress) && change.user.emailAddress.indexOf('@') > -1) { + // username is an email address can not link - 1.2.1 push log bug + logItem.add(new Label("whoChanged", change.user.getDisplayName())); + } else { + // link to user account page + logItem.add(new LinkPanel("whoChanged", null, change.user.getDisplayName(), + UserPage.class, WicketUtils.newUsernameParameter(change.user.username))); + } + } + + String preposition = "gb.of"; + boolean isDelete = false; + String what; + String by = null; + switch(change.getChangeType(fullRefName)) { + case CREATE: + if (isTag) { + // new tag + what = getString("gb.createdNewTag"); + preposition = "gb.in"; + } else { + // new branch + what = getString("gb.createdNewBranch"); + preposition = "gb.in"; + } + break; + case DELETE: + isDelete = true; + if (isTag) { + what = getString("gb.deletedTag"); + } else { + what = getString("gb.deletedBranch"); + } + preposition = "gb.from"; + break; + default: + what = MessageFormat.format(change.getCommitCount() > 1 ? getString("gb.commitsTo") : getString("gb.oneCommitTo"), change.getCommitCount()); + + if (change.getAuthorCount() == 1) { + by = MessageFormat.format(getString("gb.byOneAuthor"), change.getAuthorIdent().getName()); + } else { + by = MessageFormat.format(getString("gb.byNAuthors"), change.getAuthorCount()); + } + break; + } + logItem.add(new Label("whatChanged", what)); + logItem.add(new Label("byAuthors", by).setVisible(!StringUtils.isEmpty(by))); + + if (isDelete) { + // can't link to deleted ref + logItem.add(new Label("refChanged", shortRefName)); + } else if (isTag) { + // link to tag + logItem.add(new LinkPanel("refChanged", null, shortRefName, + TagPage.class, WicketUtils.newObjectParameter(change.repository, fullRefName))); + } else { + // link to tree + logItem.add(new LinkPanel("refChanged", null, shortRefName, + TreePage.class, WicketUtils.newObjectParameter(change.repository, fullRefName))); + } + + // to/from/etc + logItem.add(new Label("repoPreposition", getString(preposition))); + String repoName = StringUtils.stripDotGit(change.repository); + logItem.add(new LinkPanel("repoChanged", null, repoName, + SummaryPage.class, WicketUtils.newRepositoryParameter(change.repository))); + + int maxCommitCount = 5; + List commits = change.getCommits(); + if (commits.size() > maxCommitCount) { + commits = new ArrayList(commits.subList(0, maxCommitCount)); + } + + // compare link + String compareLinkText = null; + if ((change.getCommitCount() <= maxCommitCount) && (change.getCommitCount() > 1)) { + compareLinkText = MessageFormat.format(getString("gb.viewComparison"), commits.size()); + } else if (change.getCommitCount() > maxCommitCount) { + int diff = change.getCommitCount() - maxCommitCount; + compareLinkText = MessageFormat.format(diff > 1 ? getString("gb.nMoreCommits") : getString("gb.oneMoreCommit"), diff); + } + if (StringUtils.isEmpty(compareLinkText)) { + logItem.add(new Label("compareLink").setVisible(false)); + } else { + String endRangeId = change.getNewId(fullRefName); + String startRangeId = change.getOldId(fullRefName); + logItem.add(new LinkPanel("compareLink", null, compareLinkText, ComparePage.class, WicketUtils.newRangeParameter(change.repository, startRangeId, endRangeId))); + } + + final boolean showSwatch = GitBlit.getBoolean(Keys.web.repositoryListSwatches, true); + + ListDataProvider cdp = new ListDataProvider(commits); + DataView commitsView = new DataView("commit", cdp) { + private static final long serialVersionUID = 1L; + + public void populateItem(final Item commitItem) { + final RepositoryCommit commit = commitItem.getModelObject(); + + // author gravatar + commitItem.add(new GravatarImage("commitAuthor", commit.getAuthorIdent().getName(), + commit.getAuthorIdent().getEmailAddress(), null, 16, false, false)); + + // merge icon + if (commit.getParentCount() > 1) { + commitItem.add(WicketUtils.newImage("commitIcon", "commit_merge_16x16.png")); + } else { + commitItem.add(WicketUtils.newBlankImage("commitIcon")); + } + + // short message + String shortMessage = commit.getShortMessage(); + String trimmedMessage = shortMessage; + if (commit.getRefs() != null && commit.getRefs().size() > 0) { + trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG_REFS); + } else { + trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG); + } + LinkPanel shortlog = new LinkPanel("commitShortMessage", "list", + trimmedMessage, CommitPage.class, WicketUtils.newObjectParameter( + change.repository, commit.getName())); + if (!shortMessage.equals(trimmedMessage)) { + WicketUtils.setHtmlTooltip(shortlog, shortMessage); + } + commitItem.add(shortlog); + + // commit hash link + LinkPanel commitHash = new LinkPanel("hashLink", null, commit.getName().substring(0, hashLen), + CommitPage.class, WicketUtils.newObjectParameter( + change.repository, commit.getName())); + WicketUtils.setCssClass(commitHash, "shortsha1"); + WicketUtils.setHtmlTooltip(commitHash, commit.getName()); + commitItem.add(commitHash); + + if (showSwatch) { + // set repository color + String color = StringUtils.getColor(StringUtils.stripDotGit(change.repository)); + WicketUtils.setCssStyle(commitItem, MessageFormat.format("border-left: 2px solid {0};", color)); + } + } + }; + + logItem.add(commitsView); + } + }; + + add(pushView); + } + + public boolean hasMore() { + return hasMore; + } + + public boolean hideIfEmpty() { + setVisible(hasChanges); + return hasChanges; + } +} diff --git a/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html index e9196cda..02d67e30 100644 --- a/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html +++ b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html @@ -70,8 +70,6 @@ [last change] [last change], [repository size]
- -
[repository primary url]
diff --git a/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java index e7fe017e..37641d39 100644 --- a/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java +++ b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java @@ -192,7 +192,5 @@ public class ProjectRepositoryPanel extends BasePanel { } add(new ExternalLink("syndication", SyndicationServlet.asLink("", entry.name, null, 0))); - - add(new RepositoryUrlPanel("repositoryPrimaryUrl", true, user, entry)); } } diff --git a/src/main/java/com/gitblit/wicket/panels/PushesPanel.html b/src/main/java/com/gitblit/wicket/panels/PushesPanel.html deleted file mode 100644 index fb67cfc1..00000000 --- a/src/main/java/com/gitblit/wicket/panels/PushesPanel.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - -
- - - - - - - - - -
-
- [rewind] -
-
[pusher]
-
-
- - - - - - - -
[hash link] - [commit short message] -
- -
-
-
-
[more...]
-
- - \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/PushesPanel.java b/src/main/java/com/gitblit/wicket/panels/PushesPanel.java deleted file mode 100644 index 5c473f75..00000000 --- a/src/main/java/com/gitblit/wicket/panels/PushesPanel.java +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Copyright 2013 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.gitblit.wicket.panels; - -import java.text.DateFormat; -import java.text.MessageFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.TimeZone; - -import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.repeater.Item; -import org.apache.wicket.markup.repeater.data.DataView; -import org.apache.wicket.markup.repeater.data.ListDataProvider; -import org.apache.wicket.model.StringResourceModel; -import org.eclipse.jgit.lib.Repository; - -import com.gitblit.Constants; -import com.gitblit.GitBlit; -import com.gitblit.Keys; -import com.gitblit.models.DailyLogEntry; -import com.gitblit.models.PushLogEntry; -import com.gitblit.models.RepositoryCommit; -import com.gitblit.models.RepositoryModel; -import com.gitblit.utils.PushLogUtils; -import com.gitblit.utils.StringUtils; -import com.gitblit.utils.TimeUtils; -import com.gitblit.wicket.WicketUtils; -import com.gitblit.wicket.pages.CommitPage; -import com.gitblit.wicket.pages.ComparePage; -import com.gitblit.wicket.pages.PushesPage; -import com.gitblit.wicket.pages.SummaryPage; -import com.gitblit.wicket.pages.TagPage; -import com.gitblit.wicket.pages.TreePage; -import com.gitblit.wicket.pages.UserPage; - -public class PushesPanel extends BasePanel { - - private static final long serialVersionUID = 1L; - - private final boolean hasPushes; - - private boolean hasMore; - - public PushesPanel(String wicketId, final RepositoryModel model, Repository r, int limit, int pageOffset, boolean showRepo) { - super(wicketId); - boolean pageResults = limit <= 0; - int pushesPerPage = GitBlit.getInteger(Keys.web.pushesPerPage, 10); - if (pushesPerPage <= 1) { - pushesPerPage = 10; - } - - List pushes; - if (pageResults) { - pushes = PushLogUtils.getPushLogByRef(model.name, r, pageOffset * pushesPerPage, pushesPerPage); - } else { - pushes = PushLogUtils.getPushLogByRef(model.name, r, limit); - } - - // inaccurate way to determine if there are more commits. - // works unless commits.size() represents the exact end. - hasMore = pushes.size() >= pushesPerPage; - hasPushes = pushes.size() > 0; - - setup(pushes, showRepo); - - // determine to show pager, more, or neither - if (limit <= 0) { - // no display limit - add(new Label("morePushes").setVisible(false)); - } else { - if (pageResults) { - // paging - add(new Label("morePushes").setVisible(false)); - } else { - // more - if (pushes.size() == limit) { - // show more - add(new LinkPanel("morePushes", "link", new StringResourceModel("gb.morePushes", - this, null), PushesPage.class, - WicketUtils.newRepositoryParameter(model.name))); - } else { - // no more - add(new Label("morePushes").setVisible(false)); - } - } - } - } - - public PushesPanel(String wicketId, List pushes) { - super(wicketId); - hasPushes = pushes.size() > 0; - setup(pushes, true); - add(new Label("morePushes").setVisible(false)); - } - - protected void setup(List pushes, final boolean showRepo) { - final int hashLen = GitBlit.getInteger(Keys.web.shortCommitIdLength, 6); - - String dateFormat = GitBlit.getString(Keys.web.datestampLongFormat, "EEEE, MMMM d, yyyy"); - final TimeZone timezone = getTimeZone(); - final DateFormat df = new SimpleDateFormat(dateFormat); - df.setTimeZone(timezone); - final Calendar cal = Calendar.getInstance(timezone); - - ListDataProvider dp = new ListDataProvider(pushes); - DataView pushView = new DataView("push", dp) { - private static final long serialVersionUID = 1L; - - public void populateItem(final Item pushItem) { - final PushLogEntry push = pushItem.getModelObject(); - String fullRefName = push.getChangedRefs().get(0); - String shortRefName = fullRefName; - boolean isTag = false; - boolean isPull = false; - if (shortRefName.startsWith(Constants.R_HEADS)) { - shortRefName = shortRefName.substring(Constants.R_HEADS.length()); - } else if (shortRefName.startsWith(Constants.R_TAGS)) { - shortRefName = shortRefName.substring(Constants.R_TAGS.length()); - isTag = true; - } else if (shortRefName.startsWith(Constants.R_PULL)) { - shortRefName = "#" + shortRefName.substring(Constants.R_PULL.length()); - if (shortRefName.endsWith("/head")) { - // strip pull request head from name - shortRefName = shortRefName.substring(0, shortRefName.length() - "/head".length()); - } - isPull = true; - } - boolean isDigest = push instanceof DailyLogEntry; - - String fuzzydate; - TimeUtils tu = getTimeUtils(); - Date pushDate = push.date; - if (TimeUtils.isToday(pushDate, timezone)) { - fuzzydate = tu.today(); - } else if (TimeUtils.isYesterday(pushDate, timezone)) { - fuzzydate = tu.yesterday(); - } else { - // calculate a fuzzy time ago date - cal.setTime(pushDate); - cal.set(Calendar.HOUR_OF_DAY, 0); - cal.set(Calendar.MINUTE, 0); - cal.set(Calendar.SECOND, 0); - cal.set(Calendar.MILLISECOND, 0); - pushDate = cal.getTime(); - fuzzydate = getTimeUtils().timeAgo(pushDate); - } - pushItem.add(new Label("whenPushed", fuzzydate + ", " + df.format(pushDate))); - - Label pushIcon = new Label("pushIcon"); - if (showRepo) { - // if we are showing the repo, we are showing multiple - // repos. use the repository hash color to differentiate - // the icon. - String color = StringUtils.getColor(StringUtils.stripDotGit(push.repository)); - WicketUtils.setCssStyle(pushIcon, "color: " + color); - } - if (isTag) { - WicketUtils.setCssClass(pushIcon, "iconic-tag"); - } else if (isPull) { - WicketUtils.setCssClass(pushIcon, "iconic-share"); - } else if (isDigest) { - WicketUtils.setCssClass(pushIcon, "iconic-loop"); - } else { - WicketUtils.setCssClass(pushIcon, "iconic-upload"); - } - pushItem.add(pushIcon); - - if (isDigest && !isTag) { - pushItem.add(new Label("whoPushed").setVisible(false)); - } else { - if (push.user.username.equals(push.user.emailAddress) && push.user.emailAddress.indexOf('@') > -1) { - // username is an email address - 1.2.1 push log bug - pushItem.add(new Label("whoPushed", push.user.getDisplayName())); - } else { - // link to user account page - pushItem.add(new LinkPanel("whoPushed", null, push.user.getDisplayName(), - UserPage.class, WicketUtils.newUsernameParameter(push.user.username))); - } - } - - String preposition = "gb.of"; - boolean isDelete = false; - boolean isRewind = false; - String what; - String by = null; - switch(push.getChangeType(fullRefName)) { - case CREATE: - if (isTag) { - // new tag - if (isDigest) { - what = getString("gb.createdNewTag"); - preposition = "gb.in"; - } else { - what = getString("gb.pushedNewTag"); - preposition = "gb.to"; - } - } else if (isPull) { - // merged pull request - what = getString("gb.mergedPullRequest"); - preposition = "gb.in"; - } else { - // new branch - if (isDigest) { - what = getString("gb.createdNewBranch"); - preposition = "gb.in"; - } else { - what = getString("gb.pushedNewBranch"); - preposition = "gb.to"; - } - } - break; - case DELETE: - isDelete = true; - if (isTag) { - what = getString("gb.deletedTag"); - } if (isPull) { - what = getString("gb.deletedTag"); - } else { - what = getString("gb.deletedBranch"); - } - preposition = "gb.from"; - break; - case UPDATE_NONFASTFORWARD: - isRewind = true; - default: - if (isDigest) { - what = MessageFormat.format(push.getCommitCount() > 1 ? getString("gb.commitsTo") : getString("gb.oneCommitTo"), push.getCommitCount()); - } else { - what = MessageFormat.format(push.getCommitCount() > 1 ? getString("gb.pushedNCommitsTo") : getString("gb.pushedOneCommitTo") , push.getCommitCount()); - } - - if (push.getAuthorCount() == 1) { - by = MessageFormat.format(getString("gb.byOneAuthor"), push.getAuthorIdent().getName()); - } else { - by = MessageFormat.format(getString("gb.byNAuthors"), push.getAuthorCount()); - } - break; - } - pushItem.add(new Label("whatPushed", what)); - pushItem.add(new Label("byAuthors", by).setVisible(!StringUtils.isEmpty(by))); - - pushItem.add(new Label("refRewind", getString("gb.rewind")).setVisible(isRewind)); - - if (isDelete) { - // can't link to deleted ref - pushItem.add(new Label("refPushed", shortRefName)); - } else if (isTag) { - // link to tag - pushItem.add(new LinkPanel("refPushed", null, shortRefName, - TagPage.class, WicketUtils.newObjectParameter(push.repository, fullRefName))); - } else if (isPull) { - // link to pull request - pushItem.add(new LinkPanel("refPushed", null, shortRefName, - TagPage.class, WicketUtils.newObjectParameter(push.repository, fullRefName))); - } else { - // link to tree - pushItem.add(new LinkPanel("refPushed", null, shortRefName, - TreePage.class, WicketUtils.newObjectParameter(push.repository, fullRefName))); - } - - if (showRepo) { - // to/from/etc - pushItem.add(new Label("repoPreposition", getString(preposition))); - - String repoName = StringUtils.stripDotGit(push.repository); - pushItem.add(new LinkPanel("repoPushed", null, repoName, - SummaryPage.class, WicketUtils.newRepositoryParameter(push.repository))); - } else { - // do not display repository name if we are viewing the push - // log of a repository. - pushItem.add(new Label("repoPreposition").setVisible(false)); - pushItem.add(new Label("repoPushed").setVisible(false)); - } - - int maxCommitCount = 5; - List commits = push.getCommits(); - if (commits.size() > maxCommitCount) { - commits = new ArrayList(commits.subList(0, maxCommitCount)); - } - - // compare link - String compareLinkText = null; - if ((push.getCommitCount() <= maxCommitCount) && (push.getCommitCount() > 1)) { - compareLinkText = MessageFormat.format(getString("gb.viewComparison"), commits.size()); - } else if (push.getCommitCount() > maxCommitCount) { - int diff = push.getCommitCount() - maxCommitCount; - compareLinkText = MessageFormat.format(diff > 1 ? getString("gb.nMoreCommits") : getString("gb.oneMoreCommit"), diff); - } - if (StringUtils.isEmpty(compareLinkText)) { - pushItem.add(new Label("compareLink").setVisible(false)); - } else { - String endRangeId = push.getNewId(fullRefName); - String startRangeId = push.getOldId(fullRefName); - pushItem.add(new LinkPanel("compareLink", null, compareLinkText, ComparePage.class, WicketUtils.newRangeParameter(push.repository, startRangeId, endRangeId))); - } - - final boolean showSwatch = showRepo && GitBlit.getBoolean(Keys.web.repositoryListSwatches, true); - - ListDataProvider cdp = new ListDataProvider(commits); - DataView commitsView = new DataView("commit", cdp) { - private static final long serialVersionUID = 1L; - - public void populateItem(final Item commitItem) { - final RepositoryCommit commit = commitItem.getModelObject(); - - // author gravatar - commitItem.add(new GravatarImage("commitAuthor", commit.getAuthorIdent().getName(), - commit.getAuthorIdent().getEmailAddress(), null, 16, false, false)); - - // merge icon - if (commit.getParentCount() > 1) { - commitItem.add(WicketUtils.newImage("commitIcon", "commit_merge_16x16.png")); - } else { - commitItem.add(WicketUtils.newBlankImage("commitIcon")); - } - - // short message - String shortMessage = commit.getShortMessage(); - String trimmedMessage = shortMessage; - if (commit.getRefs() != null && commit.getRefs().size() > 0) { - trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG_REFS); - } else { - trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG); - } - LinkPanel shortlog = new LinkPanel("commitShortMessage", "list", - trimmedMessage, CommitPage.class, WicketUtils.newObjectParameter( - push.repository, commit.getName())); - if (!shortMessage.equals(trimmedMessage)) { - WicketUtils.setHtmlTooltip(shortlog, shortMessage); - } - commitItem.add(shortlog); - - // commit hash link - LinkPanel commitHash = new LinkPanel("hashLink", null, commit.getName().substring(0, hashLen), - CommitPage.class, WicketUtils.newObjectParameter( - push.repository, commit.getName())); - WicketUtils.setCssClass(commitHash, "shortsha1"); - WicketUtils.setHtmlTooltip(commitHash, commit.getName()); - commitItem.add(commitHash); - - if (showSwatch) { - // set repository color - String color = StringUtils.getColor(StringUtils.stripDotGit(push.repository)); - WicketUtils.setCssStyle(commitItem, MessageFormat.format("border-left: 2px solid {0};", color)); - } - } - }; - - pushItem.add(commitsView); - } - }; - - add(pushView); - } - - public boolean hasMore() { - return hasMore; - } - - public boolean hideIfEmpty() { - setVisible(hasPushes); - return hasPushes; - } -} diff --git a/src/main/java/com/gitblit/wicket/panels/ReflogPanel.html b/src/main/java/com/gitblit/wicket/panels/ReflogPanel.html new file mode 100644 index 00000000..0148d898 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/ReflogPanel.html @@ -0,0 +1,43 @@ + + + + + +
+ + + + + + + + + +
+
+ [rewind] +
+
[change author]
+
+
+ + + + + + + +
[hash link] + [commit short message] +
+ +
+
+
+
[more...]
+
+ + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/ReflogPanel.java b/src/main/java/com/gitblit/wicket/panels/ReflogPanel.java new file mode 100644 index 00000000..048ce1b0 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/ReflogPanel.java @@ -0,0 +1,305 @@ +/* + * Copyright 2013 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.panels; + +import java.text.DateFormat; +import java.text.MessageFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; + +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.markup.repeater.data.DataView; +import org.apache.wicket.markup.repeater.data.ListDataProvider; +import org.apache.wicket.model.StringResourceModel; +import org.eclipse.jgit.lib.Repository; + +import com.gitblit.Constants; +import com.gitblit.GitBlit; +import com.gitblit.Keys; +import com.gitblit.models.RefLogEntry; +import com.gitblit.models.RepositoryCommit; +import com.gitblit.models.RepositoryModel; +import com.gitblit.utils.RefLogUtils; +import com.gitblit.utils.StringUtils; +import com.gitblit.utils.TimeUtils; +import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.pages.CommitPage; +import com.gitblit.wicket.pages.ComparePage; +import com.gitblit.wicket.pages.ReflogPage; +import com.gitblit.wicket.pages.TagPage; +import com.gitblit.wicket.pages.TreePage; +import com.gitblit.wicket.pages.UserPage; + +public class ReflogPanel extends BasePanel { + + private static final long serialVersionUID = 1L; + + private final boolean hasChanges; + + private boolean hasMore; + + public ReflogPanel(String wicketId, final RepositoryModel model, Repository r, int limit, int pageOffset) { + super(wicketId); + boolean pageResults = limit <= 0; + int changesPerPage = GitBlit.getInteger(Keys.web.reflogChangesPerPage, 10); + if (changesPerPage <= 1) { + changesPerPage = 10; + } + + List changes; + if (pageResults) { + changes = RefLogUtils.getLogByRef(model.name, r, pageOffset * changesPerPage, changesPerPage); + } else { + changes = RefLogUtils.getLogByRef(model.name, r, limit); + } + + // inaccurate way to determine if there are more commits. + // works unless commits.size() represents the exact end. + hasMore = changes.size() >= changesPerPage; + hasChanges = changes.size() > 0; + + setup(changes); + + // determine to show pager, more, or neither + if (limit <= 0) { + // no display limit + add(new Label("moreChanges").setVisible(false)); + } else { + if (pageResults) { + // paging + add(new Label("moreChanges").setVisible(false)); + } else { + // more + if (changes.size() == limit) { + // show more + add(new LinkPanel("moreChanges", "link", new StringResourceModel("gb.moreChanges", + this, null), ReflogPage.class, + WicketUtils.newRepositoryParameter(model.name))); + } else { + // no more + add(new Label("moreChanges").setVisible(false)); + } + } + } + } + + public ReflogPanel(String wicketId, List changes) { + super(wicketId); + hasChanges = changes.size() > 0; + setup(changes); + add(new Label("moreChanges").setVisible(false)); + } + + protected void setup(List changes) { + final int hashLen = GitBlit.getInteger(Keys.web.shortCommitIdLength, 6); + + String dateFormat = GitBlit.getString(Keys.web.datestampLongFormat, "EEEE, MMMM d, yyyy"); + final TimeZone timezone = getTimeZone(); + final DateFormat df = new SimpleDateFormat(dateFormat); + df.setTimeZone(timezone); + final Calendar cal = Calendar.getInstance(timezone); + + ListDataProvider dp = new ListDataProvider(changes); + DataView changeView = new DataView("change", dp) { + private static final long serialVersionUID = 1L; + + public void populateItem(final Item changeItem) { + final RefLogEntry change = changeItem.getModelObject(); + String fullRefName = change.getChangedRefs().get(0); + String shortRefName = fullRefName; + boolean isTag = false; + if (shortRefName.startsWith(Constants.R_HEADS)) { + shortRefName = shortRefName.substring(Constants.R_HEADS.length()); + } else if (shortRefName.startsWith(Constants.R_TAGS)) { + shortRefName = shortRefName.substring(Constants.R_TAGS.length()); + isTag = true; + } + + String fuzzydate; + TimeUtils tu = getTimeUtils(); + Date changeDate = change.date; + if (TimeUtils.isToday(changeDate, timezone)) { + fuzzydate = tu.today(); + } else if (TimeUtils.isYesterday(changeDate, timezone)) { + fuzzydate = tu.yesterday(); + } else { + // calculate a fuzzy time ago date + cal.setTime(changeDate); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + changeDate = cal.getTime(); + fuzzydate = getTimeUtils().timeAgo(changeDate); + } + changeItem.add(new Label("whenChanged", fuzzydate + ", " + df.format(changeDate))); + + Label changeIcon = new Label("changeIcon"); + if (isTag) { + WicketUtils.setCssClass(changeIcon, "iconic-tag"); + } else { + WicketUtils.setCssClass(changeIcon, "iconic-upload"); + } + changeItem.add(changeIcon); + + if (change.user.username.equals(change.user.emailAddress) && change.user.emailAddress.indexOf('@') > -1) { + // username is an email address - 1.2.1 push log bug + changeItem.add(new Label("whoChanged", change.user.getDisplayName())); + } else { + // link to user account page + changeItem.add(new LinkPanel("whoChanged", null, change.user.getDisplayName(), + UserPage.class, WicketUtils.newUsernameParameter(change.user.username))); + } + + boolean isDelete = false; + boolean isRewind = false; + String what; + String by = null; + switch(change.getChangeType(fullRefName)) { + case CREATE: + if (isTag) { + // new tag + what = getString("gb.pushedNewTag"); + } else { + // new branch + what = getString("gb.pushedNewBranch"); + } + break; + case DELETE: + isDelete = true; + if (isTag) { + what = getString("gb.deletedTag"); + } else { + what = getString("gb.deletedBranch"); + } + break; + case UPDATE_NONFASTFORWARD: + isRewind = true; + default: + what = MessageFormat.format(change.getCommitCount() > 1 ? getString("gb.pushedNCommitsTo") : getString("gb.pushedOneCommitTo") , change.getCommitCount()); + + if (change.getAuthorCount() == 1) { + by = MessageFormat.format(getString("gb.byOneAuthor"), change.getAuthorIdent().getName()); + } else { + by = MessageFormat.format(getString("gb.byNAuthors"), change.getAuthorCount()); + } + break; + } + changeItem.add(new Label("whatChanged", what)); + changeItem.add(new Label("byAuthors", by).setVisible(!StringUtils.isEmpty(by))); + + changeItem.add(new Label("refRewind", getString("gb.rewind")).setVisible(isRewind)); + + if (isDelete) { + // can't link to deleted ref + changeItem.add(new Label("refChanged", shortRefName)); + } else if (isTag) { + // link to tag + changeItem.add(new LinkPanel("refChanged", null, shortRefName, + TagPage.class, WicketUtils.newObjectParameter(change.repository, fullRefName))); + } else { + // link to tree + changeItem.add(new LinkPanel("refChanged", null, shortRefName, + TreePage.class, WicketUtils.newObjectParameter(change.repository, fullRefName))); + } + + int maxCommitCount = 5; + List commits = change.getCommits(); + if (commits.size() > maxCommitCount) { + commits = new ArrayList(commits.subList(0, maxCommitCount)); + } + + // compare link + String compareLinkText = null; + if ((change.getCommitCount() <= maxCommitCount) && (change.getCommitCount() > 1)) { + compareLinkText = MessageFormat.format(getString("gb.viewComparison"), commits.size()); + } else if (change.getCommitCount() > maxCommitCount) { + int diff = change.getCommitCount() - maxCommitCount; + compareLinkText = MessageFormat.format(diff > 1 ? getString("gb.nMoreCommits") : getString("gb.oneMoreCommit"), diff); + } + if (StringUtils.isEmpty(compareLinkText)) { + changeItem.add(new Label("compareLink").setVisible(false)); + } else { + String endRangeId = change.getNewId(fullRefName); + String startRangeId = change.getOldId(fullRefName); + changeItem.add(new LinkPanel("compareLink", null, compareLinkText, ComparePage.class, WicketUtils.newRangeParameter(change.repository, startRangeId, endRangeId))); + } + + ListDataProvider cdp = new ListDataProvider(commits); + DataView commitsView = new DataView("commit", cdp) { + private static final long serialVersionUID = 1L; + + public void populateItem(final Item commitItem) { + final RepositoryCommit commit = commitItem.getModelObject(); + + // author gravatar + commitItem.add(new GravatarImage("commitAuthor", commit.getAuthorIdent().getName(), + commit.getAuthorIdent().getEmailAddress(), null, 16, false, false)); + + // merge icon + if (commit.getParentCount() > 1) { + commitItem.add(WicketUtils.newImage("commitIcon", "commit_merge_16x16.png")); + } else { + commitItem.add(WicketUtils.newBlankImage("commitIcon")); + } + + // short message + String shortMessage = commit.getShortMessage(); + String trimmedMessage = shortMessage; + if (commit.getRefs() != null && commit.getRefs().size() > 0) { + trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG_REFS); + } else { + trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG); + } + LinkPanel shortlog = new LinkPanel("commitShortMessage", "list", + trimmedMessage, CommitPage.class, WicketUtils.newObjectParameter( + change.repository, commit.getName())); + if (!shortMessage.equals(trimmedMessage)) { + WicketUtils.setHtmlTooltip(shortlog, shortMessage); + } + commitItem.add(shortlog); + + // commit hash link + LinkPanel commitHash = new LinkPanel("hashLink", null, commit.getName().substring(0, hashLen), + CommitPage.class, WicketUtils.newObjectParameter( + change.repository, commit.getName())); + WicketUtils.setCssClass(commitHash, "shortsha1"); + WicketUtils.setHtmlTooltip(commitHash, commit.getName()); + commitItem.add(commitHash); + } + }; + + changeItem.add(commitsView); + } + }; + + add(changeView); + } + + public boolean hasMore() { + return hasMore; + } + + public boolean hideIfEmpty() { + setVisible(hasChanges); + return hasChanges; + } +} -- cgit v1.2.3