You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

221 lines
5.7 KiB

  1. #!/usr/bin/env ruby
  2. # git update-ghpages user/repo -b gh-pages -p manual/ -i
  3. require 'fileutils'
  4. require 'tmpdir'
  5. module Params
  6. def extract(what) i = index(what) and slice!(i, 2)[1] end;
  7. def first_is(what) shift if what.include?(self.first); end
  8. def self.[](*what) what.extend Params; end
  9. def ===(argv) argv.first_is(self); end
  10. end
  11. # ============================================================================
  12. ARGV.extend Params
  13. class CLI
  14. # CLI options
  15. attr_reader :prefix #=> "doc/"
  16. attr_reader :input #=> "/home/me/projects/foo"
  17. attr_reader :message #=> "Updated"
  18. attr_reader :repo #=> "git@github.com:me/project.git"
  19. attr_reader :url #=> "http://me.github.com/project"
  20. attr_reader :branch #=> "gh-pages"
  21. def verbose?() @verbose; end
  22. def force?() @force; end
  23. def simulate?() @simulate; end
  24. def initialize
  25. # Switches
  26. @verbose = !! (ARGV.extract('--verbose') || ARGV.delete('-v'))
  27. @simulate = !! (ARGV.extract('--simulate') || ARGV.delete('-s'))
  28. @force = !! (ARGV.delete('--force') || ARGV.delete('-f'))
  29. # Stuff
  30. @prefix = ARGV.extract('--prefix') || ARGV.extract('-p') || ''
  31. @input = File.expand_path(ARGV.extract('--input') || ARGV.extract('-i') || '.')
  32. @message = ARGV.extract('--message') || ARGV.extract('-m') || 'Update'
  33. # Github info
  34. branch = ARGV.extract('--branch') || ARGV.extract('-b') || nil
  35. @repo, @url, @branch = get_github_info(ARGV.shift, branch)
  36. end
  37. def git_current_branch
  38. `git rev-parse --abbrev-ref HEAD`.strip
  39. end
  40. def git_deploy
  41. in_temp_path do |temppath|
  42. status "Cloning repository"
  43. system! "git clone #{repo} -b #{branch} #{temppath}"
  44. if git_current_branch != branch
  45. status "Warning: No #{branch} branch found in repo, creating one."
  46. return git_deploy_force
  47. end
  48. copy_files input, File.join(temppath, prefix)
  49. status "Committing files"
  50. system! "git add .; git add -u; git commit -m #{message.to_s.inspect}"
  51. unless simulate?
  52. status "Updating repo"
  53. system! "git push origin #{branch}"
  54. end
  55. true
  56. end
  57. end
  58. def git_deploy_force
  59. in_temp_path do |temppath|
  60. status "Creating new repository"
  61. system! "git init ."
  62. system! "git checkout -b gh-pages"
  63. copy_files input, File.join(temppath, prefix)
  64. status "Committing files"
  65. system! "git add . && git commit -m #{message.to_s.inspect}"
  66. unless simulate?
  67. status "Updating repo"
  68. system! "git push #{repo} gh-pages:#{branch} --force"
  69. end
  70. true
  71. end
  72. end
  73. def get_github_info(repo, branch=nil, prefix=nil)
  74. if github_format?(repo)
  75. user, repo_name = repo.split('/')
  76. r = "git@github.com:#{repo}.git"
  77. # User page or project page?
  78. if repo_name =~ /\.github\.com/
  79. [r, "http://#{repo_name}/#{prefix}", branch || 'master' ]
  80. else
  81. [r, "http://#{user}.github.com/#{repo_name}/#{prefix}", branch || 'gh-pages' ]
  82. end
  83. else
  84. [repo, nil, branch]
  85. end
  86. end
  87. def run!
  88. unless repo
  89. print_help
  90. exit 128
  91. end
  92. status "Deploying to #{repo} (branch #{branch})"
  93. msg "NOTE: Running in simulation mode." if simulate?
  94. msg "WARNING: If the repository has gh-pages history, it with be overriden." if force? && !simulate?
  95. result = force? ? git_deploy_force : git_deploy
  96. if result
  97. puts ""
  98. status "Done."
  99. msg "See: #{url}" if url && !simulate?
  100. else
  101. tip "Failed."
  102. exit 1
  103. end
  104. end
  105. def status(str)
  106. puts "#{c('===>',34)} #{c(str, 32)}"
  107. end
  108. def msg(str)
  109. puts " #{c(str, 32)}"
  110. end
  111. def c(str, color)
  112. "\033[#{color}m#{str}\033[0m"
  113. end
  114. def print_help
  115. tip \
  116. %{Usage: git update-ghpages username/repository [options]
  117. Flags:
  118. -f, --force Force an update (WARNING: kills the history!)
  119. -s, --simulate Creates the repository, but doesn't push.
  120. -v, --verbose Verbose mode
  121. Options:
  122. -p PATH, --prefix The prefix
  123. -i PATH, --input Input (defaults to current directory)
  124. -b BRANCH, --branch The branch to deploy to (defaults to gh-pages)
  125. -m MSG, --message Commit message (defaults to 'Update')
  126. Examples:
  127. Update the repo 'coffee' of github user 'james' with the files from the
  128. current directory. The files will be in http://james.github.com/coffee.
  129. $ git update-ghpages james/coffee
  130. Same as above, but take the files from 'doc/'.
  131. $ git update-ghpages james/coffee -i doc
  132. Same as the first, but the files will instead be in
  133. http://james.github.com/coffee/manual.
  134. $ git update-ghpages james/coffee -i doc -p manual
  135. }.gsub(/^ {4}/, '')
  136. end
  137. private # Helpers
  138. def tip(msg)
  139. $stderr.write "#{msg}\n"
  140. end
  141. def github_format?(str)
  142. str =~ /^([A-Za-z0-9\-_]+)\/([A-Za-z0-9\-_\.]+)$/
  143. end
  144. # Performs actions inside a temp path.
  145. def in_temp_path(&blk)
  146. require 'tmpdir'
  147. Dir.mktmpdir do |dir|
  148. Dir.chdir(dir) { yield dir }
  149. end
  150. end
  151. def system!(str)
  152. puts `#{str} 2>&1`.strip.gsub(/^/, " ")
  153. raise "Failed with exit code #{$?.to_i}" unless $?.to_i == 0
  154. end
  155. # Returns the current branch name
  156. def git_branch
  157. `git symbolic-ref HEAD`.strip.split('/').last
  158. end
  159. # Copy files from source folder to another
  160. def copy_files(from, to)
  161. status "Copying files #{from} => #{to}..." if verbose?
  162. Dir["#{from}/**/*"].each do |f|
  163. next unless File.file?(f)
  164. target = File.join(to, f.gsub(/^#{Regexp.escape from}/, ''))
  165. FileUtils.mkdir_p File.dirname(target)
  166. msg "%20s => %-20s" % [f, target] if verbose?
  167. FileUtils.cp f, target
  168. end
  169. end
  170. end
  171. CLI.new.run!