class Processor

Constants

NO_BRANCH

Attributes

all_branches[R]
all_uniq_branches[R]
current_branch[R]
dry_run[R]
dry_run_flag[R]
no_prompt[R]
remote_branch[R]

Public Class Methods

new(global_options) click to toggle source
# File lib/ezgit/processor.rb, line 9
def initialize(global_options)
  @dry_run = global_options[:dry_run]
  @dry_run_flag = @dry_run ? '-n' : ''
  @no_prompt = global_options[:force]
end

Public Instance Methods

add_remote_to_branch(branch_name) click to toggle source
# File lib/ezgit/processor.rb, line 34
def add_remote_to_branch(branch_name)
  # Get remote name.  It may not be 'origin'
  origin = `git remote show`.gsub(/\s/, '')
  remote = "#{origin}/#{branch_name}"
  remote = all_branches.include?(remote) ? remote : ''
  return remote
end
check_local_changes(opts = nil) click to toggle source

returns (bool has_changes?, Array changes)

# File lib/ezgit/processor.rb, line 165
def check_local_changes(opts = nil)
  ignored = (opts.nil? || opts[:ignored] == false) ? '' : '--ignored'
  stdin, stdout, stderr = Open3.popen3("git status --untracked-files=all --porcelain #{ignored}")
  changes = stdout.readlines
  return changes.any?, changes
end
check_remote_status() click to toggle source

returns :up_to_date/:no_remote/:rebase/:ahead/:behind, count

# File lib/ezgit/processor.rb, line 111
def check_remote_status
  return :headless if current_branch == NO_BRANCH
  ahead_count_rgx = /.*ahead.(\d+)/
  behind_count_rgx = /.*behind.(\d+)/
  stdin, stdout, stderr = Open3.popen3('git status -bs')
  stat = stdout.readlines[0]
  ahead_match = stat.match(ahead_count_rgx)
  ahead_count = (ahead_match.nil?) ? '0' : ahead_match[1]
  behind_match = stat.match(behind_count_rgx)
  behind_count = (behind_match.nil?) ? '0' : behind_match[1]
  case
    when ahead_count > '0' && behind_count == '0'
      return :ahead, ahead_count
    when ahead_count == '0' && behind_count > '0'
      return :behind, behind_count
    when ahead_count > '0' && behind_count > '0'
      return :rebase, '0'
    else
      return :no_remote, '0' if remote_branch.empty?
      return :up_to_date, '0'
  end
end
clean!(wipe_ignored) click to toggle source
# File lib/ezgit/processor.rb, line 200
def clean!(wipe_ignored)
  command = 'git clean -df'
  command += 'x' if wipe_ignored
  out, err = call_command_with_out_error(command + 'n')
  puts err.red.bold unless no_prompt
  return puts 'Nothing to clean.'.green if err.empty?
  return if dry_run
  run_lambda_with_prompt do
    puts `#{command}`
  end
end
clone(args) click to toggle source
# File lib/ezgit/processor.rb, line 191
def clone(args)
  return puts 'invalid number of arguments. Requires a source. (Destination is optional.)' if args.count < 1 || args.count > 2
  return if @dry_run
  puts out = `git clone #{args.first} #{args[1]}`
  repo_name = args[1] || out.split('\'')[1]
  puts 'You have created a copy of ' + args.first.to_s.bold + ' in the ' + repo_name.bold + ' directory.' if $? == 0
end
commit(args) click to toggle source
# File lib/ezgit/processor.rb, line 336
def commit(args)
  return puts "Please specify a message.".yellow.bold if args.count < 1
  return puts "Invalid number of arguments. Please specify only a message.".yellow.bold if args.count > 1
  has_changes, changes = check_local_changes
  return puts "There are no changes to commit".yellow.bold unless has_changes
  commit_id = args[0].to_s
  puts `git add -A`
  puts `git commit -m "#{commit_id}"`
end
create(args) click to toggle source
# File lib/ezgit/processor.rb, line 256
def create(args)
  return puts 'Please specify a branch name.'.yellow.bold if args.count < 1
  return puts 'Invalid number of arguments. Please specify only a branch name.'.yellow.bold if args.count > 1
  branch_name = args[0].to_s
  return puts "Would create branch: #{branch_name}" if dry_run
  `git checkout -b #{branch_name}`
  display_branch_list_with_current
  display_current_changes
end
delete!(args) click to toggle source
# File lib/ezgit/processor.rb, line 267
def delete!(args)
  return puts "Please specify a branch name.".yellow.bold if args.count < 1
  return puts "Invalid number of arguments. Please specify only a branch name.".yellow.bold if args.count > 1
  branch_name = args[0].to_s
  is_master = branch_name.eql?('master') || branch_name.eql?(add_remote_to_branch('master'))
  return puts "Cannot delete ".red + branch_name.red.bold + ".".red if is_master
  branches = []
  is_local = all_branches.include?(branch_name)
  branches << branch_name if is_local
  remote_name = add_remote_to_branch(branch_name)
  is_remote = all_branches.include?(remote_name)
  branches << remote_name if is_remote
  return puts "Cannot delete ".red + branch_name.red.bold + " while you are using it. Please switch to another branch and try again.".red if branches.include?(current_branch)
  return puts "Branch does not exist: ".red + branch_name.red.bold unless branches.any?
  return puts "Would completely delete branches: #{branches.join(',')}" if @dry_run
  print "  Are you sure you want to delete '#{branch_name}'(y/n)?".red.bold unless no_prompt
  return unless run_lambda_with_prompt do
    puts `git push --delete #{remote_name.sub('/', ' ')}` if is_remote
    puts `git branch -D #{branch_name}` if is_local
    refresh_branches
    display_branch_list_with_current
  end
end
display_branch_list_with_current() click to toggle source
# File lib/ezgit/processor.rb, line 87
def display_branch_list_with_current
  puts ''
  puts '  BRANCHES:'.bold
  brs = []
  all_uniq_branches.each do |b|
    #add an indicator if it is the current branch
    b = b.eql?(current_branch) ? "#{b} <-- CURRENT".bold : b
    # output the list
    puts "  #{b}".cyan
  end
end
display_current_changes(opts = nil) click to toggle source
# File lib/ezgit/processor.rb, line 173
def display_current_changes(opts = nil)
  puts ''
  puts "  TO BE COMMITTED ON: #{current_branch}".bold
  has_changes, changes = check_local_changes(opts)
  puts "  No changes.".green unless has_changes
  changes.collect! { |line|
    line.sub!('!! ', CYAN + "  ignore  " + CLEAR)
    line.gsub!(/ U |U  /, RED + BOLD + "   MERGE  " + CLEAR)
    line.gsub!(/ D |D  /, RED + BOLD + "  Delete  " + CLEAR)
    line.gsub!(/.R |R. /, YELLOW + BOLD + "  Rename  " + CLEAR)
    line.gsub!(/A  |\?\? /, YELLOW + BOLD + "     Add  " + CLEAR)
    line.gsub!(/.M |M. /, YELLOW + BOLD + "  Change  " + CLEAR)
    line
  }
  puts changes.sort!
end
display_log_graph(count = 5, show_all = false) click to toggle source
# File lib/ezgit/processor.rb, line 76
def display_log_graph(count = 5, show_all = false)
  puts ''
  puts "REPOSITORY TREE".bold + "(last #{count} commits)"
  all = show_all ? '--all' : ''
  stdin, stdout, stderr = Open3.popen3("git log --graph #{all} --format=format:\"#{CYAN}%h #{CLEAR + CYAN}(%cr) #{CYAN}%cn #{CLEAR}%s#{CYAN + BOLD}%d#{CLEAR}\" --abbrev-commit --date=relative -n #{count}")
  err = stderr.readlines
  return puts 'There is no history yet.'.cyan.bold if err.any?
  puts err.join('') + stdout.readlines.join('')
end
display_sync_status() click to toggle source
# File lib/ezgit/processor.rb, line 135
def display_sync_status
  puts ''
  puts '  SYNC STATUS:'.bold
  stat, count = check_remote_status
  commit_s = (count == 1) ? 'commit' : 'commits'
  case stat
    when :ahead
      puts "  Your #{current_branch.bold + CYAN} branch is ahead of the remote by #{count} #{commit_s}.".cyan
      puts "  (Use 'ezgit pull' to update the remote.)".cyan
    when :behind
      puts "  Your #{current_branch.bold + YELLOW} branch is behind the remote by #{count} #{commit_s}.".yellow
      puts "  (Use 'ezgit pull' to get the new changes.)".yellow
    when :rebase
      puts "  Your #{current_branch} branch has diverged #{count} #{commit_s} from the remote.".red.bold
      puts "  (Use must use git directly to put them back in sync.)".red.bold
    when :no_remote
      puts "  Your #{current_branch.bold + CYAN} branch does not yet exist on the remote.".cyan
      puts "  (Use 'ezgit pull' to update the remote.)".cyan
    when :headless
      puts "  You are in a headless state (not on a branch)".red.bold
      puts "  (Use 'ezgit create <branch>' to create a branch at this commit,".red.bold
      puts "   or use 'ezgit switch <branch>' to switch to a branch.)".red.bold
    else
      puts "  Your #{current_branch.bold + GREEN} branch is in sync with the remote.".green
      puts "  (Use 'ezgit pull' to ensure it stays in sync.)".green
  end
end
fetch() click to toggle source
# File lib/ezgit/processor.rb, line 347
def fetch
  stdin, stdout, stderr = Open3.popen3("git fetch -p #{@dry_run_flag}")
  puts stderr.readlines.join('') + stdout.readlines.join('')
  refresh_branches
end
goto!(args) click to toggle source
# File lib/ezgit/processor.rb, line 244
def goto!(args)
  return puts "Please specify a commit id.".yellow.bold if args.count < 1
  return puts "Invalid number of arguments. Please specify only a commit id.".yellow.bold if args.count > 1
  commit_id = args[0].to_s
  return puts "Would go to #{commit_id}" if dry_run
  puts "About to go to #{commit_id}. All changes in tracked files will be lost.".red.bold unless no_prompt
  run_lambda_with_prompt do
    puts `git reset --hard #{commit_id}`
  end
end
info() click to toggle source
# File lib/ezgit/processor.rb, line 100
def info
  puts '________________________________'
  display_log_graph
  display_branch_list_with_current
  display_current_changes
  display_sync_status
  puts '________________________________'
end
prompt_for_y_n() click to toggle source
# File lib/ezgit/processor.rb, line 213
def prompt_for_y_n
  begin
    system("stty raw -echo")
    input = STDIN.getc
  ensure
    system("stty -raw echo")
  end
  out = input.to_s.downcase.eql?('y')
  puts input.to_s
  return out
end
pull() click to toggle source
# File lib/ezgit/processor.rb, line 354
def pull
  fetch
  stat, count = check_remote_status
  case stat
    when :rebase
      if @dry_run
        puts 'would merge changes'
        display_sync_status
        return
      end
      puts `git rebase #{remote_branch}`
      #TODO: CONFLICT HANDLING?
      puts 'TODO: CONFLICT HANDLING?'
    when :behind
      if @dry_run
        puts "would reset branch to #{remote_branch}"
        display_sync_status
        return
      end
      puts `git reset --hard #{remote_branch}`
    when :headless
      puts '  You cannot pull unless you are on a branch.'.red.bold
      display_sync_status
      return
  end
  info
end
push() click to toggle source
# File lib/ezgit/processor.rb, line 383
def push
  stat, count = check_remote_status
  if stat.eql?(:rebase) || stat.eql?(:behind)
    puts "  The remote has been updated since you began this sync.".yellow.bold
    puts "  Try running 'ezgit pull' again".yellow.bold
  elsif stat.eql?(:no_remote) || stat.eql?(:ahead)
    puts `git push -u #{remote_branch.sub('/', ' ')}`
    refresh_branches
  elsif stat.eql?(:headless)
    puts '  You cannot push unless you are on a branch.'.red.bold
  else
    #:up_to_date | :headless
  end
  info
end
refresh_branches() click to toggle source
# File lib/ezgit/processor.rb, line 43
def refresh_branches
  @all_branches = nil
  @all_uniq_branches = nil
end
reset_hard!() click to toggle source
# File lib/ezgit/processor.rb, line 235
def reset_hard!
  return if @dry_run
  puts 'All changes in tracked files will be lost.'.red.bold unless no_prompt
  run_lambda_with_prompt do
    puts `git reset --hard`
  end
end
run_lambda_with_prompt(opts = nil) { || ... } click to toggle source
# File lib/ezgit/processor.rb, line 226
def run_lambda_with_prompt(opts = nil)
  unless no_prompt
    puts 'proceed(y/n)? '.bold
    return unless prompt_for_y_n
  end
  yield
end
switch!(mode, args) click to toggle source

Three modes:

:switch  - switch if there are not changes. Otherwise halt!
:switch! - clobber all files before switching
:move    - move files with switch
# File lib/ezgit/processor.rb, line 296
def switch!(mode, args)
  return puts "Please specify a branch name.".yellow.bold if args.count < 1
  return puts "Invalid number of arguments. Please specify only a branch name.".yellow.bold if args.count > 1
  branch_name = args[0].to_s
  return puts "Please specify a valid branch." unless all_uniq_branches.include?(branch_name)
  return puts "Already on branch: #{current_branch.bold}".green if current_branch.eql?(branch_name)
  has_changes, changes = check_local_changes
  #move files with switch
  if mode == 'move'
    x = `git checkout #{branch_name}`
    return
  end
  #switch if there are not changes. Otherwise halt!
  if has_changes && mode == 'switch'
    display_current_changes
    puts "  Cannot switch branches when you have unresolved changes".red
    puts "  Use ".red + "'ezgit switch! <branch>'".red.bold + " to abandon your changes and switch anyway,".red
    puts "  or use ".red + "'ezgit move <branch>'".red.bold + " to move your changes and switch.".red
    return
  end
  #clobber all files before switching
  #respect the -f option
  if has_changes && mode == 'switch!'
    unless no_prompt
      display_current_changes
      puts ''
      print "  WARNING: You may lose changes if you switch branches without committing.".red.bold
    end
    return unless run_lambda_with_prompt do
      @no_prompt = true
      x = `git clean -df`
      x = `git checkout -f #{branch_name}`
      return
    end
    x = `git clean -df`
  end
  x = `git checkout -f #{branch_name}`
end

Private Instance Methods

call_command_with_out_error(command) click to toggle source
# File lib/ezgit/processor.rb, line 403
def call_command_with_out_error(command)
  stdin, stdout, stderr = Open3.popen3(command)
  out = stderr.readlines.join('')
  err = stdout.readlines.join('')
  return out, err
end