arli 0.8.3 → 0.9.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.
- 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
|