1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
4  *
5  * Most of this code was taken from Zif, libzif/zif-transaction.c
6  *
7  * Licensed under the GNU Lesser General Public License Version 2.1
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or(at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
22  */
23 
24 /**
25  * SECTION:dnf-goal
26  * @short_description: Helper methods for dealing with hawkey goals.
27  * @include: libdnf.h
28  * @stability: Unstable
29  *
30  * These methods make it easier to deal with hawkey goals.
31  */
32 
33 
34 #include <glib.h>
35 
36 #include "catch-error.hpp"
37 #include "hy-util.h"
38 #include "hy-goal-private.hpp"
39 #include "dnf-goal.h"
40 #include "dnf-package.h"
41 #include "hy-packageset-private.hpp"
42 #include "hy-iutil-private.hpp"
43 #include "dnf-context.hpp"
44 #include "dnf-sack-private.hpp"
45 #include "dnf-utils.h"
46 #include "utils/bgettext/bgettext-lib.h"
47 #include "../goal/Goal.hpp"
48 
49 #include <vector>
50 
51 /**
52  * dnf_goal_depsolve:
53  * @goal: a #HyGoal.
54  * @flags: some #DnfGoalActions to enable.
55  * @error: a #GError or %NULL
56  *
57  * Returns: %TRUE if depsolve is successful.
58  *
59  * Since: 0.7.0
60  */
61 gboolean
dnf_goal_depsolve(HyGoal goal,DnfGoalActions flags,GError ** error)62 dnf_goal_depsolve(HyGoal goal, DnfGoalActions flags, GError **error) try
63 {
64     gint cnt;
65     gint j;
66     gint rc;
67     g_autoptr(GString) string = NULL;
68 
69     DnfSack * sack = hy_goal_get_sack(goal);
70 
71     libdnf::Query query(sack);
72     const auto & protected_packages = libdnf::getGlobalMainConfig().protected_packages().getValue();
73     std::vector<const char *> cprotected_packages;
74     cprotected_packages.reserve(protected_packages.size() + 1);
75     for (const auto & package : protected_packages) {
76         cprotected_packages.push_back(package.c_str());
77     }
78     cprotected_packages.push_back(nullptr);
79     query.addFilter(HY_PKG_NAME, HY_EQ, cprotected_packages.data());
80     auto pkgset = *query.runSet();
81     goal->addProtected(pkgset);
82 
83     rc = hy_goal_run_flags(goal, flags);
84     if (rc) {
85         string = g_string_new(_("Could not depsolve transaction; "));
86         cnt = hy_goal_count_problems(goal);
87         g_string_append_printf(string, P_("%i problem detected:\n", "%i problems detected:\n", cnt),
88                                cnt);
89         for (j = 0; j < cnt; j++) {
90             auto tmp = goal->describeProblemRules(j, true);
91             bool first = true;
92             for (auto & iter: tmp) {
93                 if (first) {
94                     if (cnt != 1) {
95                         g_string_append_printf(string, _(" Problem %1$i: %2$s\n"), j + 1, iter.c_str());
96                     } else {
97                         g_string_append_printf(string, _(" Problem: %s\n"), iter.c_str());
98                     }
99                     first = false;
100                 } else {
101                     g_string_append_printf(string, "  - %s\n",  iter.c_str());
102                 }
103             }
104         }
105         g_string_truncate(string, string->len - 1);
106         g_set_error_literal(error,
107                             DNF_ERROR,
108                             DNF_ERROR_PACKAGE_CONFLICTS,
109                             string->str);
110         return FALSE;
111     }
112 
113     /* anything to do? */
114     if (hy_goal_req_length(goal) == 0) {
115         g_set_error_literal(error,
116                             DNF_ERROR,
117                             DNF_ERROR_NO_PACKAGES_TO_UPDATE,
118                             "The transaction was empty");
119         return FALSE;
120     }
121     auto moduleContainer = dnf_sack_get_module_container(sack);
122     if (moduleContainer) {
123         auto installSet = goal->listInstalls();
124         auto modulesToEnable = requiresModuleEnablement(sack, &installSet);
125         for (auto module: modulesToEnable) {
126             moduleContainer->enable(module->getName(), module->getStream());
127         }
128     }
129     return TRUE;
130 } CATCH_TO_GERROR(FALSE)
131 
132 /**
133  * dnf_goal_get_packages:
134  */
135 GPtrArray *
136 dnf_goal_get_packages(HyGoal goal, ...)
137 {
138     GPtrArray *array;
139     DnfPackage *pkg;
140     gint info_tmp;
141     guint i;
142     guint j;
143     va_list args;
144 
145     /* process the valist */
146     va_start(args, goal);
147     array = g_ptr_array_new_with_free_func((GDestroyNotify) g_object_unref);
148     for (j = 0;; j++) {
149         GPtrArray *pkglist = NULL;
150         info_tmp = va_arg(args, gint);
151         if (info_tmp == -1)
152             break;
153         switch(info_tmp) {
154         case DNF_PACKAGE_INFO_REMOVE:
155             pkglist = hy_goal_list_erasures(goal, NULL);
156             for (i = 0; i < pkglist->len; i++) {
157                 pkg = (DnfPackage*)g_ptr_array_index (pkglist, i);
158                 dnf_package_set_action(pkg, DNF_STATE_ACTION_REMOVE);
159                 g_ptr_array_add(array, g_object_ref(pkg));
160             }
161             break;
162         case DNF_PACKAGE_INFO_INSTALL:
163             pkglist = hy_goal_list_installs(goal, NULL);
164             for (i = 0; i < pkglist->len; i++) {
165                 pkg = (DnfPackage*)g_ptr_array_index (pkglist, i);
166                 dnf_package_set_action(pkg, DNF_STATE_ACTION_INSTALL);
167                 g_ptr_array_add(array, g_object_ref(pkg));
168             }
169             break;
170         case DNF_PACKAGE_INFO_OBSOLETE:
171             pkglist = hy_goal_list_obsoleted(goal, NULL);
172             for (i = 0; i < pkglist->len; i++) {
173                 pkg = (DnfPackage*)g_ptr_array_index (pkglist, i);
174                 dnf_package_set_action(pkg, DNF_STATE_ACTION_OBSOLETE);
175                 g_ptr_array_add(array, g_object_ref(pkg));
176             }
177             break;
178         case DNF_PACKAGE_INFO_REINSTALL:
179             pkglist = hy_goal_list_reinstalls(goal, NULL);
180             for (i = 0; i < pkglist->len; i++) {
181                 pkg = (DnfPackage*)g_ptr_array_index (pkglist, i);
182                 dnf_package_set_action(pkg, DNF_STATE_ACTION_REINSTALL);
183                 g_ptr_array_add(array, g_object_ref(pkg));
184             }
185             break;
186         case DNF_PACKAGE_INFO_UPDATE:
187             pkglist = hy_goal_list_upgrades(goal, NULL);
188             for (i = 0; i < pkglist->len; i++) {
189                 pkg = (DnfPackage*)g_ptr_array_index (pkglist, i);
190                 dnf_package_set_action(pkg, DNF_STATE_ACTION_UPDATE);
191                 g_ptr_array_add(array, g_object_ref(pkg));
192             }
193             break;
194         case DNF_PACKAGE_INFO_DOWNGRADE:
195             pkglist = hy_goal_list_downgrades(goal, NULL);
196             for (i = 0; i < pkglist->len; i++) {
197                 pkg = (DnfPackage*)g_ptr_array_index (pkglist, i);
198                 dnf_package_set_action(pkg, DNF_STATE_ACTION_DOWNGRADE);
199                 g_ptr_array_add(array, g_object_ref(pkg));
200             }
201             break;
202         default:
203             g_assert_not_reached();
204         }
205         g_ptr_array_unref(pkglist);
206     }
207     va_end(args);
208     return array;
209 }
210 
211 /**
212  * dnf_goal_add_protected:
213  * @goal: a #HyGoal.
214  * @pset: a #DnfPackageSet that would be added to the protected packages.
215  *
216  * Since: 0.7.0
217  */
218 void
dnf_goal_add_protected(HyGoal goal,DnfPackageSet * pset)219 dnf_goal_add_protected(HyGoal goal, DnfPackageSet *pset)
220 {
221     goal->addProtected(*pset);
222 }
223 
224 /**
225  * dnf_goal_set_protected:
226  * @goal: a #HyGoal.
227  * @pset: a #DnfPackageSet of protected packages (the previous setup will be overridden).
228  *
229  * Since: 0.7.0
230  */
231 void
dnf_goal_set_protected(HyGoal goal,DnfPackageSet * pset)232 dnf_goal_set_protected(HyGoal goal, DnfPackageSet *pset)
233 {
234     goal->setProtected(*pset);
235 }
236