cpanminus: update to 1.7048.
[void-pkg.git] / common / scripts / lint-conflicts
blobd98cf3b0a01e569490251ea49caf42bb01de178d
1 #!/usr/bin/env bash
3 # Report packages installing same file and not marked with
4 # conflicts or replaces.
5 # Without argument, find conflicts between packages in local
6 # repository at hostdir/binpkgs and packages indexed in xlocate.
7 # With single path as argument, read that local repository.
8 # With -a flag, find conflicts between packages indexed in xlocate.
10 if [ "$#" = 0 ]; then
11 binpkgs="$PWD/hostdir/binpkgs"
12 elif [ "$1" = -a ]; then
13 all=1
14 elif [ -d "$1" ]; then
15 binpkgs="$1"
16 else
17 echo "Usage:"
18 echo "$0"
19 echo " check packages in ./hostdir/binpkgs"
20 echo "$0 path/to/hostdir/binpkgs"
21 echo " check packages there"
22 echo "$0 -a"
23 echo " check all packages indexed in xlocate"
24 exit 1
27 declare -A newly_built conflicts_cache providers_cache pairs owners
28 repositories=("--repository=${binpkgs}/bootstrap" "--repository=${binpkgs}" "--repository=${binpkgs}/nonfree")
29 rv=0
31 template_exists() {
32 [ -f "srcpkgs/$1/template" ]
35 partial_check() {
36 [ -z "$all" ]
39 providers_of() {
40 # print the pkgname and packages that `provides` it
41 local pkgname=$1
42 if [ "${providers_cache[$pkgname]}" = '' ]; then
43 local line provider_pkgver provided_pkgver provider_pkgname provided_pkgname
44 local -A providers
45 providers[$pkgname]=$pkgname
46 while read -r line; do
47 line=${line%%'('*}
48 provider_pkgver=${line%': '*}
49 provided_pkgver=${line#*': '}
50 provider_pkgname=${provider_pkgver%-*}
51 provided_pkgname=${provided_pkgver%-*}
52 # comes from $(xbps-query -s $pkgname), so $pkgname can be substring
53 if [ "$provided_pkgname" = "$pkgname" ]; then
54 providers[$provider_pkgname]=$provider_pkgname
56 done < <(xbps-query "${repositories[@]}" -p provides -R -s "$pkgname")
57 # leading space ensures ${[]} != ''
58 providers_cache[$pkgname]=" ${providers[*]}"
60 echo ${providers_cache[$pkgname]}
63 conflicts_of() {
64 # print list of packages that are _marked_ as conflicting with given one
65 local pkgname=$1
66 if [ "${conflicts_cache[$pkgname]}" = '' ]; then
67 local in_conflict provider
68 local -A all
69 while read -r in_conflict; do
70 in_conflict=${in_conflict%'<'*}
71 in_conflict=${in_conflict%'>'*}
72 providers_of "$in_conflict" > /dev/null # executing in same process to fill cache
73 for provider in $(providers_of "$in_conflict"); do
74 all[$provider]=$provider
75 done
76 done < <(xbps-query "${repositories[@]}" -p conflicts,replaces -R "$pkgname")
77 # leading space ensures ${[]} != ''
78 conflicts_cache[$pkgname]=" ${all[*]}"
80 echo ${conflicts_cache[$pkgname]}
83 conflict_between() {
84 # exit successfully if packages are _marked_ as conflicting
85 conflicts_of "$1" > /dev/null # executing in same process to fill cache
86 case " $(conflicts_of "$1") " in
87 *" $2 "*) return 0
88 esac
89 conflicts_of "$2" > /dev/null # executing in same process to fill cache
90 case " $(conflicts_of "$2") " in
91 *" $1 "*) return 0
92 esac
93 return 1
96 list_newly_built_files() {
97 # print one line per file in newly built packages
98 # each line contains pkgname and file path
99 local pkgver pkgname
100 while read -r pkgver; do
101 pkgname=${pkgver%-*}
102 xbps-query "${repositories[@]}" -i -f "$pkgname" | sed s'/ -> .*//;'" s/^/$pkgname /"
103 done < <(xbps-query "${repositories[@]}" -i -R -s '' | cut -d' ' -f 2)
106 list_interesting_files() {
107 # list files potentially contained in more than one package
108 # each line contains pkgver/pkgname and file path
109 if partial_check; then
110 list_newly_built_files
111 else
112 xlocate / | sed s'/ -> .*//' | grep -F -f <(xlocate / | sed 's/[^[:space:]]*[[:space:]]*//' | sed s'/ -> .*//' | sort | uniq -d)
116 group_by_file_full() {
117 # create associative array `owners` mapping file to list of packages
118 # for packages potentially conflicting with newly built ones
119 local pkgver file pkgname
120 while read -r pkgver file; do
121 pkgname=${pkgver%-*}
122 if template_exists "$pkgname"; then
123 owners[$file]+=" $pkgname"
125 done < <(list_interesting_files)
128 group_by_file_partial() {
129 # create associative array `owners` mapping file to list of packages
130 # for all packages in xlocate
131 local pkgname file
132 ## newly built packages
133 while read -r pkgver; do
134 pkgname=${pkgver%-*}
135 newly_built[$pkgname]=$pkgname
136 done < <(xbps-query "${repositories[@]}" -i -R -s '' | cut -d' ' -f 2)
137 while read -r pkgname file; do
138 owners[$file]+=" $pkgname"
139 done < <(list_newly_built_files)
140 ## rest of repository
141 while read -r pkgver file; do
142 pkgname=${pkgver%-*}
143 if [ -z "${newly_built[$pkgname]}" ] && template_exists "$pkgname"; then
144 owners[$file]+=" $pkgname"
146 done < <(xlocate / | sed s'/ -> .*//' | grep -F -f <(list_newly_built_files | cut -d ' ' -f 2-))
149 group_by_pair() {
150 # find package pairs owning same file and not marked as conflicting
151 local pkg file a b
152 while read -r pkg file; do
153 for a in ${owners[$file]}; do
154 for b in ${owners[$file]}; do
155 if ! [ "$a" "<" "$b" ]; then
156 continue
158 if partial_check && [ -z "${newly_built[$a]}" ] && [ -z "${newly_built[$b]}" ]; then
159 continue
161 if ! conflict_between "$a" "$b"; then
162 unset pair_files
163 local -A pair_files
164 eval "${pairs["$a $b"]}"
165 pair_files[$file]="$file"
166 pairs["$a $b"]="${pair_files[@]@A}"
168 done
169 done
170 done < <(list_interesting_files)
173 print_out() {
174 local pair file
175 if [ "${#pairs[@]}" = 0 ]; then
176 echo 1>&2 "No conflicts found in" "${repositories[@]#*=}"
177 exit 0
179 while read -r pair; do
180 rv=1
181 echo "${pair% *} and ${pair#* } conflict for"
182 unset pair_files
183 eval "${pairs[$pair]}"
184 for file in "${pair_files[@]}"; do
185 echo " $file"
186 done | sort
187 done < <(printf '%s\n' "${!pairs[@]}" | sort)
190 if partial_check; then
191 group_by_file_partial
192 else
193 group_by_file_full
195 group_by_pair
196 print_out
198 exit $rv