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.
- data/LICENSE +20 -0
- data/README.md +193 -0
- data/README.rdoc +194 -0
- data/Rakefile +61 -0
- data/bin/rcli +12 -0
- data/lib/commands/compile.rb +15 -0
- data/lib/commands/debug.rb +86 -0
- data/lib/commands/edit.rb +34 -0
- data/lib/commands/generate.rb +43 -0
- data/lib/commands/help.rb +47 -0
- data/lib/commands/install.rb +86 -0
- data/lib/commands/list.rb +28 -0
- data/lib/commands/uninstall.rb +36 -0
- data/lib/commands/version.rb +11 -0
- data/lib/core/actions/create_file.rb +106 -0
- data/lib/core/actions/empty_directory.rb +88 -0
- data/lib/core/actions/file_binary_read.rb +9 -0
- data/lib/core/actions.rb +9 -0
- data/lib/core/command.rb +137 -0
- data/lib/core/commander.rb +48 -0
- data/lib/core/console.rb +5 -0
- data/lib/core/global_functions.rb +16 -0
- data/lib/core/shared/rcli_installation.rb +9 -0
- data/lib/core/thor_actions/create_file.rb +100 -0
- data/lib/core/thor_actions/directory.rb +89 -0
- data/lib/core/thor_actions/empty_directory.rb +134 -0
- data/lib/core/thor_actions/file_binary_read.rb +9 -0
- data/lib/core/thor_actions/file_manipulation.rb +223 -0
- data/lib/core/thor_actions/inject_into_file.rb +102 -0
- data/lib/core/thor_actions.rb +302 -0
- data/lib/core/traceable_factory.rb +20 -0
- data/lib/core/traceable_object.rb +45 -0
- data/lib/core/tracer.rb +23 -0
- data/lib/rcli.rb +65 -0
- data/lib/templates/new_app/RCLIAPPNAME.rb +9 -0
- data/lib/templates/new_app/lib/commands/default.rb +12 -0
- data/lib/templates/new_app/lib/commands/version.rb +6 -0
- data/lib/vendor/mainline/lib/trollop.rb +782 -0
- data/lib/vendor/mainline/test/test_trollop.rb +1094 -0
- data/lib/vendor/trollop.rb +782 -0
- data/test/helper.rb +10 -0
- data/test/test_rcli-gem.rb +7 -0
- metadata +137 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
class HelpCommand < Command
|
2
|
+
|
3
|
+
# description "Shows the current help screen"
|
4
|
+
# usage "rcli help <command>"
|
5
|
+
|
6
|
+
def main
|
7
|
+
|
8
|
+
if Rcli.script_config['global']['mode'] == 'single'
|
9
|
+
cmdname = Rcli.script_config['global']['default_command']
|
10
|
+
cmd = Command.load(cmdname)
|
11
|
+
cmd[cmdname][:instance].help
|
12
|
+
else
|
13
|
+
if @params[:args].size == 0
|
14
|
+
puts
|
15
|
+
puts Rcli.script_config['global']['description']
|
16
|
+
puts
|
17
|
+
puts "usage:\n " + self.class.show_use
|
18
|
+
puts
|
19
|
+
|
20
|
+
commands = Command.load_all
|
21
|
+
|
22
|
+
# require Rcli.script_root + DS + 'lib' + DS + 'commands' + DS + 'help'
|
23
|
+
# pp ::HelpCommand.describe ; exit
|
24
|
+
|
25
|
+
puts "Commands currently implemented are:"
|
26
|
+
|
27
|
+
# calculate column width
|
28
|
+
biggest = 0
|
29
|
+
commands.each { |c,data| biggest = c.size if biggest < c.size }
|
30
|
+
|
31
|
+
commands.sort.each do |name,cmd|
|
32
|
+
next if name == 'help'
|
33
|
+
# puts "#{name}, :: #{cmd}"
|
34
|
+
puts " %-#{biggest}s" % name + " " + cmd[:instance].class.describe if name != 'debug'
|
35
|
+
end
|
36
|
+
|
37
|
+
puts
|
38
|
+
puts "Type '#{Rcli.script_config['global']['script_name']} help COMMAND' for instructions on using a specific command"
|
39
|
+
puts
|
40
|
+
else
|
41
|
+
cmd = Command.load(@params[:args][0])
|
42
|
+
|
43
|
+
cmd[@params[:args][0]][:instance].help
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require "highline/import"
|
2
|
+
require 'core/shared/rcli_installation'
|
3
|
+
class InstallCommand < Command
|
4
|
+
|
5
|
+
include Rcli::Installation
|
6
|
+
|
7
|
+
description "Installs rcli to your system, or installs a specific rcli app"
|
8
|
+
|
9
|
+
def main()
|
10
|
+
|
11
|
+
if $verbose
|
12
|
+
print "params : "
|
13
|
+
pp @params
|
14
|
+
end
|
15
|
+
|
16
|
+
if _installed_rcli_base? && @params[:args].length > 0
|
17
|
+
if @params[:args].length != 2
|
18
|
+
puts "ERROR: Incorrect syntax. Please use 'rcli install [script] [alias]'"
|
19
|
+
exit
|
20
|
+
end
|
21
|
+
unless File.exists? @params[:args][0]
|
22
|
+
puts "ERROR: The filename provided does not exist. Please type 'rcli install help' for proper usage."
|
23
|
+
end
|
24
|
+
unless File.executable_real? @params[:args][0]
|
25
|
+
puts "ERROR: The script you're trying to install is not executable. Please type 'rcli install help' for proper usage."
|
26
|
+
end
|
27
|
+
if File.exists? Rcli::RCLI_DOTFOLDER + DS + 'bin' + DS + @params[:args][1]
|
28
|
+
puts "ERROR: The install name for that script is already taken"
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
|
32
|
+
unless FileUtils.ln_s(File.expand_path(@params[:args][0]),Rcli::RCLI_DOTFOLDER + DS + 'bin' + DS + @params[:args][1])
|
33
|
+
puts "ERROR: There was a problem installing " + @params[:args][1]
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
|
37
|
+
unless File.open(File.expand_path(Rcli::RCLI_DOTFOLDER + DS + 'app_info' + DS + @params[:args][1] + '.yml'),'w') { |f|
|
38
|
+
f << 'application_root: ' + File.dirname(File.expand_path(@params[:args][0])) + "\n"
|
39
|
+
f << 'executable: ' + File.basename(File.expand_path(@params[:args][0]))
|
40
|
+
}
|
41
|
+
puts "ERROR: There was a problem installing " + @params[:args][1]
|
42
|
+
FileUtils.rm(File.expand_path(@params[:args][0]),Rcli::RCLI_DOTFOLDER + DS + 'bin' + DS + @params[:args][1])
|
43
|
+
exit
|
44
|
+
end
|
45
|
+
|
46
|
+
elsif @params[:args].length > 0 && !_installed_rcli_base?
|
47
|
+
puts "You haven't installed the rcli base yet. Please run 'rcli install' first."
|
48
|
+
elsif _installed_rcli_base?
|
49
|
+
puts "rcli base already installed"
|
50
|
+
else
|
51
|
+
if _install_rcli_base
|
52
|
+
puts "rcli successfully installed"
|
53
|
+
else
|
54
|
+
puts "ERROR"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def _install_rcli_base
|
62
|
+
if _installed_rcli_base?
|
63
|
+
return false
|
64
|
+
end
|
65
|
+
|
66
|
+
dotpath = File.expand_path('~/' + Rcli::RCLI_CONFIG['global']['hidden_dir_name'] )
|
67
|
+
puts "Installing to : #{dotpath}"
|
68
|
+
# exit
|
69
|
+
FileUtils.mkdir_p(dotpath + DS + 'bin')
|
70
|
+
FileUtils.mkdir_p(dotpath + DS + 'app_info')
|
71
|
+
|
72
|
+
if agree("Add rcli to your path to allow script installations? [yn]", true)
|
73
|
+
File.open(File.expand_path('~/.bash_profile'),'a') { |f|
|
74
|
+
f << "\n\n# rcli Installer addition on #{Time.now.inspect}. Adding appropriate PATH variables for use with rcli."
|
75
|
+
f << "\nexport PATH=#{dotpath}/bin:$PATH"
|
76
|
+
f << "\n# Finished adapting your PATH environment variable for use with rcli."
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
File.open(dotpath + DS + 'config.yml', 'w') { |f|
|
81
|
+
f << File.read(Rcli::GEM_CONFIG + DS + 'application.yml')
|
82
|
+
}
|
83
|
+
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class ListCommand < Command
|
2
|
+
|
3
|
+
description "Lists all installed rcli programs"
|
4
|
+
|
5
|
+
def main()
|
6
|
+
|
7
|
+
puts "rcli installed applications"
|
8
|
+
puts "---------------------------"
|
9
|
+
|
10
|
+
biggest = 0
|
11
|
+
Dir[Rcli::RCLI_DOTFOLDER + DS + 'app_info' + DS + '*'].each { |c| biggest = File.basename(c,'.yml').size if biggest < File.basename(c,'.yml').size }
|
12
|
+
|
13
|
+
puts "biggest is #{biggest}" if $verbose
|
14
|
+
# commands.sort.each do |name,cmd|
|
15
|
+
# puts " %-#{biggest}s" % name + " " + cmd[:instance].description
|
16
|
+
# end
|
17
|
+
|
18
|
+
Dir[Rcli::RCLI_DOTFOLDER + DS + 'app_info' + DS + '*'].each { |f|
|
19
|
+
puts "loading #{f}..." if $verbose
|
20
|
+
app_info = YAML.load_file(f)
|
21
|
+
app_config = YAML.load_file(app_info['application_root'] + DS + 'config' + DS + 'application.yml' )
|
22
|
+
pp app_info if $verbose
|
23
|
+
# puts File.basename(f,'.yml') + " : " + (app_config['global']['description'] || "No description specified in #{File.basename(f,'.yml')}'s application config/application.yml")
|
24
|
+
puts " %-#{biggest}s" % File.basename(f,'.yml') + " : " + (app_config['global']['description'] || "No description specified in #{File.basename(f,'.yml')}'s application config/application.yml")
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "highline/import"
|
2
|
+
|
3
|
+
class UninstallCommand < Command
|
4
|
+
|
5
|
+
include Rcli::Installation
|
6
|
+
|
7
|
+
description "Uninstalls rcli from your system, or uninstalls a specific rcli app"
|
8
|
+
|
9
|
+
def main()
|
10
|
+
|
11
|
+
if $verbose
|
12
|
+
print "params : "
|
13
|
+
pp @params
|
14
|
+
end
|
15
|
+
|
16
|
+
if _installed_rcli_base? && @params[:args].length > 0
|
17
|
+
unless !File.exists? Rcli::RCLI_DOTFOLDER + DS + 'bin' + DS + @params[:args][0]
|
18
|
+
puts "ERROR: The rcli app you provided does not exist. Please type 'rcli list' for list of installed apps."
|
19
|
+
end
|
20
|
+
|
21
|
+
FileUtils.rm(File.exists? Rcli::RCLI_DOTFOLDER + DS + 'bin' + DS + @params[:args][0])
|
22
|
+
FileUtils.rm(File.exists? Rcli::RCLI_DOTFOLDER + DS + 'app_info' + DS + @params[:args][0] + '.yml')
|
23
|
+
|
24
|
+
elsif @params[:args].length > 0 && !_installed_rcli_base?
|
25
|
+
puts "You haven't installed the rcli base yet. Please run 'rcli install' first."
|
26
|
+
elsif _installed_rcli_base?
|
27
|
+
if agree('Are you sure you want to completely remove rcli from your system? (y/n)', true)
|
28
|
+
puts "Deleting : " + Rcli::RCLI_DOTFOLDER if $verbose
|
29
|
+
FileUtils.rm_rf(Rcli::RCLI_DOTFOLDER)
|
30
|
+
end
|
31
|
+
else
|
32
|
+
puts "ERROR: rcli isn't installed"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'core/actions/empty_directory'
|
2
|
+
|
3
|
+
class Rcli
|
4
|
+
module Actions
|
5
|
+
|
6
|
+
# Create a new file relative to the destination root with the given data,
|
7
|
+
# which is the return value of a block or a data string.
|
8
|
+
#
|
9
|
+
# ==== Parameters
|
10
|
+
# destination<String>:: the relative path to the destination root.
|
11
|
+
# data<String|NilClass>:: the data to append to the file.
|
12
|
+
# config<Hash>:: give :verbose => false to not log the status.
|
13
|
+
#
|
14
|
+
# ==== Examples
|
15
|
+
#
|
16
|
+
# create_file "lib/fun_party.rb" do
|
17
|
+
# hostname = ask("What is the virtual hostname I should use?")
|
18
|
+
# "vhost.name = #{hostname}"
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# create_file "config/apach.conf", "your apache config"
|
22
|
+
#
|
23
|
+
def create_file(destination, data=nil, &block)
|
24
|
+
cf = CreateFile.new(destination, block || data.to_s)
|
25
|
+
cf.create
|
26
|
+
end
|
27
|
+
|
28
|
+
alias :add_file :create_file
|
29
|
+
|
30
|
+
# AddFile is a subset of Template, which instead of rendering a file with
|
31
|
+
# ERB, it gets the content from the user.
|
32
|
+
#
|
33
|
+
class CreateFile #:nodoc:
|
34
|
+
attr_reader :data
|
35
|
+
|
36
|
+
def initialize(destination, data)
|
37
|
+
@data = data
|
38
|
+
@destination = destination
|
39
|
+
@empty_dir = EmptyDirectory.new(File.dirname(destination))
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
# Checks if the content of the file at the destination is identical to the rendered result.
|
44
|
+
#
|
45
|
+
# ==== Returns
|
46
|
+
# Boolean:: true if it is identical, false otherwise.
|
47
|
+
#
|
48
|
+
def identical?
|
49
|
+
exists? && File.binread(destination) == render
|
50
|
+
end
|
51
|
+
|
52
|
+
# Holds the content to be added to the file.
|
53
|
+
#
|
54
|
+
def contents
|
55
|
+
@render ||= if data.is_a?(Proc)
|
56
|
+
data.call
|
57
|
+
else
|
58
|
+
data
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def create
|
63
|
+
|
64
|
+
@empty_dir.create
|
65
|
+
File.open(@destination, 'wb') { |f| f.write contents }
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
protected
|
70
|
+
|
71
|
+
# Now on conflict we check if the file is identical or not.
|
72
|
+
#
|
73
|
+
def on_conflict_behavior(&block)
|
74
|
+
if identical?
|
75
|
+
say_status :identical, :blue
|
76
|
+
else
|
77
|
+
options = base.options.merge(config)
|
78
|
+
force_or_skip_or_conflict(options[:force], options[:skip], &block)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# If force is true, run the action, otherwise check if it's not being
|
83
|
+
# skipped. If both are false, show the file_collision menu, if the menu
|
84
|
+
# returns true, force it, otherwise skip.
|
85
|
+
#
|
86
|
+
def force_or_skip_or_conflict(force, skip, &block)
|
87
|
+
if force
|
88
|
+
say_status :force, :yellow
|
89
|
+
block.call unless pretend?
|
90
|
+
elsif skip
|
91
|
+
say_status :skip, :yellow
|
92
|
+
else
|
93
|
+
say_status :conflict, :red
|
94
|
+
force_or_skip_or_conflict(force_on_collision?, true, &block)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Shows the file collision menu to the user and gets the result.
|
99
|
+
#
|
100
|
+
def force_on_collision?
|
101
|
+
base.shell.file_collision(destination){ render }
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
class Rcli
|
2
|
+
module Actions
|
3
|
+
|
4
|
+
# Creates an empty directory.
|
5
|
+
#
|
6
|
+
# ==== Parameters
|
7
|
+
# destination<String>:: the relative path to the destination root.
|
8
|
+
# config<Hash>:: give :verbose => false to not log the status.
|
9
|
+
#
|
10
|
+
# ==== Examples
|
11
|
+
#
|
12
|
+
# empty_directory "doc"
|
13
|
+
#
|
14
|
+
def empty_directory(destination, config={})
|
15
|
+
go EmptyDirectory.new(destination)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Class which holds create directory logic. This is the base class for
|
19
|
+
# other actions like create_file and directory.
|
20
|
+
#
|
21
|
+
# This implementation is based in Templater actions, created by Jonas Nicklas
|
22
|
+
# and Michael S. Klishin under MIT LICENSE.
|
23
|
+
#
|
24
|
+
class EmptyDirectory #:nodoc:
|
25
|
+
attr_reader :destination, :given_destination, :relative_destination
|
26
|
+
|
27
|
+
# Initializes given the source and destination.
|
28
|
+
#
|
29
|
+
# ==== Parameters
|
30
|
+
# base<Thor::Base>:: A Thor::Base instance
|
31
|
+
# source<String>:: Relative path to the source of this file
|
32
|
+
# destination<String>:: Relative path to the destination of this file
|
33
|
+
# config<Hash>:: give :verbose => false to not log the status.
|
34
|
+
#
|
35
|
+
def initialize(destination)
|
36
|
+
@destination = destination
|
37
|
+
end
|
38
|
+
|
39
|
+
# Checks if the destination folder already exists.
|
40
|
+
#
|
41
|
+
# ==== Returns
|
42
|
+
# Boolean:: true if the folder exists, false otherwise.
|
43
|
+
#
|
44
|
+
def exists?
|
45
|
+
::File.exists?(destination)
|
46
|
+
end
|
47
|
+
|
48
|
+
def create
|
49
|
+
if exists?
|
50
|
+
return false;
|
51
|
+
else
|
52
|
+
::FileUtils.mkdir_p(@destination)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
def revoke!
|
58
|
+
say_status :remove, :red
|
59
|
+
::FileUtils.rm_rf(destination) if !pretend? && exists?
|
60
|
+
given_destination
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
# Shortcut for pretend.
|
66
|
+
#
|
67
|
+
def pretend?
|
68
|
+
base.options[:pretend]
|
69
|
+
end
|
70
|
+
|
71
|
+
# Filenames in the encoded form are converted. If you have a file:
|
72
|
+
#
|
73
|
+
# %class_name%.rb
|
74
|
+
#
|
75
|
+
# It gets the class name from the base and replace it:
|
76
|
+
#
|
77
|
+
# user.rb
|
78
|
+
#
|
79
|
+
def convert_encoded_instructions(filename)
|
80
|
+
filename.gsub(/%(.*?)%/) do |string|
|
81
|
+
instruction = $1.strip
|
82
|
+
base.respond_to?(instruction) ? base.send(instruction) : string
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/core/actions.rb
ADDED
data/lib/core/command.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
class Command
|
2
|
+
|
3
|
+
attr_reader :description
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def description(d); @description = d; end
|
7
|
+
def usage(u); @usage = u; end
|
8
|
+
def describe; @description; end
|
9
|
+
def show_use; @usage; end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
before_init
|
14
|
+
@params = {}
|
15
|
+
@options = nil
|
16
|
+
|
17
|
+
# if Rcli.script_config['global']['mode'] == 'multi'
|
18
|
+
# @@description = "Current action not described. Please use \"description '...'\" in " + self.class.to_s + " to correct."
|
19
|
+
# @@usage = "Usage:\n #{Rcli.script_config['global']['script_name']} <command> [--flags,-f] arg1 arg2 arg3 "
|
20
|
+
# else
|
21
|
+
# @@description = Rcli.script_config['global']['description']
|
22
|
+
# @@usage = "Usage:\n #{Rcli.script_config['global']['script_name']} [--flags,-f] arg1 arg2 arg3 "
|
23
|
+
# end
|
24
|
+
|
25
|
+
after_init
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.default_cmd; Rcli.script_config['global']['default_command']; end
|
29
|
+
|
30
|
+
def run(params = {})
|
31
|
+
@params = params
|
32
|
+
@options = parse_parameters
|
33
|
+
$verbose= @options.verbose
|
34
|
+
main
|
35
|
+
end
|
36
|
+
|
37
|
+
def main
|
38
|
+
puts "ERROR: main() method not defined for this command. Please define " + self.class.to_s + "#main() to continue."
|
39
|
+
end
|
40
|
+
|
41
|
+
def help
|
42
|
+
ARGV.push('-h')
|
43
|
+
opts = parse_parameters
|
44
|
+
puts
|
45
|
+
end
|
46
|
+
|
47
|
+
#should be over-ridden in Command classes.
|
48
|
+
def before_init; end
|
49
|
+
def after_init; end
|
50
|
+
|
51
|
+
|
52
|
+
#### CLASS METHODS #####
|
53
|
+
def self.load_all
|
54
|
+
commands = {}
|
55
|
+
|
56
|
+
require Rcli::GEM_LIB + DS + 'commands' + DS + 'debug'
|
57
|
+
require Rcli::GEM_LIB + DS + 'commands' + DS + 'help'
|
58
|
+
commands['debug'] = { :instance => DebugCommand.new }
|
59
|
+
commands['help'] = { :instance => HelpCommand.new }
|
60
|
+
HelpCommand.description "Current action not described. Please use \"description '...'\" in HelpCommand to correct." if not HelpCommand.describe
|
61
|
+
HelpCommand.usage "#{Rcli.script_config['global']['script_name']} <command> [--flags,-f] arg1 arg2 arg3 " if not HelpCommand.show_use
|
62
|
+
DebugCommand.description "Current action not described. Please use \"description '...'\" in DebugCommand to correct." if not DebugCommand.describe
|
63
|
+
DebugCommand.usage "#{Rcli.script_config['global']['script_name']} <command> [--flags,-f] arg1 arg2 arg3 " if not DebugCommand.show_use
|
64
|
+
|
65
|
+
|
66
|
+
Command.get_allowed_commands.each do |c|
|
67
|
+
require Rcli.script_root + DS + 'lib' + DS + 'commands' + DS + c if File.exist?(Rcli.script_root + DS + 'lib' + DS + 'commands' + DS + c + '.rb')
|
68
|
+
Object.const_get("#{camelize(c)}Command").description "Current action not described. Please use \"description '...'\" in #{camelize(c)}Command to correct." if not Object.const_get("#{camelize(c)}Command").describe
|
69
|
+
Object.const_get("#{camelize(c)}Command").usage "#{Rcli.script_config['global']['script_name']} <command> [--flags,-f] arg1 arg2 arg3 " if not Object.const_get("#{camelize(c)}Command").show_use
|
70
|
+
# usage "#{Rcli.script_config['global']['script_name']} <command> [--flags,-f] arg1 arg2 arg3 "
|
71
|
+
|
72
|
+
if c != 'debug' && c != 'help'
|
73
|
+
commands[c] = {
|
74
|
+
# :instance => TraceableFactory.createTraceableObject(camelize(c) + "Command")
|
75
|
+
:instance => Object.const_get("#{camelize(c)}Command").new
|
76
|
+
}
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
commands
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.load(command)
|
84
|
+
commands = {}
|
85
|
+
|
86
|
+
if Command.get_allowed_commands.include?(command)
|
87
|
+
require Rcli.script_root + DS + 'lib' + DS + 'commands' + DS + command if File.exist?(Rcli.script_root + DS + 'lib' + DS + 'commands' + DS + command + '.rb')
|
88
|
+
Object.const_get("#{camelize(command)}Command").description "Current action not described. Please use \"description '...'\" in #{camelize(command)}Command to correct." if not Object.const_get("#{camelize(command)}Command").describe
|
89
|
+
Object.const_get("#{camelize(command)}Command").usage "#{Rcli.script_config['global']['script_name']} <command> [--flags,-f] arg1 arg2 arg3 " if not Object.const_get("#{camelize(command)}Command").show_use
|
90
|
+
commands[command] = {
|
91
|
+
# :instance => TraceableFactory.createTraceableObject("#{camelize(command)}Command")
|
92
|
+
:instance => Object.const_get("#{camelize(command)}Command").new
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
commands
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.get_allowed_commands
|
100
|
+
results = Array.new
|
101
|
+
|
102
|
+
glob = Rcli.script_root + DS + 'lib' + DS + 'commands' + DS + '*'
|
103
|
+
Dir[glob].each{ |c| results << File.basename(c,'.rb')}
|
104
|
+
|
105
|
+
results
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
# def parse_parameters
|
111
|
+
# # This works with the global ARGV, so no parameters need to be passed.
|
112
|
+
# begin
|
113
|
+
# opts = Trollop::options do
|
114
|
+
# banner @@description
|
115
|
+
# banner @@usage
|
116
|
+
# opt :verbose, "Run with extra debugging output", :default => false
|
117
|
+
# end
|
118
|
+
# rescue Trollop::HelpNeeded
|
119
|
+
# exit # stop if help is being displayed
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# end
|
123
|
+
|
124
|
+
def parse_parameters
|
125
|
+
refclass = self.class
|
126
|
+
# This works with the global ARGV, so no parameters need to be passed.
|
127
|
+
opts = Trollop::options do
|
128
|
+
banner "\n" + refclass.describe
|
129
|
+
banner "\nusage: \n " + refclass.show_use + "\n"
|
130
|
+
banner "\noptions:"
|
131
|
+
opt :verbose, "Run with extra debugging output", :default => false
|
132
|
+
|
133
|
+
banner "\n"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'core/command'
|
2
|
+
|
3
|
+
class Commander
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@commands = Command.load_all
|
7
|
+
end
|
8
|
+
|
9
|
+
def go
|
10
|
+
if ARGV.first == '--version'
|
11
|
+
ARGV[0] = 'version' # simulate 'script --version' functionality
|
12
|
+
end
|
13
|
+
|
14
|
+
if ARGV.first == '-h' || ARGV.first == '--help'
|
15
|
+
ARGV[0] = 'help' # catch help requests.
|
16
|
+
end
|
17
|
+
|
18
|
+
if Rcli.script_config['global']['mode'] == 'multi' && ARGV.size == 0
|
19
|
+
ARGV.push Command.default_cmd # default action
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
if Rcli.script_config['global']['mode'] == 'single'
|
24
|
+
if ARGV[0] != 'help' && ARGV[0] != 'version' && ARGV[0] != 'debug'
|
25
|
+
ARGV.insert( 0, Command.default_cmd)
|
26
|
+
end
|
27
|
+
elsif ARGV.first[0,1] !~ /^[a-zA-z]$/
|
28
|
+
puts "ERROR: Please specify a command as first argument"
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
|
32
|
+
command = ARGV.shift # first parameter should be the command at this point.
|
33
|
+
|
34
|
+
unless @commands.keys.include?(command)
|
35
|
+
puts "ERROR: Invalid command: " + command + ". Please use 'help' command for a list of allowed commands."
|
36
|
+
exit
|
37
|
+
end
|
38
|
+
|
39
|
+
# Separate arguments into those preceded by dashes (usually options or flags)
|
40
|
+
# and those not preceded by dashes (usually files)
|
41
|
+
opts = ARGV.collect { |arg| arg if arg[0,1] == '-' }.compact
|
42
|
+
args = ARGV.collect { |arg| arg if arg[0,1] != '-'}.compact
|
43
|
+
|
44
|
+
@commands[command][:instance].run(:opts => opts,:args =>args)
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
data/lib/core/console.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# # shortcut to call a class method that you would like to be traceable
|
2
|
+
# def ccm(className, sym, *args, &block)
|
3
|
+
# TraceableObject.call_class_method(className, sym, *args, &block)
|
4
|
+
# end
|
5
|
+
# # shortcut to instantiate a traceable object
|
6
|
+
# def cto(className)
|
7
|
+
# TraceableFactory.createTraceableObject(className)
|
8
|
+
# end
|
9
|
+
|
10
|
+
def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
|
11
|
+
if first_letter_in_uppercase
|
12
|
+
lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
|
13
|
+
else
|
14
|
+
lower_case_and_underscored_word.first + camelize(lower_case_and_underscored_word)[1..-1]
|
15
|
+
end
|
16
|
+
end
|