webruby 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|