isaacs / node-tar

tar for node
ISC License
837 stars 183 forks source link

Does not support XZ compressed data #393

Closed paulober closed 6 months ago

paulober commented 1 year ago
TAR_BAD_ARCHIVE: Unrecognized archive format
isaacs commented 1 year ago

What is xz?

paulober commented 1 year ago

A lossless data compression file format based on the LZMA algorithm most tar tools support. These archives often end with ".tar.xz" and can be created with the -J flag. For example ARM is distributing all of their embedded toolchain archives as ".tar.xz". Here the example: https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads

paulober commented 1 year ago

This is the best project I found for tar archives for nodejs. And I was not able to find a working alternative as searching for .xz archives and nodejs always result in people asking how they can install node.tar.xz on linux :) so I created this issue as I have no Idea on how to implement native javascript support for this algorithm but I may learn how to do it.

isaacs commented 1 year ago

This is the best project I found for tar archives for nodejs.

Thanks 🥰

Node-tar supports gzip and brotli because those are built into Node.

If XZ support is added to node, or if there's a reasonably fast and reliable/well tested JavaScript implementation, then I'd be happy to add support for it in node-tar, and it would be easy to do. But I'd rather not add binary dependencies to this module, which means not relying on xz-utils like tar(1) does.

If you have a way to turn an xz file into an uncompressed stream, you could also do it this way:

import { XZDecompressSomehow } from 'some-xz-module' // <-- idk what this actually is
import tar from 'tar'
import { createReadStream } from 'node:fs'

const compressed = createReadStream('some-file.tar.xz')
const decompressedStream = compressed.pipe(new XZDecompressSomehow())

// tar.x returns a minipass writable stream if no file arg is provided
decompressedStream.pipe(tar.x({ cwd: 'target-folder' }))
  .promise()
  .then(() => console.log('done extracting!'))

// or stream it synchronously if you are in a hurry and don't have anything else to do
decompressedStream.pipe(tar.x({ sync: true, cwd: 'target-folder' }))
decompressedStream.on('end', () => console.log('done extracting!'))
isaacs commented 1 year ago

Creating a compressed stream would be pretty much the same, just in reverse:

tar.c({ ...options, but not 'file' })
  .pipe(new XZCompressSomehow())
  .pipe(createWriteStream('some-file.tar.xz'))