Skip to content

Instantly share code, notes, and snippets.

@yorickvP
Last active March 7, 2020 22:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yorickvP/001a79324a921dba70617fd1d346fbca to your computer and use it in GitHub Desktop.
Save yorickvP/001a79324a921dba70617fd1d346fbca to your computer and use it in GitHub Desktop.
#define HAVE_BOEHMGC 1
#include "miniz.h"
#include <nix/eval.hh>
#include <nix/eval-inline.hh>
#include <iostream>
using namespace nix;
class ZipFileValue : public ExternalValueBase
{
mz_zip_archive zipfile;
Path path;
protected:
/* Print out the value */
virtual std::ostream & print(std::ostream & str) const {
str << "zip file at " << path;
return str;
};
public:
ZipFileValue(Path & path, const Pos & pos) : path(path) {
//std::cerr << "opening zip file " << path << std::endl;
mz_zip_zero_struct(&zipfile);
if (mz_zip_reader_init_file(&zipfile, path.c_str(), 0) == 0) {
throw EvalError(format("unable to read zip file '%1%', at %2%")
% path % pos);
}
}
/* Return a simple string describing the type */
virtual string showType() const {
return "zip file";
};
/* Return a string to be used in builtins.typeOf */
virtual string typeOf() const {
return "zipfile";
};
virtual ~ZipFileValue()
{
// todo: have never seen this called, need finalizer
std::cerr << "destroying zip file" << std::endl;
mz_zip_reader_end(&zipfile);
};
void readFile(EvalState & state, const Pos & pos, std::string & filename, Value & v) {
mz_uint32 file_index;
if (!mz_zip_reader_locate_file_v2(&zipfile, filename.c_str(), NULL, 0, &file_index))
throw EvalError(format("unable to locate file '%2%/%1%' at %3%")
% filename % path % pos);
mz_zip_archive_file_stat file_stat;
if (!mz_zip_reader_file_stat(&zipfile, file_index, &file_stat))
return; // TODO: throw
std::string out_buffer(file_stat.m_uncomp_size+1, 0);
if (!mz_zip_reader_extract_to_mem(&zipfile, file_index, out_buffer.data(), file_stat.m_uncomp_size, 0)) {
throw EvalError(format("unable to extract file '%2%/%1%' at %3%")
% filename % path % pos);
}
mkString(v, out_buffer);
}
void importFile(EvalState & state, const Pos & pos, std::string & filename, Value & v) {
Path canonical = path + "/" + filename;
// todo: parse cache
EvalState::FileEvalCache::iterator i;
if ((i = state.fileEvalCache.find(canonical)) != state.fileEvalCache.end()) {
v = i->second;
return;
}
mz_uint32 file_index;
if (!mz_zip_reader_locate_file_v2(&zipfile, filename.c_str(), NULL, 0, &file_index))
throw EvalError(format("unable to locate file '%1%', in zip file %2%, at %3%")
% filename % path % pos);
printTalkative("evaluating zipped file '%1%'", filename);
mz_zip_archive_file_stat file_stat;
if (!mz_zip_reader_file_stat(&zipfile, file_index, &file_stat))
return; // TODO: throw
std::string out_buffer(file_stat.m_uncomp_size+1, 0);
if (!mz_zip_reader_extract_to_mem(&zipfile, file_index, out_buffer.data(), file_stat.m_uncomp_size, 0)) {
throw EvalError(format("unable to extract file '%1%', in zip file %2%, at %3%")
% filename % path % pos);
}
// todo: relative paths
Expr * e = state.parseExprFromString(out_buffer, canonical);
try {
state.eval(e, v);
} catch (Error & e) {
e.addPrefix(format("while evaluating the zipped file '%1%' from '%2%\n:") % filename % path);
throw;
}
state.fileEvalCache[canonical] = v;
}
};
static void prim_openzip(EvalState & state, const Pos & pos, Value * * args, Value & v) {
PathSet context;
Path path = state.coerceToPath(pos, *args[0], context);
try {
state.realiseContext(context);
} catch (InvalidPathError & e) {
throw EvalError(format("cannot import '%1%', since path '%2%' is not valid, at %3%")
% path % e.path % pos);
}
path = state.checkSourcePath(path);
v.type = tExternal;
// todo: boehm finalizer
v.external = new ZipFileValue(path, pos);
return;
}
template<class C> C* coerceExternal(EvalState & state, const Pos & pos, Value & v, const char* name) {
state.forceValue(v, pos);
if (v.type != tExternal || dynamic_cast<C*>(v.external) == nullptr) {
if (pos)
// TODO: better error
throwTypeError("value is %1% while an external value was expected, at %2%", v, pos);
}
return dynamic_cast<C*>(v.external);
}
static void prim_readfromzip(EvalState & state, const Pos & pos, Value * * args, Value & v) {
ZipFileValue* zipfile = coerceExternal<ZipFileValue>(state, pos, *args[0], "zipfile");
string filename = state.forceStringNoCtx(*args[1], pos);
zipfile->readFile(state, pos, filename, v);
}
static void prim_importfromzip(EvalState & state, const Pos & pos, Value * * args, Value & v) {
ZipFileValue* zipfile = coerceExternal<ZipFileValue>(state, pos, *args[0], "zipfile");
string filename = state.forceStringNoCtx(*args[1], pos);
zipfile->importFile(state, pos, filename, v);
}
//extern "C" typedef void (*ValueInitializer)(EvalState & state, Value & v);
extern "C" void importme(EvalState & state, Value & v) {
state.mkAttrs(v, 3);
Symbol oz = state.symbols.create("openzip");
Symbol rF = state.symbols.create("readFile");
Symbol iF = state.symbols.create("import");
Value & openzip = *state.allocAttr(v, oz);
Value & readFile = *state.allocAttr(v, rF);
Value & importFile = *state.allocAttr(v, iF);
v.attrs->sort();
openzip.type = tPrimOp;
openzip.primOp = new PrimOp(prim_openzip, 1, oz);
readFile.type = tPrimOp;
readFile.primOp = new PrimOp(prim_readfromzip, 2, rF);
importFile.type = tPrimOp;
importFile.primOp = new PrimOp(prim_importfromzip, 2, iF);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment