arli 0.8.3 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -4
- data/.travis.yml +16 -8
- data/README.md +235 -124
- data/Rakefile +1 -1
- data/arli.gemspec +1 -0
- data/exe/arli +1 -0
- data/lib/arli.rb +1 -1
- data/lib/arli/actions/action.rb +7 -33
- data/lib/arli/actions/unzip_file.rb +9 -6
- data/lib/arli/arli_file.rb +32 -28
- data/lib/arli/cli/app.rb +2 -3
- data/lib/arli/cli/command_finder.rb +2 -2
- data/lib/arli/cli/parser.rb +36 -9
- data/lib/arli/cli/parser_factory.rb +40 -38
- data/lib/arli/cli/runner.rb +0 -1
- data/lib/arli/commands/base.rb +2 -2
- data/lib/arli/commands/install.rb +49 -31
- data/lib/arli/commands/search.rb +40 -35
- data/lib/arli/configuration.rb +4 -3
- data/lib/arli/extensions.rb +6 -0
- data/lib/arli/helpers/inherited.rb +48 -0
- data/lib/arli/helpers/output.rb +187 -0
- data/lib/arli/library.rb +21 -2
- data/lib/arli/library/installer.rb +2 -2
- data/lib/arli/library/multi_version.rb +153 -0
- data/lib/arli/library/{proxy.rb → single_version.rb} +5 -20
- data/lib/arli/lock/file.rb +1 -2
- data/lib/arli/lock/formats/base.rb +8 -0
- data/lib/arli/lock/formats/cmake.rb +21 -5
- data/lib/arli/lock/formats/json.rb +2 -0
- data/lib/arli/lock/formats/text.rb +2 -0
- data/lib/arli/lock/formats/yaml.rb +3 -1
- data/lib/arli/version.rb +1 -1
- metadata +20 -5
- data/.rake_tasks~ +0 -8
- data/lib/arli/output.rb +0 -186
data/lib/arli/cli/runner.rb
CHANGED
data/lib/arli/commands/base.rb
CHANGED
@@ -4,12 +4,12 @@ require 'open3'
|
|
4
4
|
require 'arli'
|
5
5
|
require 'arli/version'
|
6
6
|
require 'arli/errors'
|
7
|
-
require 'arli/output'
|
7
|
+
require 'arli/helpers/output'
|
8
8
|
|
9
9
|
module Arli
|
10
10
|
module Commands
|
11
11
|
class Base
|
12
|
-
include Arli::Output
|
12
|
+
include Arli::Helpers::Output
|
13
13
|
|
14
14
|
attr_accessor :config, :name
|
15
15
|
|
@@ -6,38 +6,65 @@ require 'arli'
|
|
6
6
|
require 'arduino/library'
|
7
7
|
require_relative 'base'
|
8
8
|
require_relative 'bundle'
|
9
|
+
require 'arli/library'
|
9
10
|
|
10
11
|
module Arli
|
11
12
|
module Commands
|
12
|
-
class Install <
|
13
|
+
class Install < Base
|
13
14
|
require 'arduino/library/include'
|
14
15
|
|
15
|
-
attr_accessor :library
|
16
|
+
attr_accessor :library,
|
17
|
+
:arlifile,
|
18
|
+
:install_argument,
|
19
|
+
:install_method
|
20
|
+
|
21
|
+
include ::Arli::Library
|
16
22
|
|
17
23
|
def setup
|
18
|
-
|
24
|
+
super
|
25
|
+
|
26
|
+
self.install_argument = runtime.argv.first
|
27
|
+
raise InvalidInstallSyntaxError,
|
28
|
+
"Missing installation argument: a name, a file or a URL." unless install_argument
|
19
29
|
|
20
|
-
self.library
|
21
|
-
|
30
|
+
self.library = identify_library(install_argument)
|
31
|
+
raise Arli::Errors::LibraryNotFound,
|
32
|
+
"Library #{cfg.to_hash} was not found" unless library
|
22
33
|
|
23
|
-
self.arlifile = Arli::ArliFile.new(config: config, libraries: [library])
|
34
|
+
self.arlifile = Arli::ArliFile.new(config: config, libraries: [ library ])
|
35
|
+
if config.trace
|
36
|
+
info("found library using #{install_method}:\n#{library.inspect}")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def run
|
41
|
+
arlifile.install
|
24
42
|
end
|
25
43
|
|
26
44
|
# arg can be 'Adafruit GFX Library'
|
27
45
|
def identify_library(arg)
|
28
|
-
if
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
46
|
+
results = if arg =~ %r[https?://]i
|
47
|
+
self.install_method = :url
|
48
|
+
r = search(url: /^#{arg}$/i)
|
49
|
+
if r.empty?
|
50
|
+
self.install_method = :website
|
51
|
+
r = search(website: /^#{arg}$/i)
|
52
|
+
end
|
53
|
+
if r.empty?
|
54
|
+
self.install_method = :custom
|
55
|
+
r = [ Arduino::Library::Model.from_hash(url: arg, name: File.basename(arg)) ]
|
56
|
+
end
|
57
|
+
r
|
58
|
+
elsif File.exist?(arg) || arg =~ /\.zip$/
|
59
|
+
self.install_method = :archiveFileName
|
60
|
+
search(archiveFileName: "#{File.basename(arg)}")
|
61
|
+
else
|
62
|
+
self.install_method = :name
|
63
|
+
search(name: /^#{arg}$/)
|
64
|
+
end
|
65
|
+
|
66
|
+
validate_search(arg, results)
|
67
|
+
results.sort.last if results && !results.empty?
|
41
68
|
end
|
42
69
|
|
43
70
|
def params
|
@@ -52,19 +79,10 @@ module Arli
|
|
52
79
|
|
53
80
|
def validate_search(arg, results)
|
54
81
|
raise Arli::Errors::LibraryNotFound,
|
55
|
-
"Can't find library by argument #{arg.bold.yellow}" if results.nil? || results.empty?
|
82
|
+
"Can't find library by argument #{arg.bold.yellow}, searching by #{install_method}" if results.nil? || results.empty?
|
83
|
+
dupes = results.map(&:name).uniq.size
|
56
84
|
raise Arli::Errors::TooManyMatchesError,
|
57
|
-
"More than one match found for #{arg.bold.yellow}" if
|
58
|
-
end
|
59
|
-
|
60
|
-
def validate_library
|
61
|
-
raise Arli::Errors::LibraryNotFound,
|
62
|
-
"Library #{cfg.to_hash} was not found" unless library
|
63
|
-
end
|
64
|
-
|
65
|
-
def validate_argument
|
66
|
-
raise InvalidInstallSyntaxError,
|
67
|
-
"Missing installation argument: a name, a file or a URL." unless runtime.argv.first
|
85
|
+
"More than one match found for #{arg.bold.yellow} — #{dupes} libraries matched" if dupes > 1
|
68
86
|
end
|
69
87
|
|
70
88
|
def cfg
|
data/lib/arli/commands/search.rb
CHANGED
@@ -4,53 +4,42 @@ require 'open3'
|
|
4
4
|
require 'arli'
|
5
5
|
require 'arli/commands/base'
|
6
6
|
require 'arli/errors'
|
7
|
+
require 'arli/library/multi_version'
|
7
8
|
require 'arduino/library'
|
8
9
|
|
10
|
+
|
9
11
|
module Arli
|
10
12
|
module Commands
|
11
13
|
class Search < Base
|
12
14
|
|
13
|
-
LibraryWithVersion = Struct.new(:name, :versions)
|
14
|
-
|
15
15
|
require 'arduino/library/include'
|
16
16
|
|
17
17
|
attr_accessor :search_string,
|
18
18
|
:search_opts,
|
19
|
+
:search_method,
|
19
20
|
:results,
|
20
21
|
:limit,
|
21
22
|
:database,
|
22
23
|
:format,
|
23
|
-
:
|
24
|
-
:custom_print
|
24
|
+
:unique_libraries
|
25
25
|
|
26
26
|
def initialize(*args)
|
27
27
|
super(*args)
|
28
|
-
self.format
|
29
|
-
|
30
|
-
|
28
|
+
self.format = config.search.results.output_format
|
29
|
+
valid_methods = Arli::Library::MultiVersion.format_methods
|
30
|
+
raise Arli::Errors::InvalidSearchSyntaxError,
|
31
|
+
"invalid format #{format}" unless valid_methods.include?(format)
|
31
32
|
end
|
32
33
|
|
33
34
|
def run
|
34
|
-
self.search_opts
|
35
|
-
self.results
|
36
|
-
|
37
|
-
results.map do |lib|
|
38
|
-
hash[lib.name] ||= LibraryWithVersion.new(lib.name, [])
|
39
|
-
hash[lib.name].versions << lib.version
|
40
|
-
|
41
|
-
method = "to_s_#{format}".to_sym
|
42
|
-
if lib.respond_to?(method)
|
43
|
-
self.custom_print = false
|
44
|
-
lib.send(method)
|
45
|
-
end
|
46
|
-
end
|
35
|
+
self.search_opts = process_search_options!
|
36
|
+
self.results = search(database, **search_opts).sort
|
37
|
+
self.unique_libraries = Set.new
|
47
38
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
previous = lib.name
|
53
|
-
end
|
39
|
+
results.map { |lib| add_lib_or_version(lib) }
|
40
|
+
|
41
|
+
unique_libraries.each do |multi_version|
|
42
|
+
puts multi_version.send("to_s_#{format}".to_sym)
|
54
43
|
end
|
55
44
|
print_total_with_help
|
56
45
|
rescue Exception => e
|
@@ -58,10 +47,13 @@ module Arli
|
|
58
47
|
puts e.backtrace.join("\n") if ENV['DEBUG']
|
59
48
|
end
|
60
49
|
|
61
|
-
def
|
62
|
-
|
63
|
-
|
64
|
-
|
50
|
+
def add_lib_or_version(lib)
|
51
|
+
a_version = Arli::Library::MultiVersion.new(lib)
|
52
|
+
if unique_libraries.include?(a_version)
|
53
|
+
unique_libraries.find { |l| l.name == a_version.name }&.add_version(library: lib)
|
54
|
+
else
|
55
|
+
unique_libraries << a_version
|
56
|
+
end
|
65
57
|
end
|
66
58
|
|
67
59
|
def process_search_options!
|
@@ -71,9 +63,12 @@ module Arli
|
|
71
63
|
self.limit = config.search.results.limit
|
72
64
|
search_opts = {}
|
73
65
|
begin
|
74
|
-
|
66
|
+
params_code = "{ #{search_string} }"
|
67
|
+
puts "Evaluating: [#{params_code.blue}]\nSearch Method: [#{search_method.to_s.green}]" if config.trace
|
68
|
+
search_opts = eval(params_code)
|
69
|
+
|
75
70
|
rescue => e
|
76
|
-
|
71
|
+
handle_and_raise_error(e)
|
77
72
|
end
|
78
73
|
|
79
74
|
unless search_opts.is_a?(::Hash) && search_opts.size > 0
|
@@ -91,9 +86,19 @@ module Arli
|
|
91
86
|
def extract_search_argument!
|
92
87
|
search = runtime.argv.first
|
93
88
|
if search =~ /:/
|
89
|
+
self.search_method = :ruby
|
94
90
|
search
|
91
|
+
elsif search.start_with?('/')
|
92
|
+
self.search_method = :regex_name_and_url
|
93
|
+
# exact match
|
94
|
+
"#{config.search.default_field}: #{search}, archiveFileName: #{search}"
|
95
|
+
elsif search.start_with?('=')
|
96
|
+
self.search_method = :equals
|
97
|
+
# exact match
|
98
|
+
"#{config.search.default_field}: '#{search[1..-1]}'"
|
95
99
|
elsif search
|
96
|
-
|
100
|
+
self.search_method = :regex
|
101
|
+
"#{config.search.default_field}: /#{search.downcase}/i"
|
97
102
|
end
|
98
103
|
end
|
99
104
|
|
@@ -118,10 +123,10 @@ module Arli
|
|
118
123
|
def print_total_with_help
|
119
124
|
puts "———————————————————————"
|
120
125
|
puts " Total Versions : #{results.size.to_s.bold.magenta}\n"
|
121
|
-
puts "Unique Libraries : #{
|
126
|
+
puts "Unique Libraries : #{unique_libraries.size.to_s.bold.magenta}\n"
|
122
127
|
puts "———————————————————————"
|
123
128
|
if results.size == Arli::Configuration::DEFAULT_RESULTS_LIMIT
|
124
|
-
puts "Hint: use #{'-m
|
129
|
+
puts "Hint: use #{'-m 5'.bold.green} to limit the result set."
|
125
130
|
end
|
126
131
|
end
|
127
132
|
|
data/lib/arli/configuration.rb
CHANGED
@@ -9,7 +9,7 @@ module Arli
|
|
9
9
|
DEFAULT_LOCK_FILENAME = (DEFAULT_FILENAME + '.lock').freeze
|
10
10
|
ACTIONS_WHEN_EXISTS = %i(backup overwrite abort)
|
11
11
|
ARLI_COMMAND = 'arli'.freeze
|
12
|
-
DEFAULT_RESULTS_LIMIT =
|
12
|
+
DEFAULT_RESULTS_LIMIT = 0
|
13
13
|
|
14
14
|
extend Dry::Configurable
|
15
15
|
|
@@ -43,6 +43,7 @@ module Arli
|
|
43
43
|
# Global flags
|
44
44
|
setting :debug, ENV['ARLI_DEBUG'] || false
|
45
45
|
setting :trace, false
|
46
|
+
setting :no_color, false
|
46
47
|
setting :dry_run, false
|
47
48
|
setting :verbose, false
|
48
49
|
setting :help, false
|
@@ -55,7 +56,7 @@ module Arli
|
|
55
56
|
setting :results do
|
56
57
|
setting :attrs
|
57
58
|
setting :limit, DEFAULT_RESULTS_LIMIT
|
58
|
-
setting :
|
59
|
+
setting :output_format, :short
|
59
60
|
end
|
60
61
|
end
|
61
62
|
|
@@ -64,7 +65,7 @@ module Arli
|
|
64
65
|
setting :path, ::Dir.pwd
|
65
66
|
setting :name, ::Arli::Configuration::DEFAULT_FILENAME
|
66
67
|
setting :lock_name, ::Arli::Configuration::DEFAULT_LOCK_FILENAME
|
67
|
-
setting :lock_format, :
|
68
|
+
setting :lock_format, :text
|
68
69
|
end
|
69
70
|
|
70
71
|
setting :bundle do
|
data/lib/arli/extensions.rb
CHANGED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Arli
|
2
|
+
module Helpers
|
3
|
+
module Inherited
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def set_or_get(var_name, val = nil, set_nil = false)
|
7
|
+
var = "@#{var_name}".to_sym
|
8
|
+
self.instance_variable_set(var, val) if val
|
9
|
+
self.instance_variable_set(var, nil) if set_nil
|
10
|
+
self.instance_variable_get(var)
|
11
|
+
end
|
12
|
+
|
13
|
+
def short_name
|
14
|
+
name.gsub(/.*::/, '').underscore.to_sym
|
15
|
+
end
|
16
|
+
|
17
|
+
def attr_assignable(*attrs)
|
18
|
+
self.class.instance_eval do
|
19
|
+
attrs.each do |attribute|
|
20
|
+
send(:define_method, attribute) do |val = nil, **opts|
|
21
|
+
set_or_get(attribute, val, opts && opts[:nil])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module Subclassing
|
29
|
+
def included(klass)
|
30
|
+
klass.instance_eval do
|
31
|
+
class << self
|
32
|
+
include ::Arli::Helpers::Inherited
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.included(base)
|
39
|
+
base.instance_eval do
|
40
|
+
class << self
|
41
|
+
include(::Arli::Helpers::Inherited::ClassMethods)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
base.extend(Subclassing) if base.is_a?(Class)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'colored2'
|
2
|
+
require 'tty-cursor'
|
3
|
+
|
4
|
+
module Arli
|
5
|
+
module Helpers
|
6
|
+
module Output
|
7
|
+
CHAR_FAILURE = '✖'.red
|
8
|
+
CHAR_SUCCESS = '✔'.green
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_accessor :enabled, :cursor
|
12
|
+
|
13
|
+
def enable!
|
14
|
+
self.enabled = true
|
15
|
+
end
|
16
|
+
|
17
|
+
def enabled?
|
18
|
+
self.enabled
|
19
|
+
end
|
20
|
+
|
21
|
+
def disable!
|
22
|
+
self.enabled = false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
self.enable!
|
27
|
+
self.cursor = TTY::Cursor
|
28
|
+
|
29
|
+
def cursor
|
30
|
+
Arli::Helpers::Output.cursor
|
31
|
+
end
|
32
|
+
|
33
|
+
def info(msg, header = nil)
|
34
|
+
__pf('%-20s', header.blue) if header
|
35
|
+
__pf((header ? ' : ' : '') + msg + "\n") if msg
|
36
|
+
end
|
37
|
+
|
38
|
+
def debug(msg)
|
39
|
+
__pf('%-20s', header.blue) if header
|
40
|
+
__pf((header ? ' : ' : '') + msg + "\n") if msg
|
41
|
+
end
|
42
|
+
|
43
|
+
def error(msg, exception = nil)
|
44
|
+
__pf "#{msg.to_s.red}\n" if msg
|
45
|
+
__pf "#{exception.inspect.red}\n\n" if exception
|
46
|
+
end
|
47
|
+
|
48
|
+
def report_exception(e, header = nil)
|
49
|
+
if header
|
50
|
+
__pf header.bold.yellow + ': '
|
51
|
+
else
|
52
|
+
__pf 'Error: '.bold.red
|
53
|
+
end
|
54
|
+
error e.message if (e && e.respond_to?(:message))
|
55
|
+
if e && Arli.config.trace
|
56
|
+
__pf "\n"
|
57
|
+
__pf 'Top 10 stack trace'.bold.yellow + "\n"
|
58
|
+
__pf e.backtrace.reverse[-10..-1].join("\n").red + "\n"
|
59
|
+
elsif e
|
60
|
+
__pf "\nUse -t (--trace) for detailed exception\n" +
|
61
|
+
"or -D (--debug) to print Arli config\n"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def raise_invalid_arli_command!(cmd, e = nil)
|
66
|
+
raise Arli::Errors::InvalidCommandError.new(cmd)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Shortcuts disabled in tests
|
70
|
+
def ___(msg = nil, newline = false)
|
71
|
+
return unless Arli::Helpers::Output.enabled?
|
72
|
+
__pf msg if msg
|
73
|
+
__pt if newline
|
74
|
+
end
|
75
|
+
|
76
|
+
def __pt(*args)
|
77
|
+
puts(*args) if Arli::Helpers::Output.enabled?
|
78
|
+
end
|
79
|
+
|
80
|
+
def __p(*args)
|
81
|
+
print(*args) if Arli::Helpers::Output.enabled?
|
82
|
+
end
|
83
|
+
|
84
|
+
def __pf(*args)
|
85
|
+
printf(*args) if Arli::Helpers::Output.enabled?
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def print_target_dir(d, verb = 'installed')
|
90
|
+
print_action_success(d.green, "#{verb} #{d.green} ")
|
91
|
+
end
|
92
|
+
|
93
|
+
def print_action_starting(action_name)
|
94
|
+
if verbose?
|
95
|
+
indent_cursor
|
96
|
+
___ "⇨ #{action_name.yellow} ... "
|
97
|
+
end
|
98
|
+
if block_given?
|
99
|
+
yield
|
100
|
+
ok if verbose?
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def print_action_success(short, verbose = nil)
|
105
|
+
if verbose? && !quiet?
|
106
|
+
indent_cursor
|
107
|
+
___ "⇨ #{verbose || short} #{CHAR_SUCCESS}"
|
108
|
+
elsif !quiet?
|
109
|
+
___ "#{short} #{CHAR_SUCCESS} "
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def print_action_failure(short, verbose = nil)
|
114
|
+
if verbose? && !quiet?
|
115
|
+
indent_cursor
|
116
|
+
___ "⇨ #{verbose || short} #{CHAR_FAILURE}\n"
|
117
|
+
elsif !quiet?
|
118
|
+
___ "#{short} #{CHAR_FAILURE} "
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def action_fail(action, exception)
|
123
|
+
print_action_failure(action.class.short_name,
|
124
|
+
"#{action.class.short_name} failed with #{exception.message.red}\n" +
|
125
|
+
"Action Description: #{action.class.description}")
|
126
|
+
raise(exception)
|
127
|
+
end
|
128
|
+
|
129
|
+
def action_ok(action)
|
130
|
+
print_action_success(action.action_name)
|
131
|
+
end
|
132
|
+
|
133
|
+
def ok
|
134
|
+
___ " #{CHAR_SUCCESS} "
|
135
|
+
end
|
136
|
+
|
137
|
+
def fuck
|
138
|
+
___ " #{CHAR_FAILURE} "
|
139
|
+
end
|
140
|
+
|
141
|
+
def header(command: nil)
|
142
|
+
out = "\n#{hr}\n"
|
143
|
+
out << "Arli (#{::Arli::VERSION.yellow})"
|
144
|
+
out << ", Command: #{command.name.to_s.magenta.bold}" if command
|
145
|
+
if command && command.params && Arli.config.verbose
|
146
|
+
out << "\n#{command.params.to_s.blue}\n"
|
147
|
+
end
|
148
|
+
out << "\nLibrary Path: #{Arli.default_library_path.green}\n"
|
149
|
+
out << "#{hr}\n"
|
150
|
+
info out
|
151
|
+
end
|
152
|
+
|
153
|
+
def hr
|
154
|
+
('-' * (ENV['COLUMNS'] || 80)).red.dark
|
155
|
+
end
|
156
|
+
|
157
|
+
# Some shortcuts
|
158
|
+
def verbose?
|
159
|
+
config.verbose && !quiet?
|
160
|
+
end
|
161
|
+
|
162
|
+
def quiet?
|
163
|
+
config.quiet
|
164
|
+
end
|
165
|
+
|
166
|
+
def overwrite?
|
167
|
+
config.if_exists.overwrite
|
168
|
+
end
|
169
|
+
|
170
|
+
def backup?
|
171
|
+
config.if_exists.backup
|
172
|
+
end
|
173
|
+
|
174
|
+
def abort?
|
175
|
+
config.if_exists.abort
|
176
|
+
end
|
177
|
+
|
178
|
+
def debug?
|
179
|
+
config.debug
|
180
|
+
end
|
181
|
+
|
182
|
+
def indent_cursor(value = 40)
|
183
|
+
___ cursor.column(value)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|