1
2
3
4
5
6
7
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
'use strict';
const fs = require('fs');
const path = require('path');
const stream = require('stream');
const tar = require('tar-stream');
const utils = require('../utils');
const ready = require('get-ready');
class TarFileStream extends stream.Transform {
constructor(opts) {
super(opts);
const pack = tar.pack();
pack.on('data', chunk => this.push(chunk));
pack.on('end', () => this.ready(true));
const sourceType = utils.sourceType(opts.source);
if (sourceType === 'file') {
// stat file to get file size
fs.stat(opts.source, (err, stat) => {
if (err) return this.emit('error', err);
this.entry = pack.entry({ name: opts.relativePath || path.basename(opts.source), size: stat.size, mode: stat.mode & 0o777 }, err => {
if (err) return this.emit('error', err);
pack.finalize();
});
const stream = fs.createReadStream(opts.source, opts.fs);
stream.on('error', err => this.emit('error', err));
stream.pipe(this);
});
} else if (sourceType === 'buffer') {
if (!opts.relativePath) return this.emit('error', 'opts.relativePath is required if opts.source is a buffer');
pack.entry({ name: opts.relativePath }, opts.source);
pack.finalize();
this.end();
} else { // stream or undefined
if (!opts.relativePath) return process.nextTick(() => this.emit('error', 'opts.relativePath is required'));
if (opts.size) {
this.entry = pack.entry({ name: opts.relativePath, size: opts.size }, err => {
if (err) return this.emit('error', err);
pack.finalize();
});
} else {
if (!opts.suppressSizeWarning) {
console.warn('You should specify the size of streamming data by opts.size to prevent all streaming data from loading into memory. If you are sure about memory cost, pass opts.supressSizeWarning: true to suppress this warning');
}
const buf = [];
this.entry = new stream.Writable({
write(chunk, _, callback) {
buf.push(chunk);
callback();
},
});
this.entry.on('finish', () => {
pack.entry({ name: opts.relativePath }, Buffer.concat(buf));
pack.finalize();
});
}
if (sourceType === 'stream') {
opts.source.on('error', err => this.emit('error', err));
opts.source.pipe(this);
}
}
}
_transform(chunk, encoding, callback) {
if (this.entry) {
this.entry.write(chunk, encoding, callback);
}
}
_flush(callback) {
if (this.entry) {
this.entry.end();
}
this.ready(callback);
}
}
ready.mixin(TarFileStream.prototype);
module.exports = TarFileStream;