From 4ca497d863c1c93689e5dd7581c164d1ce885569 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Aug 2017 10:46:26 +0800 Subject: Minicargo - Move build invocations to build.cpp --- tools/minicargo/manifest.cpp | 71 ++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 52 deletions(-) (limited to 'tools/minicargo/manifest.cpp') diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp index 22b63005..90bb68a5 100644 --- a/tools/minicargo/manifest.cpp +++ b/tools/minicargo/manifest.cpp @@ -25,7 +25,7 @@ namespace PackageManifest PackageManifest::load_from_toml(const ::std::string& path) { PackageManifest rv; - rv.m_manmifest_path = path; + rv.m_manifest_path = path; TomlFile toml_file(path); @@ -40,6 +40,7 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) if(key == "authors") { // TODO: Use the `authors` key + // - Ignore ofr now. } else if( key == "name" ) { @@ -67,12 +68,12 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) } 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 }); + // 2. Parse from the key-value pair target_edit_from_kv(*it, key_val, 1); } else if( section == "bin" ) @@ -97,6 +98,17 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) target_edit_from_kv(*it, key_val, 2); } + else if (section == "bench") + { + 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::Bench && idx-- == 0; }); + if (it == rv.m_targets.end()) + it = rv.m_targets.insert(it, PackageTarget{ PackageTarget::Type::Bench }); + + target_edit_from_kv(*it, key_val, 2); + } else if( section == "dependencies" ) { assert(key_val.path.size() > 1); @@ -159,10 +171,12 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) else if( section == "patch" ) { //const auto& repo = key_val.path[1]; + TODO("Support repository patches"); } else { // Unknown manifest section + TODO("Unknown manifest section " << section); } } @@ -226,66 +240,19 @@ namespace } } - -bool PackageManifest::build_lib() const +const PackageTarget& PackageManifest::get_library() 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")); } - - auto outfile = ::helpers::path("output") / ::format("lib", it->m_name, ".hir"); - - ::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; - auto cmdline_str = cmdline.str(); - DEBUG("Calling " << cmdline_str); - - CreateDirectory(static_cast<::std::string>(outfile.parent()).c_str(), NULL); - - STARTUPINFO si = {0}; - si.cb = sizeof(si); - si.dwFlags = STARTF_USESTDHANDLES; - si.hStdInput = NULL; - si.hStdError = GetStdHandle(STD_ERROR_HANDLE); - { - SECURITY_ATTRIBUTES sa = {0}; - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - si.hStdOutput = CreateFile( (static_cast<::std::string>(outfile) + "_dbg.txt").c_str(), GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); - DWORD tmp; - WriteFile(si.hStdOutput, cmdline_str.data(), cmdline_str.size(), &tmp, NULL); - WriteFile(si.hStdOutput, "\n", 1, &tmp, NULL); - } - PROCESS_INFORMATION pi = {0}; - CreateProcessA("x64\\Release\\mrustc.exe", (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, CREATE_NO_WINDOW, "MRUSTC_DEBUG=Parse\0", NULL, &si, &pi); - CloseHandle(si.hStdOutput); - WaitForSingleObject(pi.hProcess, INFINITE); - DWORD status = 1; - GetExitCodeProcess(pi.hProcess, &status); - if(status != 0) - { - DEBUG("Compiler exited with non-zero exit status " << status); - return false; - } -#elif defined(__posix__) - //spawn(); -#else -#endif - return true; + return *it; } const PackageManifest& PackageRef::get_package() const { + DEBUG("TODO: PackageRef::get_package()"); throw ""; } -- cgit v1.2.3 From 19f32ced09e7538cde01cb443b19e0a7a1c5667f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Aug 2017 20:54:45 +0800 Subject: minicargo - Dependency loading --- tools/minicargo/build.cpp | 47 ++++++- tools/minicargo/helpers.h | 176 +++++++++++++++++++++++++- tools/minicargo/main.cpp | 39 ++++-- tools/minicargo/manifest.cpp | 109 +++++++++++++--- tools/minicargo/manifest.h | 39 +++++- tools/minicargo/repository.cpp | 70 ++++++++++ tools/minicargo/repository.h | 29 +++++ tools/minicargo/toml.cpp | 13 +- tools/minicargo/toml.h | 19 +++ vsproject/minicargo/minicargo.vcxproj | 2 + vsproject/minicargo/minicargo.vcxproj.filters | 6 + 11 files changed, 507 insertions(+), 42 deletions(-) create mode 100644 tools/minicargo/repository.cpp create mode 100644 tools/minicargo/repository.h (limited to 'tools/minicargo/manifest.cpp') diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index ace0dd13..352a4dcd 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -18,6 +18,7 @@ struct BuildList }; ::std::vector m_list; + void add_dependencies(const PackageManifest& p, unsigned level); void add_package(const PackageManifest& p, unsigned level); void sort_list(); @@ -85,13 +86,16 @@ private: void MiniCargo_Build(const PackageManifest& manifest) { BuildList list; - // Generate sorted dependency list - for (const auto& dep : manifest.dependencies()) + + list.add_dependencies(manifest, 0); + + list.sort_list(); + // dedup? + for(const auto& p : list.iter()) { - list.add_package(dep.get_package(), 1); + DEBUG("WILL BUILD " << p.name() << " from " << p.manifest_path()); } - // Build dependencies Builder builder; for(const auto& p : list.iter()) @@ -106,6 +110,17 @@ void MiniCargo_Build(const PackageManifest& manifest) builder.build_library(manifest); } +void BuildList::add_dependencies(const PackageManifest& p, unsigned level) +{ + for (const auto& dep : p.dependencies()) + { + if( dep.is_optional() ) + { + continue ; + } + add_package(dep.get_package(), level+1); + } +} void BuildList::add_package(const PackageManifest& p, unsigned level) { for(auto& ent : m_list) @@ -125,17 +140,32 @@ void BuildList::add_package(const PackageManifest& p, unsigned level) void BuildList::sort_list() { ::std::sort(m_list.begin(), m_list.end(), [](const auto& a, const auto& b){ return a.level < b.level; }); + + for(auto it = m_list.begin(); it != m_list.end(); ) + { + auto it2 = ::std::find_if(m_list.begin(), it, [&](const auto& x){ return x.package == it->package; }); + if( it2 != it ) + { + it = m_list.erase(it); + } + else + { + ++it; + } + } } bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& target) const { - auto outfile = ::helpers::path("output") / ::format("lib", target.m_name, ".hir"); + auto outdir = ::helpers::path("output"); + auto outfile = outdir / ::format("lib", target.m_name, ".hir"); StringList args; args.push_back(::helpers::path(manifest.manifest_path()).parent() / ::helpers::path(target.m_path)); args.push_back("--crate-name"); args.push_back(target.m_name.c_str()); args.push_back("--crate-type"); args.push_back("rlib"); args.push_back("-o"); args.push_back(outfile); + args.push_back("-L"); args.push_back(outdir); return this->spawn_process(args, outfile + "_dbg.txt"); } @@ -157,6 +187,7 @@ bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfi STARTUPINFO si = { 0 }; si.cb = sizeof(si); +#if 1 si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = NULL; si.hStdError = GetStdHandle(STD_ERROR_HANDLE); @@ -169,8 +200,12 @@ bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfi WriteFile(si.hStdOutput, cmdline_str.data(), cmdline_str.size(), &tmp, NULL); WriteFile(si.hStdOutput, "\n", 1, &tmp, NULL); } +#endif PROCESS_INFORMATION pi = { 0 }; - CreateProcessA("x64\\Release\\mrustc.exe", (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, 0, "MRUSTC_DEBUG=\0", NULL, &si, &pi); + char env[] = + "MRUSTC_DEBUG=""\0" + ; + CreateProcessA("x64\\Release\\mrustc.exe", (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); CloseHandle(si.hStdOutput); WaitForSingleObject(pi.hProcess, INFINITE); DWORD status = 1; diff --git a/tools/minicargo/helpers.h b/tools/minicargo/helpers.h index d9fe7e3c..35e791f1 100644 --- a/tools/minicargo/helpers.h +++ b/tools/minicargo/helpers.h @@ -4,14 +4,37 @@ namespace helpers { +class string_view +{ + const char* m_start; + const size_t m_len; +public: + string_view(const char* s, size_t n): + m_start(s), m_len(n) + { + } + + bool operator==(const ::std::string& s) const { + return *this == s.c_str(); + } + bool operator==(const char* s) const { + if(::std::strncmp(m_start, s, m_len) != 0) + return false; + return s[m_len] == '\0'; + } + friend ::std::string& operator+=(::std::string& x, const string_view& sv) { + x.append(sv.m_start, sv.m_start+sv.m_len); + return x; + } +}; /// Path helper class (because I don't want to include boost) class path { #ifdef _WIN32 - const char SEP = '\\'; + static const char SEP = '\\'; #else - const char SEP = '/'; + static const char SEP = '/'; #endif ::std::string m_str; @@ -96,6 +119,155 @@ public: return m_str; } + class ComponentsIter + { + const path& p; + size_t pos; + size_t end; + + friend class path; + ComponentsIter(const path& p, size_t i): p(p), pos(i) { + end = p.m_str.find(SEP, pos); + if(end == ::std::string::npos) + end = p.m_str.size(); + } + public: + string_view operator*() const { + return string_view(p.m_str.c_str() + pos, end - pos); + } + void operator++() { + if(end == p.m_str.size()) + pos = end; + else + { + pos = end+1; + end = p.m_str.find(SEP, pos); + if(end == ::std::string::npos) + end = p.m_str.size(); + } + } + bool operator!=(const ComponentsIter& x) const { + return pos != x.pos; + } + }; + ComponentsIter begin() const { + return ComponentsIter(*this, 0); + } + ComponentsIter end() const { + return ComponentsIter(*this, m_str.size()); + } + + path normalise() const + { + path rv; + rv.m_str.reserve( m_str.size()+1 ); + + for(auto comp : *this) + { + if( comp == "." ) { + // Ignore. + } + else if( comp == ".." ) + { + // If the path is empty, OR the last element is a "..", push the element + if( rv.m_str.empty() + || (rv.m_str.size() == 3 && rv.m_str[0] == '.' && rv.m_str[1] == '.' && rv.m_str[2] == SEP) + || (rv.m_str.size() > 4 && *(rv.m_str.end()-4) == SEP && *(rv.m_str.end()-3) == '.' && *(rv.m_str.end()-2) == '.' && *(rv.m_str.end()-1) == SEP ) + ) + { + // Push + rv.m_str += comp; + rv.m_str += SEP; + } + else + { + rv.m_str.pop_back(); + auto pos = rv.m_str.find_last_of(SEP); + if(pos == ::std::string::npos) + { + rv.m_str.resize(0); + } + else if( pos == 0 ) + { + // Keep. + } + else + { + rv.m_str.resize(pos+1); + } + } + } + else { + rv.m_str += comp; + rv.m_str += SEP; + } + } + rv.m_str.pop_back(); + return rv; + } +#if 0 + void normalise_in_place() + { + size_t insert_point = 0; + + for(size_t read_pos = 0; read_pos < m_str.size(); read_pos ++) + { + auto pos = m_str.find_first_of(SEP, read_pos); + if(pos == ::std::string::npos) + pos = m_str.size(); + auto comp = string_view(m_str.c_str() + read_pos, pos - read_pos); + + bool append; + if(comp == ".") + { + // Advance read without touching insert + append = false; + } + else if( comp == ".." ) + { + // Consume parent (if not a relative component already) + // Move insertion point back to the previous separator + auto pos = m_str.find_last_of(SEP, insert_point); + if(pos == ::std::string::npos) + { + // Only one component currently (or empty) + append = true; + } + else if(string_view(m_str.c_str() + pos+1, insert_point - pos-1) == "..") + { + // Last component is ".." - keep adding + append = true; + } + else + { + insert_point = pos; + append = false; + } + } + else + { + append = true; + } + + if(append) + { + if( read_pos != insert_point ) + { + //assert(read_pos > insert_point); + while(read_pos < pos) + { + m_str[insert_point++] = m_str[read_pos++]; + } + } + } + else + { + read_pos = pos; + } + } + } +#endif + friend ::std::ostream& operator<<(::std::ostream& os, const path& p) { return os << p.m_str; diff --git a/tools/minicargo/main.cpp b/tools/minicargo/main.cpp index c2fe4c2e..236b9d77 100644 --- a/tools/minicargo/main.cpp +++ b/tools/minicargo/main.cpp @@ -6,9 +6,11 @@ */ #include #include // strcmp +#include #include "debug.h" #include "manifest.h" #include "helpers.h" +#include "repository.h" extern void MiniCargo_Build(const PackageManifest& manifest); @@ -22,6 +24,8 @@ struct ProgramOptions const char* output_directory = nullptr; + const char* vendor_dir = nullptr; + int parse(int argc, const char* argv[]); void usage() const; }; @@ -33,19 +37,34 @@ int main(int argc, const char* argv[]) return 1; } - // 1. Load the Cargo.toml file from the passed directory - auto m = PackageManifest::load_from_toml( ::helpers::path(opts.directory ? opts.directory : ".") / "Cargo.toml" ); + try + { + // Load package database + Repository repo; + // TODO: load repository from a local cache + if( opts.vendor_dir ) + { + repo.load_vendored(opts.vendor_dir); + } + + // 1. Load the Cargo.toml file from the passed directory + auto dir = ::helpers::path(opts.directory ? opts.directory : "."); + auto m = PackageManifest::load_from_toml( dir / "Cargo.toml" ); + + m.load_dependencies(repo); - // 2. Recursively load dependency manifests - for(const auto& dep : m.dependencies()) + // 3. Build dependency tree + MiniCargo_Build(m); + } + catch(const ::std::exception& e) { - throw "TODO: Deps"; + ::std::cerr << "EXCEPTION: " << e.what() << ::std::endl; + ::std::cout << "Press enter to exit..." << ::std::endl; + ::std::cin.get(); + return 1; } - // 3. Build dependency tree - MiniCargo_Build(m); - - ::std::cout << "Press any key to exit..." << ::std::endl; + ::std::cout << "Press enter to exit..." << ::std::endl; ::std::cin.get(); return 0; } @@ -106,9 +125,9 @@ void ProgramOptions::usage() const } - void Debug_Print(::std::function cb) { cb(::std::cout); ::std::cout << ::std::endl; } + diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp index 90bb68a5..d068b7bf 100644 --- a/tools/minicargo/manifest.cpp +++ b/tools/minicargo/manifest.cpp @@ -6,10 +6,7 @@ #include "helpers.h" #include #include -#include -#ifdef _WIN32 -#include -#endif +#include "repository.h" static ::std::vector<::std::shared_ptr> g_loaded_manifests; @@ -32,6 +29,7 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) for(auto key_val : toml_file) { assert(key_val.path.size() > 0); + DEBUG(key_val.path << " = " << key_val.value); const auto& section = key_val.path[0]; if( section == "package" ) { @@ -60,6 +58,20 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) { rv.m_version = PackageVersion::from_string(key_val.value.as_string()); } + else if( key == "build" ) + { + if(rv.m_build_script != "" ) + { + // TODO: Warn/error + throw ::std::runtime_error("Build script path set twice"); + } + rv.m_build_script = key_val.value.as_string(); + if(rv.m_build_script == "") + { + // TODO: Error + throw ::std::runtime_error("Build script path cannot be empty"); + } + } else { // Unknown value in `package` @@ -145,22 +157,28 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) // Set path specification of the named depenency ref.m_path = key_val.value.as_string(); } - else if (attr == "git") + else if( attr == "git" ) { // Load from git repo. TODO("Support git dependencies"); } - else if (attr == "branch") + else if( attr == "branch" ) { // Specify git branch TODO("Support git dependencies (branch)"); } - else if( attr == "version") + 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 if( attr == "optional" ) + { + assert(key_val.path.size() == 3); + ref.m_optional = key_val.value.as_bool(); + // TODO: Add a feature with the same name as the dependency. + } else { // TODO: Error @@ -168,11 +186,23 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) } } } + else if( section == "build-dependencies" ) + { + // TODO: Build deps + } else if( section == "patch" ) { //const auto& repo = key_val.path[1]; TODO("Support repository patches"); } + else if( section == "target" ) + { + // TODO: Target opts? + } + else if( section == "features" ) + { + // TODO: Features + } else { // Unknown manifest section @@ -203,36 +233,40 @@ namespace assert(kv.path.size() == base_idx + 1); target.m_enable_test = kv.value.as_bool(); } - else if (key == "doctest") + else if( key == "doctest" ) { assert(kv.path.size() == base_idx + 1); target.m_enable_doctest = kv.value.as_bool(); } - else if (key == "bench") + else if( key == "bench" ) { assert(kv.path.size() == base_idx + 1); target.m_enable_bench = kv.value.as_bool(); } - else if (key == "doc") + else if( key == "doc" ) { assert(kv.path.size() == base_idx + 1); target.m_enable_doc = kv.value.as_bool(); } - else if (key == "plugin") + else if( key == "plugin" ) { assert(kv.path.size() == base_idx + 1); target.m_is_plugin = kv.value.as_bool(); } - else if (key == "proc-macro") + 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") + else if( key == "harness" ) { assert(kv.path.size() == base_idx + 1); target.m_is_own_harness = kv.value.as_bool(); } + else if( key == "crate-type" ) + { + // TODO: Support crate types + } else { throw ::std::runtime_error( ::format("TODO: Handle target option `", key, "`") ); @@ -250,10 +284,49 @@ const PackageTarget& PackageManifest::get_library() const return *it; } -const PackageManifest& PackageRef::get_package() const +void PackageManifest::load_dependencies(Repository& repo) { - DEBUG("TODO: PackageRef::get_package()"); - throw ""; + DEBUG("Loading depencencies for " << m_name); + auto base_path = ::helpers::path(m_manifest_path).parent(); + + // 2. Recursively load dependency manifests + for(auto& dep : m_dependencies) + { + if( dep.m_optional ) + { + // TODO: Check for feature that enables this (option to a feature with no '/') + continue ; + } + dep.load_manifest(repo, base_path); + } +} + +void PackageRef::load_manifest(Repository& repo, const ::helpers::path& base_path) +{ + // If the path isn't set, check for: + // - Git (checkout and use) + // - Version and repository (check vendored, check cache, download into cache) + if( ! this->has_path() ) + { + if( this->has_git() ) + { + DEBUG("Load dependency " << this->name() << " from git"); + throw "TODO: Git"; + } + else + { + DEBUG("Load dependency " << this->name() << " from repo"); + m_manifest = repo.find(this->name(), this->get_version()); + } + } + else + { + DEBUG("Load dependency " << m_name << " from path " << m_path); + // Search for a copy of this already loaded + m_manifest = repo.from_path(base_path / ::helpers::path(m_path) / "Cargo.toml"); + } + + m_manifest->load_dependencies(repo); } PackageVersion PackageVersion::from_string(const ::std::string& s) @@ -275,4 +348,8 @@ PackageVersionSpec PackageVersionSpec::from_string(const ::std::string& s) PackageVersionSpec rv; throw ""; return rv; +} +bool PackageVersionSpec::accepts(const PackageVersion& v) const +{ + throw ""; } \ No newline at end of file diff --git a/tools/minicargo/manifest.h b/tools/minicargo/manifest.h index 054347fb..0e6c2d81 100644 --- a/tools/minicargo/manifest.h +++ b/tools/minicargo/manifest.h @@ -3,8 +3,10 @@ #include #include #include +#include "helpers.h" class PackageManifest; +class Repository; struct PackageVersion { @@ -13,6 +15,15 @@ struct PackageVersion unsigned patch; static PackageVersion from_string(const ::std::string& s); + bool operator<(const PackageVersion& x) const { + if( major < x.major ) return true; + if( major > x.major ) return false; + if( minor < x.minor ) return true; + if( minor > x.minor ) return false; + if( minor < x.patch ) return true; + if( patch > x.patch ) return false; + return false; + } }; struct PackageVersionSpec { @@ -28,10 +39,14 @@ struct PackageVersionSpec Type ty; PackageVersion ver; }; + // TODO: Just upper and lower? ::std::vector m_bounds; - // TODO: Just upper and lower? + // Construct from a string static PackageVersionSpec from_string(const ::std::string& s); + + /// Check if this spec accepts the passed version + bool accepts(const PackageVersion& v) const; }; class PackageRef @@ -40,6 +55,7 @@ class PackageRef ::std::string m_name; PackageVersionSpec m_version; + bool m_optional = false; ::std::string m_path; ::std::shared_ptr m_manifest; @@ -49,7 +65,22 @@ class PackageRef } public: - const PackageManifest& get_package() const; + const ::std::string& name() const { return m_name; } + //const ::std::string& get_repo_name() const { return m_repo; } + const PackageVersionSpec& get_version() const { return m_version; } + + bool is_optional() const { return m_optional; } + + const bool has_path() const { return m_path != ""; } + const ::std::string& path() const { return m_path; } + const bool has_git() const { return false; } + + const PackageManifest& get_package() const { + if(!m_manifest) throw ::std::runtime_error("Manifest not loaded for package " + m_name); + return *m_manifest; + } + + void load_manifest(Repository& repo, const ::helpers::path& base_path); }; struct PackageTarget @@ -98,6 +129,8 @@ class PackageManifest ::std::string m_name; PackageVersion m_version; + ::std::string m_build_script; + ::std::vector m_dependencies; ::std::vector m_targets; @@ -122,4 +155,6 @@ public: const ::std::vector& dependencies() const { return m_dependencies; } + + void load_dependencies(Repository& repo); }; diff --git a/tools/minicargo/repository.cpp b/tools/minicargo/repository.cpp new file mode 100644 index 00000000..0a097f66 --- /dev/null +++ b/tools/minicargo/repository.cpp @@ -0,0 +1,70 @@ +/* + */ +#include "repository.h" +#include "debug.h" + +void Repository::load_cache(const ::helpers::path& path) +{ + throw ""; +} +void Repository::load_vendored(const ::helpers::path& path) +{ + // Enumerate folders in this folder, try to open Cargo.toml files + // Extract package name and version from each manifest +} + +::std::shared_ptr Repository::from_path(::helpers::path path) +{ + DEBUG("Repository::from_path(" << path << ")"); + // 1. Normalise path + path = path.normalise(); + DEBUG("path = " << path); + + auto it = m_path_cache.find(path); + if(it == m_path_cache.end()) + { + ::std::shared_ptr rv ( new PackageManifest(PackageManifest::load_from_toml(path)) ); + + m_path_cache.insert( ::std::make_pair(::std::move(path), rv) ); + + return rv; + } + else + { + return it->second; + } +} +::std::shared_ptr Repository::find(const ::std::string& name, const PackageVersionSpec& version) +{ + auto itp = m_cache.equal_range(name); + + Entry* best = nullptr; + for(auto i = itp.first; i != itp.second; ++i) + { + if( version.accepts(i->second.version) ) + { + if( !best || best->version < i->second.version ) + { + best = &i->second; + } + } + } + + if( best ) + { + if( !best->loaded_manifest ) + { + if( best->manifest_path == "" ) + { + throw "TODO: Download package"; + } + best->loaded_manifest = ::std::shared_ptr( new PackageManifest(PackageManifest::load_from_toml(best->manifest_path)) ); + } + + return best->loaded_manifest; + } + else + { + return {}; + } +} diff --git a/tools/minicargo/repository.h b/tools/minicargo/repository.h new file mode 100644 index 00000000..0b186077 --- /dev/null +++ b/tools/minicargo/repository.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include "helpers.h" +#include "manifest.h" + +class Repository +{ + struct Entry + { + /// Path to the Cargo.toml file in the package root + ::std::string manifest_path; + /// Package version + PackageVersion version; + /// (Cached) loaded manifest + ::std::shared_ptr loaded_manifest; + }; + + ::std::multimap<::std::string, Entry> m_cache; + // path => manifest + ::std::map<::std::string, ::std::shared_ptr> m_path_cache; +public: + void load_cache(const ::helpers::path& path); + void load_vendored(const ::helpers::path& path); + + ::std::shared_ptr from_path(::helpers::path path); + ::std::shared_ptr find(const ::std::string& name, const PackageVersionSpec& version); +}; diff --git a/tools/minicargo/toml.cpp b/tools/minicargo/toml.cpp index 7d4b0685..fe81fa3c 100644 --- a/tools/minicargo/toml.cpp +++ b/tools/minicargo/toml.cpp @@ -158,14 +158,14 @@ TomlKeyValue TomlFile::get_next_value() { case Token::Type::String: rv.path = m_current_block; - rv.path.insert(rv.path.begin(), m_current_composite.begin(), m_current_composite.end()); + rv.path.insert(rv.path.end(), m_current_composite.begin(), m_current_composite.end()); rv.path.push_back(key_name); rv.value = TomlValue { t.m_data }; break; case Token::Type::SquareOpen: rv.path = m_current_block; - rv.path.insert(rv.path.begin(), m_current_composite.begin(), m_current_composite.end()); + rv.path.insert(rv.path.end(), m_current_composite.begin(), m_current_composite.end()); rv.path.push_back(key_name); rv.value.m_type = TomlValue::Type::List; @@ -197,14 +197,14 @@ TomlKeyValue TomlFile::get_next_value() if( t.m_data == "true" ) { rv.path = m_current_block; - rv.path.insert(rv.path.begin(), m_current_composite.begin(), m_current_composite.end()); + rv.path.insert(rv.path.end(), m_current_composite.begin(), m_current_composite.end()); rv.path.push_back(key_name); rv.value = TomlValue { true }; } else if( t.m_data == "false" ) { rv.path = m_current_block; - rv.path.insert(rv.path.begin(), m_current_composite.begin(), m_current_composite.end()); + rv.path.insert(rv.path.end(), m_current_composite.begin(), m_current_composite.end()); rv.path.push_back(key_name); rv.value = TomlValue { false }; @@ -242,7 +242,7 @@ TomlKeyValue TomlFile::get_next_value() Token Token::lex_from(::std::ifstream& is) { auto rv = Token::lex_from_inner(is); - DEBUG("lex_from: " << rv); + //DEBUG("lex_from: " << rv); return rv; } Token Token::lex_from_inner(::std::ifstream& is) @@ -307,7 +307,7 @@ Token Token::lex_from_inner(::std::ifstream& is) if(isalpha(c)) { // Identifier - while(isalnum(c) || c == '-') + while(isalnum(c) || c == '-' || c == '_') { str += (char)c; c = is.get(); @@ -317,6 +317,7 @@ Token Token::lex_from_inner(::std::ifstream& is) } else { + throw ::std::runtime_error(::format("Unexpected chracter '", (char)c, "' in file")); throw ""; } } diff --git a/tools/minicargo/toml.h b/tools/minicargo/toml.h index 1c8f90d5..17517ca3 100644 --- a/tools/minicargo/toml.h +++ b/tools/minicargo/toml.h @@ -2,6 +2,7 @@ #include #include +#include #include class TomlFileIter; @@ -91,6 +92,24 @@ struct TomlValue } return m_int_value != 0; } + + friend ::std::ostream& operator<<(::std::ostream& os, const TomlValue& x) { + switch(x.m_type) + { + case Type::Boolean: os << (x.m_int_value != 0 ? "true" : "false"); break; + case Type::Integer: os << x.m_int_value; break; + case Type::List: + os << "["; + for(auto& e : x.m_sub_values) + os << e << ","; + os << "]"; + break; + case Type::String: + os << "\"" << x.m_str_value << "\""; + break; + } + return os; + } }; struct TomlKeyValue diff --git a/vsproject/minicargo/minicargo.vcxproj b/vsproject/minicargo/minicargo.vcxproj index 9c82ff56..9fe4e4a7 100644 --- a/vsproject/minicargo/minicargo.vcxproj +++ b/vsproject/minicargo/minicargo.vcxproj @@ -113,12 +113,14 @@ + + diff --git a/vsproject/minicargo/minicargo.vcxproj.filters b/vsproject/minicargo/minicargo.vcxproj.filters index b21142bb..be88124d 100644 --- a/vsproject/minicargo/minicargo.vcxproj.filters +++ b/vsproject/minicargo/minicargo.vcxproj.filters @@ -27,6 +27,9 @@ Source Files + + Source Files + @@ -41,5 +44,8 @@ Header Files + + Header Files + \ No newline at end of file -- cgit v1.2.3 From a99e49b7505d2912d8699d4c791b8b30c194024b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Aug 2017 22:15:35 +0800 Subject: minicargo - Makefile and posix_spawn --- tools/minicargo/Makefile | 6 +++-- tools/minicargo/build.cpp | 55 ++++++++++++++++++++++++++++++++++++++++---- tools/minicargo/debug.h | 4 ++-- tools/minicargo/helpers.h | 3 ++- tools/minicargo/manifest.cpp | 6 ++++- tools/minicargo/toml.h | 2 +- 6 files changed, 64 insertions(+), 12 deletions(-) (limited to 'tools/minicargo/manifest.cpp') diff --git a/tools/minicargo/Makefile b/tools/minicargo/Makefile index ff7a5f4f..ab3f8531 100644 --- a/tools/minicargo/Makefile +++ b/tools/minicargo/Makefile @@ -9,10 +9,11 @@ V ?= @ OBJDIR := .obj/ BIN := ../bin/minicargo -OBJS := main.o +OBJS := main.o build.o manifest.o repository.o +OBJS += toml.o LINKFLAGS := -CXXFLAGS := -Wall +CXXFLAGS := -Wall -std=c++14 OBJS := $(OBJS:%=$(OBJDIR)%) @@ -29,6 +30,7 @@ $(BIN): $(OBJS) $V$(CXX) -o $@ $(OBJS) $(LINKFLAGS) $(OBJDIR)%.o: %.cpp + @mkdir -p $(dir $@) @echo [CXX] $< $V$(CXX) -o $@ -c $< $(CXXFLAGS) -MMD -MP -MF $@.dep diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index 55e45c49..8127fbf0 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -7,7 +7,13 @@ #include // stringstream #include "helpers.h" // path #ifdef _WIN32 -#include +# include +#else +# include +# include +# include +# include +# include #endif struct BuildList @@ -218,7 +224,6 @@ bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfi STARTUPINFO si = { 0 }; si.cb = sizeof(si); -#if 1 si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = NULL; si.hStdError = GetStdHandle(STD_ERROR_HANDLE); @@ -231,7 +236,6 @@ bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfi WriteFile(si.hStdOutput, cmdline_str.data(), cmdline_str.size(), &tmp, NULL); WriteFile(si.hStdOutput, "\n", 1, &tmp, NULL); } -#endif PROCESS_INFORMATION pi = { 0 }; char env[] = "MRUSTC_DEBUG=""\0" @@ -247,8 +251,49 @@ bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfi return false; } #else - // TODO: posix_spawn - return false; + + // Create logfile output directory + mkdir(static_cast<::std::string>(logfile.parent()).c_str(), 0755); + + // Create handles such that the log file is on stdout + ::std::string logfile_str = logfile; + pid_t pid; + posix_spawn_file_actions_t fa; + { + posix_spawn_file_actions_init(&fa); + posix_spawn_file_actions_addopen(&fa, 1, logfile_str.c_str(), O_CREAT|O_WRONLY|O_TRUNC, 0644); + } + + // Generate `argv` + auto argv = args.get_vec(); + argv.insert(argv.begin(), "mrustc"); + DEBUG("Calling " << argv); + argv.push_back(nullptr); + + // Generate `envp` + ::std::vector envp; + extern char **environ; + for(auto p = environ; *p; p++) + { + envp.push_back(*p); + } + envp.push_back(nullptr); + + if( posix_spawn(&pid, "../bin/mrustc", &fa, /*attr=*/nullptr, (char* const*)argv.data(), (char* const*)envp.data()) != 0 ) + { + perror("posix_spawn"); + DEBUG("Unable to spawn compiler"); + posix_spawn_file_actions_destroy(&fa); + return false; + } + posix_spawn_file_actions_destroy(&fa); + int status = -1; + waitpid(pid, &status, 0); + if( WEXITSTATUS(status) != 0 ) + { + DEBUG("Compiler exited with non-zero exit status " << WEXITSTATUS(status)); + return false; + } #endif return true; } diff --git a/tools/minicargo/debug.h b/tools/minicargo/debug.h index 5cc338e3..bff9ddf3 100644 --- a/tools/minicargo/debug.h +++ b/tools/minicargo/debug.h @@ -10,10 +10,10 @@ extern void Debug_Print(::std::function cb); #define TODO(fmt) do { Debug_Print([&](auto& os){ os << "DEBUG: " << fmt; }); abort(); } while(0) namespace { - static void format_to_stream(::std::ostream& os) { + static inline void format_to_stream(::std::ostream& os) { } template - static void format_to_stream(::std::ostream& os, const T& v, const A&... a) { + static inline void format_to_stream(::std::ostream& os, const T& v, const A&... a) { os << v; format_to_stream(os, a...); } diff --git a/tools/minicargo/helpers.h b/tools/minicargo/helpers.h index 35e791f1..f2679ef4 100644 --- a/tools/minicargo/helpers.h +++ b/tools/minicargo/helpers.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace helpers { @@ -274,4 +275,4 @@ public: } }; -} // namespace helpers \ No newline at end of file +} // namespace helpers diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp index d068b7bf..1bb815d8 100644 --- a/tools/minicargo/manifest.cpp +++ b/tools/minicargo/manifest.cpp @@ -190,6 +190,10 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) { // TODO: Build deps } + else if( section == "dev-dependencies" ) + { + // TODO: Developemnt (test/bench) deps + } else if( section == "patch" ) { //const auto& repo = key_val.path[1]; @@ -352,4 +356,4 @@ PackageVersionSpec PackageVersionSpec::from_string(const ::std::string& s) bool PackageVersionSpec::accepts(const PackageVersion& v) const { throw ""; -} \ No newline at end of file +} diff --git a/tools/minicargo/toml.h b/tools/minicargo/toml.h index 17517ca3..6f145a2e 100644 --- a/tools/minicargo/toml.h +++ b/tools/minicargo/toml.h @@ -55,7 +55,7 @@ struct TomlValue { } - const char* what() const override { + const char* what() const noexcept override { return "toml type error"; } }; -- cgit v1.2.3