Compare commits
9 Commits
Author | SHA1 | Date |
---|---|---|
Fabio Manganiello | 14e7b44f86 | |
Fabio Manganiello | ca342ee3ea | |
Fabio Manganiello | 14d6924338 | |
Fabio Manganiello | 9ba7ad9402 | |
Fabio Manganiello | d3dde80269 | |
Fabio Manganiello | 47395f0b03 | |
Fabio Manganiello | 075efde58c | |
Fabio Manganiello | c5aee0a65d | |
Fabio Manganiello | 795754f858 |
|
@ -1,6 +0,0 @@
|
|||
**/.git
|
||||
**/node_modules
|
||||
**/__pycache__
|
||||
**/venv
|
||||
**/.mypy_cache
|
||||
**/build
|
386
.drone.yml
386
.drone.yml
|
@ -1,386 +0,0 @@
|
|||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: default
|
||||
|
||||
volumes:
|
||||
- name: docs
|
||||
host:
|
||||
path: /opt/docs/platypush
|
||||
|
||||
- name: repos
|
||||
host:
|
||||
path: /opt/repos/platypush
|
||||
|
||||
steps:
|
||||
|
||||
###
|
||||
### Mirror the current repository state to Github
|
||||
###
|
||||
|
||||
- name: github-mirror
|
||||
image: alpine
|
||||
environment:
|
||||
SSH_PUBKEY:
|
||||
from_secret: ssh_pubkey
|
||||
SSH_PRIVKEY:
|
||||
from_secret: ssh_privkey
|
||||
|
||||
commands:
|
||||
- . .drone/github-mirror.sh
|
||||
|
||||
###
|
||||
### Rebuild the docs
|
||||
###
|
||||
|
||||
- name: docs
|
||||
image: alpine
|
||||
volumes:
|
||||
- name: docs
|
||||
path: /docs
|
||||
|
||||
commands:
|
||||
- . .drone/rebuild-docs.sh
|
||||
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
|
||||
###
|
||||
### Run the tests
|
||||
###
|
||||
|
||||
- name: tests
|
||||
image: alpine
|
||||
commands:
|
||||
- . .drone/run-tests.sh
|
||||
|
||||
###
|
||||
### Rebuild the UI files
|
||||
###
|
||||
|
||||
- name: build-ui
|
||||
image: node:current-alpine3.18
|
||||
|
||||
environment:
|
||||
SSH_PUBKEY:
|
||||
from_secret: ssh_pubkey
|
||||
SSH_PRIVKEY:
|
||||
from_secret: ssh_privkey
|
||||
PGP_KEY:
|
||||
from_secret: pgp_key
|
||||
PGP_KEY_ID:
|
||||
from_secret: pgp_key_id
|
||||
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
|
||||
depends_on:
|
||||
- tests
|
||||
|
||||
commands:
|
||||
- . .drone/build-ui.sh
|
||||
|
||||
###
|
||||
### Regenerate the components.json cache
|
||||
###
|
||||
|
||||
- name: update-components-cache
|
||||
image: alpine
|
||||
|
||||
environment:
|
||||
SSH_PUBKEY:
|
||||
from_secret: ssh_pubkey
|
||||
SSH_PRIVKEY:
|
||||
from_secret: ssh_privkey
|
||||
PGP_KEY:
|
||||
from_secret: pgp_key
|
||||
PGP_KEY_ID:
|
||||
from_secret: pgp_key_id
|
||||
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
|
||||
depends_on:
|
||||
- build-ui
|
||||
|
||||
commands:
|
||||
- . .drone/update-components-cache.sh
|
||||
|
||||
###
|
||||
### Update the Arch packages
|
||||
###
|
||||
|
||||
- name: update-arch-packages
|
||||
image: python:3.11-alpine
|
||||
environment:
|
||||
WORKDIR: /tmp/workdir
|
||||
SSH_PUBKEY:
|
||||
from_secret: ssh_pubkey
|
||||
SSH_PRIVKEY:
|
||||
from_secret: ssh_privkey
|
||||
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
|
||||
depends_on:
|
||||
- update-components-cache
|
||||
|
||||
commands:
|
||||
- . .drone/update-arch-packages.sh
|
||||
|
||||
###
|
||||
### Update the Debian (stable) packages
|
||||
###
|
||||
|
||||
- name: update-debian-stable-packages
|
||||
image: debian:stable
|
||||
volumes:
|
||||
- name: repos
|
||||
path: /repos
|
||||
|
||||
environment:
|
||||
DEB_VERSION: stable
|
||||
WORKDIR: /tmp/workdir
|
||||
APT_ROOT: /repos/apt
|
||||
PKG_NAME: platypush
|
||||
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
|
||||
depends_on:
|
||||
- update-components-cache
|
||||
|
||||
commands:
|
||||
- . .drone/update-deb-packages.sh
|
||||
|
||||
###
|
||||
### Update the Debian (oldstable) packages
|
||||
###
|
||||
|
||||
- name: update-debian-oldstable-packages
|
||||
image: debian:oldstable
|
||||
volumes:
|
||||
- name: repos
|
||||
path: /repos
|
||||
|
||||
environment:
|
||||
DEB_VERSION: oldstable
|
||||
WORKDIR: /tmp/workdir
|
||||
APT_ROOT: /repos/apt
|
||||
PKG_NAME: platypush
|
||||
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
|
||||
depends_on:
|
||||
- update-components-cache
|
||||
|
||||
commands:
|
||||
- . .drone/update-deb-packages.sh
|
||||
|
||||
###
|
||||
### Update the Ubuntu (latest) packages
|
||||
###
|
||||
|
||||
- name: update-ubuntu-packages
|
||||
image: ubuntu:latest
|
||||
volumes:
|
||||
- name: repos
|
||||
path: /repos
|
||||
|
||||
environment:
|
||||
DEB_VERSION: ubuntu
|
||||
WORKDIR: /tmp/workdir
|
||||
APT_ROOT: /repos/apt
|
||||
PKG_NAME: platypush
|
||||
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
|
||||
depends_on:
|
||||
- update-components-cache
|
||||
|
||||
commands:
|
||||
- . .drone/update-deb-packages.sh
|
||||
|
||||
###
|
||||
### Updates the APT repository after new packages have been pushed
|
||||
###
|
||||
|
||||
- name: update-apt-repo
|
||||
image: debian:stable
|
||||
volumes:
|
||||
- name: repos
|
||||
path: /repos
|
||||
|
||||
environment:
|
||||
REPOS_ROOT: /repos
|
||||
APT_ROOT: /repos/apt
|
||||
PGP_PUBKEY:
|
||||
from_secret: apt_pgp_pub_key
|
||||
PGP_PRIVKEY:
|
||||
from_secret: apt_pgp_priv_key
|
||||
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
|
||||
depends_on:
|
||||
- update-debian-stable-packages
|
||||
- update-debian-oldstable-packages
|
||||
- update-ubuntu-packages
|
||||
|
||||
commands:
|
||||
- . .drone/update-apt-repo.sh
|
||||
|
||||
###
|
||||
### Update the RPM (stable) packages
|
||||
###
|
||||
|
||||
- name: update-rpm-repo
|
||||
image: fedora
|
||||
volumes:
|
||||
- name: repos
|
||||
path: /repos
|
||||
|
||||
environment:
|
||||
RPM_VERSION: stable
|
||||
REPOS_ROOT: /repos
|
||||
RPM_ROOT: /repos/rpm
|
||||
WORKDIR: /tmp/workdir
|
||||
PKG_NAME: platypush
|
||||
PGP_PUBKEY:
|
||||
from_secret: rpm_pgp_pub_key
|
||||
PGP_PRIVKEY:
|
||||
from_secret: rpm_pgp_priv_key
|
||||
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
|
||||
depends_on:
|
||||
- update-components-cache
|
||||
|
||||
commands:
|
||||
- . .drone/update-rpm-repo.sh
|
||||
|
||||
###
|
||||
### Updates the pip package upon new releases
|
||||
###
|
||||
|
||||
- name: update-pip-package
|
||||
image: alpine
|
||||
environment:
|
||||
TWINE_USERNAME:
|
||||
from_secret: pypi_user
|
||||
TWINE_PASSWORD:
|
||||
from_secret: pypi_pass
|
||||
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
|
||||
depends_on:
|
||||
- tests
|
||||
- docs
|
||||
|
||||
commands:
|
||||
- . .drone/update-pip-package.sh
|
||||
|
||||
###
|
||||
### Checkpoint step that waits for all the package update
|
||||
### steps to complete before proceeding to the next steps.
|
||||
###
|
||||
|
||||
- name: wait-pkg-update
|
||||
image: alpine
|
||||
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
|
||||
depends_on:
|
||||
- update-arch-packages
|
||||
- update-rpm-repo
|
||||
- update-apt-repo
|
||||
|
||||
commands:
|
||||
- echo "All packages have been successfully updated"
|
||||
|
||||
###
|
||||
### Notifies about a new release
|
||||
###
|
||||
|
||||
- name: notify-release
|
||||
image: python:3.11-alpine
|
||||
environment:
|
||||
WORKER_RPC_SECRET:
|
||||
from_secret: worker_rpc_secret
|
||||
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
|
||||
depends_on:
|
||||
- update-pip-package
|
||||
|
||||
commands:
|
||||
- apk add --update --no-cache curl
|
||||
- |
|
||||
curl --silent -XPOST \
|
||||
-H "X-Token: $WORKER_RPC_SECRET" \
|
||||
"https://worker.ci-cd.platypush.tech/hook/notify-platypush-release?version=$(python setup.py --version)"
|
||||
|
||||
###
|
||||
### Notifies about a change in the CI/CD build status
|
||||
###
|
||||
|
||||
- name: notify-build-status
|
||||
image: alpine
|
||||
environment:
|
||||
WORKER_RPC_SECRET:
|
||||
from_secret: worker_rpc_secret
|
||||
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
status:
|
||||
- success
|
||||
- failure
|
||||
|
||||
depends_on:
|
||||
- wait-pkg-update
|
||||
|
||||
commands:
|
||||
- apk add --update --no-cache curl
|
||||
- |
|
||||
curl --silent -XPOST \
|
||||
-H "X-Token: $WORKER_RPC_SECRET" \
|
||||
"https://worker.ci-cd.platypush.tech/hook/notify-platypush-build?status=$DRONE_BUILD_STATUS"
|
|
@ -1,46 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
export SRCDIR="$PWD"
|
||||
export WEBAPP_DIR="$SRCDIR/platypush/backend/http/webapp"
|
||||
export SKIPCI="$PWD/.skipci"
|
||||
rm -rf "$SKIPCI"
|
||||
|
||||
. .drone/macros/configure-git.sh
|
||||
|
||||
cd "$WEBAPP_DIR"
|
||||
if [ $(git log --pretty=oneline $DRONE_COMMIT_AFTER...$DRONE_COMMIT_BEFORE . | wc -l) -eq 0 ]; then
|
||||
echo "No UI changes detected, skipping build"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
if [ "$(git log --pretty=format:%s HEAD...HEAD~1 | head -1)" == "[Automatic] Updated UI files" ]; then
|
||||
echo "UI changes have already been committed, skipping build"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
rm -rf dist node_modules
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
if [ $(git status --porcelain dist | wc -l) -eq 0 ]; then
|
||||
echo "No build files have been changed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create a .skipci file to mark the fact that the next steps should be skipped
|
||||
# (we're going to do another push anyway, so another pipeline will be triggered)
|
||||
touch "$SKIPCI"
|
||||
cd "$SRCDIR"
|
||||
|
||||
. .drone/macros/configure-ssh.sh
|
||||
. .drone/macros/configure-gpg.sh
|
||||
|
||||
git add "${WEBAPP_DIR}/dist"
|
||||
git commit "${WEBAPP_DIR}/dist" -S -m "[Automatic] Updated UI files" --no-verify
|
||||
git remote rm origin
|
||||
git remote add origin git@git.platypush.tech:platypush/platypush.git
|
||||
git push -f origin master
|
||||
|
||||
# Restore the original git configuration
|
||||
mv "$TMP_GIT_CONF" "$GIT_CONF"
|
|
@ -1,13 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
. .drone/macros/configure-git.sh
|
||||
. .drone/macros/configure-ssh.sh
|
||||
|
||||
ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null
|
||||
|
||||
# Clone the repository
|
||||
git remote add github git@github.com:/BlackLight/platypush.git
|
||||
git pull --rebase github "$(git branch | head -1 | awk '{print $2}')" || echo "No such branch on Github"
|
||||
|
||||
# Push the changes to the GitHub mirror
|
||||
git push --all -v github
|
|
@ -1,29 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Install git
|
||||
if [ -z "$(which git)" ]; then
|
||||
if [ -n "$(which apt-get)" ]; then
|
||||
apt-get update
|
||||
apt-get install -y git
|
||||
elif [ -n "$(which apk)" ]; then
|
||||
apk add --update --no-cache git
|
||||
elif [ -n "$(which yum)" ]; then
|
||||
yum install -y git
|
||||
elif [ -n "$(which dnf)" ]; then
|
||||
dnf install -y git
|
||||
elif [ -n "$(which pacman)" ]; then
|
||||
pacman -Sy --noconfirm git
|
||||
else
|
||||
echo "Could not find a package manager to install git"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Backup the original git configuration before changing attributes
|
||||
export GIT_CONF="$PWD/.git/config"
|
||||
export TMP_GIT_CONF=/tmp/git.config.orig
|
||||
cp "$GIT_CONF" "$TMP_GIT_CONF"
|
||||
|
||||
git config --global --add safe.directory "$PWD"
|
||||
git config user.name "Platypush CI/CD Automation"
|
||||
git config user.email "admin@platypush.tech"
|
|
@ -1,30 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
[ -z "$PGP_KEY" ] && echo "PGP_KEY is not set" && exit 1
|
||||
[ -z "$PGP_KEY_ID" ] && echo "PGP_KEY_ID is not set" && exit 1
|
||||
|
||||
# Install gpg
|
||||
if [ -z "$(which gpg)" ]; then
|
||||
if [ -n "$(which apt-get)" ]; then
|
||||
apt-get update
|
||||
apt-get install -y gnupg
|
||||
elif [ -n "$(which apk)" ]; then
|
||||
apk add --update --no-cache bash gnupg
|
||||
elif [ -n "$(which yum)" ]; then
|
||||
yum install -y gnupg
|
||||
elif [ -n "$(which dnf)" ]; then
|
||||
dnf install -y gnupg
|
||||
elif [ -n "$(which pacman)" ]; then
|
||||
pacman -Sy --noconfirm gnupg
|
||||
else
|
||||
echo "Could not find a package manager to install gnupg"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
cat <<EOF | gpg --import --armor
|
||||
$PGP_KEY
|
||||
EOF
|
||||
|
||||
git config commit.gpgsign true
|
||||
git config user.signingkey "$PGP_KEY_ID"
|
|
@ -1,35 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ -z "$SSH_PUBKEY" ] || [ -z "$SSH_PRIVKEY" ]; then
|
||||
echo "SSH_PUBKEY and SSH_PRIVKEY environment variables must be set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install ssh
|
||||
if [ -z "$(which ssh)" ]; then
|
||||
if [ -n "$(which apt-get)" ]; then
|
||||
apt-get update
|
||||
apt-get install -y openssh
|
||||
elif [ -n "$(which apk)" ]; then
|
||||
apk add --update --no-cache openssh
|
||||
elif [ -n "$(which yum)" ]; then
|
||||
yum install -y openssh
|
||||
elif [ -n "$(which dnf)" ]; then
|
||||
dnf install -y openssh
|
||||
elif [ -n "$(which pacman)" ]; then
|
||||
pacman -Sy --noconfirm openssh
|
||||
else
|
||||
echo "Could not find a package manager to install openssh"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p ~/.ssh
|
||||
echo $SSH_PUBKEY > ~/.ssh/id_rsa.pub
|
||||
|
||||
cat <<EOF > ~/.ssh/id_rsa
|
||||
$SSH_PRIVKEY
|
||||
EOF
|
||||
|
||||
chmod 0600 ~/.ssh/id_rsa
|
||||
ssh-keyscan git.platypush.tech >> ~/.ssh/known_hosts 2>/dev/null
|
|
@ -1,27 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
echo "Installing required build dependencies"
|
||||
apk add --update --no-cache git make py3-sphinx py3-myst-parser py3-pip $(cat platypush/install/requirements/alpine.txt)
|
||||
pip install -U sphinx-rtd-theme sphinx-book-theme --break-system-packages
|
||||
pip install . --break-system-packages
|
||||
mkdir -p /docs/current
|
||||
export APPDIR="$PWD"
|
||||
rm -rf "$APPDIR/docs/build"
|
||||
|
||||
echo "Building the updated documentation"
|
||||
cd "$APPDIR/docs/source"
|
||||
git clone 'https://git.platypush.tech/platypush/platypush.wiki.git' wiki
|
||||
|
||||
echo "Linking the wiki to the Sphinx index"
|
||||
cd wiki
|
||||
cd "$APPDIR/docs"
|
||||
make html
|
||||
rm -f config*.yaml
|
||||
cd "$APPDIR"
|
||||
|
||||
echo "Copying the new documentation files to the target folder"
|
||||
mv -v "$APPDIR/docs/build" /docs/new
|
||||
cd /docs
|
||||
mv current old
|
||||
mv new current
|
||||
rm -rf old
|
|
@ -1,6 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
apk add --update --no-cache $(cat platypush/install/requirements/alpine.txt)
|
||||
pip install . --break-system-packages
|
||||
pip install -r requirements-tests.txt --break-system-packages
|
||||
pytest tests
|
|
@ -1,169 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
[ -f .skipci ] && exit 0
|
||||
|
||||
echo "-- Installing dependencies"
|
||||
apt update
|
||||
apt install -y dpkg-dev gpg
|
||||
|
||||
echo "-- Creating a new apt root folder"
|
||||
export TMP_APT_ROOT="/tmp/apt"
|
||||
cp -r "$APT_ROOT" "$TMP_APT_ROOT"
|
||||
|
||||
echo "-- Cleaning up older apt releases"
|
||||
|
||||
find "$TMP_APT_ROOT/pool" -mindepth 2 -maxdepth 2 -type d | while read reldir; do
|
||||
pkg_to_remove=$(( $(ls "$reldir"/*.deb | wc -l) - 1 ))
|
||||
[ $pkg_to_remove -le 0 ] && continue
|
||||
ls "$reldir"/*.deb | sort -V | head -n$pkg_to_remove | xargs rm -f
|
||||
done
|
||||
|
||||
echo "-- Updating Packages files"
|
||||
|
||||
echo "stable\noldstable\nubuntu" | while read distro; do
|
||||
echo "main\ndev" | while read branch; do
|
||||
branch_dir="$TMP_APT_ROOT/pool/$distro/$branch"
|
||||
echo "Checking pool folder: $branch_dir"
|
||||
[ -d "$branch_dir" ] || mkdir -p "$branch_dir"
|
||||
dist_dir="$TMP_APT_ROOT/dists/$distro/$branch/all"
|
||||
mkdir -p "$dist_dir"
|
||||
pkg_file="$dist_dir/Packages"
|
||||
dpkg-scanpackages --arch all "$branch_dir" > "$pkg_file"
|
||||
sed -i "$pkg_file" -re "s|^Filename: $TMP_APT_ROOT/|Filename: |"
|
||||
cat "$pkg_file" | gzip -9 > "$pkg_file.gz"
|
||||
echo "Generated Packages file: $pkg_file"
|
||||
cat "$pkg_file"
|
||||
done
|
||||
done
|
||||
|
||||
echo "-- Updating Release files"
|
||||
|
||||
add_hashes() {
|
||||
dist_dir=$1
|
||||
hash_cmd=$2
|
||||
hash_label=$3
|
||||
|
||||
echo "$hash_label:"
|
||||
find "$dist_dir" -name 'Packages*' | while read file; do
|
||||
basename="$(echo "$file" | sed -r -e "s|^$dist_dir/||")"
|
||||
hash="$($hash_cmd "$file" | cut -d" " -f1)"
|
||||
size="$(wc -c < $file)"
|
||||
echo " $hash $size $basename"
|
||||
echo " $hash $size $(echo $basename | sed -re 's|/all/|/binary-i386/|')"
|
||||
echo " $hash $size $(echo $basename | sed -re 's|/all/|/binary-amd64/|')"
|
||||
echo " $hash $size $(echo $basename | sed -re 's|/all/|/binary-armel/|')"
|
||||
echo " $hash $size $(echo $basename | sed -re 's|/all/|/binary-armhf/|')"
|
||||
echo " $hash $size $(echo $basename | sed -re 's|/all/|/binary-arm64/|')"
|
||||
done
|
||||
}
|
||||
|
||||
echo "stable\noldstable\nubuntu" | while read distro; do
|
||||
dist_dir="$TMP_APT_ROOT/dists/$distro"
|
||||
components=$(find "$dist_dir" -name Packages | awk -F '/' '{print $(NF-2)}' | uniq | tr '\n' ' ')
|
||||
release_file="$dist_dir/Release"
|
||||
|
||||
cat <<EOF > "$release_file"
|
||||
Origin: Platypush repository
|
||||
Label: Platypush
|
||||
Suite: $distro
|
||||
Codename: $distro
|
||||
Architectures: i386 amd64 armel armhf arm64
|
||||
Components: $components
|
||||
Description: The official APT repository for Platypush
|
||||
Date: $(date -Ru)
|
||||
EOF
|
||||
|
||||
add_hashes "$dist_dir" "md5sum" "MD5Sum" >> "$release_file"
|
||||
add_hashes "$dist_dir" "sha1sum" "SHA1" >> "$release_file"
|
||||
add_hashes "$dist_dir" "sha256sum" "SHA256" >> "$release_file"
|
||||
done
|
||||
|
||||
echo "-- Generating list files"
|
||||
mkdir -p "$TMP_APT_ROOT/lists"
|
||||
|
||||
for distro in stable oldstable ubuntu; do
|
||||
for branch in main dev; do
|
||||
echo "deb https://apt.platypush.tech/ $distro $branch" > "$TMP_APT_ROOT/lists/platypush-$distro-$branch.list"
|
||||
done
|
||||
done
|
||||
|
||||
echo "-- Updating index file"
|
||||
|
||||
cat <<EOF > "$TMP_APT_ROOT/index.txt"
|
||||
Welcome to the Platypush APT repository!
|
||||
|
||||
Project homepage: https://platypush.tech
|
||||
Source code: https://git.platypush.tech/platypush/platypush
|
||||
Documentation / API reference: https://docs.platypush.tech
|
||||
|
||||
You can use this APT repository to install Platypush on Debian, Ubuntu or any
|
||||
Debian-based distro.
|
||||
|
||||
Steps:
|
||||
|
||||
1. Add this repository's PGP key to your apt keyring
|
||||
====================================================
|
||||
|
||||
# wget -q -O \\\
|
||||
/etc/apt/trusted.gpg.d/platypush.asc \\\
|
||||
https://apt.platypush.tech/pubkey.txt
|
||||
|
||||
2. Add the repository to your sources
|
||||
=====================================
|
||||
|
||||
# wget -q -O \\\
|
||||
/etc/apt/sources.list.d/platypush.list \\\
|
||||
https://apt.platypush.tech/lists/platypush-<deb_version>-<branch>.list
|
||||
|
||||
Where:
|
||||
|
||||
- deb_version can be:
|
||||
- *stable* - current Debian stable version
|
||||
- *oldstable* - previous Debian stable version
|
||||
- *ubuntu* - latest Ubuntu version
|
||||
|
||||
- branch can be either:
|
||||
- *main* - latest stable release
|
||||
- *dev* a package always in sync with the git version
|
||||
|
||||
For example, to install the latest stable tags on Debian stable:
|
||||
|
||||
# wget -q -O \\\
|
||||
/etc/apt/sources.list.d/platypush.list \\\
|
||||
https://apt.platypush.tech/lists/platypush-stable-main.list
|
||||
|
||||
3. Update your repos
|
||||
====================
|
||||
|
||||
# apt update
|
||||
|
||||
4. Install Platypush
|
||||
====================
|
||||
|
||||
# apt install platypush
|
||||
EOF
|
||||
|
||||
echo "-- Importing and refreshing PGP key"
|
||||
echo "$PGP_PUBKEY" > "$TMP_APT_ROOT/pubkey.txt"
|
||||
export PGP_KEYID=$(echo "$PGP_PUBKEY" | gpg --with-colons --import-options show-only --import --fingerprint | grep -e '^fpr:' | head -1 | awk -F ':' '{print $(NF - 1)}')
|
||||
|
||||
cat <<EOF | gpg --import --armor
|
||||
$PGP_PRIVKEY
|
||||
EOF
|
||||
|
||||
echo "-- Signing Release files"
|
||||
|
||||
find "$TMP_APT_ROOT/dists" -type f -name Release | while read file; do
|
||||
dirname="$(dirname "$file")"
|
||||
cat "$file" | gpg -q --default-key "$PGP_KEYID" -abs > "$file.gpg"
|
||||
cat "$file" | gpg -q --default-key "$PGP_KEYID" -abs --clearsign > "$dirname/InRelease"
|
||||
done
|
||||
|
||||
echo "-- Updating the apt repo root"
|
||||
export OLD_APT_ROOT="$REPOS_ROOT/oldapt"
|
||||
rm -rf "$OLD_APT_ROOT"
|
||||
mv "$APT_ROOT" "$OLD_APT_ROOT"
|
||||
mv "$TMP_APT_ROOT" "$APT_ROOT"
|
||||
|
||||
chmod -R a+r "$APT_ROOT"
|
||||
chmod a+x "$APT_ROOT"
|
|
@ -1,67 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
[ -f .skipci ] && exit 0
|
||||
|
||||
apk add --update --no-cache curl pacman sudo
|
||||
|
||||
. .drone/macros/configure-ssh.sh
|
||||
. .drone/macros/configure-git.sh
|
||||
|
||||
git pull --rebase origin master --tags
|
||||
|
||||
export VERSION=$(python setup.py --version)
|
||||
export HEAD=$(git log --pretty=format:%h HEAD...HEAD~1 | head -1)
|
||||
export GIT_VERSION="$VERSION.r$(git log --pretty=oneline HEAD...v$VERSION | wc -l).g${HEAD}"
|
||||
export TAG_URL="https://git.platypush.tech/platypush/platypush/archive/v$VERSION.tar.gz"
|
||||
|
||||
ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts 2>/dev/null
|
||||
adduser -u 1000 -D build
|
||||
mkdir -p "$WORKDIR"
|
||||
|
||||
echo "--- Updating Arch git version"
|
||||
export PKGDIR=$WORKDIR/git
|
||||
git clone ssh://aur@aur.archlinux.org/platypush-git.git "$PKGDIR"
|
||||
git config --global --add safe.directory "$PKGDIR"
|
||||
chown -R build "$PKGDIR"
|
||||
cd "$PKGDIR"
|
||||
|
||||
sed -i 'PKGBUILD' -r \
|
||||
-e "s/^pkgver=.*/pkgver=$GIT_VERSION/" \
|
||||
-e "s/^pkgrel=.*/pkgrel=1/" \
|
||||
|
||||
sudo -u build makepkg --printsrcinfo > .SRCINFO
|
||||
export FILES_CHANGED=$(git status --porcelain --untracked-files=no | wc -l)
|
||||
|
||||
if [ $FILES_CHANGED -gt 0 ]; then
|
||||
echo "--- Pushing git package version $GIT_VERSION"
|
||||
git commit -a -m '[Automatic] Package update'
|
||||
git push origin master
|
||||
fi
|
||||
|
||||
echo "--- Updating Arch stable version"
|
||||
export PKGDIR="$WORKDIR/stable"
|
||||
git clone ssh://aur@aur.archlinux.org/platypush.git "$PKGDIR"
|
||||
git config --global --add safe.directory "$PKGDIR"
|
||||
chown -R build "$PKGDIR"
|
||||
cd "$PKGDIR"
|
||||
export RELEASED_VERSION=$(grep -e '^pkgver=' PKGBUILD | sed -r -e 's/^pkgver=(.*)\s*/\1/')
|
||||
|
||||
if [ "$RELEASED_VERSION" == "$VERSION" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
export TAG_CHECKSUM=$(curl --silent "$TAG_URL" | sha512sum | awk '{print $1}')
|
||||
|
||||
sed -i 'PKGBUILD' -r \
|
||||
-e "s/^pkgver=.*/pkgver=$VERSION/" \
|
||||
-e "s/^pkgrel=.*/pkgrel=1/" \
|
||||
-e "s/^sha512sums=.*/sha512sums=('$TAG_CHECKSUM')/"
|
||||
|
||||
sudo -u build makepkg --printsrcinfo > .SRCINFO
|
||||
export FILES_CHANGED=$(git status --porcelain --untracked-files=no | wc -l)
|
||||
|
||||
if [ $FILES_CHANGED -gt 0 ]; then
|
||||
echo "--- Pushing stable package version $VERSION"
|
||||
git commit -a -m '[Automatic] Package update'
|
||||
git push origin master
|
||||
fi
|
|
@ -1,46 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
export SKIPCI="$PWD/.skipci"
|
||||
export CACHEFILE="$PWD/platypush/components.json.gz"
|
||||
|
||||
[ -f "$SKIPCI" ] && exit 0
|
||||
|
||||
# Backup the original git configuration before changing attributes
|
||||
export GIT_CONF="$PWD/.git/config"
|
||||
export TMP_GIT_CONF="/tmp/git.config.orig"
|
||||
cp "$GIT_CONF" "$TMP_GIT_CONF"
|
||||
|
||||
. .drone/macros/configure-git.sh
|
||||
|
||||
# Only regenerate the components cache if either the plugins, backends,
|
||||
# events or schemas folders have some changes (excluding the webapp files).
|
||||
if [ -z "$(git log --pretty=oneline $DRONE_COMMIT_AFTER...$DRONE_COMMIT_BEFORE -- platypush/backend platypush/plugins platypush/schemas platypush/message/event ':(exclude)platypush/backend/http/webapp')" ]; then
|
||||
echo 'No changes to the components file'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
. .drone/macros/configure-ssh.sh
|
||||
. .drone/macros/configure-gpg.sh
|
||||
|
||||
echo 'Updating components cache'
|
||||
apk add --update --no-cache $(cat platypush/install/requirements/alpine.txt)
|
||||
pip install . --break-system-packages
|
||||
|
||||
python - <<EOF
|
||||
from platypush import get_plugin
|
||||
|
||||
get_plugin('inspect').refresh_cache(force=True)
|
||||
EOF
|
||||
|
||||
# Create a .skipci file to mark the fact that the next steps should be skipped
|
||||
# (we're going to do another push anyway, so another pipeline will be triggered)
|
||||
touch "$SKIPCI"
|
||||
|
||||
git add "$CACHEFILE"
|
||||
git commit "$CACHEFILE" -S -m "[Automatic] Updated components cache" --no-verify
|
||||
git remote rm origin
|
||||
git remote add origin git@git.platypush.tech:platypush/platypush.git
|
||||
git push -f origin master
|
||||
|
||||
# Restore the original git configuration
|
||||
mv "$TMP_GIT_CONF" "$GIT_CONF"
|
|
@ -1,103 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
[ -f .skipci ] && exit 0
|
||||
|
||||
echo "-- Copying source directory"
|
||||
mkdir -p "$WORKDIR/src"
|
||||
export SRCDIR="$WORKDIR/src/$DEB_VERSION"
|
||||
cp -r "$PWD" "$SRCDIR"
|
||||
cd "$SRCDIR"
|
||||
|
||||
echo "-- Installing dependencies"
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt update
|
||||
apt install -y curl dpkg-dev gpg git python3 python3-pip python3-setuptools
|
||||
|
||||
echo "--- Parsing metadata"
|
||||
git config --global --add safe.directory "$PWD"
|
||||
git pull --rebase origin master --tags
|
||||
export VERSION=$(python3 setup.py --version)
|
||||
export GIT_VERSION="$VERSION-$(git log --pretty=oneline HEAD...v$VERSION | wc -l)"
|
||||
export GIT_BUILD_DIR="$WORKDIR/${PKG_NAME}_${GIT_VERSION}_all"
|
||||
export GIT_DEB="$WORKDIR/${PKG_NAME}_${GIT_VERSION}_all.deb"
|
||||
export POOL_PATH="$APT_ROOT/pool/$DEB_VERSION/dev"
|
||||
|
||||
echo "--- Building git package"
|
||||
pip install --prefix="$GIT_BUILD_DIR/usr" --no-cache --no-deps .
|
||||
|
||||
find "$GIT_BUILD_DIR" -name "site-packages" | while read dir; do
|
||||
base="$(dirname "$dir")"
|
||||
mv "$dir" "$base/dist-packages"
|
||||
done
|
||||
|
||||
install -m755 -d "${GIT_BUILD_DIR}/usr/lib/systemd/system"
|
||||
install -m755 -d "${GIT_BUILD_DIR}/usr/lib/systemd/user"
|
||||
install -m750 -d "${GIT_BUILD_DIR}/var/lib/platypush"
|
||||
install -m750 -d "${GIT_BUILD_DIR}/etc/platypush/scripts"
|
||||
|
||||
install -m644 "${SRCDIR}/platypush/config/config.yaml" "${GIT_BUILD_DIR}/etc/platypush/config.yaml"
|
||||
install -m644 "${SRCDIR}/platypush/config/systemd/platypush.service" "${GIT_BUILD_DIR}/usr/lib/systemd/user/platypush.service"
|
||||
install -m644 "${SRCDIR}/platypush/config/systemd/platypush.service" "${GIT_BUILD_DIR}/usr/lib/systemd/system/platypush.service"
|
||||
sed -i "${GIT_BUILD_DIR}/usr/lib/systemd/system/platypush.service" -r \
|
||||
-e 's/^#\s*Requires=(.*)/Requires=\1/' \
|
||||
-e 's/^\[Service\]$/\[Service\]\
|
||||
User=platypush\
|
||||
Group=platypush\
|
||||
WorkingDirectory=\/var\/lib\/platypush\
|
||||
Environment="PLATYPUSH_CONFIG=\/etc\/platypush\/config.yaml"\
|
||||
Environment="PLATYPUSH_WORKDIR=\/var\/lib\/platypush"/'
|
||||
|
||||
mkdir -p "$GIT_BUILD_DIR/DEBIAN"
|
||||
|
||||
cat <<EOF > "$GIT_BUILD_DIR/DEBIAN/control"
|
||||
Package: $PKG_NAME
|
||||
Version: $GIT_VERSION
|
||||
Maintainer: Fabio Manganiello <fabio@platypush.tech>
|
||||
Depends: $(cat platypush/install/requirements/debian.txt | tr '\n' ',' | sed -re 's/,$//' -e 's/,/, /g')
|
||||
Architecture: all
|
||||
Homepage: https://platypush.tech
|
||||
Description: Universal command executor and automation hub.
|
||||
EOF
|
||||
|
||||
cat <<EOF > "$GIT_BUILD_DIR/DEBIAN/postinst" && chmod +x "$GIT_BUILD_DIR/DEBIAN/postinst"
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
if [ "\$1" = "configure" ]; then
|
||||
grep -e '^platypush:' /etc/passwd 2>/dev/null || useradd -U -r -s /bin/false -d /var/lib/platypush platypush
|
||||
mkdir -p /var/lib/platypush
|
||||
chown -R platypush:platypush /var/lib/platypush
|
||||
chown -R platypush:platypush /etc/platypush
|
||||
if which systemctl; then systemctl daemon-reload; fi
|
||||
fi
|
||||
EOF
|
||||
|
||||
mkdir -p "$POOL_PATH"
|
||||
rm -f "$POOL_PATH/"*.deb
|
||||
dpkg --build "$GIT_BUILD_DIR"
|
||||
|
||||
echo "--- Copying $GIT_DEB to $POOL_PATH"
|
||||
cp "$GIT_DEB" "$POOL_PATH"
|
||||
|
||||
# If main/all/Packages doesn't exist, then we should create the first main release
|
||||
[ $(ls "$APT_ROOT/pool/$DEB_VERSION/main/${PKG_NAME}_${VERSION}-"*"_all.deb" 2>/dev/null | wc -l) -eq 0 ] && export UPDATE_STABLE_PKG=1
|
||||
|
||||
export PKGURL="https://apt.platypush.tech/dists/$DEB_VERSION/main/all/Packages"
|
||||
|
||||
[ -z "$UPDATE_STABLE_PKG" ] &&
|
||||
curl -ILs -o /dev/null -w "%{http_code}" "$PKGURL" |
|
||||
grep -e '^4' >/dev/null && export UPDATE_STABLE_PKG=1
|
||||
|
||||
# If the published release version differs from the current one, then we should publish a new main release
|
||||
if [ -z "$UPDATE_STABLE_PKG" ]; then
|
||||
RELEASED_VERSION=$(curl -s "$PKGURL" | grep -e '^Version: ' | head -1 | awk '{print $2}' | cut -d- -f 1)
|
||||
[ "$RELEASED_VERSION" != "$VERSION" ] && export UPDATE_STABLE_PKG=1
|
||||
fi
|
||||
|
||||
# Proceed and update the main release if the version number has changed
|
||||
if [ -n "$UPDATE_STABLE_PKG" ]; then
|
||||
echo "--- Updating main package"
|
||||
mkdir -p "$APT_ROOT/pool/$DEB_VERSION/main"
|
||||
cp "$GIT_DEB" "$APT_ROOT/pool/$DEB_VERSION/main/${PKG_NAME}_${VERSION}-1_all.deb"
|
||||
fi
|
|
@ -1,5 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
apk add --update --no-cache py3-twine py3-setuptools py3-wheel py3-pip
|
||||
python setup.py sdist bdist_wheel
|
||||
twine upload dist/platypush-$(python setup.py --version).tar.gz
|
|
@ -1,261 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
[ -f .skipci ] && exit 0
|
||||
|
||||
echo "-- Installing dependencies"
|
||||
yum install -y \
|
||||
createrepo \
|
||||
git \
|
||||
gpg \
|
||||
python \
|
||||
python-pip \
|
||||
python-setuptools \
|
||||
rpm-build \
|
||||
rpm-sign \
|
||||
systemd-rpm-macros \
|
||||
wget \
|
||||
yum-utils \
|
||||
|
||||
echo "-- Copying source directory"
|
||||
mkdir -p "$WORKDIR"
|
||||
export SRCDIR="$WORKDIR/src"
|
||||
cp -r "$PWD" "$SRCDIR"
|
||||
cd "$SRCDIR"
|
||||
mkdir -p "$RPM_ROOT"
|
||||
|
||||
echo "--- Parsing metadata"
|
||||
git config --global --add safe.directory $PWD
|
||||
git pull --rebase origin master --tags
|
||||
export VERSION=$(python3 setup.py --version)
|
||||
export RELNUM="$(git log --pretty=oneline HEAD...v$VERSION | wc -l)"
|
||||
export SPECFILE="$WORKDIR/$PKG_NAME.spec"
|
||||
export BUILD_DIR="$WORKDIR/build"
|
||||
export TMP_RPM_ROOT="$WORKDIR/repo"
|
||||
export SRC_URL="https://git.platypush.tech/platypush/platypush/archive/master.tar.gz"
|
||||
|
||||
echo "--- Creating git package spec"
|
||||
|
||||
cat <<EOF > $SPECFILE
|
||||
Summary: Universal command executor and automation hub.
|
||||
Name: $PKG_NAME-git
|
||||
Version: $VERSION
|
||||
Release: $RELNUM
|
||||
URL: https://platypush.tech
|
||||
Group: System
|
||||
License: MIT
|
||||
Packager: Fabio Manganiello <fabio@platypush.tech>
|
||||
Source: $SRC_URL
|
||||
Requires: $(cat platypush/install/requirements/fedora.txt | tr '\n' ' ')
|
||||
Conflicts: $PKG_NAME
|
||||
Prefix: %{_prefix}
|
||||
BuildRoot: %{_tmppath}/%{name}-root
|
||||
BuildRequires: systemd-rpm-macros
|
||||
%{?sysusers_requires_compat}
|
||||
|
||||
%description
|
||||
Universal command executor and automation hub.
|
||||
|
||||
%install
|
||||
mkdir -p %{buildroot}/
|
||||
cp -r "$BUILD_DIR"/* %{buildroot}/
|
||||
install -p -Dm0644 "${BUILD_DIR}/usr/lib/sysusers.d/platypush.conf" %{buildroot}%{_sysusersdir}/platypush.conf
|
||||
|
||||
%pre
|
||||
%sysusers_create_compat "${BUILD_DIR}/usr/lib/sysusers.d/platypush.conf"
|
||||
|
||||
%clean
|
||||
|
||||
%files
|
||||
%defattr(750,platypush,platypush,750)
|
||||
%dir /etc/platypush
|
||||
/etc/platypush/*
|
||||
/usr/bin/*
|
||||
/usr/lib/python$(python3 --version | awk '{print $2}' | cut -d. -f 1,2)/site-packages/platypush
|
||||
/usr/lib/python$(python3 --version | awk '{print $2}' | cut -d. -f 1,2)/site-packages/platypush-$VERSION.dist-info
|
||||
/usr/lib/systemd/system/*
|
||||
/usr/lib/systemd/user/*
|
||||
%defattr(750,platypush,platypush,750)
|
||||
%dir /var/lib/platypush
|
||||
%{_sysusersdir}/platypush.conf
|
||||
|
||||
%changelog
|
||||
* $(date +'%a %b %d %Y') admin <admin@platypush.tech>
|
||||
- [Automatic] Release $VERSION-$RELNUM
|
||||
EOF
|
||||
|
||||
echo "--- Building git package"
|
||||
mkdir -p "$BUILD_DIR"
|
||||
|
||||
pip install --prefix="$BUILD_DIR/usr" --no-cache --no-deps .
|
||||
|
||||
install -m755 -d "${BUILD_DIR}/usr/lib/systemd/system"
|
||||
install -m755 -d "${BUILD_DIR}/usr/lib/systemd/user"
|
||||
install -m755 -d "${BUILD_DIR}/usr/lib/sysusers.d"
|
||||
install -m750 -d "${BUILD_DIR}/var/lib/platypush"
|
||||
install -m750 -d "${BUILD_DIR}/etc/platypush/scripts"
|
||||
|
||||
install -m644 "${SRCDIR}/platypush/config/config.yaml" "${BUILD_DIR}/etc/platypush/config.yaml"
|
||||
install -Dm644 "${SRCDIR}/platypush/config/systemd/platypush-sysusers.conf" "${BUILD_DIR}/usr/lib/sysusers.d/platypush.conf"
|
||||
install -m644 "${SRCDIR}/platypush/config/systemd/platypush.service" "${BUILD_DIR}/usr/lib/systemd/user/platypush.service"
|
||||
install -m644 "${SRCDIR}/platypush/config/systemd/platypush.service" "${BUILD_DIR}/usr/lib/systemd/system/platypush.service"
|
||||
sed -i "${BUILD_DIR}/usr/lib/systemd/system/platypush.service" -r \
|
||||
-e 's/^#\s*Requires=(.*)/Requires=\1/' \
|
||||
-e 's/^\[Service\]$/\[Service\]\
|
||||
User=platypush\
|
||||
Group=platypush\
|
||||
WorkingDirectory=\/var\/lib\/platypush\
|
||||
Environment="PLATYPUSH_CONFIG=\/etc\/platypush\/config.yaml"\
|
||||
Environment="PLATYPUSH_WORKDIR=\/var\/lib\/platypush"/'
|
||||
|
||||
rpmbuild --target "noarch" -bb "$SPECFILE"
|
||||
|
||||
echo "--- Copying the new RPM package"
|
||||
mkdir -p "$TMP_RPM_ROOT"
|
||||
cp "$HOME/rpmbuild/RPMS/noarch/$PKG_NAME-git-$VERSION-$RELNUM.noarch.rpm" "$TMP_RPM_ROOT"
|
||||
|
||||
echo "--- Checking the latest released stable version"
|
||||
export LATEST_STABLE_PKG=$(ls -rt "$RPM_ROOT/$PKG_NAME"*.rpm 2>/dev/null | grep -v "$PKG_NAME-git" | tail -1)
|
||||
|
||||
if [ -z "$LATEST_STABLE_PKG" ]; then
|
||||
# If not stable release is available, then create one
|
||||
export UPDATE_STABLE_PKG=1
|
||||
else
|
||||
# Otherwise, create a new release if the reported version on the repo is different
|
||||
# from the latest released version.
|
||||
export LATEST_STABLE_VERSION=$(basename $LATEST_STABLE_PKG | cut -d- -f 2)
|
||||
if [ "$VERSION" != "$LATEST_STABLE_VERSION" ]; then
|
||||
export UPDATE_STABLE_PKG=1
|
||||
else
|
||||
# If the version has remained the same, then simply copy the existing RPM to the
|
||||
# new repository directory.
|
||||
echo "Copying the existing release $LATEST_STABLE_VERSION to the new repository"
|
||||
cp "$LATEST_STABLE_PKG" "$TMP_RPM_ROOT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# If a new stable release is required, build another RPM
|
||||
if [ -n "$UPDATE_STABLE_PKG" ]; then
|
||||
export RELNUM=1
|
||||
export SRC_URL="https://git.platypush.tech/platypush/platypush/archive/v$VERSION.tar.gz"
|
||||
|
||||
cat <<EOF > $SPECFILE
|
||||
Summary: Universal command executor and automation hub.
|
||||
Name: $PKG_NAME
|
||||
Version: $VERSION
|
||||
Release: $RELNUM
|
||||
URL: https://platypush.tech
|
||||
Group: System
|
||||
License: MIT
|
||||
Packager: Fabio Manganiello <fabio@platypush.tech>
|
||||
Source: $SRC_URL
|
||||
Requires: $(cat platypush/install/requirements/fedora.txt | tr '\n' ' ')
|
||||
Conflicts: $PKG_NAME-git
|
||||
Prefix: %{_prefix}
|
||||
BuildRoot: %{_tmppath}/%{name}-root
|
||||
BuildRequires: systemd-rpm-macros
|
||||
%{?sysusers_requires_compat}
|
||||
|
||||
%description
|
||||
Universal command executor and automation hub.
|
||||
|
||||
%install
|
||||
mkdir -p %{buildroot}/
|
||||
cp -r "$BUILD_DIR"/* %{buildroot}/
|
||||
install -p -Dm0644 "${BUILD_DIR}/usr/lib/sysusers.d/platypush.conf" %{buildroot}%{_sysusersdir}/platypush.conf
|
||||
|
||||
%pre
|
||||
%sysusers_create_compat "${BUILD_DIR}/usr/lib/sysusers.d/platypush.conf"
|
||||
|
||||
%clean
|
||||
|
||||
%files
|
||||
%defattr(750,platypush,platypush,750)
|
||||
%dir /etc/platypush
|
||||
/etc/platypush/*
|
||||
/usr/bin/*
|
||||
/usr/lib/python$(python3 --version | awk '{print $2}' | cut -d. -f 1,2)/site-packages/platypush
|
||||
/usr/lib/python$(python3 --version | awk '{print $2}' | cut -d. -f 1,2)/site-packages/platypush-$VERSION.dist-info
|
||||
/usr/lib/systemd/system/*
|
||||
/usr/lib/systemd/user/*
|
||||
%defattr(750,platypush,platypush,750)
|
||||
%dir /var/lib/platypush
|
||||
%{_sysusersdir}/platypush.conf
|
||||
|
||||
%changelog
|
||||
* $(date +'%a %b %d %Y') admin <admin@platypush.tech>
|
||||
- [Automatic] Release $VERSION-$RELNUM
|
||||
EOF
|
||||
|
||||
echo "--- Building package for stable release $VERSION"
|
||||
rpmbuild --target "noarch" -bb "$SPECFILE"
|
||||
cp "$HOME/rpmbuild/RPMS/noarch/$PKG_NAME-$VERSION-$RELNUM.noarch.rpm" "$TMP_RPM_ROOT"
|
||||
fi
|
||||
|
||||
echo "--- Importing the repository keys"
|
||||
cat <<EOF | gpg --import --armor
|
||||
$PGP_PRIVKEY
|
||||
EOF
|
||||
|
||||
export PGP_KEYID=$(echo "$PGP_PUBKEY" | gpg --with-colons --import-options show-only --import --fingerprint | grep -e '^fpr:' | head -1 | awk -F ':' '{print $(NF - 1)}')
|
||||
cat <<EOF > $HOME/.rpmmacros
|
||||
%signature gpg
|
||||
%_gpg_name $PGP_KEYID
|
||||
EOF
|
||||
|
||||
echo "--- Signing the new RPM packages"
|
||||
rpm --addsign "$TMP_RPM_ROOT"/*.rpm
|
||||
|
||||
echo "--- Creating a new copy of the RPM repository"
|
||||
createrepo "$TMP_RPM_ROOT"
|
||||
gpg --detach-sign --armor "$TMP_RPM_ROOT/repodata/repomd.xml"
|
||||
|
||||
cat <<EOF > "$TMP_RPM_ROOT/platypush.repo"
|
||||
[platypush]
|
||||
name=Platypush repository
|
||||
baseurl=https://rpm.platypush.tech
|
||||
enabled=1
|
||||
type=rpm
|
||||
gpgcheck=1
|
||||
gpgkey=https://rpm.platypush.tech/pubkey.txt
|
||||
EOF
|
||||
|
||||
cat <<EOF > "$TMP_RPM_ROOT/index.txt"
|
||||
Welcome to the Platypush RPM repository!
|
||||
|
||||
Project homepage: https://platypush.tech
|
||||
Source code: https://git.platypush.tech/platypush/platypush
|
||||
Documentation / API reference: https://docs.platypush.tech
|
||||
|
||||
You can use this RPM repository to install Platypush on Fedora or other
|
||||
RPM-based distros - as long as they are compatible with the latest Fedora
|
||||
release.
|
||||
|
||||
Steps:
|
||||
|
||||
1. Add the repository to your sources
|
||||
=====================================
|
||||
|
||||
# yum config-manager --add-repo https://rpm.platypush.tech/platypush.repo
|
||||
|
||||
2. Install Platypush
|
||||
====================
|
||||
|
||||
# yum install platypush
|
||||
|
||||
Or, if you want to install a version always up-to-date with the git repo:
|
||||
|
||||
# yum install platypush-git
|
||||
EOF
|
||||
|
||||
cat <<EOF > "$TMP_RPM_ROOT/pubkey.txt"
|
||||
$PGP_PUBKEY
|
||||
EOF
|
||||
|
||||
echo "--- Updating the repository"
|
||||
export NEW_RPM_ROOT="$REPOS_ROOT/rpm_new"
|
||||
export OLD_RPM_ROOT="$REPOS_ROOT/rpm_old"
|
||||
cp -r "$TMP_RPM_ROOT" "$NEW_RPM_ROOT"
|
||||
rm -rf "$TMP_RPM_ROOT"
|
||||
mv "$RPM_ROOT" "$OLD_RPM_ROOT"
|
||||
mv "$NEW_RPM_ROOT" "$RPM_ROOT"
|
||||
rm -rf "$OLD_RPM_ROOT"
|
22
.env.example
22
.env.example
|
@ -1,22 +0,0 @@
|
|||
# The device ID is the unique identifier for the device that runs Platypush.
|
||||
# You should make sure that it's unique at least within your local network,
|
||||
# as it is used to identify the device in the MQTT topics, on the HTTP API
|
||||
# and on the published ZeroConf services.
|
||||
PLATYPUSH_DEVICE_ID=platypush
|
||||
|
||||
# Use an external Redis server for the message queue. By default, the Platypush
|
||||
# container will run a Redis server on the same container. Also remove the
|
||||
# `--start-redis` option from the `docker run` command if you want to use an
|
||||
# external Redis server.
|
||||
# PLATYPUSH_REDIS_HOST=localhost
|
||||
# PLATYPUSH_REDIS_PORT=6379
|
||||
|
||||
# Custom location for the Platypush configuration file.
|
||||
# PLATYPUSH_CONFIG=/etc/platypush/config.yaml
|
||||
|
||||
# Custom location for the Platypush working directory.
|
||||
# PLATYPUSH_WORKDIR=/var/lib/platypush
|
||||
|
||||
# SQLAlchemy database URL. By default, the Platypush container will run on a
|
||||
# SQLite database installed under <WORKDIR>/main.db. If you want
|
||||
# PLATYPUSH_DB=sqlite:////var/lib/platypush/main.db
|
|
@ -10,7 +10,7 @@ package.sh
|
|||
platypush/backend/http/static/resources/*
|
||||
docs/build
|
||||
.idea/
|
||||
/config
|
||||
config
|
||||
platypush/backend/http/static/css/*/.sass-cache/
|
||||
.vscode
|
||||
platypush/backend/http/static/js/lib/vue.js
|
||||
|
@ -24,8 +24,3 @@ coverage.xml
|
|||
Session.vim
|
||||
/jsconfig.json
|
||||
/package.json
|
||||
/Dockerfile
|
||||
/docs/source/wiki
|
||||
/.skipci
|
||||
dump.rdb
|
||||
.env
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
sync-to-github:
|
||||
stage: build
|
||||
script:
|
||||
- echo "Synchronizing repo state to Github"
|
||||
- export REPO_DIR="$(mktemp -d /tmp/platypush-XXXXX)"
|
||||
- git clone git@git.platypush.tech:platypush/platypush.git "$REPO_DIR"
|
||||
- cd "$REPO_DIR"
|
||||
- git remote add github git@github.com:/BlackLight/platypush.git
|
||||
- git checkout $CI_COMMIT_BRANCH
|
||||
- git pull
|
||||
- git push --mirror -v github
|
||||
|
||||
run-tests:
|
||||
stage: test
|
||||
script:
|
||||
- ./.gitlab/run_ci_tests.sh
|
||||
|
||||
rebuild-docs:
|
||||
stage: deploy
|
||||
only:
|
||||
- master
|
||||
script:
|
||||
- ./.gitlab/rebuild_docs.sh
|
||||
|
||||
update-aur-packages:
|
||||
stage: deploy
|
||||
only:
|
||||
- master
|
||||
- tags
|
||||
script:
|
||||
- echo "Updating AUR packages"
|
||||
- export REPO_DIR="$(mktemp -d /tmp/platypush-distutils-XXXXX)"
|
||||
- git clone git@fabiomanganiello.com:/home/git/platypush-distutils.git "$REPO_DIR"
|
||||
- cd "$REPO_DIR"
|
||||
- git submodule init
|
||||
- git submodule update
|
||||
- cd distro/arch/git
|
||||
- git checkout master
|
||||
- git pull --rebase
|
||||
- cd ../../../
|
||||
- cd distro/arch/stable
|
||||
- git checkout master
|
||||
- git pull --rebase
|
||||
- cd ../../../
|
||||
- ./update.sh
|
||||
- cd distro/arch/git
|
||||
- changes="$(git status --porcelain --untracked-files=no)"
|
||||
- "[[ -n \"$changes\" ]] && git commit -a -m '[Automatic] Package updated' && git push || echo 'No changes'"
|
||||
- cd ../../../
|
||||
- cd distro/arch/stable
|
||||
- changes="$(git status --porcelain --untracked-files=no)"
|
||||
- "[[ -n \"$changes\" ]] && git commit -a -m '[Automatic] Package updated' && git push || echo 'No changes'"
|
||||
|
||||
upload-pip-package:
|
||||
stage: deploy
|
||||
only:
|
||||
- tags
|
||||
script:
|
||||
# Update the CI/CD configuration
|
||||
- cd ~/platypush-ci-cd
|
||||
- git pull
|
||||
- cd -
|
||||
# Build the package
|
||||
- rm -rf build dist *.egg-info
|
||||
- export VERSION=$(grep -e '^\s*__version__\s*=' platypush/__init__.py | sed -r -e 's/^\s*__version__\s*=\s*.(.+?).\s*$/\1/')
|
||||
- source ~/.credentials/pypi.env
|
||||
- python setup.py sdist bdist_wheel
|
||||
# Upload to PyPI
|
||||
- twine upload --repository platypush ./dist/platypush-${VERSION}.tar.gz
|
||||
# Upload to the local package repository
|
||||
- TWINE_USERNAME=$LOCAL_TWINE_USERNAME TWINE_PASSWORD=$LOCAL_TWINE_PASSWORD twine upload --repository-url https://git.platypush.tech/api/v4/projects/3/packages/pypi dist/platypush-${VERSION}.tar.gz
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#!/bin/bash
|
||||
|
||||
LOGFILE="./docs.log"
|
||||
STATUS_IMG_PATH="./docs-status.svg"
|
||||
|
||||
build_docs() {
|
||||
cd ./docs || exit 1
|
||||
make html 2>&1 | tee "../$LOGFILE"
|
||||
ret=$?
|
||||
cd .. || exit 1
|
||||
return $?
|
||||
}
|
||||
|
||||
########
|
||||
# MAIN #
|
||||
########
|
||||
|
||||
build_docs
|
||||
ret=$?
|
||||
|
||||
log_base_path="$(date +/opt/tests/platypush/logs/docs/%Y-%m-%dT%H:%M:%S.%m)"
|
||||
if [[ $ret == 0 ]]; then
|
||||
wget -O "$STATUS_IMG_PATH" https://ci.platypush.tech/docs/passed.svg
|
||||
cp "$LOGFILE" "${log_base_path}_PASSED.log"
|
||||
else
|
||||
wget -O "$STATUS_IMG_PATH" https://ci.platypush.tech/docs/failed.svg
|
||||
cp "$LOGFILE" "${log_base_path}_FAILED.log"
|
||||
fi
|
||||
|
||||
mv "$STATUS_IMG_PATH" /opt/tests/platypush/logs/docs/
|
||||
mv "$LOGFILE" /opt/tests/platypush/logs/latest.log
|
||||
cp -r docs/build/html /opt/repos/platypush/docs/build/
|
||||
exit $ret
|
|
@ -0,0 +1,60 @@
|
|||
#!/bin/bash
|
||||
|
||||
BASE_DIR="$(mktemp -d '/tmp/platypush-ci-tests-XXXXX')"
|
||||
VENV_DIR="$BASE_DIR/venv"
|
||||
TEST_LOG="./test.log"
|
||||
STATUS_IMG_PATH="./status.svg"
|
||||
|
||||
cleanup() {
|
||||
echo "Cleaning up environment"
|
||||
rm -rf "$BASE_DIR"
|
||||
}
|
||||
|
||||
prepare_venv() {
|
||||
echo "Preparing virtual environment"
|
||||
python -m venv "$VENV_DIR"
|
||||
cd "$VENV_DIR" || exit 1
|
||||
source ./bin/activate
|
||||
cd - || exit 1
|
||||
}
|
||||
|
||||
install_repo() {
|
||||
echo "Installing latest version of the repository"
|
||||
pip install '.[http]'
|
||||
}
|
||||
|
||||
run_tests() {
|
||||
echo "Running tests"
|
||||
pytest 2>&1 | tee "$TEST_LOG"
|
||||
deactivate
|
||||
|
||||
if grep -e '^FAILED ' "$TEST_LOG"; then
|
||||
return 2
|
||||
fi
|
||||
|
||||
return 0 # PASSED
|
||||
}
|
||||
|
||||
########
|
||||
# MAIN #
|
||||
########
|
||||
|
||||
cleanup
|
||||
prepare_venv
|
||||
install_repo
|
||||
run_tests
|
||||
ret=$?
|
||||
cleanup
|
||||
|
||||
log_base_path="$(date +/opt/tests/platypush/logs/%Y-%m-%dT%H:%M:%S.%m)"
|
||||
if [[ $ret == 0 ]]; then
|
||||
wget -O "$STATUS_IMG_PATH" https://ci.platypush.tech/passed.svg
|
||||
cp "$TEST_LOG" "${log_base_path}_PASSED.log"
|
||||
else
|
||||
wget -O "$STATUS_IMG_PATH" https://ci.platypush.tech/failed.svg
|
||||
cp "$TEST_LOG" "${log_base_path}_FAILED.log"
|
||||
fi
|
||||
|
||||
mv "$STATUS_IMG_PATH" /opt/tests/platypush/logs/status.svg
|
||||
mv "$TEST_LOG" /opt/tests/platypush/logs/latest.log
|
||||
exit $ret
|
412
CHANGELOG.md
412
CHANGELOG.md
|
@ -1,424 +1,26 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
Given the high speed of development in the first phase, changes are being
|
||||
reported only starting from v0.20.2.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- [[#281](https://git.platypush.tech/platypush/platypush/issues/281)]
|
||||
replaced `warnings.warn` with `logging.warning`, as there is no easy and
|
||||
reliable way of routing `warnings.warn` to `logging`.
|
||||
|
||||
## [1.1.0] - 2024-06-06
|
||||
|
||||
- [[#405](https://git.platypush.tech/platypush/platypush/issues/405)] Fixed
|
||||
timezone/timestamp rendering issues for `calendar.ical` events.
|
||||
- [[#403]((https://git.platypush.tech/platypush/platypush/issues/403))]
|
||||
Included inherited actions in plugins docs.
|
||||
|
||||
## [1.0.7] - 2024-06-02
|
||||
|
||||
- [[#384]((https://git.platypush.tech/platypush/platypush/issues/384))] Added
|
||||
`assistant.openai` and `tts.openai` plugins.
|
||||
|
||||
## [1.0.6] - 2024-06-01
|
||||
|
||||
- 🐛 Bug fix on one of the entities modules that prevented the application from
|
||||
loading when `.` is part of `PYTHONPATH`.
|
||||
|
||||
## [1.0.5] - 2024-06-01
|
||||
|
||||
- A proper solution for the `utcnow()` issue.
|
||||
|
||||
It was a bit trickier than expected to solve, but now Platypush uses a
|
||||
`utcnow()` facade that always returns a UTC datetime in a timezone-aware
|
||||
representation.
|
||||
|
||||
The code should however also handle the case of timestamps stored on the db in
|
||||
the old format.
|
||||
|
||||
## [1.0.4] - 2024-05-31
|
||||
|
||||
- Fixed regression introduced by
|
||||
[c18768e61fef62924f4c1fac3089ecfb83666dab](https://git.platypush.tech/platypush/platypush/commit/c18768e61fef62924f4c1fac3089ecfb83666dab).
|
||||
Python seems to have introduced a breaking change from the version 3.12 -
|
||||
`datetime.utcnow()` is not deprecated, but `datetime.UTC`, the suggested
|
||||
alternative, isn't available on older versions of Python. Added a workaround
|
||||
that makes Platypush compatible with both the implementations.
|
||||
|
||||
## [1.0.3] - 2024-05-31
|
||||
|
||||
- [[#368](https://git.platypush.tech/platypush/platypush/issues/368)] Added
|
||||
Ubuntu packages.
|
||||
|
||||
- Fixed bug that didn't get hooks to match events imported through the new
|
||||
`platypush.events` symlinked module.
|
||||
|
||||
## [1.0.2] - 2024-05-26
|
||||
|
||||
- Fixed regression introduced by the support of custom names through the
|
||||
`@procedure` decorator.
|
||||
|
||||
## [1.0.0] - 2024-05-26
|
||||
|
||||
Many, many changes for the first major release of Platypush after so many
|
||||
years.
|
||||
|
||||
- [!3](https://git.platypush.tech/platypush/platypush/milestone/3) All
|
||||
backends, except for `http`, `nodered`, `redis` and `tcp`, are gone. Many
|
||||
were already deprecated a while ago, but the change now applies to all of
|
||||
them. Backends should only be components that actively listen for application
|
||||
messages to process, not generic daemon threads for integrations. This had
|
||||
been a source of confusion for a long time. Backends and plugins are now
|
||||
merged, meaning that you won't need to configure two different sections
|
||||
instead of one for many integrations (one for the stateless plugin, and one
|
||||
for the background state listener). Please check the
|
||||
[documentation](https://docs.platypush.tech) to verify the configuration
|
||||
changes required by your integrations. This has been a long process that has
|
||||
involved the rewrite of most of the integrations, and many bugs have been
|
||||
fixed.
|
||||
|
||||
- Improved Docker support - now with a default `docker-compose.yml`, multiple
|
||||
Dockerfiles for
|
||||
[Alpine](https://git.platypush.tech/platypush/platypush/src/branch/master/platypush/install/docker/alpine.Dockerfile),
|
||||
[Debian](https://git.platypush.tech/platypush/platypush/src/branch/master/platypush/install/docker/debian.Dockerfile),
|
||||
[Ubuntu](https://git.platypush.tech/platypush/platypush/src/branch/master/platypush/install/docker/ubuntu.Dockerfile)
|
||||
and
|
||||
[Fedora](https://git.platypush.tech/platypush/platypush/src/branch/master/platypush/install/docker/fedora.Dockerfile)
|
||||
base images. Many improvements on the `platydock` and `platyvenv` scripts
|
||||
too, with better automated installation processes for optional dependencies.
|
||||
|
||||
- Added [official
|
||||
packages](https://git.platypush.tech/platypush/platypush#system-package-manager-installation)
|
||||
for
|
||||
[Debian](https://git.platypush.tech/platypush/platypush#debian-ubuntu)
|
||||
and [Fedora](https://git.platypush.tech/platypush/platypush#fedora).
|
||||
|
||||
- Added `--device-id`, `--workdir`, `--logsdir`, `--cachedir`, `--main-db`,
|
||||
`--redis-host`, `--redis-port` and `--redis-queue` CLI arguments, along the
|
||||
`PLATYPUSH_DEVICE_ID`, `PLATYPUSH_WORKDIR`, `PLATYPUSH_LOGSDIR`,
|
||||
`PLATYPUSH_CACHEDIR`, `PLATYPUSH_DB`, `PLATYPUSH_REDIS_HOST`,
|
||||
`PLATYPUSH_REDIS_PORT` and `PLATYPUSH_REDIS_QUEUE` environment variables.
|
||||
|
||||
- Added an _Extensions_ panel to the UI to dynamically:
|
||||
- Install new dependencies directly from the Web view.
|
||||
- Explore the documentation as well as the supported actions and events for
|
||||
each plugin.
|
||||
- Get ready-to-paste configuration snippets/templates.
|
||||
|
||||
- New, completely rewritten [documentation](https://docs.platypush.tech), which
|
||||
now integrates the wiki, dynamically includes plugins configuration snippets
|
||||
and dependencies, and adds a global filter bar for the integrations.
|
||||
|
||||
- [[#394](https://git.platypush.tech/platypush/platypush/issues/394)] A more
|
||||
intuitive way of installing extra dependencies via `pip`. Instead of a static
|
||||
list that the user should check inside of `setup.py`, the syntax `pip install
|
||||
'platypush[plugin1,plugin2,...]'` is now supported.
|
||||
|
||||
- No more need to manually create `__init__.py` in each of the `scripts`
|
||||
folders that you want to use to store your custom scripts. Automatic
|
||||
discovery of scripts and creation of module files has been implemented. You
|
||||
can now just drop a `.py` script with your procedures, hooks or crons in the
|
||||
scripts folder and it should be picked up by the application.
|
||||
|
||||
- The _Execute_ Web panel now supports procedures too, as well as curl snippets.
|
||||
|
||||
- Removed all `Response` objects outside of the root type. They are now all
|
||||
replaced by Marshmallow schemas with the structure automatically generated in
|
||||
the documentation.
|
||||
|
||||
- [`alarm`] [[#340](https://git.platypush.tech/platypush/platypush/issues/340)]
|
||||
Rewritten integration. It now includes a powerful UI panel to set up alarms
|
||||
with custom procedures too.
|
||||
|
||||
- [`assistant.picovoice`]
|
||||
[[#304](https://git.platypush.tech/platypush/platypush/issues/304)] New
|
||||
all-in-one Picovoice integration that replaces the previous `stt.picovoice.*`
|
||||
integrations.
|
||||
|
||||
- [`youtube`]
|
||||
[[#337](https://git.platypush.tech/platypush/platypush/issues/337)] Full
|
||||
rewrite of the plugin. It now supports Piped instances instead of the
|
||||
official YouTube API. A new UI has also been designed to explore
|
||||
subscriptions, playlists and channels.
|
||||
|
||||
- [`weather.*`]
|
||||
[[#308](https://git.platypush.tech/platypush/platypush/issues/308)] Removed
|
||||
the `weather.darksky` integration (it's now owned by Apple and the API is
|
||||
basically dead) and enhanced the `weather.openweathermap` plugin instead.
|
||||
|
||||
- [`camera.pi*`] The old `camera.pi` integration based on the deprecated
|
||||
`picamera` module has been moved to `camera.pi.legacy`. `camera.pi` is now a
|
||||
new plugin which uses the new `picamera2` API (and it's so far only
|
||||
compatible with recent versions on the Raspberry Pi OS).
|
||||
|
||||
- Dynamically auto-generate plugins documentation in the UI from the RST
|
||||
docstrings.
|
||||
|
||||
- New design for the configuration panel.
|
||||
|
||||
- Better synchronization between processes on threads on application stop -
|
||||
greatly reduced the risk of hanging processes on shutdown.
|
||||
|
||||
- Migrated all CI/CD pipelines to [Drone
|
||||
CI](https://ci-cd.platypush.tech/platypush/platypush).
|
||||
|
||||
- Removed `google.fit` integration, as Google has deprecated the API.
|
||||
|
||||
- Removed `wiimote` integration: the `cwiid` library hasn't been updated in
|
||||
years, it doesn't even work well with Python 3, and I'm not in the mood of
|
||||
bringing it back from the dead.
|
||||
|
||||
- Removed `stt.deepspeech` integration. That project has been basically
|
||||
abandoned by Mozilla, the libraries are very buggy and I don't think it's
|
||||
going to see new developments any time soon.
|
||||
|
||||
- [[#297](https://git.platypush.tech/platypush/platypush/issues/297)] Removed
|
||||
`spotify` backend integration based on Librespot. The project has gone
|
||||
through a lot of changes, and I no longer have a Spotify premium account to
|
||||
work on a new implementation. Open to contributions if somebody still wants
|
||||
it.
|
||||
|
||||
## [0.50.3] - 2023-07-22
|
||||
|
||||
### Added
|
||||
|
||||
- Added [XMPP plugin](https://git.platypush.tech/platypush/platypush/pulls/269).
|
||||
|
||||
## [0.50.2] - 2023-06-30
|
||||
|
||||
### Fixed
|
||||
|
||||
- A fix for the new `get_plugin` supported syntax. `get_plugin` now also
|
||||
accepts a plugin class/type as an argument rather than a string, but the
|
||||
previous logic didn't properly inspect the parent module.
|
||||
|
||||
## [0.50.0] - 2023-06-28
|
||||
|
||||
This should actually be a new big major release, but I'm holding on implementing
|
||||
more features before a 1.0 tag.
|
||||
|
||||
### Added
|
||||
|
||||
- Migrated many integrations to the new [entities
|
||||
framework](https://git.platypush.tech/platypush/platypush/pulls/230).
|
||||
This is a very large change to the foundations of the platform. Many plugins
|
||||
(and many others will follow) now publish and store their *entities* in a
|
||||
standard format, so e.g. all the lights, switches, Bluetooth devices, cameras,
|
||||
audio devices, media players and sensors are now supposed to expose the same
|
||||
attributes and API regardless of the type of integration. This refactor also
|
||||
includes a new default home panel, which includes all the entities detected by
|
||||
the registered integrations. Many integrations have already been migrated to
|
||||
the new framework. Among them (and many others are on their way):
|
||||
|
||||
- `arduino`
|
||||
- `bluetooth`
|
||||
- `light.hue`
|
||||
- `linode`
|
||||
- All the `sensor.*` plugins
|
||||
- `serial`
|
||||
- `smartthings`
|
||||
- `switchbot`
|
||||
- `system`
|
||||
- `variable`
|
||||
- `zigbee.mqtt`
|
||||
- `zwave.mqtt`
|
||||
|
||||
- Added support for more complex filters on event hooks. Earlier filters could
|
||||
only model key-value pair matches. The interface now supports more
|
||||
sophisticated filters - among these, structured filters with partial matches
|
||||
and relational filters. For example:
|
||||
|
||||
```python
|
||||
from platypush.event.hook import hook
|
||||
from platypush.message.event.sensor import SensorDataChangeEvent
|
||||
|
||||
@hook(SensorDataChangeEvent, data=1):
|
||||
def hook_1(event):
|
||||
"""
|
||||
Triggered when event.data == 1
|
||||
"""
|
||||
|
||||
@hook(SensorDataChangeEvent, data={'state': 1}):
|
||||
def hook_2(event):
|
||||
"""
|
||||
Triggered when event.data['state'] == 1
|
||||
"""
|
||||
|
||||
@hook(SensorDataChangeEvent, data={
|
||||
'temperature': {'$gt': 25},
|
||||
'humidity': {'$le': 15}
|
||||
}):
|
||||
def hook_3(event):
|
||||
"""
|
||||
Triggered when event.data['temperature'] > 25 and
|
||||
event.data['humidity'] <= 15.
|
||||
"""
|
||||
```
|
||||
|
||||
The supported relational fields are the same supported by ElasticSearch - `$gt`
|
||||
for greater than, `$lt` for lesser than, `$ge` for greater or equal, `$ne` for
|
||||
not equal, etc.
|
||||
|
||||
This also means that the previous `SensorDataAboveThresholdEvent` and
|
||||
`SensorDataBelowThresholdEvent` events are now deprecated, as the new hook API
|
||||
makes it much easier and flexible to define custom threshold logic on any events
|
||||
without having to pre-define thresholds in each backend's configuration.
|
||||
|
||||
- Added a Progressive WebApp (PWA) framework to the Vue webapp. It is now
|
||||
possible to install Platypush as a stand-alone webapp directly from the web
|
||||
panel if the panel is served over HTTPS. For now this only improves the user
|
||||
experience, performance and it provides a more native-like experience on
|
||||
mobile, but in the future the PWA background worker could be used to e.g.
|
||||
deliver asynchronous events and notifications to the clients without keeping
|
||||
the browser open.
|
||||
|
||||
- Added support for application database automatic migrations after an update by
|
||||
using Alembic.
|
||||
|
||||
### Changed
|
||||
|
||||
- Tornado is now used as an HTTP engine by `backend.http`, instead of using
|
||||
bare bone Flask with its inefficient Werkzeug server and an optional uwsgi
|
||||
that required extra configuration (and an extra external service).
|
||||
|
||||
- All the streaming endpoints have been rewritten and adapted to work with
|
||||
Tornado. This greatly improves performance, stability and ease of
|
||||
configuration, while remaining back-compatible with the previous URL formats.
|
||||
As a side note, all the streaming endpoints are now using Redis to stream
|
||||
information across multiple worker processes, so make sure that you have a
|
||||
version of Redis that supports pub/sub (most of the recent ones should do).
|
||||
|
||||
- The `bluetooth` plugin has been completely rewritten, merged with the (now
|
||||
deprecated) `backend.bluetooth`. The previously separated low-energy/legacy
|
||||
integrations have now been merged too. It now supports much more than passive
|
||||
scanning, as it can recognize the information published by most of the device,
|
||||
supports both legacy and low-energy connection/disconnection actions, and it
|
||||
can detect most of the device classes, services and manufacturers. It also
|
||||
supports parsing some standard features (like battery level, temperature,
|
||||
state etc.) if they are published according to some convention supported by
|
||||
*TheengsGateway*. The `switchbot.bluetooth` integration has now also been
|
||||
merged into `bluetooth`.
|
||||
|
||||
- The `sound` plugin has been completely rewritten. While it should still be
|
||||
largely back-compatible with the previous implementation, you should probably
|
||||
go and take a look at the new documentation to get a grasp of the new
|
||||
features.
|
||||
|
||||
- The `camera.ffmpeg` plugin has received a big rewrite that has improved its
|
||||
stability and robustness against several types of cameras. It is now the
|
||||
recommended way of interfacing with general-purpose cameras, even for
|
||||
PiCameras - the `camera.pi` integration is now largely deprecated, as the old
|
||||
PiCamera API is deprecated as well, and `camera.ffmpeg` should now work out of
|
||||
the box with a PiCamera if a reasonably recent version of ffmpeg is installed.
|
||||
|
||||
- `backend.websocket` has been **removed** and replaced by Tornado asynchronous
|
||||
websocket URLs registered on the HTTP backend. The two new routes that
|
||||
replace the websocket backend are:
|
||||
|
||||
- `/ws/events`: subscribe to this websocket to receive any asynchronous
|
||||
events forwarded by the application.
|
||||
- `/ws/requests`: you can send request messages to this endpoints, and the
|
||||
responses will be received asynchronously on the same channel.
|
||||
|
||||
- The `inspect` plugin has been largely improved.
|
||||
|
||||
- Its performance is now much snappier, as it scans for all the available
|
||||
integrations by searching for manifest files instead of scanning each
|
||||
single source file. Documentation about specific plugins and actions is
|
||||
fetched lazily when requested by the user.
|
||||
- It now also caches results by looking at the last modified date of the
|
||||
source file, so it won't have to re-scan source files that haven't been
|
||||
modified.
|
||||
- Its detection of RST constructs has also been improved, so most of the code
|
||||
blocks, schemas, return types and references to other objects are now
|
||||
rendered in the plugin UI.
|
||||
|
||||
- Added `variable.delete` action. The existing `variable.unset` action will now
|
||||
only set a variable to null if it exists, while `variable.delete` will
|
||||
actually remove it from the database.
|
||||
|
||||
- `backend.sensor.distance` and `gpio.sensor.distance` have been removed and
|
||||
migrated instead to a new `sensor.hcsr04` plugin, since the existing logic
|
||||
actually only applies to HC-SR04-like distance sensors.
|
||||
|
||||
- `backend.sensor.dht` and `gpio.sensor.dht` have been removed and
|
||||
migrated to a new `sensor.dht` plugin.
|
||||
|
||||
- `backend.sensor.accelerometer` and `gpio.sensor.accelerometer` have been
|
||||
removed and migrated to a new `sensor.lis3dh` plugin, since the existing
|
||||
accelerometer logic only works with these sensors.
|
||||
|
||||
- `backend.sensor.motion.pwm3901` and `gpio.sensor.motion.pwm3901` have been
|
||||
removed and migrated to a new `sensor.pwm3901` plugin.
|
||||
accelerometer logic only works with these sensors.
|
||||
|
||||
- `backend.sensor.envirophat` and `gpio.sensor.envirophat` have been removed and
|
||||
migrated to a new `sensor.envirophat` plugin.
|
||||
|
||||
- `backend.sensor.ltr559` and `gpio.sensor.ltr559` have been removed and
|
||||
migrated to a new `sensor.ltr559` plugin.
|
||||
|
||||
- `backend.sensor.bme280` and `gpio.sensor.bme280` have been removed and
|
||||
migrated to a new `sensor.bme280` plugin.
|
||||
|
||||
- `backend.sensor.distance.vl53l1x` and `gpio.sensor.distance.vl53l1x` have been
|
||||
removed and migrated to a new `sensor.vl53l1x` plugin.
|
||||
|
||||
- `backend.serial` has been removed and merged into the `serial` plugin.
|
||||
|
||||
- `backend.switch.wemo` has been removed and merged into the `switch.wemo`
|
||||
plugin.
|
||||
|
||||
- `backend.switch.tplink` has been removed and merged into the `switch.tplink`
|
||||
plugin.
|
||||
|
||||
- `backend.zigbee.mqtt` has been removed and merged into the `zigbee.mqtt`
|
||||
plugin.
|
||||
|
||||
- `backend.zwave.mqtt` has been removed and merged into the `zwave.mqtt` plugin.
|
||||
This is a very large change to the foundations of the platform, and there's
|
||||
still a lot of work in progress. A detailed description of all the changes
|
||||
will follow shortly.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Notable performance improvements for the UI (like -50% on the load time and
|
||||
memory usage in some cases). Recursive/reflective Vue components now use
|
||||
`shallowRef`, so complex UI models won't have to be fully loaded at page
|
||||
start.
|
||||
|
||||
- Fixed compatibility with SQLAlchemy 2.
|
||||
|
||||
- Migrated the `clipboard` integration from `pyperclip` to `pyclip` (see
|
||||
[#240](https://git.platypush.tech/platypush/platypush/issues/240)).
|
||||
`pyperclip` is unmaintained and largely broken, and `pyclip` seems to be a
|
||||
viable drop-in alternative.
|
||||
|
||||
- Better implementation of the UI modals - added close buttons and trigger
|
||||
closure when Esc is pressed.
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed SSL configuration from `backend.http`. Configuring SSL on
|
||||
Flask+Tornado is messy, and it won't end up with a good user experience.
|
||||
Instead, you should consider using a reverse proxy (e.g. nginx or Apache) if
|
||||
you want to make the Platypush web interface available over HTTPS. A sample
|
||||
nginx configuration has been added under `examples/nginx`. Note that running
|
||||
the web panel over HTTPS is a requirement if you want to leverage the PWA
|
||||
features, as a PWA can only be served over HTTPS.
|
||||
|
||||
- Removed the Bluetooth file server integration. It is still possible to send
|
||||
files over Bluetooth (the feature has now been merged into the `bluetooth`
|
||||
plugin, under `bluetooth.send_file`), but all the server features rely on
|
||||
features of PyOBEX that are now very broken on recent versions of Python (the
|
||||
project itself hasn't been updated in years).
|
||||
|
||||
- Removed or deprecated all the `backend.sensor.*` backends. Their logic has now
|
||||
been merged into their associated plugins, and the plugins will have the
|
||||
ability to run in the background too.
|
||||
|
||||
- Removed `backend.sensor.battery`. It has now been merged into the `system`
|
||||
plugin.
|
||||
|
||||
- Removed `gpio.sensor` plugin. It was never really fully implemented, and it
|
||||
was probably impossible to implement with an interface that could work with
|
||||
any sensor-like device connected over GPIO.
|
||||
|
||||
## [0.24.5] - 2023-02-22
|
||||
|
||||
### Added
|
||||
|
|
|
@ -27,9 +27,13 @@ Guidelines:
|
|||
you are changing some of the core entities (e.g. requests, events, procedures, hooks, crons
|
||||
or the bus) then make sure to add tests and not to break the existing tests.
|
||||
|
||||
- If the feature requires an optional dependency then make sure to document it
|
||||
in the `manifest.json` - refer to the Wiki (how to write
|
||||
[plugins](https://git.platypush.tech/platypush/platypush/wiki/Writing-your-own-plugins)
|
||||
and
|
||||
[backends](https://git.platypush.tech/platypush/platypush/wiki/Writing-your-own-backends))
|
||||
for examples on how to write an extension manifest file.
|
||||
- If the feature requires an optional dependency then make sure to document it:
|
||||
|
||||
- In the class docstring (see other plugins and backends for examples).
|
||||
- In [`setup.py`](https://git.platypush.tech/platypush/platypush/-/blob/master/setup.py#L72) as
|
||||
an `extras_require` entry.
|
||||
- In the plugin/backend class pydoc string.
|
||||
- In the `manifest.yaml` - refer to the Wiki (how to write
|
||||
[plugins](https://git.platypush.tech/platypush/platypush/wiki/Writing-your-own-plugins)
|
||||
and [backends](https://git.platypush.tech/platypush/platypush/wiki/Writing-your-own-backends))
|
||||
for examples on how to write an extension manifest file.
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
platypush/install/docker/alpine.Dockerfile
|
|
@ -1,7 +1,4 @@
|
|||
recursive-include platypush/backend/http/webapp/dist *
|
||||
recursive-include platypush/install *
|
||||
include platypush/plugins/http/webpage/mercury-parser.js
|
||||
include platypush/config/*.yaml
|
||||
include platypush/config/systemd/*
|
||||
global-include manifest.json
|
||||
global-include components.json.gz
|
||||
global-include manifest.yaml
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#!python3
|
||||
|
||||
from platypush import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
|
@ -0,0 +1,249 @@
|
|||
#!/bin/bash
|
||||
|
||||
##############################################################################
|
||||
# This script allows you to easily manage Platypush instances through Python #
|
||||
# virtual environment. You can build environments from a config.yaml file #
|
||||
# and automatically managed the required dependencies, as well as start, #
|
||||
# stop and remove them #
|
||||
# #
|
||||
# @author: Fabio Manganiello <fabio@platypush.tech> #
|
||||
# @licence: MIT #
|
||||
##############################################################################
|
||||
|
||||
|
||||
workdir="$HOME/.local/share/platypush/venv"
|
||||
|
||||
function build {
|
||||
cfgfile=
|
||||
|
||||
while getopts ':c:' opt; do
|
||||
case ${opt} in
|
||||
c)
|
||||
cfgfile=$OPTARG;;
|
||||
\?)
|
||||
echo "Invalid option: -$OPTARG" >&2
|
||||
exit 1;;
|
||||
:)
|
||||
echo "Option -$OPTARG requires the path to a Platypush configuration file" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$cfgfile" ]]; then
|
||||
echo "Usage: $0 build -c <path-to-platypush-config-file>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Parsing configuration file"
|
||||
pip_cmd=
|
||||
pkg_cmd=
|
||||
includes=()
|
||||
cmd_exec=()
|
||||
|
||||
while read -r line; do
|
||||
if echo "$line" | grep -E "^pip:\s*"; then
|
||||
pip_cmd="$(echo "$line" | sed -r -e 's/^pip:\s*(.*)'/\\1/)"
|
||||
elif echo "$line" | grep -E "^packages:\s*"; then
|
||||
pkg_cmd="$(echo "$line" | sed -r -e 's/^packages:\s*(.*)'/\\1/)"
|
||||
elif echo "$line" | grep -E "^exec:\s*"; then
|
||||
cmd_exec+=("$(echo "$line" | sed -r -e 's/^exec:\s*(.*)'/\\1/)")
|
||||
elif echo "$line" | grep -E "^include:\s*"; then
|
||||
includes+=("$(echo "$line" | sed -r -e 's/^include:\s*(.*)'/\\1/)")
|
||||
elif echo "$line" | grep -E "^device_id:\s*"; then
|
||||
device_id="$(echo "$line" | sed -r -e 's/^device_id:\s*(.*)'/\\1/)"
|
||||
fi
|
||||
done <<< "$(python <<EOF
|
||||
from platypush.config import Config
|
||||
from platypush.utils.manifest import get_install_commands_from_conf
|
||||
|
||||
deps = get_install_commands_from_conf('$(realpath "${cfgfile}")')
|
||||
print(f'device_id: {Config.get("device_id")}')
|
||||
|
||||
if deps.get('pip'):
|
||||
print(f'pip: {deps["pip"]}')
|
||||
|
||||
if deps.get('packages'):
|
||||
print(f'packages: {deps["packages"]}')
|
||||
|
||||
for cmd in deps.get('exec', []):
|
||||
print(f'exec: {cmd}')
|
||||
|
||||
for include in Config._included_files:
|
||||
print(f'include: {include}')
|
||||
EOF
|
||||
)"
|
||||
|
||||
envdir="${workdir}/${device_id}"
|
||||
etcdir="${envdir}/etc/platypush"
|
||||
|
||||
echo "Preparing virtual environment for device $device_id"
|
||||
mkdir -p "$envdir"
|
||||
mkdir -p "$etcdir"
|
||||
srcdir=$(dirname "$cfgfile")
|
||||
|
||||
for ((i=0; i < ${#includes[@]}; i++)); do
|
||||
incdir=$(dirname "${includes[$i]}")
|
||||
incdir=$(realpath --relative-to="$srcdir" "$incdir")
|
||||
destdir="$etcdir/$incdir"
|
||||
mkdir -p "$destdir"
|
||||
cp "${includes[$i]}" "$destdir"
|
||||
done
|
||||
|
||||
cp "$cfgfile" "$etcdir/config.yaml"
|
||||
cfgfile="${etcdir}/config.yaml"
|
||||
|
||||
python3 -m venv "${envdir}"
|
||||
cd "${envdir}" || exit 1
|
||||
source "${envdir}/bin/activate"
|
||||
|
||||
echo "Installing required dependencies"
|
||||
# shellcheck disable=SC2086
|
||||
[ -n "${pkg_cmd}" ] && sudo ${pkg_cmd}
|
||||
[ -n "${pip_cmd}" ] && ${pip_cmd}
|
||||
|
||||
for ((i=0; i < ${#cmd_exec[@]}; i++)); do
|
||||
${cmd_exec[$i]}
|
||||
done
|
||||
|
||||
pip install --upgrade git+https://git.platypush.tech/platypush/platypush.git
|
||||
echo "Platypush virtual environment prepared under $envdir"
|
||||
}
|
||||
|
||||
function start {
|
||||
if [[ -z "$1" ]]; then
|
||||
echo "Usage: $0 start <env-name>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
env=$1
|
||||
envdir="${workdir}/${env}"
|
||||
rundir="${envdir}/var/run"
|
||||
pidfile="${rundir}/platypush.pid"
|
||||
cfgfile="${envdir}/etc/platypush/config.yaml"
|
||||
|
||||
if [[ ! -d "$envdir" ]]; then
|
||||
echo "No such directory: $envdir" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${rundir}"
|
||||
|
||||
if [[ -f "$pidfile" ]]; then
|
||||
if pgrep -F "${pidfile}"; then
|
||||
echo "Another instance (PID $(cat "${pidfile}")) is running, please stop that instance first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "A PID file was found but the process does not seem to be running, starting anyway"
|
||||
rm -f "$pidfile"
|
||||
fi
|
||||
|
||||
python3 -m venv "${envdir}"
|
||||
cd "${envdir}" || exit 1
|
||||
source bin/activate
|
||||
bin/platypush -c "$cfgfile" -P "$pidfile" &
|
||||
start_time=$(date +'%s')
|
||||
timeout=30
|
||||
|
||||
while :; do
|
||||
[[ -f "$pidfile" ]] && break
|
||||
now=$(date +'%s')
|
||||
elapsed=$(( now-start_time ))
|
||||
if (( elapsed >= timeout )); then
|
||||
echo "Platypush instance '$env' did not start within $timeout seconds" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -n '.'
|
||||
sleep 1
|
||||
done
|
||||
|
||||
pid=$(cat "$pidfile")
|
||||
echo
|
||||
echo "Platypush environment $env started with PID $pid"
|
||||
wait "${pid}"
|
||||
echo "Platypush environment $env terminated"
|
||||
}
|
||||
|
||||
function stop {
|
||||
if [[ -z "$1" ]]; then
|
||||
echo "Usage: $0 stop <env-name>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
env=$1
|
||||
envdir="${workdir}/${env}"
|
||||
rundir="${envdir}/var/run"
|
||||
pidfile="${rundir}/platypush.pid"
|
||||
|
||||
if [[ ! -d "$envdir" ]]; then
|
||||
echo "No such directory: $envdir" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$pidfile" ]]; then
|
||||
echo "No pidfile found for instance \"${env}\""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pid=$(cat "$pidfile")
|
||||
pids="$pid $(ps --no-headers -o pid= --ppid "$pid")"
|
||||
# shellcheck disable=SC2086
|
||||
kill -9 ${pids}
|
||||
rm -f "$pidfile"
|
||||
echo "Instance '$env' with PID $pid stopped"
|
||||
}
|
||||
|
||||
function rme {
|
||||
if [[ -z "$1" ]]; then
|
||||
echo "Usage: $0 rm <env-name>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
envdir="${workdir}/$1"
|
||||
rundir="${envdir}/var/run"
|
||||
pidfile="${rundir}/platypush.pid"
|
||||
|
||||
if [[ ! -d "$envdir" ]]; then
|
||||
echo "No such directory: $envdir" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -f "$pidfile" ]]; then
|
||||
if pgrep -F "${pidfile}"; then
|
||||
echo "Another instance (PID $(cat "$pidfile")) is running, please stop that instance first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "A PID file was found but the process does not seem to be running, removing anyway"
|
||||
fi
|
||||
|
||||
echo "WARNING: This operation will permanently remove the Platypush environment $1"
|
||||
echo -n "Are you sure you want to continue? (y/N) "
|
||||
IFS= read -r answer
|
||||
echo "$answer" | grep -E '^[yY]' >/dev/null || exit 0
|
||||
rm -rf "$envdir"
|
||||
echo "$envdir removed"
|
||||
}
|
||||
|
||||
function usage {
|
||||
echo "Usage: $0 <build|start|stop|rm> [options]" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (( $# < 1 )); then
|
||||
usage
|
||||
fi
|
||||
|
||||
action=$1
|
||||
shift
|
||||
mkdir -p "${workdir}"
|
||||
|
||||
# shellcheck disable=SC2048,SC2086
|
||||
case ${action} in
|
||||
'build') build $*;;
|
||||
'start') start $*;;
|
||||
'stop') stop $*;;
|
||||
'rm') rme $*;;
|
||||
*) usage;;
|
||||
esac
|
|
@ -1,46 +0,0 @@
|
|||
services:
|
||||
platypush:
|
||||
restart: "always"
|
||||
command:
|
||||
- platypush
|
||||
# Comment --start-redis if you want to run an external Redis service
|
||||
# In such case you'll also have to ensure that the appropriate Redis
|
||||
# variables are set in the .env file, or the Redis configuration is
|
||||
# passed in the config.yaml, or use the --redis-host and --redis-port
|
||||
# command-line options
|
||||
- --start-redis
|
||||
|
||||
# Custom list of host devices that should be accessible to the container -
|
||||
# e.g. an Arduino, an ESP-compatible microcontroller, a joystick etc.
|
||||
# devices:
|
||||
# - /dev/ttyUSB0
|
||||
|
||||
# Uncomment if you need plugins that require access to low-level hardware
|
||||
# (e.g. Bluetooth BLE or GPIO/SPI/I2C) if access to individual devices is
|
||||
# not enough or isn't practical
|
||||
# privileged: true
|
||||
|
||||
build:
|
||||
context: .
|
||||
# Alpine base image
|
||||
dockerfile: ./platypush/install/docker/alpine.Dockerfile
|
||||
# Debian base image
|
||||
# dockerfile: ./platypush/install/docker/debian.Dockerfile
|
||||
# Ubuntu base image
|
||||
# dockerfile: ./platypush/install/docker/ubuntu.Dockerfile
|
||||
# Fedora base image
|
||||
# dockerfile: ./platypush/install/docker/fedora.Dockerfile
|
||||
|
||||
# Copy .env.example to .env and modify as needed
|
||||
# env_file:
|
||||
# - .env
|
||||
|
||||
ports:
|
||||
# Comment if you don't have the HTTP backend enable or you don't want to
|
||||
# expose it
|
||||
- "8008:8008"
|
||||
|
||||
volumes:
|
||||
- /path/to/your/config.yaml:/etc/platypush
|
||||
- /path/to/a/workdir:/var/lib/platypush
|
||||
# - /path/to/a/cachedir:/var/cache/platypush
|
|
@ -1,186 +0,0 @@
|
|||
import inspect
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import textwrap as tw
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
base_path = os.path.abspath(
|
||||
os.path.join(os.path.dirname(os.path.relpath(__file__)), '..', '..', '..')
|
||||
)
|
||||
|
||||
sys.path.insert(0, base_path)
|
||||
|
||||
from platypush.common.reflection import Integration # noqa: E402
|
||||
from platypush.utils import get_plugin_name_by_class # noqa: E402
|
||||
from platypush.utils.mock import auto_mocks # noqa: E402
|
||||
|
||||
|
||||
class IntegrationEnricher:
|
||||
@staticmethod
|
||||
def add_events(source: list[str], manifest: Integration, idx: int) -> int:
|
||||
if not manifest.events:
|
||||
return idx
|
||||
|
||||
source.insert(
|
||||
idx,
|
||||
'Triggered events\n----------------\n\n'
|
||||
+ '\n'.join(
|
||||
f'\t- :class:`{event.__module__}.{event.__qualname__}`'
|
||||
for event in manifest.events
|
||||
)
|
||||
+ '\n\n',
|
||||
)
|
||||
|
||||
return idx + 1
|
||||
|
||||
@staticmethod
|
||||
def add_actions(source: list[str], manifest: Integration, idx: int) -> int:
|
||||
if not (manifest.actions and manifest.cls):
|
||||
return idx
|
||||
|
||||
source.insert(
|
||||
idx,
|
||||
'Actions\n-------\n\n'
|
||||
+ '\n'.join(
|
||||
f'\t- `{get_plugin_name_by_class(manifest.cls)}.{action} '
|
||||
+ f'<#{manifest.cls.__module__}.{manifest.cls.__qualname__}.{action}>`_'
|
||||
for action in sorted(manifest.actions.keys())
|
||||
)
|
||||
+ '\n\n',
|
||||
)
|
||||
|
||||
return idx + 1
|
||||
|
||||
@staticmethod
|
||||
def _shellify(title: str, cmd: str) -> str:
|
||||
return (
|
||||
f'**{title}**\n\n'
|
||||
+ '.. code-block:: bash\n\n'
|
||||
+ tw.indent(cmd, '\t')
|
||||
+ '\n\n'
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def add_install_deps(
|
||||
cls, source: list[str], manifest: Integration, idx: int
|
||||
) -> int:
|
||||
deps = manifest.deps
|
||||
parsed_deps = {
|
||||
'before': deps.before,
|
||||
'pip': deps.pip,
|
||||
'after': deps.after,
|
||||
}
|
||||
|
||||
if not (any(parsed_deps.values()) or deps.by_pkg_manager):
|
||||
return idx
|
||||
|
||||
source.insert(idx, 'Dependencies\n------------\n\n')
|
||||
idx += 1
|
||||
|
||||
if parsed_deps['before']:
|
||||
source.insert(idx, cls._shellify('Pre-install', '\n'.join(deps.before)))
|
||||
idx += 1
|
||||
|
||||
if parsed_deps['pip']:
|
||||
source.insert(
|
||||
idx, cls._shellify('pip', 'pip install ' + ' '.join(deps.pip))
|
||||
)
|
||||
idx += 1
|
||||
|
||||
for pkg_manager, sys_deps in deps.by_pkg_manager.items():
|
||||
if not sys_deps:
|
||||
continue
|
||||
|
||||
source.insert(
|
||||
idx,
|
||||
cls._shellify(
|
||||
pkg_manager.value.default_os.value.description,
|
||||
pkg_manager.value.install_doc + ' ' + ' '.join(sys_deps),
|
||||
),
|
||||
)
|
||||
|
||||
idx += 1
|
||||
|
||||
if parsed_deps['after']:
|
||||
source.insert(idx, cls._shellify('Post-install', '\n'.join(deps.after)))
|
||||
idx += 1
|
||||
|
||||
return idx
|
||||
|
||||
@classmethod
|
||||
def add_description(cls, source: list[str], manifest: Integration, idx: int) -> int:
|
||||
docs = (
|
||||
doc
|
||||
for doc in (
|
||||
inspect.getdoc(manifest.cls) or '',
|
||||
manifest.constructor.doc if manifest.constructor else '',
|
||||
)
|
||||
if doc
|
||||
)
|
||||
|
||||
if not docs:
|
||||
return idx
|
||||
|
||||
docstring = '\n\n'.join(docs)
|
||||
source.insert(idx, f"Description\n-----------\n\n{docstring}\n\n")
|
||||
return idx + 1
|
||||
|
||||
@classmethod
|
||||
def add_conf_snippet(
|
||||
cls, source: list[str], manifest: Integration, idx: int
|
||||
) -> int:
|
||||
source.insert(
|
||||
idx,
|
||||
tw.dedent(
|
||||
f"""
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
{tw.indent(manifest.config_snippet, ' ')}
|
||||
"""
|
||||
),
|
||||
)
|
||||
|
||||
return idx + 1
|
||||
|
||||
def __call__(self, _: Sphinx, doc: str, source: list[str]):
|
||||
if not (source and re.match(r'^platypush/(backend|plugins)/.*', doc)):
|
||||
return
|
||||
|
||||
src = [src.split('\n') for src in source][0]
|
||||
if len(src) < 3:
|
||||
return
|
||||
|
||||
manifest_file = os.path.join(
|
||||
base_path,
|
||||
*doc.split(os.sep)[:-1],
|
||||
*doc.split(os.sep)[-1].split('.'),
|
||||
'manifest.json',
|
||||
)
|
||||
|
||||
if not os.path.isfile(manifest_file):
|
||||
return
|
||||
|
||||
with auto_mocks():
|
||||
manifest = Integration.from_manifest(manifest_file)
|
||||
idx = self.add_description(src, manifest, idx=3)
|
||||
idx = self.add_conf_snippet(src, manifest, idx=idx)
|
||||
idx = self.add_install_deps(src, manifest, idx=idx)
|
||||
idx = self.add_events(src, manifest, idx=idx)
|
||||
idx = self.add_actions(src, manifest, idx=idx)
|
||||
|
||||
src.insert(idx, '\n\nModule reference\n----------------\n\n')
|
||||
source[0] = '\n'.join(src)
|
||||
|
||||
|
||||
def setup(app: Sphinx):
|
||||
app.connect('source-read', IntegrationEnricher())
|
||||
return {
|
||||
'version': '0.1',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
|
@ -1,249 +0,0 @@
|
|||
const processList = (list, level, addTitle) => {
|
||||
const title = list.parentElement.querySelector('a')
|
||||
list.classList.add('grid')
|
||||
if (addTitle)
|
||||
title.classList.add('grid-title')
|
||||
|
||||
list.querySelectorAll(`li.toctree-l${level}`).forEach((item) => {
|
||||
const link = item.querySelector('a')
|
||||
if (link) {
|
||||
item.style.cursor = 'pointer'
|
||||
item.addEventListener('click', () => link.click())
|
||||
}
|
||||
|
||||
const name = item.querySelector('a').innerText
|
||||
const img = document.createElement('img')
|
||||
img.src = `https://static.platypush.tech/icons/${name.toLowerCase()}-64.png`
|
||||
img.alt = ' '
|
||||
item.prepend(img)
|
||||
})
|
||||
}
|
||||
|
||||
const addClipboard = (parent) => {
|
||||
const pre = parent.tagName === 'PRE' ? parent : parent.querySelector('pre')
|
||||
if (!pre)
|
||||
return
|
||||
|
||||
const clipboard = document.createElement('i')
|
||||
const setClipboard = (img, text) => {
|
||||
clipboard.innerHTML = `<img src="https://static.platypush.tech/icons/${img}-64.png" alt="${text}">`
|
||||
}
|
||||
|
||||
clipboard.classList.add('clipboard')
|
||||
setClipboard('clipboard-bw', 'Copy')
|
||||
clipboard.onclick = () => {
|
||||
if (navigator && navigator.clipboard && navigator.clipboard.writeText) {
|
||||
setClipboard('ok', 'Copied!')
|
||||
setTimeout(() => setClipboard('clipboard-bw', 'Copy'), 2000)
|
||||
return navigator.clipboard.writeText(pre.innerText.trim())
|
||||
}
|
||||
|
||||
return Promise.reject('The Clipboard API is not available.');
|
||||
}
|
||||
|
||||
pre.style.position = 'relative'
|
||||
pre.appendChild(clipboard)
|
||||
}
|
||||
|
||||
const Tabs = () => {
|
||||
let selectedTab = null
|
||||
let parent = null
|
||||
let data = {}
|
||||
|
||||
const init = (obj) => {
|
||||
data = obj
|
||||
if (Object.keys(data).length && selectedTab == null)
|
||||
selectedTab = Object.keys(data)[0]
|
||||
}
|
||||
|
||||
const select = (name) => {
|
||||
if (!parent) {
|
||||
console.warn('Cannot select tab: parent not set')
|
||||
return
|
||||
}
|
||||
|
||||
if (!data[name]) {
|
||||
console.warn(`Cannot select tab: invalid name: ${name}`)
|
||||
return
|
||||
}
|
||||
|
||||
const tabsBody = parent.querySelector('.body')
|
||||
selectedTab = name
|
||||
tabsBody.innerHTML = data[selectedTab]
|
||||
parent.querySelectorAll('.tabs li').forEach(
|
||||
(tab) => tab.classList.remove('selected')
|
||||
)
|
||||
|
||||
const tab = [...parent.querySelectorAll('.tabs li')].find(
|
||||
(t) => t.innerText === name
|
||||
)
|
||||
|
||||
if (!tab) {
|
||||
console.warn(`Cannot select tab: invalid name: ${name}`)
|
||||
return
|
||||
}
|
||||
|
||||
addClipboard(tabsBody)
|
||||
tab.classList.add('selected')
|
||||
}
|
||||
|
||||
const mount = (p) => {
|
||||
const tabs = document.createElement('div')
|
||||
tabs.classList.add('tabs')
|
||||
parent = p
|
||||
|
||||
const tabsList = document.createElement('ul')
|
||||
Object.keys(data).forEach((title) => {
|
||||
const tab = document.createElement('li')
|
||||
tab.innerText = title
|
||||
tab.onclick = (event) => {
|
||||
event.stopPropagation()
|
||||
select(title)
|
||||
},
|
||||
|
||||
tabsList.appendChild(tab)
|
||||
})
|
||||
|
||||
const tabsBody = document.createElement('div')
|
||||
tabsBody.classList.add('body')
|
||||
|
||||
tabs.appendChild(tabsList)
|
||||
tabs.appendChild(tabsBody)
|
||||
parent.innerHTML = ''
|
||||
parent.appendChild(tabs)
|
||||
select(selectedTab)
|
||||
}
|
||||
|
||||
return {
|
||||
init,
|
||||
select,
|
||||
mount,
|
||||
}
|
||||
}
|
||||
|
||||
const depsTabs = Tabs()
|
||||
|
||||
const convertDepsToTabs = () => {
|
||||
const depsContainer = document.getElementById('dependencies')
|
||||
if (!depsContainer)
|
||||
return
|
||||
|
||||
const blocks = [...depsContainer.querySelectorAll('.highlight-bash')].map((block) => block.outerHTML)
|
||||
const titles = [...depsContainer.querySelectorAll('p strong')].map((title) => title.innerText)
|
||||
|
||||
if (!(blocks.length && titles.length && blocks.length === titles.length))
|
||||
return
|
||||
|
||||
const title = depsContainer.querySelector('h2')
|
||||
const tabsData = titles.reduce((obj, title, i) => {
|
||||
obj[title] = blocks[i]
|
||||
return obj
|
||||
}, {})
|
||||
|
||||
depsTabs.init(tabsData)
|
||||
depsTabs.mount(depsContainer)
|
||||
depsContainer.prepend(title)
|
||||
}
|
||||
|
||||
const generateComponentsGrid = () => {
|
||||
const tocWrappers = document.querySelectorAll('.toctree-wrapper.compound')
|
||||
|
||||
if (!tocWrappers.length) {
|
||||
return
|
||||
}
|
||||
|
||||
if (window.location.pathname === '/' || window.location.pathname.endsWith('/index.html')) {
|
||||
if (tocWrappers.length < 2) {
|
||||
return
|
||||
}
|
||||
|
||||
const referenceLists = [
|
||||
...tocWrappers[1].querySelectorAll('ul li.toctree-l1 ul')
|
||||
].slice(0, 4)
|
||||
|
||||
referenceLists.forEach((list) => processList(list, 2, true))
|
||||
} else if (window.location.pathname.endsWith('/plugins.html') || window.location.pathname.endsWith('/backends.html')) {
|
||||
if (tocWrappers.length < 1) {
|
||||
return
|
||||
}
|
||||
|
||||
const list = tocWrappers[0].querySelector('ul')
|
||||
if (list)
|
||||
processList(list, 1, false)
|
||||
}
|
||||
}
|
||||
|
||||
const addClipboardToCodeBlocks = () => {
|
||||
document.querySelectorAll('pre').forEach((pre) => addClipboard(pre))
|
||||
}
|
||||
|
||||
const renderActionsList = () => {
|
||||
const actionsList = document.getElementById('actions')?.querySelector('ul')
|
||||
if (!actionsList)
|
||||
return
|
||||
|
||||
[...actionsList.querySelectorAll('li')].forEach((li) => {
|
||||
const link = li.querySelector('a')
|
||||
link.innerHTML = `<code class="docutils literal notranslate"><span class="pre">${link.innerText}</span></code>`
|
||||
})
|
||||
}
|
||||
|
||||
const createFilterBar = () => {
|
||||
const input = document.createElement('input')
|
||||
const referenceSection = document.getElementById('reference')
|
||||
|
||||
input.type = 'text'
|
||||
input.placeholder = 'Filter'
|
||||
input.classList.add('filter-bar')
|
||||
input.addEventListener('input', (event) => {
|
||||
const filter = event.target.value.toLowerCase()
|
||||
referenceSection.querySelectorAll('ul.grid li').forEach((li) => {
|
||||
if (li.innerText.toLowerCase().includes(filter)) {
|
||||
li.style.display = 'flex'
|
||||
} else {
|
||||
li.style.display = 'none'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return input
|
||||
}
|
||||
|
||||
const addFilterBar = () => {
|
||||
const container = document.querySelector('.bd-main')
|
||||
if (!container)
|
||||
return
|
||||
|
||||
const referenceSection = document.getElementById('reference')
|
||||
if (!referenceSection)
|
||||
return
|
||||
|
||||
const header = referenceSection.querySelector('h2')
|
||||
if (!header)
|
||||
return
|
||||
|
||||
const origInnerHTML = header.innerHTML
|
||||
header.innerHTML = '<span class="header-content">' + origInnerHTML + '</span>'
|
||||
|
||||
const input = createFilterBar()
|
||||
header.appendChild(input)
|
||||
|
||||
const headerOffsetTop = header.offsetTop
|
||||
|
||||
// Apply the fixed class if the header is above the viewport
|
||||
document.addEventListener('scroll', () => {
|
||||
if (headerOffsetTop < window.scrollY) {
|
||||
header.classList.add('fixed')
|
||||
} else {
|
||||
header.classList.remove('fixed')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
generateComponentsGrid()
|
||||
convertDepsToTabs()
|
||||
addClipboardToCodeBlocks()
|
||||
renderActionsList()
|
||||
addFilterBar()
|
||||
})
|
|
@ -1,188 +0,0 @@
|
|||
a, a:visited {
|
||||
/* Don't change the color for visited links */
|
||||
color: var(--pst-color-link) !important;
|
||||
}
|
||||
|
||||
ul.grid {
|
||||
display: grid;
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
grid-template-columns: repeat(1, 1fr);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 501px) and (max-width: 699px) {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 700px) {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
a.grid-title {
|
||||
width: 100%;
|
||||
display: block;
|
||||
margin: 1.5em 0;
|
||||
font-size: 1.5em !important;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
ul.grid li {
|
||||
display: flex;
|
||||
background: linear-gradient(0deg, #fff, #f9f9f9);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 0 10px 10px 0;
|
||||
padding: 20px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 15px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
ul.grid img {
|
||||
width: 48px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
ul.grid li code {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
ul.grid li code .pre {
|
||||
width: 100%;
|
||||
display: block;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
ul.grid li:hover {
|
||||
background: linear-gradient(0deg, #157765, #cbffd8) !important;
|
||||
}
|
||||
|
||||
ul.grid li a {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
ul.grid li:hover a,
|
||||
ul.grid li:hover a > code {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
ul.grid li a code {
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
ul.grid .icon {
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
/* Clipboard button */
|
||||
.clipboard {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
width: 32px;
|
||||
top: 0.5em;
|
||||
right: 0.5em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
.tabs {
|
||||
margin: 0 0 1em 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.tabs ul {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 0 0 1em 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.tabs ul li {
|
||||
display: inline-flex;
|
||||
max-width: 25%;
|
||||
margin: 0;
|
||||
padding: 0.25em 0.5em;
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
flex-grow: 1;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 0.75em 0.75em 0 0;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.tabs ul li.selected {
|
||||
background: rgb(200,255,208);
|
||||
}
|
||||
|
||||
.tabs ul li:hover {
|
||||
background: rgb(190,246,218);
|
||||
}
|
||||
|
||||
.tabs .body {
|
||||
margin-top: -1em;
|
||||
padding: 1em;
|
||||
border: 1px solid #ccc;
|
||||
border-top: none;
|
||||
border-radius: 0 0 0.75em 0.75em;
|
||||
}
|
||||
|
||||
.bd-article-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.filter-bar {
|
||||
width: 100%;
|
||||
display: block;
|
||||
font-size: 0.6em;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 0.75em;
|
||||
margin: 0.5em 0;
|
||||
padding: 0.25em;
|
||||
}
|
||||
|
||||
#reference h2.fixed {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
background: white;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#reference h2.fixed .header-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
#reference h2.fixed {
|
||||
width: 100%;
|
||||
margin-left: -0.5em;
|
||||
padding: 0.5em 0.5em 0 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 959px) {
|
||||
#reference h2.fixed {
|
||||
width: 100%;
|
||||
margin-left: -1em;
|
||||
padding: 0.5em 0.5em 0 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 960px) {
|
||||
#reference h2.fixed {
|
||||
width: 75%;
|
||||
max-width: 800px;
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
}
|
|
@ -6,7 +6,55 @@ Backends
|
|||
:maxdepth: 1
|
||||
:caption: Backends:
|
||||
|
||||
platypush/backend/adafruit.io.rst
|
||||
platypush/backend/alarm.rst
|
||||
platypush/backend/assistant.google.rst
|
||||
platypush/backend/assistant.snowboy.rst
|
||||
platypush/backend/button.flic.rst
|
||||
platypush/backend/camera.pi.rst
|
||||
platypush/backend/chat.telegram.rst
|
||||
platypush/backend/covid19.rst
|
||||
platypush/backend/file.monitor.rst
|
||||
platypush/backend/foursquare.rst
|
||||
platypush/backend/github.rst
|
||||
platypush/backend/google.fit.rst
|
||||
platypush/backend/google.pubsub.rst
|
||||
platypush/backend/gps.rst
|
||||
platypush/backend/http.rst
|
||||
platypush/backend/http.poll.rst
|
||||
platypush/backend/inotify.rst
|
||||
platypush/backend/joystick.rst
|
||||
platypush/backend/joystick.jstest.rst
|
||||
platypush/backend/joystick.linux.rst
|
||||
platypush/backend/kafka.rst
|
||||
platypush/backend/light.hue.rst
|
||||
platypush/backend/log.http.rst
|
||||
platypush/backend/mail.rst
|
||||
platypush/backend/midi.rst
|
||||
platypush/backend/mqtt.rst
|
||||
platypush/backend/music.mopidy.rst
|
||||
platypush/backend/music.mpd.rst
|
||||
platypush/backend/music.snapcast.rst
|
||||
platypush/backend/music.spotify.rst
|
||||
platypush/backend/nextcloud.rst
|
||||
platypush/backend/nfc.rst
|
||||
platypush/backend/nodered.rst
|
||||
platypush/backend/ping.rst
|
||||
platypush/backend/pushbullet.rst
|
||||
platypush/backend/redis.rst
|
||||
platypush/backend/scard.rst
|
||||
platypush/backend/sensor.ir.zeroborg.rst
|
||||
platypush/backend/sensor.leap.rst
|
||||
platypush/backend/stt.deepspeech.rst
|
||||
platypush/backend/stt.picovoice.hotword.rst
|
||||
platypush/backend/stt.picovoice.speech.rst
|
||||
platypush/backend/tcp.rst
|
||||
platypush/backend/todoist.rst
|
||||
platypush/backend/travisci.rst
|
||||
platypush/backend/trello.rst
|
||||
platypush/backend/weather.buienradar.rst
|
||||
platypush/backend/weather.darksky.rst
|
||||
platypush/backend/weather.openweathermap.rst
|
||||
platypush/backend/wiimote.rst
|
||||
platypush/backend/zwave.rst
|
||||
platypush/backend/zwave.mqtt.rst
|
||||
|
|
|
@ -15,14 +15,17 @@ import sys
|
|||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
sys.path.insert(0, os.path.abspath("./_ext"))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'Platypush'
|
||||
copyright = '2017-2024, Fabio Manganiello'
|
||||
author = 'Fabio Manganiello <fabio@manganiello.tech>'
|
||||
copyright = '2017-2021, Fabio Manganiello'
|
||||
author = 'Fabio Manganiello'
|
||||
|
||||
# The short X.Y version
|
||||
version = ''
|
||||
|
@ -40,7 +43,6 @@ release = ''
|
|||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'myst_parser',
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.todo',
|
||||
|
@ -50,7 +52,6 @@ extensions = [
|
|||
'sphinx.ext.githubpages',
|
||||
'sphinx_rtd_theme',
|
||||
'sphinx_marshmallow',
|
||||
'add_dependencies',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
|
@ -59,8 +60,8 @@ templates_path = ['_templates']
|
|||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
source_suffix = ['.rst', '.md']
|
||||
# source_suffix = '.rst'
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
@ -112,14 +113,7 @@ html_theme_options = {
|
|||
# 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,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
html_css_files = [
|
||||
'styles/custom.css',
|
||||
]
|
||||
|
||||
html_js_files = [
|
||||
'scripts/custom.js',
|
||||
]
|
||||
# html_static_path = ['_static']
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
|
@ -171,9 +165,9 @@ latex_documents = [
|
|||
man_pages = [(master_doc, 'platypush', 'platypush Documentation', [author], 1)]
|
||||
|
||||
|
||||
# -- Options for TexInfo output ----------------------------------------------
|
||||
# -- Options for Texinfo output ----------------------------------------------
|
||||
|
||||
# Grouping the document tree into TexInfo files. List of tuples
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
|
@ -196,31 +190,135 @@ texinfo_documents = [
|
|||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}
|
||||
|
||||
# -- Options for todo extension ----------------------------------------------
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
||||
|
||||
autodoc_default_options = {
|
||||
'members': True,
|
||||
'show-inheritance': True,
|
||||
'inherited-members': True,
|
||||
}
|
||||
|
||||
autodoc_mock_imports = [
|
||||
'gunicorn',
|
||||
'googlesamples.assistant.grpc.audio_helpers',
|
||||
'google.assistant.embedded',
|
||||
'google.assistant.library',
|
||||
'google.assistant.library.event',
|
||||
'google.assistant.library.file_helpers',
|
||||
'google.oauth2.credentials',
|
||||
'oauth2client',
|
||||
'apiclient',
|
||||
'tenacity',
|
||||
'smartcard',
|
||||
'Leap',
|
||||
'oauth2client',
|
||||
'rtmidi',
|
||||
'bluetooth',
|
||||
'gevent.wsgi',
|
||||
'Adafruit_IO',
|
||||
'pyclip',
|
||||
'pydbus',
|
||||
'inputs',
|
||||
'inotify',
|
||||
'omxplayer',
|
||||
'plexapi',
|
||||
'cwiid',
|
||||
'sounddevice',
|
||||
'soundfile',
|
||||
'numpy',
|
||||
'cv2',
|
||||
'nfc',
|
||||
'ndef',
|
||||
'bcrypt',
|
||||
'google',
|
||||
'feedparser',
|
||||
'kafka',
|
||||
'googlesamples',
|
||||
'icalendar',
|
||||
'httplib2',
|
||||
'mpd',
|
||||
'serial',
|
||||
'pyHS100',
|
||||
'grpc',
|
||||
'envirophat',
|
||||
'gps',
|
||||
'picamera',
|
||||
'pmw3901',
|
||||
'PIL',
|
||||
'croniter',
|
||||
'pyaudio',
|
||||
'avs',
|
||||
'PyOBEX',
|
||||
'PyOBEX.client',
|
||||
'todoist',
|
||||
'trello',
|
||||
'telegram',
|
||||
'telegram.ext',
|
||||
'pyfirmata2',
|
||||
'cups',
|
||||
'graphyte',
|
||||
'cpuinfo',
|
||||
'psutil',
|
||||
'openzwave',
|
||||
'deepspeech',
|
||||
'wave',
|
||||
'pvporcupine ',
|
||||
'pvcheetah',
|
||||
'pyotp',
|
||||
'linode_api4',
|
||||
'pyzbar',
|
||||
'tensorflow',
|
||||
'keras',
|
||||
'pandas',
|
||||
'samsungtvws',
|
||||
'paramiko',
|
||||
'luma',
|
||||
'zeroconf',
|
||||
'dbus',
|
||||
'gi',
|
||||
'gi.repository',
|
||||
'twilio',
|
||||
'Adafruit_Python_DHT',
|
||||
'RPi.GPIO',
|
||||
'RPLCD',
|
||||
'imapclient',
|
||||
'pysmartthings',
|
||||
'aiohttp',
|
||||
'watchdog',
|
||||
'pyngrok',
|
||||
'irc',
|
||||
'irc.bot',
|
||||
'irc.strings',
|
||||
'irc.client',
|
||||
'irc.connection',
|
||||
'irc.events',
|
||||
'defusedxml',
|
||||
'nio',
|
||||
'aiofiles',
|
||||
'aiofiles.os',
|
||||
'async_lru',
|
||||
'bleak',
|
||||
'bluetooth_numbers',
|
||||
'TheengsDecoder',
|
||||
'simple_websocket',
|
||||
'uvicorn',
|
||||
'websockets',
|
||||
'docutils',
|
||||
]
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../..'))
|
||||
|
||||
from platypush.utils.mock.modules import mock_imports # noqa
|
||||
|
||||
autodoc_mock_imports = [*mock_imports]
|
||||
|
||||
|
||||
# _ = app
|
||||
# __ = what
|
||||
# ___ = obj
|
||||
# ____ = options
|
||||
def _skip(_, __, name, ___, skip, ____):
|
||||
def skip(app, what, name, obj, skip, options):
|
||||
if name == "__init__":
|
||||
return False
|
||||
return skip
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.connect("autodoc-skip-member", _skip)
|
||||
app.connect("autodoc-skip-member", skip)
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -11,19 +11,22 @@ Events
|
|||
platypush/events/application.rst
|
||||
platypush/events/assistant.rst
|
||||
platypush/events/bluetooth.rst
|
||||
platypush/events/button.flic.rst
|
||||
platypush/events/camera.rst
|
||||
platypush/events/chat.slack.rst
|
||||
platypush/events/chat.telegram.rst
|
||||
platypush/events/clipboard.rst
|
||||
platypush/events/covid19.rst
|
||||
platypush/events/custom.rst
|
||||
platypush/events/dbus.rst
|
||||
platypush/events/distance.rst
|
||||
platypush/events/entities.rst
|
||||
platypush/events/file.rst
|
||||
platypush/events/flic.rst
|
||||
platypush/events/foursquare.rst
|
||||
platypush/events/geo.rst
|
||||
platypush/events/github.rst
|
||||
platypush/events/google.rst
|
||||
platypush/events/google.fit.rst
|
||||
platypush/events/google.pubsub.rst
|
||||
platypush/events/gotify.rst
|
||||
platypush/events/gpio.rst
|
||||
|
@ -64,16 +67,17 @@ Events
|
|||
platypush/events/sound.rst
|
||||
platypush/events/stt.rst
|
||||
platypush/events/sun.rst
|
||||
platypush/events/telegram.rst
|
||||
platypush/events/tensorflow.rst
|
||||
platypush/events/todoist.rst
|
||||
platypush/events/torrent.rst
|
||||
platypush/events/travisci.rst
|
||||
platypush/events/trello.rst
|
||||
platypush/events/video.rst
|
||||
platypush/events/weather.rst
|
||||
platypush/events/web.rst
|
||||
platypush/events/web.widget.rst
|
||||
platypush/events/websocket.rst
|
||||
platypush/events/xmpp.rst
|
||||
platypush/events/wiimote.rst
|
||||
platypush/events/zeroborg.rst
|
||||
platypush/events/zeroconf.rst
|
||||
platypush/events/zigbee.mqtt.rst
|
||||
|
|
|
@ -1,58 +1,28 @@
|
|||
Platypush
|
||||
#########
|
||||
|
||||
Description
|
||||
===========
|
||||
Welcome to the Platypush reference of available plugins, backends and event types.
|
||||
|
||||
This is the main documentation hub for Platypush. It includes both the wiki and
|
||||
the complete reference of the available integrations.
|
||||
For more information on Platypush check out:
|
||||
|
||||
Platypush is a general-purpose automation framework that can be used to cover
|
||||
all the cases where you'd use a home automation hub, a media center, a smart
|
||||
assistant, some IFTTT recipes, and a variety of other products and services.
|
||||
* The `main page`_ of the project
|
||||
* The `Gitea page`_ of the project
|
||||
* The `online wiki`_ for quickstart and examples
|
||||
* The `Blog articles`_ for inspiration on use-cases possible projects
|
||||
|
||||
It draws inspiration from the following projects, and it aims to cover all of
|
||||
their use-cases:
|
||||
|
||||
* `Home Assistant <https://www.home-assistant.io/>`_
|
||||
* `Homebridge <https://homebridge.io/>`_
|
||||
* `OpenHAB <https://www.openhab.org/>`_
|
||||
* `IFTTT <https://ifttt.com/>`_
|
||||
* `Tasker <https://tasker.joaoapps.com/>`_
|
||||
|
||||
Useful links
|
||||
============
|
||||
|
||||
* The `main page <https://platypush.tech>`_ of the project.
|
||||
* The `source code <https://git.platypush.tech/platypush/platypush>`_.
|
||||
* The `blog <https://blog.platypush.tech>`_.
|
||||
|
||||
Wiki
|
||||
====
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
wiki/Home
|
||||
wiki/Quickstart
|
||||
wiki/Installation
|
||||
wiki/Plugins-installation
|
||||
wiki/APIs
|
||||
wiki/Variables
|
||||
wiki/Entities
|
||||
wiki/Configuration
|
||||
wiki/A-full-configuration-example
|
||||
wiki/The-Web-interface
|
||||
|
||||
Reference
|
||||
=========
|
||||
.. _main page: https://platypush.tech
|
||||
.. _Gitea page: https://git.platypush.tech/platypush/platypush
|
||||
.. _online wiki: https://git.platypush.tech/platypush/platypush/wiki
|
||||
.. _Blog articles: https://blog.platypush.tech
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
backends
|
||||
plugins
|
||||
events
|
||||
responses
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
``adafruit.io``
|
||||
=================================
|
||||
|
||||
.. automodule:: platypush.backend.adafruit.io
|
||||
:members:
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
``alarm``
|
||||
===========================
|
||||
|
||||
.. automodule:: platypush.backend.alarm
|
||||
:members:
|
|
@ -0,0 +1,6 @@
|
|||
``assistant.google``
|
||||
======================================
|
||||
|
||||
.. automodule:: platypush.backend.assistant.google
|
||||
:members:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
``assistant.snowboy``
|
||||
=======================================
|
||||
|
||||
.. automodule:: platypush.backend.assistant.snowboy
|
||||
:members:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
``button.flic``
|
||||
=================================
|
||||
|
||||
.. automodule:: platypush.backend.button.flic
|
||||
:members:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
``camera.pi``
|
||||
===============================
|
||||
|
||||
.. automodule:: platypush.backend.camera.pi
|
||||
:members:
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
``chat.telegram``
|
||||
===================================
|
||||
|
||||
.. automodule:: platypush.backend.chat.telegram
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``covid19``
|
||||
=============================
|
||||
|
||||
.. automodule:: platypush.backend.covid19
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``file.monitor``
|
||||
==================================
|
||||
|
||||
.. automodule:: platypush.backend.file.monitor
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``foursquare``
|
||||
================================
|
||||
|
||||
.. automodule:: platypush.backend.foursquare
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``github``
|
||||
============================
|
||||
|
||||
.. automodule:: platypush.backend.github
|
||||
:members:
|
|
@ -0,0 +1,6 @@
|
|||
``google.fit``
|
||||
================================
|
||||
|
||||
.. automodule:: platypush.backend.google.fit
|
||||
:members:
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
``google.pubsub``
|
||||
===================================
|
||||
|
||||
.. automodule:: platypush.backend.google.pubsub
|
||||
:members:
|
|
@ -0,0 +1,6 @@
|
|||
``gps``
|
||||
=========================
|
||||
|
||||
.. automodule:: platypush.backend.gps
|
||||
:members:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
``http.poll``
|
||||
===============================
|
||||
|
||||
.. automodule:: platypush.backend.http.poll
|
||||
:members:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
``inotify``
|
||||
=============================
|
||||
|
||||
.. automodule:: platypush.backend.inotify
|
||||
:members:
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
``joystick.jstest``
|
||||
=====================================
|
||||
|
||||
.. automodule:: platypush.backend.joystick.jstest
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``joystick.linux``
|
||||
====================================
|
||||
|
||||
.. automodule:: platypush.backend.joystick.linux
|
||||
:members:
|
|
@ -0,0 +1,6 @@
|
|||
``joystick``
|
||||
==============================
|
||||
|
||||
.. automodule:: platypush.backend.joystick
|
||||
:members:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
``kafka``
|
||||
===========================
|
||||
|
||||
.. automodule:: platypush.backend.kafka
|
||||
:members:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
``light.hue``
|
||||
===============================
|
||||
|
||||
.. automodule:: platypush.backend.light.hue
|
||||
:members:
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
``log.http``
|
||||
==============================
|
||||
|
||||
.. automodule:: platypush.backend.log.http
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``mail``
|
||||
==========================
|
||||
|
||||
.. automodule:: platypush.backend.mail
|
||||
:members:
|
|
@ -0,0 +1,6 @@
|
|||
``midi``
|
||||
==========================
|
||||
|
||||
.. automodule:: platypush.backend.midi
|
||||
:members:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
``mqtt``
|
||||
==========================
|
||||
|
||||
.. automodule:: platypush.backend.mqtt
|
||||
:members:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
``music.mopidy``
|
||||
==================================
|
||||
|
||||
.. automodule:: platypush.backend.music.mopidy
|
||||
:members:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
``music.mpd``
|
||||
===============================
|
||||
|
||||
.. automodule:: platypush.backend.music.mpd
|
||||
:members:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
``music.snapcast``
|
||||
====================================
|
||||
|
||||
.. automodule:: platypush.backend.music.snapcast
|
||||
:members:
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
``music.spotify``
|
||||
===================================
|
||||
|
||||
.. automodule:: platypush.backend.music.spotify
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``nextcloud``
|
||||
===============================
|
||||
|
||||
.. automodule:: platypush.backend.nextcloud
|
||||
:members:
|
|
@ -0,0 +1,6 @@
|
|||
``nfc``
|
||||
=========================
|
||||
|
||||
.. automodule:: platypush.backend.nfc
|
||||
:members:
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
``ping``
|
||||
==========================
|
||||
|
||||
.. automodule:: platypush.backend.ping
|
||||
:members:
|
|
@ -0,0 +1,6 @@
|
|||
``pushbullet``
|
||||
================================
|
||||
|
||||
.. automodule:: platypush.backend.pushbullet
|
||||
:members:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
``scard``
|
||||
===========================
|
||||
|
||||
.. automodule:: platypush.backend.scard
|
||||
:members:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
``sensor.ir.zeroborg``
|
||||
========================================
|
||||
|
||||
.. automodule:: platypush.backend.sensor.ir.zeroborg
|
||||
:members:
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
``sensor.leap``
|
||||
=================================
|
||||
|
||||
.. automodule:: platypush.backend.sensor.leap
|
||||
:members:
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
``stt.deepspeech``
|
||||
====================================
|
||||
|
||||
.. automodule:: platypush.backend.stt.deepspeech
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``stt.picovoice.hotword``
|
||||
===========================================
|
||||
|
||||
.. automodule:: platypush.backend.stt.picovoice.hotword
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``stt.picovoice.speech``
|
||||
==========================================
|
||||
|
||||
.. automodule:: platypush.backend.stt.picovoice.speech
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``todoist``
|
||||
=============================
|
||||
|
||||
.. automodule:: platypush.backend.todoist
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``travisci``
|
||||
==============================
|
||||
|
||||
.. automodule:: platypush.backend.travisci
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``trello``
|
||||
============================
|
||||
|
||||
.. automodule:: platypush.backend.trello
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``weather.buienradar``
|
||||
========================================
|
||||
|
||||
.. automodule:: platypush.backend.weather.buienradar
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``weather.darksky``
|
||||
=====================================
|
||||
|
||||
.. automodule:: platypush.backend.weather.darksky
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``weather.openweathermap``
|
||||
============================================
|
||||
|
||||
.. automodule:: platypush.backend.weather.openweathermap
|
||||
:members:
|
|
@ -0,0 +1,6 @@
|
|||
``wiimote``
|
||||
=============================
|
||||
|
||||
.. automodule:: platypush.backend.wiimote
|
||||
:members:
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
``zwave.mqtt``
|
||||
================================
|
||||
|
||||
.. automodule:: platypush.backend.zwave.mqtt
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``zwave``
|
||||
===========================
|
||||
|
||||
.. automodule:: platypush.backend.zwave
|
||||
:members:
|
|
@ -0,0 +1,6 @@
|
|||
``button.flic``
|
||||
=======================================
|
||||
|
||||
.. automodule:: platypush.message.event.button.flic
|
||||
:members:
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
``chat.telegram``
|
||||
=========================================
|
||||
|
||||
.. automodule:: platypush.message.event.chat.telegram
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``covid19``
|
||||
===================================
|
||||
|
||||
.. automodule:: platypush.message.event.covid19
|
||||
:members:
|
|
@ -1,5 +0,0 @@
|
|||
``flic``
|
||||
========
|
||||
|
||||
.. automodule:: platypush.message.event.flic
|
||||
:members:
|
|
@ -0,0 +1,6 @@
|
|||
``google.fit``
|
||||
======================================
|
||||
|
||||
.. automodule:: platypush.message.event.google.fit
|
||||
:members:
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
``telegram``
|
||||
============
|
||||
|
||||
.. automodule:: platypush.message.event.telegram
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``todoist``
|
||||
===================================
|
||||
|
||||
.. automodule:: platypush.message.event.todoist
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``travisci``
|
||||
====================================
|
||||
|
||||
.. automodule:: platypush.message.event.travisci
|
||||
:members:
|
|
@ -0,0 +1,6 @@
|
|||
``wiimote``
|
||||
===================================
|
||||
|
||||
.. automodule:: platypush.message.event.wiimote
|
||||
:members:
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
``xmpp``
|
||||
========
|
||||
|
||||
.. automodule:: platypush.message.event.xmpp
|
||||
:members:
|
|
@ -1,5 +0,0 @@
|
|||
``application``
|
||||
===============
|
||||
|
||||
.. automodule:: platypush.plugins.application
|
||||
:members:
|
|
@ -0,0 +1,6 @@
|
|||
``assistant.echo``
|
||||
====================================
|
||||
|
||||
.. automodule:: platypush.plugins.assistant.echo
|
||||
:members:
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
``assistant.google.pushtotalk``
|
||||
=================================================
|
||||
|
||||
.. automodule:: platypush.plugins.assistant.google.pushtotalk
|
||||
:members:
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
``assistant.openai``
|
||||
====================
|
||||
|
||||
.. automodule:: platypush.plugins.assistant.openai
|
||||
:members:
|
|
@ -1,5 +0,0 @@
|
|||
``assistant.picovoice``
|
||||
=======================
|
||||
|
||||
.. automodule:: platypush.plugins.assistant.picovoice
|
||||
:members:
|
|
@ -1,5 +0,0 @@
|
|||
``camera.pi.legacy``
|
||||
====================
|
||||
|
||||
.. automodule:: platypush.plugins.camera.pi.legacy
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``chat.irc``
|
||||
============
|
||||
|
||||
.. automodule:: platypush.plugins.chat.irc
|
||||
:members:
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue