提交 b1233ee1 编写于 作者: C Chris Wanstrath

normal gem file structure

上级 a7974644
...@@ -3,291 +3,5 @@ ...@@ -3,291 +3,5 @@
# hub(1) # hub(1)
# alias git=hub # alias git=hub
class Hub require 'hub'
Version = '0.1.0' Hub::Runner.execute(*ARGV)
end
class Hub
# The Args class exists to make it more convenient to work with
# command line arguments intended for git from within the Hub
# codebase.
#
# The ARGV array is converted into an Args instance by the Hub
# instance when instantiated.
class Args < Array
# With no arguments, returns the `after` callback.
#
# With a single argument, sets the `after` callback.
# Can be set to a string or a proc.
#
# If proc:
# The proc is executed after the git command is executed. For
# example, the `hub version` command sets the following proc to
# print its information after running `git version`:
#
# after { puts "hub version #{version_number}" }
#
# If string:
# The string is assumed to be a command and executed after the
# git command is executed:
#
# after "echo 'hub version #{version_number}'"
def after(command = nil, &block)
@after ||= block ? block : command
end
# Boolean indicating whether an `after` callback has been set.
def after?
!!@after
end
end
end
class Hub
# The Commands module houses the git commands that hub
# lovingly wraps. If a method exists here, it is expected to have a
# corresponding git command which either gets run before or after
# the method executes.
#
# The typical flow is as follows:
#
# 1. hub is invoked from the command line:
# $ hub clone rtomayko/tilt
#
# 2. The Hub class is initialized:
# >> hub = Hub.new('clone', 'rtomayko/tilt')
#
# 3. The method representing the git subcommand is executed with the
# full args:
# >> Commands.clone('clone', 'rtomayko/tilt')
#
# 4. That method rewrites the args as it sees fit:
# >> args[1] = "git://github.com/" + args[1] + ".git"
# => "git://github.com/rtomayko/tilt.git"
#
# 5. The new args are used to run `git`:
# >> exec "git", "clone", "git://github.com/rtomayko/tilt.git"
#
# An optional `after` callback can be set. If so, it is run after
# step 5 (which then performs a `system` call rather than an
# `exec`). See `Hub::Args` for more information on the `after` callback.
module Commands
# We are a blank slate.
instance_methods.each { |m| undef_method(m) unless m =~ /(^__|send|to\?$)/ }
extend self
# Templates and useful information.
PRIVATE = 'git@github.com:%s/%s.git'
PUBLIC = 'git://github.com/%s/%s.git'
USER = `git config --global github.user`.chomp
REPO = `basename $(pwd)`.chomp
# $ hub clone rtomayko/tilt
# > git clone git://github.com/rtomayko/tilt.
#
# $ hub clone -p kneath/hemingway
# > git clone git@github.com:kneath/hemingway.git
def clone(args)
ssh = args.delete('-p')
args.each_with_index do |arg, i|
if arg.scan('/').size == 1 && !arg.include?(':')
url = ssh ? PRIVATE : PUBLIC
args[i] = url % arg.split('/')
end
end
end
# $ hub remote add pjhyett
# > git remote add pjhyett git://github.com/pjhyett/THIS_REPO.git
#
# $ hub remote add -p mojombo
# > git remote add mojombo git@github.com:mojombo/THIS_REPO.git
def remote(args)
return unless args[1] == 'add'
# Assume GitHub usernames don't ever contain : or /, while URLs
# do.
if args[-1] !~ /:\//
ssh = args.delete('-p')
user = args.last
url = ssh ? PRIVATE : PUBLIC
args << url % [ user, REPO ]
end
end
# $ hub init -g
# > git init
# > git remote add origin git@github.com:USER/REPO.git
def init(args)
if args.delete('-g')
url = PRIVATE % [ USER, REPO ]
args.after "git remote add origin #{url}"
end
end
# $ hub version
# > git version
# (print hub version)
def version(args)
args.after do
puts "hub version %s" % Version
end
end
alias_method "--version", :version
# $ hub help
# (print improved help text)
def help(args)
return if args.size > 1
puts improved_help_text
exit
end
# The text print when `hub help` is run, kept in its own method
# for the convenience of the author.
def improved_help_text
<<-help
usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]
[-p|--paginate|--no-pager] [--bare] [--git-dir=GIT_DIR]
[--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]
Creating a git repository:
clone Clone a repository into a new directory
init Create an empty git repository or reinitialize an existing one
Working with content:
add Add file contents to the index
branch List, create, or delete branches
checkout Checkout a branch or paths to the working tree
commit Record changes to the repository
diff Show changes between commits, commit and working tree, etc
log Show commit logs
merge Join two or more development histories together
mv Move or rename a file, a directory, or a symlink
rm Remove files from the working tree and from the index
status Show the working tree status
show Show various types of objects
tag Create, list, delete or verify a tag object signed with GPG
Over the network:
fetch Download objects and refs from another repository
pull Fetch from and merge with another repository or a local branch
push Update remote refs along with associated objects
remote Manage a set of tracked repositories
Advanced commands:
bisect Find by binary search the change that introduced a bug
grep Print lines matching a pattern
reset Reset current HEAD to the specified state
rebase Forward-port local commits to the updated upstream head
See 'git help COMMAND' for more information on a specific command.
help
end
# All calls to `puts` in after hooks or commands are paged,
# git-style.
def puts(content)
page_stdout
super
end
# http://nex-3.com/posts/73-git-style-automatic-paging-in-ruby
def page_stdout
return if PLATFORM =~ /win32/
return unless $stdout.tty?
read, write = IO.pipe
if Kernel.fork
# Parent process, become pager
$stdin.reopen(read)
read.close
write.close
# Don't page if the input is short enough
ENV['LESS'] = 'FSRX'
# Wait until we have input before we start the pager
Kernel.select [STDIN]
pager = ENV['PAGER'] || 'less'
exec pager rescue exec "/bin/sh", "-c", pager
else
# Child process
$stdout.reopen(write)
$stderr.reopen(write) if $stderr.tty?
read.close
write.close
end
end
end
end
# The Hub class serves as both our namespace and controlling
# application. It expects to be initialized with `ARGV` and primarily
# exists to run a git command.
#
# The actual functionality, that is, the code it runs when it needs to
# augment a git command, is kept in the `Hub::Commands` module.
class Hub
attr_reader :args
def initialize(*args)
@args = Args.new(args)
# Hack to emulate git-style
@args[0] = 'help' if @args.empty?
if Commands.respond_to?(@args[0])
Commands.send(@args[0], @args)
end
end
# Returns the current after callback, which (if set) is run after
# the target git command.
#
# See the `Hub::Args` class for more information on the `after`
# callback.
def after
args.after.to_s
end
# A string representation of the git command we would run if
# #execute were called.
def command
"git #{args.join(' ')}"
end
# Runs the target git command with an optional callback. Replaces
# the current process.
def execute
if args.after?
execute_with_after_callback
else
exec "git", *args
end
end
# Runs the target git command then executes the `after` callback.
#
# See the `Hub::Args` class for more information on the `after`
# callback.
def execute_with_after_callback
after = args.after
if system("git", *args)
after.respond_to?(:call) ? after.call : exec(after)
exit
else
exit 1
end
end
end
# Hack for Rubygems.
# But really, you don't want to run hub under Rubygems.
if $0.split('/').last == __FILE__.split('/').last
Hub.new(*ARGV).execute
end
require 'hub/args'
require 'hub/commands'
require 'hub/runner'
module Hub
Version = '0.1.0'
end
module Hub
# The Args class exists to make it more convenient to work with
# command line arguments intended for git from within the Hub
# codebase.
#
# The ARGV array is converted into an Args instance by the Hub
# instance when instantiated.
class Args < Array
# With no arguments, returns the `after` callback.
#
# With a single argument, sets the `after` callback.
# Can be set to a string or a proc.
#
# If proc:
# The proc is executed after the git command is executed. For
# example, the `hub version` command sets the following proc to
# print its information after running `git version`:
#
# after { puts "hub version #{version_number}" }
#
# If string:
# The string is assumed to be a command and executed after the
# git command is executed:
#
# after "echo 'hub version #{version_number}'"
def after(command = nil, &block)
@after ||= block ? block : command
end
# Boolean indicating whether an `after` callback has been set.
def after?
!!@after
end
end
end
module Hub
# The Commands module houses the git commands that hub
# lovingly wraps. If a method exists here, it is expected to have a
# corresponding git command which either gets run before or after
# the method executes.
#
# The typical flow is as follows:
#
# 1. hub is invoked from the command line:
# $ hub clone rtomayko/tilt
#
# 2. The Hub class is initialized:
# >> hub = Hub.new('clone', 'rtomayko/tilt')
#
# 3. The method representing the git subcommand is executed with the
# full args:
# >> Commands.clone('clone', 'rtomayko/tilt')
#
# 4. That method rewrites the args as it sees fit:
# >> args[1] = "git://github.com/" + args[1] + ".git"
# => "git://github.com/rtomayko/tilt.git"
#
# 5. The new args are used to run `git`:
# >> exec "git", "clone", "git://github.com/rtomayko/tilt.git"
#
# An optional `after` callback can be set. If so, it is run after
# step 5 (which then performs a `system` call rather than an
# `exec`). See `Hub::Args` for more information on the `after` callback.
module Commands
# We are a blank slate.
instance_methods.each { |m| undef_method(m) unless m =~ /(^__|send|to\?$)/ }
extend self
# Templates and useful information.
PRIVATE = 'git@github.com:%s/%s.git'
PUBLIC = 'git://github.com/%s/%s.git'
USER = `git config --global github.user`.chomp
REPO = `basename $(pwd)`.chomp
# $ hub clone rtomayko/tilt
# > git clone git://github.com/rtomayko/tilt.
#
# $ hub clone -p kneath/hemingway
# > git clone git@github.com:kneath/hemingway.git
def clone(args)
ssh = args.delete('-p')
args.each_with_index do |arg, i|
if arg.scan('/').size == 1 && !arg.include?(':')
url = ssh ? PRIVATE : PUBLIC
args[i] = url % arg.split('/')
end
end
end
# $ hub remote add pjhyett
# > git remote add pjhyett git://github.com/pjhyett/THIS_REPO.git
#
# $ hub remote add -p mojombo
# > git remote add mojombo git@github.com:mojombo/THIS_REPO.git
def remote(args)
return unless args[1] == 'add'
# Assume GitHub usernames don't ever contain : or /, while URLs
# do.
if args[-1] !~ /:\//
ssh = args.delete('-p')
user = args.last
url = ssh ? PRIVATE : PUBLIC
args << url % [ user, REPO ]
end
end
# $ hub init -g
# > git init
# > git remote add origin git@github.com:USER/REPO.git
def init(args)
if args.delete('-g')
url = PRIVATE % [ USER, REPO ]
args.after "git remote add origin #{url}"
end
end
# $ hub version
# > git version
# (print hub version)
def version(args)
args.after do
puts "hub version %s" % Version
end
end
alias_method "--version", :version
# $ hub help
# (print improved help text)
def help(args)
return if args.size > 1
puts improved_help_text
exit
end
# The text print when `hub help` is run, kept in its own method
# for the convenience of the author.
def improved_help_text
<<-help
usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]
[-p|--paginate|--no-pager] [--bare] [--git-dir=GIT_DIR]
[--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]
Creating a git repository:
clone Clone a repository into a new directory
init Create an empty git repository or reinitialize an existing one
Working with content:
add Add file contents to the index
branch List, create, or delete branches
checkout Checkout a branch or paths to the working tree
commit Record changes to the repository
diff Show changes between commits, commit and working tree, etc
log Show commit logs
merge Join two or more development histories together
mv Move or rename a file, a directory, or a symlink
rm Remove files from the working tree and from the index
status Show the working tree status
show Show various types of objects
tag Create, list, delete or verify a tag object signed with GPG
Over the network:
fetch Download objects and refs from another repository
pull Fetch from and merge with another repository or a local branch
push Update remote refs along with associated objects
remote Manage a set of tracked repositories
Advanced commands:
bisect Find by binary search the change that introduced a bug
grep Print lines matching a pattern
reset Reset current HEAD to the specified state
rebase Forward-port local commits to the updated upstream head
See 'git help COMMAND' for more information on a specific command.
help
end
# All calls to `puts` in after hooks or commands are paged,
# git-style.
def puts(content)
page_stdout
super
end
# http://nex-3.com/posts/73-git-style-automatic-paging-in-ruby
def page_stdout
return if PLATFORM =~ /win32/
return unless $stdout.tty?
read, write = IO.pipe
if Kernel.fork
# Parent process, become pager
$stdin.reopen(read)
read.close
write.close
# Don't page if the input is short enough
ENV['LESS'] = 'FSRX'
# Wait until we have input before we start the pager
Kernel.select [STDIN]
pager = ENV['PAGER'] || 'less'
exec pager rescue exec "/bin/sh", "-c", pager
else
# Child process
$stdout.reopen(write)
$stderr.reopen(write) if $stderr.tty?
read.close
write.close
end
end
end
end
module Hub
# The Hub runner expects to be initialized with `ARGV` and primarily
# exists to run a git command.
#
# The actual functionality, that is, the code it runs when it needs to
# augment a git command, is kept in the `Hub::Commands` module.
class Runner
attr_reader :args
def initialize(*args)
@args = Args.new(args)
# Hack to emulate git-style
@args[0] = 'help' if @args.empty?
if Commands.respond_to?(@args[0])
Commands.send(@args[0], @args)
end
end
# Shortcut
def self.execute(*args)
new(*args).execute
end
# Returns the current after callback, which (if set) is run after
# the target git command.
#
# See the `Hub::Args` class for more information on the `after`
# callback.
def after
args.after.to_s
end
# A string representation of the git command we would run if
# #execute were called.
def command
"git #{args.join(' ')}"
end
# Runs the target git command with an optional callback. Replaces
# the current process.
def execute
if args.after?
execute_with_after_callback
else
exec "git", *args
end
end
# Runs the target git command then executes the `after` callback.
#
# See the `Hub::Args` class for more information on the `after`
# callback.
def execute_with_after_callback
after = args.after
if system("git", *args)
after.respond_to?(:call) ? after.call : exec(after)
exit
else
exit 1
end
end
end
end
require 'test/unit' require 'test/unit'
load File.dirname(__FILE__) + '/../bin/hub' $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
require 'hub'
class HubTest < Test::Unit::TestCase class HubTest < Test::Unit::TestCase
# Shortcut for creating a `Hub` instance. Pass it what you would # Shortcut for creating a `Hub` instance. Pass it what you would
...@@ -8,7 +9,7 @@ class HubTest < Test::Unit::TestCase ...@@ -8,7 +9,7 @@ class HubTest < Test::Unit::TestCase
# shell: hub clone rtomayko/tilt # shell: hub clone rtomayko/tilt
# test: Hub("clone rtomayko/tilt") # test: Hub("clone rtomayko/tilt")
def Hub(args) def Hub(args)
Hub.new(*args.split(' ')) Hub::Runner.new(*args.split(' '))
end end
# Shortcut for running the `hub` command in a subprocess. Returns # Shortcut for running the `hub` command in a subprocess. Returns
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册