Files
lix/perl/lib/Nix/Store.xs
T
Tom Hubrecht b482ebbbc8 treewide: Rename Base to HashFormat
Co-authored-by: Yueh-Shun Li <shamrocklee@posteo.net>

`base` is ambiguous, since it's not about the digital bases, but about
the format of hashes. Base16, Base32 and Base64 are all character maps
for binary encoding.

Documentation of the format is also added.

Cherry-pick of:
https://github.com/NixOS/nix/pull/7708/commits/838c70f62116328ce01cb41a01886e4f1b9a727f
https://github.com/NixOS/nix/pull/7708/commits/5043e6cf4ea537dfe599470797c5b310ab0e94b9

Change-Id: Ief5425f3c2056a4cca75838091e4dfa5cca88872
2026-01-06 11:22:06 +00:00

374 lines
11 KiB
Plaintext

#include "lix/config.h"
// perl defines _ as a function-like macro for some reason.
// boost outcome uses _ as a name an internal storage type.
// can i make it any more obvious?
#include "lix/libutil/result.hh"
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#undef NDEBUG
/* Prevent a clash between some Perl and libstdc++ macros. */
#undef do_open
#undef do_close
#include "lix/libstore/derivations.hh"
#include "lix/libstore/globals.hh"
#include "lix/libstore/store-api.hh"
#include "lix/libstore/crypto.hh"
#include "lix/libutil/async.hh"
#include "lix/libutil/json.hh"
using namespace nix;
static AsyncIoRoot & aio()
{
static thread_local AsyncIoRoot root;
return root;
}
static ref<Store> store()
{
auto & aioRoot = aio();
// SAFETY: this store will be destructed after its associated aio
// root because the root is initialized first (due to call above)
static thread_local std::optional<ref<Store>> _store;
if (!_store) {
try {
initLibStore();
_store = aioRoot.blockOn(openStore());
} catch (Error & e) {
croak("%s", e.what());
}
}
return *_store;
}
MODULE = Nix::Store PACKAGE = Nix::Store
PROTOTYPES: ENABLE
#undef dNOOP // Hack to work around "error: declaration of 'Perl___notused' has a different language linkage" error message on clang.
#define dNOOP
void init()
CODE:
store();
void setVerbosity(int level)
CODE:
verbosity = (Verbosity) level;
int isValidPath(char * path)
CODE:
try {
RETVAL = aio().blockOn(store()->isValidPath(store()->parseStorePath(path)));
} catch (Error & e) {
croak("%s", e.what());
}
OUTPUT:
RETVAL
SV * queryReferences(char * path)
PPCODE:
try {
for (auto & i : aio().blockOn(store()->queryPathInfo(store()->parseStorePath(path)))->references)
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(i).c_str(), 0)));
} catch (Error & e) {
croak("%s", e.what());
}
SV * queryPathHash(char * path)
PPCODE:
try {
auto s = aio().blockOn(store()->queryPathInfo(store()->parseStorePath(path)))->narHash.to_string(HashFormat::Base32, true);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) {
croak("%s", e.what());
}
SV * queryDeriver(char * path)
PPCODE:
try {
auto info = aio().blockOn(store()->queryPathInfo(store()->parseStorePath(path)));
if (!info->deriver) XSRETURN_UNDEF;
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(*info->deriver).c_str(), 0)));
} catch (Error & e) {
croak("%s", e.what());
}
SV * queryPathInfo(char * path, int base32)
PPCODE:
try {
auto info = aio().blockOn(store()->queryPathInfo(store()->parseStorePath(path)));
if (!info->deriver)
XPUSHs(&PL_sv_undef);
else
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(*info->deriver).c_str(), 0)));
auto s = info->narHash.to_string(base32 ? HashFormat::Base32 : HashFormat::Base16, true);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
mXPUSHi(info->registrationTime);
mXPUSHi(info->narSize);
AV * refs = newAV();
for (auto & i : info->references)
av_push(refs, newSVpv(store()->printStorePath(i).c_str(), 0));
XPUSHs(sv_2mortal(newRV((SV *) refs)));
AV * sigs = newAV();
for (auto & i : info->sigs)
av_push(sigs, newSVpv(i.c_str(), 0));
XPUSHs(sv_2mortal(newRV((SV *) sigs)));
} catch (Error & e) {
croak("%s", e.what());
}
SV * queryPathFromHashPart(char * hashPart)
PPCODE:
try {
auto path = aio().blockOn(store()->queryPathFromHashPart(hashPart));
XPUSHs(sv_2mortal(newSVpv(path ? store()->printStorePath(*path).c_str() : "", 0)));
} catch (Error & e) {
croak("%s", e.what());
}
SV * computeFSClosure(int flipDirection, int includeOutputs, ...)
PPCODE:
try {
StorePathSet paths;
for (int n = 2; n < items; ++n)
aio().blockOn(store()->computeFSClosure(
store()->parseStorePath(SvPV_nolen(ST(n))), paths, flipDirection, includeOutputs
));
for (auto & i : paths)
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(i).c_str(), 0)));
} catch (Error & e) {
croak("%s", e.what());
}
SV * topoSortPaths(...)
PPCODE:
try {
StorePathSet paths;
for (int n = 0; n < items; ++n) paths.insert(store()->parseStorePath(SvPV_nolen(ST(n))));
auto sorted = aio().blockOn(store()->topoSortPaths(paths));
for (auto & i : sorted)
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(i).c_str(), 0)));
} catch (Error & e) {
croak("%s", e.what());
}
SV * followLinksToStorePath(char * path)
CODE:
try {
RETVAL = newSVpv(store()->printStorePath(store()->followLinksToStorePath(path)).c_str(), 0);
} catch (Error & e) {
croak("%s", e.what());
}
OUTPUT:
RETVAL
void exportPaths(int fd, ...)
PPCODE:
try {
StorePathSet paths;
for (int n = 1; n < items; ++n) paths.insert(store()->parseStorePath(SvPV_nolen(ST(n))));
FdSink sink(fd);
aio().blockOn(store()->exportPaths(paths, sink));
} catch (Error & e) {
croak("%s", e.what());
}
void importPaths(int fd, int dontCheckSigs)
PPCODE:
try {
FdSource source(fd);
aio().blockOn(store()->importPaths(source, dontCheckSigs ? NoCheckSigs : CheckSigs));
} catch (Error & e) {
croak("%s", e.what());
}
SV * hashPath(char * algo, int base32, char * path)
PPCODE:
try {
Hash h = hashPath(parseHashType(algo), path).first;
auto s = h.to_string(base32 ? HashFormat::Base32 : HashFormat::Base16, false);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) {
croak("%s", e.what());
}
SV * hashFile(char * algo, int base32, char * path)
PPCODE:
try {
Hash h = hashFile(parseHashType(algo), path);
auto s = h.to_string(base32 ? HashFormat::Base32 : HashFormat::Base16, false);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) {
croak("%s", e.what());
}
SV * hashString(char * algo, int base32, char * s)
PPCODE:
try {
Hash h = hashString(parseHashType(algo), s);
auto s = h.to_string(base32 ? HashFormat::Base32 : HashFormat::Base16, false);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) {
croak("%s", e.what());
}
SV * convertHash(char * algo, char * s, int toBase32)
PPCODE:
try {
auto h = Hash::parseAny(s, parseHashType(algo));
auto s = h.to_string(toBase32 ? HashFormat::Base32 : HashFormat::Base16, false);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) {
croak("%s", e.what());
}
SV * signString(char * secretKey_, char * msg)
PPCODE:
try {
auto sig = SecretKey::parse(secretKey_).signDetached(msg);
XPUSHs(sv_2mortal(newSVpv(sig.c_str(), sig.size())));
} catch (Error & e) {
croak("%s", e.what());
}
int checkSignature(SV * publicKey_, SV * sig_, char * msg)
CODE:
try {
STRLEN publicKeyLen;
char * publicKey = SvPV(publicKey_, publicKeyLen);
auto key = PublicKey::fromRaw("", {publicKey, publicKeyLen});
STRLEN sigLen;
char * sig = SvPV(sig_, sigLen);
RETVAL = key.verifyDetached(msg, {sig, sigLen});
} catch (Error & e) {
croak("%s", e.what());
}
OUTPUT:
RETVAL
SV * addToStore(char * srcPath, int recursive, char * algo)
PPCODE:
try {
auto hash = parseHashType(algo);
auto path = aio().blockOn(recursive
? store()->addToStoreRecursive(std::string(baseNameOf(srcPath)), *prepareDump(srcPath), hash)
: store()->addToStoreFlat(std::string(baseNameOf(srcPath)), srcPath, hash));
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(path).c_str(), 0)));
} catch (Error & e) {
croak("%s", e.what());
}
SV * makeFixedOutputPath(int recursive, char * algo, char * hash, char * name)
PPCODE:
try {
auto h = Hash::parseAny(hash, parseHashType(algo));
auto method = recursive ? FileIngestionMethod::Recursive : FileIngestionMethod::Flat;
auto path = store()->makeFixedOutputPath(name, FixedOutputInfo {
.method = method,
.hash = h,
.references = {},
});
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(path).c_str(), 0)));
} catch (Error & e) {
croak("%s", e.what());
}
SV * derivationFromPath(char * drvPath)
PREINIT:
HV *hash;
CODE:
try {
Derivation drv = aio().blockOn(store()->derivationFromPath(store()->parseStorePath(drvPath)));
hash = newHV();
HV * outputs = newHV();
for (auto & i : drv.outputsAndPaths(*store())) {
hv_store(
outputs, i.first.c_str(), i.first.size(),
newSVpv(store()->printStorePath(i.second.second).c_str(), 0),
0);
}
hv_stores(hash, "outputs", newRV((SV *) outputs));
AV * inputDrvs = newAV();
for (auto & i : drv.inputDrvs)
av_push(inputDrvs, newSVpv(store()->printStorePath(i.first).c_str(), 0)); // !!! ignores i->second
hv_stores(hash, "inputDrvs", newRV((SV *) inputDrvs));
AV * inputSrcs = newAV();
for (auto & i : drv.inputSrcs)
av_push(inputSrcs, newSVpv(store()->printStorePath(i).c_str(), 0));
hv_stores(hash, "inputSrcs", newRV((SV *) inputSrcs));
hv_stores(hash, "platform", newSVpv(drv.platform.c_str(), 0));
hv_stores(hash, "builder", newSVpv(drv.builder.c_str(), 0));
AV * args = newAV();
for (auto & i : drv.args)
av_push(args, newSVpv(i.c_str(), 0));
hv_stores(hash, "args", newRV((SV *) args));
HV * env = newHV();
for (auto & i : drv.env)
hv_store(env, i.first.c_str(), i.first.size(), newSVpv(i.second.c_str(), 0), 0);
hv_stores(hash, "env", newRV((SV *) env));
RETVAL = newRV_noinc((SV *)hash);
} catch (Error & e) {
croak("%s", e.what());
}
OUTPUT:
RETVAL
void addTempRoot(char * storePath)
PPCODE:
try {
aio().blockOn(store()->addTempRoot(store()->parseStorePath(storePath)));
} catch (Error & e) {
croak("%s", e.what());
}
SV * getBinDir()
PPCODE:
XPUSHs(sv_2mortal(newSVpv(settings.nixBinDir.c_str(), 0)));
SV * getStoreDir()
PPCODE:
XPUSHs(sv_2mortal(newSVpv(settings.nixStore.c_str(), 0)));