arli 0.5.1 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,72 @@
1
+ require 'forwardable'
2
+ require 'optparse'
3
+
4
+ require 'colored2'
5
+
6
+ require_relative 'parser'
7
+ require_relative 'parser_factory'
8
+ require_relative '../commands'
9
+ require_relative '../commands/search'
10
+ require_relative '../commands/install'
11
+ require_relative '../output'
12
+
13
+ module Arli
14
+ module CLI
15
+ class CommandFinder
16
+
17
+ include Arli::Output
18
+
19
+ attr_accessor :argv, :config, :command_name, :command
20
+
21
+ def initialize(argv, config: Arli.config)
22
+ self.config = config
23
+ self.argv = argv
24
+ end
25
+
26
+ def parse!
27
+ self.command_name = detect_command
28
+ parse_command_arguments!(command_name)
29
+ unless Arli.config.help
30
+ self.command = instantiate_command
31
+ if self.command
32
+ config.runtime.command.instance = command
33
+ config.runtime.command.name = command_name
34
+ end
35
+ end
36
+ self
37
+ end
38
+
39
+ def parse_command_arguments!(cmd)
40
+ parser = factory.command_parser(cmd)
41
+ if parser
42
+ factory.parse_argv(parser, argv)
43
+ end
44
+ end
45
+
46
+ def instantiate_command
47
+ self.command_name = detect_command unless command_name
48
+ begin
49
+ name = command_name.to_s.capitalize.to_sym
50
+ command_class = ::Arli::Commands.const_get(name)
51
+ raise_invalid_arli_command!(command_name) unless command_class
52
+ command_class.new(config: config) if command_class
53
+ end
54
+ end
55
+
56
+ def detect_command
57
+ return nil unless argv.first && argv.first !~ /^-.*$/
58
+ cmd = argv.shift.to_sym
59
+ if factory.valid_command?(cmd)
60
+ cmd
61
+ else
62
+ raise_invalid_arli_command!(cmd)
63
+ end
64
+ end
65
+
66
+ def factory
67
+ Arli::CLI::ParserFactory
68
+ end
69
+ end
70
+
71
+ end
72
+ end
@@ -1,21 +1,19 @@
1
- require 'arduino/library'
2
- require 'arli/config'
3
- require 'arli/version'
1
+ require 'arli/configuration'
4
2
 
5
3
  module Arli
6
- class CLI
4
+ module CLI
7
5
  class Parser < OptionParser
8
- attr_accessor :output_lines, :command, :options, :arlifile
9
6
 
10
- def initialize(command = nil)
7
+ attr_accessor :output_lines,
8
+ :command,
9
+ :config
10
+
11
+ def initialize(config: Arli.config, command: nil)
11
12
  super(nil, 22)
12
- self.output_lines = ::Array.new
13
- self.command = command
14
- self.options = ::Hashie::Mash.new
15
- self.arlifile = options[:arli_dir] ?
16
- options[:arli_dir] + '/' + Arli::Config::DEFAULT_FILENAME :
17
- Arli::Config::DEFAULT_FILENAME
18
- self.options[:arlifile] = arlifile
13
+
14
+ self.config = config
15
+ self.command = command
16
+ self.output_lines = ::Array.new
19
17
  end
20
18
 
21
19
  def sep(text = nil)
@@ -23,17 +21,18 @@ module Arli
23
21
  end
24
22
 
25
23
  def option_dependency_file
26
- on('-p', '--arli-path PATH',
24
+ on('-a', '--arli-path PATH',
27
25
  'Folder where ' + 'Arlifile'.green + ' is located,',
28
26
  "Defaults to the current directory.\n\n") do |v|
29
- options[:arli_dir] = v
27
+ config.arlifile.path = v
30
28
  end
31
29
  end
32
30
 
33
31
  def option_lib_home
34
- on('-l', '--libs PATH', 'Local folder where libraries are installed',
35
- "Defaults to #{default_library_path}\n\n") do |v|
36
- options[:lib_home] = v
32
+ on('-l', '--libraries PATH',
33
+ 'Local folder where libraries are installed',
34
+ "Defaults to #{Arli.default_library_path}\n\n") do |v|
35
+ config.libraries.path = v
37
36
  end
38
37
  end
39
38
 
@@ -41,12 +40,13 @@ module Arli
41
40
  on('-d', '--database FILE/URL',
42
41
  'a JSON file name, or a URL that contains the index',
43
42
  'Defaults to the Arduino-maintained list') do |v|
44
- options[:database] = v
43
+ config.database.path = v
45
44
  end
45
+
46
46
  on('-m', '--max NUMBER',
47
47
  'if provided, limits the result set to this number',
48
48
  'Defaults to 100') do |v|
49
- options[:limit] = v.to_i if v
49
+ config.search.results.limit = v.to_i if v
50
50
  end
51
51
  end
52
52
 
@@ -56,47 +56,37 @@ module Arli
56
56
  'it will be overwritten or updated if possible.',
57
57
  'Alternatively you can either ' + 'abort'.bold.blue + ' or ' + 'backup'.bold.blue
58
58
  ) do |v|
59
- if v =~ /abort/i
60
- options[:abort_if_exists] = true
61
- elsif v =~ /backup/
62
- options[:create_backup] = true
63
- elsif v =~ /replace/
59
+ if v == 'abort'
60
+ config.install.if_exists.abort = true
61
+ config.install.if_exists.overwrite = false
62
+ elsif v == 'backup'
63
+ config.install.if_exists.backup = true
64
64
  end
65
65
  end
66
66
  sep ' '
67
67
  end
68
68
 
69
69
  def option_help(commands: false, command_name: nil)
70
- on('-D', '--debug',
71
- 'Print debugging info.') do |v|
72
- options[:debug] = true
73
- end
74
- on('-t', '--trace',
75
- 'Print exception stack traces.') do |v|
76
- options[:trace] = v
77
- end
78
- on('-v', '--verbose',
79
- 'Print more information.') do |v|
80
- options[:verbose] = true
81
- end
82
- on('-V', '--version',
83
- 'Print current version and exit') do |v|
84
- output 'Version: ' + Arli::VERSION
85
- options[:help] = true
86
- end
70
+ common_help_options
71
+
87
72
  on('-h', '--help', 'prints this help') do
88
- output 'Description:' if command_name
89
- output ' ' * 4 + command_name[:description].green if command_name
90
- output ''
73
+ ::Arli.config.help = true
74
+
75
+ command_hash = factory.command_parsers[command_name]
76
+
77
+ if command_hash && command_hash[:description]
78
+ output 'Description:'
79
+ output ' ' + command_hash[:description]
80
+ output ''
81
+ end
82
+
91
83
  output_help
92
84
  output_command_help if commands
93
85
 
94
- if command_name && command_name[:example]
86
+ if command_hash && command_hash[:example]
95
87
  output 'Example:'
96
- output ' ' * 4 + command_name[:example]
88
+ output ' ' + command_hash[:example]
97
89
  end
98
-
99
- options[:help] = true
100
90
  end
101
91
  end
102
92
 
@@ -113,14 +103,14 @@ module Arli
113
103
  end
114
104
 
115
105
  def command_help
116
- subtext = "Available Commands:\n"
117
106
 
118
- ::Arli::CLI.commands.each_pair do |command, config|
119
- subtext << %Q/#{sprintf(' %-12s', command.to_s).green} : #{sprintf('%s', config[:description]).yellow}\n/
107
+ subtext = "Available Commands:\n"
108
+ factory.command_parsers.each_pair do |command, config|
109
+ subtext << %Q/#{sprintf(' %-12s', command.to_s).green} — #{sprintf('%s', config[:description]).blue}\n/
120
110
  end
121
111
  subtext << <<-EOS
122
-
123
- See #{COMMAND.blue + ' <command> '.green + '--help'.yellow} for more information on a specific command.
112
+
113
+ See #{Arli::Configuration::ARLI_COMMAND.blue + ' command '.green + '--help'.yellow} for more information on a specific command.
124
114
 
125
115
  EOS
126
116
  subtext
@@ -135,8 +125,28 @@ See #{COMMAND.blue + ' <command> '.green + '--help'.yellow} for more information
135
125
  puts output.join("\n") unless output.empty?
136
126
  end
137
127
 
138
- def default_library_path
139
- ::Arli.config.library_path.gsub(%r(#{ENV['HOME']}), '~').blue
128
+ def factory
129
+ Arli::CLI::ParserFactory
130
+ end
131
+
132
+ def common_help_options
133
+ on('-D', '--debug',
134
+ 'Print debugging info.') do |v|
135
+ config.debug = true
136
+ end
137
+ on('-t', '--trace',
138
+ 'Print exception stack traces.') do |v|
139
+ config.trace = v
140
+ end
141
+ on('-v', '--verbose',
142
+ 'Print more information.') do |v|
143
+ config.verbose = true
144
+ end
145
+ on('-V', '--version',
146
+ 'Print current version and exit') do |v|
147
+ puts 'Version: ' + Arli::VERSION
148
+ exit
149
+ end
140
150
  end
141
151
  end
142
152
  end
@@ -0,0 +1,97 @@
1
+ require_relative 'parser'
2
+
3
+ module Arli
4
+ module CLI
5
+ module ParserFactory
6
+
7
+ class << self
8
+
9
+ def default_help
10
+ gp = global_parser
11
+ gp.parse!(%w(--help))
12
+ gp.print
13
+ end
14
+
15
+ def parse_argv(parser, argv)
16
+ if parser
17
+ parser.parse!(argv)
18
+ parser.print
19
+ end
20
+ end
21
+
22
+ def make_parser(command = nil, &block)
23
+ ::Arli::CLI::Parser.new(command: command,
24
+ config: Arli.config, &block)
25
+ end
26
+
27
+ def global_parser
28
+ @global ||= make_parser do |parser|
29
+ parser.banner = usage_line
30
+ parser.sep
31
+ parser.option_help(commands: true)
32
+ end
33
+ end
34
+
35
+ def command_parsers
36
+ @command_parsers ||= {
37
+ install: {
38
+ description: 'installs libraries defined in Arlifile',
39
+ parser: -> (command_name) {
40
+ make_parser(command_name) do |parser|
41
+ parser.banner = usage_line 'install'
42
+ parser.option_lib_home
43
+ parser.option_dependency_file
44
+ parser.option_abort_if_exists
45
+ parser.option_help(command_name: command_name)
46
+ end
47
+ } },
48
+
49
+ search: {
50
+ description: 'Flexible Search of the Arduino Library Database',
51
+ example: 'arli search '.green + %Q['name: /AudioZero/, version: "1.0.1"'].green,
52
+ parser: -> (command_name) {
53
+ make_parser(command_name) do |parser|
54
+ parser.banner = usage_line 'search ' + '[ name-match | expression ]'.magenta
55
+ parser.option_search
56
+ parser.option_help(command_name: command_name)
57
+ end
58
+ }
59
+ }
60
+ }
61
+ end
62
+
63
+ def commands
64
+ command_parsers.keys
65
+ end
66
+
67
+ def valid_command?(command)
68
+ commands.include?(command)
69
+ end
70
+
71
+ def command_parser(cmd)
72
+ cmd_hash = command_parsers[cmd]
73
+ cmd_hash ? cmd_hash[:parser].call(cmd) : nil
74
+ end
75
+
76
+ def global_usage(command)
77
+ "Usage:\n " + Arli::Configuration::ARLI_COMMAND.blue +
78
+ ' [ options ] '.yellow + '[ ' + (command || 'command').green +
79
+ ' [ options ] '.yellow + ' ]' + "\n"
80
+ end
81
+
82
+ def command_usage(command)
83
+ "Usage:\n " + Arli::Configuration::ARLI_COMMAND.blue + ' ' +
84
+ command.green +
85
+ ' [options]'.yellow + "\n\n" +
86
+ 'Command Options'
87
+ end
88
+
89
+ def usage_line(command = nil)
90
+ command ? command_usage(command) : global_usage(command)
91
+ end
92
+ end
93
+
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,40 @@
1
+ require 'colored2'
2
+ require 'arli/cli/app'
3
+ require 'pp'
4
+ module Arli
5
+ module CLI
6
+ # For the reasons this file is the way it is, please refer to
7
+ # https://github.com/erikhuda/thor/wiki/Integrating-with-Aruba-In-Process-Runs
8
+ class Runner
9
+ def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel)
10
+ @argv, @stdin, @stdout, @stderr, @kernel = argv, stdin, stdout, stderr, kernel
11
+ end
12
+
13
+ def execute!
14
+ exit_code = begin
15
+ $stderr = @stderr
16
+ $stdin = @stdin
17
+ $stdout = @stdout
18
+
19
+ Arli::CLI::App.new(@argv).start
20
+ 0
21
+ rescue StandardError => e
22
+ b = e.backtrace
23
+ @stderr.puts("#{b.shift.bold}:\n")
24
+ @stderr.puts("#{e.message.bold.red} (#{e.class.name.yellow})")
25
+ @stderr.puts(b.map { |s| "\tfrom #{s}" }.join("\n")).red
26
+ 1
27
+ rescue SystemExit => e
28
+ e.status
29
+ ensure
30
+ $stderr = STDERR
31
+ $stdin = STDIN
32
+ $stdout = STDOUT
33
+ ap(Arli.config.to_hash, indent: 6, index: false) if Arli.config.debug
34
+ end
35
+ @kernel.exit(exit_code)
36
+ end
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,8 @@
1
+ module Arli
2
+ module Commands
3
+ end
4
+ end
5
+
6
+ require_relative 'commands/base'
7
+ require_relative 'commands/search'
8
+ require_relative 'commands/install'
@@ -4,51 +4,44 @@ require 'open3'
4
4
  require 'arli'
5
5
  require 'arli/version'
6
6
  require 'arli/errors'
7
+ require 'arli/output'
7
8
 
8
9
  module Arli
9
10
  module Commands
10
11
  class Base
11
- attr_accessor :lib_path,
12
- :arlifile,
13
- :abort_if_exists,
14
- :create_backup,
15
- :command,
16
- :debug,
17
- :trace
18
-
19
- def initialize(options)
20
- self.lib_path = options[:lib_home]
21
- self.abort_if_exists = options[:abort_if_exists]
22
- self.create_backup = options[:create_backup]
23
- self.debug = options[:debug]
24
- self.trace = options[:trace]
25
-
26
- self.command = self.class.name.gsub(/.*::/, '').downcase.to_sym
12
+ include Arli::Output
13
+
14
+ attr_accessor :config, :name
15
+
16
+ def initialize(config: Arli.config)
17
+ self.config = config
18
+ FileUtils.mkdir_p(library_path) unless Dir.exist?(library_path)
27
19
  setup
28
20
  end
29
21
 
30
- def name
31
- self.class.name.gsub(/.*::/, '').downcase
22
+ def run(*args)
23
+ raise ArgumentError, 'This method must be implemented in subclasses'
32
24
  end
33
25
 
34
- def setup
35
- FileUtils.mkdir_p(lib_path)
26
+ def runtime
27
+ config.runtime
36
28
  end
37
29
 
38
- def error(msg, exception = nil)
39
- printf 'Runtime Error: '.red + "\n#{msg}\n" if msg
40
- if exception
41
- puts
42
- printf 'Exception: '.red + "\n#{exception.inspect.red}\n\n"
43
- end
44
- puts
30
+ def name
31
+ @name ||= self.class.name.gsub(/.*::/, '').downcase.to_sym
45
32
  end
46
33
 
47
- def info(msg, header = nil)
48
- printf('%-20s', header.blue) if header
49
- printf((header ? ' : ' : '') + msg + "\n") if msg
34
+ def library_path
35
+ config.libraries.path
50
36
  end
51
37
 
38
+ def setup
39
+
40
+ end
41
+
42
+ def params
43
+
44
+ end
52
45
  end
53
46
  end
54
47
  end