feat(classes.smartarchive): Support URL streams, recursive archive unpacking and filesystem export; improve ZIP/GZIP/BZIP2 robustness; CI and package metadata updates
This commit is contained in:
@@ -6,7 +6,10 @@ import { GzipTools } from './classes.gziptools.js';
|
||||
import { TarTools } from './classes.tartools.js';
|
||||
import { ZipTools } from './classes.ziptools.js';
|
||||
|
||||
import { ArchiveAnalyzer, type IAnalyzedResult } from './classes.archiveanalyzer.js';
|
||||
import {
|
||||
ArchiveAnalyzer,
|
||||
type IAnalyzedResult,
|
||||
} from './classes.archiveanalyzer.js';
|
||||
|
||||
import type { from } from '@push.rocks/smartrx/dist_ts/smartrx.plugins.rxjs.js';
|
||||
|
||||
@@ -18,14 +21,19 @@ export class SmartArchive {
|
||||
return smartArchiveInstance;
|
||||
}
|
||||
|
||||
public static async fromArchiveFile(filePathArg: string): Promise<SmartArchive> {
|
||||
public static async fromArchiveFile(
|
||||
filePathArg: string,
|
||||
): Promise<SmartArchive> {
|
||||
const smartArchiveInstance = new SmartArchive();
|
||||
smartArchiveInstance.sourceFilePath = filePathArg;
|
||||
return smartArchiveInstance;
|
||||
}
|
||||
|
||||
public static async fromArchiveStream(
|
||||
streamArg: plugins.stream.Readable | plugins.stream.Duplex | plugins.stream.Transform
|
||||
streamArg:
|
||||
| plugins.stream.Readable
|
||||
| plugins.stream.Duplex
|
||||
| plugins.stream.Transform,
|
||||
): Promise<SmartArchive> {
|
||||
const smartArchiveInstance = new SmartArchive();
|
||||
smartArchiveInstance.sourceStream = streamArg;
|
||||
@@ -41,13 +49,19 @@ export class SmartArchive {
|
||||
|
||||
public sourceUrl: string;
|
||||
public sourceFilePath: string;
|
||||
public sourceStream: plugins.stream.Readable | plugins.stream.Duplex | plugins.stream.Transform;
|
||||
public sourceStream:
|
||||
| plugins.stream.Readable
|
||||
| plugins.stream.Duplex
|
||||
| plugins.stream.Transform;
|
||||
|
||||
public archiveName: string;
|
||||
public singleFileMode: boolean = false;
|
||||
|
||||
public addedDirectories: string[] = [];
|
||||
public addedFiles: (plugins.smartfile.SmartFile | plugins.smartfile.StreamFile)[] = [];
|
||||
public addedFiles: (
|
||||
| plugins.smartfile.SmartFile
|
||||
| plugins.smartfile.StreamFile
|
||||
)[] = [];
|
||||
public addedUrls: string[] = [];
|
||||
|
||||
constructor() {}
|
||||
@@ -81,24 +95,35 @@ export class SmartArchive {
|
||||
// return archiveStream;
|
||||
}
|
||||
|
||||
public async exportToFs(targetDir: string, fileNameArg?: string): Promise<void> {
|
||||
public async exportToFs(
|
||||
targetDir: string,
|
||||
fileNameArg?: string,
|
||||
): Promise<void> {
|
||||
const done = plugins.smartpromise.defer<void>();
|
||||
const streamFileStream = await this.exportToStreamOfStreamFiles();
|
||||
streamFileStream.pipe(
|
||||
new plugins.smartstream.SmartDuplex({
|
||||
objectMode: true,
|
||||
writeFunction: async (streamFileArg: plugins.smartfile.StreamFile, streamtools) => {
|
||||
writeFunction: async (
|
||||
streamFileArg: plugins.smartfile.StreamFile,
|
||||
streamtools,
|
||||
) => {
|
||||
const done = plugins.smartpromise.defer<void>();
|
||||
console.log(streamFileArg.relativeFilePath ? streamFileArg.relativeFilePath : 'no relative path');
|
||||
console.log(
|
||||
streamFileArg.relativeFilePath
|
||||
? streamFileArg.relativeFilePath
|
||||
: 'no relative path',
|
||||
);
|
||||
const streamFile = streamFileArg;
|
||||
const readStream = await streamFile.createReadStream();
|
||||
await plugins.smartfile.fs.ensureDir(targetDir);
|
||||
const writePath = plugins.path.join(
|
||||
targetDir,
|
||||
streamFile.relativeFilePath || fileNameArg
|
||||
streamFile.relativeFilePath || fileNameArg,
|
||||
);
|
||||
await plugins.smartfile.fs.ensureDir(plugins.path.dirname(writePath));
|
||||
const writeStream = plugins.smartfile.fsStream.createWriteStream(writePath);
|
||||
const writeStream =
|
||||
plugins.smartfile.fsStream.createWriteStream(writePath);
|
||||
readStream.pipe(writeStream);
|
||||
writeStream.on('finish', () => {
|
||||
done.resolve();
|
||||
@@ -108,15 +133,16 @@ export class SmartArchive {
|
||||
finalFunction: async () => {
|
||||
done.resolve();
|
||||
},
|
||||
})
|
||||
}),
|
||||
);
|
||||
return done.promise;
|
||||
}
|
||||
|
||||
public async exportToStreamOfStreamFiles() {
|
||||
const streamFileIntake = new plugins.smartstream.StreamIntake<plugins.smartfile.StreamFile>({
|
||||
objectMode: true,
|
||||
});
|
||||
const streamFileIntake =
|
||||
new plugins.smartstream.StreamIntake<plugins.smartfile.StreamFile>({
|
||||
objectMode: true,
|
||||
});
|
||||
const archiveStream = await this.getArchiveStream();
|
||||
const createAnalyzedStream = () => this.archiveAnalyzer.getAnalyzedStream();
|
||||
|
||||
@@ -125,15 +151,21 @@ export class SmartArchive {
|
||||
plugins.smartstream.createTransformFunction<IAnalyzedResult, any>(
|
||||
async (analyzedResultChunk) => {
|
||||
if (analyzedResultChunk.fileType?.mime === 'application/x-tar') {
|
||||
const tarStream = analyzedResultChunk.decompressionStream as plugins.tarStream.Extract;
|
||||
const tarStream =
|
||||
analyzedResultChunk.decompressionStream as plugins.tarStream.Extract;
|
||||
tarStream.on('entry', async (header, stream, next) => {
|
||||
if (header.type === 'directory') {
|
||||
console.log(`tar stream directory: ${header.name} ... skipping!`);
|
||||
console.log(
|
||||
`tar stream directory: ${header.name} ... skipping!`,
|
||||
);
|
||||
next();
|
||||
return;
|
||||
}
|
||||
console.log(`tar stream file: ${header.name}`);
|
||||
const streamfile = plugins.smartfile.StreamFile.fromStream(stream, header.name);
|
||||
const streamfile = plugins.smartfile.StreamFile.fromStream(
|
||||
stream,
|
||||
header.name,
|
||||
);
|
||||
streamFileIntake.push(streamfile);
|
||||
stream.on('end', function () {
|
||||
next(); // ready for next entry
|
||||
@@ -143,20 +175,30 @@ export class SmartArchive {
|
||||
console.log('finished');
|
||||
streamFileIntake.signalEnd();
|
||||
});
|
||||
analyzedResultChunk.resultStream.pipe(analyzedResultChunk.decompressionStream);
|
||||
analyzedResultChunk.resultStream.pipe(
|
||||
analyzedResultChunk.decompressionStream,
|
||||
);
|
||||
} else if (analyzedResultChunk.fileType?.mime === 'application/zip') {
|
||||
analyzedResultChunk.resultStream
|
||||
.pipe(analyzedResultChunk.decompressionStream)
|
||||
.pipe(new plugins.smartstream.SmartDuplex({
|
||||
objectMode: true,
|
||||
writeFunction: async (streamFileArg: plugins.smartfile.StreamFile, streamtools) => {
|
||||
streamFileIntake.push(streamFileArg);
|
||||
},
|
||||
finalFunction: async () => {
|
||||
streamFileIntake.signalEnd();
|
||||
}
|
||||
}));
|
||||
} else if (analyzedResultChunk.isArchive && analyzedResultChunk.decompressionStream) {
|
||||
.pipe(
|
||||
new plugins.smartstream.SmartDuplex({
|
||||
objectMode: true,
|
||||
writeFunction: async (
|
||||
streamFileArg: plugins.smartfile.StreamFile,
|
||||
streamtools,
|
||||
) => {
|
||||
streamFileIntake.push(streamFileArg);
|
||||
},
|
||||
finalFunction: async () => {
|
||||
streamFileIntake.signalEnd();
|
||||
},
|
||||
}),
|
||||
);
|
||||
} else if (
|
||||
analyzedResultChunk.isArchive &&
|
||||
analyzedResultChunk.decompressionStream
|
||||
) {
|
||||
analyzedResultChunk.resultStream
|
||||
.pipe(analyzedResultChunk.decompressionStream)
|
||||
.pipe(createAnalyzedStream())
|
||||
@@ -164,7 +206,7 @@ export class SmartArchive {
|
||||
} else {
|
||||
const streamFile = plugins.smartfile.StreamFile.fromStream(
|
||||
analyzedResultChunk.resultStream,
|
||||
analyzedResultChunk.fileType?.ext
|
||||
analyzedResultChunk.fileType?.ext,
|
||||
);
|
||||
streamFileIntake.push(streamFile);
|
||||
streamFileIntake.signalEnd();
|
||||
@@ -172,7 +214,7 @@ export class SmartArchive {
|
||||
},
|
||||
{
|
||||
objectMode: true,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
archiveStream.pipe(createAnalyzedStream()).pipe(createUnpackStream());
|
||||
|
Reference in New Issue
Block a user