File indexing completed on 2024-12-01 09:55:03
0001 /* 0002 SPDX-FileCopyrightText: 2007-2011 Aaron Seigo <aseigo@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef KPACKAGE_PACKAGE_H 0008 #define KPACKAGE_PACKAGE_H 0009 0010 #include <QCryptographicHash> 0011 #include <QMetaType> 0012 #include <QStringList> 0013 #include <QUrl> 0014 0015 #include <KPluginMetaData> 0016 0017 #include <kpackage/package_export.h> 0018 0019 #include <KJob> 0020 0021 namespace KPackage 0022 { 0023 /** 0024 * @class Package kpackage/package.h <KPackage/Package> 0025 * 0026 * @short object representing an installed package 0027 * 0028 * Package defines what is in a package and provides easy access to the contents. 0029 * 0030 * To define a package, one might write the following code: 0031 * 0032 @code 0033 Package package; 0034 0035 package.addDirectoryDefinition("images", "pics/"); 0036 QStringList mimeTypes; 0037 mimeTypes << "image/svg" << "image/png" << "image/jpeg"; 0038 package.setMimeTypes("images", mimeTypes); 0039 0040 package.addDirectoryDefinition("scripts", "code/"); 0041 mimeTypes.clear(); 0042 mimeTypes << "text/\*"; 0043 package.setMimeTypes("scripts", mimeTypes); 0044 0045 package.addFileDefinition("mainscript", "code/main.js"); 0046 package.setRequired("mainscript", true); 0047 @endcode 0048 * One may also choose to create a subclass of PackageStructure and include the setup 0049 * in the constructor. 0050 * 0051 * Either way, Package creates a self-documenting contract between the packager and 0052 * the application without exposing package internals such as actual on-disk structure 0053 * of the package or requiring that all contents be explicitly known ahead of time. 0054 * 0055 * Subclassing PackageStructure does have provide a number of potential const benefits: 0056 * * the package can be notified of path changes via the virtual pathChanged() method 0057 * * the subclass may implement mechanisms to install and remove packages using the 0058 * virtual install and uninstall methods 0059 * * subclasses can be compiled as plugins for easy re-use 0060 **/ 0061 // TODO: write documentation on USING a package 0062 0063 class PackagePrivate; 0064 class PackageStructure; 0065 0066 class KPACKAGE_EXPORT Package 0067 { 0068 public: 0069 /** 0070 * Error codes for the install/update/remove jobs 0071 * @since 5.17 0072 */ 0073 enum JobError { 0074 RootCreationError = KJob::UserDefinedError + 1, /**< Cannot create package root directory */ 0075 PackageFileNotFoundError, /**< The package file does not exist */ 0076 UnsupportedArchiveFormatError, /**< The archive format of the package is not supported */ 0077 PackageOpenError, /**< Can't open the package file for reading */ 0078 MetadataFileMissingError, /**< The package doesn't have a metadata.desktop file */ 0079 PluginNameMissingError, /**< The metadata.desktop file doesn't specify a plugin name */ 0080 PluginNameInvalidError, /**< The plugin name contains characters different from letters, digits, dots and underscores */ 0081 UpdatePackageTypeMismatchError, /**< A package with this plugin name was already installed, but has a different type in the metadata.desktop file */ 0082 OldVersionRemovalError, /**< Failed to remove the old version of the package during an upgrade */ 0083 NewerVersionAlreadyInstalledError, /**< We tried to update, but the same version or a newer one is already installed */ 0084 PackageAlreadyInstalledError, /**< The package is already installed and a normal install (not update) was performed */ 0085 PackageMoveError, /**< Failure to move a package from the system temporary folder to its final destination */ 0086 PackageCopyError, /**< Failure to copy a package folder from somewhere in the filesystem to its final destination */ 0087 PackageUninstallError, /**< Failure to uninstall a package */ 0088 }; 0089 0090 /** 0091 * Default constructor 0092 * 0093 * @param structure if a null pointer is passed in, this will creates an empty (invalid) Package; 0094 * otherwise the structure is allowed to set up the Package's initial layout 0095 * @since 4.6 0096 */ 0097 explicit Package(PackageStructure *structure = nullptr); 0098 0099 /** 0100 * Copy constructor 0101 * @since 4.6 0102 */ 0103 Package(const Package &other); 0104 0105 virtual ~Package(); 0106 0107 /** 0108 * Assignment operator 0109 * @since 4.6 0110 */ 0111 Package &operator=(const Package &rhs); 0112 0113 /** 0114 * @return true if this package has a valid PackageStructure associatedw it with it. 0115 * A package may not be valid, but have a valid structure. Useful when dealing with 0116 * Package objects in a semi-initialized state (e.g. before calling setPath()) 0117 * @since 5.1 0118 */ 0119 bool hasValidStructure() const; 0120 0121 /** 0122 * @return true if all the required components exist 0123 **/ 0124 bool isValid() const; 0125 0126 /** 0127 * Sets the path to the root of this package 0128 * @param path an absolute path, or a relative path to the default package root 0129 * @since 4.3 0130 */ 0131 void setPath(const QString &path); 0132 0133 /** 0134 * @return the path to the root of this particular package 0135 */ 0136 const QString path() const; 0137 0138 /** 0139 * Get the path to a given file based on the key and an optional filename. 0140 * Example: finding the main script in a scripting package: 0141 * filePath("mainscript") 0142 * 0143 * Example: finding a specific image in the images directory: 0144 * filePath("images", "myimage.png") 0145 * 0146 * @param key the key of the file type to look for, 0147 * @param filename optional name of the file to locate within the package 0148 * @return path to the file on disk. QString() if not found. 0149 **/ 0150 QString filePath(const QByteArray &key, const QString &filename = QString()) const; 0151 0152 /** 0153 * Get the url to a given file based on the key and an optional filename, is the file:// or qrc:// format 0154 * Example: finding the main script in a scripting package: 0155 * filePath("mainscript") 0156 * 0157 * Example: finding a specific image in the images directory: 0158 * filePath("images", "myimage.png") 0159 * 0160 * @param key the key of the file type to look for, 0161 * @param filename optional name of the file to locate within the package 0162 * @return path to the file on disk. QString() if not found. 0163 * @since 5.41 0164 **/ 0165 QUrl fileUrl(const QByteArray &key, const QString &filename = QString()) const; 0166 0167 /** 0168 * Get the list of files of a given type. 0169 * 0170 * @param fileType the type of file to look for, as defined in the 0171 * package structure. 0172 * @return list of files by name, suitable for passing to filePath 0173 **/ 0174 QStringList entryList(const QByteArray &key) const; 0175 0176 #if KPACKAGE_ENABLE_DEPRECATED_SINCE(5, 106) 0177 /** 0178 * @return user visible name for the given entry 0179 * @deprecated Since 5.106, deprecated for lack of usage 0180 **/ 0181 KPACKAGE_DEPRECATED_VERSION(5, 106, "deprecated for lack of usage") 0182 QString name(const QByteArray &key) const; 0183 #endif 0184 0185 /** 0186 * @return true if the item at path exists and is required 0187 **/ 0188 bool isRequired(const QByteArray &key) const; 0189 0190 /** 0191 * @return the mimeTypes associated with the path, if any 0192 **/ 0193 QStringList mimeTypes(const QByteArray &key) const; 0194 0195 /** 0196 * @return the prefix paths inserted between the base path and content entries, in order of priority. 0197 * When searching for a file, all paths will be tried in order. 0198 * @since 4.6 0199 */ 0200 QStringList contentsPrefixPaths() const; 0201 0202 /** 0203 * @return preferred package root. This defaults to kpackage/generic/ 0204 */ 0205 QString defaultPackageRoot() const; 0206 0207 /** 0208 * @return true if paths/symlinks outside the package itself should be followed. 0209 * By default this is set to false for security reasons. 0210 */ 0211 bool allowExternalPaths() const; 0212 0213 /** 0214 * Sets the metadata for the KPackage. This overwrites the current metadata. 0215 * This should be used in case a kpackage gets loaded by name, based 0216 * on the path a C++ plugin which has embedded metadata. 0217 * @since 5.88 0218 */ 0219 void setMetadata(const KPluginMetaData &data); 0220 0221 /** 0222 * @return the package metadata object. 0223 */ 0224 KPluginMetaData metadata() const; 0225 0226 #if KPACKAGE_ENABLE_DEPRECATED_SINCE(5, 21) 0227 /** 0228 * @return a SHA1 hash digest of the contents of the package in hexadecimal form 0229 * @since 4.4 0230 * @deprecated Since 5.21 use cryptographicHash 0231 */ 0232 KPACKAGE_DEPRECATED_VERSION(5, 21, "Use Package::cryptographicHash(QCryptographicHash::Algorithm)") 0233 QString contentsHash() const; 0234 #endif 0235 0236 /** 0237 * @return a hash digest of the contents of the package in hexadecimal form 0238 * @since 5.21 0239 */ 0240 QByteArray cryptographicHash(QCryptographicHash::Algorithm algorithm) const; 0241 0242 /** 0243 * Adds a directory to the structure of the package. It is added as 0244 * a not-required element with no associated mimeTypes. 0245 * 0246 * Starting in 4.6, if an entry with the given key 0247 * already exists, the path is added to it as a search alternative. 0248 * 0249 * @param key used as an internal label for this directory 0250 * @param path the path within the package for this directory 0251 * @param name the user visible (translated) name for the directory, since 5.106 this defaults to an empty string. In KF6, this parameter is removed 0252 **/ 0253 void addDirectoryDefinition(const QByteArray &key, const QString &path, const QString &name = QString()); 0254 0255 /** 0256 * Adds a file to the structure of the package. It is added as 0257 * a not-required element with no associated mimeTypes. 0258 * 0259 * Starting in 4.6, if an entry with the given key 0260 * already exists, the path is added to it as a search alternative. 0261 * 0262 * @param key used as an internal label for this file 0263 * @param path the path within the package for this file 0264 * @param name the user visible (translated) name for the file, since 5.106 this defaults to an empty string. In KF6, this parameter is removed 0265 **/ 0266 void addFileDefinition(const QByteArray &key, const QString &path, const QString &name = QString()); 0267 0268 /** 0269 * Removes a definition from the structure of the package. 0270 * @since 4.6 0271 * @param key the internal label of the file or directory to remove 0272 */ 0273 void removeDefinition(const QByteArray &key); 0274 0275 /** 0276 * Sets whether or not a given part of the structure is required or not. 0277 * The path must already have been added using addDirectoryDefinition 0278 * or addFileDefinition. 0279 * 0280 * @param key the entry within the package 0281 * @param required true if this entry is required, false if not 0282 */ 0283 void setRequired(const QByteArray &key, bool required); 0284 0285 /** 0286 * Defines the default mimeTypes for any definitions that do not have 0287 * associated mimeTypes. Handy for packages with only one or predominantly 0288 * one file type. 0289 * 0290 * @param mimeTypes a list of mimeTypes 0291 **/ 0292 void setDefaultMimeTypes(const QStringList &mimeTypes); 0293 0294 /** 0295 * Define mimeTypes for a given part of the structure 0296 * The path must already have been added using addDirectoryDefinition 0297 * or addFileDefinition. 0298 * 0299 * @param key the entry within the package 0300 * @param mimeTypes a list of mimeTypes 0301 **/ 0302 void setMimeTypes(const QByteArray &key, const QStringList &mimeTypes); 0303 0304 /** 0305 * Sets the prefixes that all the contents in this package should 0306 * appear under. This defaults to "contents/" and is added automatically 0307 * between the base path and the entries as defined by the package 0308 * structure. Multiple entries can be added. 0309 * In this case each file request will be searched in all prefixes in order, 0310 * and the first found will be returned. 0311 * 0312 * @param prefix paths the directory prefix to use 0313 * @since 4.6 0314 */ 0315 void setContentsPrefixPaths(const QStringList &prefixPaths); 0316 0317 /** 0318 * Sets whether or not external paths/symlinks can be followed by a package 0319 * @param allow true if paths/symlinks outside of the package should be followed, 0320 * false if they should be rejected. 0321 */ 0322 void setAllowExternalPaths(bool allow); 0323 0324 /** 0325 * Sets preferred package root. 0326 */ 0327 void setDefaultPackageRoot(const QString &packageRoot); 0328 0329 /** 0330 * Sets the fallback package root path 0331 * If a file won't be found in this package, it will search it in the package 0332 * with the same structure identified by path 0333 * It is intended to be used by the packageStructure 0334 * @param path package root path @see setPath 0335 */ 0336 void setFallbackPackage(const KPackage::Package &package); 0337 0338 /** 0339 * @return The fallback package root path 0340 */ 0341 KPackage::Package fallbackPackage() const; 0342 0343 // Content structure description methods 0344 /** 0345 * @return all directories registered as part of this Package's structure 0346 */ 0347 QList<QByteArray> directories() const; 0348 0349 /** 0350 * @return all directories registered as part of this Package's required structure 0351 */ 0352 QList<QByteArray> requiredDirectories() const; 0353 0354 /** 0355 * @return all files registered as part of this Package's structure 0356 */ 0357 QList<QByteArray> files() const; 0358 0359 /** 0360 * @return all files registered as part of this Package's required structure 0361 */ 0362 QList<QByteArray> requiredFiles() const; 0363 0364 /** 0365 * Installs a package matching this package structure. By default installs a 0366 * native KPackage::Package. 0367 * After the KJob will emitted finished(), if the install went well 0368 * the Package instance will be guaranteed to have loaded the package just 0369 * installed, and be valid and usable. 0370 * 0371 * @return KJob to track installation progress and result 0372 **/ 0373 KJob *install(const QString &sourcePackage, const QString &packageRoot = QString()); 0374 0375 /** 0376 * Updates a package matching this package structure. By default installs a 0377 * native KPackage::Package. If an older version is already installed, 0378 * it removes the old one. If the installed one is newer, 0379 * an error will occur. 0380 * After the KJob will emitted finished(), if the install went well 0381 * the Package instance will be guaranteed to have loaded the package just 0382 * updated, and be valid and usable. 0383 * 0384 * @return KJob to track installation progress and result 0385 * @since 5.17 0386 **/ 0387 KJob *update(const QString &sourcePackage, const QString &packageRoot = QString()); 0388 0389 /** 0390 * Uninstalls a package matching this package structure. 0391 * 0392 * @return KJob to track removal progress and result 0393 */ 0394 KJob *uninstall(const QString &packageName, const QString &packageRoot); 0395 0396 private: 0397 QExplicitlySharedDataPointer<PackagePrivate> d; 0398 friend class PackagePrivate; 0399 }; 0400 0401 } 0402 0403 Q_DECLARE_METATYPE(KPackage::Package) 0404 #endif