arli 0.9.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|