Existing implementation silently returns when an abstract package (with
no real package to back it) is requested to be installed.
E.g., package 'a' recommends unknown package 'dne' but installing 'dne'
succeeds even though no operation has taken place.
This change makes sure an error is returned during such install
operations. A package is deemed unkonwn if it is absent from repos
'repo_installed', 'repo_available', 'repo_preferred', 'repo_to_install'.
Signed-off-by: Chaitanya Vadrevu <
chaitany...@ni.com>
---
libopkg/solvers/libsolv/opkg_solver_libsolv.c | 30 +++++++++++++++
tests/Makefile | 2 +
tests/core/45_install_preexisting.py | 34 +++++++++++++++++
tests/regress/issue14459.py | 37 +++++++++++++++++++
4 files changed, 103 insertions(+)
create mode 100644 tests/core/45_install_preexisting.py
create mode 100644 tests/regress/issue14459.py
diff --git a/libopkg/solvers/libsolv/opkg_solver_libsolv.c b/libopkg/solvers/libsolv/opkg_solver_libsolv.c
index 936bea7..d152174 100644
--- a/libopkg/solvers/libsolv/opkg_solver_libsolv.c
+++ b/libopkg/solvers/libsolv/opkg_solver_libsolv.c
@@ -90,6 +90,7 @@ int opkg_solver_install(int num_pkgs, char **pkg_names)
char *name, *version;
version_constraint_t constraint;
Dataiterator di;
+ int found_match;
libsolv_solver_t *solver = libsolv_solver_new();
if (solver == NULL)
@@ -102,6 +103,8 @@ int opkg_solver_install(int num_pkgs, char **pkg_names)
}
for (i = 0; i < num_pkgs; i++) {
+ found_match = 0;
+
strip_pkg_name_and_version(pkg_names[i], &name, &version, &constraint);
dataiterator_init(&di, solver->pool, solver->repo_available, 0,
@@ -109,6 +112,33 @@ int opkg_solver_install(int num_pkgs, char **pkg_names)
while (dataiterator_step(&di)) {
libsolv_solver_add_job(solver, JOB_INSTALL, di.kv.str, version, constraint);
dataiterator_skip_solvable(&di);
+ found_match = 1;
+ }
+
+ if (!found_match) {
+ /*
+ * pkg wasn't found in repo_available which would be ok if it is present in another repo
+ * such as repo_installed, repo_preferred or repo_to_install. But if not, then the user
+ * has asked to install an unknown package in which case we should error out.
+ */
+ int j;
+ found_match = 0;
+ Repo * repos_to_check[] = {solver->repo_installed, solver->repo_preferred, solver->repo_to_install};
+
+ for (j = 0; j < sizeof(repos_to_check)/sizeof(*repos_to_check); j++) {
+ dataiterator_init(&di, solver->pool, repos_to_check[j], 0,
+ SOLVABLE_NAME | SOLVABLE_PROVIDES, name, SEARCH_GLOB);
+ if (dataiterator_step(&di)) {
+ found_match = 1;
+ break;
+ }
+ }
+
+ if (!found_match) {
+ opkg_msg(ERROR, "No candidates to install %s %s!\n", name, version);
+ err = -1;
+ goto CLEANUP;
+ }
}
dataiterator_free(&di);
diff --git a/tests/Makefile b/tests/Makefile
index 9fba054..dd883c8 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -44,6 +44,7 @@ REGRESSION_TESTS := core/01_install.py \
core/42_info_description.py \
core/43_add_ignore_recommends.py \
core/44_search.py \
+ core/45_install_preexisting.py \
regress/issue26.py \
regress/issue31.py \
regress/issue32.py \
@@ -94,6 +95,7 @@ REGRESSION_TESTS := core/01_install.py \
regress/issue11826.py \
regress/issue13574.py \
regress/issue13758.py \
+ regress/issue14459.py \
misc/filehash.py \
misc/update_loses_autoinstalled_flag.py \
misc/version_comparisons.py
diff --git a/tests/core/45_install_preexisting.py b/tests/core/45_install_preexisting.py
new file mode 100644
index 0000000..53c75ce
--- /dev/null
+++ b/tests/core/45_install_preexisting.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Create package `a` which recommends `b`
+# Install `a`
+# Pkg 'a' and 'b' should have be installed
+# No error occurs when trying to install 'b' again.
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+o = opk.OpkGroup()
+
+o.add(Package='a', Recommends='b')
+o.add(Package='b')
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+
+rc, _ = opkgcl.opkgcl('install a')
+
+assert rc == 0, "Opkg failed when installing 'a'"
+
+if not opkgcl.is_installed('a'):
+ opk.fail("Package 'a' failed to install.")
+
+if not opkgcl.is_installed('b'):
+ opk.fail("Package 'b' (recommended by 'a') failed to install.")
+
+rc, _ = opkgcl.opkgcl('install b')
+
+assert rc == 0, "Opkg failed when installing 'b'"
diff --git a/tests/regress/issue14459.py b/tests/regress/issue14459.py
new file mode 100644
index 0000000..b99c21c
--- /dev/null
+++ b/tests/regress/issue14459.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Reporter: Rasmus Villemoes <
rasmus.v...@prevas.dk>
+#
+# What steps will reproduce the problem?
+########################################
+#
+# 1. pkg 'a' recommends pkg 'dne'
+# 2. pkg 'dne' does not exist in the feed
+# 3. ask opkg to `install a dne`
+#
+# What is the expected output? What do you see instead?
+########################################
+# Expected:
+# The opkg install operation should fail, and opkg should report that it cannot
+# find a package to satisfy 'dne'.
+# Actual:
+# The opkg install operation succeeds, with no indication that package 'dne' is
+# not satisfiable.
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+o = opk.OpkGroup()
+
+o.add(Package='a', Recommends='dne')
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+
+rc, stdout = opkgcl.opkgcl('install a dne')
+
+assert rc != 0, \
+ "Opkg install returned code 0; but package 'dne' should not be satisfiable."
--
2.17.1