Skip to content

Commit

Permalink
Merge pull request #73 from gerhardberger/transform-option
Browse files Browse the repository at this point in the history
Adds transform option to api
  • Loading branch information
zcbenz committed Jul 20, 2016
2 parents 05be250 + 06f3c25 commit 3f3eed7
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 27 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,26 @@ asar.createPackage(src, dest, function() {

Please note that there is currently *no* error handling provided!

### Transform
You can pass in a `transform` option, that is a function, which either returns
nothing, or a `stream.Transform`. The latter will be used on files that will be
in the `.asar` file to transform them (e.g. compress).

```js
var asar = require('asar');

var src = 'some/path/';
var dest = 'name.asar';

function transform(filename) {
return new CustomTransformStream()
}

asar.createPackageWithOptions(src, dest, { transform: transform }, function() {
console.log('done.');
})
```

## Using with grunt

There is also an unofficial grunt plugin to generate asar archives at [bwin/grunt-asar][grunt-asar].
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"glob": "^6.0.4",
"minimatch": "^3.0.0",
"mkdirp": "^0.5.0",
"mksnapshot": "^0.3.0"
"mksnapshot": "^0.3.0",
"tmp": "0.0.28"
},
"devDependencies": {
"coffee-script": "^1.10.0",
Expand Down
31 changes: 22 additions & 9 deletions src/asar.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ module.exports.createPackageFromFiles = (src, dest, filenames, metadata, options
else
filenamesSorted = filenames

for filename in filenamesSorted
handleFile = (filename, done) ->
file = metadata[filename]
unless file
stat = fs.lstatSync filename
Expand All @@ -101,18 +101,31 @@ module.exports.createPackageFromFiles = (src, dest, filenames, metadata, options
dirName = path.relative src, path.dirname(filename)
shouldUnpack = isUnpackDir dirName, options.unpackDir
files.push filename: filename, unpack: shouldUnpack
filesystem.insertFile filename, shouldUnpack, file.stat
filesystem.insertFile filename, shouldUnpack, file, options, done
return
when 'link'
filesystem.insertLink filename, file.stat
done()

mkdirp path.dirname(dest), (error) ->
return callback(error) if error
disk.writeFilesystem dest, filesystem, files, (error) ->
insertsDone = ->
mkdirp path.dirname(dest), (error) ->
return callback(error) if error
if options.snapshot
createSnapshot src, dest, filenames, metadata, options, callback
else
callback null
disk.writeFilesystem dest, filesystem, files, metadata, (error) ->
return callback(error) if error
if options.snapshot
createSnapshot src, dest, filenames, metadata, options, callback
else
callback null

names = filenamesSorted.slice()

next = (name) ->
if !name then return insertsDone()

handleFile name, ->
next names.shift()

next names.shift()

module.exports.statFile = (archive, filename, followLinks) ->
filesystem = disk.readFilesystemSync archive
Expand Down
15 changes: 8 additions & 7 deletions src/disk.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ copyFileToSync = (dest, src, filename) ->
mkdirp.sync path.dirname(targetFile)
fs.writeFileSync targetFile, content, mode: stats.mode

writeFileListToStream = (dest, filesystem, out, list, callback) ->
writeFileListToStream = (dest, filesystem, out, list, metadata, callback) ->
if list.length is 0
out.end()
return callback null
Expand All @@ -28,15 +28,16 @@ writeFileListToStream = (dest, filesystem, out, list, callback) ->
copyFileToSync "#{dest}.unpacked", filesystem.src, filename
catch error
return callback error
writeFileListToStream dest, filesystem, out, list.slice(1), callback
writeFileListToStream dest, filesystem, out, list.slice(1), metadata, callback
else
stream = fs.createReadStream(file.filename)
tr = metadata[file.filename].transformed
stream = fs.createReadStream (if tr then tr.path else file.filename)
stream.pipe out, end: false
stream.on 'error', callback
stream.on 'end', ->
writeFileListToStream dest, filesystem, out, list.slice(1), callback
stream.pipe out, end: false
writeFileListToStream dest, filesystem, out, list.slice(1), metadata, callback

module.exports.writeFilesystem = (dest, filesystem, files, callback) ->
module.exports.writeFilesystem = (dest, filesystem, files, metadata, callback) ->
try
headerPickle = pickle.createEmpty()
headerPickle.writeString JSON.stringify(filesystem.header)
Expand All @@ -52,7 +53,7 @@ module.exports.writeFilesystem = (dest, filesystem, files, callback) ->
out.on 'error', callback
out.write sizeBuf
out.write headerBuf, ->
writeFileListToStream dest, filesystem, out, files, callback
writeFileListToStream dest, filesystem, out, files, metadata, callback

module.exports.readArchiveHeaderSync = (archive) ->
fd = fs.openSync archive, 'r'
Expand Down
44 changes: 34 additions & 10 deletions src/filesystem.coffee
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
fs = require 'fs'
path = require 'path'
tmp = require 'tmp'
UINT64 = require('cuint').UINT64

class Filesystem
Expand Down Expand Up @@ -28,23 +29,46 @@ class Filesystem
node.unpacked = shouldUnpack if shouldUnpack
node.files = {}

insertFile: (p, shouldUnpack, stat) ->
insertFile: (p, shouldUnpack, file, options, callback) ->
dirNode = @searchNodeFromPath path.dirname(p)
node = @searchNodeFromPath p
if shouldUnpack or dirNode.unpacked
node.size = stat.size
node.size = file.stat.size
node.unpacked = true
callback()
return

# JavaScript can not precisely present integers >= UINT32_MAX.
if stat.size > 4294967295
throw new Error("#{p}: file size can not be larger than 4.2GB")
handler = =>
size = if file.transformed then file.transformed.stat.size else file.stat.size

node.size = stat.size
node.offset = @offset.toString()
if process.platform isnt 'win32' and stat.mode & 0o100
node.executable = true
@offset.add UINT64(stat.size)
# JavaScript can not precisely present integers >= UINT32_MAX.
if size > 4294967295
throw new Error("#{p}: file size can not be larger than 4.2GB")

node.size = size
node.offset = this.offset.toString()
if process.platform isnt 'win32' and file.stat.mode & 0o100
node.executable = true
this.offset.add UINT64(size)

callback()

tr = options.transform && options.transform(p)
if tr
tmp.file (err, path) ->
return handler() if err
out = fs.createWriteStream(path)
stream = fs.createReadStream p

stream.pipe(tr).pipe(out)
tr.on 'end', ->
file.transformed = {
path,
stat: fs.lstatSync path
}
handler()
else
handler()

insertLink: (p, stat) ->
link = path.relative fs.realpathSync(@src), fs.realpathSync(p)
Expand Down
6 changes: 6 additions & 0 deletions test/api-spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ os = require 'os'
asar = require '../lib/asar'
compDirs = require './util/compareDirectories'
compFiles = require './util/compareFiles'
transform = require './util/transformStream'

describe 'api', ->
it 'should create archive from directory', (done) ->
Expand All @@ -17,6 +18,11 @@ describe 'api', ->
done compFiles 'tmp/packthis-api.asar', 'test/expected/packthis.asar'
return
return
it 'should create archive from directory (with transformed files)', (done) ->
asar.createPackageWithOptions 'test/input/packthis/', 'tmp/packthis-api-transformed.asar', {transform}, (error) ->
done compFiles 'tmp/packthis-api-transformed.asar', 'test/expected/packthis-transformed.asar'
return
return
it 'should list files/dirs in archive', ->
actual = asar.listPackage('test/input/extractthis.asar').join('\n')
expected = fs.readFileSync 'test/expected/extractthis-filelist.txt', 'utf8'
Expand Down
Binary file added test/expected/packthis-transformed.asar
Binary file not shown.
20 changes: 20 additions & 0 deletions test/util/transformStream.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{ Transform } = require 'stream'
{ basename } = require 'path'

class Reverser extends Transform
constructor: ->
super()
@_data = ''

_transform: (buf, enc, cb) ->
@_data += buf
cb()

_flush: (cb) ->
txt = @_data.toString().split('').reverse().join('')
@push(txt)
cb()

module.exports = (filename) ->
if basename(filename) is 'file0.txt'
return new Reverser()

0 comments on commit 3f3eed7

Please sign in to comment.