New file |
| | |
| | | /*
|
| | | * Copyright 2012 gitblit.com.
|
| | | *
|
| | | * Licensed under the Apache License, Version 2.0 (the "License");
|
| | | * you may not use this file except in compliance with the License.
|
| | | * You may obtain a copy of the License at
|
| | | *
|
| | | * http://www.apache.org/licenses/LICENSE-2.0
|
| | | *
|
| | | * Unless required by applicable law or agreed to in writing, software
|
| | | * distributed under the License is distributed on an "AS IS" BASIS,
|
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| | | * See the License for the specific language governing permissions and
|
| | | * limitations under the License.
|
| | | */
|
| | | package com.gitblit.build;
|
| | |
|
| | | import java.io.File;
|
| | | import java.io.FileInputStream;
|
| | | import java.io.IOException;
|
| | | import java.io.InputStream;
|
| | | import java.text.MessageFormat;
|
| | | import java.util.ArrayList;
|
| | | import java.util.List;
|
| | | import java.util.Set;
|
| | | import java.util.TreeSet;
|
| | |
|
| | | import org.eclipse.jgit.JGitText;
|
| | | import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
|
| | | import org.eclipse.jgit.api.errors.JGitInternalException;
|
| | | import org.eclipse.jgit.dircache.DirCache;
|
| | | import org.eclipse.jgit.dircache.DirCacheBuilder;
|
| | | import org.eclipse.jgit.dircache.DirCacheEntry;
|
| | | import org.eclipse.jgit.lib.CommitBuilder;
|
| | | import org.eclipse.jgit.lib.Constants;
|
| | | import org.eclipse.jgit.lib.FileMode;
|
| | | import org.eclipse.jgit.lib.ObjectId;
|
| | | import org.eclipse.jgit.lib.ObjectInserter;
|
| | | import org.eclipse.jgit.lib.PersonIdent;
|
| | | import org.eclipse.jgit.lib.RefUpdate;
|
| | | import org.eclipse.jgit.lib.RefUpdate.Result;
|
| | | import org.eclipse.jgit.lib.Repository;
|
| | | import org.eclipse.jgit.lib.RepositoryCache.FileKey;
|
| | | import org.eclipse.jgit.revwalk.RevCommit;
|
| | | import org.eclipse.jgit.revwalk.RevWalk;
|
| | | import org.eclipse.jgit.storage.file.FileRepository;
|
| | | import org.eclipse.jgit.treewalk.CanonicalTreeParser;
|
| | | import org.eclipse.jgit.treewalk.TreeWalk;
|
| | | import org.eclipse.jgit.util.FS;
|
| | |
|
| | | import com.beust.jcommander.JCommander;
|
| | | import com.beust.jcommander.Parameter;
|
| | | import com.beust.jcommander.ParameterException;
|
| | | import com.beust.jcommander.Parameters;
|
| | | import com.gitblit.models.RefModel;
|
| | | import com.gitblit.utils.JGitUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | |
|
| | | /**
|
| | | * Creates or updates a gh-pages branch with the specified content.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class BuildGhPages {
|
| | |
|
| | | public static void main(String[] args) {
|
| | | Params params = new Params();
|
| | | JCommander jc = new JCommander(params);
|
| | | try {
|
| | | jc.parse(args);
|
| | | } catch (ParameterException t) {
|
| | | System.err.println(t.getMessage());
|
| | | jc.usage();
|
| | | }
|
| | |
|
| | | File source = new File(params.sourceFolder);
|
| | | String ghpages = "refs/heads/gh-pages";
|
| | | try { |
| | | File gitDir = FileKey.resolve(new File(params.repositoryFolder), FS.DETECTED);
|
| | | Repository repository = new FileRepository(gitDir);
|
| | |
|
| | | RefModel issuesBranch = JGitUtils.getPagesBranch(repository);
|
| | | if (issuesBranch == null) {
|
| | | JGitUtils.createOrphanBranch(repository, "gh-pages", null);
|
| | | }
|
| | |
|
| | | System.out.println("Updating gh-pages branch...");
|
| | | ObjectId headId = repository.resolve(ghpages + "^{commit}");
|
| | | ObjectInserter odi = repository.newObjectInserter();
|
| | | try {
|
| | | // Create the in-memory index of the new/updated issue.
|
| | | DirCache index = createIndex(repository, headId, source, params.obliterate);
|
| | | ObjectId indexTreeId = index.writeTree(odi);
|
| | |
|
| | | // Create a commit object
|
| | | PersonIdent author = new PersonIdent("Gitblit", "gitblit@localhost");
|
| | | CommitBuilder commit = new CommitBuilder();
|
| | | commit.setAuthor(author);
|
| | | commit.setCommitter(author);
|
| | | commit.setEncoding(Constants.CHARACTER_ENCODING);
|
| | | commit.setMessage("updated pages");
|
| | | commit.setParentId(headId);
|
| | | commit.setTreeId(indexTreeId);
|
| | |
|
| | | // Insert the commit into the repository
|
| | | ObjectId commitId = odi.insert(commit);
|
| | | odi.flush();
|
| | |
|
| | | RevWalk revWalk = new RevWalk(repository);
|
| | | try {
|
| | | RevCommit revCommit = revWalk.parseCommit(commitId);
|
| | | RefUpdate ru = repository.updateRef(ghpages);
|
| | | ru.setNewObjectId(commitId);
|
| | | ru.setExpectedOldObjectId(headId);
|
| | | ru.setRefLogMessage("commit: " + revCommit.getShortMessage(), false);
|
| | | Result rc = ru.forceUpdate();
|
| | | switch (rc) {
|
| | | case NEW:
|
| | | case FORCED:
|
| | | case FAST_FORWARD:
|
| | | break;
|
| | | case REJECTED:
|
| | | case LOCK_FAILURE:
|
| | | throw new ConcurrentRefUpdateException(JGitText.get().couldNotLockHEAD,
|
| | | ru.getRef(), rc);
|
| | | default:
|
| | | throw new JGitInternalException(MessageFormat.format(
|
| | | JGitText.get().updatingRefFailed, ghpages, commitId.toString(), rc));
|
| | | }
|
| | | } finally {
|
| | | revWalk.release();
|
| | | }
|
| | | } finally {
|
| | | odi.release();
|
| | | }
|
| | | System.out.println("gh-pages updated.");
|
| | | } catch (Throwable t) {
|
| | | t.printStackTrace();
|
| | | }
|
| | | }
|
| | |
|
| | | /**
|
| | | * Creates an in-memory index of the issue change.
|
| | | * |
| | | * @param repo
|
| | | * @param headId
|
| | | * @param sourceFolder
|
| | | * @param obliterate
|
| | | * if true the source folder tree is used as the new tree for
|
| | | * gh-pages and non-existent files are considered deleted
|
| | | * @return an in-memory index
|
| | | * @throws IOException
|
| | | */
|
| | | private static DirCache createIndex(Repository repo, ObjectId headId, File sourceFolder,
|
| | | boolean obliterate) throws IOException {
|
| | |
|
| | | DirCache inCoreIndex = DirCache.newInCore();
|
| | | DirCacheBuilder dcBuilder = inCoreIndex.builder();
|
| | | ObjectInserter inserter = repo.newObjectInserter();
|
| | |
|
| | | try {
|
| | | // Add all files to the temporary index
|
| | | Set<String> ignorePaths = new TreeSet<String>();
|
| | | List<File> files = listFiles(sourceFolder);
|
| | | for (File file : files) {
|
| | | // create an index entry for the file
|
| | | final DirCacheEntry dcEntry = new DirCacheEntry(StringUtils.getRelativePath(
|
| | | sourceFolder.getPath(), file.getPath()));
|
| | | dcEntry.setLength(file.length());
|
| | | dcEntry.setLastModified(file.lastModified());
|
| | | dcEntry.setFileMode(FileMode.REGULAR_FILE);
|
| | |
|
| | | // add this entry to the ignore paths set
|
| | | ignorePaths.add(dcEntry.getPathString());
|
| | |
|
| | | // insert object
|
| | | InputStream inputStream = new FileInputStream(file);
|
| | | try {
|
| | | dcEntry.setObjectId(inserter.insert(Constants.OBJ_BLOB, file.length(),
|
| | | inputStream));
|
| | | } finally {
|
| | | inputStream.close();
|
| | | }
|
| | |
|
| | | // add to temporary in-core index
|
| | | dcBuilder.add(dcEntry);
|
| | | }
|
| | |
|
| | | if (!obliterate) {
|
| | | // Traverse HEAD to add all other paths
|
| | | TreeWalk treeWalk = new TreeWalk(repo);
|
| | | int hIdx = -1;
|
| | | if (headId != null)
|
| | | hIdx = treeWalk.addTree(new RevWalk(repo).parseTree(headId));
|
| | | treeWalk.setRecursive(true);
|
| | |
|
| | | while (treeWalk.next()) {
|
| | | String path = treeWalk.getPathString();
|
| | | CanonicalTreeParser hTree = null;
|
| | | if (hIdx != -1)
|
| | | hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class);
|
| | | if (!ignorePaths.contains(path)) {
|
| | | // add entries from HEAD for all other paths
|
| | | if (hTree != null) {
|
| | | // create a new DirCacheEntry with data retrieved
|
| | | // from
|
| | | // HEAD
|
| | | final DirCacheEntry dcEntry = new DirCacheEntry(path);
|
| | | dcEntry.setObjectId(hTree.getEntryObjectId());
|
| | | dcEntry.setFileMode(hTree.getEntryFileMode());
|
| | |
|
| | | // add to temporary in-core index
|
| | | dcBuilder.add(dcEntry);
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | // release the treewalk
|
| | | treeWalk.release();
|
| | | }
|
| | | |
| | | // finish temporary in-core index used for this commit
|
| | | dcBuilder.finish();
|
| | | } finally {
|
| | | inserter.release();
|
| | | }
|
| | | return inCoreIndex;
|
| | | }
|
| | |
|
| | | private static List<File> listFiles(File folder) {
|
| | | List<File> files = new ArrayList<File>();
|
| | | for (File file : folder.listFiles()) {
|
| | | if (file.isDirectory()) {
|
| | | files.addAll(listFiles(file));
|
| | | } else {
|
| | | files.add(file);
|
| | | }
|
| | | }
|
| | | return files;
|
| | | }
|
| | |
|
| | | /**
|
| | | * JCommander Parameters class for BuildGhPages.
|
| | | */
|
| | | @Parameters(separators = " ")
|
| | | private static class Params {
|
| | |
|
| | | @Parameter(names = { "--sourceFolder" }, description = "Source folder for pages", required = true)
|
| | | public String sourceFolder;
|
| | |
|
| | | @Parameter(names = { "--repository" }, description = "Repository folder", required = true)
|
| | | public String repositoryFolder;
|
| | |
|
| | | @Parameter(names = { "--obliterate" }, description = "Replace gh-pages tree with only the content in your sourcefolder")
|
| | | public boolean obliterate;
|
| | |
|
| | | }
|
| | | }
|