replicant-adb 0.0.1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - "1.9.3"
4
- script: "bundle exec rake test"
data/Gemfile DELETED
@@ -1,19 +0,0 @@
1
- source "http://rubygems.org"
2
- # Add dependencies required to use your gem here.
3
- # Example:
4
- # gem "activesupport", ">= 2.3.5"
5
-
6
- # Add dependencies to develop your gem here.
7
- # Include everything needed to run rake, tests, features, etc.
8
- gem "activesupport-core-ext", "~> 4.0", :require => false
9
-
10
- group :development do
11
- gem "rake", "~> 10.1"
12
- gem "bundler", "~> 1.0"
13
- gem "jeweler", "~> 1.8.7"
14
- end
15
-
16
- group :test do
17
- gem "minitest", "~> 5.0", :require => 'minitest/autorun'
18
- gem "mocha", "~> 0.14.0", :require => 'mocha/setup'
19
- end
data/Rakefile DELETED
@@ -1,40 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'rubygems'
4
- require 'bundler'
5
- require './lib/replicant/version'
6
-
7
- begin
8
- Bundler.setup(:default, :development)
9
- rescue Bundler::BundlerError => e
10
- $stderr.puts e.message
11
- $stderr.puts "Run `bundle install` to install missing gems"
12
- exit e.status_code
13
- end
14
- require 'rake'
15
-
16
- require 'jeweler'
17
- Jeweler::Tasks.new do |gem|
18
- # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
19
- gem.name = "replicant-adb"
20
- gem.version = Replicant::VERSION
21
- gem.homepage = "https://github.com/mttkay/replicant"
22
- gem.license = "MIT"
23
- gem.summary = "A REPL for the Android Debug Bridge"
24
- gem.description = "replicant is an interactive shell (a REPL) for ADB, the Android Debug Bridge"
25
- gem.email = "m.kaeppler@gmail.com"
26
- gem.authors = ["Matthias Kaeppler"]
27
- gem.files.exclude 'screenshots/**'
28
- # dependencies defined in Gemfile
29
- end
30
- Jeweler::RubygemsDotOrgTasks.new
31
-
32
- require 'rake/testtask'
33
- Rake::TestTask.new(:test) do |test|
34
- test.libs << 'lib' << 'test'
35
- test.pattern = 'test/**/*_spec.rb'
36
- test.verbose = true
37
- end
38
-
39
- task :default => :test
40
-
@@ -1,352 +0,0 @@
1
- require 'stringio'
2
-
3
- class Command
4
-
5
- def self.inherited(subclass)
6
- @@subclasses ||= []
7
- @@subclasses << subclass
8
- end
9
-
10
- def self.all
11
- (@@subclasses - [AdbCommand, ListCommand, EnvCommand]).map do |clazz|
12
- clazz.new(nil)
13
- end
14
- end
15
-
16
- def self.load(repl, command_line)
17
- if command_line == '!'
18
- # load command that lists available commands
19
- ListCommand.new(repl)
20
- elsif command_line == '?'
21
- EnvCommand.new(repl)
22
- elsif command_line.start_with?('!')
23
- # load custom command
24
- command_parts = command_line[1..-1].split
25
- command_name = command_parts.first
26
- command_args = command_parts[1..-1].join(' ')
27
- command_class = "#{command_name.capitalize}Command"
28
- begin
29
- clazz = Object.const_get(command_class)
30
- clazz.new(repl, command_args)
31
- rescue NameError => e
32
- nil
33
- end
34
- else
35
- # forward command to ADB
36
- AdbCommand.new(repl, command_line.strip)
37
- end
38
- end
39
-
40
- attr_reader :args
41
-
42
- def initialize(repl, args = nil, options = {})
43
- @repl = repl
44
- @args = args.strip if args
45
- @options = options
46
- end
47
-
48
- def name
49
- "!#{self.class.name.gsub("Command", "").downcase}"
50
- end
51
-
52
- # subclasses override this to provide a description of their functionality
53
- def description
54
- "TODO: description missing"
55
- end
56
-
57
- # subclasses override this to provide a usage example
58
- def usage
59
- end
60
-
61
- def execute
62
- if valid_args?
63
- run
64
- else
65
- output "Invalid arguments. Ex.: #{usage}"
66
- end
67
- end
68
-
69
- private
70
-
71
- def valid_args?
72
- true
73
- end
74
-
75
- def output(message)
76
- puts message unless @options[:silent]
77
- end
78
-
79
- end
80
-
81
- class AdbCommand < Command
82
-
83
- # the command line program
84
- ADB = 'adb'
85
-
86
- def run
87
- begin
88
- cmd = "#{adb} #{args}"
89
-
90
- if interactive?
91
- system cmd
92
- else
93
- cmd << " #{@repl.default_package}" if @repl.default_package && package_dependent?
94
- output cmd if @repl.debug?
95
- result = `#{cmd}`
96
- output result
97
- result
98
- end
99
- end
100
- end
101
-
102
- private
103
-
104
- def adb
105
- adb = "#{ADB}"
106
- adb << " -s #{@repl.default_device.id}" if @repl.default_device
107
- adb
108
- end
109
-
110
- def interactive?
111
- args == "shell" || args.start_with?("logcat")
112
- end
113
-
114
- def package_dependent?
115
- ["uninstall"].include?(args)
116
- end
117
- end
118
-
119
- class DevicesCommand < Command
120
- def description
121
- "print a list of connected devices"
122
- end
123
-
124
- def run
125
- adb = AdbCommand.new(@repl, "devices -l", :silent => true)
126
- device_lines = adb.execute.lines.to_a.reject do |line|
127
- line.strip.empty? || line.include?("daemon") || line.include?("List of devices")
128
- end
129
-
130
- device_ids = device_lines.map { |l| /([\S]+)\s+device/.match(l)[1] }
131
- device_products = device_lines.map { |l| /product:([\S]+)/.match(l).try(:[], 1) }
132
-
133
- device_names = device_lines.zip(device_ids).map do |l, id|
134
- /model:([\S]+)/.match(l).try(:[], 1) || detect_device_name(id)
135
- end
136
-
137
- devices = device_ids.zip(device_names, device_products).map do |id, name, product|
138
- Device.new(id, humanize_name(name, product))
139
- end
140
-
141
- output ""
142
- output devices_string(devices)
143
- output ""
144
- devices
145
- end
146
-
147
- private
148
-
149
- def detect_device_name(id)
150
- if id.start_with?("emulator-")
151
- "Android emulator"
152
- else
153
- "Unknown device"
154
- end
155
- end
156
-
157
- def humanize_name(name_string, product)
158
- if product == "vbox86p"
159
- "Genymotion " + name_string.gsub(/___[\d_]+___/, "_")
160
- else
161
- name_string
162
- end.gsub('_', ' ').squish
163
- end
164
-
165
- def devices_string(devices)
166
- device_string = if devices.any?
167
- padding = devices.map { |d| d.name.length }.max
168
- indices = (0..devices.length - 1).to_a
169
- indices.zip(devices).map { |i, d| "[#{i}] #{d.name}#{' ' * (padding - d.name.length)} | #{d.id}" }
170
- else
171
- "No devices found"
172
- end
173
- end
174
- end
175
-
176
- class PackageCommand < Command
177
-
178
- def description
179
- "set a default package to work with"
180
- end
181
-
182
- def usage
183
- "#{name} com.mydomain.mypackage"
184
- end
185
-
186
- def valid_args?
187
- args.present? && /^\w+(\.\w+)*$/ =~ args
188
- end
189
-
190
- def run
191
- output "Setting default package to #{args.inspect}"
192
- @repl.default_package = args
193
- end
194
- end
195
-
196
- class DeviceCommand < Command
197
- def description
198
- "set a default device to work with"
199
- end
200
-
201
- def usage
202
- "#{name} [<index>|<device_id>]"
203
- end
204
-
205
- def valid_args?
206
- args.present? && /\S+/ =~ args
207
- end
208
-
209
- def run
210
- default_device = if index?
211
- # user selected by index
212
- devices[args.to_i]
213
- else
214
- # user selected by device ID
215
- devices.detect { |d| d.id == args }
216
- end
217
-
218
- if default_device
219
- output "Setting default device to #{default_device.inspect}"
220
- @repl.default_device = default_device
221
- else
222
- output "No such device"
223
- end
224
- end
225
-
226
- private
227
-
228
- def index?
229
- /^\d+$/ =~ args
230
- end
231
-
232
- def devices
233
- @devices ||= DevicesCommand.new(@repl, nil, :silent => true).execute
234
- end
235
-
236
- end
237
-
238
- class ResetCommand < Command
239
-
240
- def description
241
- "clear current device and package"
242
- end
243
-
244
- def valid_args?
245
- args.blank?
246
- end
247
-
248
- def run
249
- @repl.default_device = nil
250
- @repl.default_package = nil
251
- end
252
-
253
- end
254
-
255
- class ListCommand < Command
256
- def valid_args?
257
- args.blank?
258
- end
259
-
260
- def description
261
- "print a list of available commands"
262
- end
263
-
264
- def run
265
- command_list = Command.all.sort_by {|c| c.name}.map do |command|
266
- padding = 20 - command.name.length
267
- desc = "#{command.name} #{' ' * padding} -- #{command.description}"
268
- desc
269
- end
270
- output command_list.join("\n")
271
- end
272
- end
273
-
274
- class RestartCommand < Command
275
- def description
276
- "restart ADB"
277
- end
278
-
279
- def run
280
- # Faster than kill-server, and also catches ADB instances launched by
281
- # IntelliJ. Moreover, start-server after kill-server sometimes makes the
282
- # server fail to start up unless you sleep for a second or so
283
- `killall adb`
284
- AdbCommand.new(@repl, "start-server").execute
285
- end
286
- end
287
-
288
- class LogcatCommand < Command
289
-
290
- def description
291
- "access device logs"
292
- end
293
-
294
- def valid_args?
295
- args.blank?
296
- end
297
-
298
- def run
299
- pid = if @repl.default_package
300
- processes = AdbCommand.new(@repl, "shell ps", :silent => true).execute
301
- pid_line = processes.lines.detect {|l| l.include?(@repl.default_package)}
302
- pid_line.split[1].strip if pid_line
303
- end
304
-
305
- logcat = "logcat -v time"
306
- logcat << " | grep -E '\(\s*#{pid}\)'"
307
- AdbCommand.new(@repl, logcat).execute
308
- end
309
- end
310
-
311
- class ClearCommand < Command
312
-
313
- def description
314
- "clear application data"
315
- end
316
-
317
- # TODO: this is not a very good argument validator
318
- def valid_args?
319
- args.present? || @repl.default_package
320
- end
321
-
322
- def usage
323
- "#{name} [com.example.package|<empty>(when default package is set)]"
324
- end
325
-
326
- def run
327
- package = args.present? ? args : @repl.default_package
328
- # Clear app data - cache, SharedPreferences, Databases
329
- AdbCommand.new(@repl, "shell su -c \"rm -r /data/data/#{package}/*\"").execute
330
- # Force application stop to recreate shared preferences, databases with new launch
331
- AdbCommand.new(@repl, "shell am force-stop #{package}").execute
332
- end
333
- end
334
-
335
- class EnvCommand < Command
336
-
337
- def valid_args?
338
- args.blank?
339
- end
340
-
341
- def run
342
- env = "Package: #{@repl.default_package || 'Not set'}\n"
343
- env << "Device: "
344
- device = @repl.default_device
345
- env << if device
346
- "#{device.name} (#{device.id})"
347
- else
348
- 'Not set'
349
- end
350
- output env
351
- end
352
- end
@@ -1,58 +0,0 @@
1
- require 'helper'
2
-
3
- class AdbCommandSpec < CommandSpecBase
4
-
5
- describe "a basic adb command" do
6
- before do
7
- @command = silent AdbCommand.new(@repl, "devices")
8
- @command.execute
9
- end
10
-
11
- it "sends a command to adb and captures the output" do
12
- @command.backtick_capture.must_equal "adb devices"
13
- end
14
-
15
- it "does not use Kernel#system" do
16
- @command.system_capture.must_be_nil
17
- end
18
- end
19
-
20
- describe "an interactive command" do
21
- before do
22
- @command = AdbCommand.new(@repl, "shell")
23
- @command.execute
24
- end
25
-
26
- it "is executed using a Kernel#system call" do
27
- @command.system_capture.must_equal "adb shell"
28
- end
29
-
30
- describe "when it's 'shell'" do
31
- it "is not treated as interactive when arguments are present" do
32
- command = AdbCommand.new(@repl, "shell ps")
33
- command.execute
34
- command.system_capture.must_be_nil
35
- command.backtick_capture.must_equal "adb shell ps"
36
- end
37
- end
38
- end
39
-
40
- describe "with a default package set" do
41
- before do
42
- @repl.stubs(:default_package).returns("com.myapp")
43
- end
44
-
45
- it "does not set the default package if command is not package dependent" do
46
- command = silent AdbCommand.new(@repl, "devices")
47
- command.execute
48
- command.backtick_capture.must_equal "adb devices"
49
- end
50
-
51
- it "adds the default package if command is package dependent" do
52
- command = silent AdbCommand.new(@repl, "uninstall")
53
- command.execute
54
- command.backtick_capture.must_equal "adb uninstall com.myapp"
55
- end
56
- end
57
-
58
- end