From 8b00a5779ace2b919f6d9f31fb50d37086a78914 Mon Sep 17 00:00:00 2001
From: "A. Wilcox" <AWilcox@Wilcox-Tech.com>
Date: Tue, 26 May 2020 02:42:30 -0500
Subject: hscript: Implement (undocumented, untested) 'version' key

---
 hscript/meta.cc     | 18 ++++++++++++++++++
 hscript/meta.hh     | 10 ++++++++++
 hscript/script.cc   |  7 +++++++
 hscript/script_i.hh | 15 ++++++++++++++-
 hscript/script_v.cc | 26 ++++++++++++++------------
 5 files changed, 63 insertions(+), 13 deletions(-)

(limited to 'hscript')

diff --git a/hscript/meta.cc b/hscript/meta.cc
index fd3e69b..ab8bdb5 100644
--- a/hscript/meta.cc
+++ b/hscript/meta.cc
@@ -655,3 +655,21 @@ bool SvcEnable::execute() const {
 #endif  /* HAS_INSTALL_ENV */
     return true;  /* LCOV_EXCL_LINE */
 }
+
+Key *Version::parseFromData(const std::string &data,
+                            const ScriptLocation &pos, int *errors, int *,
+                            const Script *script) {
+    const static std::string valid_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890.-_";
+
+    if(data.find_first_not_of(valid_chars) != std::string::npos) {
+        if(errors) *errors += 1;
+        output_error(pos, "version: invalid version", data);
+        return nullptr;
+    }
+
+    return new Version(script, pos, data);
+}
+
+bool Version::execute() const {
+    return true;
+}
diff --git a/hscript/meta.hh b/hscript/meta.hh
index b885e99..ab22f1f 100644
--- a/hscript/meta.hh
+++ b/hscript/meta.hh
@@ -128,6 +128,16 @@ public:
     bool execute() const override;
 };
 
+class Version : public StringKey {
+private:
+    Version(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 execute() const override;
+};
+
 }
 }
 
diff --git a/hscript/script.cc b/hscript/script.cc
index a3fb512..8fc15f7 100644
--- a/hscript/script.cc
+++ b/hscript/script.cc
@@ -51,6 +51,7 @@ const std::map<std::string, key_parse_fn> valid_keys = {
     {"repository", &Repository::parseFromData},
     {"signingkey", &SigningKey::parseFromData},
     {"svcenable", &SvcEnable::parseFromData},
+    {"version", &Version::parseFromData},
 
     {"netconfigtype", &NetConfigType::parseFromData},
     {"netaddress", &NetAddress::parseFromData},
@@ -122,6 +123,8 @@ bool Script::ScriptPrivate::store_key(const std::string &key_name, Key *obj,
         return true;
     } else if(key_name == "svcenable") {
         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 == "username") {
         return store_username(obj, pos, errors, warnings, opts);
     } else if(key_name == "useralias") {
@@ -381,6 +384,8 @@ const Keys::Key *Script::getOneValue(std::string name) const {
         return this->internal->lang.get();
     } else if(name == "keymap") {
         return this->internal->keymap.get();
+    } else if(name == "version") {
+        return this->internal->version.get();
     } else if(name == "firmware") {
 #ifdef NON_LIBRE_FIRMWARE
         return this->internal->firmware.get();
@@ -410,6 +415,8 @@ const std::vector<Keys::Key *> Script::getValues(std::string name) const {
         for(auto &repo : this->internal->repos) values.push_back(repo.get());
     } else if(name == "signing_key") {
         for(auto &key : this->internal->repo_keys) values.push_back(key.get());
+    } else if(name == "svcenable") {
+        for(auto &svc : this->internal->svcs_enable) values.push_back(svc.get());
     } else if(name == "username" || name == "useralias" || name == "userpw" ||
               name == "usericon" || name == "usergroups") {
         /* XXX */
diff --git a/hscript/script_i.hh b/hscript/script_i.hh
index 2a86d71..b219579 100644
--- a/hscript/script_i.hh
+++ b/hscript/script_i.hh
@@ -3,7 +3,7 @@
  * libhscript, the HorizonScript library for
  * Project Horizon
  *
- * Copyright (c) 2019 Adélie Linux and contributors.  All rights reserved.
+ * Copyright (c) 2019-2020 Adélie Linux and contributors.  All rights reserved.
  * This code is licensed under the AGPL 3.0 license, as noted in the
  * LICENSE-code file in the root directory of this repository.
  *
@@ -61,6 +61,8 @@ struct Script::ScriptPrivate {
     std::unique_ptr<Keymap> keymap;
     /*! The system timezone. */
     std::unique_ptr<Timezone> tzone;
+    /*! The version of Adélie to install. */
+    std::unique_ptr<Version> version;
 
     /*! Network addressing configuration */
     std::vector< std::unique_ptr<NetAddress> > addresses;
@@ -264,6 +266,17 @@ struct Script::ScriptPrivate {
         return true;
     }
 
+    bool store_version(Key *obj, const ScriptLocation &pos, int *errors, int *,
+                       const ScriptOptions &) {
+        if(version) {
+            DUPLICATE_ERROR(version, "version", version->value())
+            return false;
+        }
+        std::unique_ptr<Version> v(dynamic_cast<Version *>(obj));
+        version = std::move(v);
+        return true;
+    }
+
     bool store_username(Key *obj, const ScriptLocation &pos, int *errors, int *,
                         const ScriptOptions &) {
         if(accounts.size() >= 255) {
diff --git a/hscript/script_v.cc b/hscript/script_v.cc
index b91af8d..173bb50 100644
--- a/hscript/script_v.cc
+++ b/hscript/script_v.cc
@@ -107,11 +107,16 @@ int validate_one_account(const std::string &name, UserDetail *detail) {
  */
 bool add_default_repos(std::vector<std::unique_ptr<Repository>> &repos,
                        const Script *s, bool firmware = false) {
+    std::string base_url = "https://distfiles.adelielinux.org/adelie/";
+    const ScriptLocation p{"internal", 0};
+    const Key *ver = s->getOneValue("version");
+    if(ver != nullptr) {
+        base_url += dynamic_cast<const StringKey *>(ver)->value() + "/";
+    } else {
+        base_url += "stable/";
+    }
     Repository *sys_key = dynamic_cast<Repository *>(
-        Repository::parseFromData(
-            "https://distfiles.adelielinux.org/adelie/stable/system", {"", 0},
-            nullptr, nullptr, s
-        )
+        Repository::parseFromData(base_url + "system", p, nullptr, nullptr, s)
     );
     if(!sys_key) {
         output_error("internal", "failed to create default system repository");
@@ -120,10 +125,7 @@ bool add_default_repos(std::vector<std::unique_ptr<Repository>> &repos,
     std::unique_ptr<Repository> sys_repo(sys_key);
     repos.push_back(std::move(sys_repo));
     Repository *user_key = dynamic_cast<Repository *>(
-        Repository::parseFromData(
-            "https://distfiles.adelielinux.org/adelie/stable/user", {"", 0},
-            nullptr, nullptr, s
-        )
+        Repository::parseFromData(base_url + "user", p, nullptr, nullptr, s)
     );
     if(!user_key) {
         output_error("internal", "failed to create default user repository");
@@ -138,7 +140,7 @@ bool add_default_repos(std::vector<std::unique_ptr<Repository>> &repos,
         Repository *fw_key = dynamic_cast<Repository *>(
             Repository::parseFromData(
                 "https://distfiles.apkfission.net/adelie-stable/nonfree",
-                0, nullptr, nullptr, s
+                {"internal", 0}, nullptr, nullptr, s
             )
         );
         if(!fw_key) {
@@ -163,8 +165,8 @@ bool add_default_repo_keys(std::vector<std::unique_ptr<SigningKey>> &keys,
                            const Script *s, bool firmware = false) {
     SigningKey *key = dynamic_cast<SigningKey *>(
         SigningKey::parseFromData(
-            "/etc/apk/keys/packages@adelielinux.org.pub", {"", 0},
-            nullptr, nullptr, s)
+            "/etc/apk/keys/packages@adelielinux.org.pub",
+            {"internal", 0}, nullptr, nullptr, s)
     );
     if(!key) {
         output_error("internal", "failed to create default repository signing key");
@@ -178,7 +180,7 @@ bool add_default_repo_keys(std::vector<std::unique_ptr<SigningKey>> &keys,
     if(firmware) {
         SigningKey *fkey = dynamic_cast<SigningKey *>(SigningKey::parseFromData(
             "/etc/apk/keys/packages@pleroma.apkfission.net-5ac0b300.rsa.pub",
-                                                  {"", 0}, nullptr, nullptr, s)
+            {"internal", 0}, nullptr, nullptr, s)
         );
         if(!fkey) {
             output_error("internal", "failed to create firmware signing key");
-- 
cgit v1.2.3-70-g09d2