|
9 | 9 | # - OR that a #source0 comment is a substring of the cgmanifest URL
|
10 | 10 | # - The URL listed in the cgmanifets is valid (can be downloaded)
|
11 | 11 |
|
12 |
| -# $@ - Paths to spec files to check |
| 12 | +# $1 - Path to worker chroot's archive |
| 13 | +# $2+ - Paths to spec files to check |
13 | 14 |
|
14 |
| -# shellcheck source=../../toolkit/scripts/rpmops.sh |
15 |
| -source "$(git rev-parse --show-toplevel)"/toolkit/scripts/rpmops.sh |
| 15 | +set -euo pipefail |
16 | 16 |
|
17 | 17 | # Specs, which contain multiple source files and are split into many entries inside 'cgmanifest.json'.
|
18 | 18 | ignore_multiple_sources=" \
|
@@ -56,187 +56,194 @@ ignore_no_source_tarball=" \
|
56 | 56 | web-assets \
|
57 | 57 | "
|
58 | 58 |
|
59 |
| -# Specs where cgmanifest validation has known issues checking URLs. |
60 |
| -ignore_known_issues=" \ |
61 |
| - virglrenderer \ |
62 |
| - libesmtp" |
63 |
| - |
64 | 59 | alt_source_tag="Source9999"
|
65 | 60 |
|
66 |
| -function prepare_lua { |
67 |
| - local azl_lua_dir |
68 |
| - local azl_srpm_lua_dir |
69 |
| - local lua_common_path |
70 |
| - local lua_forge_path |
71 |
| - local lua_python_path |
72 |
| - local rpm_lua_dir |
73 |
| - local rpm_macros_dir |
74 |
| - |
75 |
| - rpm_macros_dir="$1" |
76 |
| - |
77 |
| - lua_common_path="common.lua" |
78 |
| - lua_forge_path="srpm/forge.lua" |
79 |
| - lua_python_path="srpm/python.lua" |
80 |
| - rpm_lua_dir="$(rpm --eval "%_rpmluadir")" |
81 |
| - azl_lua_dir="$rpm_lua_dir/azl" |
82 |
| - azl_srpm_lua_dir="$azl_lua_dir/srpm" |
83 |
| - |
84 |
| - if [[ -z "$rpm_lua_dir" ]] |
85 |
| - then |
86 |
| - echo "ERROR: no RPM LUA directory set, can't update with Azure Linux's LUA modules!" >&2 |
87 |
| - exit 1 |
| 61 | +chroot_rpmspec() { |
| 62 | + local chroot_dir_path |
| 63 | + local sourcedir |
| 64 | + |
| 65 | + chroot_dir_path="$1" |
| 66 | + shift |
| 67 | + |
| 68 | + if [[ ! -d "$chroot_dir_path" ]]; then |
| 69 | + echo "Expected a chroot directory as first argument to 'chroot_rpmspec'. Got '$chroot_dir_path'." >&2 |
| 70 | + return 1 |
88 | 71 | fi
|
89 | 72 |
|
90 |
| - # We only want to clean-up directories, which were absent from the system. |
91 |
| - for dir_path in "$rpm_lua_dir" "$azl_lua_dir" "$azl_srpm_lua_dir" |
92 |
| - do |
93 |
| - if [[ ! -d "$dir_path" ]] |
94 |
| - then |
95 |
| - FILES_TO_CLEAN_UP+=("$dir_path") |
| 73 | + # Looking for spec path in the argument list to extract its directory. |
| 74 | + sourcedir="" |
| 75 | + for arg in "$@"; do |
| 76 | + if [[ "$arg" == *.spec && -f "$chroot_dir_path/$arg" ]]; then |
| 77 | + sourcedir="$(dirname "$arg")" |
96 | 78 | break
|
97 | 79 | fi
|
98 | 80 | done
|
99 |
| - sudo mkdir -p "$azl_srpm_lua_dir" |
100 |
| - |
101 |
| - for file_path in "$lua_common_path" "$lua_forge_path" "$lua_python_path" |
102 |
| - do |
103 |
| - system_lua_path="$azl_lua_dir/$file_path" |
104 |
| - if [[ ! -f "$system_lua_path" ]] |
105 |
| - then |
106 |
| - sudo cp "$rpm_macros_dir/$(basename "$file_path")" "$system_lua_path" |
107 |
| - FILES_TO_CLEAN_UP+=("$system_lua_path") |
108 |
| - fi |
109 |
| - done |
110 |
| -} |
111 | 81 |
|
112 |
| -function specs_dir_from_spec_path { |
113 |
| - # Assuming we always check specs inside Azure Linux's core GitHub repository. |
114 |
| - # If that's the case, the spec paths will always have the following form: |
115 |
| - # [repo_directory_path]/[specs_directory]/[package_name]/[package_spec_files] |
116 |
| - echo "$(realpath "$(dirname "$1")/../../SPECS")/azurelinux-rpm-macros" |
| 82 | + if [[ -z $sourcedir ]]; then |
| 83 | + echo "Must pass valid spec path to 'chroot_rpmspec'!" >&2 |
| 84 | + return 1 |
| 85 | + fi |
| 86 | + |
| 87 | + sudo chroot "$chroot_dir_path" rpmspec -D "_sourcedir $sourcedir" "$@" |
117 | 88 | }
|
118 | 89 |
|
119 |
| -rm -f bad_registrations.txt |
120 |
| -rm -rf ./cgmanifest_test_dir/ |
| 90 | +prepare_chroot_environment() { |
| 91 | + local chroot_archive |
| 92 | + local chroot_dir_path |
| 93 | + local chroot_rpm_macros_dir_path |
| 94 | + local dist_name |
| 95 | + local dist_number |
| 96 | + local dist_tag |
| 97 | + local rpm_macros_dir_path |
| 98 | + |
| 99 | + chroot_archive="$1" |
| 100 | + chroot_dir_path="$2" |
| 101 | + |
| 102 | + echo "Creating worker chroot under '$chroot_dir_path'." |
| 103 | + |
| 104 | + sudo tar -xf "$chroot_archive" -C "$chroot_dir_path" |
| 105 | + sudo chown -R "$(id -u):$(id -g)" "$chroot_dir_path" |
| 106 | + |
| 107 | + rpm_macros_dir_path="$(sudo chroot "$chroot_dir_path" rpm --eval '%{_rpmmacrodir}')" |
| 108 | + echo "Creating the RPM macros directory '$rpm_macros_dir_path' in the chroot." |
| 109 | + chroot_rpm_macros_dir_path="$chroot_dir_path/$rpm_macros_dir_path" |
| 110 | + mkdir -vp "$chroot_rpm_macros_dir_path" |
| 111 | + |
| 112 | + echo "Setting RPM's macros for the RPM queries inside the new chroot:" |
| 113 | + dist_tag=$(make -sC toolkit get-dist-tag) |
| 114 | + # Dist name is extracted from the dist tag by removing the leading dot and the number suffix. |
| 115 | + # Example: ".azl3" -> "azl" |
| 116 | + dist_name="$(sed -E 's/^\.(.*)[0-9]+$/\1/' <<<"$dist_tag")" |
| 117 | + # Dist number is the number suffix of the dist tag. |
| 118 | + # Example: ".azl3" -> "3" |
| 119 | + dist_number="$(grep -oP "\d+$" <<<"$dist_tag")" |
| 120 | + echo "%dist $dist_tag" | tee "$chroot_rpm_macros_dir_path/macros.dist" |
| 121 | + echo "%$dist_name $dist_number" | tee -a "$chroot_rpm_macros_dir_path/macros.dist" |
| 122 | + echo "%with_check 1" | tee -a "$chroot_rpm_macros_dir_path/macros.dist" |
| 123 | + for macro_file in SPECS/azurelinux-rpm-macros/macros* SPECS/pyproject-rpm-macros/macros.pyproject SPECS/perl/macros.perl; do |
| 124 | + sudo cp -v "$macro_file" "$chroot_rpm_macros_dir_path" |
| 125 | + done |
| 126 | + |
| 127 | + echo |
| 128 | +} |
121 | 129 |
|
122 |
| -if [[ $# -eq 0 ]] |
123 |
| -then |
| 130 | +if [[ $# -lt 2 ]]; then |
124 | 131 | echo "No specs passed to validate."
|
125 |
| - exit |
| 132 | + exit 1 |
| 133 | +fi |
| 134 | + |
| 135 | +if [[ ! -f "$1" ]]; then |
| 136 | + echo "First argument is not a valid file. Please pass the path to the worker chroot's archive." |
| 137 | + exit 1 |
126 | 138 | fi
|
127 | 139 |
|
| 140 | +rm -f bad_registrations.txt |
| 141 | + |
128 | 142 | WORK_DIR=$(mktemp -d -t)
|
129 |
| -FILES_TO_CLEAN_UP=("$WORK_DIR") |
130 | 143 | function clean_up {
|
131 |
| - echo "Cleaning up..." |
132 |
| - for file_path in "${FILES_TO_CLEAN_UP[@]}" |
133 |
| - do |
134 |
| - echo " Removing ($file_path)." |
135 |
| - sudo rm -rf "$file_path" |
136 |
| - done |
| 144 | + echo "Removing the temporary directory '$WORK_DIR'." |
| 145 | + rm -rf "$WORK_DIR" |
137 | 146 | }
|
138 | 147 | trap clean_up EXIT SIGINT SIGTERM
|
139 | 148 |
|
| 149 | +prepare_chroot_environment "$1" "$WORK_DIR" |
140 | 150 |
|
141 |
| -azl_macros_dir="$(specs_dir_from_spec_path "$1")" |
142 |
| -prepare_lua "$azl_macros_dir" |
143 |
| - |
| 151 | +shift # Remove the first argument (the chroot archive) from the list of specs to check. |
144 | 152 | echo "Checking $# specs."
|
145 | 153 |
|
146 | 154 | i=0
|
147 |
| -for original_spec in "$@" |
148 |
| -do |
149 |
| - i=$((i+1)) |
150 |
| - echo "[$i/$#] Checking $original_spec" |
151 |
| - |
| 155 | +for original_spec in "$@"; do |
| 156 | + i=$((i + 1)) |
| 157 | + echo "[$i/$#] Checking $original_spec." |
152 | 158 | # Using a copy of the spec file, because parsing requires some pre-processing.
|
153 | 159 | original_spec_dir_path="$(dirname "$original_spec")"
|
154 | 160 | cp -r "$original_spec_dir_path" "$WORK_DIR"
|
155 | 161 |
|
156 | 162 | original_spec_dir_name="$(basename "$original_spec_dir_path")"
|
157 |
| - spec="$WORK_DIR/$original_spec_dir_name/$(basename "$original_spec")" |
| 163 | + chroot_spec="$original_spec_dir_name/$(basename "$original_spec")" |
| 164 | + host_spec="$WORK_DIR/$chroot_spec" |
158 | 165 |
|
159 | 166 | # Skipping specs for signed packages. Their unsigned versions should already be included in the manifest.
|
160 |
| - if echo "$original_spec" | grep -q "SPECS-SIGNED" |
161 |
| - then |
162 |
| - echo " $spec is being ignored (reason: signed package), skipping" |
| 167 | + if echo "$original_spec" | grep -q "SPECS-SIGNED"; then |
| 168 | + echo " $host_spec is being ignored (reason: signed package), skipping." |
163 | 169 | continue
|
164 | 170 | fi
|
165 | 171 |
|
166 | 172 | # Pre-processing alternate sources (commented-out "Source" lines with full URLs), if present. Currently we only care about the first source.
|
167 | 173 | # First, we replace "%%" with "%" in the alternate source's line.
|
168 |
| - sed -Ei "/^#\s*Source0?:.*%%.*/s/%%/%/g" "$spec" |
| 174 | + sed -Ei "/^#\s*Source0?:.*%%.*/s/%%/%/g" "$host_spec" |
169 | 175 | # Then we uncomment it.
|
170 |
| - sed -Ei "s/^#\s*Source0?:/$alt_source_tag:/" "$spec" |
| 176 | + sed -Ei "s/^#\s*Source0?:/$alt_source_tag:/" "$host_spec" |
171 | 177 |
|
172 | 178 | # Removing trailing comments from "Source" tags.
|
173 |
| - sed -Ei "s/^(\s*Source[0-9]*:.*)#.*/\1/" "$spec" |
| 179 | + sed -Ei "s/^(\s*Source[0-9]*:.*)#.*/\1/" "$host_spec" |
174 | 180 |
|
175 |
| - name=$(mariner_rpmspec --srpm --qf "%{NAME}" -q "$spec" 2>/dev/null) |
176 |
| - if [[ -z $name ]] |
177 |
| - then |
178 |
| - echo "Failed to get name from '$original_spec'. Please update the spec or the macros from the 'defines' variable in this script. Error:" >> bad_registrations.txt |
179 |
| - mariner_rpmspec --srpm --qf "%{NAME}" -q "$spec" &>> bad_registrations.txt |
| 181 | + name=$(chroot_rpmspec "$WORK_DIR" --srpm --qf "%{NAME}" -q "$chroot_spec" 2>/dev/null) |
| 182 | + if [[ -z $name ]]; then |
| 183 | + echo "Failed to get name from '$original_spec'. Please update the spec or the chroot macros configuration in this script. Error:" >>bad_registrations.txt |
| 184 | + chroot_rpmspec "$WORK_DIR" --srpm --qf "%{NAME}" -q "$chroot_spec" &>>bad_registrations.txt |
180 | 185 | continue
|
181 | 186 | fi
|
182 | 187 |
|
183 | 188 | # Skipping specs from the ignore lists.
|
184 |
| - if echo "$ignore_multiple_sources $ignore_no_source_tarball $ignore_known_issues" | grep -qP "(^|\s)$name($|\s)" |
185 |
| - then |
186 |
| - echo " $name is being ignored (reason: explicitly ignored package), skipping" |
| 189 | + if echo "$ignore_multiple_sources $ignore_no_source_tarball" | grep -qP "(^|\s)$name($|\s)"; then |
| 190 | + echo " $name is being ignored (reason: explicitly ignored package), skipping." |
187 | 191 | continue
|
188 | 192 | fi
|
189 | 193 |
|
190 |
| - version=$(mariner_rpmspec --srpm --qf "%{VERSION}" -q "$spec" 2>/dev/null ) |
191 |
| - if [[ -z $version ]] |
192 |
| - then |
193 |
| - echo "Failed to get version from '$original_spec'. Please update the spec or the macros from the 'defines' variable in this script. Error:" >> bad_registrations.txt |
194 |
| - mariner_rpmspec --srpm --qf "%{VERSION}" -q "$spec" &>> bad_registrations.txt |
| 194 | + version=$(chroot_rpmspec "$WORK_DIR" --srpm --qf "%{VERSION}" -q "$chroot_spec" 2>/dev/null) |
| 195 | + if [[ -z $version ]]; then |
| 196 | + echo "Failed to get version from '$original_spec'. Please update the spec or the chroot macros configuration in this script. Error:" >>bad_registrations.txt |
| 197 | + chroot_rpmspec "$WORK_DIR" --srpm --qf "%{VERSION}" -q "$chroot_spec" &>>bad_registrations.txt |
195 | 198 | continue
|
196 | 199 | fi
|
197 | 200 |
|
198 |
| - parsed_spec="$(mariner_rpmspec --parse "$spec" 2>/dev/null)" |
| 201 | + parsed_spec="$WORK_DIR/parsed.spec" |
| 202 | + chroot_rpmspec "$WORK_DIR" --parse "$chroot_spec" 2>/dev/null > "$parsed_spec" |
199 | 203 |
|
200 | 204 | # Reading the source0 file/URL.
|
201 |
| - source0=$(echo "$parsed_spec" | grep -P "^\s*Source0?:" | cut -d: -f2- | xargs) |
202 |
| - if [[ -z $source0 ]] |
203 |
| - then |
204 |
| - echo " No source file listed for $name:$version, skipping" |
| 205 | + if ! grep -qP "^\s*Source0?:" "$parsed_spec"; then |
| 206 | + echo " No source file listed for $name-$version, skipping." |
205 | 207 | continue
|
206 | 208 | fi
|
207 | 209 |
|
| 210 | + source0=$(grep -P "^\s*Source0?:" "$parsed_spec" | cut -d: -f2- | xargs) |
| 211 | + echo " Source0: $source0." |
| 212 | + |
208 | 213 | # Reading the alternate source URL.
|
209 |
| - source0alt=$(echo "$parsed_spec" | grep -P "^\s*$alt_source_tag:" | cut -d: -f2- | xargs) |
| 214 | + source0_alt="" |
| 215 | + if grep -qP "^\s*$alt_source_tag:" "$parsed_spec"; then |
| 216 | + source0_alt=$(grep -P "^\s*$alt_source_tag:" "$parsed_spec" | cut -d: -f2- | xargs) |
| 217 | + echo " Source0Alt: $source0_alt." |
| 218 | + fi |
210 | 219 |
|
211 | 220 | # Pull the current registration from the cgmanifest file. Every registration should have a URL, so if we don't find one
|
212 | 221 | # that implies the registration is missing.
|
213 |
| - manifesturl=$(jq --raw-output ".Registrations[].component.other | select(.name==\"$name\" and .version==\"$version\") | .downloadUrl" cgmanifest.json) |
214 |
| - if [[ -z $manifesturl ]] |
215 |
| - then |
216 |
| - echo "Registration for $name:$version is missing" >> bad_registrations.txt |
| 222 | + manifest_url=$(jq --raw-output ".Registrations[].component.other | select(.name==\"$name\" and .version==\"$version\") | .downloadUrl" cgmanifest.json) |
| 223 | + if [[ -z $manifest_url ]]; then |
| 224 | + echo "Registration for $name-$version is missing" >>bad_registrations.txt |
217 | 225 | else
|
218 |
| - if [[ "$manifesturl" != "$source0" && "$manifesturl" != "$source0alt" ]] |
219 |
| - then |
| 226 | + echo " Registration URL: $manifest_url." |
| 227 | + |
| 228 | + if [[ "$manifest_url" != "$source0" && "$manifest_url" != "$source0_alt" ]]; then |
220 | 229 | {
|
221 |
| - echo "Registration URL for $name:$version ($manifesturl) matches neither the first \"Source\" tag nor the alternate source URL." |
| 230 | + echo "Registration URL for $name-$version ($manifest_url) matches neither the first \"Source\" tag nor the alternate source URL." |
222 | 231 | printf '\tFirst "Source" tag:\t%s\n' "$source0"
|
223 |
| - printf '\tAlternate source URL:\t%s\n' "$source0alt" |
224 |
| - } >> bad_registrations.txt |
| 232 | + printf '\tAlternate source URL:\t%s\n' "$source0_alt" |
| 233 | + } >>bad_registrations.txt |
225 | 234 | else
|
226 | 235 | # Try a few times to download the source listed in the manifest
|
227 | 236 | # Parsing output instead of using error codes because 'wget' returns code 8 for FTP, even if the file exists.
|
228 | 237 | # Sample HTTP(S) output: Remote file exists.
|
229 | 238 | # Sample FTP output: File ‘time-1.9.tar.gz’ exists.
|
230 |
| - if ! wget --secure-protocol=TLSv1_2 --spider --timeout=30 --tries=10 "${manifesturl}" 2>&1 | grep -qP "^(Remote file|File ‘.*’) exists.*" |
231 |
| - then |
232 |
| - echo "Registration for $name:$version has invalid URL '$manifesturl' (could not download)" >> bad_registrations.txt |
| 239 | + if ! wget --secure-protocol=TLSv1_2 --spider --timeout=30 --tries=10 "${manifest_url}" 2>&1 | grep -qP "^(Remote file|File ‘.*’) exists.*"; then |
| 240 | + echo "Registration for $name-$version has invalid URL '$manifest_url' (could not download)" >>bad_registrations.txt |
233 | 241 | fi
|
234 | 242 | fi
|
235 | 243 | fi
|
236 | 244 | done
|
237 | 245 |
|
238 |
| -if [[ -s bad_registrations.txt ]] |
239 |
| -then |
| 246 | +if [[ -s bad_registrations.txt ]]; then |
240 | 247 | echo "####"
|
241 | 248 | echo "Found errors while analyzing modified spec files, cgmanifest.json may need to be updated."
|
242 | 249 | echo "####"
|
|
0 commit comments