diff --git a/src/main/scala/gitbucket/core/controller/AccountController.scala b/src/main/scala/gitbucket/core/controller/AccountController.scala index 09313ec..ebf7971 100644 --- a/src/main/scala/gitbucket/core/controller/AccountController.scala +++ b/src/main/scala/gitbucket/core/controller/AccountController.scala @@ -2,7 +2,7 @@ import gitbucket.core.account.html import gitbucket.core.helper -import gitbucket.core.model.{AccountWebHook, GroupMember, RepositoryWebHook, RepositoryWebHookEvent, Role, WebHook, WebHookContentType} +import gitbucket.core.model.{AccountWebHook, GroupMember, RepositoryWebHook, Role, WebHook, WebHookContentType} import gitbucket.core.plugin.PluginRegistry import gitbucket.core.service._ import gitbucket.core.service.WebHookService._ @@ -17,6 +17,8 @@ import org.scalatra.BadRequest import org.scalatra.forms._ +import scala.concurrent.ExecutionContext.Implicits.global + class AccountController extends AccountControllerBase with AccountService with RepositoryService with ActivityService with WikiService with LabelsService with SshKeyService with OneselfAuthenticator with UsersAuthenticator with GroupManagerAuthenticator with ReadableUsersAuthenticator @@ -462,7 +464,6 @@ get("/:groupName/_editgroup")(managersOnly { defining(params("groupName")){ groupName => - // TODO Don't use Option.get getAccountByUserName(groupName, true).map { account => html.editgroup(account, getGroupMembers(groupName), flash.get("info")) } getOrElse NotFound() @@ -530,10 +531,11 @@ LockUtil.lock(s"${form.owner}/${form.name}"){ if(getRepository(form.owner, form.name).isEmpty){ // Create the repository - createRepository(context.loginAccount.get, form.owner, form.name, form.description, form.isPrivate, form.initOption, form.sourceUrl) - - // Call hooks - PluginRegistry().getRepositoryHooks.foreach(_.created(form.owner, form.name)) + val f = createRepository(context.loginAccount.get, form.owner, form.name, form.description, form.isPrivate, form.initOption, form.sourceUrl).map { _ => + // Call hooks + PluginRegistry().getRepositoryHooks.foreach(_.created(form.owner, form.name)) + } + //Await.result(f, Duration.Inf) } } diff --git a/src/main/scala/gitbucket/core/controller/ApiController.scala b/src/main/scala/gitbucket/core/controller/ApiController.scala index 1199921..d7a6e75 100644 --- a/src/main/scala/gitbucket/core/controller/ApiController.scala +++ b/src/main/scala/gitbucket/core/controller/ApiController.scala @@ -16,6 +16,8 @@ import org.scalatra.{Created, NoContent, UnprocessableEntity} import scala.collection.JavaConverters._ +import scala.concurrent.Await +import scala.concurrent.duration.Duration class ApiController extends ApiControllerBase with RepositoryService @@ -249,7 +251,8 @@ } yield { LockUtil.lock(s"${owner}/${data.name}") { if(getRepository(owner, data.name).isEmpty){ - createRepository(context.loginAccount.get, owner, data.name, data.description, data.`private`, data.auto_init) + val f = createRepository(context.loginAccount.get, owner, data.name, data.description, data.`private`, data.auto_init) + Await.result(f, Duration.Inf) val repository = getRepository(owner, data.name).get JsonFormat(ApiRepository(repository, ApiUser(getAccountByUserName(owner).get))) } else { @@ -273,7 +276,8 @@ } yield { LockUtil.lock(s"${groupName}/${data.name}") { if(getRepository(groupName, data.name).isEmpty){ - createRepository(context.loginAccount.get, groupName, data.name, data.description, data.`private`, data.auto_init) + val f = createRepository(context.loginAccount.get, groupName, data.name, data.description, data.`private`, data.auto_init) + Await.result(f, Duration.Inf) val repository = getRepository(groupName, data.name).get JsonFormat(ApiRepository(repository, ApiUser(getAccountByUserName(groupName).get))) } else { diff --git a/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala b/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala index 311dbac..1fc39bf 100644 --- a/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala +++ b/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala @@ -148,14 +148,27 @@ * Displays the file list of the repository root and the default branch. */ get("/:owner/:repository") { - params.get("go-get") match { - case Some("1") => defining(request.paths){ paths => - getRepository(paths(0), paths(1)).map(gitbucket.core.html.goget(_))getOrElse NotFound() + val owner = params("owner") + val repository = params("repository") + + if (RepositoryCreationService.isCreating(owner, repository)) { + gitbucket.core.repo.html.creating(owner, repository) + } else { + params.get("go-get") match { + case Some("1") => defining(request.paths) { paths => + getRepository(owner, repository).map(gitbucket.core.html.goget(_)) getOrElse NotFound() + } + case _ => referrersOnly(fileList(_)) } - case _ => referrersOnly(fileList(_)) } } + ajaxGet("/:owner/:repository/creating") { + val owner = params("owner") + val repository = params("repository") + RepositoryCreationService.isCreating(owner, repository) + } + /** * Displays the file list of the specified path and branch. */ diff --git a/src/main/scala/gitbucket/core/service/RepositoryCreationService.scala b/src/main/scala/gitbucket/core/service/RepositoryCreationService.scala index e32e99c..9b5ef31 100644 --- a/src/main/scala/gitbucket/core/service/RepositoryCreationService.scala +++ b/src/main/scala/gitbucket/core/service/RepositoryCreationService.scala @@ -1,91 +1,123 @@ package gitbucket.core.service import java.nio.file.Files +import java.util.concurrent.ConcurrentHashMap import gitbucket.core.model.Profile.profile.blockingApi._ import gitbucket.core.util.SyntaxSugars._ import gitbucket.core.util.Directory._ import gitbucket.core.util.JGitUtil import gitbucket.core.model.Account +import gitbucket.core.servlet.Database import org.apache.commons.io.FileUtils import org.eclipse.jgit.api.Git import org.eclipse.jgit.dircache.DirCache import org.eclipse.jgit.lib.{Constants, FileMode} +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.Future + +object RepositoryCreationService { + + private val Creating = new ConcurrentHashMap[String, Boolean]() + + def isCreating(owner: String, repository: String): Boolean = { + Creating.containsKey(s"${owner}/${repository}") + } + + def startCreation(owner: String, repository: String): Unit = { + Creating.put(s"${owner}/${repository}", true) + } + + def endCreation(owner: String, repository: String): Unit = { + Creating.remove(s"${owner}/${repository}") + } + +} + trait RepositoryCreationService { self: AccountService with RepositoryService with LabelsService with WikiService with ActivityService with PrioritiesService => def createRepository(loginAccount: Account, owner: String, name: String, description: Option[String], - isPrivate: Boolean, createReadme: Boolean)(implicit s: Session): Unit = { + isPrivate: Boolean, createReadme: Boolean): Future[Unit] = { createRepository(loginAccount, owner, name, description, isPrivate, if (createReadme) "README" else "EMPTY", None) } def createRepository(loginAccount: Account, owner: String, name: String, description: Option[String], - isPrivate: Boolean, initOption: String, sourceUrl: Option[String])(implicit s: Session): Unit = { - val ownerAccount = getAccountByUserName(owner).get - val loginUserName = loginAccount.userName + isPrivate: Boolean, initOption: String, sourceUrl: Option[String]): Future[Unit] = Future { + RepositoryCreationService.startCreation(owner, name) + try { + Database() withTransaction { implicit session => + val ownerAccount = getAccountByUserName(owner).get + val loginUserName = loginAccount.userName - // Insert to the database at first - insertRepository(name, owner, description, isPrivate) + // Insert to the database at first + insertRepository(name, owner, description, isPrivate) -// // Add collaborators for group repository -// if(ownerAccount.isGroupAccount){ -// getGroupMembers(owner).foreach { member => -// addCollaborator(owner, name, member.userName) -// } -// } + // // Add collaborators for group repository + // if(ownerAccount.isGroupAccount){ + // getGroupMembers(owner).foreach { member => + // addCollaborator(owner, name, member.userName) + // } + // } - // Insert default labels - insertDefaultLabels(owner, name) + // Insert default labels + insertDefaultLabels(owner, name) - // Insert default priorities - insertDefaultPriorities(owner, name) + // Insert default priorities + insertDefaultPriorities(owner, name) - // Create the actual repository - val gitdir = getRepositoryDir(owner, name) - JGitUtil.initRepository(gitdir) + // Create the actual repository + val gitdir = getRepositoryDir(owner, name) + JGitUtil.initRepository(gitdir) - if (initOption == "README") { - using(Git.open(gitdir)){ git => - val builder = DirCache.newInCore.builder() - val inserter = git.getRepository.newObjectInserter() - val headId = git.getRepository.resolve(Constants.HEAD + "^{commit}") - val content = if(description.nonEmpty){ - name + "\n" + - "===============\n" + - "\n" + - description.get - } else { - name + "\n" + - "===============\n" + if (initOption == "README") { + using(Git.open(gitdir)) { git => + val builder = DirCache.newInCore.builder() + val inserter = git.getRepository.newObjectInserter() + val headId = git.getRepository.resolve(Constants.HEAD + "^{commit}") + val content = if (description.nonEmpty) { + name + "\n" + + "===============\n" + + "\n" + + description.get + } else { + name + "\n" + + "===============\n" + } + + builder.add(JGitUtil.createDirCacheEntry("README.md", FileMode.REGULAR_FILE, + inserter.insert(Constants.OBJ_BLOB, content.getBytes("UTF-8")))) + builder.finish() + + JGitUtil.createNewCommit(git, inserter, headId, builder.getDirCache.writeTree(inserter), + Constants.HEAD, loginAccount.fullName, loginAccount.mailAddress, "Initial commit") + } } - builder.add(JGitUtil.createDirCacheEntry("README.md", FileMode.REGULAR_FILE, - inserter.insert(Constants.OBJ_BLOB, content.getBytes("UTF-8")))) - builder.finish() + if (initOption == "COPY") { + sourceUrl.foreach { url => + // TODO How to feedback error in this block? + val dir = Files.createTempDirectory(s"gitbucket-${owner}-${name}").toFile - JGitUtil.createNewCommit(git, inserter, headId, builder.getDirCache.writeTree(inserter), - Constants.HEAD, loginAccount.fullName, loginAccount.mailAddress, "Initial commit") - } - } + Git.cloneRepository().setBare(true).setURI(url).setDirectory(dir).setCloneAllBranches(true).call() + using(Git.open(dir)) { git => + git.push().setRemote(gitdir.toURI.toString).setPushAll().setPushTags().call() + } - if (initOption == "COPY") { - sourceUrl.foreach { url => - val dir = Files.createTempDirectory(s"gitbucket-${owner}-${name}").toFile - println("Cloning to " + dir.getAbsolutePath) - Git.cloneRepository().setBare(true).setURI(url).setDirectory(dir).setCloneAllBranches(true).call() - using(Git.open(dir)) { git => - git.push().setRemote(gitdir.toURI.toString).setPushAll().setPushTags().call() + FileUtils.deleteQuietly(dir) + } } - FileUtils.deleteQuietly(dir) + + // Create Wiki repository + createWikiRepository(loginAccount, owner, name) + + // Record activity + recordCreateRepositoryActivity(owner, name, loginUserName) } + } finally { + RepositoryCreationService.endCreation(owner, name) } - - // Create Wiki repository - createWikiRepository(loginAccount, owner, name) - - // Record activity - recordCreateRepositoryActivity(owner, name, loginUserName) } def insertDefaultLabels(userName: String, repositoryName: String)(implicit s: Session): Unit = { diff --git a/src/main/twirl/gitbucket/core/repo/creating.scala.html b/src/main/twirl/gitbucket/core/repo/creating.scala.html new file mode 100644 index 0000000..7f695cf --- /dev/null +++ b/src/main/twirl/gitbucket/core/repo/creating.scala.html @@ -0,0 +1,26 @@ +@(owner: String, repository: String)(implicit context: gitbucket.core.controller.Context) +@gitbucket.core.html.main("Creating...") { +
+
+
+

Creating repository...

+ +
+
+
+} +