zip-lib 0.7.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cancelable.d.ts +38 -38
- package/lib/cancelable.js +65 -65
- package/lib/fs.js +175 -175
- package/lib/index.d.ts +25 -25
- package/lib/index.js +56 -52
- package/lib/unzip.d.ts +78 -78
- package/lib/unzip.js +358 -358
- package/lib/util.js +49 -49
- package/lib/zip.d.ts +59 -59
- package/lib/zip.js +213 -213
- package/package.json +12 -9
package/lib/util.js
CHANGED
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.readlink = exports.symlink = exports.rmdir = exports.access = exports.readdir = exports.chmod = exports.lstat = exports.stat = exports.realpath = exports.mkdir = exports.unlink = void 0;
|
|
4
|
-
const fs = require("fs");
|
|
5
|
-
const util = require("util");
|
|
6
|
-
function unlink(path) {
|
|
7
|
-
return util.promisify(fs.unlink)(path);
|
|
8
|
-
}
|
|
9
|
-
exports.unlink = unlink;
|
|
10
|
-
function mkdir(path, mode) {
|
|
11
|
-
return util.promisify(fs.mkdir)(path, mode);
|
|
12
|
-
}
|
|
13
|
-
exports.mkdir = mkdir;
|
|
14
|
-
function realpath(path) {
|
|
15
|
-
return util.promisify(fs.realpath)(path);
|
|
16
|
-
}
|
|
17
|
-
exports.realpath = realpath;
|
|
18
|
-
function stat(path) {
|
|
19
|
-
return util.promisify(fs.stat)(path);
|
|
20
|
-
}
|
|
21
|
-
exports.stat = stat;
|
|
22
|
-
function lstat(path) {
|
|
23
|
-
return util.promisify(fs.lstat)(path);
|
|
24
|
-
}
|
|
25
|
-
exports.lstat = lstat;
|
|
26
|
-
function chmod(path, mode) {
|
|
27
|
-
return util.promisify(fs.chmod)(path, mode);
|
|
28
|
-
}
|
|
29
|
-
exports.chmod = chmod;
|
|
30
|
-
function readdir(path) {
|
|
31
|
-
return util.promisify(fs.readdir)(path);
|
|
32
|
-
}
|
|
33
|
-
exports.readdir = readdir;
|
|
34
|
-
function access(path, mode) {
|
|
35
|
-
return util.promisify(fs.access)(path, mode);
|
|
36
|
-
}
|
|
37
|
-
exports.access = access;
|
|
38
|
-
function rmdir(path) {
|
|
39
|
-
return util.promisify(fs.rmdir)(path);
|
|
40
|
-
}
|
|
41
|
-
exports.rmdir = rmdir;
|
|
42
|
-
function symlink(target, path, type) {
|
|
43
|
-
return util.promisify(fs.symlink)(target, path, type);
|
|
44
|
-
}
|
|
45
|
-
exports.symlink = symlink;
|
|
46
|
-
function readlink(path) {
|
|
47
|
-
return util.promisify(fs.readlink)(path);
|
|
48
|
-
}
|
|
49
|
-
exports.readlink = readlink;
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readlink = exports.symlink = exports.rmdir = exports.access = exports.readdir = exports.chmod = exports.lstat = exports.stat = exports.realpath = exports.mkdir = exports.unlink = void 0;
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const util = require("util");
|
|
6
|
+
function unlink(path) {
|
|
7
|
+
return util.promisify(fs.unlink)(path);
|
|
8
|
+
}
|
|
9
|
+
exports.unlink = unlink;
|
|
10
|
+
function mkdir(path, mode) {
|
|
11
|
+
return util.promisify(fs.mkdir)(path, mode);
|
|
12
|
+
}
|
|
13
|
+
exports.mkdir = mkdir;
|
|
14
|
+
function realpath(path) {
|
|
15
|
+
return util.promisify(fs.realpath)(path);
|
|
16
|
+
}
|
|
17
|
+
exports.realpath = realpath;
|
|
18
|
+
function stat(path) {
|
|
19
|
+
return util.promisify(fs.stat)(path);
|
|
20
|
+
}
|
|
21
|
+
exports.stat = stat;
|
|
22
|
+
function lstat(path) {
|
|
23
|
+
return util.promisify(fs.lstat)(path);
|
|
24
|
+
}
|
|
25
|
+
exports.lstat = lstat;
|
|
26
|
+
function chmod(path, mode) {
|
|
27
|
+
return util.promisify(fs.chmod)(path, mode);
|
|
28
|
+
}
|
|
29
|
+
exports.chmod = chmod;
|
|
30
|
+
function readdir(path) {
|
|
31
|
+
return util.promisify(fs.readdir)(path);
|
|
32
|
+
}
|
|
33
|
+
exports.readdir = readdir;
|
|
34
|
+
function access(path, mode) {
|
|
35
|
+
return util.promisify(fs.access)(path, mode);
|
|
36
|
+
}
|
|
37
|
+
exports.access = access;
|
|
38
|
+
function rmdir(path) {
|
|
39
|
+
return util.promisify(fs.rmdir)(path);
|
|
40
|
+
}
|
|
41
|
+
exports.rmdir = rmdir;
|
|
42
|
+
function symlink(target, path, type) {
|
|
43
|
+
return util.promisify(fs.symlink)(target, path, type);
|
|
44
|
+
}
|
|
45
|
+
exports.symlink = symlink;
|
|
46
|
+
function readlink(path) {
|
|
47
|
+
return util.promisify(fs.readlink)(path);
|
|
48
|
+
}
|
|
49
|
+
exports.readlink = readlink;
|
package/lib/zip.d.ts
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
import { Cancelable } from "./cancelable";
|
|
2
|
-
export interface IZipOptions {
|
|
3
|
-
/**
|
|
4
|
-
* Indicates how to handle when the given path is a symbolic link.
|
|
5
|
-
*
|
|
6
|
-
* `true`: add the target of the symbolic link to the zip.
|
|
7
|
-
*
|
|
8
|
-
* `false`: add symbolic link itself to the zip.
|
|
9
|
-
*
|
|
10
|
-
* The default value is `false`.
|
|
11
|
-
*/
|
|
12
|
-
followSymlinks?: boolean;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Compress files or folders to a zip file.
|
|
16
|
-
*/
|
|
17
|
-
export declare class Zip extends Cancelable {
|
|
18
|
-
private options?;
|
|
19
|
-
/**
|
|
20
|
-
*
|
|
21
|
-
*/
|
|
22
|
-
constructor(options?: IZipOptions | undefined);
|
|
23
|
-
private yazlFile;
|
|
24
|
-
private isPipe;
|
|
25
|
-
private zipStream;
|
|
26
|
-
private zipFiles;
|
|
27
|
-
private zipFolders;
|
|
28
|
-
private token;
|
|
29
|
-
/**
|
|
30
|
-
* Adds a file from the file system at realPath into the zipfile as metadataPath.
|
|
31
|
-
* @param file
|
|
32
|
-
* @param metadataPath Typically metadataPath would be calculated as path.relative(root, realPath).
|
|
33
|
-
* A valid metadataPath must not start with "/" or /[A-Za-z]:\//, and must not contain "..".
|
|
34
|
-
*/
|
|
35
|
-
addFile(file: string, metadataPath?: string): void;
|
|
36
|
-
/**
|
|
37
|
-
* Adds a folder from the file system at realPath into the zipfile as metadataPath.
|
|
38
|
-
* @param folder
|
|
39
|
-
* @param metadataPath Typically metadataPath would be calculated as path.relative(root, realPath).
|
|
40
|
-
* A valid metadataPath must not start with "/" or /[A-Za-z]:\//, and must not contain "..".
|
|
41
|
-
*/
|
|
42
|
-
addFolder(folder: string, metadataPath?: string): void;
|
|
43
|
-
/**
|
|
44
|
-
* Generate zip file.
|
|
45
|
-
* @param zipFile the zip file path.
|
|
46
|
-
*/
|
|
47
|
-
archive(zipFile: string): Promise<void>;
|
|
48
|
-
/**
|
|
49
|
-
* Cancel compression.
|
|
50
|
-
* If the cancel method is called after the archive is complete, nothing will happen.
|
|
51
|
-
*/
|
|
52
|
-
cancel(): void;
|
|
53
|
-
private addEntry;
|
|
54
|
-
private addFileStream;
|
|
55
|
-
private addSymlink;
|
|
56
|
-
private walkDir;
|
|
57
|
-
private stopPipe;
|
|
58
|
-
private followSymlink;
|
|
59
|
-
}
|
|
1
|
+
import { Cancelable } from "./cancelable";
|
|
2
|
+
export interface IZipOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Indicates how to handle when the given path is a symbolic link.
|
|
5
|
+
*
|
|
6
|
+
* `true`: add the target of the symbolic link to the zip.
|
|
7
|
+
*
|
|
8
|
+
* `false`: add symbolic link itself to the zip.
|
|
9
|
+
*
|
|
10
|
+
* The default value is `false`.
|
|
11
|
+
*/
|
|
12
|
+
followSymlinks?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Compress files or folders to a zip file.
|
|
16
|
+
*/
|
|
17
|
+
export declare class Zip extends Cancelable {
|
|
18
|
+
private options?;
|
|
19
|
+
/**
|
|
20
|
+
*
|
|
21
|
+
*/
|
|
22
|
+
constructor(options?: IZipOptions | undefined);
|
|
23
|
+
private yazlFile;
|
|
24
|
+
private isPipe;
|
|
25
|
+
private zipStream;
|
|
26
|
+
private zipFiles;
|
|
27
|
+
private zipFolders;
|
|
28
|
+
private token;
|
|
29
|
+
/**
|
|
30
|
+
* Adds a file from the file system at realPath into the zipfile as metadataPath.
|
|
31
|
+
* @param file
|
|
32
|
+
* @param metadataPath Typically metadataPath would be calculated as path.relative(root, realPath).
|
|
33
|
+
* A valid metadataPath must not start with "/" or /[A-Za-z]:\//, and must not contain "..".
|
|
34
|
+
*/
|
|
35
|
+
addFile(file: string, metadataPath?: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* Adds a folder from the file system at realPath into the zipfile as metadataPath.
|
|
38
|
+
* @param folder
|
|
39
|
+
* @param metadataPath Typically metadataPath would be calculated as path.relative(root, realPath).
|
|
40
|
+
* A valid metadataPath must not start with "/" or /[A-Za-z]:\//, and must not contain "..".
|
|
41
|
+
*/
|
|
42
|
+
addFolder(folder: string, metadataPath?: string): void;
|
|
43
|
+
/**
|
|
44
|
+
* Generate zip file.
|
|
45
|
+
* @param zipFile the zip file path.
|
|
46
|
+
*/
|
|
47
|
+
archive(zipFile: string): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Cancel compression.
|
|
50
|
+
* If the cancel method is called after the archive is complete, nothing will happen.
|
|
51
|
+
*/
|
|
52
|
+
cancel(): void;
|
|
53
|
+
private addEntry;
|
|
54
|
+
private addFileStream;
|
|
55
|
+
private addSymlink;
|
|
56
|
+
private walkDir;
|
|
57
|
+
private stopPipe;
|
|
58
|
+
private followSymlink;
|
|
59
|
+
}
|
package/lib/zip.js
CHANGED
|
@@ -1,213 +1,213 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Zip = void 0;
|
|
4
|
-
const yazl = require("yazl");
|
|
5
|
-
const fs_1 = require("fs");
|
|
6
|
-
const exfs = require("./fs");
|
|
7
|
-
const path = require("path");
|
|
8
|
-
const util = require("./util");
|
|
9
|
-
const cancelable_1 = require("./cancelable");
|
|
10
|
-
/**
|
|
11
|
-
* Compress files or folders to a zip file.
|
|
12
|
-
*/
|
|
13
|
-
class Zip extends cancelable_1.Cancelable {
|
|
14
|
-
/**
|
|
15
|
-
*
|
|
16
|
-
*/
|
|
17
|
-
constructor(options) {
|
|
18
|
-
super();
|
|
19
|
-
this.options = options;
|
|
20
|
-
this.isPipe = false;
|
|
21
|
-
this.zipFiles = [];
|
|
22
|
-
this.zipFolders = [];
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Adds a file from the file system at realPath into the zipfile as metadataPath.
|
|
26
|
-
* @param file
|
|
27
|
-
* @param metadataPath Typically metadataPath would be calculated as path.relative(root, realPath).
|
|
28
|
-
* A valid metadataPath must not start with "/" or /[A-Za-z]:\//, and must not contain "..".
|
|
29
|
-
*/
|
|
30
|
-
addFile(file, metadataPath) {
|
|
31
|
-
let mpath = metadataPath;
|
|
32
|
-
if (!mpath) {
|
|
33
|
-
mpath = path.basename(file);
|
|
34
|
-
}
|
|
35
|
-
this.zipFiles.push({
|
|
36
|
-
path: file,
|
|
37
|
-
metadataPath: mpath
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Adds a folder from the file system at realPath into the zipfile as metadataPath.
|
|
42
|
-
* @param folder
|
|
43
|
-
* @param metadataPath Typically metadataPath would be calculated as path.relative(root, realPath).
|
|
44
|
-
* A valid metadataPath must not start with "/" or /[A-Za-z]:\//, and must not contain "..".
|
|
45
|
-
*/
|
|
46
|
-
addFolder(folder, metadataPath) {
|
|
47
|
-
this.zipFolders.push({
|
|
48
|
-
path: folder,
|
|
49
|
-
metadataPath
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Generate zip file.
|
|
54
|
-
* @param zipFile the zip file path.
|
|
55
|
-
*/
|
|
56
|
-
async archive(zipFile) {
|
|
57
|
-
if (!zipFile) {
|
|
58
|
-
return Promise.reject(new Error("zipPath must not be empty"));
|
|
59
|
-
}
|
|
60
|
-
const token = new cancelable_1.CancellationToken();
|
|
61
|
-
this.token = token;
|
|
62
|
-
this.isPipe = false;
|
|
63
|
-
await exfs.ensureFolder(path.dirname(zipFile));
|
|
64
|
-
// Re-instantiate yazl every time the archive method is called to ensure that files are not added repeatedly.
|
|
65
|
-
// This will also make the Zip class reusable.
|
|
66
|
-
this.yazlFile = new yazl.ZipFile();
|
|
67
|
-
return new Promise(async (c, e) => {
|
|
68
|
-
this.yazlFile.once("error", (err) => {
|
|
69
|
-
e(this.wrapError(err, token.isCancelled));
|
|
70
|
-
});
|
|
71
|
-
const zip = this.yazlFile;
|
|
72
|
-
if (!token.isCancelled) {
|
|
73
|
-
this.zipStream = fs_1.createWriteStream(zipFile);
|
|
74
|
-
this.zipStream.once("error", (err) => {
|
|
75
|
-
e(this.wrapError(err, token.isCancelled));
|
|
76
|
-
});
|
|
77
|
-
this.zipStream.once("close", () => {
|
|
78
|
-
if (token.isCancelled) {
|
|
79
|
-
e(this.canceledError());
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
c(void 0);
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
zip.outputStream.once("error", (err) => {
|
|
86
|
-
e(this.wrapError(err, token.isCancelled));
|
|
87
|
-
});
|
|
88
|
-
zip.outputStream.pipe(this.zipStream);
|
|
89
|
-
this.isPipe = true;
|
|
90
|
-
}
|
|
91
|
-
try {
|
|
92
|
-
const files = this.zipFiles;
|
|
93
|
-
for (const file of files) {
|
|
94
|
-
const entry = await exfs.getFileEntry(file.path);
|
|
95
|
-
await this.addEntry(zip, entry, file, token);
|
|
96
|
-
}
|
|
97
|
-
if (this.zipFolders.length > 0) {
|
|
98
|
-
await this.walkDir(this.zipFolders, token);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
catch (error) {
|
|
102
|
-
e(this.wrapError(error, token.isCancelled));
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
zip.end();
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Cancel compression.
|
|
110
|
-
* If the cancel method is called after the archive is complete, nothing will happen.
|
|
111
|
-
*/
|
|
112
|
-
cancel() {
|
|
113
|
-
if (this.token) {
|
|
114
|
-
this.token.cancel();
|
|
115
|
-
this.token = null;
|
|
116
|
-
}
|
|
117
|
-
this.stopPipe(this.canceledError());
|
|
118
|
-
}
|
|
119
|
-
async addEntry(zip, entry, file, token) {
|
|
120
|
-
if (entry.isSymbolicLink) {
|
|
121
|
-
if (this.followSymlink()) {
|
|
122
|
-
if (entry.type === "dir") {
|
|
123
|
-
const realPath = await util.realpath(file.path);
|
|
124
|
-
await this.walkDir([{ path: realPath, metadataPath: file.metadataPath }], token);
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
zip.addFile(file.path, file.metadataPath);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
await this.addSymlink(zip, entry, file.metadataPath);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
if (entry.type === "dir") {
|
|
136
|
-
zip.addEmptyDirectory(file.metadataPath, {
|
|
137
|
-
mtime: entry.mtime,
|
|
138
|
-
mode: entry.mode
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
await this.addFileStream(zip, entry, file.metadataPath, token);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
addFileStream(zip, file, metadataPath, token) {
|
|
147
|
-
return new Promise((c, e) => {
|
|
148
|
-
const fileStream = fs_1.createReadStream(file.path);
|
|
149
|
-
fileStream.once("error", (err) => {
|
|
150
|
-
const wrappedError = this.wrapError(err, token.isCancelled);
|
|
151
|
-
this.stopPipe(wrappedError);
|
|
152
|
-
e(wrappedError);
|
|
153
|
-
});
|
|
154
|
-
fileStream.once("close", () => {
|
|
155
|
-
c();
|
|
156
|
-
});
|
|
157
|
-
// If the file attribute is known, add the entry using `addReadStream`,
|
|
158
|
-
// this can reduce the number of calls to the `fs.stat` method.
|
|
159
|
-
zip.addReadStream(fileStream, metadataPath, {
|
|
160
|
-
mode: file.mode,
|
|
161
|
-
mtime: file.mtime
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
async addSymlink(zip, file, metadataPath) {
|
|
166
|
-
const linkTarget = await util.readlink(file.path);
|
|
167
|
-
zip.addBuffer(Buffer.from(linkTarget), metadataPath, {
|
|
168
|
-
mtime: file.mtime,
|
|
169
|
-
mode: file.mode
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
async walkDir(folders, token) {
|
|
173
|
-
for (const folder of folders) {
|
|
174
|
-
if (token.isCancelled) {
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
const entries = await exfs.readdirp(folder.path);
|
|
178
|
-
if (entries.length > 0) {
|
|
179
|
-
for (const entry of entries) {
|
|
180
|
-
if (token.isCancelled) {
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
const relativePath = path.relative(folder.path, entry.path);
|
|
184
|
-
const metadataPath = folder.metadataPath ? path.join(folder.metadataPath, relativePath) : relativePath;
|
|
185
|
-
await this.addEntry(this.yazlFile, entry, { path: entry.path, metadataPath }, token);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
// If the folder is empty and the metadataPath has a value,
|
|
190
|
-
// an empty folder should be created based on the metadataPath
|
|
191
|
-
if (folder.metadataPath) {
|
|
192
|
-
this.yazlFile.addEmptyDirectory(folder.metadataPath);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
stopPipe(err) {
|
|
198
|
-
if (this.isPipe) {
|
|
199
|
-
this.yazlFile.outputStream.unpipe(this.zipStream);
|
|
200
|
-
this.zipStream.destroy(err);
|
|
201
|
-
this.isPipe = false;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
followSymlink() {
|
|
205
|
-
let followSymlink = false;
|
|
206
|
-
if (this.options &&
|
|
207
|
-
this.options.followSymlinks === true) {
|
|
208
|
-
followSymlink = true;
|
|
209
|
-
}
|
|
210
|
-
return followSymlink;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
exports.Zip = Zip;
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Zip = void 0;
|
|
4
|
+
const yazl = require("yazl");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const exfs = require("./fs");
|
|
7
|
+
const path = require("path");
|
|
8
|
+
const util = require("./util");
|
|
9
|
+
const cancelable_1 = require("./cancelable");
|
|
10
|
+
/**
|
|
11
|
+
* Compress files or folders to a zip file.
|
|
12
|
+
*/
|
|
13
|
+
class Zip extends cancelable_1.Cancelable {
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
constructor(options) {
|
|
18
|
+
super();
|
|
19
|
+
this.options = options;
|
|
20
|
+
this.isPipe = false;
|
|
21
|
+
this.zipFiles = [];
|
|
22
|
+
this.zipFolders = [];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Adds a file from the file system at realPath into the zipfile as metadataPath.
|
|
26
|
+
* @param file
|
|
27
|
+
* @param metadataPath Typically metadataPath would be calculated as path.relative(root, realPath).
|
|
28
|
+
* A valid metadataPath must not start with "/" or /[A-Za-z]:\//, and must not contain "..".
|
|
29
|
+
*/
|
|
30
|
+
addFile(file, metadataPath) {
|
|
31
|
+
let mpath = metadataPath;
|
|
32
|
+
if (!mpath) {
|
|
33
|
+
mpath = path.basename(file);
|
|
34
|
+
}
|
|
35
|
+
this.zipFiles.push({
|
|
36
|
+
path: file,
|
|
37
|
+
metadataPath: mpath
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Adds a folder from the file system at realPath into the zipfile as metadataPath.
|
|
42
|
+
* @param folder
|
|
43
|
+
* @param metadataPath Typically metadataPath would be calculated as path.relative(root, realPath).
|
|
44
|
+
* A valid metadataPath must not start with "/" or /[A-Za-z]:\//, and must not contain "..".
|
|
45
|
+
*/
|
|
46
|
+
addFolder(folder, metadataPath) {
|
|
47
|
+
this.zipFolders.push({
|
|
48
|
+
path: folder,
|
|
49
|
+
metadataPath
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Generate zip file.
|
|
54
|
+
* @param zipFile the zip file path.
|
|
55
|
+
*/
|
|
56
|
+
async archive(zipFile) {
|
|
57
|
+
if (!zipFile) {
|
|
58
|
+
return Promise.reject(new Error("zipPath must not be empty"));
|
|
59
|
+
}
|
|
60
|
+
const token = new cancelable_1.CancellationToken();
|
|
61
|
+
this.token = token;
|
|
62
|
+
this.isPipe = false;
|
|
63
|
+
await exfs.ensureFolder(path.dirname(zipFile));
|
|
64
|
+
// Re-instantiate yazl every time the archive method is called to ensure that files are not added repeatedly.
|
|
65
|
+
// This will also make the Zip class reusable.
|
|
66
|
+
this.yazlFile = new yazl.ZipFile();
|
|
67
|
+
return new Promise(async (c, e) => {
|
|
68
|
+
this.yazlFile.once("error", (err) => {
|
|
69
|
+
e(this.wrapError(err, token.isCancelled));
|
|
70
|
+
});
|
|
71
|
+
const zip = this.yazlFile;
|
|
72
|
+
if (!token.isCancelled) {
|
|
73
|
+
this.zipStream = (0, fs_1.createWriteStream)(zipFile);
|
|
74
|
+
this.zipStream.once("error", (err) => {
|
|
75
|
+
e(this.wrapError(err, token.isCancelled));
|
|
76
|
+
});
|
|
77
|
+
this.zipStream.once("close", () => {
|
|
78
|
+
if (token.isCancelled) {
|
|
79
|
+
e(this.canceledError());
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
c(void 0);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
zip.outputStream.once("error", (err) => {
|
|
86
|
+
e(this.wrapError(err, token.isCancelled));
|
|
87
|
+
});
|
|
88
|
+
zip.outputStream.pipe(this.zipStream);
|
|
89
|
+
this.isPipe = true;
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const files = this.zipFiles;
|
|
93
|
+
for (const file of files) {
|
|
94
|
+
const entry = await exfs.getFileEntry(file.path);
|
|
95
|
+
await this.addEntry(zip, entry, file, token);
|
|
96
|
+
}
|
|
97
|
+
if (this.zipFolders.length > 0) {
|
|
98
|
+
await this.walkDir(this.zipFolders, token);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
e(this.wrapError(error, token.isCancelled));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
zip.end();
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Cancel compression.
|
|
110
|
+
* If the cancel method is called after the archive is complete, nothing will happen.
|
|
111
|
+
*/
|
|
112
|
+
cancel() {
|
|
113
|
+
if (this.token) {
|
|
114
|
+
this.token.cancel();
|
|
115
|
+
this.token = null;
|
|
116
|
+
}
|
|
117
|
+
this.stopPipe(this.canceledError());
|
|
118
|
+
}
|
|
119
|
+
async addEntry(zip, entry, file, token) {
|
|
120
|
+
if (entry.isSymbolicLink) {
|
|
121
|
+
if (this.followSymlink()) {
|
|
122
|
+
if (entry.type === "dir") {
|
|
123
|
+
const realPath = await util.realpath(file.path);
|
|
124
|
+
await this.walkDir([{ path: realPath, metadataPath: file.metadataPath }], token);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
zip.addFile(file.path, file.metadataPath);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
await this.addSymlink(zip, entry, file.metadataPath);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
if (entry.type === "dir") {
|
|
136
|
+
zip.addEmptyDirectory(file.metadataPath, {
|
|
137
|
+
mtime: entry.mtime,
|
|
138
|
+
mode: entry.mode
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
await this.addFileStream(zip, entry, file.metadataPath, token);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
addFileStream(zip, file, metadataPath, token) {
|
|
147
|
+
return new Promise((c, e) => {
|
|
148
|
+
const fileStream = (0, fs_1.createReadStream)(file.path);
|
|
149
|
+
fileStream.once("error", (err) => {
|
|
150
|
+
const wrappedError = this.wrapError(err, token.isCancelled);
|
|
151
|
+
this.stopPipe(wrappedError);
|
|
152
|
+
e(wrappedError);
|
|
153
|
+
});
|
|
154
|
+
fileStream.once("close", () => {
|
|
155
|
+
c();
|
|
156
|
+
});
|
|
157
|
+
// If the file attribute is known, add the entry using `addReadStream`,
|
|
158
|
+
// this can reduce the number of calls to the `fs.stat` method.
|
|
159
|
+
zip.addReadStream(fileStream, metadataPath, {
|
|
160
|
+
mode: file.mode,
|
|
161
|
+
mtime: file.mtime
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
async addSymlink(zip, file, metadataPath) {
|
|
166
|
+
const linkTarget = await util.readlink(file.path);
|
|
167
|
+
zip.addBuffer(Buffer.from(linkTarget), metadataPath, {
|
|
168
|
+
mtime: file.mtime,
|
|
169
|
+
mode: file.mode
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
async walkDir(folders, token) {
|
|
173
|
+
for (const folder of folders) {
|
|
174
|
+
if (token.isCancelled) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const entries = await exfs.readdirp(folder.path);
|
|
178
|
+
if (entries.length > 0) {
|
|
179
|
+
for (const entry of entries) {
|
|
180
|
+
if (token.isCancelled) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const relativePath = path.relative(folder.path, entry.path);
|
|
184
|
+
const metadataPath = folder.metadataPath ? path.join(folder.metadataPath, relativePath) : relativePath;
|
|
185
|
+
await this.addEntry(this.yazlFile, entry, { path: entry.path, metadataPath }, token);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
// If the folder is empty and the metadataPath has a value,
|
|
190
|
+
// an empty folder should be created based on the metadataPath
|
|
191
|
+
if (folder.metadataPath) {
|
|
192
|
+
this.yazlFile.addEmptyDirectory(folder.metadataPath);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
stopPipe(err) {
|
|
198
|
+
if (this.isPipe) {
|
|
199
|
+
this.yazlFile.outputStream.unpipe(this.zipStream);
|
|
200
|
+
this.zipStream.destroy(err);
|
|
201
|
+
this.isPipe = false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
followSymlink() {
|
|
205
|
+
let followSymlink = false;
|
|
206
|
+
if (this.options &&
|
|
207
|
+
this.options.followSymlinks === true) {
|
|
208
|
+
followSymlink = true;
|
|
209
|
+
}
|
|
210
|
+
return followSymlink;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
exports.Zip = Zip;
|