From 7dbc6b9ef1e54d8da9f7adc5872b6bf6e23ae5e3 Mon Sep 17 00:00:00 2001 From: Paolo Capriotti Date: Sun, 2 Dec 2007 12:04:57 +0000 Subject: [PATCH] Package refactoring as discussed on panel-devel. * Icon, preview, screenshot and release notes are gone. * Everything in a package (except metadata) is in the contents/ directory. * Package::createPackage and Package::installPackage cleanup. * Added Package::metadata method to retrieve a metadata object. svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=743935 --- package.cpp | 112 ++++++++++++++++------------------ package.h | 12 +++- packagemetadata.cpp | 58 ++---------------- packagemetadata.h | 44 +------------ tests/TODO | 10 +-- tests/packagemetadatatest.cpp | 24 -------- tests/packagemetadatatest.h | 3 - tests/plasmoidpackagetest.cpp | 71 ++++++++++++++++----- tests/plasmoidpackagetest.h | 1 + 9 files changed, 129 insertions(+), 206 deletions(-) diff --git a/package.cpp b/package.cpp index 0802a3c5b..0bd276444 100644 --- a/package.cpp +++ b/package.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -46,20 +47,24 @@ public: Private(const PackageStructure& st, const QString& p) : structure(st), basePath(p), - valid(QFile::exists(basePath)) + valid(QFile::exists(basePath)), + metadata(0) { if (valid && basePath[basePath.length() - 1] != '/') { basePath.append('/'); } - - structure.addFileDefinition("metadata", "metadata.desktop", - i18n("Package Meta Data File")); - structure.setRequired("metadata", true); + } + + ~Private() + { + delete metadata; } PackageStructure structure; QString basePath; bool valid; + PackageMetadata *metadata; + }; Package::Package(const QString& packageRoot, const QString& package, @@ -73,7 +78,6 @@ Package::Package(const QString &packagePath, const PackageStructure &structure) { } - Package::~Package() { delete d; @@ -86,14 +90,16 @@ bool Package::isValid() const } foreach (const char *dir, d->structure.requiredDirectories()) { - if (!QFile::exists(d->basePath + d->structure.path(dir))) { + if (!QFile::exists(d->basePath + "contents/" + d->structure.path(dir))) { + kWarning(505) << "Could not find required directory" << dir; d->valid = false; return false; } } foreach (const char *file, d->structure.requiredFiles()) { - if (!QFile::exists(d->basePath + d->structure.path(file))) { + if (!QFile::exists(d->basePath + "contents/" + d->structure.path(file))) { + kWarning(505) << "Could not find required file" << file; d->valid = false; return false; } @@ -114,7 +120,7 @@ QString Package::filePath(const char* fileType, const QString& filename) const return QString(); } - path.prepend(d->basePath); + path.prepend(d->basePath + "contents/"); if (!filename.isEmpty()) { path.append("/").append(filename); @@ -143,7 +149,7 @@ QStringList Package::entryList(const char* fileType) const return QStringList(); } - QDir dir(d->basePath + path); + QDir dir(d->basePath + "contents/" + path); if (!dir.exists()) { return QStringList(); @@ -152,6 +158,14 @@ QStringList Package::entryList(const char* fileType) const return dir.entryList(QDir::Files | QDir::Readable); } +const PackageMetadata *Package::metadata() const +{ + if (!d->metadata) { + d->metadata = new PackageMetadata(d->basePath + "metadata.desktop"); + } + return d->metadata; +} + //TODO: provide a version of this that allows one to ask for certain types of packages, etc? // should we be using KService here instead/as well? QStringList Package::knownPackages(const QString& packageRoot) // static @@ -184,16 +198,19 @@ bool Package::installPackage(const QString& package, if (!root.exists()) { KStandardDirs::makeDir(packageRoot); if (!root.exists()) { + kWarning(505) << "Could not create package root directory:" << packageRoot; return false; } } if (!QFile::exists(package)) { + kWarning(505) << "No such file:" << package; return false; } KZip archive(package); if (!archive.open(QIODevice::ReadOnly)) { + kWarning(505) << "Could not open package file:" << package; return false; } @@ -201,46 +218,43 @@ bool Package::installPackage(const QString& package, const KArchiveEntry* metadata = source->entry("metadata.desktop"); if (!metadata) { + kWarning(505) << "No metadata file in package" << package; return false; } QFile f(package); - QString tempdir = packageRoot + '/' + f.fileName(); - if (QFile::exists(tempdir)) { - return false; - } + KTempDir tempdir; + source->copyTo(tempdir.name()); - source->copyTo(tempdir); - - QString metadataPath = tempdir + "/metadata.desktop"; + QString metadataPath = tempdir.name() + "metadata.desktop"; if (!QFile::exists(metadataPath)) { - KIO::SimpleJob* job = KIO::file_delete(tempdir); - job->exec(); + kWarning(505) << "No metadata file in package" << package; return false; } PackageMetadata meta(metadataPath); QString targetName = meta.name(); if (targetName.isEmpty()) { - KIO::SimpleJob* job = KIO::file_delete(tempdir); - job->exec(); + kWarning(505) << "Package name not specified"; return false; } targetName = packageRoot + '/' + targetName; if (QFile::exists(targetName)) { - KIO::SimpleJob* job = KIO::file_delete(tempdir); - job->exec(); + kWarning(505) << targetName << "already exists"; return false; } - KIO::FileCopyJob* job = KIO::file_move(tempdir, targetName); + KIO::FileCopyJob* job = KIO::file_move(tempdir.name(), targetName, -1, + KIO::HideProgressInfo); if (!job->exec()) { - KIO::SimpleJob* job = KIO::file_delete(tempdir); - job->exec(); + kWarning(505) << "Could not move package to destination:" << targetName; return false; } + + // no need to remove the temp dir (which has been moved) + tempdir.setAutoRemove(false); // and now we register it as a service =) targetName.append("/metadata.desktop"); @@ -257,57 +271,35 @@ bool Package::installPackage(const QString& package, } service.append(pluginInfo.pluginName()).append(".desktop"); - job = KIO::file_copy(targetName, service); + job = KIO::file_copy(targetName, service, -1, KIO::HideProgressInfo); return job->exec(); } -bool Package::createPackage(const PackageMetadata & metadata, - const QString& source, - const QString& destination) +bool Package::createPackage(const PackageMetadata &metadata, + const QString &source, + const QString &destination, + const QString &icon) // static { if (!metadata.isComplete()) { - kWarning(550) << "Metadata file is not complete" ; + kWarning(550) << "Metadata file is not complete"; return false; } + // write metadata in a temporary file KTemporaryFile metadataFile; - metadataFile.open(); - metadata.write(metadataFile.fileName()); - - KTemporaryFile releaseNotes; - //We just write the content of the QString containing the metadata in an - //empty temporary file that we will package with the name metadata.desktop - if (releaseNotes.open()) { - QTextStream out(&releaseNotes); - if (!metadata.releaseNotes().isEmpty()) { - out << metadata.releaseNotes(); - } else { - out << "NO_RELEASE_NOTES"; - } + if (!metadataFile.open()) { + return false; } + metadata.write(metadataFile.fileName(), icon); - //OK, we've got the temporary file with the metadata in it. - //Now we just need to put everything into a zip archive. + // put everything into a zip archive KZip creation(destination); creation.setCompression(KZip::NoCompression); - if (!creation.open(QIODevice::WriteOnly)) { return false; } - + creation.addLocalFile(metadataFile.fileName(), "metadata.desktop"); - creation.addLocalFile(releaseNotes.fileName(), "notes.txt"); - - if (!metadata.icon().isEmpty()) { - //TODO: just one icon? - creation.addLocalFile(metadata.icon(), "icon.png"); - } - - if (!metadata.preview().isEmpty()) { - //TODO: just one icon? - creation.addLocalFile(metadata.preview(), "preview.png"); - } - creation.addLocalDirectory(source, "contents"); creation.close(); return true; diff --git a/package.h b/package.h index 3f6a2bfdb..f053bddc6 100644 --- a/package.h +++ b/package.h @@ -93,6 +93,11 @@ class PLASMA_EXPORT Package **/ QStringList entryList(const char* fileType) const; + /** + * @return the package metadata object. + */ + const PackageMetadata *metadata() const; + /** * Returns a list of all installed packages * @@ -123,12 +128,13 @@ class PLASMA_EXPORT Package * @arg metadata description of the package to create * @arg source path to local directory containing the individual * files to be added to the package - * @arg destination path to local directory where the package should - * be created + * @arg destination path to the package that should be created + * @arg icon path to the package icon **/ static bool createPackage(const PackageMetadata &metadata, const QString &source, - const QString &destination); + const QString &destination, + const QString &icon = QString()); private: Q_DISABLE_COPY(Package) diff --git a/packagemetadata.cpp b/packagemetadata.cpp index c3b831cf4..aa85804e7 100644 --- a/packagemetadata.cpp +++ b/packagemetadata.cpp @@ -30,10 +30,6 @@ namespace Plasma class PackageMetadata::Private { public: - Private() - : screenshot("screenshot.png") - {} - QString name; QString description; QString author; @@ -44,10 +40,6 @@ class PackageMetadata::Private QString mainFile; QString app; QString requiredVersion; - QString releaseNotes; - QString icon; - QString screenshot; - QString preview; QString type; QString serviceType; }; @@ -78,7 +70,7 @@ bool PackageMetadata::isComplete() const d->type.isEmpty()); } -void PackageMetadata::write(const QString& filename) const +void PackageMetadata::write(const QString &filename, const QString &icon) const { KConfig cfg(filename); KConfigGroup config(&cfg, "Desktop Entry"); @@ -87,8 +79,9 @@ void PackageMetadata::write(const QString& filename) const //TODO: this will be a problem for localized names? config.writeEntry("Name", d->name); config.writeEntry("Description", d->description); - config.writeEntry("Icon", d->icon); - config.writeEntry("X-KDE-Screenshot", d->screenshot); + if (!icon.isNull()) { + config.writeEntry("Icon", icon); + } config.writeEntry("X-KDE-ServiceTypes", d->serviceType); config.writeEntry("X-KDE-PluginInfo-Name", d->name); config.writeEntry("X-KDE-PluginInfo-Author", d->author); @@ -110,8 +103,6 @@ void PackageMetadata::read(const QString& filename) //TODO: this will be a problem for localized names? d->name = config.readEntry("X-KDE-PluginInfo-Name", d->name); d->description = config.readEntry("Description", d->description); - d->icon = config.readEntry("Icon", d->icon); - d->screenshot= config.readEntry("X-KDE-Screenshot", d->screenshot); d->serviceType = config.readEntry("X-KDE-ServiceTypes", d->serviceType); d->author = config.readEntry("X-KDE-PluginInfo-Author", d->author); d->email = config.readEntry("X-KDE-PluginInfo-Email", d->email); @@ -179,26 +170,6 @@ QString PackageMetadata::requiredVersion() const return d->requiredVersion; } -QString PackageMetadata::releaseNotes() const -{ - return d->releaseNotes; -} - -QString PackageMetadata::icon() const -{ - return d->icon; -} - -QString PackageMetadata::screenshot() const -{ - return d->screenshot; -} - -QString PackageMetadata::preview() const -{ - return d->preview; -} - QString PackageMetadata::type() const { return d->type; @@ -248,6 +219,7 @@ void PackageMetadata::setMainFile(const QString &mainFile) { d->mainFile = mainFile; } + void PackageMetadata::setApplication(const QString &application) { d->app = application; @@ -258,26 +230,6 @@ void PackageMetadata::setRequiredVersion(const QString &requiredVersion) d->requiredVersion = requiredVersion; } -void PackageMetadata::setReleaseNotes(const QString &releaseNotes) -{ - d->releaseNotes = releaseNotes; -} - -void PackageMetadata::setIcon(const QString &icon) -{ - d->icon = icon; -} - -void PackageMetadata::setScreenshot(const QString & screenshot) -{ - d->screenshot = screenshot; -} - -void PackageMetadata::setPreview(const QString& path) -{ - d->preview = path; -} - void PackageMetadata::setType(const QString& type) { d->type = type; diff --git a/packagemetadata.h b/packagemetadata.h index 3ac031d64..8341f94ee 100644 --- a/packagemetadata.h +++ b/packagemetadata.h @@ -52,8 +52,9 @@ public: * @see KPluginInfo * * @arg filename path to the file to write to + * @arg icon path to the package icon **/ - void write(const QString& filename) const; + void write(const QString& filename, const QString &icon = QString()) const; /** * Reads in metadata from a file, which should be a .desktop @@ -63,7 +64,7 @@ public: * * @arg filename path to the file to write to **/ - void read(const QString& filename); + void read(const QString &filename); QString name() const; QString description() const; @@ -76,24 +77,6 @@ public: QString mainFile() const; QString application() const; QString requiredVersion() const; - QString releaseNotes() const; - QString filenameToSave() const; - // filename - QString icon() const; - - /** - * @return the name of the screenshot file, screenshot.png by default - */ - QString screenshot() const; - - /** - * Path to a PNG file containing a preview image. - * This might be a screenshot, for instance. - * - * @return path to a local image file, or QString() if no - * preview is available - **/ - QString preview() const; QString type() const; @@ -108,27 +91,6 @@ public: void setMainFile(const QString &); void setApplication(const QString &); void setRequiredVersion(const QString &); - void setReleaseNotes(const QString &); - void setFilenameToSave(const QString &); - // filename - void setIcon(const QString &); - - /** - * Sets the name of the screenshot file. - * - * @param file the name of the file - */ - void setScreenshot(const QString &file); - - /** - * Sets the path for the file containing a preview image. - * This might be a screenshot, for instance. - * A PNG is expected. - * - * @args path path to the preview image file - **/ - void setPreview(const QString & path); - void setType(const QString& type); private: diff --git a/tests/TODO b/tests/TODO index 215e6fea9..07007c424 100644 --- a/tests/TODO +++ b/tests/TODO @@ -2,14 +2,10 @@ This file enumerates which classes and methods needs test. Please feel free to add a specific test you'd like to see for a class/method. // Finished (as in has test for each method) +package +packagemetadata packagestructure -// Work in progress. Enumerated methods don't have tests yet. -Package: - - knownPackages - - installPackage - - createPackage - // No tests written atm. abstractrunner animator @@ -23,8 +19,6 @@ datacontainer_p dataengine dataenginemanager glapplet -package -packagemetadata packages_p phase plasma_export diff --git a/tests/packagemetadatatest.cpp b/tests/packagemetadatatest.cpp index cb22a6565..223eaaaf3 100644 --- a/tests/packagemetadatatest.cpp +++ b/tests/packagemetadatatest.cpp @@ -59,12 +59,6 @@ void PackageMetadataTest::removeDir(const QString &subdir) local.rmpath(subd); } -void PackageMetadataTest::screenshot() -{ - // Defealt value - QCOMPARE(pm->screenshot(), QString("screenshot.png")); -} - void PackageMetadataTest::read() { pm->read("packagemetadatatest.desktop"); @@ -82,8 +76,6 @@ void PackageMetadataTest::read() QCOMPARE(pm->mainFile(), QString("Main file")); QCOMPARE(pm->application(), QString("A Test name")); QCOMPARE(pm->requiredVersion(), QString("1.2.3")); - QCOMPARE(pm->icon(), QString("test")); - QCOMPARE(pm->screenshot(), QString("a_not_default_file.svg")); QCOMPARE(pm->type(), QString("System test")); } @@ -100,7 +92,6 @@ void PackageMetadataTest::write() pm->setMainFile(QString("Main file")); pm->setApplication(QString("A Test name")); pm->setRequiredVersion(QString("1.2.3")); - pm->setIcon(QString("test")); pm->write("somefile.desktop"); delete pm; @@ -118,21 +109,6 @@ void PackageMetadataTest::write() QCOMPARE(pm->mainFile(), QString("Main file")); QCOMPARE(pm->application(), QString("A Test name")); QCOMPARE(pm->requiredVersion(), QString("1.2.3")); - QCOMPARE(pm->icon(), QString("test")); -} - -void PackageMetadataTest::preview() -{ - QCOMPARE(pm->preview(), QString()); - pm->setPreview("Test"); - QCOMPARE(pm->preview(), QString("Test")); -} - -void PackageMetadataTest::releaseNotes() -{ - QCOMPARE(pm->releaseNotes(), QString()); - pm->setReleaseNotes("Test"); - QCOMPARE(pm->releaseNotes(), QString("Test")); } QTEST_KDEMAIN(PackageMetadataTest, NoGUI) diff --git a/tests/packagemetadatatest.h b/tests/packagemetadatatest.h index 4dba43b63..fcb0fc9e4 100644 --- a/tests/packagemetadatatest.h +++ b/tests/packagemetadatatest.h @@ -32,11 +32,8 @@ public Q_SLOTS: void cleanup(); private Q_SLOTS: - void screenshot(); void read(); void write(); - void preview(); - void releaseNotes(); private: void removeDir(const QString &subdir); diff --git a/tests/plasmoidpackagetest.cpp b/tests/plasmoidpackagetest.cpp index be80b05b5..c66b2ee87 100644 --- a/tests/plasmoidpackagetest.cpp +++ b/tests/plasmoidpackagetest.cpp @@ -21,6 +21,9 @@ #include #include +#include + +#include "plasma/packagemetadata.h" #include "plasma/packages.cpp" @@ -45,8 +48,9 @@ void PlasmoidPackageTest::cleanup() QDir local = QDir::homePath() + QLatin1String("/.kde-unit-test/packageRoot/"); foreach(const QString &dir, local.entryList(QDir::Dirs)) { - removeDir(QLatin1String("packageRoot/" + dir.toLatin1() + "/code")); - removeDir(QLatin1String("packageRoot/" + dir.toLatin1() + "/images")); + removeDir(QLatin1String("packageRoot/" + dir.toLatin1() + "/contents/code")); + removeDir(QLatin1String("packageRoot/" + dir.toLatin1() + "/contents/images")); + removeDir(QLatin1String("packageRoot/" + dir.toLatin1() + "/contents")); removeDir(QLatin1String("packageRoot/" + dir.toLatin1())); } @@ -92,10 +96,10 @@ void PlasmoidPackageTest::createTestPackage(const QString &packageName) file.close(); // Create the code dir. - QVERIFY(QDir().mkpath(mPackageRoot + "/" + packageName + "/code")); + QVERIFY(QDir().mkpath(mPackageRoot + "/" + packageName + "/contents/code")); // Create the main file. - file.setFileName(mPackageRoot + "/" + packageName + "/code/main"); + file.setFileName(mPackageRoot + "/" + packageName + "/contents/code/main"); QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text)); out << "THIS IS A PLASMOID SCRIPT....."; @@ -106,8 +110,8 @@ void PlasmoidPackageTest::createTestPackage(const QString &packageName) // files to it for test purposes. // Create the images dir. - QVERIFY(QDir().mkpath(mPackageRoot + "/" + packageName + "/images")); - file.setFileName(mPackageRoot + "/" + packageName + "/images/image-1.svg"); + QVERIFY(QDir().mkpath(mPackageRoot + "/" + packageName + "/contents/images")); + file.setFileName(mPackageRoot + "/" + packageName + "/contents/images/image-1.svg"); QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text)); @@ -115,7 +119,7 @@ void PlasmoidPackageTest::createTestPackage(const QString &packageName) file.flush(); file.close(); - file.setFileName(mPackageRoot + "/" + packageName + "/images/image-2.svg"); + file.setFileName(mPackageRoot + "/" + packageName + "/contents/images/image-2.svg"); QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text)); @@ -148,12 +152,14 @@ void PlasmoidPackageTest::isValid() QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text)); QTextStream out(&file); - out << "This is a metadatafile"; + out << "[Desktop Entry]\n"; + out << "Name=test\n"; + out << "Description=Just a test desktop file"; file.flush(); file.close(); // Create the code dir. - QVERIFY(QDir().mkpath(mPackageRoot + "/" + mPackage + "/code")); + QVERIFY(QDir().mkpath(mPackageRoot + "/" + mPackage + "/contents/code")); // No main file yet so should still be invalid. delete p; @@ -161,7 +167,7 @@ void PlasmoidPackageTest::isValid() QVERIFY(!p->isValid()); // Create the main file. - file.setFileName(mPackageRoot + "/" + mPackage + "/code/main"); + file.setFileName(mPackageRoot + "/" + mPackage + "/contents/code/main"); QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text)); out.setDevice(&file); @@ -184,8 +190,8 @@ void PlasmoidPackageTest::filePath() QCOMPARE(p->filePath("scripts", "main"), QString()); - QVERIFY(QDir().mkpath(mPackageRoot + "/" + mPackage + "/code")); - QFile file(mPackageRoot + "/" + mPackage + "/code/main"); + QVERIFY(QDir().mkpath(mPackageRoot + "/" + mPackage + "/contents/code")); + QFile file(mPackageRoot + "/" + mPackage + "/contents/code/main"); QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text)); QTextStream out(&file); @@ -197,7 +203,7 @@ void PlasmoidPackageTest::filePath() delete p; p = new Plasma::Package(mPackageRoot, mPackage, *ps); - QString path = mPackageRoot + "/" + mPackage + "/code/main"; + QString path = mPackageRoot + "/" + mPackage + "/contents/code/main"; // Two ways to get the same info. // 1. Give the file type which refers to a class of files (a directory) in @@ -285,7 +291,44 @@ void PlasmoidPackageTest::metadata() QString path = mPackageRoot + '/' + plasmoid + "/metadata.desktop"; p = new Plasma::Package(mPackageRoot, plasmoid, *ps); - QCOMPARE(p->filePath("metadata"), path); + const Plasma::PackageMetadata *metadata = p->metadata(); + QVERIFY(metadata); + QCOMPARE(metadata->name(), plasmoid); +} + +void PlasmoidPackageTest::createAndInstallPackage() +{ + QString plasmoid("plasmoid_to_package"); + createTestPackage(plasmoid); + + QString packagePath = mPackageRoot + '/' + "package.zip"; + Plasma::PackageMetadata metadata( + QString(KDESRCDIR) + "/packagemetadatatest.desktop"); + QVERIFY(Plasma::Package::createPackage(metadata, + mPackageRoot + '/' + plasmoid + "/contents", + packagePath)); + QVERIFY(QFile::exists(packagePath)); + + KZip package(packagePath); + QVERIFY(package.open(QIODevice::ReadOnly)); + const KArchiveDirectory *dir = package.directory(); + QVERIFY(dir); + QVERIFY(dir->entry("metadata.desktop")); + const KArchiveEntry *contentsEntry = dir->entry("contents"); + QVERIFY(contentsEntry); + QVERIFY(contentsEntry->isDirectory()); + const KArchiveDirectory *contents = + static_cast(contentsEntry); + QVERIFY(contents->entry("code")); + QVERIFY(contents->entry("images")); + + Plasma::Package::installPackage(packagePath, mPackageRoot); + QString installedPackage = mPackageRoot + "/test"; + + QVERIFY(QFile::exists(installedPackage)); + + p = new Plasma::Package(installedPackage, *ps); + QVERIFY(p->isValid()); } QTEST_KDEMAIN(PlasmoidPackageTest, NoGUI) diff --git a/tests/plasmoidpackagetest.h b/tests/plasmoidpackagetest.h index 492d71a6d..ccf9d28ad 100644 --- a/tests/plasmoidpackagetest.h +++ b/tests/plasmoidpackagetest.h @@ -37,6 +37,7 @@ private Q_SLOTS: void entryList(); void knownPackages(); void metadata(); + void createAndInstallPackage(); private: void removeDir(const QString &subdir);