diff options
-rw-r--r-- | doc/reference/modules/freedesktop-module.qdoc | 141 | ||||
-rw-r--r-- | share/qbs/modules/freedesktop/FreeDesktop.qbs | 124 | ||||
-rw-r--r-- | share/qbs/modules/freedesktop/freedesktop.js | 69 | ||||
-rw-r--r-- | tests/auto/blackbox/testdata/freedesktop/freedesktop.qbs | 25 | ||||
-rw-r--r-- | tests/auto/blackbox/testdata/freedesktop/main.cpp | 4 | ||||
-rw-r--r-- | tests/auto/blackbox/testdata/freedesktop/myapp.appdata.xml | 15 | ||||
-rw-r--r-- | tests/auto/blackbox/testdata/freedesktop/myapp.desktop | 4 | ||||
-rw-r--r-- | tests/auto/blackbox/testdata/freedesktop/myapp.png | 0 | ||||
-rw-r--r-- | tests/auto/blackbox/tst_blackbox.cpp | 33 | ||||
-rw-r--r-- | tests/auto/blackbox/tst_blackbox.h | 1 |
10 files changed, 416 insertions, 0 deletions
diff --git a/doc/reference/modules/freedesktop-module.qdoc b/doc/reference/modules/freedesktop-module.qdoc new file mode 100644 index 000000000..48c95a0e0 --- /dev/null +++ b/doc/reference/modules/freedesktop-module.qdoc @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Alberto Mardegan +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \contentspage index.html + \qmltype freedesktop + \inqmlmodule QbsModules + \since Qbs 1.16 + + \brief Provides support for some freedesktop.org specifications. + + The \c freedesktop module contains properties and rules for building and working with + applications compliant to freedesktop.org specifications on UNIX platforms. + The areas in which this module can be of use include: + + \list + \li Creation or post-processing of + \l{https://specifications.freedesktop.org/desktop-entry-spec/latest/}{\c{.desktop} + files} + \li Installation of \l{https://www.freedesktop.org/software/appstream/docs/chap-Metadata.html}{AppStream} metadata + \li Defining the location for + \l{https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html#directory_layout} + {application icons} + \endlist + + This module is available on all platforms but is currently only useful on UNIX platforms. + + \section2 Example usage + \target example-freedesktop + + \code + Application { + ... + Depends { name: "freedesktop" } + + Group { + files: [ + ... + + // Declare the desktop and appstream files + "data/my-app.desktop", + "data/my-app.metainfo.xml", + ] + } + + // Add/change some fields in the desktop file + freedesktop.desktopKeys: ({ + 'Exec': FileInfo.joinPaths(qbs.installPrefix, + product.installDir, + product.targetName) + ' --argument', + 'X-Application-Version': product.version, + }) + + // Declare the application icon + Group { + files: "icons/my-application.svg" + fileTags: "freedesktop.appIcon" + } + } + \endcode + + \section2 Relevant File Tags + \target filetags-freedesktop + + \table + \header + \li Tag + \li Auto-tagged File Names + \li Since + \li Description + \row + \li \c{"freedesktop.desktopfile_source"} + \li \c{*.desktop} + \li 1.16 + \li A source file with this tag is a \c{.desktop} file or fragment that + will be merged into the application's final \c{.desktop} file. + \row + \li \c{"freedesktop.desktopfile"} + \li - + \li 1.16 + \li Attached to the output artifacts of the rule that produces the + merged \c{.desktop} file. + \row + \li \c{"freedesktop.appstream"} + \li \c{*.metainfo.xml}, \c{*.appdata.xml} + \li 1.16 + \li Source files with this tag are AppStream metadata files which will + be installed under \l{qbs::}{installPrefix}\c{/share/metainfo} + \row + \li \c{"freedesktop.appIcon"} + \li - + \li 1.16 + \li Source files with this tag are application icons and will be + installed under \l{qbs::}{installPrefix}\c{/share/icons/hicolor/scalable/apps} + \endtable +*/ + +/*! + \qmlproperty string freedesktop::name + + The display name of the application which will be stored in the \c{.desktop} file. + + \defaultvalue \l{Product::name}{product.name} +*/ + +/*! + \qmlproperty var freedesktop::desktopKeys + + A dictionary of key-value pairs to add to the application's \c{.desktop} + file. + + The contents of this property will be aggregated with the values from any + \c{.desktop} file. If this property and any \c{.desktop} files contain the + same key, this property will take precedence. + + \nodefaultvalue +*/ diff --git a/share/qbs/modules/freedesktop/FreeDesktop.qbs b/share/qbs/modules/freedesktop/FreeDesktop.qbs new file mode 100644 index 000000000..bb2ba79f4 --- /dev/null +++ b/share/qbs/modules/freedesktop/FreeDesktop.qbs @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Alberto Mardegan <mardy@users.sourceforge.net> +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +import qbs +import qbs.ModUtils +import qbs.TextFile +import "freedesktop.js" as Fdo + +Module { + id: fdoModule + + property string name: product.name + + property var desktopKeys + + readonly property var defaultDesktopKeys: { + return { + 'Type': 'Application', + 'Name': product.freedesktop.name, + 'Exec': product.targetName, + 'Terminal': 'false', + 'Version': '1.1', + } + } + property bool _fdoSupported: qbs.targetOS.contains("unix") && !qbs.targetOS.contains("darwin") + + additionalProductTypes: "freedesktop.desktopfile" + + FileTagger { + patterns: [ "*.desktop" ] + fileTags: [ "freedesktop.desktopfile_source" ] + } + + Rule { + condition: _fdoSupported + + inputs: [ "freedesktop.desktopfile_source" ] + outputFileTags: [ "freedesktop.desktopfile" ] + + Artifact { + fileTags: [ "freedesktop.desktopfile" ] + filePath: input.fileName + } + + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = input.fileName + "->" + output.fileName; + cmd.highlight = "codegen"; + cmd.sourceCode = function() { + var aggregateDesktopKeys = Fdo.parseDesktopFile(input.filePath); + var desktopKeys = ModUtils.moduleProperty(product, "desktopKeys") || {} + var mainSection = aggregateDesktopKeys['Desktop Entry']; + for (key in desktopKeys) { + if (desktopKeys.hasOwnProperty(key)) { + mainSection[key] = desktopKeys[key]; + } + } + + var defaultValues = product.freedesktop.defaultDesktopKeys + for (key in defaultValues) { + if (!(key in mainSection)) { + mainSection[key] = defaultValues[key]; + } + } + + Fdo.dumpDesktopFile(output.filePath, aggregateDesktopKeys); + } + return [cmd]; + } + } + + Group { + condition: fdoModule._fdoSupported + fileTagsFilter: [ "freedesktop.desktopfile" ] + qbs.install: true + qbs.installDir: "share/applications" + } + + Group { + condition: fdoModule._fdoSupported + fileTagsFilter: [ "freedesktop.appIcon" ] + qbs.install: true + qbs.installDir: "share/icons/hicolor/scalable/apps" + } + + FileTagger { + patterns: [ "*.metainfo.xml", "*.appdata.xml" ] + fileTags: [ "freedesktop.appstream" ] + } + + Group { + condition: fdoModule._fdoSupported + fileTagsFilter: [ "freedesktop.appstream" ] + qbs.install: true + qbs.installDir: "share/metainfo" + } +} diff --git a/share/qbs/modules/freedesktop/freedesktop.js b/share/qbs/modules/freedesktop/freedesktop.js new file mode 100644 index 000000000..d3c60b191 --- /dev/null +++ b/share/qbs/modules/freedesktop/freedesktop.js @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Alberto Mardegan <mardy@users.sourceforge.net> +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +var TextFile = require("qbs.TextFile"); + +function parseDesktopFile(filePath) { + var file = new TextFile(filePath); + var fileValues = {}; + var currentSection = {}; + var sectionRex = /\[(.+)\]/g; + while (!file.atEof()) { + var line = file.readLine().trim(); + if (line.length == 0) continue; + if (line[0] == '#') continue; + var match = sectionRex.exec(line); + if (match) { + var currentSectionName = match[1]; + fileValues[currentSectionName] = {}; + currentSection = fileValues[currentSectionName]; + continue; + } + var parts = line.split('=', 2); + currentSection[parts[0]] = parts[1] + } + file.close(); + return fileValues +} + +function dumpDesktopFile(filePath, keys) { + var file = new TextFile(filePath, TextFile.WriteOnly); + for (var sectionName in keys) { + file.writeLine('[' + sectionName + ']'); + var section = keys[sectionName]; + for (var key in section) { + var line = key + '=' + section[key]; + file.writeLine(line); + } + // Write an empty line between sections (and before EOF) + file.writeLine(''); + } + file.close(); +} diff --git a/tests/auto/blackbox/testdata/freedesktop/freedesktop.qbs b/tests/auto/blackbox/testdata/freedesktop/freedesktop.qbs new file mode 100644 index 000000000..60c3d304f --- /dev/null +++ b/tests/auto/blackbox/testdata/freedesktop/freedesktop.qbs @@ -0,0 +1,25 @@ +import qbs 1.0 + +Project { + CppApplication { + name: "main" + install: true + files: [ + "main.cpp", + "myapp.desktop", + "myapp.appdata.xml", + ] + + Depends { name: "freedesktop" } + + freedesktop.name: "My App" + freedesktop.desktopKeys: ({ + 'Icon': "myapp.png" + }) + + Group { + files: "myapp.png" + fileTags: "freedesktop.appIcon" + } + } +} diff --git a/tests/auto/blackbox/testdata/freedesktop/main.cpp b/tests/auto/blackbox/testdata/freedesktop/main.cpp new file mode 100644 index 000000000..905869dfa --- /dev/null +++ b/tests/auto/blackbox/testdata/freedesktop/main.cpp @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} diff --git a/tests/auto/blackbox/testdata/freedesktop/myapp.appdata.xml b/tests/auto/blackbox/testdata/freedesktop/myapp.appdata.xml new file mode 100644 index 000000000..3cf0a5641 --- /dev/null +++ b/tests/auto/blackbox/testdata/freedesktop/myapp.appdata.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<component type="desktop"> + <id>myapp.desktop</id> + <metadata_license>CC0</metadata_license> + <name>MyApp</name> + <summary>The coolest app ever</summary> + + <description> + <p>This is a cool application.</p> + </description> + + <url type="homepage">https://software.house/myapp</url> + <project_license>GPL-2.0+</project_license> + <developer_name>Coding Wizard</developer_name> +</component> diff --git a/tests/auto/blackbox/testdata/freedesktop/myapp.desktop b/tests/auto/blackbox/testdata/freedesktop/myapp.desktop new file mode 100644 index 000000000..dac3014c3 --- /dev/null +++ b/tests/auto/blackbox/testdata/freedesktop/myapp.desktop @@ -0,0 +1,4 @@ +[Desktop Entry] +GenericName=Image Editor +Comment=Create images and edit photographs +Icon=overridden.png diff --git a/tests/auto/blackbox/testdata/freedesktop/myapp.png b/tests/auto/blackbox/testdata/freedesktop/myapp.png new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/auto/blackbox/testdata/freedesktop/myapp.png diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index 66b4f8675..876d6239e 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -3771,6 +3771,39 @@ void TestBlackbox::fileTagsFilterMerging() QVERIFY2(QFile::exists(otherOutput), qPrintable(otherOutput)); } +void TestBlackbox::freedesktop() +{ + if (!HostOsInfo::isAnyUnixHost() || HostOsInfo::isMacosHost()) + QSKIP("only applies on Unix"); + + QDir::setCurrent(testDataDir + "/freedesktop"); + QCOMPARE(runQbs(), 0); + + // Check desktop file + QString desktopFilePath = + defaultInstallRoot + "/usr/local/share/applications/myapp.desktop"; + QVERIFY(QFile::exists(desktopFilePath)); + QFile desktopFile(desktopFilePath); + QVERIFY2(desktopFile.open(QIODevice::ReadOnly), qPrintable(desktopFile.errorString())); + QByteArrayList lines = desktopFile.readAll().split('\n'); + // Automatically filled line: + QVERIFY(lines.contains("Exec=main")); + // Name specified in `freedesktop.name` property + QVERIFY(lines.contains("Name=My App")); + // Overridden line: + QVERIFY(lines.contains("Icon=myapp.png")); + // Untouched line: + QVERIFY(lines.contains("Terminal=false")); + + // Check AppStream file + QVERIFY(QFile::exists(defaultInstallRoot + + "/usr/local/share/metainfo/myapp.appdata.xml")); + + // Check icon file + QVERIFY(QFile::exists(defaultInstallRoot + + "/usr/local/share/icons/hicolor/scalable/apps/myapp.png")); +} + void TestBlackbox::installedTransformerOutput() { QDir::setCurrent(testDataDir + "/installed-transformer-output"); diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h index f9a3d5c7c..eb9e06dd6 100644 --- a/tests/auto/blackbox/tst_blackbox.h +++ b/tests/auto/blackbox/tst_blackbox.h @@ -117,6 +117,7 @@ private slots: void externalLibs(); void fileDependencies(); void fileTagsFilterMerging(); + void freedesktop(); void generatedArtifactAsInputToDynamicRule(); void generateLinkerMapFile(); void generator(); |