Last active
March 7, 2020 22:36
-
-
Save yorickvP/001a79324a921dba70617fd1d346fbca to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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