diff --git a/src/main/scala/app/RepositoryViewerController.scala b/src/main/scala/app/RepositoryViewerController.scala index 54dfe7c..886a772 100644 --- a/src/main/scala/app/RepositoryViewerController.scala +++ b/src/main/scala/app/RepositoryViewerController.scala @@ -2,7 +2,7 @@ import util.Directory._ import util.Implicits._ -import util.{JGitUtil, FileTypeUtil} +import util.{JGitUtil, FileTypeUtil, CompressUtil} import org.scalatra._ import java.io.File import java.util.Date @@ -217,6 +217,47 @@ } /** + * Download repository contents as an archive. + */ + get("/:owner/:repository/archive/:name"){ + val owner = params("owner") + val repository = params("repository") + val name = params("name") + + if(name.endsWith(".zip")){ + val revision = name.replaceFirst("\\.zip$", "") + val workDir = getDownloadWorkDir(owner, repository, session.getId) + if(workDir.exists){ + FileUtils.deleteDirectory(workDir) + } + workDir.mkdirs + + // clone the repository + val cloneDir = new File(workDir, revision) + val git = Git.cloneRepository + .setURI(getRepositoryDir(owner, repository).toURI.toString) + .setDirectory(cloneDir) + .call + + // checkout the specified revision + git.checkout.setName(revision).call + git.getRepository.close + + // remove .git + FileUtils.deleteDirectory(new File(cloneDir, ".git")) + + // create zip file + val zipFile = new File(workDir, (if(revision.length == 40) revision.substring(0, 10) else revision) + ".zip") + CompressUtil.zip(zipFile, cloneDir) + + contentType = "application/octet-stream" + zipFile + } else { + BadRequest + } + } + + /** * Provides HTML of the file list. * * @param owner the repository owner diff --git a/src/main/scala/util/CompressUtil.scala b/src/main/scala/util/CompressUtil.scala new file mode 100644 index 0000000..10d4e6e --- /dev/null +++ b/src/main/scala/util/CompressUtil.scala @@ -0,0 +1,32 @@ +package util + +import java.io.File +import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry +import org.apache.commons.io.FileUtils +import org.apache.commons.io.IOUtils + +object CompressUtil { + + def zip(dest: File, dir: File): Unit = { + def addDirectoryToZip(out: ZipArchiveOutputStream, dir: File, path: String): Unit = { + dir.listFiles.map { file => + if(file.isFile){ + out.putArchiveEntry(new ZipArchiveEntry(path + "/" + file.getName)) + out.write(FileUtils.readFileToByteArray(file)) + out.closeArchiveEntry + } else if(file.isDirectory){ + addDirectoryToZip(out, file, path + "/" + file.getName) + } + } + } + + val out = new ZipArchiveOutputStream(dest) + try { + addDirectoryToZip(out, dir, dir.getName) + } finally { + IOUtils.closeQuietly(out) + } + } + +} \ No newline at end of file diff --git a/src/main/scala/util/Directory.scala b/src/main/scala/util/Directory.scala index 82158c6..6bfed55 100644 --- a/src/main/scala/util/Directory.scala +++ b/src/main/scala/util/Directory.scala @@ -34,6 +34,12 @@ new File("%s/%s/%s.git".format(RepositoryHome, owner, repository)) /** + * Temporary directory which is used to create an archive to download repository contents. + */ + def getDownloadWorkDir(owner: String, repository: String, sessionId: String): File = + new File("%s/tmp/%s/%s/download/%s".format(GitBucketHome, owner, repository, sessionId)) + + /** * Temporary directory which is used in the repository creation. * GiyBucket generates initial repository contents in this directory and push them. * This directory is removed after the repository creation. diff --git a/src/main/scala/util/WikiUtil.scala b/src/main/scala/util/WikiUtil.scala index 63177fd..924bc87 100644 --- a/src/main/scala/util/WikiUtil.scala +++ b/src/main/scala/util/WikiUtil.scala @@ -44,7 +44,7 @@ * Returns the directory of the wiki working directory which is cloned from the wiki repository. */ def getWikiWorkDir(owner: String, repository: String): File = - new File("%s/tmp/%s/%s.wiki".format(Directory.RepositoryHome, owner, repository)) + new File("%s/tmp/%s/%s.wiki".format(Directory.GitBucketHome, owner, repository)) // TODO synchronized? def createWikiRepository(owner: String, repository: String): Unit = { @@ -81,9 +81,6 @@ .sortBy(x => x) } - // TODO - //def getPageHistory(owner: String, repository: String, pageName: String): List[WikiPageHistoryInfo] - // TODO synchronized /** * Save the wiki page. diff --git a/src/main/twirl/repo/tags.scala.html b/src/main/twirl/repo/tags.scala.html index a6b4ea3..7639460 100644 --- a/src/main/twirl/repo/tags.scala.html +++ b/src/main/twirl/repo/tags.scala.html @@ -17,7 +17,7 @@ @tag.name @helpers.datetime(tag.time) @tag.id.substring(0, 10) - ZIP + ZIP }