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!
 |