buildr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From vbo...@apache.org
Subject svn commit: r749896 - /buildr/trunk/doc/scripts/gitflow.rb
Date Wed, 04 Mar 2009 04:30:43 GMT
Author: vborja
Date: Wed Mar  4 04:30:42 2009
New Revision: 749896

URL: http://svn.apache.org/viewvc?rev=749896&view=rev
Log:
GitFlow is a tool to enhance your git workflow.

Added:
    buildr/trunk/doc/scripts/gitflow.rb

Added: buildr/trunk/doc/scripts/gitflow.rb
URL: http://svn.apache.org/viewvc/buildr/trunk/doc/scripts/gitflow.rb?rev=749896&view=auto
==============================================================================
--- buildr/trunk/doc/scripts/gitflow.rb (added)
+++ buildr/trunk/doc/scripts/gitflow.rb Wed Mar  4 04:30:42 2009
@@ -0,0 +1,279 @@
+#!/usr/bin/env ruby
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with this
+# work for additional information regarding copyright ownership.  The ASF
+# licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+require 'optparse'
+require 'ostruct'
+require 'fileutils'
+
+module GitFlow
+  extend self
+  
+  attr_accessor :should_run, :trace, :program
+
+  self.program = 'gitflow'
+  self.should_run = true # should we run at exit?
+
+  HELP = <<-HELP
+
+OVERVIEW:
+
+gitflow is intended to help developers with their daily git workflow,
+performing repetitive git commands for them. It is implemented in 
+ruby so you can do anything, from invoking rake tasks to telling
+people on twitter you are having trouble with their code :P.
+
+To get help for a specific command use:
+    gitflow.rb help command
+    gitflow.rb command --help
+
+For convenience you can create an alias to be execute using git.
+The following example registers buildr-git.rb, which provides apache
+svn and git synchronization commands:
+
+    git config alias.apache "!ruby $PWD/doc/scripts/buildr-git.rb"
+
+After that you can use
+    git apache command --help
+
+EXTENDING YOUR WORKFLOW:
+
+You can create your own gitflow commands, to adapt your development 
+workflow.
+
+Simply create a ruby script somewhere say ~/.buildr/gitflow.rb
+And alias it in your local repo:
+
+    git config alias.flow "!ruby ~/.buildr/gitflow.rb"
+    git config alias.work "!ruby ~/.buildr/gitflow.rb my-flow sub-work"
+
+A sample command would look like this.. (you may want to look at buildr-git.rb)
+
+    #!/usr/bin/env ruby
+    require /path/to/gitflow.rb
+    
+    class MyCommand < GitFlow/'my-flow'
+      
+      @help = "Summary to be displayed when listing commands"
+      @documentation = "Very long help that will be paged if necessary. (for --help)"
+      
+      # takes an openstruct to place default values and option values.
+      # returns an array of arguments given to optparse.on
+      def options(opts)
+        opts.something = 'default'
+        [ 
+         ['--name NAME', lambda { |n| opts.name = n }],
+         ['--yes', lambda { |n| opts.yes = true }]
+        ]
+      end
+
+      # takes the opts openstruct after options have been parsed and
+      # an argv array with non-option arguments.
+      def execute(opts, argv)
+        # you can run another command using
+        run('other-command', '--using-this', 'arg')
+        some = git('config', '--get', 'some.property').chomp rescue nil
+        page { puts "This will be paged on terminal if needed" }
+      end
+
+      class SubCommand < MyCommand/'sub-work'
+        ... # implement a subcommand
+      end
+      
+    end
+
+You would then get help for your command with
+
+    git flow my-flow --help
+    git work --help
+
+Using gitflow you can customize per-project git interface.
+
+HELP
+
+  # Pager from http://nex-3.com/posts/73-git-style-automatic-paging-in-ruby
+  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
+
+  # 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.
+  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
+
+  def commands
+    @commands ||= Hash.new
+  end
+
+  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
+
+  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
+
+  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
+
+  module Mixin
+    include FileUtils
+
+    def options(opt)
+      []
+    end
+    
+    def execute(opt, argv)
+      fail "#{self.class.command} not implemented"
+    end
+    
+    # Run the command line given on argv
+    def run(*argv, &block)
+      GitFlow.run(*argv, &block)
+    end
+
+    # Yield paging the blocks output if necessary.
+    def page
+      GitFlow.pager
+      yield
+    end
+  
+    def trace(*str)
+      STDERR.puts(*str) if GitFlow.trace
+    end
+    
+    def git(*args)
+      cmd = 'git ' + args.map { |arg| arg[' '] ? %Q{"#{arg}"} : arg }.join(' ')
+      trace cmd
+      `#{cmd}`.tap {
+        fail "GIT command `#{cmd}` failed with status #{$?.exitstatus}" unless $?.exitstatus
== 0
+      }
+    end
+    
+    def sh(*args)
+      `#{args.join(' ')}`.tap {
+        fail "Shell command `#{args.join(' ')}` failed with status #{$?.exitstatus}" unless
$?.exitstatus == 0
+      }
+    end
+    
+    def expand_path(path, dir=Dir.pwd)
+      File.expand_path(path, dir)
+    end
+  end
+
+  class NoSuchCommand < GitFlow/nil
+    def execute(opts, argv)
+      page do
+        puts "Command not found: #{argv.join(' ').inspect}"
+        puts "Try `#{GitFlow.program} help` to obtain a list of commands."
+        puts HELP 
+      end
+      exit 1
+    end
+  end
+
+  class HelpCommand < GitFlow/:help
+    @help = "Display help for a command or show command list"
+    @documentation = "Displays help for the command given as argument"
+    
+    def execute(opts, argv)
+      if argv.empty?
+        opt = GitFlow.optparse
+        opt.banner = "Usage: #{GitFlow.program} command [options]"
+        opt.separator ' '
+        opt.separator 'COMMANDS'
+        opt.separator ' '
+        commands = GitFlow.commands.map { |name, cls| [nil, name, cls.help] }.
+          sort_by { |a| a[1] || '' }
+        commands.each { |a| opt.separator("%-2s%-25s%s" % a) if a[1] }
+        opt.separator ' '
+        opt.separator 'You can also obtain help for any command giving it --help.'
+        page { puts opt }
+      else
+        run(argv.join(' '), '--help')
+      end
+    end
+  end
+    
+end
+
+at_exit { GitFlow.run(*ARGV) if GitFlow.should_run }



Mime
View raw message