diff --git a/Gruntfile.js b/Gruntfile.js index eaa3dc0..df9f987 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -2,6 +2,7 @@ GPII Linux Personalization Framework Node.js Bootstrap Copyright 2014 RTF-US +Copyright 2014 Emergya Licensed under the New BSD license. You may not use this file except in compliance with this License. @@ -20,7 +21,9 @@ module.exports = function (grunt) { grunt.loadNpmTasks("grunt-gpii"); var usbListenerDir = "./usbDriveListener"; - + var gypCompileCmd = "node-gyp configure build"; + var gypCleanCmd = "node-gyp clean"; + function nodeGypShell(cmd, cwd) { return { options: { @@ -49,12 +52,14 @@ module.exports = function (grunt) { stderr: true, failOnError: true }, - compileGSettings: nodeGypShell("node-gyp configure build", "gpii/node_modules/gsettingsBridge/nodegsettings"), - cleanGSettings: nodeGypShell("node-gyp clean", "gpii/node_modules/gsettingsBridge/nodegsettings"), - compileAlsaBridge: nodeGypShell("node-gyp configure build", "gpii/node_modules/alsa/nodealsa"), - cleanAlsaBridge: nodeGypShell("node-gyp clean", "gpii/node_modules/alsa/nodealsa"), - compileXrandrBridge: nodeGypShell("node-gyp configure build", "gpii/node_modules/xrandr/nodexrandr"), - cleanXrandrBridge: nodeGypShell("node-gyp clean", "gpii/node_modules/xrandr/nodexrandr"), + compileGSettings: nodeGypShell(gypCompileCmd, "gpii/node_modules/gsettingsBridge/nodegsettings"), + cleanGSettings: nodeGypShell(gypCleanCmd, "gpii/node_modules/gsettingsBridge/nodegsettings"), + compileAlsaBridge: nodeGypShell(gypCompileCmd, "gpii/node_modules/alsa/nodealsa"), + cleanAlsaBridge: nodeGypShell(gypCleanCmd, "gpii/node_modules/alsa/nodealsa"), + compileXrandrBridge: nodeGypShell(gypCompileCmd, "gpii/node_modules/xrandr/nodexrandr"), + cleanXrandrBridge: nodeGypShell(gypCleanCmd, "gpii/node_modules/xrandr/nodexrandr"), + compilePackageKitBridge: nodeGypShell(gypCompileCmd, "gpii/node_modules/packagekit/nodepackagekit"), + cleanPackageKitBridge: nodeGypShell(gypCleanCmd, "gpii/node_modules/packagekit/nodepackagekit"), installUsbLib: { command: [ "sudo cp " + usbListenerDir + "/gpii-usb-user-listener /usr/bin/", @@ -83,6 +88,7 @@ module.exports = function (grunt) { grunt.task.run("shell:compileGSettings"); grunt.task.run("shell:compileAlsaBridge"); grunt.task.run("shell:compileXrandrBridge"); + grunt.task.run("shell:compilePackageKitBridge"); grunt.task.run("shell:installUsbLib"); }); @@ -90,6 +96,7 @@ module.exports = function (grunt) { grunt.task.run("shell:cleanGSettings"); grunt.task.run("shell:cleanAlsaBridge"); grunt.task.run("shell:cleanXrandrBridge"); + grunt.task.run("shell:cleanPackageKitBridge"); grunt.task.run("shell:uninstallUsbLib"); }); diff --git a/gpii.js b/gpii.js index e414978..33d1512 100644 --- a/gpii.js +++ b/gpii.js @@ -17,7 +17,8 @@ var fluid = require("universal"), - gpii = fluid.registerNamespace("gpii"); + gpii = fluid.registerNamespace("gpii"), + kettle = fluid.registerNamespace("kettle"); require("./index.js"); diff --git a/gpii/node_modules/packagekit/index.js b/gpii/node_modules/packagekit/index.js new file mode 100644 index 0000000..d019e0e --- /dev/null +++ b/gpii/node_modules/packagekit/index.js @@ -0,0 +1,28 @@ +/** + * GPII PackageKit Device Reporter + * + * Copyright 2014 Emergya + * + * Licensed under the New BSD license. You may not use this file except in + * compliance with this License. + * + * You may obtain a copy of the License at + * https://github.com/gpii/universal/LICENSE.txt + */ + +var fluid = require("universal"); + +var loader = fluid.getLoader(__dirname); + +loader.require("./packageKitDeviceReporter.js"); + +// Initialize the Device Reporter's installedPackagesCache at the very +// beginning and avoid a delay when a user is logging in into the system. +// Right now this is provisional, so we have to re-think how to initialize it +// in a smarter way. http://issues.gpii.net/browse/GPII-851 +// +var gpii = fluid.registerNamespace("gpii"); +fluid.registerNamespace("gpii.packageKit"); + +var packageKit = require("./nodepackagekit/build/Release/nodepackagekit.node"); +gpii.packageKit.installedPackagesCache = packageKit.getPackages("installed;~devel"); diff --git a/gpii/node_modules/packagekit/nodepackagekit/binding.gyp b/gpii/node_modules/packagekit/nodepackagekit/binding.gyp new file mode 100644 index 0000000..981609d --- /dev/null +++ b/gpii/node_modules/packagekit/nodepackagekit/binding.gyp @@ -0,0 +1,11 @@ +{ + "targets": [ + { + "target_name": "nodepackagekit", + "sources": ["nodepackagekit.cc"], + "libraries": [". +For example: node findSearchPk.js orca + +This takes a two step approach to determine whether the named software is +available on the system. The first step involves using the linux 'find' +command to search for the given software. The second step uses PackageKit's +search facility. + +The find command is used to search the directories listed in the PATH +environment variable. There are two outcomes: + +1. The software is not found. This is taken to mean that the software is not +installed on the system. + +2. The software is found in one of the PATH directories. This is taken to mean +that the software is installed. + +In summary, the first step uses the find command to determine if the software +is installed. + +For the first outcome, the process continues and uses the packagekit node +add-on's searchPackage(), with a filter that indicates to search for +not-installed packages. The result will either report the repository from +which the software can be installed, or, that no repository contains the +software. If found in a repository, the package id, version number, etc. is +returned. + +In the second case, the add-on's searchFiles() function is used with the given +path, and fetches the information about the package for that path. If that +fails to discover anything, the add-on's searchPackage() is used at least once, +and possibly twice. The first attempt employs a filter that indicates to search +for installed packages. If this search returns information about a package, +then no further action is taken. But, if it returns nothing, then +searchPackage() is done a second time using an not-installed filter. That may +return what is available to install. + +The end result is: +1. Package information as to what is installed on the system. +2. Package information as to what is available to be installed. +3. A combination of 1. and 2. if there is the package is installed, and there is +an update available for installation. +4. No package information. + +Issues: +- when the find command finds the software, but PackageKit knows nothing about +it, it is impossible (?) to determine the version of the software: +- while many linux commands support a "--version" option*, the output is not +consistent: +-- the format of the version string is not standardized. +-- some commands write the version string to stdout; some to stderr. +-- some GUI applications require GTK (or some other toolkit) in order to launch. + +*note: the "--version" option is supposed to launch a a minimal convfiguration +of the software, report the version, and quit. + +The end result of this script is an (array of) objects each containning a +package id, a version number, whether the package is installed, and the +associated repository. This demo prints the package information of all +packages found. + +*/ + +/* global require, process, console */ + +(function() { + + "use strict"; + + var packagekit = require ("./build/Release/nodepackagekit.node"); + + var lookingFor = process.argv[2]; + + // Record the files found by 'find', and possibly related packages. + var whatFindFound = []; + var packages = []; + + // Use package kit add-on to get version of the software. + // - searchNotInstalled() is used when 'find' found nothing. + // - searchInstalled() is used when 'find' found something. + function searchNotInstalled() { + packages = packagekit.searchPackage (lookingFor, "~installed;basename"); + } + + function searchInstalled() { + packages = packagekit.searchFiles (whatFindFound); + if (packages.length === 0) { + packages = packagekit.searchPackage (lookingFor, "installed;basename"); + } + } + + // Handle 'find' on close event -- invoke packagekit.searchPackage(). + function onFindClose() { + console.log ("'find' found " + + ( whatFindFound.length === 0 ? "nothing" : whatFindFound )); + + if (whatFindFound.length === 0) { + searchNotInstalled(); + } + else { + searchInstalled(); + if (packages.length === 0) { + searchNotInstalled(); + } + } + if (packages.length > 0) { + console.log (JSON.stringify (packages, null, " ")); + } + else { + console.log ("No package found"); + } + } + + function onFindStdout (data) { + var found = data.toString().split ("\n"); + found.forEach (function (value) { + if (value.length > 0) { + whatFindFound.push (value); + } + }); + } + + if (lookingFor !== undefined) { + var findArgs = process.env.PATH.split (":"); + findArgs.push (process.env.HOME); + findArgs.push ("-name"); + findArgs.push (lookingFor); + findArgs.push ("-type"); + findArgs.push ("f"); // only regular files. + findArgs.push ("-print"); + + // Run 'find' + var spawn = require ("child_process").spawn, + find = spawn ("find", findArgs); + + find.stdout.on ("data", onFindStdout); + + find.on ("close", onFindClose); + + find.on ("error", function (err) { + console.log ("child process : " + err); + }); + } +}()); diff --git a/gpii/node_modules/packagekit/nodepackagekit/nodepackagekit.cc b/gpii/node_modules/packagekit/nodepackagekit/nodepackagekit.cc new file mode 100644 index 0000000..b187331 --- /dev/null +++ b/gpii/node_modules/packagekit/nodepackagekit/nodepackagekit.cc @@ -0,0 +1,297 @@ +/* +GPII Node.js PackageKit Bridge + +Copyright 2012 Steven Githens +Copyright 2013 Emergya +Copyright 2013, 2014 Inclusive Design Research Centre, OCAD University + +Licensed under the New BSD license. You may not use this file except in +compliance with this License. + +You may obtain a copy of the License at +https://github.com/gpii/universal/LICENSE.txt +*/ +#define I_KNOW_THE_PACKAGEKIT_GLIB2_API_IS_SUBJECT_TO_CHANGE 1 + +#include +#include +#include +#include +#include +#include + +using namespace v8; + +/* Set DEBUG to TRUE in order to see the transactions' progress + * TODO: Allow switching DEBUG value from Node.js side + */ +static gboolean DEBUG = FALSE; + +static gchar TAG[] = "[nodePackagekit]"; + +static std::basic_string +utf8StringFromValue(v8::Handle value) +{ + v8::Local string = value->ToString(); + gchar *buffer = g_new(gchar, string->Utf8Length()); + string->WriteUtf8(buffer); + return buffer; +} + +static void +progressCallback(PkProgress *progress, PkProgressType type) { + if (!DEBUG) return; + PkStatusEnum status; + gint percentage; + gboolean allow_cancel; + + g_object_get(progress, + "status", &status, + "percentage", &percentage, + "allow-cancel", &allow_cancel, + NULL); + + if (type == PK_PROGRESS_TYPE_STATUS) { + printf ("%s Transaction status: %s\n", TAG, pk_status_enum_to_string (status)); + } else if (type == PK_PROGRESS_TYPE_PERCENTAGE) { + if (percentage > 0) + printf ("%s Current percentage: %d%%\n", TAG, percentage); + } +} + +static PkBitfield +handleFiltersArgument (const Arguments& args, const int filterIndex) { + std::basic_string filters; + + if (args.Length() > filterIndex) { + filters = utf8StringFromValue(args[filterIndex]); + } + else { + filters = (gchar *) "none"; + } + return pk_filter_bitfield_from_string (filters.c_str()); +} + +static v8::Handle +makePac (PkPackage *package) { + v8::Handle pac = v8::Object::New(); + + pac->Set(String::New("id"), String::New(pk_package_get_id (package))); + pac->Set(String::New("name"), String::New(pk_package_get_name (package))); + pac->Set(String::New("version"), + String::New (pk_package_get_version(package))); + pac->Set(String::New("arch"), + String::New (pk_package_get_arch(package))); + pac->Set(String::New("data"), String::New (pk_package_get_data(package))); + return (pac); +} + + +/** + * searchPackage: + * + * Should take as arguments: + * name: Name of the package, aka: search criteria (str) + * filters: Filters for the search as a string, e.g. "~devel;basename". See: + * http://www.packagekit.org/gtk-doc/introduction-ideas-filters.html + * Special case: the "none" filter = installed or available. + * Returns: Array of packages matching the search criteria + */ +Handle searchPackage(const Arguments& args) { + HandleScope scope; + PkClient *client = NULL; + PkResults *results = NULL; + GPtrArray *array; + PkPackageSack *sack = NULL; + std::basic_string name; + PkBitfield filtersBitField; + GError *err = NULL; + v8::Handle pac; + v8::Handle result = v8::Array::New(); + + name = utf8StringFromValue(args[0]); + gchar *names[sizeof(name)] = {&name[0]}; + + filtersBitField = handleFiltersArgument (args, 1); + + client = pk_client_new(); + results = pk_client_search_names (client, filtersBitField, + names, NULL, + (PkProgressCallback) progressCallback, NULL, &err); + + sack = pk_results_get_package_sack(results); + pk_package_sack_sort(sack, PK_PACKAGE_SACK_SORT_TYPE_NAME); + array = pk_package_sack_get_array(sack); + + for (unsigned int i=0; ilen; i++) { + PkPackage *package = (PkPackage *) g_ptr_array_index(array, i); + pac = makePac (package); + result->Set (i,pac); + } + + if (results != NULL) + g_object_unref (results); + if (sack != NULL) + g_object_unref (sack); + if (client != NULL) + g_object_unref (client); + + return scope.Close(result); +} + +/** + * searchFiles: + * + * Should take as arguments: + * name: Path name associated with package, e.g., "/usr/bin/orca". + * filters: Filters for the search as a string, e.g. "~devel;basename". See: + * http://www.packagekit.org/gtk-doc/introduction-ideas-filters.html + * Special case: the "none" filter = installed or available. + * Returns: Array of packages matching the search criteria. + */ +Handle searchFiles (const Arguments& args) { + HandleScope scope; + PkClient *client = NULL; + PkResults *results = NULL; + GPtrArray *array; + PkPackageSack *sack = NULL; + std::basic_string pathName; + PkBitfield filtersBitField; + GError *err = NULL; + v8::Handle pac; + v8::Handle result = v8::Array::New(); + + pathName = utf8StringFromValue(args[0]); + gchar *pathNames[sizeof(pathName)] = {&pathName[0]}; + filtersBitField = handleFiltersArgument (args, 1); + + client = pk_client_new(); + results = pk_client_search_files (client, filtersBitField, + pathNames, NULL, + (PkProgressCallback) progressCallback, NULL, &err); + + sack = pk_results_get_package_sack(results); + pk_package_sack_sort(sack, PK_PACKAGE_SACK_SORT_TYPE_NAME); + array = pk_package_sack_get_array(sack); + + for (unsigned int i=0; ilen; i++) { + PkPackage *package = (PkPackage *) g_ptr_array_index(array, i); + pac = makePac (package); + result->Set (i,pac); + } + + if (results != NULL) + g_object_unref (results); + if (sack != NULL) + g_object_unref (sack); + if (client != NULL) + g_object_unref (client); + + return scope.Close(result); +} + +/** + * getPackages: + * + * Should take as arguments: + * filters: Filters for list of packages to return, e.g. "installed" or + * "~installed", or "~devel;basename". + * See: + * http://www.packagekit.org/gtk-doc/introduction-ideas-filters.html + * Special case: the "none" filter = installed or available, which + * means every possible package. If no argument is passed, this + * assumes the "none" filter. + * Returns: Array of packages matching the filters. + */ +Handle getPackages(const Arguments& args) { + HandleScope scope; + PkClient *client = NULL; + PkResults *results = NULL; + GPtrArray *array; + PkPackageSack *sack = NULL; + PkBitfield filtersBitField; + GError *err = NULL; + v8::Handle pac; + v8::Handle result = v8::Array::New(); + + filtersBitField = handleFiltersArgument (args, 0); + client = pk_client_new(); + results = pk_client_get_packages (client, filtersBitField, + NULL, (PkProgressCallback) progressCallback, + NULL, &err); + + sack = pk_results_get_package_sack(results); + pk_package_sack_sort(sack, PK_PACKAGE_SACK_SORT_TYPE_NAME); + array = pk_package_sack_get_array(sack); + + for (unsigned int i=0; ilen; i++) { + PkPackage *package = (PkPackage *) g_ptr_array_index(array, i); + pac = makePac (package); + result->Set (i,pac); + } + + if (results != NULL) + g_object_unref (results); + if (sack != NULL) + g_object_unref (sack); + if (client != NULL) + g_object_unref (client); + + return scope.Close(result); +} + +/** + * performAction: + * + * Should take as arguments: + * action: action to perform, either 'install', 'update' or 'remove' (str) + * name: id of the package (str) + * Returns: true | false (bool) + */ +Handle performAction(const Arguments& args) { + HandleScope scope; + PkTask *task; + GError *err = NULL; + std::basic_string action = utf8StringFromValue(args[0]); + std::basic_string name = utf8StringFromValue(args[1]); + + gchar **package_ids = NULL; + + task = pk_task_new(); + package_ids = pk_package_ids_from_id (name.c_str()); + + if (action == "install") { + pk_task_install_packages_sync(task, package_ids, NULL, + (PkProgressCallback) progressCallback, + NULL, &err); + } else if (action == "update") { + pk_task_update_packages_sync(task, package_ids, NULL, + (PkProgressCallback) progressCallback, + NULL, &err); + } else if (action == "remove") { + pk_task_remove_packages_sync(task, package_ids, TRUE, FALSE, NULL, + (PkProgressCallback) progressCallback, + NULL, &err); + } else { + ThrowException(Exception::Error(String::New( + "You have to provide the action to be performed, either 'install'," + "'update' or 'remove'"))); + } + + g_strfreev (package_ids); + + return scope.Close(True()); +} + +void init(Handle target) { + target->Set(String::NewSymbol("searchPackage"), + FunctionTemplate::New(searchPackage)->GetFunction()); + target->Set(String::NewSymbol("searchFiles"), + FunctionTemplate::New(searchFiles)->GetFunction()); + target->Set(String::NewSymbol("getPackages"), + FunctionTemplate::New(getPackages)->GetFunction()); + target->Set(String::NewSymbol("performAction"), + FunctionTemplate::New(performAction)->GetFunction()); +} +NODE_MODULE(nodepackagekit, init) + diff --git a/gpii/node_modules/packagekit/nodepackagekit/nodepackagekit_test.js b/gpii/node_modules/packagekit/nodepackagekit/nodepackagekit_test.js new file mode 100644 index 0000000..2bbd09d --- /dev/null +++ b/gpii/node_modules/packagekit/nodepackagekit/nodepackagekit_test.js @@ -0,0 +1,262 @@ +/*! +GPII Node.js PackageKit Bridge + +Copyright 2012 Steven Githens +Copyright 2013, 2014 Inclusive Design Research Centre, OCAD University +Copyright 2013, 2014 Emergya + +Licensed under the New BSD license. You may not use this file except in +compliance with this License. + +You may obtain a copy of the License at +https://github.com/gpii/universal/LICENSE.txt +*/ + +/*global require*/ + +var fluid = require ("universal"), + jqUnit = fluid.require ("jqUnit"), + packagekit = require ("./build/Release/nodepackagekit.node"); + +(function() { + + "use strict"; + + var pkTests = fluid.registerNamespace ("gpii.tests.packageKit"); + + pkTests.isInstalled = function (pkg) { + return (!!pkg && (pkg.data.indexOf ("installed") !== -1)); + }; + + pkTests.findGlib2 = function (aPkg) { + return aPkg.name === "glib2"; + }; + + pkTests.findPackageByName = function (name, pkgArray) { + return fluid.find (pkgArray, function (aPkg) { + if (aPkg.name === name) { + return aPkg; + } + }, null); + }; + + // Return the package that matches name, version, and architecture. + pkTests.getMatchingPackage = function (pkg, pkgList) { + return fluid.find (pkgList, function (aPkg) { + if (aPkg.name === pkg.name && + aPkg.version === pkg.version && + aPkg.arch === pkg.arch) { + return aPkg; + } + }, null); + }; + + pkTests.initTuxguitar = function() { + var tuxguitar = { + pkgList: [], + pkg: null, + inInstalledList: false, + inAvailableList: false + }; + var pkgs = packagekit.searchPackage ("tuxguitar"); + tuxguitar.pkgList = pkgs; + tuxguitar.pkg = pkTests.findPackageByName ("tuxguitar", pkgs); + return tuxguitar; + }; + + pkTests.isTuxguitarInList = function (tuxguitar, pkgList) { + var matchPkg = pkTests.getMatchingPackage (tuxguitar.pkg, pkgList); + return (matchPkg !== null); + }; + + // GPII-1081: compensate for change in PackageKit between v0.8.17 and + // v1.0.3. In the later version, even when installed, the same package + // appears in the list of available packages. In v0.8.17 it did not. + // + pkTests.availableNotInstalled = function (tuxguitar, availablePkgs) { + var isAvailable = pkTests.isTuxguitarInList (tuxguitar, availablePkgs); + if (tuxguitar.inInstalledList && isAvailable) { + var installedMatchesAvailablePkg = + pkTests.getMatchingPackage (tuxguitar.pkg, availablePkgs); + + if (installedMatchesAvailablePkg !== null) { + tuxguitar.inAvailableList = false; + } + else { + tuxguitar.inAvailableList = true; + } + } + else { + tuxguitar.inAvailableList = isAvailable; + } + }; + + pkTests.initSearchTest = function() { + var tuxguitar = pkTests.initTuxguitar(); + var installedPkgs = packagekit.searchPackage ("tuxguitar", "installed"); + tuxguitar.inInstalledList = + pkTests.isTuxguitarInList (tuxguitar, installedPkgs); + + var availablePkgs = packagekit.searchPackage ("tuxguitar", "~installed"); + pkTests.availableNotInstalled (tuxguitar, availablePkgs); + + return tuxguitar; + }; + + pkTests.initGetTest = function() { + var tuxguitar = pkTests.initTuxguitar(); + var installedPkgs = packagekit.getPackages ("installed"); + tuxguitar.inInstalledList = + pkTests.isTuxguitarInList (tuxguitar, installedPkgs); + + var availablePkgs = packagekit.getPackages ("~installed"); + pkTests.availableNotInstalled (tuxguitar, availablePkgs); + + return tuxguitar; + }; + + pkTests.runInstalledVsAvailableTests = function (tuxguitar, msg) { + // Depending on whether tuxguitar is installed on not, check that it + // appears correctly in the installed or available lists. + if (pkTests.isInstalled (tuxguitar.pkg)) { + jqUnit.assertTrue (msg + " 'tuxguitar' in installed packages list", + tuxguitar.inInstalledList); + jqUnit.assertFalse (msg + " 'tuxguitar' not in available packages " + + "list", tuxguitar.inAvailableList); + } + else { + jqUnit.assertFalse (msg + " 'tuxguitar' not in installed packages " + + "list", tuxguitar.inInstalledList); + jqUnit.assertTrue (msg + " 'tuxguitar' is in available packages list", + tuxguitar.inAvailableList); + } + }; + + pkTests.searchForMatch = function (tuxguitar, searchFilter) { + var pkgs = packagekit.searchPackage ("tuxguitar", searchFilter); + return pkTests.getMatchingPackage (tuxguitar.pkg, pkgs); + }; + + pkTests.testRemovePackage = function (tuxguitar, matchPkg) { + var id = ( matchPkg !== null ? matchPkg.id : tuxguitar.pkg.id); + + // GPII-880: The 'remove' action requires an administrator password. + // Packagekit invokes PolKit authentication, putting up a dialog to + // capture aforesaid password. This needs to be automated. + packagekit.performAction ("remove", id); + matchPkg = pkTests.searchForMatch (tuxguitar, "~installed"); + jqUnit.assertNotNull ("Remove tuxguitar package", matchPkg); + return matchPkg; + }; + + pkTests.testInstallPackage = function (tuxguitar, matchPkg) { + var id = ( matchPkg !== null ? matchPkg.id : tuxguitar.pkg.id); + packagekit.performAction ("install", id); + matchPkg = pkTests.searchForMatch (tuxguitar, "installed"); + jqUnit.assertNotNull ("Install tuxguitar package", matchPkg); + return matchPkg; + }; + + jqUnit.module ("PackageKit Bridge node add-on module"); + + jqUnit.test ( + "Test searchPackage() of 'glib2' with implicit 'none' filter, meaning " + + "installed or available.", function() { + + // Packagekit-glib -- the code this add-on invokes -- itself depends on + // glib2. It must be installed, if this is running. + var pkgs = packagekit.searchPackage ("glib2"); + var found = pkgs.some (pkTests.findGlib2); + jqUnit.assertTrue ("Search 'glib2', implicit 'none' filter", found); + }); + + jqUnit.test ( + "Test searchPackage() 'glib2' with explicit 'none' filter.", function() { + + var pkgs = packagekit.searchPackage ("glib2", "none"); + var found = pkgs.some (pkTests.findGlib2); + jqUnit.assertTrue ("Search 'glib2', explicit 'none' filter", found); + }); + + jqUnit.test ("Test searchFiles() for '/usr/bin/ls'.", function() { + + // The searchFiles() function expects the full path name where the package + // would be installed, even it if is not installed. Check using the + // common utility 'ls'. + var pkgs = packagekit.searchFiles ("/usr/bin/ls"); + jqUnit.assertNotEquals ( + "Search file '/usr/bin/ls', implicit 'none' filter", 0, pkgs.length + ); + jqUnit.assertTrue ("'ls' is installed", pkTests.isInstalled (pkgs[0])); + }); + + jqUnit.test ("Test searchPackage() with 'tuxguitar' comparing installed " + + "vs. available filters.", function() { + + // Test the "installed" vs. "~installed" filters with regards to + // 'tuxguitar', and the array of packages returned by searchPackage() + // using the filters. Use the tuxguitar package, whether installed or + // not, to test against the two arrays. + var tuxguitar = pkTests.initSearchTest(); + pkTests.runInstalledVsAvailableTests (tuxguitar, "Search"); + }); + + jqUnit.test ("Test getPackages() with tuxguitar comparing installed vs. " + + "available filters.", function() { + var tuxguitar = pkTests.initGetTest(); + pkTests.runInstalledVsAvailableTests (tuxguitar, "Get"); + }); + + jqUnit.test ("Test performAction(): 'install' and 'remove' tuxguitar." + + " The order depends on whether tuxguitar is currently " + + "installed.", function() { + + // GPII-880: The 'remove' test requires an administrator password. + // Packagekit invokes PolKit authentication, putting up a dialog to + // capture aforesaid password. This needs to be automated. + + // Using the tuxguitar package: If it's installed, test removing it and + // then (re)install it ... + var matchPkg; + var tuxguitar = pkTests.initTuxguitar(); + if (pkTests.isInstalled (tuxguitar.pkg)) { + matchPkg = pkTests.testRemovePackage (tuxguitar, null); + pkTests.testInstallPackage (tuxguitar, matchPkg); + } + // ...if it isn't installed, test installing it and then removing it. + else { + matchPkg = pkTests.testInstallPackage (tuxguitar, null); + pkTests.testRemovePackage (tuxguitar, matchPkg); + } + }); + + jqUnit.test ("Test updatePackage(): with 'emacspeak'", function() { + + // The package ids of an old and newer version of 'emacspeak'. + // TODO: JS: While the following check against two version of + // 'emacspeak' works on Fedora-20, it may not work on all distros; hence, + // the check that searchPackage() finds the two versions. If so, the test + // is run; otherwise no test is run. Need to find a better way to find + // multiple versions of a package to test against. + var oldEmacspeak = "38.0-5.fc20"; + var newEmacspeak = "39.0-1.fc20"; + var pkgs = packagekit.searchPackage ("emacspseak"); + if (pkgs.length === 2 && + (pkgs[0].version === oldEmacspeak && + pkgs[1].version === newEmacspeak && + pkgs[1].data.indexOf("updates") !== -1)) { + + packagekit.updatePackage (pkgs[1].id); + var currentPkgs = packagekit.searchPackage ("emacspseak","installed"); + jqUnit.assertEquals ("Updating to " + newEmacspeak, + currentPkgs[0].version, newEmacspeak); + + // Restore to previous. + packagekit.removePackage (currentPkgs[0].id); + } + else { + jqUnit.assertTrue ("Cannot test update of emacspeak as there are no " + + "updates", true); + } + }); +}()); diff --git a/gpii/node_modules/packagekit/package.json b/gpii/node_modules/packagekit/package.json new file mode 100644 index 0000000..4b9e10b --- /dev/null +++ b/gpii/node_modules/packagekit/package.json @@ -0,0 +1,19 @@ +{ + "name": "packageKitBridge", + "description": "The packageKitBridge is a Node.js add-on of PackageKit.", + "version": "0.1.0", + "author": "Javier Hernández", + "bugs": "http://wiki.gpii.net/index.php/Main_Page", + "homepage": "http://gpii.net/", + "dependencies": {}, + "licenses": [ + { + "type": "BSD-3-Clause", + "url": "http://www.opensource.org/licenses/BSD-3-Clause" + } + ], + "keywords": ["gpii", "accessibility", "devices", "fluid"], + "repository": "git://github.com:GPII/linux.git", + "main": "./index.js", + "engines": { "node" : ">=0.8" } +} diff --git a/gpii/node_modules/packagekit/packageKitDeviceReporter.js b/gpii/node_modules/packagekit/packageKitDeviceReporter.js new file mode 100644 index 0000000..09b9437 --- /dev/null +++ b/gpii/node_modules/packagekit/packageKitDeviceReporter.js @@ -0,0 +1,49 @@ +/** + * GPII PackageKit Device Reporter + * + * Copyright 2014 Emergya + * + * Licensed under the New BSD license. You may not use this file except in + * compliance with this License. + * + * You may obtain a copy of the License at + * https://github.com/gpii/universal/LICENSE.txt + */ + +(function () { + "use strict"; + + var fluid = require("universal"); + var gpii = fluid.registerNamespace("gpii"); + var packageKit = require("./nodepackagekit/build/Release/nodepackagekit.node"); + + fluid.registerNamespace("gpii.packageKit"); + + fluid.defaults("gpii.packageKit.get", { + gradeNames: "fluid.function", + argumentMap: { + filters: 0 + } + }); + + gpii.packageKit.get = function(filters) { + return { + "id": "gpii.packageKit", + "data": packageKit.getPackages(filters) + }; + }; + + fluid.defaults("gpii.packageKit.find", { + gradeNames: "fluid.function", + argumentMap: { + name: 0 + } + }); + + gpii.packageKit.find = function(name) { + return gpii.packageKit.installedPackagesCache.some(function (pkg) { + return pkg.name === name; + }); + }; + +})(); diff --git a/gpii/node_modules/packagekit/test/all-tests.js b/gpii/node_modules/packagekit/test/all-tests.js new file mode 100644 index 0000000..f5e88b9 --- /dev/null +++ b/gpii/node_modules/packagekit/test/all-tests.js @@ -0,0 +1,28 @@ +/** + * GPII PackageKit Device Reporter Tests + * + * Copyright 2014 Emergya + * + * Licensed under the New BSD license. You may not use this file except in + * compliance with this License. + * + * You may obtain a copy of the License at + * https://github.com/gpii/universal/LICENSE.txt + */ +"use strict"; + +var fluid = require("universal"), + kettle = fluid.require("kettle"); + +kettle.loadTestingSupport(); + +var testIncludes = [ + "./packageKitModuleTests.js", + "./packageKitDeviceReporterTests.js" +]; + +var tests = []; + +fluid.each(testIncludes, function (path) { + tests = tests.concat(fluid.require(path, require)); +}); diff --git a/gpii/node_modules/packagekit/test/packageKitDeviceReporterTests.js b/gpii/node_modules/packagekit/test/packageKitDeviceReporterTests.js new file mode 100644 index 0000000..c9b9a98 --- /dev/null +++ b/gpii/node_modules/packagekit/test/packageKitDeviceReporterTests.js @@ -0,0 +1,49 @@ +/** + * GPII PackageKit Device Reporter Tests + * + * Copyright 2014 Emergya + * + * Licensed under the New BSD license. You may not use this file except in + * compliance with this License. + * + * You may obtain a copy of the License at + * https://github.com/gpii/universal/LICENSE.txt + */ +"use strict"; + +var fluid = require("universal"), + gpii = fluid.registerNamespace("gpii"), + jqUnit = fluid.require("jqUnit"); + +require("packagekit"); +fluid.registerNamespace("gpii.packageKit"); + +var originalCache = fluid.copy(gpii.packageKit.installedPackagesCache); + +jqUnit.module("GPII PackageKit Device Reporter", { + setup: function() { + // mock-up of installedPackagesCache + // + gpii.packageKit.installedPackagesCache = [ + { + "id": "foo_id", + "name": "foo", + "version": "foo_version", + "data": "installed" + } + ]; + }, + teardown: function() { + gpii.packageKit.installedPackagesCache = originalCache; + } +}); + +jqUnit.test("Running tests for PackageKit Device Reporter", function () { + jqUnit.expect(2); + + jqUnit.assertTrue("Check the availability of 'foo' through 'find' method", + gpii.packageKit.find("foo")); + + jqUnit.assertFalse("Look for 'fooo' package", gpii.packageKit.find("fooo")); +}); + diff --git a/gpii/node_modules/packagekit/test/packageKitModuleTests.js b/gpii/node_modules/packagekit/test/packageKitModuleTests.js new file mode 100644 index 0000000..37ca370 --- /dev/null +++ b/gpii/node_modules/packagekit/test/packageKitModuleTests.js @@ -0,0 +1,41 @@ +/** + * GPII PackageKit Device Reporter Tests + * + * Copyright 2014 Emergya + * + * Licensed under the New BSD license. You may not use this file except in + * compliance with this License. + * + * You may obtain a copy of the License at + * https://github.com/gpii/universal/LICENSE.txt + */ +"use strict"; + +var fluid = require("universal"), + jqUnit = fluid.require("jqUnit"); + +require("packagekit"); + +var gpii = fluid.registerNamespace("gpii"); +var packageKit = fluid.registerNamespace("gpii.packageKit"); + +jqUnit.module("GPII PackageKit Module"); + +jqUnit.test("Running tests for PackageKit Device Reporter", function () { + jqUnit.expect(4); + + // Check that the bridge is loaded and required methods are available + // + var methods = ["get", "find"]; + for (var method in methods) { + jqUnit.assertTrue("Checking availability of method '" + method + "'", + (methods[method] in packageKit)); + } + + jqUnit.assertDeepEq("Checking that 'get' reports both 'id' and 'data'", + ["id", "data"], + Object.keys(gpii.packageKit.get("installed"))); + + jqUnit.assertTrue("Checking that 'get' report installed packages", + (gpii.packageKit.get("installed").data.length > 0)); +}); diff --git a/index.js b/index.js index f62cda2..5350ca3 100644 --- a/index.js +++ b/index.js @@ -19,7 +19,13 @@ var fluid = require("universal"); fluid.module.register("gpii-linux", __dirname, require); +// Settings Handlers +// fluid.require("./gpii/node_modules/gsettingsBridge", require); fluid.require("./gpii/node_modules/orca", require); fluid.require("./gpii/node_modules/alsa", require); fluid.require("./gpii/node_modules/xrandr", require); + +// Device Reporters +// +fluid.require("./gpii/node_modules/packagekit", require); diff --git a/tests/UnitTests.sh b/tests/UnitTests.sh index 499cc3c..4209d89 100755 --- a/tests/UnitTests.sh +++ b/tests/UnitTests.sh @@ -30,6 +30,13 @@ cd ../gpii/node_modules/orca/test node orcaSettingsHandlerTests.js popd +pushd . +cd ../gpii/node_modules/packagekit/test/ +node .//all-tests.js +cd ../nodepackagekit +node nodepackagekit_test.js +popd + # These XRANDR tests crash out on my system (AMB - Fedora 19 64-bit in VMWare Workstation 10.0.1 on Windows 7 64-bit) node ../gpii/node_modules/xrandr/nodexrandr/nodexrandr_tests.js node ../gpii/node_modules/xrandr/test/xrandrSettingsHandlerTests.js