diff --git a/pkgs/by-name/ya/yazi/plugins/default.nix b/pkgs/by-name/ya/yazi/plugins/default.nix index 8094f3159d4d..170dedda57b6 100644 --- a/pkgs/by-name/ya/yazi/plugins/default.nix +++ b/pkgs/by-name/ya/yazi/plugins/default.nix @@ -6,7 +6,7 @@ }: let root = ./.; - updateScript = ./update.sh; + updateScript = ./update.py; mkYaziPlugin = args@{ diff --git a/pkgs/by-name/ya/yazi/plugins/update.py b/pkgs/by-name/ya/yazi/plugins/update.py new file mode 100755 index 000000000000..510d2e867a0a --- /dev/null +++ b/pkgs/by-name/ya/yazi/plugins/update.py @@ -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() diff --git a/pkgs/by-name/ya/yazi/plugins/update.sh b/pkgs/by-name/ya/yazi/plugins/update.sh deleted file mode 100755 index 7149fe8698bd..000000000000 --- a/pkgs/by-name/ya/yazi/plugins/update.sh +++ /dev/null @@ -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)"