replicant-adb 0.0.1 → 1.0.1
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 +7 -0
- data/README.md +32 -34
- data/lib/replicant.rb +3 -1
- data/lib/replicant/commands.rb +10 -0
- data/lib/replicant/commands/adb_command.rb +47 -0
- data/lib/replicant/commands/clear_command.rb +23 -0
- data/lib/replicant/commands/command.rb +85 -0
- data/lib/replicant/commands/device_command.rb +87 -0
- data/lib/replicant/commands/devices_command.rb +57 -0
- data/lib/replicant/commands/env_command.rb +18 -0
- data/lib/replicant/commands/list_command.rb +18 -0
- data/lib/replicant/commands/package_command.rb +19 -0
- data/lib/replicant/commands/reset_command.rb +16 -0
- data/lib/replicant/commands/restart_command.rb +13 -0
- data/lib/replicant/device.rb +7 -2
- data/lib/replicant/log_muncher.rb +83 -0
- data/lib/replicant/process_muncher.rb +47 -0
- data/lib/replicant/repl.rb +24 -9
- data/lib/replicant/styles.rb +24 -10
- data/lib/replicant/version.rb +1 -1
- metadata +30 -43
- data/.travis.yml +0 -4
- data/Gemfile +0 -19
- data/Rakefile +0 -40
- data/lib/replicant/command.rb +0 -352
- data/test/commands/adb_command_spec.rb +0 -58
- data/test/commands/command_spec.rb +0 -90
- data/test/commands/command_spec_base.rb +0 -30
- data/test/commands/device_command_spec.rb +0 -40
- data/test/commands/devices_command_spec.rb +0 -65
- data/test/commands/env_command_spec.rb +0 -30
- data/test/commands/list_command_spec.rb +0 -13
- data/test/commands/package_command_spec.rb +0 -34
- data/test/helper.rb +0 -16
@@ -0,0 +1,18 @@
|
|
1
|
+
class EnvCommand < Command
|
2
|
+
|
3
|
+
def valid_args?
|
4
|
+
args.blank?
|
5
|
+
end
|
6
|
+
|
7
|
+
def run
|
8
|
+
env = "Package: #{@repl.default_package || 'Not set'}\n"
|
9
|
+
env << "Device: "
|
10
|
+
device = @repl.default_device
|
11
|
+
env << if device
|
12
|
+
"#{device.name} (#{device.id})"
|
13
|
+
else
|
14
|
+
'Not set'
|
15
|
+
end
|
16
|
+
output env
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class ListCommand < Command
|
2
|
+
def valid_args?
|
3
|
+
args.blank?
|
4
|
+
end
|
5
|
+
|
6
|
+
def description
|
7
|
+
"print a list of available commands"
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
command_list = Command.all.sort_by {|c| c.name}.map do |command|
|
12
|
+
padding = 20 - command.name.length
|
13
|
+
desc = "#{command.name} #{' ' * padding} -- #{command.description}"
|
14
|
+
desc
|
15
|
+
end
|
16
|
+
output command_list.join("\n")
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class PackageCommand < Command
|
2
|
+
|
3
|
+
def description
|
4
|
+
"set a default package to work with"
|
5
|
+
end
|
6
|
+
|
7
|
+
def usage
|
8
|
+
"#{name} com.mydomain.mypackage"
|
9
|
+
end
|
10
|
+
|
11
|
+
def valid_args?
|
12
|
+
args.present? && /^\w+(\.\w+)*$/ =~ args
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
output "Setting default package to #{args.inspect}"
|
17
|
+
@repl.default_package = args
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class RestartCommand < Command
|
2
|
+
def description
|
3
|
+
"restart ADB"
|
4
|
+
end
|
5
|
+
|
6
|
+
def run
|
7
|
+
# Faster than kill-server, and also catches ADB instances launched by
|
8
|
+
# IntelliJ. Moreover, start-server after kill-server sometimes makes the
|
9
|
+
# server fail to start up unless you sleep for a second or so
|
10
|
+
`killall adb`
|
11
|
+
AdbCommand.new(@repl, "start-server").execute
|
12
|
+
end
|
13
|
+
end
|
data/lib/replicant/device.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
class Device
|
2
|
-
attr_reader :id, :name
|
2
|
+
attr_reader :idx, :id, :name
|
3
3
|
|
4
|
-
def initialize(id, name)
|
4
|
+
def initialize(idx, id, name)
|
5
|
+
@idx = idx
|
5
6
|
@id = id
|
6
7
|
@name = name
|
7
8
|
end
|
@@ -14,6 +15,10 @@ class Device
|
|
14
15
|
!emulator?
|
15
16
|
end
|
16
17
|
|
18
|
+
def short_name
|
19
|
+
"#{@name[0..4]}[#{@idx}]"
|
20
|
+
end
|
21
|
+
|
17
22
|
def to_s
|
18
23
|
"#{@id} [#{@name}]"
|
19
24
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
class LogMuncher
|
2
|
+
|
3
|
+
include Styles
|
4
|
+
|
5
|
+
LOGFILE = "/tmp/replicant_device"
|
6
|
+
TIMESTAMP_PATTERN = /^\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.\d{3}/
|
7
|
+
PROCESS_PATTERN = /(\w){1}\/(.*)\(\s*([0-9]+)\):\s/
|
8
|
+
|
9
|
+
attr_accessor :current_pid
|
10
|
+
|
11
|
+
def initialize(repl)
|
12
|
+
@repl = repl
|
13
|
+
@current_pid = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
# Parses the device logs and reformats / recolors them
|
17
|
+
def munch_logs
|
18
|
+
logcat = "logcat -v time"
|
19
|
+
|
20
|
+
i = IO.popen(AdbCommand.new(@repl, logcat).command)
|
21
|
+
o = File.open(LOGFILE, 'wt')
|
22
|
+
|
23
|
+
yield o if block_given?
|
24
|
+
|
25
|
+
Thread.new do
|
26
|
+
begin
|
27
|
+
i.each_line do |line|
|
28
|
+
log_line(o, line)
|
29
|
+
end
|
30
|
+
rescue Exception => e
|
31
|
+
puts e.inspect
|
32
|
+
puts e.backtrace.join("\n")
|
33
|
+
raise e
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private def log_line(o, line)
|
39
|
+
transform_line(line).each do |seg|
|
40
|
+
text = seg.first
|
41
|
+
styles = seg.last
|
42
|
+
o.print(create_style(*styles))
|
43
|
+
o.print(text)
|
44
|
+
o.print(end_style)
|
45
|
+
end
|
46
|
+
o.flush
|
47
|
+
end
|
48
|
+
|
49
|
+
private def transform_line(line)
|
50
|
+
segments = []
|
51
|
+
|
52
|
+
timestamp = line[TIMESTAMP_PATTERN]
|
53
|
+
|
54
|
+
if timestamp # found proper log line
|
55
|
+
process = PROCESS_PATTERN.match(line)
|
56
|
+
pid = process[3]
|
57
|
+
|
58
|
+
if @current_pid.nil? || @current_pid == pid
|
59
|
+
segments << [" #{timestamp} ", [:white_bg, :bold]]
|
60
|
+
# log level
|
61
|
+
level = process[1]
|
62
|
+
level_fg = case level
|
63
|
+
when "D" then :yellow_fg
|
64
|
+
when "E" then :red_fg
|
65
|
+
else :white_fg
|
66
|
+
end
|
67
|
+
segments << [" #{level} ", [:black_bg, :bold] << level_fg]
|
68
|
+
# log tag
|
69
|
+
tag = process[2].strip
|
70
|
+
segments << ["#{tag} ", [:black_bg, :cyan_fg, :bold]]
|
71
|
+
# log remaining line
|
72
|
+
remainder = [TIMESTAMP_PATTERN, PROCESS_PATTERN].reduce(line) { |l,r| l.gsub(r, '') }.strip
|
73
|
+
segments << [" #{remainder}\n", [:white_fg]]
|
74
|
+
|
75
|
+
elsif @repl.debug?
|
76
|
+
segments << [" #{timestamp} ", [:black_fg]]
|
77
|
+
segments << [" [muted]\n", [:black_fg]]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
segments
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class ProcessMuncher
|
2
|
+
|
3
|
+
def initialize(repl)
|
4
|
+
@repl = repl
|
5
|
+
end
|
6
|
+
|
7
|
+
def process_table
|
8
|
+
result = AdbCommand.new(@repl, "shell ps", :silent => true).execute
|
9
|
+
if result.code > 0
|
10
|
+
@signal_exit = true
|
11
|
+
{}
|
12
|
+
else
|
13
|
+
processes = result.output
|
14
|
+
# Parses something like:
|
15
|
+
# u0_a27 1333 123 517564 18668 ffffffff b75a59eb S com.android.musicfx
|
16
|
+
processes.lines.map do |pid_line|
|
17
|
+
columns = pid_line.split
|
18
|
+
[columns[1], columns[-1]]
|
19
|
+
end.to_h
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_pid
|
24
|
+
process_table.invert[@repl.default_package]
|
25
|
+
end
|
26
|
+
|
27
|
+
def scan_pid
|
28
|
+
@last_pid = nil
|
29
|
+
t = Thread.new do
|
30
|
+
begin
|
31
|
+
while @repl.default_package
|
32
|
+
pid = find_pid
|
33
|
+
t.exit if @signal_exit
|
34
|
+
pid_changed = (pid && pid != @last_pid) || (pid.nil? && @last_pid)
|
35
|
+
yield pid if block_given? && pid_changed
|
36
|
+
@last_pid = pid
|
37
|
+
sleep 2
|
38
|
+
end
|
39
|
+
rescue Exception => e
|
40
|
+
puts e.inspect
|
41
|
+
puts e.backtrace.join("\n")
|
42
|
+
raise e
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
data/lib/replicant/repl.rb
CHANGED
@@ -4,6 +4,9 @@ require 'rexml/document'
|
|
4
4
|
module Replicant
|
5
5
|
class REPL
|
6
6
|
|
7
|
+
Encoding.default_external = Encoding::UTF_8
|
8
|
+
Encoding.default_internal = Encoding::UTF_8
|
9
|
+
|
7
10
|
include Styles
|
8
11
|
|
9
12
|
# for auto-complete via rlwrap; should probably go in Rakefile at some point
|
@@ -34,8 +37,15 @@ module Replicant
|
|
34
37
|
PackageCommand.new(self, app_package).execute
|
35
38
|
end
|
36
39
|
|
40
|
+
# try to pre-select a device, if any
|
41
|
+
connected_devices = DevicesCommand.new(self, nil, :silent => true).execute
|
42
|
+
if connected_devices.any?
|
43
|
+
output "Found #{connected_devices.size} device(s)"
|
44
|
+
DeviceCommand.new(self, "1").execute
|
45
|
+
end
|
46
|
+
|
37
47
|
# reset terminal colors on exit
|
38
|
-
at_exit { puts
|
48
|
+
at_exit { puts end_style }
|
39
49
|
|
40
50
|
loop do
|
41
51
|
command_loop
|
@@ -56,12 +66,16 @@ module Replicant
|
|
56
66
|
command = Command.load(self, command_line)
|
57
67
|
if command
|
58
68
|
command.execute
|
59
|
-
puts
|
69
|
+
puts styled_text("OK.", :white_fg, :bold)
|
60
70
|
else
|
61
|
-
|
71
|
+
output "No such command"
|
62
72
|
end
|
63
73
|
end
|
64
74
|
|
75
|
+
def output(msg)
|
76
|
+
puts styled_text(msg, *REPL_OUT)
|
77
|
+
end
|
78
|
+
|
65
79
|
def debug?
|
66
80
|
ARGV.include?('--debug')
|
67
81
|
end
|
@@ -70,13 +84,14 @@ module Replicant
|
|
70
84
|
|
71
85
|
def prompt
|
72
86
|
prompt = ENV['REPL_PROMPT'] || begin
|
73
|
-
|
87
|
+
pr = (default_device ? "#{default_device.short_name} " : "") << ">> "
|
88
|
+
styled_text(pr, :white_fg, :bold) { create_style(*REPL_OUT) }
|
74
89
|
end.lstrip
|
75
90
|
end
|
76
91
|
|
77
92
|
def show_greeting
|
78
|
-
style =
|
79
|
-
green = lambda { |text|
|
93
|
+
style = create_style(:white_fg, :bold)
|
94
|
+
green = lambda { |text| styled_text(text, :green_fg) { style } }
|
80
95
|
|
81
96
|
logo = <<-logo
|
82
97
|
dP oo dP
|
@@ -86,16 +101,16 @@ module Replicant
|
|
86
101
|
88 88. ... 88. .88 88 88 88. ... 88. .88 88 88 88
|
87
102
|
dP `88888P' 88Y888P' dP dP `88888P' `88888P8 dP dP dP
|
88
103
|
88
|
89
|
-
dP
|
104
|
+
dP (c) 2013-2014 Matthias Kaeppler
|
90
105
|
logo
|
91
|
-
puts style + ("~" *
|
106
|
+
puts style + ("~" * Styles::CONSOLE_WIDTH)
|
92
107
|
puts " v" + Replicant::VERSION
|
93
108
|
puts green[logo]
|
94
109
|
puts ""
|
95
110
|
puts " Type '#{green['!']}' to see a list of commands, '#{green['?']}' for environment info."
|
96
111
|
puts " Commands not starting in '#{green['!']}' are sent to adb verbatim."
|
97
112
|
puts " Use #{green['Ctrl-D']} (i.e. EOF) to exit."
|
98
|
-
puts ("~" *
|
113
|
+
puts ("~" * Styles::CONSOLE_WIDTH) + end_style
|
99
114
|
end
|
100
115
|
|
101
116
|
def show_help
|
data/lib/replicant/styles.rb
CHANGED
@@ -1,29 +1,43 @@
|
|
1
1
|
module Styles
|
2
2
|
|
3
|
+
CONSOLE_WIDTH = 70
|
4
|
+
|
3
5
|
STYLES = {
|
4
6
|
# foreground text
|
5
|
-
:
|
6
|
-
:
|
7
|
-
:green_fg
|
7
|
+
:black_fg => 30,
|
8
|
+
:red_fg => 31,
|
9
|
+
:green_fg => 32,
|
10
|
+
:yellow_fg => 33,
|
11
|
+
:blue_fg => 34,
|
12
|
+
:magenta_fg => 35,
|
13
|
+
:cyan_fg => 36,
|
14
|
+
:white_fg => 37,
|
8
15
|
|
9
16
|
# background
|
10
|
-
:
|
17
|
+
:black_bg => 40,
|
18
|
+
:red_bg => 41,
|
19
|
+
:green_bg => 42,
|
20
|
+
:yellow_bg => 43,
|
21
|
+
:blue_bg => 44,
|
22
|
+
:magenta_bg => 45,
|
23
|
+
:cyan_bg => 46,
|
24
|
+
:white_bg => 47,
|
11
25
|
|
12
26
|
# text styles
|
13
27
|
:bold => 1
|
14
28
|
}
|
15
29
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
30
|
+
REPL_OUT = [:green_fg, :bold]
|
31
|
+
|
32
|
+
def styled_text(text, *styles)
|
33
|
+
create_style(*styles) + text + if block_given? then yield else end_style end
|
20
34
|
end
|
21
35
|
|
22
|
-
def
|
36
|
+
def create_style(*styles)
|
23
37
|
"\e[#{STYLES.values_at(*styles).join(';')}m"
|
24
38
|
end
|
25
39
|
|
26
|
-
def
|
40
|
+
def end_style
|
27
41
|
"\e[0m"
|
28
42
|
end
|
29
43
|
|
data/lib/replicant/version.rb
CHANGED
metadata
CHANGED
@@ -1,80 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: replicant-adb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Matthias Kaeppler
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-10-19 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: activesupport-core-ext
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- - ~>
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '4.0'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- - ~>
|
24
|
+
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '4.0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rake
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- - ~>
|
31
|
+
- - "~>"
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '10.1'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- - ~>
|
38
|
+
- - "~>"
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '10.1'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: bundler
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- - ~>
|
45
|
+
- - "~>"
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '1.0'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- - ~>
|
52
|
+
- - "~>"
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '1.0'
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: jeweler
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- - ~>
|
59
|
+
- - "~>"
|
68
60
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
61
|
+
version: '2.0'
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- - ~>
|
66
|
+
- - "~>"
|
76
67
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
68
|
+
version: '2.0'
|
78
69
|
description: replicant is an interactive shell (a REPL) for ADB, the Android Debug
|
79
70
|
Bridge
|
80
71
|
email: m.kaeppler@gmail.com
|
@@ -85,53 +76,49 @@ extra_rdoc_files:
|
|
85
76
|
- LICENSE.txt
|
86
77
|
- README.md
|
87
78
|
files:
|
88
|
-
- .travis.yml
|
89
|
-
- Gemfile
|
90
79
|
- LICENSE.txt
|
91
80
|
- README.md
|
92
|
-
- Rakefile
|
93
81
|
- bin/replicant
|
94
82
|
- lib/replicant.rb
|
95
|
-
- lib/replicant/
|
83
|
+
- lib/replicant/commands.rb
|
84
|
+
- lib/replicant/commands/adb_command.rb
|
85
|
+
- lib/replicant/commands/clear_command.rb
|
86
|
+
- lib/replicant/commands/command.rb
|
87
|
+
- lib/replicant/commands/device_command.rb
|
88
|
+
- lib/replicant/commands/devices_command.rb
|
89
|
+
- lib/replicant/commands/env_command.rb
|
90
|
+
- lib/replicant/commands/list_command.rb
|
91
|
+
- lib/replicant/commands/package_command.rb
|
92
|
+
- lib/replicant/commands/reset_command.rb
|
93
|
+
- lib/replicant/commands/restart_command.rb
|
96
94
|
- lib/replicant/device.rb
|
95
|
+
- lib/replicant/log_muncher.rb
|
96
|
+
- lib/replicant/process_muncher.rb
|
97
97
|
- lib/replicant/repl.rb
|
98
98
|
- lib/replicant/styles.rb
|
99
99
|
- lib/replicant/version.rb
|
100
|
-
- test/commands/adb_command_spec.rb
|
101
|
-
- test/commands/command_spec.rb
|
102
|
-
- test/commands/command_spec_base.rb
|
103
|
-
- test/commands/device_command_spec.rb
|
104
|
-
- test/commands/devices_command_spec.rb
|
105
|
-
- test/commands/env_command_spec.rb
|
106
|
-
- test/commands/list_command_spec.rb
|
107
|
-
- test/commands/package_command_spec.rb
|
108
|
-
- test/helper.rb
|
109
100
|
homepage: https://github.com/mttkay/replicant
|
110
101
|
licenses:
|
111
102
|
- MIT
|
103
|
+
metadata: {}
|
112
104
|
post_install_message:
|
113
105
|
rdoc_options: []
|
114
106
|
require_paths:
|
115
107
|
- lib
|
116
108
|
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
-
none: false
|
118
109
|
requirements:
|
119
|
-
- -
|
110
|
+
- - ">="
|
120
111
|
- !ruby/object:Gem::Version
|
121
112
|
version: '0'
|
122
|
-
segments:
|
123
|
-
- 0
|
124
|
-
hash: -4199582713992118202
|
125
113
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
|
-
none: false
|
127
114
|
requirements:
|
128
|
-
- -
|
115
|
+
- - ">="
|
129
116
|
- !ruby/object:Gem::Version
|
130
117
|
version: '0'
|
131
118
|
requirements: []
|
132
119
|
rubyforge_project:
|
133
|
-
rubygems_version:
|
120
|
+
rubygems_version: 2.2.2
|
134
121
|
signing_key:
|
135
|
-
specification_version:
|
122
|
+
specification_version: 4
|
136
123
|
summary: A REPL for the Android Debug Bridge
|
137
124
|
test_files: []
|