arli 0.9.0 → 1.0.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 +0 -1
- data/README.md +87 -259
- data/Rakefile +6 -3
- data/arli.gemspec +13 -11
- data/docs/arlifile.png +0 -0
- data/lib/arli.rb +8 -0
- data/lib/arli/actions/git_repo.rb +5 -15
- data/lib/arli/actions/move_to_library_path.rb +4 -28
- data/lib/arli/arli_file.rb +18 -15
- data/lib/arli/cli/command_finder.rb +1 -1
- data/lib/arli/cli/parser.rb +26 -12
- data/lib/arli/cli/parser_factory.rb +34 -2
- data/lib/arli/cli/runner.rb +2 -1
- data/lib/arli/commands.rb +2 -4
- data/lib/arli/commands/bundle.rb +1 -1
- data/lib/arli/commands/generate.rb +122 -0
- data/lib/arli/commands/install.rb +1 -2
- data/lib/arli/commands/search.rb +1 -1
- data/lib/arli/configuration.rb +14 -5
- data/lib/arli/errors.rb +3 -0
- data/lib/arli/helpers/output.rb +4 -0
- data/lib/arli/helpers/system_commands.rb +48 -0
- data/lib/arli/library/installer.rb +1 -1
- data/lib/arli/lock/file.rb +9 -9
- data/lib/arli/lock/formats/base.rb +2 -2
- data/lib/arli/lock/formats/cmake.rb +8 -19
- data/lib/arli/lock/formats/template/Arlifile.cmake.erb +38 -0
- data/lib/arli/lock/formats/template/cmake_renderer.rb +82 -0
- data/lib/arli/version.rb +1 -1
- metadata +41 -19
data/Rakefile
CHANGED
@@ -7,8 +7,11 @@ def shell(*args)
|
|
7
7
|
system(args.join(' '))
|
8
8
|
end
|
9
9
|
|
10
|
+
task :clean do
|
11
|
+
shell('rm -rfv pkg/ tmp/ coverage/' )
|
12
|
+
end
|
13
|
+
|
10
14
|
task :permissions do
|
11
|
-
shell('rm -rf pkg/ tmp/ coverage/' )
|
12
15
|
shell("chmod -v o+r,g+r * */* */*/* */*/*/* */*/*/*/* */*/*/*/*/*")
|
13
16
|
shell("find . -type d -exec chmod o+x,g+x {} \\;")
|
14
17
|
end
|
@@ -16,8 +19,8 @@ end
|
|
16
19
|
task :build => :permissions
|
17
20
|
|
18
21
|
YARD::Rake::YardocTask.new(:doc) do |t|
|
19
|
-
t.files = %w(lib/**/*.rb exe/*.rb - README.md LICENSE)
|
20
|
-
t.options.unshift('--title','
|
22
|
+
t.files = %w(lib/**/*.rb exe/*.rb - README.md LICENSE.txt)
|
23
|
+
t.options.unshift('--title','Arli — The Missing Arduino Library Manager')
|
21
24
|
t.after = ->() { exec('open doc/index.html') }
|
22
25
|
end
|
23
26
|
|
data/arli.gemspec
CHANGED
@@ -5,9 +5,11 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
5
|
require 'arli/version'
|
6
6
|
|
7
7
|
Arli::DESCRIPTION = <<-eof
|
8
|
-
This is
|
9
|
-
|
10
|
-
|
8
|
+
This is an Arduino Library manager, compatible with the "arduino-cmake" project.
|
9
|
+
Arli offers a powerful command-line tool to manage any number of dependent Github
|
10
|
+
projects, or official Arduino libraries. Arli was created to offer Arduino-based
|
11
|
+
projects of moderate to high complexity an easy way to reference external libraries
|
12
|
+
and install them at build time, instead of committing them into the project repo.
|
11
13
|
eof
|
12
14
|
|
13
15
|
Gem::Specification.new do |spec|
|
@@ -29,20 +31,20 @@ Gem::Specification.new do |spec|
|
|
29
31
|
spec.require_paths = ['lib']
|
30
32
|
|
31
33
|
spec.add_dependency 'arduino-library', '~> 0.5.4'
|
32
|
-
spec.add_dependency 'colored2'
|
33
34
|
spec.add_dependency 'awesome_print'
|
34
|
-
spec.add_dependency '
|
35
|
-
spec.add_dependency 'dry-types'
|
36
|
-
spec.add_dependency 'dry-struct'
|
35
|
+
spec.add_dependency 'colored2'
|
37
36
|
spec.add_dependency 'dry-configurable'
|
37
|
+
spec.add_dependency 'dry-struct'
|
38
|
+
spec.add_dependency 'dry-types'
|
39
|
+
spec.add_dependency 'hashie'
|
40
|
+
spec.add_dependency 'require_dir'
|
38
41
|
spec.add_dependency 'tty-cursor'
|
39
42
|
|
40
|
-
|
41
|
-
spec.add_development_dependency 'yard'
|
42
|
-
spec.add_development_dependency 'simplecov'
|
43
|
+
spec.add_development_dependency 'aruba'
|
43
44
|
spec.add_development_dependency 'bundler', '~> 1.15'
|
44
45
|
spec.add_development_dependency 'rake', '~> 10.0'
|
45
46
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
46
47
|
spec.add_development_dependency 'rspec-its'
|
47
|
-
spec.add_development_dependency '
|
48
|
+
spec.add_development_dependency 'simplecov'
|
49
|
+
spec.add_development_dependency 'yard'
|
48
50
|
end
|
data/docs/arlifile.png
CHANGED
Binary file
|
data/lib/arli.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
|
+
require 'require_dir'
|
2
|
+
|
3
|
+
module Arli
|
4
|
+
extend RequireDir
|
5
|
+
init __FILE__
|
6
|
+
end
|
7
|
+
|
1
8
|
require 'arduino/library'
|
2
9
|
require 'arli/helpers/inherited'
|
10
|
+
require 'arli/helpers/system_commands'
|
3
11
|
require 'arli/version'
|
4
12
|
require 'arli/extensions'
|
5
13
|
require 'arli/errors'
|
@@ -1,7 +1,12 @@
|
|
1
1
|
require_relative 'action'
|
2
|
+
require_relative '../helpers/system_commands'
|
3
|
+
|
2
4
|
module Arli
|
3
5
|
module Actions
|
4
6
|
class GitRepo < Action
|
7
|
+
|
8
|
+
include ::Arli::Helpers::SystemCommands
|
9
|
+
|
5
10
|
description 'Fetches or updates remote git repositories'
|
6
11
|
check_command 'git --version'
|
7
12
|
check_pattern 'git version'
|
@@ -19,21 +24,6 @@ module Arli
|
|
19
24
|
"git clone -v #{library.url} #{library.dir} 2>&1"
|
20
25
|
end
|
21
26
|
|
22
|
-
protected
|
23
|
-
|
24
|
-
# @param <String> *args — list of arguments or a single string
|
25
|
-
def run_system_command(*args)
|
26
|
-
cmd = args.join(' ')
|
27
|
-
raise 'No command to run was given' unless cmd
|
28
|
-
info("\n" + cmd.green) if Arli.debug?
|
29
|
-
o, e, s = Open3.capture3(cmd)
|
30
|
-
info("\n" + o) if o if Arli.debug?
|
31
|
-
info("\n" + e.red) if e && Arli.debug?
|
32
|
-
rescue Exception => e
|
33
|
-
error "Error running [#{args.join(' ')}]\n" +
|
34
|
-
"Current folder is [#{Dir.pwd.yellow}]", e
|
35
|
-
raise e
|
36
|
-
end
|
37
27
|
end
|
38
28
|
end
|
39
29
|
end
|
@@ -1,15 +1,17 @@
|
|
1
1
|
require_relative 'action'
|
2
|
+
require_relative '../helpers/system_commands'
|
2
3
|
|
3
4
|
module Arli
|
4
5
|
module Actions
|
5
6
|
class MoveToLibraryPath < Action
|
7
|
+
|
6
8
|
description 'Moves the downloaded library to the proper path, optionally creating a backup'
|
7
9
|
|
10
|
+
include ::Arli::Helpers::SystemCommands
|
11
|
+
|
8
12
|
def execute
|
9
13
|
Dir.chdir(config.runtime.pwd) do
|
10
|
-
|
11
14
|
handle_preexisting_folder(path) if exists?
|
12
|
-
|
13
15
|
if Dir.exist?(temp_path) && !Dir.exist?(path)
|
14
16
|
FileUtils.mkdir_p(File.dirname(path))
|
15
17
|
___ "current: #{Dir.pwd.yellow}\ntemp_path: #{temp_path.yellow}\nlibrary_path: #{path.yellow}\n" if debug?
|
@@ -23,32 +25,6 @@ module Arli
|
|
23
25
|
end
|
24
26
|
end
|
25
27
|
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def handle_preexisting_folder(to)
|
30
|
-
if Dir.exist?(to)
|
31
|
-
if abort?
|
32
|
-
raise ::Arli::Errors::LibraryAlreadyExists, "Directory #{to} already exists"
|
33
|
-
elsif backup?
|
34
|
-
backup!(to)
|
35
|
-
elsif overwrite?
|
36
|
-
FileUtils.rm_rf(to)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def backup!(p)
|
42
|
-
if Dir.exist?(p)
|
43
|
-
backup_path = "#{p}.arli-backup-#{Time.now.strftime('%Y%m%d%H%M%S')}"
|
44
|
-
FileUtils.mv(p, backup_path)
|
45
|
-
print_target_dir(backup_path, 'backed up')
|
46
|
-
if verbose?
|
47
|
-
___ "\nNOTE: path #{p.blue} has been backed up to #{backup_path.bold.green}\n"
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
28
|
end
|
53
29
|
end
|
54
30
|
end
|
data/lib/arli/arli_file.rb
CHANGED
@@ -18,9 +18,10 @@ module Arli
|
|
18
18
|
include ::Arli::Library
|
19
19
|
|
20
20
|
attr_accessor :dependencies,
|
21
|
-
:
|
21
|
+
:arlifile_hash,
|
22
22
|
:arlifile_path,
|
23
|
-
:config
|
23
|
+
:config,
|
24
|
+
:device
|
24
25
|
|
25
26
|
def initialize(config: Arli.config, libraries: [])
|
26
27
|
self.config = config
|
@@ -29,15 +30,7 @@ module Arli
|
|
29
30
|
|
30
31
|
self.config.libraries.temp_dir ||= Dir.mktmpdir
|
31
32
|
|
32
|
-
|
33
|
-
if parsed_data.libraries_path
|
34
|
-
self.config.libraries.path = parsed_data.libraries_path
|
35
|
-
end
|
36
|
-
|
37
|
-
if parsed_data.lock_format
|
38
|
-
Arli.config.arlifile.lock_format = parsed_data.lock_format
|
39
|
-
end
|
40
|
-
end
|
33
|
+
configure_via_arlifile!(arlifile_hash)
|
41
34
|
end
|
42
35
|
|
43
36
|
alias libraries dependencies
|
@@ -50,6 +43,14 @@ module Arli
|
|
50
43
|
|
51
44
|
private
|
52
45
|
|
46
|
+
def configure_via_arlifile!(mash)
|
47
|
+
if mash
|
48
|
+
config.libraries.path = mash.libraries_path if mash.libraries_path
|
49
|
+
config.arlifile.lock_format = mash.lock_format if mash.lock_format
|
50
|
+
self.device = mash.device if mash.device
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
53
54
|
def within_temp_path(&block)
|
54
55
|
within_path(Arli.config.libraries.temp_dir, &block)
|
55
56
|
end
|
@@ -80,15 +81,17 @@ module Arli
|
|
80
81
|
end
|
81
82
|
|
82
83
|
def parse_yaml_file
|
83
|
-
self.
|
84
|
+
self.arlifile_hash = Hashie::Mash.new(
|
84
85
|
Hashie::Extensions::SymbolizeKeys.symbolize_keys(
|
85
86
|
::YAML.load(
|
86
|
-
::File.read(
|
87
|
-
self.arlifile_path)
|
87
|
+
::File.read(self.arlifile_path)
|
88
88
|
)
|
89
89
|
)
|
90
90
|
)
|
91
|
-
|
91
|
+
|
92
|
+
config.arlifile.hash = arlifile_hash
|
93
|
+
|
94
|
+
arlifile_hash.dependencies.map {|lib| make_lib(lib)}
|
92
95
|
end
|
93
96
|
end
|
94
97
|
end
|
data/lib/arli/cli/parser.rb
CHANGED
@@ -97,9 +97,27 @@ module Arli
|
|
97
97
|
option_search_attributes
|
98
98
|
end
|
99
99
|
|
100
|
-
def
|
100
|
+
def option_generate
|
101
|
+
on('-w', '--workspace DIR',
|
102
|
+
'a top-level folder under which the project will be created',
|
103
|
+
'Default is the current folder.' + "\n\n") do |v|
|
104
|
+
config.generate.workspace = v
|
105
|
+
end
|
106
|
+
|
107
|
+
# on('-L', '--libs "LIBS"',
|
108
|
+
# 'Comma separated list of library names, or name ',
|
109
|
+
# 'substrings, to be searched for and added to the ',
|
110
|
+
# 'initial Arlifile. Multiple matches are added anyway',
|
111
|
+
# 'while no matches are skipped' + "\n\n") do |v|
|
112
|
+
# config.generate.libs = v.split(',')
|
113
|
+
# end
|
114
|
+
|
115
|
+
option_if_exists('project')
|
116
|
+
end
|
117
|
+
|
118
|
+
def option_if_exists(what = 'library')
|
101
119
|
on('-e', '--if-exists ACTION',
|
102
|
-
|
120
|
+
"If a #{what} folder already exists, by default",
|
103
121
|
'it will be overwritten or updated if possible.',
|
104
122
|
'Alternatively you can either ' + 'abort'.bold.blue + ' or ' + 'backup'.bold.blue
|
105
123
|
) do |v|
|
@@ -115,23 +133,19 @@ module Arli
|
|
115
133
|
|
116
134
|
def option_help(commands: false, command_name: nil)
|
117
135
|
common_help_options
|
118
|
-
|
119
136
|
on('-h', '--help', 'prints this help') do
|
120
137
|
::Arli.config.help = true
|
121
138
|
|
122
139
|
command_hash = output_command_description(command_name)
|
123
|
-
|
124
|
-
output_help
|
140
|
+
output_examples(command_hash[:examples]) if command_hash && command_hash[:examples]
|
125
141
|
output_command_help if commands
|
142
|
+
output_help
|
126
143
|
|
127
|
-
|
128
|
-
output_examples(command_hash[:examples])
|
129
|
-
else
|
130
|
-
print_version_copyright
|
131
|
-
end
|
144
|
+
print_version_copyright
|
132
145
|
end
|
133
146
|
end
|
134
147
|
|
148
|
+
|
135
149
|
def option_search_attributes
|
136
150
|
on('-A', '--print-attrs', 'prints full list of available library',
|
137
151
|
'attributes that can be used in search strings.', ' ') do
|
@@ -240,12 +254,12 @@ See #{Arli::Configuration::ARLI_COMMAND.blue + ' command '.green + '--help'.yell
|
|
240
254
|
if command_hash.description
|
241
255
|
header 'Description'
|
242
256
|
if command_hash.sentence
|
243
|
-
output indent + command_hash.sentence.bold
|
257
|
+
output indent + command_hash.sentence.bold.blue
|
244
258
|
output ''
|
245
259
|
end
|
246
260
|
|
247
261
|
text = Array(command_hash[:description]).flatten.join(' ')
|
248
|
-
output text.reformat_wrapped(width = 70, indent_with =
|
262
|
+
output text.reformat_wrapped(width = 70, indent_with = 4).yellow.dark
|
249
263
|
end
|
250
264
|
end
|
251
265
|
|
@@ -75,6 +75,38 @@ module Arli
|
|
75
75
|
}
|
76
76
|
}),
|
77
77
|
|
78
|
+
generate: Hashie::Mash.new(
|
79
|
+
{
|
80
|
+
sentence: 'Generates a new Arduino project with Arlifile',
|
81
|
+
|
82
|
+
description: %Q[This will create a new project folder, a source file, and an Arlifile
|
83
|
+
based on the template project repo defined in the config file. At the moment
|
84
|
+
only arduino-cmake is supported as the build environment as it's the one that
|
85
|
+
provides the widest choice of developer IDEs to use for programming your project.
|
86
|
+
You can use Vim or Emacs, Atom, CLion, Eclipse, Visual Studio, or just plain
|
87
|
+
command line to build and upload your project. Some knowledge of CMake is
|
88
|
+
helpful.
|
89
|
+
],
|
90
|
+
examples: [
|
91
|
+
{ desc: 'Creates a new project in the specified folder. Default is current dir.',
|
92
|
+
cmd: 'arli generate MyClock --workspace ~/Documents/Arduino/Sketches' },
|
93
|
+
|
94
|
+
{ desc: 'Creates a folder "Blinker" in the current directory',
|
95
|
+
cmd: %Q{arli generate Blinker } },
|
96
|
+
|
97
|
+
{ desc: 'Populate initial Arlifile with the libs provided',
|
98
|
+
cmd: %Q{arli generate Weather --libs 'Adafruit Unified Sensor,Adafruit GFX Library,Time' } },
|
99
|
+
],
|
100
|
+
|
101
|
+
parser: -> (command_name) {
|
102
|
+
make_parser(command_name) do |parser|
|
103
|
+
parser.banner = usage_line 'generate' + ' project-name '.magenta
|
104
|
+
parser.option_generate
|
105
|
+
parser.option_help(command_name: command_name)
|
106
|
+
end
|
107
|
+
}
|
108
|
+
}),
|
109
|
+
|
78
110
|
bundle: Hashie::Mash.new(
|
79
111
|
{
|
80
112
|
sentence: 'Installs all libraries specified in Arlifile',
|
@@ -145,7 +177,7 @@ module Arli
|
|
145
177
|
def global_usage(command)
|
146
178
|
'Usage:'.magenta.bold +
|
147
179
|
"\n " + arli_command + ' options '.yellow +
|
148
|
-
"\n " + arli_command + ' ' + ((command || 'command')).
|
180
|
+
"\n " + arli_command + ' ' + ((command || 'command')).cyan.bold + ' [ options ] '.yellow + "\n"
|
149
181
|
end
|
150
182
|
|
151
183
|
def arli_command
|
@@ -154,7 +186,7 @@ module Arli
|
|
154
186
|
|
155
187
|
def command_usage(command)
|
156
188
|
'Usage:'.magenta.bold +
|
157
|
-
"\n " + arli_command + ' ' + command.
|
189
|
+
"\n " + arli_command + ' ' + command.bold.cyan + ' [options]'.yellow + "\n\n" +
|
158
190
|
'Options'.magenta.bold
|
159
191
|
end
|
160
192
|
|
data/lib/arli/cli/runner.rb
CHANGED
data/lib/arli/commands.rb
CHANGED
data/lib/arli/commands/bundle.rb
CHANGED
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'arli'
|
3
|
+
require 'net/http'
|
4
|
+
require_relative 'base'
|
5
|
+
require_relative '../arli_file'
|
6
|
+
require_relative '../helpers/system_commands'
|
7
|
+
require 'forwardable'
|
8
|
+
module Arli
|
9
|
+
module Commands
|
10
|
+
class Generate < Base
|
11
|
+
include ::Arli::Helpers::SystemCommands
|
12
|
+
|
13
|
+
extend Forwardable
|
14
|
+
def_delegators :@settings, :project_name, :project_name=, :workspace, :workspace=, :libs, :libs=, :template_repo
|
15
|
+
|
16
|
+
attr_accessor :settings, :dir
|
17
|
+
|
18
|
+
|
19
|
+
def setup
|
20
|
+
config.generate.project_name = config.runtime.argv.first
|
21
|
+
|
22
|
+
self.settings = config.generate
|
23
|
+
|
24
|
+
raise ::Arli::Errors::RequiredArgumentsMissing, 'Project name is required' unless project_name
|
25
|
+
raise ::Arli::Errors::RequiredArgumentsMissing, 'Template Repo is missing' unless template_repo
|
26
|
+
|
27
|
+
self.dir = settings.workspace + '/' + project_name
|
28
|
+
handle_preexisting_folder(dir) if Dir.exist?(dir)
|
29
|
+
FileUtils.mkdir_p(workspace) unless Dir.exist?(workspace)
|
30
|
+
end
|
31
|
+
|
32
|
+
def run
|
33
|
+
Dir.chdir(workspace) do
|
34
|
+
run_system_command "git clone -v #{template_repo} #{project_name} 2>&1"
|
35
|
+
Dir.chdir(project_name) do
|
36
|
+
FileUtils.rm_rf('.git')
|
37
|
+
run_system_command 'git init .'
|
38
|
+
run_system_command 'bin/setup'
|
39
|
+
configure_template!
|
40
|
+
rename_files!
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def additional_info
|
46
|
+
"Generating project #{project_name.bold.green} into #{workspace.bold.yellow}..."
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def rename_files!
|
52
|
+
Dir.chdir('src') do
|
53
|
+
FileUtils.mv('MyProject.cpp', "#{project_name}.cpp")
|
54
|
+
run_system_command "sed -i 's/MyProject/#{project_name}/g' CMakeLists.txt"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def configure_template!
|
59
|
+
File.open('README.md', 'w') do |f|
|
60
|
+
f.write <<-EOF
|
61
|
+
|
62
|
+
# #{project_name}
|
63
|
+
|
64
|
+
Please refer to the README for the template project, available here:
|
65
|
+
[arli-cmake](#{template_repo}).
|
66
|
+
|
67
|
+
## Usage
|
68
|
+
|
69
|
+
Let's cd into the project folder:
|
70
|
+
|
71
|
+
```bash
|
72
|
+
cd #{project_name}
|
73
|
+
```
|
74
|
+
|
75
|
+
The directory structure should look as follows:
|
76
|
+
|
77
|
+
```
|
78
|
+
#{project_name}
|
79
|
+
|
|
80
|
+
|__ bin/
|
81
|
+
| |___ setup
|
82
|
+
| |___ build
|
83
|
+
|
|
84
|
+
|__ cmake/
|
85
|
+
| |___ Arli.cmake
|
86
|
+
| |___ ArduinoToolchain.cmake <———— provided by arduino-cmake project
|
87
|
+
| |___ Platform/ <———— provided by arduino-cmake project
|
88
|
+
|
|
89
|
+
|__ src/
|
90
|
+
| |___ Arlifile
|
91
|
+
| |___ CMakeLists.txt
|
92
|
+
| |___ #{project_name}.cpp
|
93
|
+
|
|
94
|
+
|__ example/
|
95
|
+
|___ Arlifile
|
96
|
+
|___ CMakeLists.txt
|
97
|
+
|___ Adafruit7SDisplay.cpp
|
98
|
+
```
|
99
|
+
|
100
|
+
You might need to run `bin/setup` first to ensure you have all the dependencies.
|
101
|
+
|
102
|
+
Once you do that, you can build any of the source folders (i.e. either `src` or `example`) by
|
103
|
+
running `bin/build src` or `bin/build example`.
|
104
|
+
|
105
|
+
### Building Manually
|
106
|
+
|
107
|
+
The process to build and upload manually is super simple too:
|
108
|
+
|
109
|
+
```bash
|
110
|
+
cd src
|
111
|
+
rm -rf build && mkdir build && cd build
|
112
|
+
cmake ..
|
113
|
+
make
|
114
|
+
make upload
|
115
|
+
```
|
116
|
+
|
117
|
+
EOF
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|