Module: GitFlow

Extended by:
GitFlow
Included in:
GitFlow
Defined in:
lib/git_bpf/lib/gitflow.rb

Defined Under Namespace

Modules: Mixin Classes: HelpCommand, NoSuchCommand

Constant Summary collapse

HELP =
"\nGitFlow is a tool to create custom git commands implemented in ruby.\nIt is generic enougth to be used on any git based project besides Apache Buildr.\n\nOVERVIEW:\n\ngitflow is intended to help developers with their daily git workflow,\nperforming repetitive git commands for them. It is implemented in\nruby so you can do anything, from invoking rake tasks to telling\npeople on twitter you are having trouble with their code :P.\n\nTo get help for a specific command use:\n    gitflow.rb help command\n    gitflow.rb command --help\n\nFor convenience you can create an alias to be execute using git.\nThe following example registers buildr-git.rb, which provides apache\nsvn and git synchronization commands:\n\n    git config alias.apache '!'\"ruby $PWD/doc/scripts/buildr-git.rb\"\n\nAfter that you can use\n    git apache command --help\n\nEXTENDING YOUR WORKFLOW:\n\nYou can create your own gitflow commands, to adapt your development\nworkflow.\n\nSimply create a ruby script somewhere say ~/.buildr/gitflow.rb\nAnd alias it in your local repo:\n\n    git config alias.flow '!'\"ruby ~/.buildr/gitflow.rb\"\n    git config alias.work '!'\"ruby ~/.buildr/gitflow.rb my-flow sub-work\"\n\nA sample command would look like this.. (you may want to look at buildr-git.rb)\n\n    #!/usr/bin/env ruby\n    require /path/to/gitflow.rb\n\n    class MyCommand < GitFlow/'my-flow'\n\n      @help = \"Summary to be displayed when listing commands\"\n      @documentation = \"Very long help that will be paged if necessary. (for --help)\"\n\n      # takes an openstruct to place default values and option values.\n      # returns an array of arguments given to optparse.on\n      def options(opts)\n        opts.something = 'default'\n        [\n         ['--name NAME', lambda { |n| opts.name = n }],\n         ['--yes', lambda { |n| opts.yes = true }]\n        ]\n      end\n\n      # takes the opts openstruct after options have been parsed and\n      # an argv array with non-option arguments.\n      def execute(opts, argv)\n        # you can run another command using\n        run('other-command', '--using-this', 'arg')\n        some = git('config', '--get', 'some.property').chomp rescue nil\n        page { puts \"This will be paged on terminal if needed\" }\n      end\n\n      class SubCommand < MyCommand/'sub-work'\n        ... # implement a subcommand\n      end\n\n    end\n\nYou would then get help for your command with\n\n    git flow my-flow --help\n    git work --help\n\nUsing gitflow you can customize per-project git interface.\n\n"

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#programObject

Returns the value of attribute program.



24
25
26
# File 'lib/git_bpf/lib/gitflow.rb', line 24

def program
  @program
end

#should_runObject

Returns the value of attribute should_run.



24
25
26
# File 'lib/git_bpf/lib/gitflow.rb', line 24

def should_run
  @should_run
end

#traceObject

Returns the value of attribute trace.



24
25
26
# File 'lib/git_bpf/lib/gitflow.rb', line 24

def trace
  @trace
end

Instance Method Details

#/(command_name) ⇒ Object

Return a class to be extended in order to register a GitFlow command if command name is nil, it will be registered as the top level command. Classes implementing commands also provide this method, allowing for sub-command creation.



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/git_bpf/lib/gitflow.rb', line 140

def /(command_name)
  command_name = command_name.to_s unless command_name.nil?
  cls = Class.new { include GitFlow::Mixin }
  (class << cls; self; end).module_eval do
    attr_accessor :help, :documentation, :command
    define_method(:/) do |subcommand|
      raise "Subcommand cannot be nil" unless subcommand
      GitFlow/([command_name, subcommand].compact.join(' '))
    end
    define_method(:inherited) do |subclass|
      subclass.command = command_name
      GitFlow.commands[command_name] = subclass
    end
  end
  cls
end

#command(argv) ⇒ Object



173
174
175
176
177
178
179
180
# File 'lib/git_bpf/lib/gitflow.rb', line 173

def command(argv)
  cmds = []
  argv.each_with_index do |arg, i|
    arg = argv[0..i].join(' ')
    cmds << commands[arg] if commands.key?(arg)
  end
  cmds.last || commands[nil]
end

#commandsObject



157
158
159
# File 'lib/git_bpf/lib/gitflow.rb', line 157

def commands
  @commands ||= Hash.new
end

#optparseObject



161
162
163
164
165
166
167
168
169
170
171
# File 'lib/git_bpf/lib/gitflow.rb', line 161

def optparse
  optparse = opt = OptionParser.new
  opt.separator ' '
  opt.separator 'OPTIONS'
  opt.separator ' '
  opt.on('-h', '--help', 'Display this help') do
    GitFlow.pager; puts opt; throw :exit
  end
  opt.on('--trace', 'Display traces') { GitFlow.trace = true }
  optparse
end

#pagerObject



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/git_bpf/lib/gitflow.rb', line 110

def pager
  return if RUBY_PLATFORM =~ /win32/
  return unless STDOUT.tty?

  read, write = IO.pipe

  unless Kernel.fork # Child process
    STDOUT.reopen(write)
    STDERR.reopen(write) if STDERR.tty?
    read.close
    write.close
    return
  end

  # Parent process, become pager
  STDIN.reopen(read)
  read.close
  write.close

  ENV['LESS'] = 'FSRX' # Don't page if the input is short enough

  Kernel.select [STDIN] # Wait until we have input before we start the pager
  pager = ENV['PAGER'] || 'less'
  exec pager rescue exec '/bin/sh', '-c', pager
end

#run(*argv) ⇒ Object



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/git_bpf/lib/gitflow.rb', line 182

def run(*argv)
  catch :exit do
    command = self.command(argv).new
    argv = argv[command.class.command.split.length..-1] if command.class.command
    parser = optparse
    parser.banner = "Usage: #{GitFlow.program} #{command.class.command} [options]"
    options = OpenStruct.new
    if command.respond_to?(:options)
      command.options(options).each { |args| parser.on(*args) }
    end
    if command.class.documentation && command.class.documentation != ''
      parser.separator ' '
      parser.separator command.class.documentation.split(/\n/)
    end
    parser.parse!(argv)
    command.execute(options, argv)
  end
end