git-style-binaries 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,16 @@
1
+ class Object
2
+ def returning(value)
3
+ yield(value)
4
+ value
5
+ end unless Object.respond_to?(:returning)
6
+ end
7
+
8
+ class Symbol
9
+ def to_proc
10
+ Proc.new { |*args| args.shift.__send__(self, *args) }
11
+ end
12
+ end
13
+
14
+ class IO
15
+ attr_accessor :use_color
16
+ end
@@ -0,0 +1,88 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+ require 'rubygems'
3
+
4
+ # Load the vendor gems
5
+ $:.unshift(File.dirname(__FILE__) + "/../vendor/gems")
6
+ %w(trollop).each do |library|
7
+ begin
8
+ require "#{library}/lib/#{library}"
9
+ rescue LoadError
10
+ begin
11
+ require 'trollop'
12
+ rescue LoadError
13
+ puts "There was an error loading #{library}. Try running git submodule init && git submodule update to correct the problem"
14
+ end
15
+ end
16
+ end
17
+
18
+ require 'ext/core'
19
+ require 'ext/colorize'
20
+ require 'git-style-binary/autorunner'
21
+ Dir[File.dirname(__FILE__) + "/git-style-binary/helpers/*.rb"].each {|f| require f}
22
+
23
+ module GitStyleBinary
24
+
25
+ class << self
26
+ include Helpers::NameResolver
27
+ attr_accessor :current_command
28
+ attr_accessor :primary_command
29
+ attr_writer :known_commands
30
+
31
+ # If set to false GitStyleBinary will not automatically run at exit.
32
+ attr_writer :run
33
+
34
+ # Automatically run at exit?
35
+ def run?
36
+ @run ||= false
37
+ end
38
+
39
+ def parser
40
+ @p ||= Parser.new
41
+ end
42
+
43
+ def known_commands
44
+ @known_commands ||= {}
45
+ end
46
+
47
+ def load_primary
48
+ unless @loaded_primary
49
+ @loaded_primary = true
50
+ primary_file = File.join(binary_directory, basename)
51
+ load primary_file
52
+
53
+ if !GitStyleBinary.primary_command # you still dont have a primary load a default
54
+ GitStyleBinary.primary do
55
+ run do |command|
56
+ educate
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ def load_subcommand
64
+ unless @loaded_subcommand
65
+ @loaded_subcommand = true
66
+ cmd_file = GitStyleBinary.binary_filename_for(GitStyleBinary.current_command_name)
67
+ load cmd_file
68
+ end
69
+ end
70
+
71
+ def load_command_file(name, file)
72
+ self.name_of_command_being_loaded = name
73
+ load file
74
+ self.name_of_command_being_loaded = nil
75
+ end
76
+
77
+ # UGLY eek
78
+ attr_accessor :name_of_command_being_loaded
79
+
80
+ end
81
+ end
82
+
83
+ at_exit do
84
+ unless $! || GitStyleBinary.run?
85
+ command = GitStyleBinary::AutoRunner.run
86
+ exit 0
87
+ end
88
+ end
@@ -0,0 +1,21 @@
1
+ require 'git-style-binary/parser'
2
+
3
+ module GitStyleBinary
4
+ class AutoRunner
5
+
6
+ def self.run(argv=ARGV)
7
+ r = new
8
+ r.run
9
+ end
10
+
11
+ def run
12
+ unless GitStyleBinary.run?
13
+ if !GitStyleBinary.current_command
14
+ GitStyleBinary.load_primary
15
+ end
16
+ GitStyleBinary.current_command.run
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,204 @@
1
+ require 'git-style-binary'
2
+
3
+ module GitStyleBinary
4
+ def self.command(&block)
5
+ returning Command.new(:constraints => [block]) do |c|
6
+ c.name ||= (GitStyleBinary.name_of_command_being_loaded || GitStyleBinary.current_command_name)
7
+ GitStyleBinary.known_commands[c.name] = c
8
+
9
+ if !GitStyleBinary.current_command || GitStyleBinary.current_command.is_primary?
10
+ GitStyleBinary.current_command = c
11
+ end
12
+ end
13
+ end
14
+
15
+ def self.primary(&block)
16
+ returning Primary.new(:constraints => [block]) do |c|
17
+ c.name ||= (GitStyleBinary.name_of_command_being_loaded || GitStyleBinary.current_command_name)
18
+ GitStyleBinary.known_commands[c.name] = c
19
+
20
+ GitStyleBinary.primary_command = c unless GitStyleBinary.primary_command
21
+ GitStyleBinary.current_command = c unless GitStyleBinary.current_command
22
+ end
23
+ end
24
+
25
+ class Command
26
+ class << self
27
+ def defaults
28
+ lambda do
29
+ name_desc "#{command.full_name}\#{command.short_desc ? ' - ' + command.short_desc : ''}" # eval jit
30
+ version_string = defined?(VERSION) ? VERSION : "0.0.1"
31
+ version "#{version_string} (c) #{Time.now.year}"
32
+ banner <<-EOS
33
+ #{"SYNOPSIS".colorize(:red)}
34
+ #{command.full_name.colorize(:light_blue)} #{all_options_string}
35
+
36
+ #{"SUBCOMMANDS".colorize(:red)}
37
+ \#{GitStyleBinary.pretty_known_subcommands.join("\n ")}
38
+
39
+ See '#{command.full_name} help COMMAND' for more information on a specific command.
40
+ EOS
41
+
42
+ opt :verbose, "verbose", :default => false
43
+ end
44
+ end
45
+ end
46
+
47
+ attr_reader :constraints
48
+ attr_reader :opts
49
+ attr_accessor :name
50
+
51
+ def initialize(o={})
52
+ o.each do |k,v|
53
+ eval "@#{k.to_s}= v"
54
+ end
55
+ end
56
+
57
+ def parser
58
+ @parser ||= begin
59
+ p = Parser.new
60
+ p.command = self
61
+ p
62
+ end
63
+ end
64
+
65
+ def constraints
66
+ @constraints ||= []
67
+ end
68
+
69
+ def run
70
+ GitStyleBinary.load_primary unless is_primary?
71
+ GitStyleBinary.load_subcommand if is_primary? && running_subcommand?
72
+ load_all_parser_constraints
73
+ @opts = process_args_with_subcmd
74
+ call_parser_run_block
75
+ self
76
+ end
77
+
78
+ def running_subcommand?
79
+ GitStyleBinary.valid_subcommand?(GitStyleBinary.current_command_name)
80
+ end
81
+
82
+ def load_all_parser_constraints
83
+ @loaded_all_parser_constraints ||= begin
84
+ load_parser_default_constraints
85
+ load_parser_primary_constraints
86
+ load_parser_local_constraints
87
+ true
88
+ end
89
+ end
90
+
91
+ def load_parser_default_constraints
92
+ parser.consume_all([self.class.defaults])
93
+ end
94
+
95
+ def load_parser_primary_constraints
96
+ parser.consume_all(GitStyleBinary.primary_command.constraints)
97
+ end
98
+
99
+ def load_parser_local_constraints
100
+ cur = GitStyleBinary.current_command # see, why isn't 'this' current_command?
101
+
102
+ unless self.is_primary? && cur == self
103
+ # TODO TODO - the key lies in this function. figure out when you hav emore engergy
104
+ # soo UGLY. see #process_parser! unify with that method
105
+ # parser.consume_all(constraints) rescue ArgumentError
106
+ parser.consume_all(cur.constraints)
107
+ end
108
+ end
109
+
110
+ def call_parser_run_block
111
+ runs = GitStyleBinary.current_command.parser.runs
112
+
113
+ parser.run_callbacks(:before_run, self)
114
+ parser.runs.last.call(self) # ... not too happy with this
115
+ parser.run_callbacks(:after_run, self)
116
+ end
117
+
118
+ def process_args_with_subcmd(args = ARGV, *a, &b)
119
+ cmd = GitStyleBinary.current_command_name
120
+ vals = process_args(args, *a, &b)
121
+ parser.leftovers.shift if parser.leftovers[0] == cmd
122
+ vals
123
+ end
124
+
125
+ # TOOooootally ugly! why? bc load_parser_local_constraints doesn't work
126
+ # when loading the indivdual commands because it depends on
127
+ # #current_command. This really sucks and is UGLY.
128
+ # the todo is to put in 'load_all_parser_constraints' and this works
129
+ def process_parser!
130
+ # load_all_parser_constraints
131
+
132
+ load_parser_default_constraints
133
+ load_parser_primary_constraints
134
+ # load_parser_local_constraints
135
+ parser.consume_all(constraints)
136
+
137
+ # hack
138
+ parser.consume {
139
+ opt :version, "Print version and exit" if @version unless @specs[:version] || @long["version"]
140
+ opt :help, "Show this message" unless @specs[:help] || @long["help"]
141
+ resolve_default_short_options
142
+ } # hack
143
+ end
144
+
145
+ def process_args(args = ARGV, *a, &b)
146
+ p = parser
147
+ begin
148
+ vals = p.parse args
149
+ args.clear
150
+ p.leftovers.each { |l| args << l }
151
+ vals # ugly todo
152
+ rescue Trollop::CommandlineError => e
153
+ $stderr.puts "Error: #{e.message}."
154
+ $stderr.puts "Try --help for help."
155
+ exit(-1)
156
+ rescue Trollop::HelpNeeded
157
+ p.educate
158
+ exit
159
+ rescue Trollop::VersionNeeded
160
+ puts p.version
161
+ exit
162
+ end
163
+ end
164
+
165
+ def is_primary?
166
+ false
167
+ end
168
+
169
+ def argv
170
+ parser.leftovers
171
+ end
172
+
173
+ def short_desc
174
+ parser.short_desc
175
+ end
176
+
177
+ def full_name
178
+ # ugly, should be is_primary?
179
+ GitStyleBinary.primary_name == name ? GitStyleBinary.primary_name : GitStyleBinary.primary_name + "-" + name
180
+ end
181
+
182
+ def die arg, msg=nil
183
+ p = parser # create local copy
184
+ Trollop.instance_eval { @p = p }
185
+ Trollop::die(arg, msg)
186
+ end
187
+
188
+ # Helper to return the option
189
+ def [](k)
190
+ opts[k]
191
+ end
192
+
193
+ end
194
+
195
+ class Primary < Command
196
+ def is_primary?
197
+ true
198
+ end
199
+ def primary
200
+ self
201
+ end
202
+ end
203
+
204
+ end
@@ -0,0 +1,32 @@
1
+ module GitStyleBinary
2
+ module Commands
3
+ class Help
4
+ # not loving this syntax, but works for now
5
+ GitStyleBinary.command do
6
+ short_desc "get help for a specific command"
7
+ run do |command|
8
+
9
+ # this is slightly ugly b/c it has to muck around in the internals to
10
+ # get information about commands other than itself. This isn't a
11
+ # typical case
12
+ def educate_about_command(name)
13
+ load_all_commands
14
+ if GitStyleBinary.known_commands.has_key?(name)
15
+ cmd = GitStyleBinary.known_commands[name]
16
+ cmd.process_parser!
17
+ cmd.parser.educate
18
+ else
19
+ puts "Unknown command '#{name}'"
20
+ end
21
+ end
22
+
23
+ if command.argv.size > 0
24
+ command.argv.first == "help" ? educate : educate_about_command(command.argv.first)
25
+ else
26
+ educate
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,78 @@
1
+ module GitStyleBinary
2
+ module Helpers
3
+ module NameResolver
4
+
5
+ def basename(filename=zero)
6
+ File.basename(filename).match(/(.*?)(\-|$)/).captures.first
7
+ end
8
+ alias_method :primary_name, :basename
9
+
10
+ # checks the bin directory for all files starting with +basename+ and
11
+ # returns an array of strings specifying the subcommands
12
+ def subcommand_names(filename=zero)
13
+ subfiles = Dir[File.join(binary_directory, basename + "-*")]
14
+ cmds = subfiles.collect{|file| File.basename(file).sub(/^#{basename}-/, '')}.sort
15
+ cmds += built_in_command_names
16
+ cmds.uniq
17
+ end
18
+
19
+ def binary_directory(filename=zero)
20
+ File.dirname(filename)
21
+ end
22
+
23
+ def built_in_commands_directory
24
+ File.dirname(__FILE__) + "/../commands"
25
+ end
26
+
27
+ def built_in_command_names
28
+ Dir[built_in_commands_directory + "/*.rb"].collect{|f| File.basename(f.sub(/\.rb$/,''))}
29
+ end
30
+
31
+ def list_subcommands(filename=zero)
32
+ subcommand_names(filename).join(", ")
33
+ end
34
+
35
+ # load first from users binary directory. then load built-in commands if
36
+ # available
37
+ def binary_filename_for(name)
38
+ user_file = File.join(binary_directory, "#{basename}-#{name}")
39
+ return user_file if File.exists?(user_file)
40
+ built_in = File.join(built_in_commands_directory, "#{name}.rb")
41
+ return built_in if File.exists?(built_in)
42
+ user_file
43
+ end
44
+
45
+ def current_command_name(filename=zero,argv=ARGV)
46
+ current = File.basename(zero)
47
+ first_arg = ARGV[0]
48
+ return first_arg if valid_subcommand?(first_arg)
49
+ return basename if basename == current
50
+ current.sub(/^#{basename}-/, '')
51
+ end
52
+
53
+ # returns the command name with the prefix if needed
54
+ def full_current_command_name(filename=zero,argv=ARGV)
55
+ cur = current_command_name(filename, argv)
56
+ subcmd = cur == basename(filename) ? false : true # is this a subcmd?
57
+ "%s%s%s" % [basename(filename), subcmd ? "-" : "", subcmd ? current_command_name(filename, argv) : ""]
58
+ end
59
+
60
+ def valid_subcommand?(name)
61
+ subcommand_names.include?(name)
62
+ end
63
+
64
+ def zero
65
+ $0
66
+ end
67
+
68
+ def pretty_known_subcommands(theme=:long)
69
+ GitStyleBinary.known_commands.collect do |k,cmd|
70
+ next if k == basename
71
+ cmd.process_parser!
72
+ ("%-s%s%-10s" % [basename, '-', k]).colorize(:light_blue) + ("%s " % [theme == :long ? "\n" : ""]) + ("%s" % [cmd.short_desc]) + "\n"
73
+ end.compact.sort
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,37 @@
1
+ module GitStyleBinary
2
+ module Helpers
3
+ module Pager
4
+
5
+ # by Nathan Weizenbaum - http://nex-3.com/posts/73-git-style-automatic-paging-in-ruby
6
+ def run_pager
7
+ return if PLATFORM =~ /win32/
8
+ return unless STDOUT.tty?
9
+ STDOUT.use_color = true
10
+
11
+ read, write = IO.pipe
12
+
13
+ unless Kernel.fork # Child process
14
+ STDOUT.reopen(write)
15
+ STDERR.reopen(write) if STDERR.tty?
16
+ read.close
17
+ write.close
18
+ return
19
+ end
20
+
21
+ # Parent process, become pager
22
+ STDIN.reopen(read)
23
+ read.close
24
+ write.close
25
+
26
+ ENV['LESS'] = 'FSRX' # Don't page if the input is short enough
27
+
28
+ Kernel.select [STDIN] # Wait until we have input before we start the pager
29
+ pager = ENV['PAGER'] || 'less -erXF'
30
+ exec pager rescue exec "/bin/sh", "-c", pager
31
+ end
32
+
33
+ module_function :run_pager
34
+
35
+ end
36
+ end
37
+ end