|
1 | | -// mcpp.lockfile — read & write mcpp.lock (TOML). |
| 1 | +// mcpp.lockfile — backward-compat shim. The implementation has moved |
| 2 | +// to `mcpp.pm.lock_io` as part of the package-management subsystem |
| 3 | +// refactor (PR-R2 in |
| 4 | +// `.agents/docs/2026-05-08-pm-subsystem-architecture.md`). |
| 5 | +// |
| 6 | +// All existing callers continue to use `mcpp::lockfile::Lockfile`, |
| 7 | +// `mcpp::lockfile::load`, etc. — the aliases below resolve those to |
| 8 | +// the new `mcpp::pm` types. Once `cli.cppm` migrates to `mcpp::pm::` |
| 9 | +// directly this shim can be deleted. |
2 | 10 |
|
3 | 11 | export module mcpp.lockfile; |
4 | 12 |
|
5 | 13 | import std; |
6 | | -import mcpp.libs.toml; |
| 14 | +export import mcpp.pm.lock_io; |
7 | 15 |
|
8 | 16 | export namespace mcpp::lockfile { |
9 | 17 |
|
10 | | -struct LockedPackage { |
11 | | - std::string name; |
12 | | - std::string version; |
13 | | - std::string source; // e.g. "mcpp-index+https://..." (M2 placeholder) |
14 | | - std::string hash; // "sha256:..." or "fnv1a:..." |
15 | | -}; |
| 18 | +using LockedPackage = mcpp::pm::LockedPackage; |
| 19 | +using Lockfile = mcpp::pm::Lockfile; |
| 20 | +using LockError = mcpp::pm::LockError; |
16 | 21 |
|
17 | | -struct Lockfile { |
18 | | - int schemaVersion = 1; |
19 | | - std::vector<LockedPackage> packages; |
20 | | -}; |
21 | | - |
22 | | -struct LockError { |
23 | | - std::string message; |
24 | | -}; |
25 | | - |
26 | | -std::expected<Lockfile, LockError> load(const std::filesystem::path& path); |
27 | | -std::expected<void, LockError> write(const Lockfile& lock, const std::filesystem::path& path); |
28 | | - |
29 | | -std::string serialize(const Lockfile& lock); |
30 | | -std::string compute_hash(const Lockfile& lock); |
31 | | - |
32 | | -} // namespace mcpp::lockfile |
33 | | - |
34 | | -namespace mcpp::lockfile { |
35 | | - |
36 | | -namespace t = mcpp::libs::toml; |
37 | | - |
38 | | -std::expected<Lockfile, LockError> load(const std::filesystem::path& path) { |
39 | | - if (!std::filesystem::exists(path)) { |
40 | | - return Lockfile{}; // no lock yet |
41 | | - } |
42 | | - auto doc = t::parse_file(path); |
43 | | - if (!doc) return std::unexpected(LockError{ |
44 | | - std::format("{}:{}:{}: {}", path.string(), doc.error().where.line, |
45 | | - doc.error().where.column, doc.error().message)}); |
46 | | - |
47 | | - Lockfile lock; |
48 | | - if (auto v = doc->get_int("version")) lock.schemaVersion = static_cast<int>(*v); |
49 | | - |
50 | | - // [[package]] arrays are not in our minimal parser. We use [package.<name>] instead. |
51 | | - // Or just iterate the root looking for top-level "package" table that contains a list. |
52 | | - // For simplicity in M2: accept either format with top-level array of tables described |
53 | | - // as [package.X] sections. |
54 | | - auto* pkgs = doc->get_table("package"); |
55 | | - if (pkgs) { |
56 | | - for (auto& [k, v] : *pkgs) { |
57 | | - if (!v.is_table()) continue; |
58 | | - auto& tt = v.as_table(); |
59 | | - LockedPackage lp; |
60 | | - lp.name = k; |
61 | | - if (auto it = tt.find("version"); it != tt.end() && it->second.is_string()) lp.version = it->second.as_string(); |
62 | | - if (auto it = tt.find("source"); it != tt.end() && it->second.is_string()) lp.source = it->second.as_string(); |
63 | | - if (auto it = tt.find("hash"); it != tt.end() && it->second.is_string()) lp.hash = it->second.as_string(); |
64 | | - lock.packages.push_back(std::move(lp)); |
65 | | - } |
66 | | - } |
67 | | - return lock; |
| 22 | +inline std::expected<Lockfile, LockError> |
| 23 | +load(const std::filesystem::path& path) { |
| 24 | + return mcpp::pm::load(path); |
68 | 25 | } |
69 | 26 |
|
70 | | -std::string serialize(const Lockfile& lock) { |
71 | | - std::string out; |
72 | | - out += "# Auto-generated by mcpp. Do not edit by hand.\n"; |
73 | | - out += std::format("version = {}\n\n", lock.schemaVersion); |
74 | | - for (auto& p : lock.packages) { |
75 | | - out += std::format("[package.\"{}\"]\n", p.name); |
76 | | - out += std::format("version = {}\n", t::escape_string(p.version)); |
77 | | - out += std::format("source = {}\n", t::escape_string(p.source)); |
78 | | - out += std::format("hash = {}\n\n", t::escape_string(p.hash)); |
79 | | - } |
80 | | - return out; |
| 27 | +inline std::expected<void, LockError> |
| 28 | +write(const Lockfile& lock, const std::filesystem::path& path) { |
| 29 | + return mcpp::pm::write(lock, path); |
81 | 30 | } |
82 | 31 |
|
83 | | -std::expected<void, LockError> write(const Lockfile& lock, const std::filesystem::path& path) { |
84 | | - std::error_code ec; |
85 | | - std::filesystem::create_directories(path.parent_path(), ec); |
86 | | - std::ofstream os(path); |
87 | | - if (!os) return std::unexpected(LockError{std::format("cannot write '{}'", path.string())}); |
88 | | - os << serialize(lock); |
89 | | - return {}; |
90 | | -} |
91 | | - |
92 | | -std::string compute_hash(const Lockfile& lock) { |
93 | | - // FNV-1a over the canonical serialized form. |
94 | | - auto s = serialize(lock); |
95 | | - std::uint64_t h = 0xcbf29ce484222325ull; |
96 | | - for (unsigned char c : s) { |
97 | | - h ^= c; |
98 | | - h *= 0x100000001b3ull; |
99 | | - } |
100 | | - return std::format("{:016x}", h); |
101 | | -} |
| 32 | +inline std::string serialize(const Lockfile& lock) { return mcpp::pm::serialize(lock); } |
| 33 | +inline std::string compute_hash(const Lockfile& lock) { return mcpp::pm::compute_hash(lock); } |
102 | 34 |
|
103 | 35 | } // namespace mcpp::lockfile |
0 commit comments