Implementing 3rd-party bundle-list command

This commit introduces a new command to list bundles from all 3rd-party
repositories. At this point users cannot choose a specific repo to show
its bundles but rather all repos are shown.

Signed-off-by: Castulo Martinez <castulo.martinez@intel.com>
This commit is contained in:
Castulo Martinez
2019-12-05 15:44:51 -08:00
committed by Castulo J. Martinez
parent 068f52aa6d
commit be1573f064
11 changed files with 447 additions and 53 deletions
+1
View File
@@ -34,6 +34,7 @@ AM_CPPFLAGS = $(AM_CFLAGS) $(libarchive_CFLAGS)
swupd_SOURCES = \
src/3rd_party_add.c \
src/3rd_party_bundle_add.c \
src/3rd_party_bundle_list.c \
src/3rd_party.c \
src/3rd_party_list.c \
src/3rd_party_remove.c \
+16
View File
@@ -356,3 +356,19 @@
#skip_optional=<true/false>
[3rd-party-bundle-list]
#
# Options for the "swupd 3rd-party bundle-list" command
#
# List all available bundles for the current version of Clear
# Linux (boolean value)
#all=<true/false>
# List bundles included by BUNDLE (string value)
#deps=[BUNDLE]
# List dependency tree of all bundles which have BUNDLE as a
# dependency (string value)
#has_dep=[BUNDLE]
+1
View File
@@ -29,6 +29,7 @@ static struct subcmd third_party_commands[] = {
{ "remove", "Remove third party repository", third_party_remove_main },
{ "list", "List third party repository", third_party_list_main },
{ "bundle-add", "Install a bundle from a third party repository", third_party_bundle_add_main },
{ "bundle-list", "List bundles from a third party repository", third_party_bundle_list_main },
{ 0 }
};
+199
View File
@@ -0,0 +1,199 @@
/*
* Software Updater - client side
*
* Copyright © 2019 Intel Corporation.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 or later of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#define _GNU_SOURCE
#include "3rd_party_repos.h"
#include "swupd.h"
#ifdef THIRDPARTY
#define FLAG_DEPS 2000
static bool cmdline_local = true;
static bool cmdline_option_all = false;
static char *cmdline_option_has_dep = NULL;
static char *cmdline_option_deps = NULL;
static void free_has_dep(void)
{
free_string(&cmdline_option_has_dep);
}
static void free_deps(void)
{
free_string(&cmdline_option_deps);
}
static void print_help(void)
{
print("Usage:\n");
print(" swupd 3rd-party bundle-list [OPTIONS...]\n\n");
global_print_help();
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("\n");
}
static const struct option prog_opts[] = {
{ "all", no_argument, 0, 'a' },
{ "deps", required_argument, 0, FLAG_DEPS },
{ "has-dep", required_argument, 0, 'D' },
};
static bool parse_opt(int opt, char *optarg)
{
switch (opt) {
case 'a':
cmdline_option_all = optarg_to_bool(optarg);
cmdline_local = !cmdline_option_all;
return true;
case 'D':
string_or_die(&cmdline_option_has_dep, "%s", optarg);
atexit(free_has_dep);
cmdline_local = false;
return true;
case FLAG_DEPS:
string_or_die(&cmdline_option_deps, "%s", optarg);
atexit(free_deps);
cmdline_local = false;
return true;
default:
return false;
}
return false;
}
static const struct global_options opts = {
prog_opts,
sizeof(prog_opts) / sizeof(struct option),
parse_opt,
print_help,
};
static bool parse_options(int argc, char **argv)
{
int ind = global_parse_options(argc, argv, &opts);
if (ind < 0) {
return false;
}
if (argc > ind) {
error("unexpected arguments\n\n");
return false;
}
return true;
}
static void print_repo_header(const char *repo_name)
{
char *header = NULL;
int header_length;
string_or_die(&header, " 3rd-Party Repo: %s", repo_name);
header_length = strlen(header);
print_pattern("_", header_length + 1);
info("%s\n", header);
print_pattern("_", header_length + 1);
info("\n");
free_string(&header);
}
static enum swupd_code list_bundles(struct repo *repo)
{
enum swupd_code ret;
if (cmdline_local) {
ret = list_local_bundles(repo->version);
} else if (cmdline_option_deps != NULL) {
ret = show_included_bundles(cmdline_option_deps, repo->version);
} else if (cmdline_option_has_dep != NULL) {
ret = show_bundle_reqd_by(cmdline_option_has_dep, cmdline_option_all, repo->version);
} else {
ret = list_installable_bundles(repo->version);
}
info("\n");
return ret;
}
enum swupd_code third_party_bundle_list_main(int argc, char **argv)
{
struct list *repos = NULL;
struct list *iter = NULL;
char *state_dir;
char *path_prefix;
enum swupd_code ret;
const int steps_in_bundlelist = 1;
if (!parse_options(argc, argv)) {
print_help();
return SWUPD_INVALID_OPTION;
}
progress_init_steps("3rd-party-bundle-list", steps_in_bundlelist);
if (cmdline_local && !is_root()) {
ret = swupd_init(SWUPD_NO_ROOT);
} else {
ret = swupd_init(SWUPD_ALL);
}
if (ret != SWUPD_OK) {
error("Failed swupd initialization, exiting now\n");
goto finish;
}
/* load the existing 3rd-party repos from the repo.ini config file */
repos = third_party_get_repos();
/* backup the original state_dir and path_prefix values */
state_dir = strdup_or_die(globals.state_dir);
path_prefix = strdup_or_die(globals.path_prefix);
for (iter = repos; iter; iter = iter->next) {
struct repo *repo = iter->data;
/* set the appropriate content_dir and state_dir for the selected 3rd-party repo */
if (third_party_set_repo(state_dir, path_prefix, repo)) {
ret = SWUPD_COULDNT_CREATE_DIR;
goto clean_and_exit;
}
print_repo_header(repo->name);
ret = list_bundles(repo);
}
clean_and_exit:
free_string(&state_dir);
free_string(&path_prefix);
list_free_list_and_data(repos, repo_free_data);
swupd_deinit();
finish:
progress_finish_steps(ret);
return ret;
}
#endif
+33 -52
View File
@@ -118,7 +118,7 @@ static bool parse_options(int argc, char **argv)
* /usr/share/clear/bundles/), get the list of local bundles and print
* them sorted.
*/
static enum swupd_code list_local_bundles()
enum swupd_code list_local_bundles(int version)
{
char *name;
char *path = NULL;
@@ -126,22 +126,17 @@ static enum swupd_code list_local_bundles()
struct list *item = NULL;
struct manifest *MoM = NULL;
struct file *bundle_manifest = NULL;
int current_version;
bool mix_exists;
int count = 0;
current_version = get_current_version(globals.path_prefix);
if (current_version < 0) {
goto skip_mom;
if (version > 0) {
mix_exists = (check_mix_exists() & system_on_mix());
MoM = load_mom(version, mix_exists, NULL);
if (!MoM) {
warn("Could not determine which installed bundles are experimental\n\n");
}
}
mix_exists = (check_mix_exists() & system_on_mix());
MoM = load_mom(current_version, mix_exists, NULL);
if (!MoM) {
warn("Could not determine which installed bundles are experimental\n");
}
skip_mom:
string_or_die(&path, "%s/%s", globals.path_prefix, BUNDLES_DIR);
errno = 0;
@@ -181,25 +176,17 @@ skip_mom:
}
/* Return recursive list of included bundles */
static enum swupd_code show_included_bundles(char *bundle_name)
enum swupd_code show_included_bundles(char *bundle_name, int version)
{
int ret = 0;
int current_version = CURRENT_OS_VERSION;
struct list *subs = NULL;
struct list *deps = NULL;
struct manifest *mom = NULL;
int count = 0;
current_version = get_current_version(globals.path_prefix);
if (current_version < 0) {
error("Unable to determine current OS version\n");
ret = SWUPD_CURRENT_VERSION_UNKNOWN;
goto out;
}
mom = load_mom(current_version, false, NULL);
mom = load_mom(version, false, NULL);
if (!mom) {
error("Cannot load official manifest MoM for version %i\n", current_version);
error("Cannot load official manifest MoM for version %i\n", version);
ret = SWUPD_COULDNT_LOAD_MOM;
goto out;
}
@@ -283,24 +270,17 @@ out:
* Parse the full manifest for the current version of the OS and print
* all available bundles.
*/
static enum swupd_code list_installable_bundles()
enum swupd_code list_installable_bundles(int version)
{
char *name;
struct list *list;
struct file *file;
struct manifest *MoM = NULL;
int current_version;
int count;
int count = 0;
bool mix_exists;
current_version = get_current_version(globals.path_prefix);
if (current_version < 0) {
error("Unable to determine current OS version\n");
return SWUPD_CURRENT_VERSION_UNKNOWN;
}
mix_exists = (check_mix_exists() & system_on_mix());
MoM = load_mom(current_version, mix_exists, NULL);
MoM = load_mom(version, mix_exists, NULL);
if (!MoM) {
return SWUPD_COULDNT_LOAD_MOM;
}
@@ -322,10 +302,9 @@ static enum swupd_code list_installable_bundles()
return 0;
}
static enum swupd_code show_bundle_reqd_by(const char *bundle_name, bool server)
enum swupd_code show_bundle_reqd_by(const char *bundle_name, bool server, int version)
{
int ret = 0;
int version = CURRENT_OS_VERSION;
struct manifest *current_manifest = NULL;
struct list *subs = NULL;
struct list *reqd_by = NULL;
@@ -338,13 +317,6 @@ static enum swupd_code show_bundle_reqd_by(const char *bundle_name, bool server)
goto out;
}
version = get_current_version(globals.path_prefix);
if (version < 0) {
error("Unable to determine current OS version\n");
ret = SWUPD_CURRENT_VERSION_UNKNOWN;
goto out;
}
current_manifest = load_mom(version, false, NULL);
if (!current_manifest) {
error("Unable to download/verify %d Manifest.MoM\n", version);
@@ -411,7 +383,8 @@ out:
enum swupd_code bundle_list_main(int argc, char **argv)
{
int ret;
enum swupd_code ret;
int current_version;
const int steps_in_bundlelist = 1;
/* there is no need to report in progress for bundle-list at this time */
@@ -427,27 +400,35 @@ enum swupd_code bundle_list_main(int argc, char **argv)
} else {
ret = swupd_init(SWUPD_ALL);
}
/* if swupd fails to initialize, the only list command we can still attempt is
if (ret != SWUPD_OK) {
error("Failed swupd initialization, exiting now\n");
progress_finish_steps(ret);
return ret;
}
/* if we cannot get the current_version, the only list command we can still attempt is
* listing locally installed bundles (with the limitation of not showing what
* bundles are experimental) */
if (ret != 0) {
error("Failed updater initialization. Exiting now\n");
current_version = get_current_version(globals.path_prefix);
if (current_version < 0 && !cmdline_local) {
error("Unable to determine current OS version\n");
ret = SWUPD_CURRENT_VERSION_UNKNOWN;
goto finish;
}
if (cmdline_local) {
ret = list_local_bundles();
ret = list_local_bundles(current_version);
} else if (cmdline_option_deps != NULL) {
ret = show_included_bundles(cmdline_option_deps);
ret = show_included_bundles(cmdline_option_deps, current_version);
} else if (cmdline_option_has_dep != NULL) {
ret = show_bundle_reqd_by(cmdline_option_has_dep, cmdline_option_all);
ret = show_bundle_reqd_by(cmdline_option_has_dep, cmdline_option_all, current_version);
} else {
ret = list_installable_bundles();
ret = list_installable_bundles(current_version);
}
swupd_deinit();
finish:
swupd_deinit();
progress_finish_steps(ret);
return ret;
}
+6
View File
@@ -344,6 +344,12 @@ extern void verify_set_extra_files_only(bool opt);
/* repair.c */
extern regex_t *compile_whitelist(const char *whitelist_pattern);
/* bundle_list.c*/
extern enum swupd_code list_local_bundles(int version);
extern enum swupd_code list_installable_bundles(int version);
extern enum swupd_code show_included_bundles(char *bundle_name, int version);
extern enum swupd_code show_bundle_reqd_by(const char *bundle_name, bool server, int version);
/* telemetry.c */
typedef enum telem_prio_t {
TELEMETRY_DEBG = 1,
+1
View File
@@ -27,6 +27,7 @@ enum swupd_code bundle_info_main(int argc, char **argv);
enum swupd_code verify_main(int argc, char **argv);
enum swupd_code third_party_main(int argc, char **argv);
enum swupd_code third_party_bundle_add_main(int argc, char **argv);
enum swupd_code third_party_bundle_list_main(int argc, char **argv);
/**
* @brief Creates a new third-party repo under THIRDPARTY_REPO_PREFIX
+1 -1
View File
@@ -84,7 +84,7 @@ _swupd()
opts="$global --version --manifest --fix --picky --picky-tree --picky-whitelist --install --quick --force --install "
break;;
("3rd-party")
opts="$global add remove list bundle-add"
opts="$global add remove list bundle-add bundle-list "
break;;
("add")
opts="$global --repo"
+1
View File
@@ -191,6 +191,7 @@ if [[ -n "$state" ]]; then
'(help)remove[Remove third party repo]'
'(help)add[Add third party repo]'
'(help)bundle-add[Install a bundle from a third party repository]'
'(help)bundle-list[List bundles from a third party repository]'
_arguments $thirdparty && ret=0
;;
add)
+105
View File
@@ -0,0 +1,105 @@
#!/usr/bin/env bats
# Author: Castulo Martinez
# Email: castulo.martinez@intel.com
load "../testlib"
global_setup() {
create_test_environment "$TEST_NAME"
create_bundle -n test-bundle-upstream -f /file_upstream "$TEST_NAME"
# create a couple of 3rd-party repos with bundles
create_third_party_repo "$TEST_NAME" 10 staging repo1
create_bundle -n test-bundle1 -f /foo/file_1A -u repo1 "$TEST_NAME"
create_bundle -L -n test-bundle2 -f /bar/file_2 -u repo1 "$TEST_NAME"
create_third_party_repo "$TEST_NAME" 10 staging repo2
create_bundle -n test-bundle1 -f /baz/file_1B -u repo2 "$TEST_NAME"
create_bundle -L -n test-bundle3 -f /baz/file_3 -u repo2 "$TEST_NAME"
}
test_setup() {
return
}
test_teardown() {
return
}
global_teardown() {
destroy_test_environment "$TEST_NAME"
}
@test "TPR018: List installed 3rd-party bundles" {
# When a user list 3rd-party bundles without specifiying a repo, all
# installed bundles from 3rd-party repos should be shown
run sudo sh -c "$SWUPD 3rd-party bundle-list $SWUPD_OPTS"
assert_status_is "$SWUPD_OK"
expected_output=$(cat <<-EOM
_______________________
3rd-Party Repo: repo1
_______________________
Installed bundles:
- test-bundle2
Total: 1
_______________________
3rd-Party Repo: repo2
_______________________
Installed bundles:
- test-bundle3
Total: 1
EOM
)
assert_is_output --identical "$expected_output"
}
@test "TPR019: List all available 3rd-party bundles" {
# users should be able to list all 3rd-party bundles without specifiying a repo,
# all available bundles should be displayed
run sudo sh -c "$SWUPD 3rd-party bundle-list --all $SWUPD_OPTS"
assert_status_is "$SWUPD_OK"
expected_output=$(cat <<-EOM
_______________________
3rd-Party Repo: repo1
_______________________
All available bundles:
- test-bundle1
- test-bundle2
Total: 2
_______________________
3rd-Party Repo: repo2
_______________________
All available bundles:
- test-bundle1
- test-bundle3
Total: 2
EOM
)
assert_is_output --identical "$expected_output"
}
+83
View File
@@ -0,0 +1,83 @@
#!/usr/bin/env bats
# Author: Castulo Martinez
# Email: castulo.martinez@intel.com
load "../testlib"
global_setup() {
create_test_environment "$TEST_NAME"
# create a 3rd-party repo with bundles that have dependencies
create_third_party_repo "$TEST_NAME" 10 staging repo1
create_bundle -n test-bundle1 -f /foo/file_1 -u repo1 "$TEST_NAME"
create_bundle -n test-bundle2 -f /bar/file_2 -u repo1 "$TEST_NAME"
create_bundle -n test-bundle3 -f /baz/file_3 -u repo1 "$TEST_NAME"
create_bundle -n test-bundle4 -f /file_4 -u repo1 "$TEST_NAME"
create_bundle -n test-bundle5 -f /bat/file_5 -u repo1 "$TEST_NAME"
add_dependency_to_manifest "$TPWEBDIR"/10/Manifest.test-bundle2 test-bundle3
add_dependency_to_manifest "$TPWEBDIR"/10/Manifest.test-bundle3 test-bundle4
add_dependency_to_manifest "$TPWEBDIR"/10/Manifest.test-bundle2 test-bundle5
}
test_setup() {
return
}
test_teardown() {
return
}
global_teardown() {
destroy_test_environment "$TEST_NAME"
}
@test "TPR020: List dependencies of a 3rd-party bundle" {
run sudo sh -c "$SWUPD 3rd-party bundle-list $SWUPD_OPTS --deps test-bundle2"
assert_status_is "$SWUPD_OK"
expected_output=$(cat <<-EOM
_______________________
3rd-Party Repo: repo1
_______________________
Bundles included by test-bundle2:
- test-bundle3
- test-bundle4
- test-bundle5
Total: 3
EOM
)
assert_is_output --identical "$expected_output"
}
@test "TPR021: List all 3rd-party bundles that have a given bundle as dependency" {
run sudo sh -c "$SWUPD 3rd-party bundle-list $SWUPD_OPTS --has-dep test-bundle4 --all"
assert_status_is "$SWUPD_OK"
expected_output=$(cat <<-EOM
_______________________
3rd-Party Repo: repo1
_______________________
All bundles that have test-bundle4 as a dependency:
- test-bundle2
- test-bundle3
Total: 2
EOM
)
assert_is_output --identical "$expected_output"
}