Skip to content

Commit

Permalink
feat: add support for apple silicon
Browse files Browse the repository at this point in the history
* update prompt-install to detect and handle prompt installation for
  apple silicon (arm64e) architecture
* install homebrew used to manage rosetta 2 installations (x86_64) in
  /usr/local
* install homebrew used to manage native installations (arm64e) in
  /opt/homebrew
* introduce `brew-intel` and `brew-arm` aliases to enable management of
  both installations regardless of the architecture of the current shell
* update `use-shell` to detect arm64e native shells
* fix an issue where the PATH variable is reordered by invalid
  path_helper invocations
* normalise and fix areas where the PATH variable is modified
* normalise eval invocations (such as completions)
* remove completion check for gulp and grunt, which are largely obsolete
* fix an issue where it was assumed that gpg was available
* add end-to-end tests for Windows 2019 under WSL 1
* add end-to-end tests for all validated linux distributions
  - create a non-root user
  - add user to sudoers
  - install gosu
  - use gosu to invoke installs and tests under non-root user
* update VERSION logic in prompt-install / update to support the `next`
  branch and any future branches
  - this should be improved in the future to correctly recommend updates
    based on semver tags (or the branch/channel used to install prompt)

Closes: #66, #69

NOTE:

Homebrew, which we rely heavily on, does not yet officially support
apple silicon. In addition, very few formulae include bottles (pre-compiled)
binaries for the SoC. As a result, most formulae must be compiled from
source. Many formulae do not yet successfully compile for apple silicon
and so we must gracefully fallback to their x86_64 counterparts.

The following methodology is used to support prompt on apple silicon
macs:

1. install homebrew instance for intel/rosetta (x86_64) under /usr/local
2. detect apple silicon (arm64e) and install homebrew instance in
  /opt/homebrew
3. attempt to install all tools included with prompt natively in
  /opt/homebrew
4. install all tools included with prompt under rosetta in /usr/local
5. ensure /opt/homebrew is prioritised in the PATH variable

The above methodology will enable native tools if and when they are
available and working with apple silicon. Tools that are not available
and/or fail will fallback to the rosetta versions. This enables a
seamless experience for apple silicon users.
  • Loading branch information
dmccaffery committed Dec 16, 2020
1 parent a378183 commit b2685ce
Show file tree
Hide file tree
Showing 41 changed files with 517 additions and 143 deletions.
4 changes: 3 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,6 @@ AUTHORS text
*.psd1 text eol=crlf

# unix files
*.sh text eol=lf
*.sh text eol=lf
src/** text eol=lf
template/* text eol=lf
106 changes: 75 additions & 31 deletions .github/workflows/end-to-end.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,37 +35,81 @@ jobs:
- name: checkout
uses: actions/checkout@v2
- name: install-bash
run: ./install.sh bash | tee log.txt && bash -lc 'cat $AM_PROMPT/.sha'
run: ./hack/install.sh bash
- name: install-zsh
run: ./install.sh zsh | tee log.txt && zsh -lc 'cat $AM_PROMPT/.sha'
run: ./hack/install.sh zsh
- name: run-tests
run: ./test.sh
run: ./hack/test.sh

# TODO: add this after figuring out a consistent way to create a non-root user without having to create specialised
# dockerfiles for each container type (linuxbrew refuses to install with the root user)
# docker:
# name: "end-to-end-${{ matrix.container }}"
# runs-on: ubuntu-20.04
# container: ${{ matrix.container }}
# needs: cancel
# strategy:
# matrix:
# container:
# - centos:7
# - centos:8
# - debian:9
# - debian:10
# - fedora:32
# - fedora:33
# - linuxmintd/mint18-amd64
# - linuxmintd/mint19-amd64
# - linuxmintd/mint20-amd64
# steps:
# - name: checkout
# uses: actions/checkout@v2
# - name: install-bash
# run: ./install.sh bash | tee log.txt && bash -lc 'cat $AM_PROMPT/.sha'
# - name: install-zsh
# run: ./install.sh zsh | tee log.txt && zsh -lc 'cat $AM_PROMPT/.sha'
# - name: run-tests
# run: ./test.sh
win:
name: "end-to-end-${{ matrix.os }}"
runs-on: ${{ matrix.os }}
needs: cancel
strategy:
matrix:
os:
- windows-2019
defaults:
run:
shell: wsl-bash {0}
steps:
- name: setup-wsl
uses: vampire/setup-wsl@v1
- name: checkout
uses: actions/checkout@v2
- name: install-pre
run: ./hack/pre.apt.sh
- name: install-bash
run: gosu build ./hack/install.sh bash
- name: install-zsh
run: gosu build ./hack/install.sh zsh
- name: run-tests
run: gosu build ./hack/test.sh

docker-apt:
name: "end-to-end-${{ matrix.container }}"
runs-on: ubuntu-20.04
container: ${{ matrix.container }}
needs: cancel
strategy:
matrix:
container:
- debian:9
- debian:10
- linuxmintd/mint18-amd64
- linuxmintd/mint19-amd64
- linuxmintd/mint20-amd64
steps:
- name: checkout
uses: actions/checkout@v2
- name: install-pre
run: ./hack/pre.apt.sh
- name: install-bash
run: gosu build ./hack/install.sh bash
- name: install-zsh
run: gosu build ./hack/install.sh zsh
- name: run-tests
run: gosu build ./hack/test.sh

docker-yum:
name: "end-to-end-${{ matrix.container }}"
runs-on: ubuntu-20.04
container: ${{ matrix.container }}
needs: cancel
strategy:
matrix:
container:
- centos:8
- fedora:32
- fedora:33
steps:
- name: checkout
uses: actions/checkout@v2
- name: install-pre
run: ./hack/pre.yum.sh
- name: install-bash
run: gosu build ./hack/install.sh bash
- name: install-zsh
run: gosu build ./hack/install.sh zsh
- name: run-tests
run: gosu build ./hack/test.sh
8 changes: 7 additions & 1 deletion .releaserc.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
plugins:
- "@semantic-release/commit-analyzer"
- "@semantic-release/release-notes-generator"
- "@semantic-release/github"
- "@semantic-release/changelog"
- path: "@semantic-release/exec"
prepareCmd: echo ${nextRelease.gitHead} > VERSION
- path: "@semantic-release/github"
assets:
- CHANGELOG.md
- VERSION

branches:
- master
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ only validate a few of the most popular.
| ubuntu | 16.04 (Xenial Xerus), 18.04 (Bionic Beaver), and 20.04 (Focal Fossa) |
| fedora | 32 and 33 |
| debian | 9 (Stretch) and 10 (Buster) |
| centOS | 7 and 8 |
| centOS | 8 |
| mint | 18 (Sarah), 19 (Tara), and 20 (Ulyana) |

> NOTE: not all capabilities are tested. If you discover any bugs or wish to add your favourite distro to the validated
Expand Down
1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
b420dd99ffaa647cd1d8e97ad4b1e6914b03a811
21 changes: 21 additions & 0 deletions hack/e2e.apt.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#! /usr/bin/env sh

set -e

SCRIPT_DIR=$(mktemp -d)

cat <<- 'EOT' > $SCRIPT_DIR.e2e.sh
#! /usr/bin/env sh
set -e
./hack/pre.apt.sh
./hack/install.sh bash
./hack/install.sh zsh
./hack/test.sh
EOT

chmod +x $SCRIPT_DIR/e2e.sh

docker run \
--volume $PWD:/home/build
--volume $SCRIPT_DIR:/build \
debian --tty 'sh -c /build/e2e.sh'
7 changes: 7 additions & 0 deletions hack/e2e.darwin.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#! /usr/bin/env sh

set -e

./hack/install.sh bash
./hack/install.sh zsh
./hack/test.sh
21 changes: 21 additions & 0 deletions hack/e2e.yum.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#! /usr/bin/env sh

set -e

SCRIPT_DIR=$(mktemp -d)

cat <<- 'EOT' > $SCRIPT_DIR.e2e.sh
#! /usr/bin/env sh
set -e
./hack/pre.apt.sh
./hack/install.sh bash
./hack/install.sh zsh
./hack/test.sh
EOT

chmod +x $SCRIPT_DIR/e2e.sh

docker run \
--volume $PWD:/home/build
--volume $SCRIPT_DIR:/build \
centos --tty 'sh -c /build/e2e.sh'
19 changes: 19 additions & 0 deletions hack/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#! /usr/bin/env sh

set -e

SHELL_NAME=${1:-'bash'}

./install.sh $SHELL_NAME

SHELL=$SHELL_NAME

if [ -f /opt/homebrew/bin/$SHELL_NAME ]; then
SHELL=/opt/homebrew/bin/$SHELL_NAME
elif [ -f /usr/local/bin/$SHELL_NAME ]; then
SHELL=/usr/local/bin/${SHELL_NAME}
elif [ -f /home/linuxbrew/.linuxbrew/bin/$SHELL_NAME ]; then
SHELL=/home/linuxbrew/.linuxbrew/bin/${SHELL_NAME}
fi

$SHELL -lc 'cat $AM_PROMPT/.sha'
11 changes: 11 additions & 0 deletions hack/pre.apt.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#! /usr/bin/env sh

set -e

apt-get update && apt-get install -y gosu sudo git
gosu nobody true

useradd --uid 1000 --user-group --system --create-home --no-log-init --groups tty --shell /bin/bash build
echo 'build ALL=(ALL) NOPASSWD:ALL' >>/etc/sudoers
chown -R build:build /home/build
chmod u=rwx,g=rx,o= /home/build
17 changes: 17 additions & 0 deletions hack/pre.yum.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#! /usr/bin/env sh

set -e

gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4
curl -o /usr/local/bin/gosu -SL "https://github.com/tianon/gosu/releases/download/1.11/gosu-amd64"
curl -o /usr/local/bin/gosu.asc -SL "https://github.com/tianon/gosu/releases/download/1.11/gosu-amd64.asc"
gpg --verify /usr/local/bin/gosu.asc
chmod +x /usr/local/bin/gosu
gosu nobody true

yum update -y && yum install -y sudo

useradd --uid 1000 --user-group --system --create-home --no-log-init \--groups tty --shell /bin/bash build
echo 'build ALL=(ALL) NOPASSWD:ALL' >>/etc/sudoers
chown -R build:build /home/build
chmod u=rwx,g=rx,o= /home/build
27 changes: 27 additions & 0 deletions hack/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env sh

final=0

SHELL_NAME=${1:-'bash'}
SHELL=$SHELL_NAME

if [ -f /opt/homebrew/bin/$SHELL_NAME ]; then
SHELL=/opt/homebrew/bin/$SHELL_NAME
elif [ -f /usr/local/bin/$SHELL_NAME ]; then
SHELL=/usr/local/bin/${SHELL_NAME}
elif [ -f /home/linuxbrew/.linuxbrew/bin/$SHELL_NAME ]; then
SHELL=/home/linuxbrew/.linuxbrew/bin/${SHELL_NAME}
fi

for test in ./test/sh/scripts/*.test.sh; do
TERM=dumb $SHELL -lc "$test"
exit_code=$?

if [ $exit_code -ne 0 ]; then
name=$(basename $test)
echo "test ($name) failed: $exit_code"
final=1
fi
done

exit $final
15 changes: 8 additions & 7 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@
set -e

CLR_SUCCESS="\033[1;32m" # BRIGHT GREEN
CLR_WARN="\033[1;33m" # BRIGHT YELLOW
CLR_CLEAR="\033[0m" # DEFAULT COLOR
ECHO='echo'

AM_HOME="$HOME/.am"
AM_PROMPT="$AM_HOME/prompt"

# when not outputing to a tty, add spacing instead of colors
if [ ! -t 1 ]; then
CLR_SUCCESS="\n------------------------------------------------------------------------------------------------------------------------\n"
CLR_WARN=$CLR_SUCCESS
CLR_CLEAR=$CLR_SUCCESS
ECHO='printf'
fi

AM_HOME="$HOME/.am"
AM_PROMPT="$AM_HOME/prompt"

__am_prompt_success() {
$ECHO "${CLR_SUCCESS}prompt-install: $1${CLR_CLEAR}"
}
Expand Down Expand Up @@ -116,10 +118,9 @@ __am_prompt_install() {
local CURL_OPT="$CURL_OPT -H 'Authorization: token $GITHUB_TOKEN'"
fi

local SHA_URI="https://api.github.com/repos/automotivemastermind/prompt/commits/master"
local PROMPT_SHA=$(curl $CURL_OPT $SHA_URI | grep sha | head -n 1 | sed 's#.*\:.*"\(.*\).*",#\1#')
local PROMPT_SHA=$(cat VERSION)
local PROMPT_SHA_PATH=$HOME/.am/prompt/.sha
local PROMPT_CHANGELOG_URI="https://github.com/automotivemastermind/prompt/blob/$PROMPT_SHA/CHANGELOG.md"
local PROMPT_CHANGELOG_URL="https://github.com/automotivemastermind/prompt/blob/$PROMPT_SHA/CHANGELOG.md"

echo $PROMPT_SHA > $PROMPT_SHA_PATH

Expand Down Expand Up @@ -147,7 +148,7 @@ __am_prompt_install() {
. $AM_PROMPT/sh/scripts/use-shell $PROMPT_SHELL

# open the changelog url
. $AM_PROMPT/sh/scripts/open-url $PROMPT_CHANGELOG_URI 1>/dev/null
. $AM_PROMPT/sh/scripts/open-url $PROMPT_CHANGELOG_URL
}

__am_prompt_install $@
8 changes: 0 additions & 8 deletions src/bash/scripts/eval/set-completion
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,6 @@ elif [ -f /usr/share/bash-completion/bash_completion ]; then
. /usr/share/bash-completion/bash_completion
fi

if type gulp 1>/dev/null 2>&1; then
. <(gulp --completion=bash)
fi

if type grunt 1>/dev/null 2>&1; then
. <(grunt --completion=bash)
fi

if type kubectl 1>/dev/null 2>&1; then
. <(kubectl completion bash)
fi
Expand Down
2 changes: 1 addition & 1 deletion src/bash/scripts/eval/set-gcloud-path
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ __am_prompt_set_gcloud_path() {
fi

# add gcloud to the path
export PATH="$HOME/.gcloud/bin":$PATH
export PATH="$HOME/.gcloud/bin:$PATH"
fi

local GCLOUD_CMD=$(command -v gcloud)
Expand Down
8 changes: 3 additions & 5 deletions src/sh/install/centos.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@
__am_prompt_install_centos() {
local SUDO=$(command -v sudo 2>/dev/null || "")
local YUM=$(command -v dnf 2>/dev/null || command -v yum)
local PACKAGES='sudo curl file git which findutils bash'
local PACKAGES='sudo curl file git which findutils bash util-linux-user'

$ECHO "${CLR_SUCCESS}installing development tools...${CLR_CLEAR}"
$SUDO $YUM groupinstall -y "Development Tools"

for pkg in $PACKAGES; do
$ECHO "${CLR_SUCCESS}installing $pkg...${CLR_CLEAR}"
$SUDO $YUM install -y ${pkg}
done
$ECHO "${CLR_SUCCESS}installing $PACKAGES...${CLR_CLEAR}"
$SUDO $YUM install -y ${PACKAGES}

. "$AM_PROMPT/sh/install/linux.sh"
}
Expand Down
Loading

0 comments on commit b2685ce

Please sign in to comment.