diff options
author | Thomas Schmid <schmid-thomas@gmx.net> | 2019-09-29 13:01:19 +0300 |
---|---|---|
committer | Thomas Schmid <schmid-thomas@gmx.net> | 2019-09-29 13:01:19 +0300 |
commit | 67d7b1cd6adda23794e1c7b2e6ddb39bbbd2367e (patch) | |
tree | 1ad36466101cda62970c024ec851aa39aa812732 /gulp | |
parent | 53a30669ba1b6499d9541e07f6655b4d5a03a44b (diff) |
Fix packaging XPIs
Diffstat (limited to 'gulp')
-rw-r--r-- | gulp/gulpfile.addon.js | 260 | ||||
-rw-r--r-- | gulp/gulpfile.app.js | 235 | ||||
-rw-r--r-- | gulp/gulpfile.common.js | 266 | ||||
-rw-r--r-- | gulp/gulpfile.testing.js | 102 |
4 files changed, 863 insertions, 0 deletions
diff --git a/gulp/gulpfile.addon.js b/gulp/gulpfile.addon.js new file mode 100644 index 00000000..7756a73a --- /dev/null +++ b/gulp/gulpfile.addon.js @@ -0,0 +1,260 @@ +/* + * The content of this file is licensed. You may obtain a copy of + * the license at https://github.com/thsmi/sieve/ or request it via + * email from the author. + * + * Do not remove or change this comment. + * + * The initial author of the code is: + * Thomas Schmid <schmid-thomas@gmx.net> + */ + +const { src, dest, watch, parallel } = require('gulp'); + +const common = require("./gulpfile.common.js"); + +const zip = require('gulp-zip'); +const fs = require('fs'); +const path = require('path'); + +const BUILD_DIR_ADDON = path.join(common.BASE_DIR_BUILD, "/thunderbird/"); +const BASE_DIR_ADDON = "./src/addon"; + +/** + * Updates the version in an rdf file. + * + * @param {string} version + * the new version string. + * @param {string} file + * the path to the rdf file + * + * @returns {undefined} + */ +async function setRdfVersion(version, file) { + "use strict"; + + version = version.join("."); + + console.log(`Updating ${file} to ${version}`); + + let regexp = new RegExp("<em:version>(\\d)*\\.(\\d)*\\.(\\d)*<\\/em:version>", "g"); + + let data = await fs.promises.readFile(file, 'utf8'); + data = data.replace( + regexp, + `<em:version>${version}</em:version>`); + + await fs.promises.writeFile(file, data, 'utf-8'); +} + +/** + * Packages the license file into the build directory. + * @returns {undefined} + */ +async function packageLicense() { + "use strict"; + + await src([ + "./LICENSE.md" + ]).pipe(dest(BUILD_DIR_ADDON)); +} + +/** + * Packages jquery into the build directory. + * @returns {undefined} + */ +async function packageJQuery() { + "use strict"; + + await common.packageJQuery( + BUILD_DIR_ADDON + "/chrome/chromeFiles/content/libs/jQuery"); +} + +/** + * Packages codemirror into the build directory. + * @returns {undefined} + */ +async function packageCodeMirror() { + "use strict"; + + await common.packageCodeMirror( + `${BUILD_DIR_ADDON}/chrome/chromeFiles/content/libs/CodeMirror`); +} + +/** + * Pacakges bootstrap into the build directory. + * @returns {undefined} + */ +async function packageBootstrap() { + "use strict"; + + await common.packageBootstrap( + `${BUILD_DIR_ADDON}/chrome/chromeFiles/content/libs/bootstrap`); +} + +/** + * Packages material design icons into the build directory. + * @returns {undefined} + */ +async function packageMaterialIcons() { + "use strict"; + + await common.packageMaterialIcons( + `${BUILD_DIR_ADDON}/chrome/chromeFiles/content/libs/material-icons`); +} + +/** + * Packages the source files into the build directory. + * @returns {undefined} + */ +async function packageSrc() { + "use strict"; + + await src([ + BASE_DIR_ADDON + "/**", + + "!" + BASE_DIR_ADDON + "/chrome/chromeFiles/content/filterList", + "!" + BASE_DIR_ADDON + "/chrome/chromeFiles/content/filterList/**" + ]).pipe(dest(BUILD_DIR_ADDON)); +} + +/** + * Packages common files into the build directory. + * @returns {undefined} + */ +async function packageCommon() { + "use strict"; + + await src([ + common.BASE_DIR_COMMON + "/**", + + // Filter out the rfc documents + "!" + common.BASE_DIR_COMMON + "/libSieve/**/rfc*.txt", + "!" + common.BASE_DIR_COMMON + "/libSieve/**/tests/", + "!" + common.BASE_DIR_COMMON + "/libSieve/**/tests/**" + ]).pipe(dest(`${BUILD_DIR_ADDON}/chrome/chromeFiles/content/libs`)); +} + +/** + * Zips the build directory and creates a XPI inside the release folder. + * @returns {undefined} + */ +async function packageXpi() { + "use strict"; + + const version = (await common.getPackageVersion()).join("."); + + console.log(`Packaging sieve-${version}.xpi`); + + await src([`${BUILD_DIR_ADDON}/**`], {buffer:false}) + .pipe(zip(`sieve-${version}.xpi`)) + .pipe(dest('./release/thunderbird')); + // place code for your default task here +} + +/** + * Thunderbirds allows loading addons from outside of + * the extension directory. In our case this would be + * the build directory. To do so you need to create + * a file with the addons id which contains the path + * to the extension directory. + * + * The rational behind this is that a addon:watch + * automagically updates the addon. + * + * @returns {undefined} + **/ +async function deploy() { + "use strict"; + + let { SieveThunderbirdImport } = require("../src/app/utils/SieveThunderbirdImport.js"); + + let target = (new SieveThunderbirdImport()).getDefaultUserProfile(); + + target = path.join(target, "extensions"); + + if (fs.existsSync(target) === false) + throw new Error("Failed to locate extension directory " + target); + + target = path.join(target, "sieve@mozdev.org"); + + let source = path.join( + path.resolve(BUILD_DIR_ADDON), + path.sep); + + // Bail out in case the directory already exists. + if (await(fs.promises.exists(target))) { + if ((await fs.promises.readFileSync(target, "utf-8")).trim() === source) { + console.log("Skipping file already exists"); + return; + } + } + + // otherwise write or overwrite the existing file. + await fs.promises.writeFile(target, source, "utf-8"); +} + +/** + * Updates the addon's version. + * It reads the information from the npm package and updates the install.rdf as well as the manifest.json + * @returns {undefined} + */ +async function updateVersion() { + "use strict"; + + const pkgVersion = await common.getPackageVersion(); + + // Older Thunderbird version use the install rdf. + await setRdfVersion(pkgVersion, './src/addon/install.rdf'); + // Newer version use the json file + await common.setPackageVersion(pkgVersion, './src/addon/manifest.json'); +} + +/** + * Watches for changed source files and copies them into the build directory. + * @returns {undefined} + */ +function watchSrc() { + + "use strict"; + + watch( + ['./src/**/*.js', + './src/**/*.jsm', + './src/**/*.html', + './src/**/*.css', + './src/**/*.xul', + './src/**/*.dtd', + './src/**/*.properties'], + parallel( + packageSrc, + packageCommon) + ); +} + +exports["packageSrc"] = packageSrc; +exports["packageCommon"] = packageCommon; +exports["packageJQuery"] = packageJQuery; +exports["packageBootstrap"] = packageBootstrap; +exports["packageLicense"] = packageLicense; +exports["packageCodeMirror"] = packageCodeMirror; +exports["packageMaterialIcons"] = packageMaterialIcons; + +exports["packageXpi"] = packageXpi; + + +exports['package'] = parallel( + packageSrc, + packageCommon, + packageJQuery, + packageBootstrap, + packageLicense, + packageCodeMirror, + packageMaterialIcons, +); + +exports['updateVersion'] = updateVersion; + +exports["deploy"] = deploy; + +exports["watch"] = watchSrc; diff --git a/gulp/gulpfile.app.js b/gulp/gulpfile.app.js new file mode 100644 index 00000000..679f87ab --- /dev/null +++ b/gulp/gulpfile.app.js @@ -0,0 +1,235 @@ +/* + * The content of this file is licensed. You may obtain a copy of + * the license at https://github.com/thsmi/sieve/ or request it via + * email from the author. + * + * Do not remove or change this comment. + * + * The initial author of the code is: + * Thomas Schmid <schmid-thomas@gmx.net> + */ + +const { src, dest, watch, parallel } = require('gulp'); + +const common = require("./gulpfile.common.js"); +const path = require('path'); + +const BUILD_DIR_APP = path.join(common.BASE_DIR_BUILD, "electron/resources"); +const BASE_DIR_APP = "./src/app/"; + +/** + * Copies and updates the package.json inside the build directory. + * It is typically used by other tools like the electron-packager. + * @returns {undefined} + */ +async function packageDefinition() { + + "use strict"; + + const BASE_PATH = "."; + + await src([ + BASE_PATH + "/package.json" + ], { base: BASE_PATH }).pipe(dest(BUILD_DIR_APP)); +} + +/** + * Copies the license file into the build directory. + * @returns {undefined} + */ +async function packageLicense() { + "use strict"; + + await src([ + "./LICENSE.md" + ]).pipe(dest(BUILD_DIR_APP)); +} + + +/** + * Copies the jquery sources into the build directory. + * @returns {undefined} + */ +async function packageJQuery() { + "use strict"; + + await common.packageJQuery( + BUILD_DIR_APP + "/libs/jquery"); +} + +/** + * Copies the codemirror sources into the build directory. + * @returns {undefined} + */ +async function packageCodeMirror() { + "use strict"; + + await common.packageCodeMirror( + `${BUILD_DIR_APP}/libs/CodeMirror`); +} + +/** + * Copies the bootstrap sources into the build directory. + * @returns {undefined} + **/ +async function packageBootstrap() { + "use strict"; + + await common.packageBootstrap( + `${BUILD_DIR_APP}/libs/bootstrap`); +} + +/** + * Copies the material design icons into the build directory. + * @returns {undefined} + */ +async function packageMaterialIcons() { + "use strict"; + + await common.packageMaterialIcons( + `${BUILD_DIR_APP}/libs/material-icons`); +} + +/** + * Copies the source files into the app/ directory... + * @returns {undefined} + */ +async function packageSrc() { + "use strict"; + + await src([ + BASE_DIR_APP + "/**" + ]).pipe(dest(BUILD_DIR_APP)); +} + +/** + * The common files need to go into the app/lib directory... + * @returns {undefined} + */ +async function packageCommon() { + "use strict"; + + await src([ + common.BASE_DIR_COMMON + "/**", + // Filter out the editor wrapper + "!" + common.BASE_DIR_COMMON + "/editor", + "!" + common.BASE_DIR_COMMON + "/editor/**", + // Filter out the rfc documents + "!" + common.BASE_DIR_COMMON + "/libSieve/**/rfc*.txt", + "!" + common.BASE_DIR_COMMON + "/libSieve/**/tests/", + "!" + common.BASE_DIR_COMMON + "/libSieve/**/tests/**" + ]).pipe(dest(BUILD_DIR_APP + '/libs')); +} + +/** + * Packages the build directory and electron for windows. + * @returns {undefined} + */ +async function packageWin32() { + "use strict"; + + const options = { + dir: BUILD_DIR_APP, + arch: "ia32", + platform: "win32", + download: { + cache: path.join(common.BASE_DIR_BUILD, "/electron/cache") + }, + out: path.join(common.BASE_DIR_BUILD, "/electron/out"), + overwrite: true, + packageManager: "yarn", + // packageManager : false, + prune: true, + icon: "./../test.ico" + }; + + const packager = require('electron-packager'); + await packager(options); +} + +/** + * Packages the build directory and electron for linux + * @returns {undefined} + */ +async function packageLinux() { + "use strict"; + + let options = { + dir: BUILD_DIR_APP, + arch: "x64", + platform: "linux", + download: { + cache: path.join(common.BASE_DIR_BUILD, "/electron/cache") + }, + out: path.join(common.BASE_DIR_BUILD, "/electron/out"), + overwrite: true, + // packageManager : "yarn" + // packageManager : false, + prune: true + }; + + const packager = require('electron-packager'); + await packager(options); +} + +/** + * Updates the addon's version. + * @returns {undefined} + */ +async function updateVersion() { + "use strict"; + + // there is no need to do anything here. + // Electron packager will to it for us. +} + +/** + * Watches for changed source files and copies them into the build directory. + * @returns {undefined} + */ +function watchSrc() { + + "use strict"; + + watch( + ['./src/**/*.js', + './src/**/*.jsm', + './src/**/*.html', + './src/**/*.tpl', + './src/**/*.css', + './src/**/*.xul', + './src/**/*.dtd', + './src/**/*.properties'], + parallel( + packageSrc, + packageCommon) + ); +} + +exports["watch"] = watchSrc; + +exports["updateVersion"] = updateVersion; + +exports["packageDefinition"] = packageDefinition; +exports["packageJQuery"] = packageJQuery; +exports["packageCodeMirror"] = packageCodeMirror; +exports["packageBootstrap"] = packageBootstrap; +exports["packageMaterialIcons"] = packageMaterialIcons; +exports["packageLicense"] = packageLicense; +exports["packageSrc"] = packageSrc; +exports["packageCommon"] = packageCommon; + +exports["packageWin32"] = packageWin32; +exports["packageLinux"] = packageLinux; + +exports['package'] = parallel( + packageDefinition, + packageJQuery, + packageCodeMirror, + packageBootstrap, + packageMaterialIcons, + packageLicense, + packageSrc, + packageCommon +); + diff --git a/gulp/gulpfile.common.js b/gulp/gulpfile.common.js new file mode 100644 index 00000000..4fa0216a --- /dev/null +++ b/gulp/gulpfile.common.js @@ -0,0 +1,266 @@ +/* + * The content of this file is licensed. You may obtain a copy of + * the license at https://github.com/thsmi/sieve/ or request it via + * email from the author. + * + * Do not remove or change this comment. + * + * The initial author of the code is: + * Thomas Schmid <schmid-thomas@gmx.net> + */ + +const fs = require('fs'); +const { src, dest } = require('gulp'); + +const BASE_DIR_BOOTSTRAP = "./node_modules/bootstrap/dist"; +const BASE_DIR_MATERIALICONS = "./node_modules/material-design-icons-iconfont/dist"; +const BASE_DIR_JQUERY = "./node_modules/jquery/dist"; +const BASE_DIR_CODEMIRROR = "./node_modules/codemirror"; + +const BASE_DIR_COMMON = "./src/common"; +const BASE_DIR_BUILD = "./build"; + +const INDEX_MAJOR = 0; +const INDEX_MINOR = 1; +const INDEX_PATCH = 2; + +/** + * Delete all files from the given path. + * + * @param {string} path + * the base path which should be cleared. + * @returns {undefined} + */ +async function deleteRecursive(path) { + "use strict"; + + if (! fs.existsSync(path)) + return; + + const files = await fs.promises.readdir(path); + + for (const file of files) { + let curPath = path + "/" + file; + if (!(await fs.promises.lstat(curPath)).isDirectory()) { + await fs.promises.unlink(curPath); + continue; + } + + await deleteRecursive(curPath); + } + + await fs.promises.rmdir(path); +} + +/** + * Clean the build environment including all build and packaging artifacts. + * @returns {undefined} + */ +async function clean() { + "use strict"; + await deleteRecursive(BASE_DIR_BUILD); +} + +/** + * Copies the jquery sources into the given build directory. + * + * @param {string} destination + * where to place the jquery sources + * @returns {undefined} + */ +async function packageJQuery(destination) { + "use strict"; + + await src([ + BASE_DIR_JQUERY + "/jquery.min.js" + ], { base: BASE_DIR_JQUERY }).pipe( + dest(destination)); +} + +/** + * Copies the codemirror sources into the build directory. + * + * @param {string} destination + * where to place the codemirror sources + * @returns {undefined} + */ +async function packageCodeMirror(destination) { + "use strict"; + + await src([ + BASE_DIR_CODEMIRROR + "/addon/edit/**", + BASE_DIR_CODEMIRROR + "/addon/search/**", + BASE_DIR_CODEMIRROR + "/lib/**", + BASE_DIR_CODEMIRROR + "/mode/sieve/**", + BASE_DIR_CODEMIRROR + "/theme/eclipse.css", + BASE_DIR_CODEMIRROR + "/LICENSE", + BASE_DIR_CODEMIRROR + "/package.json" + ], { base: BASE_DIR_CODEMIRROR }).pipe( + dest(destination)); +} + +/** + * Copies the bootstrap sources into the build directory. + * + * @param {string} destination + * where to place the bootstrap sources + * @returns {undefined} + **/ +async function packageBootstrap(destination) { + "use strict"; + + await src([ + BASE_DIR_BOOTSTRAP + "/css/*.min.css", + BASE_DIR_BOOTSTRAP + "/js/*.bundle.min.js" + ], { base: BASE_DIR_BOOTSTRAP }).pipe( + dest(destination)); +} + +/** + * Copies the material design icons into the build directory. + * + * @param {string} destination + * where to place the material design sources + * @returns {undefined} + */ +async function packageMaterialIcons(destination) { + "use strict"; + + await src([ + BASE_DIR_MATERIALICONS + "/material-design-icons.css", + BASE_DIR_MATERIALICONS + "/fonts/MaterialIcons-Regular.woff2" + ], { base: BASE_DIR_MATERIALICONS }).pipe(dest(destination)); +} + +/** + * Extracts the version from the package.json file + * + * @param {string} [file] + * the path to the package json file. + * @returns {int[]} + * the version as a tripple of integer + */ +async function getPackageVersion(file) { + "use strict"; + + if ((typeof (file) === "undefined") || file === null) + file = "./package.json"; + + let version = JSON.parse(await fs.promises.readFile(file, 'utf8')).version; + + version = version.split("."); + + while (version.length < 3) + version.push(0); + + return version; +} + +/** + * Updates the version in a package json file. + * + * @param {string} version + * the new version string + * @param {string} [file] + * the path to the npm package json file. + * + * @returns {undefined} + */ +async function setPackageVersion(version, file) { + "use strict"; + + if ((typeof (file) === "undefined") || file === null) + file = "./package.json"; + + version = version.join("."); + + console.log(`Updating ${file} to ${version}`); + + let data = JSON.parse(await fs.promises.readFile(file, 'utf8')); + data.version = version; + + await fs.promises.writeFile(file, JSON.stringify(data, null, 2), 'utf-8'); +} + +// We can only use major, minor and patch. Everything else +// clashes with mozilla's naming semantic. + +/** + * Bumps the package.json version info to the next major version. + * The minor and patch level is reset to zero + * + * @returns {undefined} + */ +async function bumpMajorVersion() { + "use strict"; + + let pkgVersion = await getPackageVersion('./package.json'); + + console.log("Major bump from " + pkgVersion.join(".") + " ..."); + + pkgVersion[INDEX_MAJOR] = parseInt(pkgVersion[INDEX_MAJOR], 10) + 1; + pkgVersion[INDEX_MINOR] = 0; + pkgVersion[INDEX_PATCH] = 0; + + console.log("... to " + pkgVersion.join(".")); + + await setPackageVersion(pkgVersion, './package.json'); +} + +/** + * Bumps the package.json version info to the next minor version. + * The major version remains untouched but the patch level is reset to zero + * + * @returns {undefined} + */ +async function bumpMinorVersion() { + "use strict"; + + let pkgVersion = await getPackageVersion('./package.json'); + + console.log("Minor bump from " + pkgVersion.join(".")); + + pkgVersion[INDEX_MINOR] = parseInt(pkgVersion[INDEX_MINOR], 10) + 1; + pkgVersion[INDEX_PATCH] = 0; + + console.log("... to " + pkgVersion.join(".")); + + await setPackageVersion(pkgVersion, './package.json'); +} + +/** + * Pumps the package.json version info to the next patch level. + * Neither the major nor the minor version will be changed. + * + * @returns {undefined} + */ +async function bumpPatchVersion() { + "use strict"; + + let pkgVersion = await getPackageVersion('./package.json'); + + console.log("Patch bump from " + pkgVersion.join(".")); + + pkgVersion[INDEX_PATCH] = parseInt(pkgVersion[INDEX_PATCH], 10) + 1; + + console.log("... to " + pkgVersion.join(".")); + + await setPackageVersion(pkgVersion, './package.json'); +} + +exports["clean"] = clean; + +exports["packageJQuery"] = packageJQuery; +exports["packageCodeMirror"] = packageCodeMirror; +exports["packageBootstrap"] = packageBootstrap; +exports["packageMaterialIcons"] = packageMaterialIcons; + +exports["getPackageVersion"] = getPackageVersion; +exports["setPackageVersion"] = setPackageVersion; + +exports["bumpMajorVersion"] = bumpMajorVersion; +exports["bumpMinorVersion"] = bumpMinorVersion; +exports["bumpPatchVersion"] = bumpPatchVersion; + +exports["BASE_DIR_BUILD"] = BASE_DIR_BUILD; +exports["BASE_DIR_COMMON"] = BASE_DIR_COMMON; diff --git a/gulp/gulpfile.testing.js b/gulp/gulpfile.testing.js new file mode 100644 index 00000000..246e590b --- /dev/null +++ b/gulp/gulpfile.testing.js @@ -0,0 +1,102 @@ +/* + * The content of this file is licensed. You may obtain a copy of + * the license at https://github.com/thsmi/sieve/ or request it via + * email from the author. + * + * Do not remove or change this comment. + * + * The initial author of the code is: + * Thomas Schmid <schmid-thomas@gmx.net> + */ + +const { src, dest, watch, parallel } = require('gulp'); + +const common = require("./gulpfile.common.js"); +const path = require('path'); + +const BUILD_DIR_TEST = path.join(common.BASE_DIR_BUILD, "test/"); + +/** + * Copies jquery into the test folder. + * @returns {undefined} + */ +async function packageJQuery() { + "use strict"; + + await common.packageJQuery( + `${BUILD_DIR_TEST}/common/jQuery/`); +} + +/** + * Copies the common files into the test folder. + * @returns {undefined} + */ +async function packageCommon() { + "use strict"; + + await src([ + common.BASE_DIR_COMMON + "/**", + + // Filter out the rfc documents + "!" + common.BASE_DIR_COMMON + "/libSieve/**/rfc*.txt" + ]).pipe(dest(`${BUILD_DIR_TEST}/common/`)); +} + +/** + * Copies the test suite files into the test folder. + * @returns {undefined} + */ +async function packageTestSuite() { + "use strict"; + + const BASE_PATH = "./tests"; + + await src([ + BASE_PATH + "/**" + ]).pipe(dest(BUILD_DIR_TEST + '/')); +} + +/** + * Copies the addons source files into the test folder. + * @returns {undefined} + */ +async function packageAddonSrc() { + "use strict"; + + const BASE_PATH = "./src/addon/chrome/chromeFiles/content"; + + await src([ + BASE_PATH + "/**", + + "!" + BASE_PATH + "/filterList", + "!" + BASE_PATH + "/filterList/**" + ]).pipe(dest(BUILD_DIR_TEST + "/addon/")); +} + +/** + * Watches for changed source files and copies them into the build directory. + * @returns {undefined} + */ +function watchSrc() { + + "use strict"; + + watch( + ['./src/**/*.js', + './src/**/*.jsm', + './tests/**/*.json', + './tests/**/*.js'], + parallel( + packageCommon, + packageTestSuite) + ); +} + +exports["package"] = parallel( + packageCommon, + packageAddonSrc, + packageJQuery, + packageTestSuite +); + +exports["watch"] = watchSrc; |