mobo 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []