yaziPlugins: rewrite update script in python

This commit is contained in:
Austin Horstman
2025-04-09 20:35:40 -05:00
parent 2de042325d
commit 581cdfc6de
3 changed files with 257 additions and 142 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
}:
let
root = ./.;
updateScript = ./update.sh;
updateScript = ./update.py;
mkYaziPlugin =
args@{
+256
View File
@@ -0,0 +1,256 @@
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p python3 python3Packages.requests python3Packages.packaging nix curl git
import os
import re
import subprocess
import sys
from pathlib import Path
from typing import Dict, Tuple
import requests
from packaging import version
def run_command(cmd: str, capture_output: bool = True) -> str:
"""Run a shell command and return its output"""
result = subprocess.run(cmd, shell=True, text=True, capture_output=capture_output)
if result.returncode != 0:
if capture_output:
print(f"Error running command: {cmd}")
print(f"stderr: {result.stderr}")
sys.exit(1)
return result.stdout.strip() if capture_output else ""
def get_plugin_info(nixpkgs_dir: str, plugin_name: str) -> Dict[str, str]:
"""Get plugin repository information from Nix"""
owner = run_command(f"nix eval --raw -f {nixpkgs_dir} yaziPlugins.\"{plugin_name}\".src.owner")
repo = run_command(f"nix eval --raw -f {nixpkgs_dir} yaziPlugins.\"{plugin_name}\".src.repo")
return {
"owner": owner,
"repo": repo
}
def get_yazi_version(nixpkgs_dir: str) -> str:
"""Get the current Yazi version from Nix"""
return run_command(f"nix eval --raw -f {nixpkgs_dir} yazi-unwrapped.version")
def get_github_headers() -> Dict[str, str]:
"""Create headers for GitHub API requests"""
headers = {"Accept": "application/vnd.github.v3+json"}
github_token = os.environ.get("GITHUB_TOKEN")
if github_token:
headers["Authorization"] = f"token {github_token}"
return headers
def fetch_plugin_content(owner: str, repo: str, plugin_pname: str, headers: Dict[str, str]) -> str:
"""Fetch the plugin's main.lua content from GitHub"""
plugin_path = f"{plugin_pname}/" if owner == "yazi-rs" else ""
main_lua_url = f"https://raw.githubusercontent.com/{owner}/{repo}/main/{plugin_path}main.lua"
try:
response = requests.get(main_lua_url, headers=headers)
response.raise_for_status()
return response.text
except requests.RequestException as e:
print(f"Error fetching plugin content: {e}")
sys.exit(1)
def check_version_compatibility(plugin_content: str, plugin_name: str, yazi_version: str) -> str:
"""Check if the plugin is compatible with the current Yazi version"""
required_version_match = re.search(r"since ([0-9.]+)", plugin_content.split("\n")[0])
required_version = required_version_match.group(1) if required_version_match else "0"
if required_version == "0":
print(f"No version requirement found for {plugin_name}, assuming compatible with any Yazi version")
else:
# Check if the plugin is compatible with current Yazi version
if version.parse(required_version) > version.parse(yazi_version):
print(f"{plugin_name} plugin requires Yazi {required_version}, but we have {yazi_version}")
sys.exit(0)
return required_version
def get_latest_commit(owner: str, repo: str, plugin_pname: str, headers: Dict[str, str]) -> Tuple[str, str]:
"""Get the latest commit hash and date for the plugin"""
if owner == "yazi-rs":
# For official plugins, get commit info for the specific plugin file
api_url = f"https://api.github.com/repos/{owner}/{repo}/commits?path={plugin_pname}/main.lua&per_page=1"
else:
# For third-party plugins, get latest commit on main branch
api_url = f"https://api.github.com/repos/{owner}/{repo}/commits/main"
try:
response = requests.get(api_url, headers=headers)
response.raise_for_status()
commit_data = response.json()
except requests.RequestException as e:
print(f"Error fetching commit data: {e}")
sys.exit(1)
if owner == "yazi-rs":
latest_commit = commit_data[0]["sha"]
commit_date = commit_data[0]["commit"]["committer"]["date"].split("T")[0]
else:
latest_commit = commit_data["sha"]
commit_date = commit_data["commit"]["committer"]["date"].split("T")[0]
if not latest_commit:
print("Error: Could not get latest commit hash")
sys.exit(1)
return latest_commit, commit_date
def calculate_sri_hash(owner: str, repo: str, latest_commit: str) -> str:
"""Calculate the SRI hash for the plugin source"""
prefetch_url = f"https://github.com/{owner}/{repo}/archive/{latest_commit}.tar.gz"
try:
new_hash = run_command(f"nix-prefetch-url --unpack --type sha256 {prefetch_url} 2>/dev/null")
# If the hash is not in SRI format, convert it
if not new_hash.startswith("sha256-"):
# Try to convert the hash to SRI format
new_hash = run_command(f"nix hash to-sri --type sha256 {new_hash} 2>/dev/null")
# If that fails, try another approach
if not new_hash.startswith("sha256-"):
print("Warning: Failed to get SRI hash directly, trying alternative method...")
raw_hash = run_command(f"nix-prefetch-url --type sha256 {prefetch_url} 2>/dev/null")
new_hash = run_command(f"nix hash to-sri --type sha256 {raw_hash} 2>/dev/null")
except Exception as e:
print(f"Error calculating hash: {e}")
sys.exit(1)
# Verify we got a valid SRI hash
if not new_hash.startswith("sha256-"):
print(f"Error: Failed to generate valid SRI hash. Output was: {new_hash}")
sys.exit(1)
return new_hash
def read_nix_file(file_path: str) -> str:
"""Read the content of a Nix file"""
try:
with open(file_path, 'r') as f:
return f.read()
except IOError as e:
print(f"Error reading file {file_path}: {e}")
sys.exit(1)
def write_nix_file(file_path: str, content: str) -> None:
"""Write content to a Nix file"""
try:
with open(file_path, 'w') as f:
f.write(content)
except IOError as e:
print(f"Error writing to file {file_path}: {e}")
sys.exit(1)
def update_nix_file(default_nix_path: str, latest_commit: str, new_version: str, new_hash: str) -> None:
"""Update the default.nix file with new version, revision and hash"""
default_nix_content = read_nix_file(default_nix_path)
# Update the revision in default.nix
default_nix_content = re.sub(r'rev = "[^"]*"', f'rev = "{latest_commit}"', default_nix_content)
# Update the version in default.nix
if 'version = "' in default_nix_content:
default_nix_content = re.sub(r'version = "[^"]*"', f'version = "{new_version}"', default_nix_content)
else:
# Add version attribute after pname if it doesn't exist
default_nix_content = re.sub(r'(pname = "[^"]*";)', f'\\1\n version = "{new_version}";', default_nix_content)
# Update hash in default.nix
if 'hash = "' in default_nix_content:
default_nix_content = re.sub(r'hash = "[^"]*"', f'hash = "{new_hash}"', default_nix_content)
elif 'fetchFromGitHub' in default_nix_content:
default_nix_content = re.sub(r'sha256 = "[^"]*"', f'sha256 = "{new_hash}"', default_nix_content)
else:
print(f"Error: Could not find hash attribute in {default_nix_path}")
sys.exit(1)
# Write the updated content back to the file
write_nix_file(default_nix_path, default_nix_content)
# Verify the hash was updated
updated_content = read_nix_file(default_nix_path)
if f'hash = "{new_hash}"' in updated_content or f'sha256 = "{new_hash}"' in updated_content:
print(f"Successfully updated hash to: {new_hash}")
else:
print(f"Error: Failed to update hash in {default_nix_path}")
sys.exit(1)
def validate_environment() -> Tuple[str, str, str]:
"""Validate environment variables and paths"""
nixpkgs_dir = os.getcwd()
plugin_name = os.environ.get("PLUGIN_NAME")
plugin_pname = os.environ.get("PLUGIN_PNAME")
if not plugin_name or not plugin_pname:
print("Error: PLUGIN_NAME and PLUGIN_PNAME environment variables must be set")
sys.exit(1)
plugin_dir = f"{nixpkgs_dir}/pkgs/by-name/ya/yazi/plugins/{plugin_name}"
if not Path(f"{plugin_dir}/default.nix").exists():
print(f"Error: Could not find default.nix for plugin {plugin_name} at {plugin_dir}")
sys.exit(1)
return nixpkgs_dir, plugin_name, plugin_pname
def main():
"""Main function to update a Yazi plugin"""
# Basic setup and validation
nixpkgs_dir, plugin_name, plugin_pname = validate_environment()
plugin_dir = f"{nixpkgs_dir}/pkgs/by-name/ya/yazi/plugins/{plugin_name}"
default_nix_path = f"{plugin_dir}/default.nix"
# Get repository info
plugin_info = get_plugin_info(nixpkgs_dir, plugin_name)
owner = plugin_info["owner"]
repo = plugin_info["repo"]
# Get Yazi version separately
yazi_version = get_yazi_version(nixpkgs_dir)
# Setup GitHub API headers
headers = get_github_headers()
# Check plugin compatibility with current Yazi version
plugin_content = fetch_plugin_content(owner, repo, plugin_pname, headers)
required_version = check_version_compatibility(plugin_content, plugin_name, yazi_version)
# Get latest commit info
latest_commit, commit_date = get_latest_commit(owner, repo, plugin_pname, headers)
print(f"Updating {plugin_name} to commit {latest_commit} ({commit_date})")
# Generate new version string
new_version = f"{required_version}-unstable-{commit_date}"
# Calculate hash for the plugin
new_hash = calculate_sri_hash(owner, repo, latest_commit)
print(f"Generated SRI hash: {new_hash}")
# Update the default.nix file
update_nix_file(default_nix_path, latest_commit, new_version, new_hash)
print(f"Successfully updated {plugin_name} to version {new_version} (commit {latest_commit})")
if __name__ == "__main__":
main()
-141
View File
@@ -1,141 +0,0 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p bash curl coreutils jq git
set -e
# Basic setup and validation
NIXPKGS_DIR="$PWD"
if [ "${PLUGIN_NAME:-}" = "" ] || [ "${PLUGIN_PNAME:-}" = "" ]; then
echo "Error: PLUGIN_NAME and PLUGIN_PNAME environment variables must be set"
exit 1
fi
PLUGIN_DIR="$NIXPKGS_DIR/pkgs/by-name/ya/yazi/plugins/$PLUGIN_NAME"
if [ ! -f "$PLUGIN_DIR/default.nix" ]; then
echo "Error: Could not find default.nix for plugin $PLUGIN_NAME at $PLUGIN_DIR"
exit 1
fi
GITHUB_HEADER=(-H "Accept: application/vnd.github.v3+json")
if [ "${GITHUB_TOKEN:-}" != "" ]; then
GITHUB_HEADER+=(-H "Authorization: token $GITHUB_TOKEN")
fi
# Get repository info and Yazi version
OWNER=$(nix eval --raw -f "$NIXPKGS_DIR" yaziPlugins."$PLUGIN_NAME".src.owner)
REPO=$(nix eval --raw -f "$NIXPKGS_DIR" yaziPlugins."$PLUGIN_NAME".src.repo)
YAZI_VERSION=$(nix eval --raw -f "$NIXPKGS_DIR" yazi-unwrapped.version)
# Check plugin compatibility with current Yazi version
PLUGIN_PATH="$([[ $OWNER == "yazi-rs" ]] && echo "$PLUGIN_PNAME/" || echo "")"
MAIN_LUA_URL="https://raw.githubusercontent.com/$OWNER/$REPO/main/${PLUGIN_PATH}main.lua"
PLUGIN_CONTENT=$(curl --silent "${GITHUB_HEADER[@]}" "$MAIN_LUA_URL")
REQUIRED_VERSION=$(echo "$PLUGIN_CONTENT" | head -n 1 | grep -o "since [0-9.]*" | sed 's/since \([0-9.]*\)/\1/')
# If no version requirement is found, default to "0"
if [ "$REQUIRED_VERSION" = "" ]; then
echo "No version requirement found for $PLUGIN_NAME, assuming compatible with any Yazi version"
REQUIRED_VERSION="0"
else
# Check if the plugin is compatible with current Yazi version
if ! printf "%s\n%s\n" "$REQUIRED_VERSION" "$YAZI_VERSION" | sort -C -V; then
echo "$PLUGIN_NAME plugin requires Yazi $REQUIRED_VERSION, but we have $YAZI_VERSION"
exit 0
fi
fi
# Get latest commit info
if [ "$OWNER" == "yazi-rs" ]; then
# For official plugins, get commit info for the specific plugin file
API_URL="https://api.github.com/repos/$OWNER/$REPO/commits?path=$PLUGIN_PNAME/main.lua&per_page=1"
else
# For third-party plugins, get latest commit on main branch
API_URL="https://api.github.com/repos/$OWNER/$REPO/commits/main"
fi
if [ "$OWNER" == "yazi-rs" ]; then
COMMIT_DATA=$(curl --silent "${GITHUB_HEADER[@]}" "$API_URL")
LATEST_COMMIT=$(echo "$COMMIT_DATA" | jq -r '.[0].sha')
COMMIT_DATE=$(echo "$COMMIT_DATA" | jq -r '.[0].commit.committer.date' | cut -d'T' -f1)
else
COMMIT_DATA=$(curl --silent "${GITHUB_HEADER[@]}" "$API_URL")
LATEST_COMMIT=$(echo "$COMMIT_DATA" | jq -r '.sha')
COMMIT_DATE=$(echo "$COMMIT_DATA" | jq -r '.commit.committer.date' | cut -d'T' -f1)
fi
if [ "$LATEST_COMMIT" = "" ] || [ "$LATEST_COMMIT" == "null" ]; then
echo "Error: Could not get latest commit hash for $PLUGIN_NAME"
exit 1
fi
echo "Updating $PLUGIN_NAME to commit $LATEST_COMMIT ($COMMIT_DATE)"
# Update version and revision
NEW_VERSION="${REQUIRED_VERSION}-unstable-${COMMIT_DATE}"
# Update the revision in default.nix
sed -i "s/rev = \"[^\"]*\"/rev = \"$LATEST_COMMIT\"/" "$PLUGIN_DIR/default.nix"
# Update the version in default.nix
if grep -q 'version = "' "$PLUGIN_DIR/default.nix"; then
sed -i "s/version = \"[^\"]*\"/version = \"$NEW_VERSION\"/" "$PLUGIN_DIR/default.nix"
else
# Add version attribute after pname if it doesn't exist
sed -i "/pname = \"[^\"]*\"/a \ \ version = \"$NEW_VERSION\";" "$PLUGIN_DIR/default.nix"
fi
# Update the hash
# Calculate hash directly for all plugins
PREFETCH_URL="https://github.com/$OWNER/$REPO/archive/$LATEST_COMMIT.tar.gz"
# Get the hash directly in SRI format
NEW_HASH=$(nix-prefetch-url --unpack --type sha256 "$PREFETCH_URL" 2>/dev/null)
# If the hash is not in SRI format, convert it
if [[ ! "$NEW_HASH" =~ ^sha256- ]]; then
# Try to convert the hash to SRI format
NEW_HASH=$(nix hash to-sri --type sha256 "$NEW_HASH" 2>/dev/null)
# If that fails, try another approach
if [[ ! "$NEW_HASH" =~ ^sha256- ]]; then
echo "Warning: Failed to get SRI hash directly, trying alternative method..."
RAW_HASH=$(nix-prefetch-url --type sha256 "$PREFETCH_URL" 2>/dev/null)
NEW_HASH=$(nix hash to-sri --type sha256 "$RAW_HASH" 2>/dev/null)
fi
fi
# Verify we got a valid SRI hash (starts with sha256-)
if [[ ! "$NEW_HASH" =~ ^sha256- ]]; then
echo "Error: Failed to generate valid SRI hash. Output was:"
echo "$NEW_HASH"
exit 1
fi
echo "Generated SRI hash: $NEW_HASH"
# Update hash in default.nix
if grep -q 'hash = "' "$PLUGIN_DIR/default.nix"; then
sed -i "s|hash = \"[^\"]*\"|hash = \"$NEW_HASH\"|" "$PLUGIN_DIR/default.nix"
else
# For files that use fetchFromGitHub, update the hash there
if grep -q 'fetchFromGitHub' "$PLUGIN_DIR/default.nix"; then
sed -i "s|sha256 = \"[^\"]*\"|sha256 = \"$NEW_HASH\"|" "$PLUGIN_DIR/default.nix"
else
echo "Error: Could not find hash attribute in $PLUGIN_DIR/default.nix"
exit 1
fi
fi
# Verify the hash was updated
if grep -q "hash = \"$NEW_HASH\"" "$PLUGIN_DIR/default.nix" || grep -q "sha256 = \"$NEW_HASH\"" "$PLUGIN_DIR/default.nix"; then
echo "Successfully updated hash to: $NEW_HASH"
else
echo "Error: Failed to update hash in $PLUGIN_DIR/default.nix"
exit 1
fi
# Update the revision in default.nix
sed -i "s/rev = \"[^\"]*\"/rev = \"$LATEST_COMMIT\"/" "$PLUGIN_DIR/default.nix"
echo "Successfully updated $PLUGIN_NAME to version $NEW_VERSION (commit $LATEST_COMMIT)"