Skip to content
This repository was archived by the owner on Dec 15, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ Supported file extensions:
* .tar
* .tar.gz
* .tgz
* .tar.bz2
* .tbz
* .tbz2
* .war
* .zip
* .egg
Expand Down Expand Up @@ -69,6 +72,17 @@ Buffer contents of the uncompressed paths. The `callback` gets two arguments
`callback` - The function to call after reading completes with an error or
the Buffer contents.

### archive.readBzip(bzipArchivePath, callback)

Read the contents of the bzipped archive path and invoke the callback with the
Buffer contents of the uncompressed paths. The `callback` gets two arguments
`(error, pathContents)`.

`bzipArchivePath` - The string path to the bzipped archive file.

`callback` - The function to call after reading completes with an error or
the Buffer contents.

### ArchiveEntry

Class representing a path entry inside an archive file.
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"async": "~0.2.9",
"colors": "~0.6.2",
"rimraf": "~2.2.6",
"unbzip2-stream": "^1.3.3",
"yauzl": "^2.9.1"
}
}
198 changes: 198 additions & 0 deletions spec/bzip-spec.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
archive = require '../lib/ls-archive'
path = require 'path'

describe "bzipped tar files", ->
fixturesRoot = null

beforeEach ->
fixturesRoot = path.join(__dirname, 'fixtures')

describe ".list()", ->
describe "when the archive file exists", ->
it "returns files in the bzipped tar archive", ->
bzipPaths = null
callback = (error, paths) -> bzipPaths = paths
archive.list(path.join(fixturesRoot, 'one-file.tar.bz2'), callback)
waitsFor -> bzipPaths?
runs ->
expect(bzipPaths.length).toBe 1
expect(bzipPaths[0].path).toBe 'file.txt'
expect(bzipPaths[0].isDirectory()).toBe false
expect(bzipPaths[0].isFile()).toBe true
expect(bzipPaths[0].isSymbolicLink()).toBe false

it "returns files in the bzipped tar archive", ->
bzipPaths = null
callback = (error, paths) -> bzipPaths = paths
archive.list(path.join(fixturesRoot, 'one-file.tbz'), callback)
waitsFor -> bzipPaths?
runs ->
expect(bzipPaths.length).toBe 1
expect(bzipPaths[0].path).toBe 'file.txt'
expect(bzipPaths[0].isDirectory()).toBe false
expect(bzipPaths[0].isFile()).toBe true
expect(bzipPaths[0].isSymbolicLink()).toBe false

it "returns files in the bzipped tar archive", ->
bzipPaths = null
callback = (error, paths) -> bzipPaths = paths
archive.list(path.join(fixturesRoot, 'one-file.tbz2'), callback)
waitsFor -> bzipPaths?
runs ->
expect(bzipPaths.length).toBe 1
expect(bzipPaths[0].path).toBe 'file.txt'
expect(bzipPaths[0].isDirectory()).toBe false
expect(bzipPaths[0].isFile()).toBe true
expect(bzipPaths[0].isSymbolicLink()).toBe false

it "returns folders in the bzipped tar archive", ->
bzipPaths = null
callback = (error, paths) -> bzipPaths = paths
archive.list(path.join(fixturesRoot, 'one-folder.tar.bz2'), callback)
waitsFor -> bzipPaths?
runs ->
expect(bzipPaths.length).toBe 1
expect(bzipPaths[0].path).toBe 'folder'
expect(bzipPaths[0].isDirectory()).toBe true
expect(bzipPaths[0].isFile()).toBe false
expect(bzipPaths[0].isSymbolicLink()).toBe false

it "returns folders in the bzipped tar archive", ->
bzipPaths = null
callback = (error, paths) -> bzipPaths = paths
archive.list(path.join(fixturesRoot, 'one-folder.tbz'), callback)
waitsFor -> bzipPaths?
runs ->
expect(bzipPaths.length).toBe 1
expect(bzipPaths[0].path).toBe 'folder'
expect(bzipPaths[0].isDirectory()).toBe true
expect(bzipPaths[0].isFile()).toBe false
expect(bzipPaths[0].isSymbolicLink()).toBe false

it "returns folders in the bzipped tar archive", ->
bzipPaths = null
callback = (error, paths) -> bzipPaths = paths
archive.list(path.join(fixturesRoot, 'one-folder.tbz2'), callback)
waitsFor -> bzipPaths?
runs ->
expect(bzipPaths.length).toBe 1
expect(bzipPaths[0].path).toBe 'folder'
expect(bzipPaths[0].isDirectory()).toBe true
expect(bzipPaths[0].isFile()).toBe false
expect(bzipPaths[0].isSymbolicLink()).toBe false

describe "when the archive path does not exist", ->
it "calls back with an error", ->
archivePath = path.join(fixturesRoot, 'not-a-file.tar.bz2')
pathError = null
callback = (error) -> pathError = error
archive.list(archivePath, callback)
waitsFor -> pathError?
runs -> expect(pathError.message.length).toBeGreaterThan 0

describe "when the archive path isn't a valid bzipped tar file", ->
it "calls back with an error", ->
archivePath = path.join(fixturesRoot, 'invalid.tar.bz2')
pathError = null
callback = (error) -> pathError = error
archive.list(archivePath, callback)
waitsFor -> pathError?
runs -> expect(pathError.message.length).toBeGreaterThan 0

describe "when the second to last extension isn't .tar", ->
it "calls back with an error", ->
archivePath = path.join(fixturesRoot, 'invalid.txt.bz2')
pathError = null
callback = (error, contents) -> pathError = error
archive.list(archivePath, callback)
waitsFor -> pathError?
runs -> expect(pathError.message.length).toBeGreaterThan 0

describe ".readFile()", ->
describe "when the path exists in the archive", ->
it "calls back with the contents of the given path", ->
archivePath = path.join(fixturesRoot, 'one-file.tar.bz2')
pathContents = null
callback = (error, contents) -> pathContents = contents
archive.readFile(archivePath, 'file.txt', callback)
waitsFor -> pathContents?
runs -> expect(pathContents.toString()).toBe 'hello\n'

it "calls back with the contents of the given path", ->
archivePath = path.join(fixturesRoot, 'one-file.tbz')
pathContents = null
callback = (error, contents) -> pathContents = contents
archive.readFile(archivePath, 'file.txt', callback)
waitsFor -> pathContents?
runs -> expect(pathContents.toString()).toBe 'hello\n'

it "calls back with the contents of the given path", ->
archivePath = path.join(fixturesRoot, 'one-file.tbz2')
pathContents = null
callback = (error, contents) -> pathContents = contents
archive.readFile(archivePath, 'file.txt', callback)
waitsFor -> pathContents?
runs -> expect(pathContents.toString()).toBe 'hello\n'

describe "when the path does not exist in the archive", ->
it "calls back with an error", ->
archivePath = path.join(fixturesRoot, 'one-file.tar.bz2')
pathError = null
callback = (error, contents) -> pathError = error
archive.readFile(archivePath, 'not-a-file.txt', callback)
waitsFor -> pathError?
runs -> expect(pathError.message.length).toBeGreaterThan 0

describe "when the archive path does not exist", ->
it "calls back with an error", ->
archivePath = path.join(fixturesRoot, 'not-a-file.tar.bz2')
pathError = null
callback = (error, contents) -> pathError = error
archive.readFile(archivePath, 'not-a-file.txt', callback)
waitsFor -> pathError?
runs -> expect(pathError.message.length).toBeGreaterThan 0

describe "when the archive path isn't a valid bzipped tar file", ->
it "calls back with an error", ->
archivePath = path.join(fixturesRoot, 'invalid.tar.bz2')
pathError = null
callback = (error, contents) -> pathError = error
archive.readFile(archivePath, 'invalid.txt', callback)
waitsFor -> pathError?
runs -> expect(pathError.message.length).toBeGreaterThan 0

describe "when the second to last extension isn't .tar", ->
it "calls back with an error", ->
archivePath = path.join(fixturesRoot, 'invalid.txt.bz2')
pathError = null
callback = (error, contents) -> pathError = error
archive.readFile(archivePath, 'invalid.txt', callback)
waitsFor -> pathError?
runs -> expect(pathError.message.length).toBeGreaterThan 0

describe ".readBzip()", ->
it "calls back with the string contents of the archive", ->
archivePath = path.join(fixturesRoot, 'file.txt.bz2')
archiveContents = null
callback = (error, contents) -> archiveContents = contents
archive.readBzip(archivePath, callback)
waitsFor -> archiveContents?
runs -> expect(archiveContents.toString()).toBe 'hello\n'

describe "when the archive path isn't a valid bzipped tar file", ->
it "calls back with an error", ->
archivePath = path.join(fixturesRoot, 'invalid.tar.bz2')
readError = null
callback = (error, contents) -> readError = error
archive.readBzip(archivePath, callback)
waitsFor -> readError?
runs -> expect(readError.message.length).toBeGreaterThan 0

describe "when the archive path does not exist", ->
it "calls back with an error", ->
archivePath = path.join(fixturesRoot, 'not-a-file.tar.bz2')
readError = null
callback = (error, contents) -> readError = error
archive.readBzip(archivePath, callback)
waitsFor -> readError?
runs -> expect(readError.message.length).toBeGreaterThan 0
Binary file added spec/fixtures/file.txt.bz2
Binary file not shown.
Binary file added spec/fixtures/one-file.tar.bz2
Binary file not shown.
Binary file added spec/fixtures/one-file.tbz
Binary file not shown.
Binary file added spec/fixtures/one-file.tbz2
Binary file not shown.
Binary file added spec/fixtures/one-folder.tar.bz2
Binary file not shown.
Binary file added spec/fixtures/one-folder.tbz
Binary file not shown.
Binary file added spec/fixtures/one-folder.tbz2
Binary file not shown.
2 changes: 1 addition & 1 deletion src/ls-archive-cli.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module.exports = ->

List the files and folders inside an archive file.

Supports .zip, .tar, .tar.gz, and .tgz files.
Supports .zip, .tar, .tar.gz, .tgz, .tar.bz2, .tbz and .tbz2 files.
""")
.describe('colors', 'Enable colored output').default('colors', true).boolean('colors')
.describe('help', 'Show this message').alias('h', 'help')
Expand Down
46 changes: 45 additions & 1 deletion src/ls-archive.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ listGzip = (archivePath, options, callback) ->
gzipStream.on 'error', callback
listTarStream(gzipStream, options, callback)

listBzip = (archivePath, options, callback) ->
bzip = require 'unbzip2-stream'
fileStream = fs.createReadStream(archivePath)
fileStream.on 'error', callback
bzipStream = fileStream.pipe(bzip())
bzipStream.on 'error', callback
listTarStream(bzipStream, options, callback)

listTar = (archivePath, options, callback) ->
fileStream = fs.createReadStream(archivePath)
fileStream.on 'error', callback
Expand Down Expand Up @@ -139,6 +147,15 @@ readFileFromGzip = (archivePath, filePath, callback) ->
callback("#{filePath} does not exist in the archive: #{archivePath}")
readFileFromTarStream(gzipStream, archivePath, filePath, callback)

readFileFromBzip = (archivePath, filePath, callback) ->
fileStream = fs.createReadStream(archivePath)
fileStream.on 'error', callback
bzipStream = fileStream.pipe(require('unbzip2-stream')())
bzipStream.on 'error', callback
bzipStream.on 'end', ->
callback("#{filePath} does not exist in the archive: #{archivePath}")
readFileFromTarStream(bzipStream, archivePath, filePath, callback)

readFileFromTar = (archivePath, filePath, callback) ->
fileStream = fs.createReadStream(archivePath)
fileStream.on 'error', callback
Expand Down Expand Up @@ -175,10 +192,18 @@ isGzipPath = (archivePath) ->
path.extname(archivePath) is '.tgz' or
path.extname(path.basename(archivePath, '.gz')) is '.tar'

isBzipPath = (archivePath) ->
path.extname(archivePath) is '.tbz' or
path.extname(archivePath) is '.tbz2' or
path.extname(path.basename(archivePath, '.bz2')) is '.tar'

module.exports =
isPathSupported: (archivePath) ->
return false unless archivePath
isTarPath(archivePath) or isZipPath(archivePath) or isGzipPath(archivePath)
isTarPath(archivePath) or
isZipPath(archivePath) or
isGzipPath(archivePath) or
isBzipPath(archivePath)

list: (archivePath, options={}, callback) ->
if typeof options is 'function'
Expand All @@ -189,6 +214,8 @@ module.exports =
listTar(archivePath, options, wrapCallback(callback))
else if isGzipPath(archivePath)
listGzip(archivePath, options, wrapCallback(callback))
else if isBzipPath(archivePath)
listBzip(archivePath, options, wrapCallback(callback))
else if isZipPath(archivePath)
listZip(archivePath, options, wrapCallback(callback))
else
Expand All @@ -200,6 +227,8 @@ module.exports =
readFileFromTar(archivePath, filePath, wrapCallback(callback))
else if isGzipPath(archivePath)
readFileFromGzip(archivePath, filePath, wrapCallback(callback))
else if isBzipPath(archivePath)
readFileFromBzip(archivePath, filePath, wrapCallback(callback))
else if isZipPath(archivePath)
readFileFromZip(archivePath, filePath, wrapCallback(callback))
else
Expand All @@ -220,3 +249,18 @@ module.exports =
chunks.push(chunk)
gzipStream.on 'end', ->
callback(null, Buffer.concat(chunks))

readBzip: (bzipArchivePath, callback) ->
callback = wrapCallback(callback)

bzip = require 'unbzip2-stream'
fileStream = fs.createReadStream(bzipArchivePath)
fileStream.on 'error', callback
bzipStream = fileStream.pipe(bzip())
bzipStream.on 'error', callback

chunks = []
bzipStream.on 'data', (chunk) ->
chunks.push(chunk)
bzipStream.on 'end', ->
callback(null, Buffer.concat(chunks))