git: 2bad8d171afe - main - Uses/cargo: Rework git source support based on patch-in-config sections

From: Tobias Kortkamp <tobik_at_FreeBSD.org>
Date: Mon, 25 Oct 2021 08:56:59 UTC
The branch main has been updated by tobik:

URL: https://cgit.FreeBSD.org/ports/commit/?id=2bad8d171afe848ac88585270964342a55d504ce

commit 2bad8d171afe848ac88585270964342a55d504ce
Author:     Tobias Kortkamp <tobik@FreeBSD.org>
AuthorDate: 2021-09-07 14:08:46 +0000
Commit:     Tobias Kortkamp <tobik@FreeBSD.org>
CommitDate: 2021-10-25 08:49:06 +0000

    Uses/cargo: Rework git source support based on patch-in-config sections
    
    Git sources from `Cargo.lock` are added to `CARGO_CRATES` through
    the normal mechanism of `make cargo-crates` by the porter.  They
    are used to populate `MASTER_SITES`, `DISTFILES` with static
    git-archive(1) tarballs a la `USE_GITHUB`, `USE_GITLAB`.  In the
    configure phase we generate `[patch]` sections in the config file
    which will cause `cargo update` to auto-update `Cargo.lock` to point
    to the appropriate extraction directories.
    
    Normally `cargo update` would connect to the network to update all
    Git sources but since rust-1.55.0 our cargo has been patched to
    skip this when `CARGO_FREEBSD_PORTS_SKIP_GIT_UPDATE` is set in the
    environment.
    
    This replaces the old `CARGO_USE_GITHUB`, `CARGO_USE_GITLAB` hacks
    where this was done by editing all `Cargo.toml` with sed(1) calls.
    
    Additionally, we try to automatically infer the individiual crate
    sub-directories inside the Git sources based on `package.name` in
    `Cargo.toml` to remove the need for `CARGO_GIT_SUBDIR`.
    
    USES=cargo also now sets `WRKSRC_crate_$name` for each crate to
    point to the crate extraction directories.
    
    PR:             256581
    Reviewed by:    jbeich
---
 Mk/Scripts/cargo-crates-git-common.awk    | 105 +++++++++++++++++++++++
 Mk/Scripts/cargo-crates-git-configure.awk | 137 ++++++++++++++++++++++++++++++
 Mk/Scripts/cargo-crates-git-fetch.awk     |  20 +++++
 Mk/Scripts/cargo-crates.awk               |  80 +++--------------
 Mk/Uses/cargo.mk                          | 116 ++++++++++++-------------
 5 files changed, 330 insertions(+), 128 deletions(-)

diff --git a/Mk/Scripts/cargo-crates-git-common.awk b/Mk/Scripts/cargo-crates-git-common.awk
new file mode 100644
index 000000000000..c1c5dcc7ce6e
--- /dev/null
+++ b/Mk/Scripts/cargo-crates-git-common.awk
@@ -0,0 +1,105 @@
+# MAINTAINER: rust@FreeBSD.org
+
+BEGIN {
+	# No approval required to add a new gitlab instance here
+	gitlab_hosts["code.videolan.org"] = 1
+	gitlab_hosts["foss.heptapod.net"] = 1
+	gitlab_hosts["framagit.org"] = 1
+	gitlab_hosts["gitlab.com"] = 1
+	gitlab_hosts["gitlab.common-lisp.net"] = 1
+	gitlab_hosts["gitlab.cs.fau.de"] = 1
+	gitlab_hosts["gitlab.dune-project.org"] = 1
+	gitlab_hosts["gitlab.freedesktop.org"] = 1
+	gitlab_hosts["gitlab.gnome.org"] = 1
+	gitlab_hosts["gitlab.howett.net"] = 1
+	gitlab_hosts["gitlab.inria.fr"] = 1
+	gitlab_hosts["gitlab.isc.org"] = 1
+	gitlab_hosts["gitlab.linphone.org"] = 1
+	gitlab_hosts["gitlab.mathematik.uni-stuttgart.de"] = 1
+	gitlab_hosts["gitlab.mn.tu-dresden.de"] = 1
+	gitlab_hosts["gitlab.mpcdf.mpg.de"] = 1
+	gitlab_hosts["gitlab.redox-os.org"] = 1
+	gitlab_hosts["gitlab.torproject.org"] = 1
+	gitlab_hosts["gitlab.xfce.org"] = 1
+	gitlab_hosts["invent.kde.org"] = 1
+	gitlab_hosts["salsa.debian.org"] = 1
+	gitlab_hosts["source.puri.sm"] = 1
+}
+
+function warn(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z) {
+	printf("WARNING: " fmt "\n", a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z) >"/dev/stderr"
+}
+
+function commit_from_git_url(url) {
+	if (url["query", "tag"]) {
+		return url["query", "tag"]
+	} else {
+		return url["fragment"]
+	}
+}
+
+function split_git_url(info, git_url,		url, path, account, project, commit, i, dir_ver, host) {
+	delete info
+	split_url(url, git_url)
+	url["scheme"] = tolower(url["scheme"])
+	url["host"] = tolower(url["host"])
+	if (url["scheme"] ~ /^git(\+https?)?$/) {
+		if (url["host"] == "github.com") {
+			split(url["path"], path, "/")
+			account = path[2]
+			project = path[3]
+			sub(/\.[gG][iI][tT]$/, "", project)
+			commit = commit_from_git_url(url)
+
+			delete url
+			url["scheme"] = "https"
+			url["host"] = "codeload.github.com"
+			url["path"] = sprintf("/%s/%s/tar.gz/%s", account, project, commit)
+			url["query"] = "dummy"
+			url["query", "dummy"] = "/"
+			info["site"] = join_url(url)
+
+			info["filename"] = sprintf("%s-%s-%s_GH0.tar.gz", account, project, commit)
+
+			# Per bsd.sites.mk:
+			# "GitHub silently converts tags starting with v to not have v in the filename
+			# and extraction directory.  It also replaces + with -."
+			dir_ver = commit
+			sub(/^[vV]/, "", dir_ver)
+			gsub(/\+/, "-", dir_ver)
+			gsub(/--/, "-", dir_ver)
+			info["dir"] = sprintf("%s-%s", project, dir_ver)
+
+			return 1
+		} else if (gitlab_hosts[url["host"]]) {
+			split(url["path"], path, "/")
+			account = path[2]
+			for (i = 3; i < length(path); i++) {
+				account = account "/" path[i]
+			}
+			project = path[i]
+			sub(/\.[gG][iI][tT]$/, "", project)
+			commit = commit_from_git_url(url)
+
+			host = url["host"]
+			delete url
+			url["scheme"] = "https"
+			url["host"] = host
+			url["path"] = sprintf("/%s/%s/-/archive/%s.tar.gz", account, project, commit)
+			url["query"] = "dummy"
+			url["query", "dummy"] = "/"
+			info["site"] = join_url(url)
+
+			gsub(/\//, "-", account)
+			info["filename"] = sprintf("%s-%s-%s_GL0.tar.gz", account, project, commit)
+
+			info["dir"] = sprintf("%s-%s", project, commit)
+
+			return 1
+		}
+	}
+
+	warn("Do not know how to handle %s", git_url)
+	warn("If it points to a GitLab instance try adding the hostname to gitlab_hosts[] at the top of cargo-crates-git-common.awk")
+	return 0
+}
diff --git a/Mk/Scripts/cargo-crates-git-configure.awk b/Mk/Scripts/cargo-crates-git-configure.awk
new file mode 100644
index 000000000000..ade8718e44f6
--- /dev/null
+++ b/Mk/Scripts/cargo-crates-git-configure.awk
@@ -0,0 +1,137 @@
+# MAINTAINER: rust@FreeBSD.org
+
+function parse_sources(		sources_len, raw_sources, i, j, k, original_crate_source, url, crate_source, crate_names, crate_name) {
+	sources_len = 0
+	split(GIT_SOURCES, raw_sources)
+	for (i = 1; i <= length(raw_sources); i++) {
+		j = index(raw_sources[i], "@")
+		if (j == 0) {
+			warn("invalid source: %s\n", raw_sources[i])
+			continue
+		}
+		original_crate_source = substr(raw_sources[i], j + 1)
+		split_url(url, original_crate_source)
+		sub(/^git\+/, "", url["scheme"])
+		delete url["fragment"]
+		delete url["query"]
+		#sub(/\.git$/, "", url["path"])
+		crate_source = join_url(url)
+
+		split(substr(raw_sources[i], 1, j - 1), crate_names, ",")
+		for (k = 1; k <= length(crate_names); k++) {
+			crate_name = crate_names[k]
+			if (!source_crates[crate_source]) {
+				sources[++sources_len] = crate_source
+			}
+			source_crates[crate_source] = source_crates[crate_source] " " crate_name
+			original_crate_sources[crate_source, crate_name] = original_crate_source
+		}
+	}
+}
+
+function get_source_dir(crate_source, crate_name,		git_info, path, in_package, pattern, cmd, cargotoml, line) {
+	if (!split_git_url(git_info, original_crate_sources[crate_source, crate_name])) {
+		exit 1
+	}
+	path = WRKDIR "/" git_info["dir"]
+	# Try to find the first Cargo.toml that defines our crate
+	# We are looking for
+	# [package]
+	# name = "$crate_name"
+	in_package = 0
+	pattern = sprintf("^[ \t]*name[ \t]*=[ \t]*['\"]%s['\"]", crate_name)
+	cmd = FIND " " path " -name Cargo.toml -type f"
+	while ((cmd | getline cargotoml) > 0) {
+		while (getline line <cargotoml) {
+			if (in_package && line ~ pattern) {
+				path = cargotoml
+				sub(/\/Cargo\.toml$/, "", path)
+				close(cmd)
+				close(cargotoml)
+				return path
+			} else if (line ~ /^[ \t]*\[[ \t]*package[ \t]*\][ \t]*$/) {
+				in_package = 1
+			} else if (line ~ /^[ \t]*\[/) {
+				in_package = 0
+			}
+		}
+		close(cargotoml)
+	}
+	close(cmd)
+
+	return path
+}
+
+function find_replaced_crates(input, output,		in_patch_crates_io, line, cols) {
+	delete replaced_crates
+# When Cargo.toml has constructs like this (e.g., www/miniserve, x11/wezterm )
+# [patch.crates-io]
+# mime_guess = { git = "https://github.com/svenstaro/mime_guess.git" }
+# cargo fails to find the replacements we setup.  Check for this
+# and replace with our own [patch.crates-io] section.
+# Note that we need to filter out the original patch section.
+	in_patch_crates_io = 0
+	while (getline line <input) {
+		if (in_patch_crates_io) {
+			if (line ~ /[ \t]*git[ \t]*=/ && line !~ /^[ \t]*#/) {
+				split(line, cols)
+				replaced_crates[cols[1]] = 1
+				print "# " line >output
+				continue
+			}
+		} else if (line ~ /^[ \t]*\[[ \t]*patch\.crates-io[ \t]*\][ \t]*$/) {
+			in_patch_crates_io = 1
+		} else if (line ~ /^[ \t]*\[/) {
+			in_patch_crates_io = 0
+		}
+		print line >output
+	}
+	close(input)
+	close(output)
+}
+
+function add_crates_io_patches(		header_printed, cmd, cargotoml, source, crates) {
+	header_printed = 0
+# --exclude-dir not supported on FreeBSD < 13
+#	cmd = GREP " --include='*/Cargo.toml' --exclude-dir='" CARGO_VENDOR_DIR "' -Flr 'patch.crates-io' " WRKSRC
+	cmd = FIND " " WRKSRC " -name Cargo.toml -not -path '" CARGO_VENDOR_DIR "/*' -exec " GREP " -Flr 'patch.crates-io' {} \\\+"
+	while (cmd | getline cargotoml) {
+		if (0 != system(CP " " cargotoml " " cargotoml ".orig-cargo")) {
+			exit 1
+		}
+		find_replaced_crates(cargotoml ".orig-cargo", cargotoml)
+		if (length(replaced_crates) > 0) {
+			for (i in sources) {
+				source = sources[i]
+				split(source_crates[source], crates)
+				for (j in crates) {
+					if (replaced_crates[crates[j]]) {
+						if (!header_printed) {
+							printf("[patch.crates-io]\n")
+							header_printed = 1
+						}
+						printf("%s = { path = '%s' }\n", crates[j], get_source_dir(source, crates[j]))
+					}
+				}
+			}
+		}
+	}
+	close(cmd)
+}
+
+function add_git_patches(		i, j, source, crates) {
+	for (i = 1; i <= length(sources); i++) {
+		source = sources[i]
+		split(source_crates[source], crates)
+		printf("[patch.'%s']\n", source)
+		for (j = 1; j <= length(crates); j++) {
+			printf("%s = { path = '%s' }\n", crates[j], get_source_dir(source, crates[j]))
+		}
+	}
+}
+
+END {
+	parse_sources()
+	add_crates_io_patches()
+	add_git_patches()
+}
diff --git a/Mk/Scripts/cargo-crates-git-fetch.awk b/Mk/Scripts/cargo-crates-git-fetch.awk
new file mode 100644
index 000000000000..241b6d3b72f2
--- /dev/null
+++ b/Mk/Scripts/cargo-crates-git-fetch.awk
@@ -0,0 +1,20 @@
+# MAINTAINER: rust@FreeBSD.org
+#
+# Return (index, site, filename, wrksrc, crates) 5-tuples from git URL specs in CARGO_CRATES
+
+END {
+	split(GIT_SOURCES, git_sources)
+	for (i = 1; i <= length(git_sources); i++) {
+		git_source = git_sources[i]
+		j = index(git_source, "@")
+		if (j == 0) {
+			warn("invalid source: %s", git_source)
+		} else {
+			crate_source = substr(git_source, j + 1)
+			crates = substr(git_source, 0, j - 1)
+			if (split_git_url(git_info, crate_source)) {
+				printf("%d %s %s %s %s\n", group++, git_info["site"], git_info["filename"], git_info["dir"], crates)
+			}
+		}
+	}
+}
diff --git a/Mk/Scripts/cargo-crates.awk b/Mk/Scripts/cargo-crates.awk
index 56b3beafac11..0cc8fe7a27f9 100644
--- a/Mk/Scripts/cargo-crates.awk
+++ b/Mk/Scripts/cargo-crates.awk
@@ -1,26 +1,15 @@
 # MAINTAINER: rust@FreeBSD.org
 
 BEGIN {
-	gh_tuple_len = 0
-	gl_tuple_len = 0
 	crates_len = 0
-	package_name = "<unknown>"
 	crate_name = "<unknown>"
 	crate_version = "<unknown>"
 	crate_source = "<unknown>"
-
-	gitlab_sites["https://gitlab.com"] = 1
-	gitlab_sites["https://gitlab.freedesktop.org"] = 1
-	gitlab_sites["https://gitlab.gnome.org"] = 1
-	gitlab_sites["https://gitlab.redox-os.org"] = 1
 }
 
 /^name = ".*"/ {
 	crate_name = $3
 	gsub(/"/, "", crate_name)
-
-	package_name = $3
-	gsub("[^a-zA-Z_]", "", package_name)
 }
 
 /^version = ".*"/ {
@@ -38,7 +27,14 @@ BEGIN {
 }
 
 function add_crate() {
-	if (crate_source == "registry+https://github.com/rust-lang/crates.io-index") {
+	if (crate_source ~ /^git\+/) {
+		gsub(/#/, "\\#", crate_source)
+		if (git_crates[crate_source]) {
+			git_crates[crate_source] = git_crates[crate_source] "," crate_name
+		} else {
+			git_crates[crate_source] = crate_name
+		}
+	} else if (crate_source == "registry+https://github.com/rust-lang/crates.io-index") {
 		crates[crates_len++] = sprintf("%s-%s", crate_name, crate_version)
 	}
 	crate_name = "<unknown>"
@@ -46,50 +42,6 @@ function add_crate() {
 	crate_source = "<unknown>"
 }
 
-!gh_tuple_seen[$0] && /^source = "git\+(https|http|git):\/\/.*\/.*#.*"/ {
-	gh_tuple_seen[$0] = 1
-	split_url(url, substr($3, 1 + length("\"git+"), length($3) - 1 - length("\"git+")))
-
-	split(url["path"], path, "/")
-	account = path[2]
-	project = path[3]
-	gsub("\.git$", "", project)
-
-	if (match(url["query"], "^tag=")) {
-		split(url["query"], tag_, "=")
-		tag = tag_[2]
-	} else {
-		tag = url["fragment"]
-	}
-
-	added = 0
-	if (url["host"] == "github.com") {
-		added = 1
-		gh_tuple[gh_tuple_len++] = sprintf(\
-			"%s:%s:%s:%s", account, project, tag, package_name)
-	} else {
-		repo_site = sprintf("%s://%s", url["scheme"], url["host"])
-		for (site in gitlab_sites) {
-			if (repo_site != site) {
-				continue
-			}
-			if (ENVIRON["GL_SITE"] == site) {
-				gl_tuple[gl_tuple_len++] = sprintf(\
-					"%s:%s:%s:%s", account, project, tag, package_name)
-			} else {
-				gl_tuple[gl_tuple_len++] = sprintf(\
-					"%s:%s:%s:%s:%s", site, account, project, tag, package_name)
-			}
-			added = 1
-			break
-		}
-	}
-
-	if (!added) {
-		printf "Warning: Ignoring git source on line %d: %s\n", NR, $3 > "/dev/stderr"
-	}
-}
-
 function print_array(start, arr, arrlen) {
 	end = " \\\n"
 	for (i = 0; i < arrlen; i++) {
@@ -103,20 +55,8 @@ function print_array(start, arr, arrlen) {
 
 END {
 	add_crate()
-
-	if (gh_tuple_len > 0 && ENVIRON["USE_GITHUB"] == "") {
-		printf "USE_GITHUB=\tnodefault\n"
-	}
-	print_array("GH_TUPLE=", gh_tuple, gh_tuple_len)
-	if (gl_tuple_len > 0 && ENVIRON["USE_GITLAB"] == "") {
-		printf "USE_GITLAB=\tnodefault\n"
+	for (crate_source in git_crates) {
+		crates[crates_len++] = git_crates[crate_source] "@" crate_source
 	}
-	print_array("GL_TUPLE=", gl_tuple, gl_tuple_len)
 	print_array("CARGO_CRATES=", crates, crates_len)
-	if (gh_tuple_len > 0) {
-		printf "CARGO_USE_GITHUB=\tyes\n"
-	}
-	if (gl_tuple_len > 0) {
-		printf "CARGO_USE_GITLAB=\tyes\n"
-	}
 }
diff --git a/Mk/Uses/cargo.mk b/Mk/Uses/cargo.mk
index 131b02f52ba1..e1f5544b9c0b 100644
--- a/Mk/Uses/cargo.mk
+++ b/Mk/Uses/cargo.mk
@@ -46,16 +46,53 @@ CARGO_CRATE_EXT=	.crate
 # slow grep runs for every CARGO_CRATE_EXT access.
 CARGO_CRATE_EXT=	${defined(_CARGO_CRATE_EXT_CACHE):?${_CARGO_CRATE_EXT_CACHE}:${:!if ${GREP} -q '\(${CARGO_DIST_SUBDIR}/.*\.tar\.gz\)' "${DISTINFO_FILE}" 2>/dev/null; then ${ECHO_CMD} .tar.gz; else ${ECHO_CMD} .crate; fi!:_=_CARGO_CRATE_EXT_CACHE}}
 .endif
+
+_CARGO_CRATES:=		${CARGO_CRATES:N*@git+*}
+_CARGO_GIT_SOURCES:=	${CARGO_CRATES:M*@git+*}
 # enumerate crates for unqiue and sane distfile group names
-_CARGO_CRATES:=	${empty(CARGO_CRATES):?:${CARGO_CRATES:range:@i@$i ${CARGO_CRATES:[$i]}@}}
+_CARGO_CRATES:=		${empty(_CARGO_CRATES):?:${_CARGO_CRATES:range:@i@$i ${_CARGO_CRATES:[$i]}@}}
 # split up crates into (index, crate, name, version) 4-tuples
-_CARGO_CRATES:=	${_CARGO_CRATES:C/^([-_a-zA-Z0-9]+)-([0-9].*)/\0 \1 \2/}
+_CARGO_CRATES:=		${_CARGO_CRATES:C/^([-_a-zA-Z0-9]+)-([0-9].*)/\0 \1 \2/}
+
 .for _index _crate _name _version in ${_CARGO_CRATES}
 # Resolving CRATESIO alias is very inefficient with many MASTER_SITES, consume MASTER_SITE_CRATESIO directly
 MASTER_SITES+=	${MASTER_SITE_CRATESIO:S,%SUBDIR%,${_name}/${_version},:S,$,:_cargo_${_index},}
 DISTFILES+=	${CARGO_DIST_SUBDIR}/${_crate}${CARGO_CRATE_EXT}:_cargo_${_index}
+
+# Provide pointer to the crate's extraction dir
+WRKSRC_crate_${_name}=	${CARGO_VENDOR_DIR}/${_crate}
+# ...  also with version suffix in case of multiple versions of the
+# same crate
+WRKSRC_crate_${_crate}=	${CARGO_VENDOR_DIR}/${_crate}
 .endfor
 
+_CARGO_AWK=	${AWK} -vCP="${CP}" -vFIND="${FIND}" -vGREP="${GREP}" \
+		-vCARGO_VENDOR_DIR="${CARGO_VENDOR_DIR}" \
+		-vGIT_SOURCES="${_CARGO_GIT_SOURCES}" \
+		-vWRKDIR="${WRKDIR}" -vWRKSRC="${WRKSRC}" \
+		-f${SCRIPTSDIR}/split-url.awk \
+		-f${SCRIPTSDIR}/cargo-crates-git-common.awk -f
+
+.if !empty(_CARGO_GIT_SOURCES)
+.  for _index _site _filename _wrksrc _crates in ${:!${_CARGO_AWK} ${SCRIPTSDIR}/cargo-crates-git-fetch.awk /dev/null!}
+MASTER_SITES+=	${_site}:_cargo_git${_index}
+DISTFILES+=	${_filename}:_cargo_git${_index}
+.    for _crate in ${_crates:S/,/ /g}
+# Make sure the build dependencies checks below can work for git sourced crates too
+_CARGO_CRATES+=	@git ${_crate} ${_crate} @git
+
+# Provide pointer to the crate's extraction dir
+#
+# This might not point to the actual crate's sources since a
+# single git source can contain multiple crates.  We cannot collect
+# subdir information until after the full extraction is done and we
+# cannot set make variables at that point.  This is better than
+# nothing.
+WRKSRC_crate_${_crate}=	${WRKDIR}/${_wrksrc}
+.    endfor
+.  endfor
+.endif
+
 # Build dependencies.
 
 CARGO_BUILDDEP?=	yes
@@ -106,9 +143,8 @@ STRIP_CMD=	${LOCALBASE}/bin/strip # unsupported e_type with base strip
 .endif
 
 # Helper to shorten cargo calls.
-CARGO_CARGO_RUN= \
-	cd ${WRKSRC} && ${SETENV} ${MAKE_ENV} ${CARGO_ENV} \
-		${CARGO_CARGO_BIN}
+_CARGO_RUN=		${SETENV} ${MAKE_ENV} ${CARGO_ENV} ${CARGO_CARGO_BIN}
+CARGO_CARGO_RUN=	cd ${WRKSRC}; ${SETENV} CARGO_FREEBSD_PORTS_SKIP_GIT_UPDATE=1 ${_CARGO_RUN}
 
 # User arguments for cargo targets.
 CARGO_BUILD_ARGS?=
@@ -123,15 +159,6 @@ CARGO_CONFIGURE?=	yes
 CARGO_INSTALL?=	yes
 CARGO_TEST?=	yes
 
-# Set CARGO_USE_GIT{HUB,LAB} to yes if your application requires
-# some dependencies from git repositories hosted on GitHub or
-# GitLab instances.  All Cargo.toml files will be patched to point
-# to the right offline sources based on what is defined in
-# {GH,GL}_TUPLE.  This makes sure that cargo does not attempt to
-# access the network during the build.
-CARGO_USE_GITHUB?=	no
-CARGO_USE_GITLAB?=	no
-
 # rustc stashes intermediary files in TMPDIR (default /tmp) which
 # might cause issues for users that for some reason space limit
 # their /tmp.  WRKDIR should have plenty of space.
@@ -235,7 +262,8 @@ cargo-extract:
 # the local crates directory.
 	@${ECHO_MSG} "===>  Moving crates to ${CARGO_VENDOR_DIR}"
 	@${MKDIR} ${CARGO_VENDOR_DIR}
-.for _crate in ${CARGO_CRATES}
+.for _index _crate _name _version in ${_CARGO_CRATES}
+.  if ${_index} != @git
 	@${MV} ${WRKDIR}/${_crate} ${CARGO_VENDOR_DIR}/${_crate}
 	@${PRINTF} '{"package":"%s","files":{}}' \
 		$$(${SHA256} -q ${DISTDIR}/${CARGO_DIST_SUBDIR}/${_crate}${CARGO_CRATE_EXT}) \
@@ -244,44 +272,9 @@ cargo-extract:
 		${MV} ${CARGO_VENDOR_DIR}/${_crate}/Cargo.toml.orig \
 			${CARGO_VENDOR_DIR}/${_crate}/Cargo.toml.orig-cargo; \
 	fi
+.  endif
 .endfor
 
-_CARGO_GIT_PATCH_CARGOTOML=
-.if ${CARGO_USE_GITHUB:tl} == "yes"
-.  for _group in ${GH_TUPLE:C@^[^:]*:[^:]*:[^:]*:(([^:/]*)?)((/.*)?)@\2@}
-.    if empty(CARGO_GIT_SUBDIR:M${_group}\:*)
-_CARGO_GIT_PATCH_CARGOTOML:= ${_CARGO_GIT_PATCH_CARGOTOML} \
-	-e "s@git *= *['\"](https|http|git)://github.com/${GH_ACCOUNT_${_group}}/${GH_PROJECT_${_group}}(\.git)?/?[\"']@path = \"${WRKSRC_${_group}}\"@"
-.    else
-.      for _group2 _crate _subdir in ${CARGO_GIT_SUBDIR:M${_group}\:*:S,:, ,g}
-_CARGO_GIT_PATCH_CARGOTOML:= ${_CARGO_GIT_PATCH_CARGOTOML} \
-	-e "/^${_crate} =/ s@git *= *['\"](https|http|git)://github.com/${GH_ACCOUNT_${_group}}/${GH_PROJECT_${_group}}(\.git)?/?[\"']@path = \"${WRKSRC_${_group}}/${_subdir}\"@"
-.	endfor
-.    endif
-.  endfor
-.endif
-.if ${CARGO_USE_GITLAB:tl} == "yes"
-.  for _group in ${GL_TUPLE:C@^(([^:]*://[^:/]*(:[0-9]{1,5})?(/[^:]*[^/])?:)?)([^:]*):([^:]*):([^:]*)(:[^:/]*)((/.*)?)@\8@:S/^://}
-.    if empty(CARGO_GIT_SUBDIR:M${_group}\:*)
-_CARGO_GIT_PATCH_CARGOTOML:= ${_CARGO_GIT_PATCH_CARGOTOML} \
-	-e "s@git *= *['\"]${GL_SITE_${_group}}/${GL_ACCOUNT_${_group}}/${GL_PROJECT_${_group}}(\.git)?/?['\"]@path = \"${WRKSRC_${_group}}\"@"
-.    else
-.      for _group2 _crate _subdir in ${CARGO_GIT_SUBDIR:M${_group}\:*:S,:, ,g}
-_CARGO_GIT_PATCH_CARGOTOML:= ${_CARGO_GIT_PATCH_CARGOTOML} \
-	-e "/^${_crate} = / s@git *= *['\"]${GL_SITE_${_group}}/${GL_ACCOUNT_${_group}}/${GL_PROJECT_${_group}}(\.git)?/?['\"]@path = \"${WRKSRC_${_group}}/${_subdir}\"@"
-.      endfor
-.    endif
-.  endfor
-.endif
-
-.if !empty(_CARGO_GIT_PATCH_CARGOTOML)
-_USES_patch+=	600:cargo-patch-git
-
-cargo-patch-git:
-	@${FIND} ${WRKDIR} -name Cargo.toml -type f -exec \
-		${SED} -i.dist -E ${_CARGO_GIT_PATCH_CARGOTOML} {} +
-.endif
-
 .if ${CARGO_CONFIGURE:tl} == "yes"
 _USES_configure+=	250:cargo-configure
 
@@ -291,17 +284,25 @@ cargo-configure:
 # Check that the running kernel has COMPAT_FREEBSD11 required by lang/rust post-ino64
 	@${SETENV} CC="${CC}" OPSYS="${OPSYS}" OSVERSION="${OSVERSION}" WRKDIR="${WRKDIR}" \
 		${SH} ${SCRIPTSDIR}/rust-compat11-canary.sh
+	@${ECHO_MSG} "===>   Cargo config:"
 	@${MKDIR} ${WRKDIR}/.cargo
-	@${ECHO_CMD} "[source.cargo]" > ${WRKDIR}/.cargo/config
-	@${ECHO_CMD} "directory = '${CARGO_VENDOR_DIR}'" >> ${WRKDIR}/.cargo/config
-	@${ECHO_CMD} "[source.crates-io]" >> ${WRKDIR}/.cargo/config
-	@${ECHO_CMD} "replace-with = 'cargo'" >> ${WRKDIR}/.cargo/config
+	@: > ${WRKDIR}/.cargo/config.toml
+	@${ECHO_CMD} "[source.cargo]" >> ${WRKDIR}/.cargo/config.toml
+	@${ECHO_CMD} "directory = '${CARGO_VENDOR_DIR}'" >> ${WRKDIR}/.cargo/config.toml
+	@${ECHO_CMD} "[source.crates-io]" >> ${WRKDIR}/.cargo/config.toml
+	@${ECHO_CMD} "replace-with = 'cargo'" >> ${WRKDIR}/.cargo/config.toml
+.if !empty(_CARGO_GIT_SOURCES)
+	@${_CARGO_AWK} ${SCRIPTSDIR}/cargo-crates-git-configure.awk \
+		/dev/null >> ${WRKDIR}/.cargo/config.toml
+.endif
+	@${CAT} ${WRKDIR}/.cargo/config.toml
 	@if ! ${GREP} -qF '[profile.release]' ${CARGO_CARGOTOML}; then \
 		${ECHO_CMD} "" >> ${CARGO_CARGOTOML}; \
 		${ECHO_CMD} "[profile.release]" >> ${CARGO_CARGOTOML}; \
 		${ECHO_CMD} "opt-level = 2" >> ${CARGO_CARGOTOML}; \
 		${ECHO_CMD} "debug = false" >> ${CARGO_CARGOTOML}; \
 	fi
+	@${ECHO_MSG} "===>   Updating Cargo.lock"
 	@${CARGO_CARGO_RUN} update \
 		--manifest-path ${CARGO_CARGOTOML} \
 		--verbose \
@@ -349,12 +350,11 @@ do-test:
 cargo-crates: extract
 	@if [ ! -r "${CARGO_CARGOLOCK}" ]; then \
 		${ECHO_MSG} "===> ${CARGO_CARGOLOCK} not found.  Trying to generate it..."; \
-		${CARGO_CARGO_RUN} generate-lockfile \
+		cd ${WRKSRC}; ${_CARGO_RUN} generate-lockfile \
 			--manifest-path ${CARGO_CARGOTOML} \
 			--verbose; \
 	fi
-	@${SETENV} USE_GITHUB=${USE_GITHUB} USE_GITLAB=${USE_GITLAB} GL_SITE=${GL_SITE} \
-		${AWK} -f ${SCRIPTSDIR}/split-url.awk -f ${SCRIPTSDIR}/cargo-crates.awk ${CARGO_CARGOLOCK}
+	@${_CARGO_AWK} ${SCRIPTSDIR}/cargo-crates.awk ${CARGO_CARGOLOCK}
 
 # cargo-crates-licenses will try to grab license information from
 # all downloaded crates.