summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2011-10-10 18:12:40 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2011-10-10 18:12:40 +0000
commit73fe6871c479f7670f8c93b0cc9ef7bb1a851777 (patch)
tree41b4e3c7bc772bdd3e1df34fb929faa6e70268d0
parent55481c44d4767ffde561c02b039717916e0536f6 (diff)
downloadguix-73fe6871c479f7670f8c93b0cc9ef7bb1a851777.tar.gz
* 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.

-rw-r--r--Makefile.am2
-rw-r--r--configure.ac1
-rw-r--r--perl/MANIFEST7
-rw-r--r--perl/Makefile.am25
-rw-r--r--perl/lib/Nix/Store.pm23
-rw-r--r--perl/lib/Nix/Store.xs129
6 files changed, 186 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index 0e1d1413ce..b946b1e362 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 3b8617f93d..b0ce642a79 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 0000000000..08897647c9
--- /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 0000000000..548708a338
--- /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 0000000000..af69debeda
--- /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 0000000000..dd5cffdbb7
--- /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 <store-api.hh>
+#include <globals.hh>
+#include <misc.hh>
+#include <util.hh>
+
+
+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());
+        }