UNPKG

3.69 kBJavaScriptView Raw
1'use strict';
2
3var fs = require('fs');
4var map = require('map-key');
5var mkdir = require('mkdirp');
6var path = require('path');
7var pipeline = require('stream-combiner');
8var rm = require('rimraf');
9var tempfile = require('tempfile');
10
11/**
12 * Initialize Decompress with options
13 *
14 * Options:
15 *
16 * - `ext` String with file name, MIME type, etc
17 * - `path` Path to extract to
18 * - `strip` Equivalent to --strip-components for tar
19 *
20 * @param {Object} opts
21 * @api private
22 */
23
24function Decompress(opts) {
25 opts = opts || {};
26 this.opts = opts;
27 this.path = opts.path || process.cwd();
28 this.ext = opts.ext || '';
29 this.strip = +opts.strip || 0;
30 this.extractors = {
31 '.zip': this._extractZip,
32 '.tar': this._extractTar,
33 '.tar.gz': this._extractTarGz,
34 '.tgz': this._extractTarGz,
35 'application/zip': this._extractZip,
36 'application/x-gzip': this._extractTarGz,
37 'application/x-tar': this._extractTar,
38 'application/x-tgz': this._extractTarGz
39 };
40 this.extractor = this._getExtractor(this.ext);
41}
42
43/**
44 * Extract an archive
45 *
46 * @api public
47 */
48
49Decompress.prototype.extract = function () {
50 var self = this;
51 var stream = this.extractor();
52
53 if (!fs.existsSync(this.path)) {
54 mkdir.sync(self.path);
55 }
56
57 return stream;
58};
59
60/**
61 * Check if a file can be extracted
62 *
63 * @param {String} src
64 * @param {String} mime
65 * @api public
66 */
67
68Decompress.prototype.canExtract = function (src, mime) {
69 if (this._getExtractor(src)) {
70 return true;
71 }
72
73 if (mime && this._getExtractor(mime)) {
74 return true;
75 }
76
77 return false;
78};
79
80/**
81 * Get the extractor for a desired file
82 *
83 * @param {String} src
84 * @api private
85 */
86
87Decompress.prototype._getExtractor = function (src) {
88 src = src.toLowerCase();
89 return map(this.extractors, src);
90};
91
92/**
93 * Extract a zip file
94 *
95 * @api private
96 */
97
98Decompress.prototype._extractZip = function () {
99 var AdmZip = require('adm-zip');
100 var tmp = tempfile('.zip');
101 var self = this;
102 var stream = fs.createWriteStream(tmp);
103 var zip;
104
105 stream.on('close', function () {
106 zip = new AdmZip(tmp);
107
108 zip.getEntries().forEach(function (entry) {
109 if (!entry.isDirectory) {
110 var dest;
111 var dir = path.dirname(entry.entryName.toString()).split(path.sep);
112 var file = path.basename(entry.rawEntryName.toString());
113
114 if (self.strip) {
115 dir = dir.slice(self.strip);
116 }
117
118 dest = path.join(self.path, dir.join(path.sep), file);
119
120 mkdir.sync(path.dirname(dest));
121 fs.writeFileSync(dest, entry.getData());
122
123 if (self.opts.mode) {
124 fs.chmodSync(dest, self.opts.mode);
125 }
126 }
127 });
128
129 rm.sync(tmp);
130 });
131
132 return stream;
133};
134
135/**
136 * Extract a tar file
137 *
138 * @api private
139 */
140
141Decompress.prototype._extractTar = function () {
142 var tar = require('tar');
143 var stream = tar.Extract(this.opts);
144
145 return stream;
146};
147
148/**
149 * Extract a tar.gz file
150 *
151 * @api private
152 */
153
154Decompress.prototype._extractTarGz = function () {
155 var tar = require('tar');
156 var zlib = require('zlib');
157 var stream = zlib.Unzip();
158 var dest = tar.Extract(this.opts);
159
160 return pipeline(stream, dest);
161};
162
163/**
164 * Module exports
165 */
166
167module.exports = function (opts) {
168 var decompress = new Decompress(opts);
169 return decompress.extract();
170};
171
172module.exports.canExtract = function (src, mime) {
173 var decompress = new Decompress();
174 return decompress.canExtract(src, mime);
175};