On Mon, Sep 7, 2009 at 4:43 PM, Xavier Chantry <shiningxc@gmail.com> wrote:
And a new --print-format option to configure the output.
This implements FS#14208
Signed-off-by: Xavier Chantry <shiningxc@gmail.com> --- contrib/bash_completion | 9 +++- contrib/zsh_completion | 1 + doc/pacman.8.txt | 11 ++++ src/pacman/conf.c | 1 + src/pacman/conf.h | 3 +- src/pacman/pacman.c | 24 +++++++-- src/pacman/remove.c | 6 ++ src/pacman/sync.c | 24 ++------- src/pacman/upgrade.c | 8 +++- src/pacman/util.c | 120 +++++++++++++++++++++++++++++++++++++++++++---- src/pacman/util.h | 1 + 11 files changed, 171 insertions(+), 37 deletions(-)
diff --git a/contrib/bash_completion b/contrib/bash_completion index 65135cf..8fd62d6 100644 --- a/contrib/bash_completion +++ b/contrib/bash_completion @@ -167,7 +167,7 @@ _pacman () groups) mod="${mod}g" ;; info) mod="${mod}i" ;; list) mod="${mod}l" ;; - print-uris) mod="${mod}p" ;; + print) mod="${mod}p" ;; search) mod="${mod}s" ;; sysupgrade) mod="${mod}u" ;; upgrades) mod="${mod}u" ;; @@ -231,6 +231,8 @@ _pacman () -v --verbose \ -r --root \ -b --dbpath \ + -p --print \ + --print-format \ --cachedir \ ' -- $cur ) ) return 0 @@ -252,6 +254,8 @@ _pacman () -v --verbose \ -r --root \ -b --dbpath \ + -p --print \ + --print-format \ --cachedir \ ' -- $cur ) ) return 0 @@ -267,7 +271,6 @@ _pacman () -h --help \ -i --info \ -l --list \ - -p --print-uris \ -s --search \ -u --sysupgrade \ -w --downloadonly \ @@ -283,6 +286,8 @@ _pacman () -v --verbose \ -r --root \ -b --dbpath \ + -p --print \ + --print-format \ --cachedir \ ' -- $cur ) ) return 0 diff --git a/contrib/zsh_completion b/contrib/zsh_completion index 2f43d9b..2ecef35 100644 --- a/contrib/zsh_completion +++ b/contrib/zsh_completion @@ -26,6 +26,7 @@ _pacman_opts_common=( '--noconfirm[Do not ask for confirmation]' '--noprogressbar[Do not show a progress bar when downloading files]' '--noscriptlet[Do not execute the install scriptlet if one exists]' + '--print[Only print the targets instead of performing the operation]' )
# options for passing to _arguments: options for --upgrade commands diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt index a534e05..e38b909 100644 --- a/doc/pacman.8.txt +++ b/doc/pacman.8.txt @@ -169,6 +169,17 @@ Options *\--arch* <'arch'>:: Specify an alternate architecture.
+*\--print*:: + Only print the targets instead of performing the actual operation (sync, + remove or upgrade). Use '\--print-format' to specify how targets are + displayed. + +*\--print-format* <'format'>:: + Specify a printf-like format to control the output of the '\--print' + operation. The possible are attributes are : %n for pkgname, %v for pkgver, %l + for location, %r for repo and %s for size. The default format string is "%l", + which displays url with '-S', filename with '-U' and pkgname-pkgver with '-R'. +
* Isn't --print actually -p/--print? * Should the default format stuff actually be in the --print documentation (either as well, or completely move it there?). I feel like I would look there first. * You didn't kill the print-uri documentation.
Query Options[[QO]] ------------------- *-c, \--changelog*:: diff --git a/src/pacman/conf.c b/src/pacman/conf.c index 92c6f4e..a8da49c 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -62,6 +62,7 @@ int config_free(config_t *oldconfig) free(oldconfig->dbpath); free(oldconfig->logfile); free(oldconfig->xfercommand); + free(oldconfig->print_format); free(oldconfig); oldconfig = NULL;
diff --git a/src/pacman/conf.h b/src/pacman/conf.h index 2d3de98..192f80f 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -31,6 +31,8 @@ typedef struct __config_t { unsigned short noconfirm; unsigned short noprogressbar; unsigned short logmask; + unsigned short print; + char *print_format; /* unfortunately, we have to keep track of paths both here and in the library * because they can come from both the command line or config file, and we * need to ensure we get the order of preference right. */ @@ -59,7 +61,6 @@ typedef struct __config_t { unsigned short op_s_sync; unsigned short op_s_search; unsigned short op_s_upgrade; - unsigned short op_s_printuris;
unsigned short group; pmtransflag_t flags; diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 3747208..929f745 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -128,7 +128,6 @@ static void usage(int op, const char * const myname) printf(_(" -g, --groups view all members of a package group\n")); printf(_(" -i, --info view package information\n")); printf(_(" -l, --list <repo> view a list of packages in a repo\n")); - printf(_(" -p, --print-uris print out URIs for given packages and their dependencies\n")); printf(_(" -s, --search <regex> search remote repositories for matching strings\n")); printf(_(" -u, --sysupgrade upgrade all outdated packages (-uu enables downgrade)\n")); printf(_(" -w, --downloadonly download packages but do not install/upgrade anything\n")); @@ -139,6 +138,9 @@ static void usage(int op, const char * const myname) " ignore a group upgrade (can be used more than once)\n")); printf(_(" -q, --quiet show less information for query and search\n")); } + printf(_(" --print only print the targets instead of performing the operation\n")); + printf(_(" --print-format <string>\n" + " specify how the targets should be printed\n")); printf(_(" --config <path> set an alternate configuration file\n")); printf(_(" --logfile <path> set an alternate log file\n")); printf(_(" --noconfirm do not ask for any confirmation\n")); @@ -366,7 +368,7 @@ static int parseargs(int argc, char *argv[]) {"nosave", no_argument, 0, 'n'}, {"owns", no_argument, 0, 'o'}, {"file", no_argument, 0, 'p'}, - {"print-uris", no_argument, 0, 'p'}, + {"print", no_argument, 0, 'p'}, {"quiet", no_argument, 0, 'q'}, {"root", required_argument, 0, 'r'}, {"recursive", no_argument, 0, 's'}, @@ -391,6 +393,7 @@ static int parseargs(int argc, char *argv[]) {"needed", no_argument, 0, 1011}, {"asexplicit", no_argument, 0, 1012}, {"arch", required_argument, 0, 1013}, + {"print-format", required_argument, 0, 1014}, {0, 0, 0, 0} };
@@ -468,6 +471,9 @@ static int parseargs(int argc, char *argv[]) case 1013: setarch(optarg); break; + case 1014: + config->print_format = strdup(optarg); + break; case 'Q': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_QUERY); break; case 'R': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_REMOVE); break; case 'S': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_SYNC); break; @@ -503,9 +509,7 @@ static int parseargs(int argc, char *argv[]) case 'o': config->op_q_owns = 1; break; case 'p': config->op_q_isfile = 1; - config->op_s_printuris = 1; - config->flags |= PM_TRANS_FLAG_NOCONFLICTS; - config->flags |= PM_TRANS_FLAG_NOLOCK; + config->print = 1; break; case 'q': config->quiet = 1; @@ -1075,6 +1079,16 @@ int main(int argc, char *argv[]) alpm_option_set_totaldlcb(cb_dl_total); }
+ /* set up the print operations */ + if(config->print) { + config->noconfirm = 1; + config->flags |= PM_TRANS_FLAG_NOCONFLICTS; + config->flags |= PM_TRANS_FLAG_NOLOCK; + /* Display only errors */ + config->logmask &= ~PM_LOG_WARNING; Man, I hate having to do this. We really should think about a stderr/stdout jihad.
+ } + + #if defined(HAVE_GETEUID) && !defined(CYGWIN) /* check if we have sufficient permission for the requested operation */ if(myuid > 0 && needs_root()) { diff --git a/src/pacman/remove.c b/src/pacman/remove.c index b5119fa..06503d3 100644 --- a/src/pacman/remove.c +++ b/src/pacman/remove.c @@ -159,6 +159,12 @@ int pacman_remove(alpm_list_t *targets) }
/* Step 3: actually perform the removal */ + if(config->print) { /* --print */ + print_packages(alpm_trans_get_pkgs()); + /* we are done */ None of the comments here seem particularly necessary. (/*--print*/, /*we are done*/). Can you kill them?
+ goto cleanup; + } + if(alpm_trans_commit(NULL) == -1) { pm_fprintf(stderr, PM_LOG_ERROR, _("failed to commit transaction (%s)\n"), alpm_strerrorlast()); diff --git a/src/pacman/sync.c b/src/pacman/sync.c index 896d028..30638bb 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -697,22 +697,8 @@ static int sync_trans(alpm_list_t *targets) }
/* Step 3: actually perform the operation */ - if(config->op_s_printuris) { - /* print uris */ - alpm_list_t *i; - for(i = packages; i; i = alpm_list_next(i)) { - pmpkg_t *pkg = alpm_list_getdata(i); - pmdb_t *db = alpm_pkg_get_db(pkg); - const char *dburl = alpm_db_get_url(db); - if(dburl) { - printf("%s/%s\n", dburl, alpm_pkg_get_filename(pkg)); - } else { - /* can't use WARNING here, we don't show warnings in -Sp... */ - pm_fprintf(stderr, PM_LOG_ERROR, _("no database for package: %s\n"), - alpm_pkg_get_name(pkg)); - } - - } + if(config->print) { + print_packages(packages); /* we are done */ goto cleanup; } @@ -785,8 +771,8 @@ int pacman_sync(alpm_list_t *targets) { alpm_list_t *sync_dbs = NULL;
- /* Display only errors with -Sp and -Sw operations */ - if((config->flags & PM_TRANS_FLAG_DOWNLOADONLY) || config->op_s_printuris) { + /* Display only errors with -Sw operations */ + if(config->flags & PM_TRANS_FLAG_DOWNLOADONLY) { Why do we do this for -Sw?
config->logmask &= ~PM_LOG_WARNING; }
@@ -859,7 +845,7 @@ int pacman_sync(alpm_list_t *targets) }
alpm_list_t *targs = alpm_list_strdup(targets); - if(!(config->flags & PM_TRANS_FLAG_DOWNLOADONLY) && !config->op_s_printuris) { + if(!(config->flags & PM_TRANS_FLAG_DOWNLOADONLY) && !config->print) { /* check for newer versions of packages to be upgraded first */ alpm_list_t *packages = syncfirst(); if(packages) { diff --git a/src/pacman/upgrade.c b/src/pacman/upgrade.c index e769118..8269b3d 100644 --- a/src/pacman/upgrade.c +++ b/src/pacman/upgrade.c @@ -70,7 +70,6 @@ int pacman_upgrade(alpm_list_t *targets) }
/* add targets to the created transaction */ - printf(_("loading package data...\n")); for(i = targets; i; i = alpm_list_next(i)) { char *targ = alpm_list_getdata(i); if(alpm_trans_addtarget(targ) == -1) { @@ -143,6 +142,13 @@ int pacman_upgrade(alpm_list_t *targets) alpm_list_free(data);
/* Step 3: perform the installation */ + if(config->print) { /* --print */ + print_packages(alpm_trans_get_pkgs()); + /* we are done */ + trans_release(); + return(0); Kill comments + } + if(alpm_trans_commit(NULL) == -1) { pm_fprintf(stderr, PM_LOG_ERROR, _("failed to commit transaction (%s)\n"), alpm_strerrorlast()); diff --git a/src/pacman/util.c b/src/pacman/util.c index a02b43c..8558302 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -47,8 +47,15 @@
int trans_init(pmtranstype_t type, pmtransflag_t flags) { - if(alpm_trans_init(type, flags, cb_trans_evt, - cb_trans_conv, cb_trans_progress) == -1) { + int ret; + if(config->print) { + ret = alpm_trans_init(type, flags, NULL, NULL, NULL); + } else { + ret = alpm_trans_init(type, flags, cb_trans_evt, cb_trans_conv, + cb_trans_progress); + } + + if(ret == -1) { pm_fprintf(stderr, PM_LOG_ERROR, _("failed to init transaction (%s)\n"), alpm_strerrorlast()); if(pm_errno == PM_ERR_HANDLE_LOCK) { @@ -72,13 +79,16 @@ int trans_release(void)
int needs_root(void) { - if(config->op == PM_OP_UPGRADE || config->op == PM_OP_REMOVE || /* -U, -R */ - (config->op == PM_OP_SYNC && (config->op_s_clean || config->op_s_sync || /* -Sc, -Sy */ - (!config->group && !config->op_s_info && !config->op_q_list /* all other -S combinations, where */ - && !config->op_s_search && !config->op_s_printuris)))) { /* -g, -i, -l, -s, -p is not set */ - return(1); - } else { - return(0); + switch(config->op) { + case PM_OP_UPGRADE: + case PM_OP_REMOVE: + return(!config->print); + case PM_OP_SYNC: + return(config->op_s_clean || config->op_s_sync || + (!config->group && !config->op_s_info && !config->op_q_list && + !config->op_s_search && !config->print)); + default: + return(0); Aha, much cleaner. I'll assume your logic translation is right. :) } }
@@ -607,6 +617,98 @@ void display_synctargets(const alpm_list_t *syncpkgs) alpm_list_free(rpkglist); }
+off_t pkg_get_size(pmpkg_t *pkg) +{ + switch(config->op) { + case PM_OP_SYNC: + return(alpm_pkg_download_size(pkg)); + case PM_OP_UPGRADE: + return(alpm_pkg_get_size(pkg)); + default: + return(alpm_pkg_get_isize(pkg)); + } +} + +char *pkg_get_location(pmpkg_t *pkg) +{ + pmdb_t *db; + const char *dburl; + char *string; + switch(config->op) { + case PM_OP_SYNC: + db = alpm_pkg_get_db(pkg); + dburl = alpm_db_get_url(db); + if(dburl) { + char *pkgurl = NULL; + asprintf(&pkgurl, "%s/%s", dburl, alpm_pkg_get_filename(pkg)); + return(pkgurl); + } + case PM_OP_UPGRADE: + return(strdup(alpm_pkg_get_filename(pkg))); + default: + string = NULL; + asprintf(&string, "%s-%s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); + return(string); + } +} + +void print_packages(const alpm_list_t *packages) +{ + const alpm_list_t *i; + if(!config->print_format) { + config->print_format = strdup("%l"); + } + for(i = packages; i; i = alpm_list_next(i)) { + pmpkg_t *pkg = alpm_list_getdata(i); + char *string = strdup(config->print_format); + char *temp = string; + /* %n : pkgname */ + if(strstr(temp,"%n")) { + string = strreplace(temp, "%n", alpm_pkg_get_name(pkg)); + free(temp); + temp = string; + } + /* %v : pkgver */ + if(strstr(temp,"%v")) { + string = strreplace(temp, "%v", alpm_pkg_get_version(pkg)); + free(temp); + temp = string; + } + /* %l : location */ + if(strstr(temp,"%l")) { + char *pkgloc = pkg_get_location(pkg); + string = strreplace(temp, "%l", pkgloc); + free(pkgloc); + free(temp); + temp = string; + } + /* %r : repo */ + if(strstr(temp,"%r")) { + const char *repo = "local"; + pmdb_t *db = alpm_pkg_get_db(pkg); + if(db) { + repo = alpm_db_get_name(db); + } + string = strreplace(temp, "%r", repo); + free(temp); + temp = string; + } + /* %s : size */ + if(strstr(temp,"%s")) { + char *size; + double mbsize = 0.0; + mbsize = pkg_get_size(pkg) / (1024.0 * 1024.0); + asprintf(&size, "%.2f", mbsize); + string = strreplace(temp, "%s", size); + free(size); + free(temp); + temp = string; + } This strreplace() stuff seems a bit naive, considering we could do a lot of replaces on the string. I'm not sure we need to worry about it but could be a place for some improvement.
+ printf("%s\n",string); + free(string); + } +} + /* Helper function for comparing strings using the * alpm "compare func" signature */ int str_cmp(const void *s1, const void *s2) diff --git a/src/pacman/util.h b/src/pacman/util.h index 1282422..25a8168 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -57,6 +57,7 @@ void display_targets(const alpm_list_t *pkgs, int install); void display_synctargets(const alpm_list_t *syncpkgs); void display_new_optdepends(pmpkg_t *oldpkg, pmpkg_t *newpkg); void display_optdepends(pmpkg_t *pkg); +void print_packages(const alpm_list_t *packages); int yesno(char *fmt, ...); int noyes(char *fmt, ...); int pm_printf(pmloglevel_t level, const char *format, ...) __attribute__((format(printf,2,3))); -- 1.6.4.2
OK, and now for some usability testing. $ ./src/pacman/pacman -Q <big list of packages> ... zope-interface 3.5.1-1 zvbi 0.2.33-1 $ ./src/pacman/pacman -Q --print error: no targets specified (use -h for help) So two things here- I expected --print to work and it did not, and we already have the standard "pkgname <space> pkgver" output that our default print format uses. Do we want to invent a new one with the default --print for remove? Oh wait, does --print even work for -Q? Now I'm all confused. :) $ ./src/pacman/pacman -Q --print pacman-git error: package "pacman-git" not found $ ./src/pacman/pacman -Q pacman-git pacman-git 20091018-1 More unexpected behavior... $ ./src/pacman/pacman -Ss --print pacman core/pacman 3.3.3-1 (base) A library-based package manager with dependency support core/pacman-mirrorlist 20090616-1 (base) [installed] Arch Linux mirror list for use by pacman extra/namcap 2.4-1 [installed] A Pacman package analyzer I wanted a list of URLs for all packages that matched my pacman search, I did not get that... -Dan