Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copilot Instructions for This Repository
# workspace

Please follow these guidelines when using Copilot or creating code in this repository:

- Language: English.

- All comments, function and variable names, and code must be written in English and follow the Inkypi coding standards and templates. Use the same naming and documentation model across the repository to keep style consistent.
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Project name capitalization is inconsistent: this file refers to "Inkypi" (e.g., "Inkypi coding standards"), while the repository uses "InkyPi" (see README.md). Update the wording to match the project name consistently.

Suggested change
- All comments, function and variable names, and code must be written in English and follow the Inkypi coding standards and templates. Use the same naming and documentation model across the repository to keep style consistent.
- All comments, function and variable names, and code must be written in English and follow the InkyPi coding standards and templates. Use the same naming and documentation model across the repository to keep style consistent.

Copilot uses AI. Check for mistakes.

- When creating a new plugin, or if you have any questions, consult the repository documentation in the `docs/` folder first. Follow the guidance there (plugin architecture, contribution guidelines, coding standards) before opening issues or pull requests.

- When you create or modify code, always run the project's test suite and include the exact command below at the end of your chat response (so the user can run it locally):

source ./venv/bin/activate && pytest -q

- If you add new runnable code, run the tests locally before finishing your response and report the test outcome (pass/fail and summary) in the chat.
- Keep changes small and focused; include any required instructions to reproduce test results.

These instructions are for developer convenience and to keep the repository stable when code is proposed.
119 changes: 119 additions & 0 deletions install/cli/inkypi-plugin
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ usage() {
echo ""
echo "Plugin commands:"
echo " inkypi plugin install <plugin_id> <git_repository_url>"
echo " inkypi plugin update <plugin_id>"
echo " inkypi plugin remove <plugin_id>"
Comment thread
saulob marked this conversation as resolved.
echo " inkypi plugin list"
echo ""
Expand Down Expand Up @@ -157,6 +158,121 @@ list_plugins() {
done
} | column -t -s $'\t'
}
# ----------------------------
# UPDATE
# ----------------------------
update_plugin() {
if [[ $# -ne 1 ]]; then
echo "Usage: inkypi plugin update <plugin_id>"
exit 1
fi

PLUGIN_ID="$1"
DEST_DIR="$PLUGINS_DIR/$PLUGIN_ID"
INFO_FILE="$DEST_DIR/plugin-info.json"

require_plugins_dir

# Check plugin is installed
if [[ ! -d "$DEST_DIR" ]]; then
echo "[ERROR] Plugin '$PLUGIN_ID' is not installed."
exit 1
fi

# Check plugin-info.json exists
if [[ ! -f "$INFO_FILE" ]]; then
echo "[ERROR] Plugin '$PLUGIN_ID' has no plugin-info.json."
exit 1
fi

# Read repository URL from plugin-info.json
REPO_URL=$(jq -r '.repository // empty' "$INFO_FILE")

if [[ -z "$REPO_URL" ]]; then
echo "[ERROR] Plugin '$PLUGIN_ID' has no repository URL in plugin-info.json."
Comment thread
saulob marked this conversation as resolved.
echo "[ERROR] Only third-party plugins with a saved repository can be updated."
exit 1
fi

echo "[INFO] Updating plugin '$PLUGIN_ID' from $REPO_URL"

# Clone into a temporary directory to validate before touching DEST_DIR
TMP_DIR=$(mktemp -d)
trap 'rm -rf "$TMP_DIR"' EXIT

if ! git clone --depth 1 --filter=blob:none --sparse "$REPO_URL" "$TMP_DIR/repo" &>/dev/null; then
echo "[ERROR] Failed to clone repository: $REPO_URL"
exit 1
fi

# Check if the plugin folder exists in the repo
DEFAULT_BRANCH=$(git -C "$TMP_DIR/repo" symbolic-ref --short HEAD 2>/dev/null || echo main)
if ! git -C "$TMP_DIR/repo" ls-tree --name-only "$DEFAULT_BRANCH" | grep -qx "$PLUGIN_ID"; then
echo "[ERROR] Plugin '$PLUGIN_ID' does not exist in the repository."
exit 1
fi

cd "$TMP_DIR/repo"
git sparse-checkout set "$PLUGIN_ID" &>/dev/null

if [[ ! -d "$TMP_DIR/repo/$PLUGIN_ID" ]]; then
echo "[ERROR] Failed to checkout plugin files."
exit 1
fi

# Prepare new plugin files in staging
mkdir -p "$TMP_DIR/staging"
shopt -s dotglob
mv "$TMP_DIR/repo/$PLUGIN_ID"/* "$TMP_DIR/staging/"

Comment thread
saulob marked this conversation as resolved.
# All validated — now replace DEST_DIR
if [[ -d "$DEST_DIR" ]]; then
sudo chown -R "$(whoami)":"$(whoami)" "$DEST_DIR" 2>/dev/null || true
chmod -R u+rw "$DEST_DIR" 2>/dev/null || true
fi

rm -rf "$DEST_DIR"
mkdir -p "$DEST_DIR"
cp -a "$TMP_DIR/staging"/. "$DEST_DIR/"

Comment thread
saulob marked this conversation as resolved.
# Ensure repository URL is preserved in plugin-info.json
if [[ -f "$DEST_DIR/plugin-info.json" ]]; then
CURRENT_REPO=$(jq -r '.repository // empty' "$DEST_DIR/plugin-info.json")
if [[ -z "$CURRENT_REPO" ]]; then
TMP_INFO=$(mktemp)
jq --arg repo "$REPO_URL" '.repository = $repo' "$DEST_DIR/plugin-info.json" > "$TMP_INFO"
mv "$TMP_INFO" "$DEST_DIR/plugin-info.json"
fi
fi

echo "[INFO] Plugin files updated at $DEST_DIR"

# Install requirements if any
REQ_FILE="$DEST_DIR/requirements.txt"

if [[ -f "$REQ_FILE" ]]; then
echo "[INFO] requirements.txt found, installing dependencies..."

if [[ ! -d "$VENV_PATH" ]]; then
echo "[ERROR] Virtual environment not found at $VENV_PATH"
exit 1
fi

source "$VENV_PATH/bin/activate"
pip install -r "$REQ_FILE"
deactivate

echo "[INFO] Dependencies installed"
else
echo "[INFO] No requirements.txt found, skipping dependency install"
fi

echo "[INFO] Restarting $APPNAME service."
sudo systemctl restart "$APPNAME.service"

echo "[INFO] Updated plugin '$PLUGIN_ID' from $REPO_URL"
}

# ----------------------------
# COMMAND ROUTER
# ----------------------------
Expand All @@ -165,6 +281,9 @@ case "$command" in
install)
install_plugin "$@"
;;
update)
update_plugin "$@"
;;
uninstall)
uninstall_plugin "$@"
;;
Expand Down
Loading