Compare commits
35 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7def5108ea | ||
|
|
01be1e437d | ||
|
|
0a414a2342 | ||
|
|
7fc4630f1d | ||
|
|
1522b71317 | ||
|
|
45b0cafa2b | ||
|
|
897d6ddbe8 | ||
|
|
7bc3e74309 | ||
|
|
4da4afa879 | ||
|
|
9358afeb47 | ||
|
|
97bb660d5a | ||
|
|
03c93a553d | ||
|
|
96716ae034 | ||
|
|
41516d60bf | ||
|
|
1047b67c97 | ||
|
|
dddedd92ba | ||
|
|
7d12b16fba | ||
|
|
9bd7f6a47e | ||
|
|
85686eede4 | ||
|
|
3f624ecf57 | ||
|
|
0dbb994e53 | ||
|
|
9f669806d7 | ||
|
|
163cccd4bf | ||
|
|
e75ff020e4 | ||
|
|
91e6e1cd67 | ||
|
|
8503f01a23 | ||
|
|
3ede731b6c | ||
|
|
c6bf44ccd9 | ||
|
|
4e2a55651d | ||
|
|
5bee5778fc | ||
|
|
c818ade2ae | ||
|
|
5f10a029a2 | ||
|
|
7051c1e78c | ||
|
|
9af4579fdd | ||
|
|
a403315421 |
11 changed files with 354 additions and 126 deletions
13
.github/release-drafter.yml
vendored
Normal file
13
.github/release-drafter.yml
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# SPDX-FileCopyrightText: 2023 Melissa LeBlanc-Williams, written for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
change-template: "- $TITLE #$NUMBER by @$AUTHOR"
|
||||
template: |
|
||||
## What's Changed
|
||||
|
||||
$CHANGES
|
||||
|
||||
To use in CPython, `pip3 install Adafruit-Python-Shell`.
|
||||
|
||||
Read the [docs](https://circuitpython.readthedocs.io/projects/shell/en/latest/) for info on how to use it.
|
||||
35
.github/workflows/build.yml
vendored
35
.github/workflows/build.yml
vendored
|
|
@ -10,31 +10,27 @@ jobs:
|
|||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
- name: Translate Repo Name For Build Tools filename_prefix
|
||||
id: repo-name
|
||||
run: |
|
||||
echo ::set-output name=repo-name::$(
|
||||
echo repo-name=$(
|
||||
echo ${{ github.repository }} |
|
||||
awk -F '\/' '{ print tolower($2) }' |
|
||||
tr '_' '-'
|
||||
)
|
||||
- name: Set up Python 3.7
|
||||
uses: actions/setup-python@v1
|
||||
) >> $GITHUB_OUTPUT
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.7
|
||||
python-version: '3.11'
|
||||
- name: Versions
|
||||
run: |
|
||||
python3 --version
|
||||
- name: Checkout Current Repo
|
||||
uses: actions/checkout@v1
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- name: Checkout tools repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: adafruit/actions-ci-circuitpython-libs
|
||||
path: actions-ci
|
||||
|
|
@ -44,26 +40,23 @@ jobs:
|
|||
source actions-ci/install.sh
|
||||
- name: Pip install pylint, Sphinx, pre-commit
|
||||
run: |
|
||||
pip install --force-reinstall pylint Sphinx sphinx-rtd-theme pre-commit
|
||||
pip install --force-reinstall Sphinx sphinx-rtd-theme pre-commit
|
||||
- name: Library version
|
||||
run: git describe --dirty --always --tags
|
||||
- name: Pre-commit hooks
|
||||
run: |
|
||||
pre-commit run --all-files
|
||||
- name: PyLint
|
||||
run: |
|
||||
pylint $( find . -path './adafruit*.py' )
|
||||
- name: Build docs
|
||||
working-directory: docs
|
||||
run: sphinx-build -E -W -b html . _build/html
|
||||
- name: Check For setup.py
|
||||
- name: Check For pyproject.toml
|
||||
id: need-pypi
|
||||
run: |
|
||||
echo ::set-output name=setup-py::$( find . -wholename './setup.py' )
|
||||
echo pyproject-toml=$( find . -wholename './pyproject.toml' ) >> $GITHUB_OUTPUT
|
||||
- name: Build Python package
|
||||
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
|
||||
if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml')
|
||||
run: |
|
||||
pip install --upgrade setuptools wheel twine readme_renderer testresources
|
||||
python setup.py sdist
|
||||
python setup.py bdist_wheel --universal
|
||||
pip install --upgrade build twine
|
||||
find -type f -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) -exec sed -i -e "s/0.0.0+auto.0/1.2.3/" {} +
|
||||
python -m build
|
||||
twine check dist/*
|
||||
|
|
|
|||
25
.github/workflows/release-drafter.yml
vendored
Normal file
25
.github/workflows/release-drafter.yml
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# SPDX-FileCopyrightText: 2023 Melissa LeBlanc-Williams, written for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: Release Drafter
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
update_release_draft:
|
||||
permissions:
|
||||
# write permission is required to create a github release
|
||||
contents: write
|
||||
pull-requests: read
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: release-drafter/release-drafter@v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
21
.github/workflows/release.yml
vendored
21
.github/workflows/release.yml
vendored
|
|
@ -12,26 +12,27 @@ jobs:
|
|||
upload-pypi:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Check For setup.py
|
||||
- uses: actions/checkout@v3
|
||||
- name: Check For pyproject.toml
|
||||
id: need-pypi
|
||||
run: |
|
||||
echo ::set-output name=setup-py::$( find . -wholename './setup.py' )
|
||||
echo pyproject-toml=$( find . -wholename './pyproject.toml' ) >> $GITHUB_OUTPUT
|
||||
- name: Set up Python
|
||||
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
|
||||
uses: actions/setup-python@v1
|
||||
if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml')
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
python-version: '3.11'
|
||||
- name: Install dependencies
|
||||
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
|
||||
if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml')
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install setuptools wheel twine
|
||||
pip install --upgrade build twine
|
||||
- name: Build and publish
|
||||
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
|
||||
if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml')
|
||||
env:
|
||||
TWINE_USERNAME: ${{ secrets.pypi_username }}
|
||||
TWINE_PASSWORD: ${{ secrets.pypi_password }}
|
||||
run: |
|
||||
python setup.py sdist
|
||||
find -type f -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) -exec sed -i -e "s/0.0.0+auto.0/${{github.event.release.tag_name}}/" {} +
|
||||
python -m build
|
||||
twine upload dist/*
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ repos:
|
|||
hooks:
|
||||
- id: reuse
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
rev: v5.0.0
|
||||
hooks:
|
||||
- id: check-yaml
|
||||
- id: end-of-file-fixer
|
||||
|
|
|
|||
|
|
@ -396,4 +396,4 @@ min-public-methods=1
|
|||
|
||||
# Exceptions that will emit a warning when being caught. Defaults to
|
||||
# "Exception"
|
||||
overgeneral-exceptions=Exception
|
||||
overgeneral-exceptions=builtins.Exception
|
||||
|
|
|
|||
|
|
@ -23,19 +23,56 @@ Implementation Notes
|
|||
# imports
|
||||
import sys
|
||||
import os
|
||||
import stat
|
||||
import shutil
|
||||
import subprocess
|
||||
import fcntl
|
||||
import platform
|
||||
import fileinput
|
||||
import re
|
||||
import pwd
|
||||
from datetime import datetime
|
||||
from clint.textui import colored, prompt
|
||||
import adafruit_platformdetect
|
||||
|
||||
__version__ = "0.0.0-auto.0"
|
||||
__version__ = "0.0.0+auto.0"
|
||||
__repo__ = "https://github.com/adafruit/Adafruit_Python_Shell.git"
|
||||
|
||||
# This must be by order of release
|
||||
RASPI_VERSIONS = (
|
||||
"wheezy",
|
||||
"jessie",
|
||||
"stretch",
|
||||
"buster",
|
||||
"bullseye",
|
||||
"bookworm",
|
||||
"trixie",
|
||||
)
|
||||
|
||||
WINDOW_MANAGERS = {
|
||||
"x11": "W1",
|
||||
"wayfire": "W2",
|
||||
"labwc": "W3",
|
||||
}
|
||||
|
||||
FILE_MODES = {
|
||||
"+x": stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH,
|
||||
"+r": stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH,
|
||||
"+w": stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH,
|
||||
"a+x": stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH,
|
||||
"a+r": stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH,
|
||||
"a+w": stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH,
|
||||
"u+x": stat.S_IXUSR,
|
||||
"u+r": stat.S_IRUSR,
|
||||
"u+w": stat.S_IWUSR,
|
||||
"g+x": stat.S_IXGRP,
|
||||
"g+r": stat.S_IRGRP,
|
||||
"g+w": stat.S_IWGRP,
|
||||
"o+x": stat.S_IXOTH,
|
||||
"o+r": stat.S_IROTH,
|
||||
"o+w": stat.S_IWOTH,
|
||||
}
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
class Shell:
|
||||
|
|
@ -65,7 +102,9 @@ class Shell:
|
|||
)
|
||||
return prompt.options(message, options)
|
||||
|
||||
def run_command(self, cmd, suppress_message=False, return_output=False):
|
||||
def run_command(
|
||||
self, cmd, suppress_message=False, return_output=False, run_as_user=None
|
||||
):
|
||||
"""
|
||||
Run a shell command and show the output as it runs
|
||||
"""
|
||||
|
|
@ -79,13 +118,31 @@ class Shell:
|
|||
except TypeError:
|
||||
return ""
|
||||
|
||||
# Allow running as a different user if we are root
|
||||
if self.is_root() and run_as_user is not None:
|
||||
pw_record = pwd.getpwnam(run_as_user)
|
||||
env = os.environ.copy()
|
||||
env["HOME"] = pw_record.pw_dir
|
||||
env["LOGNAME"] = run_as_user
|
||||
env["USER"] = pw_record.pw_name
|
||||
|
||||
def preexec():
|
||||
os.setgid(pw_record.pw_gid)
|
||||
os.setuid(pw_record.pw_uid)
|
||||
|
||||
else:
|
||||
env = None
|
||||
preexec = None
|
||||
|
||||
full_output = ""
|
||||
with subprocess.Popen(
|
||||
with subprocess.Popen( # pylint: disable=subprocess-popen-preexec-fn
|
||||
cmd,
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True,
|
||||
env=env,
|
||||
preexec_fn=preexec,
|
||||
) as proc:
|
||||
while proc.poll() is None:
|
||||
err = read_stream(proc.stderr)
|
||||
|
|
@ -104,6 +161,50 @@ class Shell:
|
|||
return False
|
||||
return True
|
||||
|
||||
def write_templated_file(self, output_path, template, **kwargs):
|
||||
"""
|
||||
Use a template file and render it with the given context and write it to the specified path.
|
||||
The template file should contain placeholders in the format {key} which will be replaced
|
||||
with the corresponding values from the kwargs dictionary.
|
||||
"""
|
||||
# if path is an existing directory, the template filename will be used
|
||||
output_path = self.path(output_path)
|
||||
if os.path.isdir(output_path):
|
||||
output_path = os.path.join(output_path, os.path.basename(template))
|
||||
|
||||
# Render the template with the provided context
|
||||
rendered_content = self.load_template(template, **kwargs)
|
||||
|
||||
if rendered_content is None:
|
||||
self.error(
|
||||
f"Failed to load template '{template}'. Unable to write file '{output_path}'."
|
||||
)
|
||||
return False
|
||||
|
||||
append = kwargs.get("append", False)
|
||||
self.write_text_file(output_path, rendered_content, append=append)
|
||||
|
||||
return True
|
||||
|
||||
def load_template(self, template, **kwargs):
|
||||
"""
|
||||
Load a template file and return its content with the placeholders replaced by the provided
|
||||
context. The template file should contain placeholders in the format {key} which will be
|
||||
replaced with the corresponding values from the kwargs dictionary.
|
||||
"""
|
||||
if not os.path.exists(template):
|
||||
self.error(f"Template file '{template}' does not exist")
|
||||
return None
|
||||
|
||||
with open(template, "r") as template_file:
|
||||
template_content = template_file.read()
|
||||
|
||||
# Render the template with the provided context
|
||||
for key, value in kwargs.items():
|
||||
template_content = template_content.replace(f"{{{key}}}", str(value))
|
||||
|
||||
return template_content
|
||||
|
||||
def info(self, message, **kwargs):
|
||||
"""
|
||||
Display a message with the group in green
|
||||
|
|
@ -203,9 +304,9 @@ class Shell:
|
|||
# directory = self.getcwd() + "/" + directory
|
||||
directory = self.path(directory)
|
||||
if not self.exists(directory):
|
||||
raise ValueError("Directory does not exist")
|
||||
raise ValueError(f"Directory '{directory}' does not exist")
|
||||
if not self.isdir(directory):
|
||||
raise ValueError("Given location is not a directory")
|
||||
raise ValueError(f"The given location '{directory}' is not a directory")
|
||||
os.chdir(directory)
|
||||
|
||||
def pushd(self, directory):
|
||||
|
|
@ -283,7 +384,10 @@ class Shell:
|
|||
# Not found; append (silently)
|
||||
self.write_text_file(file, replacement, append=True)
|
||||
|
||||
def pattern_search(self, location, pattern, multi_line=False, return_match=False):
|
||||
# pylint: disable=too-many-arguments
|
||||
def pattern_search(
|
||||
self, location, pattern, multi_line=False, return_match=False, find_all=False
|
||||
):
|
||||
"""
|
||||
Similar to grep, but uses pure python
|
||||
multi_line will search the entire file as a large text glob,
|
||||
|
|
@ -293,16 +397,17 @@ class Shell:
|
|||
"""
|
||||
location = self.path(location)
|
||||
found = False
|
||||
search_function = re.findall if find_all else re.search
|
||||
|
||||
if self.exists(location) and not self.isdir(location):
|
||||
if multi_line:
|
||||
with open(location, "r+", encoding="utf-8") as file:
|
||||
match = re.search(pattern, file.read(), flags=re.DOTALL)
|
||||
match = search_function(pattern, file.read(), flags=re.DOTALL)
|
||||
if match:
|
||||
found = True
|
||||
else:
|
||||
for line in fileinput.FileInput(location):
|
||||
match = re.search(pattern, line)
|
||||
match = search_function(pattern, line)
|
||||
if match:
|
||||
found = True
|
||||
break
|
||||
|
|
@ -379,8 +484,13 @@ class Shell:
|
|||
Change the permissions of a file or directory
|
||||
"""
|
||||
location = self.path(location)
|
||||
# Convert a text mode to an integer mode
|
||||
if isinstance(mode, str):
|
||||
if mode not in FILE_MODES:
|
||||
raise ValueError(f"Invalid mode string '{mode}'")
|
||||
mode = FILE_MODES[mode]
|
||||
if not 0 <= mode <= 0o777:
|
||||
raise ValueError("Invalid mode value")
|
||||
raise ValueError(f"Invalid mode value '{mode}'")
|
||||
if os.path.exists(location):
|
||||
os.chmod(location, mode)
|
||||
|
||||
|
|
@ -437,6 +547,16 @@ class Shell:
|
|||
with open(self.path(path), mode, encoding="utf-8") as service_file:
|
||||
service_file.write(content)
|
||||
|
||||
def read_text_file(self, path):
|
||||
"""
|
||||
Read the contents of a file at the specified path
|
||||
"""
|
||||
path = self.path(path)
|
||||
if not os.path.exists(path):
|
||||
raise FileNotFoundError(f"File '{path}' does not exist")
|
||||
with open(path, "r", encoding="utf-8") as file:
|
||||
return file.read()
|
||||
|
||||
@staticmethod
|
||||
def is_python3():
|
||||
"Check if we are running Python 3 or later"
|
||||
|
|
@ -534,17 +654,29 @@ class Shell:
|
|||
"""Return a string containing the raspbian version"""
|
||||
if self.get_os() != "Raspbian":
|
||||
return None
|
||||
raspbian_releases = ("bullseye", "buster", "stretch", "jessie", "wheezy")
|
||||
if os.path.exists("/etc/os-release"):
|
||||
with open("/etc/os-release", encoding="utf-8") as f:
|
||||
release_file = f.read()
|
||||
if "/sid" in release_file:
|
||||
return "unstable"
|
||||
for raspbian in raspbian_releases:
|
||||
for raspbian in RASPI_VERSIONS:
|
||||
if raspbian in release_file:
|
||||
return raspbian
|
||||
return None
|
||||
|
||||
def is_minumum_version(self, version):
|
||||
"""Check if the version is at least the specified version"""
|
||||
# Check that version is a string
|
||||
if not isinstance(version, str):
|
||||
raise ValueError("Version must be a string")
|
||||
# Check that version is in the list of valid versions
|
||||
if version.lower() not in RASPI_VERSIONS:
|
||||
raise ValueError("Invalid version")
|
||||
# Check that the current version is at least the specified version
|
||||
return RASPI_VERSIONS.index(
|
||||
self.get_raspbian_version()
|
||||
) >= RASPI_VERSIONS.index(version.lower())
|
||||
|
||||
def prompt_reboot(self, default="y", **kwargs):
|
||||
"""Prompt the user for a reboot"""
|
||||
if not self.prompt("REBOOT NOW?", default=default, **kwargs):
|
||||
|
|
@ -564,21 +696,87 @@ class Shell:
|
|||
)
|
||||
self.prompt_reboot()
|
||||
|
||||
def check_kernel_userspace_mismatch(self):
|
||||
def check_kernel_userspace_mismatch(self, attempt_fix=True, fix_with_x11=False):
|
||||
"""
|
||||
Check if the userspace is 64-bit and kernel is 32-bit
|
||||
"""
|
||||
if self.is_arm64() and platform.architecture()[0] == "32bit":
|
||||
if self.is_kernel_userspace_mismatched():
|
||||
print(
|
||||
"Unable to compile driver because kernel space is 64-bit, but user space is 32-bit."
|
||||
)
|
||||
if self.is_raspberry_pi_os() and self.prompt(
|
||||
"Add parameter to /boot/config.txt to use 32-bit kernel?"
|
||||
config = self.get_boot_config()
|
||||
if (
|
||||
self.is_raspberry_pi_os()
|
||||
and attempt_fix
|
||||
and config
|
||||
and self.prompt(f"Add parameter to {config} to use 32-bit kernel?")
|
||||
):
|
||||
self.reconfig("/boot/config.txt", "^.*arm_64bit.*$", "arm_64bit=0")
|
||||
# Set to use 32-bit kernel
|
||||
self.reconfig(config, "^.*arm_64bit.*$", "arm_64bit=0")
|
||||
if fix_with_x11:
|
||||
self.set_window_manager("x11")
|
||||
self.prompt_reboot()
|
||||
else:
|
||||
self.bail("Unable to continue while mismatch is present.")
|
||||
raise RuntimeError("Unable to continue while mismatch is present.")
|
||||
|
||||
def set_window_manager(self, manager):
|
||||
"""
|
||||
Call raspi-config to set a new window manager
|
||||
"""
|
||||
if not self.is_minumum_version("bullseye"):
|
||||
return
|
||||
|
||||
if manager.lower() not in WINDOW_MANAGERS:
|
||||
raise ValueError("Invalid window manager")
|
||||
|
||||
if manager.lower() == "labwc" and not self.exists("/usr/bin/labwc"):
|
||||
raise RuntimeError("labwc is not installed")
|
||||
|
||||
print(f"Using {manager} as the window manager")
|
||||
if not self.run_command(
|
||||
"sudo raspi-config nonint do_wayland " + WINDOW_MANAGERS[manager.lower()]
|
||||
):
|
||||
raise RuntimeError("Unable to change window manager")
|
||||
|
||||
def get_window_manager(self):
|
||||
"""
|
||||
Get the current window manager
|
||||
"""
|
||||
sessions = {"wayfire": "LXDE-pi-wayfire"}
|
||||
# Check for Raspbian Desktop sessions
|
||||
if self.exists("/usr/share/xsessions/rpd-x.desktop") or self.exists(
|
||||
"/usr/share/wayland-sessions/rpd-labwc.desktop"
|
||||
):
|
||||
sessions.update({"x11": "rpd-x", "labwc": "rpd-labwc"})
|
||||
else:
|
||||
sessions.update({"x11": "LXDE-pi-x", "labwc": "LXDE-pi-labwc"})
|
||||
|
||||
matches = self.pattern_search(
|
||||
"/etc/lightdm/lightdm.conf", "^(?!#.*?)user-session=(.+)", False, True
|
||||
)
|
||||
if matches:
|
||||
session_match = matches.group(1)
|
||||
for key, session in sessions.items():
|
||||
if session_match == session:
|
||||
return key
|
||||
return None
|
||||
|
||||
def get_boot_config(self):
|
||||
"""
|
||||
Get the location of the boot config file
|
||||
"""
|
||||
# check if /boot/firmware/config.txt exists
|
||||
if self.exists("/boot/firmware/config.txt"):
|
||||
return "/boot/firmware/config.txt"
|
||||
if self.exists("/boot/config.txt"):
|
||||
return "/boot/config.txt"
|
||||
return None
|
||||
|
||||
def is_kernel_userspace_mismatched(self):
|
||||
"""
|
||||
If the userspace 64-bit and kernel is 32-bit?
|
||||
"""
|
||||
return self.is_arm64() and platform.architecture()[0] == "32bit"
|
||||
|
||||
# pylint: enable=invalid-name
|
||||
|
||||
|
|
@ -604,6 +802,14 @@ class Shell:
|
|||
detector = adafruit_platformdetect.Detector()
|
||||
return detector.board.id
|
||||
|
||||
@staticmethod
|
||||
def is_pi5_or_newer():
|
||||
"""
|
||||
Use PlatformDetect to check if this is a Raspberry Pi 5 or newer
|
||||
"""
|
||||
detector = adafruit_platformdetect.Detector()
|
||||
return detector.board.any_raspberry_pi_5_board
|
||||
|
||||
@staticmethod
|
||||
def get_architecture():
|
||||
"""
|
||||
|
|
|
|||
23
docs/conf.py
23
docs/conf.py
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
import os
|
||||
import sys
|
||||
import datetime
|
||||
|
||||
sys.path.insert(0, os.path.abspath(".."))
|
||||
|
||||
|
|
@ -16,13 +17,14 @@ sys.path.insert(0, os.path.abspath(".."))
|
|||
# ones.
|
||||
extensions = [
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinxcontrib.jquery",
|
||||
"sphinx.ext.intersphinx",
|
||||
"sphinx.ext.napoleon",
|
||||
"sphinx.ext.todo",
|
||||
]
|
||||
|
||||
intersphinx_mapping = {
|
||||
"python": ("https://docs.python.org/3.4", None),
|
||||
"python": ("https://docs.python.org/3", None),
|
||||
"CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None),
|
||||
}
|
||||
|
||||
|
|
@ -36,7 +38,14 @@ master_doc = "index"
|
|||
|
||||
# General information about the project.
|
||||
project = "Adafruit Shell Library"
|
||||
copyright = "2020 Melissa LeBlanc-Williams"
|
||||
creation_year = "2020"
|
||||
current_year = str(datetime.datetime.now().year)
|
||||
year_duration = (
|
||||
current_year
|
||||
if current_year == creation_year
|
||||
else creation_year + " - " + current_year
|
||||
)
|
||||
copyright = year_duration + " Melissa LeBlanc-Williams"
|
||||
author = "Melissa LeBlanc-Williams"
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
|
|
@ -91,19 +100,9 @@ napoleon_numpy_docstring = False
|
|||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
on_rtd = os.environ.get("READTHEDOCS", None) == "True"
|
||||
|
||||
if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
try:
|
||||
import sphinx_rtd_theme
|
||||
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."]
|
||||
except:
|
||||
html_theme = "default"
|
||||
html_theme_path = ["."]
|
||||
else:
|
||||
html_theme_path = ["."]
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
|
|
|
|||
3
optional_dependencies.txt
Normal file
3
optional_dependencies.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# SPDX-FileCopyrightText: 2023 Alec Delaney, written for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
|
@ -1,6 +1,54 @@
|
|||
# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò
|
||||
# SPDX-FileCopyrightText: 2023 Alec Delaney for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: Unlicense
|
||||
|
||||
[tool.black]
|
||||
target-version = ['py35']
|
||||
[build-system]
|
||||
requires = [
|
||||
"setuptools",
|
||||
"wheel",
|
||||
"setuptools-scm",
|
||||
]
|
||||
|
||||
[project]
|
||||
name = "adafruit-python-shell"
|
||||
description = "Python helper for running Shell scripts in Python"
|
||||
version = "0.0.0+auto.0"
|
||||
readme = "README.rst"
|
||||
authors = [
|
||||
{name = "Adafruit Industries", email = "circuitpython@adafruit.com"}
|
||||
]
|
||||
urls = {Homepage = "https://github.com/adafruit/Adafruit_Python_Shell"}
|
||||
keywords = [
|
||||
"adafruit",
|
||||
"blinka",
|
||||
"circuitpython",
|
||||
"micropython",
|
||||
"python",
|
||||
"shell",
|
||||
"installation",
|
||||
"raspberry",
|
||||
"pi",
|
||||
"console",
|
||||
"terminal",
|
||||
"installer",
|
||||
]
|
||||
license = {text = "MIT"}
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"Topic :: Software Development :: Libraries",
|
||||
"Topic :: System :: Hardware",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.4",
|
||||
"Programming Language :: Python :: 3.5",
|
||||
]
|
||||
dynamic = ["dependencies", "optional-dependencies"]
|
||||
|
||||
[tool.setuptools]
|
||||
py-modules = ["adafruit_shell"]
|
||||
|
||||
[tool.setuptools.dynamic]
|
||||
dependencies = {file = ["requirements.txt"]}
|
||||
optional-dependencies = {optional = {file = ["optional_requirements.txt"]}}
|
||||
|
|
|
|||
60
setup.py
60
setup.py
|
|
@ -1,60 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2020 Melissa LeBlanc-Williams for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
"""A setuptools based setup module.
|
||||
|
||||
See:
|
||||
https://packaging.python.org/en/latest/distributing.html
|
||||
https://github.com/pypa/sampleproject
|
||||
"""
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
# To use a consistent encoding
|
||||
from codecs import open
|
||||
from os import path
|
||||
|
||||
here = path.abspath(path.dirname(__file__))
|
||||
|
||||
# Get the long description from the README file
|
||||
with open(path.join(here, "README.rst"), encoding="utf-8") as f:
|
||||
long_description = f.read()
|
||||
|
||||
setup(
|
||||
name="adafruit-python-shell",
|
||||
use_scm_version=True,
|
||||
setup_requires=["setuptools_scm"],
|
||||
description="Python helper for running Shell scripts in Python",
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/x-rst",
|
||||
# The project's main homepage.
|
||||
url="https://github.com/adafruit/Adafruit_Python_Shell",
|
||||
# Author details
|
||||
author="Adafruit Industries",
|
||||
author_email="circuitpython@adafruit.com",
|
||||
install_requires=[
|
||||
"clint",
|
||||
"Adafruit-PlatformDetect",
|
||||
],
|
||||
# Choose your license
|
||||
license="MIT",
|
||||
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
|
||||
classifiers=[
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"Topic :: Software Development :: Libraries",
|
||||
"Topic :: System :: Hardware",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.4",
|
||||
"Programming Language :: Python :: 3.5",
|
||||
],
|
||||
# What does your project relate to?
|
||||
keywords="adafruit blinka circuitpython micropython python shell installation raspberry pi "
|
||||
"console terminal installer",
|
||||
# You can just specify the packages manually here if your project is
|
||||
# simple. Or you can use find_packages().
|
||||
py_modules=["adafruit_shell"],
|
||||
)
|
||||
Loading…
Reference in a new issue