aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--README.md21
-rw-r--r--myapp/BUILD12
-rw-r--r--myapp/myapp.py8
-rw-r--r--myapp/requirements.txt1
-rw-r--r--mylib/BUILD1
-rw-r--r--mylib/__init__.py3
-rw-r--r--mylib/main.py0
-rwxr-xr-xpants372
-rw-r--r--pants.toml9
10 files changed, 433 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d2553fc
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+# Pants workspace files
+/.pants.d/
+/dist/
+/.pids
+/.pants.workdir.file_lock*
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..340104c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,21 @@
+# Sample Pants Project
+
+This is just an example of how to use Pants to manage a monorepo. To run from
+scratch you will need to activate a python interpreter `3.6.15` and the
+following command.
+
+```
+./pants run myapp:pex
+```
+
+or to build a pex
+
+```
+./pants package myapp:pex
+./dist/myapp/pex.pex
+```
+
+Things Tested:
+ - How to include a requirements
+ - How to pin a interpreter version (myapp)
+ - How to include an additional local dependancy (mylib)
diff --git a/myapp/BUILD b/myapp/BUILD
new file mode 100644
index 0000000..4061830
--- /dev/null
+++ b/myapp/BUILD
@@ -0,0 +1,12 @@
+python_library()
+
+# You don't need to pass in 'requirements_relpath' if the file
+# is called 'requirements.txt' but I added this just for explicitness
+python_requirements(requirements_relpath="requirements.txt")
+
+pex_binary(
+ name="pex",
+ dependencies=["mylib"],
+ entry_point="myapp.py",
+ interpreter_constraints=["CPython==3.6.15"],
+)
diff --git a/myapp/myapp.py b/myapp/myapp.py
new file mode 100644
index 0000000..7f5c16b
--- /dev/null
+++ b/myapp/myapp.py
@@ -0,0 +1,8 @@
+import requests
+
+import mylib
+
+
+print(requests.get("https://www.google.com"))
+print(requests.__version__)
+mylib.hello_world()
diff --git a/myapp/requirements.txt b/myapp/requirements.txt
new file mode 100644
index 0000000..7d34355
--- /dev/null
+++ b/myapp/requirements.txt
@@ -0,0 +1 @@
+requests==2.25.0
diff --git a/mylib/BUILD b/mylib/BUILD
new file mode 100644
index 0000000..d80ecb5
--- /dev/null
+++ b/mylib/BUILD
@@ -0,0 +1 @@
+python_library()
diff --git a/mylib/__init__.py b/mylib/__init__.py
new file mode 100644
index 0000000..3f1e31f
--- /dev/null
+++ b/mylib/__init__.py
@@ -0,0 +1,3 @@
+"""My super library."""
+def hello_world():
+ print("Hello World!")
diff --git a/mylib/main.py b/mylib/main.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mylib/main.py
diff --git a/pants b/pants
new file mode 100755
index 0000000..f5b2b80
--- /dev/null
+++ b/pants
@@ -0,0 +1,372 @@
+#!/usr/bin/env bash
+# Copyright 2020 Pants project contributors (see CONTRIBUTORS.md).
+# Licensed under the Apache License, Version 2.0 (see LICENSE).
+
+# =============================== NOTE ===============================
+# This ./pants bootstrap script comes from the pantsbuild/setup
+# project. It is intended to be checked into your code repository so
+# that other developers have the same setup.
+#
+# Learn more here: https://www.pantsbuild.org/docs/installation
+# ====================================================================
+
+set -eou pipefail
+
+# NOTE: To use an unreleased version of Pants from the pantsbuild/pants main branch,
+# locate the main branch SHA, set PANTS_SHA=<SHA> in the environment, and run this script as usual.
+#
+# E.g., PANTS_SHA=725fdaf504237190f6787dda3d72c39010a4c574 ./pants --version
+
+PYTHON_BIN_NAME="${PYTHON:-unspecified}"
+
+# Set this to specify a non-standard location for this script to read the Pants version from.
+# NB: This will *not* cause Pants itself to use this location as a config file.
+# You can use PANTS_CONFIG_FILES or --pants-config-files to do so.
+PANTS_TOML=${PANTS_TOML:-pants.toml}
+
+PANTS_BIN_NAME="${PANTS_BIN_NAME:-$0}"
+
+PANTS_SETUP_CACHE="${PANTS_SETUP_CACHE:-${XDG_CACHE_HOME:-$HOME/.cache}/pants/setup}"
+# If given a relative path, we fix it to be absolute.
+if [[ "$PANTS_SETUP_CACHE" != /* ]]; then
+ PANTS_SETUP_CACHE="${PWD}/${PANTS_SETUP_CACHE}"
+fi
+
+PANTS_BOOTSTRAP="${PANTS_SETUP_CACHE}/bootstrap-$(uname -s)-$(uname -m)"
+
+_PEX_VERSION=2.1.42
+_PEX_URL="https://github.com/pantsbuild/pex/releases/download/v${_PEX_VERSION}/pex"
+_PEX_EXPECTED_SHA256="69d6b1b1009b00dd14a3a9f19b72cff818a713ca44b3186c9b12074b2a31e51f"
+
+VIRTUALENV_VERSION=20.4.7
+VIRTUALENV_REQUIREMENTS=$(
+cat << EOF
+virtualenv==${VIRTUALENV_VERSION} --hash sha256:2b0126166ea7c9c3661f5b8e06773d28f83322de7a3ff7d06f0aed18c9de6a76
+filelock==3.0.12 --hash sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836
+six==1.16.0 --hash sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+distlib==0.3.2 --hash sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c
+appdirs==1.4.4 --hash sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128
+importlib-resources==5.1.4; python_version < "3.7" --hash sha256:e962bff7440364183203d179d7ae9ad90cb1f2b74dcb84300e88ecc42dca3351
+importlib-metadata==4.5.0; python_version < "3.8" --hash sha256:833b26fb89d5de469b24a390e9df088d4e52e4ba33b01dc5e0e4f41b81a16c00
+zipp==3.4.1; python_version < "3.10" --hash sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098
+typing-extensions==3.10.0.0; python_version < "3.8" --hash sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84
+EOF
+)
+
+COLOR_RED="\x1b[31m"
+COLOR_GREEN="\x1b[32m"
+COLOR_YELLOW="\x1b[33m"
+COLOR_RESET="\x1b[0m"
+
+function log() {
+ echo -e "$@" 1>&2
+}
+
+function die() {
+ (($# > 0)) && log "${COLOR_RED}$*${COLOR_RESET}"
+ exit 1
+}
+
+function green() {
+ (($# > 0)) && log "${COLOR_GREEN}$*${COLOR_RESET}"
+}
+
+function warn() {
+ (($# > 0)) && log "${COLOR_YELLOW}$*${COLOR_RESET}"
+}
+
+function tempdir {
+ mkdir -p "$1"
+ mktemp -d "$1"/pants.XXXXXX
+}
+
+function get_exe_path_or_die {
+ local exe="$1"
+ if ! command -v "${exe}"; then
+ die "Could not find ${exe}. Please ensure ${exe} is on your PATH."
+ fi
+}
+
+function get_pants_config_value {
+ local config_key="$1"
+ local optional_space="[[:space:]]*"
+ local prefix="^${config_key}${optional_space}=${optional_space}"
+ local raw_value
+ raw_value="$(sed -ne "/${prefix}/ s#${prefix}##p" "${PANTS_TOML}")"
+ echo "${raw_value}" | tr -d \"\' && return 0
+ return 0
+}
+
+function get_python_major_minor_version {
+ local python_exe="$1"
+ "$python_exe" <<EOF
+import sys
+major_minor_version = ''.join(str(version_num) for version_num in sys.version_info[0:2])
+print(major_minor_version)
+EOF
+}
+
+# The high-level flow:
+#
+# 1.) Resolve the Pants version from config so that we know what interpreters we can use, what to name the venv,
+# and what to install via pip.
+# 2.) Resolve the Python interpreter, first reading from the env var $PYTHON, then using a default based on the Pants
+# version.
+# 3.) Check if the venv already exists via a naming convention, and create the venv if not found.
+# 4.) Execute Pants with the resolved Python interpreter and venv.
+#
+# After that, Pants itself will handle making sure any requested plugins
+# are installed and up to date.
+
+function determine_pants_version {
+ if [ -n "${PANTS_SHA:-}" ]; then
+ # get_version_for_sha will echo the version, thus "returning" it from this function.
+ get_version_for_sha "$PANTS_SHA"
+ return
+ fi
+
+ pants_version="$(get_pants_config_value 'pants_version')"
+ if [[ -z "${pants_version}" ]]; then
+ die "Please explicitly specify the \`pants_version\` in your \`pants.toml\` under the \`[GLOBAL]\` scope.
+See https://pypi.org/project/pantsbuild.pants/#history for all released versions
+and https://www.pantsbuild.org/docs/installation for more instructions."
+ fi
+ pants_major_version="$(echo "${pants_version}" | cut -d '.' -f1)"
+ pants_minor_version="$(echo "${pants_version}" | cut -d '.' -f2)"
+ # 1.26 is the first version to support `pants.toml`, so we fail eagerly if using an outdated version.
+ if [[ "${pants_major_version}" -eq 1 && "${pants_minor_version}" -le 25 ]]; then
+ die "This version of the \`./pants\` script does not work with Pants <= 1.25.0 (and it also requires using \`pants.toml\`,
+rather than \`pants.ini\`). Instead, either upgrade your \`pants_version\` or use the version of the \`./pants\` script
+at https://raw.githubusercontent.com/Eric-Arellano/setup/0d445edef57cb89fd830db70810e38f050b0a268/pants."
+ fi
+ echo "${pants_version}"
+}
+
+function set_supported_python_versions {
+ local pants_version="$1"
+ local pants_major_version
+ local pants_minor_version
+ pants_major_version="$(echo "${pants_version}" | cut -d '.' -f1)"
+ pants_minor_version="$(echo "${pants_version}" | cut -d '.' -f2)"
+ if [[ "${pants_major_version}" -eq 1 ]]; then
+ supported_python_versions_decimal=('3.6' '3.7' '3.8')
+ supported_python_versions_int=('36' '37' '38')
+ supported_message='3.6, 3.7, or 3.8'
+ elif [[ "${pants_major_version}" -eq 2 && "${pants_minor_version}" -eq 0 ]]; then
+ supported_python_versions_decimal=('3.6' '3.7' '3.8')
+ supported_python_versions_int=('36' '37' '38')
+ supported_message='3.6, 3.7, or 3.8'
+ elif [[ "${pants_major_version}" -eq 2 && "${pants_minor_version}" -eq 1 ]]; then
+ supported_python_versions_decimal=('3.7' '3.8' '3.6')
+ supported_python_versions_int=('37' '38' '36')
+ supported_message='3.7, 3.8, or 3.6 (deprecated)'
+ elif [[ "${pants_major_version}" -eq 2 && "${pants_minor_version}" -lt 5 ]]; then
+ supported_python_versions_decimal=('3.8' '3.7')
+ supported_python_versions_int=('38' '37')
+ supported_message='3.7 or 3.8'
+ else
+ # We put 3.9 first because Apple Silicon only works properly with Python 3.9, even though it's possible to have
+ # older Pythons installed. This makes it more likely that Pants will work out-of-the-box.
+ supported_python_versions_decimal=('3.9' '3.8' '3.7')
+ supported_python_versions_int=('39' '38' '37')
+ supported_message='3.7, 3.8, or 3.9'
+ fi
+}
+
+function check_python_exe_compatible_version {
+ local python_exe="$1"
+ local major_minor_version
+ major_minor_version="$(get_python_major_minor_version "${python_exe}")"
+ for valid_version in "${supported_python_versions_int[@]}"; do
+ if [[ "${major_minor_version}" == "${valid_version}" ]]; then
+ echo "${python_exe}" && return 0
+ fi
+ done
+}
+
+function determine_default_python_exe {
+ for version in "${supported_python_versions_decimal[@]}" "3" ""; do
+ local interpreter_path
+ interpreter_path="$(command -v "python${version}")"
+ if [[ -z "${interpreter_path}" ]]; then
+ continue
+ fi
+ # Check if the Python version is installed via Pyenv but not activated.
+ if [[ "$("${interpreter_path}" --version 2>&1 > /dev/null)" == "pyenv: python${version}"* ]]; then
+ continue
+ fi
+ if [[ -n "$(check_python_exe_compatible_version "${interpreter_path}")" ]]; then
+ echo "${interpreter_path}" && return 0
+ fi
+ done
+}
+
+function determine_python_exe {
+ local pants_version="$1"
+ set_supported_python_versions "${pants_version}"
+ local requirement_str="For \`pants_version = \"${pants_version}\"\`, Pants requires Python ${supported_message} to run."
+
+ local python_exe
+ if [[ "${PYTHON_BIN_NAME}" != 'unspecified' ]]; then
+ python_exe="$(get_exe_path_or_die "${PYTHON_BIN_NAME}")" || exit 1
+ if [[ -z "$(check_python_exe_compatible_version "${python_exe}")" ]]; then
+ die "Invalid Python interpreter version for ${python_exe}. ${requirement_str}"
+ fi
+ else
+ python_exe="$(determine_default_python_exe)"
+ if [[ -z "${python_exe}" ]]; then
+ die "No valid Python interpreter found. ${requirement_str} Please check that a valid interpreter is installed and on your \$PATH."
+ fi
+ fi
+ echo "${python_exe}"
+}
+
+function compute_sha256 {
+ local python="$1"
+ local path="$2"
+
+ "$python" <<EOF
+import hashlib
+
+hasher = hashlib.sha256()
+with open('${path}', 'rb') as fp:
+ buf = fp.read()
+ hasher.update(buf)
+print(hasher.hexdigest())
+EOF
+}
+
+# TODO(John Sirois): GC race loser tmp dirs leftover from bootstrap_XXX
+# functions. Any tmp dir w/o a symlink pointing to it can go.
+
+function bootstrap_pex {
+ local python="$1"
+ local bootstrapped="${PANTS_BOOTSTRAP}/pex-${_PEX_VERSION}/pex"
+ if [[ ! -f "${bootstrapped}" ]]; then
+ (
+ green "Downloading the Pex PEX."
+ mkdir -p "${PANTS_BOOTSTRAP}"
+ local staging_dir
+ staging_dir=$(tempdir "${PANTS_BOOTSTRAP}")
+ cd "${staging_dir}"
+ curl -LO "${_PEX_URL}"
+ fingerprint="$(compute_sha256 "${python}" "pex")"
+ if [[ "${_PEX_EXPECTED_SHA256}" != "${fingerprint}" ]]; then
+ die "SHA256 of ${_PEX_URL} is not as expected. Aborting."
+ fi
+ green "SHA256 fingerprint of ${_PEX_URL} verified."
+ mkdir -p "$(dirname "${bootstrapped}")"
+ mv -f "${staging_dir}/pex" "${bootstrapped}"
+ rmdir "${staging_dir}"
+ ) 1>&2 || exit 1
+ fi
+ echo "${bootstrapped}"
+}
+
+function scrub_PEX_env_vars {
+ # Ensure the virtualenv PEX runs as shrink-wrapped.
+ # See: https://github.com/pantsbuild/setup/issues/105
+ if [[ -n "${!PEX_@}" ]]; then
+ warn "Scrubbing ${!PEX_@}"
+ unset "${!PEX_@}"
+ fi
+}
+
+function bootstrap_virtualenv {
+ local python="$1"
+ local bootstrapped="${PANTS_BOOTSTRAP}/virtualenv-${VIRTUALENV_VERSION}/virtualenv.pex"
+ if [[ ! -f "${bootstrapped}" ]]; then
+ (
+ green "Creating the virtualenv PEX."
+ pex_path="$(bootstrap_pex "${python}")" || exit 1
+ mkdir -p "${PANTS_BOOTSTRAP}"
+ local staging_dir
+ staging_dir=$(tempdir "${PANTS_BOOTSTRAP}")
+ cd "${staging_dir}"
+ echo "${VIRTUALENV_REQUIREMENTS}" > requirements.txt
+ (
+ scrub_PEX_env_vars
+ "${python}" "${pex_path}" -r requirements.txt -c virtualenv -o virtualenv.pex
+ )
+ mkdir -p "$(dirname "${bootstrapped}")"
+ mv -f "${staging_dir}/virtualenv.pex" "${bootstrapped}"
+ rm -rf "${staging_dir}"
+ ) 1>&2 || exit 1
+ fi
+ echo "${bootstrapped}"
+}
+
+function find_links_url {
+ local pants_version="$1"
+ local pants_sha="$2"
+ echo -n "https://binaries.pantsbuild.org/wheels/pantsbuild.pants/${pants_sha}/${pants_version/+/%2B}/index.html"
+}
+
+function get_version_for_sha {
+ local sha="$1"
+
+ # Retrieve the Pants version associated with this commit.
+ local pants_version
+ pants_version="$(curl --fail -sL "https://raw.githubusercontent.com/pantsbuild/pants/${sha}/src/python/pants/VERSION")"
+
+ # Construct the version as the release version from src/python/pants/VERSION, plus the string `+gitXXXXXXXX`,
+ # where the XXXXXXXX is the first 8 characters of the SHA.
+ echo "${pants_version}+git${sha:0:8}"
+}
+
+function bootstrap_pants {
+ local pants_version="$1"
+ local python="$2"
+ local pants_sha="${3:-}"
+
+ local pants_requirement="pantsbuild.pants==${pants_version}"
+ local maybe_find_links
+ if [[ -z "${pants_sha}" ]]; then
+ maybe_find_links=""
+ else
+ maybe_find_links="--find-links=$(find_links_url "${pants_version}" "${pants_sha}")"
+ fi
+ local python_major_minor_version
+ python_major_minor_version="$(get_python_major_minor_version "${python}")"
+ local target_folder_name="${pants_version}_py${python_major_minor_version}"
+ local bootstrapped="${PANTS_BOOTSTRAP}/${target_folder_name}"
+
+ if [[ ! -d "${bootstrapped}" ]]; then
+ (
+ green "Bootstrapping Pants using ${python}"
+ local staging_dir
+ staging_dir=$(tempdir "${PANTS_BOOTSTRAP}")
+ local virtualenv_path
+ virtualenv_path="$(bootstrap_virtualenv "${python}")" || exit 1
+ green "Installing ${pants_requirement} into a virtual environment at ${bootstrapped}"
+ (
+ scrub_PEX_env_vars
+ # shellcheck disable=SC2086
+ "${python}" "${virtualenv_path}" --no-download "${staging_dir}/install" && \
+ "${staging_dir}/install/bin/pip" install -U pip && \
+ "${staging_dir}/install/bin/pip" install ${maybe_find_links} --progress-bar off "${pants_requirement}"
+ ) && \
+ ln -s "${staging_dir}/install" "${staging_dir}/${target_folder_name}" && \
+ mv "${staging_dir}/${target_folder_name}" "${bootstrapped}" && \
+ green "New virtual environment successfully created at ${bootstrapped}."
+ ) 1>&2 || exit 1
+ fi
+ echo "${bootstrapped}"
+}
+
+# Ensure we operate from the context of the ./pants buildroot.
+cd "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
+pants_version="$(determine_pants_version)"
+python="$(determine_python_exe "${pants_version}")"
+pants_dir="$(bootstrap_pants "${pants_version}" "${python}" "${PANTS_SHA:-}")" || exit 1
+
+pants_python="${pants_dir}/bin/python"
+pants_binary="${pants_dir}/bin/pants"
+pants_extra_args=""
+if [[ -n "${PANTS_SHA:-}" ]]; then
+ pants_extra_args="${pants_extra_args} --python-repos-repos=$(find_links_url "$pants_version" "$PANTS_SHA")"
+fi
+
+# shellcheck disable=SC2086
+exec "${pants_python}" "${pants_binary}" ${pants_extra_args} \
+ --pants-bin-name="${PANTS_BIN_NAME}" --pants-version=${pants_version} "$@"
diff --git a/pants.toml b/pants.toml
new file mode 100644
index 0000000..ca4fd82
--- /dev/null
+++ b/pants.toml
@@ -0,0 +1,9 @@
+[GLOBAL]
+pants_version = "2.7.1"
+backend_packages = ["pants.backend.python"]
+
+[anonymous-telemetry]
+enabled = false
+
+[source]
+marker_filenames = [".SOURCE_ROOT"]