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