mobo 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 769b5307fcef24c8fd89ae3812977029429d9aa3
4
+ data.tar.gz: 03bb960b0e2aa5bec20a8d9605d0dece15504896
5
+ SHA512:
6
+ metadata.gz: 17af1fe2a87d0929d89cdc1d4b8762939a32300845fb0099279d7d638fd4047f3b9cbf2e8c1e11a11f240a67b02e08dd042f110dda9aa8a524b45f1c14ca4348
7
+ data.tar.gz: 7e8831e69051b35a96797f5b31817a35ddc3eea5358cca8ac10e3afd7e2cd7deb4c20c2ef0dcf2d95ed785e0efaf05158ba4a532d69ba4859f8e7817dfdd4db2
data/bin/mobo ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/mobo'
3
+
4
+ MOBO_DEVICES_FILE = Dir.pwd + '/devices.yaml'
5
+ MOBO_DEVICES_CACHE_FILE = Dir.pwd + '/.mobo-devices.yaml'
6
+
7
+ case ARGV[0]
8
+ when "up"
9
+ Mobo.up(MOBO_DEVICES_FILE)
10
+ when "status"
11
+ Mobo.status(MOBO_DEVICES_CACHE_FILE)
12
+ when "destroy"
13
+ Mobo.destroy(MOBO_DEVICES_CACHE_FILE)
14
+ end
@@ -0,0 +1,247 @@
1
+ module Mobo
2
+
3
+ module Android
4
+
5
+ class << self
6
+ def exists?
7
+ add_to_path
8
+ Mobo.cmd("which android")
9
+ end
10
+
11
+ def install
12
+ Mobo.cmd("curl -O http://dl.google.com/android/android-sdk_r24.3.4-linux.tgz")
13
+ Mobo.cmd("sudo tar -xf android-sdk_r24.3.4-linux.tgz -C /usr/local/")
14
+ Mobo.cmd("sudo chown -R $(whoami) /usr/local/android-sdk-linux")
15
+ add_to_path
16
+ end
17
+
18
+ # setting env variables in the bash profile and trying to reload them isn't easy,
19
+ # as the variables are only set in the sub process the bash_profile is executed in
20
+ # so we can set env variables, which take effect here, and also set them in bash_profile
21
+ # for the user to use later on
22
+ def add_to_path
23
+ android_home = "/usr/local/android-sdk-linux"
24
+
25
+ if !ENV['PATH'].match(/#{android_home}/)
26
+ ENV['ANDROID_HOME'] = android_home
27
+ ENV['PATH'] += ":#{ENV['ANDROID_HOME']}/tools"
28
+ Mobo.cmd("echo \"export ANDROID_HOME=#{ENV['ANDROID_HOME']}\" >> ~/.bash_profile")
29
+ Mobo.cmd("echo \"export PATH=#{ENV['PATH']}\" >> ~/.bash_profile")
30
+ Mobo.log.info("ANDROID_HOME and PATH env variables have been updated.
31
+ Start a new terminal session for them to take effect")
32
+ raise "Setting ANDROID_HOME and PATH failed" unless self.exists?
33
+ end
34
+ end
35
+
36
+ def package_exists?(package)
37
+ Mobo.cmd("android list sdk --extended --no-ui --all | grep '\"#{package}\"'")
38
+ end
39
+
40
+ def install_package(package)
41
+ Mobo.cmd("echo y | android update sdk --no-ui --all --filter #{package} 2>&1 >> /dev/null")
42
+ end
43
+ end
44
+
45
+ module Targets
46
+ class << self
47
+ def exists?(target)
48
+ Mobo.cmd("android list targets --compact | grep #{target}")
49
+ end
50
+
51
+ def target_details(target)
52
+ output = Mobo.cmd_out("android list targets")
53
+ records = output.split('----------')
54
+ records.each do |record|
55
+ return record if record.match(/#{target}/)
56
+ end
57
+ end
58
+
59
+ def abi_package(target, abi)
60
+ prepend = "sys-img"
61
+ "#{prepend}-#{abi}-#{target}"
62
+ end
63
+
64
+ def has_abi?(target, abi)
65
+ target_details(target).match(/#{abi}/)
66
+ end
67
+
68
+ def has_skin?(target, skin)
69
+ target_details(target).match(/#{skin}/)
70
+ end
71
+ end
72
+ end
73
+
74
+ module Avd
75
+ class << self
76
+ def create(device)
77
+ SystemCheck.target_exists(device["target"])
78
+ SystemCheck.abi_exists?(device["target"], device["abi"])
79
+ SystemCheck.skin_exists?(device["target"], device["skin"])
80
+ emulator_cmd =
81
+ "echo no | android create avd \
82
+ --name #{device["name"]} \
83
+ --target #{device["target"]} \
84
+ --abi #{device["abi"]} \
85
+ --force"
86
+ emulator_cmd += " --skin #{device["skin"]}" if device["skin"]
87
+ Mobo.cmd(emulator_cmd)
88
+
89
+ raise "Error creating AVD" unless $?.success?
90
+ end
91
+ end
92
+ end
93
+
94
+ class Adb
95
+ class << self
96
+
97
+ def add_to_path
98
+ if !ENV['PATH'].match(/platform-tools/)
99
+ ENV['PATH'] += ":#{ENV['ANDROID_HOME']}/platform-tools"
100
+ Mobo.cmd("echo \"export PATH=#{ENV['PATH']}\" >> ~/.bash_profile")
101
+ Mobo.log.debug("ENV['PATH'] set to #{ENV['PATH']}")
102
+ Mobo.log.info("PATH env variables has been updated.
103
+ Start a new terminal session for it to take effect")
104
+ end
105
+ end
106
+
107
+ def exists?
108
+ add_to_path
109
+ Mobo.cmd("which adb")
110
+ end
111
+
112
+ def install
113
+ Mobo.cmd("echo yes | android update sdk --all --no-ui --filter platform-tools 2>&1 >> /dev/null")
114
+ add_to_path
115
+ raise "Installing adb failed" unless self.exists?
116
+ end
117
+ end
118
+ end
119
+
120
+ class Emulator
121
+ PORT_START = 5600
122
+ BOOT_SLEEP = 5
123
+ BOOT_WAIT_ATTEMPTS = 30
124
+ UNLOCK_KEY_EVENT = 82
125
+ BACK_KEY_EVENT = 4
126
+
127
+ class << self
128
+ attr_accessor :last_port
129
+ end
130
+
131
+ def initialize(device)
132
+ @device = device
133
+ end
134
+
135
+ def find_open_port
136
+ port = (Emulator.last_port || PORT_START) + 2
137
+ until not Mobo.cmd("netstat -an | grep 127.0.0.1.#{port}")
138
+ port += 2
139
+ end
140
+ Emulator.last_port = port
141
+ @device["port"] = port
142
+ end
143
+
144
+ def create_sdcard
145
+ @device["sdcard"] = "#{@device["name"]}_sdcard.img"
146
+ Mobo.cmd("mksdcard -l e #{@device["sdcard_size"]} #{@device["sdcard"]}")
147
+ end
148
+
149
+ def destroy_sdcard
150
+ Mobo.cmd("rm -f #{@device["sdcard"]}")
151
+ end
152
+
153
+ def create_cache
154
+ @device["cache"] = @device["name"] + "_cache.img"
155
+ end
156
+
157
+ def destroy_cache
158
+ Mobo.cmd("rm -f #{@device["cache"]}")
159
+ end
160
+
161
+ def start
162
+ find_open_port
163
+ create_sdcard
164
+ create_cache
165
+
166
+ cmd ="emulator @#{@device["name"]} \
167
+ -port #{@device["port"]} \
168
+ -sdcard #{@device["sdcard"]} \
169
+ -cache #{@device["cache"]}"
170
+ pid = Process.fork {
171
+ Mobo.cmd(cmd)
172
+ Mobo.log.info("Emulator #{@device["name"]} has stopped")
173
+ }
174
+
175
+ @device["pid"] = pid
176
+ @device["id"] = "emulator-#{@device["port"]}"
177
+ return @device
178
+ end
179
+
180
+ def unlock_when_booted
181
+ Process.fork do
182
+ BOOT_WAIT_ATTEMPTS.times do |attempt|
183
+ if booted?
184
+ Mobo.log.info("#{@device["id"]} has booted")
185
+ break
186
+ elsif !running?
187
+ Mobo.log.error("Emulator #{@device["name"]} has stopped")
188
+ break
189
+ else
190
+ Mobo.log.debug("waiting for #{@device["id"]} to boot...")
191
+ sleep(BOOT_SLEEP)
192
+ end
193
+ end
194
+
195
+ if running? && booted?
196
+ unlock
197
+ end
198
+ end
199
+ end
200
+
201
+ def running?
202
+ begin
203
+ Process.getpgid( @device["pid"] )
204
+ true
205
+ rescue Errno::ESRCH
206
+ false
207
+ end
208
+ end
209
+
210
+ def booted?
211
+ bootanim = Mobo.cmd_out("adb -s #{@device["id"]} shell 'getprop init.svc.bootanim'")
212
+ if bootanim.match(/stopped/)
213
+ return true
214
+ else
215
+ return false
216
+ end
217
+ end
218
+
219
+ def unlock
220
+ # unlock the emulator, so it can be used for UI testing
221
+ # then, pressing back because sometimes a menu appears
222
+ [UNLOCK_KEY_EVENT, BACK_KEY_EVENT].each do |key|
223
+ sleep(BOOT_SLEEP)
224
+ Mobo.cmd("adb -s #{@device["id"]} shell input keyevent #{key}")
225
+ end
226
+ end
227
+
228
+ def status
229
+ Mobo.log.info("#{@device["name"]} (#{@device["id"]}) is running: #{booted?}")
230
+ end
231
+
232
+ def destroy
233
+ (0..10).each do
234
+ if booted?
235
+ Mobo.cmd("adb -s #{@device["id"]} emu kill")
236
+ sleep 1
237
+ else
238
+ Mobo.log.info("#{@device["name"]} (#{@device["id"]}) is shutdown")
239
+ destroy_cache
240
+ destroy_sdcard
241
+ break
242
+ end
243
+ end
244
+ end
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,41 @@
1
+ module Mobo
2
+ module SystemCheck
3
+ class << self
4
+ def bash_check(cmd, msg, error)
5
+ system(cmd)
6
+ Mobo.log.info("#{msg} : #{$?}")
7
+ raise error unless $?.success?
8
+ end
9
+
10
+ def android
11
+ Android.exists?
12
+ end
13
+
14
+ def target_exists(target)
15
+ unless Android::Targets.exists?(target)
16
+ SystemSetup.install_target(target)
17
+ end
18
+ end
19
+
20
+ def abi_exists?(target, abi)
21
+ unless Android::Targets.has_abi?(target, abi)
22
+ SystemSetup.install_abi(target, abi)
23
+ end
24
+ end
25
+
26
+ def skin_exists?(target, abi)
27
+ Android::Targets.has_skin?(target, abi)
28
+ end
29
+
30
+ def adb
31
+ unless Android::Adb.exists?
32
+ SystemSetup.install_adb
33
+ end
34
+ end
35
+
36
+ def device_file_exists?(filename)
37
+ File.exists?(filename)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,32 @@
1
+ module Mobo
2
+ module SystemSetup
3
+ class << self
4
+
5
+ def base_libraries
6
+ #if ubuntu
7
+ if(Mobo.cmd("which apt-get"))
8
+ Mobo.cmd("sudo apt-get install -y libc6-i386 lib32stdc++6 lib32gcc1 lib32ncurses5 lib32z1")
9
+ end
10
+ end
11
+
12
+ def install_android
13
+ Android.install
14
+ end
15
+
16
+ def install_target(target)
17
+ Android.install_package(target) if Android.package_exists?(target)
18
+ raise "Cannot install target: #{target}" unless $?.success?
19
+ end
20
+
21
+ def install_abi(target, abi)
22
+ package_name = Android::Targets.abi_package(target, abi)
23
+ Android.install_package(package_name) if Android.package_exists?(package_name)
24
+ raise "Cannot install abi: #{abi} for #{target}" unless $?.success?
25
+ end
26
+
27
+ def install_adb
28
+ Android::Adb.install unless Android::Adb.exists?
29
+ end
30
+ end
31
+ end
32
+ end
data/lib/mobo.rb ADDED
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env ruby
2
+ require 'yaml'
3
+ require 'pp'
4
+ require 'logger'
5
+ require_relative 'mobo/android'
6
+ require_relative 'mobo/system_check'
7
+ require_relative 'mobo/system_setup'
8
+
9
+ module Mobo
10
+ class << self
11
+ attr_accessor :log, :data, :devices
12
+
13
+ def log
14
+ @log || @log = Logger.new(STDOUT)
15
+ end
16
+
17
+ def cmd(command)
18
+ log.debug(command)
19
+ system(command)
20
+ end
21
+
22
+ def cmd_out(command)
23
+ log.debug(command)
24
+ `#{command}`
25
+ end
26
+
27
+ def start_process(cmd)
28
+ pid = Process.spawn(cmd)
29
+ Process.detach(pid)
30
+ pid
31
+ end
32
+
33
+ def ask_user(msg, &block)
34
+ puts msg
35
+ ans = STDIN.gets.chomp
36
+ if ans.match(/yes|y|Y/)
37
+ yield
38
+ end
39
+ end
40
+
41
+ def devices
42
+ @devices = @devices.nil? ? {} : @devices
43
+ end
44
+
45
+ def device_config(device)
46
+ defaults = {
47
+ "name" => "default",
48
+ "target" => "android-22",
49
+ "abi" => "x86_64",
50
+ "height" => "1200",
51
+ "width" => "720",
52
+ "sdcard_size" => "20M" }
53
+ device = defaults.merge(device)
54
+ end
55
+
56
+ def load_data(filename)
57
+ raise "Cannot file #{filename}" unless SystemCheck.device_file_exists?(filename)
58
+ Mobo.data = YAML::load_file(filename)
59
+ end
60
+
61
+ def system_checks
62
+ SystemSetup.base_libraries
63
+ SystemCheck.android
64
+ SystemCheck.adb
65
+ end
66
+
67
+ def up(filename)
68
+ system_checks
69
+ load_data(filename)
70
+ # retrive settings for one of each device
71
+ Mobo.data["devices"].each do |device|
72
+ device = device_config(device)
73
+ Mobo.devices[device["name"]] = device
74
+ end
75
+
76
+ # build and boot devices
77
+ Mobo.devices.each_pair do |name, device|
78
+ Mobo::Android::Avd.create(device)
79
+ emulator = Android::Emulator.new(device)
80
+ emulator.start
81
+ emulator.unlock_when_booted
82
+ end
83
+ File.open(MOBO_DEVICES_CACHE_FILE, "w") do |file|
84
+ file.write Mobo.devices.to_yaml
85
+ end
86
+ Process.waitall
87
+ end
88
+
89
+ def status(filename)
90
+ load_data(filename)
91
+ Mobo.data.each_pair do |name, device|
92
+ Mobo::Android::Emulator.new(device).status
93
+ end
94
+ end
95
+
96
+ def destroy(filename)
97
+ load_data(filename)
98
+ Mobo.data.each_pair do |name, device|
99
+ Mobo::Android::Emulator.new(device).destroy
100
+ end
101
+ end
102
+
103
+ end
104
+
105
+ end
data/mobo.rb ADDED
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+ require 'yaml'
3
+ require 'pp'
4
+ require 'logger'
5
+ require_relative 'lib/mobo/android'
6
+ require_relative 'lib/mobo/system_check'
7
+
8
+ module Mobo
9
+ class << self
10
+ attr_accessor :log, :data, :devices
11
+
12
+ def log
13
+ @log || @log = Logger.new(STDOUT)
14
+ end
15
+
16
+ def cmd(command)
17
+ log.debug(command)
18
+ system(command)
19
+ end
20
+
21
+ def cmd_out(command)
22
+ log.debug(command)
23
+ `#{command}`
24
+ end
25
+
26
+ def start_process(cmd)
27
+ pid = Process.spawn(cmd)
28
+ Process.detach(pid)
29
+ pid
30
+ end
31
+
32
+ def devices
33
+ @devices = @devices.nil? ? {} : @devices
34
+ end
35
+
36
+ def device_config(device)
37
+ defaults = {
38
+ "name" => "default",
39
+ "target" => "android-22",
40
+ "abi" => "default/x86_64",
41
+ "height" => "1200",
42
+ "width" => "720",
43
+ "sdcard_size" => "20M" }
44
+ defaults.merge(device)
45
+ end
46
+
47
+ def up
48
+ # retrive settings for one of each device
49
+ Mobo.data["devices"].each do |device|
50
+ device = device_config(device)
51
+ Mobo.devices[device["name"]] = device
52
+ end
53
+
54
+ # build and boot devices
55
+ Mobo.devices.each_pair do |name, device|
56
+ Mobo::Android::Avd.create(device)
57
+ emulator = Android::Emulator.new(device)
58
+ emulator.start
59
+ emulator.unlock_when_booted
60
+ end
61
+ File.open(MOBO_DEVICES_FILE, "w") do |file|
62
+ file.write Mobo.devices.to_yaml
63
+ end
64
+ end
65
+
66
+ def status
67
+ Mobo.data.each_pair do |name, device|
68
+ Mobo::Android::Emulator.new(device).status
69
+ end
70
+ end
71
+
72
+ def destroy
73
+ Mobo.data.each_pair do |name, device|
74
+ Mobo::Android::Emulator.new(device).destroy
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mobo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mark O'Shea
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-05 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Abstract android emaulators with a simple yaml file
14
+ email: mark@osheatech.com
15
+ executables:
16
+ - mobo
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - mobo.rb
21
+ - lib/mobo/android.rb
22
+ - lib/mobo/system_check.rb
23
+ - lib/mobo/system_setup.rb
24
+ - lib/mobo.rb
25
+ - bin/mobo
26
+ homepage: https://github.com/moshea/mobo
27
+ licenses:
28
+ - MIT
29
+ metadata: {}
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubyforge_project:
46
+ rubygems_version: 2.0.3
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: Mobo - android emulator abstraction
50
+ test_files: []