@@ -8,6 +8,7 @@ EXIT_MISSING_DEPS=2
88EXIT_KERNEL_ROOT_INVALID=3
99EXIT_INDEX_FAILED=4
1010EXIT_COLLATE_FAILED=5
11+ EXIT_CATALOG_UPDATE_FAILED=6
1112
1213# Default configuration
1314DEFAULT_KERNEL_ROOT=" /sw/icrn/jupyter/icrn_ncsa_resources/Kernels"
@@ -151,6 +152,174 @@ validate_collated_file() {
151152 return 0
152153}
153154
155+ # Normalize language name to match catalog conventions (capitalize first letter)
156+ normalize_language () {
157+ local lang=" $1 "
158+ if [ -z " $lang " ]; then
159+ echo " "
160+ return
161+ fi
162+ # Capitalize first letter, lowercase the rest
163+ local first_char=$( echo " ${lang: 0: 1} " | tr ' [:lower:]' ' [:upper:]' )
164+ local rest_chars=$( echo " ${lang: 1} " | tr ' [:upper:]' ' [:lower:]' )
165+ echo " ${first_char}${rest_chars} "
166+ }
167+
168+ # Update icrn_kernel_catalog.json with discovered kernels
169+ update_kernel_catalog () {
170+ local collated_manifests=" $1 "
171+ local catalog_file=" ${KERNEL_ROOT} /icrn_kernel_catalog.json"
172+
173+ log_info " Starting catalog update phase..."
174+ log_info " Reading collated manifests from: ${collated_manifests} "
175+ log_info " Catalog file: ${catalog_file} "
176+
177+ # Check if collated manifests file exists
178+ if [ ! -f " ${collated_manifests} " ]; then
179+ log_error " Collated manifests file not found: ${collated_manifests} "
180+ return 1
181+ fi
182+
183+ # Validate collated manifests JSON
184+ if ! jq ' .' " ${collated_manifests} " > /dev/null 2>&1 ; then
185+ log_error " Invalid JSON in collated manifests: ${collated_manifests} "
186+ return 1
187+ fi
188+
189+ # Load existing catalog or create empty structure
190+ local existing_catalog
191+ if [ -f " ${catalog_file} " ]; then
192+ log_info " Loading existing catalog from: ${catalog_file} "
193+ if ! jq ' .' " ${catalog_file} " > /dev/null 2>&1 ; then
194+ log_error " Invalid JSON in existing catalog: ${catalog_file} "
195+ return 1
196+ fi
197+ existing_catalog=$( cat " ${catalog_file} " )
198+ else
199+ log_info " Catalog file does not exist, creating new catalog"
200+ existing_catalog=" {}"
201+ fi
202+
203+ # Create temporary file for updated catalog
204+ local temp_catalog=$( mktemp)
205+
206+ # Process each kernel from collated manifests
207+ local kernel_count=0
208+ local updated_count=0
209+ local added_count=0
210+
211+ # Extract kernels array and process each kernel
212+ local kernels_json=$( jq -c ' .kernels[]?' " ${collated_manifests} " 2> /dev/null)
213+
214+ if [ -z " $kernels_json " ]; then
215+ log_warn " No kernels found in collated manifests"
216+ # If no kernels and catalog doesn't exist, create empty catalog
217+ if [ ! -f " ${catalog_file} " ]; then
218+ echo " {}" | jq ' .' > " ${temp_catalog} "
219+ if [ " ${ATOMIC_WRITES} " = " true" ]; then
220+ mv " ${temp_catalog} " " ${catalog_file} "
221+ else
222+ cp " ${temp_catalog} " " ${catalog_file} "
223+ rm -f " ${temp_catalog} "
224+ fi
225+ log_info " Created empty catalog file"
226+ fi
227+ return 0
228+ fi
229+
230+ # Start with existing catalog
231+ local updated_catalog=" $existing_catalog "
232+
233+ # Process each kernel
234+ while IFS= read -r kernel_json; do
235+ [ -z " $kernel_json " ] && continue
236+
237+ kernel_count=$(( kernel_count + 1 ))
238+
239+ # Extract kernel information
240+ local kernel_name=$( echo " $kernel_json " | jq -r ' .kernel_name // empty' )
241+ local kernel_version=$( echo " $kernel_json " | jq -r ' .kernel_version // empty' )
242+ local language=$( echo " $kernel_json " | jq -r ' .language // empty' )
243+
244+ if [ -z " $kernel_name " ] || [ -z " $kernel_version " ] || [ -z " $language " ]; then
245+ log_warn " Skipping kernel with missing required fields: ${kernel_json} "
246+ continue
247+ fi
248+
249+ # Normalize language name
250+ local normalized_lang=$( normalize_language " $language " )
251+
252+ # Construct paths
253+ local environment_location=" ${KERNEL_ROOT} /${normalized_lang} /${kernel_name} /${kernel_version} "
254+ local manifest_path=" ${KERNEL_ROOT} /${normalized_lang} /${kernel_name} /${kernel_version} /package_manifest.json"
255+
256+ log_debug " Processing kernel: ${normalized_lang} /${kernel_name} /${kernel_version} "
257+
258+ # Check if kernel entry already exists in catalog
259+ if echo " $updated_catalog " | jq -e --arg lang " $normalized_lang " --arg name " $kernel_name " --arg ver " $kernel_version " \
260+ ' .[$lang][$name][$ver] != null' > /dev/null 2>&1 ; then
261+ # Update existing entry
262+ updated_catalog=$( echo " $updated_catalog " | jq --arg lang " $normalized_lang " \
263+ --arg name " $kernel_name " \
264+ --arg ver " $kernel_version " \
265+ --arg env_loc " $environment_location " \
266+ --arg manifest " $manifest_path " \
267+ ' .[$lang][$name][$ver].environment_location = $env_loc |
268+ .[$lang][$name][$ver].manifest = $manifest' )
269+ updated_count=$(( updated_count + 1 ))
270+ log_debug " Updated existing catalog entry: ${normalized_lang} /${kernel_name} /${kernel_version} "
271+ else
272+ # Add new entry
273+ updated_catalog=$( echo " $updated_catalog " | jq --arg lang " $normalized_lang " \
274+ --arg name " $kernel_name " \
275+ --arg ver " $kernel_version " \
276+ --arg env_loc " $environment_location " \
277+ --arg manifest " $manifest_path " \
278+ ' if .[$lang] == null then .[$lang] = {} else . end |
279+ if .[$lang][$name] == null then .[$lang][$name] = {} else . end |
280+ .[$lang][$name][$ver] = {
281+ environment_location: $env_loc,
282+ manifest: $manifest
283+ }' )
284+ added_count=$(( added_count + 1 ))
285+ log_debug " Added new catalog entry: ${normalized_lang} /${kernel_name} /${kernel_version} "
286+ fi
287+ done <<< " $kernels_json"
288+
289+ # Write updated catalog to temp file
290+ echo " $updated_catalog " | jq ' .' > " ${temp_catalog} "
291+
292+ if [ $? -ne 0 ]; then
293+ log_error " Failed to write updated catalog to temp file"
294+ rm -f " ${temp_catalog} "
295+ return 1
296+ fi
297+
298+ # Validate the updated catalog JSON
299+ if ! jq ' .' " ${temp_catalog} " > /dev/null 2>&1 ; then
300+ log_error " Invalid JSON in updated catalog"
301+ rm -f " ${temp_catalog} "
302+ return 1
303+ fi
304+
305+ # Write catalog file (atomic if enabled)
306+ if [ " ${ATOMIC_WRITES} " = " true" ]; then
307+ mv " ${temp_catalog} " " ${catalog_file} "
308+ log_info " Catalog updated atomically: ${catalog_file} "
309+ else
310+ cp " ${temp_catalog} " " ${catalog_file} "
311+ rm -f " ${temp_catalog} "
312+ log_info " Catalog updated: ${catalog_file} "
313+ fi
314+
315+ log_info " Catalog update completed successfully"
316+ log_info " Processed kernels: ${kernel_count} "
317+ log_info " Updated entries: ${updated_count} "
318+ log_info " Added entries: ${added_count} "
319+
320+ return 0
321+ }
322+
154323# Main execution
155324main () {
156325 log_info " Starting kernel indexer container"
@@ -223,6 +392,24 @@ main() {
223392 exit $EXIT_COLLATE_FAILED
224393 fi
225394
395+ # Execute catalog update phase
396+ log_info " Starting catalog update phase..."
397+
398+ if update_kernel_catalog " ${collated_manifests} " ; then
399+ log_info " Catalog update phase completed successfully"
400+
401+ # Validate updated catalog file
402+ local catalog_file=" ${KERNEL_ROOT} /icrn_kernel_catalog.json"
403+ if ! validate_collated_file " ${catalog_file} " " kernel catalog" ; then
404+ log_error " Catalog file validation failed"
405+ exit $EXIT_CATALOG_UPDATE_FAILED
406+ fi
407+ else
408+ local exit_code=$?
409+ log_error " Catalog update phase failed with exit code: ${exit_code} "
410+ exit $EXIT_CATALOG_UPDATE_FAILED
411+ fi
412+
226413 log_info " Kernel indexing completed successfully"
227414 exit $EXIT_SUCCESS
228415}
0 commit comments