rcli 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|