summary refs log tree commit diff
path: root/nixos/gui/chrome/content/nixos.js
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/gui/chrome/content/nixos.js')
-rw-r--r--nixos/gui/chrome/content/nixos.js255
1 files changed, 255 insertions, 0 deletions
diff --git a/nixos/gui/chrome/content/nixos.js b/nixos/gui/chrome/content/nixos.js
new file mode 100644
index 000000000000..63a3c16a573f
--- /dev/null
+++ b/nixos/gui/chrome/content/nixos.js
@@ -0,0 +1,255 @@
+
+function NixOS () {
+  var env = Components.classes["@mozilla.org/process/environment;1"].
+    getService(Components.interfaces.nsIEnvironment);
+
+  if (env.exists("NIXOS"))
+    this.nixos = env.get("NIXOS");
+  if (env.exists("NIXOS_CONFIG"))
+    this.config = env.get("NIXOS_CONFIG");
+  if (env.exists("NIXPKGS"))
+    this.nixpkgs = env.get("NIXPKGS");
+  if (env.exists("mountPoint"))
+    this.root = env.get("mountPoint");
+  if (env.exists("NIXOS_OPTION"))
+    this.optionBin = env.get("NIXOS_OPTION");
+  this.option = new Option("options", this, null);
+};
+
+NixOS.prototype = {
+  root: "",
+  nixos: "/etc/nixos/nixos",
+  nixpkgs: "/etc/nixos/nixpkgs",
+  config: "/etc/nixos/configuration.nix",
+  instantiateBin: "/run/current-system/sw/bin/nix-instantiate",
+  optionBin: "/run/current-system/sw/bin/nixos-option",
+  tmpFile: "nixos-gui",
+  option: null
+};
+
+function Option (name, context, parent) {
+  this.name = name;
+  this.context_ = context;
+  if (parent == null)
+    this.path = "";
+  else if (parent.path == "")
+    this.path = name;
+  else
+    this.path = parent.path + "." + name;
+};
+
+Option.prototype = {
+  load: function () {
+    var env = "";
+    env += "'NIXOS=" + this.context_.root + this.context_.nixos + "' ";
+    env += "'NIXOS_PKGS=" + this.context_.root + this.context_.nixpkgs + "' ";
+    env += "'NIXOS_CONFIG=" + this.context_.config + "' ";
+    var out = makeTempFile(this.context_.tmpFile);
+    var prog = this.context_.optionBin + " 2>&1 >" + out.path + " ";
+    var args = " --xml " + this.path;
+
+    runProgram(/*env + */ prog + args);
+    var xml = readFromFile(out);
+    out.remove(false);
+
+    // jQuery does a stack overflow when converting a huge XML to a DOM.
+    var dom = DOMParser().parseFromString(xml, "text/xml");
+    var xmlAttrs = $("expr > attrs > attr", dom);
+
+    this.isOption = xmlAttrs.first().attr("name") == "_isOption";
+
+    if (!this.isOption)
+      this.loadSubOptions(xmlAttrs);
+    else
+      this.loadOption(xmlAttrs);
+    this.isLoaded = true;
+  },
+
+  loadSubOptions:  function (xmlAttrs) {
+    var cur = this;
+    var attrs = new Array();
+
+    xmlAttrs.each(
+      function (index) {
+        var name = $(this).attr("name");
+        var attr = new Option(name, cur.context_, cur);
+        attrs.push(attr);
+      }
+    );
+
+    this.subOptions = attrs;
+  },
+
+  optionAttributeMap: {
+    _isOption: function (cur, v) { },
+    value: function (cur, v) { cur.value = xml2nix($(v).children().first()); },
+    default: function (cur, v) { cur.defaultValue = xml2nix($(v).children().first()); },
+    example: function (cur, v) { cur.example = xml2nix($(v).children().first()); },
+    description: function (cur, v) { cur.description = this.string(v); },
+    typename: function (cur, v) { cur.typename = this.string(v); },
+    options: function (cur, v) { cur.loadSubOptions($("attrs", v).children()); },
+    declarations: function (cur, v) { cur.declarations = this.pathList(v); },
+    definitions: function (cur, v) { cur.definitions = this.pathList(v); },
+
+    string: function (v) {
+      return $(v).children("string").first().attr("value");
+    },
+
+    pathList: function (v) {
+      var list = [];
+      $(v).children("list").first().children().each(
+        function (idx) {
+          list.push($(this).attr("value"));
+        }
+      );
+      return list;
+    }
+  },
+
+
+  loadOption: function (attrs) {
+    var cur = this;
+
+    attrs.each(
+      function (index) {
+        var name = $(this).attr("name");
+        log("loadOption: " + name);
+        cur.optionAttributeMap[name](cur, this);
+      }
+    );
+  },
+
+  // keep the context under which this option has been used.
+  context_: null,
+  // name of the option.
+  name: "",
+  // result of nixos-option.
+  value: null,
+  typename: null,
+  defaultValue: null,
+  example: null,
+  description: "",
+  declarations: [],
+  definitions: [],
+  // path to reach this option
+  path: "",
+
+  // list of options accessible from here.
+  isLoaded: false,
+  isOption: false,
+  subOptions: []
+};
+
+var xml2nix_pptable = {
+  attrs: function (node, depth, pp) {
+    var children = node.children().not(
+      function () {
+        var name = $(this).attr("name");
+        return name.charAt(0) == "_";
+      }
+    );
+    var c = 0;
+    var out = "";
+    out += "{";
+    depth += 1;
+    children.each(
+      function (idx) {
+        c += 1;
+        out += pp.indent(depth);
+        out += pp.dispatch($(this), depth, pp);
+      }
+    );
+    depth -= 1;
+    if (c > 0)
+      out += this.indent(depth);
+    else
+      out += " ";
+    out += "}";
+    return out;
+  },
+  list: function (node, depth, pp) {
+    var children = node.children();
+    var c = 0;
+    var out = "";
+    out += "[";
+    depth += 1;
+    children.each(
+      function (idx) {
+        c += 1;
+        out += pp.indent(depth);
+        out += pp.dispatch($(this), depth, pp);
+      }
+    );
+    depth -= 1;
+    if (c > 0)
+      out += this.indent(depth);
+    else
+      out += " ";
+    out += "]";
+    return out;
+  },
+  attr: function (node, depth, pp) {
+    var name = node.attr("name");
+    var out = "";
+    var val = "";
+    out += name + " = ";
+    depth += 1;
+    val = pp.dispatch(node.children().first(), depth, pp);
+    out += val;
+    depth -= 1;
+    out += ";";
+    return out;
+  },
+  string: function (node, depth, pp) {
+    return "\"" + node.attr("value") + "\"";
+  },
+  path: function (node, depth, pp) {
+    return node.attr("value");
+  },
+  bool: function (node, depth, pp) {
+    return node.attr("value");
+  },
+  "int": function (node, depth, pp) {
+    return node.attr("value");
+  },
+  null: function (node, depth, pp) {
+    return "null";
+  },
+  derivation: function (node, depth, pp) {
+    return "<derivation>";
+  },
+  function: function (node, depth, pp) {
+    return "<function>";
+  },
+  unevaluated: function (node, depth, pp) {
+    return "<unevaluated>";
+  },
+
+  dispatch: function (node, depth, pp) {
+    for (var key in pp)
+    {
+      if(node.is(key))
+      {
+        // log(this.indent(depth) + "dispatch: " + key);
+        var out = pp[key](node, depth, pp);
+        // log(this.indent(depth) + "dispatch: => " + out);
+        return out;
+      }
+    }
+    return "<dispatch-error>";
+  },
+  indent: function (depth) {
+    var ret = "\n";
+    while (depth--)
+      ret += "  ";
+    return ret;
+  }
+};
+
+function xml2nix(node) {
+  var depth = 0;
+  var pp = xml2nix_pptable;
+  var out = pp.dispatch(node, depth, pp);
+  // log("pretty:\n" + out);
+  return out;
+}