From efe16d2b85fd7efc546f840dd380f382f5865622 Mon Sep 17 00:00:00 2001
From: "A. Wilcox" <AWilcox@Wilcox-Tech.com>
Date: Sat, 13 Jun 2020 17:58:58 -0500
Subject: hscript: Stub unfinished implementation of 'bootloader' key

---
 hscript/meta.cc     | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 hscript/meta.hh     | 11 ++++++
 hscript/script.cc   |  5 +++
 hscript/script_i.hh | 13 ++++++++
 4 files changed, 125 insertions(+)

diff --git a/hscript/meta.cc b/hscript/meta.cc
index c3308d2..75f4ca1 100644
--- a/hscript/meta.cc
+++ b/hscript/meta.cc
@@ -676,3 +676,99 @@ Key *Version::parseFromData(const std::string &data,
 bool Version::execute() const {
     return true;
 }
+
+
+Key *Bootloader::parseFromData(const std::string &data,
+                               const ScriptLocation &pos, int *errors, int *,
+                               const Script *script) {
+    if(data.find_first_of(" ") != std::string::npos) {
+        if(errors) *errors += 1;
+        output_error(pos, "bootloader: invalid bootloader", data);
+        return nullptr;
+    }
+
+    return new Bootloader(script, pos, data);
+}
+
+const std::string my_arch(const Horizon::Script *script) {
+    const Key *arch_key = script->getOneValue("arch");
+    if(arch_key != nullptr) {
+        const Arch *real_arch = dynamic_cast<const Arch *>(arch_key);
+        return real_arch->value();
+    } else {
+#   if defined(__powerpc64__)
+        return "ppc64";
+#   elif defined(__powerpc__)
+        return "ppc";
+#   elif defined(__aarch64__)
+        return "aarch64";
+#   elif defined(__arm__)
+        return "armv7";
+#   elif defined(__i386__)
+        return "pmmx";
+#   elif defined(__x86_64__)
+        return "x86_64";
+#   else
+#       error Unknown architecture.
+#   endif
+    }
+}
+
+bool Bootloader::validate() const {
+    const std::string arch = my_arch(script);
+
+    /* 'true' and 'false' are always valid. */
+    if(_value == "true" || _value == "false") return true;
+
+    if(arch == "ppc64") {
+        const static std::set<std::string> valid_ppc64 = {"grub-ieee1275"};
+        return valid_ppc64.find(this->value()) != valid_ppc64.end();
+    } else if(arch == "ppc") {
+        const static std::set<std::string> valid_ppc = {"grub-ieee1275",
+                                                        "iquik"};
+        return valid_ppc.find(this->value()) != valid_ppc.end();
+    } else if(arch == "aarch64") {
+        const static std::set<std::string> valid_arm64 = {"grub-efi"};
+        return valid_arm64.find(this->value()) != valid_arm64.end();
+    } else if(arch == "armv7") {
+        const static std::set<std::string> valid_arm = {};
+        return valid_arm.find(this->value()) != valid_arm.end();
+    } else if(arch == "pmmx") {
+        const static std::set<std::string> valid_pmmx = {"grub-bios",
+                                                         "grub-efi"};
+        return valid_pmmx.find(this->value()) != valid_pmmx.end();
+    } else if(arch == "x86_64") {
+        const static std::set<std::string> valid_x86 = {"grub-bios",
+                                                        "grub-efi"};
+        return valid_x86.find(this->value()) != valid_x86.end();
+    } else {
+        output_error(pos, "bootloader: unknown architecture", arch);
+        return false;
+    }
+}
+
+bool Bootloader::execute() const {
+    /* Nothing to do. */
+    if(_value == "false") return true;
+
+    const std::string arch = my_arch(script);
+    std::string method;
+
+    if(_value == "true") {
+        if(arch == "ppc64" || arch == "ppc") {
+            method = "grub-ieee1275";
+        } else if(arch == "aarch64") {
+            method = "grub-efi";
+        } else if(arch == "x86_64" || arch == "pmmx") {
+            if(fs::exists("/sys/firmware/efi")) method = "grub-efi";
+            else method = "grub-bios";
+        } else {
+            output_error(pos, "bootloader: no default for architecture", arch);
+            return false;
+        }
+    } else {
+        method = _value;
+    }
+
+    return false;
+}
diff --git a/hscript/meta.hh b/hscript/meta.hh
index ab22f1f..912cabf 100644
--- a/hscript/meta.hh
+++ b/hscript/meta.hh
@@ -138,6 +138,17 @@ public:
     bool execute() const override;
 };
 
+class Bootloader : public StringKey {
+private:
+    Bootloader(const Script *_s, const ScriptLocation &_p,
+               const std::string &_v) : StringKey(_s, _p, _v) {}
+public:
+    static Key *parseFromData(const std::string &, const ScriptLocation &,
+                              int *, int *, const Script *);
+    bool validate() const override;
+    bool execute() const override;
+};
+
 }
 }
 
diff --git a/hscript/script.cc b/hscript/script.cc
index 8fc15f7..897d5d4 100644
--- a/hscript/script.cc
+++ b/hscript/script.cc
@@ -52,6 +52,7 @@ const std::map<std::string, key_parse_fn> valid_keys = {
     {"signingkey", &SigningKey::parseFromData},
     {"svcenable", &SvcEnable::parseFromData},
     {"version", &Version::parseFromData},
+    {"bootloader", &Bootloader::parseFromData},
 
     {"netconfigtype", &NetConfigType::parseFromData},
     {"netaddress", &NetAddress::parseFromData},
@@ -125,6 +126,8 @@ bool Script::ScriptPrivate::store_key(const std::string &key_name, Key *obj,
         return store_svcenable(obj, pos, errors, warnings, opts);
     } else if(key_name == "version") {
         return store_version(obj, pos, errors, warnings, opts);
+    } else if(key_name == "bootloader") {
+        return store_bootloader(obj, pos, errors, warnings, opts);
     } else if(key_name == "username") {
         return store_username(obj, pos, errors, warnings, opts);
     } else if(key_name == "useralias") {
@@ -386,6 +389,8 @@ const Keys::Key *Script::getOneValue(std::string name) const {
         return this->internal->keymap.get();
     } else if(name == "version") {
         return this->internal->version.get();
+    } else if(name == "bootloader") {
+        return this->internal->boot.get();
     } else if(name == "firmware") {
 #ifdef NON_LIBRE_FIRMWARE
         return this->internal->firmware.get();
diff --git a/hscript/script_i.hh b/hscript/script_i.hh
index c6dbb54..b223608 100644
--- a/hscript/script_i.hh
+++ b/hscript/script_i.hh
@@ -63,6 +63,8 @@ struct Script::ScriptPrivate {
     std::unique_ptr<Timezone> tzone;
     /*! The version of Adélie to install. */
     std::unique_ptr<Version> version;
+    /*! The desired bootloader configuration. */
+    std::unique_ptr<Bootloader> boot;
 
     /*! Network addressing configuration */
     std::vector< std::unique_ptr<NetAddress> > addresses;
@@ -278,6 +280,17 @@ struct Script::ScriptPrivate {
         return true;
     }
 
+    bool store_bootloader(Key *obj, const ScriptLocation &pos, int *errors,
+                          int *, const ScriptOptions &) {
+        if(boot) {
+            DUPLICATE_ERROR(boot, "bootloader", boot->value())
+            return false;
+        }
+        std::unique_ptr<Bootloader> b(dynamic_cast<Bootloader *>(obj));
+        boot = std::move(b);
+        return true;
+    }
+
     bool store_username(Key *obj, const ScriptLocation &pos, int *errors, int *,
                         const ScriptOptions &) {
         if(accounts.size() >= 255) {
-- 
cgit v1.2.3-70-g09d2