]> pd.if.org Git - zpackage/commitdiff
support for package dependencies v0.6.2
authorNathan Wagner <nw@hydaspes.if.org>
Fri, 22 Feb 2019 22:26:56 +0000 (22:26 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Fri, 22 Feb 2019 22:26:56 +0000 (22:26 +0000)
12 files changed:
Makefile
doc/zpm-pkgdeps.8 [new file with mode: 0644]
doc/zpm.8
lib/jsw/jsw_atree.c
lib/jsw/jsw_atree.h
schema/main.sql
src/search.c
t/basics.t
zpm-gc
zpm-pkgdeps [new file with mode: 0755]
zpm-update
zpm.h

index 969127610e1ff39b276402801a4c1a841a301516..802360ba8ce644bffc8176952ad2f70b47c84554 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -38,7 +38,8 @@ ZPKGBIN=zpm-addfile zpm-extract zpm-init zpm-vercmp zpm-stat zpm-hash \
 
 SCRIPTS=zpm zpm-install zpm-merge zpm-list zpm-test zpm-log \
        zpm-contents zpm-uninstall zpm-pathmod zpm-rmpackage zpm-newpackage \
-       zpm-pkg zpm-pkgfile zpm-gc zpm-repo zpm-update zpm-confgit
+       zpm-pkg zpm-pkgfile zpm-gc zpm-repo zpm-update zpm-confgit \
+       zpm-pkgdeps
 
 MANPAGES=$(shell ls doc/*.8)
 #MANPAGES=doc/zpm.8 $(addprefix doc/zpm-, list.8 contents.8 hash.8 quote.8 pathmod.8 note.8 vercmp.8 repo.8 gc.8)
diff --git a/doc/zpm-pkgdeps.8 b/doc/zpm-pkgdeps.8
new file mode 100644 (file)
index 0000000..cdda376
--- /dev/null
@@ -0,0 +1,77 @@
+.TH zpm-pkgdeps 8 2019-02-22 "ZPM 0.3"
+.SH NAME
+zpm-pkgdeps \- run pkgdeps
+.SH SYNOPSIS
+               f) pkgfile="$OPTARG" ;;
+               s) setlist="$setlist $OPTARG"; clearlist=1 ;;
+               a) add="$add $OPTARG"; ;;
+               r) remove="$remove $OPTARG" ;;
+               q) quiet=1 ;;
+               c) clearlist=1 ;;
+.B zpm pkgdeps
+[
+.BI \-f " pkgfile"
+]
+[
+.B \-qc
+]
+[
+.BI \-s " dep"
+]
+[
+.BI \-a " dep"
+]
+[
+.BI \-r " dep"
+]
+.RI [ package ...]
+.SH DESCRIPTION
+\fBzpm-pkgdeps\fR
+manipulates and prints the set of package dependencies of a package.
+The non-argument \fIpackage\fR is a full or partial package id,
+and will be looked as if by zpm-findpkg.  A package dependency
+is a full or partial package id, which is taken as a minimum package
+version.  After any updates are made, the (new) set of dependencies
+is printed to stdout on one line.
+.PP
+Actions to set, add, or remove dependencies are done in the order
+of clearing the set, adding dependencies, and then removing dependencies.
+It is not an error if a dependency to remove is not present.
+.PP
+Dependencies are package ids, and thus can't have whitespace or illegal
+characters.  Illegal characters are not checked for, and whitespace
+will be interpreted as separating dependencies.
+.SH OPTIONS
+.TP
+.BI \-f package
+specify the package file to find packages in
+.TP
+.B \-q
+Suppress printing the set of package deps.
+.TP
+.B \-c
+Clear the set of dependencies.
+.TP
+.BI \-s " dep"
+Add a dependency to the set of dependencies to set.  Implies \-c.
+.TP
+.BI \-a " dep"
+Add a dependency to the package.
+.TP
+.BI \-r " dep"
+Remove a dependency from the package.
+.SH EXAMPLES
+.TP
+.B zpm pkgdeps vim
+List dependencies of the vim package.
+.SH EXIT STATUS
+0 on success non zero on failure
+.SH FILES
+/var/lib/zpm/local.db
+.SH ENVIRONMENT
+ZPMDB
+.SH AUTHOR
+Nathan Wagner
+.SH SEE ALSO
+.BR zpm (8)
+.BR zpm-findpkg (8)
index ae923db1750f24bf3cdf27c6e9253c6366d7d622..1ad54f8130a0ccf0311bb5f261453cf6ffc9602c 100644 (file)
--- a/doc/zpm.8
+++ b/doc/zpm.8
@@ -1,4 +1,4 @@
-.TH zpm 8 2019-02-15 "ZPM 0.3"
+.TH zpm 8 2019-02-22 "ZPM 0.3"
 .SH NAME
 zpm \- the ultimate package manager
 .SH SYNOPSIS
@@ -92,6 +92,9 @@ from http://git.tukaani.org/xz.git
 .TP
 SSL root certificates
 taken from http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt
+.TP
+JSW data structures code.
+Adapted from JSW's data structures code at http://www.eternallyconfuzzled.com/
 .PP
 All other code written by Nathan Wagner and also placed in the public domain.
 .SH LICENSE
index 82c24ca81aa1bef809df5b3bfca26d83a29c269b..d73e22afc18898ad80d579f5c61efa0e2ce4075f 100644 (file)
@@ -1,3 +1,4 @@
+#define _POSIX_C_SOURCE 200809L
 /*
   Andersson tree library
 
@@ -66,6 +67,10 @@ struct jsw_atrav {
   }                                                                \
 } while(0)
 
+int jsw_afind_strcmp(const void *a, const void *b) {
+       return strcmp(a, b);
+}
+
 static jsw_anode_t *new_node ( jsw_atree_t *tree, void *data )
 {
   jsw_anode_t *rn = malloc ( sizeof *rn );
@@ -80,6 +85,10 @@ static jsw_anode_t *new_node ( jsw_atree_t *tree, void *data )
   return rn;
 }
 
+jsw_atree_t *jsw_anew_str(void) {
+       return jsw_anew(jsw_afind_strcmp, (dup_f)strdup, (rel_f)free);
+}
+
 jsw_atree_t *jsw_anew ( cmp_f cmp, dup_f dup, rel_f rel )
 {
   jsw_atree_t *rt = malloc ( sizeof *rt );
@@ -108,10 +117,16 @@ jsw_atree_t *jsw_anew ( cmp_f cmp, dup_f dup, rel_f rel )
   return rt;
 }
 
-void jsw_adelete ( jsw_atree_t *tree )
-{
-  jsw_anode_t *it = tree->root;
-  jsw_anode_t *save;
+void jsw_adelete(jsw_atree_t *tree) {
+       jsw_anode_t *it;
+       jsw_anode_t *save;
+
+       if (!tree) {
+               return;
+       }
+
+       it = tree->root;
+
 
   /* Destruction by rotation */
   while ( it != tree->nil ) {
index 7274ba016f7f7e11dbf2e6db990ab6d6ea423e13..6dccf07061a8b56e43d4bc6f5565e2c6f66417c2 100644 (file)
@@ -39,11 +39,13 @@ jsw_atree_t *jsw_anew (
                void *(dup)(void *),
                void (*rel)(void *)
                );
+jsw_atree_t *jsw_anew_str(void);
 void         jsw_adelete ( jsw_atree_t *tree );
 void        *jsw_afind ( jsw_atree_t *tree, void *data );
 int          jsw_ainsert ( jsw_atree_t *tree, void *data );
 int          jsw_aerase ( jsw_atree_t *tree, void *data );
 size_t       jsw_asize ( jsw_atree_t *tree );
+int jsw_afind_strcmp(const void *a, const void *b); 
 
 /* Traversal functions */
 jsw_atrav_t *jsw_atnew ( void );
index b0675509e1a6884e8b2ba6560a91350111bed3fd..85546d9321e0a2e9b484894472a7fe1f1685269f 100644 (file)
@@ -325,13 +325,15 @@ select printf('%s-%s-%s', package, version, release) as pkgid, *
 from scripts
 ;
 
--- package dependencies: table of package, dependency, dep type (package, soname)
+-- package dependencies: table of package, dependency, dep type (package,
+       -- soname)
+-- how to specify min/max/exact
 create table packagedeps (
        package text,
        version text,
        release integer,
-       requires text, -- package, can be partial
-       primary key (package,version,release,package),
+       requires text, -- package, can be partial, minimum
+       primary key (package,version,release,requires),
        foreign key (package,version,release) references packages (package,version,release) on delete cascade on update cascade
 );
 
index fd8d793fce6c1711b273deaa7065989dd3c69162..1943f3b26265012e5ad3d8685dd73be0d02db746 100644 (file)
@@ -62,7 +62,7 @@ char *pathcat(char *dir, char *path) {
        return cat;
 }
 
-char *checkfile(char *pkgstr, char *path) {
+char *checkfile(char *pkgstr, char *path, int orgreater) {
        struct zpm pkgfile;
        char *pkgid = 0;
 
@@ -70,7 +70,11 @@ char *checkfile(char *pkgstr, char *path) {
                return NULL;
        }
        
-       pkgid = zpm_findpkg(&pkgfile, pkgstr, NULL);
+       if (orgreater) {
+               pkgid = zpm_findpkg_range(&pkgfile, pkgstr, 0, 0, 0);
+       } else {
+               pkgid = zpm_findpkg(&pkgfile, pkgstr, NULL);
+       }
        zpm_close(&pkgfile);
 
        return pkgid;
@@ -146,6 +150,9 @@ int find_globs(struct search_ctl *opt) {
        return 1;
 }
 
+/*
+ * find a package and packagefile that supplies a library
+ */
 int find_lib(char *soname, struct search_ctl *opt, struct pkgloc *pkg) {
        char *latest = 0;
        char *installed = 0, *found = 0;
@@ -193,6 +200,69 @@ int find_lib(char *soname, struct search_ctl *opt, struct pkgloc *pkg) {
        return 0;
 }
 
+struct pkgloc *find_atleast_package(char *pkgstr, struct search_ctl *opt, int stopifinstalled) {
+       char *latest = 0;
+       char *installed = 0, *found = 0;
+       char *pkgfile = 0;
+       struct pkgloc *pkg = 0;
+       int rv;
+       unsigned int i;
+
+       if (opt->localdb) {
+               installed = zpm_findpkg_range(opt->zpmdb, pkgstr, 0, "status = 'installed'", 0);
+               if (installed) {
+                       latest = installed;
+                       pkgfile = opt->zpmdb->path;
+                       if (stopifinstalled) {
+                               pkg = malloc(sizeof *pkg);
+                               pkg->id = strdup(latest);
+                               pkg->file = pkgfile;
+                               pkg->installed = 1;
+                               return pkg;
+                       }
+               }
+               if (!opt->onlylocalinstalled) {
+                       found = zpm_findpkg_range(opt->zpmdb, pkgstr, 0, NULL, 0);
+                       if (found) {
+                               rv = zpm_vercmp(found, latest);
+                               if (rv == 1) {
+                                       latest = found;
+                                       pkgfile = opt->zpmdb->path;
+                               }
+                       }
+               }
+       }
+
+       for (i = 0; i < opt->repos.gl_pathc; i++) {
+               if (!opt->matchallpkgfile
+                               && !strstr(opt->repos.gl_pathv[i], pkgstr)
+                               && !strstr(opt->repos.gl_pathv[i], ".repo")
+                               ) {
+                       continue;
+               }
+               found = checkfile(pkgstr, opt->repos.gl_pathv[i], 1);
+               if (found) {
+                       rv = zpm_vercmp(found, latest);
+                       if (rv == 1) {
+                               latest = found;
+                               pkgfile = strdup(opt->repos.gl_pathv[i]);
+                       }
+               }
+       }
+
+       if (latest && pkgfile) {
+               pkg = malloc(sizeof *pkg);
+               pkg->id = strdup(latest);
+               pkg->file = pkgfile;
+               pkg->installed = 0;
+               if (installed) {
+                      pkg->installed = !strcmp(latest, installed);
+               }
+       }
+
+       return pkg;
+}
+
 struct pkgloc *find_package(char *pkgstr, struct search_ctl *opt) {
        char *latest = 0;
        char *installed = 0, *found = 0;
@@ -232,7 +302,7 @@ struct pkgloc *find_package(char *pkgstr, struct search_ctl *opt) {
                                ) {
                        continue;
                }
-               found = checkfile(pkgstr, opt->repos.gl_pathv[i]);
+               found = checkfile(pkgstr, opt->repos.gl_pathv[i], 0);
                if (found) {
                        rv = zpm_vercmp(found, latest);
                        if (rv == 1) {
@@ -272,6 +342,8 @@ with pkglibs as (\
      where PL.pkgid = %Q\
      ";
 
+char *pkgdeps = "select requires from packagedeps_pkgid where pkgid = %Q";
+
 static int afind_strcmp(const void *a, const void *b) {
        return strcmp(a, b);
 }
@@ -283,13 +355,13 @@ void checklibs(struct search_ctl *opts,
 
        /* checked_libs is a list of checked sonames
         * checked is a list of checked packages
-        * needed is list of libs for package
+        * needed is list of libs for package, or list of package deps
         */
        jsw_atree_t *needed = 0, *checked, *checked_libs;
 
-       int libs;
+       int libs, count;
        jsw_atrav_t *i;
-       char *soname;
+       char *soname, *package;
        
        checked = jsw_anew(afind_strcmp, (dup_f)strdup, (rel_f)free);
        checked_libs = jsw_anew(afind_strcmp, (dup_f)strdup, (rel_f)free);
@@ -328,14 +400,45 @@ void checklibs(struct search_ctl *opts,
                        exit(EXIT_FAILURE);
                }
 
-               /* get the libraries needed by this package */
+               /* get the libraries and packages needed by this package */
                if (!zpm_open(&src, pkgfile)) {
                        fprintf(stderr, "can't zpm open %s\n", pkgfile);
                        break;
                }
 
-               if (needed) jsw_adelete(needed);
-               needed = jsw_anew(afind_strcmp, (dup_f)strdup, (rel_f)free);
+               jsw_adelete(needed);
+               needed = jsw_anew_str();
+               count = zpm_packages_needed(&src, pkgid, needed);
+               if (count) {
+                       struct pkgloc *pkg = 0;
+                       i = jsw_atnew();
+
+                       if (pkg) {
+                               free(pkg->file);
+                               free(pkg->id);
+                               free(pkg);
+                       }
+
+                       for (package = jsw_atfirst(i, needed); package; package = jsw_atnext(i)) {
+                               pkg = find_atleast_package(package, opts, 1);
+                               if (!pkg || pkg->installed) {
+                                       continue;
+                               }
+                               /* look for a package at least that version */
+                               /* if package is installed, or already
+                                * handled, skip.  Otherwise, add it
+                                * to the list of installed
+                                */
+                       }
+                       if (pkg) {
+                               free(pkg->file);
+                               free(pkg->id);
+                               free(pkg);
+                       }
+               }
+
+               jsw_adelete(needed);
+               needed = jsw_anew_str();
                libs = zpm_libraries_needed(&src, pkgid, needed);
                zpm_close(&src);
 
@@ -349,7 +452,8 @@ void checklibs(struct search_ctl *opts,
                        int found;
                        struct pkgloc pkginfo;
 
-                       /* if it's in checked_libs, we've already looked at this one */
+                       /* if it's in checked_libs, we've already looked at
+                        * this one */
                        if (jsw_afind(checked_libs, soname)) {
                                if (opts->verbose > 1) {
                                        fprintf(stderr, "already checked %s\n", soname);
index 34aef28047ad178d56ba92ce5a315110db67e3c5..3f926f58bbf4b0bead44acc88c5ab1a1789b3602 100755 (executable)
@@ -2,7 +2,7 @@
 
 . tap.sh
 
-plan 15
+plan 20
 
 PF=test.db
 
@@ -36,6 +36,18 @@ okstreq "$val" 'baz' newpackage set description
 val=$(zpm pkg -f $PF valset url)
 okstreq "$val" 'quux' newpackage set url
 
+# package dependencies
+deps=$(zpm pkgdeps -f $PF valset)
+okstreq "$deps" '' new package empty deps
+deps=$(zpm pkgdeps -f $PF -s foo valset)
+okstreq "$deps" 'foo' pkgdeps set and print
+deps=$(zpm pkgdeps -f $PF -c valset)
+okstreq "$deps" '' pkgdeps clear
+deps=$(zpm pkgdeps -f $PF -q -s foo valset)
+okstreq "$deps" '' pkgdeps set and quiet
+deps=$(zpm pkgdeps -f $PF valset)
+okstreq "$deps" 'foo' pkgdeps set
+
 cd ..
 rm -rf tmp
 finish
diff --git a/zpm-gc b/zpm-gc
index d2d49fc861c0dd95472395f13be317312f2b1410..2559f0d5724dbd4f7ac93bfaca1b5738a67dacd5 100755 (executable)
--- a/zpm-gc
+++ b/zpm-gc
@@ -82,12 +82,12 @@ export ZPMDB
 # remove failed packages
 for pkg in $(zpm list -s failed); do
        zpm rmpackage -m 'gc removed failed' "$pkg"
-       echo removed $pkg
+       echo removed failed $pkg
 done
 
 for pkg in $(zpm list -s dryrun); do
        zpm rmpackage -m 'gc removed dryrun' "$pkg"
-       echo removed $pkg
+       echo removed dryrun $pkg
 done
 
 # remove incomplete packages
@@ -95,7 +95,7 @@ done
 if [ $remove_incomplete_packages -ne 0 ]; then
        for pkg in $(zpm list -F 'hash is null'); do
                zpm rmpackage -m 'gc removed incomplete' $pkg
-       echo removed $pkg
+       echo removed incomplete $pkg
        done
 fi
 
@@ -104,7 +104,7 @@ fi
 if [ $remove_old_packages -ne 0 ]; then
        zpm shell $ZPMDB "select printf('%s-%s-%s',package,version,release) from package_age where age > $retain_old" | while read pkg; do
        zpm rmpackage -m 'gc removed old package' $pkg
-       echo removed $pkg
+       echo removed old package $pkg
 done
 fi
 
diff --git a/zpm-pkgdeps b/zpm-pkgdeps
new file mode 100755 (executable)
index 0000000..b1ea0ce
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+add=
+remove=
+setlist=
+quiet=0
+clearlist=0
+
+while getopts :f:s:a:r:qc opt; do
+       case $opt in
+               f) pkgfile="$OPTARG" ;;
+               s) setlist="$setlist $OPTARG"; clearlist=1 ;;
+               a) add="$add $OPTARG"; ;;
+               r) remove="$remove $OPTARG" ;;
+               q) quiet=1 ;;
+               c) clearlist=1 ;;
+       esac
+done
+shift $(( OPTIND - 1))
+
+: ${pkgfile:=${ZPMDB:-/var/lib/zpm/local.db}}
+
+if [ -z "$pkgfile" ]; then
+       echo "must specify package file"
+       exit 1
+fi
+
+pkgid=$(zpm findpkg -f $pkgfile "$1")
+if [ -z "$pkgid" ]; then
+       echo "cannot find pkgid for $1"
+       exit 1
+fi
+
+eval $(zpm parse -E "$pkgid")
+package=$(zpm quote -q "$name")
+version=$(zpm quote -q "$version")
+pkgselector="package = $package and version = $version and release = $release"
+listdeps="select requires from packagedeps where %s;\n"
+adddep='insert or ignore into packagedeps (package,version,release,requires) values (%s,%s,%d,%s);\n'
+rmdep='delete from packagedeps where %s and requires = %s;\n'
+cleardeps='delete from packagedeps where %s;\n'
+
+{
+       printf ".bail on\n";
+       printf "begin;\n";
+if [ $clearlist -eq 1 ]; then
+       printf "$cleardeps" "$pkgselector"
+fi
+if [ -n "$setlist" ]; then
+       for dep in $setlist; do
+               qdep=$(zpm quote -q "$dep")
+               printf "$adddep" "$package" "$version" "$release" "$qdep"
+       done
+fi
+if [ -n "$add" ]; then
+       for dep in $add; do
+               qdep=$(zpm quote -q "$dep")
+               printf "$adddep" "$package" "$version" "$release" "$qdep"
+       done
+fi
+if [ -n "$remove" ]; then
+       for dep in $remove; do
+               qdep=$(zpm quote -q "$dep")
+               printf "$rmdep" "$pkgselector" "$qdep"
+       done
+fi
+if [ $quiet -eq 0 ]; then
+       printf "$listdeps" "$pkgselector"
+fi
+       printf "commit;\n";
+} | zpm shell $pkgfile
index 5ee5008c55430d80d9cdc7c28f04b947d7f5e5ff..e1accc87393faf4acf73923aa0e8d2b9399c6c6f 100755 (executable)
@@ -202,6 +202,8 @@ fi
 
 if [ $ignorelibdeps -eq 1 ]; then
        merge=$(zpm search -iIO $search)
+       # TODO search for libs anyway and put a note for non-installed
+       # library deps
 else
        merge=$(zpm search -iIO -l $search)
 fi
diff --git a/zpm.h b/zpm.h
index 157eb37b5625c64ae6828c19a142e687a29e389c..5eddd56e1646716a839e7d1596ddb49aefaa2029 100644 (file)
--- a/zpm.h
+++ b/zpm.h
@@ -92,6 +92,7 @@ char *zpm_findpkg_range(struct zpm *zpm, char *minpkg, char *maxpkg, char *where
 int zpm_findhash(struct zpm *zpm, char *find, char *dest);
 char *zpm_findlib(struct zpm *zpm, char *soname, char *where);
 int zpm_libraries_needed(struct zpm *zpm, char *pkgid, jsw_atree_t *list); 
+int zpm_packages_needed(struct zpm *zpm, char *pkgid, jsw_atree_t *list);
 int zpm_quote(char *value, char *dest, size_t n);
 
 struct zpm_file {