1 /*
2  * Copyright (C) 2018 Red Hat, Inc.
3  *
4  * Licensed under the GNU Lesser General Public License Version 2.1
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #ifndef LIBDNF_MODULEPACKAGECONTAINER_HPP
22 #define LIBDNF_MODULEPACKAGECONTAINER_HPP
23 
24 #include "libdnf/dnf-utils.h"
25 #include "ModulePackage.hpp"
26 #include "libdnf/nsvcap.hpp"
27 
28 #include <map>
29 #include <memory>
30 #include <string>
31 #include <vector>
32 #include <set>
33 #include <stdexcept>
34 
35 namespace libdnf {
36 
37 struct ModulePackageContainer
38 {
39 public:
40     enum class ModuleState {
41         UNKNOWN,
42         ENABLED,
43         DISABLED,
44         DEFAULT,
45         INSTALLED
46     };
47 
48     enum class ModuleErrorType {
49         NO_ERROR = 0,
50         INFO,
51         /// Error in module defaults detected during resolvement of module dependencies
52         ERROR_IN_DEFAULTS,
53         /// Error detected during resolvement of module dependencies
54         ERROR,
55         /// Error detected during resolvement of module dependencies - Unexpected error!!!
56         CANNOT_RESOLVE_MODULES,
57         CANNOT_RESOLVE_MODULE_SPEC,
58         CANNOT_ENABLE_MULTIPLE_STREAMS,
59         CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE,
60         /// Problem with latest modules during resolvement of module dependencies
61         ERROR_IN_LATEST
62     };
63 
64     struct Exception : public std::runtime_error
65     {
Exceptionlibdnf::ModulePackageContainer::Exception66         explicit Exception(const std::string &what) : runtime_error(what) {}
67     };
68 
69     struct NoModuleException : public Exception
70     {
NoModuleExceptionlibdnf::ModulePackageContainer::NoModuleException71         explicit NoModuleException(const std::string &moduleName) : Exception("No such module: " + moduleName) {}
72     };
73 
74     struct NoStreamException : public Exception
75     {
NoStreamExceptionlibdnf::ModulePackageContainer::NoStreamException76         explicit NoStreamException(const std::string &moduleStream) : Exception("No such stream: " + moduleStream) {}
77     };
78 
79     struct EnabledStreamException : public Exception
80     {
EnabledStreamExceptionlibdnf::ModulePackageContainer::EnabledStreamException81         explicit EnabledStreamException(const std::string &moduleName) : Exception("No enabled stream for module: " + moduleName) {}
82     };
83 
84     struct EnableMultipleStreamsException : public Exception
85     {
86         explicit EnableMultipleStreamsException(const std::string & moduleName);
87     };
88 
89     struct ConflictException : public Exception
90     {
ConflictExceptionlibdnf::ModulePackageContainer::ConflictException91         explicit ConflictException(const std::string &what) : Exception(what) {}
92     };
93 
94     struct ResolveException : public Exception
95     {
ResolveExceptionlibdnf::ModulePackageContainer::ResolveException96         explicit ResolveException(const std::string &what) : Exception(what) {}
97     };
98 
99     explicit ModulePackageContainer(bool allArch, std::string installRoot, const char * arch,
100                                     const char * persistDir = nullptr);
101     ~ModulePackageContainer();
102 
103     void add(const std::string & fileContent, const std::string & repoID);
104 
105     /**
106      * @brief Can raise ModulePackageContainer::ConflictException
107      *
108      */
109     void add(DnfSack * sack);
110 
111     /**
112      * @brief Can raise ModulePackageContainer::ConflictException
113      *
114      */
115     void addDefaultsFromDisk();
116     void moduleDefaultsResolve();
117     Id addPlatformPackage(const std::string &osReleasePath, const char *  platformModule);
118     Id addPlatformPackage(DnfSack * sack,
119         const std::vector<std::string> & osReleasePath, const char * platformModule);
120     /// DEPRECATED
121     void createConflictsBetweenStreams();
122 
123     /**
124      * @brief Return true if no module package in container
125      *
126      * @return bool
127      */
128     bool empty() const noexcept;
129 
130     /**
131     * @brief Can throw std::out_of_range exception
132     */
133     ModulePackage * getModulePackage(Id id);
134     std::vector<ModulePackage *> getModulePackages();
135     std::vector<std::vector<std::vector<ModulePackage *>>> getLatestModulesPerRepo(
136         ModuleState moduleFilter, std::vector<ModulePackage *> modulePackages);
137 
138     /**
139     * @brief Return all latest ModulePackages for each module Name, stream, context and architecture. In case of
140     * multiple latest packages, all will be returned. When activeOnly is true, it returns only the latest active
141     * packages.
142     *
143     * @return std::vector<ModulePackage *>
144     */
145     std::vector<ModulePackage *> getLatestModules(const std::vector<ModulePackage *> modulePackages, bool activeOnly);
146 
147     ModulePackage * getLatestModule(std::vector<ModulePackage *> modulePackages, bool activeOnly);
148 
149     std::vector<ModulePackage *> requiresModuleEnablement(const libdnf::PackageSet & packages);
150 
151     /**
152     * @brief Enable module stream. Return true if requested change realy triggers a change in
153     * the persistor.
154     * When the count parameter is set to false the change will not count towards the limit of
155     * module state modifications.
156     * It can throw ModulePackageContainer::EnableMultipleStreamsException or
157     * ModulePackageContainer::NoModuleException exceprion if module do not exist
158     *
159     * @return bool
160     */
161     bool enable(const std::string &name, const std::string &stream, const bool count = true);
162 
163     /**
164     * @brief Enable module stream. Return true if requested changes realy triggers a change in
165     * the persistor.
166     * When the count parameter is set to false the change will not count towards the limit of
167     * module state modifications.
168     * It can throw ModulePackageContainer::EnableMultipleStreamsException or
169     * ModulePackageContainer::NoModuleException exceprion if module do not exist
170     *
171     * @return bool
172     */
173     bool enable(const ModulePackage * module, const bool count = true);
174     /**
175      * @brief unmark module 'name' from any streams
176      * When the count parameter is set to false the change will not count towards the limit of
177      * module state modifications.
178      */
179     void disable(const std::string & name, const bool count = true);
180     void disable(const ModulePackage * module, const bool count = true);
181     /**
182      * @brief Reset module state so it's no longer enabled or disabled.
183      * When the count parameter is set to false the change will not count towards the limit of
184      * module state modifications.
185      */
186     void reset(const std::string &name, const bool count = true);
187     void reset(const ModulePackage * module, const bool count = true);
188     /**
189      * @brief add profile to name:stream
190      */
191     void install(const std::string &name, const std::string &stream, const std::string &profile);
192     void install(const ModulePackage * module, const std::string &profile);
193     /**
194      * @brief remove profile from name:stream
195      */
196     void uninstall(const std::string &name, const std::string &stream, const std::string &profile);
197     void uninstall(const ModulePackage * module, const std::string &profile);
198     /**
199      * @brief commit module changes to storage
200      */
201     void save();
202     /**
203      * @brief discard all module changes and revert to storage state
204      */
205     void rollback();
206     /**
207      * @brief Are there any changes to be saved?
208      */
209     bool isChanged();
210 
211     bool isEnabled(const std::string &name, const std::string &stream);
212     bool isEnabled(const ModulePackage * module);
213 
214     bool isDisabled(const std::string &name);
215     bool isDisabled(const ModulePackage * module);
216     ModuleState getModuleState(const std::string & name);
217     std::set<std::string> getInstalledPkgNames();
218 
219     std::string getReport();
220 
221     /**
222     * @brief Get configured default profiles for module stream
223     */
224     std::vector<std::string> getDefaultProfiles(std::string moduleName, std::string moduleStream);
225 
226     /**
227      * @brief Get configured default stream for a module
228      */
229     const std::string & getDefaultStream(const std::string &name) const;
230 
231     /**
232      * @brief get enabled stream for a module
233      */
234     const std::string & getEnabledStream(const std::string &name);
235 
236     /**
237      * @brief list of name:stream for module streams that are to be enable
238      */
239     std::map<std::string, std::string> getEnabledStreams();
240 
241     /**
242      * @brief list of names of modules that are to be disabled
243      */
244     std::vector<std::string> getDisabledModules();
245 
246     /**
247      * @brief list of name:stream for module streams that are to be disabled
248      * "Will be removed after 2019-12-31. Use getDisabledModules() instead."
249      */
250     DEPRECATED("Will be removed after 2019-12-31. Use getDisabledModules() instead.")
251     std::map<std::string, std::string> getDisabledStreams();
252 
253     /**
254      * @brief list of names of modules that are to be reset
255      */
256     std::vector<std::string> getResetModules();
257 
258     /**
259      * @brief list of name:stream for module streams that are to be reset
260      * "Will be removed after 2019-12-31. Use getResetModules() instead."
261      */
262     DEPRECATED("Will be removed after 2019-12-31. Use getResetModules() instead.")
263     std::map<std::string, std::string> getResetStreams();
264     /**
265      * @brief list of name:<old_stream:new_stream> for modules whose stream has changed
266      */
267     std::map<std::string, std::pair<std::string, std::string>> getSwitchedStreams();
268     /**
269      * @brief list of name:[profiles] for module profiles being added
270      */
271     std::map<std::string, std::vector<std::string>> getInstalledProfiles();
272 
273     /**
274      * @brief list of installed profiles for module name
275      */
276     std::vector<std::string> getInstalledProfiles(std::string moduleName);
277     /**
278      * @brief list of name:[profiles] for module profiles being removed
279      */
280     std::map<std::string, std::vector<std::string>> getRemovedProfiles();
281     /**
282     * @brief Query modules according libdnf::Nsvcap. But the search ignores profiles
283     *
284     */
285     std::vector<ModulePackage *> query(libdnf::Nsvcap & moduleNevra);
286     /**
287     * @brief Requiers subject in format <name>, <name>:<stream>, or <name>:<stream>:<contex>
288     *
289     * @param subject p_subject:...
290     * @return std::vector<ModulePackage *>
291     */
292     std::vector<ModulePackage *> query(std::string subject);
293     std::vector<ModulePackage *> query(std::string name, std::string stream,
294         std::string version, std::string context, std::string arch);
295     void enableDependencyTree(std::vector<ModulePackage *> & modulePackages);
296     std::pair<std::vector<std::vector<std::string>>, ModulePackageContainer::ModuleErrorType> resolveActiveModulePackages(bool debugSolver);
297     bool isModuleActive(Id id);
298     bool isModuleActive(const ModulePackage * modulePackage);
299     void loadFailSafeData();
300     void updateFailSafeData();
301     void applyObsoletes();
302 
303 private:
304     class Impl;
305     std::unique_ptr<Impl> pImpl;
306 };
307 
308 }
309 
310 #endif //LIBDNF_MODULEPACKAGECONTAINER_HPP
311