hyper-scripter-util 0.7.5

Tools for hyper-scripter. Not indetended to be used directly.
Documentation
# frozen_string_literal: true

# [HS_HELP]: Create git commit for hyper-scripter home.
# [HS_HELP]:
# [HS_HELP]: The commit message is auto-generated by date and hyper-scripter home
# [HS_HELP]: e.g. [Auto Commit 2022-11-30 (my_scripts)]
# [HS_HELP]: You can modify this message so that the commit is not treated as auto-generated
# [HS_HELP]: Consecutive auto-generated commit with same message will be merged (using --amend)
# [HS_HELP]:
# [HS_HELP]: USAGE:
# [HS_HELP]:     hs commit

require_relative './common'

def dump_db
  require 'tempfile'
  file = Tempfile.new('script_info')
  system("cp .script_info.db #{file.path}")
  system("sqlite3 #{file.path} 'DELETE FROM last_events'")
  system("sqlite3 #{file.path} '.dump' > .script_info.sql")
end

REAL_HS_HOME = File.realpath(HS_ENV.home)
Dir.chdir(REAL_HS_HOME)
dump_db

GIT_HOME = run_cmd('git rev-parse --show-toplevel').chop
BRANCH = run_cmd('git rev-parse --abbrev-ref HEAD').chop
REMOTE = 'origin'
Dir.chdir(GIT_HOME)

def confirm(msg)
  loop do
    $stderr.print(msg, ' ')
    case read_char
    when 'y', 'Y'
      warn 'Y'
      return true
    when 'n', 'N'
      warn 'N'
      return false
    else
      warn 'Only Y and N is allowed'
    end
  end
end

def get_branch_state
  ahead = !run_cmd("git rev-list #{REMOTE}/#{BRANCH}..#{BRANCH}").chop.empty?
  behind = !run_cmd("git rev-list #{BRANCH}..#{REMOTE}/#{BRANCH}").chop.empty?
  if ahead && behind
    :diverged
  elsif ahead
    :ahead
  elsif behind
    :behind
  else
    :up_to_date
  end
end
system('git fetch --all', exception: true)
branch_state = get_branch_state
warn "branch state = #{branch_state}"

# Check if diverge
if branch_state == :diverged
  warn 'branch is diverged!'
  exit 1
end

def recur_check_dirty(file)
  return if File.identical?(REAL_HS_HOME, file)

  unless REAL_HS_HOME.start_with?(file)
    status = run_cmd("git status #{file} --porcelain")
    unless status.empty?
      warn status
      ok = confirm("#{file} is not clean. Sure to proceed? [Y/N]")
      exit 1 unless ok
    end
    return
  end

  Dir.foreach(file) do |f|
    next if ['.', '..', '.git'].include?(f)

    recur_check_dirty("#{file}/#{f}")
  end
end

recur_check_dirty(GIT_HOME)

if branch_state == :behind
  # Check if remote had changed
  system('git add -A', exception: true)
  system('git stash', exception: true)

  if File.exist?(REAL_HS_HOME) # else: hs home was just created, no need to check
    diff = run_cmd("git diff --stat #{REMOTE}/#{BRANCH} #{REAL_HS_HOME}").chop
    unless diff.empty?
      warn 'remote home had changed!'
      warn diff
      system('git stash pop', exception: true)
      exit 1
    end
  end

  # prepare the files
  system('git pull', exception: true)
  system('git stash pop', exception: true)
end

# create the commit
last_commit_msg = run_cmd("git log --pretty=format:'%s' --max-count 1")

date = Time.now.utc
date_str = date.strftime('%Y-%m-%d')
msg = "[Auto Commit #{date_str} (#{File.basename(REAL_HS_HOME)})]"

system('git add -A', exception: true)
if last_commit_msg.start_with?(msg)
  warn 'Amend the last commit'
else
  warn 'Create new commit'
  system("git commit -m '#{msg}'", exception: true)
end

system('git commit --amend', exception: true)