serialize async operations
This commit is contained in:
parent
a526cb9c81
commit
c6e8d209fb
|
|
@ -58,6 +58,7 @@ function parseHeader(buffer: Buffer) {
|
|||
type TarHeader = NonNullable<ReturnType<typeof parseHeader>>;
|
||||
|
||||
export class TarExtractor extends Writable {
|
||||
private queue = Promise.resolve();
|
||||
private buffer = Buffer.alloc(0);
|
||||
private currentHeader: TarHeader | null = null;
|
||||
private remainingBytes = 0;
|
||||
|
|
@ -67,49 +68,11 @@ export class TarExtractor extends Writable {
|
|||
super();
|
||||
}
|
||||
|
||||
async mkdir(dir: string) {
|
||||
try {
|
||||
await fs.promises.mkdir(dir, { recursive: true });
|
||||
// Set proper permissions for directories
|
||||
await fs.promises.chmod(dir, 0o755);
|
||||
} catch (err) {
|
||||
if (err.code !== 'EEXIST')
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async processHeader(header: TarHeader) {
|
||||
const fullPath = this.outputPath(header.name);
|
||||
await this.mkdir(path.dirname(fullPath));
|
||||
|
||||
if (header.type === 'directory') {
|
||||
await this.mkdir(fullPath);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (header.type === 'symlink') {
|
||||
await this.createSymlink(fullPath, header.linkname);
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: track chmod maybe
|
||||
|
||||
return fs.createWriteStream(fullPath, { mode: header.mode });
|
||||
}
|
||||
|
||||
async createSymlink(symlinkPath: string, targetPath: string) {
|
||||
try {
|
||||
await fs.promises.unlink(symlinkPath);
|
||||
} catch (err) {
|
||||
if (err.code !== 'ENOENT')
|
||||
throw err;
|
||||
}
|
||||
|
||||
await fs.promises.symlink(targetPath, symlinkPath);
|
||||
}
|
||||
|
||||
override async _write(chunk: Buffer, _encoding: string, callback: (err?: Error) => void) {
|
||||
try {
|
||||
this.queue = this.queue.then(() => this._writeImpl(chunk)).then(callback).catch(callback);
|
||||
}
|
||||
|
||||
private async _writeImpl(chunk: Buffer): Promise<undefined> {
|
||||
this.buffer = Buffer.concat([this.buffer, chunk]);
|
||||
|
||||
while (this.buffer.length >= 512) {
|
||||
|
|
@ -163,9 +126,46 @@ export class TarExtractor extends Writable {
|
|||
}
|
||||
}
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
async mkdir(dir: string) {
|
||||
try {
|
||||
await fs.promises.mkdir(dir, { recursive: true });
|
||||
// Set proper permissions for directories
|
||||
await fs.promises.chmod(dir, 0o755);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
if (err.code !== 'EEXIST')
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async processHeader(header: TarHeader) {
|
||||
const fullPath = this.outputPath(header.name);
|
||||
await this.mkdir(path.dirname(fullPath));
|
||||
|
||||
if (header.type === 'directory') {
|
||||
await this.mkdir(fullPath);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (header.type === 'symlink') {
|
||||
await this.createSymlink(fullPath, header.linkname);
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: track chmod maybe
|
||||
|
||||
return fs.createWriteStream(fullPath, { mode: header.mode });
|
||||
}
|
||||
|
||||
async createSymlink(symlinkPath: string, targetPath: string) {
|
||||
try {
|
||||
await fs.promises.unlink(symlinkPath);
|
||||
} catch (err) {
|
||||
if (err.code !== 'ENOENT')
|
||||
throw err;
|
||||
}
|
||||
|
||||
await fs.promises.symlink(targetPath, symlinkPath);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue