diff --git a/bin/xbps-rindex/Makefile b/bin/xbps-rindex/Makefile index 6dc200fb4..bdacd6724 100644 --- a/bin/xbps-rindex/Makefile +++ b/bin/xbps-rindex/Makefile @@ -2,7 +2,7 @@ TOPDIR = ../.. -include $(TOPDIR)/config.mk BIN = xbps-rindex -OBJS = main.o index-add.o index-clean.o remove-obsoletes.o repoflush.o sign.o +OBJS = main.o index-add.o index-clean.o index-remove.o remove-obsoletes.o repoflush.o sign.o include $(TOPDIR)/mk/prog.mk diff --git a/bin/xbps-rindex/defs.h b/bin/xbps-rindex/defs.h index 1545ed235..d1deeb484 100644 --- a/bin/xbps-rindex/defs.h +++ b/bin/xbps-rindex/defs.h @@ -75,6 +75,9 @@ int index_clean(struct xbps_handle *, const char *, bool, const char *); /* From remove-obsoletes.c */ int remove_obsoletes(struct xbps_handle *, const char *); +/* From index-remove.c */ +int index_remove(struct xbps_handle *, int, int, char **, const char *); + /* From sign.c */ int sign_repo(struct xbps_handle *, const char *, const char *, const char *, const char *); diff --git a/bin/xbps-rindex/index-remove.c b/bin/xbps-rindex/index-remove.c new file mode 100644 index 000000000..4657dc4d0 --- /dev/null +++ b/bin/xbps-rindex/index-remove.c @@ -0,0 +1,157 @@ +/*- + * Copyright (c) 2012-2015 Juan Romero Pardines. + * Copyright (c) 2019 Piotr Wójcik + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "defs.h" + +static xbps_dictionary_t idx; + +int +index_remove(struct xbps_handle *xhp, int args, int argmax, char **argv, const char *compression) +{ + struct xbps_repo *repo = NULL; + char *tmprepodir = NULL; + const char *repodir = NULL; + char *rlockfname = NULL; + int rv = 0, rlockfd = -1; + + assert(argv); + + if ((tmprepodir = strdup(argv[args])) == NULL) + return ENOMEM; + repodir = dirname(tmprepodir); + if (!xbps_repo_lock(xhp, repodir, &rlockfd, &rlockfname)) { + rv = errno; + fprintf(stderr, "%s: cannot lock repository: %s\n", + _XBPS_RINDEX, strerror(rv)); + goto earlyout; + } + repo = xbps_repo_public_open(xhp, repodir); + if (repo == NULL) { + rv = errno; + fprintf(stderr, "%s: cannot read repository %s data: %s\n", + _XBPS_RINDEX, repodir, strerror(errno)); + goto earlyout; + } + if (repo->idx == NULL) { + fprintf(stderr, "%s: incomplete repository data file!\n", _XBPS_RINDEX); + rv = EINVAL; + goto earlyout; + } + idx = xbps_dictionary_copy_mutable(repo->idx); + + for (int i = args; i < argmax; i++) { + xbps_dictionary_t curpkgd = NULL; + const char *pkg = argv[i], *opkgver = NULL; + char *pkgver = NULL, *arch = NULL; + char pkgname[XBPS_NAME_SIZE]; + + /* + * Take package properties from passed path. + */ + assert(pkg); + pkgver = xbps_binpkg_pkgver(pkg); + if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) { + fprintf(stderr, "%s: argument %s doesn't look like path to binary package\n", _XBPS_RINDEX, pkg); + free(pkgver); + goto out; + } + arch = xbps_binpkg_arch(pkg); + if (!xbps_pkg_arch_match(xhp, arch, NULL)) { + fprintf(stderr, "%s: ignoring %s, unmatched arch (%s)\n", _XBPS_RINDEX, pkgver, arch); + goto again; + } + + /* + * Check if this package exists already in the index + */ + curpkgd = xbps_dictionary_get(idx, pkgname); + if (!curpkgd) { + if (errno == ENOENT) { + xbps_dbg_printf(xhp, "Package %s isn't indexed in %s, skipping.\n", + pkgname, repodir); + goto again; + } + rv = errno; + fprintf(stderr, "%s: cannot read metadata of %s from repodata\n", _XBPS_RINDEX, pkgname); + free(arch); + free(pkgver); + goto out; + } + + + /* + * Unindex. + */ + xbps_dictionary_get_cstring_nocopy(curpkgd, "pkgver", &opkgver); + if (!opkgver) + { + fprintf(stderr, "%s: cannot read version of %s from repodata\n", _XBPS_RINDEX, pkgname); + } + printf("index: unindexing %s\n", opkgver); + xbps_dictionary_remove(idx, pkgname); + +again: + free(arch); + free(pkgver); + } + + /* + * Generate repository data files. + */ + if (!xbps_dictionary_equals(idx, repo->idx)) { + if (!repodata_flush(xhp, repodir, "repodata", idx, repo->idxmeta, compression)) { + rv = errno; + fprintf(stderr, "%s: failed to write repodata: %s\n", + _XBPS_RINDEX, strerror(errno)); + goto out; + } + } + printf("index: %u packages in index.\n", xbps_dictionary_count(idx)); + + +out: + xbps_object_release(idx); + +earlyout: + if (repo) + xbps_repo_close(repo); + xbps_repo_unlock(rlockfd, rlockfname); + free(tmprepodir); + + return rv; +} diff --git a/bin/xbps-rindex/main.c b/bin/xbps-rindex/main.c index 296c84523..1b04ec89f 100644 --- a/bin/xbps-rindex/main.c +++ b/bin/xbps-rindex/main.c @@ -49,6 +49,7 @@ usage(bool fail) "MODE\n" " -a --add ... Add package(s) to repository index\n" " -c --clean Clean repository index\n" + " -R --remove ... Removes package(s) from repository\n" " -r --remove-obsoletes Removes obsolete packages from repository\n" " -s --sign Initialize repository metadata signature\n" " -S --sign-pkg archive.xbps ... Sign binary package archive\n\n"); @@ -58,13 +59,14 @@ usage(bool fail) int main(int argc, char **argv) { - const char *shortopts = "acdfhrsCSVv"; + const char *shortopts = "acdfhRrsCSVv"; struct option longopts[] = { { "add", no_argument, NULL, 'a' }, { "clean", no_argument, NULL, 'c' }, { "debug", no_argument, NULL, 'd' }, { "force", no_argument, NULL, 'f' }, { "help", no_argument, NULL, 'h' }, + { "remove", no_argument, NULL, 'R' }, { "remove-obsoletes", no_argument, NULL, 'r' }, { "version", no_argument, NULL, 'V' }, { "verbose", no_argument, NULL, 'v' }, @@ -80,11 +82,11 @@ main(int argc, char **argv) const char *compression = NULL; const char *privkey = NULL, *signedby = NULL; int rv, c, flags = 0, modes_count = 0; - bool add_mode, clean_mode, rm_mode, sign_mode, sign_pkg_mode, force, - hashcheck; + bool add_mode, clean_mode, obsoletes_mode, remove_mode, sign_mode, sign_pkg_mode, + force, hashcheck; - add_mode = clean_mode = rm_mode = sign_mode = sign_pkg_mode = force = - hashcheck = false; + add_mode = clean_mode = obsoletes_mode = remove_mode = sign_mode = sign_pkg_mode = + force = hashcheck = false; while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch (c) { @@ -114,8 +116,12 @@ main(int argc, char **argv) case 'h': usage(false); /* NOTREACHED */ + case 'R': + remove_mode = true; + modes_count++; + break; case 'r': - rm_mode = true; + obsoletes_mode = true; modes_count++; break; case 's': @@ -141,7 +147,7 @@ main(int argc, char **argv) usage(true); } else if (modes_count > 1) { fprintf(stderr, "Only one mode can be specified: add, clean, " - "remove-obsoletes, sign or sign-pkg.\n"); + "remove, remove-obsoletes, sign or sign-pkg.\n"); exit(EXIT_FAILURE); } @@ -158,8 +164,10 @@ main(int argc, char **argv) rv = index_add(&xh, optind, argc, argv, force, compression); else if (clean_mode) rv = index_clean(&xh, argv[optind], hashcheck, compression); - else if (rm_mode) + else if (obsoletes_mode) rv = remove_obsoletes(&xh, argv[optind]); + else if (remove_mode) + rv = index_remove(&xh, optind, argc, argv, compression); else if (sign_mode) rv = sign_repo(&xh, argv[optind], privkey, signedby, compression); else if (sign_pkg_mode) diff --git a/bin/xbps-rindex/xbps-rindex.1 b/bin/xbps-rindex/xbps-rindex.1 index affb0cf93..c6bebed70 100644 --- a/bin/xbps-rindex/xbps-rindex.1 +++ b/bin/xbps-rindex/xbps-rindex.1 @@ -26,10 +26,18 @@ This flag is only useful with the .Em clean mode. .It Fl f -force -Forcefully register binary package into the local repository, overwriting existing entry. -Or forcefully create a package signature, even if there's an existing one already. +Used with +.Ar -a , +forcefully register binary package into the local repository, overwriting existing entry. +Used with +.Ar -R , +forcefully unregister binary package from the local repository, without comparing versions. +Used with +.Ar -S , +forcefully create a package signature, even if there's an existing one already. This flag is only useful with the -.Em add +.Em add , +.Em remove or .Em sign-pkg modes. @@ -56,6 +64,13 @@ Absolute path to the local repository is expected. .It Sy -c, --clean Ar /path/to/repository Removes obsolete entries found in the local repository. Absolute path to the local repository is expected. +.It Sy -R, --remove Ar /path/to/repository /path/to/repository/binpkg.xbps ... +Removes specified packages from repository. +Absolute path to the local repository is expected, then absolute +paths to existing binpkgs. +Packages aren't removed when archives contain version older than indexed, +unless in force mode. +In force mode pkgnames may be passed instead of archive paths. .It Sy -r, --remove-obsoletes Ar /path/to/repository Removes obsolete packages from .Ar repository . diff --git a/data/_xbps b/data/_xbps index 6a7687b7b..5f0d6a13a 100644 --- a/data/_xbps +++ b/data/_xbps @@ -208,6 +208,7 @@ _xbps_rindex() { - '(mode)' \ {-a,--add}'[Add package to repository index]' \ {-c,--clean}'[Clean repository index]' \ + {-R,--remove}'[Remove packages from repository index]' \ {-r,--remove-obsoletes}'[Removes obsolete packages from repository]' \ {-s,--sign}'[Sign repository index]' \ {-S,--sign-pkg}'[Sign binary package archive]' \