Skip to content

Commit

Permalink
Implementing tree view for bundle-list --deps
Browse files Browse the repository at this point in the history
Sometimes is useful to see the list of dependencies in a tree view form,
for example when trying to remove bundles from a system.

This commit adds the ability of listing the dependencies of a bundle in
a tree view when --verbose is used.

Closes #929

Signed-off-by: Castulo Martinez <[email protected]>
  • Loading branch information
castulo committed Jan 8, 2020
1 parent 72896ce commit 1f61fb3
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 41 deletions.
4 changes: 2 additions & 2 deletions src/3rd_party_bundle_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ static void print_help(void)
print("Options:\n");
print(" -R, --repo Specify the 3rd-party repository to use\n");
print(" -a, --all List all available bundles for the current version of Clear Linux\n");
print(" -D, --has-dep=[BUNDLE] List all bundles which have BUNDLE as a dependency\n");
print(" --deps=[BUNDLE] List bundles included by BUNDLE\n");
print(" -D, --has-dep=[BUNDLE] List all bundles which have BUNDLE as a dependency (use --verbose for tree view)\n");
print(" --deps=[BUNDLE] List BUNDLE dependencies (use --verbose for tree view)\n");
print("\n");
}

Expand Down
38 changes: 20 additions & 18 deletions src/bundle_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ static void print_help(void)

print("Options:\n");
print(" -a, --all List all available bundles for the current version of Clear Linux\n");
print(" -D, --has-dep=[BUNDLE] List all bundles which have BUNDLE as a dependency\n");
print(" --deps=[BUNDLE] List bundles included by BUNDLE\n");
print(" -D, --has-dep=[BUNDLE] List all bundles which have BUNDLE as a dependency (use --verbose for tree view)\n");
print(" --deps=[BUNDLE] List BUNDLE dependencies (use --verbose for tree view)\n");
print("\n");
}

Expand Down Expand Up @@ -208,11 +208,12 @@ static enum swupd_code list_local_bundles(int version)
static enum swupd_code show_included_bundles(char *bundle_name, int version)
{
int ret = 0;
struct list *bundles = NULL;
struct list *subs = NULL;
struct list *iter = NULL;
struct manifest *mom = NULL;
struct sub *bundle_sub = NULL;
int count = 0;
bool verbose = (log_get_level() == LOG_INFO_VERBOSE);

progress_next_step("load_manifests", PROGRESS_UNDEFINED);
info("Loading required manifests...\n");
Expand All @@ -224,10 +225,8 @@ static enum swupd_code show_included_bundles(char *bundle_name, int version)
}

// add_subscriptions takes a list, so construct one with only bundle_name
struct list *bundles = NULL;
bundles = list_prepend_data(bundles, bundle_name);
ret = add_subscriptions(bundles, &subs, mom, true, 0);
list_free_list(bundles);
if (ret != add_sub_NEW) {
// something went wrong or there were no includes, print a message and exit
if (ret & add_sub_ERR) {
Expand Down Expand Up @@ -255,25 +254,28 @@ static enum swupd_code show_included_bundles(char *bundle_name, int version)

info("\nBundles included by %s:\n", bundle_name);

subs = list_sort(subs, subscription_sort_component);
iter = list_head(subs);
while (iter) {
bundle_sub = iter->data;
iter = iter->next;
// subs include the requested bundle, skip it
if (strcmp(bundle_name, bundle_sub->component) == 0) {
continue;
if (verbose) {
ret = subscription_get_tree(bundles, &subs, mom, true, 0);
} else {
subs = list_sort(subs, subscription_sort_component);
iter = list_head(subs);
while (iter) {
bundle_sub = iter->data;
iter = iter->next;
// subs include the requested bundle, skip it
if (strcmp(bundle_name, bundle_sub->component) == 0) {
continue;
}
info(" - ");
print("%s\n", bundle_sub->component);
}

info(" - ");
print("%s\n", bundle_sub->component);
count++;
}
info("\nTotal: %d\n", count);
info("\nTotal: %d\n", list_len(subs) - 1);

ret = SWUPD_OK;

out:
list_free_list(bundles);
manifest_free(mom);
free_subscriptions(&subs);

Expand Down
73 changes: 53 additions & 20 deletions src/subscriptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ void create_and_append_subscription(struct list **subs, const char *component)
2 new subscriptions
4 bad name given
*/
int add_subscriptions(struct list *bundles, struct list **subs, struct manifest *mom, bool find_all, int recursion)
static int recurse_subscriptions(struct list *bundles, struct list **subs, struct manifest *mom, bool find_all, int recursion, subs_fn_t subs_fn)
{
char *bundle;
int manifest_err;
Expand Down Expand Up @@ -214,37 +214,70 @@ int add_subscriptions(struct list *bundles, struct list **subs, struct manifest
goto out;
}

/*
* If we're recursing a tree of includes, we need to cut out early
* if the bundle we're looking at is already subscribed...
* Because if it is, we'll visit it soon anyway at the top level.
*
* We can't do this for the toplevel of the recursion because
* that is how we initiallly fill in the include tree.
*/
if (component_subscribed(*subs, bundle)) {
if (recursion > 0) {
manifest_free(manifest);
continue;
}
} else {
// Just add it to a list if it doesn't exist
create_and_append_subscription(subs, bundle);
ret |= add_sub_NEW; /* We have added at least one */
if (!subs_fn(subs, bundle, recursion)) {
/* nothing else to do with the current bundle */
manifest_free(manifest);
continue;
}

ret |= add_sub_NEW; /* We have gone through at least one bundle */

if (manifest->includes) {
/* merge in recursive call results */
ret |= add_subscriptions(manifest->includes, subs, mom, find_all, recursion + 1);
ret |= recurse_subscriptions(manifest->includes, subs, mom, find_all, recursion + 1, subs_fn);
}

if (!globals.skip_optional_bundles && manifest->optional) {
/* merge in recursive call results */
ret |= add_subscriptions(manifest->optional, subs, mom, find_all, recursion + 1);
ret |= recurse_subscriptions(manifest->optional, subs, mom, find_all, recursion + 1, subs_fn);
}

manifest_free(manifest);
}
out:
return ret;
}

static bool create_subscriptions(struct list **subs, const char *component, int recursion)
{
/*
* If we're recursing a tree of includes, we need to cut out early
* if the bundle we're looking at is already subscribed...
* Because if it is, we'll visit it soon anyway at the top level.
*
* We can't do this for the toplevel of the recursion because
* that is how we initiallly fill in the include tree.
*/
if (component_subscribed(*subs, (char *)component)) {
if (recursion > 0) {
return false;
}
}
create_and_append_subscription(subs, component);

return true;
}

static bool print_subscriptions_tree(UNUSED_PARAM struct list **subs, const char *component, int recursion)
{
int indent = 0;

if (recursion == 0) {
info("%*s* %s\n", 2, "", component);
} else {
indent = recursion * 4;
info("%*s|-- %s\n", indent, "", component);
}

return true;
}

int add_subscriptions(struct list *bundles, struct list **subs, struct manifest *mom, bool find_all, int recursion)
{
return recurse_subscriptions(bundles, subs, mom, find_all, recursion, create_subscriptions);
}

int subscription_get_tree(struct list *bundles, struct list **subs, struct manifest *mom, bool find_all, int recursion)
{
return recurse_subscriptions(bundles, subs, mom, find_all, recursion, print_subscriptions_tree);
}
2 changes: 2 additions & 0 deletions src/swupd.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,10 +317,12 @@ extern int link_or_rename(const char *orig, const char *dest);
extern int create_state_dirs(const char *state_dir_path);

/* subscription.c */
typedef bool (*subs_fn_t)(struct list **subs, const char *component, int recursion);
struct list *free_list_file(struct list *item);
extern void create_and_append_subscription(struct list **subs, const char *component);
extern char *get_tracking_dir(void);
extern int add_subscriptions(struct list *bundles, struct list **subs, struct manifest *mom, bool find_all, int recursion);
extern int subscription_get_tree(struct list *bundles, struct list **subs, struct manifest *mom, bool find_all, int recursion);
extern int subscription_bundlename_strcmp(const void *a, const void *b);
extern int subscription_sort_component(const void *a, const void *b);

Expand Down
23 changes: 22 additions & 1 deletion test/functional/bundlelist/list-deps-nested.bats
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ test_setup() {
@test "LST007: List bundle's dependencies when bundle has nested dependencies" {

run sudo sh -c "$SWUPD bundle-list $SWUPD_OPTS --deps test-bundle1"
assert_status_is 0

assert_status_is "$SWUPD_OK"
expected_output=$(cat <<-EOM
Loading required manifests...
Expand All @@ -31,3 +32,23 @@ test_setup() {
assert_is_output --identical "$expected_output"

}

@test "LST023: List bundle's dependencies (with nested deps) in a tree view" {

run sudo sh -c "$SWUPD bundle-list $SWUPD_OPTS --deps test-bundle1 --verbose"

assert_status_is "$SWUPD_OK"
expected_output=$(cat <<-EOM
Loading required manifests...
Bundles included by test-bundle1:
* test-bundle1
|-- test-bundle2
|-- test-bundle3
Total: 2
EOM
)
assert_is_output --identical "$expected_output"

}

0 comments on commit 1f61fb3

Please sign in to comment.