├── .gitignore ├── .gitmodules ├── .npmignore ├── AUTHORS ├── LICENSE ├── LICENSE.acorn ├── LICENSE.browserfs ├── LICENSE.browserify ├── LICENSE.node ├── Makefile ├── README.md ├── analyze.sh ├── app-spec ├── elements │ ├── browsix-terminal │ │ ├── browsix-terminal.html │ │ └── browsix-terminal.ts │ └── elements.html ├── favicon.ico ├── images │ └── touch │ │ ├── apple-touch-icon.png │ │ ├── chrome-splashscreen-icon-384x384.png │ │ ├── chrome-touch-icon-192x192.png │ │ ├── icon-128x128.png │ │ ├── ms-icon-144x144.png │ │ └── ms-touch-icon-144x144-precomposed.png ├── index.html ├── scripts │ └── main.js └── styles │ ├── app-theme.html │ ├── main.css │ └── shared-styles.html ├── app ├── elements │ ├── browsix-terminal │ │ ├── browsix-terminal.html │ │ └── browsix-terminal.ts │ └── elements.html ├── favicon.ico ├── images │ └── touch │ │ ├── apple-touch-icon.png │ │ ├── chrome-splashscreen-icon-384x384.png │ │ ├── chrome-touch-icon-192x192.png │ │ ├── icon-128x128.png │ │ ├── ms-icon-144x144.png │ │ └── ms-touch-icon-144x144-precomposed.png ├── index.html ├── scripts │ └── main.js └── styles │ ├── app-theme.html │ ├── main.css │ └── shared-styles.html ├── bench └── bench.ts ├── benchmark.sh ├── bower.json ├── browsix-spec.md ├── chrome_sab ├── doc ├── acm_proc_article-sp.cls ├── img │ ├── shell.png │ ├── stack-eps-converted-to.pdf │ ├── stack.eps │ ├── stack.graffle │ ├── utilities-eps-converted-to.pdf │ ├── utilities.eps │ └── utilities.graffle ├── meme_screenshot.png ├── report.bib ├── report.pdf └── report.tex ├── docker ├── Dockerfile └── build.sh ├── examples ├── go-curl │ └── main.go ├── go-stat │ └── main.go ├── go-wait │ └── main.go ├── hello-wasm │ ├── .gitignore │ ├── Makefile │ └── hello.c ├── hello-world-http │ ├── .gitignore │ ├── Makefile │ ├── cl │ └── main.go ├── hello-world │ ├── Makefile │ ├── index.html │ └── main.go ├── latex-editor │ ├── .babelrc │ ├── .bowerrc │ ├── .editorconfig │ ├── .gitignore │ ├── .yo-rc.json │ ├── Makefile │ ├── app │ │ ├── apple-touch-icon.png │ │ ├── favicon.ico │ │ ├── font-awesome.css │ │ ├── fonts │ │ │ ├── fontawesome-webfont.woff │ │ │ └── fontawesome-webfont.woff2 │ │ ├── index.html │ │ ├── robots.txt │ │ ├── scripts │ │ │ └── main.js │ │ └── styles │ │ │ └── main.scss │ ├── bower.json │ ├── fs │ │ ├── dev │ │ │ └── null │ │ └── etc │ │ │ └── passwd │ ├── gulpfile.babel.js │ ├── mktexlsr │ ├── package.json │ ├── test │ │ ├── index.html │ │ └── spec │ │ │ └── test.js │ └── xhrfs-index ├── meme-service │ ├── .gitignore │ ├── Makefile │ ├── frontend │ │ ├── .babelrc │ │ ├── .bowerrc │ │ ├── .editorconfig │ │ ├── .gitignore │ │ ├── .yo-rc.json │ │ ├── app │ │ │ ├── apple-touch-icon.png │ │ │ ├── favicon.ico │ │ │ ├── font-awesome.css │ │ │ ├── fonts │ │ │ │ ├── fontawesome-webfont.woff │ │ │ │ └── fontawesome-webfont.woff2 │ │ │ ├── index.html │ │ │ ├── robots.txt │ │ │ ├── scripts │ │ │ │ └── main.js │ │ │ ├── styles │ │ │ │ └── main.scss │ │ │ └── sw.js │ │ ├── bower.json │ │ ├── fs │ │ │ ├── etc │ │ │ │ ├── systemd │ │ │ │ │ └── system │ │ │ │ │ │ ├── default.target │ │ │ │ │ │ └── server.service │ │ │ │ └── systemgo │ │ │ │ │ └── systemgo.yaml │ │ │ ├── font │ │ │ │ └── impact.ttf │ │ │ └── img │ │ │ │ ├── gopher.png │ │ │ │ ├── j-walter-weatherman.jpg │ │ │ │ └── zoidberg.jpg │ │ ├── gulpfile.babel.js │ │ ├── package.json │ │ ├── test │ │ │ ├── index.html │ │ │ └── spec │ │ │ │ └── test.js │ │ └── xhrfs-index │ ├── handler.go │ ├── img.go │ ├── main.go │ ├── server.service.in │ └── server.spec.in └── worker-latency │ ├── index.html │ ├── kernel.js │ └── worker.js ├── gulp-plugins └── add-shebang.js ├── gulpfile.js ├── karma.conf.js ├── node-modified └── lib │ ├── binding │ └── http_parser.js │ └── internal │ └── child_process.js ├── node ├── fix_paths.sh └── lib │ ├── _debug_agent.js │ ├── _debugger.js │ ├── _http_agent.js │ ├── _http_client.js │ ├── _http_common.js │ ├── _http_incoming.js │ ├── _http_outgoing.js │ ├── _http_server.js │ ├── _linklist.js │ ├── _stream_duplex.js │ ├── _stream_passthrough.js │ ├── _stream_readable.js │ ├── _stream_transform.js │ ├── _stream_wrap.js │ ├── _stream_writable.js │ ├── _tls_common.js │ ├── _tls_legacy.js │ ├── _tls_wrap.js │ ├── assert.js │ ├── buffer.js │ ├── child_process.js │ ├── cluster.js │ ├── console.js │ ├── constants.js │ ├── crypto.js │ ├── dgram.js │ ├── dns.js │ ├── domain.js │ ├── events.js │ ├── freelist.js │ ├── fs.js │ ├── http.js │ ├── https.js │ ├── internal │ ├── child_process.js │ ├── freelist.js │ ├── module.js │ ├── readme.md │ ├── repl.js │ ├── socket_list.js │ ├── streams │ │ └── lazy_transform.js │ └── util.js │ ├── module.js │ ├── net.js │ ├── os.js │ ├── path.js │ ├── process.js │ ├── punycode.js │ ├── querystring.js │ ├── readline.js │ ├── repl.js │ ├── stream.js │ ├── string_decoder.js │ ├── sys.js │ ├── timers.js │ ├── tls.js │ ├── tty.js │ ├── url.js │ ├── util.js │ ├── v8.js │ ├── vm.js │ └── zlib.js ├── package.json ├── spec-bins ├── runspec ├── sleep └── tar ├── spec_server.js ├── src ├── bin │ ├── cat.ts │ ├── cp.ts │ ├── curl.ts │ ├── echo.ts │ ├── exec.ts │ ├── grep.ts │ ├── head.ts │ ├── hello-socket.ts │ ├── hello.ts │ ├── http-example.ts │ ├── ls.ts │ ├── mkdir.ts │ ├── pipeline-example.ts │ ├── rm.ts │ ├── rmdir.ts │ ├── sha1sum.ts │ ├── socket-example.ts │ ├── sort.ts │ ├── stat.ts │ ├── tail.ts │ ├── tee.ts │ ├── touch.ts │ ├── wc.ts │ └── xargs.ts ├── browser-node │ ├── binding │ │ ├── buffer.ts │ │ ├── cares_wrap.ts │ │ ├── constants.ts │ │ ├── contextify.ts │ │ ├── fs.ts │ │ ├── fs_event_wrap.ts │ │ ├── pipe_wrap.ts │ │ ├── process_wrap.ts │ │ ├── spawn_sync.ts │ │ ├── stream_wrap.ts │ │ ├── tcp_wrap.ts │ │ ├── timer_wrap.ts │ │ ├── tty_wrap.ts │ │ ├── udp_wrap.ts │ │ ├── util.ts │ │ └── uv.ts │ ├── browser-node.ts │ ├── ipc.ts │ └── syscall.ts ├── dash.js ├── hello-sync │ └── hello-sync.ts ├── ipc.ts ├── kernel │ ├── constants.ts │ ├── file.ts │ ├── ipc.ts │ ├── kernel.ts │ ├── pipe.ts │ ├── socket.ts │ └── types.ts ├── ld.js └── syscall-api │ ├── generate-table.bash │ ├── syscall-api.ts │ └── table.ts ├── test ├── test-all.ts ├── test-cat.ts ├── test-cp.ts ├── test-echo.ts ├── test-exec.ts ├── test-grep.ts ├── test-head.ts ├── test-ls.ts ├── test-mkdir.ts ├── test-nice.ts ├── test-pipeline-example.ts ├── test-rm.ts ├── test-rmdir.ts ├── test-sh.ts ├── test-sort.ts ├── test-stat.ts ├── test-tail.ts ├── test-tee.ts ├── test-touch.ts ├── test-wc.ts ├── test-xargs.ts └── test-xhrfs.ts ├── tsconfig.json ├── tslint.json └── xhrfs-index /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /bower_components 3 | /lib 4 | /dist 5 | *~ 6 | /test/*.js 7 | /core.* 8 | /fs 9 | /fs_* 10 | /lib-dist 11 | /.tmp 12 | /bench/*.js 13 | /app/elements/**/*.js 14 | *.aux 15 | *.bbl 16 | *.log 17 | *.blg 18 | *.dvi 19 | /report.out 20 | /results 21 | /benchfs 22 | /examples/meme-service/frontend/fs/meme-service.js 23 | /examples/latex-editor/fs/usr/bin 24 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/BrowserFS"] 2 | path = vendor/BrowserFS 3 | url = https://github.com/jvilk/BrowserFS 4 | [submodule "src/vendor/BrowserFS"] 5 | path = src/vendor/BrowserFS 6 | url = https://github.com/jvilk/BrowserFS 7 | [submodule "src/kernel/vendor/BrowserFS"] 8 | path = src/kernel/vendor/BrowserFS 9 | url = https://github.com/bpowers/BrowserFS 10 | [submodule "test/hbench-os"] 11 | path = bench/hbench-os 12 | url = https://github.com/bpowers/HBench-OS 13 | [submodule "src/init"] 14 | path = src/init 15 | url = http://github.com/plasma-umass/systemgo 16 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /bower_components 3 | /dist 4 | *~ 5 | /test/*.js 6 | /core.* 7 | /fs 8 | /fs_* 9 | /.tmp 10 | /bench/*.js 11 | /app/elements/**/*.js 12 | *.aux 13 | *.bbl 14 | *.log 15 | *.blg 16 | *.dvi 17 | /report.out 18 | /results 19 | /benchfs 20 | /examples/meme-service/frontend/fs/meme-service.js 21 | /examples/latex-editor/fs/usr/bin 22 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | University of Massachusetts Amherst 2 | Bobby Powers 3 | Craig Greenberg 4 | Emery Berger 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 The Browsix Authors, see AUTHORS file. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | ==== 23 | 24 | See the other LICENSE.* files for additional licenses this project 25 | falls under. 26 | -------------------------------------------------------------------------------- /LICENSE.acorn: -------------------------------------------------------------------------------- 1 | Copyright (C) 2012-2016 by various contributors (see https://github.com/ternjs/acorn/blob/master/AUTHORS) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /LICENSE.browserify: -------------------------------------------------------------------------------- 1 | Browserify is licenced under the MIT license. 2 | 3 | Some pieces from builtins/ taken from node core under this license: 4 | 5 | ---- 6 | 7 | Copyright Joyent, Inc. and other Node contributors. 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a 10 | copy of this software and associated documentation files (the 11 | "Software"), to deal in the Software without restriction, including 12 | without limitation the rights to use, copy, modify, merge, publish, 13 | distribute, sublicense, and/or sell copies of the Software, and to permit 14 | persons to whom the Software is furnished to do so, subject to the 15 | following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included 18 | in all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 21 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 23 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 24 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 25 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 26 | USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | 28 | ---- 29 | 30 | buffer_ieee754.js has this license in it: 31 | 32 | ---- 33 | 34 | Copyright (c) 2008-2015, Fair Oaks Labs, Inc. 35 | All rights reserved. 36 | 37 | Redistribution and use in source and binary forms, with or without 38 | modification, are permitted provided that the following conditions are met: 39 | 40 | * Redistributions of source code must retain the above copyright notice, 41 | this list of conditions and the following disclaimer. 42 | 43 | * Redistributions in binary form must reproduce the above copyright notice, 44 | this list of conditions and the following disclaimer in the documentation 45 | and/or other materials provided with the distribution. 46 | 47 | * Neither the name of Fair Oaks Labs, Inc. nor the names of its contributors 48 | may be used to endorse or promote products derived from this software 49 | without specific prior written permission. 50 | 51 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 52 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 55 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 56 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 57 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 58 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 59 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 60 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 61 | POSSIBILITY OF SUCH DAMAGE. 62 | 63 | Modifications to writeIEEE754 to support negative zeroes made by Brian White 64 | 65 | ---- 66 | -------------------------------------------------------------------------------- /LICENSE.node: -------------------------------------------------------------------------------- 1 | Node.js is licensed for use as follows: 2 | 3 | """ 4 | Copyright Node.js contributors. All rights reserved. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to 8 | deal in the Software without restriction, including without limitation the 9 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | sell copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 | IN THE SOFTWARE. 23 | """ 24 | 25 | This license applies to parts of Node.js originating from the 26 | https://github.com/joyent/node repository: 27 | 28 | """ 29 | Copyright Joyent, Inc. and other Node contributors. All rights reserved. 30 | Permission is hereby granted, free of charge, to any person obtaining a copy 31 | of this software and associated documentation files (the "Software"), to 32 | deal in the Software without restriction, including without limitation the 33 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 34 | sell copies of the Software, and to permit persons to whom the Software is 35 | furnished to do so, subject to the following conditions: 36 | 37 | The above copyright notice and this permission notice shall be included in 38 | all copies or substantial portions of the Software. 39 | 40 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 41 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 42 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 43 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 44 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 45 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 46 | IN THE SOFTWARE. 47 | """ 48 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | BOWER ?= node_modules/.bin/bower 3 | GULP ?= node_modules/.bin/gulp 4 | TSLINT ?= node_modules/.bin/tslint 5 | MOCHA ?= node_modules/.bin/mocha 6 | 7 | TEX = pdflatex 8 | 9 | NPM_DEPS = $(GULP) $(TSLINT) $(MOCHA) 10 | BUILD_DEPS = $(NPM_DEPS) bower_components 11 | 12 | SYSTEMGO = github.com/rvolosatovs/systemgo 13 | INIT = fs/usr/bin/init 14 | SYSTEMCTL = fs/usr/bin/systemctl 15 | 16 | # quiet output, but allow us to look at what commands are being 17 | # executed by passing 'V=1' to make, without requiring temporarily 18 | # editing the Makefile. 19 | ifneq ($V, 1) 20 | MAKEFLAGS += -s 21 | endif 22 | 23 | # GNU make, you are the worst. 24 | .SUFFIXES: 25 | %: %,v 26 | %: RCS/%,v 27 | %: RCS/% 28 | %: s.% 29 | %: SCCS/s.% 30 | .SUFFIXES: .tex .pdf 31 | 32 | all: test-once 33 | 34 | dist: $(BUILD_DEPS) 35 | @echo " DIST" 36 | $(GULP) 'build:dist' 37 | 38 | .tex.pdf: report.bib 39 | @echo " LATEX $@" 40 | $(TEX) $< 41 | bibtex $(shell echo $< | cut -d '.' -f 1).aux 42 | $(TEX) $< 43 | $(TEX) $< 44 | 45 | 46 | report: report.pdf 47 | 48 | test-once: $(BUILD_DEPS) 49 | @echo " TEST" 50 | $(GULP) 51 | 52 | shell: serve 53 | 54 | serve: $(BUILD_DEPS) 55 | @echo " SERVE" 56 | $(GULP) serve 57 | 58 | browsix-spec: $(BUILD_DEPS) 59 | @echo " Browsix SPEC" 60 | $(GULP) browsix-spec 61 | 62 | node_modules: bower_components package.json 63 | @echo " NPM" 64 | npm install 65 | touch -c $@ 66 | 67 | $(BOWER): 68 | @echo " NPM bower" 69 | npm install bower 70 | touch -c $@ 71 | 72 | $(NPM_DEPS): node_modules 73 | touch -c $@ 74 | 75 | bower_components: $(BOWER) bower.json 76 | @echo " BOWER" 77 | $(BOWER) install --silent 78 | touch -c $@ 79 | 80 | syscall-api: $(BUILD_DEPS) 81 | @echo " SYSCALL" 82 | node_modules/.bin/gulp dist-syscall-api 83 | 84 | bin: $(BUILD_DEPS) 85 | @echo " BIN" 86 | node_modules/.bin/gulp index-fs 87 | 88 | systemgo: init systemctl 89 | 90 | init: $(BUILD_DEPS) 91 | @echo " INIT" 92 | browsix-gopherjs build $(SYSTEMGO)/cmd/init -o $(INIT) 93 | rm $(INIT).map 94 | chmod +x $(INIT) 95 | 96 | systemctl: $(BUILD_DEPS) 97 | @echo " SYSTEMCTL" 98 | browsix-gopherjs build $(SYSTEMGO)/cmd/systemctl -o $(SYSTEMCTL) 99 | rm $(SYSTEMCTL).map 100 | chmod +x $(SYSTEMCTL) 101 | 102 | test-browser: $(BUILD_DEPS) 103 | @echo " TEST BROWSER" 104 | $(GULP) test-browser 105 | 106 | test: test-browser 107 | 108 | clean: 109 | rm -rf dist lib lib-dist fs report.{pdf,aux,bbl,blg,log} test/*.js 110 | find . -name '*~' | xargs rm -f 111 | 112 | distclean: clean 113 | rm -rf node_modules bower_components 114 | 115 | .PHONY: all clean distclean test test-browser test-node report test-once shell serve init systemctl 116 | -------------------------------------------------------------------------------- /analyze.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | if [ $# != 1 ]; then 5 | echo "usage: $0 DIR" 6 | exit 1 7 | fi 8 | 9 | DIR="$1" 10 | 11 | RESULTS="$DIR/results.tsv" 12 | 13 | HOSTID="$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" 14 | HOSTDIR="$DIR/$HOSTID/$(hostname)" 15 | 16 | echo "system test command kind data" >"$RESULTS" 17 | cat "$DIR/raw" | grep 'LOG:' | cut -d "'" -f 2 | grep -v conf >>"$RESULTS" 18 | 19 | for f in $HOSTDIR/lat_*; do 20 | TEST="$(basename $f)" 21 | cat "$f" | while read l; do 22 | echo -e "$HOSTID\t$TEST\t_\trun\t$l" >>"$RESULTS" 23 | done 24 | done 25 | 26 | 27 | 28 | # BROWSERS="$(cat "$RESULTS" | cut -f 1 | sort -u)" 29 | 30 | # for b in $BROWSERS; do 31 | # TESTS=$(cat "$RESULTS" | grep "$b" | cut -f 2 | sort -u) 32 | 33 | # for t in $TESTS; do 34 | # TDIR="$DIR/$b/$t" 35 | # mkdir -p "$TDIR" 36 | # cat "$RESULTS" | grep "$b" | grep "$t" | grep conf | cut -f 5 >"$TDIR/conf" 37 | # cat "$RESULTS" | grep "$b" | grep "$t" | grep run | cut -f 5 >"$TDIR/results" 38 | # done 39 | # done 40 | -------------------------------------------------------------------------------- /app-spec/elements/browsix-terminal/browsix-terminal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app-spec/elements/browsix-terminal/browsix-terminal.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | interface ExitCallback { 4 | (pid: number, code: number): void; 5 | } 6 | 7 | interface OutputCallback { 8 | (pid: number, output: string): void; 9 | } 10 | 11 | interface Kernel { 12 | fs: any; 13 | system(cmd: string, onExit: ExitCallback, onStdout: OutputCallback, onStderr: OutputCallback): void; 14 | kill(pid: number): void; 15 | } 16 | 17 | namespace Terminal { 18 | 'use strict'; 19 | 20 | const ERROR = 'FLAGRANT SYSTEM ERROR'; 21 | 22 | @component('browsix-terminal') 23 | class Terminal extends polymer.Base { 24 | @property({type: Object}) 25 | kernel: any; 26 | 27 | @property({type: String}) 28 | ps1: string = '$ '; 29 | 30 | constructor() { 31 | super(); 32 | (window).Boot( 33 | 'XmlHttpRequest', 34 | ['index.json', 'fs', true], 35 | (err: any, k: Kernel) => { 36 | if (err) { 37 | console.log(err); 38 | this.$.output.innerHTML = ERROR; 39 | throw new Error(err); 40 | } 41 | this.kernel = k; 42 | }, 43 | {readOnly: false}); 44 | } 45 | 46 | attached(): void { 47 | return; 48 | this.$.input.addEventListener('keypress', this.onInput.bind(this)); 49 | (document).body.addEventListener('click', this.focus.bind(this)); 50 | } 51 | 52 | onInput(ev: any): void { 53 | // If key pressed is not Return/Enter, skip 54 | return; 55 | if (ev.keyCode !== 13) return; 56 | 57 | let cmd = this.$.input.value; 58 | this.$.output.innerHTML += this.ps1 + cmd + '
'; 59 | if (cmd === '') { 60 | this.scrollBottom(); 61 | return; 62 | } 63 | this.setEditable(false); 64 | let bg = cmd[cmd.length - 1] === '&'; 65 | if (bg) { 66 | cmd = cmd.slice(0, -1).trim(); 67 | setTimeout(() => { this.setEditable(true); }, 0); 68 | } 69 | 70 | let completed = (pid: number, code: number) => { 71 | this.setEditable(true); 72 | this.$.input.value = ''; 73 | this.focus(); 74 | this.scrollBottom(); 75 | }; 76 | 77 | let onInput = (pid: number, out: string) => { 78 | // Replace all LF with HTML breaks 79 | out = out.split('\n').join('
'); 80 | this.$.output.innerHTML += out; 81 | this.scrollBottom(); 82 | }; 83 | 84 | this.kernel.system(cmd, completed, onInput, onInput); 85 | } 86 | 87 | @observe('kernel') 88 | kernelChanged(_: Kernel, oldKernel: Kernel): void { 89 | // we expect this to be called once, after 90 | // we've booted the kernel. 91 | if (oldKernel) { 92 | console.log('unexpected kernel change'); 93 | return; 94 | } 95 | } 96 | 97 | focus(): void { 98 | return; 99 | this.$.input.focus(); 100 | } 101 | 102 | setEditable(editable: boolean): void { 103 | // Hide input if not editable 104 | return; 105 | this.$.input_container.style.visibility = (editable) ? '' : 'hidden'; 106 | } 107 | 108 | scrollBottom(): void { 109 | return; 110 | (window).scrollTo(0, document.documentElement.scrollHeight 111 | || document.body.scrollHeight); 112 | } 113 | } 114 | 115 | Terminal.register(); 116 | } 117 | -------------------------------------------------------------------------------- /app-spec/elements/elements.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app-spec/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/app-spec/favicon.ico -------------------------------------------------------------------------------- /app-spec/images/touch/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/app-spec/images/touch/apple-touch-icon.png -------------------------------------------------------------------------------- /app-spec/images/touch/chrome-splashscreen-icon-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/app-spec/images/touch/chrome-splashscreen-icon-384x384.png -------------------------------------------------------------------------------- /app-spec/images/touch/chrome-touch-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/app-spec/images/touch/chrome-touch-icon-192x192.png -------------------------------------------------------------------------------- /app-spec/images/touch/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/app-spec/images/touch/icon-128x128.png -------------------------------------------------------------------------------- /app-spec/images/touch/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/app-spec/images/touch/ms-icon-144x144.png -------------------------------------------------------------------------------- /app-spec/images/touch/ms-touch-icon-144x144-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/app-spec/images/touch/ms-touch-icon-144x144-precomposed.png -------------------------------------------------------------------------------- /app-spec/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Browsix 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 35 | 36 | 37 |
38 | 39 | 40 | 41 |
42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app-spec/styles/main.css: -------------------------------------------------------------------------------- 1 | body{background:#171a1b;font-size:24px;font-family:Hack,Roboto,'Helvetica Neue',Helvetica,Arial,sans-serif;color:#eeeeec}img{position:absolute} -------------------------------------------------------------------------------- /app-spec/styles/shared-styles.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/elements/browsix-terminal/browsix-terminal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /app/elements/browsix-terminal/browsix-terminal.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | interface ExitCallback { 4 | (pid: number, code: number): void; 5 | } 6 | 7 | interface OutputCallback { 8 | (pid: number, output: string): void; 9 | } 10 | 11 | interface Kernel { 12 | fs: any; 13 | system(cmd: string, onExit: ExitCallback, onStdout: OutputCallback, onStderr: OutputCallback): void; 14 | kill(pid: number): void; 15 | } 16 | 17 | namespace Terminal { 18 | 'use strict'; 19 | 20 | const ERROR = 'FLAGRANT SYSTEM ERROR'; 21 | 22 | @component('browsix-terminal') 23 | class Terminal extends polymer.Base { 24 | @property({type: Object}) 25 | kernel: any; 26 | 27 | @property({type: String}) 28 | ps1: string = '$ '; 29 | 30 | constructor() { 31 | super(); 32 | (window).Boot( 33 | 'XmlHttpRequest', 34 | ['index.json', 'fs', true], 35 | (err: any, k: Kernel) => { 36 | if (err) { 37 | console.log(err); 38 | this.$.output.innerHTML = ERROR; 39 | throw new Error(err); 40 | } 41 | this.kernel = k; 42 | }, 43 | {readOnly: false}); 44 | } 45 | 46 | attached(): void { 47 | this.$.input.addEventListener('keypress', this.onInput.bind(this)); 48 | (document).body.addEventListener('click', this.focus.bind(this)); 49 | } 50 | 51 | onInput(ev: any): void { 52 | // If key pressed is not Return/Enter, skip 53 | if (ev.keyCode !== 13) return; 54 | 55 | let cmd = this.$.input.value; 56 | this.$.output.innerHTML += this.ps1 + cmd + '
'; 57 | if (cmd === '') { 58 | this.scrollBottom(); 59 | return; 60 | } 61 | this.setEditable(false); 62 | let bg = cmd[cmd.length - 1] === '&'; 63 | if (bg) { 64 | cmd = cmd.slice(0, -1).trim(); 65 | setTimeout(() => { this.setEditable(true); }, 0); 66 | } 67 | 68 | let completed = (pid: number, code: number) => { 69 | this.setEditable(true); 70 | this.$.input.value = ''; 71 | this.focus(); 72 | this.scrollBottom(); 73 | }; 74 | 75 | let onInput = (pid: number, out: string) => { 76 | // Replace all LF with HTML breaks 77 | out = out.split('\n').join('
'); 78 | this.$.output.innerHTML += out; 79 | this.scrollBottom(); 80 | }; 81 | 82 | this.kernel.system(cmd, completed, onInput, onInput); 83 | } 84 | 85 | @observe('kernel') 86 | kernelChanged(_: Kernel, oldKernel: Kernel): void { 87 | // we expect this to be called once, after 88 | // we've booted the kernel. 89 | if (oldKernel) { 90 | console.log('unexpected kernel change'); 91 | return; 92 | } 93 | } 94 | 95 | focus(): void { 96 | this.$.input.focus(); 97 | } 98 | 99 | setEditable(editable: boolean): void { 100 | // Hide input if not editable 101 | this.$.input_container.style.visibility = (editable) ? '' : 'hidden'; 102 | } 103 | 104 | scrollBottom(): void { 105 | (window).scrollTo(0, document.documentElement.scrollHeight 106 | || document.body.scrollHeight); 107 | } 108 | } 109 | 110 | Terminal.register(); 111 | } 112 | -------------------------------------------------------------------------------- /app/elements/elements.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/app/favicon.ico -------------------------------------------------------------------------------- /app/images/touch/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/app/images/touch/apple-touch-icon.png -------------------------------------------------------------------------------- /app/images/touch/chrome-splashscreen-icon-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/app/images/touch/chrome-splashscreen-icon-384x384.png -------------------------------------------------------------------------------- /app/images/touch/chrome-touch-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/app/images/touch/chrome-touch-icon-192x192.png -------------------------------------------------------------------------------- /app/images/touch/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/app/images/touch/icon-128x128.png -------------------------------------------------------------------------------- /app/images/touch/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/app/images/touch/ms-icon-144x144.png -------------------------------------------------------------------------------- /app/images/touch/ms-touch-icon-144x144-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/app/images/touch/ms-touch-icon-144x144-precomposed.png -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Browsix-SPEC 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /app/styles/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #171a1b; 3 | font-size: 24px; 4 | font-family: 'Hack', 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif; 5 | color: #eeeeec; 6 | } 7 | 8 | img { 9 | position: absolute; 10 | } 11 | -------------------------------------------------------------------------------- /app/styles/shared-styles.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | -------------------------------------------------------------------------------- /benchmark.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | FSROOT="./benchfs" 5 | BIN="$FSROOT/usr/bin" 6 | HBENCH="./bench/hbench-os" 7 | SHROOT="./fs" 8 | RESULTDIRB="results/browsix" 9 | 10 | export FIREFOX_BIN='/opt/firefox-nightly/firefox' 11 | #export FIREFOX_BIN='/home/bpowers/src/mozilla-central/obj-x86_64-pc-linux-gnu/dist/bin/firefox' 12 | export CHROME_BIN='chrome_sab' 13 | 14 | #export EMCC_BROWSIX_ASYNC=1 15 | export EMFLAGS='-s TOTAL_MEMORY=16000 -Os' 16 | 17 | rm -rf "$HBENCH/bin/browsix-js" 18 | 19 | (cd $HBENCH && emmake make PLATFORM=js-pc-browsix EXT=.js CC="emcc $EMFLAGS" CFLAGS="-static -DNO_PORTMAPPER") 20 | 21 | # benchmarks to run 22 | BENCHMARKS='lat_syscall lat_pipe lat_tcp lat_proc hello lat_fs lat_fslayer mhz' 23 | 24 | mkdir -p "$FSROOT/tmp" 25 | mkdir -p "$BIN" 26 | 27 | for b in $BENCHMARKS; do 28 | cp -a "$HBENCH/bin/browsix-js/$b.js" "$BIN/$b" 29 | done 30 | 31 | exit 32 | make bin 33 | 34 | # copy in a few extra programs, mainly the shell 35 | cp "$SHROOT/usr/bin/sh" "$BIN" 36 | 37 | mkdir -p results 38 | 39 | RESULTDIR="$RESULTDIRB.1" 40 | while [ -d $RESULTDIR ]; do 41 | EXT=`expr $EXT + 1` 42 | RESULTDIR=$RESULTDIRB.$EXT 43 | done 44 | 45 | mkdir -p "$RESULTDIR" 46 | 47 | node_modules/.bin/gulp bench >"$RESULTDIR/raw" 48 | 49 | (cd "$HBENCH" && rm -rf Results/linux* && make && make run) 50 | 51 | mv "$HBENCH/Results/linux-x86_64" "$RESULTDIR" 52 | 53 | ./analyze.sh "$RESULTDIR" 54 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "browsix", 3 | "dependencies": { 4 | "iron-elements": "PolymerElements/iron-elements#^1.0.9", 5 | "neon-elements": "PolymerElements/neon-elements#^1.0.0", 6 | "page": "visionmedia/page.js#~1.6.4", 7 | "paper-elements": "PolymerElements/paper-elements#^1.0.7", 8 | "platinum-elements": "PolymerElements/platinum-elements#^2.0.0", 9 | "polymer": "Polymer/polymer#^1.4.0", 10 | "polymer-ts": "~0.1.26" 11 | }, 12 | "devDependencies": { 13 | "web-component-tester": "*", 14 | "test-fixture": "PolymerElements/test-fixture#^3.0.0-rc.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /chrome_sab: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | exec google-chrome-beta --js-flags=--harmony-sharedarraybuffer --enable-blink-feature=SharedArrayBuffer "$@" 4 | -------------------------------------------------------------------------------- /doc/img/shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/doc/img/shell.png -------------------------------------------------------------------------------- /doc/img/stack-eps-converted-to.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/doc/img/stack-eps-converted-to.pdf -------------------------------------------------------------------------------- /doc/img/stack.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/doc/img/stack.graffle -------------------------------------------------------------------------------- /doc/img/utilities-eps-converted-to.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/doc/img/utilities-eps-converted-to.pdf -------------------------------------------------------------------------------- /doc/img/utilities.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/doc/img/utilities.graffle -------------------------------------------------------------------------------- /doc/meme_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/doc/meme_screenshot.png -------------------------------------------------------------------------------- /doc/report.bib: -------------------------------------------------------------------------------- 1 | @TechReport{ souci:2014, 2 | author = "Souci, Benjamin and Lemaire, Maude", 3 | title = "An Inside Look at the Architecture of NodeJS", 4 | institution = "McGill University", 5 | year = 2014, 6 | } 7 | 8 | @inproceedings{vilk:2014doppio, 9 | title={Doppio: breaking the browser language barrier}, 10 | author={Vilk, John and Berger, Emery D}, 11 | booktitle={ACM SIGPLAN Notices}, 12 | volume={49}, 13 | number={6}, 14 | pages={508--518}, 15 | year={2014}, 16 | organization={ACM} 17 | } 18 | 19 | @misc{mcilroy:2015chrome47, 20 | title = {Chrome 47 Beta: Idle time work, splash screens, and desktop notification management}, 21 | howpublished = {\url{https://blog.chromium.org/2015/10/chrome-47-beta-idle-time-work-splash.html}}, 22 | note = {Accessed: 2015-10-22}, 23 | author = {Ross McIlroy} 24 | } 25 | 26 | @misc{yasskin:2015webbluetooth, 27 | title = {Web Bluetooth}, 28 | howpublished = {\url{https://webbluetoothcg.github.io/web-bluetooth/}}, 29 | note = {Accessed: 2015-10-22}, 30 | author = {Jeff Yasskin} 31 | } 32 | -------------------------------------------------------------------------------- /doc/report.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/doc/report.pdf -------------------------------------------------------------------------------- /docker/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # hack to invalidate Docker cache 4 | touch README.md 5 | 6 | echo "-------" 7 | echo "tagging: " 8 | REPO_NAME=$(basename `git rev-parse --show-toplevel`) 9 | GIT_REV=$(git rev-parse --short HEAD) 10 | 11 | IMAGE_NAME="$REPO_NAME:$GIT_REV" 12 | echo $IMAGE_NAME 13 | echo "-------" 14 | 15 | echo "---------" 16 | echo "building: " 17 | docker \ 18 | build -t $IMAGE_NAME \ 19 | -f ./docker/Dockerfile \ 20 | . 21 | echo "---------" 22 | 23 | echo "-------" 24 | echo "running: " 25 | docker run -t -i $IMAGE_NAME 26 | echo "-------" 27 | -------------------------------------------------------------------------------- /examples/go-curl/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io" 7 | "net/http" 8 | "os" 9 | ) 10 | 11 | func main() { 12 | flag.Parse() 13 | 14 | if flag.NArg() != 1 { 15 | fmt.Fprintf(os.Stderr, "1 required arg: URL\n") 16 | os.Exit(1) 17 | } 18 | 19 | url := flag.Arg(0) 20 | 21 | resp, err := http.Get(url) 22 | if err != nil { 23 | fmt.Fprintf(os.Stderr, "Get(%s): %s", url, err) 24 | os.Exit(1) 25 | } 26 | defer resp.Body.Close() 27 | 28 | n, err := io.Copy(os.Stdout, resp.Body) 29 | if err != nil { 30 | fmt.Fprintf(os.Stderr, "Copy: %s", err) 31 | } 32 | fmt.Fprintf(os.Stderr, "copied %d bytes\n", n) 33 | 34 | os.Exit(0) 35 | } 36 | -------------------------------------------------------------------------------- /examples/go-stat/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | if len(os.Args) != 2 { 11 | log.Fatalf("usage: %s FILE", os.Args[0]) 12 | } 13 | 14 | fname := os.Args[1] 15 | 16 | fi, err := os.Stat(fname) 17 | if err != nil { 18 | log.Fatalf("Stat(%s): %s", fname, err) 19 | } 20 | 21 | fmt.Printf("%s: %#v\n", fname, fi) 22 | } 23 | -------------------------------------------------------------------------------- /examples/go-wait/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os/exec" 6 | ) 7 | 8 | func main() { 9 | cmd := exec.Command("sleep", "5") 10 | err := cmd.Start() 11 | if err != nil { 12 | log.Fatal(err) 13 | } 14 | log.Printf("Waiting for command to finish...") 15 | err = cmd.Wait() 16 | log.Printf("Command finished with error: %v", err) 17 | } 18 | -------------------------------------------------------------------------------- /examples/hello-wasm/.gitignore: -------------------------------------------------------------------------------- 1 | /hello 2 | /hello.js 3 | -------------------------------------------------------------------------------- /examples/hello-wasm/Makefile: -------------------------------------------------------------------------------- 1 | hello: hello.c 2 | emcc -O2 -g3 -o hello hello.c -s BINARYEN=1 -s "BINARYEN_METHOD='native-wasm'" 3 | 4 | clean: 5 | rm -f hello hello.js 6 | 7 | .PHONY: hello clean 8 | -------------------------------------------------------------------------------- /examples/hello-wasm/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | main() { 5 | printf("hello from WebAssembly\n"); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /examples/hello-world-http/.gitignore: -------------------------------------------------------------------------------- 1 | /*.js 2 | /*.js.map 3 | /hello-world-http 4 | -------------------------------------------------------------------------------- /examples/hello-world-http/Makefile: -------------------------------------------------------------------------------- 1 | MAIN = hello-world-http 2 | 3 | all: $(MAIN).js 4 | 5 | $(MAIN).js: 6 | # rm ~/pkg/linux_js -r 7 | browsix-gopherjs build 8 | cp hello-world-http.js ../../fs/usr/bin/go-hello 9 | 10 | .PHONY: $(MAIN).js 11 | -------------------------------------------------------------------------------- /examples/hello-world-http/cl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /// 3 | 'use strict'; 4 | var child_process_1 = require('child_process'); 5 | var http = require('http'); 6 | function main() { 7 | var serverFinished = false; 8 | var clientFinished = false; 9 | var server = child_process_1.spawn('./hello-world-http', [], { stdio: [0, 1, 2] }); 10 | server.on('error', function (err) { 11 | process.stderr.write('error: ' + err + '\n', function () { 12 | serverFinished = true; 13 | if (clientFinished) 14 | return process.exit(0); 15 | }); 16 | }); 17 | server.on('exit', function () { 18 | serverFinished = true; 19 | if (clientFinished) 20 | return process.exit(0); 21 | }); 22 | setTimeout(client, 5000); 23 | function client() { 24 | var options = { 25 | host: 'localhost', 26 | port: 8080, 27 | path: '/', 28 | }; 29 | function callback(response) { 30 | var str = ''; 31 | response.on('data', function (chunk) { 32 | str += chunk; 33 | process.stdout.write('http client got: ' + chunk + '\n'); 34 | setTimeout(process.exit, 0); 35 | }); 36 | } 37 | http.request(options, callback).end(); 38 | } 39 | } 40 | main(); 41 | 42 | -------------------------------------------------------------------------------- /examples/hello-world-http/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "html" 6 | "log" 7 | "net/http" 8 | "os" 9 | "time" 10 | ) 11 | 12 | func main() { 13 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 14 | fmt.Fprintf(w, "Hello from go: %q\n", html.EscapeString(r.URL.Path)) 15 | // after we've responded once, get outta town 16 | go func() { 17 | time.Sleep(1 * time.Second) 18 | os.Exit(0) 19 | }() 20 | }) 21 | 22 | log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil)) 23 | } 24 | -------------------------------------------------------------------------------- /examples/hello-world/Makefile: -------------------------------------------------------------------------------- 1 | MAIN = hello-world 2 | 3 | all: $(MAIN).js 4 | 5 | $(MAIN).js: 6 | # rm ~/pkg/linux_js -r 7 | browsix-gopherjs build 8 | cp $(MAIN).js ../../fs/usr/bin/hello-from-go 9 | 10 | .PHONY: $(MAIN).js 11 | -------------------------------------------------------------------------------- /examples/hello-world/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Go Browsix 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/hello-world/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println("Hello, 世界") 7 | } 8 | -------------------------------------------------------------------------------- /examples/latex-editor/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /examples/latex-editor/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /examples/latex-editor/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | 14 | [*.js] 15 | indent_style = tab 16 | indent_size = 8 17 | 18 | [{*.py,mktexlsr}] 19 | indent_style = space 20 | indent_size = 4 21 | 22 | 23 | 24 | [*.md] 25 | trim_trailing_whitespace = false 26 | 27 | 28 | [{package,bower}.json] 29 | indent_style = space 30 | indent_size = 2 31 | -------------------------------------------------------------------------------- /examples/latex-editor/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .tmp 4 | .sass-cache 5 | bower_components 6 | test/bower_components 7 | *~ 8 | /app/kernel.js 9 | /fs/Makefile 10 | /fs/img/ 11 | /fs/index.json 12 | /fs/main.bib 13 | /fs/main.tex 14 | /fs/plots/ 15 | /fs/redis.conf 16 | /fs/test.sh 17 | /fs/test1.dot 18 | /fs/texmf/ 19 | 20 | -------------------------------------------------------------------------------- /examples/latex-editor/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-mocha": {} 3 | } -------------------------------------------------------------------------------- /examples/latex-editor/Makefile: -------------------------------------------------------------------------------- 1 | 2 | BOWER ?= node_modules/.bin/bower 3 | GULP ?= node_modules/.bin/gulp 4 | 5 | NPM_DEPS = $(GULP) 6 | BUILD_DEPS = $(NPM_DEPS) bower_components 7 | 8 | 9 | # quiet output, but allow us to look at what commands are being 10 | # executed by passing 'V=1' to make, without requiring temporarily 11 | # editing the Makefile. 12 | ifneq ($V, 1) 13 | MAKEFLAGS += -s 14 | endif 15 | 16 | # GNU make, you are the worst. 17 | .SUFFIXES: 18 | %: %,v 19 | %: RCS/%,v 20 | %: RCS/% 21 | %: s.% 22 | %: SCCS/s.% 23 | .SUFFIXES: .tex .pdf 24 | 25 | all: serve 26 | 27 | serve: $(BUILD_DEPS) 28 | @echo " SERVE" 29 | $(GULP) serve 30 | 31 | node_modules: bower_components package.json 32 | @echo " NPM" 33 | npm install 34 | touch -c $@ 35 | 36 | $(BOWER): 37 | @echo " NPM bower" 38 | npm install bower 39 | touch -c $@ 40 | 41 | $(NPM_DEPS): node_modules 42 | touch -c $@ 43 | 44 | bower_components: $(BOWER) bower.json 45 | @echo " BOWER" 46 | $(BOWER) install --silent 47 | touch -c $@ 48 | 49 | clean: 50 | rm -rf dist 51 | find . -name '*~' | xargs rm -f 52 | 53 | distclean: clean 54 | rm -rf node_modules bower_components 55 | 56 | .PHONY: all clean distclean serve 57 | -------------------------------------------------------------------------------- /examples/latex-editor/app/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/examples/latex-editor/app/apple-touch-icon.png -------------------------------------------------------------------------------- /examples/latex-editor/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/examples/latex-editor/app/favicon.ico -------------------------------------------------------------------------------- /examples/latex-editor/app/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/examples/latex-editor/app/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /examples/latex-editor/app/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/examples/latex-editor/app/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /examples/latex-editor/app/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | Disallow: 5 | -------------------------------------------------------------------------------- /examples/latex-editor/app/styles/main.scss: -------------------------------------------------------------------------------- 1 | $icon-font-path: '../fonts/'; 2 | 3 | // bower:scss 4 | @import "bower_components/bootstrap-sass/assets/stylesheets/_bootstrap.scss"; 5 | // endbower 6 | 7 | .browserupgrade { 8 | margin: 0.2em 0; 9 | background: #ccc; 10 | color: #000; 11 | padding: 0.2em 0; 12 | } 13 | 14 | /* Space out content a bit */ 15 | body { 16 | padding-top: 20px; 17 | padding-bottom: 20px; 18 | } 19 | 20 | /* Everything but the jumbotron gets side spacing for mobile first views */ 21 | .header, 22 | .marketing, 23 | .footer { 24 | padding-left: 15px; 25 | padding-right: 15px; 26 | } 27 | 28 | /* Custom page header */ 29 | .header { 30 | border-bottom: 1px solid #e5e5e5; 31 | 32 | /* Make the masthead heading the same height as the navigation */ 33 | h3 { 34 | margin-top: 0; 35 | margin-bottom: 0; 36 | line-height: 40px; 37 | padding-bottom: 19px; 38 | } 39 | } 40 | 41 | /* Custom page footer */ 42 | .footer { 43 | padding-top: 19px; 44 | color: #777; 45 | border-top: 1px solid #e5e5e5; 46 | } 47 | 48 | .container-narrow > hr { 49 | margin: 30px 0; 50 | } 51 | 52 | /* Main marketing message and sign up button */ 53 | .jumbotron { 54 | text-align: center; 55 | border-bottom: 1px solid #e5e5e5; 56 | .btn { 57 | font-size: 21px; 58 | padding: 14px 24px; 59 | } 60 | } 61 | 62 | /* Supporting marketing content */ 63 | .marketing { 64 | margin: 40px 0; 65 | p + h4 { 66 | margin-top: 28px; 67 | } 68 | } 69 | 70 | /* Responsive: Portrait tablets and up */ 71 | @media screen and (min-width: 768px) { 72 | .container { 73 | max-width: 730px; 74 | } 75 | 76 | /* Remove the padding we set earlier */ 77 | .header, 78 | .marketing, 79 | .footer { 80 | padding-left: 0; 81 | padding-right: 0; 82 | } 83 | 84 | /* Space out the masthead */ 85 | .header { 86 | margin-bottom: 30px; 87 | } 88 | 89 | /* Remove the bottom border on the jumbotron for visual effect */ 90 | .jumbotron { 91 | border-bottom: 0; 92 | } 93 | } 94 | 95 | .has-spinner.is-active { 96 | cursor:progress; 97 | } 98 | 99 | .form-control { 100 | border-radius: 0px; 101 | } 102 | 103 | .btn { 104 | border-radius: 0px; 105 | } 106 | 107 | .input-group-addon { 108 | border-radius: 0px; 109 | } 110 | 111 | .in-text { 112 | font-size: 14px; 113 | font-family: 'Hack', 'Courier New', Courier, monospace; 114 | outline: 0px solid transparent; 115 | width: 100%; 116 | } 117 | 118 | #ed-tex { 119 | height: 500px; 120 | } 121 | #ed-bib { 122 | height: 300px; 123 | } 124 | 125 | .pdf { 126 | width: 100%; 127 | height: 800px; 128 | } 129 | 130 | .col-6 { 131 | width: 48%; 132 | display: inline-block; 133 | } 134 | 135 | .vertical-center { 136 | padding-bottom: 500px; 137 | } 138 | 139 | .vcenter { 140 | font-weight: bold; 141 | display: inline-block; 142 | vertical-align: bottom; 143 | height: 300px; 144 | float: none; 145 | } 146 | 147 | @media (max-width: 768px) { 148 | .navbar-nav { 149 | margin: 0px; 150 | } 151 | .navbar-header { 152 | float: left; 153 | } 154 | 155 | .navbar-nav > li { 156 | float: left; 157 | } 158 | 159 | .navbar-right { 160 | float: right !important; 161 | margin-right: -15px; 162 | } 163 | } 164 | 165 | .container > .navbar-header { 166 | margin-right: 0; 167 | margin-left: 0; 168 | } 169 | 170 | 171 | .navbar-right { 172 | margin-right: 20px; 173 | margin-top: 8px; 174 | } 175 | 176 | body { 177 | padding-top: 70px; 178 | } 179 | 180 | .browsix-hidden { 181 | display:none; 182 | } 183 | 184 | #loading { 185 | padding-right: 8px; 186 | } 187 | 188 | 189 | @media (max-width: 1200px) { 190 | .col-lg-6 { 191 | width: 50%; 192 | } 193 | 194 | .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { 195 | float: left; 196 | } 197 | } 198 | 199 | #toolbar { 200 | display: flex; 201 | align-items: center; 202 | } 203 | 204 | #build-progress { 205 | align-items: flex-start; 206 | text-align: center; 207 | 208 | width: 200px; 209 | 210 | margin-right: 10px; 211 | margin-bottom: 0px; 212 | } 213 | -------------------------------------------------------------------------------- /examples/latex-editor/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meme-frontend", 3 | "private": true, 4 | "dependencies": { 5 | "bootstrap-sass": "~3.3.6", 6 | "lodash": "^4.11.1" 7 | }, 8 | "overrides": { 9 | "bootstrap-sass": { 10 | "main": [ 11 | "assets/stylesheets/_bootstrap.scss", 12 | "assets/fonts/bootstrap/*", 13 | "assets/javascripts/bootstrap.js" 14 | ] 15 | } 16 | }, 17 | "devDependencies": { 18 | "chai": "^3.5.0", 19 | "mocha": "^2.4.5" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/latex-editor/fs/dev/null: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/examples/latex-editor/fs/dev/null -------------------------------------------------------------------------------- /examples/latex-editor/fs/etc/passwd: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /examples/latex-editor/mktexlsr: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | import argparse 4 | import os 5 | import re 6 | import sys 7 | 8 | from os.path import isdir, join 9 | 10 | 11 | def index_dir(index_file, root, prefix, d): 12 | is_root = prefix == '' 13 | err = False 14 | full_dir = join(root, prefix, d) 15 | dents = sorted(os.listdir(full_dir)) 16 | dents = filter(lambda f: f != 'ls-R', dents) 17 | 18 | if is_root: 19 | index_file.write('./:\n') 20 | index_file.write('%s:\n' % join(prefix, d)) 21 | index_file.write('\n'.join(dents)) 22 | index_file.write('\n\n') 23 | 24 | subdirs = filter(lambda f: isdir(join(full_dir, f)), dents) 25 | for sd in subdirs: 26 | err |= index_dir(index_file, root, join(prefix, d), sd) 27 | 28 | return err 29 | 30 | 31 | def main(): 32 | parser = argparse.ArgumentParser() 33 | parser.add_argument('DIR', help='path to index into tex-compatible ls-R file') 34 | args = parser.parse_args() 35 | 36 | err = False 37 | 38 | with open(join(args.DIR, 'ls-R'), 'w') as index_file: 39 | err |= index_dir(index_file, args.DIR, '', '.') 40 | 41 | return err 42 | 43 | if __name__ == '__main__': 44 | exit(main()) 45 | -------------------------------------------------------------------------------- /examples/latex-editor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "engines": { 4 | "node": ">=0.12.0" 5 | }, 6 | "devDependencies": { 7 | "babel-core": "^6.4.0", 8 | "babel-preset-es2015": "^6.3.13", 9 | "browser-sync": "^2.2.1", 10 | "del": "^1.1.1", 11 | "gulp": "^3.9.0", 12 | "gulp-autoprefixer": "^3.0.1", 13 | "gulp-babel": "^6.1.1", 14 | "gulp-cache": "^0.2.8", 15 | "gulp-cssnano": "^2.0.0", 16 | "gulp-eslint": "^0.13.2", 17 | "gulp-htmlmin": "^1.3.0", 18 | "gulp-if": "^1.2.5", 19 | "gulp-imagemin": "^2.2.1", 20 | "gulp-load-plugins": "^0.10.0", 21 | "gulp-plumber": "^1.0.1", 22 | "gulp-rename": "^1.2.2", 23 | "gulp-run": "^1.6.12", 24 | "gulp-sass": "^2.0.0", 25 | "gulp-size": "^1.2.1", 26 | "gulp-sourcemaps": "^1.5.0", 27 | "gulp-uglify": "^1.1.0", 28 | "gulp-useref": "^3.0.0", 29 | "main-bower-files": "^2.5.0", 30 | "proxy-middleware": "^0.15.0", 31 | "wiredep": "^2.2.2" 32 | }, 33 | "eslintConfig": { 34 | "env": { 35 | "es6": true, 36 | "node": true, 37 | "browser": true 38 | }, 39 | "rules": { 40 | "quotes": [ 41 | 2, 42 | "single" 43 | ] 44 | } 45 | }, 46 | "dependencies": { 47 | "browsix": "^0.9.0", 48 | "mobile-detect": "^1.3.2" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/latex-editor/test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mocha Spec Runner 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /examples/latex-editor/test/spec/test.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | describe('Give it some context', function () { 5 | describe('maybe a bit more context here', function () { 6 | it('should run here few assertions', function () { 7 | 8 | }); 9 | }); 10 | }); 11 | })(); 12 | -------------------------------------------------------------------------------- /examples/latex-editor/xhrfs-index: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // based on jvilk's XHRIndexer, but in plain JS using async APIs 3 | 4 | 'use strict'; 5 | 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | 9 | var exclude = [ 10 | /^\./, // dotfiles 11 | /^bower_components$/, 12 | /^node_modules$/, 13 | /^build$/, 14 | /^dist$/, 15 | /~$/, // emacs backups 16 | ]; 17 | 18 | function shouldExclude(name) { 19 | for (var i = 0; i < exclude.length; i++) { 20 | if (name.match(exclude[i])) 21 | return true; 22 | } 23 | return false; 24 | } 25 | 26 | var outstanding = 1; 27 | var tree = {}; 28 | 29 | function subtreeAt(relative) { 30 | if (!relative) 31 | return tree; 32 | 33 | var parts = relative.split(path.sep); 34 | var subtree = tree; 35 | // start at 1 to skip the leading / 36 | for (var i = 1; i < parts.length; i++) 37 | subtree = subtree[parts[i]]; 38 | 39 | return subtree; 40 | } 41 | 42 | function maybeFinished(file, err, onComplete) { 43 | if (--outstanding === 0) { 44 | onComplete(err, tree); 45 | } 46 | } 47 | 48 | function walkDir(base, curr, onComplete) { 49 | var parent = curr.slice(base.length); 50 | fs.readdir(curr, function(err, files) { 51 | if (err) { 52 | process.stderr.write('error reading dir: ' + err); 53 | maybeFinished(curr, err, onComplete); 54 | return; 55 | } 56 | for (var i = 0; i < files.length; i++) { 57 | var file = files[i]; 58 | if (shouldExclude(file)) 59 | continue; 60 | 61 | outstanding++; 62 | 63 | var absFile = path.join(curr, file) 64 | fs.stat(absFile, function statFile(absFile, err, stats) { 65 | if (err) { 66 | maybeFinished(absFile, err, onComplete); 67 | return; 68 | } 69 | var parts = absFile.split(path.sep); 70 | var file = parts[parts.length-1]; 71 | var subtree = subtreeAt(parent); 72 | if (stats.isDirectory()) { 73 | subtree[file] = {}; 74 | walkDir(base, absFile, onComplete); 75 | } else { 76 | subtree[file] = null; 77 | maybeFinished(absFile, null, onComplete); 78 | } 79 | }.bind(null, absFile)); 80 | } 81 | maybeFinished(curr, null, onComplete); 82 | }); 83 | } 84 | 85 | function main() { 86 | var pathToNode = process.argv[0]; 87 | var pathToScript = process.argv[1]; 88 | var args = process.argv.slice(2); 89 | 90 | var root = process.cwd(); 91 | if (args.length > 0) 92 | root = args[0]; 93 | 94 | walkDir(root, root, function writeJSON(err, tree) { 95 | if (err) { 96 | process.stderr.write('error: ' + err + '\n'); 97 | process.exit(-1); 98 | return; 99 | } 100 | process.stdout.write(JSON.stringify(tree) + '\n'); 101 | }); 102 | } 103 | 104 | main(); 105 | -------------------------------------------------------------------------------- /examples/meme-service/.gitignore: -------------------------------------------------------------------------------- 1 | /meme-service 2 | /meme-service.js 3 | /meme-service.js.map 4 | /static 5 | /package 6 | /site 7 | /server.spec 8 | -------------------------------------------------------------------------------- /examples/meme-service/Makefile: -------------------------------------------------------------------------------- 1 | NAME = $(shell basename `pwd` | cut -d '-' -f 1) 2 | VERSION = 0.1 3 | N = 23 4 | 5 | EXE=$(shell basename `pwd`) 6 | PKGNAME=$(EXE) 7 | RPMSHORT=$(PKGNAME)-$(VERSION)-1.x86_64.rpm 8 | RPM=package/RPMS/x86_64/$(RPMSHORT) 9 | 10 | MAIN = $(EXE) 11 | 12 | 13 | all: build systemgo 14 | 15 | $(MAIN).js: *.go Makefile 16 | # rm ~/pkg/linux_js -r 17 | browsix-gopherjs build 18 | 19 | build: $(MAIN).js fs 20 | go build 21 | cp ../../lib-dist/lib/kernel/kernel.js frontend/app 22 | cp $(MAIN).js frontend/fs/$(MAIN).js 23 | cd frontend && bower install 24 | cd frontend && npm install 25 | cd frontend && rm -rf dist 26 | cd frontend && gulp build 27 | rm -rf static 28 | cp -a frontend/dist static 29 | cp -a frontend/fs static/fs 30 | 31 | systemgo: ../../fs/usr/bin/init ../../fs/usr/bin/systemctl 32 | mkdir -p frontend/fs/usr/bin 33 | cp ../../fs/usr/bin/init frontend/fs/usr/bin/init 34 | cp ../../fs/usr/bin/systemctl frontend/fs/usr/bin/systemctl 35 | 36 | dev: $(MAIN).js systemgo 37 | cp ../../lib-dist/lib/kernel/kernel.js frontend/app 38 | cp $(MAIN).js frontend/fs 39 | chmod +x frontend/fs/$(MAIN).js 40 | go build 41 | pkill meme-service || true 42 | (./meme-service &) 43 | cd frontend && gulp serve 44 | 45 | 46 | rpm: $(RPM) 47 | 48 | $(EXE): build 49 | mkdir -p site 50 | cp -a $(MAIN) site/ 51 | cp -a static site/ 52 | 53 | $(RPM): $(EXE) server.service server.spec 54 | cp -a site $(PKGNAME)-$(VERSION) 55 | mkdir -p package/{RPMS,BUILD,SOURCES,BUILDROOT} 56 | tar -czf package/SOURCES/$(PKGNAME)-$(VERSION).tar.gz $(PKGNAME)-$(VERSION) 57 | rm -rf $(PKGNAME)-$(VERSION) 58 | rpmbuild --define "_topdir $(PWD)/package" -ba server.spec 59 | rm -rf package/{BUILD,BUILDROOT} 60 | 61 | server.spec: 62 | cat server.spec.in | sed "s/%NAME%/$(NAME)/g" | sed "s/%VERSION%/$(VERSION)/g" >server.spec 63 | 64 | server.service: 65 | cat server.service.in | sed "s/%NAME%/$(NAME)/g" >server.service 66 | 67 | 68 | .PHONY: $(MAIN).js all dev rpm build systemgo fs 69 | -------------------------------------------------------------------------------- /examples/meme-service/frontend/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /examples/meme-service/frontend/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /examples/meme-service/frontend/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # change these settings to your own preference 11 | indent_style = tab 12 | indent_size = 8 13 | 14 | # we recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | 23 | [{package,bower}.json] 24 | indent_style = space 25 | indent_size = 2 26 | -------------------------------------------------------------------------------- /examples/meme-service/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .tmp 4 | .sass-cache 5 | bower_components 6 | test/bower_components 7 | *~ 8 | /fs/index.json 9 | /fs/usr 10 | /app/kernel.js 11 | -------------------------------------------------------------------------------- /examples/meme-service/frontend/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-mocha": {} 3 | } -------------------------------------------------------------------------------- /examples/meme-service/frontend/app/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/examples/meme-service/frontend/app/apple-touch-icon.png -------------------------------------------------------------------------------- /examples/meme-service/frontend/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/examples/meme-service/frontend/app/favicon.ico -------------------------------------------------------------------------------- /examples/meme-service/frontend/app/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/examples/meme-service/frontend/app/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /examples/meme-service/frontend/app/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/examples/meme-service/frontend/app/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /examples/meme-service/frontend/app/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | Disallow: 5 | -------------------------------------------------------------------------------- /examples/meme-service/frontend/app/sw.js: -------------------------------------------------------------------------------- 1 | var CACHE_VERSION = 'v7'; 2 | 3 | this.addEventListener('install', function(event) { 4 | event.waitUntil( 5 | caches.open(CACHE_VERSION).then(function(cache) { 6 | console.log('populating cache ' + CACHE_VERSION); 7 | return cache.addAll([ 8 | // '/', 9 | '/?force-remote', 10 | '/?force-clientside', 11 | '/apple-touch-icon.png', 12 | '/favicon.ico', 13 | '/font-awesome.css', 14 | '/fonts/fontawesome-webfont.woff', 15 | '/fonts/fontawesome-webfont.woff?v=4.6.1', 16 | '/fonts/fontawesome-webfont.woff2', 17 | '/fonts/fontawesome-webfont.woff2?v=4.6.1', 18 | '/fs/font/impact.ttf', 19 | '/fs/img/gopher.png', 20 | '/fs/img/zoidberg.jpg', 21 | '/fs/index.json', 22 | '/fs/meme-service.js', 23 | '/index.html', 24 | '/kernel.js', 25 | '/robots.txt', 26 | // '/scripts/main.js', 27 | '/scripts/plugins.js', 28 | '/scripts/vendor.js', 29 | '/styles/main.css', 30 | ]); 31 | }) 32 | ); 33 | }); 34 | 35 | this.addEventListener('fetch', function(event) { 36 | event.respondWith(caches.match(event.request).catch(function() { 37 | return fetch(event.request); 38 | }).then(function(response) { 39 | if (response) { 40 | if (event.request.method === 'GET') { 41 | caches.open(CACHE_VERSION).then(function(cache) { 42 | cache.put(event.request, response); 43 | }); 44 | } 45 | return response.clone(); 46 | } else { 47 | return fetch(event.request.clone()).then(function(response) { 48 | return response; 49 | }); 50 | } 51 | }).catch(function(error) { 52 | // This catch() will handle exceptions that arise from 53 | // the match() or fetch() operations. Note that a 54 | // HTTP error response (e.g. 404) will NOT trigger an 55 | // exception. It will return a normal response object 56 | // that has the appropriate error code set. 57 | console.error(' Error in fetch handler:', error); 58 | })); 59 | }); 60 | -------------------------------------------------------------------------------- /examples/meme-service/frontend/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meme-frontend", 3 | "private": true, 4 | "dependencies": { 5 | "bootstrap-sass": "~3.3.6", 6 | "lodash": "^4.11.1" 7 | }, 8 | "overrides": { 9 | "bootstrap-sass": { 10 | "main": [ 11 | "assets/stylesheets/_bootstrap.scss", 12 | "assets/fonts/bootstrap/*", 13 | "assets/javascripts/bootstrap.js" 14 | ] 15 | } 16 | }, 17 | "devDependencies": { 18 | "chai": "^3.5.0", 19 | "mocha": "^2.4.5" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/meme-service/frontend/fs/etc/systemd/system/default.target: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Requires=server.service 3 | -------------------------------------------------------------------------------- /examples/meme-service/frontend/fs/etc/systemd/system/server.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=meme service 3 | After=syslog.target network.target 4 | 5 | [Service] 6 | ExecStart=/meme-service.js -bgdir=img -fontfile=font/impact.ttf 7 | ;WorkingDirectory=/ 8 | ;User=meme 9 | ;Restart=always 10 | ;RestartSec=0 11 | 12 | [Install] 13 | WantedBy=default.target 14 | -------------------------------------------------------------------------------- /examples/meme-service/frontend/fs/etc/systemgo/systemgo.yaml: -------------------------------------------------------------------------------- 1 | debug: false 2 | paths: 3 | - /etc/systemd/system 4 | -------------------------------------------------------------------------------- /examples/meme-service/frontend/fs/font/impact.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/examples/meme-service/frontend/fs/font/impact.ttf -------------------------------------------------------------------------------- /examples/meme-service/frontend/fs/img/gopher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/examples/meme-service/frontend/fs/img/gopher.png -------------------------------------------------------------------------------- /examples/meme-service/frontend/fs/img/j-walter-weatherman.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/examples/meme-service/frontend/fs/img/j-walter-weatherman.jpg -------------------------------------------------------------------------------- /examples/meme-service/frontend/fs/img/zoidberg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plasma-umass/browsix/04f0830088560f27d480cde3e37c28269375f59f/examples/meme-service/frontend/fs/img/zoidberg.jpg -------------------------------------------------------------------------------- /examples/meme-service/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "engines": { 4 | "node": ">=0.12.0" 5 | }, 6 | "devDependencies": { 7 | "babel-core": "^6.4.0", 8 | "babel-preset-es2015": "^6.3.13", 9 | "browser-sync": "^2.2.1", 10 | "del": "^2.2.1", 11 | "gulp": "^3.9.1", 12 | "gulp-autoprefixer": "^3.0.1", 13 | "gulp-babel": "^6.1.1", 14 | "gulp-cache": "^0.2.8", 15 | "gulp-cssnano": "^2.0.0", 16 | "gulp-eslint": "^3.0.1", 17 | "gulp-htmlmin": "^2.0.0", 18 | "gulp-if": "^1.2.5", 19 | "gulp-ignore": "^2.0.1", 20 | "gulp-imagemin": "^2.2.1", 21 | "gulp-load-plugins": "^0.10.0", 22 | "gulp-plumber": "^1.0.1", 23 | "gulp-rename": "^1.2.2", 24 | "gulp-run": "^1.6.12", 25 | "gulp-sass": "^2.0.0", 26 | "gulp-size": "^1.2.1", 27 | "gulp-sourcemaps": "^1.5.0", 28 | "gulp-uglify": "^1.5.4", 29 | "gulp-useref": "^3.0.0", 30 | "gulp-util": "^3.0.7", 31 | "main-bower-files": "^2.5.0", 32 | "proxy-middleware": "^0.15.0", 33 | "wiredep": "^4.0.0" 34 | }, 35 | "eslintConfig": { 36 | "env": { 37 | "es6": true, 38 | "node": true, 39 | "browser": true 40 | }, 41 | "rules": { 42 | "quotes": [ 43 | 2, 44 | "single" 45 | ] 46 | } 47 | }, 48 | "dependencies": { 49 | "browsix": "^0.9.0", 50 | "mobile-detect": "^1.3.2" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /examples/meme-service/frontend/test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mocha Spec Runner 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /examples/meme-service/frontend/test/spec/test.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | describe('Give it some context', function () { 5 | describe('maybe a bit more context here', function () { 6 | it('should run here few assertions', function () { 7 | 8 | }); 9 | }); 10 | }); 11 | })(); 12 | -------------------------------------------------------------------------------- /examples/meme-service/frontend/xhrfs-index: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // based on jvilk's XHRIndexer, but in plain JS using async APIs 3 | 4 | 'use strict'; 5 | 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | 9 | var exclude = [ 10 | /^\./, // dotfiles 11 | /^bower_components$/, 12 | /^node_modules$/, 13 | /^build$/, 14 | /^dist$/, 15 | /~$/, // emacs backups 16 | ]; 17 | 18 | function shouldExclude(name) { 19 | for (var i = 0; i < exclude.length; i++) { 20 | if (name.match(exclude[i])) 21 | return true; 22 | } 23 | return false; 24 | } 25 | 26 | var outstanding = 1; 27 | var tree = {}; 28 | 29 | function subtreeAt(relative) { 30 | if (!relative) 31 | return tree; 32 | 33 | var parts = relative.split(path.sep); 34 | var subtree = tree; 35 | // start at 1 to skip the leading / 36 | for (var i = 1; i < parts.length; i++) 37 | subtree = subtree[parts[i]]; 38 | 39 | return subtree; 40 | } 41 | 42 | function maybeFinished(file, err, onComplete) { 43 | if (--outstanding === 0) { 44 | onComplete(err, tree); 45 | } 46 | } 47 | 48 | function walkDir(base, curr, onComplete) { 49 | var parent = curr.slice(base.length); 50 | fs.readdir(curr, function(err, files) { 51 | if (err) { 52 | process.stderr.write('error reading dir: ' + err); 53 | maybeFinished(curr, err, onComplete); 54 | return; 55 | } 56 | for (var i = 0; i < files.length; i++) { 57 | var file = files[i]; 58 | if (shouldExclude(file)) 59 | continue; 60 | 61 | outstanding++; 62 | 63 | var absFile = path.join(curr, file) 64 | fs.stat(absFile, function statFile(absFile, err, stats) { 65 | if (err) { 66 | maybeFinished(absFile, err, onComplete); 67 | return; 68 | } 69 | var parts = absFile.split(path.sep); 70 | var file = parts[parts.length-1]; 71 | var subtree = subtreeAt(parent); 72 | if (stats.isDirectory()) { 73 | subtree[file] = {}; 74 | walkDir(base, absFile, onComplete); 75 | } else { 76 | subtree[file] = null; 77 | maybeFinished(absFile, null, onComplete); 78 | } 79 | }.bind(null, absFile)); 80 | } 81 | maybeFinished(curr, null, onComplete); 82 | }); 83 | } 84 | 85 | function main() { 86 | var pathToNode = process.argv[0]; 87 | var pathToScript = process.argv[1]; 88 | var args = process.argv.slice(2); 89 | 90 | var root = process.cwd(); 91 | if (args.length > 0) 92 | root = args[0]; 93 | 94 | walkDir(root, root, function writeJSON(err, tree) { 95 | if (err) { 96 | process.stderr.write('error: ' + err + '\n'); 97 | process.exit(-1); 98 | return; 99 | } 100 | process.stdout.write(JSON.stringify(tree) + '\n'); 101 | }); 102 | } 103 | 104 | main(); 105 | -------------------------------------------------------------------------------- /examples/meme-service/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Bobby Powers, portions copyright Michael Fogleman. 2 | 3 | package main 4 | 5 | import ( 6 | "flag" 7 | "io/ioutil" 8 | "log" 9 | "net/http" 10 | 11 | "github.com/golang/freetype/truetype" 12 | "golang.org/x/image/font" 13 | ) 14 | 15 | var ( 16 | addr = flag.String("addr", "127.0.0.1:8014", "address to listen on") 17 | dpi = flag.Float64("dpi", 144, "screen resolution in Dots Per Inch") 18 | fontfile = flag.String("fontfile", "./static/fs/font/impact.ttf", "filename of the ttf font") 19 | size = flag.Float64("size", 48, "font size in points") 20 | imgDir = flag.String("bgdir", "./static/fs/img", "directory where background images live") 21 | ) 22 | 23 | // from fogleman/gg 24 | func loadFontFace(path string, points float64) (font.Face, error) { 25 | fontBytes, err := ioutil.ReadFile(path) 26 | if err != nil { 27 | return nil, err 28 | } 29 | f, err := truetype.Parse(fontBytes) 30 | if err != nil { 31 | return nil, err 32 | } 33 | face := truetype.NewFace(f, &truetype.Options{ 34 | Size: points, 35 | Hinting: font.HintingFull, 36 | }) 37 | return face, nil 38 | } 39 | 40 | func main() { 41 | flag.Parse() 42 | 43 | ic := NewImageCache(*imgDir) 44 | 45 | font, err := loadFontFace(*fontfile, *size) 46 | if err != nil { 47 | log.Println(err) 48 | return 49 | } 50 | 51 | http.Handle("/api/v1/", http.StripPrefix("/api/v1/", NewHandler(ic, font))) 52 | http.Handle("/", http.FileServer(http.Dir("./static"))) 53 | 54 | log.Printf("ready and listening on %s", *addr) 55 | // start http server 56 | err = http.ListenAndServe(*addr, nil) 57 | if err != nil { 58 | log.Printf("ListenAndServe: %s", err) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /examples/meme-service/server.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=%NAME% service 3 | After=syslog.target network.target 4 | 5 | [Service] 6 | ExecStart=/opt/%NAME%/%NAME%-service 7 | WorkingDirectory=/opt/%NAME% 8 | User=%NAME% 9 | Restart=always 10 | RestartSec=0 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /examples/meme-service/server.spec.in: -------------------------------------------------------------------------------- 1 | %global basename %NAME% 2 | %global basedir /opt/%NAME% 3 | %global unitname %NAME%-service.service 4 | 5 | %define debug_package %{nil} 6 | 7 | Name: %NAME%-service 8 | Version: %VERSION% 9 | Release: 1%{?dist} 10 | Summary: %NAME% website server 11 | 12 | Group: System Environment/Applications 13 | License: MIT 14 | URL: https://meme.bpowers.net 15 | Source0: %{name}-%{version}.tar.gz 16 | Source1: server.service 17 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) 18 | 19 | Requires(pre): shadow-utils 20 | 21 | %description 22 | %NAME% Server & Assets 23 | 24 | %prep 25 | %setup 26 | 27 | %build 28 | 29 | %pre 30 | systemctl stop %{unitname} || true 31 | getent group %NAME% >/dev/null || groupadd -r %NAME% 32 | getent passwd %NAME% >/dev/null || \ 33 | useradd -r -g %NAME% -d %{basedir} -s /sbin/nologin \ 34 | -c "%NAME% server user" %NAME% 35 | exit 0 36 | 37 | %install 38 | rm -rf $RPM_BUILD_ROOT 39 | %{__install} -d -m 0755 $RPM_BUILD_ROOT%{_usr}/lib/systemd/system 40 | %{__install} -m 0644 %{SOURCE1} $RPM_BUILD_ROOT%{_usr}/lib/systemd/system/%{unitname} 41 | %{__install} -d -m 0755 $RPM_BUILD_ROOT%{basedir} 42 | %{__cp} -a * $RPM_BUILD_ROOT%{basedir} 43 | 44 | 45 | %post 46 | systemctl daemon-reload 47 | systemctl restart %{unitname} 48 | 49 | %clean 50 | rm -rf $RPM_BUILD_ROOT 51 | 52 | %files 53 | %defattr(-,%NAME%,%NAME%,-) 54 | /%{basedir} 55 | /usr/lib/systemd/system/%{unitname} 56 | 57 | %changelog 58 | -------------------------------------------------------------------------------- /examples/worker-latency/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | worker latency 6 | 7 | 8 | 9 | 10 |

worker communication latency test

11 |

12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/worker-latency/kernel.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var N = 200000; 3 | var PID = 3; 4 | 5 | var worker = undefined; 6 | var sequence = 1; 7 | 8 | function log(msg) { 9 | var el = document.getElementById('stdout'); 10 | el.innerHTML += msg + '
\n'; 11 | } 12 | 13 | function syscallHandler(e) { 14 | if (!e.data) { 15 | log('no data on syscall event'); 16 | return; 17 | } 18 | if (e.data.perf) { 19 | log(e.data.perf + ' μs'); 20 | return; 21 | } 22 | 23 | if (e.data.id !== sequence) 24 | log('sequence mismatch: ' + e.data.id + ' !== ' + sequence); 25 | 26 | worker.postMessage({ 27 | id: sequence++, 28 | pid: PID, 29 | }); 30 | 31 | if (sequence > N) { 32 | // todo: kill 33 | return; 34 | } 35 | } 36 | 37 | window.onload = function () { 38 | worker = new Worker('worker.js'); 39 | worker.onmessage = syscallHandler; 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /examples/worker-latency/worker.js: -------------------------------------------------------------------------------- 1 | 2 | var N = 200000; 3 | var PID = 3; 4 | var sequence = 0; 5 | var start = undefined; 6 | 7 | 8 | function log(msg) { 9 | console.log('worker: ' + msg); 10 | } 11 | 12 | self.onmessage = function(e) { 13 | if (!e.data) { 14 | log('no data on event'); 15 | return; 16 | } 17 | 18 | if (e.data.id !== sequence) 19 | log('sequence mismatch: ' + e.data.id + ' !== ' + sequence); 20 | if (e.data.pid !== PID) 21 | log('pid mismatch'); 22 | 23 | if (sequence === N) { 24 | log('DONE'); 25 | count = N - 1; 26 | end = performance.now(); 27 | log((end - start) / count); 28 | log(((end - start) / count) * 1000); 29 | self.postMessage({ 30 | perf: ((end - start) / count) * 1000, 31 | }); 32 | return; 33 | } 34 | 35 | self.postMessage({ 36 | id: ++sequence, 37 | }); 38 | 39 | } 40 | 41 | start = performance.now(); 42 | self.postMessage({ 43 | id: ++sequence, 44 | }); 45 | -------------------------------------------------------------------------------- /gulp-plugins/add-shebang.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var through = require('through2'); 4 | var gutil = require('gulp-util'); 5 | var util = require('util'); 6 | 7 | var PluginError = gutil.PluginError; 8 | var File = gutil.File; 9 | 10 | var PLUGIN_NAME = 'build-runtime'; 11 | 12 | function prefixStream(prefixText) { 13 | var stream = through(); 14 | stream.write(prefixText); 15 | return stream; 16 | } 17 | 18 | // based on gulp example: 19 | // https://github.com/gulpjs/gulp/blob/master/docs/writing-a-plugin/dealing-with-streams.md 20 | function addShebang(shebangText) { 21 | if (!shebangText) 22 | throw new PluginError(PLUGIN_NAME, 'Missing shebang'); 23 | else if (typeof shebangText !== 'string') 24 | throw new PluginError(PLUGIN_NAME, 'shebang arg should be string containing interpreter command'); 25 | 26 | var shebang = new Buffer(shebangText); 27 | 28 | var stream = through.obj(function(file, enc, cb) { 29 | if (file.isBuffer()) { 30 | file.contents = Buffer.concat([shebang, file.contents]); 31 | } 32 | 33 | if (file.isStream()) { 34 | var streamer = prefixStream(shebang); 35 | streamer.on('error', this.emit.bind(this, 'error')); 36 | file.contents = file.contents.pipe(streamer); 37 | } 38 | 39 | this.push(file); 40 | cb(); 41 | }); 42 | 43 | return stream; 44 | } 45 | 46 | module.exports = addShebang; 47 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Fri Oct 02 2015 10:32:16 GMT-0400 (EDT) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | // base path that will be used to resolve all patterns (eg. files, exclude) 7 | basePath: '.', 8 | 9 | 10 | // frameworks to use 11 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 12 | frameworks: ['mocha'], 13 | 14 | 15 | // list of files / patterns to load in the browser 16 | files: [ 17 | 'lib-dist/test/*.js', 18 | { 19 | pattern: 'fs/**/*', 20 | included: false, 21 | nocache: true, 22 | }, 23 | ], 24 | 25 | proxies: { 26 | }, 27 | 28 | 29 | // list of files to exclude 30 | exclude: [ 31 | ], 32 | 33 | 34 | // preprocess matching files before serving them to the browser 35 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 36 | preprocessors: { 37 | }, 38 | 39 | 40 | // test results reporter to use 41 | // possible values: 'dots', 'progress' 42 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 43 | reporters: ['progress'], 44 | 45 | 46 | // web server port 47 | port: 9876, 48 | 49 | 50 | // enable / disable colors in the output (reporters and logs) 51 | colors: true, 52 | 53 | 54 | // level of logging 55 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 56 | logLevel: config.LOG_INFO, 57 | 58 | 59 | // enable / disable watching file and executing tests whenever any file changes 60 | autoWatch: true, 61 | 62 | 63 | // start these browsers 64 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 65 | browsers: [], 66 | 67 | 68 | // Continuous Integration mode 69 | // if true, Karma captures browsers, runs the tests and exits 70 | singleRun: false 71 | }) 72 | } 73 | -------------------------------------------------------------------------------- /node/fix_paths.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # make all paths relative 4 | find . -name '*.js' | xargs perl -pi -e "s/require\('/require('.\//" 5 | 6 | # remove const + let 7 | find . -name '*.js' | xargs perl -pi -e 's/^(\s*)const\s/$1var /' 8 | find . -name '*.js' | xargs perl -pi -e 's/^(\s*)let\s/$1var /' 9 | find . -name '*.js' | xargs perl -pi -e 's/for\s*\(let\s/for (var /' 10 | -------------------------------------------------------------------------------- /node/lib/_linklist.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function init(list) { 4 | list._idleNext = list; 5 | list._idlePrev = list; 6 | } 7 | exports.init = init; 8 | 9 | 10 | // show the most idle item 11 | function peek(list) { 12 | if (list._idlePrev == list) return null; 13 | return list._idlePrev; 14 | } 15 | exports.peek = peek; 16 | 17 | 18 | // remove the most idle item from the list 19 | function shift(list) { 20 | var first = list._idlePrev; 21 | remove(first); 22 | return first; 23 | } 24 | exports.shift = shift; 25 | 26 | 27 | // remove a item from its list 28 | function remove(item) { 29 | if (item._idleNext) { 30 | item._idleNext._idlePrev = item._idlePrev; 31 | } 32 | 33 | if (item._idlePrev) { 34 | item._idlePrev._idleNext = item._idleNext; 35 | } 36 | 37 | item._idleNext = null; 38 | item._idlePrev = null; 39 | } 40 | exports.remove = remove; 41 | 42 | 43 | // remove a item from its list and place at the end. 44 | function append(list, item) { 45 | remove(item); 46 | item._idleNext = list._idleNext; 47 | list._idleNext._idlePrev = item; 48 | item._idlePrev = list; 49 | list._idleNext = item; 50 | } 51 | exports.append = append; 52 | 53 | 54 | function isEmpty(list) { 55 | return list._idleNext === list; 56 | } 57 | exports.isEmpty = isEmpty; 58 | -------------------------------------------------------------------------------- /node/lib/_stream_duplex.js: -------------------------------------------------------------------------------- 1 | // a duplex stream is just a stream that is both readable and writable. 2 | // Since JS doesn't have multiple prototypal inheritance, this class 3 | // prototypally inherits from Readable, and then parasitically from 4 | // Writable. 5 | 6 | 'use strict'; 7 | 8 | module.exports = Duplex; 9 | 10 | var util = require('./util'); 11 | var Readable = require('./_stream_readable'); 12 | var Writable = require('./_stream_writable'); 13 | 14 | util.inherits(Duplex, Readable); 15 | 16 | var keys = Object.keys(Writable.prototype); 17 | for (var v = 0; v < keys.length; v++) { 18 | var method = keys[v]; 19 | if (!Duplex.prototype[method]) 20 | Duplex.prototype[method] = Writable.prototype[method]; 21 | } 22 | 23 | function Duplex(options) { 24 | if (!(this instanceof Duplex)) 25 | return new Duplex(options); 26 | 27 | Readable.call(this, options); 28 | Writable.call(this, options); 29 | 30 | if (options && options.readable === false) 31 | this.readable = false; 32 | 33 | if (options && options.writable === false) 34 | this.writable = false; 35 | 36 | this.allowHalfOpen = true; 37 | if (options && options.allowHalfOpen === false) 38 | this.allowHalfOpen = false; 39 | 40 | this.once('end', onend); 41 | } 42 | 43 | // the no-half-open enforcer 44 | function onend() { 45 | // if we allow half-open state, or if the writable side ended, 46 | // then we're ok. 47 | if (this.allowHalfOpen || this._writableState.ended) 48 | return; 49 | 50 | // no more data can be written. 51 | // But allow more writes to happen in this tick. 52 | process.nextTick(onEndNT, this); 53 | } 54 | 55 | function onEndNT(self) { 56 | self.end(); 57 | } 58 | -------------------------------------------------------------------------------- /node/lib/_stream_passthrough.js: -------------------------------------------------------------------------------- 1 | // a passthrough stream. 2 | // basically just the most minimal sort of Transform stream. 3 | // Every written chunk gets output as-is. 4 | 5 | 'use strict'; 6 | 7 | module.exports = PassThrough; 8 | 9 | var Transform = require('./_stream_transform'); 10 | var util = require('./util'); 11 | util.inherits(PassThrough, Transform); 12 | 13 | function PassThrough(options) { 14 | if (!(this instanceof PassThrough)) 15 | return new PassThrough(options); 16 | 17 | Transform.call(this, options); 18 | } 19 | 20 | PassThrough.prototype._transform = function(chunk, encoding, cb) { 21 | cb(null, chunk); 22 | }; 23 | -------------------------------------------------------------------------------- /node/lib/console.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('./util'); 4 | 5 | function Console(stdout, stderr) { 6 | if (!(this instanceof Console)) { 7 | return new Console(stdout, stderr); 8 | } 9 | if (!stdout || typeof stdout.write !== 'function') { 10 | throw new TypeError('Console expects a writable stream instance'); 11 | } 12 | if (!stderr) { 13 | stderr = stdout; 14 | } 15 | var prop = { 16 | writable: true, 17 | enumerable: false, 18 | configurable: true 19 | }; 20 | prop.value = stdout; 21 | Object.defineProperty(this, '_stdout', prop); 22 | prop.value = stderr; 23 | Object.defineProperty(this, '_stderr', prop); 24 | prop.value = new Map(); 25 | Object.defineProperty(this, '_times', prop); 26 | 27 | // bind the prototype functions to this Console instance 28 | var keys = Object.keys(Console.prototype); 29 | for (var v = 0; v < keys.length; v++) { 30 | var k = keys[v]; 31 | this[k] = this[k].bind(this); 32 | } 33 | } 34 | 35 | Console.prototype.log = function() { 36 | this._stdout.write(util.format.apply(this, arguments) + '\n'); 37 | }; 38 | 39 | 40 | Console.prototype.info = Console.prototype.log; 41 | 42 | 43 | Console.prototype.warn = function() { 44 | this._stderr.write(util.format.apply(this, arguments) + '\n'); 45 | }; 46 | 47 | 48 | Console.prototype.error = Console.prototype.warn; 49 | 50 | 51 | Console.prototype.dir = function(object, options) { 52 | this._stdout.write(util.inspect(object, util._extend({ 53 | customInspect: false 54 | }, options)) + '\n'); 55 | }; 56 | 57 | 58 | Console.prototype.time = function(label) { 59 | this._times.set(label, Date.now()); 60 | }; 61 | 62 | 63 | Console.prototype.timeEnd = function(label) { 64 | var time = this._times.get(label); 65 | if (!time) { 66 | throw new Error('No such label: ' + label); 67 | } 68 | var duration = Date.now() - time; 69 | this.log('%s: %dms', label, duration); 70 | }; 71 | 72 | 73 | Console.prototype.trace = function trace() { 74 | // TODO probably can to do this better with V8's debug object once that is 75 | // exposed. 76 | var err = new Error(); 77 | err.name = 'Trace'; 78 | err.message = util.format.apply(this, arguments); 79 | Error.captureStackTrace(err, trace); 80 | this.error(err.stack); 81 | }; 82 | 83 | 84 | Console.prototype.assert = function(expression) { 85 | if (!expression) { 86 | var arr = Array.prototype.slice.call(arguments, 1); 87 | require('./assert').ok(false, util.format.apply(this, arr)); 88 | } 89 | }; 90 | 91 | 92 | module.exports = new Console(process.stdout, process.stderr); 93 | module.exports.Console = Console; 94 | -------------------------------------------------------------------------------- /node/lib/constants.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = process.binding('constants'); 4 | -------------------------------------------------------------------------------- /node/lib/freelist.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('./internal/util'); 4 | 5 | module.exports = require('./internal/freelist'); 6 | util.printDeprecationMessage('freelist module is deprecated.'); 7 | -------------------------------------------------------------------------------- /node/lib/http.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('./util'); 4 | var internalUtil = require('./internal/util'); 5 | var EventEmitter = require('./events'); 6 | 7 | 8 | exports.IncomingMessage = require('./_http_incoming').IncomingMessage; 9 | 10 | 11 | var common = require('./_http_common'); 12 | exports.METHODS = common.methods.slice().sort(); 13 | 14 | 15 | exports.OutgoingMessage = require('./_http_outgoing').OutgoingMessage; 16 | 17 | 18 | var server = require('./_http_server'); 19 | exports.ServerResponse = server.ServerResponse; 20 | exports.STATUS_CODES = server.STATUS_CODES; 21 | 22 | 23 | var agent = require('./_http_agent'); 24 | var Agent = exports.Agent = agent.Agent; 25 | exports.globalAgent = agent.globalAgent; 26 | 27 | var client = require('./_http_client'); 28 | var ClientRequest = exports.ClientRequest = client.ClientRequest; 29 | 30 | exports.request = function(options, cb) { 31 | return new ClientRequest(options, cb); 32 | }; 33 | 34 | exports.get = function(options, cb) { 35 | var req = exports.request(options, cb); 36 | req.end(); 37 | return req; 38 | }; 39 | 40 | exports._connectionListener = server._connectionListener; 41 | var Server = exports.Server = server.Server; 42 | 43 | exports.createServer = function(requestListener) { 44 | return new Server(requestListener); 45 | }; 46 | 47 | 48 | // Legacy Interface 49 | 50 | function Client(port, host) { 51 | if (!(this instanceof Client)) return new Client(port, host); 52 | EventEmitter.call(this); 53 | 54 | host = host || 'localhost'; 55 | port = port || 80; 56 | this.host = host; 57 | this.port = port; 58 | this.agent = new Agent({ host: host, port: port, maxSockets: 1 }); 59 | } 60 | util.inherits(Client, EventEmitter); 61 | Client.prototype.request = function(method, path, headers) { 62 | var self = this; 63 | var options = {}; 64 | options.host = self.host; 65 | options.port = self.port; 66 | if (method[0] === '/') { 67 | headers = path; 68 | path = method; 69 | method = 'GET'; 70 | } 71 | options.method = method; 72 | options.path = path; 73 | options.headers = headers; 74 | options.agent = self.agent; 75 | var c = new ClientRequest(options); 76 | c.on('error', function(e) { 77 | self.emit('error', e); 78 | }); 79 | // The old Client interface emitted 'end' on socket end. 80 | // This doesn't map to how we want things to operate in the future 81 | // but it will get removed when we remove this legacy interface. 82 | c.on('socket', function(s) { 83 | s.on('end', function() { 84 | if (self._decoder) { 85 | var ret = self._decoder.end(); 86 | if (ret) 87 | self.emit('data', ret); 88 | } 89 | self.emit('end'); 90 | }); 91 | }); 92 | return c; 93 | }; 94 | 95 | exports.Client = internalUtil.deprecate(Client, 'http.Client is deprecated.'); 96 | 97 | exports.createClient = internalUtil.deprecate(function(port, host) { 98 | return new Client(port, host); 99 | }, 'http.createClient is deprecated. Use http.request instead.'); 100 | -------------------------------------------------------------------------------- /node/lib/internal/freelist.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This is a free list to avoid creating so many of the same object. 4 | exports.FreeList = function(name, max, constructor) { 5 | this.name = name; 6 | this.constructor = constructor; 7 | this.max = max; 8 | this.list = []; 9 | }; 10 | 11 | 12 | exports.FreeList.prototype.alloc = function() { 13 | return this.list.length ? this.list.shift() : 14 | this.constructor.apply(this, arguments); 15 | }; 16 | 17 | 18 | exports.FreeList.prototype.free = function(obj) { 19 | if (this.list.length < this.max) { 20 | this.list.push(obj); 21 | return true; 22 | } 23 | return false; 24 | }; 25 | -------------------------------------------------------------------------------- /node/lib/internal/module.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports.stripBOM = stripBOM; 4 | 5 | /** 6 | * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) 7 | * because the buffer-to-string conversion in `fs.readFileSync()` 8 | * translates it to FEFF, the UTF-16 BOM. 9 | */ 10 | function stripBOM(content) { 11 | if (content.charCodeAt(0) === 0xFEFF) { 12 | content = content.slice(1); 13 | } 14 | return content; 15 | } 16 | -------------------------------------------------------------------------------- /node/lib/internal/readme.md: -------------------------------------------------------------------------------- 1 | # Internal Modules 2 | 3 | The modules in `lib/internal` are intended for internal use in Node.js core only, and are not accessible with `require()` from user modules. 4 | These are subject to change at **any** time. Reliance on these modules outside of core is **not supported** in any way. 5 | -------------------------------------------------------------------------------- /node/lib/internal/socket_list.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = {SocketListSend, SocketListReceive}; 4 | 5 | var EventEmitter = require('./events'); 6 | var util = require('./util'); 7 | 8 | // This object keep track of the socket there are sended 9 | function SocketListSend(slave, key) { 10 | EventEmitter.call(this); 11 | 12 | this.key = key; 13 | this.slave = slave; 14 | } 15 | util.inherits(SocketListSend, EventEmitter); 16 | 17 | SocketListSend.prototype._request = function(msg, cmd, callback) { 18 | var self = this; 19 | 20 | if (!this.slave.connected) return onclose(); 21 | this.slave.send(msg); 22 | 23 | function onclose() { 24 | self.slave.removeListener('internalMessage', onreply); 25 | callback(new Error('Slave closed before reply')); 26 | } 27 | 28 | function onreply(msg) { 29 | if (!(msg.cmd === cmd && msg.key === self.key)) return; 30 | self.slave.removeListener('disconnect', onclose); 31 | self.slave.removeListener('internalMessage', onreply); 32 | 33 | callback(null, msg); 34 | } 35 | 36 | this.slave.once('disconnect', onclose); 37 | this.slave.on('internalMessage', onreply); 38 | }; 39 | 40 | SocketListSend.prototype.close = function close(callback) { 41 | this._request({ 42 | cmd: 'NODE_SOCKET_NOTIFY_CLOSE', 43 | key: this.key 44 | }, 'NODE_SOCKET_ALL_CLOSED', callback); 45 | }; 46 | 47 | SocketListSend.prototype.getConnections = function getConnections(callback) { 48 | this._request({ 49 | cmd: 'NODE_SOCKET_GET_COUNT', 50 | key: this.key 51 | }, 'NODE_SOCKET_COUNT', function(err, msg) { 52 | if (err) return callback(err); 53 | callback(null, msg.count); 54 | }); 55 | }; 56 | 57 | // This object keep track of the socket there are received 58 | function SocketListReceive(slave, key) { 59 | EventEmitter.call(this); 60 | 61 | var self = this; 62 | 63 | this.connections = 0; 64 | this.key = key; 65 | this.slave = slave; 66 | 67 | function onempty() { 68 | if (!self.slave.connected) return; 69 | 70 | self.slave.send({ 71 | cmd: 'NODE_SOCKET_ALL_CLOSED', 72 | key: self.key 73 | }); 74 | } 75 | 76 | this.slave.on('internalMessage', function(msg) { 77 | if (msg.key !== self.key) return; 78 | 79 | if (msg.cmd === 'NODE_SOCKET_NOTIFY_CLOSE') { 80 | // Already empty 81 | if (self.connections === 0) return onempty(); 82 | 83 | // Wait for sockets to get closed 84 | self.once('empty', onempty); 85 | } else if (msg.cmd === 'NODE_SOCKET_GET_COUNT') { 86 | if (!self.slave.connected) return; 87 | self.slave.send({ 88 | cmd: 'NODE_SOCKET_COUNT', 89 | key: self.key, 90 | count: self.connections 91 | }); 92 | } 93 | }); 94 | } 95 | util.inherits(SocketListReceive, EventEmitter); 96 | 97 | SocketListReceive.prototype.add = function(obj) { 98 | var self = this; 99 | 100 | this.connections++; 101 | 102 | // Notify previous owner of socket about its state change 103 | obj.socket.once('close', function() { 104 | self.connections--; 105 | 106 | if (self.connections === 0) self.emit('empty'); 107 | }); 108 | }; 109 | -------------------------------------------------------------------------------- /node/lib/internal/streams/lazy_transform.js: -------------------------------------------------------------------------------- 1 | // LazyTransform is a special type of Transform stream that is lazily loaded. 2 | // This is used for performance with bi-API-ship: when two APIs are available 3 | // for the stream, one conventional and one non-conventional. 4 | 'use strict'; 5 | 6 | var stream = require('./stream'); 7 | var util = require('./util'); 8 | 9 | module.exports = LazyTransform; 10 | 11 | function LazyTransform(options) { 12 | this._options = options; 13 | } 14 | util.inherits(LazyTransform, stream.Transform); 15 | 16 | [ 17 | '_readableState', 18 | '_writableState', 19 | '_transformState' 20 | ].forEach(function(prop, i, props) { 21 | Object.defineProperty(LazyTransform.prototype, prop, { 22 | get: function() { 23 | stream.Transform.call(this, this._options); 24 | this._writableState.decodeStrings = false; 25 | this._writableState.defaultEncoding = 'binary'; 26 | return this[prop]; 27 | }, 28 | set: function(val) { 29 | Object.defineProperty(this, prop, { 30 | value: val, 31 | enumerable: true, 32 | configurable: true, 33 | writable: true 34 | }); 35 | }, 36 | configurable: true, 37 | enumerable: true 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /node/lib/internal/util.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var prefix = '(node) '; 4 | 5 | // All the internal deprecations have to use this function only, as this will 6 | // prepend the prefix to the actual message. 7 | exports.deprecate = function(fn, msg) { 8 | return exports._deprecate(fn, `${prefix}${msg}`); 9 | }; 10 | 11 | // All the internal deprecations have to use this function only, as this will 12 | // prepend the prefix to the actual message. 13 | exports.printDeprecationMessage = function(msg, warned) { 14 | return exports._printDeprecationMessage(`${prefix}${msg}`, warned); 15 | }; 16 | 17 | exports._printDeprecationMessage = function(msg, warned) { 18 | if (process.noDeprecation) 19 | return true; 20 | 21 | if (warned) 22 | return warned; 23 | 24 | if (process.throwDeprecation) 25 | throw new Error(msg); 26 | else if (process.traceDeprecation) 27 | console.trace(msg.startsWith(prefix) ? msg.replace(prefix, '') : msg); 28 | else 29 | console.error(msg); 30 | 31 | return true; 32 | }; 33 | 34 | // Mark that a method should not be used. 35 | // Returns a modified function which warns once by default. 36 | // If --no-deprecation is set, then it is a no-op. 37 | exports._deprecate = function(fn, msg) { 38 | // Allow for deprecating things in the process of starting up. 39 | if (global.process === undefined) { 40 | return function() { 41 | return exports._deprecate(fn, msg).apply(this, arguments); 42 | }; 43 | } 44 | 45 | if (process.noDeprecation === true) { 46 | return fn; 47 | } 48 | 49 | var warned = false; 50 | function deprecated() { 51 | warned = exports._printDeprecationMessage(msg, warned); 52 | return fn.apply(this, arguments); 53 | } 54 | 55 | return deprecated; 56 | }; 57 | -------------------------------------------------------------------------------- /node/lib/os.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var binding = process.binding('os'); 4 | var util = require('./util'); 5 | var internalUtil = require('./internal/util'); 6 | var isWindows = process.platform === 'win32'; 7 | 8 | exports.hostname = binding.getHostname; 9 | exports.loadavg = binding.getLoadAvg; 10 | exports.uptime = binding.getUptime; 11 | exports.freemem = binding.getFreeMem; 12 | exports.totalmem = binding.getTotalMem; 13 | exports.cpus = binding.getCPUs; 14 | exports.type = binding.getOSType; 15 | exports.release = binding.getOSRelease; 16 | exports.networkInterfaces = binding.getInterfaceAddresses; 17 | exports.homedir = binding.getHomeDirectory; 18 | 19 | 20 | exports.arch = function() { 21 | return process.arch; 22 | }; 23 | 24 | exports.platform = function() { 25 | return process.platform; 26 | }; 27 | 28 | var trailingSlashRe = isWindows ? /[^:]\\$/ 29 | : /.\/$/; 30 | 31 | exports.tmpdir = function() { 32 | var path; 33 | if (isWindows) { 34 | path = process.env.TEMP || 35 | process.env.TMP || 36 | (process.env.SystemRoot || process.env.windir) + '\\temp'; 37 | } else { 38 | path = process.env.TMPDIR || 39 | process.env.TMP || 40 | process.env.TEMP || 41 | '/tmp'; 42 | } 43 | if (trailingSlashRe.test(path)) 44 | path = path.slice(0, -1); 45 | return path; 46 | }; 47 | 48 | exports.tmpDir = exports.tmpdir; 49 | 50 | exports.getNetworkInterfaces = internalUtil.deprecate(function() { 51 | return exports.networkInterfaces(); 52 | }, 'os.getNetworkInterfaces is deprecated. ' + 53 | 'Use os.networkInterfaces instead.'); 54 | 55 | exports.EOL = isWindows ? '\r\n' : '\n'; 56 | 57 | if (binding.isBigEndian) 58 | exports.endianness = function() { return 'BE'; }; 59 | else 60 | exports.endianness = function() { return 'LE'; }; 61 | -------------------------------------------------------------------------------- /node/lib/process.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Re-export process as a native module 4 | module.exports = process; 5 | -------------------------------------------------------------------------------- /node/lib/stream.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = Stream; 4 | 5 | var EE = require('./events'); 6 | var util = require('./util'); 7 | 8 | util.inherits(Stream, EE); 9 | Stream.Readable = require('./_stream_readable'); 10 | Stream.Writable = require('./_stream_writable'); 11 | Stream.Duplex = require('./_stream_duplex'); 12 | Stream.Transform = require('./_stream_transform'); 13 | Stream.PassThrough = require('./_stream_passthrough'); 14 | 15 | // Backwards-compat with node 0.4.x 16 | Stream.Stream = Stream; 17 | 18 | 19 | // old-style streams. Note that the pipe method (the only relevant 20 | // part of this class) is overridden in the Readable class. 21 | 22 | function Stream() { 23 | EE.call(this); 24 | } 25 | 26 | Stream.prototype.pipe = function(dest, options) { 27 | var source = this; 28 | 29 | function ondata(chunk) { 30 | if (dest.writable) { 31 | if (false === dest.write(chunk) && source.pause) { 32 | source.pause(); 33 | } 34 | } 35 | } 36 | 37 | source.on('data', ondata); 38 | 39 | function ondrain() { 40 | if (source.readable && source.resume) { 41 | source.resume(); 42 | } 43 | } 44 | 45 | dest.on('drain', ondrain); 46 | 47 | // If the 'end' option is not supplied, dest.end() will be called when 48 | // source gets the 'end' or 'close' events. Only dest.end() once. 49 | if (!dest._isStdio && (!options || options.end !== false)) { 50 | source.on('end', onend); 51 | source.on('close', onclose); 52 | } 53 | 54 | var didOnEnd = false; 55 | function onend() { 56 | if (didOnEnd) return; 57 | didOnEnd = true; 58 | 59 | dest.end(); 60 | } 61 | 62 | 63 | function onclose() { 64 | if (didOnEnd) return; 65 | didOnEnd = true; 66 | 67 | if (typeof dest.destroy === 'function') dest.destroy(); 68 | } 69 | 70 | // don't leave dangling pipes when there are errors. 71 | function onerror(er) { 72 | cleanup(); 73 | if (EE.listenerCount(this, 'error') === 0) { 74 | throw er; // Unhandled stream error in pipe. 75 | } 76 | } 77 | 78 | source.on('error', onerror); 79 | dest.on('error', onerror); 80 | 81 | // remove all the event listeners that were added. 82 | function cleanup() { 83 | source.removeListener('data', ondata); 84 | dest.removeListener('drain', ondrain); 85 | 86 | source.removeListener('end', onend); 87 | source.removeListener('close', onclose); 88 | 89 | source.removeListener('error', onerror); 90 | dest.removeListener('error', onerror); 91 | 92 | source.removeListener('end', cleanup); 93 | source.removeListener('close', cleanup); 94 | 95 | dest.removeListener('close', cleanup); 96 | } 97 | 98 | source.on('end', cleanup); 99 | source.on('close', cleanup); 100 | 101 | dest.on('close', cleanup); 102 | 103 | dest.emit('pipe', source); 104 | 105 | // Allow for unix-like usage: A.pipe(B).pipe(C) 106 | return dest; 107 | }; 108 | -------------------------------------------------------------------------------- /node/lib/sys.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('./internal/util'); 4 | 5 | // the sys module was renamed to 'util'. 6 | // this shim remains to keep old programs working. 7 | // sys is deprecated and shouldn't be used 8 | 9 | module.exports = require('./util'); 10 | util.printDeprecationMessage('sys is deprecated. Use util instead.'); 11 | -------------------------------------------------------------------------------- /node/lib/tty.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('./util'); 4 | var internalUtil = require('./internal/util'); 5 | var net = require('./net'); 6 | var TTY = process.binding('tty_wrap').TTY; 7 | var isTTY = process.binding('tty_wrap').isTTY; 8 | var inherits = util.inherits; 9 | var errnoException = util._errnoException; 10 | 11 | 12 | exports.isatty = function(fd) { 13 | return isTTY(fd); 14 | }; 15 | 16 | 17 | // backwards-compat 18 | exports.setRawMode = internalUtil.deprecate(function(flag) { 19 | if (!process.stdin.isTTY) { 20 | throw new Error('can\'t set raw mode on non-tty'); 21 | } 22 | process.stdin.setRawMode(flag); 23 | }, 'tty.setRawMode is deprecated. ' + 24 | 'Use process.stdin.setRawMode instead.'); 25 | 26 | 27 | function ReadStream(fd, options) { 28 | if (!(this instanceof ReadStream)) 29 | return new ReadStream(fd, options); 30 | 31 | options = util._extend({ 32 | highWaterMark: 0, 33 | readable: true, 34 | writable: false, 35 | handle: new TTY(fd, true) 36 | }, options); 37 | 38 | net.Socket.call(this, options); 39 | 40 | this.isRaw = false; 41 | this.isTTY = true; 42 | } 43 | inherits(ReadStream, net.Socket); 44 | 45 | exports.ReadStream = ReadStream; 46 | 47 | ReadStream.prototype.setRawMode = function(flag) { 48 | flag = !!flag; 49 | this._handle.setRawMode(flag); 50 | this.isRaw = flag; 51 | }; 52 | 53 | 54 | function WriteStream(fd) { 55 | if (!(this instanceof WriteStream)) return new WriteStream(fd); 56 | net.Socket.call(this, { 57 | handle: new TTY(fd, false), 58 | readable: false, 59 | writable: true 60 | }); 61 | 62 | var winSize = []; 63 | var err = this._handle.getWindowSize(winSize); 64 | if (!err) { 65 | this.columns = winSize[0]; 66 | this.rows = winSize[1]; 67 | } 68 | } 69 | inherits(WriteStream, net.Socket); 70 | exports.WriteStream = WriteStream; 71 | 72 | 73 | WriteStream.prototype.isTTY = true; 74 | 75 | 76 | WriteStream.prototype._refreshSize = function() { 77 | var oldCols = this.columns; 78 | var oldRows = this.rows; 79 | var winSize = []; 80 | var err = this._handle.getWindowSize(winSize); 81 | if (err) { 82 | this.emit('error', errnoException(err, 'getWindowSize')); 83 | return; 84 | } 85 | var newCols = winSize[0]; 86 | var newRows = winSize[1]; 87 | if (oldCols !== newCols || oldRows !== newRows) { 88 | this.columns = newCols; 89 | this.rows = newRows; 90 | this.emit('resize'); 91 | } 92 | }; 93 | 94 | 95 | // backwards-compat 96 | WriteStream.prototype.cursorTo = function(x, y) { 97 | require('./readline').cursorTo(this, x, y); 98 | }; 99 | WriteStream.prototype.moveCursor = function(dx, dy) { 100 | require('./readline').moveCursor(this, dx, dy); 101 | }; 102 | WriteStream.prototype.clearLine = function(dir) { 103 | require('./readline').clearLine(this, dir); 104 | }; 105 | WriteStream.prototype.clearScreenDown = function() { 106 | require('./readline').clearScreenDown(this); 107 | }; 108 | WriteStream.prototype.getWindowSize = function() { 109 | return [this.columns, this.rows]; 110 | }; 111 | -------------------------------------------------------------------------------- /node/lib/v8.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, StrongLoop Inc. 2 | // 3 | // Permission to use, copy, modify, and/or distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | 'use strict'; 16 | 17 | var v8binding = process.binding('v8'); 18 | 19 | var heapStatisticsBuffer = 20 | new Uint32Array(v8binding.heapStatisticsArrayBuffer); 21 | 22 | var kTotalHeapSizeIndex = v8binding.kTotalHeapSizeIndex; 23 | var kTotalHeapSizeExecutableIndex = v8binding.kTotalHeapSizeExecutableIndex; 24 | var kTotalPhysicalSizeIndex = v8binding.kTotalPhysicalSizeIndex; 25 | var kTotalAvailableSize = v8binding.kTotalAvailableSize; 26 | var kUsedHeapSizeIndex = v8binding.kUsedHeapSizeIndex; 27 | var kHeapSizeLimitIndex = v8binding.kHeapSizeLimitIndex; 28 | 29 | exports.getHeapStatistics = function() { 30 | var buffer = heapStatisticsBuffer; 31 | 32 | v8binding.updateHeapStatisticsArrayBuffer(); 33 | 34 | return { 35 | 'total_heap_size': buffer[kTotalHeapSizeIndex], 36 | 'total_heap_size_executable': buffer[kTotalHeapSizeExecutableIndex], 37 | 'total_physical_size': buffer[kTotalPhysicalSizeIndex], 38 | 'total_available_size': buffer[kTotalAvailableSize], 39 | 'used_heap_size': buffer[kUsedHeapSizeIndex], 40 | 'heap_size_limit': buffer[kHeapSizeLimitIndex] 41 | }; 42 | }; 43 | 44 | exports.setFlagsFromString = v8binding.setFlagsFromString; 45 | -------------------------------------------------------------------------------- /node/lib/vm.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var binding = process.binding('contextify'); 4 | var Script = binding.ContextifyScript; 5 | 6 | // The binding provides a few useful primitives: 7 | // - ContextifyScript(code, { filename = "evalmachine.anonymous", 8 | // displayErrors = true } = {}) 9 | // with methods: 10 | // - runInThisContext({ displayErrors = true } = {}) 11 | // - runInContext(sandbox, { displayErrors = true, timeout = undefined } = {}) 12 | // - makeContext(sandbox) 13 | // - isContext(sandbox) 14 | // From this we build the entire documented API. 15 | 16 | Script.prototype.runInNewContext = function(sandbox, options) { 17 | var context = exports.createContext(sandbox); 18 | return this.runInContext(context, options); 19 | }; 20 | 21 | exports.Script = Script; 22 | 23 | exports.createScript = function(code, options) { 24 | return new Script(code, options); 25 | }; 26 | 27 | exports.createContext = function(sandbox) { 28 | if (sandbox === undefined) { 29 | sandbox = {}; 30 | } else if (binding.isContext(sandbox)) { 31 | return sandbox; 32 | } 33 | 34 | binding.makeContext(sandbox); 35 | return sandbox; 36 | }; 37 | 38 | exports.runInDebugContext = function(code) { 39 | return binding.runInDebugContext(code); 40 | }; 41 | 42 | exports.runInContext = function(code, contextifiedSandbox, options) { 43 | var script = new Script(code, options); 44 | return script.runInContext(contextifiedSandbox, options); 45 | }; 46 | 47 | exports.runInNewContext = function(code, sandbox, options) { 48 | var script = new Script(code, options); 49 | return script.runInNewContext(sandbox, options); 50 | }; 51 | 52 | exports.runInThisContext = function(code, options) { 53 | var script = new Script(code, options); 54 | return script.runInThisContext(options); 55 | }; 56 | 57 | exports.isContext = binding.isContext; 58 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "browsix", 3 | "version": "0.9.2", 4 | "description": "in-browser, multi-process operating system", 5 | "main": "lib/kernel/kernel.js", 6 | "scripts": { 7 | "prepublishOnly": "node_modules/.bin/gulp build:dist", 8 | "test": "node_modules/.bin/gulp test-once" 9 | }, 10 | "repository": { 11 | "url": "https://github.com/plasma-umass/browsix.git" 12 | }, 13 | "license": "MIT", 14 | "bugs": { 15 | "url": "https://github.com/plasma-umass/browsix/issues" 16 | }, 17 | "homepage": "https://github.com/plasma-umass/browsix", 18 | "devDependencies": { 19 | "bfs-buffer": "^0.1.7", 20 | "bfs-path": "^0.1.2", 21 | "bower": "^1.8.8", 22 | "browser-sync": "^2.13.0", 23 | "browserfs-browsix-tmp": "0.5.15", 24 | "browserify": "^13.0.1", 25 | "chai": "^4.0.2", 26 | "connect-history-api-fallback": "^1.1.0", 27 | "del": "^3.0.0", 28 | "express": "^4.16.4", 29 | "gulp": "^3.9.1", 30 | "gulp-autoprefixer": "^4.0.0", 31 | "gulp-cache": "^0.4.5", 32 | "gulp-changed": "^1.3.0", 33 | "gulp-chmod": "^1.3.0", 34 | "gulp-copy": "0.0.2", 35 | "gulp-cssmin": "^0.2.0", 36 | "gulp-if": "^2.0.0", 37 | "gulp-imagemin": "^2.4.0", 38 | "gulp-load-plugins": "^1.2.0", 39 | "gulp-minify-html": "^1.0.5", 40 | "gulp-mocha": "^2.2.0", 41 | "gulp-rename": "^1.2.2", 42 | "gulp-replace": "^0.6.1", 43 | "gulp-run": "^1.6.12", 44 | "gulp-size": "^2.0.0", 45 | "gulp-tslint": "^8.1.1", 46 | "gulp-typescript": "^3.1.7", 47 | "gulp-useref": "^3.1.2", 48 | "gulp-util": "^3.0.6", 49 | "gulp-vulcanize": "^6.1.0", 50 | "karma": "^1.1.1", 51 | "karma-chai": "^0.1.0", 52 | "karma-chrome-launcher": "^2.2.0", 53 | "karma-firefox-launcher": "^1.0.0", 54 | "karma-mocha": "^1.1.1", 55 | "merge2": "^1.1.0", 56 | "mocha": "^3.4.2", 57 | "through2": "^2.0.3", 58 | "tslint": "^5.5.0", 59 | "typescript": "^2.4.1", 60 | "vinyl-buffer": "^1.0.0", 61 | "vinyl-source-stream": "^1.1.0" 62 | }, 63 | "dependencies": { 64 | "@types/chai": "^4.0.1", 65 | "@types/dropboxjs": "0.0.29", 66 | "@types/filesystem": "0.0.28", 67 | "@types/mocha": "^2.2.41", 68 | "child_process": "^1.0.2", 69 | "node-binary-marshal": "^0.4.2", 70 | "term.js": "github:bpowers/term.js" 71 | }, 72 | "engines": { 73 | "node": ">=4.3.0" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/bin/curl.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { spawn } from 'child_process'; 4 | import { connect, Socket } from 'net'; 5 | import * as http from 'http'; 6 | 7 | function main(): void { 8 | let argv = process.argv; 9 | let pathToNode = argv[0]; 10 | let pathToScript = argv[1]; 11 | let args = argv.slice(2); 12 | 13 | if (!args.length) { 14 | process.stderr.write('usage:\n curl URL\n', () => { 15 | process.exit(1); 16 | }); 17 | return; 18 | } 19 | 20 | let url = args[0]; 21 | let port = 80; 22 | let parts = url.split('://')[1].split('/'); 23 | let host = parts[0]; 24 | let path = '/' + parts.slice(1).join('/'); 25 | if (host.indexOf(':') > -1) { 26 | let sPort = ''; 27 | [host, sPort] = host.split(':'); 28 | port = parseInt(sPort, 10); 29 | } 30 | 31 | let options = { 32 | host: host, 33 | port: port, 34 | path: path, 35 | }; 36 | 37 | function callback(response: http.IncomingMessage): void { 38 | let chunks: Buffer[] = []; 39 | 40 | response.on('data', (chunk: string) => { 41 | chunks.push(new Buffer(chunk)); 42 | }); 43 | 44 | response.on('end', () => { 45 | let all = Buffer.concat(chunks); 46 | process.stdout.write(all, () => { 47 | setTimeout(process.exit, 0); 48 | }); 49 | }); 50 | } 51 | 52 | http.request(options, callback).end(); 53 | } 54 | 55 | main(); 56 | -------------------------------------------------------------------------------- /src/bin/echo.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as fs from 'fs'; 4 | import {format} from 'util'; 5 | 6 | function log(fmt: string, ...args: any[]): void { 7 | let cb: Function = undefined; 8 | if (args.length && typeof args[args.length-1] === 'function') { 9 | cb = args[args.length-1]; 10 | args = args.slice(0, -1); 11 | } 12 | let prog = process.argv[1].split('/').slice(-1); 13 | let msg = prog + ': ' + format.apply(undefined, [fmt].concat(args)) + '\n'; 14 | 15 | if (cb) 16 | process.stderr.write(msg, cb); 17 | else 18 | process.stderr.write(msg); 19 | } 20 | 21 | function parseArgs(args: string[], handlers: {[n: string]: Function}): [string[], boolean] { 22 | let ok = true; 23 | let positionalArgs: string[] = args.filter((arg) => arg.substring(0, 1) !== '-'); 24 | args = args.filter((arg) => arg.substring(0, 1) === '-'); 25 | 26 | let errs = 0; 27 | function done(): void { 28 | errs--; 29 | if (!errs) 30 | process.exit(1); 31 | } 32 | function error(...args: any[]): void { 33 | errs++; 34 | ok = false; 35 | // apply the arguments we've been given to log, and 36 | // append our own callback. 37 | log.apply(this, args.concat([done])); 38 | } 39 | function usage(): void { 40 | errs++; 41 | let prog = process.argv[1].split('/').slice(-1); 42 | let flags = Object.keys(handlers).concat(['h']).sort().join(''); 43 | let msg = format('usage: %s [-%s] ARGS\n', prog, flags); 44 | process.stderr.write(msg, done); 45 | } 46 | 47 | outer: 48 | for (let i = 0; i < args.length; i++) { 49 | let argList = args[i].slice(1); 50 | if (argList.length && argList[0] === '-') { 51 | error('unknown option "%s"', args[i]); 52 | continue; 53 | } 54 | for (let j = 0; j < argList.length; j++) { 55 | let arg = argList[j]; 56 | if (handlers[arg]) { 57 | handlers[arg](); 58 | } else if (arg === 'h') { 59 | ok = false; 60 | break outer; 61 | } else { 62 | error('invalid option "%s"', arg); 63 | } 64 | } 65 | } 66 | 67 | if (!ok) usage(); 68 | 69 | return [positionalArgs, ok]; 70 | } 71 | 72 | function main(): void { 73 | let trailingNewline: boolean = true; 74 | 75 | let [args, ok] = parseArgs( 76 | process.argv.slice(2), { 77 | 'n': (): any => trailingNewline = false, 78 | } 79 | ); 80 | if (!ok) 81 | return; 82 | 83 | let out = ''; 84 | for (let i = 0; i < args.length; i++) { 85 | if (i !== 0) 86 | out += ' '; 87 | out += args[i]; 88 | } 89 | 90 | if (trailingNewline) 91 | out += '\n'; 92 | 93 | process.stdout.write(out, 'utf-8', (err: any) => { 94 | let code = 0; 95 | if (err) { 96 | code = -1; 97 | log(err.message, () => { process.exit(code); }); 98 | return; 99 | } 100 | process.exit(code); 101 | }); 102 | } 103 | 104 | main(); 105 | -------------------------------------------------------------------------------- /src/bin/exec.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as child_process from 'child_process'; 4 | import * as fs from 'fs'; 5 | import * as path from 'path'; 6 | 7 | function main(): void { 8 | 'use strict'; 9 | 10 | let pathToScript = process.argv[1]; 11 | let args = process.argv.slice(2); 12 | 13 | if (args.length < 1) { 14 | let usage = 'usage: ' + path.basename(pathToScript) + ' CMD [ARGS...]\n'; 15 | process.stderr.write(usage, (err: any) => { 16 | process.exit(1); 17 | }); 18 | return; 19 | } 20 | 21 | let opts = { 22 | // pass our stdin, stdout, stderr to the child 23 | stdio: [0, 1, 2], 24 | }; 25 | 26 | let child = child_process.spawn(args[0], args.slice(1), opts); 27 | child.on('error', (err: any) => { 28 | process.stderr.write('error: ' + err, () => { 29 | process.exit(1); 30 | }); 31 | }); 32 | child.on('exit', (code: number) => { 33 | process.exit(code); 34 | }); 35 | } 36 | 37 | main(); 38 | -------------------------------------------------------------------------------- /src/bin/head.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as fs from 'fs'; 4 | import * as readline from 'readline'; 5 | 6 | // This is heavily based on the design of cat.c from sbase: 7 | // http://git.suckless.org/sbase/tree/cat.c . Seemingly more 8 | // traditional 'node' way to do things would be to read the entire 9 | // file contents and then dump them, but that doesn't work correctly 10 | // for stdin where cat can read chunks at a time (think typing 'echo' 11 | // and hitting enter) until it receives EOF. 12 | 13 | // Recursively read each input and write it to the specified output, 14 | // only moving onto the next input when EOF is reached. Each file is 15 | // a node stream object - which means that we consume it by adding 2 16 | // event listeners, the first for when there is data available, and 17 | // secondly for when we've reached EOF. 18 | 19 | function head(inputs: NodeJS.ReadableStream[], output: NodeJS.WritableStream, numlines: number, code: number): void { 20 | 'use strict'; 21 | if (!inputs || !inputs.length) { 22 | process.exit(code); 23 | return; 24 | } 25 | 26 | let current = inputs[0]; 27 | inputs = inputs.slice(1); 28 | 29 | let closed = false; 30 | let outstanding = 0; 31 | 32 | function next(): void { 33 | closed = true; 34 | if (outstanding) 35 | return; 36 | // use setTimeout to avoid a deep stack as well as 37 | // cooperatively yield 38 | setTimeout(head, 0, inputs, output, numlines, code); 39 | } 40 | 41 | function finished(): void { 42 | outstanding--; 43 | if (!outstanding && closed) 44 | return next(); 45 | } 46 | 47 | if (!current) 48 | return next(); 49 | 50 | let n = 0; 51 | current.on('readable', function(): void { 52 | let rl = readline.createInterface({ 53 | input: current, 54 | output: null, 55 | }); 56 | rl.on('line', (line: string) => { 57 | n++; 58 | if (n > numlines) { 59 | rl.close(); 60 | next(); 61 | } else { 62 | outstanding++; 63 | output.write(line +'\n', finished); 64 | } 65 | }); 66 | }); 67 | 68 | current.on('end', next); 69 | } 70 | 71 | function main(): void { 72 | 'use strict'; 73 | 74 | let argv = process.argv; 75 | let pathToNode = argv[0]; 76 | let pathToScript = argv[1]; 77 | let args = argv.slice(2); 78 | 79 | // exit code to use - if we fail to open an input file it gets 80 | // set to 1 below. 81 | let code = 0; 82 | let defaultLimit = 10; 83 | let limit = defaultLimit; 84 | 85 | if (args.length && args[0] === '-n') { 86 | limit = +args[1]; 87 | args = args.slice(2); 88 | } 89 | if (!args.length) 90 | args = ['-']; 91 | 92 | let files: NodeJS.ReadableStream[] = []; 93 | let nOpened = 0; 94 | 95 | function opened(): void { 96 | nOpened++; 97 | if (nOpened === args.length) 98 | setTimeout(head, 0, files, process.stdout, limit, code); 99 | } 100 | 101 | // use map instead of a for loop so that we easily get the 102 | // tuple of (path, i) on each iteration. 103 | args.map(function(path, i): void { 104 | // '-' represents stdin, which is already open. 105 | // Special-case it. 106 | if (path === '-') { 107 | files[i] = process.stdin; 108 | // if we've opened all of the files, pipe them 109 | // to stdout. 110 | opened(); 111 | return; 112 | } 113 | fs.open(path, 'r', function(err: any, fd: any): void { 114 | if (err) { 115 | // if we couldn't open the specified 116 | // file we should print a message but 117 | // not exit early - we need to process 118 | // as many inputs as we can. 119 | files[i] = null; 120 | code = 1; 121 | let msg = pathToScript + ': ' + err.message + '\n'; 122 | process.stderr.write(msg, opened); 123 | return; 124 | } 125 | files[i] = fs.createReadStream(path, {fd: fd}); 126 | opened(); 127 | }); 128 | }); 129 | } 130 | 131 | main(); 132 | -------------------------------------------------------------------------------- /src/bin/hello-socket.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { createServer, Socket } from 'net'; 4 | 5 | function main(): void { 6 | let server = createServer((socket: Socket) => { 7 | 8 | process.stdout.write('Connection from ' + socket.remoteAddress + '\n'); 9 | socket.end("Hello World\n"); 10 | setTimeout(process.exit, 0); 11 | }); 12 | 13 | // Fire up the server bound to port 7000 on localhost 14 | server.listen(7000, 'localhost'); 15 | 16 | // Put a friendly message on the terminal 17 | process.stdout.write('TCP server listening on port 7000 at localhost.\n'); 18 | } 19 | 20 | main(); 21 | -------------------------------------------------------------------------------- /src/bin/hello.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { createServer, IncomingMessage, ServerResponse } from 'http'; 4 | 5 | function main(): void { 6 | let s = createServer((req: IncomingMessage, resp: ServerResponse) => { 7 | resp.writeHead(200, {"Content-Type": "text/plain"}); 8 | resp.end("Hello World over HTTP\n"); 9 | setTimeout(process.exit, 0); 10 | }); 11 | s.listen(8000); 12 | process.stdout.write('Server running at http://127.0.0.1:8000/\n'); 13 | } 14 | 15 | main(); 16 | -------------------------------------------------------------------------------- /src/bin/http-example.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { spawn } from 'child_process'; 4 | import { connect, Socket } from 'net'; 5 | import * as http from 'http'; 6 | 7 | function main(): void { 8 | let serverFinished = false; 9 | let clientFinished = false; 10 | 11 | let server = spawn('usr/bin/go-hello', [], { stdio: [0, 1, 2] }); 12 | server.on('error', (err: any) => { 13 | process.stderr.write('error: ' + err + '\n', () => { 14 | serverFinished = true; 15 | if (clientFinished) 16 | return process.exit(0); 17 | }); 18 | }); 19 | server.on('exit', () => { 20 | serverFinished = true; 21 | if (clientFinished) 22 | return process.exit(0); 23 | }); 24 | 25 | setTimeout(client, 5000); 26 | function client(): void { 27 | let options = { 28 | host: 'localhost', 29 | port: 8080, 30 | path: '/', 31 | }; 32 | 33 | function callback(response: http.IncomingMessage): void { 34 | let str = ''; 35 | 36 | response.on('data', (chunk: string) => { 37 | str += chunk; 38 | process.stdout.write('http client got: ' + chunk + '\n'); 39 | setTimeout(process.exit, 0); 40 | }); 41 | 42 | //response.on('end', () => { 43 | // process.stdout.write('http client got: ' + str + '\n'); 44 | //}); 45 | } 46 | 47 | http.request(options, callback).end(); 48 | } 49 | } 50 | 51 | main(); 52 | -------------------------------------------------------------------------------- /src/bin/ls.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as fs from 'fs'; 4 | import {format} from 'util'; 5 | 6 | function log(fmt: string, ...args: any[]): void { 7 | let cb: Function = undefined; 8 | if (args.length && typeof args[args.length-1] === 'function') { 9 | cb = args[args.length-1]; 10 | args = args.slice(0, -1); 11 | } 12 | let prog = process.argv[1].split('/').slice(-1); 13 | let msg = prog + ': ' + format.apply(undefined, [fmt].concat(args)) + '\n'; 14 | 15 | if (cb) 16 | process.stderr.write(msg, cb); 17 | else 18 | process.stderr.write(msg); 19 | } 20 | 21 | function parseArgs(args: string[], handlers: {[n: string]: Function}): [string[], boolean] { 22 | let ok = true; 23 | let positionalArgs: string[] = args.filter((arg) => arg.substring(0, 1) !== '-'); 24 | args = args.filter((arg) => arg.substring(0, 1) === '-'); 25 | 26 | let errs = 0; 27 | function done(): void { 28 | errs--; 29 | if (!errs) 30 | process.exit(1); 31 | } 32 | function error(...args: any[]): void { 33 | errs++; 34 | ok = false; 35 | // apply the arguments we've been given to log, and 36 | // append our own callback. 37 | log.apply(this, args.concat([done])); 38 | } 39 | function usage(): void { 40 | errs++; 41 | let prog = process.argv[1].split('/').slice(-1); 42 | let flags = Object.keys(handlers).concat(['h']).sort().join(''); 43 | let msg = format('usage: %s [-%s] ARGS\n', prog, flags); 44 | process.stderr.write(msg, done); 45 | } 46 | 47 | outer: 48 | for (let i = 0; i < args.length; i++) { 49 | let argList = args[i].slice(1); 50 | if (argList.length && argList[0] === '-') { 51 | error('unknown option "%s"', args[i]); 52 | continue; 53 | } 54 | for (let j = 0; j < argList.length; j++) { 55 | let arg = argList[j]; 56 | if (handlers[arg]) { 57 | handlers[arg](); 58 | } else if (arg === 'h') { 59 | ok = false; 60 | break outer; 61 | } else { 62 | error('invalid option "%s"', arg); 63 | } 64 | } 65 | } 66 | 67 | if (!ok) usage(); 68 | 69 | return [positionalArgs, ok]; 70 | } 71 | 72 | function main(): void { 73 | let all: boolean = false; 74 | 75 | let [args, ok] = parseArgs( 76 | process.argv.slice(2), { 77 | '1': (): any => {}, // nop, but make sure it doesn't error out 78 | 'l': (): any => {}, // nop, but make sure it doesn't error out 79 | 'a': (): any => all = true, 80 | } 81 | ); 82 | if (!ok) 83 | return; 84 | 85 | if (!args.length) 86 | args = ['.']; 87 | 88 | let code: number = 0; 89 | let outstanding: number = args.length; 90 | 91 | for (let i = 0; i < args.length; i++) { 92 | ((path: string) => { 93 | fs.readdir(path, readdirFinished.bind(null, path)); 94 | })(args[i]); 95 | } 96 | 97 | function done(): void { 98 | outstanding--; 99 | if (!outstanding) 100 | process.exit(code); 101 | } 102 | 103 | function readdirFinished(dir: string, err: any, files: string[]): void { 104 | if (err) { 105 | log(err.message, done); 106 | return; 107 | } 108 | if (!all) 109 | files = files.filter((f: string) => f.length && f[0] !== '.'); 110 | process.stdout.write(files.join('\n') + '\n', 'utf-8', (werr: any) => { 111 | if (werr) { 112 | code = -1; 113 | log('write: %s', werr, done); 114 | return; 115 | } 116 | done(); 117 | }); 118 | } 119 | } 120 | 121 | main(); 122 | -------------------------------------------------------------------------------- /src/bin/pipeline-example.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as child_process from 'child_process'; 4 | import * as fs from 'fs'; 5 | import * as path from 'path'; 6 | import { pipe2 } from 'node-pipe2'; 7 | 8 | function main(): void { 9 | 'use strict'; 10 | 11 | let pathToScript = process.argv[1]; 12 | let args = process.argv.slice(2); 13 | let waiting = 2; 14 | let exit = 0; 15 | 16 | function childFinished(err: any, code: number = 0): void { 17 | if (err && !code) 18 | code = -1; 19 | waiting--; 20 | if (!waiting) 21 | process.exit(code); 22 | } 23 | 24 | pipe2((perr: any, rfd: number, wfd: number) => { 25 | if (perr) 26 | throw new Error('pipe2 failed: ' + perr); 27 | 28 | let echo = child_process.spawn('/usr/bin/echo', ['hello world'], { stdio: [0, wfd, 2] }); 29 | echo.on('error', (err: any) => { 30 | process.stderr.write('error: ' + err, () => { 31 | exit = 1; 32 | childFinished(err); 33 | }); 34 | }); 35 | echo.on('exit', (code: number) => { 36 | childFinished(null, code); 37 | }); 38 | 39 | // XXX: we don't need the wfd at this point, and 40 | // keeping it open seems to prevent cat from getting 41 | // an EOF on the pipe? 42 | fs.close(wfd, () => { 43 | let cat = child_process.spawn('/usr/bin/cat', [], { stdio: [rfd, 1, 2] }); 44 | cat.on('error', (err: any) => { 45 | process.stderr.write('error: ' + err, () => { 46 | childFinished(err); 47 | }); 48 | }); 49 | cat.on('exit', (code: number) => { 50 | childFinished(null, code); 51 | }); 52 | fs.close(rfd); 53 | }); 54 | 55 | }); 56 | } 57 | 58 | main(); 59 | -------------------------------------------------------------------------------- /src/bin/rmdir.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as fs from 'fs'; 4 | 5 | function main(): void { 6 | 'use strict'; 7 | 8 | let pathToScript = process.argv[1]; 9 | let args = process.argv.slice(2); 10 | 11 | /*if (args.length && args[0] === '-n') { 12 | trailingNewline = false; 13 | args = args.slice(1); 14 | }*/ 15 | let code = 0; 16 | fs.rmdir(args[0], () => { 17 | process.exit(code); 18 | }); 19 | } 20 | 21 | main(); 22 | -------------------------------------------------------------------------------- /src/bin/socket-example.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { spawn } from 'child_process'; 4 | import { connect, Socket } from 'net'; 5 | 6 | function main(): void { 7 | let serverFinished = false; 8 | let clientFinished = false; 9 | 10 | let server = spawn('usr/bin/hello-socket', [], { stdio: [0, 1, 2] }); 11 | server.on('error', (err: any) => { 12 | process.stderr.write('error: ' + err + '\n', () => { 13 | serverFinished = true; 14 | if (clientFinished) 15 | return process.exit(0); 16 | }); 17 | }); 18 | server.on('exit', () => { 19 | serverFinished = true; 20 | if (clientFinished) 21 | return process.exit(0); 22 | }); 23 | 24 | setTimeout(client, 1000); 25 | function client(): void { 26 | let client = connect({port: 7000}, () => { 27 | process.stdout.write('connected to server!\n'); 28 | }); 29 | client.on('data', (data: any) => { 30 | process.stdout.write('client got: ' + data.toString().trim() + '\n'); 31 | clientFinished = true; 32 | if (serverFinished) 33 | return process.exit(0); 34 | }); 35 | } 36 | } 37 | 38 | main(); 39 | -------------------------------------------------------------------------------- /src/bin/sort.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as fs from 'fs'; 4 | import * as readline from 'readline'; 5 | 6 | // This is heavily based on the design of cat.c from sbase: 7 | // http://git.suckless.org/sbase/tree/cat.c . Seemingly more 8 | // traditional 'node' way to do things would be to read the entire 9 | // file contents and then dump them, but that doesn't work correctly 10 | // for stdin where cat can read chunks at a time (think typing 'echo' 11 | // and hitting enter) until it receives EOF. 12 | 13 | // Recursively read each input and write it to the specified output, 14 | // only moving onto the next input when EOF is reached. Each file is 15 | // a node stream object - which means that we consume it by adding 2 16 | // event listeners, the first for when there is data available, and 17 | // secondly for when we've reached EOF. 18 | function sort(inputs: NodeJS.ReadableStream[], output: NodeJS.WritableStream, code: number, lines: string[]): void { 19 | 'use strict'; 20 | 21 | if (!inputs || !inputs.length) { 22 | lines.sort(); 23 | output.write(lines.join('\n') + '\n', () => { 24 | process.exit(code); 25 | }); 26 | return; 27 | } 28 | 29 | let current = inputs[0]; 30 | inputs = inputs.slice(1); 31 | 32 | if (!current) { 33 | // use setTimeout to avoid a deep stack as well as 34 | // cooperatively yield 35 | setTimeout(sort, 0, inputs, output, code, lines); 36 | return; 37 | } 38 | 39 | current.on('readable', function(): void { 40 | let rl = readline.createInterface({ 41 | input: current, 42 | output: null 43 | }); 44 | 45 | rl.on('line', (line: string) => { 46 | lines.push(line); 47 | }); 48 | }); 49 | 50 | current.on('end', function(): void { 51 | setTimeout(sort, 0, inputs, output, code, lines); 52 | }); 53 | } 54 | 55 | function main(): void { 56 | 'use strict'; 57 | 58 | let argv = process.argv; 59 | let pathToNode = argv[0]; 60 | let pathToScript = argv[1]; 61 | let args = argv.slice(2); 62 | 63 | // exit code to use - if we fail to open an input file it gets 64 | // set to 1 below. 65 | let code = 0; 66 | let lines: string[] = []; 67 | 68 | if (!args.length) { 69 | // no args? just sort stdin and write to stdout 70 | setTimeout(sort, 0, [process.stdin], process.stdout, code, lines); 71 | } else { 72 | let files: NodeJS.ReadableStream[] = []; 73 | let opened = 0; 74 | // use map instead of a for loop so that we easily get 75 | // the tuple of (path, i) on each iteration. 76 | args.map(function(path, i): void { 77 | if (path === '-') { 78 | files[i] = process.stdin; 79 | // if we've opened all of the files, pipe them to 80 | // stdout. 81 | if (++opened === args.length) 82 | setTimeout(sort, 0, files, process.stdout, code, lines); 83 | return; 84 | } 85 | fs.open(path, 'r', function(err: any, fd: any): void { 86 | if (err) { 87 | // if we couldn't open the 88 | // specified file we should 89 | // print a message but not 90 | // exit early - we need to 91 | // process as many inputs as 92 | // we can. 93 | files[i] = null; 94 | code = 1; 95 | process.stderr.write(pathToScript + ': ' + err.message + '\n'); 96 | } else { 97 | files[i] = fs.createReadStream(path, {fd: fd}); 98 | } 99 | // if we've opened all of the files, 100 | // pipe them to stdout. 101 | if (++opened === args.length) 102 | setTimeout(sort, 0, files, process.stdout, code, lines); 103 | }); 104 | }); 105 | } 106 | } 107 | 108 | main(); 109 | -------------------------------------------------------------------------------- /src/bin/stat.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as fs from 'fs'; 4 | 5 | 6 | // TODO: column alignment 7 | function formatStats(path: string, stats: fs.Stats): string { 8 | /* tslint:disable indent */ 9 | return ` File: ‘${path}’ 10 | Size: ${stats.size} Blocks: ${stats.blocks} IO Block: ${stats.blksize} 11 | Device: ${stats.dev} Inode: ${stats.ino} Links: ${stats.nlink} 12 | Access: ${stats.mode} Uid: ${stats.uid} Gid: ${stats.gid} 13 | Access: ${stats.atime} 14 | Modify: ${stats.mtime} 15 | Change: ${stats.ctime} 16 | Birth: ${stats.birthtime} 17 | `; 18 | /* tslint:enable indent */ 19 | } 20 | 21 | function stat(inputs: string[], output: NodeJS.WritableStream, code: number): void { 22 | 'use strict'; 23 | 24 | if (!inputs || !inputs.length) { 25 | process.exit(code); 26 | return; 27 | } 28 | 29 | let current = inputs[0]; 30 | inputs = inputs.slice(1); 31 | 32 | if (!current) { 33 | // use setTimeout to avoid a deep stack as well as 34 | // cooperatively yield 35 | setTimeout(stat, 0, inputs, output, code); 36 | return; 37 | } 38 | 39 | fs.stat(current, function(err: any, stats: fs.Stats): void { 40 | if (err) { 41 | process.stderr.write('ERROR: ' + err, writeCompleted); 42 | return; 43 | } 44 | output.write(formatStats(current, stats), writeCompleted); 45 | 46 | function writeCompleted(): void { 47 | setTimeout(stat, 0, inputs, output, code); 48 | } 49 | }); 50 | } 51 | 52 | function main(): void { 53 | 'use strict'; 54 | 55 | let argv = process.argv; 56 | let pathToNode = argv[0]; 57 | let pathToScript = argv[1]; 58 | let args = argv.slice(2); 59 | 60 | if (!args.length) { 61 | process.stderr.write(pathToScript + ': missing operand\n', () => { 62 | process.exit(1); 63 | }); 64 | return; 65 | } 66 | 67 | setTimeout(stat, 0, args, process.stdout, 0); 68 | } 69 | 70 | main(); 71 | -------------------------------------------------------------------------------- /src/bin/tail.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as fs from 'fs'; 4 | import * as readline from 'readline'; 5 | 6 | // This is heavily based on the design of cat.c from sbase: 7 | // http://git.suckless.org/sbase/tree/cat.c . Seemingly more 8 | // traditional 'node' way to do things would be to read the entire 9 | // file contents and then dump them, but that doesn't work correctly 10 | // for stdin where cat can read chunks at a time (think typing 'echo' 11 | // and hitting enter) until it receives EOF. 12 | 13 | // Recursively read each input and write it to the specified output, 14 | // only moving onto the next input when EOF is reached. Each file is 15 | // a node stream object - which means that we consume it by adding 2 16 | // event listeners, the first for when there is data available, and 17 | // secondly for when we've reached EOF. 18 | 19 | function tail(inputs: NodeJS.ReadableStream[], output: NodeJS.WritableStream, numlines: number, code: number): void { 20 | 'use strict'; 21 | if (!inputs || !inputs.length) { 22 | process.exit(code); 23 | return; 24 | } 25 | 26 | let current = inputs[0]; 27 | inputs = inputs.slice(1); 28 | let n = 0; 29 | let outstanding = 0; 30 | let linebuffer: string[] = []; 31 | if (!current) { 32 | // use setTimeout to avoid a deep stack as well as 33 | // cooperatively yield 34 | setTimeout(tail, 0, inputs, output, numlines, code); 35 | return; 36 | } 37 | 38 | current.on('readable', function(): void { 39 | let rl = readline.createInterface({ 40 | input: current, 41 | output: null 42 | }); 43 | 44 | rl.on('line', (line: string) => { 45 | n++; 46 | linebuffer.push(line); 47 | if (n > numlines) { 48 | linebuffer.shift(); 49 | } 50 | }); 51 | }); 52 | 53 | // FIXME: this only works for the case of a single input file 54 | current.on('end', function(): void { 55 | outstanding = linebuffer.length; 56 | for (let i = 0; i < linebuffer.length; i++) { 57 | output.write(linebuffer[i] + "\n", () => { 58 | outstanding--; 59 | if (!outstanding) 60 | process.exit(0); 61 | }); 62 | } 63 | //setTimeout(tail, 0, inputs, output, numlines, code); 64 | }); 65 | } 66 | 67 | function main(): void { 68 | 'use strict'; 69 | 70 | let argv = process.argv; 71 | let pathToNode = argv[0]; 72 | let pathToScript = argv[1]; 73 | let args = argv.slice(2); 74 | 75 | // exit code to use - if we fail to open an input file it gets 76 | // set to 1 below. 77 | let code = 0; 78 | let def_numlines = 10; 79 | let numlines = def_numlines; 80 | if (args.length && args[0] === '-n') { 81 | numlines = +args[1]; 82 | args = args.slice(2); 83 | } 84 | if (!args.length) { 85 | // no args? just copy default num lines from stdin to stdout 86 | setTimeout(tail, 0, [process.stdin], process.stdout, numlines, code); 87 | } else { 88 | let files: NodeJS.ReadableStream[] = []; 89 | let opened = 0; 90 | // use map instead of a for loop so that we easily get 91 | // the tuple of (path, i) on each iteration. 92 | args.map(function(path, i): void { 93 | if (path === '-') { 94 | files[i] = process.stdin; 95 | // if we've opened all of the files, pipe them to 96 | // stdout. 97 | if (++opened === args.length) 98 | setTimeout(tail, 0, files, process.stdout, numlines, code); 99 | return; 100 | } 101 | fs.open(path, 'r', function(err: any, fd: any): void { 102 | if (err) { 103 | // if we couldn't open the 104 | // specified file we should 105 | // print a message but not 106 | // exit early - we need to 107 | // process as many inputs as 108 | // we can. 109 | files[i] = null; 110 | code = 1; 111 | process.stderr.write(pathToScript + ': ' + err.message + '\n'); 112 | } else { 113 | files[i] = fs.createReadStream(path, {fd: fd}); 114 | } 115 | // if we've opened all of the files, 116 | // pipe them to stdout. 117 | if (++opened === args.length) 118 | setTimeout(tail, 0, files, process.stdout, numlines, code); 119 | }); 120 | }); 121 | } 122 | } 123 | 124 | main(); 125 | -------------------------------------------------------------------------------- /src/bin/tee.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as fs from 'fs'; 4 | 5 | // This is heavily based on the design of cat.c from sbase: 6 | // http://git.suckless.org/sbase/tree/cat.c . Seemingly more 7 | // traditional 'node' way to do things would be to read the entire 8 | // file contents and then dump them, but that doesn't work correctly 9 | // for stdin where cat can read chunks at a time (think typing 'echo' 10 | // and hitting enter) until it receives EOF. 11 | 12 | // Recursively read each input and write it to the specified output, 13 | // only moving onto the next input when EOF is reached. Each file is 14 | // a node stream object - which means that we consume it by adding 2 15 | // event listeners, the first for when there is data available, and 16 | // secondly for when we've reached EOF. 17 | function tee(current: NodeJS.ReadableStream, outputs: NodeJS.WritableStream[], code: number): void { 18 | 19 | current.on('readable', function(): void { 20 | let buf = current.read(); 21 | if (buf !== null) 22 | for (let i = 0; i < outputs.length; i++) { 23 | outputs[i].write(buf); 24 | } 25 | }); 26 | 27 | current.on('end', function(): void { 28 | let outstanding = outputs.length; 29 | for (let i = 0; i < outputs.length; i++) { 30 | outputs[i].end(undefined, undefined, () => { 31 | outstanding--; 32 | if (!outstanding) 33 | process.exit(code); 34 | }); 35 | } 36 | }); 37 | } 38 | 39 | function main(): void { 40 | 'use strict'; 41 | 42 | let argv = process.argv; 43 | let pathToNode = argv[0]; 44 | let pathToScript = argv[1]; 45 | let args = argv.slice(2); 46 | 47 | // exit code to use - if we fail to open an input file it gets 48 | // set to 1 below. 49 | let code = 0; 50 | 51 | if (!args.length) { 52 | // no args? just copy stdin to stdout 53 | setTimeout(tee, 0, process.stdin, [process.stdout], code); 54 | } else { 55 | let files: NodeJS.WritableStream[] = []; 56 | files.push(process.stdout); 57 | let opened = 0; 58 | // use map instead of a for loop so that we easily get 59 | // the tuple of (path, i) on each iteration. 60 | args.map(function(path, i): void { 61 | fs.open(path, 'w', function(err: any, fd: any): void { 62 | if (err) { 63 | // if we couldn't open the 64 | // specified file we should 65 | // print a message but not 66 | // exit early - we need to 67 | // process as many inputs as 68 | // we can. 69 | files[i+1] = null; 70 | code = 1; 71 | process.stderr.write(pathToScript + ': ' + err.message + '\n'); 72 | } else { 73 | files[i+1] = fs.createWriteStream(path, {fd: fd}); 74 | } 75 | // if we've opened all of the files, 76 | // pipe them to stdout. 77 | if (++opened === args.length) 78 | setTimeout(tee, 0, process.stdin, files, code); 79 | }); 80 | }); 81 | } 82 | } 83 | 84 | main(); 85 | -------------------------------------------------------------------------------- /src/bin/touch.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as fs from 'fs'; 4 | 5 | 6 | function main(): void { 7 | 'use strict'; 8 | 9 | let argv = process.argv; 10 | let pathToNode = argv[0]; 11 | let pathToScript = argv[1]; 12 | let args = argv.slice(2); 13 | 14 | // exit code to use - if we fail to open an input file it gets 15 | // set to 1 below. 16 | let code = 0; 17 | 18 | let now: Date = new Date(); 19 | let opened = 0; 20 | 21 | function finished(): void { 22 | opened++; 23 | if (opened === args.length) 24 | process.exit(code); 25 | } 26 | 27 | if (!args.length) { 28 | // no args? no dice! 29 | process.stderr.write('usage:\n touch FILE\n', () => { 30 | process.exit(1); 31 | }); 32 | } else { 33 | // use map instead of a for loop so that we easily get 34 | // the tuple of (path, i) on each iteration. 35 | args.map(function(path: string, i: number): void { 36 | fs.stat(path, function(err: any, stats: fs.Stats): void { 37 | if (err) { 38 | // if we couldn't stat the 39 | // specified file we should 40 | // create it. Pass 'x' for 41 | // the CREAT flag. 42 | fs.open(path, 'wx', function(oerr: any, fd: number): void { 43 | if (oerr) { 44 | // now we're in trouble and 45 | // we should try other files instead. 46 | code = 1; 47 | let msg = pathToScript + ': ' + oerr + '\n'; 48 | process.stderr.write(msg, finished); 49 | } 50 | // thats it - close the sucker. 51 | fs.close(fd, finished); 52 | }); 53 | } else { 54 | // file exists - just use utimes, 55 | // no need to open it. 56 | fs.utimes(path, now, now, (uerr: any) => { 57 | if (uerr) { 58 | code = 1; 59 | process.stderr.write('utimes: ' + uerr.message + '\n', finished); 60 | return; 61 | } 62 | finished(); 63 | }); 64 | } 65 | }); 66 | }); 67 | } 68 | } 69 | 70 | main(); 71 | -------------------------------------------------------------------------------- /src/browser-node/binding/cares_wrap.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // returns 0, 4, or 6 4 | export function isIP(s: string): number { 5 | // TODO: this should avoid triggering DNS lookup code 6 | return 4; 7 | } 8 | 9 | export class TCP { 10 | constructor() { 11 | (console).trace('TODO: someone wants a tcp'); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/browser-node/binding/contextify.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export class ContextifyScript { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/browser-node/binding/fs_event_wrap.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export class FSEvent { 4 | onchange: (status: any, event: any, filename: string) => void = undefined; 5 | onstop: () => void = undefined; 6 | 7 | start(filename: string, persistent: boolean, recursive: boolean): any { 8 | 9 | } 10 | 11 | stop(): void { 12 | 13 | } 14 | 15 | close(): void { 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/browser-node/binding/pipe_wrap.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export class Pipe { 4 | constructor() { 5 | (console).trace('TODO: someone wants a pipe'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/browser-node/binding/process_wrap.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { syscall, SyscallResponse } from '../syscall'; 4 | import * as uv from './uv'; 5 | 6 | // FIXME: internal/child_process checks for specific errors. I think 7 | // other errors will cause us to throw? not sure how that is handled. 8 | const ERROR = uv.UV_EMFILE; 9 | const ENOENT = uv.UV_ENOENT; 10 | 11 | export interface Environment { [k: string]: string; } 12 | 13 | export interface File { 14 | type: string; // 'pipe' | 'ignore' | 'inherit' | 'fd' 15 | fd: number; // only when type is fd 16 | readable: boolean; 17 | writable: boolean; 18 | } 19 | 20 | export interface SpawnOptions { 21 | cwd: string; 22 | file: string; 23 | args: string[]; 24 | envPairs: string[]; 25 | stdio: File[]; 26 | detached: boolean; 27 | uid: number; // TODO: not implemented 28 | gid: number; // TODO: not implemented 29 | } 30 | 31 | export class Process { 32 | onerror: Function = undefined; 33 | onexit: Function = undefined; 34 | pid: number; 35 | 36 | constructor() {} 37 | 38 | spawn(opts: SpawnOptions): any { 39 | let files: number[] = []; 40 | for (let i = 0; i < opts.stdio.length; i++) { 41 | let f = opts.stdio[i]; 42 | if (f.type !== 'fd') 43 | throw new Error('unsupported type ' + f.type + ' for FD ' + f.fd); 44 | files.push(f.fd); 45 | } 46 | 47 | let bins = (process.env['PATH'] || '/usr/local/bin:/bin:/usr/bin').split(':'); 48 | let cmds = [opts.file]; 49 | // spawn calls execvp, which will attempt to execute a 50 | // file depending on the contents of the $PATH 51 | // environmental variable. If the file contains a / 52 | // (meaning it is an absolute or relative path), $PATH 53 | // interpolation is skipped. 54 | if (cmds[0].indexOf('/') === -1) { 55 | cmds = bins.map((p: string) => { 56 | // remove trailing slash if it exists 57 | if (p.length && p[p.length-1] === '/') 58 | p = p.slice(0, -1); 59 | return p + '/' + opts.file; 60 | }); 61 | } 62 | 63 | let cwd = opts.cwd; 64 | if (!cwd) 65 | cwd = process.cwd(); 66 | 67 | let trySpawn = (): void => { 68 | let cmd = cmds.shift(); 69 | syscall.spawn(cwd, cmd, opts.args, opts.envPairs, files, (err: any, pid: number) => { 70 | if (err === -ENOENT && cmds.length) { 71 | trySpawn(); 72 | return; 73 | } else if (err) { 74 | if (this.onexit) 75 | this.onexit(-128, -1); 76 | return; 77 | } 78 | this.pid = pid; 79 | syscall.addEventListener('child', this.handleSigchild.bind(this)); 80 | }); 81 | }; 82 | 83 | trySpawn(); 84 | 85 | return null; 86 | } 87 | 88 | close(): void { 89 | // TODO: anything we need to take care of w.r.t. HandleWrap? 90 | } 91 | 92 | ref(): void { 93 | // TODO: ref 94 | console.log('TODO: Process.ref'); 95 | } 96 | 97 | unref(): void { 98 | // TODO: unref 99 | console.log('TODO: Process.unref'); 100 | } 101 | 102 | handleSigchild(data: SyscallResponse): void { 103 | let pid = data.args[0]; 104 | if (pid !== this.pid) { 105 | return; 106 | } 107 | let exitCode = data.args[1]; 108 | let signalCode = data.args[2]; 109 | if (this.onexit) 110 | this.onexit(exitCode, signalCode); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/browser-node/binding/spawn_sync.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export function spawn(): any { 4 | (console).trace('TODO: cry if someone asks for spawn_sync'); 5 | return null; 6 | } 7 | -------------------------------------------------------------------------------- /src/browser-node/binding/stream_wrap.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | export class StreamWrap { 5 | constructor() { 6 | } 7 | } 8 | 9 | 10 | export class ShutdownWrap { 11 | constructor() { 12 | (console).trace('TODO: someone wants a shutdown_wrap'); 13 | } 14 | } 15 | 16 | export class WriteWrap { 17 | handle: any; 18 | oncomplete: Function; 19 | async: boolean; 20 | } 21 | -------------------------------------------------------------------------------- /src/browser-node/binding/timer_wrap.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let nowFn: ()=>number; 4 | 5 | if (typeof performance !== 'undefined') { 6 | nowFn = performance.now.bind(performance); 7 | } else { 8 | nowFn = function(): number { 9 | let [sec, nanosec] = process.hrtime(); 10 | return sec*1e3 + nanosec/1e6; 11 | }; 12 | } 13 | 14 | 15 | export class Timer { 16 | 17 | when: any; 18 | 19 | static now(): number { 20 | return nowFn(); 21 | } 22 | 23 | constructor() { 24 | } 25 | 26 | start(msecs: number): number { 27 | //setTimeout(msecs); 28 | //debugger; 29 | (console).trace('TODO: someone wants a start'); 30 | return 0; 31 | } 32 | stop(): number { 33 | (console).trace('TODO: someone wants a stop'); 34 | return 0; 35 | } 36 | close(): void { 37 | (console).trace('TODO: someone wants a close'); 38 | 39 | } 40 | ref(): void {} 41 | unref(): void {} 42 | } 43 | -------------------------------------------------------------------------------- /src/browser-node/binding/tty_wrap.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export class TTY { 4 | constructor() { 5 | (console).trace('TODO: someone wants a tty'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/browser-node/binding/udp_wrap.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | export class UDP { 5 | constructor() { 6 | (console).trace('TODO: someone wants a UDP'); 7 | } 8 | } 9 | 10 | export class SendWrap { 11 | constructor() { 12 | (console).trace('TODO: someone wants a SendWrap'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/browser-node/binding/util.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export function isMapIterator(arg: any): boolean { 4 | console.log('TODO: isMapIterator'); 5 | return false; 6 | } 7 | 8 | export function isSetIterator(arg: any): boolean { 9 | console.log('TODO: isSetIterator'); 10 | return false; 11 | } 12 | -------------------------------------------------------------------------------- /src/browser-node/binding/uv.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as constants from './constants'; 4 | 5 | export const UV_EOF = -0xfff; 6 | 7 | export const UV_EAGAIN = constants.EAGAIN; 8 | export const UV_EMFILE = constants.EMFILE; 9 | export const UV_ENFILE = constants.ENFILE; 10 | export const UV_ENOENT = constants.ENOENT; 11 | 12 | 13 | // enum uv_stdio_flags 14 | export const UV_IGNORE = 0x00; 15 | export const UV_CREATE_PIPE = 0x01; 16 | export const UV_INHERIT_FD = 0x02; 17 | export const UV_INHERIT_STREAM = 0x04; 18 | // When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and 19 | // UV_WRITABLE_PIPE determine the direction of flow, from the child 20 | // process' perspective. Both flags may be specified to create a 21 | // duplex data stream. 22 | export const UV_READABLE_PIPE = 0x10; 23 | export const UV_WRITABLE_PIPE = 0x20; 24 | 25 | 26 | // enum uv_process_flags 27 | 28 | // Set the child process' user id. The user id is supplied in the 29 | // `uid` field of the options struct. This does not work on windows; 30 | // setting this flag will cause uv_spawn() to fail. 31 | export const UV_PROCESS_SETUID = (1 << 0); 32 | // Set the child process' group id. The user id is supplied in the 33 | // `gid` field of the options struct. This does not work on windows; 34 | // setting this flag will cause uv_spawn() to fail. 35 | export const UV_PROCESS_SETGID = (1 << 1); 36 | // Do not wrap any arguments in quotes, or perform any other escaping, 37 | // when converting the argument list into a command line string. This 38 | // option is only meaningful on Windows systems. On Unix it is 39 | // silently ignored. 40 | export const UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2); 41 | // Spawn the child process in a detached state - this will make it a 42 | // process group leader, and will effectively enable the child to keep 43 | // running after the parent exits. Note that the child process will 44 | // still keep the parent's event loop alive unless the parent process 45 | // calls uv_unref() on the child's process handle. 46 | export const UV_PROCESS_DETACHED = (1 << 3); 47 | // Hide the subprocess console window that would normally be 48 | // created. This option is only meaningful on Windows systems. On Unix 49 | // it is silently ignored. 50 | export const UV_PROCESS_WINDOWS_HIDE = (1 << 4); 51 | 52 | 53 | export function errname(arg: any): string { 54 | // FIXME: actual errname implementation 55 | return '' + arg; 56 | } 57 | -------------------------------------------------------------------------------- /src/browser-node/ipc.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Browsix Authors. All rights reserved. 2 | // Use of this source code is governed by the ISC 3 | // license that can be found in the LICENSE file. 4 | 5 | 'use strict'; 6 | 7 | // use performance.now in the browser, and hrtime under node. 8 | let nowFn: () => number; 9 | if (typeof performance !== 'undefined') { 10 | nowFn = performance.now.bind(performance); 11 | } else { 12 | nowFn = function(): number { 13 | let [sec, nanosec] = process.hrtime(); 14 | return sec*1e3 + nanosec/1e6; 15 | }; 16 | } 17 | 18 | export const now = nowFn; 19 | -------------------------------------------------------------------------------- /src/ipc.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Browsix Authors. All rights reserved. 2 | // Use of this source code is governed by the ISC 3 | // license that can be found in the LICENSE file. 4 | 5 | /// 6 | 7 | 'use strict'; 8 | 9 | export var now: () => number; 10 | 11 | // use performance.now in the browser, and hrtime under node. 12 | if (typeof performance !== 'undefined') { 13 | now = performance.now.bind(performance); 14 | } else { 15 | now = function(): number { 16 | let [sec, nanosec] = process.hrtime(); 17 | return sec*1e3 + nanosec/1e6; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /src/kernel/ipc.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Browsix Authors. All rights reserved. 2 | // Use of this source code is governed by the ISC 3 | // license that can be found in the LICENSE file. 4 | 5 | 'use strict'; 6 | 7 | // use performance.now in the browser, and hrtime under node. 8 | let nowFn: () => number; 9 | if (typeof performance !== 'undefined') { 10 | nowFn = performance.now.bind(performance); 11 | } else { 12 | nowFn = function(): number { 13 | let [sec, nanosec] = process.hrtime(); 14 | return sec*1e3 + nanosec/1e6; 15 | }; 16 | } 17 | 18 | export const now = nowFn; 19 | -------------------------------------------------------------------------------- /src/kernel/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2016 UMass Amherst. All rights reserved. 2 | // Use of this source code is governed by the ISC 3 | // license that can be found in the LICENSE file. 4 | 5 | 'use strict'; 6 | 7 | export interface ExitCallback { 8 | (pid: number, code: number): void; 9 | } 10 | 11 | export interface OutputCallback { 12 | // TODO: change from string to Buffer 13 | (pid: number, output: string): void; 14 | } 15 | 16 | export interface RWCallback { 17 | (err: number, len?: number): void; 18 | } 19 | 20 | export interface SyscallResult { 21 | id: number; 22 | name: string; 23 | args: any[]; 24 | } 25 | 26 | export interface ConnectCallback { 27 | (err: number): void; 28 | } 29 | 30 | export interface IKernel { 31 | fs: any; // FIXME 32 | 33 | nCPUs: number; 34 | debug: boolean; 35 | 36 | system(cmd: string, onExit: ExitCallback, onStdout: OutputCallback, onStderr: OutputCallback): void; 37 | exit(task: ITask, code: number): void; 38 | wait(pid: number): void; 39 | doSyscall(syscall: Syscall): void; 40 | connect(s: IFile, addr: string, port: number, cb: ConnectCallback): void; 41 | unbind(s: IFile, addr: string, port: number): any; 42 | 43 | once(event: string, cb: Function): any; 44 | } 45 | 46 | export interface Environment { 47 | [name: string]: string; 48 | } 49 | 50 | export interface IFile { 51 | port?: number; 52 | addr?: string; 53 | 54 | write(buf: Buffer, pos: number, cb: (err: any, len?: number) => void): void; 55 | read(buf: Buffer, pos: number, cb: (err: any, len?: number) => void): void; 56 | stat(cb: (err: any, stats: any) => void): void; 57 | llseek(offhi: number, offlo: number, whence: number, cb: (err: number, off: number) => void): void; 58 | readdir(cb: (err: any, files: string[]) => void): void; 59 | 60 | ref(): void; 61 | unref(): void; 62 | } 63 | 64 | export interface ITask { 65 | kernel: IKernel; 66 | parent: ITask; 67 | worker: Worker; 68 | 69 | pid: number; 70 | files: {[n: number]: IFile; }; 71 | 72 | exitCode: number; 73 | 74 | exePath: string; 75 | args: string[]; 76 | env: Environment; 77 | cwd: string; 78 | priority: number; 79 | 80 | personality(kind: number, sab: SharedArrayBuffer, off: number, cb: (err: any) => void): void; 81 | exec(filename: string, args: string[], env: Environment, cb: (err: any, pid: number) => void): void; 82 | allocFD(): number; 83 | addFile(f: IFile): number; 84 | schedule(msg: SyscallResult): void; 85 | setPriority(prio: number): number; 86 | wait4(pid: number, options: number, cb: (pid: number, wstatus?: number, rusage?: any) => void): void; 87 | chdir(path: string, cb: Function): void; 88 | } 89 | 90 | export class SyscallContext { 91 | constructor( 92 | public task: ITask, 93 | public id: number) {} 94 | 95 | complete(...args: any[]): void { 96 | this.task.schedule({ 97 | id: this.id, 98 | name: undefined, 99 | args: args, 100 | }); 101 | } 102 | } 103 | 104 | export class Syscall { 105 | private static requiredOnData: string[] = ['id', 'name', 'args']; 106 | 107 | static From(task: ITask, ev: MessageEvent): Syscall { 108 | if (!ev.data) 109 | return; 110 | for (let i = 0; i < Syscall.requiredOnData.length; i++) { 111 | if (!ev.data.hasOwnProperty(Syscall.requiredOnData[i])) 112 | return; 113 | } 114 | let ctx = new SyscallContext(task, ev.data.id); 115 | return new Syscall(ctx, ev.data.name, ev.data.args); 116 | } 117 | 118 | constructor( 119 | public ctx: SyscallContext, 120 | public name: string, 121 | public args: any[]) {} 122 | 123 | callArgs(): any[] { 124 | return [this.ctx].concat(this.args); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/syscall-api/generate-table.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LINUX_SRC="$HOME/src/linux" 4 | SYSCALLS="$(cat $LINUX_SRC/arch/x86/entry/syscalls/syscall_64.tbl)" 5 | 6 | TABLE="$(echo -n "$SYSCALLS" | grep -v 'x32' | grep '^[0-9]' | awk '{print("\tsys_ni_syscall, "// $1 " " $3)}')" 7 | 8 | cat >table.ts < { process.emit('ready'); }, 0); 82 | } 83 | 84 | declare var global: any; 85 | declare var exports: any; 86 | if (typeof window !== "undefined") { /* web page */ 87 | (window).$syscall = exports; 88 | (window).process = process; 89 | } else if (typeof self !== "undefined") { /* web worker */ 90 | (self).$syscall = exports; 91 | (self).process = process; 92 | } else if (typeof global !== "undefined") { /* Node.js */ 93 | (global).$syscall = exports; 94 | //(global).process = process; 95 | } else { /* others (e.g. Nashorn) */ 96 | (this).$syscall = exports; 97 | (this).process = process; 98 | } 99 | -------------------------------------------------------------------------------- /test/test-all.ts: -------------------------------------------------------------------------------- 1 | require('./test-stat'); 2 | require('./test-cat'); 3 | require('./test-echo'); 4 | require('./test-xhrfs'); 5 | require('./test-exec'); 6 | require('./test-head'); 7 | require('./test-rm'); 8 | require('./test-tail'); 9 | require('./test-sh'); 10 | require('./test-pipeline-example'); 11 | require('./test-wc'); 12 | require('./test-rmdir'); 13 | require('./test-mkdir'); 14 | require('./test-ls'); 15 | require('./test-sort'); 16 | require('./test-tee'); 17 | require('./test-xargs'); 18 | require('./test-cp'); 19 | -------------------------------------------------------------------------------- /test/test-cat.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-cat'; 14 | 15 | describe('cat /a /b', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | const A_CONTENTS = 'contents of a'; 19 | const B_CONTENTS = 'wish you were here'; 20 | let kernel: Kernel = null; 21 | 22 | it('should boot', function(done: MochaDone): void { 23 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 24 | expect(err).to.be.null; 25 | expect(freshKernel).not.to.be.null; 26 | kernel = freshKernel; 27 | done(); 28 | }); 29 | }); 30 | 31 | it('should create /a', function(done: MochaDone): void { 32 | kernel.fs.writeFile('/a', A_CONTENTS, function(err: any): void { 33 | expect(err).to.be.undefined; 34 | done(); 35 | }); 36 | }); 37 | 38 | it('should create /b', function(done: MochaDone): void { 39 | kernel.fs.writeFile('/b', B_CONTENTS, function(err: any): void { 40 | expect(err).to.be.undefined; 41 | done(); 42 | }); 43 | }); 44 | 45 | it('should run `cat /a /b`', function(done: MochaDone): void { 46 | let stdout = ''; 47 | let stderr = ''; 48 | kernel.system('/usr/bin/cat /a /b', onExit, onStdout, onStderr); 49 | function onStdout(pid: number, out: string): void { 50 | stdout += out; 51 | } 52 | function onStderr(pid: number, out: string): void { 53 | stderr += out; 54 | } 55 | function onExit(pid: number, code: number): void { 56 | try { 57 | expect(code).to.equal(0); 58 | expect(stdout).to.equal(A_CONTENTS + B_CONTENTS); 59 | expect(stderr).to.equal(''); 60 | done(); 61 | } catch (e) { 62 | done(e); 63 | } 64 | } 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /test/test-echo.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-echo'; 14 | 15 | describe('echo a b c', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | let kernel: Kernel = null; 19 | 20 | it('should boot', function(done: MochaDone): void { 21 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 22 | expect(err).to.be.null; 23 | expect(freshKernel).not.to.be.null; 24 | kernel = freshKernel; 25 | done(); 26 | }); 27 | }); 28 | 29 | it('should run `echo a b c`', function(done: MochaDone): void { 30 | let stdout: string = ''; 31 | let stderr: string = ''; 32 | kernel.system('/usr/bin/echo a b c', onExit, onStdout, onStderr); 33 | function onStdout(pid: number, out: string): void { 34 | stdout += out; 35 | } 36 | function onStderr(pid: number, out: string): void { 37 | stderr += out; 38 | } 39 | function onExit(pid: number, code: number): void { 40 | try { 41 | expect(code).to.equal(0); 42 | expect(stdout).to.equal('a b c\n'); 43 | expect(stderr).to.equal(''); 44 | done(); 45 | } catch (e) { 46 | done(e); 47 | } 48 | } 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /test/test-exec.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | import { ENOENT } from '../lib/kernel/constants'; 6 | 7 | const expect = chai.expect; 8 | 9 | const MINS = 60 * 1000; // milliseconds 10 | 11 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 12 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 13 | 14 | export const name = 'test-exec'; 15 | 16 | describe('echo a b c', function(): void { 17 | this.timeout(10 * MINS); 18 | 19 | let kernel: Kernel = null; 20 | 21 | it('should boot', function(done: MochaDone): void { 22 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 23 | expect(err).to.be.null; 24 | expect(freshKernel).not.to.be.null; 25 | kernel = freshKernel; 26 | done(); 27 | }); 28 | }); 29 | 30 | it('should run `exec /usr/bin/echo hi`', function(done: MochaDone): void { 31 | let stdout: string = ''; 32 | let stderr: string = ''; 33 | kernel.system('/usr/bin/exec /usr/bin/echo hi', onExit, onStdout, onStderr); 34 | function onStdout(pid: number, out: string): void { 35 | stdout += out; 36 | } 37 | function onStderr(pid: number, out: string): void { 38 | stderr += out; 39 | } 40 | function onExit(pid: number, code: number): void { 41 | try { 42 | expect(code).to.equal(0); 43 | expect(stdout).to.equal('hi\n'); 44 | expect(stderr).to.equal(''); 45 | done(); 46 | } catch (e) { 47 | done(e); 48 | } 49 | } 50 | }); 51 | 52 | it('should run `exec echo hi`', function(done: MochaDone): void { 53 | let stdout: string = ''; 54 | let stderr: string = ''; 55 | kernel.system('/usr/bin/exec echo hi', onExit, onStdout, onStderr); 56 | function onStdout(pid: number, out: string): void { 57 | stdout += out; 58 | } 59 | function onStderr(pid: number, out: string): void { 60 | stderr += out; 61 | } 62 | function onExit(pid: number, code: number): void { 63 | try { 64 | expect(code).to.equal(0); 65 | expect(stdout).to.equal('hi\n'); 66 | expect(stderr).to.equal(''); 67 | done(); 68 | } catch (e) { 69 | done(e); 70 | } 71 | } 72 | }); 73 | 74 | it('should fail `system /non/existent/cmd`', function(done: MochaDone): void { 75 | let stdout: string = ''; 76 | let stderr: string = ''; 77 | kernel.system('/non/existent/cmd', onExit, onStdout, onStderr); 78 | function onStdout(pid: number, out: string): void { 79 | stdout += out; 80 | } 81 | function onStderr(pid: number, out: string): void { 82 | stderr += out; 83 | } 84 | function onExit(pid: number, code: number): void { 85 | try { 86 | expect(code).to.equal(-ENOENT); 87 | expect(stdout).to.equal(''); 88 | expect(stderr).to.not.equal(''); 89 | done(); 90 | } catch (e) { 91 | done(e); 92 | } 93 | } 94 | }); 95 | }); 96 | -------------------------------------------------------------------------------- /test/test-grep.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-grep'; 14 | 15 | describe('grep /a /b', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | const A_CONTENTS = 'the horse raced\npast the barn fell.'; 19 | const B_CONTENTS = 'the past plate\npassed last.'; 20 | let kernel: Kernel = null; 21 | 22 | it('should boot', function(done: MochaDone): void { 23 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 24 | expect(err).to.be.null; 25 | expect(freshKernel).not.to.be.null; 26 | kernel = freshKernel; 27 | done(); 28 | }); 29 | }); 30 | 31 | it('should create /a', function(done: MochaDone): void { 32 | kernel.fs.writeFile('/a', A_CONTENTS, function(err: any): void { 33 | expect(err).to.be.undefined; 34 | done(); 35 | }); 36 | }); 37 | 38 | it('should create /b', function(done: MochaDone): void { 39 | kernel.fs.writeFile('/b', B_CONTENTS, function(err: any): void { 40 | expect(err).to.be.undefined; 41 | done(); 42 | }); 43 | }); 44 | 45 | it('should run `grep past /a /b`', function(done: MochaDone): void { 46 | let stdout: string = ''; 47 | let stderr: string = ''; 48 | kernel.system('/usr/bin/grep past /a /b', onExit, onStdout, onStderr); 49 | function onStdout(pid: number, out: string): void { 50 | stdout += out; 51 | } 52 | function onStderr(pid: number, out: string): void { 53 | stderr += out; 54 | } 55 | function onExit(pid: number, code: number): void { 56 | try { 57 | expect(code).to.equal(0); 58 | expect(stdout).to.equal('past the barn fell.\nthe past plate.'); 59 | expect(stderr).to.equal(""); 60 | done(); 61 | } catch (e) { 62 | done(e); 63 | } 64 | } 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /test/test-head.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-head'; 14 | 15 | describe('head /a', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | const A_CONTENTS = 'line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10\nline 11\n'; 19 | let kernel: Kernel = null; 20 | 21 | it('should boot', function(done: MochaDone): void { 22 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 23 | expect(err).to.be.null; 24 | expect(freshKernel).not.to.be.null; 25 | kernel = freshKernel; 26 | done(); 27 | }); 28 | }); 29 | 30 | it('should create /a', function(done: MochaDone): void { 31 | kernel.fs.writeFile('/a', A_CONTENTS, function(err: any): void { 32 | expect(err).to.be.undefined; 33 | done(); 34 | }); 35 | }); 36 | 37 | it('should run `head /a`', function(done: MochaDone): void { 38 | let stdout: string = ''; 39 | let stderr: string = ''; 40 | kernel.system('/usr/bin/head /a', onExit, onStdout, onStderr); 41 | function onStdout(pid: number, out: string): void { 42 | stdout += out; 43 | } 44 | function onStderr(pid: number, out: string): void { 45 | stderr += out; 46 | } 47 | function onExit(pid: number, code: number): void { 48 | try { 49 | expect(code).to.equal(0); 50 | expect(stdout).to.equal('line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10\n'); 51 | expect(stderr).to.equal(''); 52 | done(); 53 | } catch (e) { 54 | done(e); 55 | } 56 | } 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /test/test-ls.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-ls'; 14 | 15 | describe('ls /boot', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | let kernel: Kernel = null; 19 | 20 | it('should boot', function(done: MochaDone): void { 21 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 22 | expect(err).to.be.null; 23 | expect(freshKernel).not.to.be.null; 24 | kernel = freshKernel; 25 | done(); 26 | }); 27 | }); 28 | 29 | it('should run `ls /boot`', function(done: MochaDone): void { 30 | let stdout = ''; 31 | let stderr = ''; 32 | kernel.system('/usr/bin/ls /boot', onExit, onStdout, onStderr); 33 | function onStdout(pid: number, out: string): void { 34 | stdout += out; 35 | } 36 | function onStderr(pid: number, out: string): void { 37 | stderr += out; 38 | } 39 | function onExit(pid: number, code: number): void { 40 | try { 41 | expect(code).to.equal(0); 42 | expect(stdout).to.equal('kernel.js\n'); 43 | expect(stderr).to.equal(''); 44 | done(); 45 | } catch (e) { 46 | done(e); 47 | } 48 | } 49 | }); 50 | 51 | it('should NOT run `ls -w`', function(done: MochaDone): void { 52 | let stdout = ''; 53 | let stderr = ''; 54 | kernel.system('/usr/bin/ls -w', onExit, onStdout, onStderr); 55 | function onStdout(pid: number, out: string): void { 56 | stdout += out; 57 | } 58 | function onStderr(pid: number, out: string): void { 59 | stderr += out; 60 | } 61 | function onExit(pid: number, code: number): void { 62 | try { 63 | expect(code).to.equal(1); 64 | expect(stdout).to.equal(''); 65 | expect(stderr).to.equal('ls: invalid option "w"\nusage: ls [-1ahl] ARGS\n'); 66 | done(); 67 | } catch (e) { 68 | done(e); 69 | } 70 | } 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /test/test-mkdir.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-mkdir'; 14 | 15 | describe('mkdir /a', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | const A_CONTENTS = 'contents of a'; 19 | let kernel: Kernel = null; 20 | 21 | it('should boot', function(done: MochaDone): void { 22 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 23 | expect(err).to.be.null; 24 | expect(freshKernel).not.to.be.null; 25 | kernel = freshKernel; 26 | done(); 27 | }); 28 | }); 29 | 30 | it('should run `mkdir /a`', function(done: MochaDone): void { 31 | let stdout = ''; 32 | let stderr = ''; 33 | kernel.system('mkdir /a', onExit, onStdout, onStderr); 34 | function onStdout(pid: number, out: string): void { 35 | stdout += out; 36 | } 37 | function onStderr(pid: number, out: string): void { 38 | stderr += out; 39 | } 40 | function onExit(pid: number, code: number): void { 41 | try { 42 | expect(code).to.equal(0); 43 | expect(stdout).to.equal(''); 44 | expect(stderr).to.equal(''); 45 | done(); 46 | } catch (e) { 47 | done(e); 48 | } 49 | } 50 | }); 51 | it('should have /a', function(done: MochaDone): void { 52 | kernel.fs.stat('/a', function(err: any, stat: any): void { 53 | expect(err).to.be.null; 54 | expect(stat).not.to.be.null; 55 | done(); 56 | }); 57 | }); 58 | 59 | it('should run `mkdir -p /b/c/d e f/g/h`', function(done: MochaDone): void { 60 | let stdout = ''; 61 | let stderr = ''; 62 | kernel.system('mkdir -p /b/c/d e f/g/h', onExit, onStdout, onStderr); 63 | function onStdout(pid: number, out: string): void { 64 | stdout += out; 65 | } 66 | function onStderr(pid: number, out: string): void { 67 | stderr += out; 68 | } 69 | function onExit(pid: number, code: number): void { 70 | try { 71 | expect(code).to.equal(0); 72 | expect(stdout).to.equal(''); 73 | expect(stderr).to.equal(''); 74 | done(); 75 | } catch (e) { 76 | done(e); 77 | } 78 | } 79 | }); 80 | it('should error out on `mkdir -p`', function(done: MochaDone): void { 81 | let stdout = ''; 82 | let stderr = ''; 83 | kernel.system('mkdir -p', onExit, onStdout, onStderr); 84 | function onStdout(pid: number, out: string): void { 85 | stdout += out; 86 | } 87 | function onStderr(pid: number, out: string): void { 88 | stderr += out; 89 | } 90 | function onExit(pid: number, code: number): void { 91 | try { 92 | expect(code).to.equal(1); 93 | expect(stdout).to.equal(''); 94 | expect(stderr).to.equal('usage: mkdir [-hp] ARGS\n'); 95 | done(); 96 | } catch (e) { 97 | done(e); 98 | } 99 | } 100 | }); 101 | it('should have /b/c/d', function(done: MochaDone): void { 102 | kernel.fs.stat('/b/c/d', function(err: any, stat: any): void { 103 | expect(err).to.be.null; 104 | expect(stat).not.to.be.null; 105 | done(); 106 | }); 107 | }); 108 | it('should have a', function(done: MochaDone): void { 109 | kernel.fs.stat('/a', function(err: any, stat: any): void { 110 | expect(err).to.be.null; 111 | expect(stat).not.to.be.null; 112 | done(); 113 | }); 114 | }); 115 | it('should have f/g/h', function(done: MochaDone): void { 116 | kernel.fs.stat('/f/g/h', function(err: any, stat: any): void { 117 | expect(err).to.be.null; 118 | expect(stat).not.to.be.null; 119 | done(); 120 | }); 121 | }); 122 | 123 | 124 | }); 125 | -------------------------------------------------------------------------------- /test/test-nice.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-nice'; 14 | 15 | describe('nice -n 10 nice', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | let kernel: Kernel = null; 19 | 20 | it('should boot', function(done: MochaDone): void { 21 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 22 | expect(err).to.be.null; 23 | expect(freshKernel).not.to.be.null; 24 | kernel = freshKernel; 25 | done(); 26 | }); 27 | }); 28 | 29 | it('should run `nice -n 10 nice`', function(done: MochaDone): void { 30 | let stdout: string = ''; 31 | let stderr: string = ''; 32 | kernel.system('nice -n 10 nice', onExit, onStdout, onStderr); 33 | function onStdout(pid: number, out: string): void { 34 | stdout += out; 35 | } 36 | function onStderr(pid: number, out: string): void { 37 | stderr += out; 38 | } 39 | function onExit(pid: number, code: number): void { 40 | try { 41 | expect(code).to.equal(0); 42 | expect(stdout).to.equal('10\n'); 43 | expect(stderr).to.equal(''); 44 | done(); 45 | } catch (e) { 46 | done(e); 47 | } 48 | } 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /test/test-pipeline-example.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-pipeline-example'; 14 | 15 | describe('echo a b c', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | let kernel: Kernel = null; 19 | 20 | it('should boot', function(done: MochaDone): void { 21 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 22 | expect(err).to.be.null; 23 | expect(freshKernel).not.to.be.null; 24 | kernel = freshKernel; 25 | done(); 26 | }); 27 | }); 28 | 29 | it('should run `echo a b c`', function(done: MochaDone): void { 30 | let stdout = ''; 31 | let stderr = ''; 32 | kernel.system('/usr/bin/pipeline-example', onExit, onStdout, onStderr); 33 | function onStdout(pid: number, out: string): void { 34 | stdout += out; 35 | } 36 | function onStderr(pid: number, out: string): void { 37 | stderr += out; 38 | } 39 | function onExit(pid: number, code: number): void { 40 | try { 41 | expect(code).to.equal(0); 42 | expect(stdout).to.equal('hello world\n'); 43 | expect(stderr).to.equal(''); 44 | done(); 45 | } catch (e) { 46 | done(e); 47 | } 48 | } 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /test/test-rmdir.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-rmdir'; 14 | 15 | describe('rmdir /a', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | const A_CONTENTS = 'contents of a'; 19 | let kernel: Kernel = null; 20 | 21 | it('should boot', function(done: MochaDone): void { 22 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 23 | expect(err).to.be.null; 24 | expect(freshKernel).not.to.be.null; 25 | kernel = freshKernel; 26 | done(); 27 | }); 28 | }); 29 | 30 | it('should create /a', function(done: MochaDone): void { 31 | kernel.fs.mkdir('/a', function(err: any): void { 32 | expect(err).to.be.undefined; 33 | done(); 34 | }); 35 | }); 36 | 37 | it('should run `rmdir /a`', function(done: MochaDone): void { 38 | let stdout = ''; 39 | let stderr = ''; 40 | kernel.system('/usr/bin/rmdir /a', onExit, onStdout, onStderr); 41 | function onStdout(pid: number, out: string): void { 42 | stdout += out; 43 | } 44 | function onStderr(pid: number, out: string): void { 45 | stderr += out; 46 | } 47 | function onExit(pid: number, code: number): void { 48 | try { 49 | expect(code).to.equal(0); 50 | expect(stdout).to.equal(''); 51 | expect(stderr).to.equal(''); 52 | done(); 53 | } catch (e) { 54 | done(e); 55 | } 56 | } 57 | }); 58 | it('should remove /a', function(done: MochaDone): void { 59 | kernel.fs.stat('/a', function(err: any): void { 60 | expect(err); 61 | done(); 62 | }); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /test/test-sh.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-sh'; 14 | 15 | describe('sh "/usr/bin/cat /a /b | /usr/bin/head"', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | const A_CONTENTS = 'contents of a'; 19 | const B_CONTENTS = 'wish you were here'; 20 | let kernel: Kernel = null; 21 | 22 | it('should boot', function(done: MochaDone): void { 23 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 24 | expect(err).to.be.null; 25 | expect(freshKernel).not.to.be.null; 26 | kernel = freshKernel; 27 | done(); 28 | }); 29 | }); 30 | 31 | it('should create /a', function(done: MochaDone): void { 32 | kernel.fs.writeFile('/a', A_CONTENTS, function(err: any): void { 33 | expect(err).to.be.undefined; 34 | done(); 35 | }); 36 | }); 37 | 38 | it('should create /b', function(done: MochaDone): void { 39 | kernel.fs.writeFile('/b', B_CONTENTS, function(err: any): void { 40 | expect(err).to.be.undefined; 41 | done(); 42 | }); 43 | }); 44 | 45 | it('should run `sh cat /a /b | cat`', function(done: MochaDone): void { 46 | let stdout = ''; 47 | let stderr = ''; 48 | kernel.system('/usr/bin/cat /a /b | cat', onExit, onStdout, onStderr); 49 | function onStdout(pid: number, out: string): void { 50 | stdout += out; 51 | } 52 | function onStderr(pid: number, out: string): void { 53 | stderr += out; 54 | } 55 | function onExit(pid: number, code: number): void { 56 | try { 57 | expect(code).to.equal(0); 58 | expect(stdout).to.equal(A_CONTENTS + B_CONTENTS); 59 | expect(stderr).to.equal(''); 60 | done(); 61 | } catch (e) { 62 | done(e); 63 | } 64 | } 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /test/test-sort.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-sort'; 14 | 15 | describe('sort /a /b', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | const A_CONTENTS = 'z\ny\nx\n'; 19 | const B_CONTENTS = 'b\nc\na\n'; 20 | let kernel: Kernel = null; 21 | 22 | it('should boot', function(done: MochaDone): void { 23 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 24 | expect(err).to.be.null; 25 | expect(freshKernel).not.to.be.null; 26 | kernel = freshKernel; 27 | done(); 28 | }); 29 | }); 30 | 31 | it('should create /a', function(done: MochaDone): void { 32 | kernel.fs.writeFile('/a', A_CONTENTS, function(err: any): void { 33 | expect(err).to.be.undefined; 34 | done(); 35 | }); 36 | }); 37 | 38 | it('should create /b', function(done: MochaDone): void { 39 | kernel.fs.writeFile('/b', B_CONTENTS, function(err: any): void { 40 | expect(err).to.be.undefined; 41 | done(); 42 | }); 43 | }); 44 | 45 | it('should run `sort /a /b`', function(done: MochaDone): void { 46 | let stdout: string = ''; 47 | let stderr: string = ''; 48 | kernel.system('/usr/bin/sort /a /b', onExit, onStdout, onStderr); 49 | function onStdout(pid: number, out: string): void { 50 | stdout += out; 51 | } 52 | function onStderr(pid: number, out: string): void { 53 | stderr += out; 54 | } 55 | function onExit(pid: number, code: number): void { 56 | try { 57 | expect(code).to.equal(0); 58 | expect(stdout).to.equal(['a', 'b', 'c', 'x', 'y', 'z'].join('\n') + '\n'); 59 | expect(stderr).to.equal(''); 60 | done(); 61 | } catch (e) { 62 | done(e); 63 | } 64 | } 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /test/test-stat.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-stat'; 14 | 15 | describe('stat /a', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | const A_CONTENTS = 'contents of a'; 19 | let kernel: Kernel = null; 20 | 21 | it('should boot', function(done: MochaDone): void { 22 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 23 | expect(err).to.be.null; 24 | expect(freshKernel).not.to.be.null; 25 | kernel = freshKernel; 26 | done(); 27 | }); 28 | }); 29 | 30 | it('should create /a', function(done: MochaDone): void { 31 | kernel.fs.writeFile('/a', A_CONTENTS, function(err: any): void { 32 | expect(err).to.be.undefined; 33 | done(); 34 | }); 35 | }); 36 | 37 | it('should run `stat /a`', function(done: MochaDone): void { 38 | let stdout = ''; 39 | let stderr = ''; 40 | kernel.system('/usr/bin/stat /a', onExit, onStdout, onStderr); 41 | function onStdout(pid: number, out: string): void { 42 | stdout += out; 43 | } 44 | function onStderr(pid: number, out: string): void { 45 | stderr += out; 46 | } 47 | function onExit(pid: number, code: number): void { 48 | expect(code).to.equal(0); 49 | let re = new RegExp('Size', 'g'); 50 | let i = stdout.search(re); 51 | let offset = "Size: ".length; 52 | let size = stdout.slice(i + offset, i + offset + 2); 53 | expect(size).to.equal('13'); 54 | expect(stderr).to.equal(''); 55 | done(); 56 | } 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /test/test-tail.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-tail'; 14 | 15 | describe('tail /a', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | const A_CONTENTS = 'line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10\nline 11\n'; 19 | let kernel: Kernel = null; 20 | 21 | it('should boot', function(done: MochaDone): void { 22 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 23 | expect(err).to.be.null; 24 | expect(freshKernel).not.to.be.null; 25 | kernel = freshKernel; 26 | done(); 27 | }); 28 | }); 29 | 30 | it('should create /a', function(done: MochaDone): void { 31 | kernel.fs.writeFile('/a', A_CONTENTS, function(err: any): void { 32 | expect(err).to.be.undefined; 33 | done(); 34 | }); 35 | }); 36 | 37 | it('should run `tail /a`', function(done: MochaDone): void { 38 | let stdout: string = ''; 39 | let stderr: string = ''; 40 | kernel.system('/usr/bin/tail /a', onExit, onStdout, onStderr); 41 | function onStdout(pid: number, out: string): void { 42 | stdout += out; 43 | } 44 | function onStderr(pid: number, out: string): void { 45 | stderr += out; 46 | } 47 | function onExit(pid: number, code: number): void { 48 | try { 49 | expect(code).to.equal(0); 50 | expect(stdout).to.equal('line 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10\nline 11\n'); 51 | expect(stderr).to.equal(''); 52 | done(); 53 | } catch (e) { 54 | done(e); 55 | } 56 | } 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /test/test-tee.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-tee'; 14 | 15 | describe('echo hi | tee /a', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | let kernel: Kernel = null; 19 | 20 | it('should boot', function(done: MochaDone): void { 21 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 22 | expect(err).to.be.null; 23 | expect(freshKernel).not.to.be.null; 24 | kernel = freshKernel; 25 | done(); 26 | }); 27 | }); 28 | 29 | it('should run `echo hi | tee`', function(done: MochaDone): void { 30 | let stdout: string = ''; 31 | let stderr: string = ''; 32 | kernel.system('echo hi | tee', onExit, onStdout, onStderr); 33 | function onStdout(pid: number, out: string): void { 34 | stdout += out; 35 | } 36 | function onStderr(pid: number, out: string): void { 37 | stderr += out; 38 | } 39 | function onExit(pid: number, code: number): void { 40 | try { 41 | expect(code).to.equal(0); 42 | expect(stdout).to.equal('hi\n'); 43 | expect(stderr).to.equal(''); 44 | done(); 45 | } catch (e) { 46 | done(e); 47 | } 48 | } 49 | }); 50 | 51 | it('should run `echo hi | tee`', function(done: MochaDone): void { 52 | let stdout: string = ''; 53 | let stderr: string = ''; 54 | kernel.system('echo hi | tee /greeting', onExit, onStdout, onStderr); 55 | function onStdout(pid: number, out: string): void { 56 | stdout += out; 57 | } 58 | function onStderr(pid: number, out: string): void { 59 | stderr += out; 60 | } 61 | function onExit(pid: number, code: number): void { 62 | try { 63 | expect(code).to.equal(0); 64 | expect(stdout).to.equal('hi\n'); 65 | expect(stderr).to.equal(''); 66 | done(); 67 | } catch (e) { 68 | done(e); 69 | } 70 | } 71 | }); 72 | 73 | it('should read /greeting', function(done: MochaDone): void { 74 | kernel.fs.readFile('/greeting', 'utf-8', function(err: any, contents: string): void { 75 | expect(err).to.be.undefined; 76 | expect(contents).to.equal('hi\n'); 77 | done(); 78 | }); 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /test/test-touch.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-touch'; 14 | 15 | describe('touch /a', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | const B_CONTENTS = 'wishing you were here'; 19 | let kernel: Kernel = null; 20 | 21 | it('should boot', function(done: MochaDone): void { 22 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 23 | expect(err).to.be.null; 24 | expect(freshKernel).not.to.be.null; 25 | kernel = freshKernel; 26 | done(); 27 | }); 28 | }); 29 | 30 | it('should create /b', function(done: MochaDone): void { 31 | kernel.fs.writeFile('/b', B_CONTENTS, function(err: any): void { 32 | expect(err).to.be.undefined; 33 | done(); 34 | }); 35 | }); 36 | 37 | it('should run `touch /a`', function(done: MochaDone): void { 38 | let stdout = ''; 39 | let stderr = ''; 40 | kernel.system('touch /a', onExit, onStdout, onStderr); 41 | function onStdout(pid: number, out: string): void { 42 | stdout += out; 43 | } 44 | function onStderr(pid: number, out: string): void { 45 | stderr += out; 46 | } 47 | function onExit(pid: number, code: number): void { 48 | try { 49 | expect(code).to.equal(0); 50 | expect(stdout).to.equal(''); 51 | expect(stderr).to.equal(''); 52 | done(); 53 | } catch (e) { 54 | done(e); 55 | } 56 | } 57 | }); 58 | it('should read /a', function(done: MochaDone): void { 59 | kernel.fs.readFile('/a', 'utf-8', function(err: any, contents: string): void { 60 | expect(err).to.be.undefined; 61 | expect(contents).to.equal(''); 62 | done(); 63 | }); 64 | }); 65 | 66 | it('should have new timestamps', function(done: MochaDone): void { 67 | kernel.fs.stat('/a', function(err: any, stats: any): void { 68 | expect(err).to.be.null; 69 | let now = new Date(); 70 | expect(stats.atime === now); 71 | expect(stats.mtime === now); 72 | done(); 73 | }); 74 | }); 75 | /* this doesn't seem to work (code =1). because it already exists and doesn't like to be touched? 76 | it('should run `touch /b`', function(done: MochaDone): void { 77 | kernel.system('touch /b', catExited); 78 | function catExited(code: number, stdout: string, stderr: string): void { 79 | try { 80 | expect(code).to.equal(0); 81 | expect(stdout).to.equal(''); 82 | expect(stderr).to.equal(''); 83 | done(); 84 | } catch (e) { 85 | //console.log(e); 86 | done(e); 87 | } 88 | } 89 | }); 90 | */ 91 | }); 92 | -------------------------------------------------------------------------------- /test/test-wc.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-wc'; 14 | 15 | describe('wc /a', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | const A_CONTENTS = 'line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10\nline 11\n'; 19 | let kernel: Kernel = null; 20 | 21 | it('should boot', function(done: MochaDone): void { 22 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 23 | expect(err).to.be.null; 24 | expect(freshKernel).not.to.be.null; 25 | kernel = freshKernel; 26 | done(); 27 | }); 28 | }); 29 | 30 | it('should create /a', function(done: MochaDone): void { 31 | kernel.fs.writeFile('/a', A_CONTENTS, function(err: any): void { 32 | expect(err).to.be.undefined; 33 | done(); 34 | }); 35 | }); 36 | 37 | it('should run `wc /a`', function(done: MochaDone): void { 38 | let stdout = ''; 39 | let stderr = ''; 40 | kernel.system('/usr/bin/wc /a', onExit, onStdout, onStderr); 41 | function onStdout(pid: number, out: string): void { 42 | stdout += out; 43 | } 44 | function onStderr(pid: number, out: string): void { 45 | stderr += out; 46 | } 47 | function onExit(pid: number, code: number): void { 48 | try { 49 | expect(code).to.equal(0); 50 | expect(stdout).to.equal('11\t22\t79\t\n'); 51 | expect(stderr).to.equal(''); 52 | done(); 53 | } catch (e) { 54 | done(e); 55 | } 56 | } 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /test/test-xargs.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | export const name = 'test-xargs'; 14 | 15 | describe('xargs', function(): void { 16 | this.timeout(10 * MINS); 17 | 18 | let kernel: Kernel = null; 19 | 20 | it('should boot', function(done: MochaDone): void { 21 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 22 | expect(err).to.be.null; 23 | expect(freshKernel).not.to.be.null; 24 | kernel = freshKernel; 25 | done(); 26 | }); 27 | }); 28 | 29 | it('should split on "," and pass max 2 args to COMMAND with a char limit of 13 on 1,12,123,12,1,1234', function(done: MochaDone): void { 30 | let stdout: string = ''; 31 | let stderr: string = ''; 32 | kernel.system('/usr/bin/echo 1,12,123,12,1,1234 | /usr/bin/xargs -n 2 -s 13 -d , -x', onExit, onStdout, onStderr); 33 | function onStdout(pid: number, out: string): void { 34 | stdout += out; 35 | } 36 | function onStderr(pid: number, out: string): void { 37 | stderr += out; 38 | } 39 | function onExit(pid: number, code: number): void { 40 | try { 41 | expect(code).to.equal(0); 42 | expect(stdout).to.equal('1 12\n123 12\n1 1234\n'); 43 | expect(stderr).to.equal(''); 44 | done(); 45 | } catch (e) { 46 | done(e); 47 | } 48 | } 49 | }); 50 | 51 | it('should split on "Bar" and limit the query to 8 chars, exit without printing if exceeded on "fooBarfooBarfooBarfoofooBarfoofoo"', function(done: MochaDone): void { 52 | let stdout: string = ''; 53 | let stderr: string = ''; 54 | kernel.system('/usr/bin/echo fooBarfooBarfooBarfoofooBarfoofoo | /usr/bin/xargs -s 8 -d Bar -x', onExit, onStdout, onStderr); 55 | function onStdout(pid: number, out: string): void { 56 | stdout += out; 57 | } 58 | function onStderr(pid: number, out: string): void { 59 | stderr += out; 60 | } 61 | function onExit(pid: number, code: number): void { 62 | try { 63 | let len = 'argument line too long\n'.length; 64 | expect(code).to.not.equal(0); 65 | expect(stdout).to.equal(''); 66 | expect(stderr.substr(0, len)).to.equal('argument line too long\n'); 67 | done(); 68 | } catch (e) { 69 | done(e); 70 | } 71 | } 72 | }); 73 | it('should be verbose and pass 2 args max on "foo bar foo"', function(done: MochaDone): void { 74 | let stdout: string = ''; 75 | let stderr: string = ''; 76 | kernel.system('/usr/bin/echo foo bar foo | /usr/bin/xargs -n 2 -t', onExit, onStdout, onStderr); 77 | function onStdout(pid: number, out: string): void { 78 | stdout += out; 79 | } 80 | function onStderr(pid: number, out: string): void { 81 | stderr += out; 82 | } 83 | function onExit(pid: number, code: number): void { 84 | try { 85 | expect(code).to.equal(0); 86 | expect(stdout).to.equal('echo foo bar\nfoo bar\necho foo\nfoo\n'); 87 | expect(stderr).to.equal(''); 88 | done(); 89 | } catch (e) { 90 | done(e); 91 | } 92 | } 93 | }); 94 | }); 95 | -------------------------------------------------------------------------------- /test/test-xhrfs.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as chai from 'chai'; 4 | import { Boot, Kernel } from '../lib/kernel/kernel'; 5 | 6 | const expect = chai.expect; 7 | 8 | const MINS = 60 * 1000; // milliseconds 9 | 10 | const IS_KARMA = typeof window !== 'undefined' && typeof (window).__karma__ !== 'undefined'; 11 | const ROOT = IS_KARMA ? '/base/fs/' : '/fs/'; 12 | 13 | const NODE = '/usr/bin/node'; 14 | 15 | export const name = 'test-xhrfs'; 16 | 17 | describe('find /bin/node', function(): void { 18 | this.timeout(10 * MINS); 19 | 20 | let kernel: Kernel = null; 21 | 22 | it('should boot', function(done: MochaDone): void { 23 | Boot('XmlHttpRequest', ['index.json', ROOT, true], function(err: any, freshKernel: Kernel): void { 24 | expect(err).to.be.null; 25 | expect(freshKernel).not.to.be.null; 26 | kernel = freshKernel; 27 | done(); 28 | }); 29 | }); 30 | 31 | it('should open /usr/bin/node', function(done: MochaDone): void { 32 | kernel.fs.open('/usr/bin/node', 'r', nodeOpened); 33 | function nodeOpened(err: any, fd: any): void { 34 | try { 35 | expect(err).to.be.null; 36 | expect(fd).not.to.be.null; 37 | done(); 38 | } catch (e) { 39 | done(e); 40 | } 41 | } 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "noImplicitAny": true, 7 | "removeComments": true, 8 | "experimentalDecorators": true, 9 | "newLine": "LF" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "align": [true, 4 | "parameters", 5 | "arguments", 6 | "statements"], 7 | "ban": false, 8 | "class-name": true, 9 | "comment-format": [true 10 | ], 11 | "curly": false, 12 | "eofline": true, 13 | "forin": true, 14 | "indent": [true, "tabs"], 15 | "interface-name": false, 16 | "jsdoc-format": true, 17 | "label-position": true, 18 | "max-line-length": [true, 140], 19 | "member-access": false, 20 | "member-ordering": [true, 21 | "public-before-private", 22 | "static-before-instance", 23 | "variables-before-functions" 24 | ], 25 | "no-any": false, 26 | "no-arg": true, 27 | "no-bitwise": false, 28 | "no-conditional-assignment": false, 29 | "no-console": [true, 30 | "debug", 31 | "info", 32 | "time", 33 | "timeEnd" 34 | ], 35 | "no-construct": true, 36 | "no-constructor-vars": false, 37 | "no-debugger": false, 38 | "no-shadowed-variable": false, 39 | "no-duplicate-variable": true, 40 | "no-empty": false, 41 | "no-eval": true, 42 | "no-internal-module": true, 43 | "no-require-imports": false, 44 | "no-string-literal": false, 45 | "no-switch-case-fall-through": true, 46 | "no-trailing-whitespace": true, 47 | "no-unused-expression": true, 48 | "no-unused-variable": false, 49 | "no-use-before-declare": false, 50 | "no-var-keyword": true, 51 | "no-var-requires": false, 52 | "one-line": [true, 53 | "check-open-brace", 54 | "check-catch", 55 | "check-whitespace" 56 | ], 57 | "radix": true, 58 | "semicolon": true, 59 | "switch-default": false, 60 | "triple-equals": [true, "allow-null-check"], 61 | "typedef": [true, 62 | "call-signature", 63 | "property-declaration", 64 | "member-variable-declaration" 65 | ], 66 | "typedef-whitespace": [true, { 67 | "call-signature": "nospace", 68 | "index-signature": "nospace", 69 | "parameter": "nospace", 70 | "property-declaration": "nospace", 71 | "variable-declaration": "nospace" 72 | }], 73 | "variable-name": false, 74 | "whitespace": [true, 75 | "check-branch", 76 | "check-decl", 77 | "check-separator", 78 | "check-type" 79 | ] 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /xhrfs-index: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // based on jvilk's XHRIndexer, but in plain JS using async APIs 3 | 4 | 'use strict'; 5 | 6 | var fs = require('fs'); 7 | var path = require('path'); 8 | 9 | var exclude = [ 10 | // /^\./, // dotfiles 11 | /^bower_components$/, 12 | /^node_modules$/, 13 | /^build$/, 14 | /^dist$/, 15 | /~$/, // emacs backups 16 | ]; 17 | 18 | function shouldExclude(name) { 19 | for (var i = 0; i < exclude.length; i++) { 20 | if (name.match(exclude[i])) 21 | return true; 22 | } 23 | return false; 24 | } 25 | 26 | var outstanding = 1; 27 | var tree = {}; 28 | 29 | function subtreeAt(relative) { 30 | if (!relative) 31 | return tree; 32 | 33 | var parts = relative.split(path.sep); 34 | var subtree = tree; 35 | // start at 1 to skip the leading / 36 | for (var i = 1; i < parts.length; i++) 37 | subtree = subtree[parts[i]]; 38 | 39 | return subtree; 40 | } 41 | 42 | function maybeFinished(file, err, onComplete) { 43 | if (--outstanding === 0) { 44 | onComplete(err, tree); 45 | } 46 | } 47 | 48 | function walkDir(base, curr, onComplete) { 49 | var parent = curr.slice(base.length); 50 | fs.readdir(curr, function(err, files) { 51 | if (err) { 52 | process.stderr.write('error reading dir: ' + err); 53 | maybeFinished(curr, err, onComplete); 54 | return; 55 | } 56 | for (var i = 0; i < files.length; i++) { 57 | var file = files[i]; 58 | if (shouldExclude(file)) 59 | continue; 60 | 61 | outstanding++; 62 | 63 | var absFile = path.join(curr, file) 64 | fs.stat(absFile, function statFile(absFile, err, stats) { 65 | if (err) { 66 | maybeFinished(absFile, err, onComplete); 67 | return; 68 | } 69 | var parts = absFile.split(path.sep); 70 | var file = parts[parts.length-1]; 71 | var subtree = subtreeAt(parent); 72 | if (stats.isDirectory()) { 73 | subtree[file] = {}; 74 | walkDir(base, absFile, onComplete); 75 | } else { 76 | subtree[file] = null; 77 | maybeFinished(absFile, null, onComplete); 78 | } 79 | }.bind(null, absFile)); 80 | } 81 | maybeFinished(curr, null, onComplete); 82 | }); 83 | } 84 | 85 | function main() { 86 | var pathToNode = process.argv[0]; 87 | var pathToScript = process.argv[1]; 88 | var args = process.argv.slice(2); 89 | 90 | var root = process.cwd(); 91 | if (args.length > 0) 92 | root = args[0]; 93 | 94 | walkDir(root, root, function writeJSON(err, tree) { 95 | if (err) { 96 | process.stderr.write('error: ' + err + '\n'); 97 | process.exit(-1); 98 | return; 99 | } 100 | process.stdout.write(JSON.stringify(tree) + '\n'); 101 | }); 102 | } 103 | 104 | main(); 105 | --------------------------------------------------------------------------------