import chalk from 'chalk' import { Command } from 'commander' import { checkImageUpdate, resolveVersionPattern } from '../lib/common' import { updateLockEntry } from '../lib/lock' interface UpdateOptions { imageName?: string force?: boolean check?: boolean verbose?: boolean } interface UpdateResult { success: boolean } interface OCIImageConfig { tag: string sourceDir?: string targetDir?: string [key: string]: any } /** * Process an image update * @param imageName The name of the image to process * @param imageConfig The image configuration * @returns Result of the update operation */ async function processImage( imageName: string, imageConfig: OCIImageConfig ): Promise { try { console.log(`Processing image ${imageName}:${imageConfig.tag}...`) // Resolve the version pattern to the actual tag for the update const resolvedTag = await resolveVersionPattern( imageName, imageConfig.tag, false ) if (!resolvedTag) { console.error( `❌ Could not resolve tag for ${imageName}:${imageConfig.tag}` ) return { success: false } } // Update the lock file with the new version information try { console.log(`Successfully resolved ${imageConfig.tag} to ${resolvedTag}`) // Create placeholder for digest until we can pull the image const placeholderDigest = 'unknown' // Update lock file. We'll update the entry for the existing image, // regardless of the tag, instead of creating a new entry // Use the resolved tag (e.g. v0.0.2) instead of the pattern (^0) updateLockEntry(imageName, resolvedTag, placeholderDigest, true) console.log( `Updated ${imageName} to ${resolvedTag} (lock file entry for ${imageConfig.tag})` ) return { success: true } } catch (error) { console.error(`Failed to update lock file: ${error}`) return { success: false } } } catch (error) { console.error(`Failed to process image ${imageName}: ${error}`) return { success: false } } } /** * Load configured image entries from config * @param filterImageName Optional image name to filter results * @returns Array of image entries */ async function loadConfigEntries( filterImageName?: string ): Promise> { // Mock implementation - would actually load from config file const entries = [ { imageName: 'zondax/zzup-make', config: { tag: '^0' }, }, ] // Filter by image name if provided if (filterImageName) { return entries.filter(entry => entry.imageName === filterImageName) } return entries } /** * Combined command to check for updates and update if confirmed * @param options Command options */ export async function cmdUpdate(options: UpdateOptions): Promise { try { // Load configuration entries const configEntries = await loadConfigEntries(options.imageName) if (configEntries.length === 0) { console.log(`No matching image configurations found.`) return } // Check for updates let updateCount = 0 for (const { imageName, config } of configEntries) { const tag = config.tag console.log(chalk.bold(`📦 ${imageName}:${tag}`)) // Check for update const updateCheck = await checkImageUpdate( imageName, tag, options.verbose ) // Only show relevant version info, not the full list of tags if (updateCheck.hasUpdate && updateCheck.availableVersion) { updateCount++ console.log( chalk.green( `✅ New version available: ${updateCheck.availableVersion}` ) ) // If only checking, don't update if (options.check) { continue } // Process update const result = await processImage(imageName, config) if (!result.success) { console.error(chalk.red(`❌ Failed to update ${imageName}`)) } } else { console.log( chalk.yellow(`✓ No update available for ${imageName}:${tag}`) ) // Show additional info about installed version if (updateCheck.currentVersion && updateCheck.availableVersion) { console.log( ` Current: ${updateCheck.currentVersion}, Latest: ${updateCheck.availableVersion}` ) } } } // Print summary if (options.check) { console.log( `\n${updateCount > 0 ? chalk.green(`✅ Updates available for ${updateCount} images`) : chalk.yellow(`✓ No updates available`)}` ) } else { console.log( `\n${updateCount > 0 ? chalk.green(`✅ Updated ${updateCount} images`) : chalk.yellow(`✓ No images updated`)}` ) } } catch (error) { console.error(chalk.red(`Error in update command: ${error}`)) } } /** * Function to configure the update command */ export function configureUpdateCommand(command: Command): Command { return command .option('--image-name ', 'Name of a specific image to update') .option('--force', 'Force update even if no newer version is available') .option('--check', 'Only check for updates without applying them') .option('--verbose', 'Enable verbose logging showing all available tags') } export function registerUpdateCommand(program: Command): void { program .command('update') .description('Update images to their latest versions') .option('--image-name ', 'Update a specific image') .option('--force', 'Force update even if not needed') .option('--check', 'Only check for updates without applying them') .option('--verbose', 'Enable verbose logging showing all available tags') }