isaac_toolbelt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 40358e002bf9fe9c20944a4e8c2ec5f1bec045c7
4
+ data.tar.gz: 8f57377a2edb23046216096fcc974729fdfad333
5
+ SHA512:
6
+ metadata.gz: ee3a5322e9b329e1bd8634026e5f39d208315b7b2302c346f226fb317c8f2f00ea5f24de3f030c4f3dfeb53888afcd04b8cb03e795daf3520b684ef94465d859
7
+ data.tar.gz: 446643e8c4e3fc45bb20070abc0a86cd7ae666175df41617e5060204cb3a530159396b75bf1960475870886cb7d8ce4c0bee0a54490eb629577cec23c3e128a9
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /vendor/bundle
11
+ /.bundle
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.3
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in isaac_toolbelt.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # IsaacToolbelt
2
+
3
+ CLI tool for issac.
4
+ It is inspired by [heroku toolbelt](https://toolbelt.heroku.com/).
5
+
6
+
7
+ ## Installation
8
+
9
+ $ brew brew install dfu-util coreutils gnu-getopt
10
+ $ brew tap jlhonora/lsusb && brew install lsusb
11
+ $ gem install specific_install
12
+ $ gem specific_install git@github.com:xshellinc/isaac_toolbelt.git
13
+
14
+
15
+ ## Usage
16
+
17
+ Connect your SBC with USB cable.
18
+
19
+ ### Show all commands
20
+
21
+ ```sh
22
+ isaac help
23
+ ```
24
+
25
+ ### Show device informations
26
+
27
+ ```sh
28
+ isaac device info
29
+ ```
30
+
31
+ ### Write access key
32
+
33
+ ```sh
34
+ isaac device config YOUR_ACCESS_KEY
35
+ ```
36
+
37
+ ### Show device logs
38
+
39
+ ```sh
40
+ isaac device logs
41
+ ```
42
+
43
+ ### Run an isaac app
44
+
45
+ ```sh
46
+ cd path/to/isaac_project
47
+ vim main.py # At now, only the file named "main.py" is runnable.
48
+ isaac local start
49
+ ```
50
+
51
+ ### Run a command with isaac environment
52
+
53
+ ```sh
54
+ cd path/to/isaac_project
55
+ isaac local run python
56
+ ```
57
+
58
+ ### Run shell on the SBC
59
+
60
+ ```sh
61
+ isaac local console
62
+ ```
63
+
64
+ ## Development
65
+
66
+ ### Setup
67
+
68
+ ```sh
69
+ bundle install
70
+ ```
71
+
72
+ ### Debug in pry
73
+
74
+ ```sh
75
+ bin/console
76
+ ```
77
+
78
+ then, you can access the instance of IsaacToolbelt::Device named `device`:
79
+
80
+ ```ruby
81
+ [1] pry(main)> device
82
+ => #<IsaacToolbelt::Device:0x007ffbfa11f140
83
+ @_initializer=[[], {}, {}],
84
+ @_invocations={},
85
+ @args=[],
86
+ @options={},
87
+ @shell=#<Thor::Shell::Color:0x007ffbfa0a6fb0 @always_force=false, @base=#<IsaacToolbelt::Device:0x007ffbfa11f140 ...>, @mute=false, @padding=0>>
88
+ [2] pry(main)> cd device
89
+ [3] pry(#<IsaacToolbelt::Device>):1> ls
90
+ Thor::Base#methods: args args= options options= parent_options parent_options=
91
+ Thor::Invocation#methods: current_command_chain invoke invoke_all invoke_command invoke_task invoke_with_padding
92
+ Thor::Shell#methods: ask error file_collision no? print_in_columns print_table print_wrapped say say_status set_color shell shell= terminal_width with_padding yes?
93
+ IsaacToolbelt::Helper#methods: check_file config_network host mkdir_if_not reboot ssh_run_command temp_path transfer_files upload_string_as_file waitfor waitfor_network
94
+ IsaacToolbelt::Device#methods: _reboot config_access_key config_wifi help init show
95
+ self.methods: __pry__
96
+ instance variables: @_initializer @_invocations @args @options @shell
97
+ locals: _ __ _dir_ _ex_ _file_ _in_ _out_ _pry_
98
+ ```
99
+
100
+ ## Contributing
101
+
102
+ Bug reports and pull requests are welcome on GitHub at https://github.com/xshellinc/isaac_toolbelt.
103
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "isaac_toolbelt"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'pry'
14
+
15
+ device = IsaacToolbelt::Device.new
16
+ Pry.start self
data/bin/isaac ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "isaac_toolbelt"
4
+
5
+ IsaacToolbelt::CLI.start
6
+
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'isaac_toolbelt/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "isaac_toolbelt"
8
+ spec.version = IsaacToolbelt::VERSION
9
+ spec.authors = ["xshell inc."]
10
+ spec.email = ["info@xshell.io"]
11
+
12
+ spec.summary = %q{Isaac CLI tool}
13
+ spec.description = %q{Isaac CLI tool}
14
+ spec.homepage = "https://isaacapp.io/"
15
+
16
+ ## Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
17
+ ## delete this section to allow pushing this gem to any host.
18
+ #if spec.respond_to?(:metadata)
19
+ # spec.metadata['allowed_push_host'] = ""
20
+ #else
21
+ # raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
22
+ #end
23
+
24
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ spec.bindir = "bin"
26
+ #spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.executables = ["isaac"]
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_development_dependency "bundler", "~> 1.10"
31
+ spec.add_development_dependency "rake", "~> 10.0"
32
+ spec.add_development_dependency "minitest"
33
+ spec.add_development_dependency "pry"
34
+ spec.add_dependency "sshkit"
35
+ spec.add_dependency "thor"
36
+ spec.add_dependency "curb"
37
+ spec.add_dependency "ruby-progressbar"
38
+ spec.add_dependency "archive"
39
+ end
@@ -0,0 +1,548 @@
1
+ require "isaac_toolbelt/version"
2
+
3
+ require 'digest/sha1'
4
+ require 'sshkit'
5
+ require 'sshkit/dsl'
6
+ require 'thor'
7
+ require 'yaml'
8
+ require 'curb'
9
+ require 'ruby-progressbar'
10
+ require 'archive'
11
+ require 'mkmf'
12
+
13
+ REQUIREMENTS_TXT = <<"EOF"
14
+ cffi==1.4.2
15
+ cryptography==1.2.1
16
+ ecdsa==0.13
17
+ enum34==1.1.2
18
+ honcho==0.6.6
19
+ idna==2.0
20
+ ipaddress==1.0.16
21
+ ndg-httpsclient==0.4.0
22
+ paho-mqtt==1.1
23
+ paramiko==1.16.0
24
+ pyasn1==0.1.9
25
+ pycparser==2.14
26
+ pycrypto==2.6.1
27
+ pyOpenSSL==0.15.1
28
+ PyYAML==3.11
29
+ requests==2.9.1
30
+ six==1.10.0
31
+ wheel==0.24.0
32
+ EOF
33
+
34
+ DEVICE_MODE = <<"EOS"
35
+ Usage:
36
+ device mode development # Set ISAAC to development mode.
37
+ device mode production # Set ISAAC to production mode.
38
+ EOS
39
+
40
+ ## /etc/opkg/base-feeds.conf
41
+ #BASE_FEEDS_CONF = <<"EOF"
42
+ #src/gz all http://repo.opkg.net/edison/repo/all
43
+ #src/gz edison http://repo.opkg.net/edison/repo/edison
44
+ #src/gz core2-32 http://repo.opkg.net/edison/repo/core2-32
45
+ #EOF
46
+ #
47
+ ## /etc/opkg/intel-iotdk.conf
48
+ #INTEL_IOTDK_CONF = <<"EOF"
49
+ #src intel-iotdk http://iotdk.intel.com/repos/2.0/intelgalactic
50
+ #src intel-all http://iotdk.intel.com/repos/2.0/iotdk/all
51
+ #src intel-i586 http://iotdk.intel.com/repos/2.0/iotdk/i586
52
+ #src intel-x86 http://iotdk.intel.com/repos/2.0/iotdk/x86
53
+ #EOF
54
+ #
55
+ ## /etc/opkg/isaac-repo.conf
56
+ #ISAAC_REPO_CONF = <<"EOF"
57
+ #src isaac http://ec2-52-26-157-115.us-west-2.compute.amazonaws.com
58
+ #EOF
59
+
60
+ module MakeMakefile::Logging
61
+ @logfile = '/dev/null'
62
+ end
63
+
64
+ SSHKit::Backend::Netssh.configure do |ssh|
65
+ ssh.connection_timeout = 3
66
+ ssh.ssh_options = {
67
+ :auth_methods => ['keyboard-interactive'],
68
+ :paranoid => false,
69
+ :user_known_hosts_file => '/dev/null',
70
+ :keepalive_interval => 1,
71
+ :keepalive_maxcount => 3
72
+ }
73
+ end
74
+
75
+ module IsaacToolbelt
76
+ HOME = ENV['HOME']
77
+ ISAAC_DIR = File.join(HOME, '.isaac')
78
+ DEVICE_IP_ADDRESS = '192.168.2.15'
79
+ SSH_USERNAME = 'root'
80
+ SSH_OPTIONS = '-o PreferredAuthentications=keyboard-interactive -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ServerAliveInterval=1 -o ServerAliveCountMax=3'
81
+ TEMP_ROOT = '/tmp/isaac'
82
+ ISAAC_CONF_PATH = '/etc/isaac.conf'
83
+ ISAAC_EDISON_IMAGE_URL='https://s3-ap-northeast-1.amazonaws.com/isaac-os-images/edison/toFlash.tar.bz2'
84
+
85
+ module Helper
86
+ def check_file(filename)
87
+ unless File.exist?(File.join(Dir.pwd, filename))
88
+ STDERR.puts "#{filename} not found!"
89
+ exit(1)
90
+ end
91
+ end
92
+
93
+ def host
94
+ SSHKit::Host.new("#{SSH_USERNAME}@#{DEVICE_IP_ADDRESS}")
95
+ end
96
+
97
+ def temp_path
98
+ File.join(TEMP_ROOT, Digest::SHA1.hexdigest(Dir.pwd));
99
+ end
100
+
101
+ def mkdir_if_not(destination_path)
102
+ on host do
103
+ unless test("[ -d #{destination_path} ]")
104
+ execute :mkdir, '-p', destination_path
105
+ end
106
+ end
107
+ end
108
+
109
+ def upload_string_as_file(string, dst)
110
+ on host do
111
+ io = StringIO.new(string)
112
+ upload! io, dst
113
+ end
114
+ end
115
+
116
+ def transfer_files(destination_path)
117
+ check_file('Procfile')
118
+ check_file('.gitignore')
119
+ mkdir_if_not(destination_path)
120
+ puts "Uploading files to: #{destination_path}"
121
+ pwd = Dir.pwd
122
+ ret = system("rsync -av -e \"ssh #{SSH_OPTIONS}\" -C --include=\".env\" --exclude=\".git\" --filter=\":- .gitignore\" #{File.join(pwd, '/')} #{SSH_USERNAME}@#{DEVICE_IP_ADDRESS}:#{destination_path}")
123
+ end
124
+
125
+ def config_network
126
+ on host do
127
+ dns_settings = StringIO.new("nameserver 8.8.8.8\n")
128
+ upload! dns_settings, '/etc/resolv.conf'
129
+ execute :ip, *%w(route replace default via 192.168.2.1)
130
+ end
131
+ end
132
+
133
+ def waitfor
134
+ until system('ping -c 1 192.168.2.15 > /dev/null 2>&1') do
135
+ puts 'waiting board...'
136
+ sleep 1
137
+ end
138
+ end
139
+
140
+ def waitfor_network
141
+ on host do
142
+ until test(:ping, *%w(-c 1 8.8.8.8)) do
143
+ puts 'The board waiting network...'
144
+ sleep 1
145
+ end
146
+ end
147
+ end
148
+
149
+ def reboot
150
+ puts 'rebooting...'
151
+ ssh_run_command 'reboot'
152
+ sleep 10
153
+ waitfor
154
+ puts 'rebooted!'
155
+ end
156
+
157
+ #
158
+ # ssh options:
159
+ # -o LogLevel=info
160
+ #
161
+ def ssh_run_command(cmd_string)
162
+ Process.fork do
163
+ exec 'ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ServerAliveInterval=1 -o ServerAliveCountMax=3 -t %s@%s "%s"' % ['root', DEVICE_IP_ADDRESS, cmd_string]
164
+ end
165
+ Process.waitall
166
+ end
167
+ end
168
+
169
+ class Local < Thor
170
+ extend Helper
171
+
172
+ # from https://github.com/ddollar/foreman/blob/59d87c91a2004e05f6b12d4b150dcb4c911eb31c/lib/foreman/cli.rb#L28
173
+ class << self
174
+ # Hackery. Take the run method away from Thor so that we can redefine it.
175
+ def is_thor_reserved_word?(word, type)
176
+ return false if word == "run"
177
+ super
178
+ end
179
+ end
180
+
181
+ desc 'start', 'Run the project on the debug mode device that connected via RNDIS'
182
+ def start
183
+ temp_path = self.class.temp_path
184
+ self.class.transfer_files(temp_path)
185
+ self.class.ssh_run_command("cd #{temp_path}; " + 'honcho start')
186
+ end
187
+
188
+ desc 'run', 'Run a command with .env on the debug mode device that connected via RNDIS'
189
+ def run(*args)
190
+ temp_path = self.class.temp_path
191
+ self.class.transfer_files(temp_path)
192
+ self.class.ssh_run_command("cd #{temp_path}; " + 'honcho run ' + args.shelljoin)
193
+ end
194
+
195
+ desc 'debug_node', 'Run node.js app on the device that connected via RNDIS'
196
+ def debug_node
197
+ temp_path = self.class.make_temp_dir(TEMP_ROOT)
198
+ result = self.class.transfer_files(temp_path)
199
+ if result
200
+ self.class.ssh_run_command('cd %s; npm install; node app.js' % [temp_path])
201
+ else
202
+ puts 'Transfer failed'
203
+ end
204
+ end
205
+
206
+ #map 'shell' => 'console'
207
+ #map 'shell' => 'shell_'
208
+ end
209
+
210
+ class Device < Thor
211
+ include IsaacToolbelt::Helper
212
+
213
+ def self.curl(url, save_dir)
214
+ filename = url.split('/').last
215
+ filepath = File.join(save_dir, filename)
216
+ curl = Curl::Easy.new
217
+ curl.url = url
218
+ curl.follow_location = true
219
+ print "Downloads: '#{curl.url}'"
220
+ File.open(filepath, 'wb') do |f|
221
+ bar = ProgressBar.create(:title => filename, :starting_at => 0)
222
+ curl.on_progress do |dl_total, dl_now, ul_total, ul_now|
223
+ if dl_total > dl_now
224
+ bar.total = dl_total
225
+ bar.progress = dl_now
226
+ end
227
+ true
228
+ end
229
+ curl.on_body do |data|
230
+ f << data; data.size
231
+ end
232
+ curl.perform
233
+ puts "=> '#{filepath}'"
234
+ end
235
+ return filename
236
+ end
237
+
238
+ desc 'init', 'Initialize SBC for use with isaac'
239
+ option :ssid, :aliases => '-s', :required => true, :type => :string, :desc => 'Specify WiFi SSID'
240
+ option :wpa, :aliases => '-w', :required => true, :type => :string, :desc => 'Specify WPA Key for the SSID'
241
+ option :access_key, :aliases => '-a', :required => false, :type => :string, :desc => 'Specify ISAAC access key for the device'
242
+ def init
243
+ unless !!find_executable('dfu-util')
244
+ STDERR.puts 'dfu-util is not installed!'
245
+ STDERR.puts 'try: brew install dfu-util'
246
+ exit 1
247
+ end
248
+
249
+ # donwload and extract yocto image
250
+ extract_path = prepare_os_image()
251
+
252
+ # execute flashall.sh
253
+ flash_os_image(extract_path)
254
+
255
+ # wait for reboot
256
+ waitfor
257
+
258
+ # configure WiFi
259
+ configure_wifi(options[:ssid], options[:wpa])
260
+ waitfor_network
261
+
262
+ # install pip dependencies for isaacd : hacky
263
+ on host do
264
+ execute :pip, *%w(install --upgrade pip)
265
+ execute :pip, *%w(install --upgrade setuptools)
266
+ execute :rm, *%w(-rf /usr/lib/python2.7/site-packages/distribute*)
267
+ requirements = StringIO.new(REQUIREMENTS_TXT)
268
+ dst = '/tmp/requirements.txt'
269
+ upload! requirements, dst
270
+ execute :pip, *%w(install -r), dst
271
+ end
272
+
273
+ ## install opkg dependencies for isaacd : hacky
274
+ #upload_string_as_file(BASE_FEEDS_CONF, '/etc/opkg/base-feeds.conf')
275
+ #upload_string_as_file(INTEL_IOTDK_CONF, '/etc/opkg/intel-iotdk.conf')
276
+ #upload_string_as_file(ISAAC_REPO_CONF, '/etc/opkg/isaac-repo.conf')
277
+ #on host do
278
+ # execute :opkg, 'update'
279
+ # execute :opkg, *%w(install libmraa0)
280
+ #end
281
+
282
+ # init isaacd
283
+ if options[:access_key]
284
+ set_conf({'access_key' => options[:access_key]})
285
+ on host do
286
+ execute :systemctl, *%w(enable isaacd)
287
+ end
288
+ end
289
+
290
+ # wait until rebooted
291
+ reboot
292
+ end
293
+
294
+ desc 'info', 'Show device status'
295
+ def info
296
+ uname = get_uname()
297
+ conf = get_conf()
298
+
299
+ rjust_count = 20
300
+
301
+ print "Operating System: ".rjust(rjust_count, ' ')
302
+ puts "#{uname}"
303
+
304
+ print "Access Key: ".rjust(rjust_count, ' ')
305
+ puts "#{conf['access_key']}"
306
+ end
307
+
308
+ desc 'config:access_key ACCESS_KEY', 'Set ISAAC Access Token'
309
+ def config_access_key(access_key)
310
+ configure_access_key(access_key)
311
+ end
312
+ map 'config:access_key' => 'config_access_key'
313
+
314
+ desc 'config:wifi', 'Configure WiFi'
315
+ option :ssid, :aliases => '-s', :required => true, :type => :string, :desc => 'Specify WiFi SSID'
316
+ option :wpa, :aliases => '-w', :required => true, :type => :string, :desc => 'Specify WPA Key for the SSID'
317
+ def config_wifi
318
+ configure_wifi(options[:ssid], options[:wpa])
319
+ end
320
+ map 'config:wifi' => 'config_wifi'
321
+
322
+ desc 'console', 'Shell on the debug mode device that connected via RNDIS'
323
+ def console
324
+ ssh_run_command('')
325
+ end
326
+
327
+ desc 'logs', 'show logs on the device that connected via RNDIS'
328
+ def logs
329
+ ssh_run_command('journalctl -f')
330
+ end
331
+
332
+ desc 'mode', 'Set modes whether production mode or development mode.'
333
+ def mode(state)
334
+ on host do
335
+ if state == "development" then
336
+ execute :systemctl, *%w(stop isaacd)
337
+ execute :systemctl, *%w(disable isaacd)
338
+ elsif state == "production" then
339
+ execute :systemctl, *%w(enable isaacd)
340
+ execute :systemctl, *%w(start isaacd)
341
+ else
342
+ puts DEVICE_MODE
343
+ end
344
+ end
345
+ end
346
+
347
+ desc 'reboot', 'Reboot ISAAC OS'
348
+ def _reboot
349
+ reboot
350
+ end
351
+ map 'reboot' => '_reboot'
352
+
353
+
354
+ private
355
+ def prepare_os_image
356
+ easy = Curl::Easy.new
357
+ easy.follow_location = true
358
+ easy.url = ISAAC_EDISON_IMAGE_URL
359
+ images_path = File.join(ISAAC_DIR, 'images')
360
+ system("mkdir -p #{images_path}")
361
+ filename = easy.url.split('/').last
362
+ filepath = File.join(images_path, filename)
363
+ unless File.exist? filepath
364
+ print "Downloads: '#{easy.url}'"
365
+ File.open(filepath, 'wb') do|f|
366
+ bar = ProgressBar.create(:title => filename, :starting_at => 0)
367
+ easy.on_progress do |dl_total, dl_now, ul_total, ul_now|
368
+ bar.total = dl_total if dl_total > dl_now
369
+ bar.progress = dl_now
370
+ end
371
+ easy.on_body {|data| f << data; data.size }
372
+ easy.perform
373
+ puts "=> '#{filepath}'"
374
+ end
375
+ else
376
+ puts "#{filepath} already exists"
377
+ end
378
+
379
+ # extract
380
+ extract_dir = filename.split('.').first
381
+ extract_path = File.join(images_path, extract_dir)
382
+ unless Dir.exist?(extract_path)
383
+ puts "Extracting..."
384
+ Archive.extract(filepath, images_path)
385
+ end
386
+
387
+ return extract_path
388
+ end
389
+
390
+ def flash_os_image(extract_path)
391
+ base_dir = extract_path
392
+ usb_vid = '8087'
393
+ usb_pid = '0a99'
394
+ ifwi_dfu_file = File.join(base_dir, 'edison_ifwi-dbg')
395
+ var_dir = File.join(base_dir, 'u-boot-envs')
396
+
397
+ dfu_wait
398
+
399
+ puts "Flashing IFWI"
400
+ %w(00 01 02 03 04 05 06).each do |ifwi_number|
401
+ ifwi_file_path = File.join(extract_path, "edison_ifwi-dbg-#{ifwi_number}-dfu.bin")
402
+ dfu_ifwi_download(usb_vid, usb_pid, "ifwi#{ifwi_number}", ifwi_file_path)
403
+ dfu_ifwi_download(usb_vid, usb_pid, "ifwib#{ifwi_number}", ifwi_file_path)
404
+ end
405
+
406
+ puts "Flashing U-Boot"
407
+ uboot_file_path = File.join(extract_path, "u-boot-edison.bin")
408
+ dfu_download(usb_vid, usb_pid, "u-boot0", uboot_file_path)
409
+
410
+ variant_file_path = File.join(extract_path, "u-boot-envs/edison-blankcdc.bin")
411
+
412
+ puts "Flashing U-Boot Environment"
413
+ dfu_download(usb_vid, usb_pid, "u-boot-env0", variant_file_path)
414
+
415
+ puts "Flashing U-Boot Environment Backup"
416
+ dfu_download(usb_vid, usb_pid, "u-boot-env0", variant_file_path, true)
417
+
418
+ dfu_wait
419
+
420
+ puts "Flashing boot partition (kernel)"
421
+ kernel_file_path = File.join(extract_path, "edison-image-edison.hddimg")
422
+ dfu_download(usb_vid, usb_pid, "boot", kernel_file_path)
423
+
424
+ puts "Flashing rootfs"
425
+ rootfs_file_path = File.join(extract_path, "edison-image-edison.ext4")
426
+ dfu_download(usb_vid, usb_pid, "rootfs", rootfs_file_path, true)
427
+ end
428
+
429
+ def dfu_ifwi_download(usb_vid, usb_pid, alt_name, file_path)
430
+ if dfu_alt_name_exists?(usb_vid, usb_pid, alt_name)
431
+ dfu_download(usb_vid, usb_pid, alt_name, file_path)
432
+ end
433
+ end
434
+
435
+ def dfu_download(usb_vid, usb_pid, alt_name, file_path, do_reboot=false)
436
+ loop do
437
+ params = %W(dfu-util -v -d #{usb_vid}:#{usb_pid} --alt #{alt_name} -D #{file_path})
438
+ params << '-R' if do_reboot
439
+ _pid = Process.fork do
440
+ Process.exec *params
441
+ end
442
+ pid, status = Process.waitpid2(_pid)
443
+ puts "dfu-util exit with: #{status.to_i}"
444
+ if status.to_i == 0
445
+ break
446
+ else
447
+ sleep 1
448
+ end
449
+ end
450
+ end
451
+
452
+ def dfu_alt_name_exists?(usb_vid, usb_pid, alt_name)
453
+ dfu_list(usb_vid, usb_pid).select {|e|
454
+ e[:name] == alt_name
455
+ }.count > 0
456
+ end
457
+
458
+ def dfu_wait
459
+ usb_vid = '8087'
460
+ usb_pid = '0a99'
461
+ until dfu_device_counts(usb_vid, usb_pid) > 0
462
+ puts 'waiting dfu...'
463
+ sleep 1
464
+ end
465
+ end
466
+
467
+ def dfu_device_counts(usb_vid, usb_pid)
468
+ `dfu-util -l -d #{usb_vid}:#{usb_pid}`.split("\n").select{|l0|
469
+ l0 =~ /Found/
470
+ }.select{|l1|
471
+ l1 =~ /#{usb_vid}/
472
+ }.count
473
+ end
474
+
475
+ def dfu_list(usb_vid, usb_pid)
476
+ `dfu-util -l -d #{usb_vid}:#{usb_pid}`.split("\n").select{|l0|
477
+ l0 =~ /Found/
478
+ }.map {|str|
479
+ ver = str.slice(/ver=.+?,/).chop.split('=')[1]
480
+ devnum = str.slice(/devnum=.+?,/).chop.split('=')[1]
481
+ cfg = str.slice(/cfg=.+?,/).chop.split('=')[1]
482
+ intf = str.slice(/intf=.+?,/).chop.split('=')[1]
483
+ alt = str.slice(/alt=.+?,/).chop.split('=')[1]
484
+ name = str.slice(/name=.+?,/).gsub('"', '').chop.split('=')[1]
485
+ serial = str.slice(/serial.+/).gsub('"', '').split('=')[1]
486
+ {
487
+ :ver => ver,
488
+ :devnum => devnum,
489
+ :cfg => cfg,
490
+ :intf => intf,
491
+ :alt => alt,
492
+ :name => name,
493
+ :serial => serial
494
+ }
495
+ }
496
+ end
497
+
498
+ def configure_wifi(ssid, wpa_key)
499
+ on host do
500
+ execute :wpa_passphrase, ssid, wpa_key, '>>', '/etc/wpa_supplicant/wpa_supplicant.conf'
501
+ execute :systemctl, *%w(restart wpa_supplicant.service)
502
+ execute :systemctl, *%w(enable wpa_supplicant.service)
503
+ end
504
+ end
505
+
506
+ def configure_access_key(access_key)
507
+ conf = get_conf
508
+ conf["access_key"] = access_key
509
+ set_conf(conf)
510
+ end
511
+
512
+ def get_conf
513
+ conf = nil
514
+ on host do
515
+ conf = YAML.load(capture(:cat, ISAAC_CONF_PATH))
516
+ end
517
+ return conf
518
+ end
519
+
520
+ def set_conf(conf)
521
+ y = YAML.dump(conf)
522
+ upload_io = StringIO.new(y)
523
+ on host do
524
+ upload! upload_io, ISAAC_CONF_PATH
525
+ end
526
+ return nil
527
+ end
528
+
529
+ def get_uname
530
+ uname = nil
531
+ on host do
532
+ uname = capture(:uname, '-a')
533
+ end
534
+ return uname
535
+ end
536
+ end
537
+
538
+ class CLI < Thor
539
+ register Local, 'local', 'local <COMMAND>', 'Run the app on local SBC'
540
+ register Device, 'device', 'device <COMMAND>', 'Configure SBC connected via USB'
541
+ end
542
+ end
543
+
544
+ Signal.trap(:INT) {
545
+ puts 'Quit'
546
+ exit 1
547
+ }
548
+
@@ -0,0 +1,3 @@
1
+ module IsaacToolbelt
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,182 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: isaac_toolbelt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - xshell inc.
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sshkit
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: thor
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: curb
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: ruby-progressbar
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: archive
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: Isaac CLI tool
140
+ email:
141
+ - info@xshell.io
142
+ executables:
143
+ - isaac
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - ".gitignore"
148
+ - ".travis.yml"
149
+ - Gemfile
150
+ - README.md
151
+ - Rakefile
152
+ - bin/console
153
+ - bin/isaac
154
+ - bin/setup
155
+ - isaac_toolbelt.gemspec
156
+ - lib/isaac_toolbelt.rb
157
+ - lib/isaac_toolbelt/version.rb
158
+ homepage: https://isaacapp.io/
159
+ licenses: []
160
+ metadata: {}
161
+ post_install_message:
162
+ rdoc_options: []
163
+ require_paths:
164
+ - lib
165
+ required_ruby_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ required_rubygems_version: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ requirements: []
176
+ rubyforge_project:
177
+ rubygems_version: 2.4.5.1
178
+ signing_key:
179
+ specification_version: 4
180
+ summary: Isaac CLI tool
181
+ test_files: []
182
+ has_rdoc: