rcli 0.1.0

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.
Files changed (43) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +193 -0
  3. data/README.rdoc +194 -0
  4. data/Rakefile +61 -0
  5. data/bin/rcli +12 -0
  6. data/lib/commands/compile.rb +15 -0
  7. data/lib/commands/debug.rb +86 -0
  8. data/lib/commands/edit.rb +34 -0
  9. data/lib/commands/generate.rb +43 -0
  10. data/lib/commands/help.rb +47 -0
  11. data/lib/commands/install.rb +86 -0
  12. data/lib/commands/list.rb +28 -0
  13. data/lib/commands/uninstall.rb +36 -0
  14. data/lib/commands/version.rb +11 -0
  15. data/lib/core/actions/create_file.rb +106 -0
  16. data/lib/core/actions/empty_directory.rb +88 -0
  17. data/lib/core/actions/file_binary_read.rb +9 -0
  18. data/lib/core/actions.rb +9 -0
  19. data/lib/core/command.rb +137 -0
  20. data/lib/core/commander.rb +48 -0
  21. data/lib/core/console.rb +5 -0
  22. data/lib/core/global_functions.rb +16 -0
  23. data/lib/core/shared/rcli_installation.rb +9 -0
  24. data/lib/core/thor_actions/create_file.rb +100 -0
  25. data/lib/core/thor_actions/directory.rb +89 -0
  26. data/lib/core/thor_actions/empty_directory.rb +134 -0
  27. data/lib/core/thor_actions/file_binary_read.rb +9 -0
  28. data/lib/core/thor_actions/file_manipulation.rb +223 -0
  29. data/lib/core/thor_actions/inject_into_file.rb +102 -0
  30. data/lib/core/thor_actions.rb +302 -0
  31. data/lib/core/traceable_factory.rb +20 -0
  32. data/lib/core/traceable_object.rb +45 -0
  33. data/lib/core/tracer.rb +23 -0
  34. data/lib/rcli.rb +65 -0
  35. data/lib/templates/new_app/RCLIAPPNAME.rb +9 -0
  36. data/lib/templates/new_app/lib/commands/default.rb +12 -0
  37. data/lib/templates/new_app/lib/commands/version.rb +6 -0
  38. data/lib/vendor/mainline/lib/trollop.rb +782 -0
  39. data/lib/vendor/mainline/test/test_trollop.rb +1094 -0
  40. data/lib/vendor/trollop.rb +782 -0
  41. data/test/helper.rb +10 -0
  42. data/test/test_rcli-gem.rb +7 -0
  43. metadata +137 -0
@@ -0,0 +1,302 @@
1
+ require 'fileutils'
2
+ require 'uri'
3
+ require 'core/actions/file_binary_read'
4
+
5
+ Dir[File.join(Rcli::GEM_LIB, "actions", "*.rb")].each do |action|
6
+ require action
7
+ end
8
+
9
+ class Rcli
10
+ module Actions
11
+ attr_accessor :behavior
12
+
13
+ def self.included(base) #:nodoc:
14
+ base.extend ClassMethods
15
+ end
16
+
17
+ module ClassMethods
18
+ # Hold source paths for one Thor instance. source_paths_for_search is the
19
+ # method responsible to gather source_paths from this current class,
20
+ # inherited paths and the source root.
21
+ #
22
+ def source_paths
23
+ @_source_paths ||= []
24
+ end
25
+
26
+ # Stores and return the source root for this class
27
+ def source_root(path=nil)
28
+ @_source_root = path if path
29
+ @_source_root
30
+ end
31
+
32
+ # Returns the source paths in the following order:
33
+ #
34
+ # 1) This class source paths
35
+ # 2) Source root
36
+ # 3) Parents source paths
37
+ #
38
+ def source_paths_for_search
39
+ paths = []
40
+ paths += self.source_paths
41
+ paths << self.source_root if self.source_root
42
+ paths += from_superclass(:source_paths, [])
43
+ paths
44
+ end
45
+
46
+ # Add runtime options that help actions execution.
47
+ #
48
+ def add_runtime_options!
49
+ class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime,
50
+ :desc => "Overwrite files that already exist"
51
+
52
+ class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
53
+ :desc => "Run but do not make any changes"
54
+
55
+ class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
56
+ :desc => "Supress status output"
57
+
58
+ class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
59
+ :desc => "Skip files that already exist"
60
+ end
61
+ end
62
+
63
+ # Extends initializer to add more configuration options.
64
+ #
65
+ # ==== Configuration
66
+ # behavior<Symbol>:: The actions default behavior. Can be :invoke or :revoke.
67
+ # It also accepts :force, :skip and :pretend to set the behavior
68
+ # and the respective option.
69
+ #
70
+ # destination_root<String>:: The root directory needed for some actions.
71
+ #
72
+ # def initialize(args=[], options={}, config={})
73
+ # pp args
74
+ # puts "asdfasdf"
75
+ # pp options
76
+ # puts "asdfasdf"
77
+ # pp config
78
+ # puts "asdfasdf"
79
+ # self.behavior = case config[:behavior].to_s
80
+ # when "force", "skip"
81
+ # _cleanup_options_and_set(options, config[:behavior])
82
+ # :invoke
83
+ # when "revoke"
84
+ # :revoke
85
+ # else
86
+ # :invoke
87
+ # end
88
+ #
89
+ # super
90
+ # self.destination_root = config[:destination_root]
91
+ # end
92
+
93
+ # Wraps an action object and call it accordingly to the thor class behavior.
94
+ #
95
+ def action(instance) #:nodoc:
96
+ if behavior == :revoke
97
+ instance.revoke!
98
+ else
99
+ instance.invoke!
100
+ end
101
+ end
102
+
103
+ # Returns the root for this thor class (also aliased as destination root).
104
+ #
105
+ def destination_root
106
+ @destination_stack.last
107
+ end
108
+
109
+ # Sets the root for this thor class. Relatives path are added to the
110
+ # directory where the script was invoked and expanded.
111
+ #
112
+ def destination_root=(root)
113
+ @destination_stack ||= []
114
+ @destination_stack[0] = File.expand_path(root || '')
115
+ end
116
+
117
+ # Returns the given path relative to the absolute root (ie, root where
118
+ # the script started).
119
+ #
120
+ def relative_to_original_destination_root(path, remove_dot=true)
121
+ path = path.gsub(@destination_stack[0], '.')
122
+ remove_dot ? (path[2..-1] || '') : path
123
+ end
124
+
125
+ # Holds source paths in instance so they can be manipulated.
126
+ #
127
+ def source_paths
128
+ @source_paths ||= self.class.source_paths_for_search
129
+ end
130
+
131
+ # Receives a file or directory and search for it in the source paths.
132
+ #
133
+ def find_in_source_paths(file)
134
+ relative_root = relative_to_original_destination_root(destination_root, false)
135
+
136
+ source_paths.each do |source|
137
+ source_file = File.expand_path(file, File.join(source, relative_root))
138
+ return source_file if File.exists?(source_file)
139
+ end
140
+
141
+ message = "Could not find #{file.inspect} in any of your source paths. "
142
+
143
+ unless self.class.source_root
144
+ message << "Please invoke #{self.class.name}.source_root(PATH) with the PATH containing your templates. "
145
+ end
146
+
147
+ if source_paths.empty?
148
+ message << "Currently you have no source paths."
149
+ else
150
+ message << "Your current source paths are: \n#{source_paths.join("\n")}"
151
+ end
152
+
153
+ raise Error, message
154
+ end
155
+
156
+ # Do something in the root or on a provided subfolder. If a relative path
157
+ # is given it's referenced from the current root. The full path is yielded
158
+ # to the block you provide. The path is set back to the previous path when
159
+ # the method exits.
160
+ #
161
+ # ==== Parameters
162
+ # dir<String>:: the directory to move to.
163
+ # config<Hash>:: give :verbose => true to log and use padding.
164
+ #
165
+ def inside(dir='', config={}, &block)
166
+ verbose = config.fetch(:verbose, false)
167
+
168
+ say_status :inside, dir, verbose
169
+ shell.padding += 1 if verbose
170
+ @destination_stack.push File.expand_path(dir, destination_root)
171
+
172
+ FileUtils.mkdir_p(destination_root) unless File.exist?(destination_root)
173
+ FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield }
174
+
175
+ @destination_stack.pop
176
+ shell.padding -= 1 if verbose
177
+ end
178
+
179
+ # Goes to the root and execute the given block.
180
+ #
181
+ def in_root
182
+ inside(@destination_stack.first) { yield }
183
+ end
184
+
185
+ # Loads an external file and execute it in the instance binding.
186
+ #
187
+ # ==== Parameters
188
+ # path<String>:: The path to the file to execute. Can be a web address or
189
+ # a relative path from the source root.
190
+ #
191
+ # ==== Examples
192
+ #
193
+ # apply "http://gist.github.com/103208"
194
+ #
195
+ # apply "recipes/jquery.rb"
196
+ #
197
+ def apply(path, config={})
198
+ verbose = config.fetch(:verbose, true)
199
+ path = find_in_source_paths(path) unless path =~ /^http\:\/\//
200
+
201
+ say_status :apply, path, verbose
202
+ shell.padding += 1 if verbose
203
+
204
+ if URI(path).is_a?(URI::HTTP)
205
+ contents = open(path, "Accept" => "application/x-thor-template") {|io| io.read }
206
+ else
207
+ contents = open(path) {|io| io.read }
208
+ end
209
+
210
+ instance_eval(contents, path)
211
+ shell.padding -= 1 if verbose
212
+ end
213
+
214
+ # Executes a command returning the contents of the command.
215
+ #
216
+ # ==== Parameters
217
+ # command<String>:: the command to be executed.
218
+ # config<Hash>:: give :verbose => false to not log the status. Specify :with
219
+ # to append an executable to command executation.
220
+ #
221
+ # ==== Example
222
+ #
223
+ # inside('vendor') do
224
+ # run('ln -s ~/edge rails')
225
+ # end
226
+ #
227
+ def run(command, config={})
228
+ return unless behavior == :invoke
229
+
230
+ destination = relative_to_original_destination_root(destination_root, false)
231
+ desc = "#{command} from #{destination.inspect}"
232
+
233
+ if config[:with]
234
+ desc = "#{File.basename(config[:with].to_s)} #{desc}"
235
+ command = "#{config[:with]} #{command}"
236
+ end
237
+
238
+ say_status :run, desc, config.fetch(:verbose, true)
239
+ `#{command}` unless options[:pretend]
240
+ end
241
+
242
+ # Executes a ruby script (taking into account WIN32 platform quirks).
243
+ #
244
+ # ==== Parameters
245
+ # command<String>:: the command to be executed.
246
+ # config<Hash>:: give :verbose => false to not log the status.
247
+ #
248
+ def run_ruby_script(command, config={})
249
+ return unless behavior == :invoke
250
+ run command, config.merge(:with => Thor::Util.ruby_command)
251
+ end
252
+
253
+ # Run a thor command. A hash of options can be given and it's converted to
254
+ # switches.
255
+ #
256
+ # ==== Parameters
257
+ # task<String>:: the task to be invoked
258
+ # args<Array>:: arguments to the task
259
+ # config<Hash>:: give :verbose => false to not log the status. Other options
260
+ # are given as parameter to Thor.
261
+ #
262
+ # ==== Examples
263
+ #
264
+ # thor :install, "http://gist.github.com/103208"
265
+ # #=> thor install http://gist.github.com/103208
266
+ #
267
+ # thor :list, :all => true, :substring => 'rails'
268
+ # #=> thor list --all --substring=rails
269
+ #
270
+ def thor(task, *args)
271
+ config = args.last.is_a?(Hash) ? args.pop : {}
272
+ verbose = config.key?(:verbose) ? config.delete(:verbose) : true
273
+ pretend = config.key?(:pretend) ? config.delete(:pretend) : false
274
+
275
+ args.unshift task
276
+ args.push Thor::Options.to_switches(config)
277
+ command = args.join(' ').strip
278
+
279
+ run command, :with => :thor, :verbose => verbose, :pretend => pretend
280
+ end
281
+
282
+ protected
283
+
284
+ # Allow current root to be shared between invocations.
285
+ #
286
+ def _shared_configuration #:nodoc:
287
+ super.merge!(:destination_root => self.destination_root)
288
+ end
289
+
290
+ def _cleanup_options_and_set(options, key) #:nodoc:
291
+ case options
292
+ when Array
293
+ %w(--force -f --skip -s).each { |i| options.delete(i) }
294
+ options << "--#{key}"
295
+ when Hash
296
+ [:force, :skip, "force", "skip"].each { |i| options.delete(i) }
297
+ options.merge!(key => true)
298
+ end
299
+ end
300
+
301
+ end
302
+ end
@@ -0,0 +1,20 @@
1
+ require 'core/traceable_object'
2
+
3
+ class TraceableFactory
4
+
5
+ def self.createTraceableObject( className, *args )
6
+
7
+ TraceableObject.before_init(className) if Rcli.trace_app
8
+
9
+ obj = Object.const_get( className ).new(*args)
10
+
11
+ TraceableObject.after_init(className) if Rcli.trace_app
12
+
13
+ if Rcli.trace_app
14
+ return TraceableObject.new(obj,*args)
15
+ else
16
+ return obj
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,45 @@
1
+ class TraceableObject
2
+
3
+ def initialize(obj)
4
+ @obj = obj
5
+ end
6
+
7
+ def self.before_init(classname)
8
+ puts "-- s - #{classname}.initialize() ---"
9
+ end
10
+
11
+ def self.after_init(classname)
12
+ puts "-- f - #{classname}.initialize() ---"
13
+
14
+ end
15
+
16
+ def before_trace(sym)
17
+ puts "-- s - #{@obj.class}.#{sym}() ---"
18
+ end
19
+
20
+ def after_trace(sym)
21
+ puts "-- f - #{@obj.class}.#{sym}() ---"
22
+ end
23
+
24
+ def self.before_trace(className, sym)
25
+ puts "-- s - #{className}::#{sym}() ---"
26
+ end
27
+
28
+ def self.after_trace(className, sym)
29
+ puts "-- f - #{className}::#{sym}() ---"
30
+ end
31
+
32
+ def method_missing(sym, *args, &block)
33
+ before_trace(sym)
34
+ @obj.send sym, *args, &block
35
+ after_trace(sym)
36
+ end
37
+
38
+ def self.call_class_method(className, sym, *args, &block)
39
+ self.before_trace(className, sym) if Rcli.trace_app
40
+ retval = Object.const_get( className ).send sym, *args, &block
41
+ self.after_trace(className, sym) if Rcli.trace_app
42
+ retval
43
+ end
44
+
45
+ end
@@ -0,0 +1,23 @@
1
+ def s
2
+ trace = ''
3
+ m = caller[0][/`([^']*)'/, 1]
4
+ if "#{self.class}" == "Class"
5
+ trace = "-- s - #{self}::#{m}() --- "
6
+ else
7
+ trace = "-- s - #{self.class}.#{m}() --- "
8
+ end
9
+
10
+ puts trace if TRACE_APP
11
+ end
12
+
13
+ def f
14
+ trace = ''
15
+ m = caller[0][/`([^']*)'/, 1]
16
+ if "#{self.class}" == "Class"
17
+ trace = "-- f - #{self}::#{m}() --- "
18
+ else
19
+ trace = "-- f - #{self.class}.#{m}() --- "
20
+ end
21
+
22
+ puts trace if TRACE_APP
23
+ end
data/lib/rcli.rb ADDED
@@ -0,0 +1,65 @@
1
+ ### Core Libraries
2
+ require 'rubygems'
3
+ require 'text'
4
+ require 'YAML'
5
+ require 'pp'
6
+ require 'pathname'
7
+ require 'highline/import'
8
+
9
+ ### Globals
10
+ $verbose = false # set to true by command line
11
+ DS = File::SEPARATOR # / on unix, \ on windows. DS is a shortcut and faster to type
12
+
13
+
14
+ require 'core/shared/rcli_installation.rb'
15
+
16
+ class Rcli
17
+
18
+ include Rcli::Installation
19
+
20
+ SRC_PATH = File.expand_path('~/lib/ruby/rcli_framework')
21
+
22
+ GEM_ROOT = File.dirname(File.dirname(__FILE__))
23
+ GEM_LIB = GEM_ROOT + DS + 'lib'
24
+ GEM_BIN = GEM_ROOT + DS + 'bin'
25
+ GEM_CONFIG = GEM_ROOT + DS + 'lib' + DS + 'config'
26
+
27
+ RCLI_DOTFOLDER = File.expand_path("~" + DS + '.rcli')
28
+
29
+ if File.exists? (RCLI_DOTFOLDER + DS + 'config.yml')
30
+ RCLI_CONFIG = YAML.load_file(RCLI_DOTFOLDER + DS + 'config.yml')
31
+ else
32
+ RCLI_CONFIG = YAML.load_file(GEM_LIB + DS + 'config' + DS + 'application.yml')
33
+ end
34
+
35
+ @@trace_app = false
36
+ @@script_root = 'uninitialized'
37
+ @@script_config = nil
38
+ @@type = :app
39
+
40
+ def self.script_root ; @@script_root ; end
41
+ def self.script_root=(sr) ;
42
+ @@script_root = sr ;
43
+ if @@type == :app
44
+ @@script_config = YAML.load_file(sr + DS + 'config' + DS + 'application.yml')
45
+ else
46
+ @@script_config = RCLI_CONFIG
47
+ end
48
+ end
49
+ def self.script_config ; @@script_config ; end
50
+ def self.script_config=(sc) ; @@script_config = sc ; end
51
+ def self.trace_app ; @@trace_app ; end
52
+ def self.trace_app=(ta) ; @@trace_app = ta ; end
53
+ def self.type ; @@type ; end
54
+ def self.type=(t) ; @@type = t ; end
55
+
56
+ def self.go ; Commander.new.go ; end
57
+ end
58
+
59
+
60
+ ### Application Libraries
61
+ require 'core/traceable_factory'
62
+ require 'core/actions'
63
+ require 'core/global_functions'
64
+ require 'vendor/trollop'
65
+ require 'core/commander'
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'rcli'
4
+
5
+ #Rcli.trace_app = true # Uncomment if you want to enable tracing.
6
+
7
+ ### LAUNCH RCLIAPPNAME
8
+ Rcli.script_root = Pathname(__FILE__).realpath.parent.to_s
9
+ Commander.new.go
@@ -0,0 +1,12 @@
1
+ class DefaultCommand < Command
2
+
3
+ #description "Your application description (showed in help) goes here"
4
+ #usage "RCLIAPPNAME [-hv]"
5
+
6
+ def main
7
+ # script code goes here:
8
+
9
+ end
10
+
11
+
12
+ end
@@ -0,0 +1,6 @@
1
+ class VersionCommand < Command
2
+
3
+ def main
4
+ puts "RCLIAPPNAME -- version 0.1a"
5
+ end
6
+ end