mirror of
				https://github.com/docker/setup-qemu-action.git
				synced 2025-10-31 09:10:10 +08:00 
			
		
		
		
	feat: binfmt image local cached
This commit is contained in:
		
							parent
							
								
									f30d974279
								
							
						
					
					
						commit
						ee123d82a5
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -51,3 +51,6 @@ jspm_packages/ | |||||||
| .yarn/build-state.yml | .yarn/build-state.yml | ||||||
| .yarn/install-state.gz | .yarn/install-state.gz | ||||||
| .pnp.* | .pnp.* | ||||||
|  | 
 | ||||||
|  | # IDE | ||||||
|  | .idea/ | ||||||
| @ -23,6 +23,7 @@ describe('getInputs', () => { | |||||||
|         image: 'docker.io/tonistiigi/binfmt:latest', |         image: 'docker.io/tonistiigi/binfmt:latest', | ||||||
|         platforms: 'all', |         platforms: 'all', | ||||||
|         cacheImage: true, |         cacheImage: true, | ||||||
|  |         localCachePath: '' | ||||||
|       } as context.Inputs |       } as context.Inputs | ||||||
|     ], |     ], | ||||||
|     [ |     [ | ||||||
| @ -36,6 +37,7 @@ describe('getInputs', () => { | |||||||
|         image: 'docker/binfmt:latest', |         image: 'docker/binfmt:latest', | ||||||
|         platforms: 'arm64,riscv64,arm', |         platforms: 'arm64,riscv64,arm', | ||||||
|         cacheImage: false, |         cacheImage: false, | ||||||
|  |         localCachePath: '' | ||||||
|       } as context.Inputs |       } as context.Inputs | ||||||
|     ], |     ], | ||||||
|     [ |     [ | ||||||
| @ -48,6 +50,21 @@ describe('getInputs', () => { | |||||||
|         image: 'docker.io/tonistiigi/binfmt:latest', |         image: 'docker.io/tonistiigi/binfmt:latest', | ||||||
|         platforms: 'arm64,riscv64,arm', |         platforms: 'arm64,riscv64,arm', | ||||||
|         cacheImage: true, |         cacheImage: true, | ||||||
|  |         localCachePath: '' | ||||||
|  |       } as context.Inputs | ||||||
|  |     ], | ||||||
|  |     [ | ||||||
|  |       3, | ||||||
|  |       new Map<string, string>([ | ||||||
|  |         ['platforms', 'arm64'], | ||||||
|  |         ['cache-image', 'false'], | ||||||
|  |         ['local-cache-path', '/tmp/cache'], | ||||||
|  |       ]), | ||||||
|  |       { | ||||||
|  |         image: 'docker.io/tonistiigi/binfmt:latest', | ||||||
|  |         platforms: 'arm64', | ||||||
|  |         cacheImage: false, | ||||||
|  |         localCachePath: '/tmp/cache' | ||||||
|       } as context.Inputs |       } as context.Inputs | ||||||
|     ] |     ] | ||||||
|   ])( |   ])( | ||||||
|  | |||||||
| @ -19,6 +19,12 @@ inputs: | |||||||
|     description: 'Cache binfmt image to GitHub Actions cache backend' |     description: 'Cache binfmt image to GitHub Actions cache backend' | ||||||
|     default: 'true' |     default: 'true' | ||||||
|     required: false |     required: false | ||||||
|  |   local-cache-path: | ||||||
|  |     description: > | ||||||
|  |       Local path to store the binfmt image. Using this enables local caching instead of GitHub Actions cache. | ||||||
|  |       Note: The "latest" tag won't auto-update - delete the cached file to fetch updates. | ||||||
|  |     default: '' | ||||||
|  |     required: false | ||||||
| 
 | 
 | ||||||
| outputs: | outputs: | ||||||
|   platforms: |   platforms: | ||||||
|  | |||||||
| @ -5,12 +5,14 @@ export interface Inputs { | |||||||
|   image: string; |   image: string; | ||||||
|   platforms: string; |   platforms: string; | ||||||
|   cacheImage: boolean; |   cacheImage: boolean; | ||||||
|  |   localCachePath: string; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function getInputs(): Inputs { | export function getInputs(): Inputs { | ||||||
|   return { |   return { | ||||||
|     image: core.getInput('image') || 'docker.io/tonistiigi/binfmt:latest', |     image: core.getInput('image') || 'docker.io/tonistiigi/binfmt:latest', | ||||||
|     platforms: Util.getInputList('platforms').join(',') || 'all', |     platforms: Util.getInputList('platforms').join(',') || 'all', | ||||||
|     cacheImage: core.getBooleanInput('cache-image') |     cacheImage: core.getBooleanInput('cache-image'), | ||||||
|  |     localCachePath: core.getInput('local-cache-path') || '' | ||||||
|   }; |   }; | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										57
									
								
								src/local-cache.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/local-cache.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | |||||||
|  | import * as fs from 'fs'; | ||||||
|  | import * as path from 'path'; | ||||||
|  | import * as core from '@actions/core'; | ||||||
|  | import {Docker} from '@docker/actions-toolkit/lib/docker/docker'; | ||||||
|  | 
 | ||||||
|  | function getImageCacheFileName(imageName: string): string { | ||||||
|  |   return `${imageName.replace(/[\/\:]/g, '-')}.tar`; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export async function loadDockerImageFromCache(localCachePath: string, imageName: string): Promise<void> { | ||||||
|  |   const cacheFilePath = path.join(localCachePath, getImageCacheFileName(imageName)); | ||||||
|  | 
 | ||||||
|  |   try { | ||||||
|  |     if (fs.existsSync(cacheFilePath)) { | ||||||
|  |       await Docker.getExecOutput(['load', '-i', cacheFilePath], { | ||||||
|  |         ignoreReturnCode: true | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res.stderr.length > 0 && res.exitCode != 0) { | ||||||
|  |           throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'); | ||||||
|  |         } | ||||||
|  |         core.info(`Loaded image from ${cacheFilePath}`); | ||||||
|  |       }); | ||||||
|  |     } else { | ||||||
|  |       core.info(`Cache file not found at ${cacheFilePath}, pulling image instead`); | ||||||
|  |       await Docker.pull(imageName); | ||||||
|  |     } | ||||||
|  |   } catch (error) { | ||||||
|  |     core.warning(`Failed to check/load cache file: ${error}`); | ||||||
|  |     await Docker.pull(imageName); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export async function saveDockerImageToCache(localCachePath: string, imageName: string): Promise<void> { | ||||||
|  |   const cacheFilePath = path.join(localCachePath, getImageCacheFileName(imageName)); | ||||||
|  | 
 | ||||||
|  |   try { | ||||||
|  |     if (!fs.existsSync(localCachePath)) { | ||||||
|  |       fs.mkdirSync(localCachePath, {recursive: true}); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (fs.existsSync(cacheFilePath)) { | ||||||
|  |       core.info(`Cache file already exists at ${cacheFilePath}, skipping save`); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     await Docker.getExecOutput(['save', '-o', cacheFilePath, imageName], { | ||||||
|  |       ignoreReturnCode: true | ||||||
|  |     }).then(res => { | ||||||
|  |       if (res.stderr.length > 0 && res.exitCode != 0) { | ||||||
|  |         throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'); | ||||||
|  |       } | ||||||
|  |       core.info(`Saved image to ${cacheFilePath}`); | ||||||
|  |     }); | ||||||
|  |   } catch (error) { | ||||||
|  |     core.warning(`Failed to save image to cache file: ${error}`); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								src/main.ts
									
									
									
									
									
								
							| @ -3,6 +3,7 @@ import * as core from '@actions/core'; | |||||||
| import * as actionsToolkit from '@docker/actions-toolkit'; | import * as actionsToolkit from '@docker/actions-toolkit'; | ||||||
| 
 | 
 | ||||||
| import {Docker} from '@docker/actions-toolkit/lib/docker/docker'; | import {Docker} from '@docker/actions-toolkit/lib/docker/docker'; | ||||||
|  | import {loadDockerImageFromCache, saveDockerImageToCache} from './local-cache'; | ||||||
| 
 | 
 | ||||||
| interface Platforms { | interface Platforms { | ||||||
|   supported: string[]; |   supported: string[]; | ||||||
| @ -19,9 +20,15 @@ actionsToolkit.run( | |||||||
|       await Docker.printInfo(); |       await Docker.printInfo(); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |     if (input.localCachePath !== '') { | ||||||
|  |       await core.group(`Pulling binfmt Docker image`, async () => { | ||||||
|  |         await loadDockerImageFromCache(input.localCachePath, input.image); | ||||||
|  |       }); | ||||||
|  |     } else { | ||||||
|       await core.group(`Pulling binfmt Docker image`, async () => { |       await core.group(`Pulling binfmt Docker image`, async () => { | ||||||
|         await Docker.pull(input.image, input.cacheImage); |         await Docker.pull(input.image, input.cacheImage); | ||||||
|       }); |       }); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     await core.group(`Image info`, async () => { |     await core.group(`Image info`, async () => { | ||||||
|       await Docker.getExecOutput(['image', 'inspect', input.image], { |       await Docker.getExecOutput(['image', 'inspect', input.image], { | ||||||
| @ -56,5 +63,15 @@ actionsToolkit.run( | |||||||
|         core.setOutput('platforms', platforms.supported.join(',')); |         core.setOutput('platforms', platforms.supported.join(',')); | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
|  |   }, | ||||||
|  | 
 | ||||||
|  |   // post
 | ||||||
|  |   async () => { | ||||||
|  |     const input: context.Inputs = context.getInputs(); | ||||||
|  |     if (input.localCachePath !== '') { | ||||||
|  |       await core.group(`Saving binfmt Docker image`, async () => { | ||||||
|  |         await saveDockerImageToCache(input.localCachePath, input.image); | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| ); | ); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 문성하
						문성하