SOURCES (megabajt): poldek-browse-pkgs-by-groups.patch (NEW) - added -brows...
megabajt
megabajt at pld-linux.org
Sat Mar 7 17:57:55 CET 2009
Author: megabajt Date: Sat Mar 7 16:57:55 2009 GMT
Module: SOURCES Tag: megabajt
---- Log message:
- added -browse-pkgs-by-groups.patch; this experimental patch adds additional
functionality which allows you to browse packages by groups. Currently only
basic features are implemented.
---- Files affected:
SOURCES:
poldek-browse-pkgs-by-groups.patch (NONE -> 1.1.2.1) (NEW)
---- Diffs:
================================================================
Index: SOURCES/poldek-browse-pkgs-by-groups.patch
diff -u /dev/null SOURCES/poldek-browse-pkgs-by-groups.patch:1.1.2.1
--- /dev/null Sat Mar 7 17:57:56 2009
+++ SOURCES/poldek-browse-pkgs-by-groups.patch Sat Mar 7 17:57:50 2009
@@ -0,0 +1,591 @@
+diff --git a/cli/cli.c b/cli/cli.c
+index 8ec851f..0f6af91 100644
+--- a/cli/cli.c
++++ b/cli/cli.c
+@@ -625,17 +625,27 @@ int poclidek_load_packages(struct poclidek_ctx *cctx, unsigned flags)
+
+ if (flags & POCLIDEK_LOAD_INSTALLED) {
+ int reload = (flags & POCLIDEK_LOAD_RELOAD);
++ char *pwd = NULL, pwdpath[PATH_MAX];
+
+- if (reload)
++ if (reload) {
+ cctx->_flags &= ~POLDEKCLI_LOADED_INSTALLED;
++
++ /* save current path. It is likely that we will need to
++ restore it after reload */
++ pwd = poclidek_pwd(cctx, pwdpath, sizeof(pwdpath));
++ }
+
+ if ((cctx->_flags & POLDEKCLI_LOADED_INSTALLED) == 0) {
+ cctx->_flags |= POLDEKCLI_LOADED_INSTALLED;
+ if (!poclidek_load_installed(cctx, reload))
+ nerr++;
+ else {
+- if (cctx->currdir == cctx->rootdir)
++ if (cctx->currdir == cctx->rootdir) {
+ poclidek_chdir(cctx, POCLIDEK_INSTALLEDDIR);
++
++ } else if (pwd != NULL) {
++ poclidek_chdir(cctx, pwd);
++ }
+ }
+ }
+ }
+@@ -809,7 +819,7 @@ void poclidek_apply_iinf(struct poclidek_ctx *cctx, struct poldek_ts *ts)
+
+ pkgdir_remove_package(cctx->dbpkgdir, pkg);
+ if (ent)
+- pkg_dent_remove_pkg(ent, pkg);
++ pkg_dent_remove_pkg(cctx, ent, pkg);
+
+ n++;
+ DBGF("- %s\n", pkg_id(pkg));
+diff --git a/cli/dent.c b/cli/dent.c
+index 1c9380c..e927a07 100644
+--- a/cli/dent.c
++++ b/cli/dent.c
+@@ -34,6 +34,10 @@
+ #include "arg_packages.h"
+ #include "poldek_util.h"
+
++static void pkg_dent_groupdir_add_ent(struct poclidek_ctx *cctx, struct pkg_dent *groupdir, struct pkg_dent *ent);
++static void pkg_dent_groupdir_remove_ent(struct poclidek_ctx *cctx, struct pkg_dent *groupdir, struct pkg_dent *ent, const char *ent_group);
++static void poclidek_dent_groupdir_setup(struct poclidek_ctx *cctx, struct pkg_dent *dent);
++
+ static inline
+ struct pkg_dent *pkg_dent_new(struct poclidek_ctx *cctx, const char *name,
+ struct pkg *pkg, int flags)
+@@ -53,6 +57,7 @@ struct pkg_dent *pkg_dent_new(struct poclidek_ctx *cctx, const char *name,
+ ent->_refcnt = 0;
+ ent->flags = flags;
+ ent->parent = NULL;
++ ent->subdirs = NULL;
+
+ if (name) {
+ char *p;
+@@ -64,17 +69,20 @@ struct pkg_dent *pkg_dent_new(struct poclidek_ctx *cctx, const char *name,
+ if (strchr(p, '/'))
+ p = n_dirname(p);
+
++ /* XXX: I don't know why directories can't have space in their names
+ while (*p) {
+ if (isspace(*p) || *p == '/')
+ *p = '.';
+ p++;
+- }
++ }*/
+ }
+
+ if (flags & PKG_DENT_DIR) {
+ ent->pkg_dent_ents = n_array_new(128, (tn_fn_free)pkg_dent_free,
+ (tn_fn_cmp)pkg_dent_cmp);
+ n_array_ctl(ent->pkg_dent_ents, TN_ARRAY_AUTOSORTED);
++
++ ent->subdirs = n_hash_new(4, (tn_fn_free)pkg_dent_free);
+
+ } else {
+ ent->name = pkg_id(pkg);
+@@ -107,6 +115,9 @@ void pkg_dent_free(struct pkg_dent *ent)
+ n_array_free(ent->pkg_dent_ents);
+ ent->pkg_dent_ents = NULL;
+
++ n_hash_free(ent->subdirs);
++ ent->subdirs = NULL;
++
+ } else {
+ pkg_free(ent->pkg_dent_pkg);
+ ent->pkg_dent_pkg = NULL;
+@@ -182,44 +193,86 @@ int pkg_dent_cmp_bday(struct pkg_dent *ent1, struct pkg_dent *ent2)
+ }
+
+
++struct pkg_dent *pkg_dent_get_groupdir(struct poclidek_ctx *cctx, struct pkg_dent *dent)
++{
++ struct pkg_dent *groupdir = NULL;
++
++ if ((groupdir = n_hash_get(dent->subdirs, "groups")) == NULL)
++ groupdir = pkg_dent_add_dir(cctx, dent, "groups");
++
++ return groupdir;
++}
+
+ struct pkg_dent *pkg_dent_add_pkg(struct poclidek_ctx *cctx,
+ struct pkg_dent *dent, struct pkg *pkg)
+ {
++ struct pkg_dent *groupdir = NULL;
+ struct pkg_dent *ent;
+
+ ent = pkg_dent_new_pkg(cctx, pkg);
+ n_array_push(dent->pkg_dent_ents, ent);
+ n_array_sort(dent->pkg_dent_ents);
++
++ /* add ent to groupdir too */
++ groupdir = pkg_dent_get_groupdir(cctx, dent);
++ pkg_dent_groupdir_add_ent(cctx, groupdir, pkg_dent_link(ent));
++
+ return ent;
+ }
+
+-void pkg_dent_remove_pkg(struct pkg_dent *dent, struct pkg *pkg)
++void pkg_dent_remove_pkg(struct poclidek_ctx *cctx, struct pkg_dent *dent, struct pkg *pkg)
+ {
+ struct pkg_dent tmp;
++ int idx;
+
+- n_array_sort(dent->pkg_dent_ents);
+ tmp.name = pkg_id(pkg);
+- n_array_remove(dent->pkg_dent_ents, &tmp);
+-}
+-
+
++ idx = n_array_bsearch_idx(dent->pkg_dent_ents, &tmp);
++
++ /* package in array */
++ if (idx > -1) {
++ struct pkg_dent *ent = NULL;
++ const char *ent_group = NULL;
++
++ ent = n_array_nth(dent->pkg_dent_ents, idx);
++
++ if ((ent_group = pkg_group(ent->pkg_dent_pkg)) != NULL) {
++ struct pkg_dent *groupdir = NULL;
++
++ if ((groupdir = n_hash_get(dent->subdirs, "groups")) != NULL)
++ pkg_dent_groupdir_remove_ent(cctx, groupdir, &tmp, ent_group);
++ }
++
++ n_array_remove_nth(dent->pkg_dent_ents, idx);
++ }
++}
+
+ inline
+ int pkg_dent_add_pkgs(struct poclidek_ctx *cctx,
+ struct pkg_dent *dent, tn_array *pkgs)
+ {
++ struct pkg_dent *groupdir = NULL;
+ int i;
+ struct pkg_dent *ent;
+
++ groupdir = pkg_dent_get_groupdir(cctx, dent);
++
++ n_assert(groupdir != NULL);
++
+ for (i=0; i < n_array_size(pkgs); i++) {
+ struct pkg *pkg = n_array_nth(pkgs, i);
++
+ if (pkg_is_scored(pkg, PKG_IGNORED))
+ continue;
++
+ ent = pkg_dent_new_pkg(cctx, pkg);
+ n_array_push(dent->pkg_dent_ents, ent);
++
++ pkg_dent_groupdir_add_ent(cctx, groupdir, pkg_dent_link(ent));
+ }
++
+ n_array_sort(dent->pkg_dent_ents);
++
+ return 1;
+ }
+
+@@ -228,12 +281,14 @@ int pkg_dent_replace_pkgs(struct poclidek_ctx *cctx, struct pkg_dent *dent,
+ tn_array *pkgs)
+ {
+ int i, n;
+- struct pkg_dent *ent;
++ struct pkg_dent *ent = NULL;
+ tn_array *ents;
+
+-
+ ents = n_array_dup(dent->pkg_dent_ents, (tn_fn_dup)pkg_dent_link);
++
++ /* we are cleaning dent directory */
+ n_array_clean(dent->pkg_dent_ents);
++ n_hash_clean(dent->subdirs);
+
+ n = 0;
+ for (i=0; i < n_array_size(pkgs); i++) {
+@@ -242,11 +297,17 @@ int pkg_dent_replace_pkgs(struct poclidek_ctx *cctx, struct pkg_dent *dent,
+ if (pkg_is_scored(pkg, PKG_IGNORED))
+ continue;
+
+- if (n == n_array_size(ents))
+- break;
+-
+- ent = n_array_nth(ents, n);
+- n++;
++ /* ent may be directory and then we must skip it */
++ do {
++ if (n == n_array_size(ents))
++ break;
++
++ ent = n_array_nth(ents, n);
++ n++;
++ } while (pkg_dent_isdir(ent));
++
++ if (ent == NULL || pkg_dent_isdir(ent))
++ break;
+
+ ent->name = pkg_id(pkg);
+ pkg_free(ent->pkg_dent_pkg);
+@@ -259,10 +320,14 @@ int pkg_dent_replace_pkgs(struct poclidek_ctx *cctx, struct pkg_dent *dent,
+
+ if (pkg_is_scored(pkg, PKG_IGNORED))
+ continue;
++
+ ent = pkg_dent_new_pkg(cctx, pkg);
+ n_array_push(dent->pkg_dent_ents, ent);
+ }
+
++ /* rebuild groups dir */
++ poclidek_dent_groupdir_setup(cctx, dent);
++
+ n_array_sort(dent->pkg_dent_ents);
+ n_array_free(ents);
+ return 1;
+@@ -276,11 +341,16 @@ struct pkg_dent *pkg_dent_add_dir(struct poclidek_ctx *cctx,
+
+ ent = pkg_dent_new_dir(cctx, name);
+ DBGF("adddir %s\n", name);
++
+ if (parent) {
+ ent->parent = parent;
+ n_array_push(parent->pkg_dent_ents, ent);
+ n_array_sort(parent->pkg_dent_ents);
++
++ /* add to parent's subdirs too */
++ n_hash_insert(parent->subdirs, ent->name, pkg_dent_link(ent));
+ }
++
+ return ent;
+ }
+
+@@ -301,7 +371,7 @@ char *poclidek_dent_dirpath(char *path, int size, const struct pkg_dent *dent)
+ path[1] = '\0';
+ n = 1;
+ while (n_array_size(stack))
+- n += n_snprintf(&path[n], size - n, "%s/", n_array_shift(stack));
++ n += n_snprintf(&path[n], size - n, "%s/", n_array_pop(stack));
+
+ if (n > 1)
+ path[n - 1] = '\0'; /* eat '/' */
+@@ -318,6 +388,31 @@ static void dent_sort(const char *foo, void *dent)
+ n_array_sort(ent->pkg_dent_ents);
+ }
+
++static void poclidek_dent_groupdir_setup(struct poclidek_ctx *cctx, struct pkg_dent *dent)
++{
++ struct pkg_dent *groupdir = NULL;
++ int i;
++
++ /* groupdir can be created only for dir dents */
++ n_assert(pkg_dent_isdir(dent));
++
++ groupdir = pkg_dent_get_groupdir(cctx, dent);
++
++ for (i = 0; i < n_array_size(dent->pkg_dent_ents); i++) {
++ struct pkg_dent *ent = n_array_nth(dent->pkg_dent_ents, i);
++
++ if (pkg_dent_isdir(ent))
++ continue;
++
++ pkg_dent_groupdir_add_ent(cctx, groupdir, pkg_dent_link(ent));
++ }
++}
++
++static inline void groupdir_setup(const char *key, void *data, void *cctx)
++{
++ poclidek_dent_groupdir_setup(cctx, data);
++}
++
+ struct pkg_dent *poclidek_dent_setup(struct poclidek_ctx *cctx,
+ const char *path, tn_array *pkgs,
+ int force)
+@@ -391,6 +486,8 @@ struct pkg_dent *poclidek_dent_setup(struct poclidek_ctx *cctx,
+ }
+
+ n_hash_map(dent_ht, dent_sort);
++ n_hash_map_arg(dent_ht, groupdir_setup, cctx);
++
+ n_hash_free(dent_ht);
+ return dest;
+ }
+@@ -398,7 +495,7 @@ struct pkg_dent *poclidek_dent_setup(struct poclidek_ctx *cctx,
+
+ static
+ struct pkg_dent *get_dir_dent(struct poclidek_ctx *cctx,
+- struct pkg_dent *currdir, const char *path)
++ struct pkg_dent *currdir, const char *path, int create_missing)
+ {
+ const char **tl, **tl_save, *p;
+ struct pkg_dent *ent = NULL;
+@@ -410,8 +507,12 @@ struct pkg_dent *get_dir_dent(struct poclidek_ctx *cctx,
+ n_assert(currdir);
+
+ if ((p = strchr(path, '/')) == NULL) {
+- ent = n_array_bsearch_ex(currdir->pkg_dent_ents, path,
+- (tn_fn_cmp)pkg_dent_strcmp);
++ if ((ent = n_hash_get(currdir->subdirs, path)) == NULL) {
++ /* requested dir doesn't exist. Maybe we should add it? */
++ if (create_missing)
++ ent = pkg_dent_add_dir(cctx, currdir, path);
++ }
++
+ return ent;
+ }
+
+@@ -422,8 +523,9 @@ struct pkg_dent *get_dir_dent(struct poclidek_ctx *cctx,
+ rc = 1;
+ while (*tl) {
+ if (n_str_ne(*tl, "")) {
+- if ((ent = get_dir_dent(cctx, currdir, *tl)) == NULL)
+- break;
++ if ((ent = get_dir_dent(cctx, currdir, *tl, create_missing)) == NULL)
++ break;
++
+ currdir = ent;
+ }
+
+@@ -456,8 +558,8 @@ int poclidek_chdir(struct poclidek_ctx *cctx, const char *path)
+ }
+
+ if ((p = strchr(path, '/')) == NULL) {
+- ent = n_array_bsearch_ex(cctx->currdir->pkg_dent_ents, path,
+- (tn_fn_cmp)pkg_dent_strcmp);
++ ent = n_hash_get(cctx->currdir->subdirs, path);
++
+ if (ent) {
+ cctx->currdir = ent;
+ return 1;
+@@ -517,11 +619,13 @@ struct pkg_dent *poclidek_dent_ldfind(struct poclidek_ctx *cctx, const char *pat
+
+ struct pkg_dent *poclidek_dent_find(struct poclidek_ctx *cctx, const char *path)
+ {
+-
+ if (path == NULL || (n_str_eq(path, ".") || n_str_eq(path, "")))
+ return cctx->currdir;
+
+- return get_dir_dent(cctx, cctx->currdir, path);
++ if (n_str_eq(path, "/"))
++ return cctx->rootdir;
++
++ return get_dir_dent(cctx, cctx->currdir, path, 0);
+ }
+
+
+@@ -717,4 +821,75 @@ char *poclidek_pwd(struct poclidek_ctx *cctx, char *path, int size)
+ return poclidek_dent_dirpath(path, size, cctx->currdir);
+ }
+
++static void pkg_dent_groupdir_add_ent(struct poclidek_ctx *cctx, struct pkg_dent *groupdir, struct pkg_dent *ent)
++{
++ const char *ent_group = NULL;
++
++ ent_group = pkg_group(ent->pkg_dent_pkg);
++
++ /* some ents don't have groups (see gpg-pubkey in /installed as an example) */
++ if (ent_group) {
++ struct pkg_dent *destdir = NULL;
++
++ /* get destination dir; create if not exist */
++ destdir = get_dir_dent(cctx, groupdir, ent_group, 1);
++
++ n_assert(destdir != NULL);
++
++ n_array_push(destdir->pkg_dent_ents, ent);
++ }
++}
+
++void pkg_dent_remove_dir(struct pkg_dent *dent)
++{
++ struct pkg_dent *parent = dent->parent;
++ struct pkg_dent *ent = NULL;
++
++ /* remove dent from parents subdirs */
++ ent = n_hash_remove(parent->subdirs, dent->name);
++
++ if (ent != NULL)
++ pkg_dent_free(ent);
++
++ n_array_remove(parent->pkg_dent_ents, dent);
++}
++
++/**
++ * remove_empty_groupdirs:
++ *
++ * Removes dent directory and its parents, but only when the following conditions are met:
++ * - dent->subdirs hash table is empty (dent has no subdirs)
++ * - there are no packages in dent directory
++ **/
++static void remove_empty_groupdirs(struct pkg_dent *dent)
++{
++ struct pkg_dent *parent = dent->parent;
++
++ /* it can be called only for dir dents */
++ n_assert(dent->flags & PKG_DENT_DIR);
++
++ if (n_hash_size(dent->subdirs) > 0)
++ return;
++
++ if (n_array_size(dent->pkg_dent_ents) > 0)
++ return;
++
++ pkg_dent_remove_dir(dent);
++
++ remove_empty_groupdirs(parent);
++}
++
++static void pkg_dent_groupdir_remove_ent(struct poclidek_ctx *cctx, struct pkg_dent *groupdir,
++ struct pkg_dent *ent, const char *ent_group)
++{
++ /* package is in groupdir only if it has group */
++ if (ent_group) {
++ struct pkg_dent *destdir = NULL;
++
++ if ((destdir = get_dir_dent(cctx, groupdir, ent_group, 0)) != NULL) {
++ n_array_remove(destdir->pkg_dent_ents, ent);
++
++ remove_empty_groupdirs(destdir);
++ }
++ }
++}
+diff --git a/cli/dent.h b/cli/dent.h
+index 6653978..5faf82c 100644
+--- a/cli/dent.h
++++ b/cli/dent.h
+@@ -12,6 +12,8 @@ struct pkg_dent {
+ uint16_t _refcnt;
+ uint16_t flags;
+ struct pkg_dent *parent;
++
++ tn_hash *subdirs;
+
+ union {
+ tn_array *ents;
+@@ -40,8 +42,8 @@ int pkg_dent_add_pkgs(struct poclidek_ctx *cctx,
+ struct pkg_dent *pkg_dent_add_pkg(struct poclidek_ctx *cctx,
+ struct pkg_dent *dent, struct pkg *pkg);
+
+-void pkg_dent_remove_pkg(struct pkg_dent *dent, struct pkg *pkg);
+-
++void pkg_dent_remove_pkg(struct poclidek_ctx *cctx,
++ struct pkg_dent *dent, struct pkg *pkg);
+
+ int pkg_dent_cmp(struct pkg_dent *ent1, struct pkg_dent *ent2);
+ int pkg_dent_cmp_btime(struct pkg_dent *ent1, struct pkg_dent *ent2);
+diff --git a/cli/shell.c b/cli/shell.c
+index 0869a37..9dda9e0 100644
+--- a/cli/shell.c
++++ b/cli/shell.c
+@@ -306,7 +306,85 @@ static char *pkgname_generator(const char *text, int state)
+
+ static char *dirname_generator(const char *text, int state)
+ {
+- return arg_generator(text, state, 0);
++ struct pkg_dent *currdir = NULL;
++ static char *dirname = NULL;
++ char *name = NULL;
++ static int i;
++
++ /* do some initialization on start */
++ if (state == 0) {
++ i = 0;
++
++ n_strdupap(text, &dirname);
++
++ dirname = n_dirname(dirname);
++
++ /* For:
++ text="installed" dirname=NULL
++ text="/installed" dirname='\0'
++ text="/installed/groups" dirname="/installed" */
++ if (dirname) {
++ char *dn = NULL;
++
++ if (*dirname == '\0')
++ dn = n_strdup("/");
++ else
++ dn = n_str_concat(dirname, "/", NULL);
++
++ dirname = dn;
++
++ if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&dn)) {
++ free(dirname);
++ dirname = dn;
++ }
++
++ rl_filename_completion_desired = 1;
++ }
++ }
++
++ if (dirname)
++ currdir = poclidek_dent_find(sh_ctx.cctx, dirname);
++ else
++ currdir = sh_ctx.cctx->currdir;
++
++ /* currdir sometimes has NULL value as dirname can be wrong */
++ if (currdir) {
++ tn_array *subdirs = NULL;
++ char *basename = NULL;
++ int bnlen;
++
++ subdirs = n_hash_keys(currdir->subdirs);
++
++ n_strdupap(text, &basename);
++ basename = n_basenam(basename);
++
++ bnlen = strlen(basename);
++
++ while (i < n_array_size(subdirs)) {
++ const char *subdir = n_array_nth(subdirs, i++);
++
++ if (strncmp(subdir, basename, bnlen) == 0) {
++ if (dirname)
++ name = n_str_concat(dirname, subdir, NULL);
++ else
++ name = n_strdup(subdir);
++
++ break;
++ }
++ }
++
++ n_array_free(subdirs);
++ }
++
++ if (name)
++ return name;
++
++ if (dirname) {
++ free(dirname);
++ dirname = NULL;
++ }
++
++ return NULL;
+ }
+
+ #ifndef HAVE_READLINE_4_2
+@@ -327,6 +405,10 @@ static char **poldek_completion(const char *text, int start, int end)
+ while (isspace(*p))
+ p++;
+
++ /* set defaults */
++ rl_completer_word_break_characters = " \t\n\"\\'`@$><=;|&{(";
++ rl_completion_append_character = ' ';
++
+ if (*p) { /* XXX: alias context should be configurable, TODO */
+ if (strncmp(p, "un", 2) == 0) /* uninstall cmd */
+ sh_ctx.completion_ctx = COMPLETITION_CTX_INSTALLED;
+@@ -353,11 +435,10 @@ static char **poldek_completion(const char *text, int start, int end)
+ if (start == 0 || strchr(p, ' ') == NULL) {
+ matches = rl_completion_matches(text, command_generator);
+
+- } else {
+- rl_completer_word_break_characters = " \t\n\"\\'`@$><=;|&{(";
+-
++ } else {
+ switch (sh_ctx.completion_ctx) {
+ case COMPLETITION_CTX_DIRNAME:
++ rl_completion_append_character = '/';
+ matches = rl_completion_matches(text, dirname_generator);
+ break;
+
<<Diff was trimmed, longer than 597 lines>>
More information about the pld-cvs-commit
mailing list