From fabe060d3a435f116128851f828e35c2af5fde67 Mon Sep 17 00:00:00 2001 From: James Moger <james.moger@gitblit.com> Date: Mon, 10 Sep 2012 16:26:27 -0400 Subject: [PATCH] Strip folder name and .git from repo links in the project view --- src/com/gitblit/wicket/pages/RepositoryPage.java | 372 ++++++++++++++++++++++++++++++++-------------------- 1 files changed, 227 insertions(+), 145 deletions(-) diff --git a/src/com/gitblit/wicket/pages/RepositoryPage.java b/src/com/gitblit/wicket/pages/RepositoryPage.java index 22d3323..7e21911 100644 --- a/src/com/gitblit/wicket/pages/RepositoryPage.java +++ b/src/com/gitblit/wicket/pages/RepositoryPage.java @@ -20,132 +20,90 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; 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.markup.html.basic.Label; import org.apache.wicket.markup.html.form.DropDownChoice; -import org.apache.wicket.markup.html.form.StatelessForm; import org.apache.wicket.markup.html.form.TextField; -import org.apache.wicket.markup.html.link.BookmarkablePageLink; import org.apache.wicket.markup.html.link.ExternalLink; import org.apache.wicket.markup.html.panel.Fragment; -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.IModel; import org.apache.wicket.model.Model; +import org.apache.wicket.protocol.http.RequestUtils; +import org.apache.wicket.request.target.basic.RedirectRequestTarget; import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; +import com.gitblit.Constants; import com.gitblit.GitBlit; import com.gitblit.Keys; +import com.gitblit.PagesServlet; import com.gitblit.SyndicationServlet; import com.gitblit.models.RepositoryModel; +import com.gitblit.models.SubmoduleModel; +import com.gitblit.utils.ArrayUtils; import com.gitblit.utils.JGitUtils; -import com.gitblit.utils.JGitUtils.SearchType; import com.gitblit.utils.StringUtils; import com.gitblit.utils.TicgitUtils; import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.PageRegistration; +import com.gitblit.wicket.PageRegistration.OtherPageLink; +import com.gitblit.wicket.SessionlessForm; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.panels.LinkPanel; +import com.gitblit.wicket.panels.NavigationPanel; import com.gitblit.wicket.panels.RefsPanel; public abstract class RepositoryPage extends BasePage { + protected final String projectName; protected final String repositoryName; protected final String objectId; - + private transient Repository r; private RepositoryModel m; - private final Map<String, PageRegistration> registeredPages = new HashMap<String, PageRegistration>() { - - private static final long serialVersionUID = 1L; - - { - put("summary", new PageRegistration("gb.summary", SummaryPage.class)); - put("log", new PageRegistration("gb.log", LogPage.class)); - put("branches", new PageRegistration("gb.branches", BranchesPage.class)); - put("tags", new PageRegistration("gb.tags", TagsPage.class)); - put("tree", new PageRegistration("gb.tree", TreePage.class)); - put("tickets", new PageRegistration("gb.tickets", TicketsPage.class)); - put("edit", new PageRegistration("gb.edit", EditRepositoryPage.class)); - put("docs", new PageRegistration("gb.docs", DocsPage.class)); - } - }; + private Map<String, SubmoduleModel> submodules; + + private final Map<String, PageRegistration> registeredPages; public RepositoryPage(PageParameters params) { super(params); repositoryName = WicketUtils.getRepositoryName(params); + if (repositoryName.indexOf('/') > -1) { + projectName = repositoryName.substring(0, repositoryName.indexOf('/')); + } else { + projectName = GitBlit.getString(Keys.web.repositoryRootGroupName, "main"); + } objectId = WicketUtils.getObject(params); - + if (StringUtils.isEmpty(repositoryName)) { - error(MessageFormat.format("Repository not specified for {0}!", getPageName()), true); + error(MessageFormat.format(getString("gb.repositoryNotSpecifiedFor"), getPageName()), true); } - Repository r = getRepository(); - RepositoryModel model = getRepositoryModel(); + if (!getRepositoryModel().hasCommits) { + setResponsePage(EmptyRepositoryPage.class, params); + } + + // register the available page links for this page and user + registeredPages = registerPages(); // standard page links - addRegisteredPageLink("summary"); - addRegisteredPageLink("log"); - addRegisteredPageLink("branches"); - addRegisteredPageLink("tags"); - addRegisteredPageLink("tree"); - - // per-repository extra page links - List<String> extraPageLinks = new ArrayList<String>(); - if (model.useTickets && TicgitUtils.getTicketsBranch(r) != null) { - extraPageLinks.add("tickets"); - } - if (model.useDocs) { - extraPageLinks.add("docs"); - } - - final boolean showAdmin; - if (GitBlit.getBoolean(Keys.web.authenticateAdminPages, true)) { - boolean allowAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, false); - showAdmin = allowAdmin && GitBlitWebSession.get().canAdmin(); - } else { - showAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, false); - } - - // Conditionally add edit link - if (showAdmin - || GitBlitWebSession.get().isLoggedIn() - && (model.owner != null && model.owner.equalsIgnoreCase(GitBlitWebSession.get() - .getUser().username))) { - extraPageLinks.add("edit"); - } - - final String pageName = getPageName(); - final String pageWicketId = getLinkWicketId(pageName); - ListDataProvider<String> extrasDp = new ListDataProvider<String>(extraPageLinks); - DataView<String> extrasView = new DataView<String>("extra", extrasDp) { - private static final long serialVersionUID = 1L; - - public void populateItem(final Item<String> item) { - String extra = item.getModelObject(); - PageRegistration pageReg = registeredPages.get(extra); - item.add(new Label("extraSeparator", " | ")); - item.add(new LinkPanel("extraLink", null, getString(pageReg.translationKey), - pageReg.pageClass, WicketUtils.newRepositoryParameter(repositoryName)) - .setEnabled(!extra.equals(pageWicketId))); - } - }; - add(extrasView); + List<PageRegistration> pages = new ArrayList<PageRegistration>(registeredPages.values()); + NavigationPanel navigationPanel = new NavigationPanel("navPanel", getClass(), pages); + add(navigationPanel); add(new ExternalLink("syndication", SyndicationServlet.asLink(getRequest() .getRelativePathPrefixToContextRoot(), repositoryName, null, 0))); - - // disable current page - disableRegisteredPageLink(pageName); // add floating search form SearchForm searchForm = new SearchForm("searchForm", repositoryName); @@ -156,31 +114,72 @@ setStatelessHint(true); } - public String getLinkWicketId(String pageName) { - for (String wicketId : registeredPages.keySet()) { - String key = registeredPages.get(wicketId).translationKey; - String linkName = getString(key); - if (linkName.equals(pageName)) { - return wicketId; - } + private Map<String, PageRegistration> registerPages() { + PageParameters params = null; + if (!StringUtils.isEmpty(repositoryName)) { + params = WicketUtils.newRepositoryParameter(repositoryName); } - return null; + Map<String, PageRegistration> pages = new LinkedHashMap<String, PageRegistration>(); + + // standard links + pages.put("repositories", new PageRegistration("gb.repositories", RepositoriesPage.class)); + pages.put("project", new PageRegistration("gb.project", ProjectPage.class, WicketUtils.newProjectParameter(projectName))); + pages.put("summary", new PageRegistration("gb.summary", SummaryPage.class, params)); + pages.put("log", new PageRegistration("gb.log", LogPage.class, params)); + pages.put("branches", new PageRegistration("gb.branches", BranchesPage.class, params)); + pages.put("tags", new PageRegistration("gb.tags", TagsPage.class, params)); + pages.put("tree", new PageRegistration("gb.tree", TreePage.class, params)); + + // conditional links + Repository r = getRepository(); + RepositoryModel model = getRepositoryModel(); + + // per-repository extra page links + if (model.useTickets && TicgitUtils.getTicketsBranch(r) != null) { + pages.put("tickets", new PageRegistration("gb.tickets", TicketsPage.class, params)); + } + if (model.useDocs) { + pages.put("docs", new PageRegistration("gb.docs", DocsPage.class, params)); + } + if (JGitUtils.getPagesBranch(r) != null) { + OtherPageLink pagesLink = new OtherPageLink("gb.pages", PagesServlet.asLink( + getRequest().getRelativePathPrefixToContextRoot(), repositoryName, null)); + pages.put("pages", pagesLink); + } + + // Conditionally add edit link + final boolean showAdmin; + if (GitBlit.getBoolean(Keys.web.authenticateAdminPages, true)) { + boolean allowAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, false); + showAdmin = allowAdmin && GitBlitWebSession.get().canAdmin(); + } else { + showAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, false); + } + if (showAdmin + || GitBlitWebSession.get().isLoggedIn() + && (model.owner != null && model.owner.equalsIgnoreCase(GitBlitWebSession.get() + .getUsername()))) { + pages.put("edit", new PageRegistration("gb.edit", EditRepositoryPage.class, params)); + } + return pages; } - public void disableRegisteredPageLink(String pageName) { - String wicketId = getLinkWicketId(pageName); - if (!StringUtils.isEmpty(wicketId)) { - Component c = get(wicketId); - if (c != null) { - c.setEnabled(false); - } + @Override + protected void setupPage(String repositoryName, String pageName) { + add(new LinkPanel("repositoryName", null, StringUtils.stripDotGit(repositoryName), + SummaryPage.class, WicketUtils.newRepositoryParameter(repositoryName))); + add(new Label("pageName", pageName).setRenderBodyOnly(true)); + if (getRepositoryModel().isBare) { + add(new Label("workingCopy").setVisible(false)); + } else { + Fragment fragment = new Fragment("workingCopy", "workingCopyFragment", this); + Label lbl = new Label("workingCopy", getString("gb.workingCopy")); + WicketUtils.setHtmlTooltip(lbl, getString("gb.workingCopyWarning")); + fragment.add(lbl); + add(fragment); } - } - private void addRegisteredPageLink(String key) { - PageRegistration pageReg = registeredPages.get(key); - add(new BookmarkablePageLink<Void>(key, pageReg.pageClass, - WicketUtils.newRepositoryParameter(repositoryName))); + super.setupPage(repositoryName, pageName); } protected void addSyndicationDiscoveryLink() { @@ -193,7 +192,7 @@ if (r == null) { Repository r = GitBlit.self().getRepository(repositoryName); if (r == null) { - error("Can not load repository " + repositoryName, true); + error(getString("gb.canNotLoadRepository") + " " + repositoryName, true); return null; } this.r = r; @@ -206,7 +205,13 @@ RepositoryModel model = GitBlit.self().getRepositoryModel( GitBlitWebSession.get().getUser(), repositoryName); if (model == null) { - authenticationError("Unauthorized access for repository " + repositoryName); + if (GitBlit.self().hasRepository(repositoryName)) { + // has repository, but unauthorized + authenticationError(getString("gb.unauthorizedAccessForRepository") + " " + repositoryName); + } else { + // does not have repository + error(getString("gb.canNotLoadRepository") + " " + repositoryName, true); + } return null; } m = model; @@ -217,10 +222,87 @@ protected RevCommit getCommit() { RevCommit commit = JGitUtils.getCommit(r, objectId); if (commit == null) { - error(MessageFormat.format("Failed to find commit \"{0}\" in {1} for {2} page!", + error(MessageFormat.format(getString("gb.failedToFindCommit"), objectId, repositoryName, getPageName()), true); } + getSubmodules(commit); return commit; + } + + private Map<String, SubmoduleModel> getSubmodules(RevCommit commit) { + if (submodules == null) { + submodules = new HashMap<String, SubmoduleModel>(); + for (SubmoduleModel model : JGitUtils.getSubmodules(r, commit.getTree())) { + submodules.put(model.path, model); + } + } + return submodules; + } + + protected Map<String, SubmoduleModel> getSubmodules() { + return submodules; + } + + protected SubmoduleModel getSubmodule(String path) { + SubmoduleModel model = submodules.get(path); + if (model == null) { + // undefined submodule?! + model = new SubmoduleModel(path.substring(path.lastIndexOf('/') + 1), path, path); + model.hasSubmodule = false; + model.gitblitPath = model.name; + return model; + } else { + // extract the repository name from the clone url + List<String> patterns = GitBlit.getStrings(Keys.git.submoduleUrlPatterns); + String submoduleName = StringUtils.extractRepositoryPath(model.url, patterns.toArray(new String[0])); + + // determine the current path for constructing paths relative + // to the current repository + String currentPath = ""; + if (repositoryName.indexOf('/') > -1) { + currentPath = repositoryName.substring(0, repositoryName.lastIndexOf('/') + 1); + } + + // try to locate the submodule repository + // prefer bare to non-bare names + List<String> candidates = new ArrayList<String>(); + + // relative + candidates.add(currentPath + StringUtils.stripDotGit(submoduleName)); + candidates.add(candidates.get(candidates.size() - 1) + ".git"); + + // relative, no subfolder + if (submoduleName.lastIndexOf('/') > -1) { + String name = submoduleName.substring(submoduleName.lastIndexOf('/') + 1); + candidates.add(currentPath + StringUtils.stripDotGit(name)); + candidates.add(currentPath + candidates.get(candidates.size() - 1) + ".git"); + } + + // absolute + candidates.add(StringUtils.stripDotGit(submoduleName)); + candidates.add(candidates.get(candidates.size() - 1) + ".git"); + + // absolute, no subfolder + if (submoduleName.lastIndexOf('/') > -1) { + String name = submoduleName.substring(submoduleName.lastIndexOf('/') + 1); + candidates.add(StringUtils.stripDotGit(name)); + candidates.add(candidates.get(candidates.size() - 1) + ".git"); + } + + // create a unique, ordered set of candidate paths + Set<String> paths = new LinkedHashSet<String>(candidates); + for (String candidate : paths) { + if (GitBlit.self().hasRepository(candidate)) { + model.hasSubmodule = true; + model.gitblitPath = candidate; + return model; + } + } + + // we do not have a copy of the submodule, but we need a path + model.gitblitPath = candidates.get(0); + return model; + } } protected String getShortObjectId(String objectId) { @@ -232,11 +314,11 @@ } protected void addFullText(String wicketId, String text, boolean substituteRegex) { - String html; + String html = StringUtils.escapeForHtml(text, true); if (substituteRegex) { html = GitBlit.self().processCommitMessage(repositoryName, text); } else { - html = StringUtils.breakLinesForHtml(text); + html = StringUtils.breakLinesForHtml(html); } add(new Label(wicketId, html).setEscapeModelStrings(false)); } @@ -244,46 +326,46 @@ protected abstract String getPageName(); protected Component createPersonPanel(String wicketId, PersonIdent identity, - SearchType searchType) { + Constants.SearchType searchType) { + String name = identity == null ? "" : identity.getName(); + String address = identity == null ? "" : identity.getEmailAddress(); boolean showEmail = GitBlit.getBoolean(Keys.web.showEmailAddresses, false); - if (!showEmail || StringUtils.isEmpty(identity.getName()) - || StringUtils.isEmpty(identity.getEmailAddress())) { - String value = identity.getName(); + if (!showEmail || StringUtils.isEmpty(name) || StringUtils.isEmpty(address)) { + String value = name; if (StringUtils.isEmpty(value)) { if (showEmail) { - value = identity.getEmailAddress(); + value = address; } else { value = getString("gb.missingUsername"); } } Fragment partial = new Fragment(wicketId, "partialPersonIdent", this); - LinkPanel link = new LinkPanel("personName", "list", value, SearchPage.class, + LinkPanel link = new LinkPanel("personName", "list", value, GitSearchPage.class, WicketUtils.newSearchParameter(repositoryName, objectId, value, searchType)); setPersonSearchTooltip(link, value, searchType); partial.add(link); return partial; } else { Fragment fullPerson = new Fragment(wicketId, "fullPersonIdent", this); - LinkPanel nameLink = new LinkPanel("personName", "list", identity.getName(), - SearchPage.class, WicketUtils.newSearchParameter(repositoryName, objectId, - identity.getName(), searchType)); - setPersonSearchTooltip(nameLink, identity.getName(), searchType); + LinkPanel nameLink = new LinkPanel("personName", "list", name, GitSearchPage.class, + WicketUtils.newSearchParameter(repositoryName, objectId, name, searchType)); + setPersonSearchTooltip(nameLink, name, searchType); fullPerson.add(nameLink); - LinkPanel addressLink = new LinkPanel("personAddress", "list", "<" - + identity.getEmailAddress() + ">", SearchPage.class, - WicketUtils.newSearchParameter(repositoryName, objectId, - identity.getEmailAddress(), searchType)); - setPersonSearchTooltip(addressLink, identity.getEmailAddress(), searchType); + LinkPanel addressLink = new LinkPanel("personAddress", "hidden-phone list", "<" + address + ">", + GitSearchPage.class, WicketUtils.newSearchParameter(repositoryName, objectId, + address, searchType)); + setPersonSearchTooltip(addressLink, address, searchType); fullPerson.add(addressLink); return fullPerson; } } - protected void setPersonSearchTooltip(Component component, String value, SearchType searchType) { - if (searchType.equals(SearchType.AUTHOR)) { + protected void setPersonSearchTooltip(Component component, String value, + Constants.SearchType searchType) { + if (searchType.equals(Constants.SearchType.AUTHOR)) { WicketUtils.setHtmlTooltip(component, getString("gb.searchForAuthor") + " " + value); - } else if (searchType.equals(SearchType.COMMITTER)) { + } else if (searchType.equals(Constants.SearchType.COMMITTER)) { WicketUtils.setHtmlTooltip(component, getString("gb.searchForCommitter") + " " + value); } } @@ -330,36 +412,21 @@ return WicketUtils.newObjectParameter(repositoryName, commitId); } - protected PageParameters newPathParameter(String path) { - return WicketUtils.newPathParameter(repositoryName, objectId, path); - } - - private static class PageRegistration implements Serializable { - private static final long serialVersionUID = 1L; - - final String translationKey; - final Class<? extends BasePage> pageClass; - - PageRegistration(String translationKey, Class<? extends BasePage> pageClass) { - this.translationKey = translationKey; - this.pageClass = pageClass; - } - } - - private static class SearchForm extends StatelessForm<Void> implements Serializable { + private class SearchForm extends SessionlessForm<Void> implements Serializable { private static final long serialVersionUID = 1L; private final String repositoryName; private final IModel<String> searchBoxModel = new Model<String>(""); - private final IModel<SearchType> searchTypeModel = new Model<SearchType>(SearchType.COMMIT); + private final IModel<Constants.SearchType> searchTypeModel = new Model<Constants.SearchType>( + Constants.SearchType.COMMIT); public SearchForm(String id, String repositoryName) { - super(id); + super(id, RepositoryPage.this.getClass(), RepositoryPage.this.getPageParameters()); this.repositoryName = repositoryName; - DropDownChoice<SearchType> searchType = new DropDownChoice<SearchType>("searchType", - Arrays.asList(SearchType.values())); + DropDownChoice<Constants.SearchType> searchType = new DropDownChoice<Constants.SearchType>( + "searchType", Arrays.asList(Constants.SearchType.values())); searchType.setModel(searchTypeModel); add(searchType.setVisible(GitBlit.getBoolean(Keys.web.showSearchTypeSelection, false))); TextField<String> searchBox = new TextField<String>("searchBox", searchBoxModel); @@ -368,15 +435,19 @@ void setTranslatedAttributes() { WicketUtils.setHtmlTooltip(get("searchType"), getString("gb.searchTypeTooltip")); - WicketUtils.setHtmlTooltip(get("searchBox"), getString("gb.searchTooltip")); + WicketUtils.setHtmlTooltip(get("searchBox"), + MessageFormat.format(getString("gb.searchTooltip"), repositoryName)); WicketUtils.setInputPlaceholder(get("searchBox"), getString("gb.search")); } @Override public void onSubmit() { - SearchType searchType = searchTypeModel.getObject(); + Constants.SearchType searchType = searchTypeModel.getObject(); String searchString = searchBoxModel.getObject(); - for (SearchType type : SearchType.values()) { + if (searchString == null) { + return; + } + for (Constants.SearchType type : Constants.SearchType.values()) { if (searchString.toLowerCase().startsWith(type.name().toLowerCase() + ":")) { searchType = type; searchString = searchString.substring(type.name().toLowerCase().length() + 1) @@ -384,8 +455,19 @@ break; } } - setResponsePage(SearchPage.class, - WicketUtils.newSearchParameter(repositoryName, null, searchString, searchType)); + Class<? extends BasePage> searchPageClass = GitSearchPage.class; + RepositoryModel model = GitBlit.self().getRepositoryModel(repositoryName); + if (GitBlit.getBoolean(Keys.web.allowLuceneIndexing, true) + && !ArrayUtils.isEmpty(model.indexedBranches)) { + // this repository is Lucene-indexed + searchPageClass = LuceneSearchPage.class; + } + // use an absolute url to workaround Wicket-Tomcat problems with + // mounted url parameters (issue-111) + PageParameters params = WicketUtils.newSearchParameter(repositoryName, null, searchString, searchType); + String relativeUrl = urlFor(searchPageClass, params).toString(); + String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl); + getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl)); } } } -- Gitblit v1.9.1