From 73fe6871c479f7670f8c93b0cc9ef7bb1a851777 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 10 Oct 2011 18:12:40 +0000 Subject: [PATCH] * Include the Nix Perl bindings in Nix itself. This will allow the bindings to be used in Nix's own Perl scripts. The only downside is that Perl XS and Automake/libtool don't really like each other, so building is a bit tricky. --- Makefile.am | 2 +- configure.ac | 1 + perl/MANIFEST | 7 +++ perl/Makefile.am | 25 ++++++++ perl/lib/Nix/Store.pm | 23 ++++++++ perl/lib/Nix/Store.xs | 129 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 perl/MANIFEST create mode 100644 perl/Makefile.am create mode 100644 perl/lib/Nix/Store.pm create mode 100644 perl/lib/Nix/Store.xs diff --git a/Makefile.am b/Makefile.am index 0e1d1413c..b946b1e36 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = externals src scripts corepkgs doc misc tests +SUBDIRS = externals src perl scripts corepkgs doc misc tests EXTRA_DIST = substitute.mk nix.spec nix.spec.in bootstrap.sh \ nix.conf.example NEWS version diff --git a/configure.ac b/configure.ac index 3b8617f93..b0ce642a7 100644 --- a/configure.ac +++ b/configure.ac @@ -341,6 +341,7 @@ AC_CONFIG_FILES([Makefile src/nix-setuid-helper/Makefile src/nix-log2xml/Makefile src/bsdiff-4.3/Makefile + perl/Makefile scripts/Makefile corepkgs/Makefile corepkgs/nar/Makefile diff --git a/perl/MANIFEST b/perl/MANIFEST new file mode 100644 index 000000000..08897647c --- /dev/null +++ b/perl/MANIFEST @@ -0,0 +1,7 @@ +Changes +Makefile.PL +MANIFEST +Nix.xs +README +t/Nix.t +lib/Nix.pm diff --git a/perl/Makefile.am b/perl/Makefile.am new file mode 100644 index 000000000..548708a33 --- /dev/null +++ b/perl/Makefile.am @@ -0,0 +1,25 @@ +perlversion := $(shell perl -e 'use Config; print $$Config{version};') +perlarchname := $(shell perl -e 'use Config; print $$Config{archname};') +perllibdir = $(libdir)/perl5/site_perl/$(perlversion)/$(perlarchname) + +install-exec-local: lib/Nix/*.pm + $(INSTALL) -d $(DESTDIR)$(perllibdir)/Nix + $(INSTALL_DATA) lib/Nix/*.pm $(DESTDIR)$(perllibdir)/Nix + $(INSTALL) -d $(DESTDIR)$(perllibdir)/auto/Nix/Store + ln -sfn $(pkglibdir)/libNixStore.so $(DESTDIR)$(perllibdir)/auto/Nix/Store/Store.so + +# Awful hackery to get libtool to build Perl XS bindings. +pkglib_LTLIBRARIES = libNixStore.la + +libNixStore_la_SOURCES = lib/Nix/Store.cc + +libNixStore_la_LIBADD = $(top_srcdir)/src/libstore/libstore.la + +AM_CXXFLAGS = \ + -I$(top_srcdir)/src -I$(top_srcdir)/src/libutil -I$(top_srcdir)/src/libstore \ + -I$(shell perl -e 'use Config; print $$Config{archlibexp};')/CORE + +lib/Nix/Store.cc: lib/Nix/Store.xs + xsubpp $^ -output $@ + +EXTRA_DIST = lib/Nix/*.pm lib/Nix/Store.xs diff --git a/perl/lib/Nix/Store.pm b/perl/lib/Nix/Store.pm new file mode 100644 index 000000000..af69debed --- /dev/null +++ b/perl/lib/Nix/Store.pm @@ -0,0 +1,23 @@ +package Nix::Store; + +use 5.010001; +use strict; +use warnings; + +require Exporter; + +our @ISA = qw(Exporter); + +our %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); + +our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); + +our @EXPORT = qw( ); + +our $VERSION = '0.15'; + +require XSLoader; +XSLoader::load('Nix::Store', $VERSION); + +1; +__END__ diff --git a/perl/lib/Nix/Store.xs b/perl/lib/Nix/Store.xs new file mode 100644 index 000000000..dd5cffdbb --- /dev/null +++ b/perl/lib/Nix/Store.xs @@ -0,0 +1,129 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +/* Prevent a clash between some Perl and libstdc++ macros. */ +#undef do_open +#undef do_close + +#include +#include +#include +#include + + +using namespace nix; + + +void doInit() +{ + if (!store) { + nixStore = canonPath(getEnv("NIX_STORE_DIR", getEnv("NIX_STORE", "/nix/store"))); + nixStateDir = canonPath(getEnv("NIX_STATE_DIR", "/nix/var/nix")); + nixDBPath = getEnv("NIX_DB_DIR", nixStateDir + "/db"); + try { + store = openStore(); + } catch (Error & e) { + croak(e.what()); + } + } +} + + +MODULE = Nix::Store PACKAGE = Nix::Store +PROTOTYPES: ENABLE + + +void init() + CODE: + doInit(); + + +int isValidPath(path) + char * path + CODE: + try { + doInit(); + RETVAL = store->isValidPath(path); + } catch (Error & e) { + croak(e.what()); + } + OUTPUT: + RETVAL + + +SV * queryReferences(path) + char * path + PPCODE: + try { + doInit(); + PathSet paths; + store->queryReferences(path, paths); + for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) + XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0))); + } catch (Error & e) { + croak(e.what()); + } + + +SV * queryPathHash(path) + char * path + PPCODE: + try { + doInit(); + Hash hash = store->queryPathHash(path); + string s = "sha256:" + printHash(hash); + XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0))); + } catch (Error & e) { + croak(e.what()); + } + + +SV * queryDeriver(path) + char * path + PPCODE: + try { + doInit(); + Path deriver = store->queryDeriver(path); + if (deriver == "") XSRETURN_UNDEF; + XPUSHs(sv_2mortal(newSVpv(deriver.c_str(), 0))); + } catch (Error & e) { + croak(e.what()); + } + + +SV * queryPathInfo(path) + char * path + PPCODE: + try { + doInit(); + ValidPathInfo info = store->queryPathInfo(path); + if (info.deriver == "") + XPUSHs(&PL_sv_undef); + else + XPUSHs(sv_2mortal(newSVpv(info.deriver.c_str(), 0))); + string s = "sha256:" + printHash(info.hash); + XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0))); + mXPUSHi(info.registrationTime); + mXPUSHi(info.narSize); + AV * arr = newAV(); + for (PathSet::iterator i = info.references.begin(); i != info.references.end(); ++i) + av_push(arr, newSVpv(i->c_str(), 0)); + XPUSHs(sv_2mortal(newRV((SV *) arr))); + } catch (Error & e) { + croak(e.what()); + } + + +SV * computeFSClosure(int flipDirection, int includeOutputs, ...) + PPCODE: + try { + doInit(); + PathSet paths; + for (int n = 2; n < items; ++n) + computeFSClosure(*store, SvPV_nolen(ST(n)), paths, flipDirection, includeOutputs); + for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) + XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0))); + } catch (Error & e) { + croak(e.what()); + }