# -*- coding: UTF-8 -*- require 'mj/tools/subprocess' require 'mj/error' # # module MJ; module VCS; module Git; @git_available = nil # Is the git executable available? def self.git_available?() return @git_available unless @git_available.nil? %x( git --version 2>&1 ) @git_available = $?.success? return @git_available end # Thrown if git signals a problem class GitError < MJ::Error; end # A (local) git repository. # class Repository include MJ::Tools::SubProcess attr_reader :path # Some helper methods that should be factored out somewhere # Create directory +dir+ recursively if needed. def mkdir_p(dir) logger.debug "mkdir -p #{dir}" FileUtils.mkdir_p(dir) if !@noop end # Checkout a branch def checkout(opts) if ! exist? and ! $noop raise GitError, "Repository #{path} does not exist!" end # Fetch only from remote if specified git("checkout " + opts) end # Clone a repository def clone(url, branch = 'master' ) # Initialize the repository init(url) remote_add(url, "origin") fetch("origin") checkout("-b master origin/#{branch}") end # def clone # Check if the repository exists def exist? # If path does not exist the repo does not exist return false if !path.exist? # If the path is not a directory we have a problem raise GitError, "#{path.to_s} is not a directory!" if !path.directory? # If the path is a directory but no .git directory is found we have a problem too if !path.join( ".git" ).exist? raise GitError, "#{path.to_s} is not a git repo!" end return true end def fetch(remote = nil) if ! exist? and ! $noop raise GitError, "Repository #{path} does not exist!" end # Fetch only from remote if specified cmd = "fetch" if remote cmd += " -q #{remote}" end git(cmd) end # Execute +command+ from working directory +wd+. If specified call +block+ with every line # of command output. def git(command, wd = path, &block) rc = self.class.execute "git #{command}", wd, &block if rc != 0 raise GitError, "git #{command || "" } failed with error code #{rc}"; end rc end def init(url) # If the repository already exists we cannot initialize if exist? raise GitError, "Repository #{path} already exists!" end # Create the repository parent directory if needed mkdir_p path # Initialize the repository git("init") end # If +noop+ is true no methods invoked on this object actually do any changes. The # required actions will be logged but not executed. def initialize(path, noop=false) @path = path @noop = noop end def log(rev="") @lines = Array.new git("log #{rev}") do |line| @lines << line end @lines end def rebase(branch, remote="origin") if ! exist? and ! $noop raise GitError, "Repository #{path} does not exist!" end # Fetch only from remote if specified cmd = "rebase " if remote cmd += "#{remote}/#{branch}" else cmd += "origin/#{branch}" end git(cmd) end # Add a new remote def remote_add(url, name) if ! exist? and ! $noop raise GitError, "Repository #{path} does not exist!" end # Add the origin remote git("remote add #{name} #{url.to_s}") end end # class Git end; end; end # module BuildTool::VCS::Git