]> source.dussan.org Git - gitblit.git/commitdiff
Update the gh-pages branch on release with the built site
authorJames Moger <james.moger@gitblit.com>
Wed, 11 Jan 2012 21:18:02 +0000 (16:18 -0500)
committerJames Moger <james.moger@gitblit.com>
Wed, 11 Jan 2012 21:18:02 +0000 (16:18 -0500)
build.xml
src/com/gitblit/build/BuildGhPages.java [new file with mode: 0644]

index 0d906ed657c2e1ac03af6b96f1a8cc2ff4e3ca1e..7bb09cfd33c60ac0905f432dbc1bbc364e630c54 100644 (file)
--- a/build.xml
+++ b/build.xml
                <delete dir="${project.express.dir}" />\r
        </target>\r
 \r
+       \r
+       <!--\r
+               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \r
+               Update the gh-pages branch with the current site\r
+               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
+       -->\r
+       <target name="updateGhPages" depends="buildSite">\r
+               <!-- Build gh-pages branch -->\r
+               <java classpath="${project.build.dir}" classname="com.gitblit.build.BuildGhPages">\r
+                       <classpath refid="master-classpath" />\r
+                       <arg value="--sourceFolder" />\r
+                       <arg value="${basedir}/site" />\r
+\r
+                       <arg value="--repository" />\r
+                       <arg value="${basedir}" />\r
+                       \r
+                       <arg value="--obliterate" />\r
+               </java>\r
+       </target>\r
+       \r
 \r
        <!-- \r
                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
                You must add ext/commons-net-1.4.0.jar to your ANT classpath.\r
                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
        -->\r
-       <target name="publishSite" depends="buildSite" description="Publish the Gitblit site to a webserver (requires ext/commons-net-1.4.0.jar)" >\r
+       <target name="publishSite" depends="buildSite,updateGhPages" description="Publish the Gitblit site to a webserver (requires ext/commons-net-1.4.0.jar)" >\r
 \r
                <echo>Uploading Gitblit ${gb.version} website</echo>\r
 \r
diff --git a/src/com/gitblit/build/BuildGhPages.java b/src/com/gitblit/build/BuildGhPages.java
new file mode 100644 (file)
index 0000000..efeb43c
--- /dev/null
@@ -0,0 +1,259 @@
+/*\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.build;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.text.MessageFormat;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.Set;\r
+import java.util.TreeSet;\r
+\r
+import org.eclipse.jgit.JGitText;\r
+import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;\r
+import org.eclipse.jgit.api.errors.JGitInternalException;\r
+import org.eclipse.jgit.dircache.DirCache;\r
+import org.eclipse.jgit.dircache.DirCacheBuilder;\r
+import org.eclipse.jgit.dircache.DirCacheEntry;\r
+import org.eclipse.jgit.lib.CommitBuilder;\r
+import org.eclipse.jgit.lib.Constants;\r
+import org.eclipse.jgit.lib.FileMode;\r
+import org.eclipse.jgit.lib.ObjectId;\r
+import org.eclipse.jgit.lib.ObjectInserter;\r
+import org.eclipse.jgit.lib.PersonIdent;\r
+import org.eclipse.jgit.lib.RefUpdate;\r
+import org.eclipse.jgit.lib.RefUpdate.Result;\r
+import org.eclipse.jgit.lib.Repository;\r
+import org.eclipse.jgit.lib.RepositoryCache.FileKey;\r
+import org.eclipse.jgit.revwalk.RevCommit;\r
+import org.eclipse.jgit.revwalk.RevWalk;\r
+import org.eclipse.jgit.storage.file.FileRepository;\r
+import org.eclipse.jgit.treewalk.CanonicalTreeParser;\r
+import org.eclipse.jgit.treewalk.TreeWalk;\r
+import org.eclipse.jgit.util.FS;\r
+\r
+import com.beust.jcommander.JCommander;\r
+import com.beust.jcommander.Parameter;\r
+import com.beust.jcommander.ParameterException;\r
+import com.beust.jcommander.Parameters;\r
+import com.gitblit.models.RefModel;\r
+import com.gitblit.utils.JGitUtils;\r
+import com.gitblit.utils.StringUtils;\r
+\r
+/**\r
+ * Creates or updates a gh-pages branch with the specified content.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
+public class BuildGhPages {\r
+\r
+       public static void main(String[] args) {\r
+               Params params = new Params();\r
+               JCommander jc = new JCommander(params);\r
+               try {\r
+                       jc.parse(args);\r
+               } catch (ParameterException t) {\r
+                       System.err.println(t.getMessage());\r
+                       jc.usage();\r
+               }\r
+\r
+               File source = new File(params.sourceFolder);\r
+               String ghpages = "refs/heads/gh-pages";\r
+               try {                   \r
+                       File gitDir = FileKey.resolve(new File(params.repositoryFolder), FS.DETECTED);\r
+                       Repository repository = new FileRepository(gitDir);\r
+\r
+                       RefModel issuesBranch = JGitUtils.getPagesBranch(repository);\r
+                       if (issuesBranch == null) {\r
+                               JGitUtils.createOrphanBranch(repository, "gh-pages", null);\r
+                       }\r
+\r
+                       System.out.println("Updating gh-pages branch...");\r
+                       ObjectId headId = repository.resolve(ghpages + "^{commit}");\r
+                       ObjectInserter odi = repository.newObjectInserter();\r
+                       try {\r
+                               // Create the in-memory index of the new/updated issue.\r
+                               DirCache index = createIndex(repository, headId, source, params.obliterate);\r
+                               ObjectId indexTreeId = index.writeTree(odi);\r
+\r
+                               // Create a commit object\r
+                               PersonIdent author = new PersonIdent("Gitblit", "gitblit@localhost");\r
+                               CommitBuilder commit = new CommitBuilder();\r
+                               commit.setAuthor(author);\r
+                               commit.setCommitter(author);\r
+                               commit.setEncoding(Constants.CHARACTER_ENCODING);\r
+                               commit.setMessage("updated pages");\r
+                               commit.setParentId(headId);\r
+                               commit.setTreeId(indexTreeId);\r
+\r
+                               // Insert the commit into the repository\r
+                               ObjectId commitId = odi.insert(commit);\r
+                               odi.flush();\r
+\r
+                               RevWalk revWalk = new RevWalk(repository);\r
+                               try {\r
+                                       RevCommit revCommit = revWalk.parseCommit(commitId);\r
+                                       RefUpdate ru = repository.updateRef(ghpages);\r
+                                       ru.setNewObjectId(commitId);\r
+                                       ru.setExpectedOldObjectId(headId);\r
+                                       ru.setRefLogMessage("commit: " + revCommit.getShortMessage(), false);\r
+                                       Result rc = ru.forceUpdate();\r
+                                       switch (rc) {\r
+                                       case NEW:\r
+                                       case FORCED:\r
+                                       case FAST_FORWARD:\r
+                                               break;\r
+                                       case REJECTED:\r
+                                       case LOCK_FAILURE:\r
+                                               throw new ConcurrentRefUpdateException(JGitText.get().couldNotLockHEAD,\r
+                                                               ru.getRef(), rc);\r
+                                       default:\r
+                                               throw new JGitInternalException(MessageFormat.format(\r
+                                                               JGitText.get().updatingRefFailed, ghpages, commitId.toString(), rc));\r
+                                       }\r
+                               } finally {\r
+                                       revWalk.release();\r
+                               }\r
+                       } finally {\r
+                               odi.release();\r
+                       }\r
+                       System.out.println("gh-pages updated.");\r
+               } catch (Throwable t) {\r
+                       t.printStackTrace();\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Creates an in-memory index of the issue change.\r
+        * \r
+        * @param repo\r
+        * @param headId\r
+        * @param sourceFolder\r
+        * @param obliterate\r
+        *            if true the source folder tree is used as the new tree for\r
+        *            gh-pages and non-existent files are considered deleted\r
+        * @return an in-memory index\r
+        * @throws IOException\r
+        */\r
+       private static DirCache createIndex(Repository repo, ObjectId headId, File sourceFolder,\r
+                       boolean obliterate) throws IOException {\r
+\r
+               DirCache inCoreIndex = DirCache.newInCore();\r
+               DirCacheBuilder dcBuilder = inCoreIndex.builder();\r
+               ObjectInserter inserter = repo.newObjectInserter();\r
+\r
+               try {\r
+                       // Add all files to the temporary index\r
+                       Set<String> ignorePaths = new TreeSet<String>();\r
+                       List<File> files = listFiles(sourceFolder);\r
+                       for (File file : files) {\r
+                               // create an index entry for the file\r
+                               final DirCacheEntry dcEntry = new DirCacheEntry(StringUtils.getRelativePath(\r
+                                               sourceFolder.getPath(), file.getPath()));\r
+                               dcEntry.setLength(file.length());\r
+                               dcEntry.setLastModified(file.lastModified());\r
+                               dcEntry.setFileMode(FileMode.REGULAR_FILE);\r
+\r
+                               // add this entry to the ignore paths set\r
+                               ignorePaths.add(dcEntry.getPathString());\r
+\r
+                               // insert object\r
+                               InputStream inputStream = new FileInputStream(file);\r
+                               try {\r
+                                       dcEntry.setObjectId(inserter.insert(Constants.OBJ_BLOB, file.length(),\r
+                                                       inputStream));\r
+                               } finally {\r
+                                       inputStream.close();\r
+                               }\r
+\r
+                               // add to temporary in-core index\r
+                               dcBuilder.add(dcEntry);\r
+                       }\r
+\r
+                       if (!obliterate) {\r
+                               // Traverse HEAD to add all other paths\r
+                               TreeWalk treeWalk = new TreeWalk(repo);\r
+                               int hIdx = -1;\r
+                               if (headId != null)\r
+                                       hIdx = treeWalk.addTree(new RevWalk(repo).parseTree(headId));\r
+                               treeWalk.setRecursive(true);\r
+\r
+                               while (treeWalk.next()) {\r
+                                       String path = treeWalk.getPathString();\r
+                                       CanonicalTreeParser hTree = null;\r
+                                       if (hIdx != -1)\r
+                                               hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class);\r
+                                       if (!ignorePaths.contains(path)) {\r
+                                               // add entries from HEAD for all other paths\r
+                                               if (hTree != null) {\r
+                                                       // create a new DirCacheEntry with data retrieved\r
+                                                       // from\r
+                                                       // HEAD\r
+                                                       final DirCacheEntry dcEntry = new DirCacheEntry(path);\r
+                                                       dcEntry.setObjectId(hTree.getEntryObjectId());\r
+                                                       dcEntry.setFileMode(hTree.getEntryFileMode());\r
+\r
+                                                       // add to temporary in-core index\r
+                                                       dcBuilder.add(dcEntry);\r
+                                               }\r
+                                       }\r
+                               }\r
+\r
+                               // release the treewalk\r
+                               treeWalk.release();\r
+                       }\r
+                       \r
+                       // finish temporary in-core index used for this commit\r
+                       dcBuilder.finish();\r
+               } finally {\r
+                       inserter.release();\r
+               }\r
+               return inCoreIndex;\r
+       }\r
+\r
+       private static List<File> listFiles(File folder) {\r
+               List<File> files = new ArrayList<File>();\r
+               for (File file : folder.listFiles()) {\r
+                       if (file.isDirectory()) {\r
+                               files.addAll(listFiles(file));\r
+                       } else {\r
+                               files.add(file);\r
+                       }\r
+               }\r
+               return files;\r
+       }\r
+\r
+       /**\r
+        * JCommander Parameters class for BuildGhPages.\r
+        */\r
+       @Parameters(separators = " ")\r
+       private static class Params {\r
+\r
+               @Parameter(names = { "--sourceFolder" }, description = "Source folder for pages", required = true)\r
+               public String sourceFolder;\r
+\r
+               @Parameter(names = { "--repository" }, description = "Repository folder", required = true)\r
+               public String repositoryFolder;\r
+\r
+               @Parameter(names = { "--obliterate" }, description = "Replace gh-pages tree with only the content in your sourcefolder")\r
+               public boolean obliterate;\r
+\r
+       }\r
+}\r