From 01b6b0849ed098d4d3d8db3591443db3df6aa11b Mon Sep 17 00:00:00 2001
From: Levente Polyak <anthraxx@archlinux.org>
Date: Sun, 26 Nov 2023 00:37:47 +0100
Subject: doc(man): fix cut off page names by switching to modern asciidoctor

Asciidoc is the old reference implementation in Python, which has some
shortcoming. Specifically we are hitting cut off page names for long
subcommands. Fix this by switching to a more modern implementation named
asciidoctor.

During the migration, get rid of the explicit asciidoc.conf file that
was required to define a linkman macro, which is now supported out of
the box.

Fixes #170

Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
---
 doc/man/pkgctl-version.1.asciidoc | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

(limited to 'doc/man/pkgctl-version.1.asciidoc')

diff --git a/doc/man/pkgctl-version.1.asciidoc b/doc/man/pkgctl-version.1.asciidoc
index fa83314..e6e4037 100644
--- a/doc/man/pkgctl-version.1.asciidoc
+++ b/doc/man/pkgctl-version.1.asciidoc
@@ -15,7 +15,7 @@ Description
 
 Commands related to package versions, including checks for outdated packages.
 
-Uses linkman:nvchecker[1] and a `.nvchecker.toml` file located alongside the
+Uses nvchecker(1) and a `.nvchecker.toml` file located alongside the
 PKGBUILD.
 
 Configuration
@@ -28,7 +28,7 @@ corresponding package.
 
 For detailed information on the various configuration options available for the
 `.nvchecker.toml` file, refer to the configuration files section in
-linkman:nvchecker[1]. This documentation provides insights into the possible
+nvchecker(1). This documentation provides insights into the possible
 options that can be utilized to customize the version checking process.
 
 To supply GitHub or GitLab tokens to nvchecker, a `keyfile.toml` should be
@@ -54,7 +54,7 @@ pkgctl version upgrade::
 See Also
 --------
 
-linkman:pkgctl-version-check[1]
-linkman:pkgctl-version-upgrade[1]
+pkgctl-version-check(1)
+pkgctl-version-upgrade(1)
 
 include::include/footer.asciidoc[]
-- 
cgit v1.2.3-70-g09d2


From 81f5e7b3b3f6e2687ebca03e212e0e7bc2da171f Mon Sep 17 00:00:00 2001
From: Jelle van der Waa <jelle@archlinux.org>
Date: Sun, 21 Jan 2024 13:25:57 +0100
Subject: 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>
---
 contrib/completion/bash/devtools.in     |  12 +
 contrib/completion/zsh/_devtools.in     |  10 +
 doc/man/pkgctl-version-setup.1.asciidoc | 120 ++++++++
 doc/man/pkgctl-version.1.asciidoc       |   7 +
 src/lib/common.sh                       |   6 +
 src/lib/version.sh                      |  10 +
 src/lib/version/setup.sh                | 528 ++++++++++++++++++++++++++++++++
 7 files changed, 693 insertions(+)
 create mode 100644 doc/man/pkgctl-version-setup.1.asciidoc
 create mode 100644 src/lib/version/setup.sh

(limited to 'doc/man/pkgctl-version.1.asciidoc')

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
+}
-- 
cgit v1.2.3-70-g09d2

