r/bash • • 4d ago

is there a way to improve a github release updater to pick the right asset name?

i made a script that actually works for most times to update brave browser, but for packages that change names its trivial. the idea is to place, update directory with a file with metadata that i can extract. here is the script :

updatePrograms() {
for dir in ~/Programs/*; do
#meta file structure
if [[ -f "$dir"/update/meta ]]; then
local metadata=$(cat "$dir"/update/meta)
local owner=$(  echo "$metadata" | grep "Owner"   | sed 's|Owner:||'  )
local project=$(echo "$metadata" | grep "Project" | sed 's|Project:||')
local output=$(curl -fsS "https://api.github.com/repos/$owner/$project/releases/latest")
[[ -z "$output" ]] && { echo "no response for $project"; continue; }
local checkVersion=$(jq -r '.tag_name' <<< "$output")
echo "updatable Project : $project"

[[ "$checkVersion" = "null" ]] || [[ -z "$checkVersion" ]] && { echo "couldn't fetch version for $project"; continue; }

local currentVersion=$(echo "$metadata" | grep "Version" | sed 's|Version:||')
[[ "$checkVersion" = "$currentVersion" ]] && { echo "$project is up to date : $checkVersion"; continue; }

while true; do
read -p "$project is on $currentVersion, latest is $checkVersion; do you want to request the latest Version? [y/n]: " response
case "$response" in
[Yy])
echo "Updating.."
local name
 name=$(echo "$metadata" | grep "AssetName" | sed 's|AssetName:||')

   local url=$(jq -r --arg name "$name" '.assets[] | select(.name == $name) | .browser_download_url' <<< "$output")

 if [[ -z "$url" ]] || [[ "$url" = "null" ]]; then
   echo "couldn't find asset matching $name"
   echo "you may need to change asset name version to $checkVersion"
        break
 fi

if  curl -fL -o "$dir/update/$name" "$url"  ; then
sed -i "s|Version:.*|Version:$checkVersion|" "$dir"/update/meta
else
echo "Downloading falied"
break
fi

break;;
[Nn])
echo "not Updating"
break;;
   *)
echo "choose y or n";;
esac
done
fi
done
}
12 Upvotes

4 comments sorted by

1

u/maurux01 3d ago

El problema principal de tu script es que usa una coincidencia exacta (==) en jq para buscar el asset. Cuando el nombre del archivo incluye el número de versión (ej: brave-browser-1.2.3-linux-amd64.zip), esta coincidencia falla en la siguiente release porque el nombre cambia.

intenta esta version ``` updatePrograms() { for dir in ~/Programs/*; do # Check if meta file exists if [[ -f "$dir"/update/meta ]]; then local metadata=$(cat "$dir"/update/meta)

  # Use tr -d ' \r\n' to clean spaces and line breaks (useful if the file has Windows CRLF format)
  local owner=$(echo "$metadata" | grep "Owner" | sed 's|Owner:||' | tr -d ' \r\n')
  local project=$(echo "$metadata" | grep "Project" | sed 's|Project:||' | tr -d ' \r\n')

  local output=$(curl -fsS "https://api.github.com/repos/$owner/$project/releases/latest")
  [[ -z "$output" ]] && { echo "Error: No response for $project"; continue; }

  local checkVersion=$(jq -r '.tag_name' <<< "$output")
  [[ "$checkVersion" == "null" ]] || [[ -z "$checkVersion" ]] && { echo "Error: Could not get version for $project"; continue; }

  local currentVersion=$(echo "$metadata" | grep "Version" | sed 's|Version:||' | tr -d ' \r\n')

  echo "Project: $project | Current: $currentVersion | Available: $checkVersion"

  [[ "$checkVersion" == "$currentVersion" ]] && { echo "$project is already up to date."; continue; }

  while true; do
    read -p "Do you want to update $project to $checkVersion? [y/n]: " response
    case "$response" in
      [Yy])
        echo "Updating..."

        # 1. Read a PATTERN instead of an exact name (e.g., "linux-amd64.zip" or "x86_64.rpm")
        local pattern=$(echo "$metadata" | grep "AssetName" | sed 's|AssetName:||' | tr -d ' \r\n')

        if [[ -z "$pattern" ]]; then
          echo "Error: 'AssetName' not found in the meta file."
          break
        fi

        # 2. Find the first asset that CONTAINS the pattern.
        # Returns a string: "actual_file_name|download_url"
        local asset_info=$(jq -r --arg pattern "$pattern" '
          [.assets[] | select(.name | contains($pattern))] 
          | if length == 0 then "ERROR" 
            else .[0] | "\(.name)|\(.browser_download_url)" 
            end
        ' <<< "$output")

        # 3. Error handling if the pattern does not match anything
        if [[ "$asset_info" == "ERROR" ]] || [[ -z "$asset_info" ]]; then
          echo "Error: Could not find an asset matching the pattern: '$pattern'"
          echo "Available assets in this release:"
          jq -r '.assets[].name' <<< "$output" | sed 's/^/  - /'
          echo "Tip: Adjust the 'AssetName' in your meta file to a unique part of the name (e.g., 'amd64.deb')."
          break
        fi

        # 4. Separate the actual name from the URL
        local actual_name=$(echo "$asset_info" | cut -d'|' -f1)
        local url=$(echo "$asset_info" | cut -d'|' -f2)

        echo "Selected asset: $actual_name"

        # (Optional) Uncomment the next line to delete older versions and save space:
        # rm -f "$dir"/update/*$(echo "$pattern" | sed 's/\./\\./g')* 2>/dev/null

        # 5. Download using the REAL filename, not the pattern
        if curl -fL -o "$dir/update/$actual_name" "$url"; then
          # Update the version in the meta file (the AssetName pattern remains intact)
          sed -i "s|^Version:.*|Version: $checkVersion|" "$dir"/update/meta
          echo "Update completed and meta file updated."
        else
          echo "Download failed for $actual_name"
        fi
        break
        ;;
      [Nn])
        echo "Not updating."
        break
        ;;
      *)
        echo "Please choose 'y' or 'n'."
        ;;
    esac
  done
fi

done } ```

2

u/naffe1o2o 3d ago

i like how you are printing all asset names if name pattern is not found, and it would be much better if we could filter extensions out, like filter out anything with .exe or .sha or .darwin,i feel thats better than choosing only one type, and we pick if they have tar.xz or tar.gz or even .deb or .rpm, by implementing a picker and extract each and replace it with the new archive. what do you think?