liberate 0.1.pre.alpha

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 44260d07f0d85b17fd875b0a0d03d5c0328217c8
4
+ data.tar.gz: c68a969a6dd249244b7b364bcf4f4f7bdc9564b2
5
+ SHA512:
6
+ metadata.gz: 85ad2b1a4ed9ff95d61c6bbac1db3447ba2337d6fe82ad73d1138919246733c83dc424d74f2c426b7c45327e786cac53773f15105175d00b0362549810ff51e0
7
+ data.tar.gz: a45338bea2fa2a4c144a9a7491f3541c01ce591fcc2009678c50a387fba23380a84adf41460f730cc79226fe280347947e7e2d42e3af7b6ef429aed92ea672ca
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require 'bundler/setup'
3
+ require 'liberate'
4
+
5
+ Liberate::App.new(ARGV).has_adb_in_path
@@ -0,0 +1,301 @@
1
+ require 'liberate/version'
2
+ require 'optparse'
3
+ require 'colorize'
4
+ require 'open3'
5
+
6
+ module Liberate
7
+
8
+ ### This is where all the action happens!
9
+ class App
10
+
11
+ # Regex
12
+ DEVICE_ID_REGEX = "[\\w\\d\\.\\:]+"
13
+ VALUE_SUFFIX_REGEX = "\:([a-zA-Z0-9_])+"
14
+ IP_V4_REGEX = "([0-9])+\\.([0-9])+\\.([0-9])+\\.([0-9])+" # TODO Make a tighter regex
15
+
16
+ # Other constants
17
+ PORT_NUMBER = 5555
18
+ ROW_FORMAT = '%-20s %-12s %-12s %s'
19
+
20
+ ### Good ol' constructor
21
+ def initialize(args)
22
+ # args.push "-h" if args.size == 0
23
+ # Command-line options
24
+ create_options_parser(args)
25
+ end
26
+
27
+ ### Checks if 'adb' is present in the system path
28
+ def has_adb_in_path
29
+ unless which('adb')
30
+ puts "'adb' (Android Debug Bridge) not found in path.".red
31
+ exit 1
32
+ end
33
+ end
34
+
35
+ ### Checks if a given command is found in the system path
36
+ # see http://stackoverflow.com/a/5471032/421372
37
+ def which(cmd)
38
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
39
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
40
+ exts.each { |ext|
41
+ exe = File.join(path, "#{cmd}#{ext}")
42
+ return exe if File.executable?(exe) && !File.directory?(exe)
43
+ }
44
+ end
45
+ return nil
46
+ end
47
+
48
+ ### Creates an options parser
49
+ def create_options_parser(args)
50
+ args.options do |opts|
51
+ opts.banner = "Usage: liberate <options>"
52
+ opts.separator ''
53
+ opts.separator "where possible options are:"
54
+
55
+ # List connected devices
56
+ opts.on('-l', '--list', 'list connected devices') do
57
+ list_devices
58
+ exit
59
+ end
60
+
61
+ # Liberate a specific device
62
+ opts.on('-d', '--device', 'liberate a specific device') do
63
+ if args.size == 0
64
+ puts "You must specify a device when using the -d option.".yellow
65
+ exit 0
66
+ end
67
+
68
+ liberate_device(args[0])
69
+ exit
70
+ end
71
+
72
+ # Version
73
+ opts.on('-v', '--version', 'show version number') do
74
+ puts Liberate::NAME.concat(' ').concat(Liberate::VERSION)
75
+ exit
76
+ end
77
+
78
+ # Help
79
+ opts.on('-h', '--help', 'show help') do
80
+ puts opts.help
81
+ exit
82
+ end
83
+
84
+ opts.parse!
85
+ end
86
+ end
87
+
88
+ ### Handles the -l option
89
+ def list_devices
90
+ devices = get_devices
91
+ print_devices_table(devices)
92
+ end
93
+
94
+ ### Handles the -d option
95
+ def liberate_device(key)
96
+ devices = get_devices
97
+
98
+ matching_devices = Array.new
99
+ devices.each do |device|
100
+ matching_devices << device if device.matches(key)
101
+ end
102
+
103
+ found = matching_devices.size
104
+ if found == 0
105
+ message = "Oops... no device matched '%s'." % [key]
106
+ puts message.yellow
107
+ elsif found > 1
108
+ puts "Multiple devices found.".yellow
109
+ puts matching_devices
110
+ else
111
+ device = matching_devices[0]
112
+ liberate(device)
113
+ end
114
+ end
115
+
116
+ ### Gets the list of connected devices (sorted by '@model')
117
+ def get_devices()
118
+ command = 'adb devices -l'
119
+ console_output, console_error, exit_code = execute_shell_command(command)
120
+
121
+ if exit_code != 0
122
+ puts "Trouble starting 'adb', try restarting it manually.".red
123
+ puts "Details...".yellow
124
+ puts console_output
125
+ puts console_error
126
+ exit 1
127
+ else
128
+ console_output = console_output.split("\n")
129
+ console_output.delete_at(0) # DELETE this line => List of devices attached
130
+
131
+ if console_output.size == 0
132
+ puts "No connected devices found.".yellow
133
+ exit
134
+ end
135
+
136
+ # Collect and print device information
137
+ return parse_devices(console_output)
138
+ end
139
+ end
140
+
141
+ ### Gets the list of devices from console output
142
+ def parse_devices(console_output)
143
+ devices = Array.new
144
+ console_output.each do |line|
145
+ devices << extract_device(line)
146
+ end
147
+
148
+ return devices.sort! { |a,b| a.model.downcase <=> b.model.downcase }
149
+ end
150
+
151
+ ### Get a device from the console output
152
+ def extract_device(line)
153
+ # Sample line => [51b64dcb device usb:1-12 product:A6020a40 model:Lenovo_A6020a40 device:A6020a40]
154
+ id = line.match(DEVICE_ID_REGEX)[0]
155
+ device = extract_value("device", line)
156
+ product = extract_value("product", line)
157
+ model = extract_value("model", line)
158
+
159
+ return Device.new(id, device, product, model)
160
+ end
161
+
162
+ ### Extracts value for the 'key' from a given console output line
163
+ def extract_value(key, line)
164
+ return line.match(key.concat(VALUE_SUFFIX_REGEX))[0].split(':').last
165
+ .gsub('_', ' ')
166
+ end
167
+
168
+ ### Formats and prints a device table
169
+ def print_devices_table(devices)
170
+ # Table Header
171
+ header = ROW_FORMAT % ['Model', 'Device', 'Product', 'ID']
172
+ puts header.yellow
173
+
174
+ # Table Rows
175
+ liberated_devices = 0
176
+ devices.each do |d|
177
+ row = ROW_FORMAT % [d.model, d.device, d.product, d.id]
178
+ if d.is_connected
179
+ liberated_devices += 1
180
+ puts row.light_blue
181
+ else
182
+ puts row
183
+ end
184
+ end
185
+
186
+ # Message
187
+ message = "%d/%d device(s) liberated." % [liberated_devices, devices.size]
188
+ puts message.green
189
+ end
190
+
191
+ ### Liberates the specified device
192
+ def liberate(device)
193
+ command = "adb -s %s shell ip -f inet addr show wlan0" % [device.id]
194
+ console_output, console_error, exit_code = execute_shell_command(command)
195
+
196
+ if exit_code == 0
197
+ if console_output != nil
198
+ ip_address = extract_ip_address(console_output)
199
+ adb_connect_tcpip(device, ip_address)
200
+ else
201
+ message = "WiFi is turned off on '%s', turn it on from your device's settings." % [device.model]
202
+ puts message.yellow
203
+ end
204
+ else
205
+ # TODO Display adb error message
206
+ end
207
+ end
208
+
209
+ ### Extracts the IPv4 address from the console output
210
+ def extract_ip_address(console_output)
211
+ console_output = console_output.split("\n")
212
+ console_output.each do |line|
213
+ ip_address = line.match(IP_V4_REGEX)
214
+ return ip_address if ip_address != nil
215
+ end
216
+
217
+ return nil
218
+ end
219
+
220
+ ### Connect to the device via its IP address and port number
221
+ def adb_connect_tcpip(device, ip_address)
222
+ open_tcpip(device)
223
+
224
+ command = "adb -s %s connect %s:%d" % [device.id, ip_address, PORT_NUMBER]
225
+ console_output, console_error, exit_code = execute_shell_command(command)
226
+
227
+ if exit_code == 0
228
+ message = "%s liberated!" % [device.model]
229
+ puts message.green
230
+ else
231
+ message = "Unable to connect to '%s' via %s. Are we on the same network?" % [device.model, ip_address]
232
+ puts message.red
233
+ puts "Details...".yellow
234
+ puts console_output
235
+ puts console_error
236
+ exit 1
237
+ end
238
+ end
239
+
240
+ ### Opens a TCPIP port on the device for a remote connection
241
+ def open_tcpip(device)
242
+ command = "adb -s %s tcpip %d" % [device.id, PORT_NUMBER]
243
+ console_output, console_error, exit_code = execute_shell_command(command)
244
+
245
+ if exit_code != 0
246
+ message = "Unable to open port on '%s'." % [device.model]
247
+ puts message.red
248
+ puts "Details...".yellow
249
+ puts console_output
250
+ puts console_error
251
+ exit 1
252
+ end
253
+ end
254
+
255
+ ### This is an elegant method that abstracts the "Open3.popen3" call
256
+ def execute_shell_command(command)
257
+ stdin, stdout, stderr, wait_thr = Open3.popen3(command)
258
+
259
+ console_output = stdout.gets(nil)
260
+ console_error = stderr.gets(nil)
261
+ exit_code = wait_thr.value
262
+
263
+ # Free resources
264
+ stdin.close
265
+ stdout.close
266
+ stderr.close
267
+
268
+ return console_output, console_error, exit_code
269
+ end
270
+
271
+ ### Class that holds a device information
272
+ class Device
273
+ attr_accessor :id, :device, :product, :model
274
+
275
+ def initialize(id, device, product, model)
276
+ @id = id
277
+ @device = device
278
+ @product = product
279
+ @model = model
280
+ end
281
+
282
+ def matches(key)
283
+ key = key.downcase
284
+ @id.downcase.include?(key) || @device.downcase.include?(key) ||
285
+ @product.downcase.include?(key) || @model.downcase.include?(key)
286
+ end
287
+
288
+ def is_connected()
289
+ @id.end_with? ":%d" % [PORT_NUMBER]
290
+ end
291
+
292
+ def to_s
293
+ "ID: ".concat(@id)
294
+ .concat(" | Device: ").concat(@device)
295
+ .concat(" | Product: ").concat(@product)
296
+ .concat(" | Model: ").concat(@model)
297
+ end
298
+ end
299
+
300
+ end
301
+ end
@@ -0,0 +1,4 @@
1
+ module Liberate
2
+ NAME = 'Liberate!'
3
+ VERSION = '0.1-alpha'
4
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: liberate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.pre.alpha
5
+ platform: ruby
6
+ authors:
7
+ - Ragunath Jawahar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: colorize
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.1
27
+ description: A gem that liberates your Android devices from USB cables during development.
28
+ email: rj@mobsandgeeks.com
29
+ executables:
30
+ - liberate
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - bin/liberate
35
+ - lib/liberate.rb
36
+ - lib/liberate/version.rb
37
+ homepage: https://github.com/ragunathjawahar/liberate
38
+ licenses:
39
+ - Apache-2.0
40
+ metadata: {}
41
+ post_install_message:
42
+ rdoc_options: []
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 2.0.0
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.3.1
55
+ requirements: []
56
+ rubyforge_project:
57
+ rubygems_version: 2.6.4
58
+ signing_key:
59
+ specification_version: 4
60
+ summary: Liberate!
61
+ test_files: []