diff --git a/index.js b/index.js index e1b2c78..36d1e71 100644 --- a/index.js +++ b/index.js @@ -23,12 +23,18 @@ module.exports = (filename, options) => { firstFile = file; } - archive.append(file.contents, { - name: file.relative.replace(/\\/g, '/') + (file.isNull() ? '/' : ''), - mode: file.stat && file.stat.mode, - date: file.stat && file.stat.mtime ? file.stat.mtime : null, - ...options - }); + const nameNormalized = file.relative.replace(/\\/g, '/'); + + if (file.isSymbolic()) { + archive.symlink(nameNormalized, file.symlink); + } else { + archive.append(file.contents, { + name: nameNormalized + (file.isNull() ? '/' : ''), + mode: file.stat && file.stat.mode, + date: file.stat && file.stat.mtime ? file.stat.mtime : null, + ...options + }); + } callback(); }, function (callback) { diff --git a/package.json b/package.json index 2b4dffc..478ba5f 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "devDependencies": { "gulp": "^4.0.2", "gulp-gzip": "^1.2.0", + "vinyl-fs": "^3.0.3", "mocha": "^6.2.0", "nyc": "^14.1.1", "rimraf": "^3.0.0", diff --git a/test/fixture/.symlink/symlink.txt b/test/fixture/.symlink/symlink.txt new file mode 120000 index 0000000..98771c4 --- /dev/null +++ b/test/fixture/.symlink/symlink.txt @@ -0,0 +1 @@ +../fixture.txt \ No newline at end of file diff --git a/test/symlink.js b/test/symlink.js new file mode 100644 index 0000000..cd4abc4 --- /dev/null +++ b/test/symlink.js @@ -0,0 +1,60 @@ +/* eslint-env mocha */ +const {createReadStream} = require('fs'); +const path = require('path'); +const zlib = require('zlib'); +const assert = require('assert'); +const gulp = require('gulp'); +const gulpZip = require('gulp-gzip'); +const tarfs = require('tar-fs'); +const rimraf = require('rimraf'); +const vinylFs = require('vinyl-fs'); +const gulpTar = require('..'); + +it('should include symlink', done => { + const onTargz = () => { + const filename = 'archive.tar.gz'; + const fullPath = path.join(__dirname, 'dest', filename); + const rs = createReadStream(fullPath); + + rs.pipe(zlib.createGunzip()) + .pipe( + tarfs.extract(path.join(__dirname, 'dest-out'), { + map: header => { + const expected = expectedNames.pop(); + assert.strictEqual(header.name, expected.name); + assert.strictEqual(header.type, expected.type); + if (header.type === 'symlink') { + assert.strictEqual(header.linkname, expected.linkname); + } + + return header; + } + }) + ) + .on('finish', () => { + for (const directory of ['dest', 'dest-out']) { + rimraf.sync(path.join(__dirname, directory)); + } + + done(); + }); + }; + + const expectedNames = [ + {name: 'fixture/.symlink/symlink.txt', type: 'symlink', linkname: '../fixture.txt'}, + {name: 'fixture/dir-fixture/inside.txt', type: 'file'}, + {name: 'fixture/fixture.txt', type: 'file'}, + {name: 'fixture/dir-fixture/', type: 'directory'} + ]; + + vinylFs + .src(['fixture/**/*', 'fixture/.symlink/**/*'], { + cwd: __dirname, + base: __dirname, + resolveSymlinks: false + }) + .pipe(gulpTar('archive.tar')) + .pipe(gulpZip()) + .pipe(gulp.dest('dest', {cwd: __dirname})) + .on('finish', onTargz); +});