From 1f735a34406c1856fd2f6f9a522a06b429c4f799 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 30 Oct 2015 12:33:40 +0100 Subject: [PATCH] : Support xz-compressed NARs --- configure.ac | 4 ++++ release.nix | 2 +- src/libstore/builtins.cc | 3 +++ src/libutil/compression.cc | 46 ++++++++++++++++++++++++++++++++++++++ src/libutil/compression.hh | 9 ++++++++ src/libutil/local.mk | 4 +++- tests/fetchurl.sh | 14 ++++++++++++ 7 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 src/libutil/compression.cc create mode 100644 src/libutil/compression.hh diff --git a/configure.ac b/configure.ac index a30e0c3b..68695456 100644 --- a/configure.ac +++ b/configure.ac @@ -218,6 +218,10 @@ PKG_CHECK_MODULES([SODIUM], [libsodium], AC_SUBST(HAVE_SODIUM, [$have_sodium]) +# Look for liblzma, a required dependency. +PKG_CHECK_MODULES([LIBLZMA], [liblzma], [CXXFLAGS="$LIBLZMA_CFLAGS $CXXFLAGS"]) + + # Whether to use the Boehm garbage collector. AC_ARG_ENABLE(gc, AC_HELP_STRING([--enable-gc], [enable garbage collection in the Nix expression evaluator (requires Boehm GC) [default=no]]), diff --git a/release.nix b/release.nix index 4459bf16..d0794d01 100644 --- a/release.nix +++ b/release.nix @@ -83,7 +83,7 @@ let src = tarball; buildInputs = - [ curl perl bzip2 openssl pkgconfig sqlite boehmgc ] + [ curl perl bzip2 xz openssl pkgconfig sqlite boehmgc ] ++ lib.optional stdenv.isLinux libsodium; configureFlags = '' diff --git a/src/libstore/builtins.cc b/src/libstore/builtins.cc index fefad63b..a1c4b48b 100644 --- a/src/libstore/builtins.cc +++ b/src/libstore/builtins.cc @@ -2,6 +2,7 @@ #include "download.hh" #include "store-api.hh" #include "archive.hh" +#include "compression.hh" namespace nix { @@ -28,6 +29,8 @@ void builtinFetchurl(const BasicDerivation & drv) auto unpack = drv.env.find("unpack"); if (unpack != drv.env.end() && unpack->second == "1") { + if (string(data.data, 0, 6) == string("\xfd" "7zXZ\0", 6)) + data.data = decompressXZ(data.data); StringSource source(data.data); restorePath(storePath, source); } else diff --git a/src/libutil/compression.cc b/src/libutil/compression.cc new file mode 100644 index 00000000..446fcb78 --- /dev/null +++ b/src/libutil/compression.cc @@ -0,0 +1,46 @@ +#include "compression.hh" +#include "types.hh" + +#include + +namespace nix { + +std::string decompressXZ(const std::string & in) +{ + lzma_stream strm = LZMA_STREAM_INIT; + + lzma_ret ret = lzma_stream_decoder( + &strm, UINT64_MAX, LZMA_CONCATENATED); + if (ret != LZMA_OK) + throw Error("unable to initialise lzma decoder"); + + lzma_action action = LZMA_RUN; + uint8_t outbuf[BUFSIZ]; + string res; + strm.next_in = (uint8_t *) in.c_str(); + strm.avail_in = in.size(); + strm.next_out = outbuf; + strm.avail_out = sizeof(outbuf); + + while (true) { + + if (strm.avail_in == 0) + action = LZMA_FINISH; + + lzma_ret ret = lzma_code(&strm, action); + + if (strm.avail_out == 0 || ret == LZMA_STREAM_END) { + res.append((char *) outbuf, sizeof(outbuf) - strm.avail_out); + strm.next_out = outbuf; + strm.avail_out = sizeof(outbuf); + } + + if (ret == LZMA_STREAM_END) + return res; + + if (ret != LZMA_OK) + throw Error("error while decompressing xz file"); + } +} + +} diff --git a/src/libutil/compression.hh b/src/libutil/compression.hh new file mode 100644 index 00000000..962ce5ac --- /dev/null +++ b/src/libutil/compression.hh @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace nix { + +std::string decompressXZ(const std::string & in); + +} diff --git a/src/libutil/local.mk b/src/libutil/local.mk index 8af2e78d..4a97b662 100644 --- a/src/libutil/local.mk +++ b/src/libutil/local.mk @@ -6,8 +6,10 @@ libutil_DIR := $(d) libutil_SOURCES := $(wildcard $(d)/*.cc) +libutil_LDFLAGS = -llzma + ifeq ($(HAVE_OPENSSL), 1) - libutil_LDFLAGS = $(OPENSSL_LIBS) + libutil_LDFLAGS += $(OPENSSL_LIBS) else libutil_SOURCES += $(d)/md5.c $(d)/sha1.c $(d)/sha256.c endif diff --git a/tests/fetchurl.sh b/tests/fetchurl.sh index 495d42a2..b6fa3a27 100644 --- a/tests/fetchurl.sh +++ b/tests/fetchurl.sh @@ -2,12 +2,14 @@ source common.sh clearStore +# Test fetching a flat file. hash=$(nix-hash --flat --type sha256 ./fetchurl.sh) outPath=$(nix-build '' --argstr url file://$(pwd)/fetchurl.sh --argstr sha256 $hash --no-out-link) cmp $outPath fetchurl.sh +# Test unpacking a NAR. rm -rf $TEST_ROOT/archive mkdir -p $TEST_ROOT/archive cp ./fetchurl.sh $TEST_ROOT/archive @@ -25,3 +27,15 @@ echo $outPath | grep -q 'xyzzy' test -x $outPath/fetchurl.sh test -L $outPath/symlink + +nix-store --delete $outPath + +# Test unpacking a compressed NAR. +narxz=$TEST_ROOT/archive.nar.xz +rm -f $narxz +xz --keep $nar +outPath=$(nix-build '' --argstr url file://$narxz --argstr sha256 $hash \ + --arg unpack true --argstr name xyzzy --no-out-link) + +test -x $outPath/fetchurl.sh +test -L $outPath/symlink