summaryrefslogtreecommitdiff
path: root/tools/minicargo/manifest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/minicargo/manifest.cpp')
-rw-r--r--tools/minicargo/manifest.cpp290
1 files changed, 290 insertions, 0 deletions
diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp
new file mode 100644
index 00000000..69660702
--- /dev/null
+++ b/tools/minicargo/manifest.cpp
@@ -0,0 +1,290 @@
+/*
+ */
+#include "manifest.h"
+#include "toml.h"
+#include "debug.h"
+#include "helpers.h"
+#include <cassert>
+#include <algorithm>
+#include <sstream>
+#ifdef _WIN32
+#include <Windows.h>
+#endif
+
+static ::std::vector<::std::shared_ptr<PackageManifest>> g_loaded_manifests;
+
+PackageManifest::PackageManifest()
+{
+}
+
+namespace
+{
+ void target_edit_from_kv(PackageTarget& target, TomlKeyValue& kv, unsigned base_idx);
+}
+
+PackageManifest PackageManifest::load_from_toml(const ::std::string& path)
+{
+ PackageManifest rv;
+ rv.m_manmifest_path = path;
+
+ TomlFile toml_file(path);
+
+ for(auto key_val : toml_file)
+ {
+ assert(key_val.path.size() > 0);
+ const auto& section = key_val.path[0];
+ if( section == "package" )
+ {
+ assert(key_val.path.size() > 1);
+ const auto& key = key_val.path[1];
+ if(key == "authors")
+ {
+ // TODO: Use the `authors` key
+ }
+ else if( key == "name" )
+ {
+ if(rv.m_name != "" )
+ {
+ // TODO: Warn/error
+ throw ::std::runtime_error("Package name set twice");
+ }
+ rv.m_name = key_val.value.as_string();
+ if(rv.m_name == "")
+ {
+ // TODO: Error
+ throw ::std::runtime_error("Package name cannot be empty");
+ }
+ }
+ else if( key == "version" )
+ {
+ rv.m_version = PackageVersion::from_string(key_val.value.as_string());
+ }
+ else
+ {
+ // Unknown value in `package`
+ throw ::std::runtime_error("Unknown key `" + key + "` in [package]");
+ }
+ }
+ else if( section == "lib" )
+ {
+ // TODO: Parse information related to use as a library
+ // 1. Find (and add if needed) the `lib` descriptor
+ auto it = ::std::find_if(rv.m_targets.begin(), rv.m_targets.end(), [](const auto& x){ return x.m_type == PackageTarget::Type::Lib; });
+ if(it == rv.m_targets.end())
+ it = rv.m_targets.insert(it, PackageTarget { PackageTarget::Type::Lib });
+
+ target_edit_from_kv(*it, key_val, 1);
+ }
+ else if( section == "bin" )
+ {
+ assert(key_val.path.size() > 1);
+ unsigned idx = ::std::stoi( key_val.path[1] );
+
+ auto it = ::std::find_if(rv.m_targets.begin(), rv.m_targets.end(), [&idx](const auto& x) { return x.m_type == PackageTarget::Type::Bin && idx-- == 0; });
+ if (it == rv.m_targets.end())
+ it = rv.m_targets.insert(it, PackageTarget{ PackageTarget::Type::Bin });
+
+ target_edit_from_kv(*it, key_val, 2);
+ }
+ else if (section == "test")
+ {
+ assert(key_val.path.size() > 1);
+ unsigned idx = ::std::stoi(key_val.path[1]);
+
+ auto it = ::std::find_if(rv.m_targets.begin(), rv.m_targets.end(), [&idx](const auto& x) { return x.m_type == PackageTarget::Type::Test && idx-- == 0; });
+ if (it == rv.m_targets.end())
+ it = rv.m_targets.insert(it, PackageTarget{ PackageTarget::Type::Test });
+
+ target_edit_from_kv(*it, key_val, 2);
+ }
+ else if( section == "dependencies" )
+ {
+ assert(key_val.path.size() > 1);
+
+ const auto& depname = key_val.path[1];
+
+ // Find/create dependency descriptor
+ auto it = ::std::find_if(rv.m_dependencies.begin(), rv.m_dependencies.end(), [&](const auto& x) { return x.m_name == depname; });
+ bool was_added = (it == rv.m_dependencies.end());
+ if (it == rv.m_dependencies.end())
+ {
+ it = rv.m_dependencies.insert(it, PackageRef{ depname });
+ }
+ auto& ref = *it;
+
+ if( key_val.path.size() == 2 )
+ {
+ // Shorthand, picks a version from the package repository
+ if(!was_added)
+ {
+ throw ::std::runtime_error(::format("ERROR: Duplicate dependency `", depname, "`"));
+ }
+
+ const auto& version_spec_str = key_val.value.as_string();
+ ref.m_version = PackageVersionSpec::from_string(version_spec_str);
+ }
+ else
+ {
+
+ // (part of a) Full dependency specification
+ const auto& attr = key_val.path[2];
+ if( attr == "path" )
+ {
+ // Set path specification of the named depenency
+ ref.m_path = key_val.value.as_string();
+ }
+ else if (attr == "git")
+ {
+ // Load from git repo.
+ TODO("Support git dependencies");
+ }
+ else if (attr == "branch")
+ {
+ // Specify git branch
+ TODO("Support git dependencies (branch)");
+ }
+ else if( attr == "version")
+ {
+ assert(key_val.path.size() == 3);
+ // Parse version specifier
+ ref.m_version = PackageVersionSpec::from_string(key_val.value.as_string());
+ }
+ else
+ {
+ // TODO: Error
+ throw ::std::runtime_error(::format("ERROR: Unkown depencency attribute `", attr, "` on dependency `", depname, "`"));
+ }
+ }
+ }
+ else if( section == "patch" )
+ {
+ //const auto& repo = key_val.path[1];
+ }
+ else
+ {
+ // Unknown manifest section
+ }
+ }
+
+ return rv;
+}
+
+namespace
+{
+ void target_edit_from_kv(PackageTarget& target, TomlKeyValue& kv, unsigned base_idx)
+ {
+ const auto& key = kv.path[base_idx];
+ if(key == "name")
+ {
+ assert(kv.path.size() == base_idx+1);
+ target.m_name = kv.value.as_string();
+ }
+ else if(key == "path")
+ {
+ assert(kv.path.size() == base_idx + 1);
+ target.m_path = kv.value.as_string();
+ }
+ else if(key == "test")
+ {
+ assert(kv.path.size() == base_idx + 1);
+ target.m_enable_test = kv.value.as_bool();
+ }
+ else if (key == "doctest")
+ {
+ assert(kv.path.size() == base_idx + 1);
+ target.m_enable_doctest = kv.value.as_bool();
+ }
+ else if (key == "bench")
+ {
+ assert(kv.path.size() == base_idx + 1);
+ target.m_enable_bench = kv.value.as_bool();
+ }
+ else if (key == "doc")
+ {
+ assert(kv.path.size() == base_idx + 1);
+ target.m_enable_doc = kv.value.as_bool();
+ }
+ else if (key == "plugin")
+ {
+ assert(kv.path.size() == base_idx + 1);
+ target.m_is_plugin = kv.value.as_bool();
+ }
+ else if (key == "proc-macro")
+ {
+ assert(kv.path.size() == base_idx + 1);
+ target.m_is_proc_macro = kv.value.as_bool();
+ }
+ else if (key == "harness")
+ {
+ assert(kv.path.size() == base_idx + 1);
+ target.m_is_own_harness = kv.value.as_bool();
+ }
+ else
+ {
+ throw ::std::runtime_error( ::format("TODO: Handle target option `", key, "`") );
+ }
+ }
+}
+
+
+void PackageManifest::build_lib() const
+{
+ auto it = ::std::find_if(m_targets.begin(), m_targets.end(), [](const auto& x) { return x.m_type == PackageTarget::Type::Lib; });
+ if (it == m_targets.end())
+ {
+ throw ::std::runtime_error(::format("Package ", m_name, " doesn't have a library"));
+ }
+ ::std::vector<::std::string> args;
+ args.push_back( ::helpers::path(m_manmifest_path).parent() / ::helpers::path(it->m_path) );
+ args.push_back("--crate-name"); args.push_back(it->m_name);
+ args.push_back("--crate-type"); args.push_back("rlib");
+ args.push_back("-o"); args.push_back( ::helpers::path("output") / ::format("lib", it->m_name, ".hir") );
+#ifdef _WIN32
+ ::std::stringstream cmdline;
+ cmdline << "mrustc.exe";
+ for(const auto& arg : args)
+ cmdline << " " << arg;
+ DEBUG("Calling " << cmdline.str());
+
+ STARTUPINFO si = {0};
+ PROCESS_INFORMATION pi;
+ CreateProcessA("x64\\Release\\mrustc.exe", (LPSTR)cmdline.str().c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ DWORD status = 1;
+ GetExitCodeProcess(pi.hProcess, &status);
+ if(status != 0)
+ {
+ DEBUG("Compiler exited with non-zero exit status " << status);
+ throw "";
+ }
+#elif defined(__posix__)
+ //spawn();
+#else
+#endif
+}
+
+const PackageManifest& PackageRef::get_package() const
+{
+ throw "";
+}
+
+PackageVersion PackageVersion::from_string(const ::std::string& s)
+{
+ PackageVersion rv;
+ ::std::istringstream iss { s };
+ iss >> rv.major;
+ iss.get();
+ iss >> rv.minor;
+ if( iss.get() != EOF )
+ {
+ iss >> rv.patch;
+ }
+ return rv;
+}
+
+PackageVersionSpec PackageVersionSpec::from_string(const ::std::string& s)
+{
+ PackageVersionSpec rv;
+ throw "";
+ return rv;
+} \ No newline at end of file