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>>;
|
type TarHeader = NonNullable<ReturnType<typeof parseHeader>>;
|
||||||
|
|
||||||
export class TarExtractor extends Writable {
|
export class TarExtractor extends Writable {
|
||||||
|
private queue = Promise.resolve();
|
||||||
private buffer = Buffer.alloc(0);
|
private buffer = Buffer.alloc(0);
|
||||||
private currentHeader: TarHeader | null = null;
|
private currentHeader: TarHeader | null = null;
|
||||||
private remainingBytes = 0;
|
private remainingBytes = 0;
|
||||||
|
|
@ -67,49 +68,11 @@ export class TarExtractor extends Writable {
|
||||||
super();
|
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) {
|
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]);
|
this.buffer = Buffer.concat([this.buffer, chunk]);
|
||||||
|
|
||||||
while (this.buffer.length >= 512) {
|
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) {
|
} 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