aboutsummaryrefslogtreecommitdiff
path: root/xbmc/addons/AddonRepos.h
blob: 4284674f01146fb818d9668b92de1623c50959e5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/*
 *  Copyright (C) 2005-2020 Team Kodi
 *  This file is part of Kodi - https://kodi.tv
 *
 *  SPDX-License-Identifier: GPL-2.0-or-later
 *  See LICENSES/README.md for more information.
 */

#pragma once

#include "addons/AddonDatabase.h"

#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>

namespace ADDON
{

class CAddonVersion;
class CAddonMgr;
class CRepository;
class IAddon;
enum class AddonCheckType : bool;

enum class CheckAddonPath
{
  CHOICE_YES = true,
  CHOICE_NO = false,
};

using AddonWithUpdate = std::pair<std::shared_ptr<IAddon>, std::shared_ptr<IAddon>>;

/**
 * Class - CAddonRepos
 * Reads information about installed official/third party repos and their contained add-ons from the database.
 * Used to check for updates for installed add-ons and dependencies while obeying permission rules.
 * Note that this class is not responsible for refreshing the repo data stored in the database.
 */
class CAddonRepos
{
public:
  CAddonRepos(); // load all add-ons from all installed repositories
  explicit CAddonRepos(const std::string& addonId); // load a specific add-on id only
  explicit CAddonRepos(const std::shared_ptr<IAddon>& repoAddon); // load add-ons of a specific repo

  /*!
   * \brief Build the list of addons to be updated depending on defined rules
   *        or the list of outdated addons
   * \param installed vector of all addons installed on the system that are
   *        checked for an update
   * \param[in] addonCheckType build list of OUTDATED or UPDATES
   * \param[out] result list of addon versions that are going to be installed
   *             or are outdated
   */
  void BuildUpdateOrOutdatedList(const std::vector<std::shared_ptr<IAddon>>& installed,
                                 std::vector<std::shared_ptr<IAddon>>& result,
                                 AddonCheckType addonCheckType) const;

  /*!
   * \brief Build the list of outdated addons and their available updates.
   * \param installed vector of all addons installed on the system that are
   *        checked for an update
   * \param[out] addonsWithUpdate target map
   */
  void BuildAddonsWithUpdateList(const std::vector<std::shared_ptr<IAddon>>& installed,
                                 std::map<std::string, AddonWithUpdate>& addonsWithUpdate) const;

  /*!
   * \brief Checks if the origin-repository of a given addon is defined as official repo
   *        and can also verify if the origin-path (e.g. https://mirrors.kodi.tv ...)
   *        is matching
   * \note if this function is called on locally installed add-ons, for instance when populating
   *       'My add-ons', the local installation path is returned as origin.
   *       thus parameter CheckAddonPath::CHOICE_NO needs to be passed in such cases
   * \param addon pointer to addon to be checked
   * \param checkAddonPath also check origin path
   * \return true if the repository id of a given addon is defined as official
   *         and the addons origin matches the defined official origin of the repo id
   */
  static bool IsFromOfficialRepo(const std::shared_ptr<IAddon>& addon,
                                 CheckAddonPath checkAddonPath);

  /*!
   * \brief Checks if the passed in repository is defined as official repo
   *        which includes ORIGIN_SYSTEM
   * \param repoId repository id to check
   * \return true if the repository id is defined as official, false otherwise
   */
  static bool IsOfficialRepo(const std::string& repoId);

  /*!
   * \brief Check if an update is available for a single addon
   * \param addon that is checked for an update
   * \param[out] update pointer to the found update
   * \return true if an installable update was found, false otherwise
   */
  bool DoAddonUpdateCheck(const std::shared_ptr<IAddon>& addon,
                          std::shared_ptr<IAddon>& update) const;

  /*!
   * \brief Retrieves the latest version of an addon from all installed repositories
   *        follows addon origin restriction rules
   * \param addonId addon id we're looking the latest version for
   * \param[out] addon pointer to the found addon
   * \return true if a version was found, false otherwise
   */
  bool GetLatestAddonVersionFromAllRepos(const std::string& addonId,
                                         std::shared_ptr<IAddon>& addon) const;

  /*!
   * \brief Retrieves the latest official versions of addons to vector.
   *        Private versions are added obeying updateMode.
   *        (either OFFICIAL_ONLY or ANY_REPOSITORY)
   * \param[out] addonList retrieved addon list in a vector
   */
  void GetLatestAddonVersions(std::vector<std::shared_ptr<IAddon>>& addonList) const;

  /*!
   * \brief Retrieves the latest official versions of addons to vector.
   *        Private versions (latest per repository) are added obeying updateMode.
   *        (either OFFICIAL_ONLY or ANY_REPOSITORY)
   * \param[out] addonList retrieved addon list in a vector
   */
  void GetLatestAddonVersionsFromAllRepos(std::vector<std::shared_ptr<IAddon>>& addonList) const;

  /*!
   * \brief Find a dependency to install during an addon install or update
   *        If the dependency cannot be found in official versions we look in the
   *        installing/updating addon's (the parent's) origin repository
   * \param dependsId addon id of the dependency we're looking for
   * \param parentRepoId origin repository of the dependee
   * \param [out] dependencyToInstall pointer to the found dependency, only use
   *              if function returns true
   * \param [out] repoForDep the repository that dependency will install from finally
   * \return true if the dependency was found, false otherwise
   */
  bool FindDependency(const std::string& dependsId,
                      const std::string& parentRepoId,
                      std::shared_ptr<IAddon>& dependencyToInstall,
                      std::shared_ptr<CRepository>& repoForDep) const;

  /*!
   * \brief Find a dependency addon in the repository of its parent
   * \param dependsId addon id of the dependency we're looking for
   * \param parentRepoId origin repository of the dependee
   * \param [out] dependencyToInstall pointer to the found dependency, only use
   *              if function returns true
   * \return true if the dependency was found, false otherwise
   */
  bool FindDependencyByParentRepo(const std::string& dependsId,
                                  const std::string& parentRepoId,
                                  std::shared_ptr<IAddon>& dependencyToInstall) const;

  /*!
   * \brief Build compatible versions list based on the contents of m_allAddons
   * \note content of m_allAddons depends on the preceding call to @ref LoadAddonsFromDatabase()
   * \param[out] compatibleVersions target vector to be filled
   */
  void BuildCompatibleVersionsList(std::vector<std::shared_ptr<IAddon>>& compatibleVersions) const;

  /*!
   * \brief Return whether add-ons repo/version information was properly loaded after construction
   * \return true on success, false otherwise
   */
  bool IsValid() const { return m_valid; }

private:
  /*!
   * \brief Load and configure add-on maps
   * \return true on success, false otherwise
   */
  bool LoadAddonsFromDatabase(const std::string& addonId, const std::shared_ptr<IAddon>& repoAddon);

  /*!
   * \brief Looks up an addon in a given repository map and
   *        checks if an update is available
   * \param addonToCheck the addon we want to find and version check
   * \param map the repository map we want to check against
   * \param[out] pointer to the found update. if the addon is
   *              up-to-date on our system, this param will return 'nullptr'
   * \return true if the addon was found in the desired map and
   *         its version is newer than our local version.
   *         false if the addon does NOT exist in the map or it is up to date.
   */
  bool FindAddonAndCheckForUpdate(const std::shared_ptr<IAddon>& addonToCheck,
                                  const std::map<std::string, std::shared_ptr<IAddon>>& map,
                                  std::shared_ptr<IAddon>& update) const;

  /*!
   * \brief Adds the latest version of an addon to the desired map
   * \param addonToAdd the addon whose latest version should be added
   * \param map target map, e.g. latestOfficialVersions or latestPrivateVersions
   */
  void AddAddonIfLatest(const std::shared_ptr<IAddon>& addonToAdd,
                        std::map<std::string, std::shared_ptr<IAddon>>& map) const;

  /*!
   * \brief Adds the latest version of an addon to the desired map per repository
   *        used to populate 'latestVersionsByRepo'
   * \param repoId the repository that addon comes from
   * \param addonToAdd the addon whose latest version should be added
   * \param map target map, latestVersionsByRepo
   */
  void AddAddonIfLatest(
      const std::string& repoId,
      const std::shared_ptr<IAddon>& addonToAdd,
      std::map<std::string, std::map<std::string, std::shared_ptr<IAddon>>>& map) const;

  /*!
   * \brief Looks up an addon entry in a specific map
   * \param addonId addon we want to retrieve
   * \param map the map we're looking into for the wanted addon
   * \param[out] addon pointer to the found addon, only use when function returns true
   * \return true if the addon was found in the map, false otherwise
   */
  bool GetLatestVersionByMap(const std::string& addonId,
                             const std::map<std::string, std::shared_ptr<IAddon>>& map,
                             std::shared_ptr<IAddon>& addon) const;

  const CAddonMgr& m_addonMgr;
  CAddonDatabase m_addonDb;
  bool m_valid{false};

  std::vector<std::shared_ptr<IAddon>> m_allAddons;

  std::map<std::string, std::shared_ptr<IAddon>> m_latestOfficialVersions;
  std::map<std::string, std::shared_ptr<IAddon>> m_latestPrivateVersions;
  std::map<std::string, std::map<std::string, std::shared_ptr<IAddon>>> m_latestVersionsByRepo;
  std::map<std::string, std::multimap<std::string, std::shared_ptr<IAddon>>> m_addonsByRepoMap;
};

}; /* namespace ADDON */