rpremote 0.6.0 → 0.7.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/CHANGELOG.md +6 -0
- data/README.ja.md +3 -1
- data/README.md +3 -1
- data/RELEASING.md +2 -2
- data/THIRD_PARTY_NOTICES.md +1 -1
- data/lib/rpremote/build_command.rb +3 -3
- data/lib/rpremote/builder.rb +14 -8
- data/lib/rpremote/cli/filesystem_commands.rb +105 -0
- data/lib/rpremote/cli.rb +20 -105
- data/lib/rpremote/config.rb +6 -5
- data/lib/rpremote/config_show.rb +13 -5
- data/lib/rpremote/deploy_command.rb +85 -54
- data/lib/rpremote/help/dfu_commands.rb +59 -0
- data/lib/rpremote/help/filesystem_commands.rb +36 -0
- data/lib/rpremote/help/project_commands.rb +89 -0
- data/lib/rpremote/help/remote_commands.rb +54 -0
- data/lib/rpremote/help/root_text.rb +63 -0
- data/lib/rpremote/help.rb +27 -300
- data/lib/rpremote/mrbgems/definition.rb +116 -0
- data/lib/rpremote/mrbgems/file_writer.rb +26 -0
- data/lib/rpremote/mrbgems/lockfile.rb +131 -0
- data/lib/rpremote/mrbgems.rb +95 -155
- data/lib/rpremote/mrbgems_command.rb +19 -4
- data/lib/rpremote/version.rb +1 -1
- data/patches/picoruby-4.0.4-pwm-sleep-clock.patch +27 -0
- data/sig/rpremote.rbs +11 -4
- metadata +11 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 69cb11c8175c8864e4ae4a11108fb37e1ac08bab49b0b61ade2331f550b7d4b6
|
|
4
|
+
data.tar.gz: 7e32c77e20cda016f4b95ad5e60a5ccabf8a5d8aa1570ce8bcf3fd642b700b9d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f690408489ed84040dd492d4872747ec0a523d17bafc76603c885722c5aaca43a3a5f0d74584ca81f0ec5e7b4758bf0477a17f2877af045c81756894962fd5a8
|
|
7
|
+
data.tar.gz: bd1046210f3d48e00604328f72531455f236bd3e348b2bded6495b2681bf383367413ed2083b1469090d24ce10ab37ce85605454efa867e01c88a351807595aa
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ Notable changes to the `rpremote` RubyGem will be documented in this file. Repos
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.7.0 - 2026-10-04
|
|
8
|
+
|
|
9
|
+
- Add Bundler-style `group` blocks and `gem ..., group:` to `Mrbgems`; `mrbgems lock|update --with/--without` now selects the locked firmware contents, with exclusions taking precedence, and build/runtime commands consume `Mrbgems.lock` without selecting groups again.
|
|
10
|
+
- Make `Mrbgems.lock` version 2 a self-contained build input, add path checksum verification, and replace build/runtime `--mrbgems` and `--groups` options with `--lockfile`.
|
|
11
|
+
- Keep active RP2040/RP2350 PWM slices clocked during scheduler sleep on PicoRuby 4.0.4, and restore clock gating after the final slice stops.
|
|
12
|
+
|
|
7
13
|
## 0.6.0 - 2026-09-20
|
|
8
14
|
|
|
9
15
|
- Change the default PicoRuby version to `latest`, backed by the current `master` branch, while retaining `--language-version` for selecting a release tag.
|
data/README.ja.md
CHANGED
|
@@ -59,7 +59,9 @@ rpremote mrbgems lock
|
|
|
59
59
|
rpremote build
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
`Mrbgems.lock
|
|
62
|
+
`Mrbgems.lock`は`build`で使うmrbgemを確定します。ビルドは`Mrbgems`を評価せず、GitHub branchも解決せずにlockを読みます。新しいコミットを解決するのは`rpremote mrbgems update`です。
|
|
63
|
+
|
|
64
|
+
構成ごとのgemは`group :development do ... end`または`gem ..., group: :development`で整理できます。`rpremote mrbgems lock --with production --without test`はグループ外の共通gemとproduction gemをlockへ記録します。除外指定が優先され、`build`、`deploy`、`run`、`exec`はそのlockだけを使います。
|
|
63
65
|
|
|
64
66
|
ファームウェアへ組み込む一方で、すべての`run`、`exec`、`deploy`に先行ロードしないgemには`auto_require: false`を指定できます。アプリケーション側から必要なgemを明示的に`require`してください。
|
|
65
67
|
|
data/README.md
CHANGED
|
@@ -59,7 +59,9 @@ rpremote mrbgems lock
|
|
|
59
59
|
rpremote build
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
`Mrbgems.lock` pins
|
|
62
|
+
`Mrbgems.lock` pins the exact mrbgems used by `build`. Builds read the lock without evaluating `Mrbgems` or resolving GitHub branches; `rpremote mrbgems update` deliberately resolves new commits.
|
|
63
|
+
|
|
64
|
+
Use `group :development do ... end` blocks or `gem ..., group: :development` to organize variant-specific gems. `rpremote mrbgems lock --with production --without test` writes common and production gems to the lock; exclusions take precedence, and `build`, `deploy`, `run`, and `exec` then use exactly that lock.
|
|
63
65
|
|
|
64
66
|
Set `auto_require: false` for a gem that should remain embedded in firmware without being loaded before every `run`, `exec`, or `deploy`. Require that gem explicitly from the application when needed.
|
|
65
67
|
|
data/RELEASING.md
CHANGED
|
@@ -49,7 +49,7 @@ bundle exec rake release
|
|
|
49
49
|
After the tag exists on GitHub, create a GitHub Release and attach the exact gem that passed validation. `--verify-tag` prevents GitHub CLI from silently creating a tag at another commit:
|
|
50
50
|
|
|
51
51
|
```sh
|
|
52
|
-
gh release create v0.
|
|
52
|
+
gh release create v0.7.0 rpremote-0.7.0.gem --verify-tag --generate-notes
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
Replace `0.
|
|
55
|
+
Replace `0.7.0` in both places for later versions. Finally, install from RubyGems.org in a fresh environment and run `rpremote --version`.
|
data/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Third-Party Notices
|
|
2
2
|
|
|
3
|
-
`rpremote` does not bundle R2P2 firmware. The `setup` command downloads
|
|
3
|
+
`rpremote` does not bundle R2P2 firmware. The `setup` command downloads and prepares the selected PicoRuby/R2P2 source archive from the PicoRuby project.
|
|
4
4
|
|
|
5
5
|
`setup` also downloads Raspberry Pi's `nuke_universal.uf2` from the official Pico SDK prebuilts release. It is used only by `rpremote bootsel --reset-flash-memory` to erase external flash memory.
|
|
6
6
|
|
|
@@ -19,7 +19,7 @@ module Rpremote
|
|
|
19
19
|
board: Target::DEFAULT_BOARD,
|
|
20
20
|
cache_dir: defaults.fetch(:cache, Target::DEFAULT_CACHE_DIR),
|
|
21
21
|
firmware: defaults[:firmware],
|
|
22
|
-
|
|
22
|
+
mrbgems_lock: defaults[:mrbgems_lock]
|
|
23
23
|
}.merge(defaults.except(:cache))
|
|
24
24
|
OptionParser.new do |parser|
|
|
25
25
|
parser.on("--language LANGUAGE") { |value| options[:language] = value }
|
|
@@ -27,8 +27,8 @@ module Rpremote
|
|
|
27
27
|
parser.on("--board BOARD") { |value| options[:board] = value }
|
|
28
28
|
parser.on("--firmware FILE") { |value| options[:firmware] = value }
|
|
29
29
|
parser.on("--cache DIR") { |value| options[:cache_dir] = value }
|
|
30
|
-
parser.on("--
|
|
31
|
-
parser.on("--no-mrbgems") { options[:
|
|
30
|
+
parser.on("--lockfile FILE") { |value| options[:mrbgems_lock] = value }
|
|
31
|
+
parser.on("--no-mrbgems") { options[:mrbgems_lock] = false }
|
|
32
32
|
end.parse!(args)
|
|
33
33
|
raise ArgumentError, "build does not accept arguments" unless args.empty?
|
|
34
34
|
|
data/lib/rpremote/builder.rb
CHANGED
|
@@ -71,12 +71,12 @@ module Rpremote
|
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def add_mrbgems_environment!(environment, options, source_dir, output)
|
|
74
|
-
|
|
75
|
-
return unless
|
|
74
|
+
lock_file = mrbgems_lock(options[:mrbgems_lock])
|
|
75
|
+
return unless lock_file
|
|
76
76
|
|
|
77
|
-
manager = mrbgems_class.new(
|
|
77
|
+
manager = mrbgems_class.new(lock_path: lock_file, cwd: root)
|
|
78
78
|
config_language = mrbgems_config_language(
|
|
79
|
-
manager.
|
|
79
|
+
manager.locked_vm, options.fetch(:language), options.fetch(:language_version)
|
|
80
80
|
)
|
|
81
81
|
config_name = "r2p2-#{config_language}-#{options.fetch(:board)}"
|
|
82
82
|
base_config = File.join(source_dir, "build_config", "#{config_name}.rb")
|
|
@@ -90,7 +90,6 @@ module Rpremote
|
|
|
90
90
|
environment["RPREMOTE_CONFIG_NAME"] = config_name
|
|
91
91
|
environment["RPREMOTE_MRUBY_CONFIG"] = overlay.path
|
|
92
92
|
environment["RPREMOTE_MRBGEMS_FINGERPRINT"] = overlay.fingerprint
|
|
93
|
-
output.puts("using Mrbgems: #{manager.path}")
|
|
94
93
|
output.puts("using Mrbgems.lock: #{manager.lock_path}")
|
|
95
94
|
end
|
|
96
95
|
|
|
@@ -103,12 +102,19 @@ module Rpremote
|
|
|
103
102
|
modern ? "picoruby" : "microruby"
|
|
104
103
|
end
|
|
105
104
|
|
|
106
|
-
def
|
|
105
|
+
def mrbgems_lock(option)
|
|
107
106
|
return if option == false
|
|
108
107
|
|
|
109
|
-
candidate = File.expand_path(option || Mrbgems::
|
|
108
|
+
candidate = File.expand_path(option || Mrbgems::DEFAULT_LOCK_PATH, root)
|
|
110
109
|
return candidate if File.file?(candidate)
|
|
111
|
-
raise Error, "mrbgems
|
|
110
|
+
raise Error, "mrbgems lock file does not exist: #{candidate}" if option
|
|
111
|
+
|
|
112
|
+
definition = File.join(root, Mrbgems::DEFAULT_PATH)
|
|
113
|
+
if File.file?(definition)
|
|
114
|
+
raise Error,
|
|
115
|
+
"Mrbgems.lock does not exist: #{candidate}; " \
|
|
116
|
+
"run `rpremote mrbgems lock` before building"
|
|
117
|
+
end
|
|
112
118
|
|
|
113
119
|
nil
|
|
114
120
|
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rpremote
|
|
4
|
+
class CLI
|
|
5
|
+
module FilesystemCommands
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def fs(args)
|
|
9
|
+
subcommand = args.shift
|
|
10
|
+
recursive = subcommand == "cp" && (args.delete("--recursive") || args.delete("-r"))
|
|
11
|
+
options = parse_connection_options(args)
|
|
12
|
+
case subcommand
|
|
13
|
+
when "cp"
|
|
14
|
+
copy(args, options, recursive: recursive)
|
|
15
|
+
when "push"
|
|
16
|
+
copy(args, options, recursive: true, command: "push")
|
|
17
|
+
when "cat"
|
|
18
|
+
cat(args, options)
|
|
19
|
+
when "ls", "rm", "mkdir"
|
|
20
|
+
filesystem_shell_command(subcommand, args, options)
|
|
21
|
+
else
|
|
22
|
+
raise ArgumentError, "unknown fs command: #{subcommand || "(none)"}"
|
|
23
|
+
end
|
|
24
|
+
rescue Shell::TimeoutError => e
|
|
25
|
+
raise Shell::TimeoutError, "filesystem connection failed: #{e.message}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def copy(args, options, recursive: false, command: "cp")
|
|
29
|
+
usage = command == "push" ? "rpremote fs push LOCAL_DIR :/REMOTE_DIR" : "rpremote fs cp SOURCE DESTINATION"
|
|
30
|
+
raise ArgumentError, "usage: #{usage} [options]" unless args.length == 2
|
|
31
|
+
|
|
32
|
+
source, destination = args
|
|
33
|
+
source_remote = RemotePath.remote?(source)
|
|
34
|
+
destination_remote = RemotePath.remote?(destination)
|
|
35
|
+
raise ArgumentError, "exactly one cp path must be remote (prefix remote paths with :)" if source_remote == destination_remote
|
|
36
|
+
return RecursiveCopy.new(output: stdout, serial: serial, device: device).call(source, destination, options) if recursive
|
|
37
|
+
|
|
38
|
+
ensure_filesystem_connection!(options)
|
|
39
|
+
if source_remote
|
|
40
|
+
data = with_modem(options) { |modem| modem.download(RemotePath.unwrap(source)) }
|
|
41
|
+
File.binwrite(local_destination(destination, source), data)
|
|
42
|
+
stdout.puts("downloaded #{data.bytesize} bytes: #{source} -> #{destination}")
|
|
43
|
+
else
|
|
44
|
+
data = File.binread(source)
|
|
45
|
+
with_modem(options) { |modem| modem.upload(RemotePath.unwrap(destination), data) }
|
|
46
|
+
stdout.puts("uploaded #{data.bytesize} bytes: #{source} -> #{destination}")
|
|
47
|
+
end
|
|
48
|
+
rescue Errno::ENOENT => e
|
|
49
|
+
raise ArgumentError, e.message
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def cat(args, options)
|
|
53
|
+
raise ArgumentError, "usage: rpremote fs cat :/REMOTE/PATH [options]" unless args.length == 1
|
|
54
|
+
raise ArgumentError, "cat path must be remote (prefix it with :)" unless RemotePath.remote?(args.first)
|
|
55
|
+
|
|
56
|
+
stdout.write(with_modem(options) { |modem| modem.download(RemotePath.unwrap(args.first)) })
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def filesystem_shell_command(command, args, options)
|
|
60
|
+
usage = "usage: rpremote fs #{command} :/REMOTE/PATH [options]"
|
|
61
|
+
raise ArgumentError, usage unless args.length == 1
|
|
62
|
+
|
|
63
|
+
path = RemotePath.validate(args.first)
|
|
64
|
+
stdout.puts("deleting remote path permanently: #{path}") if command == "rm"
|
|
65
|
+
output = with_shell(options) do |shell|
|
|
66
|
+
shell.execute("#{command} #{Shell.quote_argument(path)}")
|
|
67
|
+
end
|
|
68
|
+
ensure_filesystem_success!(command, output)
|
|
69
|
+
stdout.write(output)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def ensure_filesystem_success!(command, output)
|
|
73
|
+
failed = command == "ls" ? output.start_with?("ls:") : !output.empty?
|
|
74
|
+
raise Shell::CommandError, output.strip if failed
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def ensure_filesystem_connection!(options)
|
|
78
|
+
output = with_shell(options) { |shell| shell.execute("ls '/'") }
|
|
79
|
+
ensure_filesystem_success!("ls", output)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def with_modem(options)
|
|
83
|
+
port_path = device.main_port(options[:port])
|
|
84
|
+
serial.open(port_path, baud: options[:baud]) do |port|
|
|
85
|
+
yield PicoModem.new(port, timeout: options[:timeout])
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def with_shell(options)
|
|
90
|
+
port_path = device.main_port(options[:port])
|
|
91
|
+
serial.open(port_path, baud: options[:baud]) do |port|
|
|
92
|
+
shell = Shell.new(port, timeout: options[:timeout])
|
|
93
|
+
shell.synchronize!
|
|
94
|
+
yield shell
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def local_destination(destination, source)
|
|
99
|
+
return destination unless File.directory?(destination)
|
|
100
|
+
|
|
101
|
+
File.join(destination, File.basename(RemotePath.unwrap(source)))
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
data/lib/rpremote/cli.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "optparse"
|
|
4
4
|
require_relative "build_command"
|
|
5
5
|
require_relative "bootsel_command"
|
|
6
|
+
require_relative "cli/filesystem_commands"
|
|
6
7
|
require_relative "config_show"
|
|
7
8
|
require_relative "dfu_command"
|
|
8
9
|
require_relative "deploy_command"
|
|
@@ -12,9 +13,10 @@ require_relative "mrbgems_command"
|
|
|
12
13
|
require_relative "recursive_copy"
|
|
13
14
|
require_relative "setup_command"
|
|
14
15
|
|
|
15
|
-
# rubocop:disable Metrics/ClassLength
|
|
16
16
|
module Rpremote
|
|
17
17
|
class CLI
|
|
18
|
+
include FilesystemCommands
|
|
19
|
+
|
|
18
20
|
def self.start(argv = ARGV, config: Config, **options)
|
|
19
21
|
new(**options).run(argv, config: config)
|
|
20
22
|
rescue OptionParser::ParseError, ArgumentError, SystemCallError, Rpremote::Error => e
|
|
@@ -136,44 +138,24 @@ module Rpremote
|
|
|
136
138
|
ConfigShow.run(args, defaults: config_options, output: stdout)
|
|
137
139
|
end
|
|
138
140
|
|
|
139
|
-
def fs(args)
|
|
140
|
-
subcommand = args.shift
|
|
141
|
-
recursive = subcommand == "cp" && (args.delete("--recursive") || args.delete("-r"))
|
|
142
|
-
options = parse_connection_options(args)
|
|
143
|
-
case subcommand
|
|
144
|
-
when "cp"
|
|
145
|
-
copy(args, options, recursive: recursive)
|
|
146
|
-
when "push"
|
|
147
|
-
copy(args, options, recursive: true, command: "push")
|
|
148
|
-
when "cat"
|
|
149
|
-
cat(args, options)
|
|
150
|
-
when "ls", "rm", "mkdir"
|
|
151
|
-
filesystem_shell_command(subcommand, args, options)
|
|
152
|
-
else
|
|
153
|
-
raise ArgumentError, "unknown fs command: #{subcommand || "(none)"}"
|
|
154
|
-
end
|
|
155
|
-
rescue Shell::TimeoutError => e
|
|
156
|
-
raise Shell::TimeoutError, "filesystem connection failed: #{e.message}"
|
|
157
|
-
end
|
|
158
|
-
|
|
159
141
|
def run_file(args)
|
|
160
142
|
reset_on_timeout = !args.delete("--reset-on-timeout").nil?
|
|
161
|
-
options = parse_connection_options(args)
|
|
143
|
+
options = parse_connection_options(args, mrbgems_lock: true)
|
|
162
144
|
raise ArgumentError, "usage: rpremote run FILE [options]" unless args.length == 1
|
|
163
145
|
|
|
164
146
|
source = args.first
|
|
165
147
|
source = File.join(source, "main.rb") if File.directory?(source)
|
|
166
|
-
data = prepend_mrbgem_requires(File.binread(source))
|
|
148
|
+
data = prepend_mrbgem_requires(File.binread(source), options[:mrbgems_lock])
|
|
167
149
|
execute_temporary(data, options, output: stdout, reset_on_timeout: reset_on_timeout)
|
|
168
150
|
rescue Errno::ENOENT => e
|
|
169
151
|
raise ArgumentError, e.message
|
|
170
152
|
end
|
|
171
153
|
|
|
172
154
|
def execute_code(args)
|
|
173
|
-
options = parse_connection_options(args)
|
|
155
|
+
options = parse_connection_options(args, mrbgems_lock: true)
|
|
174
156
|
raise ArgumentError, "usage: rpremote exec CODE [options]" unless args.length == 1
|
|
175
157
|
|
|
176
|
-
execute_temporary(prepend_mrbgem_requires(args.first), options, output: stdout)
|
|
158
|
+
execute_temporary(prepend_mrbgem_requires(args.first, options[:mrbgems_lock]), options, output: stdout)
|
|
177
159
|
end
|
|
178
160
|
|
|
179
161
|
def execute_temporary(data, options, output: nil, reset_on_timeout: false)
|
|
@@ -197,8 +179,13 @@ module Rpremote
|
|
|
197
179
|
"#{timeout_error.message}; automatic reset failed: #{e.message}"
|
|
198
180
|
end
|
|
199
181
|
|
|
200
|
-
def prepend_mrbgem_requires(data)
|
|
201
|
-
|
|
182
|
+
def prepend_mrbgem_requires(data, lock_file)
|
|
183
|
+
return data if lock_file == false
|
|
184
|
+
|
|
185
|
+
path = lock_file || Mrbgems::DEFAULT_LOCK_PATH
|
|
186
|
+
raise ArgumentError, "mrbgems lock file does not exist: #{path}" if lock_file && !File.file?(path)
|
|
187
|
+
|
|
188
|
+
Mrbgems.new(cwd: Dir.pwd, lock_path: path).prepend_requires(data)
|
|
202
189
|
end
|
|
203
190
|
|
|
204
191
|
def interactive(args, repl: false)
|
|
@@ -227,18 +214,23 @@ module Rpremote
|
|
|
227
214
|
stdout.puts("reset R2P2: #{port_path}")
|
|
228
215
|
end
|
|
229
216
|
|
|
230
|
-
def parse_connection_options(args, default_timeout: PicoModem::DEFAULT_TIMEOUT)
|
|
217
|
+
def parse_connection_options(args, default_timeout: PicoModem::DEFAULT_TIMEOUT, mrbgems_lock: false)
|
|
231
218
|
options = {
|
|
232
219
|
port: config_options[:port],
|
|
233
220
|
baud: config_options.fetch(:baud, Serial::BAUD_RATE),
|
|
234
221
|
timeout: config_options.fetch(:timeout, default_timeout),
|
|
235
222
|
language: config_options.fetch(:language, Target::DEFAULT_LANGUAGE)
|
|
236
223
|
}
|
|
224
|
+
options[:mrbgems_lock] = config_options[:mrbgems_lock] if mrbgems_lock
|
|
237
225
|
parser = OptionParser.new do |opts|
|
|
238
226
|
opts.on("--port PORT") { |value| options[:port] = value }
|
|
239
227
|
opts.on("--baud RATE", Integer) { |value| options[:baud] = value }
|
|
240
228
|
opts.on("--timeout SECONDS", Float) { |value| options[:timeout] = value }
|
|
241
229
|
opts.on("--language LANGUAGE") { |value| options[:language] = value }
|
|
230
|
+
if mrbgems_lock
|
|
231
|
+
opts.on("--lockfile FILE") { |value| options[:mrbgems_lock] = value }
|
|
232
|
+
opts.on("--no-mrbgems") { options[:mrbgems_lock] = false }
|
|
233
|
+
end
|
|
242
234
|
end
|
|
243
235
|
parser.parse!(args)
|
|
244
236
|
raise ArgumentError, "--baud must be positive" unless options[:baud].positive?
|
|
@@ -246,82 +238,5 @@ module Rpremote
|
|
|
246
238
|
|
|
247
239
|
options
|
|
248
240
|
end
|
|
249
|
-
|
|
250
|
-
def copy(args, options, recursive: false, command: "cp")
|
|
251
|
-
usage = command == "push" ? "rpremote fs push LOCAL_DIR :/REMOTE_DIR" : "rpremote fs cp SOURCE DESTINATION"
|
|
252
|
-
raise ArgumentError, "usage: #{usage} [options]" unless args.length == 2
|
|
253
|
-
|
|
254
|
-
source, destination = args
|
|
255
|
-
source_remote = RemotePath.remote?(source)
|
|
256
|
-
destination_remote = RemotePath.remote?(destination)
|
|
257
|
-
raise ArgumentError, "exactly one cp path must be remote (prefix remote paths with :)" if source_remote == destination_remote
|
|
258
|
-
return RecursiveCopy.new(output: stdout, serial: serial, device: device).call(source, destination, options) if recursive
|
|
259
|
-
|
|
260
|
-
ensure_filesystem_connection!(options)
|
|
261
|
-
if source_remote
|
|
262
|
-
data = with_modem(options) { |modem| modem.download(RemotePath.unwrap(source)) }
|
|
263
|
-
File.binwrite(local_destination(destination, source), data)
|
|
264
|
-
stdout.puts("downloaded #{data.bytesize} bytes: #{source} -> #{destination}")
|
|
265
|
-
else
|
|
266
|
-
data = File.binread(source)
|
|
267
|
-
with_modem(options) { |modem| modem.upload(RemotePath.unwrap(destination), data) }
|
|
268
|
-
stdout.puts("uploaded #{data.bytesize} bytes: #{source} -> #{destination}")
|
|
269
|
-
end
|
|
270
|
-
rescue Errno::ENOENT => e
|
|
271
|
-
raise ArgumentError, e.message
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
def cat(args, options)
|
|
275
|
-
raise ArgumentError, "usage: rpremote fs cat :/REMOTE/PATH [options]" unless args.length == 1
|
|
276
|
-
raise ArgumentError, "cat path must be remote (prefix it with :)" unless RemotePath.remote?(args.first)
|
|
277
|
-
|
|
278
|
-
stdout.write(with_modem(options) { |modem| modem.download(RemotePath.unwrap(args.first)) })
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
def filesystem_shell_command(command, args, options)
|
|
282
|
-
usage = "usage: rpremote fs #{command} :/REMOTE/PATH [options]"
|
|
283
|
-
raise ArgumentError, usage unless args.length == 1
|
|
284
|
-
|
|
285
|
-
path = RemotePath.validate(args.first)
|
|
286
|
-
stdout.puts("deleting remote path permanently: #{path}") if command == "rm"
|
|
287
|
-
output = with_shell(options) do |shell|
|
|
288
|
-
shell.execute("#{command} #{Shell.quote_argument(path)}")
|
|
289
|
-
end
|
|
290
|
-
ensure_filesystem_success!(command, output)
|
|
291
|
-
stdout.write(output)
|
|
292
|
-
end
|
|
293
|
-
|
|
294
|
-
def ensure_filesystem_success!(command, output)
|
|
295
|
-
failed = command == "ls" ? output.start_with?("ls:") : !output.empty?
|
|
296
|
-
raise Shell::CommandError, output.strip if failed
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
def ensure_filesystem_connection!(options)
|
|
300
|
-
output = with_shell(options) { |shell| shell.execute("ls '/'") }
|
|
301
|
-
ensure_filesystem_success!("ls", output)
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
def with_modem(options)
|
|
305
|
-
port_path = device.main_port(options[:port])
|
|
306
|
-
serial.open(port_path, baud: options[:baud]) do |port|
|
|
307
|
-
yield PicoModem.new(port, timeout: options[:timeout])
|
|
308
|
-
end
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
def with_shell(options)
|
|
312
|
-
port_path = device.main_port(options[:port])
|
|
313
|
-
serial.open(port_path, baud: options[:baud]) do |port|
|
|
314
|
-
shell = Shell.new(port, timeout: options[:timeout])
|
|
315
|
-
shell.synchronize!
|
|
316
|
-
yield shell
|
|
317
|
-
end
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
def local_destination(destination, source)
|
|
321
|
-
return destination unless File.directory?(destination)
|
|
322
|
-
|
|
323
|
-
File.join(destination, File.basename(RemotePath.unwrap(source)))
|
|
324
|
-
end
|
|
325
241
|
end
|
|
326
242
|
end
|
|
327
|
-
# rubocop:enable Metrics/ClassLength
|
data/lib/rpremote/config.rb
CHANGED
|
@@ -16,17 +16,17 @@ module Rpremote
|
|
|
16
16
|
baud: Integer,
|
|
17
17
|
timeout: Numeric,
|
|
18
18
|
language: String,
|
|
19
|
-
|
|
19
|
+
mrbgems_lock: [String, FalseClass].freeze
|
|
20
20
|
}.freeze
|
|
21
21
|
COMMAND_OPTIONS = {
|
|
22
22
|
"setup" => %i[cache language language_version],
|
|
23
|
-
"build" => %i[cache language language_version board firmware
|
|
23
|
+
"build" => %i[cache language language_version board firmware mrbgems_lock],
|
|
24
24
|
"bootsel" => %i[mount port baud timeout],
|
|
25
|
-
"deploy" => %i[cache language language_version board firmware
|
|
25
|
+
"deploy" => %i[cache language language_version board firmware mrbgems_lock mount port baud timeout],
|
|
26
26
|
"dfu" => %i[cache language language_version port baud timeout],
|
|
27
27
|
"flash" => %i[cache language language_version board firmware mount port timeout],
|
|
28
|
-
"run" => %i[port baud timeout language],
|
|
29
|
-
"exec" => %i[port baud timeout language],
|
|
28
|
+
"run" => %i[port baud timeout language mrbgems_lock],
|
|
29
|
+
"exec" => %i[port baud timeout language mrbgems_lock],
|
|
30
30
|
"reset" => %i[port baud timeout],
|
|
31
31
|
"monitor" => %i[port baud timeout],
|
|
32
32
|
"repl" => %i[port baud timeout],
|
|
@@ -106,6 +106,7 @@ module Rpremote
|
|
|
106
106
|
expected = OPTION_TYPES[key]
|
|
107
107
|
raise Error, "unknown config option: #{key}" unless expected
|
|
108
108
|
raise Error, "config option #{key} must be a #{type_name(expected)}" unless valid_value?(value, expected)
|
|
109
|
+
|
|
109
110
|
next unless %i[baud timeout].include?(key)
|
|
110
111
|
next if value.positive?
|
|
111
112
|
|
data/lib/rpremote/config_show.rb
CHANGED
|
@@ -38,7 +38,7 @@ module Rpremote
|
|
|
38
38
|
board: defaults.fetch(:board, Target::DEFAULT_BOARD),
|
|
39
39
|
cache: defaults.fetch(:cache, Target::DEFAULT_CACHE_DIR),
|
|
40
40
|
firmware: defaults[:firmware],
|
|
41
|
-
|
|
41
|
+
mrbgems_lock: defaults[:mrbgems_lock],
|
|
42
42
|
mount: defaults[:mount],
|
|
43
43
|
port: defaults[:port],
|
|
44
44
|
baud: defaults.fetch(:baud, Serial::BAUD_RATE),
|
|
@@ -53,8 +53,8 @@ module Rpremote
|
|
|
53
53
|
opts.on("--board BOARD") { |value| options[:board] = value }
|
|
54
54
|
opts.on("--cache DIR") { |value| options[:cache] = value }
|
|
55
55
|
opts.on("--firmware FILE") { |value| options[:firmware] = value }
|
|
56
|
-
opts.on("--
|
|
57
|
-
opts.on("--no-mrbgems") { options[:
|
|
56
|
+
opts.on("--lockfile FILE") { |value| options[:mrbgems_lock] = value }
|
|
57
|
+
opts.on("--no-mrbgems") { options[:mrbgems_lock] = false }
|
|
58
58
|
opts.on("--mount DIR") { |value| options[:mount] = value }
|
|
59
59
|
opts.on("--port PORT") { |value| options[:port] = value }
|
|
60
60
|
opts.on("--baud RATE", Integer) { |value| options[:baud] = value }
|
|
@@ -70,19 +70,27 @@ module Rpremote
|
|
|
70
70
|
cache_dir: options[:cache],
|
|
71
71
|
firmware: options[:firmware]
|
|
72
72
|
)
|
|
73
|
+
print_target_options(target)
|
|
74
|
+
print_runtime_options(options)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def print_target_options(target)
|
|
73
78
|
output.puts("language=#{target.language}")
|
|
74
79
|
output.puts("language_version=#{target.language_version}")
|
|
75
80
|
output.puts("board=#{target.board}")
|
|
76
81
|
output.puts("cache=#{target.cache_dir}")
|
|
77
82
|
output.puts("firmware=#{target.firmware_path}")
|
|
78
|
-
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def print_runtime_options(options)
|
|
86
|
+
output.puts("mrbgems_lock=#{mrbgems_lock_value(options[:mrbgems_lock])}")
|
|
79
87
|
output.puts("mount=#{options[:mount] || "auto"}")
|
|
80
88
|
output.puts("port=#{options[:port] || "auto"}")
|
|
81
89
|
output.puts("baud=#{options[:baud]}")
|
|
82
90
|
output.puts("timeout=#{options[:timeout]}")
|
|
83
91
|
end
|
|
84
92
|
|
|
85
|
-
def
|
|
93
|
+
def mrbgems_lock_value(value)
|
|
86
94
|
return "false" if value == false
|
|
87
95
|
|
|
88
96
|
value || "auto"
|