* \r
* @param repository\r
* @param user\r
- * @return true, if successful\r
+ * @return the repository model of the fork, if successful\r
+ * @throws GitBlitException\r
*/\r
- public boolean fork(RepositoryModel repository, UserModel user) {\r
+ public RepositoryModel fork(RepositoryModel repository, UserModel user) throws GitBlitException {\r
String cloneName = MessageFormat.format("~{0}/{1}.git", user.username, StringUtils.stripDotGit(StringUtils.getLastPathElement(repository.name)));\r
String fromUrl = MessageFormat.format("file://{0}/{1}", repositoriesFolder.getAbsolutePath(), repository.name);\r
+\r
+ // clone the repository\r
try {\r
- // clone the repository\r
JGitUtils.cloneRepository(repositoriesFolder, cloneName, fromUrl, true, null);\r
- \r
- // create a Gitblit repository model for the clone\r
- RepositoryModel cloneModel = repository.cloneAs(cloneName);\r
- cloneModel.owner = user.username;\r
- updateRepositoryModel(cloneName, cloneModel, false);\r
- \r
- if (AuthorizationControl.NAMED.equals(cloneModel.authorizationControl)) {\r
- // add the owner of the source repository to the clone's access list\r
- if (!StringUtils.isEmpty(repository.owner)) {\r
- UserModel owner = getUserModel(repository.owner);\r
- if (owner != null) {\r
- owner.repositories.add(cloneName);\r
- updateUserModel(owner.username, owner, false);\r
- }\r
+ } catch (Exception e) {\r
+ throw new GitBlitException(e);\r
+ }\r
+\r
+ // create a Gitblit repository model for the clone\r
+ RepositoryModel cloneModel = repository.cloneAs(cloneName);\r
+ cloneModel.owner = user.username;\r
+ updateRepositoryModel(cloneName, cloneModel, false);\r
+\r
+ if (AuthorizationControl.NAMED.equals(cloneModel.authorizationControl)) {\r
+ // add the owner of the source repository to the clone's access list\r
+ if (!StringUtils.isEmpty(repository.owner)) {\r
+ UserModel owner = getUserModel(repository.owner);\r
+ if (owner != null) {\r
+ owner.repositories.add(cloneName);\r
+ updateUserModel(owner.username, owner, false);\r
}\r
- \r
- // inherit origin's access lists\r
- List<String> users = getRepositoryUsers(repository);\r
- setRepositoryUsers(cloneModel, users);\r
- \r
- List<String> teams = getRepositoryTeams(repository);\r
- setRepositoryTeams(cloneModel, teams);\r
}\r
- \r
- // add this clone to the cached model\r
- addToCachedRepositoryList(cloneModel.name, cloneModel);\r
- return true;\r
- } catch (Exception e) {\r
- logger.error("failed to fork", e);\r
+\r
+ // inherit origin's access lists\r
+ List<String> users = getRepositoryUsers(repository);\r
+ setRepositoryUsers(cloneModel, users);\r
+\r
+ List<String> teams = getRepositoryTeams(repository);\r
+ setRepositoryTeams(cloneModel, teams);\r
}\r
- return false;\r
+\r
+ // add this clone to the cached model\r
+ addToCachedRepositoryList(cloneModel.name, cloneModel);\r
+ return cloneModel;\r
}\r
}\r
\r
public RepositoryModel cloneAs(String cloneName) {\r
RepositoryModel clone = new RepositoryModel();\r
+ clone.originRepository = name;\r
clone.name = cloneName;\r
+ clone.projectPath = StringUtils.getFirstPathElement(cloneName);\r
+ clone.isBare = true;\r
clone.description = description;\r
clone.accessRestriction = accessRestriction;\r
clone.authorizationControl = authorizationControl;\r
import com.gitblit.wicket.pages.CommitPage;\r
import com.gitblit.wicket.pages.DocsPage;\r
import com.gitblit.wicket.pages.FederationRegistrationPage;\r
+import com.gitblit.wicket.pages.ForkPage;\r
import com.gitblit.wicket.pages.ForksPage;\r
import com.gitblit.wicket.pages.GitSearchPage;\r
import com.gitblit.wicket.pages.GravatarProfilePage;\r
mount("/projects", ProjectsPage.class);\r
mount("/user", UserPage.class, "user");\r
mount("/forks", ForksPage.class, "r");\r
+ mount("/fork", ForkPage.class, "r");\r
}\r
\r
private void mount(String location, Class<? extends WebPage> clazz, String... parameters) {\r
gb.forks = forks\r
gb.forkRepository = fork {0}?\r
gb.repositoryForked = {0} has been forked\r
-gb.repositoryForkFailed= failed to fork {1}\r
+gb.repositoryForkFailed= fork has failed\r
gb.personalRepositories = personal repositories\r
gb.allowForks = allow forks\r
gb.allowForksDescription = allow authorized users to fork this repository\r
gb.myFork = view my fork\r
gb.forksProhibited = forks prohibited\r
gb.forksProhibitedWarning = this repository forbids forks\r
-gb.noForks = {0} has no forks
\ No newline at end of file
+gb.noForks = {0} has no forks\r
+gb.forkNotAuthorized = sorry, you are not authorized to fork {0}\r
+gb.forkInProgress = fork in progress\r
+gb.preparingFork = Gitblit is preparing your fork
\ No newline at end of file
\r
import java.util.Map;\r
import java.util.TimeZone;\r
+import java.util.concurrent.atomic.AtomicBoolean;\r
\r
import org.apache.wicket.Page;\r
import org.apache.wicket.PageParameters;\r
\r
private String requestUrl;\r
\r
+ private AtomicBoolean isForking;\r
+ \r
public GitBlitWebSession(Request request) {\r
super(request);\r
+ isForking = new AtomicBoolean();\r
}\r
\r
public void invalidate() {\r
errorMessage = null;\r
return msg;\r
}\r
+ \r
+ public boolean isForking() {\r
+ return isForking.get();\r
+ }\r
+ \r
+ public void isForking(boolean val) {\r
+ isForking.set(val);\r
+ }\r
\r
public static GitBlitWebSession get() {\r
return (GitBlitWebSession) Session.get();\r
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" \r
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd" \r
+ xml:lang="en" \r
+ lang="en"> \r
+\r
+<body>\r
+<wicket:head>\r
+ <noscript>\r
+ <meta http-equiv="refresh" content="5"></meta>\r
+ </noscript>\r
+ <script type="text/javascript"">\r
+ function doLoad() { setTimeout( "refresh()", 5*1000 ); }\r
+ function refresh() { window.location.reload(); }\r
+ </script>\r
+</wicket:head>\r
+<wicket:extend>\r
+<!-- need to specify body.onload -->\r
+<body onload="doLoad()">\r
+\r
+ <div class="row">\r
+ <div class="span6 offset3">\r
+ <div wicket:id="forkText" class="pageTitle project" style="border:0;font-weight:bold; text-align:center;">[fork text]</div>\r
+ </div>\r
+ <div class="span4 offset4">\r
+ <div class="progress progress-striped active">\r
+ <div class="bar" style="width: 100%;"></div>\r
+ </div>\r
+ </div>\r
+ <div class="span6 offset3">\r
+ <div style="opacity:0.2;">\r
+ <center><img style="padding:10px" src="git-black.png"></img></center>\r
+ </div>\r
+ </div>\r
+ </div>\r
+</body>\r
+\r
+</wicket:extend> \r
+</body>\r
+</html>
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright 2012 gitblit.com.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package com.gitblit.wicket.pages;\r
+\r
+import java.text.MessageFormat;\r
+\r
+import org.apache.wicket.PageParameters;\r
+import org.apache.wicket.markup.html.basic.Label;\r
+import org.slf4j.LoggerFactory;\r
+\r
+import com.gitblit.GitBlit;\r
+import com.gitblit.models.RepositoryModel;\r
+import com.gitblit.models.UserModel;\r
+import com.gitblit.wicket.GitBlitWebSession;\r
+import com.gitblit.wicket.GitblitRedirectException;\r
+import com.gitblit.wicket.WicketUtils;\r
+\r
+public class ForkPage extends RepositoryPage {\r
+\r
+\r
+ public ForkPage(PageParameters params) {\r
+ super(params);\r
+\r
+ setVersioned(false);\r
+ \r
+ GitBlitWebSession session = GitBlitWebSession.get();\r
+\r
+ RepositoryModel repository = getRepositoryModel();\r
+ UserModel user = session.getUser();\r
+ boolean canFork = user.canForkRepository(repository);\r
+\r
+ if (!canFork) {\r
+ // redirect to the summary page if this repository is not empty\r
+ GitBlitWebSession.get().cacheErrorMessage(\r
+ MessageFormat.format(getString("gb.forkNotAuthorized"), repository.name));\r
+ throw new GitblitRedirectException(SummaryPage.class, WicketUtils.newRepositoryParameter(repository.name));\r
+ }\r
+\r
+ String fork = GitBlit.self().getFork(user.username, repository.name);\r
+ if (fork != null) {\r
+ // redirect to user's fork\r
+ throw new GitblitRedirectException(SummaryPage.class, WicketUtils.newRepositoryParameter(fork));\r
+ }\r
+\r
+ add(new Label("forkText", getString("gb.preparingFork")));\r
+\r
+ if (!session.isForking()) {\r
+ // prepare session\r
+ session.isForking(true);\r
+\r
+ // fork it\r
+ ForkThread forker = new ForkThread(repository, session);\r
+ forker.start();\r
+ }\r
+ }\r
+\r
+ @Override\r
+ protected boolean allowForkControls() {\r
+ return false;\r
+ }\r
+\r
+ @Override\r
+ protected String getPageName() {\r
+ return "fork";\r
+ }\r
+\r
+ /**\r
+ * ForkThread does the work of working the repository in a background\r
+ * thread. The completion status is tracked through a session variable and\r
+ * monitored by this page.\r
+ */\r
+ private static class ForkThread extends Thread {\r
+\r
+ private final RepositoryModel repository;\r
+ private final GitBlitWebSession session;\r
+\r
+ public ForkThread(RepositoryModel repository, GitBlitWebSession session) {\r
+ this.repository = repository;\r
+ this.session = session;\r
+ }\r
+\r
+ @Override\r
+ public void run() {\r
+ UserModel user = session.getUser();\r
+ try {\r
+ GitBlit.self().fork(repository, user);\r
+ } catch (Exception e) {\r
+ LoggerFactory.getLogger(ForkPage.class).error(MessageFormat.format("Failed to fork {0} for {1}", repository.name, user.username), e);\r
+ } finally {\r
+ session.isForking(false);\r
+ }\r
+ }\r
+ }\r
+}\r
\r
import org.apache.wicket.Component;\r
import org.apache.wicket.PageParameters;\r
-import org.apache.wicket.RedirectException;\r
import org.apache.wicket.markup.html.basic.Label;\r
import org.apache.wicket.markup.html.form.DropDownChoice;\r
import org.apache.wicket.markup.html.form.TextField;\r
import org.apache.wicket.markup.html.link.ExternalLink;\r
-import org.apache.wicket.markup.html.link.Link;\r
import org.apache.wicket.markup.html.panel.Fragment;\r
import org.apache.wicket.model.IModel;\r
import org.apache.wicket.model.Model;\r
import com.gitblit.wicket.PageRegistration.OtherPageLink;\r
import com.gitblit.wicket.SessionlessForm;\r
import com.gitblit.wicket.WicketUtils;\r
-import com.gitblit.wicket.panels.BasePanel.JavascriptEventConfirmation;\r
import com.gitblit.wicket.panels.LinkPanel;\r
import com.gitblit.wicket.panels.NavigationPanel;\r
import com.gitblit.wicket.panels.RefsPanel;\r
}\r
return pages;\r
}\r
+ \r
+ protected boolean allowForkControls() {\r
+ return true;\r
+ }\r
\r
@Override\r
protected void setupPage(String repositoryName, String pageName) {\r
}\r
\r
// fork controls\r
- if (user == null) {\r
+ if (!allowForkControls() || user == null) {\r
// must be logged-in to fork, hide all fork controls\r
add(new ExternalLink("forkLink", "").setVisible(false));\r
add(new ExternalLink("myForkLink", "").setVisible(false));\r
// can fork and we do not have one\r
add(new Label("forksProhibitedIndicator").setVisible(false));\r
add(new ExternalLink("myForkLink", "").setVisible(false));\r
- Link<Void> forkLink = new Link<Void>("forkLink") {\r
-\r
- private static final long serialVersionUID = 1L;\r
-\r
- @Override\r
- public void onClick() {\r
- UserModel user = GitBlitWebSession.get().getUser();\r
- RepositoryModel model = getRepositoryModel();\r
- String asFork = MessageFormat.format("~{0}/{1}.git", user.username, StringUtils.stripDotGit(StringUtils.getLastPathElement(model.name)));\r
- if (GitBlit.self().fork(model, GitBlitWebSession.get().getUser())) {\r
- throw new RedirectException(SummaryPage.class, WicketUtils.newRepositoryParameter(asFork));\r
- } else {\r
- error(MessageFormat.format(getString("gb.repositoryForkFailed"), model));\r
- }\r
- }\r
- };\r
- forkLink.add(new JavascriptEventConfirmation("onclick", MessageFormat.format(\r
- getString("gb.forkRepository"), getRepositoryModel())));\r
- add(forkLink);\r
+ String url = getRequestCycle().urlFor(ForkPage.class, WicketUtils.newRepositoryParameter(model.name)).toString();\r
+ add(new ExternalLink("forkLink", url));\r
}\r
}\r
\r
\r
import org.apache.wicket.Component;\r
import org.apache.wicket.Localizer;\r
-import org.apache.wicket.Page;\r
import org.apache.wicket.PageParameters;\r
import org.apache.wicket.markup.html.basic.Label;\r
import org.apache.wicket.markup.html.link.BookmarkablePageLink;\r
@Override\r
public void onClick() {\r
if (GitBlit.self().deleteRepositoryModel(entry)) {\r
- info(MessageFormat.format(getString("gb.repositoryDeleted"), entry));\r
// redirect to the owning page\r
if (entry.isPersonalRepository()) {\r
setResponsePage(getPage().getClass(), WicketUtils.newUsernameParameter(entry.projectPath.substring(1)));\r
@Override\r
public void onClick() {\r
if (GitBlit.self().deleteRepositoryModel(entry)) {\r
- info(MessageFormat.format(getString("gb.repositoryDeleted"), entry));\r
if (dp instanceof SortableRepositoriesProvider) {\r
+ info(MessageFormat.format(getString("gb.repositoryDeleted"), entry));\r
((SortableRepositoriesProvider) dp).remove(entry);\r
} else {\r
- ((RepositoriesProvider) dp).remove(entry);\r
+ setResponsePage(getPage().getClass(), getPage().getPageParameters());\r
}\r
} else {\r
error(MessageFormat.format(getString("gb.repositoryDeleteFailed"), entry));\r