Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJelle van der Waa <jelle@archlinux.org>2024-01-21 13:25:57 +0100
committerChristian Heusel <christian@heusel.eu>2024-03-23 23:57:45 +0100
commit81f5e7b3b3f6e2687ebca03e212e0e7bc2da171f (patch)
treed84fce3878db9e52a8628e359e6d8882ebb22f78
parent01b6b0849ed098d4d3d8db3591443db3df6aa11b (diff)
feat(version): add command to automatically detect and setup nvchecker
Introduce a new version subcommand `setup` which does a best effort to generate the most minimal required .nvchecker.toml file for specific sources. It supports a wide range of common sources like: - Git, GitHub, GitLab, Hackage, NPM, PyPI, RubyGems, CPAN, crates.io The creation logic is based on matching a domain for a source which is something predictable and then simply passes an array of the url parts for every source creator to extract the useful bits out of the url array. Component: pkgctl version setup Co-authored-by: Levente Polyak <anthraxx@archlinux.org> Signed-off-by: Jelle van der Waa <jelle@archlinux.org>
-rw-r--r--contrib/completion/bash/devtools.in12
-rw-r--r--contrib/completion/zsh/_devtools.in10
-rw-r--r--doc/man/pkgctl-version-setup.1.asciidoc120
-rw-r--r--doc/man/pkgctl-version.1.asciidoc7
-rw-r--r--src/lib/common.sh6
-rw-r--r--src/lib/version.sh10
-rw-r--r--src/lib/version/setup.sh528
7 files changed, 693 insertions, 0 deletions
diff --git a/contrib/completion/bash/devtools.in b/contrib/completion/bash/devtools.in
index 11fa234..136c80f 100644
--- a/contrib/completion/bash/devtools.in
+++ b/contrib/completion/bash/devtools.in
@@ -350,6 +350,7 @@ _pkgctl_repo_switch_opts() {
_pkgctl_version_cmds=(
check
+ setup
upgrade
)
@@ -360,6 +361,17 @@ _pkgctl_version_check_args=(
_pkgctl_version_check_opts() { _filedir -d; }
+_pkgctl_version_setup_args=(
+ --prefer-platform-api
+ --url
+ --no-check
+ -f --force
+ -h --help
+)
+
+_pkgctl_version_setup_opts() { _filedir -d; }
+_pkgctl_version_setup_args__url_opts() { :; }
+
_pkgctl_version_upgrade_args=(
-v --verbose
-h --help
diff --git a/contrib/completion/zsh/_devtools.in b/contrib/completion/zsh/_devtools.in
index ee6da85..f430dae 100644
--- a/contrib/completion/zsh/_devtools.in
+++ b/contrib/completion/zsh/_devtools.in
@@ -291,6 +291,7 @@ _pkgctl_args=(
_pkgctl_version_cmds=(
"pkgctl version command"
"check[Compares local package versions against upstream versions]"
+ "setup[Automatically detect and setup a basic nvchecker config]"
"upgrade[Adjust the PKGBUILD to match the latest upstream version]"
)
@@ -300,6 +301,15 @@ _pkgctl_version_check_args=(
'*:git_dir:_files -/'
)
+_pkgctl_version_setup_args=(
+ '(-f --force)'{-f,--force}'[Do not prompt before overwriting]'
+ '--prefer-platform-api[Prefer platform specific GitHub/GitLab API for complex cases]'
+ '--url[Derive check target from URL instead of source array]:url:'
+ '--no-check[Do not run version check after setup]'
+ '(-h --help)'{-h,--help}'[Display usage]'
+ '*:git_dir:_files -/'
+)
+
_pkgctl_version_upgrade_args=(
'(-v --verbose)'{-v,--verbose}'[Display results including up-to-date versions]'
'(-h --help)'{-h,--help}'[Display usage]'
diff --git a/doc/man/pkgctl-version-setup.1.asciidoc b/doc/man/pkgctl-version-setup.1.asciidoc
new file mode 100644
index 0000000..81ef008
--- /dev/null
+++ b/doc/man/pkgctl-version-setup.1.asciidoc
@@ -0,0 +1,120 @@
+pkgctl-version-setup(1)
+=======================
+
+Name
+----
+pkgctl-version-setup - Automatically detect and setup a basic nvchecker config
+
+Synopsis
+--------
+pkgctl version setup [OPTIONS] [PKGBASE...]
+
+Description
+-----------
+
+This subcommand automates the creation of a basic nvchecker(1) configuration
+file by analyzing the source array specified in the PKGBUILD(1) file of a
+package. This command intelligently detects various platforms and APIs (e.g.,
+GitHub, GitLab, PyPI) used by the package sources and generates a corresponding
+`.nvchecker.toml` configuration based on its best guess.
+
+This is particularly useful for initializing nvchecker(1) settings for a
+package without manually crafting the `.nvchecker.toml` file. It simplifies the
+process of setting up version checks, especially when transitioning a package's
+monitoring from one source platform to another or starting version checks for a
+new package.
+
+If no `PKGBASE` is specified, the command defaults to using the current working
+directory.
+
+To obtain a list of supported sources and their expected URL formats, please
+consult the sources section.
+
+Options
+-------
+
+*-f, --force*::
+ Overwrite existing nvchecker(1) configuration
+
+*--prefer-platform-api*::
+ Prefer platform specific GitHub/GitLab API over git for complex cases
+
+*--url* 'URL'::
+ Derive check target from the given URL instead of the source array entries
+
+
+*--no-check*::
+ Do not run pkgctl-version-check(1) after setup
+
+*-h, --help*::
+ Show a help text
+
+Sources
+-------
+
+Here are the currently supported platforms and sources, along with examples of
+URL formats that enable their automatic detection as specific source types:
+
+*Git*::
+ * https://github.com/example/project
+ * https://gitlab.com/example/group/project
+ * git://git.foobar.org/example
+ * git+https://git.foobar.org/example
+
+*GitHub*::
+ * https://github.com/example/project
+ * https://github.com/example/project/archive/v1.0/project-v1.0.tar.gz
+
+*GitLab*::
+ * https://gitlab.com/example/group/project
+ * https://gitlab.archlinux.org/archlinux/devtools.git
+ * https://gitlab.archlinux.org/archlinux/devtools/-/releases/v1.1.0/downloads/devtools-v1.1.0.tar.gz
+
+*Hackage*::
+ * https://hackage.haskell.org/package/xmonad
+ * https://hackage.haskell.org/package/xmonad-0.18.0/xmonad-0.18.0.tar.gz
+ * https://hackage.haskell.org/packages/archive/xmonad/0.18.0/xmonad-0.18.0.tar.gz
+
+*NPM*::
+ * https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz
+ * https://www.npmjs.com/package/node-gyp
+
+*PyPI*::
+ * https://pypi.io/packages/source/p/pyflakes
+ * https://pypi.org/packages/source/b/bleach
+ * https://files.pythonhosted.org/packages/source/p/pyflakes
+ * https://pypi.org/project/SQLAlchemy/
+
+*RubyGems*::
+ * https://rubygems.org/downloads/diff-lcs-1.5.1.gem
+ * https://rubygems.org/gems/diff-lcs
+
+*CPAN*::
+ * https://search.cpan.org/CPAN/authors/id/C/CO/COSIMO/Locale-PO-0.27.tar.gz
+ * https://cpan.metacpan.org/authors/id/C/CO/COSIMO/Locale-PO-0.27.tar.gz
+
+*crates.io*::
+ * https://static.crates.io/crates/shotgun/shotgun-1.0.crate
+ * https://crates.io/api/v1/crates/shotgun/1.0/download
+ * https://crates.io/crates/git-smash
+
+Examples
+--------
+
+*pkgctl version setup*::
+ Detects the source from the current directory's PKGBUILD(1) and
+ sets up a basic `.nvchecker.toml`.
+
+*pkgctl version setup --url https://github.com/example/project*::
+ Generates an `.nvchecker.toml` for the current PKGBUILD(1) but
+ overrides the source URL with the specified GitHub project.
+
+See Also
+--------
+
+pkgctl-version(1)
+pkgctl-version-check(1)
+nvchecker(1)
+PKGBUILD(5)
+
+include::include/footer.asciidoc[]
diff --git a/doc/man/pkgctl-version.1.asciidoc b/doc/man/pkgctl-version.1.asciidoc
index e6e4037..a72173b 100644
--- a/doc/man/pkgctl-version.1.asciidoc
+++ b/doc/man/pkgctl-version.1.asciidoc
@@ -26,6 +26,9 @@ package's pkgbase. The pkgbase section within the `.nvchecker.toml` file
specifies the source and method for checking the latest version of the
corresponding package.
+Use pkgctl-version-setup(1) to automatically detect and setup a basic nvchecker
+config based on the source array of the package PKGBUILD.
+
For detailed information on the various configuration options available for the
`.nvchecker.toml` file, refer to the configuration files section in
nvchecker(1). This documentation provides insights into the possible
@@ -48,6 +51,9 @@ Subcommands
pkgctl version check::
Compares local package versions against upstream
+pkgctl version setup::
+ Automatically detect and setup a basic nvchecker config
+
pkgctl version upgrade::
Adjust the PKGBUILD to match the latest upstream version
@@ -55,6 +61,7 @@ See Also
--------
pkgctl-version-check(1)
+pkgctl-version-setup(1)
pkgctl-version-upgrade(1)
include::include/footer.asciidoc[]
diff --git a/src/lib/common.sh b/src/lib/common.sh
index ff767c6..00ece97 100644
--- a/src/lib/common.sh
+++ b/src/lib/common.sh
@@ -342,3 +342,9 @@ is_debug_package() {
pkgdesc="$(getpkgdesc "${pkgfile}")"
[[ ${pkgdesc} == "Detached debugging symbols for "* && ${pkgbase}-debug = "${pkgname}" ]]
}
+
+join_by() {
+ local IFS="$1"
+ shift
+ echo "$*"
+}
diff --git a/src/lib/version.sh b/src/lib/version.sh
index ac810ae..a18da83 100644
--- a/src/lib/version.sh
+++ b/src/lib/version.sh
@@ -19,6 +19,7 @@ pkgctl_version_usage() {
COMMANDS
check Compares local package versions against upstream
+ setup Automatically detect and setup a basic nvchecker config
upgrade Adjust the PKGBUILD to match the latest upstream version
OPTIONS
@@ -26,6 +27,7 @@ pkgctl_version_usage() {
EXAMPLES
$ ${COMMAND} check libfoo linux libbar
+ $ ${COMMAND} setup libfoo
_EOF_
}
@@ -57,6 +59,14 @@ pkgctl_version() {
pkgctl_version_upgrade "$@"
exit $?
;;
+ setup)
+ _DEVTOOLS_COMMAND+=" $1"
+ shift
+ # shellcheck source=src/lib/version/setup.sh
+ source "${_DEVTOOLS_LIBRARY_DIR}"/lib/version/setup.sh
+ pkgctl_version_setup "$@"
+ exit 0
+ ;;
*)
die "invalid argument: %s" "$1"
;;
diff --git a/src/lib/version/setup.sh b/src/lib/version/setup.sh
new file mode 100644
index 0000000..123862c
--- /dev/null
+++ b/src/lib/version/setup.sh
@@ -0,0 +1,528 @@
+#!/bin/bash
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+[[ -z ${DEVTOOLS_INCLUDE_VERSION_SETUP_SH:-} ]] || return 0
+DEVTOOLS_INCLUDE_VERSION_SETUP_SH=1
+
+_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
+# shellcheck source=src/lib/common.sh
+source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
+# shellcheck source=src/lib/version/check.sh
+source "${_DEVTOOLS_LIBRARY_DIR}"/lib/version/check.sh
+
+source /usr/share/makepkg/util/message.sh
+source /usr/share/makepkg/util/source.sh
+
+set -eo pipefail
+
+
+pkgctl_version_setup_usage() {
+ local -r COMMAND=${_DEVTOOLS_COMMAND:-${BASH_SOURCE[0]##*/}}
+ cat <<- _EOF_
+ Usage: ${COMMAND} [OPTIONS] [PKGBASE]...
+
+ Automate the creation of a basic nvchecker configuration file by
+ analyzing the source array specified in the PKGBUILD file of a package.
+
+ If no PKGBASE is specified, the command defaults to using the current
+ working directory.
+
+ OPTIONS
+ -f, --force Overwrite existing nvchecker configuration
+ --prefer-platform-api Prefer platform specific GitHub/GitLab API for complex cases
+ --url URL Derive check target from URL instead of source array
+ --no-check Do not run version check after setup
+ -h, --help Show this help text
+
+ EXAMPLES
+ $ ${COMMAND} neovim vim
+_EOF_
+}
+
+pkgctl_version_setup() {
+ local pkgbases=()
+ local override_url=
+ local run_check=1
+ local force=0
+ local prefer_platform_api=0
+
+ local path ret
+ local checks=()
+
+ while (( $# )); do
+ case $1 in
+ -h|--help)
+ pkgctl_version_setup_usage
+ exit 0
+ ;;
+ -f|--force)
+ force=1
+ shift
+ ;;
+ --prefer-platform-api)
+ prefer_platform_api=1
+ shift
+ ;;
+ --url)
+ (( $# <= 1 )) && die "missing argument for %s" "$1"
+ override_url=$2
+ shift 2
+ ;;
+ --no-check)
+ run_check=0
+ shift
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*)
+ die "invalid argument: %s" "$1"
+ ;;
+ *)
+ pkgbases=("$@")
+ break
+ ;;
+ esac
+ done
+
+ # Check if used without pkgbases in a packaging directory
+ if (( ${#pkgbases[@]} == 0 )); then
+ if [[ -f PKGBUILD ]]; then
+ pkgbases=(".")
+ else
+ pkgctl_version_setup_usage
+ exit 1
+ fi
+ fi
+
+ ret=0
+ for path in "${pkgbases[@]}"; do
+ # skip paths that are not directories
+ if [[ ! -d "${path}" ]]; then
+ continue
+ fi
+
+ pushd "${path}" >/dev/null
+ if nvchecker_setup "${path}" "${force}" "${prefer_platform_api}" "${override_url}"; then
+ checks+=("${path}")
+ else
+ ret=1
+ fi
+ popd >/dev/null
+ done
+
+ # run checks on the setup targets
+ if (( run_check )) && (( ${#checks[@]} >= 1 )); then
+ echo
+ pkgctl_version_check --verbose "${checks[@]}" || true
+ fi
+
+ return $ret
+}
+
+nvchecker_setup() {
+ local path=$1
+ local force=$2
+ local prefer_platform_api=$3
+ local override_url=$4
+ local pkgbase pkgname source source_url proto domain url_parts section body
+
+ if [[ ! -f PKGBUILD ]]; then
+ msg_error "${BOLD}${path}:${ALL_OFF} no PKGBUILD found"
+ return 1
+ fi
+
+ unset body pkgbase pkgname source url
+ # shellcheck source=contrib/makepkg/PKGBUILD.proto
+ if ! . ./PKGBUILD; then
+ msg_error "${BOLD}${path}:${ALL_OFF} failed to source PKGBUILD"
+ return 1
+ fi
+ pkgbase=${pkgbase:-$pkgname}
+
+ # try to guess from url as last try
+ if [[ -n ${url} ]]; then
+ source+=("${url}")
+ fi
+
+ # handle overwrite of existing config
+ if [[ -f .nvchecker.toml ]] && (( ! force )); then
+ msg_warn "${BOLD}${pkgbase}:${ALL_OFF} nvchecker already configured"
+ return 1
+ fi
+
+ # override the source array with a passed URL
+ if [[ -n ${override_url} ]]; then
+ source=("${override_url}")
+ fi
+
+ # skip empty source array
+ if (( ${#source[@]} == 0 )); then
+ msg_error "${BOLD}${pkgbase}:${ALL_OFF} PKGBUILD has no source array"
+ return 1
+ fi
+
+ for source_url in "${source[@]}"; do
+ # Strips out filename::http for example
+ source_url=$(get_url "${source_url}")
+ # discard query fragments
+ source_url=${source_url%\?*}
+ source_url=${source_url%#*}
+
+ # skip patches
+ if [[ ${source_url} == *.patch ]]; then
+ continue
+ fi
+ # skip signatures
+ if [[ ${source_url} == *.asc ]] || [[ ${source_url} == *.sig ]]; then
+ continue
+ fi
+ # skip local files
+ if [[ ${source_url} != *://* ]]; then
+ continue
+ fi
+
+ # split URL segments while avoiding empty element after protocol and newline at the end
+ mapfile -td / url_parts <<< "${source_url/:\/\//\/}/"
+ unset "url_parts[-1]"
+
+ # extract protocol and domain to select the configuration type
+ proto=${url_parts[0]}
+ domain=${url_parts[1]}
+
+ case "${domain}" in
+ gitlab.*)
+ if (( prefer_platform_api )); then
+ body=$(nvchecker_setup_gitlab "${url_parts[@]}")
+ else
+ body=$(nvchecker_setup_git "${url_parts[@]}")
+ fi
+ break
+ ;;
+ github.com)
+ if (( prefer_platform_api )); then
+ body=$(nvchecker_setup_github "${url_parts[@]}")
+ else
+ body=$(nvchecker_setup_git "${url_parts[@]}")
+ fi
+ break
+ ;;
+ codeberg.org)
+ body=$(nvchecker_setup_git "${url_parts[@]}")
+ break
+ ;;
+ pypi.org|pypi.io|files.pythonhosted.org)
+ body=$(nvchecker_setup_pypi "${url_parts[@]}")
+ break
+ ;;
+ hackage.haskell.org)
+ body=$(nvchecker_setup_hackage "${url_parts[@]}")
+ break
+ ;;
+ registry.npmjs.org|npmjs.com|www.npmjs.com)
+ body=$(nvchecker_setup_npm "${url_parts[@]}")
+ break
+ ;;
+ rubygems.org)
+ body=$(nvchecker_setup_rubygems "${url_parts[@]}")
+ break
+ ;;
+ *.cpan.org|*.mcpan.org|*.metacpan.org)
+ body=$(nvchecker_setup_cpan "${url_parts[@]}")
+ break
+ ;;
+ crates.io|*.crates.io)
+ body=$(nvchecker_setup_crates_io "${url_parts[@]}")
+ break
+ ;;
+ *)
+ if [[ ${proto} == git ]] || [[ ${proto} == git+https ]]; then
+ body=$(nvchecker_setup_git "${url_parts[@]}")
+ fi
+ ;;
+ esac
+ done
+
+ if [[ -z "${body}" ]]; then
+ msg_error "${BOLD}${pkgbase}:${ALL_OFF} unable to automatically setup nvchecker"
+ return 1
+ fi
+
+ # escape the section if it contains toml subsection chars
+ section="${pkgbase}"
+ if [[ ${section} == *.* ]]; then
+ section="\"${section}\""
+ fi
+
+ msg_success "${BOLD}${pkgbase}:${ALL_OFF} successfully configured nvchecker"
+ cat > .nvchecker.toml << EOF
+[${section}]
+${body}
+EOF
+}
+
+get_git_url_from_parts() {
+ local url_parts=("$@")
+ local proto=${url_parts[0]#*+}
+ local domain=${url_parts[1]}
+ local url
+ url="${proto}://$(join_by / "${url_parts[@]:1}")"
+
+ case "${domain}" in
+ gitlab.*)
+ url=${url%/-/*/*}
+ [[ ${url} != *.git ]] && url+=.git
+ ;;
+ github.com|codeberg.org)
+ url="${proto}://$(join_by / "${url_parts[@]:1:3}")"
+ [[ ${url} != *.git ]] && url+=.git
+ ;;
+ esac
+
+ printf '%s' "${url}"
+}
+
+# PyPI
+#
+# As Arch python packages don't necessarily match the pypi name, when the
+# provided source url comes from pypi.io or pypi.org try to extract the package
+# name from the (predictable) tarball download url for example:
+#
+# https://pypi.io/packages/source/p/pyflakes/pyflakes-3.1.0.tar.gz
+# https://pypi.io/packages/source/p/pyflakes
+# https://pypi.org/packages/source/b/bleach
+# https://files.pythonhosted.org/packages/source/p/pyflakes
+# https://pypi.org/project/SQLAlchemy/
+nvchecker_setup_pypi() {
+ local url_parts=("$@")
+ local pypi
+
+ if [[ ${url_parts[2]} == packages ]]; then
+ pypi=${url_parts[5]}
+ elif [[ ${url_parts[2]} == project ]]; then
+ pypi=${url_parts[3]}
+ else
+ return 1
+ fi
+
+ cat << EOF
+source = "pypi"
+pypi = "${pypi}"
+EOF
+}
+
+# Git
+#
+# Set up a generic Git source, while removing the proto specific part from makepkg
+#
+# git+https://github.com/prometheus/prometheus.git
+# https://git.foobar.com/some/path/group/project.git
+# https://gitlab.com/sub/group/project/-/archive/8.0.0/packages-8.0.0.tar.gz
+nvchecker_setup_git() {
+ local url_parts=("$@")
+ local url
+ url=$(get_git_url_from_parts "${url_parts[@]}")
+
+ cat << EOF
+source = "git"
+git = "${url}"
+EOF
+
+ # best effort check if the tags are prefixed with v
+ if git_tags_have_version_prefix "${url}"; then
+ echo 'prefix = "v"'
+ fi
+}
+
+git_tags_have_version_prefix() {
+ local url=$1
+ # best effort check if the tags are prefixed with v
+ if ! grep --max-count=1 --quiet --extended-regex 'refs/tags/v[0-9]+[\.0-9]*$' \
+ <(GIT_TERMINAL_PROMPT=0 git ls-remote --quiet --tags "${url}" 2>/dev/null); then
+ return 1
+ fi
+ return 0
+}
+
+# Github
+#
+# We want to know the $org/$project name from the url
+#
+# https://github.com/prometheus/prometheus/archive/v2.49.1.tar.gz
+nvchecker_setup_github() {
+ local url_parts=("$@")
+ local url project
+ if ! url=$(get_git_url_from_parts "${url_parts[@]}"); then
+ return 1
+ fi
+ project=${url#*://*/}
+ project=${project%.git}
+
+ cat << EOF
+source = "github"
+github = "${project}"
+use_max_tag = true
+EOF
+
+ # best effort check if the tags are prefixed with v
+ if git_tags_have_version_prefix "${url}"; then
+ echo 'prefix = "v"'
+ fi
+}
+
+# GitLab
+#
+# We want to know the $org/$project name from the url
+#
+# git+https://gitlab.com/inkscape/inkscape.git#tag=091e20ef0f204eb40ecde54436e1ef934a03d894
+nvchecker_setup_gitlab() {
+ local url_parts=("$@")
+ local url project host
+ if ! url=$(get_git_url_from_parts "${url_parts[@]}"); then
+ return 1
+ fi
+ project=${url#*://*/}
+ project=${project%.git}
+ cat << EOF
+source = "gitlab"
+gitlab = "${project}"
+EOF
+
+ host=${url#*://}
+ host=${host%%/*}
+ if [[ ${host} != gitlab.com ]]; then
+ echo "host = \"${host}\""
+ fi
+
+ echo "use_max_tag = true"
+
+ # best effort check if the tags are prefixed with v
+ if git_tags_have_version_prefix "${url}"; then
+ echo 'prefix = "v"'
+ fi
+}
+
+# Hackage
+#
+# We want to know the project name
+#
+# https://hackage.haskell.org/package/xmonad
+# https://hackage.haskell.org/package/xmonad-0.18.0/xmonad-0.18.0.tar.gz
+# https://hackage.haskell.org/packages/archive/digits/0.3.1/digits-0.3.1.tar.gz
+nvchecker_setup_hackage() {
+ local url_parts=("$@")
+ local hackage
+
+ if [[ ${url_parts[2]} == packages ]]; then
+ hackage=${url_parts[4]}
+ elif [[ ${url_parts[2]} == package ]] && (( ${#url_parts[@]} == 4 )); then
+ hackage=${url_parts[3]}
+ elif [[ ${url_parts[2]} == package ]] && (( ${#url_parts[@]} >= 5 )); then
+ hackage=${url_parts[3]%-*}
+ else
+ return 1
+ fi
+
+ cat << EOF
+source = "hackage"
+hackage = "${hackage}"
+EOF
+}
+
+# NPM
+#
+# We want to know the project name
+#
+# https://registry.npmjs.org/eslint_d/-/eslint_d-12.1.0.tgz
+# https://www.npmjs.com/package/node-gyp
+nvchecker_setup_npm() {
+ local url_parts=("$@")
+ local npm
+
+ if [[ ${url_parts[1]} == registry.npmjs.org ]]; then
+ npm=${url_parts[2]}
+ elif [[ ${url_parts[2]} == package ]] && (( ${#url_parts[@]} == 4 )); then
+ npm=${url_parts[3]}
+ else
+ return 1
+ fi
+
+ cat << EOF
+source = "npm"
+npm = "${npm}"
+EOF
+}
+
+# RubyGems
+#
+# We want to know the project name
+#
+# https://rubygems.org/downloads/polyglot-0.3.5.gem
+# https://rubygems.org/gems/diff-lcs
+nvchecker_setup_rubygems() {
+ local url_parts=("$@")
+ local gem
+
+ if [[ ${url_parts[2]} == downloads ]]; then
+ gem=${url_parts[-1]%-*}
+ elif [[ ${url_parts[2]} == gems ]]; then
+ gem=${url_parts[3]}
+ else
+ return 1
+ fi
+
+ cat << EOF
+source = "gems"
+gems = "${gem}"
+EOF
+}
+
+# CPAN
+#
+# We want to know the project name
+#
+# source = https://search.cpan.org/CPAN/authors/id/C/CO/COSIMO/Locale-PO-1.2.3.tar.gz
+nvchecker_setup_cpan() {
+ local url_parts=("$@")
+ local cpan=${url_parts[-1]}
+ cpan=${cpan%-*}
+
+ cat << EOF
+source = "cpan"
+cpan = "${cpan}"
+EOF
+}
+
+# crates.io
+#
+# We want to know the crate name
+#
+# https://crates.io/api/v1/crates/${pkgname}/${pkgver}/download
+# https://static.crates.io/crates/${pkgname}/$pkgname-$pkgver.crate
+# https://crates.io/crates/git-smash
+nvchecker_setup_crates_io() {
+ local url_parts=("$@")
+ local crate
+
+ if [[ ${url_parts[2]} == crates ]]; then
+ crate=${url_parts[3]}
+ elif [[ ${url_parts[4]} == crates ]]; then
+ crate=${url_parts[5]}
+ else
+ return 1
+ fi
+
+
+ for i in "${!url_parts[@]}"; do
+ if [[ ${url_parts[i]} == crates ]]; then
+ crate=${url_parts[(( i + 1 ))]}
+ fi
+ done
+
+ cat << EOF
+source = "cratesio"
+cratesio = "${crate}"
+EOF
+}