From patchwork Fri Jun 5 23:19:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Will Song X-Patchwork-Id: 1679 Return-Path: Delivered-To: patchwork@archlinux.org Received: from apollo.archlinux.org (localhost [127.0.0.1]) by apollo.archlinux.org (Postfix) with ESMTP id 16F891930C98B for ; Fri, 5 Jun 2020 23:19:24 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on apollo.archlinux.org X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=DKIM_SIGNED=0.1, DKIM_VALID=-0.1,DKIM_VALID_AU=-0.1,MAILING_LIST_MULTI=-1, RCVD_IN_DNSWL_MED=-2.3,RCVD_IN_MSPIKE_H4=0.001,RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001,T_DMARC_POLICY_QUAR=0.01 autolearn=ham autolearn_force=no version=3.4.4 X-Spam-BL-Results: [127.0.0.19] [127.0.9.2] [127.0.0.10] Received: from orion.archlinux.org (orion.archlinux.org [88.198.91.70]) by apollo.archlinux.org (Postfix) with ESMTPS for ; Fri, 5 Jun 2020 23:19:24 +0000 (UTC) Received: from orion.archlinux.org (localhost [127.0.0.1]) by orion.archlinux.org (Postfix) with ESMTP id 502DD1C92EAE5F; Fri, 5 Jun 2020 23:19:20 +0000 (UTC) Received: from luna.archlinux.org (luna.archlinux.org [IPv6:2a01:4f8:160:3033::2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits)) (No client certificate requested) (Authenticated sender: luna) by orion.archlinux.org (Postfix) with ESMTPSA id 1847A1C92EAE5B; Fri, 5 Jun 2020 23:19:20 +0000 (UTC) Authentication-Results: orion.archlinux.org; dkim=pass (1024-bit key) header.d=incertia.net header.i=@incertia.net header.b=dcnb90WI Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id 0E0B829CC9; Fri, 5 Jun 2020 23:19:20 +0000 (UTC) Authentication-Results: luna.archlinux.org; dkim=pass (1024-bit key) header.d=incertia.net header.i=@incertia.net header.b=dcnb90WI Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id 1C29029CC5 for ; Fri, 5 Jun 2020 23:19:17 +0000 (UTC) Received: from mail.incertia.net (mail.incertia.net [159.203.23.253]) by luna.archlinux.org (Postfix) with ESMTPS for ; Fri, 5 Jun 2020 23:19:16 +0000 (UTC) Received: from incertia.net (d60-65-215-180.col.wideopenwest.com [65.60.180.215]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (Client did not present a certificate) by mail.incertia.net (Postfix) with ESMTPSA id 6EC3E20EA3 for ; Fri, 5 Jun 2020 19:19:10 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=incertia.net; s=mail; t=1591399150; bh=dqHrgx1MQoeDyFBRcBCr6tN1yA0l8N4oaGtd4S+zzgk=; h=Date:From:To:Subject:In-Reply-To; b=dcnb90WIwFnSyLEwshVHn1twHvY0QEWsSHNQfMh0cxHBl7YrI273o4CozQn066wR1 c2EGfFwAT0uO0a32z6sbYz51CLTVR07umitpu1vyMByA1C2+sonFatBxJsKd/qyWim BRDIHJgN9pCfBw++lgZBHs3zCCUqIl4o9vz8IJyU= Date: Fri, 5 Jun 2020 18:19:14 -0500 From: Will Song To: pacman-contrib@lists.archlinux.org Subject: [PATCH] introduce the --optional flag (FS#61336) Message-ID: <20200605231914.GE27697@incertia.net> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <74d1f34f-4774-9ca3-cc58-b0bcee0d5b33@archlinux.org> X-Homepage: https://www.incertia.net/ X-PGP-Key: https://www.incertia.net/files/pubkey-new.asc User-Agent: Mutt/1.12.2 (2019-09-21) X-BeenThere: pacman-contrib@lists.archlinux.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: Discussion list for pacman-contrib development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: pacman-contrib-bounces@lists.archlinux.org Sender: "pacman-contrib" --optional[=DEPTH] will control the depth at which optional dependencies are printed. Its behavior is fairly simple. If the maximum depth is not yet exceeded, and it encounters an optional dependency, it will print it like a normal dependency except with an optional tag. A negative number means infinite depth. Signed-off-by: Will Song --- Hopefully this patch is a bit easier to apply. I took the email formatted patch and pasted it directly into mutt and am just modifying the commit comment after the ---, as you suggested. I have updated the manpage and the patch follows below. -- Will Song doc/pactree.8.txt | 6 ++ src/pactree.c | 160 +++++++++++++++++++++++++++++++++------------- 2 files changed, 120 insertions(+), 46 deletions(-) diff --git a/doc/pactree.8.txt b/doc/pactree.8.txt index 296d04e..02eee5b 100644 --- a/doc/pactree.8.txt +++ b/doc/pactree.8.txt @@ -58,6 +58,12 @@ Options *-u, \--unique*:: List dependent packages once. Implies '\--linear'. +*-o, \--optional[=DEPTH]*:: + Additionally prints optional dependencies up to a certain depth, default 1 + for immediate optional dependencies. When used in conjunction with '-r' it + shows which packages it is optional for. In Graphviz mode, produce dotted + lines. Negative values mean infinite depth. + *\--config *:: Specify an alternate pacman configuration file. diff --git a/src/pactree.c b/src/pactree.c index cf83326..39328e7 100644 --- a/src/pactree.c +++ b/src/pactree.c @@ -28,6 +28,8 @@ #define LINE_MAX 512 +#include + typedef struct tdepth { struct tdepth *prev; struct tdepth *next; @@ -37,6 +39,7 @@ typedef struct tdepth { /* output */ struct graph_style { const char *provides; + const char *optional; const char *tip; const char *last; const char *limb; @@ -50,6 +53,7 @@ struct graph_style { static struct graph_style graph_utf8 = { " provides", + " (optional)", UTF_VR UTF_H, UTF_UR UTF_H, UTF_V " ", @@ -58,6 +62,7 @@ static struct graph_style graph_utf8 = { static struct graph_style graph_default = { " provides", + " (optional)", "|-", "`-", "|", @@ -69,6 +74,7 @@ static struct graph_style graph_linear = { "", "", "", + "", 0 }; @@ -124,6 +130,7 @@ static int reverse = 0; static int unique = 0; static int searchsyncs = 0; static int debug = 0; +static int opt_level = 0; static const char *dbpath = DBPATH; static const char *configfile = CONFFILE; static const char *gpgdir = GPGDIR; @@ -243,20 +250,22 @@ static void usage(void) fprintf(stdout, "pactree v" PACKAGE_VERSION "\n\n" "A simple dependency tree viewer.\n\n" "Usage: pactree [options] PACKAGE\n\n" - " -a, --ascii use ASCII characters for tree formatting\n" - " -b, --dbpath set an alternate database location\n" - " -c, --color colorize output\n" - " -d, --depth <#> limit the depth of recursion\n" - " -g, --graph generate output for graphviz's dot\n" - " -h, --help display this help message\n" - " -l, --linear enable linear output\n" - " -r, --reverse list packages that depend on the named package\n" - " -s, --sync search sync databases instead of local\n" - " -u, --unique show dependencies with no duplicates (implies -l)\n" - " -v, --version display the version\n" - " --config set an alternate configuration file\n" - " --debug display debug messages\n" - " --gpgdir set an alternate home directory for GnuPG\n"); + " -a, --ascii use ASCII characters for tree formatting\n" + " -b, --dbpath set an alternate database location\n" + " -c, --color colorize output\n" + " -d, --depth <#> limit the depth of recursion\n" + " -g, --graph generate output for graphviz's dot\n" + " -h, --help display this help message\n" + " -l, --linear enable linear output\n" + " -r, --reverse list packages that depend on the named package\n" + " -s, --sync search sync databases instead of local\n" + " -u, --unique show dependencies with no duplicates (implies -l)\n" + " -o, --optional[=DEPTH] controls at which depth to stop printing optional deps\n" + " (-1 for no limit)\n" + " -v, --version display the version\n" + " --config set an alternate configuration file\n" + " --debug display debug messages\n" + " --gpgdir set an alternate home directory for GnuPG\n"); } static void version(void) @@ -280,6 +289,7 @@ static int parse_options(int argc, char *argv[]) {"reverse", no_argument, 0, 'r'}, {"sync", no_argument, 0, 's'}, {"unique", no_argument, 0, 'u'}, + {"optional",optional_argument, 0, 'o'}, {"version", no_argument, 0, 'v'}, {"config", required_argument, 0, OP_CONFIG}, @@ -294,7 +304,7 @@ static int parse_options(int argc, char *argv[]) style = &graph_utf8; } - while((opt = getopt_long(argc, argv, "ab:cd:ghlrsuv", opts, &option_index))) { + while((opt = getopt_long(argc, argv, "ab:cd:ghlrsuo::v", opts, &option_index))) { if(opt < 0) { break; } @@ -345,6 +355,17 @@ static int parse_options(int argc, char *argv[]) case 'v': version(); cleanup(0); + case 'o': + if(optarg) { + opt_level = (int)strtol(optarg, &endptr, 10); + if(*endptr != '\0') { + fprintf(stderr, "error: invalid optional depth -- %s\n", optarg); + return 1; + } + } else { + opt_level = 1; + } + break; case 'h': usage(); cleanup(0); @@ -364,9 +385,10 @@ static int parse_options(int argc, char *argv[]) /* pkg provides provision */ static void print_text(const char *pkg, const char *provision, - tdepth *depth, int last) + tdepth *depth, int last, int opt_dep) { const char *tip = ""; + const char *opt_str = opt_dep ? style->optional : ""; int level = 1; if(!pkg && !provision) { /* not much we can do */ @@ -395,38 +417,39 @@ static void print_text(const char *pkg, const char *provision, * want to print the provided package. This makes output easier to parse and * to reuse. */ if(!pkg && provision) { - printf("%s%s%s%s [unresolvable]%s\n", tip, color->leaf1, - provision, color->branch1, color->off); + printf("%s%s%s%s [unresolvable]%s%s\n", tip, color->leaf1, + provision, color->branch1, opt_str, color->off); } else if(provision && strcmp(pkg, provision) != 0 && *(style->provides) != '\0') { - printf("%s%s%s%s%s %s%s%s\n", tip, color->leaf1, pkg, - color->leaf2, style->provides, color->leaf1, provision, + printf("%s%s%s%s%s %s%s%s%s\n", tip, color->leaf1, pkg, + color->leaf2, style->provides, color->leaf1, provision, opt_str, color->off); } else { - printf("%s%s%s%s\n", tip, color->leaf1, pkg, color->off); + printf("%s%s%s%s%s\n", tip, color->leaf1, pkg, opt_str, color->off); } } -static void print_graph(const char *parentname, const char *pkgname, const char *depname) +static void print_graph(const char *parentname, const char *pkgname, const char *depname, int opt_dep) { + const char *style = opt_dep ? ", style=dotted" : ""; if(depname) { - printf("\"%s\" -> \"%s\" [color=chocolate4];\n", parentname, depname); + printf("\"%s\" -> \"%s\" [color=chocolate4%s];\n", parentname, depname, style); if(pkgname && strcmp(depname, pkgname) != 0 && !alpm_list_find_str(provisions, depname)) { - printf("\"%s\" -> \"%s\" [arrowhead=none, color=grey];\n", depname, pkgname); + printf("\"%s\" -> \"%s\" [arrowhead=none, color=grey%s];\n", depname, pkgname, style); provisions = alpm_list_add(provisions, strdup(depname)); } } else if(pkgname) { - printf("\"%s\" -> \"%s\" [color=chocolate4];\n", parentname, pkgname); + printf("\"%s\" -> \"%s\" [color=chocolate4%s];\n", parentname, pkgname, style); } } /* parent depends on dep which is satisfied by pkg */ static void print(const char *parentname, const char *pkgname, - const char *depname, tdepth *depth, int last) + const char *depname, tdepth *depth, int last, int opt_dep) { if(graphviz) { - print_graph(parentname, pkgname, depname); + print_graph(parentname, pkgname, depname, opt_dep); } else { - print_text(pkgname, depname, depth, last); + print_text(pkgname, depname, depth, last, opt_dep); } } @@ -442,7 +465,7 @@ static void print_start(const char *pkgname, const char *provname) NULL, 0 }; - print_text(pkgname, provname, &d, 0); + print_text(pkgname, provname, &d, 0, 0); } } @@ -465,23 +488,34 @@ static alpm_list_t *get_pkg_deps(alpm_pkg_t *pkg) return dep_strings; } -/** - * walk dependencies, showing dependencies of the target - */ -static void walk_deps(alpm_list_t *dblist, alpm_pkg_t *pkg, tdepth *depth, int rev) +static alpm_list_t *get_pkg_optdeps(alpm_pkg_t *pkg) { - alpm_list_t *deps, *i; - - if(!pkg || ((max_depth >= 0) && (depth->level > max_depth))) { - return; + alpm_list_t *i, *dep_strings = NULL; + for(i = alpm_pkg_get_optdepends(pkg); i; i = alpm_list_next(i)) { + alpm_depend_t *dep = i->data; + char *ds = alpm_dep_compute_string(dep); + dep_strings = alpm_list_add(dep_strings, ds); } + return dep_strings; +} - walked = alpm_list_add(walked, (void *)alpm_pkg_get_name(pkg)); +/* forward declaration */ +static void walk_deps(alpm_list_t *dblist, alpm_pkg_t *pkg, tdepth *depth, int rev, int optional); - if(rev) { - deps = alpm_pkg_compute_requiredby(pkg); +/** + * print the dependency list given, passing the optional parameter when required + */ +static void print_dep_list(alpm_list_t *deps, alpm_list_t *dblist, alpm_pkg_t *pkg, tdepth *depth, int rev, int optional, int opt_dep) +{ + alpm_list_t *i; + int new_optional; + + if(optional > 0) { + /* decrease the depth by 1 */ + new_optional = optional - 1; } else { - deps = get_pkg_deps(pkg); + /* preserve 0 (ran out of depth) and negative numbers (infinite depth) */ + new_optional = optional; } for(i = deps; i; i = alpm_list_next(i)) { @@ -494,10 +528,10 @@ static void walk_deps(alpm_list_t *dblist, alpm_pkg_t *pkg, tdepth *depth, int r /* if we've already seen this package, don't print in "unique" output * and don't recurse */ if(!unique) { - print(alpm_pkg_get_name(pkg), alpm_pkg_get_name(dep_pkg), pkgname, depth, last); + print(alpm_pkg_get_name(pkg), alpm_pkg_get_name(dep_pkg), pkgname, depth, last, opt_dep); } } else { - print(alpm_pkg_get_name(pkg), alpm_pkg_get_name(dep_pkg), pkgname, depth, last); + print(alpm_pkg_get_name(pkg), alpm_pkg_get_name(dep_pkg), pkgname, depth, last, opt_dep); if(dep_pkg) { tdepth d = { depth, @@ -506,7 +540,7 @@ static void walk_deps(alpm_list_t *dblist, alpm_pkg_t *pkg, tdepth *depth, int r }; depth->next = &d; /* last dep, cut off the limb here */ - if(last) { + if((last && optional && opt_dep) || (last && !optional)) { if(depth->prev) { depth->prev->next = &d; d.prev = depth->prev; @@ -515,13 +549,47 @@ static void walk_deps(alpm_list_t *dblist, alpm_pkg_t *pkg, tdepth *depth, int r d.prev = NULL; } } - walk_deps(dblist, dep_pkg, &d, rev); + walk_deps(dblist, dep_pkg, &d, rev, new_optional); depth->next = NULL; } } } +} + +/** + * walk dependencies, showing dependencies of the target + */ +static void walk_deps(alpm_list_t *dblist, alpm_pkg_t *pkg, tdepth *depth, int rev, int optional) +{ + alpm_list_t *deps; + + if(!pkg || ((max_depth >= 0) && (depth->level > max_depth))) { + return; + } + + walked = alpm_list_add(walked, (void *)alpm_pkg_get_name(pkg)); + + if(rev) { + deps = alpm_pkg_compute_requiredby(pkg); + } else { + deps = get_pkg_deps(pkg); + } + + print_dep_list(deps, dblist, pkg, depth, rev, optional, 0); FREELIST(deps); + + if(optional){ + if(rev) { + deps = alpm_pkg_compute_optionalfor(pkg); + } else { + deps = get_pkg_optdeps(pkg); + } + + print_dep_list(deps, dblist, pkg, depth, rev, optional, 1); + + FREELIST(deps); + } } int main(int argc, char *argv[]) @@ -576,7 +644,7 @@ int main(int argc, char *argv[]) NULL, 1 }; - walk_deps(dblist, pkg, &d, reverse); + walk_deps(dblist, pkg, &d, reverse, opt_level); print_end();