From 1e79b123aa614315062681ab38ed4c7a591812cc Mon Sep 17 00:00:00 2001 From: Christian Bundy Date: Fri, 21 Feb 2020 16:04:53 -0800 Subject: [PATCH 01/15] Add build script that creates zip files Problem: Most people don't have npm installed and we probably shouldn't force them to have a full development environment to use Oasis. It would be nice to have a way to install Oasis without any development tools. Solution: Add a build script that can create .zip files that work on Unix systems like macOs and Linux. Users will need to download the zip, extract it, and double-click the `oasis` script. This script will run `npm start || npm install && npm start`, which uses binaries that we ship in the zip file so that they don't need to have `node` or `npm` installed. --- scripts/build.sh | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100755 scripts/build.sh diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..fa6bf5f --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +set -x + +BASEDIR="$(dirname $0)" + +cd "$BASEDIR/.." + +TARGET_VERSION="12.16.1" +TARGET_PLATFORM="$1" +TARGET_ARCH="$2" + +echo "Target version: $TARGET_VERSION" +echo "Target platform: $TARGET_PLATFORM" +echo "Target arch: $TARGET_ARCH" + +git clean -fdx + +mkdir -p vendor +cd vendor + +TARGET="node-v$TARGET_VERSION-$TARGET_PLATFORM-$TARGET_ARCH" +TARBALL="$TARGET.tar.gz" +URL="https://nodejs.org/dist/v$TARGET_VERSION/$TARBALL" +echo $URL + +wget "$URL" +tar -xvf "$TARBALL" +rm -rf "$TARBALL" +cd .. + +cat << EOF > oasis +#!/bin/sh + +echo "Installing dependencies..." + +BASEDIR="\$(dirname $)" + +node="\$BASEDIR/vendor/node-v$TARGET_VERSION-$TARGET_PLATFORM-$TARGET_ARCH/bin/node" + +npm () { + "\$node" "\$BASEDIR/vendor/node-v$TARGET_VERSION-$TARGET_PLATFORM-$TARGET_ARCH/lib/node_modules/npm/bin/npm-cli.js" --scripts-prepend-node-path=true --silent \$@; +} + +npm start > /dev/null 2>&1 || rm -rf "\$BASEDIR/node_modules" && npm install --only=prod --no-audit --no-fund && npm start +EOF + +chmod +x oasis + +zip -r "/tmp/oasis-$TARGET_PLATFORM-$TARGET_ARCH.zip" . -x '.git/**' +git clean -fdx + From 5d6ef8acbe84976847860136942b13cc139185a4 Mon Sep 17 00:00:00 2001 From: Christian Bundy Date: Sat, 22 Feb 2020 08:53:29 -0800 Subject: [PATCH 02/15] Pass through build script command-line arguments Problem: Running `./oasis --version` should output the current version, it shouldn't just start the server by default. Solution: Pass through command-line arguments with `$@` so that we respect what the user is asking us to do. --- scripts/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build.sh b/scripts/build.sh index fa6bf5f..79337a3 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -42,7 +42,7 @@ npm () { "\$node" "\$BASEDIR/vendor/node-v$TARGET_VERSION-$TARGET_PLATFORM-$TARGET_ARCH/lib/node_modules/npm/bin/npm-cli.js" --scripts-prepend-node-path=true --silent \$@; } -npm start > /dev/null 2>&1 || rm -rf "\$BASEDIR/node_modules" && npm install --only=prod --no-audit --no-fund && npm start +npm start -- \$@ > /dev/null 2>&1 || rm -rf "\$BASEDIR/node_modules" && npm install --only=prod --no-audit --no-fund; npm start \$@ EOF chmod +x oasis From f9013255ef673dcec8e04c066dcbd2e49286262a Mon Sep 17 00:00:00 2001 From: Christian Bundy Date: Mon, 24 Feb 2020 14:45:44 -0800 Subject: [PATCH 03/15] Avoid making installer build from source Problem: The previous approach of having the installer run `npm install` was hazardous at best and didn't work well offline. Solution: Package all of the source code with the application and use the installer to ensure that it works on the target device. The installer should ensure that we can `require()` the module, and if that doesn't work then it should choose between two options: - If the module is optional, `rm -rf` it and don't worry about it. - If the module is mandatory, try running `npm install` with some flags to ensure that we stay offline and print the absolute minimal output. This should never happen, because we should never be packaging Oasis for architectures and platforms that we don't have prebuilds for, but it's a fine fallback behavior for experimental hackery. --- scripts/build.sh | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index 79337a3..01e2866 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,6 +1,6 @@ #!/bin/sh -set -x +set -ex BASEDIR="$(dirname $0)" @@ -29,12 +29,13 @@ tar -xvf "$TARBALL" rm -rf "$TARBALL" cd .. +# Avoid building anything from source. +npm ci --only=prod --ignore-scripts --no-audit --no-fund + cat << EOF > oasis #!/bin/sh -echo "Installing dependencies..." - -BASEDIR="\$(dirname $)" +BASEDIR="\$(cd "\$(dirname "\$0")" && pwd)" node="\$BASEDIR/vendor/node-v$TARGET_VERSION-$TARGET_PLATFORM-$TARGET_ARCH/bin/node" @@ -42,11 +43,26 @@ npm () { "\$node" "\$BASEDIR/vendor/node-v$TARGET_VERSION-$TARGET_PLATFORM-$TARGET_ARCH/lib/node_modules/npm/bin/npm-cli.js" --scripts-prepend-node-path=true --silent \$@; } -npm start -- \$@ > /dev/null 2>&1 || rm -rf "\$BASEDIR/node_modules" && npm install --only=prod --no-audit --no-fund; npm start \$@ +verify () { + node -p "require('\$1')" \$@ > /dev/null 2>&1 || echo "Building \$1..."; (cd "node_modules/\$1" && npm install --only=prod --offline --no-audit --no-fund) +} + +verify_optional () { + node -p "require('\$1')" \$@ > /dev/null 2>&1 || rm -rf "node_modules/\$1" +} + +verify_all () { + verify leveldown + verify sodium-native + verify_optional sharp +} + +verify_all +exec "\$node" "src/index.js" \$@ + EOF chmod +x oasis zip -r "/tmp/oasis-$TARGET_PLATFORM-$TARGET_ARCH.zip" . -x '.git/**' git clean -fdx - From f32e93e7a29124e6d404108f03668fcbf7c49a7d Mon Sep 17 00:00:00 2001 From: Christian Bundy Date: Tue, 25 Feb 2020 07:38:16 -0800 Subject: [PATCH 04/15] Reduce installer size Problem: The installer contained npm and npx and a bunch of code that we really don't need unless we're building from source. Since we don't want our end-users to build anything from source, we can remove these. Solution: Use shell-check to make some small fixups to the code and remove everything we're downloading via wget except the `node` binary. This requires moving the "build from source" fallback, and also includes the `.appimage` hack when building from Linux to get double-click opening working. --- scripts/build.sh | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index 01e2866..efabea7 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -2,7 +2,7 @@ set -ex -BASEDIR="$(dirname $0)" +BASEDIR="$(dirname "$0")" cd "$BASEDIR/.." @@ -22,47 +22,48 @@ cd vendor TARGET="node-v$TARGET_VERSION-$TARGET_PLATFORM-$TARGET_ARCH" TARBALL="$TARGET.tar.gz" URL="https://nodejs.org/dist/v$TARGET_VERSION/$TARBALL" -echo $URL wget "$URL" -tar -xvf "$TARBALL" +tar -xvf "$TARBALL" "$TARGET/bin/node" rm -rf "$TARBALL" cd .. # Avoid building anything from source. npm ci --only=prod --ignore-scripts --no-audit --no-fund -cat << EOF > oasis +BINARY_NAME="oasis" + +# Append .appimage for double-click support on Linux +if [ "$TARGET_PLATFORM" = "linux" ]; then + BINARY_NAME="$BINARY_NAME.appimage" +fi + +echo $BINARY_NAME + +cat << EOF > "$BINARY_NAME" #!/bin/sh - BASEDIR="\$(cd "\$(dirname "\$0")" && pwd)" - node="\$BASEDIR/vendor/node-v$TARGET_VERSION-$TARGET_PLATFORM-$TARGET_ARCH/bin/node" - -npm () { - "\$node" "\$BASEDIR/vendor/node-v$TARGET_VERSION-$TARGET_PLATFORM-$TARGET_ARCH/lib/node_modules/npm/bin/npm-cli.js" --scripts-prepend-node-path=true --silent \$@; -} - verify () { - node -p "require('\$1')" \$@ > /dev/null 2>&1 || echo "Building \$1..."; (cd "node_modules/\$1" && npm install --only=prod --offline --no-audit --no-fund) + node -p "require('\$1')" > /dev/null 2>&1 || echo "Error: \$1 not supported on your platform" } - verify_optional () { - node -p "require('\$1')" \$@ > /dev/null 2>&1 || rm -rf "node_modules/\$1" + node -p "require('\$1')" > /dev/null 2>&1 || rm -rf "node_modules/\$1" } - verify_all () { verify leveldown verify sodium-native verify_optional sharp } - verify_all -exec "\$node" "src/index.js" \$@ - +exec "\$node" "src/index.js" "\$@" EOF -chmod +x oasis +chmod +x "$BINARY_NAME" -zip -r "/tmp/oasis-$TARGET_PLATFORM-$TARGET_ARCH.zip" . -x '.git/**' +# I think if the zip already exists it's adding files to the existing archive? +ZIP_PATH="/tmp/oasis-$TARGET_PLATFORM-$TARGET_ARCH.zip" +rm -f "$ZIP_PATH" + +zip -r "$ZIP_PATH" . -x ".git/**" git clean -fdx From 8eb9fa12c46f16d8ab3b03894ed313a892ea846c Mon Sep 17 00:00:00 2001 From: Christian Bundy Date: Tue, 25 Feb 2020 12:58:36 -0800 Subject: [PATCH 05/15] Provide debugging output for failed module require Problem: We try to `require()` our native modules to ensure that they work correctly, but when they don't work we need to produce an error that will help us debug the problem. Solution: Switch from `node -p` to `node -e` to avoid printing unnecessary output and don't redirect output for mandatory modules so that we can debug them. --- scripts/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index efabea7..3ad61d4 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -45,10 +45,10 @@ cat << EOF > "$BINARY_NAME" BASEDIR="\$(cd "\$(dirname "\$0")" && pwd)" node="\$BASEDIR/vendor/node-v$TARGET_VERSION-$TARGET_PLATFORM-$TARGET_ARCH/bin/node" verify () { - node -p "require('\$1')" > /dev/null 2>&1 || echo "Error: \$1 not supported on your platform" + node -e "require('\$1')" || echo "Error: \$1 may not work correctly on your platform" } verify_optional () { - node -p "require('\$1')" > /dev/null 2>&1 || rm -rf "node_modules/\$1" + node -e "require('\$1')" > /dev/null 2>&1 || rm -rf "node_modules/\$1" } verify_all () { verify leveldown From 3a486c851fba35c8f9906fea881eff72a4d86156 Mon Sep 17 00:00:00 2001 From: Christian Bundy Date: Tue, 25 Feb 2020 16:20:33 -0800 Subject: [PATCH 06/15] Replace shell script with C program for max compat Problem: The shell script didn't work on other platforms and the AppImage hack ended up confusing people who tried to install it with AppImageLauncher. Solution: This feels absolutely ridiculous, but I've written the worst C program in the world which does the equivalent of `exec ./node src "$@"` and immediately gets out of our way. This ends up being an executable that both Nautilus and Dolphin (GNOME and KDE file managers) let us double-click, and should also work on macOS. It might even work on Windows if we rename it as an `.exe`, but I'm not sure and *definitely* haven't tested that. --- scripts/build.sh | 58 ++++++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index 3ad61d4..4130641 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -2,6 +2,7 @@ set -ex + BASEDIR="$(dirname "$0")" cd "$BASEDIR/.." @@ -14,6 +15,13 @@ echo "Target version: $TARGET_VERSION" echo "Target platform: $TARGET_PLATFORM" echo "Target arch: $TARGET_ARCH" +if [ "$TARGET_ARCH" == "x64" ]; then + GCC_ARCH="x86-64" +else + echo "Unsupported architecture: $TARGET_ARCH" + exit 1 +fi + git clean -fdx mkdir -p vendor @@ -30,33 +38,41 @@ cd .. # Avoid building anything from source. npm ci --only=prod --ignore-scripts --no-audit --no-fund +# More trouble than it's worth :) +rm -rf ./node_modules/sharp BINARY_NAME="oasis" -# Append .appimage for double-click support on Linux -if [ "$TARGET_PLATFORM" = "linux" ]; then - BINARY_NAME="$BINARY_NAME.appimage" -fi - echo $BINARY_NAME -cat << EOF > "$BINARY_NAME" -#!/bin/sh -BASEDIR="\$(cd "\$(dirname "\$0")" && pwd)" -node="\$BASEDIR/vendor/node-v$TARGET_VERSION-$TARGET_PLATFORM-$TARGET_ARCH/bin/node" -verify () { - node -e "require('\$1')" || echo "Error: \$1 may not work correctly on your platform" +cat << EOF | gcc -Wall -g -no-pie -o "$BINARY_NAME" -x c -march="$GCC_ARCH" - +#include +#include +#include + +int main (int argc, char *argv[]) { + static const char node[] = "./vendor/node-v$TARGET_VERSION-$TARGET_PLATFORM-$TARGET_ARCH/bin/node"; + static const char src[] = "src"; + + char** new_argv = malloc(((argc+1) * sizeof *new_argv) + sizeof src); + + int pad = 0; + for(int i = 0; i < argc; i++) { + size_t length = strlen(argv[i])+1; + new_argv[i+pad] = malloc(length); + memcpy(new_argv[i+pad], argv[i], length); + if (i == 0) { + pad = 1; + new_argv[i + pad] = src; + } + } + + new_argv[argc + 1] = NULL; + + execv(node, new_argv); + return 1; } -verify_optional () { - node -e "require('\$1')" > /dev/null 2>&1 || rm -rf "node_modules/\$1" -} -verify_all () { - verify leveldown - verify sodium-native - verify_optional sharp -} -verify_all -exec "\$node" "src/index.js" "\$@" + EOF chmod +x "$BINARY_NAME" From 4fac7a70b4dba4d2981ce5b38d8a3319407c6053 Mon Sep 17 00:00:00 2001 From: Christian Bundy Date: Tue, 25 Feb 2020 17:58:08 -0800 Subject: [PATCH 07/15] Move C program to its own file Problem: Writing C in a heredoc is super janky and I think it's worth avoiding whenever we can. We've also been getting compiler warnings that we should probably resolve. Solution: Move the C to its own file and resolve the compiler warnings. --- scripts/build.sh | 41 ++++++++--------------------------------- scripts/oasis.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 33 deletions(-) create mode 100644 scripts/oasis.c diff --git a/scripts/build.sh b/scripts/build.sh index 4130641..8b7607c 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -30,9 +30,10 @@ cd vendor TARGET="node-v$TARGET_VERSION-$TARGET_PLATFORM-$TARGET_ARCH" TARBALL="$TARGET.tar.gz" URL="https://nodejs.org/dist/v$TARGET_VERSION/$TARBALL" +TARGET_NODE="$TARGET/bin/node" wget "$URL" -tar -xvf "$TARBALL" "$TARGET/bin/node" +tar -xvf "$TARBALL" "$TARGET_NODE" rm -rf "$TARBALL" cd .. @@ -43,43 +44,17 @@ rm -rf ./node_modules/sharp BINARY_NAME="oasis" -echo $BINARY_NAME +VENDOR_NODE="vendor/$TARGET_NODE" -cat << EOF | gcc -Wall -g -no-pie -o "$BINARY_NAME" -x c -march="$GCC_ARCH" - -#include -#include -#include - -int main (int argc, char *argv[]) { - static const char node[] = "./vendor/node-v$TARGET_VERSION-$TARGET_PLATFORM-$TARGET_ARCH/bin/node"; - static const char src[] = "src"; - - char** new_argv = malloc(((argc+1) * sizeof *new_argv) + sizeof src); - - int pad = 0; - for(int i = 0; i < argc; i++) { - size_t length = strlen(argv[i])+1; - new_argv[i+pad] = malloc(length); - memcpy(new_argv[i+pad], argv[i], length); - if (i == 0) { - pad = 1; - new_argv[i + pad] = src; - } - } - - new_argv[argc + 1] = NULL; - - execv(node, new_argv); - return 1; -} - -EOF +gcc scripts/oasis.c -Wall -g -no-pie -o "$BINARY_NAME" -march="$GCC_ARCH" -D "NODE=\"$VENDOR_NODE\"" chmod +x "$BINARY_NAME" # I think if the zip already exists it's adding files to the existing archive? ZIP_PATH="/tmp/oasis-$TARGET_PLATFORM-$TARGET_ARCH.zip" -rm -f "$ZIP_PATH" +rm -f "$ZIP_PATH" zip -r "$ZIP_PATH" . -x ".git/**" -git clean -fdx + +rm -f oasis +rm -rf vendor diff --git a/scripts/oasis.c b/scripts/oasis.c new file mode 100644 index 0000000..731a3ca --- /dev/null +++ b/scripts/oasis.c @@ -0,0 +1,32 @@ +#ifndef NODE +#define NODE "/usr/bin/node" +#endif + +#include +#include +#include + +int main (int argc, char *argv[]) { + static const char src[] = "src"; + char** new_argv = malloc(((argc + 1) * sizeof *new_argv) + strlen(src)); + + int pad = 0; + for(int i = 0; i < argc; i++) { + size_t length = strlen(argv[i]) + 1; + new_argv[i + pad] = malloc(length); + memcpy(new_argv[i + pad], argv[i], length); + + if (i == 0) { + pad = 1; + size_t length = strlen(src) + 1; + new_argv[i + pad] = malloc(length); + memcpy(new_argv[i + pad], src, length); + } + } + + new_argv[argc + 1] = NULL; + + execv(NODE, new_argv); + return 1; +} + From 6812347b02ecd6e73ba31a006bb2623b0122a45c Mon Sep 17 00:00:00 2001 From: Christian Bundy Date: Tue, 25 Feb 2020 20:41:57 -0800 Subject: [PATCH 08/15] Distribute shell/batch scripts on macOS/Window Problem: I've quickly learned that cross-compiling is a major headache and that C programming lacks both rainbows and butterflies. It seems that my executable only works on Linux, but probably not macOS or Windows. Solution: Use shell scripts on macOS, which work when you double-click them, and batch scripts on Windows, which I *think* work when you double-click them. I haven't tested this on a macOS device yet, but I tested the previous shell script on macOS and it seemed to work fine. Unless I've done something silly, this should work on macOS, but the Windows batch script is just me writing code from memory and probably doesn't work correcly. I'll probably beg @SoapDog to help me fix it. --- scripts/build.sh | 72 ++++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index 8b7607c..6832570 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -2,39 +2,45 @@ set -ex - BASEDIR="$(dirname "$0")" cd "$BASEDIR/.." TARGET_VERSION="12.16.1" -TARGET_PLATFORM="$1" -TARGET_ARCH="$2" - -echo "Target version: $TARGET_VERSION" -echo "Target platform: $TARGET_PLATFORM" -echo "Target arch: $TARGET_ARCH" - -if [ "$TARGET_ARCH" == "x64" ]; then - GCC_ARCH="x86-64" -else - echo "Unsupported architecture: $TARGET_ARCH" - exit 1 -fi git clean -fdx mkdir -p vendor cd vendor -TARGET="node-v$TARGET_VERSION-$TARGET_PLATFORM-$TARGET_ARCH" -TARBALL="$TARGET.tar.gz" -URL="https://nodejs.org/dist/v$TARGET_VERSION/$TARBALL" -TARGET_NODE="$TARGET/bin/node" +get_tgz () { + TARGET_PLATFORM="$1" + TARGET="node-v$TARGET_VERSION-$TARGET_PLATFORM-x64" + ARCHIVE="$TARGET.tar.gz" + URL="https://nodejs.org/dist/v$TARGET_VERSION/$ARCHIVE" + TARGET_NODE="$TARGET/bin/node" + + wget "$URL" + tar -xvf "$ARCHIVE" "$TARGET_NODE" + rm -rf "$ARCHIVE" +} + +get_zip () { + TARGET_PLATFORM="$1" + TARGET="node-v$TARGET_VERSION-$TARGET_PLATFORM-x64" + ARCHIVE="$TARGET.zip" + URL="https://nodejs.org/dist/v$TARGET_VERSION/$ARCHIVE" + TARGET_NODE="$TARGET/node.exe" + + wget "$URL" + unzip "$ARCHIVE" "$TARGET_NODE" + rm -rf "$ARCHIVE" +} + +get_tgz darwin +get_tgz linux +get_zip win -wget "$URL" -tar -xvf "$TARBALL" "$TARGET_NODE" -rm -rf "$TARBALL" cd .. # Avoid building anything from source. @@ -42,19 +48,31 @@ npm ci --only=prod --ignore-scripts --no-audit --no-fund # More trouble than it's worth :) rm -rf ./node_modules/sharp -BINARY_NAME="oasis" +# Darwin (shell script) +cat << EOF > oasis-darwin-x64 +#!/bin/sh +exec vendor/node-v$TARGET_VERSION-darwin-x64/bin/node src "\$@" +EOF +chmod +x oasis-darwin-x64 -VENDOR_NODE="vendor/$TARGET_NODE" +# Linux (ELF executable) +clang scripts/oasis.c -Wall -g -no-pie -o "oasis-linux-x64" --target=x86_64-linux-unknown -D "NODE=\"vendor/node-v$TARGET_VERSION-linux-x64/bin/node\"" +chmod +x oasis-linux-x64 -gcc scripts/oasis.c -Wall -g -no-pie -o "$BINARY_NAME" -march="$GCC_ARCH" -D "NODE=\"$VENDOR_NODE\"" +# Windows (batch file) +cat << EOF > oasis-win-x64.bat +vendor\\node-v$TARGET_VERSION-darwin-x64\\bin\\node src "\$@" +EOF -chmod +x "$BINARY_NAME" +chmod +x oasis-win-x64.bat # I think if the zip already exists it's adding files to the existing archive? -ZIP_PATH="/tmp/oasis-$TARGET_PLATFORM-$TARGET_ARCH.zip" +ZIP_PATH="/tmp/oasis-x64.zip" rm -f "$ZIP_PATH" zip -r "$ZIP_PATH" . -x ".git/**" -rm -f oasis +rm -f oasis-darwin-x64 +rm -f oasis-linux-x64 +rm -f oasis-win-x64.bat rm -rf vendor From 8ed77e5a64983d00e1e48b06b8752269c8299a08 Mon Sep 17 00:00:00 2001 From: Christian Bundy Date: Wed, 26 Feb 2020 07:32:56 -0800 Subject: [PATCH 09/15] Add basedir check for macOS shell script Problem: When running the Darwin binary from another directory, the script would look in the user's current working directory for both `node` and `src`, which is wrong. Solution: Set `BASEDIR` and use it so that we use the correct paths. --- scripts/build.sh | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index 6832570..8fe9430 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -3,11 +3,10 @@ set -ex BASEDIR="$(dirname "$0")" +TARGET_VERSION="12.16.1" cd "$BASEDIR/.." -TARGET_VERSION="12.16.1" - git clean -fdx mkdir -p vendor @@ -51,12 +50,13 @@ rm -rf ./node_modules/sharp # Darwin (shell script) cat << EOF > oasis-darwin-x64 #!/bin/sh -exec vendor/node-v$TARGET_VERSION-darwin-x64/bin/node src "\$@" +BASEDIR="\$(dirname "\$0")" +exec "\$BASEDIR/vendor/node-v$TARGET_VERSION-darwin-x64/bin/node" "\$BASEDIR/src" "\$@" EOF chmod +x oasis-darwin-x64 # Linux (ELF executable) -clang scripts/oasis.c -Wall -g -no-pie -o "oasis-linux-x64" --target=x86_64-linux-unknown -D "NODE=\"vendor/node-v$TARGET_VERSION-linux-x64/bin/node\"" +clang scripts/oasis.c -Wall -g -no-pie -o "oasis-linux-x64" --target=x86_64-linux -D "NODE=\"vendor/node-v$TARGET_VERSION-linux-x64/bin/node\"" chmod +x oasis-linux-x64 # Windows (batch file) @@ -72,7 +72,4 @@ ZIP_PATH="/tmp/oasis-x64.zip" rm -f "$ZIP_PATH" zip -r "$ZIP_PATH" . -x ".git/**" -rm -f oasis-darwin-x64 -rm -f oasis-linux-x64 -rm -f oasis-win-x64.bat -rm -rf vendor +git clean -fdx From dd81f0877ae041805923bb42cfc4f9522175cf94 Mon Sep 17 00:00:00 2001 From: Christian Bundy Date: Wed, 26 Feb 2020 15:36:19 -0800 Subject: [PATCH 10/15] Fix typo in batch file path Problem: We were using `darwin` instead of `win`. Solution: Replace `darwin` with `win` to ensure that we're using the correct path in the batch file we produce. --- scripts/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build.sh b/scripts/build.sh index 8fe9430..fe09aa5 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -61,7 +61,7 @@ chmod +x oasis-linux-x64 # Windows (batch file) cat << EOF > oasis-win-x64.bat -vendor\\node-v$TARGET_VERSION-darwin-x64\\bin\\node src "\$@" +vendor\\node-v$TARGET_VERSION-win-x64\\bin\\node src "\$@" EOF chmod +x oasis-win-x64.bat From 51981ebfdbcf566fcae3439089abafcb5eaeafe5 Mon Sep 17 00:00:00 2001 From: Christian Bundy Date: Wed, 26 Feb 2020 15:40:13 -0800 Subject: [PATCH 11/15] Fix argument expansion on Windows Problem: Apparently one of the previous commits switched us to shell-style argument expansion. Solution: Use the appropriate solution on Windows, `%*`. --- scripts/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build.sh b/scripts/build.sh index fe09aa5..218bb8c 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -61,7 +61,7 @@ chmod +x oasis-linux-x64 # Windows (batch file) cat << EOF > oasis-win-x64.bat -vendor\\node-v$TARGET_VERSION-win-x64\\bin\\node src "\$@" +vendor\\node-v$TARGET_VERSION-win-x64\\bin\\node src %* EOF chmod +x oasis-win-x64.bat From 9b53ee94dcbc2a4c0470ee565b32dbf5848d0286 Mon Sep 17 00:00:00 2001 From: Christian Bundy Date: Wed, 26 Feb 2020 18:07:49 -0800 Subject: [PATCH 12/15] Replace C launcher with Golang launcher Problem: I don't know what I'm doing and can't figure out how to cross-compile this simple C program to macOS and Windows Solution: @cryptix reminded me that Go makes cross-compiling easy, so I took a stab at writing my first Go program. It seems to be working on macOS and Linux, but I haven't tested on Windows. --- scripts/build.sh | 32 +++++++++++++++++--------------- scripts/oasis.c | 32 -------------------------------- scripts/oasis.go | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 47 deletions(-) delete mode 100644 scripts/oasis.c create mode 100644 scripts/oasis.go diff --git a/scripts/build.sh b/scripts/build.sh index 218bb8c..5850869 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -21,7 +21,7 @@ get_tgz () { wget "$URL" tar -xvf "$ARCHIVE" "$TARGET_NODE" - rm -rf "$ARCHIVE" + rm -f "$ARCHIVE" } get_zip () { @@ -33,7 +33,7 @@ get_zip () { wget "$URL" unzip "$ARCHIVE" "$TARGET_NODE" - rm -rf "$ARCHIVE" + rm -f "$ARCHIVE" } get_tgz darwin @@ -47,24 +47,25 @@ npm ci --only=prod --ignore-scripts --no-audit --no-fund # More trouble than it's worth :) rm -rf ./node_modules/sharp +export GOARCH="amd64" + # Darwin (shell script) -cat << EOF > oasis-darwin-x64 -#!/bin/sh -BASEDIR="\$(dirname "\$0")" -exec "\$BASEDIR/vendor/node-v$TARGET_VERSION-darwin-x64/bin/node" "\$BASEDIR/src" "\$@" -EOF -chmod +x oasis-darwin-x64 +export GOOS="darwin" +OUTFILE="oasis-$GOOS-$GOARCH" +go build -ldflags "-X main.node=vendor/node-v$TARGET_VERSION-darwin-x64/bin/node" -o "$OUTFILE" scripts/oasis.go +chmod +x "$OUTFILE" # Linux (ELF executable) -clang scripts/oasis.c -Wall -g -no-pie -o "oasis-linux-x64" --target=x86_64-linux -D "NODE=\"vendor/node-v$TARGET_VERSION-linux-x64/bin/node\"" -chmod +x oasis-linux-x64 +export GOOS="linux" +OUTFILE="oasis-$GOOS-$GOARCH" +go build -ldflags "-X main.node=vendor/node-v$TARGET_VERSION-linux-x64/bin/node" -o "$OUTFILE" scripts/oasis.go +chmod +x "$OUTFILE" # Windows (batch file) -cat << EOF > oasis-win-x64.bat -vendor\\node-v$TARGET_VERSION-win-x64\\bin\\node src %* -EOF - -chmod +x oasis-win-x64.bat +export GOOS="windows" +OUTFILE="oasis-$GOOS-$GOARCH.exe" +go build -ldflags "-X main.node=vendor\\node-v$TARGET_VERSION-win-x64\\bin\\node" -o "$OUTFILE" scripts/oasis.go +chmod +x "$OUTFILE" # I think if the zip already exists it's adding files to the existing archive? ZIP_PATH="/tmp/oasis-x64.zip" @@ -73,3 +74,4 @@ rm -f "$ZIP_PATH" zip -r "$ZIP_PATH" . -x ".git/**" git clean -fdx + diff --git a/scripts/oasis.c b/scripts/oasis.c deleted file mode 100644 index 731a3ca..0000000 --- a/scripts/oasis.c +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef NODE -#define NODE "/usr/bin/node" -#endif - -#include -#include -#include - -int main (int argc, char *argv[]) { - static const char src[] = "src"; - char** new_argv = malloc(((argc + 1) * sizeof *new_argv) + strlen(src)); - - int pad = 0; - for(int i = 0; i < argc; i++) { - size_t length = strlen(argv[i]) + 1; - new_argv[i + pad] = malloc(length); - memcpy(new_argv[i + pad], argv[i], length); - - if (i == 0) { - pad = 1; - size_t length = strlen(src) + 1; - new_argv[i + pad] = malloc(length); - memcpy(new_argv[i + pad], src, length); - } - } - - new_argv[argc + 1] = NULL; - - execv(NODE, new_argv); - return 1; -} - diff --git a/scripts/oasis.go b/scripts/oasis.go new file mode 100644 index 0000000..3eaba20 --- /dev/null +++ b/scripts/oasis.go @@ -0,0 +1,33 @@ +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" +) + +var node string + +func main() { + node := filepath.Join(filepath.Dir(os.Args[0]), node) + src := filepath.Join(filepath.Dir(os.Args[0]), "src") + + args := []string{src} + + for i := 1; i < len(os.Args); i++ { + args = append(args, os.Args[i]) + } + + cmd := exec.Command(node, args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Run() + + if err != nil { + fmt.Println(err) + } + + + fmt.Println(args) +} From fb2e042a121128d2e9893fbe8811ed86547581b6 Mon Sep 17 00:00:00 2001 From: Christian Bundy Date: Wed, 26 Feb 2020 20:40:23 -0800 Subject: [PATCH 13/15] Remove debug output and add comments Problem: The previous code was printing debug output so that I could ensure that my argument checking worked correctly, but we don't want to distribute a binary that echoes back your arguments to you. Solution: Remove the debug output and add lots of comments to document all of my misunderstandings of how the current code works. :~) --- scripts/oasis.go | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/scripts/oasis.go b/scripts/oasis.go index 3eaba20..b7bb29b 100644 --- a/scripts/oasis.go +++ b/scripts/oasis.go @@ -7,27 +7,51 @@ import ( "path/filepath" ) +// The relative path to the `node` binary depends on the platform, so we +// pass this via an `-ldflags` hack I don't completely understand. In my +// head this is similar to how GCC lets you use `-D` to define a macro to +// be inserted by the preprocessor. var node string func main() { + // The problem with relative paths is that they only work when + // you run `./oasis-platform-x64`, but not when you run a command + // like `./path/to/oasis-platform-x64`. To resolve this problem + // we need to put together an absolute path, which we can build + // with the first argument (the relative path of this executable) + // and the relative path of either the `node` binary or the + // source code directory so that we can run `node src`. node := filepath.Join(filepath.Dir(os.Args[0]), node) src := filepath.Join(filepath.Dir(os.Args[0]), "src") + // We know that the command will be the absolute path to `node` + // and the first argument will be the absolute path to the `src` + // directory, but we need to get collect the rest of the arguments + // programatically by pulling them out of the `os.Args` slice and + // putting them in a new slice called `args`. args := []string{src} - for i := 1; i < len(os.Args); i++ { args = append(args, os.Args[i]) } + // This seems to execute the script and pass-through all of the + // arguments we want, *plus* it hooks up stdout and stderr, but + // the exit code of Oasis doesn't seem to be passed through. This + // is easy to test with a command like: + // + // ./oasis-platform-x64 --port -1 + // + // This should give an exit code of 1, but it seems to exit 0. :/ cmd := exec.Command(node, args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - err := cmd.Run() + // This catches problems like "no such file or directory" if the + // `node` variable points to a path where there isn't a binary. + // + // TODO: I think we're supposed to handle the exit code here. + err := cmd.Run() if err != nil { fmt.Println(err) } - - - fmt.Println(args) } From bdcc127674c456a3018f6b0c8fde53458319e125 Mon Sep 17 00:00:00 2001 From: Christian Bundy Date: Fri, 20 Mar 2020 11:33:18 -0700 Subject: [PATCH 14/15] Fix crash when linking directly to private message Problem: Trying to view a private message crashes the server and leaks a bunch of memory. That's bad. This problem is caused by faulty handling in the function that finds thread ancestors. There's some code that says "if the next ancestor is a private message, just return the ancestors that we know about", which returns nothing when we're looking up a private post (because we can't identify *any* ancestors). Solution: Ensure that we're only resolving the promise once in the function by chaining `else if`s and ensure that we only return the ancestor list if there are actually ancestor in it. If the ancestor list is empty, we can just return the single message that we know about and pass it off. --- src/models.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/models.js b/src/models.js index 5af947f..4ff46f3 100644 --- a/src/models.js +++ b/src/models.js @@ -1052,17 +1052,22 @@ module.exports = ({ cooler, isPublic }) => { debug("getting root ancestor of %s", msg.key); if (typeof msg.value.content === "string") { - debug("private message"); // Private message we can't decrypt, stop looking for parents. - resolve(parents); - } - - if (msg.value.content.type !== "post") { + debug("private message"); + if (parents.length > 0) { + // If we already have some parents, return those. + resolve(parents); + } else { + // If we don't know of any parents, resolve this message. + resolve(msg); + } + } else if (msg.value.content.type !== "post") { debug("not a post"); resolve(msg); - } - - if (isLooseReply(msg) && ssbRef.isMsg(msg.value.content.fork)) { + } else if ( + isLooseReply(msg) && + ssbRef.isMsg(msg.value.content.fork) + ) { debug("reply, get the parent"); try { // It's a message reply, get the parent! From a4b00696abd04d6fc1531cbd8836d132dc8e9892 Mon Sep 17 00:00:00 2001 From: Nick Wynja Date: Tue, 24 Mar 2020 13:53:19 -0400 Subject: [PATCH 15/15] Load theme using existing config mechanisms This allow someone to pass in the theme as a command line arg or set the theme in defaults.json, while still allowing someone to set the theme on a per-browser basis as a cookie. --- src/cli.js | 5 +++++ src/index.js | 6 ++---- src/views/i18n.js | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cli.js b/src/cli.js index c980e60..5d8c1e5 100644 --- a/src/cli.js +++ b/src/cli.js @@ -43,4 +43,9 @@ module.exports = (presets, defaultConfigFile) => default: _.get(presets, "debug", false), type: "boolean" }) + .options("theme", { + describe: "The theme to use, if a theme hasn't been set in the cookies", + default: _.get(presets, "theme", "atelier-sulphurPool-light"), + type: "string" + }) .epilog(`The defaults can be configured in ${defaultConfigFile}.`).argv; diff --git a/src/index.js b/src/index.js index 24c3562..28d9e4e 100755 --- a/src/index.js +++ b/src/index.js @@ -173,8 +173,6 @@ try { // Optional dependency } -const defaultTheme = "atelier-sulphurPool-light".toLowerCase(); - const readmePath = path.join(__dirname, "..", "README.md"); const packagePath = path.join(__dirname, "..", "package.json"); @@ -320,7 +318,7 @@ router ctx.body = await hashtagView({ hashtag, messages }); }) .get("/theme.css", ctx => { - const theme = ctx.cookies.get("theme") || defaultTheme; + const theme = ctx.cookies.get("theme") || config.theme; const packageName = "@fraction/base16-css"; const filePath = `${packageName}/src/base16-${theme}.css`; @@ -500,7 +498,7 @@ router ctx.body = await image({ blobId, imageSize: Number(imageSize) }); }) .get("/settings/", async ctx => { - const theme = ctx.cookies.get("theme") || defaultTheme; + const theme = ctx.cookies.get("theme") || config.theme; const getMeta = async ({ theme }) => { const status = await meta.status(); const peers = await meta.peers(); diff --git a/src/views/i18n.js b/src/views/i18n.js index b6d088b..e9255ed 100644 --- a/src/views/i18n.js +++ b/src/views/i18n.js @@ -125,7 +125,7 @@ module.exports = { ], theme: "Theme", themeIntro: - "Choose from any theme you'd like. The default theme is Atelier-SulphurPool-Light.", + "Choose from any theme you'd like. The default theme is Atelier-SulphurPool-Light. You can also set your theme in the default configuration file.", setTheme: "Set theme", language: "Language", languageDescription: