1function parse_sources(		sources_len, raw_sources, i, j, k, original_crate_source, url, crate_source, crate_names, crate_name) {
2	sources_len = 0
3	split(GIT_SOURCES, raw_sources)
4	for (i = 1; i <= length(raw_sources); i++) {
5		j = index(raw_sources[i], "@")
6		if (j == 0) {
7			warn("invalid source: %s\n", raw_sources[i])
8			continue
9		}
10		original_crate_source = substr(raw_sources[i], j + 1)
11		split_url(url, original_crate_source)
12		sub(/^git\+/, "", url["scheme"])
13		delete url["fragment"]
14		delete url["query"]
15		#sub(/\.git$/, "", url["path"])
16		crate_source = join_url(url)
17
18		split(substr(raw_sources[i], 1, j - 1), crate_names, ",")
19		for (k = 1; k <= length(crate_names); k++) {
20			crate_name = crate_names[k]
21			if (!source_crates[crate_source]) {
22				sources[++sources_len] = crate_source
23			}
24			source_crates[crate_source] = source_crates[crate_source] " " crate_name
25			original_crate_sources[crate_source, crate_name] = original_crate_source
26		}
27	}
28}
29
30function get_source_dir(crate_source, crate_name,		git_info, path, in_package, pattern, cmd, cargotoml, line) {
31	if (!split_git_url(git_info, original_crate_sources[crate_source, crate_name])) {
32		exit 1
33	}
34	path = WRKDIR "/" git_info["dir"]
35	# Try to find the first Cargo.toml that defines our crate
36	# We are looking for
37	# [package]
38	# name = "$crate_name"
39	in_package = 0
40	pattern = sprintf("^[ \t]*name[ \t]*=[ \t]*['\"]%s['\"]", crate_name)
41	cmd = FIND " " path " -name Cargo.toml -type f"
42	while ((cmd | getline cargotoml) > 0) {
43		while (getline line <cargotoml) {
44			if (in_package && line ~ pattern) {
45				path = cargotoml
46				sub(/\/Cargo\.toml$/, "", path)
47				close(cmd)
48				close(cargotoml)
49				return path
50			} else if (line ~ /^[ \t]*\[[ \t]*package[ \t]*\][ \t]*$/) {
51				in_package = 1
52			} else if (line ~ /^[ \t]*\[/) {
53				in_package = 0
54			}
55		}
56		close(cargotoml)
57	}
58	close(cmd)
59
60	return path
61}
62
63function find_replaced_crates(input, output,		in_patch_crates_io, line, cols) {
64	delete replaced_crates
65# When Cargo.toml has constructs like this (e.g., www/miniserve, x11/wezterm )
66# [patch.crates-io]
67# mime_guess = { git = "https://github.com/svenstaro/mime_guess.git" }
68# cargo fails to find the replacements we setup.  Check for this
69# and replace with our own [patch.crates-io] section.
70# Note that we need to filter out the original patch section.
71	in_patch_crates_io = 0
72	while (getline line <input) {
73		if (in_patch_crates_io) {
74			if (line ~ /[ \t]*git[ \t]*=/ && line !~ /^[ \t]*#/) {
75				split(line, cols)
76				replaced_crates[cols[1]] = 1
77				print "# " line >output
78				continue
79			}
80		} else if (line ~ /^[ \t]*\[[ \t]*patch\.crates-io[ \t]*\][ \t]*$/) {
81			in_patch_crates_io = 1
82		} else if (line ~ /^[ \t]*\[/) {
83			in_patch_crates_io = 0
84		}
85		print line >output
86	}
87	close(input)
88	close(output)
89}
90
91function add_crates_io_patches(		header_printed, cmd, cargotoml, source, crates) {
92	header_printed = 0
93# --exclude-dir not supported on FreeBSD < 13
94#	cmd = GREP " --include='*/Cargo.toml' --exclude-dir='" CARGO_VENDOR_DIR "' -Flr 'patch.crates-io' " WRKSRC
95	cmd = FIND " " WRKSRC " -name Cargo.toml -not -path '" CARGO_VENDOR_DIR "/*' -exec " GREP " -Flr 'patch.crates-io' {} \\\+"
96	while (cmd | getline cargotoml) {
97		if (0 != system(CP " " cargotoml " " cargotoml ".orig-cargo")) {
98			exit 1
99		}
100		find_replaced_crates(cargotoml ".orig-cargo", cargotoml)
101		if (length(replaced_crates) > 0) {
102			for (i in sources) {
103				source = sources[i]
104				split(source_crates[source], crates)
105				for (j in crates) {
106					if (replaced_crates[crates[j]]) {
107						if (!header_printed) {
108							printf("[patch.crates-io]\n")
109							header_printed = 1
110						}
111						printf("%s = { path = '%s' }\n", crates[j], get_source_dir(source, crates[j]))
112					}
113				}
114			}
115		}
116	}
117	close(cmd)
118}
119
120function add_git_patches(		i, j, source, crates) {
121	for (i = 1; i <= length(sources); i++) {
122		source = sources[i]
123		split(source_crates[source], crates)
124		printf("[patch.'%s']\n", source)
125		for (j = 1; j <= length(crates); j++) {
126			printf("%s = { path = '%s' }\n", crates[j], get_source_dir(source, crates[j]))
127		}
128	}
129}
130
131END {
132	parse_sources()
133	add_crates_io_patches()
134	add_git_patches()
135}
136