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.
@@ -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,16 @@
1
+ class ResetCommand < Command
2
+
3
+ def description
4
+ "clear current device and package"
5
+ end
6
+
7
+ def valid_args?
8
+ args.blank?
9
+ end
10
+
11
+ def run
12
+ @repl.default_device = nil
13
+ @repl.default_package = nil
14
+ end
15
+
16
+ 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
@@ -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
@@ -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 unstyled }
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 span("OK.", :white_fg, :bold) { unstyled }
69
+ puts styled_text("OK.", :white_fg, :bold)
60
70
  else
61
- puts "No such command"
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
- span('>> ', :white_fg, :bold) { styled(:green_fg) }
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 = styled(:white_fg, :black_bg, :bold)
79
- green = lambda { |text| span(text, :green_fg) { style } }
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 (c) 2013 Matthias Kaeppler
104
+ dP (c) 2013-2014 Matthias Kaeppler
90
105
  logo
91
- puts style + ("~" * 70)
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 ("~" * 70) + unstyled
113
+ puts ("~" * Styles::CONSOLE_WIDTH) + end_style
99
114
  end
100
115
 
101
116
  def show_help
@@ -1,29 +1,43 @@
1
1
  module Styles
2
2
 
3
+ CONSOLE_WIDTH = 70
4
+
3
5
  STYLES = {
4
6
  # foreground text
5
- :white_fg => 37,
6
- :black_fg => 30,
7
- :green_fg => 32,
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
- :white_bg => 47,
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
- def span(text, *styles)
17
- styled = "\e[#{STYLES.values_at(*styles).join(';')}m#{text}"
18
- styled << yield if block_given?
19
- styled
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 styled(*styles)
36
+ def create_style(*styles)
23
37
  "\e[#{STYLES.values_at(*styles).join(';')}m"
24
38
  end
25
39
 
26
- def unstyled
40
+ def end_style
27
41
  "\e[0m"
28
42
  end
29
43
 
@@ -1,3 +1,3 @@
1
1
  module Replicant
2
- VERSION = "0.0.1"
2
+ VERSION = "1.0.1"
3
3
  end
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: 0.0.1
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: 2013-11-27 00:00:00.000000000 Z
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: 1.8.7
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: 1.8.7
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/command.rb
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: 1.8.25
120
+ rubygems_version: 2.2.2
134
121
  signing_key:
135
- specification_version: 3
122
+ specification_version: 4
136
123
  summary: A REPL for the Android Debug Bridge
137
124
  test_files: []