arli 0.3.2 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 445a4cbb2237add42b7a6dac5d41ef30cb7ffc6c
4
- data.tar.gz: 79d3becd74cabb839d0f2dfa699c1bfcfccf417e
3
+ metadata.gz: 233ae21fdec4ad9e4f6fd73c632dc632d626a5df
4
+ data.tar.gz: 4db04f61697a98c6288a81d5179bfc62fccf79ee
5
5
  SHA512:
6
- metadata.gz: 16ebcf812896a46d11cd336ab05dda084e655f549fa0468fd367226f8dd0ae012f8b91651139e5a11906f894c183cb94a91c1731eec4790f0a362575399bc3ab
7
- data.tar.gz: 21952cf71941c8b994b5b59aff00a305ab51f7abb0c98464112502e3e891c241be31518bfacb1d85bb77ad0d20c714541fd50a0a9ca77c060812f754b52b194d
6
+ metadata.gz: ca67abe8ac90302ffdf49aedfc0c3a33f999f5bc28721aa027e7f9ad104a29cbadff9bcc4ace2fed7bbb2fccf0fc6aada19f38f4096f597599c4188ed8eaf950
7
+ data.tar.gz: 1635be7126e6515ad602c68388d0e660b2536a12a5d197621c057fcec48f0641a477224cbd87072ea673c9b51c2692a9b9153e2dec1fbc6465c02816dfbb7c66
data/.gitignore CHANGED
@@ -14,3 +14,4 @@
14
14
  **/.DS_Store
15
15
  .ruby-version
16
16
  .rspec_status
17
+ !/lib/arli/commands/install.rb
@@ -1,5 +1,18 @@
1
+ env:
2
+ global:
3
+ - CC_TEST_REPORTER_ID=f8f229bdf1f374a3a9227d3bef6f57b78f88c73a2d4705c9de5852bb484eaaef
1
4
  sudo: false
2
5
  language: ruby
6
+ cache: bundler
3
7
  rvm:
4
8
  - 2.4.1
9
+ - 2.3.5
5
10
  before_install: gem install bundler -v 1.15.4
11
+ before_script:
12
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
13
+ - chmod +x ./cc-test-reporter
14
+ - ./cc-test-reporter before-build
15
+ script:
16
+ - bundle exec rspec
17
+ after_script:
18
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
data/README.md CHANGED
@@ -1,23 +1,29 @@
1
+ [![Gem Version](https://badge.fury.io/rb/arli.svg)](https://badge.fury.io/rb/arli)
1
2
  [![Build Status](https://travis-ci.org/kigster/arli.svg?branch=master)](https://travis-ci.org/kigster/arli)
3
+ [![Maintainability](https://api.codeclimate.com/v1/badges/0812671b4bec27ba89b9/maintainability)](https://codeclimate.com/github/kigster/arli/maintainability)
4
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/0812671b4bec27ba89b9/test_coverage)](https://codeclimate.com/github/kigster/arli/test_coverage)
2
5
 
3
6
  # Arli
4
7
 
5
- Arli is a simple and easy to use installer of dependencies that can be
6
- declared in a YAML file of the following format:
8
+ Arli is a simple and easy to use Arduino Dependency Manager, that uses a
9
+ a YAML formatted file declaring dependencies, as follows:
7
10
 
8
11
  ```yaml
12
+ # vi:syntax=yaml
9
13
  version: 1.0.0
10
14
  dependencies:
11
15
  - name: ESP8266WiFi
12
16
  version: '1.0'
13
17
  url: https://github.com/esp8266/Arduino
14
- subfolder: libraries/ESP8266WiFi
15
- - name: NTPClient
16
- version: '3.1.0'
18
+ - name: Time
19
+ - name: "Adafruit GFX Library"
17
20
  - name: SimpleTimer
18
- urL: https://github.com/jfturcot/SimpleTimer
21
+ url: https://github.com/jfturcot/SimpleTimer
19
22
  ```
20
23
 
24
+ The libraries may be specified with a name and url only, OR they can be specified by name (and optionally version) — as long as this is one of the standard libraries documented in the [Arduino official library database](http://downloads.arduino.cc/libraries/library_index.json.gz) JSON file.
25
+
26
+
21
27
  Basically a simple pairing of a library/project name
22
28
  (which also happens to be the local directory it's cloned into)
23
29
  and a remote URL.
@@ -31,11 +37,9 @@ API was loosely inspired by Bundler.
31
37
  Install the gem globally like this:
32
38
 
33
39
  ```bash
34
- # if using rbenv, or rvm
40
+ # if using rbenv, or rvm; otherwise you may need to prefix
41
+ # with 'sudo'
35
42
  $ gem install arli
36
-
37
- # OR, if your Ruby is a system ruby installed in eg. /usr/local,
38
- $ sudo gem install arli
39
43
  ```
40
44
 
41
45
  ## Usage
@@ -43,14 +47,18 @@ $ sudo gem install arli
43
47
  Run `arli --help` for more information:
44
48
 
45
49
  ```bash
50
+
46
51
  Usage:
47
- arli [options] [ command [options] ]
52
+ arli [options] [ command [options] ]
48
53
 
49
- -h, --help prints this help
54
+ -D, --debug Print debugging info.
55
+ -t, --trace Print exception stack traces.
56
+ -v, --verbose Print more information.
57
+ -V, --version Print current version and exit
58
+ -h, --help prints this help
50
59
 
51
60
  Available Commands:
52
- install : installs libraries defined in ArliFile.yml
53
- update : updates libraries defined in the ArliFile.yml
61
+ install : installs libraries defined in Arlifile
54
62
  search : Flexible Search of the Arduino Library Database
55
63
 
56
64
  See arli <command> --help for more information on a specific command.
@@ -66,41 +74,30 @@ target library already exists.
66
74
 
67
75
  ```bash
68
76
  Description:
69
- installs libraries defined in ArliFile.yml
77
+ installs libraries defined in Arlifile
70
78
 
71
79
  Usage:
72
80
  arli install [options]
73
81
 
74
82
  Command Options
75
- -l, --lib-home HOME Local folder where libraries are installed
76
- Default: ~/Documents/Arduino/Libraries
77
-
78
- -a, --arli-file FILE ArliFile.yml is the file listing the dependencies
79
- Default filename is ArliFile.yml
80
-
81
- -e, --abort-on-exiting Abort if a library folder already exists
82
- instead of updating it.
83
- -h, --help prints this help
84
- ```
83
+ -l, --libs PATH Local folder where libraries are installed
84
+ Defaults to ~/Dropbox/Workspace/oss/arduino/libraries
85
85
 
86
- #### Update Command
86
+ -p, --arli-path PATH Folder where Arlifile is located,
87
+ Defaults to the current directory.
87
88
 
88
- To upate previously checked out libraries, use the `update` command:
89
+ -e, --if-exists ACTION If a library folder already exists, by default
90
+ it will be overwritten or updated if possible.
91
+ Alternatively you can either abort or backup
89
92
 
90
- ```bash
91
- Description:
92
- updates libraries defined in the JSON file
93
-
94
- Usage:
95
- arli update [options]
96
-
97
- Command Options
98
- -l, --lib-home HOME Local folder where libraries are installed
99
- Default: ~/Documents/Arduino/Libraries
100
- -j, --json FILE JSON file with dependencies (defaults to arli.json)
93
+ -D, --debug Print debugging info.
94
+ -t, --trace Print exception stack traces.
95
+ -v, --verbose Print more information.
96
+ -V, --version Print current version and exit
101
97
  -h, --help prints this help
102
98
  ```
103
99
 
100
+
104
101
  #### Search Command
105
102
 
106
103
  To search Arduino library database, you can use the search command:
@@ -110,17 +107,22 @@ Description:
110
107
  Flexible Search of the Arduino Library Database
111
108
 
112
109
  Usage:
113
- arli search [options]
110
+ arli search <query> [options]
114
111
 
115
112
  Command Options
116
- -s, --search TERMS ruby-style hash arguments to search for
117
- eg: -s "name: 'AudioZero', version: /^1.0/"
118
- -d, --database SOURCE a JSON file name, or a URL that contains the index
119
- By default, the Arduino-maintained list is searched
120
- -m, --max LIMIT if provided, limits the result set to this number
121
- Default value is 100
113
+ -d FILE/URL, a JSON file name, or a URL that contains the index
114
+ --database Defaults to the Arduino-maintained list
115
+ -m, --max NUMBER if provided, limits the result set to this number
116
+ Defaults to 100
117
+ -D, --debug Print debugging info.
118
+ -t, --trace Print exception stack traces.
119
+ -v, --verbose Print more information.
120
+ -V, --version Print current version and exit
122
121
  -h, --help prints this help
123
- ```
122
+
123
+ Example:
124
+ arli search 'name: /AudioZero/, version: "1.0.1"'
125
+ I```
124
126
 
125
127
  ## Development
126
128
 
@@ -28,12 +28,13 @@ Gem::Specification.new do |spec|
28
28
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
29
  spec.require_paths = ['lib']
30
30
 
31
- spec.add_dependency 'arduino-library'
31
+ spec.add_dependency 'arduino-library', '~> 0.4.1'
32
32
  spec.add_dependency 'colored2'
33
33
  spec.add_dependency 'hashie'
34
34
  spec.add_dependency 'dry-types'
35
35
  spec.add_dependency 'dry-struct'
36
36
  spec.add_dependency 'awesome_print'
37
+ spec.add_dependency 'archive-zip'
37
38
 
38
39
 
39
40
  spec.add_development_dependency 'simplecov'
data/exe/arli CHANGED
@@ -6,4 +6,3 @@ Arli::CLI.new.tap do |cli|
6
6
  cli.parse
7
7
  end
8
8
 
9
-
@@ -1,41 +1,42 @@
1
- require 'arli/version'
2
- require 'arli/arli_file'
3
- require 'arli/configuration'
4
- require 'arli/cli'
1
+ require 'forwardable'
5
2
  require 'logger'
3
+ require 'arduino/library'
6
4
 
7
- module Arli
8
- LIBRARY_INDEX_JSON_GZ = 'http://downloads.arduino.cc/libraries/library_index.json.gz'.freeze
5
+ require 'arli/version'
6
+ require 'arli/errors'
7
+ require 'arli/logger'
8
+ require 'arli/config'
9
9
 
10
- DEFAULT_ARLI_FILE_ENV = 'ARDUINO_ARLI_LIBRARY_FILE'.freeze
11
- DEFAULT_ARLI_FILE = ENV[DEFAULT_ARLI_FILE_ENV] || ArliFile::DEFAULT_FILE_NAME
10
+ module Arli
12
11
 
13
- DEBUG = ENV['DEBUG'] ? true : false
12
+ class << self
13
+ attr_accessor :config
14
+ end
14
15
 
15
- @logger = Logger.new(STDOUT)
16
- @logger.level = Logger::INFO
16
+ self.config = ::Arli::Config
17
17
 
18
18
  class << self
19
- attr_accessor :logger
20
- attr_writer :configuration
19
+ extend Forwardable
20
+ def_delegators :@config, *::Arli::Config::PARAMS
21
21
 
22
- %i(debug info error warn fatal).each do |level|
23
- define_method level do |*args|
24
- self.logger.send(level, *args) if self.logger
25
- end
22
+ def configure(&_block)
23
+ yield(self.config)
26
24
  end
27
- end
28
-
29
- def self.configuration
30
- @configuration ||= Configuration.new
31
- end
32
25
 
33
- def self.reset
34
- @configuration = Configuration.new
26
+ def debug?
27
+ self.debug
28
+ end
35
29
  end
30
+ end
36
31
 
37
- def self.configure
38
- yield(configuration)
39
- end
32
+ Arli.configure do |config|
33
+ config.library_path = ::Arduino::Library::DefaultDatabase.library_path
34
+ config.library_index_path = ::Arduino::Library::DefaultDatabase.library_index_path
35
+ config.library_index_url = ::Arduino::Library::DefaultDatabase.library_index_url
36
+ config.logger = ::Logger.new(STDOUT, level: :info)
37
+ config.debug = ENV['ARLI_DEBUG'] || false
40
38
  end
41
39
 
40
+ require 'arli/arli_file'
41
+ require 'arli/installer'
42
+ require 'arli/cli'
@@ -1,24 +1,67 @@
1
1
  require 'arli'
2
- require 'arduino/library'
3
2
  require 'yaml'
3
+ require 'forwardable'
4
+ require 'arduino/library'
4
5
 
5
6
  module Arli
6
7
  class ArliFile
7
8
  require 'arduino/library/include'
8
9
 
10
+ include Enumerable
11
+
9
12
  extend Forwardable
10
13
  def_delegators :@dependencies, *(Array.new.methods - Object.methods)
11
14
 
12
- DEFAULT_FILE_NAME = 'ArliFile.yml'.freeze
15
+ attr_accessor :dependencies, :file_hash, :file, :lib_path, :resolved
13
16
 
14
- attr_accessor :dependencies, :arli_hash, :file
17
+ def initialize(lib_path: Arli.library_path,
18
+ arlifile_path: nil)
19
+
20
+ self.lib_path = lib_path
21
+ self.file = arlifile_path ? "#{arlifile_path}/#{Arli::Config::DEFAULT_FILENAME}" :
22
+ Arli::Config::DEFAULT_FILENAME
23
+ raise(Arli::Errors::ArliFileNotFound, 'Arlifile could not be found') unless file || !File.exist?(file)
24
+ self.dependencies = []
25
+
26
+ parse!
27
+ end
15
28
 
16
- def initialize(file = DEFAULT_FILE_NAME)
17
- self.file = file
18
- self.arli_hash = ::YAML.load(File.read(file))
19
- self.dependencies = arli_hash['dependencies'].map do |lib_hash|
20
- library_from(lib_hash)
29
+
30
+ def libraries
31
+ self.dependencies
32
+ end
33
+
34
+ def within_lib_path
35
+ FileUtils.mkpath(lib_path) unless Dir.exist?(lib_path)
36
+ Dir.chdir(lib_path) do
37
+ yield if block_given?
21
38
  end
22
39
  end
40
+
41
+ def each_dependency(&_block)
42
+ within_lib_path do
43
+ dependencies.each do |dependency|
44
+ yield(dependency)
45
+ end
46
+ end
47
+ end
48
+
49
+ def error(*args)
50
+ STDERR.puts *args.join("\n")
51
+ end
52
+
53
+ def info(*args)
54
+ STDOUT.puts *args.join("\n") if Arli.debug?
55
+ end
56
+
57
+ private
58
+
59
+ def parse!
60
+ self.file_hash = ::YAML.load(::File.read(self.file))
61
+ self.dependencies = file_hash['dependencies'].map do |lib|
62
+ ::Arduino::Library::Model.from_hash(lib)
63
+ end
64
+ end
65
+
23
66
  end
24
67
  end
@@ -4,19 +4,16 @@ require 'hashie/extensions/symbolize_keys'
4
4
  require 'colored2'
5
5
  require 'arli'
6
6
  require 'arli/parser'
7
- require 'arli/commands/update'
8
7
  require 'arli/commands/install'
9
8
  require 'arli/commands/search'
10
9
 
11
10
  module Arli
12
11
  class CLI
13
- class InvalidCommandError < ArgumentError;
14
- end
15
12
 
16
- COMMAND = 'arli'
13
+ COMMAND = 'arli'.freeze
17
14
  PARSER = ::Arli::CLI::Parser
18
15
 
19
- attr_accessor :argv, :command, :parser
16
+ attr_accessor :argv, :parser, :command_name, :command
20
17
  attr_accessor :options
21
18
 
22
19
  def initialize(argv = ARGV.dup)
@@ -41,53 +38,95 @@ module Arli
41
38
 
42
39
  self.options = Hashie::Extensions::SymbolizeKeys.symbolize_keys!(options.to_h)
43
40
 
44
- run_command! unless options[:help]
41
+ unless options[:help]
42
+ self.command = create_command if command_name
43
+ execute
44
+ end
45
45
 
46
- rescue InvalidCommandError => e
47
- output e.message
48
- end
46
+ rescue OptionParser::InvalidOption => e
47
+ report_exception(e, 'Command line usage error!')
49
48
 
50
- def self.output(*args)
51
- puts args.join("\n") unless args.empty?
52
- end
49
+ rescue Arli::Errors::InvalidCommandError
50
+ report_exception(e, 'This command does not exist')
53
51
 
54
- def output(*args)
55
- self.class.output(*args)
52
+ rescue Exception => e
53
+ report_exception(e)
54
+ raise e if options[:trace]
56
55
  end
57
56
 
58
57
  private
59
58
 
60
- def run_command!
61
- if command
62
- command_class = ::Arli::Commands.const_get(command.to_s.capitalize)
63
-
64
- options[:arli_file] ||= ::Arli::DEFAULT_ARLI_FILE
65
- options[:lib_home] ||= ::Arduino::Library::DEFAULT_ARDUINO_LIBRARY_PATH
59
+ def report_exception(e, header = nil)
60
+ error header.bold.yellow if header
61
+ printf ' ☠ '
62
+ error e.message if e && e.respond_to?(:message)
63
+ end
66
64
 
67
- output "run_command #{command.to_s.bold.green}, options: #{options.inspect.bold.blue}" if Arli::DEBUG
68
- @command_instance = command_class.new(options)
69
- @command_instance.header.run
65
+ def execute
66
+ if command
67
+ header
68
+ command.run
69
+ else
70
+ gp = self.class.global
71
+ gp.parse!(%w(--help))
72
+ gp.print
73
+ nil
70
74
  end
71
75
  rescue NameError => e
72
- output e.inspect
76
+ error e.inspect
77
+ error e.backtrace.join("\n") if options[:trace]
78
+ end
79
+
80
+ def create_command
81
+ command_class = ::Arli::Commands.const_get(command_name.to_s.capitalize)
82
+
83
+ options[:lib_home] ||= ::Arli.config.library_path
84
+ options[:argv] = argv
85
+
86
+ info "created command #{command_name.to_s.green},\noptions: #{options.inspect.blue}" if Arli.debug?
87
+
88
+ command_class.new(options)
89
+ end
90
+
91
+ def header
92
+ out = ''
93
+ out << "Arli (#{::Arli::VERSION.yellow})"
94
+ out << " running #{command.name.to_s.blue}" if command
95
+ out << "\n"
96
+ out << "Library Folder: #{options[:lib_home].gsub(/#{ENV['HOME']}/, '~').green}\n" if options[:lib_home]
97
+ out << '——————————————————————————————————————————————————————————'
98
+ info out
99
+ end
100
+
101
+ def info(*args)
102
+ self.class.output(*args)
103
+ end
104
+
105
+ def error(*args)
106
+ self.class.output(*(args.compact.map { |a| a.to_s.red }))
73
107
  end
74
108
 
75
109
  def parse_command_options!
76
- self.class.parser_for(command)
110
+ self.class.parser_for(command_name)
77
111
  end
78
112
 
79
113
  def command_detected?
80
- self.command = argv.shift if argv.first && argv.first !~ /^-.*$/
81
- if self.command
82
- self.command = command.to_sym
83
- unless self.class.commands.key?(command)
84
- raise InvalidCommandError, "Error: #{command ? command.to_s.bold.red : 'nil'} is not a valid arli command!"
114
+ self.command_name = argv.shift if argv.first && argv.first !~ /^-.*$/
115
+ if self.command_name
116
+ self.command_name = command_name.to_sym
117
+ unless self.class.commands.key?(command_name)
118
+ raise Arli::Errors::InvalidCommandError, "Error: #{command_name ? command_name.to_s.red : 'nil'} is not a valid arli command_name!"
85
119
  end
86
120
  end
87
- self.command
121
+ self.command_name
88
122
  end
89
123
 
90
124
  class << self
125
+
126
+ def output(*args)
127
+ puts args.join("\n") unless args.empty?
128
+ end
129
+
91
130
  def global
92
131
  @global ||= PARSER.new do |parser|
93
132
  parser.banner = usage_line
@@ -101,63 +140,43 @@ module Arli
101
140
  end
102
141
 
103
142
  def global_usage(command)
104
- "Usage:\n ".bold + COMMAND.bold.blue +
105
- ' [options] '.yellow + '[' + (command || 'command').green +
106
- ' [options]'.yellow + ']' + "\n"
143
+ "Usage:\n " + COMMAND.blue +
144
+ ' [options] '.yellow + '[ ' + (command || 'command').green +
145
+ ' [options] '.yellow + ' ]' + "\n"
107
146
  end
108
147
 
109
148
  def command_usage(command)
110
- "Usage:\n ".bold + COMMAND.bold.blue + ' ' +
111
- command.bold.green +
149
+ "Usage:\n " + COMMAND.blue + ' ' +
150
+ command.green +
112
151
  ' [options]'.yellow + "\n\n" +
113
- 'Command Options'.bold
152
+ 'Command Options'
114
153
  end
115
154
 
116
155
  def commands
117
156
  @commands ||= {
118
157
  install: {
119
- description: 'installs libraries defined in ArliFile.yml',
120
- parser: -> (command) {
158
+ description: 'installs libraries defined in Arlifile',
159
+ parser: -> (command_name) {
121
160
  PARSER.new do |parser|
122
161
  parser.banner = usage_line 'install'
123
162
  parser.option_lib_home
124
163
  parser.option_dependency_file
125
164
  parser.option_abort_if_exists
126
- parser.option_help(command: command)
127
- end
128
- } },
129
-
130
- update: {
131
- description: 'updates libraries defined in the ArliFile.yml',
132
- parser: -> (command) {
133
- PARSER.new do |parser|
134
- parser.banner = usage_line 'update'
135
- parser.option_lib_home
136
- parser.option_dependency_file
137
- parser.option_help(command: command)
165
+ parser.option_help(command_name: command_name)
138
166
  end
139
167
  } },
140
168
 
141
169
  search: {
142
170
  description: 'Flexible Search of the Arduino Library Database',
143
- parser: -> (command) {
171
+ example: 'arli search '.green + %Q['name: /AudioZero/, version: "1.0.1"'].green,
172
+ parser: -> (command_name) {
144
173
  PARSER.new do |parser|
145
- parser.banner = usage_line 'search'
174
+ parser.banner = usage_line 'search ' + '<query>'.magenta
146
175
  parser.option_search
147
- parser.option_help(command: command)
176
+ parser.option_help(command_name: command_name)
148
177
  end
149
- } }
150
-
151
- # library: {
152
- # description: 'Install, update, or remove a single library',
153
- # parser: -> (command) {
154
- # PARSER.new do |parser|
155
- # parser.banner = usage_line 'library'
156
- # parser.option_lib_home
157
- # parser.option_library
158
- # parser.option_help(command: command)
159
- # end
160
- # } }
178
+ }
179
+ }
161
180
  }
162
181
  end
163
182
 
@@ -166,7 +185,8 @@ module Arli
166
185
  cmd_hash = commands[cmd]
167
186
  commands[cmd][:parser][cmd_hash]
168
187
  else
169
- raise(InvalidCommandError, "'#{cmd}' is not a valid command.\nSupported commands are:\n\t#{commands.keys.join("\n\t")}")
188
+ raise(Arli::Errors::InvalidCommandError,
189
+ "'#{cmd}' is not a valid command_name.\nSupported commands are:\n\t#{commands.keys.join("\n\t")}")
170
190
  end
171
191
  end
172
192
  end