diff --git a/library/.coveragerc b/.coveragerc similarity index 100% rename from library/.coveragerc rename to .coveragerc diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..07620e3 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,41 @@ +name: Build + +on: + pull_request: + push: + branches: + - main + +jobs: + test: + name: Python ${{ matrix.python }} + runs-on: ubuntu-latest + strategy: + matrix: + python: ['3.9', '3.10', '3.11'] + + env: + RELEASE_FILE: ${{ github.event.repository.name }}-${{ github.event.release.tag_name || github.sha }}-py${{ matrix.python }} + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python }} + + - name: Install Dependencies + run: | + make dev-deps + + - name: Build Packages + run: | + make build + + - name: Upload Packages + uses: actions/upload-artifact@v4 + with: + name: ${{ env.RELEASE_FILE }} + path: dist/ diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml new file mode 100644 index 0000000..ac672a5 --- /dev/null +++ b/.github/workflows/qa.yml @@ -0,0 +1,39 @@ +name: QA + +on: + pull_request: + push: + branches: + - main + +jobs: + test: + name: linting & spelling + runs-on: ubuntu-latest + env: + TERM: xterm-256color + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Set up Python '3,11' + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install Dependencies + run: | + make dev-deps + + - name: Run Quality Assurance + run: | + make qa + + - name: Run Code Checks + run: | + make check + + - name: Run Bash Code Checks + run: | + make shellcheck diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3bb75bb..6f8cff7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,37 +1,41 @@ -name: Python Tests +name: Tests on: pull_request: push: branches: - - master + - main jobs: test: + name: Python ${{ matrix.python }} runs-on: ubuntu-latest strategy: matrix: - python: [2.7, 3.5, 3.7, 3.9] + python: ['3.9', '3.10', '3.11'] steps: - - uses: actions/checkout@v2 + - name: Checkout Code + uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} + - name: Install Dependencies run: | - python -m pip install --upgrade setuptools tox + make dev-deps + - name: Run Tests - working-directory: library run: | - tox -e py + make pytest + - name: Coverage + if: ${{ matrix.python == '3.9' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - working-directory: library run: | python -m pip install coveralls - coveralls --service github - if: ${{ matrix.python == '3.9' }} + coveralls --service=github diff --git a/library/CHANGELOG.txt b/CHANGELOG.md similarity index 86% rename from library/CHANGELOG.txt rename to CHANGELOG.md index 57ca0d0..78fec49 100644 --- a/library/CHANGELOG.txt +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +2.0.0 +----- + +* Repackage to hatch/pyproject.toml +* Drop Python 2.7 support +* Switch from smbu2 to smbus2 + 1.1.1 ----- diff --git a/Makefile b/Makefile index 40934ad..56cf0df 100644 --- a/Makefile +++ b/Makefile @@ -1,70 +1,66 @@ -LIBRARY_VERSION=$(shell grep version library/setup.cfg | awk -F" = " '{print $$2}') -LIBRARY_NAME=$(shell grep name library/setup.cfg | awk -F" = " '{print $$2}') +LIBRARY_NAME := $(shell hatch project metadata name 2> /dev/null) +LIBRARY_VERSION := $(shell hatch version 2> /dev/null) -.PHONY: usage install uninstall +.PHONY: usage install uninstall check pytest qa build-deps check tag wheel sdist clean dist testdeploy deploy usage: +ifdef LIBRARY_NAME @echo "Library: ${LIBRARY_NAME}" @echo "Version: ${LIBRARY_VERSION}\n" +else + @echo "WARNING: You should 'make dev-deps'\n" +endif @echo "Usage: make , where target is one of:\n" - @echo "install: install the library locally from source" - @echo "uninstall: uninstall the local library" - @echo "check: peform basic integrity checks on the codebase" - @echo "python-readme: generate library/README.md from README.md + library/CHANGELOG.txt" - @echo "python-wheels: build python .whl files for distribution" - @echo "python-sdist: build python source distribution" - @echo "python-clean: clean python build and dist directories" - @echo "python-dist: build all python distribution files" - @echo "python-testdeploy: build all and deploy to test PyPi" - @echo "tag: tag the repository with the current version" + @echo "install: install the library locally from source" + @echo "uninstall: uninstall the local library" + @echo "dev-deps: install Python dev dependencies" + @echo "check: perform basic integrity checks on the codebase" + @echo "qa: run linting and package QA" + @echo "pytest: run Python test fixtures" + @echo "clean: clean Python build and dist directories" + @echo "build: build Python distribution files" + @echo "testdeploy: build and upload to test PyPi" + @echo "deploy: build and upload to PyPi" + @echo "tag: tag the repository with the current version\n" + +version: + @hatch version install: - ./install.sh + ./install.sh --unstable uninstall: ./uninstall.sh -check: - @echo "Checking for trailing whitespace" - @! grep -IUrn --color "[[:blank:]]$$" --exclude-dir=packaging --exclude-dir=sphinx --exclude-dir=.tox --exclude-dir=.git --exclude=PKG-INFO - @echo "Checking for DOS line-endings" - @! grep -IlUrn --color " " --exclude-dir=sphinx --exclude-dir=.tox --exclude-dir=.git --exclude=Makefile - @echo "Checking library/CHANGELOG.txt" - @cat library/CHANGELOG.txt | grep ^${LIBRARY_VERSION} - @echo "Checking library/${LIBRARY_NAME}/__init__.py" - @cat library/${LIBRARY_NAME}/__init__.py | grep "^__version__ = '${LIBRARY_VERSION}'" - -tag: - git tag -a "v${LIBRARY_VERSION}" -m "Version ${LIBRARY_VERSION}" +dev-deps: + python3 -m pip install -r requirements-dev.txt + sudo apt install dos2unix shellcheck -python-readme: library/README.md +check: + @bash check.sh -python-license: library/LICENSE.txt +shellcheck: + shellcheck *.sh -library/README.md: README.md library/CHANGELOG.txt - cp README.md library/README.md - printf "\n# Changelog\n" >> library/README.md - cat library/CHANGELOG.txt >> library/README.md +qa: + tox -e qa -library/LICENSE.txt: LICENSE - cp LICENSE library/LICENSE.txt +pytest: + tox -e py -python-wheels: python-readme python-license - cd library; python3 setup.py bdist_wheel - cd library; python setup.py bdist_wheel +nopost: + @bash check.sh --nopost -python-sdist: python-readme python-license - cd library; python setup.py sdist +tag: version + git tag -a "v${LIBRARY_VERSION}" -m "Version ${LIBRARY_VERSION}" -python-clean: - -rm -r library/dist - -rm -r library/build - -rm -r library/*.egg-info +build: check + @hatch build -python-dist: python-clean python-wheels python-sdist - ls library/dist +clean: + -rm -r dist -python-testdeploy: python-dist - twine upload --repository-url https://test.pypi.org/legacy/ library/dist/* +testdeploy: build + twine upload --repository testpypi dist/* -python-deploy: check python-dist - twine upload library/dist/* +deploy: nopost build + twine upload dist/* diff --git a/README.md b/README.md index 50f2d4c..0c71b7f 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,19 @@ -# BME68x +# BME680 -[![Build Status](https://travis-ci.org/pimoroni/bme680-python.svg?branch=master)](https://travis-ci.org/pimoroni/bme680-python) -[![Coverage Status](https://coveralls.io/repos/github/pimoroni/bme680-python/badge.svg?branch=master)](https://coveralls.io/github/pimoroni/bme680-python?branch=master) +[![Build Status](https://img.shields.io/github/actions/workflow/status/pimoroni/bme680-python/test.yml?branch=main)](https://github.com/pimoroni/bme680-python/actions/workflows/test.yml) +[![Coverage Status](https://coveralls.io/repos/github/pimoroni/bme680-python/badge.svg?branch=main)](https://coveralls.io/github/pimoroni/bme680-python?branch=main) [![PyPi Package](https://img.shields.io/pypi/v/bme680.svg)](https://pypi.python.org/pypi/bme680) [![Python Versions](https://img.shields.io/pypi/pyversions/bme680.svg)](https://pypi.python.org/pypi/bme680) -BME68x is a series of state-of-the-art environmental sensors that let you measure temperature, pressure, humidity and indoor air quality. +https://shop.pimoroni.com/products/bme680 -This library is designed to work with the following products: - -* BME680 Breakout - https://shop.pimoroni.com/products/bme680 -* BME688 4-in-1 Air Quality Breakout - https://shop.pimoroni.com/products/bme688-breakout +The state-of-the-art BME680 breakout lets you measure temperature, pressure, humidity, and indoor air quality. ## Installing ### Full install (recommended): -We've created an easy installation script that will install all pre-requisites and get your BME68x +We've created an easy installation script that will install all pre-requisites and get your BME680 up and running with minimal efforts. To run it, fire up Terminal which you'll find in Menu -> Accessories -> Terminal on your Raspberry Pi desktop, as illustrated below: @@ -25,35 +22,35 @@ on your Raspberry Pi desktop, as illustrated below: In the new terminal window type the command exactly as it appears below (check for typos) and follow the on-screen instructions: ```bash -curl https://get.pimoroni.com/bme680 | bash +git clone https://github.com/pimoroni/bme680-python +cd bme680-python +./install.sh ``` -### Manual install: - -#### Library install for Python 3: +**Note** Libraries will be installed in the "pimoroni" virtual environment, you will need to activate it to run examples: -```bash -sudo pip3 install bme680 ``` - -#### Library install for Python 2: - -```bash -sudo pip2 install bme680 +source ~/.virtualenvs/pimoroni/bin/activate ``` ### Development: -If you want to contribute, or like living on the edge of your seat by having the latest code, you should clone this repository, `cd` to the library directory, and run: +If you want to contribute, or like living on the edge of your seat by having the latest code, you can install the development version like so: ```bash -sudo python3 setup.py install +git clone https://github.com/pimoroni/bme680-python +cd bme680-python +./install.sh --unstable ``` -(or `sudo python setup.py install` whichever your primary Python environment may be) -In all cases you will have to have I2C enabled (`sudo raspi-config`, under 'Interfacing Options'). +In all cases you will have to enable the i2c bus: + +``` +sudo raspi-config nonint do_i2c 0 +``` ## Documentation & Support * Guides and tutorials - https://learn.pimoroni.com/bme680-breakout * Get help - http://forums.pimoroni.com/c/support + diff --git a/library/bme680/__init__.py b/bme680/__init__.py similarity index 99% rename from library/bme680/__init__.py rename to bme680/__init__.py index cb2fa6f..56d547a 100644 --- a/library/bme680/__init__.py +++ b/bme680/__init__.py @@ -1,11 +1,11 @@ """BME680 Temperature, Pressure, Humidity & Gas Sensor.""" -from .constants import lookupTable1, lookupTable2 -from .constants import BME680Data -from . import constants import math import time -__version__ = '1.1.1' +from . import constants +from .constants import BME680Data, lookupTable1, lookupTable2 + +__version__ = '2.0.0' # Export constants to global namespace @@ -39,8 +39,8 @@ def __init__(self, i2c_addr=constants.I2C_ADDR_PRIMARY, i2c_device=None): self.i2c_addr = i2c_addr self._i2c = i2c_device if self._i2c is None: - import smbus - self._i2c = smbus.SMBus(1) + import smbus2 + self._i2c = smbus2.SMBus(1) try: self.chip_id = self._get_regs(constants.CHIP_ID_ADDR, 1) diff --git a/library/bme680/constants.py b/bme680/constants.py similarity index 98% rename from library/bme680/constants.py rename to bme680/constants.py index 78b4b30..d77415d 100644 --- a/library/bme680/constants.py +++ b/bme680/constants.py @@ -239,7 +239,7 @@ def bytes_to_word(msb, lsb, bits=16, signed=False): """Convert a most and least significant byte into a word.""" - # TODO: Reimpliment with struct + # TODO: Reimplement with struct word = (msb << 8) | lsb if signed: word = twos_comp(word, bits) @@ -248,7 +248,7 @@ def bytes_to_word(msb, lsb, bits=16, signed=False): def twos_comp(val, bits=16): """Convert two bytes into a two's compliment signed word.""" - # TODO: Reimpliment with struct + # TODO: Reimplement with struct if val & (1 << (bits - 1)) != 0: val = val - (1 << bits) return val @@ -312,7 +312,7 @@ def __init__(self): # noqa D107 self.range_sw_err = None def set_from_array(self, calibration): - """Set paramaters from an array of bytes.""" + """Set parameters from an array of bytes.""" # Temperature related coefficients self.par_t1 = bytes_to_word(calibration[T1_MSB_REG], calibration[T1_LSB_REG]) self.par_t2 = bytes_to_word(calibration[T2_MSB_REG], calibration[T2_LSB_REG], bits=16, signed=True) diff --git a/check.sh b/check.sh new file mode 100755 index 0000000..38dfc3a --- /dev/null +++ b/check.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +# This script handles some basic QA checks on the source + +NOPOST=$1 +LIBRARY_NAME=$(hatch project metadata name) +LIBRARY_VERSION=$(hatch version | awk -F "." '{print $1"."$2"."$3}') +POST_VERSION=$(hatch version | awk -F "." '{print substr($4,0,length($4))}') +TERM=${TERM:="xterm-256color"} + +success() { + echo -e "$(tput setaf 2)$1$(tput sgr0)" +} + +inform() { + echo -e "$(tput setaf 6)$1$(tput sgr0)" +} + +warning() { + echo -e "$(tput setaf 1)$1$(tput sgr0)" +} + +while [[ $# -gt 0 ]]; do + K="$1" + case $K in + -p|--nopost) + NOPOST=true + shift + ;; + *) + if [[ $1 == -* ]]; then + printf "Unrecognised option: %s\n" "$1"; + exit 1 + fi + POSITIONAL_ARGS+=("$1") + shift + esac +done + +inform "Checking $LIBRARY_NAME $LIBRARY_VERSION\n" + +inform "Checking for trailing whitespace..." +if grep -IUrn --color "[[:blank:]]$" --exclude-dir=dist --exclude-dir=.tox --exclude-dir=.git --exclude=PKG-INFO; then + warning "Trailing whitespace found!" + exit 1 +else + success "No trailing whitespace found." +fi +printf "\n" + +inform "Checking for DOS line-endings..." +if grep -lIUrn --color $'\r' --exclude-dir=dist --exclude-dir=.tox --exclude-dir=.git --exclude=Makefile; then + warning "DOS line-endings found!" + exit 1 +else + success "No DOS line-endings found." +fi +printf "\n" + +inform "Checking CHANGELOG.md..." +if ! grep "^${LIBRARY_VERSION}" CHANGELOG.md > /dev/null 2>&1; then + warning "Changes missing for version ${LIBRARY_VERSION}! Please update CHANGELOG.md." + exit 1 +else + success "Changes found for version ${LIBRARY_VERSION}." +fi +printf "\n" + +inform "Checking for git tag ${LIBRARY_VERSION}..." +if ! git tag -l | grep -E "${LIBRARY_VERSION}$"; then + warning "Missing git tag for version ${LIBRARY_VERSION}" +fi +printf "\n" + +if [[ $NOPOST ]]; then + inform "Checking for .postN on library version..." + if [[ "$POST_VERSION" != "" ]]; then + warning "Found .$POST_VERSION on library version." + inform "Please only use these for testpypi releases." + exit 1 + else + success "OK" + fi +fi diff --git a/examples/compensated-temperature.py b/examples/compensated-temperature.py index 45a4564..275f7ff 100755 --- a/examples/compensated-temperature.py +++ b/examples/compensated-temperature.py @@ -1,9 +1,9 @@ #!/usr/bin/env python import time -import bme680 from subprocess import PIPE, Popen +import bme680 print("""compensated-temperature.py - Use the CPU temperature to compensate temperature readings from the BME680 sensor. Method adapted from Initial State's Enviro pHAT diff --git a/examples/indoor-air-quality.py b/examples/indoor-air-quality.py index 6f12446..64e47e3 100755 --- a/examples/indoor-air-quality.py +++ b/examples/indoor-air-quality.py @@ -1,8 +1,9 @@ #!/usr/bin/env python -import bme680 import time +import bme680 + print("""indoor-air-quality.py - Estimates indoor air quality. Runs the sensor for a burn-in period, then uses a diff --git a/examples/read-all.py b/examples/read-all.py index 7b299df..00c2d40 100755 --- a/examples/read-all.py +++ b/examples/read-all.py @@ -1,8 +1,9 @@ #!/usr/bin/env python -import bme680 import time +import bme680 + print("""read-all.py - Displays temperature, pressure, humidity, and gas. Press Ctrl+C to exit! diff --git a/install-bullseye.sh b/install-bullseye.sh deleted file mode 100755 index 76743a9..0000000 --- a/install-bullseye.sh +++ /dev/null @@ -1,254 +0,0 @@ -#!/bin/bash -CONFIG=/boot/config.txt -DATESTAMP=`date "+%Y-%m-%d-%H-%M-%S"` -CONFIG_BACKUP=false -APT_HAS_UPDATED=false -USER_HOME=/home/$SUDO_USER -RESOURCES_TOP_DIR=$USER_HOME/Pimoroni -WD=`pwd` -USAGE="sudo ./install.sh (--unstable)" -POSITIONAL_ARGS=() -UNSTABLE=false -PYTHON="/usr/bin/python3" -CODENAME=`lsb_release -sc` - -distro_check() { - if [[ $CODENAME != "bullseye" ]]; then - printf "This installer is for Raspberry Pi OS: Bullseye only, current distro: $CODENAME\n" - exit 1 - fi -} - -user_check() { - if [ $(id -u) -ne 0 ]; then - printf "Script must be run as root. Try 'sudo ./install.sh'\n" - exit 1 - fi -} - -confirm() { - if [ "$FORCE" == '-y' ]; then - true - else - read -r -p "$1 [y/N] " response < /dev/tty - if [[ $response =~ ^(yes|y|Y)$ ]]; then - true - else - false - fi - fi -} - -prompt() { - read -r -p "$1 [y/N] " response < /dev/tty - if [[ $response =~ ^(yes|y|Y)$ ]]; then - true - else - false - fi -} - -success() { - echo -e "$(tput setaf 2)$1$(tput sgr0)" -} - -inform() { - echo -e "$(tput setaf 6)$1$(tput sgr0)" -} - -warning() { - echo -e "$(tput setaf 1)$1$(tput sgr0)" -} - -function do_config_backup { - if [ ! $CONFIG_BACKUP == true ]; then - CONFIG_BACKUP=true - FILENAME="config.preinstall-$LIBRARY_NAME-$DATESTAMP.txt" - inform "Backing up $CONFIG to /boot/$FILENAME\n" - cp $CONFIG /boot/$FILENAME - mkdir -p $RESOURCES_TOP_DIR/config-backups/ - cp $CONFIG $RESOURCES_TOP_DIR/config-backups/$FILENAME - if [ -f "$UNINSTALLER" ]; then - echo "cp $RESOURCES_TOP_DIR/config-backups/$FILENAME $CONFIG" >> $UNINSTALLER - fi - fi -} - -function apt_pkg_install { - PACKAGES=() - PACKAGES_IN=("$@") - for ((i = 0; i < ${#PACKAGES_IN[@]}; i++)); do - PACKAGE="${PACKAGES_IN[$i]}" - if [ "$PACKAGE" == "" ]; then continue; fi - printf "Checking for $PACKAGE\n" - dpkg -L $PACKAGE > /dev/null 2>&1 - if [ "$?" == "1" ]; then - PACKAGES+=("$PACKAGE") - fi - done - PACKAGES="${PACKAGES[@]}" - if ! [ "$PACKAGES" == "" ]; then - echo "Installing missing packages: $PACKAGES" - if [ ! $APT_HAS_UPDATED ]; then - apt update - APT_HAS_UPDATED=true - fi - apt install -y $PACKAGES - if [ -f "$UNINSTALLER" ]; then - echo "apt uninstall -y $PACKAGES" - fi - fi -} - -while [[ $# -gt 0 ]]; do - K="$1" - case $K in - -u|--unstable) - UNSTABLE=true - shift - ;; - -p|--python) - PYTHON=$2 - shift - shift - ;; - *) - if [[ $1 == -* ]]; then - printf "Unrecognised option: $1\n"; - printf "Usage: $USAGE\n"; - exit 1 - fi - POSITIONAL_ARGS+=("$1") - shift - esac -done - -distro_check -user_check - -if [ ! -f "$PYTHON" ]; then - printf "Python path $PYTHON not found!\n" - exit 1 -fi - -PYTHON_VER=`$PYTHON --version` - -inform "Installing. Please wait..." - -$PYTHON -m pip install --upgrade configparser - -CONFIG_VARS=`$PYTHON - < $UNINSTALLER -printf "It's recommended you run these steps manually.\n" -printf "If you want to run the full script, open it in\n" -printf "an editor and remove 'exit 1' from below.\n" -exit 1 -EOF - -printf "$LIBRARY_NAME $LIBRARY_VERSION Python Library: Installer\n\n" - -if $UNSTABLE; then - warning "Installing unstable library from source.\n\n" -else - printf "Installing stable library from pypi.\n\n" -fi - -cd library - -printf "Installing for $PYTHON_VER...\n" -apt_pkg_install "${PY3_DEPS[@]}" -if $UNSTABLE; then - $PYTHON setup.py install > /dev/null -else - $PYTHON -m pip install --upgrade $LIBRARY_NAME -fi -if [ $? -eq 0 ]; then - success "Done!\n" - echo "$PYTHON -m pip uninstall $LIBRARY_NAME" >> $UNINSTALLER -fi - -cd $WD - -for ((i = 0; i < ${#SETUP_CMDS[@]}; i++)); do - CMD="${SETUP_CMDS[$i]}" - # Attempt to catch anything that touches /boot/config.txt and trigger a backup - if [[ "$CMD" == *"raspi-config"* ]] || [[ "$CMD" == *"$CONFIG"* ]] || [[ "$CMD" == *"\$CONFIG"* ]]; then - do_config_backup - fi - eval $CMD -done - -for ((i = 0; i < ${#CONFIG_TXT[@]}; i++)); do - CONFIG_LINE="${CONFIG_TXT[$i]}" - if ! [ "$CONFIG_LINE" == "" ]; then - do_config_backup - inform "Adding $CONFIG_LINE to $CONFIG\n" - sed -i "s/^#$CONFIG_LINE/$CONFIG_LINE/" $CONFIG - if ! grep -q "^$CONFIG_LINE" $CONFIG; then - printf "$CONFIG_LINE\n" >> $CONFIG - fi - fi -done - -if [ -d "examples" ]; then - if confirm "Would you like to copy examples to $RESOURCES_DIR?"; then - inform "Copying examples to $RESOURCES_DIR" - cp -r examples/ $RESOURCES_DIR - echo "rm -r $RESOURCES_DIR" >> $UNINSTALLER - success "Done!" - fi -fi - -printf "\n" - -if [ -f "/usr/bin/pydoc" ]; then - printf "Generating documentation.\n" - pydoc -w $LIBRARY_NAME > /dev/null - if [ -f "$LIBRARY_NAME.html" ]; then - cp $LIBRARY_NAME.html $RESOURCES_DIR/docs.html - rm -f $LIBRARY_NAME.html - inform "Documentation saved to $RESOURCES_DIR/docs.html" - success "Done!" - else - warning "Error: Failed to generate documentation." - fi -fi - -success "\nAll done!" -inform "If this is your first time installing you should reboot for hardware changes to take effect.\n" -inform "Find uninstall steps in $UNINSTALLER\n" diff --git a/install.sh b/install.sh index 0c73d6a..3db90bc 100755 --- a/install.sh +++ b/install.sh @@ -1,31 +1,29 @@ #!/bin/bash - -CONFIG=/boot/config.txt -DATESTAMP=`date "+%Y-%m-%d-%H-%M-%S"` +LIBRARY_NAME=$(grep -m 1 name pyproject.toml | awk -F" = " '{print substr($2,2,length($2)-2)}') +CONFIG_FILE=config.txt +CONFIG_DIR="/boot/firmware" +DATESTAMP=$(date "+%Y-%m-%d-%H-%M-%S") CONFIG_BACKUP=false APT_HAS_UPDATED=false -USER_HOME=/home/$SUDO_USER -RESOURCES_TOP_DIR=$USER_HOME/Pimoroni -WD=`pwd` -USAGE="sudo ./install.sh (--unstable)" +RESOURCES_TOP_DIR="$HOME/Pimoroni" +VENV_BASH_SNIPPET="$RESOURCES_TOP_DIR/auto_venv.sh" +VENV_DIR="$HOME/.virtualenvs/pimoroni" +USAGE="./install.sh (--unstable)" POSITIONAL_ARGS=() +FORCE=false UNSTABLE=false -CODENAME=`lsb_release -sc` +PYTHON="python" +CMD_ERRORS=false -if [[ $CODENAME == "bullseye" ]]; then - bash ./install-bullseye.sh - exit $? -fi user_check() { - if [ $(id -u) -ne 0 ]; then - printf "Script must be run as root. Try 'sudo ./install.sh'\n" - exit 1 + if [ "$(id -u)" -eq 0 ]; then + fatal "Script should not be run as root. Try './install.sh'\n" fi } confirm() { - if [ "$FORCE" == '-y' ]; then + if $FORCE; then true else read -r -p "$1 [y/N] " response < /dev/tty @@ -37,15 +35,6 @@ confirm() { fi } -prompt() { - read -r -p "$1 [y/N] " response < /dev/tty - if [[ $response =~ ^(yes|y|Y)$ ]]; then - true - else - false - fi -} - success() { echo -e "$(tput setaf 2)$1$(tput sgr0)" } @@ -55,49 +44,128 @@ inform() { } warning() { - echo -e "$(tput setaf 1)$1$(tput sgr0)" + echo -e "$(tput setaf 1)⚠ WARNING:$(tput sgr0) $1" +} + +fatal() { + echo -e "$(tput setaf 1)⚠ FATAL:$(tput sgr0) $1" + exit 1 +} + +find_config() { + if [ ! -f "$CONFIG_DIR/$CONFIG_FILE" ]; then + CONFIG_DIR="/boot" + if [ ! -f "$CONFIG_DIR/$CONFIG_FILE" ]; then + fatal "Could not find $CONFIG_FILE!" + fi + fi + inform "Using $CONFIG_FILE in $CONFIG_DIR" +} + +venv_bash_snippet() { + inform "Checking for $VENV_BASH_SNIPPET\n" + if [ ! -f "$VENV_BASH_SNIPPET" ]; then + inform "Creating $VENV_BASH_SNIPPET\n" + mkdir -p "$RESOURCES_TOP_DIR" + cat << EOF > "$VENV_BASH_SNIPPET" +# Add "source $VENV_BASH_SNIPPET" to your ~/.bashrc to activate +# the Pimoroni virtual environment automagically! +VENV_DIR="$VENV_DIR" +if [ ! -f \$VENV_DIR/bin/activate ]; then + printf "Creating user Python environment in \$VENV_DIR, please wait...\n" + mkdir -p \$VENV_DIR + python3 -m venv --system-site-packages \$VENV_DIR +fi +printf " ↓ ↓ ↓ ↓ Hello, we've activated a Python venv for you. To exit, type \"deactivate\".\n" +source \$VENV_DIR/bin/activate +EOF + fi +} + +venv_check() { + PYTHON_BIN=$(which "$PYTHON") + if [[ $VIRTUAL_ENV == "" ]] || [[ $PYTHON_BIN != $VIRTUAL_ENV* ]]; then + printf "This script should be run in a virtual Python environment.\n" + if confirm "Would you like us to create and/or use a default one?"; then + printf "\n" + if [ ! -f "$VENV_DIR/bin/activate" ]; then + inform "Creating a new virtual Python environment in $VENV_DIR, please wait...\n" + mkdir -p "$VENV_DIR" + /usr/bin/python3 -m venv "$VENV_DIR" --system-site-packages + venv_bash_snippet + # shellcheck disable=SC1091 + source "$VENV_DIR/bin/activate" + else + inform "Activating existing virtual Python environment in $VENV_DIR\n" + printf "source \"%s/bin/activate\"\n" "$VENV_DIR" + # shellcheck disable=SC1091 + source "$VENV_DIR/bin/activate" + fi + else + printf "\n" + fatal "Please create and/or activate a virtual Python environment and try again!\n" + fi + fi + printf "\n" +} + +check_for_error() { + if [ $? -ne 0 ]; then + CMD_ERRORS=true + warning "^^^ 😬 previous command did not exit cleanly!" + fi } function do_config_backup { if [ ! $CONFIG_BACKUP == true ]; then CONFIG_BACKUP=true FILENAME="config.preinstall-$LIBRARY_NAME-$DATESTAMP.txt" - inform "Backing up $CONFIG to /boot/$FILENAME\n" - cp $CONFIG /boot/$FILENAME - mkdir -p $RESOURCES_TOP_DIR/config-backups/ - cp $CONFIG $RESOURCES_TOP_DIR/config-backups/$FILENAME + inform "Backing up $CONFIG_DIR/$CONFIG_FILE to $CONFIG_DIR/$FILENAME\n" + sudo cp "$CONFIG_DIR/$CONFIG_FILE" "$CONFIG_DIR/$FILENAME" + mkdir -p "$RESOURCES_TOP_DIR/config-backups/" + cp $CONFIG_DIR/$CONFIG_FILE "$RESOURCES_TOP_DIR/config-backups/$FILENAME" if [ -f "$UNINSTALLER" ]; then - echo "cp $RESOURCES_TOP_DIR/config-backups/$FILENAME $CONFIG" >> $UNINSTALLER + echo "cp $RESOURCES_TOP_DIR/config-backups/$FILENAME $CONFIG_DIR/$CONFIG_FILE" >> "$UNINSTALLER" fi fi } function apt_pkg_install { - PACKAGES=() + PACKAGES_NEEDED=() PACKAGES_IN=("$@") + # Check the list of packages and only run update/install if we need to for ((i = 0; i < ${#PACKAGES_IN[@]}; i++)); do PACKAGE="${PACKAGES_IN[$i]}" if [ "$PACKAGE" == "" ]; then continue; fi - printf "Checking for $PACKAGE\n" - dpkg -L $PACKAGE > /dev/null 2>&1 + printf "Checking for %s\n" "$PACKAGE" + dpkg -L "$PACKAGE" > /dev/null 2>&1 if [ "$?" == "1" ]; then - PACKAGES+=("$PACKAGE") + PACKAGES_NEEDED+=("$PACKAGE") fi done - PACKAGES="${PACKAGES[@]}" + PACKAGES="${PACKAGES_NEEDED[*]}" if ! [ "$PACKAGES" == "" ]; then - echo "Installing missing packages: $PACKAGES" + printf "\n" + inform "Installing missing packages: $PACKAGES" if [ ! $APT_HAS_UPDATED ]; then - apt update + sudo apt update APT_HAS_UPDATED=true fi - apt install -y $PACKAGES + # shellcheck disable=SC2086 + sudo apt install -y $PACKAGES + check_for_error if [ -f "$UNINSTALLER" ]; then - echo "apt uninstall -y $PACKAGES" + echo "apt uninstall -y $PACKAGES" >> "$UNINSTALLER" fi fi } +function pip_pkg_install { + # A null Keyring prevents pip stalling in the background + PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring $PYTHON -m pip install --upgrade "$@" + check_for_error +} + while [[ $# -gt 0 ]]; do K="$1" case $K in @@ -105,10 +173,19 @@ while [[ $# -gt 0 ]]; do UNSTABLE=true shift ;; + -f|--force) + FORCE=true + shift + ;; + -p|--python) + PYTHON=$2 + shift + shift + ;; *) if [[ $1 == -* ]]; then - printf "Unrecognised option: $1\n"; - printf "Usage: $USAGE\n"; + printf "Unrecognised option: %s\n" "$1"; + printf "Usage: %s\n" "$USAGE"; exit 1 fi POSITIONAL_ARGS+=("$1") @@ -116,136 +193,178 @@ while [[ $# -gt 0 ]]; do esac done +printf "Installing %s...\n\n" "$LIBRARY_NAME" + user_check +venv_check -apt_pkg_install python-configparser - -CONFIG_VARS=`python - < $UNINSTALLER +# Previous install.sh scripts were run as root with sudo, which caused +# the ~/Pimoroni dir to be created with root ownership. Try and fix it. +if [[ "$RES_DIR_OWNER" == "root" ]]; then + warning "\n\nFixing $RESOURCES_TOP_DIR permissions!\n\n" + sudo chown -R "$USER:$USER" "$RESOURCES_TOP_DIR" +fi + +mkdir -p "$RESOURCES_DIR" + +# Create a stub uninstaller file, we'll try to add the inverse of every +# install command run to here, though it's not complete. +cat << EOF > "$UNINSTALLER" printf "It's recommended you run these steps manually.\n" printf "If you want to run the full script, open it in\n" printf "an editor and remove 'exit 1' from below.\n" exit 1 +source $VIRTUAL_ENV/bin/activate EOF -printf "$LIBRARY_NAME $LIBRARY_VERSION Python Library: Installer\n\n" +printf "\n" -if $UNSTABLE; then - warning "Installing unstable library from source.\n\n" -else - printf "Installing stable library from pypi.\n\n" -fi +inform "Installing for $PYTHON_VER...\n" -cd library +# Install apt packages from pyproject.toml / tool.pimoroni.apt_packages +apt_pkg_install "${APT_PACKAGES[@]}" + +printf "\n" -printf "Installing for Python 2..\n" -apt_pkg_install "${PY2_DEPS[@]}" if $UNSTABLE; then - python setup.py install > /dev/null + warning "Installing unstable library from source.\n" + pip_pkg_install . else - pip install --upgrade $LIBRARY_NAME + inform "Installing stable library from pypi.\n" + pip_pkg_install "$LIBRARY_NAME" fi + +# shellcheck disable=SC2181 # One of two commands run, depending on --unstable flag if [ $? -eq 0 ]; then success "Done!\n" - echo "pip uninstall $LIBRARY_NAME" >> $UNINSTALLER + echo "$PYTHON -m pip uninstall $LIBRARY_NAME" >> "$UNINSTALLER" fi -if [ -f "/usr/bin/python3" ]; then - printf "Installing for Python 3..\n" - apt_pkg_install "${PY3_DEPS[@]}" - if $UNSTABLE; then - python3 setup.py install > /dev/null - else - pip3 install --upgrade $LIBRARY_NAME - fi - if [ $? -eq 0 ]; then - success "Done!\n" - echo "pip3 uninstall $LIBRARY_NAME" >> $UNINSTALLER - fi -fi +find_config -cd $WD +printf "\n" + +# Run the setup commands from pyproject.toml / tool.pimoroni.commands +inform "Running setup commands...\n" for ((i = 0; i < ${#SETUP_CMDS[@]}; i++)); do CMD="${SETUP_CMDS[$i]}" - # Attempt to catch anything that touches /boot/config.txt and trigger a backup - if [[ "$CMD" == *"raspi-config"* ]] || [[ "$CMD" == *"$CONFIG"* ]] || [[ "$CMD" == *"\$CONFIG"* ]]; then + # Attempt to catch anything that touches config.txt and trigger a backup + if [[ "$CMD" == *"raspi-config"* ]] || [[ "$CMD" == *"$CONFIG_DIR/$CONFIG_FILE"* ]] || [[ "$CMD" == *"\$CONFIG_DIR/\$CONFIG_FILE"* ]]; then do_config_backup fi - eval $CMD + if [[ ! "$CMD" == printf* ]]; then + printf "Running: \"%s\"\n" "$CMD" + fi + eval "$CMD" + check_for_error done +printf "\n" + +# Add the config.txt entries from pyproject.toml / tool.pimoroni.configtxt + for ((i = 0; i < ${#CONFIG_TXT[@]}; i++)); do CONFIG_LINE="${CONFIG_TXT[$i]}" if ! [ "$CONFIG_LINE" == "" ]; then do_config_backup - inform "Adding $CONFIG_LINE to $CONFIG\n" - sed -i "s/^#$CONFIG_LINE/$CONFIG_LINE/" $CONFIG - if ! grep -q "^$CONFIG_LINE" $CONFIG; then - printf "$CONFIG_LINE\n" >> $CONFIG + inform "Adding $CONFIG_LINE to $CONFIG_DIR/$CONFIG_FILE" + sudo sed -i "s/^#$CONFIG_LINE/$CONFIG_LINE/" $CONFIG_DIR/$CONFIG_FILE + if ! grep -q "^$CONFIG_LINE" $CONFIG_DIR/$CONFIG_FILE; then + printf "%s \n" "$CONFIG_LINE" | sudo tee --append $CONFIG_DIR/$CONFIG_FILE fi fi done +printf "\n" + +# Just a straight copy of the examples/ dir into ~/Pimoroni/board/examples + if [ -d "examples" ]; then if confirm "Would you like to copy examples to $RESOURCES_DIR?"; then inform "Copying examples to $RESOURCES_DIR" - cp -r examples/ $RESOURCES_DIR - echo "rm -r $RESOURCES_DIR" >> $UNINSTALLER + cp -r examples/ "$RESOURCES_DIR" + echo "rm -r $RESOURCES_DIR" >> "$UNINSTALLER" success "Done!" fi fi printf "\n" -if [ -f "/usr/bin/pydoc" ]; then - printf "Generating documentation.\n" - pydoc -w $LIBRARY_NAME > /dev/null - if [ -f "$LIBRARY_NAME.html" ]; then - cp $LIBRARY_NAME.html $RESOURCES_DIR/docs.html - rm -f $LIBRARY_NAME.html - inform "Documentation saved to $RESOURCES_DIR/docs.html" +# Use pdoc to generate basic documentation from the installed module + +if confirm "Would you like to generate documentation?"; then + inform "Installing pdoc. Please wait..." + pip_pkg_install pdoc + inform "Generating documentation.\n" + if $PYTHON -m pdoc "$LIBRARY_NAME" -o "$RESOURCES_DIR/docs" > /dev/null; then + inform "Documentation saved to $RESOURCES_DIR/docs" success "Done!" else warning "Error: Failed to generate documentation." fi fi -success "\nAll done!" -inform "If this is your first time installing you should reboot for hardware changes to take effect.\n" -inform "Find uninstall steps in $UNINSTALLER\n" +printf "\n" + +if [ "$CMD_ERRORS" = true ]; then + warning "One or more setup commands appear to have failed." + printf "This might prevent things from working properly.\n" + printf "Make sure your OS is up to date and try re-running this installer.\n" + printf "If things still don't work, report this or find help at %s.\n\n" "$GITHUB_URL" +else + success "\nAll done!" +fi + +printf "If this is your first time installing you should reboot for hardware changes to take effect.\n" +printf "Find uninstall steps in %s\n\n" "$UNINSTALLER" + +if [ "$CMD_ERRORS" = true ]; then + exit 1 +else + exit 0 +fi diff --git a/library/LICENSE.txt b/library/LICENSE.txt deleted file mode 100644 index b3e25b2..0000000 --- a/library/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018 Pimoroni Ltd - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/library/MANIFEST.in b/library/MANIFEST.in deleted file mode 100644 index c8f01ed..0000000 --- a/library/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include CHANGELOG.txt -include LICENSE.txt -include README.md -include setup.py -recursive-include bme680 *.py diff --git a/library/README.md b/library/README.md deleted file mode 100644 index 899cb3e..0000000 --- a/library/README.md +++ /dev/null @@ -1,101 +0,0 @@ -# BME680 - -[![Build Status](https://travis-ci.org/pimoroni/bme680-python.svg?branch=master)](https://travis-ci.org/pimoroni/bme680-python) -[![Coverage Status](https://coveralls.io/repos/github/pimoroni/bme680-python/badge.svg?branch=master)](https://coveralls.io/github/pimoroni/bme680-python?branch=master) -[![PyPi Package](https://img.shields.io/pypi/v/bme680.svg)](https://pypi.python.org/pypi/bme680) -[![Python Versions](https://img.shields.io/pypi/pyversions/bme680.svg)](https://pypi.python.org/pypi/bme680) - -https://shop.pimoroni.com/products/bme680 - -The state-of-the-art BME680 breakout lets you measure temperature, pressure, humidity, and indoor air quality. - -## Installing - -### Full install (recommended): - -We've created an easy installation script that will install all pre-requisites and get your BME680 -up and running with minimal efforts. To run it, fire up Terminal which you'll find in Menu -> Accessories -> Terminal -on your Raspberry Pi desktop, as illustrated below: - -![Finding the terminal](http://get.pimoroni.com/resources/github-repo-terminal.png) - -In the new terminal window type the command exactly as it appears below (check for typos) and follow the on-screen instructions: - -```bash -curl https://get.pimoroni.com/bme680 | bash -``` - -### Manual install: - -#### Library install for Python 3: - -```bash -sudo pip3 install bme680 -``` - -#### Library install for Python 2: - -```bash -sudo pip2 install bme680 -``` - -### Development: - -If you want to contribute, or like living on the edge of your seat by having the latest code, you should clone this repository, `cd` to the library directory, and run: - -```bash -sudo python3 setup.py install -``` -(or `sudo python setup.py install` whichever your primary Python environment may be) - -In all cases you will have to enable the i2c bus. - -## Documentation & Support - -* Guides and tutorials - https://learn.pimoroni.com/bme680-breakout -* Get help - http://forums.pimoroni.com/c/support - -# Changelog -1.1.1 ------ - -* New: constants to clarify heater on/off states - -1.1.0 ------ - -* New: support for BME688 "high" gas resistance variant -* New: set/get gas heater disable bit -* Enhancement: fail with descriptive RuntimeError when chip is not detected - -1.0.5 ------ - -* New: set_temp_offset to calibrate temperature offset in degrees C - -1.0.4 ------ - -* Fix to range_sw_err for extremely high gas readings -* Convert to unsigned int to fix negative gas readings - -1.0.3 ------ - -* Merged temperature compensation fix from Bosch's BME680_driver 3.5.3 - -1.0.2 ------ - -* Fixed set_gas_heater_temperature to avoid i2c TypeError - -1.0.1 ------ - -* Added Manifest to Python package - -1.0.0 ------ - -* Initial release - diff --git a/library/setup.cfg b/library/setup.cfg deleted file mode 100644 index a2efae0..0000000 --- a/library/setup.cfg +++ /dev/null @@ -1,53 +0,0 @@ -# -*- coding: utf-8 -*- -[metadata] -name = bme680 -version = 1.1.1 -author = Philip Howard -author_email = phil@pimoroni.com -description = Python library for the BME680 temperature, humidity and gas sensor -long_description = file: README.md -long_description_content_type = text/markdown -keywords = Raspberry Pi -url = https://www.pimoroni.com -project_urls = - GitHub=https://www.github.com/pimoroni/bme680-python -license = MIT -# This includes the license file(s) in the wheel. -# https://wheel.readthedocs.io/en/stable/user_guide.html#including-license-files-in-the-generated-wheel-file -license_files = LICENSE.txt -classifiers = - Development Status :: 5 - Production/Stable - Operating System :: POSIX :: Linux - License :: OSI Approved :: MIT License - Intended Audience :: Developers - Programming Language :: Python :: 3 - Programming Language :: Python :: 2.7 - Topic :: Software Development - Topic :: Software Development :: Libraries - Topic :: System :: Hardware - -[options] -python_requires = >= 2.7 -packages = bme680 -install_requires = smbus - -[flake8] -exclude = - .tox, - .eggs, - .git, - __pycache__, - build, - dist -ignore = - E501 - W504 # Line-break after binary operator, for formatting of conversion formulas - -[pimoroni] -py3only = true -py2deps = -py3deps = -configtxt = -commands = - printf "Setting up i2c...\n" - raspi-config nonint do_i2c 0 diff --git a/library/setup.py b/library/setup.py deleted file mode 100755 index afb1ee1..0000000 --- a/library/setup.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Copyright (c) 2016 Pimoroni - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -""" - -from setuptools import setup, __version__ -from pkg_resources import parse_version - -minimum_version = parse_version('30.4.0') - -if parse_version(__version__) < minimum_version: - raise RuntimeError("Package setuptools must be at least version {}".format(minimum_version)) - -setup() diff --git a/library/tox.ini b/library/tox.ini deleted file mode 100644 index 49a034c..0000000 --- a/library/tox.ini +++ /dev/null @@ -1,25 +0,0 @@ -[tox] -envlist = py{27,35,37,39},qa -skip_missing_interpreters = True - -[testenv] -commands = - python setup.py install - coverage run -m py.test -v -r wsx - coverage report -deps = - mock - pytest>=3.1 - pytest-cov - -[testenv:qa] -commands = - check-manifest --ignore tox.ini,tests/*,.coveragerc - python setup.py sdist bdist_wheel - twine check dist/* - flake8 -deps = - check-manifest - flake8 - twine - diff --git a/packaging/CHANGELOG b/packaging/CHANGELOG deleted file mode 100644 index 8cb1ba9..0000000 --- a/packaging/CHANGELOG +++ /dev/null @@ -1,36 +0,0 @@ -bme680 (1.0.5) stable; urgency=low - - * New: set_temp_offset to calibrate temperature offset in degrees C - - -- Phil Howard Fri, 01 Jun 2018 00:00:00 +0000 - -bme680 (1.0.4) stable; urgency=low - - * Fix to range_sw_err for extremely high gas readings - * Convert to unsigned int to fix negative gas readings - - -- Phil Howard Mon, 04 Dec 2017 00:00:00 +0000 - -bme680 (1.0.3) stable; urgency=low - - * Merged temperature compensation fix from Bosch's BME680_driver 3.5.3 - - -- Phil Howard Wed, 22 Nov 2017 00:00:00 +0000 - -bme680 (1.0.2) stable; urgency=low - - * Fixed set_gas_heater_temperature to avoid i2c TypeError - - -- Phil Howard Wed, 18 Oct 2017 00:00:00 +0000 - -bme680 (1.0.1) stable; urgency=low - - * Added Manifest to Python package - - -- Phil Howard Tue, 17 Oct 2017 00:00:00 +0000 - -bme680 (1.0.0) stable; urgency=low - - * Initial release - - -- Phil Howard Tue, 17 Oct 2017 00:00:00 +0000 diff --git a/packaging/bme680_1.0.2_armhf.raspberrypi.upload b/packaging/bme680_1.0.2_armhf.raspberrypi.upload deleted file mode 100644 index c90ca84..0000000 --- a/packaging/bme680_1.0.2_armhf.raspberrypi.upload +++ /dev/null @@ -1,5 +0,0 @@ -Successfully uploaded bme680_1.0.2.dsc to build-master.raspberrypi.org for raspberrypi. -Successfully uploaded bme680_1.0.2.tar.xz to build-master.raspberrypi.org for raspberrypi. -Successfully uploaded python-bme680_1.0.2_all.deb to build-master.raspberrypi.org for raspberrypi. -Successfully uploaded python3-bme680_1.0.2_all.deb to build-master.raspberrypi.org for raspberrypi. -Successfully uploaded bme680_1.0.2_armhf.changes to build-master.raspberrypi.org for raspberrypi. diff --git a/packaging/debian/README b/packaging/debian/README deleted file mode 100644 index 9f7ca36..0000000 --- a/packaging/debian/README +++ /dev/null @@ -1,9 +0,0 @@ -README - -Python library for the BME680 gas, temperature, pressure and humidity sensor. Supports communication over i2c only. - -IMPORTANT - -The bme680 library requires i2c. -To enable run `curl get.pimoroni.com/i2c | bash` -or use raspi-config and reboot your Raspberry Pi. diff --git a/packaging/debian/changelog b/packaging/debian/changelog deleted file mode 100644 index 8cb1ba9..0000000 --- a/packaging/debian/changelog +++ /dev/null @@ -1,36 +0,0 @@ -bme680 (1.0.5) stable; urgency=low - - * New: set_temp_offset to calibrate temperature offset in degrees C - - -- Phil Howard Fri, 01 Jun 2018 00:00:00 +0000 - -bme680 (1.0.4) stable; urgency=low - - * Fix to range_sw_err for extremely high gas readings - * Convert to unsigned int to fix negative gas readings - - -- Phil Howard Mon, 04 Dec 2017 00:00:00 +0000 - -bme680 (1.0.3) stable; urgency=low - - * Merged temperature compensation fix from Bosch's BME680_driver 3.5.3 - - -- Phil Howard Wed, 22 Nov 2017 00:00:00 +0000 - -bme680 (1.0.2) stable; urgency=low - - * Fixed set_gas_heater_temperature to avoid i2c TypeError - - -- Phil Howard Wed, 18 Oct 2017 00:00:00 +0000 - -bme680 (1.0.1) stable; urgency=low - - * Added Manifest to Python package - - -- Phil Howard Tue, 17 Oct 2017 00:00:00 +0000 - -bme680 (1.0.0) stable; urgency=low - - * Initial release - - -- Phil Howard Tue, 17 Oct 2017 00:00:00 +0000 diff --git a/packaging/debian/clean b/packaging/debian/clean deleted file mode 100644 index 45149aa..0000000 --- a/packaging/debian/clean +++ /dev/null @@ -1 +0,0 @@ -*.egg-info/* diff --git a/packaging/debian/compat b/packaging/debian/compat deleted file mode 100644 index ec63514..0000000 --- a/packaging/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/packaging/debian/control b/packaging/debian/control deleted file mode 100644 index cdd3cc5..0000000 --- a/packaging/debian/control +++ /dev/null @@ -1,29 +0,0 @@ -Source: bme680 -Maintainer: Phil Howard -Homepage: https://github.com/pimoroni/bme680 -Section: python -Priority: extra -Build-Depends: debhelper (>= 9.0.0), dh-python, python-all (>= 2.7), python-setuptools, python3-all (>= 3.4), python3-setuptools -Standards-Version: 3.9.6 -X-Python-Version: >= 2.7 -X-Python3-Version: >= 3.4 - -Package: python-bme680 -Architecture: all -Section: python -Depends: ${misc:Depends}, ${python:Depends}, python-rpi.gpio, python-spidev -Description: Python library for the BME680 gas, temperature, pressure and humidity sensor. - The BME680 is a gas, temperature, pressure and humidity sensor. - Supports communication over i2c only. - . - This is the Python 2 version of the package. - -Package: python3-bme680 -Architecture: all -Section: python -Depends: ${misc:Depends}, ${python3:Depends}, python3-rpi.gpio, python3-spidev -Description: Python library for the BME680 gas, temperature, pressure and humidity sensor. - The BME680 is a gas, temperature, pressure and humidity sensor. - Supports communication over i2c only. - . - This is the Python 3 version of the package. diff --git a/packaging/debian/copyright b/packaging/debian/copyright deleted file mode 100644 index d039c34..0000000 --- a/packaging/debian/copyright +++ /dev/null @@ -1,26 +0,0 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: bme680 -Source: https://github.com/pimoroni/bme680 - -Files: * -Copyright: 2016 Pimoroni Ltd -License: MIT - -License: MIT - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - . - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - . - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. diff --git a/packaging/debian/docs b/packaging/debian/docs deleted file mode 100644 index e69de29..0000000 diff --git a/packaging/debian/rules b/packaging/debian/rules deleted file mode 100755 index b4ac200..0000000 --- a/packaging/debian/rules +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- - -#export DH_VERBOSE=1 -export DH_OPTIONS - -%: - dh $@ --with python2,python3 --buildsystem=python_distutils - -override_dh_auto_install: - python setup.py install --root debian/python-bme680 --install-layout=deb - python3 setup.py install --root debian/python3-bme680 --install-layout=deb diff --git a/packaging/debian/source/format b/packaging/debian/source/format deleted file mode 100644 index 89ae9db..0000000 --- a/packaging/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (native) diff --git a/packaging/debian/source/options b/packaging/debian/source/options deleted file mode 100644 index 8f82c91..0000000 --- a/packaging/debian/source/options +++ /dev/null @@ -1 +0,0 @@ -extend-diff-ignore = "^[^/]+\.egg-info/" diff --git a/packaging/makeall.sh b/packaging/makeall.sh deleted file mode 100755 index abca395..0000000 --- a/packaging/makeall.sh +++ /dev/null @@ -1,165 +0,0 @@ -#!/bin/bash - -# script control variables - -reponame="" # leave this blank for auto-detection -libname="" # leave this blank for auto-detection -packagename="" # leave this blank for auto-selection - -debianlog="debian/changelog" -debcontrol="debian/control" -debcopyright="debian/copyright" -debrules="debian/rules" -debreadme="debian/README" - -debdir="$(pwd)" -rootdir="$(dirname $debdir)" -libdir="$rootdir/library" - -FLAG=false - -# function define - -success() { - echo "$(tput setaf 2)$1$(tput sgr0)" -} - -inform() { - echo "$(tput setaf 6)$1$(tput sgr0)" -} - -warning() { - echo "$(tput setaf 1)$1$(tput sgr0)" -} - -newline() { - echo "" -} - -# assessing repo and library variables - -if [ -z "$reponame" ] || [ -z "$libname" ]; then - inform "detecting reponame and libname..." -else - inform "using reponame and libname overrides" -fi - -if [ -z "$reponame" ]; then - if [[ $rootdir == *"python"* ]]; then - repodir="$(dirname $rootdir)" - reponame="$(basename $repodir)" - else - repodir="$rootdir" - reponame="$(basename $repodir)" - fi - reponame=$(echo "$reponame" | tr "[A-Z]" "[a-z]") -fi - -if [ -z "$libname" ]; then - cd "$libdir" - libname=$(grep "name" setup.py | tr -d "[:space:]" | cut -c 7- | rev | cut -c 3- | rev) - libname=$(echo "$libname" | tr "[A-Z]" "[a-z]") && cd "$debdir" -fi - -if [ -z "$packagename" ]; then - packagename="$libname" -fi - -echo "reponame is $reponame and libname is $libname" -echo "output packages will be python-$packagename and python3-$packagename" - -# checking generating changelog file - -./makelog.sh -version=$(head -n 1 "$libdir/CHANGELOG.txt") -echo "building $libname version $version" - -# checking debian/changelog file - -inform "checking debian/changelog file..." - -if ! head -n 1 $debianlog | grep "$libname" &> /dev/null; then - warning "library not mentioned in header!" && FLAG=true -elif head -n 1 $debianlog | grep "UNRELEASED"; then - warning "this changelog is not going to generate a release!" - warning "change distribution to 'stable'" && FLAG=true -fi - -# checking debian/copyright file - -inform "checking debian/copyright file..." - -if ! grep "^Source" $debcopyright | grep "$reponame" &> /dev/null; then - warning "$(grep "^Source" $debcopyright)" && FLAG=true -fi - -if ! grep "^Upstream-Name" $debcopyright | grep "$libname" &> /dev/null; then - warning "$(grep "^Upstream-Name" $debcopyright)" && FLAG=true -fi - -# checking debian/control file - -inform "checking debian/control file..." - -if ! grep "^Source" $debcontrol | grep "$libname" &> /dev/null; then - warning "$(grep "^Source" $debcontrol)" && FLAG=true -fi - -if ! grep "^Homepage" $debcontrol | grep "$reponame" &> /dev/null; then - warning "$(grep "^Homepage" $debcontrol)" && FLAG=true -fi - -if ! grep "^Package: python-$packagename" $debcontrol &> /dev/null; then - warning "$(grep "^Package: python-" $debcontrol)" && FLAG=true -fi - -if ! grep "^Package: python3-$packagename" $debcontrol &> /dev/null; then - warning "$(grep "^Package: python3-" $debcontrol)" && FLAG=true -fi - -if ! grep "^Priority: extra" $debcontrol &> /dev/null; then - warning "$(grep "^Priority" $debcontrol)" && FLAG=true -fi - - -# checking debian/rules file - -inform "checking debian/rules file..." - -if ! grep "debian/python-$packagename" $debrules &> /dev/null; then - warning "$(grep "debian/python-" $debrules)" && FLAG=true -fi - -if ! grep "debian/python3-$packagename" $debrules &> /dev/null; then - warning "$(grep "debian/python3-" $debrules)" && FLAG=true -fi - -# checking debian/README file - -inform "checking debian/readme file..." - -if ! grep -e "$libname" -e "$reponame" $debreadme &> /dev/null; then - warning "README does not seem to mention product, repo or lib!" && FLAG=true -fi - -# summary of checks pre build - -if $FLAG; then - warning "Check all of the above and correct!" && exit 1 -else - inform "we're good to go... bulding!" -fi - -# building deb and final checks - -./makedeb.sh - -inform "running lintian..." -lintian -v $(find -name "python*$version*.deb") -lintian -v $(find -name "python3*$version*.deb") - -inform "checking signatures..." -gpg --verify $(find -name "*$version*changes") -gpg --verify $(find -name "*$version*dsc") - -exit 0 diff --git a/packaging/makedeb.sh b/packaging/makedeb.sh deleted file mode 100755 index 84ba0e2..0000000 --- a/packaging/makedeb.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -gettools="no" -setup="yes" -cleanup="yes" -pkgfiles=( "build" "changes" "deb" "dsc" "tar.xz" ) - - -if [ $gettools == "yes" ]; then - sudo apt-get update && sudo apt-get install build-essential debhelper devscripts dh-make dh-python dput gnupg - sudo apt-get install python-all python-setuptools python3-all python3-setuptools -fi - -if [ $setup == "yes" ]; then - rm -R ../library/build ../library/debian &> /dev/null - cp -R ./debian/ ../library/ -fi - -cd ../library && debuild -aarmhf - -for file in ${pkgfiles[@]}; do - mv ../*.$file ../packaging -done - -if [ $cleanup == "yes" ]; then - debuild clean - rm -R ./build ./debian &> /dev/null -fi - -exit 0 diff --git a/packaging/makelog.sh b/packaging/makelog.sh deleted file mode 100755 index 15d660e..0000000 --- a/packaging/makelog.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/bash - -# script control variables - -libname="" # leave this blank for auto-detection -sibname=() # name of sibling in packages list -versionwarn="yes" # set to anything but 'yes' to turn off warning - -debdir="$(pwd)" -rootdir="$(dirname $debdir)" -libdir="$rootdir/library" - -mainlog="CHANGELOG" -debianlog="debian/changelog" -pypilog="$libdir/CHANGELOG.txt" - -# function define - -success() { - echo "$(tput setaf 2)$1$(tput sgr0)" -} - -inform() { - echo "$(tput setaf 6)$1$(tput sgr0)" -} - -warning() { - echo "$(tput setaf 1)$1$(tput sgr0)" -} - -newline() { - echo "" -} - -# generate debian changelog - -cat $mainlog > $debianlog -inform "seeded debian changelog" - -# generate pypi changelog - -sed -e "/--/d" \ - -e "s/ \*/\*/" \ - -e "s/.*(\([0-9].[0-9].[0-9]\)).*/\1/" \ - -e '/^[0-9].[0-9].[0-9]$/ a\ ------' $mainlog | cat -s > $pypilog - -version=$(head -n 1 $pypilog) -inform "pypi changelog generated" - -# touch up version in setup.py file - -if [ -n $(grep version "$libdir/setup.py" &> /dev/null) ]; then - inform "touched up version in setup.py" - sed -i "s/'[0-9].[0-9].[0-9]'/'$version'/" "$libdir/setup.py" -else - warning "couldn't touch up version in setup, no match found" -fi - -# touch up version in lib or package siblings - -if [ -z "$libname" ]; then - cd "$libdir" - libname=$(grep "name" setup.py | tr -d "[:space:]" | cut -c 7- | rev | cut -c 3- | rev) - libname=$(echo "$libname" | tr "[A-Z]" "[a-z]") && cd "$debdir" - sibname+=( "$libname" ) -elif [ "$libname" != "package" ]; then - sibname+=( "$libname" ) -fi - -for sibling in ${sibname[@]}; do - if grep -e "__version__" "$libdir/$sibling.py" &> /dev/null; then - sed -i "s/__version__ = '[0-9].[0-9].[0-9]'/__version__ = '$version'/" "$libdir/$sibling.py" - inform "touched up version in $sibling.py" - elif grep -e "__version__" "$libdir/$sibling/__init__.py" &> /dev/null; then - sed -i "s/__version__ = '[0-9].[0-9].[0-9]'/__version__ = '$version'/" "$libdir/$sibling/__init__.py" - inform "touched up version in $sibling/__init__.py" - elif [ "$versionwarn" == "yes" ]; then - warning "couldn't touch up __version__ in $sibling, no match found" - fi -done - -exit 0 diff --git a/packaging/test.txt b/packaging/test.txt deleted file mode 100644 index e69de29..0000000 diff --git a/packaging/testlog.sh b/packaging/testlog.sh deleted file mode 100755 index 691b69f..0000000 --- a/packaging/testlog.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - - -sed -e "/--/d" \ - -e "s/ \*/\*/" \ - -e "s/.*(\([0-9].[0-9].[0-9]\)).*/\1/" \ - -e '/^[0-9].[0-9].[0-9]$/ a\ ------' CHANGELOG diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..7230aec --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,117 @@ +[build-system] +requires = ["hatchling", "hatch-fancy-pypi-readme"] +build-backend = "hatchling.build" + +[project] +name = "bme680" +dynamic = ["version", "readme"] +description = "Python library for the BME680 temperature, humidity and gas sensor" +license = {file = "LICENSE"} +requires-python = ">= 3.7" +authors = [ + { name = "Philip Howard", email = "phil@pimoroni.com" }, +] +maintainers = [ + { name = "Philip Howard", email = "phil@pimoroni.com" }, +] +keywords = [ + "Pi", + "Raspberry", +] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: POSIX :: Linux", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3 :: Only", + "Topic :: Software Development", + "Topic :: Software Development :: Libraries", + "Topic :: System :: Hardware", +] +dependencies = [ + "smbus2" +] + +[project.urls] +GitHub = "https://www.github.com/pimoroni/bme680-python" +Homepage = "https://www.pimoroni.com" + +[tool.hatch.version] +path = "bme680/__init__.py" + +[tool.hatch.build] +include = [ + "bme680", + "README.md", + "CHANGELOG.md", + "LICENSE" +] + +[tool.hatch.build.targets.sdist] +include = [ + "*" +] +exclude = [ + ".*", + "dist" +] + +[tool.hatch.metadata.hooks.fancy-pypi-readme] +content-type = "text/markdown" +fragments = [ + { path = "README.md" }, + { text = "\n" }, + { path = "CHANGELOG.md" } +] + +[tool.ruff] +exclude = [ + '.tox', + '.egg', + '.git', + '__pycache__', + 'build', + 'dist' +] +line-length = 200 + +[tool.codespell] +skip = """ +./.tox,\ +./.egg,\ +./.git,\ +./__pycache__,\ +./build,\ +./dist.\ +""" + +[tool.isort] +line_length = 200 + +[tool.check-manifest] +ignore = [ + '.stickler.yml', + 'boilerplate.md', + 'check.sh', + 'install.sh', + 'uninstall.sh', + 'Makefile', + 'tox.ini', + 'tests/*', + 'examples/*', + '.coveragerc', + 'requirements-dev.txt' +] + +[tool.pimoroni] +apt_packages = [] +configtxt = [] +commands = [ + "sudo raspi-config nonint do_i2c 0" +] diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..525b042 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,9 @@ +check-manifest +ruff +codespell +isort +twine +hatch +hatch-fancy-pypi-readme +tox +pdoc diff --git a/library/tests/conftest.py b/tests/conftest.py similarity index 95% rename from library/tests/conftest.py rename to tests/conftest.py index 44c4054..57c485f 100644 --- a/library/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,8 @@ import sys + import mock import pytest + import bme680 from bme680.constants import CalibrationData @@ -46,9 +48,9 @@ def smbus_notpresent(): """Mock smbus module.""" smbus = mock.MagicMock() smbus.SMBus = MockSMBus - sys.modules['smbus'] = smbus + sys.modules['smbus2'] = smbus yield smbus - del sys.modules['smbus'] + del sys.modules['smbus2'] @pytest.fixture(scope='function', autouse=False) @@ -56,9 +58,9 @@ def smbus(): """Mock smbus module.""" smbus = mock.MagicMock() smbus.SMBus = MockSMBusPresent - sys.modules['smbus'] = smbus + sys.modules['smbus2'] = smbus yield smbus - del sys.modules['smbus'] + del sys.modules['smbus2'] @pytest.fixture(scope='function', autouse=False) diff --git a/library/tests/setup.cfg b/tests/setup.cfg similarity index 100% rename from library/tests/setup.cfg rename to tests/setup.cfg diff --git a/library/tests/test_compensation.py b/tests/test_compensation.py similarity index 100% rename from library/tests/test_compensation.py rename to tests/test_compensation.py diff --git a/library/tests/test_setup.py b/tests/test_setup.py similarity index 99% rename from library/tests/test_setup.py rename to tests/test_setup.py index b401d91..0c1554d 100644 --- a/library/tests/test_setup.py +++ b/tests/test_setup.py @@ -1,4 +1,5 @@ import pytest + import bme680 diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..4726cef --- /dev/null +++ b/tox.ini @@ -0,0 +1,34 @@ +[tox] +envlist = py,qa +skip_missing_interpreters = True +isolated_build = true +minversion = 4.0.0 + +[testenv] +commands = + coverage run -m pytest -v -r wsx + coverage report +deps = + mock + pytest>=3.1 + pytest-cov + build + +[testenv:qa] +commands = + check-manifest + python -m build --no-isolation + python -m twine check dist/* + isort --check . + ruff check . + codespell . +deps = + check-manifest + ruff + codespell + isort + twine + build + hatch + hatch-fancy-pypi-readme + diff --git a/uninstall.sh b/uninstall.sh index 0231997..3314b7f 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -1,24 +1,72 @@ #!/bin/bash -PACKAGE="bme680" +FORCE=false +LIBRARY_NAME=$(grep -m 1 name pyproject.toml | awk -F" = " '{print substr($2,2,length($2)-2)}') +RESOURCES_DIR=$HOME/Pimoroni/$LIBRARY_NAME +PYTHON="python" -printf "BME680 Python Library: Uninstaller\n\n" -if [ $(id -u) -ne 0 ]; then - printf "Script must be run as root. Try 'sudo ./uninstall.sh'\n" - exit 1 -fi +venv_check() { + PYTHON_BIN=$(which $PYTHON) + if [[ $VIRTUAL_ENV == "" ]] || [[ $PYTHON_BIN != $VIRTUAL_ENV* ]]; then + printf "This script should be run in a virtual Python environment.\n" + exit 1 + fi +} -cd library +user_check() { + if [ "$(id -u)" -eq 0 ]; then + printf "Script should not be run as root. Try './uninstall.sh'\n" + exit 1 + fi +} -printf "Unnstalling for Python 2..\n" -pip uninstall $PACKAGE +confirm() { + if $FORCE; then + true + else + read -r -p "$1 [y/N] " response < /dev/tty + if [[ $response =~ ^(yes|y|Y)$ ]]; then + true + else + false + fi + fi +} -if [ -f "/usr/bin/pip3" ]; then - printf "Uninstalling for Python 3..\n" - pip3 uninstall $PACKAGE -fi +prompt() { + read -r -p "$1 [y/N] " response < /dev/tty + if [[ $response =~ ^(yes|y|Y)$ ]]; then + true + else + false + fi +} + +success() { + echo -e "$(tput setaf 2)$1$(tput sgr0)" +} + +inform() { + echo -e "$(tput setaf 6)$1$(tput sgr0)" +} + +warning() { + echo -e "$(tput setaf 1)$1$(tput sgr0)" +} -cd .. +printf "%s Python Library: Uninstaller\n\n" "$LIBRARY_NAME" + +user_check +venv_check + +printf "Uninstalling for Python 3...\n" +$PYTHON -m pip uninstall "$LIBRARY_NAME" + +if [ -d "$RESOURCES_DIR" ]; then + if confirm "Would you like to delete $RESOURCES_DIR?"; then + rm -r "$RESOURCES_DIR" + fi +fi printf "Done!\n"