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)
--- /dev/null
+.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)
-.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
.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
+#define _POSIX_C_SOURCE 200809L
/*
Andersson tree library
} \
} 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 );
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 );
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 ) {
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 );
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
);
return cat;
}
-char *checkfile(char *pkgstr, char *path) {
+char *checkfile(char *pkgstr, char *path, int orgreater) {
struct zpm pkgfile;
char *pkgid = 0;
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;
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;
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;
) {
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) {
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);
}
/* 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);
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);
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);
. tap.sh
-plan 15
+plan 20
PF=test.db
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
# 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
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
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
--- /dev/null
+#!/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
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
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 {