uppy/packages/@uppy/aws-s3/tests/s3-client/docker.ts
Prakash 2d429a8aef
@uppy/aws-s3: remote uploads and golden retriever (#6186)
- add support for remote uploads
- add support for restore using golden-retriever
- update examples
- #6181 still persists

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Mikael Finstad <finstaden@gmail.com>
2026-06-17 13:54:48 +05:30

89 lines
2.7 KiB
TypeScript

import { exec, spawn } from 'node:child_process'
import { promisify } from 'node:util'
const execAsync = promisify(exec)
export async function getContainerName(serviceName: string) {
// Find container by service name using docker ps
const { stdout } = await execAsync(
`docker ps --filter "label=com.docker.compose.service=${serviceName}" --format "{{.Names}}"`,
)
const containerName = stdout.trim().split('\n')[0] // Get first matching container
if (!containerName) {
throw new Error(`No running container found for service: ${serviceName}`)
}
return containerName
}
export async function execDockerCommand(
containerName: string,
command: string,
timeoutMs = 10000,
) {
// If it's a service name (like 'garage'), find the actual container name
let actualContainerName = containerName
if (['garage', 'minio', 'ceph'].includes(containerName)) {
try {
actualContainerName = await getContainerName(containerName)
// console.log(`Found container: ${actualContainerName} for service: ${containerName}`,)
} catch (_error) {
console.log(`Using container name as-is: ${containerName}`)
}
}
const dockerCommand = `docker exec ${actualContainerName} ${command}`
try {
// Add timeout to prevent hanging
const execPromise = execAsync(dockerCommand, { timeout: timeoutMs })
const { stdout, stderr } = await execPromise
if (stderr && !stderr.includes('WARNING')) {
console.warn(`Warning from docker exec: ${stderr}`)
}
return stdout.trim()
} catch (error) {
// Handle timeout specifically
if (error.killed && error.signal === 'SIGTERM') {
throw new Error(
`Command timed out after ${timeoutMs}ms: ${dockerCommand}`,
)
}
console.error(`Docker exec error details:`, {
command: dockerCommand,
message: error.message,
stderr: error.stderr,
stdout: error.stdout,
code: error.code,
killed: error.killed,
signal: error.signal,
})
throw error
}
}
async function run(cmd: string, args: string[], env?: Record<string, string>) {
// console.log('running command:', cmd, args.join(' '))
return new Promise<void>((res, rej) => {
const p = spawn(cmd, args, {
stdio: 'inherit',
env: { ...process.env, ...env },
})
p.on('close', (code) =>
code === 0
? res()
: rej(new Error(`${cmd} ${args.join(' ')} exited ${code}`)),
)
p.on('error', (err) => rej(err))
})
}
export const composeUpWait = (file: string, env?: Record<string, string>) =>
run(
'docker',
['compose', '-f', file, 'up', '-d', '--force-recreate', '--wait'],
env,
)
export const composeDown = (file: string) =>
run('docker', ['compose', '-f', file, 'down', '--remove-orphans', '-v'])