001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.maven.scm.provider.git.jgit.command.branch; 020 021import java.util.ArrayList; 022import java.util.HashSet; 023import java.util.Iterator; 024import java.util.List; 025import java.util.Set; 026 027import org.apache.maven.scm.ScmException; 028import org.apache.maven.scm.ScmFile; 029import org.apache.maven.scm.ScmFileSet; 030import org.apache.maven.scm.ScmFileStatus; 031import org.apache.maven.scm.ScmResult; 032import org.apache.maven.scm.command.branch.AbstractBranchCommand; 033import org.apache.maven.scm.command.branch.BranchScmResult; 034import org.apache.maven.scm.provider.ScmProviderRepository; 035import org.apache.maven.scm.provider.git.command.GitCommand; 036import org.apache.maven.scm.provider.git.jgit.command.JGitUtils; 037import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository; 038import org.eclipse.jgit.api.Git; 039import org.eclipse.jgit.api.errors.GitAPIException; 040import org.eclipse.jgit.lib.Constants; 041import org.eclipse.jgit.lib.Ref; 042import org.eclipse.jgit.lib.Repository; 043import org.eclipse.jgit.revwalk.RevCommit; 044import org.eclipse.jgit.revwalk.RevWalk; 045import org.eclipse.jgit.transport.RefSpec; 046import org.eclipse.jgit.treewalk.TreeWalk; 047 048/** 049 * @author Dominik Bartholdi (imod) 050 * @since 1.9 051 */ 052public class JGitBranchCommand extends AbstractBranchCommand implements GitCommand { 053 054 /** 055 * {@inheritDoc} 056 */ 057 @Override 058 protected ScmResult executeBranchCommand( 059 ScmProviderRepository repo, ScmFileSet fileSet, String branch, String message) throws ScmException { 060 if (branch == null || branch.trim().isEmpty()) { 061 throw new ScmException("branch name must be specified"); 062 } 063 064 if (!fileSet.getFileList().isEmpty()) { 065 throw new ScmException("This provider doesn't support branching subsets of a directory"); 066 } 067 068 Git git = null; 069 try { 070 git = JGitUtils.openRepo(fileSet.getBasedir()); 071 Ref branchResult = git.branchCreate().setName(branch).call(); 072 logger.info("created [" + branchResult.getName() + "]"); 073 074 if (logger.isDebugEnabled()) { 075 for (String branchName : getShortLocalBranchNames(git)) { 076 logger.debug("local branch available: " + branchName); 077 } 078 } 079 080 if (repo.isPushChanges()) { 081 logger.info("push branch [" + branch + "] to remote..."); 082 JGitUtils.push(git, (GitScmProviderRepository) repo, new RefSpec(Constants.R_HEADS + branch)); 083 } 084 085 // search for the tagged files 086 final RevWalk revWalk = new RevWalk(git.getRepository()); 087 RevCommit commit = revWalk.parseCommit(branchResult.getObjectId()); 088 revWalk.close(); 089 090 final TreeWalk walk = new TreeWalk(git.getRepository()); 091 walk.reset(); // drop the first empty tree, which we do not need here 092 walk.setRecursive(true); 093 walk.addTree(commit.getTree()); 094 095 List<ScmFile> files = new ArrayList<>(); 096 while (walk.next()) { 097 files.add(new ScmFile(walk.getPathString(), ScmFileStatus.CHECKED_OUT)); 098 } 099 walk.close(); 100 101 return new BranchScmResult("JGit branch", files); 102 103 } catch (Exception e) { 104 throw new ScmException("JGit branch failed!", e); 105 } finally { 106 JGitUtils.closeRepo(git); 107 } 108 } 109 110 /** 111 * gets a set of names of the available branches in the given repo 112 * 113 * @param git the repo to list the branches for 114 * @return set of short branch names 115 * @throws GitAPIException 116 */ 117 public static Set<String> getShortLocalBranchNames(Git git) throws GitAPIException { 118 Set<String> branches = new HashSet<>(); 119 Iterator<Ref> iter = git.branchList().call().iterator(); 120 while (iter.hasNext()) { 121 branches.add(Repository.shortenRefName(iter.next().getName())); 122 } 123 return branches; 124 } 125}