diff --git a/.github/workflows/package-build.yaml b/.github/workflows/package-build.yaml new file mode 100644 index 000000000..72d4d0107 --- /dev/null +++ b/.github/workflows/package-build.yaml @@ -0,0 +1,65 @@ +# This is a reusable workflow, as defined by +# https://docs.github.com/en/actions/using-workflows/reusing-workflows +# +# Maintain this separately as the "meat" of the packaging work. Other +# files of form packaging-*.yaml call this one from a different +# perspective. +# +# To handle the documented limitations of reusable workflows, make +# sure the near the /!\ comments match your intended repository and +# user. + +name: Package for publication +on: + workflow_call: + inputs: + fallback_version: + type: string + required: true + git_ref: + type: string + required: true + deb_version: + type: string + required: false + rpm_version: + type: string + required: false + pacman_tgz_version: + type: string + required: false +defaults: + run: + shell: bash +jobs: + package-pash: + runs-on: ubuntu-latest + steps: + - name: Clone PaSh + uses: actions/checkout@v2 + with: + ref: ${{ inputs.git_ref }} + - name: Clone FPM + uses: actions/checkout@v2 + with: + repository: jordansissel/fpm + token: ${{ secrets.GH_PAT }} + path: scripts/package/fpm + - name: Build packages + run: | + build() { + ./deploy.sh "$1" "${2:-${{ inputs.fallback_version }}}" "$3"; + } + cd scripts/package + sed -i 's/--squash//g' fpm/Makefile + DOCKERHUB_TOKEN='${{ secrets.DOCKERHUB_TOKEN }}' + DOCKERHUB_USERNAME='${{ secrets.DOCKERHUB_USERNAME }}' + echo "$DOCKERHUB_TOKEN" | docker login --username "$DOCKERHUB_USERNAME" --password-stdin; + build ubuntu '${{ inputs.deb_version }}' deb; + build fedora '${{ inputs.rpm_version }}' rpm; + build archlinux '${{ inputs.pacman_tgz_version }}' pacman; + - name: Upload Packages as Artifacts + uses: actions/upload-artifact@v3 + with: + name: Packages + path: scripts/package/output diff --git a/.github/workflows/package-gui.yaml b/.github/workflows/package-gui.yaml new file mode 100644 index 000000000..bfd44a26f --- /dev/null +++ b/.github/workflows/package-gui.yaml @@ -0,0 +1,37 @@ +# For use in GitHub's Actions GUI +# https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/ +name: On-demand Packaging +on: + workflow_dispatch: + branches: + - '*' + inputs: + fallback_version: + # TODO: The comment in ./package-pull-requests.yaml + # impacts whether this is good for the user to read. + description: 'What fallback version string can I use for some package format? Compatibility not guarenteed for all package formats.' + default: '0.0.1' + required: true + git_ref: + description: 'Git reference, like a branch name or commit hash' + default: 'main' + required: true + deb_version: + description: "What version string should I use in .deb format packages, if not the fallback?" + required: false + rpm_version: + description: '.rpm?' + required: false + pacman_tgz_version: + description: "pacman's .tar.gz?" + required: false +jobs: + build-packages: + uses: zyrolasting/pash/.github/workflows/package-build.yaml@fpm + with: + fallback_version: ${{ inputs.fallback_version }} + deb_version: ${{ inputs.deb_version }} + rpm_version: ${{ inputs.rpm_version }} + pacman_tgz_version: ${{ inputs.pacman_tgz_version }} + git_ref: ${{ inputs.git_ref }} + secrets: inherit diff --git a/.github/workflows/package-pull-requests.yaml b/.github/workflows/package-pull-requests.yaml new file mode 100644 index 000000000..cb8d96e3d --- /dev/null +++ b/.github/workflows/package-pull-requests.yaml @@ -0,0 +1,17 @@ +name: Package Public Pull Requests (always 0.0.0) +on: + pull_request: + branches: + - main + - future +jobs: + build-packages: + if: ${{ github.event.pull_request.draft == false }} + uses: zyrolasting/pash/.github/workflows/package-build.yaml@main + with: + # TODO: consider using version files in the repository + # 0.0.0 has been tested to work in Fedora, Ubuntu, Debian, and Arch, + # which does not imply compatibility with all package formats. + fallback_version: '0.0.0' + git_ref: ${{ github.event.pull_request.head.sha }} + secrets: inherit diff --git a/.github/workflows/package.yaml b/.github/workflows/package.yaml new file mode 100644 index 000000000..83a3acf1c --- /dev/null +++ b/.github/workflows/package.yaml @@ -0,0 +1,27 @@ +name: Packaging +on: + pull_request: + branches: + - main + - future + +jobs: + package-pash: + runs-on: ubuntu-latest + if: github.event.pull_request.draft == false + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: Make .deb + run: bash scripts/package/deploy.sh ubuntu "$GITHUB_HEAD_REF" deb + - name: Make .rpm + run: bash scripts/package/deploy.sh fedora "$GITHUB_HEAD_REF" rpm + - name: Make .tar.gz (Pacman) + run: bash scripts/package/deploy.sh archlinux "$GITHUB_HEAD_REF" pacman + - name: Upload Packages as Artifacts + uses: actions/upload-artifact@v3 + with: + name: Packages + path: scripts/package/output diff --git a/docs/tooling/packaging.md b/docs/tooling/packaging.md new file mode 100644 index 000000000..50023b0db --- /dev/null +++ b/docs/tooling/packaging.md @@ -0,0 +1,75 @@ +# Packaging PaSh + +`scripts/package` packages PaSh into various formats. The software inside is a suitable +replacement for deployments depending on `install.sh`, +`setup-pash.sh`, `up.sh`, `distro-deps.sh`, and/or `pkg.sh`. + + +## Building Packages +[eef]: https://github.com/docker/cli/blob/master/experimental/README.md + +``` +build.sh VERSION [OUTPUT_FORMAT ...] +``` + +Creates new package files using the repository's current content, each +with mode 440. All output files appear in `scripts/package/output`. + +**Clean up junk files and new test results!** The scripts use a +reasonable ignore list, but otherwise defaults to including files +within the PaSh repository. + +Command-line arguments correspond to those found in [FPM's +CLI](https://fpm.readthedocs.io/en/v1.14.2/cli-reference.html): + + - `VERSION` is the value of `--version`. + - `OUTPUT_FORMAT` is some value for `--output-type` + + +## Testing Packages + +``` + deploy.sh IMAGE VERSION FORMAT +``` + +Performs a test deployment of PaSh, as follows: + +1. Run `build.sh VERSION FORMAT` +2. Start Docker container based on `docker pull IMAGE` +3. Install the package from Step 1 in the container from Step 2. +4. Run the newly-installed `pa.sh` against a bundled `evaluation/intro/hello-world.sh` example. + +Here, `deploy.sh` installs a `pacman`/`.tar.gz` package deploys in +Arch, a `.deb` package for Debian and Ubuntu, and an RPM package for +Fedora. + +``` +$ version=0.0.1 +$ PATH="$PASH_TOP/scripts/package:$PATH" +$ deploy.sh archlinux $version pacman +$ deploy.sh debian $version deb +$ deploy.sh ubuntu $version deb +$ deploy.sh fedora $version rpm +``` + +## Developing Packages + +``` + iterate.sh IMAGE FORMAT +``` + +Runs `deploy.sh IMAGE 0.0.1 FORMAT`, then prompts to repeat. + + +## GitHub Actions + +The source code repository defines workflows for GitHub actions. The +workflows for packaging all use `deploy.sh` to build and run PaSh's +"Hello, World" example. One workflow responds to new pull requests. + +**On-Demand Packaging** is the only workflow that can be directly +used in the GitHub GUI. You can find it under the **Actions** tab. + +![image](https://user-images.githubusercontent.com/1312121/181671950-89ec5f57-5b9f-4fdb-90a2-6d1099257ad1.png) + +Click "Run Workflow" and fill out the form. The form defines what commit of PaSh gets packaged, and each package format may have its own version string. diff --git a/pa.sh b/pa.sh index 50ab34632..6b58ea1d6 100755 --- a/pa.sh +++ b/pa.sh @@ -2,9 +2,15 @@ export PASH_TOP=${PASH_TOP:-${BASH_SOURCE%/*}} export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib/" -# point to the local downloaded folders -export PYTHONPATH=${PASH_TOP}/python_pkgs/ -## Register the signal handlers, we can add more signals here + +# Until PaSh is set up in a way that naturally integrates with +# Python's system-level paths, prefer local package installations. +export PYTHONPATH="$( + find "$PASH_TOP" \ + -type d \( -name site-packages -or -name dist-packages \) \ + -printf '%p:' +)$PASH_TOP/python_pkgs" + trap kill_all SIGTERM SIGINT ## kill all the pending processes that are spawned by this shell @@ -14,6 +20,7 @@ function kill_all() { # kill pash_daemon kill -s SIGKILL "$daemon_pid" } + ## Save the umask to first create some files and then revert it old_umask=$(umask) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..80cd1c5cd --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +jsonpickle +matplotlib +numpy +pexpect diff --git a/scripts/package/.gitignore b/scripts/package/.gitignore new file mode 100644 index 000000000..2626ba200 --- /dev/null +++ b/scripts/package/.gitignore @@ -0,0 +1,2 @@ +fpm +output diff --git a/scripts/package/build.sh b/scripts/package/build.sh new file mode 100755 index 000000000..ff4f87fce --- /dev/null +++ b/scripts/package/build.sh @@ -0,0 +1,45 @@ +#! /usr/bin/env bash +# Launch REPL for building PaSh system packages. + +here="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" +PASH_TOP=$(readlink -f "$here/../..") + +# We need FPM's source code to build a key Docker image. +if [ ! -d "$here/fpm" ]; then + git clone --depth 1 git@github.com:jordansissel/fpm.git "$here/fpm" + sed -i 's/--squash//g' "$here/fpm/Makefile" +fi + +# Make a Docker image that knows about building packages. +if ! docker image inspect fpm 2>&1 >/dev/null; then + make -C "$here/fpm" docker-release-everything +fi + +mkdir -p "$here/output" + +main() { + local docker_interactive_flags='' + local entrypoint_interactive_flags='' + + if [[ $- == *i* ]]; then + set -x + docker_interactive_flags='--interactive --tty' + entrypoint_interactive_flags='--rcfile' + set +x + fi + + docker run \ + --entrypoint /bin/bash \ + --rm \ + --user "$(id -u):$(id -g)" \ + --volume "$here/output:/out" \ + --volume "$here/tools:/tools" \ + --volume "$PASH_TOP:/src" \ + $docker_interactive_flags \ + fpm \ + $entrypoint_interactive_flags \ + /tools/start "$@" +} + +# Only enter if script was not sourced +(return 2>/dev/null) || main "$@" diff --git a/scripts/package/deploy.sh b/scripts/package/deploy.sh new file mode 100755 index 000000000..40bd7f559 --- /dev/null +++ b/scripts/package/deploy.sh @@ -0,0 +1,61 @@ +#! /usr/bin/env bash + +# Build, install, and use PaSh in a new Docker container. +# +# deploy.sh IMAGE VERSION FORMAT +# +# Exit code matches that from running `./tests/$3/main.sh` in the +# container. 0 is a sign of PaSh's functionality in the other +# environment. +# +# Scripts in ./tests may use /package in the container to store +# information on the host, but printing should suffice. +# +# $1 - IMAGE name from Docker Hub to use +# $2 - VERSION of PaSh to install in a container +# $3 - FPM package FORMAT for the named PaSh version + +set -euo pipefail + +me="$(readlink -f "${BASH_SOURCE[0]}")" +mydirname="$(dirname "$me")" +myname="$(basename "$me")" + +if [ -f /.dockerenv ]; then + set +x + # Pass control to vertification script. + target_version="$1" + output_format="$2" + + # Keep this here, so tests don't need to keep setting the variable. + export PASH_TOP=/usr/lib/pash + + "$mydirname/fire-hook.sh" "before-test" "$output_format" "$target_version" + + # Basic example must always work, no matter where we're going. + [ -d "$PASH_TOP" ] + test_script="${PASH_TOP}/evaluation/intro/hello-world.sh" + set -x + time pa.sh "$test_script" + time bash "$test_script" + set +x +else + image="$1" + target_version="$2" + output_format="$3" + + # Perform a one-off build for the package. + "$mydirname/build.sh" "$target_version" "$output_format" + + # It's important to use Docker hub here because we want to verify + # PaSh's behavior against other people's work, namely official OS + # images. + docker pull "$image" + + # Invoke self in the container. + docker run \ + --rm \ + --volume "${mydirname}:/package" \ + "$image" \ + "/package/${myname}" "$target_version" "$output_format" +fi diff --git a/scripts/package/fire-hook.sh b/scripts/package/fire-hook.sh new file mode 100755 index 000000000..8368391e9 --- /dev/null +++ b/scripts/package/fire-hook.sh @@ -0,0 +1,18 @@ +#! /usr/bin/env bash + +# Fire hook script in response to an event. Hooks are format-specific, +# so Debian packages can respond differently than Arch packages, for +# example. + +set -eu +event_name="$1"; shift + +here="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" +event="$here/hooks/${event_name}" + +if [ -f "$event/hook" ]; then + # Pass directory path so the script don't need to figure out where + # it is. -f implies the script does not have to be Bash, but use + # of non-executables must raise an error. + "$event/hook" "$event" "$@" +fi diff --git a/scripts/package/hooks/after-install/hook b/scripts/package/hooks/after-install/hook new file mode 100755 index 000000000..963faa3d0 --- /dev/null +++ b/scripts/package/hooks/after-install/hook @@ -0,0 +1,66 @@ +#! /usr/bin/env bash + +# This script is called by a system package manager to request on-site +# setup on a host, after the package itself is installed. + +set -euo pipefail + +PASH_LOG=/var/log/pash +PASH_TOP=/usr/lib/pash + +# We don't want the entry point to set its own environment variable, +# because that would entail checks that cannot be optimized. +sed -i "s@^export[[:space:]]\{1,\}PASH_TOP=.*@export PASH_TOP='$PASH_TOP'@" "${PASH_TOP}/pa.sh" + +post_install_current_target() { + this_directory="$1" + output_format="$2" + recipe="${this_directory}/${output_format}" + + # Give the user a place to look when things go wrong. + log_file="$PASH_LOG/post-install.log" + mkdir -vp "$PASH_LOG" + printf "pash: post-install log: '%s'\n" "$log_file" 1>&2 + + # Put pa.sh in PATH, replacing any existing link. -f helps if a + # distribution leaves the link after uninstallation, but adds the + # risk of breaking a working link. + ln -fs "$PASH_TOP/pa.sh" /usr/bin/pa.sh + + export PASH_TOP + + ( + set -e + post_install_python_project + post_install_libdash + post_install_runtime + if [ -f "$recipe" ]; then + "$recipe" # -f, so non-executables raise an error + fi + ) | tee "$log_file" +} + + +post_install_python_project() { + python3 -m pip install \ + --ignore-installed \ + --requirement "$PASH_TOP/requirements.txt" \ + --root "$PASH_TOP/python_pkgs" +} + + +post_install_libdash() { + cd "$PASH_TOP/compiler/parser" + rm -rf libdash # might have survived uninstallation, and I don't trust the make cache. + git clone https://github.com/angelhof/libdash/ + make libdash +} + +post_install_runtime() { + cd "$PASH_TOP/runtime" + make clean + make +} + + +(return 2>/dev/null) || post_install_current_target "$@" diff --git a/scripts/package/hooks/before-test/deb b/scripts/package/hooks/before-test/deb new file mode 100755 index 000000000..ffadcb972 --- /dev/null +++ b/scripts/package/hooks/before-test/deb @@ -0,0 +1,7 @@ +#! /usr/bin/env sh +apt update + +# Suppress mid-installation timezone prompt +DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata + +apt install -y "/package/output/pash-$1.deb" diff --git a/scripts/package/hooks/before-test/hook b/scripts/package/hooks/before-test/hook new file mode 100755 index 000000000..625b533f1 --- /dev/null +++ b/scripts/package/hooks/before-test/hook @@ -0,0 +1,8 @@ +#! /usr/bin/env sh +# $1 - Path to containing directory +# $2 - Output format, as used in FPM +# $3 - Package version +# +# Dispatch to script, such that the script can assume it runs for a +# specific package format. +"$1/$2" "$3" diff --git a/scripts/package/hooks/before-test/pacman b/scripts/package/hooks/before-test/pacman new file mode 100755 index 000000000..7c67a0860 --- /dev/null +++ b/scripts/package/hooks/before-test/pacman @@ -0,0 +1,4 @@ +#! /usr/bin/env sh +set -eu +pacman -Sy +LC_ALL=en_US.UTF-8 pacman --noconfirm -U "/package/output/pash-$1.tar.gz" diff --git a/scripts/package/hooks/before-test/rpm b/scripts/package/hooks/before-test/rpm new file mode 100755 index 000000000..45820f904 --- /dev/null +++ b/scripts/package/hooks/before-test/rpm @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +sudo yum localinstall -y "/package/output/pash-${1}.rpm" diff --git a/scripts/package/iterate.sh b/scripts/package/iterate.sh new file mode 100755 index 000000000..5d7207266 --- /dev/null +++ b/scripts/package/iterate.sh @@ -0,0 +1,6 @@ +#! /usr/bin/env bash +set -u +./deploy.sh "$1" 0.0.1 "$2" +read -p "Repeat? [Y/n]" -n 1 -r +echo +[[ $REPLY =~ ^[Yy]$ ]] && "$0" diff --git a/scripts/package/tools/build b/scripts/package/tools/build new file mode 100755 index 000000000..1f4f7c532 --- /dev/null +++ b/scripts/package/tools/build @@ -0,0 +1,247 @@ +#! /usr/bin/env bash + +# Build a specific package in the context of FPM's Docker container. +# https://fpm.readthedocs.io/ +# +# Do not use any system package manager here. + +set -eo pipefail +version="${1:-now}" +install_dir=/usr/lib/pash +if [ -n "$1" ]; then shift; fi +set -u + + +print_dotfpm() { + local output_format="$1" + local after_install="$2" + + # I/O rules, with Docker container paths + flag --chdir /src + flag --input-type dir + flag --output-type "$output_format" + flag --log info + flag --verbose + flag --force + + # Discovery information + flag --name pash + flag --description "Parallelize POSIX shell scripts" + flag --license mit + flag --architecture all + flag --url 'https://github.com/binpash/pash' + flag --version "$version" + + # Pass control to PaSh after installation + flag --after-install "$after_install" + + # Target information + case "$output_format" in + deb) + print_dotfpm_deb + ;; + freebsd) + print_dotfpm_freebsd + ;; + pacman) + print_dotfpm_pacman + ;; + python) + print_dotfpm_python + ;; + rpm) + print_dotfpm_rpm + ;; + *) + printf "Unsupported format: '%s'\n" "$output_format" 1>&2 + exit 1 + ;; + esac + + # Map contents from here to target system. + # + # TODO: Consider include-only approach. This will pick up any + # junk not expressly excluded. Maybe bind to Git's tracked files? + flag --exclude '*.git*' + flag --exclude '*.pyc' + flag --exclude '*__pycache__*' + flag --exclude '*compiler/parser/libdash*' + flag --exclude '*python_pkg*' + flag --exclude '*package/output*' + flag --exclude '*package/fpm*' + + printf ".=%s\n" "$install_dir" +} + + +# +# Target-specific flags +# + +print_dotfpm_pacman() { + # FPM seems to think every tar binary supports --zstd + # at time of writing, so fall back to gzip on Arch. + print_dotfpm_output_path .tar.gz + flag --pacman-compression gz + + flag --depends autoconf + flag --depends automake + flag --depends bash + flag --depends bc + flag --depends curl + flag --depends gcc + flag --depends git + flag --depends inetutils + flag --depends libffi + flag --depends libtool + flag --depends m4 + flag --depends make + flag --depends openbsd-netcat + flag --depends pkg-config + flag --depends python + flag --depends python-pip + flag --depends sudo + flag --depends wget +} + + +print_dotfpm_rpm() { + print_dotfpm_output_path .rpm + + flag --depends autoconf + flag --depends automake + flag --depends bash + flag --depends bc + flag --depends curl + flag --depends diffutils + flag --depends gcc + flag --depends gcc-c++ + flag --depends git + flag --depends glibc-langpack-en + flag --depends hostname + flag --depends libjpeg-devel + flag --depends libtool + flag --depends libtool + flag --depends m4 + flag --depends make + flag --depends nc + flag --depends pip + flag --depends pkg-config + flag --depends procps + flag --depends python + flag --depends python-devel + flag --depends python3 + flag --depends python3-pip + flag --depends python3-setuptools + flag --depends python3-testresources + flag --depends wget + flag --depends zlib-devel +} + + +print_dotfpm_deb() { + print_dotfpm_output_path .deb + + flag --depends autoconf + flag --depends automake + flag --depends bash + flag --depends bc + flag --depends bsdmainutils + flag --depends curl + flag --depends g++-10 + flag --depends git + flag --depends libffi-dev + flag --depends libtool + flag --depends locales + flag --depends locales-all + flag --depends m4 + flag --depends netcat-openbsd + flag --depends pkg-config + flag --depends python3-pip + flag --depends python3-setuptools + flag --depends python3-testresources + flag --depends wamerican-insane + flag --depends wget +} + + +print_dotfpm_python() { + # TODO: Is this extension correct? + print_dotfpm_output_path .tar + + # Handle requirements.txt with `python3 -m pip` + # That is, the 'internal' pip. + flag --python-bin /bin/python3 + flag --python-obey-requirements-txt + flag --python-internal-pip +} + + +print_dotfpm_freebsd() { + # TODO: Is this extension correct? + print_dotfpm_output_path .tar + + flag --depends autoconf + flag --depends automake + flag --depends bash + flag --depends bc + flag --depends curl + flag --depends gcc + flag --depends git + flag --depends gmake + flag --depends gsed + flag --depends libffi + flag --depends libtool + flag --depends m4 + flag --depends pkg-config + flag --depends py38-pip + flag --depends wget +} + + + +print_dotfpm_output_path() { + output_file="${output_file_prefix}${1}" + flag --package "$output_file" +} + +# Post-installation steps depend on the target. Rather than ask one +# script to entertain every platform, dispatch to a specialized +# script. +print_post_install_script() { + local output_format="$1" + printf '#! /usr/bin/env bash\n' + printf "/usr/lib/pash/scripts/package/fire-hook.sh 'after-install' '%s'\n" "$output_format" +} + +# +# The rest defines how the above works. +# + +flag() { + if [ "$#" -gt 1 ]; then + printf "%s '%s'\n" "$1" "$2" + else + printf "%s\n" "$1" + fi +} + + +main() { + for output_format in "$@"; do + after_install="$(mktemp)" + print_post_install_script "$output_format" > "$after_install" + cat "$after_install" + output_file_prefix="/out/pash-${version}" + + print_dotfpm "$output_format" "$after_install" > .fpm + + set +e + /fpm/bin/fpm && chmod 440 "$output_file" + rm -vf "$after_install" .fpm + set -e + printf '\n' + done +} + +main "$@" diff --git a/scripts/package/tools/help b/scripts/package/tools/help new file mode 100644 index 000000000..e69de29bb diff --git a/scripts/package/tools/start b/scripts/package/tools/start new file mode 100755 index 000000000..72a992c21 --- /dev/null +++ b/scripts/package/tools/start @@ -0,0 +1,6 @@ +#! /usr/bin/env bash +export PASH_TOP="/src" +export PATH="/tools:$PATH" + +# Non-interactive shells are used to build packages, namely via CI. +[[ $- == *i* ]] || build "$@" diff --git a/scripts/utils.sh b/scripts/utils.sh index 4c5974b5f..faba1af2b 100755 --- a/scripts/utils.sh +++ b/scripts/utils.sh @@ -43,6 +43,16 @@ append_nl_if_not(){ fi } + +use_alternative_debian_gpp10() { + apt-get install software-properties-common -y + add-apt-repository ppa:ubuntu-toolchain-r/test -y + apt-get install g++-10 + update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 100 + update-alternatives --set g++ /usr/bin/g++-10 +} + + install_deps_source_setup() { # move to the input directory cd input/ @@ -59,6 +69,8 @@ install_deps_source_setup() { setup_dataset $1 > /dev/null cd .. } + + ######################### # The command line help # #########################