lib/origen/revision_control/git.rb in origen-0.1.3 vs lib/origen/revision_control/git.rb in origen-0.2.0

- old
+ new

@@ -23,13 +23,18 @@ puts 'Please supply a branch name as the version to checkout the latest version of it, e.g. origen rc co -v develop' exit 1 end if options[:force] - git 'reset HEAD' - git 'pull', options - git "checkout #{version} #{paths.join(' ')}", options + version = "origin/#{version}" if remote_branch?(version) + if paths == [local.to_s] + git "reset --hard #{version}" + else + git 'reset HEAD' + git 'pull', options + git "checkout #{version} #{paths.join(' ')}", options + end else if paths.size > 1 || paths.first != local.to_s fail 'The Git driver does not support partial merge checkout, it has to be the whole workspace' end git 'reset HEAD' @@ -61,12 +66,12 @@ def checkin(path = nil, options = {}) paths, options = clean_path(path, options) # Can't check in unless we have the latest if options[:force] && !options[:initial] # Locally check in the given files - checkin(paths.join(' '), local: true, verbose: false, comment: options[:comment]) - local_rev = current_commit + checkin(paths.join(' '), no_push: true, verbose: false, comment: options[:comment]) + local_rev = current_commit(short: false) # Pull latest checkout # Restore the given files to our previous version # Errors are ignored here since this can fail if the given file didn't exist until now, # in that case we already implicitly have the previous version @@ -101,11 +106,11 @@ if options[:time] cmd += " --date=\"#{options[:time].strftime('%a %b %e %H:%M:%S %Y %z')}\"" end git cmd, options end - git "push origin #{current_branch}" unless options[:local] + git "push origin #{current_branch}" unless options[:no_push] paths end # Returns true if the current user can checkin to the given repo (means has permission # to push in Git terms) @@ -159,12 +164,16 @@ }.merge(options) cmd = "ls-files #{paths.first} --exclude-standard --others" git(cmd, options).map(&:strip) end - def diff_cmd(file, version) - "git difftool --tool tkdiff -y #{prefix_tag(version)} #{file}" + def diff_cmd(file, version = nil) + if version + "git difftool --tool tkdiff -y #{prefix_tag(version)} #{file}" + else + "git difftool --tool tkdiff -y #{file}" + end end def tag(id, options = {}) id = VersionString.new(id) id = id.prefixed if id.semantic? @@ -182,36 +191,96 @@ def current_branch git('rev-parse --abbrev-ref HEAD', verbose: false).first end + def current_commit(options = {}) + options = { + short: true + }.merge(options) + commit = git('rev-parse HEAD', verbose: false).first + if options[:short] + commit[0, 11] + else + commit + end + end + # Returns true if the given tag already exists def tag_exists?(tag) git('fetch', verbose: false) unless @all_tags_fetched @all_tags_fetched = true git('tag', verbose: false).include?(tag.to_s) end + # Returns true if the given string matches a branch name in the remote repo + # Origen.app.rc.remote_branch?("master") # => true + # Origen.app.rc.remote_branch?("feature/exists") # => true + # Origen.app.rc.remote_branch?("feature/does_not_exist") # => false + def remote_branch?(str) + # Github doesn't like the ssh:// for this command, whereas Stash seems + # to require it. + if github? + rem = remote_without_protocol + else + rem = remote + end + !git("ls-remote --heads #{rem} #{str}", verbose: false).empty? + end + def initialized? File.exist?("#{local}/.git") && - git('remote -v', verbose: false).any? { |r| r =~ /#{remote_without_protocol}/ } && + git('remote -v', verbose: false).any? { |r| r =~ /#{remote_without_protocol_and_user}/ || r =~ /#{remote_without_protocol_and_user.to_s.gsub(':', "\/")}/ } && !git('status', verbose: false).any? { |l| l =~ /^#? ?Initial commit$/ } end # Delete everything in the given directory, or the whole repo def delete_all(dir = nil, options = {}) paths, options = clean_path(dir, options) files = git("ls-files #{paths.first}") FileUtils.rm_f files end + # A class method is provided to fetch the user name since it is useful to have access + # to this when outside of an application workspace, e.g. when creating a new app + def self.user_name + git('config user.name', verbose: false).first + rescue + nil + end + + # A class method is provided to fetch the user email since it is useful to have access + # to this when outside of an application workspace, e.g. when creating a new app + def self.user_email + git('config user.email', verbose: false).first + rescue + nil + end + + def user_name + self.class.user_name + end + + def user_email + self.class.user_email + end + + # Returns true if the remote points to a github url + def github? + !!(remote.to_s =~ /github.com/) + end + private def remote_without_protocol Pathname.new(remote.sub(/^.*:\/\//, '')) end + def remote_without_protocol_and_user + Pathname.new(remote_without_protocol.to_s.sub(/^.*@/, '')) + end + def create_gitignore c = Origen::Generator::Compiler.new c.compile "#{Origen.top}/templates/git/gitignore.erb", output_directory: local, quiet: true, @@ -221,35 +290,36 @@ def changes_pending_commit? !(git('status --verbose', verbose: false).last =~ /^(no changes|nothing to commit)/) end - def current_commit - git('rev-parse HEAD', verbose: false).first - end - def initialize_local_dir super unless initialized? Origen.log.debug "Initializing Git workspace at #{local}" git 'init' git "remote add origin #{remote}" end end - # Execute a git operation, the resultant output is returned in an array def git(command, options = {}) + options[:local] = local + self.class.git(command, options) + end + + # Execute a git operation, the resultant output is returned in an array + def self.git(command, options = {}) options = { check_errors: true, verbose: true }.merge(options) output = [] if options[:verbose] Origen.log.info "git #{command}" Origen.log.info '' end - Dir.chdir local do + chdir options[:local] do Open3.popen2e("git #{command}") do |_stdin, stdout_err, wait_thr| while line = stdout_err.gets Origen.log.info line.strip if options[:verbose] unless line.strip.empty? output << line.strip @@ -263,9 +333,19 @@ end end end end output + end + + def self.chdir(dir) + if dir + Dir.chdir dir do + yield + end + else + yield + end end end end end