-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: move exec back into compression implementation
By passing the tar details to the deflator
- Loading branch information
Showing
11 changed files
with
162 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,19 @@ | ||
import stream from 'stream'; | ||
import { ExecaReturnValue } from 'execa'; | ||
import execa from 'execa'; | ||
import { Artifact } from '../model'; | ||
|
||
export interface Compression { | ||
extension: string; | ||
export type TarInputArgs = { argv: string[]; input: string } | { file: string }; | ||
|
||
export interface Compression { | ||
/** | ||
* inflate just does the inflation, in place | ||
* inflate decompresses an input stream (usually an in-progress artifact download), writing decompressed files to disk | ||
* at the given outputPath (usually the working dir) | ||
*/ | ||
inflate(input: stream.Readable, outputPath?: string): Promise<ExecaReturnValue>; | ||
inflate(input: stream.Readable, outputPath?: string): Promise<execa.ExecaReturnValue>; | ||
|
||
/** | ||
* Returns a command (argv) that deflates from stdin to the given outputPath | ||
* | ||
* The return value is an argv that can be sent to a `sh -c`-style shell interpreter | ||
* deflate either takes a tar, or creates on on the fly, and passes this to a compression algorithm, outputting the | ||
* desired artifact | ||
*/ | ||
deflateCmd(outputPath: string): Promise<string[]>; | ||
deflate(output: Artifact, tarInputArgs: TarInputArgs): Promise<execa.ExecaChildProcess>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,51 @@ | ||
import stream from 'stream'; | ||
import debug from 'debug'; | ||
import execa, { ExecaChildProcess } from 'execa'; | ||
import execa from 'execa'; | ||
import { exec } from '../../util/exec'; | ||
import { Artifact } from '../model'; | ||
import { Compression } from './compression'; | ||
import { Compression, TarInputArgs } from './compression'; | ||
import { desync } from './desync'; | ||
import { gzip } from './gzip'; | ||
import { lz4 } from './lz4'; | ||
import { tar } from './tar'; | ||
|
||
const log = debug('monofo:artifact:compression'); | ||
|
||
// TODO: use file extension information automatically | ||
export * from './compression'; | ||
|
||
export const compressors: Record<string, Compression> = { | ||
desync, | ||
gzip, | ||
lz4, | ||
caidx: desync, | ||
'tar.gz': gzip, | ||
'tar.lz4': lz4, | ||
tar, | ||
}; | ||
|
||
export function deflateCmd(artifact: Artifact): Promise<string[]> { | ||
switch (artifact.ext) { | ||
case 'tar': | ||
return Promise.resolve(['cat', '>', artifact.filename]); | ||
case compressors.gzip.extension: | ||
return compressors.gzip.deflateCmd(artifact.filename); | ||
case compressors.lz4.extension: | ||
return compressors.lz4.deflateCmd(artifact.filename); | ||
case compressors.desync.extension: | ||
return compressors.desync.deflateCmd(artifact.filename); | ||
default: | ||
throw new Error(`Unsupported artifact format: ${artifact.ext}`); | ||
export function deflator(output: Artifact, tarInputArgs: TarInputArgs): Promise<execa.ExecaChildProcess> { | ||
const compressor = compressors?.[output.ext]; | ||
|
||
if (!compressor) { | ||
throw new Error(`Unsupported output artifact format: ${output.ext}`); | ||
} | ||
|
||
return compressor.deflate(output, tarInputArgs); | ||
} | ||
|
||
export async function inflator( | ||
input: stream.Readable, | ||
artifact: Artifact, | ||
outputPath = '.' | ||
): Promise<ExecaChildProcess> { | ||
): Promise<execa.ExecaChildProcess> { | ||
if (artifact.skip) { | ||
log(`Skipping download and inflate for ${artifact.name} because skip is enabled`); | ||
return Promise.resolve(execa('true')); | ||
} | ||
|
||
switch (artifact.ext) { | ||
case 'tar': | ||
// eslint-disable-next-line @typescript-eslint/return-await | ||
return Promise.resolve(execa('tar', ['-C', outputPath, '-xf', '-'], { input, stderr: 'inherit' })); | ||
case compressors.gzip.extension: | ||
return compressors.gzip.inflate(input, outputPath); | ||
case compressors.lz4.extension: | ||
return compressors.lz4.inflate(input, outputPath); | ||
case compressors.desync.extension: | ||
return compressors.desync.inflate(input, outputPath); | ||
default: | ||
// eslint-disable-next-line @typescript-eslint/return-await | ||
return Promise.resolve(execa('tee', [artifact.filename], { input, stderr: 'inherit' })); | ||
const compressor = compressors?.[artifact.ext]; | ||
|
||
if (!compressor) { | ||
log(`Using no compression: inflating ${artifact.name} "as-is"`); | ||
return exec('cat', ['>', artifact.filename], { input }); | ||
} | ||
} | ||
|
||
export * from './compression'; | ||
return compressor.inflate(input, outputPath); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import stream from 'stream'; | ||
import debug from 'debug'; | ||
import execa, { ExecaReturnValue } from 'execa'; | ||
import { EmptyArgsError, exec, hasBin } from '../../util/exec'; | ||
import { tar as tarBin } from '../../util/tar'; | ||
import { Compression, TarInputArgs } from './compression'; | ||
|
||
const log = debug('monofo:artifact:compression:lz4'); | ||
|
||
let enabled: boolean | undefined; | ||
|
||
async function checkEnabled() { | ||
if (enabled === undefined) { | ||
enabled = await hasBin('tar'); | ||
} | ||
|
||
if (!enabled) { | ||
throw new Error('tar is disabled due to no tar binary found on PATH'); | ||
} | ||
} | ||
|
||
export function tarExecArgs(tarInputArgs: TarInputArgs): string[] { | ||
if ('file' in tarInputArgs) { | ||
return ['cat', tarInputArgs.file]; // https://porkmail.org/era/unix/award.html#cat | ||
} | ||
|
||
return tarInputArgs.argv; | ||
} | ||
|
||
export function tarExecOptions(tarInputArgs: TarInputArgs): Partial<execa.Options> { | ||
if ('input' in tarInputArgs) { | ||
return { input: tarInputArgs.input }; | ||
} | ||
|
||
return {}; | ||
} | ||
|
||
export function execFromTar( | ||
tarInputArgs: TarInputArgs, | ||
argv: string[], | ||
options: execa.Options = {} | ||
): Promise<execa.ExecaChildProcess> { | ||
const [first, ...rest] = [...tarExecArgs(tarInputArgs), ...argv]; | ||
|
||
if (!first) { | ||
throw new EmptyArgsError(); | ||
} | ||
|
||
return exec(first, rest, { ...tarExecOptions(tarInputArgs), ...options }); | ||
} | ||
|
||
export const tar: Compression = { | ||
async deflate(artifact, tarInputArgs): Promise<execa.ExecaChildProcess> { | ||
await checkEnabled(); | ||
|
||
return execFromTar(tarInputArgs, ['>', artifact.filename]); | ||
}, | ||
|
||
async inflate(input: stream.Readable, outputPath = '.'): Promise<ExecaReturnValue> { | ||
await checkEnabled(); | ||
|
||
log(`Inflating .tar archive: tar -C ${outputPath} -x -f -`); | ||
|
||
const result = await exec(await tarBin(), ['-C', outputPath, '-x', '-f', '-'], { | ||
input, | ||
}); | ||
|
||
log('Finished inflating .tar archive'); | ||
|
||
return result; | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.