#! /bin/bash

TYPE=$1
DEFAULT_GH_USER=linuxserver
DEFAULT_GH_REPO=proot-apps

if [[ ! -z ${LOCALREPO+x} ]] && [[ ! -z ${PA_REPO_FOLDER+x} ]]; then
  ROOT_DIR=$PA_REPO_FOLDER
else
  ROOT_DIR=$HOME/proot-apps
fi

# Check for deps
if [[ ! -f /usr/bin/curl ]]; then
  echo "Curl was not found on this system please install them to continue"
  exit 1
fi

#### Functions ####

# Get sha for image to download
get_blob_sha() {
  MULTIDIGEST=$(curl -s -f --retry 3 --retry-max-time 20 --retry-connrefused \
    --location \
    --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \
    --header "Accept: application/vnd.oci.image.index.v1+json" \
    --header "Authorization: Bearer ${1}" \
    --user-agent "${UA}" \
    "${2}/${3}")
  if $HOME/.local/bin/jq -e '.layers // empty' <<< "${MULTIDIGEST}" >/dev/null 2>&1; then
    # If there's a layer element it's a single-arch manifest so just get that digest
    $HOME/.local/bin/jq -r '.layers[0].digest' <<< "${MULTIDIGEST}";
  else
    # Otherwise it's multi-arch or has manifest annotations
    if $HOME/.local/bin/jq -e '.manifests[]?.annotations // empty' <<< "${MULTIDIGEST}" >/dev/null 2>&1; then
      # Check for manifest annotations and delete if found
      MULTIDIGEST=$($HOME/.local/bin/jq 'del(.manifests[] | select(.annotations))' <<< "${MULTIDIGEST}")
    fi
    if [[ $($HOME/.local/bin/jq '.manifests | length' <<< "${MULTIDIGEST}") -gt 1 ]]; then
      # If there's still more than one digest, it's multi-arch
      MULTIDIGEST=$($HOME/.local/bin/jq -r ".manifests[] | select(.platform.architecture == \"${4}\").digest?" <<< "${MULTIDIGEST}")
      if [[ -z "${MULTIDIGEST}" ]]; then
        cleanup
      fi
    else
      # Otherwise it's single arch
      MULTIDIGEST=$($HOME/.local/bin/jq -r ".manifests[].digest?" <<< "${MULTIDIGEST}")
    fi
    if DIGEST=$(curl -s -f --retry 3 --retry-max-time 20 --retry-connrefused \
      --location \
      --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \
      --header "Accept: application/vnd.oci.image.manifest.v1+json" \
      --header "Authorization: Bearer ${1}" \
      --user-agent "${UA}" \
      "${2}/${MULTIDIGEST}"); then
      $HOME/.local/bin/jq -r '.layers[0].digest' <<< "${DIGEST}";
    fi
  fi
}

# Trigger panel reload for selkies-desktop
function trigger_panel_reload() {
  if [ -f "$HOME/.config/panel-reload" ]; then
    touch "$HOME/.config/panel-reload"
  fi
}

# Get registry endpoint and auth
registry_setup() {
  IMAGE=$1
  # Determine endpoints and auth
  case "${IMAGE}" in
    ghcr.io/* )
    GHIMAGE=$(echo ${IMAGE} | sed 's|ghcr.io/||g')
    ENDPOINT="${GHIMAGE%%:*}"
    USERNAME="${GHIMAGE%%/*}"
    TAG="${GHIMAGE#*:}"
    REGISTRY="ghcr.io"
    AUTH_URL="https://ghcr.io/token?scope=repository%3A${ENDPOINT}%3Apull"
    ;;
  * )
    ENDPOINT="${IMAGE%%:*}"
    USERNAME="${IMAGE%%/*}"
    TAG="${IMAGE#*:}"
    REGISTRY="registry-1.docker.io"
    AUTH_URL="https://auth.docker.io/token?service=registry.docker.io&scope=repository:${ENDPOINT}:pull"
    ;;
  esac
  MANIFEST_URL="https://${REGISTRY}/v2/${ENDPOINT}/manifests"
  BLOB_URL="https://${REGISTRY}/v2/${ENDPOINT}/blobs/"
  TOKEN="$( 
    curl -s -f --retry 3 --retry-max-time 20 --retry-connrefused \
      "${AUTH_URL}" |
      $HOME/.local/bin/jq -r '.token'
  )"
}

# Download layer
function dl_layer() {
  mkdir -p $ROOT_DIR
  # CLI vars
  IMAGE=$1
  IMAGE_FOLDER=$(echo "${IMAGE}"| sed 's|/|_|g'| sed 's|:|_|g')
  ARCH=$(uname -m| sed 's/x86_64/amd64/g'| sed 's/aarch64/arm64/')
  UA="Mozilla/5.0 (Linux $(uname -m)) kasmweb.com"

  # Destination directory
  mkdir -p "${ROOT_DIR}/${IMAGE_FOLDER}"
  touch "${ROOT_DIR}/${IMAGE_FOLDER}/DOWNLOADING"

  ## Functions ##

  # Cleanup and exit 1 if something went wrong
  cleanup() {
    rm -Rf "${ROOT_DIR}/${IMAGE_FOLDER}"
    exit 1
  }
  
  if [[ -z ${SHALAYER+x} ]]; then
    if [[ ! -z ${PA_REPO_FOLDER+x} ]] && [[ -z ${LOCALREPO+x} ]]; then
      SHALAYER=$(cat $PA_REPO_FOLDER/${IMAGE_FOLDER}/SHALAYER)
    else
      registry_setup ${IMAGE}
      SHALAYER=$(get_blob_sha "${TOKEN}" "${MANIFEST_URL}" "${TAG}" "${ARCH}")
    fi
  fi
  if [[ $? -eq 1 ]]; then
    echo "No manifest available for ${IMAGE}, cannot fetch"
    cleanup
  elif [[ -z "${SHALAYER}" ]]; then
    echo "${IMAGE} digest could not be fetched from ${REGISTRY}"
    cleanup
  fi

  # Download layer
  if [[ ! -z ${PA_REPO_FOLDER+x} ]] && [[ -z ${LOCALREPO+x} ]]; then
    echo "Extracting from local repo"
    tar -xf \
      $PA_REPO_FOLDER/${IMAGE_FOLDER}/app.tar.gz -C \
      "${ROOT_DIR}/${IMAGE_FOLDER}/"
  else
    if [[ ! -z ${LOCALREPO+x} ]] && [[ ! -z ${PA_REPO_FOLDER+x} ]]; then
      curl -f --retry 3 --retry-max-time 20 \
        -o ${ROOT_DIR}/${IMAGE_FOLDER}/app.tar.gz \
        --location \
        --header "Authorization: Bearer ${TOKEN}" \
        --user-agent "${UA}" \
        "${BLOB_URL}${SHALAYER}" 
    else
      curl -f --retry 3 --retry-max-time 20 \
        --location \
        --header "Authorization: Bearer ${TOKEN}" \
        --user-agent "${UA}" \
        "${BLOB_URL}${SHALAYER}" \
        | tar -xzf - -C "${ROOT_DIR}/${IMAGE_FOLDER}/"
    fi
    if [[ $? -ne 0 ]]; then
      echo "Error downloading ${IMAGE}"
      cleanup
    fi
  fi
  # Tag image
  echo "${SHALAYER}" > "${ROOT_DIR}/${IMAGE_FOLDER}/SHALAYER"

  # Cleanup
  rm -f "${ROOT_DIR}/${IMAGE_FOLDER}/DOWNLOADING"
}

# Update Icon cache
function update_icon_cache() {
  if [ ! -f "$HOME/.local/share/icons/hicolor/index.theme" ]; then
    mkdir -p $HOME/.local/share/icons/hicolor
    cp \
      /usr/share/icons/hicolor/index.theme \
      $HOME/.local/share/icons/hicolor/
  fi
  if which gtk-update-icon-cache >/dev/null 2>&1; then
    gtk-update-icon-cache $HOME/.local/share/icons/hicolor >/dev/null 2>&1 
  elif which update-icon-caches >/dev/null 2>&1; then
    update-icon-caches $HOME/.local/share/icons/hicolor >/dev/null 2>&1
  fi
}

# Run a unix socket to relay commands to the host
start_system_socket() {
  if ! pgrep -f ${1}system.socket; then
    rm -f ${1}system.socket
    $HOME/.local/bin/ncat -k -U -l ${1}system.socket | bash &
    BG_PIDS=$(jobs -p)
    chmod 600 ${1}system.socket || :
    tail --pid=$2 -f /dev/null
    kill -9 $BG_PIDS || :
  fi
}

# Run update
function update() {
  IMAGE_FOLDER=$1
  IMAGE=$(echo "${IMAGE_FOLDER}"| sed 's/\(.*\)_/\1:/' | sed 's|_|/|g')
  if [ ! -d "$ROOT_DIR/${IMAGE_FOLDER}/" ]; then
    echo "${IMAGE} not present on system run install or get first"
    exit 1
  fi
  LOCAL_SHA=$(cat "$ROOT_DIR/${IMAGE_FOLDER}/SHALAYER")
  if [[ ! -z ${PA_REPO_FOLDER+x} ]] && [[ -z ${LOCALREPO+x} ]]; then
    if [ ! -f $PA_REPO_FOLDER/${IMAGE_FOLDER}/SHALAYER ]; then
      echo "${IMAGE} is not available in local repo"
      exit 1
    fi
    # Use local SHA
    SHALAYER=$(cat $PA_REPO_FOLDER/${IMAGE_FOLDER}/SHALAYER)
  else
    # Check remote SHA
    ARCH=$(uname -m| sed 's/x86_64/amd64/g'| sed 's/aarch64/arm64/')
    UA="Mozilla/5.0 (Linux $(uname -m)) kasmweb.com"
    registry_setup ${IMAGE}
    SHALAYER=$(get_blob_sha "${TOKEN}" "${MANIFEST_URL}" "${TAG}" "${ARCH}")
  fi
  if [[ "${SHALAYER}" == "${LOCAL_SHA}" ]]; then
    echo "${IMAGE} is up to date: ${LOCAL_SHA}"
  else
    echo "Updating ${IMAGE_FOLDER}"
    # Run remove logic
    if [[ ! -z ${LOCALREPO+x} ]] && [[ ! -z ${PA_REPO_FOLDER+x} ]]; then
      echo "Removing app root local"
      rm -Rf $ROOT_DIR/${IMAGE_FOLDER}/
      dl_layer ${IMAGE}
    else
      if [ -f "$ROOT_DIR/${IMAGE_FOLDER}/remove" ]; then
        $HOME/.local/bin/proot \
          -R $ROOT_DIR/${IMAGE_FOLDER}/ \
          /remove
      fi
      # Remove app layer
      echo "Removing app root"
      rm -Rf $ROOT_DIR/${IMAGE_FOLDER}/
      dl_layer ${IMAGE}
      $HOME/.local/bin/proot \
        -R $ROOT_DIR/${IMAGE_FOLDER}/ \
        /install >/dev/null 2>&1
      # Refresh icon cache
      update_icon_cache
      # Install
      $HOME/.local/bin/proot \
        -R $ROOT_DIR/${IMAGE_FOLDER}/ \
        /install
    fi
    trigger_panel_reload
  fi
}

# Run remove
function remove() {
  IMAGE_FOLDER=$1
  IMAGE=$(echo "${IMAGE_FOLDER}"| sed 's/\(.*\)_/\1:/' | sed 's|_|/|g')
  echo "Removing ${IMAGE}"
  if [ ! -d "$ROOT_DIR/${IMAGE_FOLDER}/" ]; then
    echo "${IMAGE} not present on system run install or get first"
    exit 1
  fi
  if [[ ! -z ${LOCALREPO+x} ]] && [[ ! -z ${PA_REPO_FOLDER+x} ]]; then
    echo "localremove ${IMAGE}"
  else
    # Run remove logic
    if [ -f "$ROOT_DIR/${IMAGE_FOLDER}/remove" ]; then
      $HOME/.local/bin/proot \
        -R $ROOT_DIR/${IMAGE_FOLDER}/ \
        /remove
    fi
    # Remove bin wrapper if defined
    if [ -f "$ROOT_DIR/${IMAGE_FOLDER}/bin-name" ]; then
      rm -f $HOME/.local/bin/$(cat $ROOT_DIR/${IMAGE_FOLDER}/bin-name)
    fi
  fi
  # Remove app layer
  echo "Removing app root"
  rm -Rf $ROOT_DIR/${IMAGE_FOLDER}/
  trigger_panel_reload
}

# Run uninstall
function uninstall() {
  IMAGE_FOLDER=$1
  IMAGE=$(echo "${IMAGE_FOLDER}"| sed 's/\(.*\)_/\1:/' | sed 's|_|/|g')
  echo "Uninstalling ${IMAGE}"
  if [ ! -d "$ROOT_DIR/${IMAGE_FOLDER}/" ]; then
    echo "${IMAGE} not present on system run install or get first"
    exit 1
  fi
  # Run remove logic
  if [ -f "$ROOT_DIR/${IMAGE_FOLDER}/remove" ]; then
    $HOME/.local/bin/proot \
      -R $ROOT_DIR/${IMAGE_FOLDER}/ \
      /remove
  fi
  # Remove bin wrapper if defined
  if [ -f "$ROOT_DIR/${IMAGE_FOLDER}/bin-name" ]; then
    rm -f $HOME/.local/bin/$(cat $ROOT_DIR/${IMAGE_FOLDER}/bin-name)
  fi
  trigger_panel_reload
}

# Install
function install_app() {
  IMAGE=$1
  IMAGE_FOLDER=$(echo "${IMAGE}"| sed 's|/|_|g'| sed 's|:|_|g')
  echo "Installing ${IMAGE}"
  # Download if not present
  if [ ! -d "$ROOT_DIR/${IMAGE_FOLDER}" ]; then
    dl_layer ${IMAGE}
  fi
  # Add bin wrapper if defined
  if [ -f "$ROOT_DIR/${IMAGE_FOLDER}/bin-name" ]; then
    echo "\$HOME/.local/bin/proot-apps run ${IMAGE} \"\$@\"" > $HOME/.local/bin/$(cat $ROOT_DIR/${IMAGE_FOLDER}/bin-name)
    chmod +x $HOME/.local/bin/$(cat $ROOT_DIR/${IMAGE_FOLDER}/bin-name)
    echo "$(cat $ROOT_DIR/${IMAGE_FOLDER}/bin-name) is now available from the command line"
  fi
  $HOME/.local/bin/proot \
    -R $ROOT_DIR/${IMAGE_FOLDER}/ \
    /install >/dev/null 2>&1
  # Refresh icon cache
  update_icon_cache
  # Install
  $HOME/.local/bin/proot \
    -R $ROOT_DIR/${IMAGE_FOLDER}/ \
    /install
  trigger_panel_reload
}

# Get
function get_app() {
  IMAGE=$1
  IMAGE_FOLDER=$(echo "${IMAGE}"| sed 's|/|_|g'| sed 's|:|_|g')
  echo "Getting ${IMAGE}"
  # Download if not present
  if [ ! -d "$ROOT_DIR/${IMAGE_FOLDER}" ]; then
    dl_layer ${IMAGE}
  else
    echo "${IMAGE} present on this system use update to update"
  fi
}

#### Runtime ####

# If a non docker endpoint is passed assume the default repo
if [[ ! -z ${2+x} ]]; then
  if ([[ "${2}" != *"/"* ]] || [[ "${2}" != *":"* ]]) && [[ "${2}" != "all" ]]; then
    IMAGE=ghcr.io/${DEFAULT_GH_USER}/${DEFAULT_GH_REPO}:${2}
  else
    IMAGE=${2}
  fi
fi

# Run the application
if [ "${TYPE}" == "run" ]; then
  if [[ -z ${2+x} ]]; then
    echo "The image is required"
    echo "Usage: proot-apps run myorg/myimage:tag"
    exit 1
  fi
  IMAGE_FOLDER=$(echo "${IMAGE}"| sed 's|/|_|g'| sed 's|:|_|g')
  if [ ! -d "$ROOT_DIR/${IMAGE_FOLDER}/" ]; then
    echo "${IMAGE} not present on system run install or get first"
    exit 1
  fi
  # Docker shims for known desktop containers
  if [ -d "/defaults" ]; then
    PULSE_BIND="-b /defaults:/defaults"
  elif [ -d "/var/run/pulse" ]; then
    PULSE_BIND="-b /var/run/pulse:/var/run/pulse"
  fi
  # Mount repo location for the gui app
  if [[ ! -z ${PA_REPO_FOLDER+x} ]] && [[ "${IMAGE_FOLDER}" == *gui ]]; then
    REPO_BIND="-b ${PA_REPO_FOLDER}:${PA_REPO_FOLDER}"
    mkdir -p "$ROOT_DIR/${IMAGE_FOLDER}${PA_REPO_FOLDER}"
  fi
  # Fonts
  if [ -d "/usr/share/fonts" ] && [ -d "/usr/share/fontconfig" ] && [ -d "/etc/fonts" ]; then
    FONTS_BIND="-b /usr/share/fonts:/usr/share/fonts -b /usr/share/fontconfig:/usr/share/fontconfig -b /etc/fonts:/etc/fonts"
  fi
  $HOME/.local/bin/proot \
    ${PULSE_BIND} ${FONTS_BIND} ${REPO_BIND} -n \
    -R $ROOT_DIR/${IMAGE_FOLDER}/ \
    /entrypoint "${@:3}" &
  start_system_socket "$ROOT_DIR/${IMAGE_FOLDER}/" $!
fi

# Run installation
if [ "${TYPE}" == "install" ]; then
  if [[ -z ${2+x} ]]; then
    echo "The image is required"
    echo "Usage: proot-apps install myorg/myimage:tag"
    exit 1
  fi
  # Install multiple
  if [[ ! -z ${3+x} ]]; then
    for APP in "${@:2}"; do
      if [[ "${APP}" != *"/"* ]] || [[ "${APP}" != *":"* ]]; then
        install_app ghcr.io/${DEFAULT_GH_USER}/${DEFAULT_GH_REPO}:${APP}
      else
        install_app "${APP}"
      fi
      unset SHALAYER
    done
  # Install single or all
  else
    if [[ "${IMAGE}" != "all" ]]; then
      install_app "${IMAGE}"
    else
      if [ -n "$(ls -A $ROOT_DIR 2>/dev/null)" ]; then
        for IMAGE_FOLDER in $(ls $ROOT_DIR); do
          IMAGE=$(echo "${IMAGE_FOLDER}"| sed 's/\(.*\)_/\1:/' | sed 's|_|/|g')
          install_app "${IMAGE}"
        done
      else
        echo "no apps to install"
      fi
    fi
  fi
fi

# Run remove
if [ "${TYPE}" == "remove" ]; then
  if [[ -z ${2+x} ]]; then
    echo "The image is required"
    echo "Usage: proot-apps remove myorg/myimage:tag"
    exit 1
  fi
  # Remove multiple
  if [[ ! -z ${3+x} ]]; then
    for APP in "${@:2}"; do
      if [[ "${APP}" != *"/"* ]] || [[ "${APP}" != *":"* ]]; then
        IMAGE=ghcr.io/${DEFAULT_GH_USER}/${DEFAULT_GH_REPO}:${APP}
        IMAGE_FOLDER=$(echo "${IMAGE}"| sed 's|/|_|g'| sed 's|:|_|g')
        remove "${IMAGE_FOLDER}"
      else
        IMAGE_FOLDER=$(echo "${APP}"| sed 's|/|_|g'| sed 's|:|_|g')
        remove "${IMAGE_FOLDER}"
      fi
    done
  # Uninstall single or all
  else
    if [[ "${IMAGE}" != "all" ]]; then
      IMAGE_FOLDER=$(echo "${IMAGE}"| sed 's|/|_|g'| sed 's|:|_|g')
      remove "${IMAGE_FOLDER}"
    else
      if [ -n "$(ls -A $ROOT_DIR 2>/dev/null)" ]; then
        for IMAGE_FOLDER in $(ls $ROOT_DIR); do
          remove "${IMAGE_FOLDER}"
        done
      else
        echo "no apps to remove"
      fi
    fi
  fi
fi

# Run uninstall
if [ "${TYPE}" == "uninstall" ]; then
  if [[ -z ${2+x} ]]; then
    echo "The image is required"
    echo "Usage: proot-apps uninstall myorg/myimage:tag"
    exit 1
  fi
  # Uninstall multiple
  if [[ ! -z ${3+x} ]]; then
    for APP in "${@:2}"; do
      if [[ "${APP}" != *"/"* ]] || [[ "${APP}" != *":"* ]]; then 
        IMAGE=ghcr.io/${DEFAULT_GH_USER}/${DEFAULT_GH_REPO}:${APP}
        IMAGE_FOLDER=$(echo "${IMAGE}"| sed 's|/|_|g'| sed 's|:|_|g')
        uninstall "${IMAGE_FOLDER}"
      else
        IMAGE_FOLDER=$(echo "${APP}"| sed 's|/|_|g'| sed 's|:|_|g')
        uninstall "${IMAGE_FOLDER}"
      fi
    done
  # Uninstall single or all
  else
    if [[ "${IMAGE}" != "all" ]]; then
      IMAGE_FOLDER=$(echo "${IMAGE}"| sed 's|/|_|g'| sed 's|:|_|g')
      uninstall "${IMAGE_FOLDER}"
    else
      if [ -n "$(ls -A $ROOT_DIR 2>/dev/null)" ]; then
        for IMAGE_FOLDER in $(ls $ROOT_DIR); do
          uninstall "${IMAGE_FOLDER}"
        done
      else
        echo "no apps to uninstall"
      fi
    fi
  fi
fi

# Run update
if [ "${TYPE}" == "update" ]; then
  if [[ -z ${2+x} ]]; then
    echo "The image is required"
    echo "Usage: proot-apps update myorg/myimage:tag"
    exit 1
  fi
  # Update multiple
  if [[ ! -z ${3+x} ]]; then
    for APP in "${@:2}"; do
      if [[ "${APP}" != *"/"* ]] || [[ "${APP}" != *":"* ]]; then
        IMAGE=ghcr.io/${DEFAULT_GH_USER}/${DEFAULT_GH_REPO}:${APP}
        IMAGE_FOLDER=$(echo "${IMAGE}"| sed 's|/|_|g'| sed 's|:|_|g')
        update "${IMAGE_FOLDER}"
      else
        IMAGE_FOLDER=$(echo "${APP}"| sed 's|/|_|g'| sed 's|:|_|g')
        update "${IMAGE_FOLDER}"
      fi
    done
  # Update single or all
  else
    if [[ "${IMAGE}" != "all" ]]; then
      IMAGE_FOLDER=$(echo "${IMAGE}"| sed 's|/|_|g'| sed 's|:|_|g')
      update "${IMAGE_FOLDER}"
    else
      if [ -n "$(ls -A $ROOT_DIR 2>/dev/null)" ]; then
        for IMAGE_FOLDER in $(ls $ROOT_DIR); do
          update "${IMAGE_FOLDER}"
        done
      else
        echo "no apps to update"
      fi
    fi
  fi
fi

# Run get
if [ "${TYPE}" == "get" ]; then
  if [[ -z ${2+x} ]]; then
    echo "The image is required"
    echo "Usage: proot-apps get myorg/myimage:tag"
    exit 1
  fi
  # Get multiple
  if [[ ! -z ${3+x} ]]; then
    for APP in "${@:2}"; do
      if [[ "${APP}" != *"/"* ]] || [[ "${APP}" != *":"* ]]; then
        IMAGE=ghcr.io/${DEFAULT_GH_USER}/${DEFAULT_GH_REPO}:${APP}
        get_app "${IMAGE}"
      else
        get_app "${IMAGE}"
      fi
      unset SHALAYER
    done
  # Get single
  else
    get_app "${IMAGE}"
  fi
fi

# Run localrepo actions
if [ "${TYPE}" == "localrepo" ]; then
  if [ -z ${PA_REPO_FOLDER+x} ]; then
    echo "error: PA_REPO_FOLDER is not set in env"
    exit 1
  fi
  if [[ -z ${2+x} ]] || [[ -z ${3+x} ]]; then
    echo "Usage: proot-apps localrepo [get,remove,update] myorg/myimage:tag"
    exit 1
  fi
  export LOCALREPO=true
  if [[ "${2}" =~ ^(get|remove|update)$ ]]; then
    "$(realpath "$0")" "${@:2}"
  fi
fi

# Usage
if [[ -z ${1+x} ]]; then
  echo "+-----------------------------------------------------------+"
  echo "| Usage:    | proot-apps [type] [image_name]                |"
  echo "+-----------------------------------------------------------+"
  echo "| Run       | proot-apps run myorg/myimage:tag              |"
  echo "| Install   | proot-apps install [myorg/myimage:tag|all]    |"
  echo "| Uninstall | proot-apps uninstall [myorg/myimage:tag|all]  |"
  echo "| Remove    | proot-apps remove [myorg/myimage:tag|all]     |"
  echo "| Get       | proot-apps get myorg/myimage:tag              |"
  echo "| Update    | proot-apps update [myorg/myimage:tag|all]     |"
  echo "+-----------------------------------------------------------+"
fi
