Skip to content

Commit

Permalink
Add finalize: false option to pack(), to allow advanced tar strea…
Browse files Browse the repository at this point in the history
…m manipulation (#65)

* Failing test for finish hooks

* Add finish hook support for packing and extracting

* Add test for tar.pack() with finalize: false

* Add opts.finalize support to tar.pack

* Document advanced tar-stream usage
  • Loading branch information
courajs authored and mafintosh committed Oct 5, 2017
1 parent 4c89247 commit 6f3aeb2
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 1 deletion.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,26 @@ Copying a directory with permissions and mtime intact is as simple as
tar.pack('source-directory').pipe(tar.extract('dest-directory'))
```

## Interaction with [`tar-stream`](https://github.com/mafintosh/tar-stream)

Use `finalize: false` and the `finish` hook to
leave the pack stream open for further entries (see
[`tar-stream#pack`](https://github.com/mafintosh/tar-stream#packing)),
and use `pack` to pass an existing pack stream.

``` js
var mypack = tar.pack('./my-directory', {
finalize: false,
finish: function(sameAsMypack) {
mypack.entry({name: 'generated-file.txt'}, "hello")
tar.pack('./other-directory', {
pack: sameAsMypack
})
}
})
```


## Performance

Packing and extracting a 6.1 GB with 2496 directories and 2398 files yields the following results on my Macbook Air.
Expand Down
8 changes: 7 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ exports.pack = function (cwd, opts) {
var dmode = typeof opts.dmode === 'number' ? opts.dmode : 0
var fmode = typeof opts.fmode === 'number' ? opts.fmode : 0
var pack = opts.pack || tar.pack()
var finish = opts.finish || noop

if (opts.strip) map = strip(map, opts.strip)

Expand All @@ -94,7 +95,10 @@ exports.pack = function (cwd, opts) {

var onstat = function (err, filename, stat) {
if (err) return pack.destroy(err)
if (!filename) return pack.finalize()
if (!filename) {
if (opts.finalize !== false) pack.finalize()
return finish(pack)
}

if (stat.isSocket()) return onnextentry() // tar does not support sockets...

Expand Down Expand Up @@ -309,6 +313,8 @@ exports.extract = function (cwd, opts) {
})
})

if (opts.finish) extract.on('finish', opts.finish)

return extract
}

Expand Down
67 changes: 67 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,3 +225,70 @@ test('check type while mapping header on packing', function (t) {

tar.pack(e, { map: checkHeaderType })
})

test('finish callbacks', function (t) {
t.plan(3)

var a = path.join(__dirname, 'fixtures', 'a')
var b = path.join(__dirname, 'fixtures', 'copy', 'a')

rimraf.sync(b)

var packEntries = 0
var extractEntries = 0

var countPackEntry = function (header) { packEntries++ }
var countExtractEntry = function (header) { extractEntries++ }

var pack
var onPackFinish = function (passedPack) {
t.equal(packEntries, 2, 'All entries have been packed') // 2 entries - the file and base directory
t.equal(passedPack, pack, 'The finish hook passes the pack')
}

var onExtractFinish = function () { t.equal(extractEntries, 2) }

pack = tar.pack(a, {map: countPackEntry, finish: onPackFinish})

pack.pipe(tar.extract(b, {map: countExtractEntry, finish: onExtractFinish}))
.on('finish', function () {
t.end()
})
})

test('not finalizing the pack', function (t) {
t.plan(2)

var a = path.join(__dirname, 'fixtures', 'a')
var b = path.join(__dirname, 'fixtures', 'b')

var out = path.join(__dirname, 'fixtures', 'copy', 'merged-packs')

rimraf.sync(out)

var prefixer = function (prefix) {
return function (header) {
header.name = path.join(prefix, header.name)
return header
}
}

tar.pack(a, {
map: prefixer('a-files'),
finalize: false,
finish: packB
})

function packB (pack) {
tar.pack(b, {pack: pack, map: prefixer('b-files')})
.pipe(tar.extract(out))
.on('finish', assertResults)
}

function assertResults () {
var containers = fs.readdirSync(out)
t.deepEqual(containers, ['a-files', 'b-files'])
var aFiles = fs.readdirSync(path.join(out, 'a-files'))
t.deepEqual(aFiles, ['hello.txt'])
}
})

0 comments on commit 6f3aeb2

Please sign in to comment.