webruby 0.2.4 → 0.2.5
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 +4 -4
- data/lib/webruby/environment.rb +4 -0
- data/lib/webruby/rake/files.rake +2 -1
- data/lib/webruby/rake/mruby.rake +4 -2
- data/modules/emscripten/AUTHORS +1 -0
- data/modules/emscripten/cmake/Platform/Emscripten.cmake +2 -0
- data/modules/emscripten/emcc +96 -40
- data/modules/emscripten/emrun +301 -136
- data/modules/emscripten/emscripten.py +5 -45
- data/modules/emscripten/src/analyzer.js +11 -1
- data/modules/emscripten/src/compiler.js +1 -1
- data/modules/emscripten/src/emrun_postjs.js +2 -2
- data/modules/emscripten/src/emrun_prejs.js +5 -0
- data/modules/emscripten/src/emscripten-source-map.min.js +31 -0
- data/modules/emscripten/src/library.js +187 -0
- data/modules/emscripten/src/library_egl.js +20 -0
- data/modules/emscripten/src/library_sdl.js +1 -0
- data/modules/emscripten/src/preamble.js +4 -0
- data/modules/emscripten/src/relooper/Relooper.cpp +33 -15
- data/modules/emscripten/src/relooper/Relooper.h +20 -14
- data/modules/emscripten/src/relooper/fuzzer.py +6 -0
- data/modules/emscripten/src/relooper/test.cpp +28 -0
- data/modules/emscripten/src/relooper/test.txt +211 -166
- data/modules/emscripten/src/relooper/test2.txt +20 -20
- data/modules/emscripten/src/relooper/test3.txt +41 -41
- data/modules/emscripten/src/relooper/test4.txt +26 -26
- data/modules/emscripten/src/relooper/test5.txt +52 -52
- data/modules/emscripten/src/relooper/test6.txt +19 -19
- data/modules/emscripten/src/relooper/test_dead.txt +1 -1
- data/modules/emscripten/src/relooper/test_debug.txt +31 -31
- data/modules/emscripten/src/relooper/test_fuzz1.txt +50 -50
- data/modules/emscripten/src/relooper/test_fuzz2.txt +21 -21
- data/modules/emscripten/src/relooper/test_fuzz3.txt +18 -18
- data/modules/emscripten/src/relooper/test_fuzz4.txt +28 -28
- data/modules/emscripten/src/relooper/test_fuzz5.txt +61 -61
- data/modules/emscripten/src/relooper/test_fuzz6.txt +179 -179
- data/modules/emscripten/src/relooper/test_inf.txt +846 -846
- data/modules/emscripten/src/relooper/testit.sh +15 -15
- data/modules/emscripten/system/include/emscripten/emscripten.h +64 -0
- data/modules/emscripten/tools/eliminator/asm-eliminator-test-output.js +8 -2
- data/modules/emscripten/tools/eliminator/asm-eliminator-test.js +9 -1
- data/modules/emscripten/tools/eliminator/eliminator-test-output.js +11 -0
- data/modules/emscripten/tools/eliminator/eliminator-test.js +16 -1
- data/modules/emscripten/tools/file_packager.py +59 -49
- data/modules/emscripten/tools/js-optimizer.js +47 -8
- data/modules/emscripten/tools/shared.py +3 -3
- data/modules/emscripten/tools/test-js-optimizer-asm-pre-output.js +5 -3
- data/modules/emscripten/tools/test-js-optimizer-asm-pre.js +4 -0
- data/modules/mruby/INSTALL +11 -6
- data/modules/mruby/include/mrbconf.h +0 -3
- data/modules/mruby/include/mruby/khash.h +34 -36
- data/modules/mruby/include/mruby/string.h +3 -0
- data/modules/mruby/include/mruby.h +3 -3
- data/modules/mruby/mrblib/string.rb +3 -0
- data/modules/mruby/src/class.c +12 -12
- data/modules/mruby/src/codegen.c +18 -11
- data/modules/mruby/src/hash.c +12 -12
- data/modules/mruby/src/kernel.c +3 -3
- data/modules/mruby/src/load.c +29 -14
- data/modules/mruby/src/numeric.c +1 -1
- data/modules/mruby/src/object.c +14 -2
- data/modules/mruby/src/state.c +13 -10
- data/modules/mruby/src/string.c +1 -3
- data/modules/mruby/src/symbol.c +44 -18
- data/modules/mruby/src/variable.c +6 -6
- data/modules/mruby/test/t/class.rb +34 -0
- data/modules/mruby/test/t/module.rb +1 -1
- data/modules/mruby/test/t/syntax.rb +28 -0
- metadata +5 -13
- data/modules/emscripten/src/relooper.js +0 -11516
- data/modules/emscripten/src/relooper.js.raw.js +0 -11511
- data/modules/emscripten/tools/__init__.pyc +0 -0
- data/modules/emscripten/tools/cache.pyc +0 -0
- data/modules/emscripten/tools/gen_struct_info.pyc +0 -0
- data/modules/emscripten/tools/js_optimizer.pyc +0 -0
- data/modules/emscripten/tools/jsrun.pyc +0 -0
- data/modules/emscripten/tools/response_file.pyc +0 -0
- data/modules/emscripten/tools/shared.pyc +0 -0
- data/modules/emscripten/tools/tempfiles.pyc +0 -0
data/modules/emscripten/emrun
CHANGED
@@ -8,6 +8,7 @@ import os, platform, optparse, logging, re, pprint, atexit, urlparse, subprocess
|
|
8
8
|
from operator import itemgetter
|
9
9
|
from urllib import unquote
|
10
10
|
from Queue import PriorityQueue
|
11
|
+
from threading import Thread, RLock
|
11
12
|
|
12
13
|
# Populated from cmdline params
|
13
14
|
emrun_options = None
|
@@ -41,6 +42,9 @@ processname_killed_atexit = ""
|
|
41
42
|
# If user does not specify a --port parameter, this port is used to launch the server.
|
42
43
|
default_webserver_port = 6931
|
43
44
|
|
45
|
+
# Location of Android Debug Bridge executable
|
46
|
+
ADB = ''
|
47
|
+
|
44
48
|
# Host OS detection to autolocate browsers and other OS-specific support needs.
|
45
49
|
WINDOWS = False
|
46
50
|
LINUX = False
|
@@ -73,7 +77,7 @@ last_message_time = time.clock()
|
|
73
77
|
page_start_time = time.clock()
|
74
78
|
|
75
79
|
# Stores the time of most recent http page serve.
|
76
|
-
page_last_served_time =
|
80
|
+
page_last_served_time = None
|
77
81
|
|
78
82
|
# Returns given log message formatted to be outputted on a HTML page.
|
79
83
|
def format_html(msg):
|
@@ -82,21 +86,14 @@ def format_html(msg):
|
|
82
86
|
msg = cgi.escape(msg)
|
83
87
|
msg = msg.replace('\r\n', '<br />').replace('\n', '<br />')
|
84
88
|
return msg
|
85
|
-
|
89
|
+
|
90
|
+
# HTTP requests are handled from separate threads - synchronize them to avoid race conditions
|
91
|
+
http_mutex = RLock()
|
92
|
+
|
86
93
|
# Prints a log message to 'info' stdout channel. Always printed.
|
87
94
|
def logi(msg):
|
88
95
|
global last_message_time
|
89
|
-
|
90
|
-
sys.stdout.write(format_html(msg))
|
91
|
-
else:
|
92
|
-
print >> sys.stdout, msg
|
93
|
-
sys.stdout.flush()
|
94
|
-
last_message_time = time.clock()
|
95
|
-
|
96
|
-
# Prints a verbose log message to stdout channel. Only shown if run with --verbose.
|
97
|
-
def logv(msg):
|
98
|
-
global emrun_options, last_message_time
|
99
|
-
if emrun_options.verbose:
|
96
|
+
with http_mutex:
|
100
97
|
if emrun_options.log_html:
|
101
98
|
sys.stdout.write(format_html(msg))
|
102
99
|
else:
|
@@ -104,15 +101,28 @@ def logv(msg):
|
|
104
101
|
sys.stdout.flush()
|
105
102
|
last_message_time = time.clock()
|
106
103
|
|
104
|
+
# Prints a verbose log message to stdout channel. Only shown if run with --verbose.
|
105
|
+
def logv(msg):
|
106
|
+
global emrun_options, last_message_time
|
107
|
+
with http_mutex:
|
108
|
+
if emrun_options.verbose:
|
109
|
+
if emrun_options.log_html:
|
110
|
+
sys.stdout.write(format_html(msg))
|
111
|
+
else:
|
112
|
+
print >> sys.stdout, msg
|
113
|
+
sys.stdout.flush()
|
114
|
+
last_message_time = time.clock()
|
115
|
+
|
107
116
|
# Prints an error message to stderr channel.
|
108
117
|
def loge(msg):
|
109
118
|
global last_message_time
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
119
|
+
with http_mutex:
|
120
|
+
if emrun_options.log_html:
|
121
|
+
sys.stderr.write(format_html(msg))
|
122
|
+
else:
|
123
|
+
print >> sys.stderr, msg
|
124
|
+
sys.stderr.flush()
|
125
|
+
last_message_time = time.clock()
|
116
126
|
|
117
127
|
def format_eol(msg):
|
118
128
|
if WINDOWS:
|
@@ -122,8 +132,6 @@ def format_eol(msg):
|
|
122
132
|
# Prints a message to the browser stdout output stream.
|
123
133
|
def browser_logi(msg):
|
124
134
|
global browser_stdout_handle
|
125
|
-
if browser_stdout_handle != sys.stdout and not msg.endswith('\n'):
|
126
|
-
msg += '\n'
|
127
135
|
msg = format_eol(msg)
|
128
136
|
print >> browser_stdout_handle, msg
|
129
137
|
browser_stdout_handle.flush()
|
@@ -132,8 +140,6 @@ def browser_logi(msg):
|
|
132
140
|
# Prints a message to the browser stderr output stream.
|
133
141
|
def browser_loge(msg):
|
134
142
|
global browser_stderr_handle
|
135
|
-
if browser_stderr_handle != sys.stderr and not msg.endswith('\n'):
|
136
|
-
msg += '\n'
|
137
143
|
msg = format_eol(msg)
|
138
144
|
print >> browser_stderr_handle, msg
|
139
145
|
browser_stderr_handle.flush()
|
@@ -153,7 +159,7 @@ def is_browser_process_alive():
|
|
153
159
|
|
154
160
|
# Kills browser_process and processname_killed_atexit.
|
155
161
|
def kill_browser_process():
|
156
|
-
global browser_process, processname_killed_atexit
|
162
|
+
global browser_process, processname_killed_atexit, emrun_options, ADB
|
157
163
|
if browser_process:
|
158
164
|
try:
|
159
165
|
logv('Terminating browser process..')
|
@@ -161,21 +167,25 @@ def kill_browser_process():
|
|
161
167
|
except:
|
162
168
|
pass
|
163
169
|
browser_process = None
|
164
|
-
|
165
170
|
if len(processname_killed_atexit) > 0:
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
process = subprocess.Popen(['taskkill', '/F', '/IM', process_image, '/T'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
170
|
-
process.communicate()
|
171
|
+
if emrun_options.android:
|
172
|
+
logv("Terminating Android app '" + processname_killed_atexit + "'.")
|
173
|
+
subprocess.call([ADB, 'shell', 'am', 'force-stop', processname_killed_atexit])
|
171
174
|
else:
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
+
logv("Terminating all processes that have string '" + processname_killed_atexit + "' in their name.")
|
176
|
+
if WINDOWS:
|
177
|
+
process_image = processname_killed_atexit if '.exe' in processname_killed_atexit else (processname_killed_atexit + '.exe')
|
178
|
+
process = subprocess.Popen(['taskkill', '/F', '/IM', process_image, '/T'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
179
|
+
process.communicate()
|
180
|
+
else:
|
175
181
|
try:
|
176
|
-
subprocess.call(['
|
182
|
+
subprocess.call(['pkill', processname_killed_atexit])
|
177
183
|
except OSError, e:
|
178
|
-
|
184
|
+
try:
|
185
|
+
subprocess.call(['killall', processname_killed_atexit])
|
186
|
+
except OSError, e:
|
187
|
+
loge('Both commands pkill and killall failed to clean up the spawned browser process. Perhaps neither of these utilities is available on your system?')
|
188
|
+
# Clear the process name to represent that the browser is now dead.
|
179
189
|
processname_killed_atexit = ''
|
180
190
|
|
181
191
|
# Our custom HTTP web server that will server the target page to run via .html.
|
@@ -190,56 +200,60 @@ class HTTPWebServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
|
|
190
200
|
|
191
201
|
def handle_incoming_message(self, seq_num, log, data):
|
192
202
|
global have_received_messages
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
self.expected_http_seq_num
|
197
|
-
|
198
|
-
|
199
|
-
log
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
203
|
+
with http_mutex:
|
204
|
+
have_received_messages = True
|
205
|
+
|
206
|
+
if self.expected_http_seq_num == -1:
|
207
|
+
self.expected_http_seq_num = seq_num+1
|
208
|
+
log(data)
|
209
|
+
elif seq_num == -1: # Message arrived without a sequence number? Just log immediately
|
210
|
+
log(data)
|
211
|
+
elif seq_num == self.expected_http_seq_num:
|
212
|
+
log(data)
|
213
|
+
self.expected_http_seq_num += 1
|
214
|
+
self.print_messages_due()
|
215
|
+
elif seq_num < self.expected_http_seq_num:
|
216
|
+
log(data)
|
217
|
+
else:
|
218
|
+
self.http_message_queue += [(seq_num, data, log)]
|
219
|
+
self.http_message_queue.sort(key=itemgetter(0))
|
220
|
+
if len(self.http_message_queue) > 16:
|
221
|
+
self.print_next_message()
|
212
222
|
|
213
223
|
# If it's been too long since we we got a message, prints out the oldest queued message, ignoring the proper order.
|
214
224
|
# This ensures that if any messages are actually lost, that the message queue will be orderly flushed.
|
215
225
|
def print_timed_out_messages(self):
|
216
226
|
global last_message_time
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
self.
|
227
|
+
with http_mutex:
|
228
|
+
now = time.clock()
|
229
|
+
max_message_queue_time = 5
|
230
|
+
if len(self.http_message_queue) > 0 and now - last_message_time > max_message_queue_time:
|
231
|
+
self.print_next_message()
|
221
232
|
|
222
233
|
# Skips to printing the next message in queue now, independent of whether there was missed messages in the sequence numbering.
|
223
234
|
def print_next_message(self):
|
224
|
-
|
225
|
-
self.
|
226
|
-
|
235
|
+
with http_mutex:
|
236
|
+
if len(self.http_message_queue) > 0:
|
237
|
+
self.expected_http_seq_num = self.http_message_queue[0][0]
|
238
|
+
self.print_messages_due()
|
227
239
|
|
228
240
|
# Completely flushes all out-of-order messages in the queue.
|
229
241
|
def print_all_messages(self):
|
230
|
-
|
231
|
-
self.
|
242
|
+
with http_mutex:
|
243
|
+
while len(self.http_message_queue) > 0:
|
244
|
+
self.print_next_message()
|
232
245
|
|
233
246
|
# Prints any messages that are now due after we logged some other previous messages.
|
234
247
|
def print_messages_due(self):
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
msg[
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
248
|
+
with http_mutex:
|
249
|
+
while len(self.http_message_queue) > 0:
|
250
|
+
msg = self.http_message_queue[0]
|
251
|
+
if msg[0] == self.expected_http_seq_num:
|
252
|
+
msg[2](msg[1])
|
253
|
+
self.expected_http_seq_num += 1
|
254
|
+
self.http_message_queue.pop(0)
|
255
|
+
else:
|
256
|
+
return
|
243
257
|
|
244
258
|
def serve_forever(self, timeout=0.5):
|
245
259
|
global emrun_options, last_message_time, page_exit_code, have_received_messages, emrun_not_enabled_nag_printed
|
@@ -278,10 +292,11 @@ class HTTPWebServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
|
|
278
292
|
page_exit_code = emrun_options.timeout_returncode
|
279
293
|
|
280
294
|
# If we detect that the page is not running with emrun enabled, print a warning message.
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
295
|
+
if not emrun_not_enabled_nag_printed and page_last_served_time is not None:
|
296
|
+
time_since_page_serve = now - page_last_served_time
|
297
|
+
if not have_received_messages and time_since_page_serve > 10:
|
298
|
+
logi('The html page you are running is not emrun-capable. Stdout, stderr and exit(returncode) capture will not work. Recompile the application with the --emrun linker flag to enable this, or pass --no_emrun_detect to emrun to hide this check.')
|
299
|
+
emrun_not_enabled_nag_printed = True
|
285
300
|
|
286
301
|
# Clean up at quit, print any leftover messages in queue.
|
287
302
|
self.print_all_messages()
|
@@ -411,6 +426,19 @@ def get_cpu_infoline():
|
|
411
426
|
|
412
427
|
return platform.machine() + ', ' + cpu_name
|
413
428
|
|
429
|
+
def get_android_cpu_infoline():
|
430
|
+
lines = subprocess.check_output([ADB, 'shell', 'cat', '/proc/cpuinfo']).split('\n')
|
431
|
+
processor = ''
|
432
|
+
hardware = ''
|
433
|
+
for line in lines:
|
434
|
+
if line.startswith('Processor'):
|
435
|
+
processor = line[line.find(':')+1:].strip()
|
436
|
+
elif line.startswith('Hardware'):
|
437
|
+
hardware = line[line.find(':')+1:].strip()
|
438
|
+
|
439
|
+
freq = int(subprocess.check_output([ADB, 'shell', 'cat', '/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq']).strip())/1000
|
440
|
+
return 'CPU: ' + processor + ', ' + hardware + ' @ ' + str(freq) + ' MHz'
|
441
|
+
|
414
442
|
def win_print_gpu_info():
|
415
443
|
gpus = []
|
416
444
|
gpu_memory = []
|
@@ -575,19 +603,24 @@ def get_os_version():
|
|
575
603
|
return 'Unknown OS'
|
576
604
|
|
577
605
|
def get_system_memory():
|
606
|
+
global emrun_options
|
607
|
+
|
578
608
|
try:
|
579
|
-
if
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
mem.close()
|
609
|
+
if LINUX or emrun_options.android:
|
610
|
+
if emrun_options.android:
|
611
|
+
lines = subprocess.check_output([ADB, 'shell', 'cat', '/proc/meminfo']).split('\n')
|
612
|
+
else:
|
613
|
+
mem = open('/proc/meminfo', 'r')
|
614
|
+
lines = mem.readlines()
|
615
|
+
mem.close()
|
587
616
|
for i in lines:
|
588
617
|
sline = i.split()
|
589
618
|
if str(sline[0]) == 'MemTotal:':
|
590
619
|
return int(sline[1]) * 1024
|
620
|
+
elif WINDOWS:
|
621
|
+
return win32api.GlobalMemoryStatusEx()['TotalPhys']
|
622
|
+
elif OSX:
|
623
|
+
return int(subprocess.check_output(['sysctl', '-n', 'hw.memsize']).strip())
|
591
624
|
except:
|
592
625
|
return -1
|
593
626
|
|
@@ -698,6 +731,75 @@ def find_browser(name):
|
|
698
731
|
|
699
732
|
return None # Could not find the browser
|
700
733
|
|
734
|
+
def get_android_model():
|
735
|
+
global ADB
|
736
|
+
manufacturer = subprocess.check_output([ADB, 'shell', 'getprop', 'ro.product.manufacturer']).strip()
|
737
|
+
brand = subprocess.check_output([ADB, 'shell', 'getprop', 'ro.product.brand']).strip()
|
738
|
+
model = subprocess.check_output([ADB, 'shell', 'getprop', 'ro.product.model']).strip()
|
739
|
+
board = subprocess.check_output([ADB, 'shell', 'getprop', 'ro.product.board']).strip()
|
740
|
+
device = subprocess.check_output([ADB, 'shell', 'getprop', 'ro.product.device']).strip()
|
741
|
+
name = subprocess.check_output([ADB, 'shell', 'getprop', 'ro.product.name']).strip()
|
742
|
+
return manufacturer + ' ' + brand + ' ' + model + ' ' + board + ' ' + device + ' ' + name
|
743
|
+
|
744
|
+
def get_android_os_version():
|
745
|
+
global ADB
|
746
|
+
ver = subprocess.check_output([ADB, 'shell', 'getprop', 'ro.build.version.release']).strip()
|
747
|
+
apiLevel = subprocess.check_output([ADB, 'shell', 'getprop', 'ro.build.version.sdk']).strip()
|
748
|
+
if not apiLevel:
|
749
|
+
apiLevel = subprocess.check_output([ADB, 'shell', 'getprop', 'ro.build.version.sdk_int']).strip()
|
750
|
+
|
751
|
+
os = ''
|
752
|
+
if ver:
|
753
|
+
os += 'Android ' + ver + ' '
|
754
|
+
if apiLevel:
|
755
|
+
os += 'SDK API Level ' + apiLevel + ' '
|
756
|
+
os += subprocess.check_output([ADB, 'shell', 'getprop', 'ro.build.description']).strip()
|
757
|
+
return os
|
758
|
+
|
759
|
+
def list_android_browsers():
|
760
|
+
global ADB
|
761
|
+
apps = subprocess.check_output([ADB, 'shell', 'pm', 'list', 'packages', '-f']).replace('\r\n', '\n')
|
762
|
+
browsers = []
|
763
|
+
for line in apps.split('\n'):
|
764
|
+
line = line.strip()
|
765
|
+
if line.endswith('=org.mozilla.firefox'):
|
766
|
+
browsers += ['firefox']
|
767
|
+
if line.endswith('=org.mozilla.firefox_beta'):
|
768
|
+
browsers += ['firefox_beta']
|
769
|
+
if line.endswith('=org.mozilla.fennec_aurora'):
|
770
|
+
browsers += ['firefox_aurora']
|
771
|
+
if line.endswith('=org.mozilla.fennec'):
|
772
|
+
browsers += ['firefox_nightly']
|
773
|
+
if line.endswith('=com.android.chrome'):
|
774
|
+
browsers += ['chrome']
|
775
|
+
if line.endswith('=com.chrome.beta'):
|
776
|
+
browsers += ['chrome_beta']
|
777
|
+
if line.endswith('=com.opera.browser'):
|
778
|
+
browsers += ['opera']
|
779
|
+
if line.endswith('=com.opera.mini.android'):
|
780
|
+
browsers += ['opera_mini']
|
781
|
+
if line.endswith('=mobi.mgeek.TunnyBrowser'):
|
782
|
+
browsers += ['dolphin']
|
783
|
+
|
784
|
+
browsers.sort()
|
785
|
+
logi('emrun has automatically found the following browsers on the connected Android device:')
|
786
|
+
for browser in browsers:
|
787
|
+
logi(' - ' + browser)
|
788
|
+
|
789
|
+
def list_pc_browsers():
|
790
|
+
browsers = ['firefox', 'firefox_beta', 'firefox_aurora', 'firefox_nightly', 'chrome', 'chrome_canary', 'iexplore', 'safari', 'opera']
|
791
|
+
logi('emrun has automatically found the following browsers in the default install locations on the system:')
|
792
|
+
logi('')
|
793
|
+
for browser in browsers:
|
794
|
+
browser_exe = find_browser(browser)
|
795
|
+
if type(browser_exe) == list:
|
796
|
+
browser_exe = browser_exe[0]
|
797
|
+
if browser_exe:
|
798
|
+
logi(' - ' + browser + ': ' + browser_display_name(browser_exe) + ' ' + get_executable_version(browser_exe))
|
799
|
+
logi('')
|
800
|
+
logi('You can pass the --browser <id> option to launch with the given browser above.')
|
801
|
+
logi('Even if your browser was not detected, you can use --browser /path/to/browser/executable to launch with that browser.')
|
802
|
+
|
701
803
|
def browser_display_name(browser):
|
702
804
|
b = browser.lower()
|
703
805
|
if 'iexplore' in b:
|
@@ -718,7 +820,7 @@ def browser_display_name(browser):
|
|
718
820
|
return browser
|
719
821
|
|
720
822
|
def main():
|
721
|
-
global browser_process, processname_killed_atexit, emrun_options, emrun_not_enabled_nag_printed
|
823
|
+
global browser_process, processname_killed_atexit, emrun_options, emrun_not_enabled_nag_printed, ADB
|
722
824
|
usage_str = "usage: %prog [options] [optional_portnum]"
|
723
825
|
parser = optparse.OptionParser(usage=usage_str)
|
724
826
|
|
@@ -773,6 +875,9 @@ def main():
|
|
773
875
|
parser.add_option('--browser', dest='browser', default='',
|
774
876
|
help='Specifies the browser executable to run the web page in.')
|
775
877
|
|
878
|
+
parser.add_option('--android', dest='android', action='store_true', default=False,
|
879
|
+
help='Launches the page in a browser of an Android device connected to an USB on the local system. (via adb)')
|
880
|
+
|
776
881
|
parser.add_option('--system_info', dest='system_info', action='store_true',
|
777
882
|
help='Prints information about the current system at startup.')
|
778
883
|
|
@@ -785,7 +890,13 @@ def main():
|
|
785
890
|
(options, args) = parser.parse_args(sys.argv)
|
786
891
|
emrun_options = options
|
787
892
|
|
788
|
-
if
|
893
|
+
if options.android:
|
894
|
+
ADB = which('adb')
|
895
|
+
if not ADB:
|
896
|
+
loge("Could not find the adb tool. Install Android SDK and add the directory of adb to PATH.")
|
897
|
+
return 1
|
898
|
+
|
899
|
+
if not options.browser and not options.android:
|
789
900
|
if WINDOWS:
|
790
901
|
options.browser = 'start'
|
791
902
|
elif LINUX:
|
@@ -795,19 +906,11 @@ def main():
|
|
795
906
|
elif OSX:
|
796
907
|
options.browser = 'safari'
|
797
908
|
|
798
|
-
browsers = ['firefox', 'firefox_beta', 'firefox_aurora', 'firefox_nightly', 'chrome', 'chrome_canary', 'iexplore', 'safari', 'opera']
|
799
909
|
if options.list_browsers:
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
if type(browser_exe) == list:
|
805
|
-
browser_exe = browser_exe[0]
|
806
|
-
if browser_exe:
|
807
|
-
logi(' - ' + browser + ': ' + browser_display_name(browser_exe) + ' ' + get_executable_version(browser_exe))
|
808
|
-
logi('')
|
809
|
-
logi('You can pass the --browser <id> option to launch with the given browser above.')
|
810
|
-
logi('Even if your browser was not detected, you can use --browser /path/to/browser/executable to launch with that browser.')
|
910
|
+
if options.android:
|
911
|
+
list_android_browsers()
|
912
|
+
else:
|
913
|
+
list_pc_browsers()
|
811
914
|
return
|
812
915
|
|
813
916
|
if len(args) < 2 and (options.system_info or options.browser_info):
|
@@ -827,58 +930,109 @@ def main():
|
|
827
930
|
url = os.path.relpath(os.path.abspath(file_to_serve), serve_dir)
|
828
931
|
if len(cmdlineparams) > 0:
|
829
932
|
url += '?' + '&'.join(cmdlineparams)
|
830
|
-
|
933
|
+
server_root = 'localhost'
|
934
|
+
if options.android:
|
935
|
+
server_root = socket.gethostbyname(socket.gethostname())
|
936
|
+
url = 'http://' + server_root + ':' + str(options.port)+'/'+url
|
831
937
|
|
832
938
|
os.chdir(serve_dir)
|
833
939
|
logv('Web server root directory: ' + os.path.abspath('.'))
|
834
940
|
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
browser
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
941
|
+
if options.android:
|
942
|
+
if not options.no_browser:
|
943
|
+
if not options.browser:
|
944
|
+
loge("Running on Android requires that you explicitly specify the browser to run with --browser <id>. Run emrun --android --list_browsers to obtain a list of installed browsers you can use.")
|
945
|
+
return 1
|
946
|
+
elif options.browser == 'firefox':
|
947
|
+
browser_app = 'org.mozilla.firefox/.App'
|
948
|
+
elif options.browser == 'firefox_beta':
|
949
|
+
browser_app = 'org.mozilla.firefox_beta/.App'
|
950
|
+
elif options.browser == 'firefox_aurora' or options.browser == 'fennec_aurora':
|
951
|
+
browser_app = 'org.mozilla.fennec_aurora/.App'
|
952
|
+
elif options.browser == 'firefox_nightly' or options.browser == 'fennec':
|
953
|
+
browser_app = 'org.mozilla.fennec/.App'
|
954
|
+
elif options.browser == 'chrome':
|
955
|
+
browser_app = 'com.android.chrome/.Main'
|
956
|
+
elif options.browser == 'chrome_beta' or options.browser == 'chrome_canary': # There is no Chrome Canary for Android, but Play store has 'Chrome Beta' instead.
|
957
|
+
browser_app = 'com.chrome.beta/com.android.chrome.Main'
|
958
|
+
elif options.browser == 'opera':
|
959
|
+
browser_app = 'com.opera.browser/com.opera.Opera'
|
960
|
+
elif options.browser == 'opera_mini': # Launching the URL works, but page seems to never load (Fails with 'Network problem' even when other browsers work)
|
961
|
+
browser_app = 'com.opera.mini.android/.Browser'
|
962
|
+
elif options.browser =='dolphin': # Current stable Dolphin as of 12/2013 does not have WebGL support.
|
963
|
+
browser_app = 'mobi.mgeek.TunnyBrowser/.BrowserActivity'
|
964
|
+
else:
|
965
|
+
loge("Don't know how to launch browser " + options.browser + ' on Android!')
|
966
|
+
return 1
|
967
|
+
# To add support for a new Android browser in the list above:
|
968
|
+
# 1. Install the browser to Android phone, connect it via adb to PC.
|
969
|
+
# 2. Type 'adb shell pm list packages -f' to locate the package name of that application.
|
970
|
+
# 3. Type 'adb pull <packagename>.apk' to copy the apk of that application to PC.
|
971
|
+
# 4. Type 'aapt d xmltree <packagename>.apk AndroidManifest.xml > manifest.txt' to extract the manifest from the package.
|
972
|
+
# 5. Locate the name of the main activity for the browser in manifest.txt and add an entry to above list in form 'appname/mainactivityname'
|
973
|
+
|
974
|
+
if WINDOWS:
|
975
|
+
url = url.replace('&', '\\&')
|
976
|
+
browser = [ADB, 'shell', 'am', 'start', '-a', 'android.intent.action.VIEW', '-n', browser_app, '-d', url]
|
977
|
+
processname_killed_atexit = browser_app[:browser_app.find('/')]
|
978
|
+
else: #Launching a web page on local system.
|
979
|
+
browser = find_browser(str(options.browser))
|
980
|
+
browser_exe = browser[0]
|
981
|
+
browser_args = []
|
982
|
+
|
983
|
+
if 'safari' in browser_exe.lower():
|
984
|
+
# Safari has a bug that a command line 'Safari http://page.com' does not launch that page,
|
985
|
+
# but instead launches 'file:///http://page.com'. To remedy this, must use the open -a command
|
986
|
+
# to run Safari, but unfortunately this will end up spawning Safari process detached from emrun.
|
987
|
+
if OSX:
|
988
|
+
browser = ['open', '-a', 'Safari'] + (browser[1:] if len(browser) > 1 else [])
|
989
|
+
|
990
|
+
processname_killed_atexit = 'Safari'
|
991
|
+
elif 'chrome' in browser_exe.lower():
|
992
|
+
processname_killed_atexit = 'chrome'
|
993
|
+
browser_args = ['--incognito', '--enable-nacl', '--enable-pnacl', '--disable-restore-session-state', '--enable-webgl', '--no-default-browser-check', '--no-first-run', '--allow-file-access-from-files']
|
994
|
+
# if options.no_server:
|
995
|
+
# browser_args += ['--disable-web-security']
|
996
|
+
elif 'firefox' in browser_exe.lower():
|
997
|
+
processname_killed_atexit = 'firefox'
|
998
|
+
elif 'iexplore' in browser_exe.lower():
|
999
|
+
processname_killed_atexit = 'iexplore'
|
1000
|
+
browser_args = ['-private']
|
1001
|
+
elif 'opera' in browser_exe.lower():
|
1002
|
+
processname_killed_atexit = 'opera'
|
1003
|
+
|
1004
|
+
# In Windows cmdline, & character delimits multiple commmands, so must use ^ to escape them.
|
1005
|
+
if browser_exe == 'cmd':
|
1006
|
+
url = url.replace('&', '^&')
|
1007
|
+
browser += browser_args + [url]
|
864
1008
|
|
865
1009
|
if options.kill_on_start:
|
1010
|
+
pname = processname_killed_atexit
|
866
1011
|
kill_browser_process()
|
1012
|
+
processname_killed_atexit = pname
|
867
1013
|
|
868
1014
|
if options.system_info:
|
869
1015
|
logi('Time of run: ' + time.strftime("%x %X"))
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
1016
|
+
if options.android:
|
1017
|
+
logi('Model: ' + get_android_model())
|
1018
|
+
logi('OS: ' + get_android_os_version() + ' with ' + str(get_system_memory()/1024/1024) + ' MB of System RAM')
|
1019
|
+
logi('CPU: ' + get_android_cpu_infoline())
|
1020
|
+
else:
|
1021
|
+
logi('Computer name: ' + socket.gethostname()) # http://stackoverflow.com/questions/799767/getting-name-of-windows-computer-running-python-script
|
1022
|
+
logi('OS: ' + get_os_version() + ' with ' + str(get_system_memory()/1024/1024) + ' MB of System RAM')
|
1023
|
+
logi('CPU: ' + get_cpu_infoline())
|
1024
|
+
print_gpu_infolines()
|
874
1025
|
if options.browser_info:
|
875
|
-
|
1026
|
+
if options.android:
|
1027
|
+
logi('Browser: Android ' + browser_app)
|
1028
|
+
else:
|
1029
|
+
logi('Browser: ' + browser_display_name(browser[0]) + ' ' + get_executable_version(browser_exe))
|
876
1030
|
|
877
1031
|
# Suppress run warning if requested.
|
878
1032
|
if options.no_emrun_detect:
|
879
1033
|
emrun_not_enabled_nag_printed = True
|
880
1034
|
|
881
|
-
global browser_stdout_handle, browser_stderr_handle
|
1035
|
+
global browser_stdout_handle, browser_stderr_handle
|
882
1036
|
if options.log_stdout:
|
883
1037
|
browser_stdout_handle = open(options.log_stdout, 'ab')
|
884
1038
|
if options.log_stderr:
|
@@ -887,6 +1041,10 @@ def main():
|
|
887
1041
|
else:
|
888
1042
|
browser_stderr_handle = open(options.log_stderr, 'ab')
|
889
1043
|
|
1044
|
+
if not options.no_server:
|
1045
|
+
logv('Starting web server in port ' + str(options.port))
|
1046
|
+
httpd = HTTPWebServer(('', options.port), HTTPHandler)
|
1047
|
+
|
890
1048
|
if not options.no_browser:
|
891
1049
|
logv("Executing %s" % ' '.join(browser))
|
892
1050
|
if browser[0] == 'cmd':
|
@@ -894,10 +1052,15 @@ def main():
|
|
894
1052
|
browser_process = subprocess.Popen(browser)
|
895
1053
|
if options.kill_on_exit:
|
896
1054
|
atexit.register(kill_browser_process)
|
1055
|
+
# For Android automation, we execute adb, so this process does not represent a browser and no point killing it.
|
1056
|
+
if options.android:
|
1057
|
+
browser_process = None
|
897
1058
|
|
1059
|
+
if browser_process and browser_process.poll() == None:
|
1060
|
+
options.serve_after_close = True
|
1061
|
+
logv('Warning: emrun got detached from the target browser process. Cannot detect when user closes the browser. Behaving as if --serve_after_close was passed in.')
|
1062
|
+
|
898
1063
|
if not options.no_server:
|
899
|
-
logv('Starting web server in port ' + str(options.port))
|
900
|
-
httpd = HTTPWebServer(('', options.port), HTTPHandler)
|
901
1064
|
try:
|
902
1065
|
httpd.serve_forever()
|
903
1066
|
except KeyboardInterrupt:
|
@@ -915,4 +1078,6 @@ def main():
|
|
915
1078
|
return page_exit_code
|
916
1079
|
|
917
1080
|
if __name__ == '__main__':
|
918
|
-
|
1081
|
+
returncode = main()
|
1082
|
+
logv('emrun quitting with process exit code ' + str(returncode))
|
1083
|
+
sys.exit(returncode)
|