dir-archiver 2.0.0 → 2.1.1
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/README.md +8 -1
- package/cli.js +15 -30
- package/index.js +145 -103
- package/package.json +13 -3
package/README.md
CHANGED
|
@@ -35,7 +35,14 @@ const excludes = ['directory_name', 'file.extension'];
|
|
|
35
35
|
var archive = new DirArchiver('path/to/directory', 'path/to/desination/zipfile.zip', true, excludes);
|
|
36
36
|
|
|
37
37
|
// Create the zip file.
|
|
38
|
-
archive.createZip()
|
|
38
|
+
archive.createZip().then(() => {
|
|
39
|
+
console.log('Archive ready');
|
|
40
|
+
}).catch((err) => {
|
|
41
|
+
console.error(err);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Or with async/await:
|
|
45
|
+
// await archive.createZip();
|
|
39
46
|
```
|
|
40
47
|
## Command Line Interface
|
|
41
48
|
|
package/cli.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const DirArchiver = require( './index' );
|
|
4
|
+
const parseArgs = require( 'argv-flags' );
|
|
4
5
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
var excludes = [];
|
|
6
|
+
const directoryPath = parseArgs( '--src', 'string' );
|
|
7
|
+
const zipPath = parseArgs( '--dest', 'string' );
|
|
8
|
+
const includeBaseDirectory = parseArgs( '--includebasedir', 'boolean' );
|
|
9
|
+
const excludes = parseArgs( '--exclude', 'array' ) || [];
|
|
10
10
|
|
|
11
|
-
if (
|
|
12
|
-
|
|
11
|
+
if ( directoryPath === false || zipPath === false ) {
|
|
12
|
+
console.log( ` Dir Archiver could not be executed. Some arguments are missing.
|
|
13
13
|
|
|
14
14
|
Options:
|
|
15
15
|
--src The path of the folder to archive. [string][required]
|
|
@@ -20,27 +20,12 @@ if ( ! arguments.includes( '--src' ) || ! arguments.includes( '--dest' ) ) {
|
|
|
20
20
|
an archive that includes this base directory.
|
|
21
21
|
If this option is set to false the archive created will
|
|
22
22
|
unzip its content to the current directory. [bool]
|
|
23
|
-
--exclude A list with the names of the files and folders to exclude. [array]`);
|
|
24
|
-
|
|
23
|
+
--exclude A list with the names of the files and folders to exclude. [array]` );
|
|
24
|
+
process.exit(); // eslint-disable-line n/no-process-exit
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
zipPath = arguments[parseInt(argumentIndex) + 1];
|
|
33
|
-
}
|
|
34
|
-
if( arguments[argumentIndex] === '--includebasedir' ) {
|
|
35
|
-
includeBaseDirectory = ( arguments[parseInt(argumentIndex) + 1] === 'true' );
|
|
36
|
-
}
|
|
37
|
-
if( afterExclude === true ) {
|
|
38
|
-
excludes.push( arguments[argumentIndex] );
|
|
39
|
-
}
|
|
40
|
-
if( arguments[argumentIndex] === '--exclude' ) {
|
|
41
|
-
var afterExclude = true;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const archive = new DirArchiver(directoryPath, zipPath, includeBaseDirectory, excludes);
|
|
46
|
-
archive.createZip();
|
|
27
|
+
const archive = new DirArchiver( directoryPath, zipPath, includeBaseDirectory, excludes );
|
|
28
|
+
archive.createZip().catch( ( err ) => {
|
|
29
|
+
console.error( err );
|
|
30
|
+
process.exitCode = 1;
|
|
31
|
+
} );
|
package/index.js
CHANGED
|
@@ -5,108 +5,150 @@ const fs = require( 'fs' );
|
|
|
5
5
|
const archiver = require( 'archiver' );
|
|
6
6
|
|
|
7
7
|
class DirArchiver {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
8
|
+
/**
|
|
9
|
+
* The constructor.
|
|
10
|
+
* @param {string} directoryPath - the path of the folder to archive.
|
|
11
|
+
* @param {string} zipPath - The path of the zip file to create.
|
|
12
|
+
* @param {Boolean} includeBaseDirectory - Includes a base directory at the root of the archive. For example, if the root folder of your project is named "your-project", setting includeBaseDirectory to true will create an archive that includes this base directory. If this option is set to false the archive created will unzip its content to the current directory.
|
|
13
|
+
* @param {array} excludes - The name of the files and foldes to exclude.
|
|
14
|
+
*/
|
|
15
|
+
constructor( directoryPath, zipPath, includeBaseDirectory, excludes ) {
|
|
16
|
+
|
|
17
|
+
// Contains the excluded files and folders.
|
|
18
|
+
const safeExcludes = Array.isArray( excludes ) ? excludes : [];
|
|
19
|
+
this.excludes = safeExcludes.map( ( element ) => {
|
|
20
|
+
return path.normalize( element );
|
|
21
|
+
} );
|
|
22
|
+
|
|
23
|
+
this.directoryPath = path.resolve( directoryPath );
|
|
24
|
+
|
|
25
|
+
this.zipPath = path.resolve( zipPath );
|
|
26
|
+
|
|
27
|
+
this.includeBaseDirectory = includeBaseDirectory;
|
|
28
|
+
|
|
29
|
+
this.baseDirectory = path.basename( this.directoryPath );
|
|
30
|
+
|
|
31
|
+
const relativeZipPath = path.relative( this.directoryPath, this.zipPath );
|
|
32
|
+
const isZipInsideSource = relativeZipPath && ! relativeZipPath.startsWith( '..' ) && ! path.isAbsolute( relativeZipPath );
|
|
33
|
+
if ( isZipInsideSource ) {
|
|
34
|
+
const normalizedZipPath = path.normalize( relativeZipPath );
|
|
35
|
+
if ( ! this.excludes.includes( normalizedZipPath ) ) {
|
|
36
|
+
this.excludes.push( normalizedZipPath );
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Recursively traverse the directory tree and append the files to the archive.
|
|
43
|
+
* @param {string} directoryPath - The path of the directory being looped through.
|
|
44
|
+
*/
|
|
45
|
+
traverseDirectoryTree( directoryPath ) {
|
|
46
|
+
const files = fs.readdirSync( directoryPath );
|
|
47
|
+
for ( const file of files ) {
|
|
48
|
+
const currentPath = path.join( path.resolve( directoryPath ), file );
|
|
49
|
+
if ( path.resolve( currentPath ) === this.zipPath ) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const stats = fs.statSync( currentPath );
|
|
53
|
+
let relativePath = path.relative( this.directoryPath, currentPath );
|
|
54
|
+
if ( stats.isFile() && ! this.excludes.includes( relativePath ) ) {
|
|
55
|
+
if ( this.includeBaseDirectory === true ) {
|
|
56
|
+
this.archive.file( currentPath, {
|
|
57
|
+
name: path.join( this.baseDirectory, relativePath )
|
|
58
|
+
} );
|
|
59
|
+
} else {
|
|
60
|
+
this.archive.file( currentPath, {
|
|
61
|
+
name: relativePath
|
|
62
|
+
} );
|
|
63
|
+
}
|
|
64
|
+
} else if ( stats.isDirectory() && ! this.excludes.includes( relativePath ) ) {
|
|
65
|
+
this.traverseDirectoryTree( currentPath );
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
prettyBytes( bytes ) {
|
|
71
|
+
if ( bytes > 1000 && bytes < 1000000 ) {
|
|
72
|
+
return Math.round( ( ( bytes / 1000 ) + Number.EPSILON ) * 100 ) / 100 + ' KB';
|
|
73
|
+
}
|
|
74
|
+
if ( bytes > 1000000 && bytes < 1000000000 ) {
|
|
75
|
+
return Math.round( ( ( bytes / 1000000 ) + Number.EPSILON ) * 100 ) / 100 + ' MB';
|
|
76
|
+
}
|
|
77
|
+
if ( bytes > 1000000000 ) {
|
|
78
|
+
return Math.round( ( ( bytes / 1000000000 ) + Number.EPSILON ) * 100 ) / 100 + ' GB';
|
|
79
|
+
}
|
|
80
|
+
return bytes + ' bytes';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
createZip () {
|
|
84
|
+
return new Promise( ( resolve, reject ) => {
|
|
85
|
+
let settled = false;
|
|
86
|
+
const safeResolve = ( value ) => {
|
|
87
|
+
if ( settled ) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
settled = true;
|
|
91
|
+
resolve( value );
|
|
92
|
+
};
|
|
93
|
+
const safeReject = ( err ) => {
|
|
94
|
+
if ( settled ) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
settled = true;
|
|
98
|
+
reject( err );
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Remove the destination zip if it exists.
|
|
102
|
+
// see : https://github.com/Ismail-elkorchi/dir-archiver/issues/5
|
|
103
|
+
try {
|
|
104
|
+
if ( fs.existsSync( this.zipPath ) ) {
|
|
105
|
+
fs.unlinkSync( this.zipPath );
|
|
106
|
+
}
|
|
107
|
+
} catch ( err ) {
|
|
108
|
+
safeReject( err );
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Create a file to stream archive data to.
|
|
113
|
+
this.output = fs.createWriteStream( this.zipPath );
|
|
114
|
+
this.archive = archiver( 'zip', {
|
|
115
|
+
zlib: { level: 9 }
|
|
116
|
+
} );
|
|
117
|
+
|
|
118
|
+
// Catch warnings during archiving.
|
|
119
|
+
this.archive.on( 'warning', ( err ) => {
|
|
120
|
+
if ( err.code === 'ENOENT' ) {
|
|
121
|
+
// log warning
|
|
122
|
+
console.log( err );
|
|
123
|
+
} else {
|
|
124
|
+
safeReject( err );
|
|
125
|
+
}
|
|
126
|
+
} );
|
|
127
|
+
|
|
128
|
+
// Catch errors during archiving.
|
|
129
|
+
this.archive.on( 'error', ( err ) => {
|
|
130
|
+
safeReject( err );
|
|
131
|
+
} );
|
|
132
|
+
|
|
133
|
+
this.output.on( 'error', ( err ) => {
|
|
134
|
+
safeReject( err );
|
|
135
|
+
} );
|
|
136
|
+
|
|
137
|
+
// Listen for all archive data to be written.
|
|
138
|
+
this.output.on( 'close', () => {
|
|
139
|
+
console.log( `Created ${this.zipPath} of ${this.prettyBytes( this.archive.pointer() )}` );
|
|
140
|
+
safeResolve( this.zipPath );
|
|
141
|
+
} );
|
|
142
|
+
|
|
143
|
+
// Pipe archive data to the file.
|
|
144
|
+
this.archive.pipe( this.output );
|
|
145
|
+
|
|
146
|
+
// Recursively traverse the directory tree and append the files to the archive.
|
|
147
|
+
this.traverseDirectoryTree( this.directoryPath );
|
|
148
|
+
|
|
149
|
+
// Finalize the archive.
|
|
150
|
+
this.archive.finalize();
|
|
151
|
+
} );
|
|
152
|
+
}
|
|
111
153
|
}
|
|
112
154
|
module.exports = DirArchiver;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dir-archiver",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Compress a whole directory (including subdirectories) into a zip file, with options to exclude specific files, or directories.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "index.js",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"LICENSE",
|
|
12
|
-
"index.js"
|
|
12
|
+
"index.js",
|
|
13
|
+
"cli.js"
|
|
13
14
|
],
|
|
14
15
|
"keywords": [
|
|
15
16
|
"zip",
|
|
@@ -31,7 +32,16 @@
|
|
|
31
32
|
},
|
|
32
33
|
"bugs": "https://github.com/Ismail-elkorchi/dir-archiver/issues",
|
|
33
34
|
"homepage": "https://github.com/Ismail-elkorchi/dir-archiver",
|
|
35
|
+
"scripts": {
|
|
36
|
+
"lint": "eslint cli.js index.js",
|
|
37
|
+
"lint:fix": "eslint --fix cli.js index.js"
|
|
38
|
+
},
|
|
34
39
|
"dependencies": {
|
|
35
|
-
"archiver": "^
|
|
40
|
+
"archiver": "^7.0.1",
|
|
41
|
+
"argv-flags": "^0.1.1"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"eslint": "^8.24.0",
|
|
45
|
+
"eslint-plugin-n": "^15.3.0"
|
|
36
46
|
}
|
|
37
47
|
}
|