blob: f9760fee6b072e80e7f23302be677b13deef942a [file] [log] [blame]
#!/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!