221 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			Ruby
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			221 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			Ruby
		
	
	
		
			Executable file
		
	
	
	
	
#!/usr/bin/env ruby
 | 
						|
# git update-ghpages user/repo -b gh-pages -p manual/ -i
 | 
						|
 | 
						|
require 'fileutils'
 | 
						|
require 'tmpdir'
 | 
						|
 | 
						|
module Params
 | 
						|
  def extract(what)   i = index(what) and slice!(i, 2)[1] end;
 | 
						|
  def first_is(what)  shift  if what.include?(self.first); end
 | 
						|
  def self.[](*what)  what.extend Params; end
 | 
						|
  def ===(argv)       argv.first_is(self); end
 | 
						|
end
 | 
						|
 | 
						|
# ============================================================================
 | 
						|
 | 
						|
ARGV.extend Params
 | 
						|
 | 
						|
class CLI
 | 
						|
  # CLI options
 | 
						|
  attr_reader :prefix    #=> "doc/"
 | 
						|
  attr_reader :input     #=> "/home/me/projects/foo"
 | 
						|
  attr_reader :message   #=> "Updated"
 | 
						|
  attr_reader :repo      #=> "git@github.com:me/project.git"
 | 
						|
  attr_reader :url       #=> "http://me.github.com/project"
 | 
						|
  attr_reader :branch    #=> "gh-pages"
 | 
						|
 | 
						|
  def verbose?() @verbose; end
 | 
						|
  def force?() @force; end
 | 
						|
  def simulate?() @simulate; end
 | 
						|
 | 
						|
  def initialize
 | 
						|
    # Switches
 | 
						|
    @verbose  = !! (ARGV.extract('--verbose') || ARGV.delete('-v'))
 | 
						|
    @simulate = !! (ARGV.extract('--simulate') || ARGV.delete('-s'))
 | 
						|
    @force    = !! (ARGV.delete('--force') || ARGV.delete('-f'))
 | 
						|
 | 
						|
    # Stuff
 | 
						|
    @prefix   = ARGV.extract('--prefix') || ARGV.extract('-p') || ''
 | 
						|
    @input    = File.expand_path(ARGV.extract('--input') || ARGV.extract('-i') || '.')
 | 
						|
    @message  = ARGV.extract('--message') || ARGV.extract('-m') || 'Update'
 | 
						|
 | 
						|
    # Github info
 | 
						|
    branch = ARGV.extract('--branch') || ARGV.extract('-b') || nil
 | 
						|
    @repo, @url, @branch = get_github_info(ARGV.shift, branch)
 | 
						|
  end
 | 
						|
 | 
						|
  def git_current_branch
 | 
						|
    `git rev-parse --abbrev-ref HEAD`.strip
 | 
						|
  end
 | 
						|
 | 
						|
  def git_deploy
 | 
						|
    in_temp_path do |temppath|
 | 
						|
      status "Cloning repository"
 | 
						|
      system! "git clone #{repo} -b #{branch} #{temppath}"
 | 
						|
 | 
						|
      if git_current_branch != branch
 | 
						|
        status "Warning: No #{branch} branch found in repo, creating one."
 | 
						|
        return git_deploy_force
 | 
						|
      end
 | 
						|
 | 
						|
      copy_files input, File.join(temppath, prefix)
 | 
						|
 | 
						|
      status "Committing files"
 | 
						|
      system! "git add .; git add -u; git commit -m #{message.to_s.inspect}"
 | 
						|
 | 
						|
      unless simulate?
 | 
						|
        status "Updating repo"
 | 
						|
        system! "git push origin #{branch}"
 | 
						|
      end
 | 
						|
      true
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def git_deploy_force
 | 
						|
    in_temp_path do |temppath|
 | 
						|
      status "Creating new repository"
 | 
						|
      system! "git init ."
 | 
						|
      system! "git checkout -b gh-pages"
 | 
						|
 | 
						|
      copy_files input, File.join(temppath, prefix)
 | 
						|
 | 
						|
      status "Committing files"
 | 
						|
      system! "git add . && git commit -m #{message.to_s.inspect}"
 | 
						|
 | 
						|
      unless simulate?
 | 
						|
        status "Updating repo"
 | 
						|
        system! "git push #{repo} gh-pages:#{branch} --force"
 | 
						|
      end
 | 
						|
      true
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def get_github_info(repo, branch=nil, prefix=nil)
 | 
						|
    if github_format?(repo)
 | 
						|
      user, repo_name = repo.split('/')
 | 
						|
      r = "git@github.com:#{repo}.git"
 | 
						|
 | 
						|
      # User page or project page?
 | 
						|
      if repo_name =~ /\.github\.com/
 | 
						|
        [r, "http://#{repo_name}/#{prefix}", branch || 'master' ]
 | 
						|
      else
 | 
						|
        [r, "http://#{user}.github.com/#{repo_name}/#{prefix}", branch || 'gh-pages' ]
 | 
						|
      end
 | 
						|
    else
 | 
						|
      [repo, nil, branch]
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def run!
 | 
						|
    unless repo
 | 
						|
      print_help
 | 
						|
      exit 128
 | 
						|
    end
 | 
						|
 | 
						|
    status "Deploying to #{repo} (branch #{branch})"
 | 
						|
    msg "NOTE: Running in simulation mode." if simulate?
 | 
						|
    msg "WARNING: If the repository has gh-pages history, it with be overriden." if force? && !simulate?
 | 
						|
 | 
						|
    result = force? ? git_deploy_force : git_deploy
 | 
						|
 | 
						|
    if result
 | 
						|
      puts ""
 | 
						|
      status "Done."
 | 
						|
      msg "See: #{url}" if url && !simulate?
 | 
						|
    else
 | 
						|
      tip "Failed."
 | 
						|
      exit 1
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def status(str)
 | 
						|
    puts "#{c('===>',34)} #{c(str, 32)}"
 | 
						|
  end
 | 
						|
 | 
						|
  def msg(str)
 | 
						|
    puts "     #{c(str, 32)}"
 | 
						|
  end
 | 
						|
 | 
						|
  def c(str, color)
 | 
						|
    "\033[#{color}m#{str}\033[0m"
 | 
						|
  end
 | 
						|
 | 
						|
  def print_help
 | 
						|
    tip \
 | 
						|
    %{Usage: git update-ghpages username/repository [options]
 | 
						|
 | 
						|
      Flags:
 | 
						|
        -f,        --force       Force an update (WARNING: kills the history!)
 | 
						|
        -s,        --simulate    Creates the repository, but doesn't push.
 | 
						|
        -v,        --verbose     Verbose mode
 | 
						|
 | 
						|
      Options:
 | 
						|
        -p PATH,   --prefix      The prefix
 | 
						|
        -i PATH,   --input       Input (defaults to current directory)
 | 
						|
        -b BRANCH, --branch      The branch to deploy to (defaults to gh-pages)
 | 
						|
        -m MSG,    --message     Commit message (defaults to 'Update')
 | 
						|
 | 
						|
      Examples:
 | 
						|
 | 
						|
      Update the repo 'coffee' of github user 'james' with the files from the
 | 
						|
      current directory. The files will be in http://james.github.com/coffee.
 | 
						|
 | 
						|
        $ git update-ghpages james/coffee
 | 
						|
 | 
						|
      Same as above, but take the files from 'doc/'.
 | 
						|
 | 
						|
        $ git update-ghpages james/coffee -i doc
 | 
						|
 | 
						|
      Same as the first, but the files will instead be in
 | 
						|
      http://james.github.com/coffee/manual.
 | 
						|
 | 
						|
        $ git update-ghpages james/coffee -i doc -p manual
 | 
						|
    }.gsub(/^ {4}/, '')
 | 
						|
  end
 | 
						|
 | 
						|
private # Helpers
 | 
						|
 | 
						|
  def tip(msg)
 | 
						|
    $stderr.write "#{msg}\n"
 | 
						|
  end
 | 
						|
 | 
						|
  def github_format?(str)
 | 
						|
    str =~ /^([A-Za-z0-9\-_]+)\/([A-Za-z0-9\-_\.]+)$/
 | 
						|
  end
 | 
						|
 | 
						|
  # Performs actions inside a temp path.
 | 
						|
  def in_temp_path(&blk)
 | 
						|
    require 'tmpdir'
 | 
						|
    Dir.mktmpdir do |dir|
 | 
						|
      Dir.chdir(dir) { yield dir }
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def system!(str)
 | 
						|
    puts `#{str} 2>&1`.strip.gsub(/^/, "     ")
 | 
						|
    raise "Failed with exit code #{$?.to_i}" unless $?.to_i == 0
 | 
						|
  end
 | 
						|
 | 
						|
  # Returns the current branch name
 | 
						|
  def git_branch
 | 
						|
    `git symbolic-ref HEAD`.strip.split('/').last
 | 
						|
  end
 | 
						|
 | 
						|
  # Copy files from source folder to another
 | 
						|
  def copy_files(from, to)
 | 
						|
    status "Copying files #{from} => #{to}..."  if verbose?
 | 
						|
 | 
						|
    Dir["#{from}/**/*"].each do |f|
 | 
						|
      next  unless File.file?(f)
 | 
						|
 | 
						|
      target = File.join(to, f.gsub(/^#{Regexp.escape from}/, ''))
 | 
						|
 | 
						|
      FileUtils.mkdir_p File.dirname(target)
 | 
						|
      msg "%20s => %-20s" % [f, target]  if verbose?
 | 
						|
      FileUtils.cp f, target
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
CLI.new.run!
 |