Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Install script for CLI package #1889

Merged
merged 6 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci-javascript.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ jobs:
mv wrappers packages/test-cases/cases

- name: Build CLI standalone package for testing
run: yarn pkg:dev
run: yarn pkg:ci
working-directory: ./packages/cli

- name: Test CLI standalone package
Expand Down
333 changes: 333 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
#!/bin/sh

# Adapted from https://github.com/teaxyz/setup/blob/main/install.sh

set -e
set -o noglob

# prevent existing env breaking this script
unset POLYWRAP_DESTDIR
unset POLYWRAP_VERSION

unset stop
while test "$#" -gt 0 -a -z "$stop"; do
case $1 in
--prefix)
POLYWRAP_DESTDIR="$2"
if test -z "$POLYWRAP_DESTDIR"; then
echo "polywrap: error: --prefix requires an argument" >&2
exit 1
fi
shift;shift;;
--version)
POLYWRAP_VERSION="$2"
if test -z "$POLYWRAP_VERSION"; then
echo "polywrap: error: --version requires an argument" >&2
exit 1
fi
shift;shift;;
--yes|-y)
POLYWRAP_YES=1
shift;;
--help|-h)
echo "polywrap: docs: https://github.com/polywrap/cli/blob/origin-dev/packages/cli/README.md#installation"
exit;;
*)
stop=1;;
esac
done
unset stop


####################################################################### funcs
prepare() {
# ensure ⌃C works
trap "echo; exit" INT

if test -n "$VERBOSE" -o -n "$GITHUB_ACTIONS" -a -n "$RUNNER_DEBUG"; then
set -x
fi

if test $# -eq 0; then
MODE="install"
else
MODE="exec"
fi

HW_TARGET=$(uname)/$(uname -m)

case $HW_TARGET in
Darwin/arm64)
POLYWRAP_OSARCH=macos-arm64;;
Darwin/x86_64)
POLYWRAP_OSARCH=macos-x64;;
Linux/arm64|Linux/aarch64|CYGWIN_NT-10.0/arm64|MSYS_NT-10.0/arm64)
POLYWRAP_OSARCH=linux-arm64;;
Linux/x86_64|CYGWIN_NT-10.0/x86_64|MSYS_NT-10.0/x86_64)
POLYWRAP_OSARCH=linux-x64;;
*)
echo "polywrap: error: (currently) unsupported OS or architecture ($HW_TARGET)" >&2
echo "Let’s talk about it: https://discord.com/invite/Z5m88a5qWu" >&2
exit 1;;
esac

if test -z "$POLYWRAP_DESTDIR"; then
# update existing installation if found
if command -v polywrap >/dev/null; then
set +e
if [ "$(uname)" = "Darwin" ]; then
POLYWRAP_DESTDIR=$(stat -f%Y "$(which polywrap)")
else
POLYWRAP_DESTDIR=$(readlink -f "$(which polywrap)")
fi
POLYWRAP_DESTDIR=$(dirname "$POLYWRAP_DESTDIR")
# reverse path, split on "/polywrap/" to get the last occurrence, take the second part, reverse again
# this makes sure we get the correct path even if a user or destination folder is named polywrap
POLYWRAP_DESTDIR=$(echo "$POLYWRAP_DESTDIR" | rev | awk -F'/parwylop/' '{print $2}' | rev)

echo Found polywrap in $POLYWRAP_DESTDIR

if test $? -eq 0 -a -n "$POLYWRAP_DESTDIR"; then
case "$POLYWRAP_DESTDIR" in
*/.yarn/*|*/.npm/*|*/node_modules/*)
echo The existing installation is managed by a JavaScript package manager. If you continue, this script will create a separate installation that may conflict with it.
unset POLYWRAP_DESTDIR
;;
*)
ALREADY_INSTALLED=1
;;
esac
else
unset POLYWRAP_DESTDIR
fi
set -e
fi

# we check again: in case the above failed for some reason
if test -z "$POLYWRAP_DESTDIR"; then
if test "$MODE" = exec; then
POLYWRAP_DESTDIR="$(mktemp -dt polywrap-XXXXXX)"
else
POLYWRAP_DESTDIR="$HOME/.polywrap"
fi
fi
fi

if test -z "$CURL"; then
if command -v curl >/dev/null; then
CURL="curl -Ssf"
else
echo "polywrap: error: you need curl (or set \`\$CURL\`)" >&2
exit 1
fi
fi
}

welcome() {
cat <<-EoMD

# Hi 👋 Welcome to Polywrap!
* Let's get you set up.
* We'll install polywrap at: $POLYWRAP_DESTDIR
* Everything Polywrap installs goes there.
* (we won't touch anything else)

> docs https://github.com/polywrap/cli/blob/origin-dev/packages/cli/README.md#installation
EoMD

if test -n "$POLYWRAP_YES"; then
choice="1"
else
cat <<-EoMD

Let's gooooo! 🚀
1) Install polywrap
2) Cancel
EoMD
printf "Choice: "
read -r choice
fi

if [ "$choice" != "1" ]; then
cat <<-EoMD

# Aborting! No changes were made.
> Learn more about Polywrap at https://docs.polywrap.io/
EoMD
echo #spacer
exit 1
fi
unset choice

echo #spacer
}

get_polywrap_version() {
if test -n "$POLYWRAP_VERSION"; then
return
fi

v_sh="$(mktemp)"
cat <<-EoMD >"$v_sh"
$CURL "https://raw.githubusercontent.com/polywrap/cli/origin-dev/VERSION" | head -n1 > "$v_sh"
EoMD

echo "Determining polywrap version"
sh "$v_sh"

POLYWRAP_VERSION="$(cat "$v_sh")"

if test -z "$POLYWRAP_VERSION"; then
echo "failed to get the latest version" >&2
exit 1
fi

POLYWRAP_VERSION_MAJOR="$(echo "$POLYWRAP_VERSION" | cut -d. -f1)"

echo "Latest polywrap version: v$POLYWRAP_VERSION"
}

fix_links() {
OLDWD="$PWD"

link() {
if test -d "v$1" -a ! -L "v$1"; then
echo "'v$1' is unexpectedly a directory" >&2
else
rm -f "v$1"
ln -s "v$POLYWRAP_VERSION" "v$1"
fi
}

cd "$POLYWRAP_DESTDIR"/polywrap
link \*
link "$(echo "$POLYWRAP_VERSION" | cut -d. -f1)"
link "$(echo "$POLYWRAP_VERSION" | cut -d. -f1-2)"
cd "$OLDWD"
}

install() {
if test -n "$ALREADY_INSTALLED"; then
TITLE="Updating to polywrap v$POLYWRAP_VERSION"
else
TITLE="Fetching polywrap v$POLYWRAP_VERSION"
fi

mkdir -p "$POLYWRAP_DESTDIR/polywrap/v$POLYWRAP_VERSION/bin/"
POLYWRAP_DESTDIR="$(cd "$POLYWRAP_DESTDIR" && pwd)" # we need this PATH to be an absolute path for later stuff
POLYWRAP_TMP_SCRIPT="$(mktemp)"
URL="https://github.com/polywrap/cli/releases/download/$POLYWRAP_VERSION/polywrap-$POLYWRAP_OSARCH"
echo "set -e; $CURL -L '$URL' -o '$POLYWRAP_DESTDIR/polywrap/v$POLYWRAP_VERSION/bin/polywrap-$POLYWRAP_OSARCH'" > "$POLYWRAP_TMP_SCRIPT"
echo "$TITLE"
sh "$POLYWRAP_TMP_SCRIPT"

POLYWRAP_TMP_SCRIPT="$(mktemp)"
echo "chmod +x '$POLYWRAP_DESTDIR/polywrap/v$POLYWRAP_VERSION/bin/polywrap-$POLYWRAP_OSARCH';" > "$POLYWRAP_TMP_SCRIPT"
sh "$POLYWRAP_TMP_SCRIPT"

fix_links

if ! test "$MODE" = exec; then
echo -- "Successfully installed \`$POLYWRAP_DESTDIR/polywrap/v$POLYWRAP_VERSION/bin/polywrap-$POLYWRAP_OSARCH\`"
fi

POLYWRAP_EXENAME="$POLYWRAP_DESTDIR/polywrap/v$POLYWRAP_VERSION_MAJOR/bin/polywrap-$POLYWRAP_OSARCH"
}

check_path() {
if test -n "$POLYWRAP_YES"; then
choice="1"
else
cat <<-EoMD

Should we add $POLYWRAP_DESTDIR/polywrap/v$POLYWRAP_VERSION_MAJOR/bin to your PATH?
This may require your root password.
1) Yes
2) Skip
EoMD
printf "Choice: "
read -r choice
fi

if [ "$choice" = "1" ]; then
echo #spacer

# NOTE: Binary -a and -o are inherently ambiguous. Use 'test EXPR1
# && test EXPR2' or 'test EXPR1 || test EXPR2' instead.
# https://man7.org/linux/man-pages/man1/test.1.html
if test -w /usr/local/bin || (test ! -e /usr/local/bin && mkdir -p /usr/local/bin >/dev/null 2>&1)
then
mkdir -p /usr/local/bin
ln -sf "$POLYWRAP_EXENAME" /usr/local/bin/polywrap
echo "Added PATH alias at \`/usr/local/bin/polywrap\`"
elif command -v sudo >/dev/null
then
sudo --reset-timestamp
sudo mkdir -p /usr/local/bin
sudo ln -sf "$POLYWRAP_EXENAME" /usr/local/bin/polywrap
echo "Added PATH alias at \`/usr/local/bin/polywrap\`"
else
echo #spacer
cat <<-EoMD
> sudo command not found.
> try installing sudo
EoMD
fi

if ! command -v polywrap >/dev/null
then
echo #spacer
cat -- <<-EoMD
> It seems \`/usr/local/bin\` isn’t in your PATH, or we couldn't write to it.
\`PATH=$PATH\`
EoMD
fi
fi

echo #spacer
}

########################################################################## go
prepare "$@"
if test $MODE = install -a -z "$ALREADY_INSTALLED"; then
welcome
fi
get_polywrap_version
if ! test -f "$POLYWRAP_DESTDIR/polywrap/v$POLYWRAP_VERSION/bin/polywrap-$POLYWRAP_OSARCH"; then
install
else
fix_links # be proactive in repairing the user installation just in case that's what they ran this for
POLYWRAP_IS_CURRENT=1
POLYWRAP_EXENAME="$POLYWRAP_DESTDIR/polywrap/v$POLYWRAP_VERSION_MAJOR/bin/polywrap-$POLYWRAP_OSARCH"
fi

case $MODE in
install)
if ! test -n "$ALREADY_INSTALLED"; then
check_path
if test -n "$GITHUB_ACTIONS"; then
# if the user did call us directly from GHA may as well help them out
echo "$POLYWRAP_DESTDIR/polywrap/v$POLYWRAP_VERSION_MAJOR/bin" >> "$GITHUB_PATH"
fi
echo "You’re all set!"
elif test -n "$POLYWRAP_IS_CURRENT"; then
cat <<-EoMD
# The latest version of polywrap is already installed
> $POLYWRAP_DESTDIR/polywrap/v$POLYWRAP_VERSION/bin/polywrap-$POLYWRAP_OSARCH
EoMD
fi
echo #spacer
;;
exec)
# ensure we use the just installed polywrap
export POLYWRAP_PREFIX="$POLYWRAP_DESTDIR"

if test -z "$ALREADY_INSTALLED" -a -t 1; then
$POLYWRAP_EXENAME "$@"
echo #spacer
else
export PATH="$POLYWRAP_PREFIX/polywrap/v*/bin:$PATH"
exec "$POLYWRAP_EXENAME" "$@"
fi
;;
esac
15 changes: 15 additions & 0 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,21 @@ You can install Cue by following the instructions found [here](https://cuelang.o

## Installation

### Standalone Executable

For MacOS, Linux, and WSL:

```shell
$ sh <(curl https://raw.githubusercontent.com/polywrap/cli/origin-dev/install.sh)

# Installs to `~/.polywrap`
# If polywrap is already installed, the script instead checks for updates
```

We do not have an easy installation script for native Windows users, but we do produce a standalone executable for Windows users to download. You can find the latest release [here](https://github.com/polywrap/cli/releases).

### With NodeJS

Within a single project:

```bash
Expand Down
16 changes: 13 additions & 3 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@
"test:golang": "yarn test:cmd -- --config ./jest.go.config.js",
"test:watch": "yarn test -- --watch",
"test:pkg": "PKG_CLI=true yarn test:e2e:p1 && yarn test:e2e:p2",
"pkg:prod": "ts-node ./scripts/buildStandaloneBinaries.ts --prod",
"pkg:dev": "ts-node ./scripts/buildStandaloneBinaries.ts"
"pkg:prod": "pkg . --compress Brotli",
"pkg:dev": "pkg . --compress GZip",
"pkg:ci": "pkg . --compress GZip -t node18-linux-x64 --output ./standalone-binaries/polywrap-linux-x64"
Comment on lines +38 to +40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need these scripts or only the pkg:ci? can you explain to me what the pkg:ci does exactly? in my ignorance, it seems that is only building for one target but not sure

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, pkg:prod and pkg:dev are no longer used in CI/CD.

I think pkg:prod can be removed.

The pkg:dev script is useful if you want to test with the binary as you're working on the CLI, since it's fairly quick and it produces binaries for all of the targets. The tests will select the correct binary for your OS and arch. I think it's worth keeping.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pkg:ci script only builds for the target used by CI. The purpose is to make CI faster. If we want fewer scripts, CI can just use pkg:dev.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pkg:ci script only builds for the target used by CI. The purpose is to make CI faster. If we want fewer scripts, CI can just use pkg:dev.

right, so I think there's two things here (please correct me if I misunderstood something):

  • Testing polywrap CLI as a standalone (in the CI), this will just build the binary in the gh action runner platform; and it will try to interact with the CLI; making sure it works as expected
  • Doing the actual release; here the CD process is actually going to build the binaries to all supported platforms (which are defined here), and then just adding those as assets.

Based on this, what I would propose its to just have one script (I would actually name something like build:binaries), and then in the CI, we can do build:binaries -- -t node18..... This way we would just have one script that its reused in the different processes. Wdyt? @krisbitney

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #1892

},
"resolutions": {
"colors": "1.4.0"
Expand Down Expand Up @@ -112,6 +113,15 @@
"build/lib/defaults/build-strategies/**/*",
"build/lib/defaults/deploy-modules/**/*",
"build/lib/defaults/infra-modules/**/*"
]
],
"targets": [
"node18-macos-arm64",
"node18-macos-x64",
"node18-linux-arm64",
"node18-linux-x64",
"node18-win-arm64",
"node18-win-x64"
],
"outputPath":"./standalone-binaries"
}
}
Loading
Loading