diff --git a/gui/README b/gui/README new file mode 100644 index 00000000000..7eee9040e3f --- /dev/null +++ b/gui/README @@ -0,0 +1,19 @@ +This file should become a nix expression. + +you need to: +- download the latest jQuery from: + http://jqueryjs.googlecode.com/files/jquery-1.3.2.js + SHA1 Checksum: f0b95e99225f314fbe37ccf6b74ce2f916c517de + +- install 'xulrunner' with nix: + nix-env -i xulrunner + +- install and add nix-intantiate in your path + +- have /etc/nixos/nixpkgs +- have /etc/nixos/nixos + + +to run it, either: +- cd /etc/nixos/nixos/gui; ./nixos-gui +- xulrunner /etc/nixos/nixos/gui/application.ini diff --git a/gui/application.ini b/gui/application.ini new file mode 100644 index 00000000000..0da5e498dad --- /dev/null +++ b/gui/application.ini @@ -0,0 +1,35 @@ +[App] +; +; This field specifies your organization's name. This field is recommended, +; but optional. +Vendor=NixOS +; +; This field specifies your application's name. This field is required. +Name=NixOS-gui +; +; This field specifies your application's version. This field is optional. +Version=0.0 +; +; This field specifies your application's build ID (timestamp). This field is +; required. +BuildID=20090925 +; +; This field specifies a compact copyright notice for your application. This +; field is optional. +;Copyright= +; +; This ID is just an example. Every XUL app ought to have it's own unique ID. +; You can use the microsoft "guidgen" or "uuidgen" tools, or go on +; irc.mozilla.org and /msg botbot uuid. This field is optional. +;ID= + +[Gecko] +; +; This field is required. It specifies the minimum Gecko version that this +; application requires. +MinVersion=1.9a5 +; +; This field is optional. It specifies the maximum Gecko version that this +; application requires. It should be specified if your application uses +; unfrozen interfaces. +;MaxVersion=1.9.0.* diff --git a/gui/chrome/chrome.manifest b/gui/chrome/chrome.manifest new file mode 100644 index 00000000000..6b524807eaa --- /dev/null +++ b/gui/chrome/chrome.manifest @@ -0,0 +1 @@ +content nixos-gui content/nixos-gui/ diff --git a/gui/chrome/content/nixos-gui/io.js b/gui/chrome/content/nixos-gui/io.js new file mode 100644 index 00000000000..3e3b080b814 --- /dev/null +++ b/gui/chrome/content/nixos-gui/io.js @@ -0,0 +1,74 @@ +function makeTempFile(prefix) +{ + var file = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("TmpD", Components.interfaces.nsIFile); + file.append(prefix || "xulrunner"); + file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0664); + return file; +} + +function writeToFile(file, data) +{ + // file is nsIFile, data is a string + var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"] + .createInstance(Components.interfaces.nsIFileOutputStream); + + // use 0x02 | 0x10 to open file for appending. + foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate + foStream.write(data, data.length); + foStream.close(); +} + +function readFromFile(file) +{ + // |file| is nsIFile + var data = ""; + var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"] + .createInstance(Components.interfaces.nsIFileInputStream); + var sstream = Components.classes["@mozilla.org/scriptableinputstream;1"] + .createInstance(Components.interfaces.nsIScriptableInputStream); + fstream.init(file, -1, 0, 0); + sstream.init(fstream); + + var str = sstream.read(4096); + while (str.length > 0) { + data += str; + str = sstream.read(4096); + } + + sstream.close(); + fstream.close(); + + return data; +} + +function runProgram(commandLine) +{ + // create an nsILocalFile for the executable + var file = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + file.initWithPath("/bin/sh"); + + // create an nsIProcess + var process = Components.classes["@mozilla.org/process/util;1"] + .createInstance(Components.interfaces.nsIProcess); + process.init(file); + + // Run the process. + // If first param is true, calling thread will be blocked until + // called process terminates. + // Second and third params are used to pass command-line arguments + // to the process. + var args = ["-c", commandLine]; + process.run(true, args, args.length); +} + +// only for testing... +function testIO() +{ + var f = makeTempFile(); + writeToFile(f, "essai\ntest"); + alert(readFromFile(f)); + runProgram("zenity --info"); +} diff --git a/gui/chrome/content/nixos-gui/main.js b/gui/chrome/content/nixos-gui/main.js new file mode 100644 index 00000000000..baa934e43e2 --- /dev/null +++ b/gui/chrome/content/nixos-gui/main.js @@ -0,0 +1,171 @@ +var COPYCOL = 2; +var gOptionListView = new treeView(["opt-success","opt-name","opt-desc"], + COPYCOL); + +// Run xulrunner application.ini -jsconsole -console, to see messages. +function log(str) +{ + Components.classes['@mozilla.org/consoleservice;1'] + .getService(Components.interfaces.nsIConsoleService) + .logStringMessage(str); +} + + +// return the DOM of the value returned by nix-instantiate +function dumpOptions(path) +{ + var nixInstantiate = "nix-instantiate"; // "@nix@/bin/nix-instantiate"; + var nixos = "/etc/nixos/nixos/default.nix"; // "@nixos@/default.nix"; + + var o = makeTempFile("nixos-options"); + + path = "eval.options" + (path? "." + path : ""); + log("retrieve options from: " + path); + + runProgram(nixInstantiate+" "+nixos+" -A "+path+" --eval-only --strict --xml 2>/dev/null | tr -d '' >" + o.path); + + var xml = readFromFile(o); + o.remove(false); + + // jQuery does a stack overflow when converting the XML to a DOM. + var dom = DOMParser().parseFromString(xml, "text/xml"); + + log("return dom"); + return dom; +} + + +// Pretty print Nix values. +function nixPP(value, level) +{ + function indent(level) { ret = ""; while (level--) ret+= " "; return ret; } + + if (!level) level = 0; + var ret = ""; + if (value.is("attrs")) { + var content = ""; + value.children().each(function (){ + var name = $(this).attr("name"); + var value = nixPP($(this).children(), level + 1); + content += indent(level + 1) + name + " = " + value + ";\n"; + }); + ret = "{\n" + content + indent(level) + "}"; + } + else if (value.is("list")) { + var content = ""; + value.children().each(function (){ + content += indent(level + 1) + "(" + nixPP($(this), level + 1) + ")\n"; + }); + ret = "[\n" + content + indent(level) + "]"; + } + else if (value.is("bool")) + ret = (value.attr("value") == "true"); + else if (value.is("string")) + ret = '"' + value.attr("value") + '"'; + else if (value.is("path")) + ret = value.attr("value"); + else if (value.is("int")) + ret = parseInt(value.attr("value")); + else if (value.is("derivation")) + ret = value.attr("outPath"); + else if (value.is("function")) + ret = ""; + else { + var content = ""; + value.children().each(function (){ + content += indent(level + 1) + "(" + nixPP($(this), level + 1) + ")\n"; + }); + ret = ""; + } + return ret; +} + +// Function used to reproduce the select operator on the XML DOM. +// It return the value contained in the targeted attribute. +function nixSelect(attrs, selector) +{ + var names = selector.split("."); + var value = $(attrs); + for (var i = 0; i < names.length; i++) { + log(nixPP(value) + "." + names[i]); + if (value.is("attrs")) + value = value.children("attr[name='" + names[i] + "']").children(); + else { + log("Cannot do an attribute selection."); + break + } + } + + log("nixSelect return: " + nixPP(value)); + + var ret; + if (value.is("attrs") || value.is("list")) + ret = value; + else if (value.is("bool")) + ret = value.attr("value") == "true"; + else if (value.is("string")) + ret = value.attr("value"); + else if (value.is("int")) + ret = parseInt(value.attr("value")); + else if (value.is("derivation")) + ret = value.attr("outPath"); + else if (value.is("function")) + ret = ""; + + return ret; +} + +var gProgressBar; +function setProgress(current, max) +{ + if (gProgressBar) { + gProgressBar.value = 100 * current / max; + log("progress: " + gProgressBar.value + "%"); + } + else + log("unknow progress bar"); +} + +// fill the list of options +function setOptionList(optionDOM) +{ + var options = $("attrs", optionDOM).filter(function () { + return $(this) + .children("attr[name='_type']") + .children("string[value='option']") + .length != 0; + }); + + var max = options.length; + + log("Number of options: " + max); + + setProgress(0, max); + gOptionListView.clear(); + options.each(function (index){ + var success = nixSelect(this, "config.success"); + var name = nixSelect(this, "name"); + var desc = nixSelect(this, "description"); + if (success && name && desc) { + log("Add option '" + name + "' in the list."); + gOptionListView.addRow([success, name, desc]); + } + else + log("A problem occur while scanning an option."); + setProgress(index + 1, max); + }); +} + + +function onload() +{ + var optionList = document.getElementById("option-list"); + gProgressBar = document.getElementById("progress-bar"); + setProgress(0, 1); + optionList.view = gOptionListView; + + // try to avoid blocking the rendering, unfortunately this is not perfect. + setTimeout(function (){ + setOptionList(dumpOptions("hardware"));} + , 100); +} diff --git a/gui/chrome/content/nixos-gui/myviewer.xul b/gui/chrome/content/nixos-gui/myviewer.xul new file mode 100644 index 00000000000..c0c2bd6f822 --- /dev/null +++ b/gui/chrome/content/nixos-gui/myviewer.xul @@ -0,0 +1,30 @@ + + + + + + + + +