|
12 | 12 | #include "core/commands.hpp" |
13 | 13 | #include "core/constants.h" |
14 | 14 | #include "core/lockfile.hpp" |
| 15 | +#include "core/registry.hpp" |
15 | 16 | #include "core/toml_reader.hpp" |
16 | 17 | #include "core/workspace.hpp" |
17 | 18 |
|
18 | 19 | #include <cstring> |
19 | 20 | #include <filesystem> |
| 21 | +#include <fstream> |
20 | 22 | #include <string> |
21 | 23 |
|
22 | 24 | using namespace cforge; |
@@ -108,9 +110,9 @@ cforge_int_t cforge_cmd_lock(const cforge_context_t *ctx) { |
108 | 110 | return 1; |
109 | 111 | } |
110 | 112 |
|
111 | | - // Get dependencies directory |
| 113 | + // Get dependencies directory (default: deps) |
112 | 114 | std::string deps_dir_str = |
113 | | - config.get_string("dependencies.directory", "vendor"); |
| 115 | + config.get_string("dependencies.directory", "deps"); |
114 | 116 | std::filesystem::path deps_dir = current_dir / deps_dir_str; |
115 | 117 |
|
116 | 118 | // Handle --verify option |
@@ -153,6 +155,116 @@ cforge_int_t cforge_cmd_lock(const cforge_context_t *ctx) { |
153 | 155 | // Generate/update lock file |
154 | 156 | logger::print_action("Generating", "lock file"); |
155 | 157 |
|
| 158 | + // Check if using FetchContent mode |
| 159 | + bool use_fetch_content = config.get_bool("dependencies.fetch_content", true); |
| 160 | + |
| 161 | + if (use_fetch_content) { |
| 162 | + // FetchContent mode: generate lock file from cforge.toml + registry |
| 163 | + registry reg; |
| 164 | + std::filesystem::path lock_path = current_dir / LOCK_FILE; |
| 165 | + std::ofstream lock_file(lock_path); |
| 166 | + |
| 167 | + if (!lock_file.is_open()) { |
| 168 | + logger::print_error("Failed to create lock file: " + lock_path.string()); |
| 169 | + return 1; |
| 170 | + } |
| 171 | + |
| 172 | + // Write lock file header |
| 173 | + lock_file << "# cforge.lock - Dependency lock file for reproducible builds\n"; |
| 174 | + lock_file << "# Generated by cforge - DO NOT EDIT MANUALLY\n"; |
| 175 | + lock_file << "# Mode: FetchContent\n\n"; |
| 176 | + |
| 177 | + // Get index dependencies from cforge.toml |
| 178 | + auto dep_keys = config.get_table_keys("dependencies"); |
| 179 | + bool has_deps = false; |
| 180 | + |
| 181 | + for (const auto &key : dep_keys) { |
| 182 | + // Skip config keys |
| 183 | + if (key == "fetch_content" || key == "directory" || key == "git" || key == "vcpkg") { |
| 184 | + continue; |
| 185 | + } |
| 186 | + |
| 187 | + std::string version = config.get_string("dependencies." + key, "*"); |
| 188 | + |
| 189 | + // Try to get package info from registry |
| 190 | + auto pkg_info = reg.get_package(key); |
| 191 | + std::string resolved_version = version; |
| 192 | + std::string repository; |
| 193 | + std::string git_tag; |
| 194 | + |
| 195 | + if (pkg_info) { |
| 196 | + repository = pkg_info->repository; |
| 197 | + // Resolve version |
| 198 | + resolved_version = reg.resolve_version(key, version); |
| 199 | + if (resolved_version.empty()) { |
| 200 | + resolved_version = version; |
| 201 | + } |
| 202 | + // Get git tag for the version |
| 203 | + for (const auto &ver : pkg_info->versions) { |
| 204 | + if (ver.version == resolved_version) { |
| 205 | + git_tag = ver.tag; |
| 206 | + break; |
| 207 | + } |
| 208 | + } |
| 209 | + // If no explicit tag, use tag pattern |
| 210 | + if (git_tag.empty() && !pkg_info->tags.pattern.empty()) { |
| 211 | + git_tag = pkg_info->tags.pattern; |
| 212 | + size_t pos = git_tag.find("{version}"); |
| 213 | + if (pos != std::string::npos) { |
| 214 | + git_tag.replace(pos, 9, resolved_version); |
| 215 | + } |
| 216 | + } |
| 217 | + } |
| 218 | + |
| 219 | + lock_file << "[dependency." << key << "]\n"; |
| 220 | + lock_file << "source_type = \"index\"\n"; |
| 221 | + lock_file << "version = \"" << resolved_version << "\"\n"; |
| 222 | + if (!repository.empty()) { |
| 223 | + lock_file << "url = \"" << repository << "\"\n"; |
| 224 | + } |
| 225 | + if (!git_tag.empty()) { |
| 226 | + lock_file << "resolved = \"" << git_tag << "\"\n"; |
| 227 | + } |
| 228 | + lock_file << "\n"; |
| 229 | + has_deps = true; |
| 230 | + |
| 231 | + if (verbose) { |
| 232 | + logger::print_verbose("Locked " + key + " @ " + resolved_version); |
| 233 | + } |
| 234 | + } |
| 235 | + |
| 236 | + // Also handle git dependencies |
| 237 | + for (const auto &key : config.get_table_keys("dependencies.git")) { |
| 238 | + std::string url = config.get_string("dependencies.git." + key + ".url", ""); |
| 239 | + std::string tag = config.get_string("dependencies.git." + key + ".tag", ""); |
| 240 | + std::string branch = config.get_string("dependencies.git." + key + ".branch", ""); |
| 241 | + std::string commit = config.get_string("dependencies.git." + key + ".commit", ""); |
| 242 | + |
| 243 | + lock_file << "[dependency." << key << "]\n"; |
| 244 | + lock_file << "source_type = \"git\"\n"; |
| 245 | + if (!url.empty()) lock_file << "url = \"" << url << "\"\n"; |
| 246 | + if (!tag.empty()) lock_file << "version = \"" << tag << "\"\n"; |
| 247 | + if (!branch.empty()) lock_file << "branch = \"" << branch << "\"\n"; |
| 248 | + if (!commit.empty()) lock_file << "resolved = \"" << commit << "\"\n"; |
| 249 | + lock_file << "\n"; |
| 250 | + has_deps = true; |
| 251 | + } |
| 252 | + |
| 253 | + lock_file.close(); |
| 254 | + |
| 255 | + if (!has_deps) { |
| 256 | + logger::print_warning("No dependencies found to lock"); |
| 257 | + std::filesystem::remove(lock_path); |
| 258 | + return 0; |
| 259 | + } |
| 260 | + |
| 261 | + logger::generated(std::string(LOCK_FILE)); |
| 262 | + logger::print_action( |
| 263 | + "Note", "commit this file to version control for reproducible builds"); |
| 264 | + return 0; |
| 265 | + } |
| 266 | + |
| 267 | + // Non-FetchContent mode: scan deps directory |
156 | 268 | if (!std::filesystem::exists(deps_dir)) { |
157 | 269 | logger::print_warning("Dependencies directory not found: " + |
158 | 270 | deps_dir.string()); |
|
0 commit comments