Skip to content

Commit e985ab8

Browse files
committed
Fix bugs
1 parent 74a2fa3 commit e985ab8

File tree

7 files changed

+261
-29
lines changed

7 files changed

+261
-29
lines changed

CMakeLists.txt

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,6 @@ target_link_libraries(${PROJECT_NAME} PUBLIC
120120
tomlplusplus::tomlplusplus
121121
)
122122

123-
# Definitions for config 'Debug'
124-
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
125-
target_compile_definitions(${PROJECT_NAME} PUBLIC DEBUG=1)
126-
target_compile_definitions(${PROJECT_NAME} PUBLIC FMT_HEADER_ONLY=ON)
127-
target_compile_definitions(${PROJECT_NAME} PUBLIC FMT_UNICODE=0)
128-
endif()
129-
130123
# Link libraries
131124
target_link_libraries(${PROJECT_NAME} PUBLIC
132125
)
@@ -169,7 +162,7 @@ endif()
169162

170163
# CPack configuration
171164
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}")
172-
set(CPACK_PACKAGE_VENDOR "Chase Sunstrom")
165+
set(CPACK_PACKAGE_VENDOR "Unknown")
173166
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A C/C++ build tool with dependency management")
174167
set(CPACK_PACKAGE_VERSION "2.3.0")
175168
set(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME}")

cforge.hash

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
# Do not commit to version control.
44

55
[metadata]
6-
generated = "2025-12-08T23:58:51Z"
6+
generated = "2025-12-09T00:30:37Z"
77

88
[config]
9-
hash = "192a6443b869e18e"
9+
hash = "7f2b48ac9f98c592"
1010

include/core/lockfile.hpp

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "cforge/log.hpp"
1212
#include "core/constants.h"
1313
#include "core/git_utils.hpp"
14+
#include "core/registry.hpp"
1415
#include "core/toml_reader.hpp"
1516

1617
#include <chrono>
@@ -514,4 +515,118 @@ inline bool verify_lockfile(const std::filesystem::path &project_dir,
514515
return all_match;
515516
}
516517

518+
/**
519+
* @brief Generate lock file from cforge.toml configuration (for FetchContent mode)
520+
*
521+
* @param project_dir Project directory
522+
* @param config Project configuration
523+
* @param verbose Verbose output
524+
* @return true if lock file was generated successfully
525+
*/
526+
inline bool generate_lockfile_from_config(const std::filesystem::path &project_dir,
527+
const toml_reader &config,
528+
bool verbose = false) {
529+
registry reg;
530+
std::filesystem::path lock_path = project_dir / LOCK_FILE;
531+
std::ofstream lock_file(lock_path);
532+
533+
if (!lock_file.is_open()) {
534+
if (verbose) {
535+
logger::print_warning("Failed to create lock file: " + lock_path.string());
536+
}
537+
return false;
538+
}
539+
540+
// Write lock file header
541+
lock_file << "# cforge.lock - Dependency lock file for reproducible builds\n";
542+
lock_file << "# Generated by cforge - DO NOT EDIT MANUALLY\n";
543+
lock_file << "# Mode: FetchContent\n\n";
544+
545+
// Get index dependencies from cforge.toml
546+
auto dep_keys = config.get_table_keys("dependencies");
547+
bool has_deps = false;
548+
549+
for (const auto &key : dep_keys) {
550+
// Skip config keys
551+
if (key == "fetch_content" || key == "directory" || key == "git" || key == "vcpkg") {
552+
continue;
553+
}
554+
555+
std::string version = config.get_string("dependencies." + key, "*");
556+
557+
// Try to get package info from registry
558+
auto pkg_info = reg.get_package(key);
559+
std::string resolved_version = version;
560+
std::string repository;
561+
std::string git_tag;
562+
563+
if (pkg_info) {
564+
repository = pkg_info->repository;
565+
// Resolve version
566+
resolved_version = reg.resolve_version(key, version);
567+
if (resolved_version.empty()) {
568+
resolved_version = version;
569+
}
570+
// Get git tag for the version
571+
for (const auto &ver : pkg_info->versions) {
572+
if (ver.version == resolved_version) {
573+
git_tag = ver.tag;
574+
break;
575+
}
576+
}
577+
// If no explicit tag, use tag pattern
578+
if (git_tag.empty() && !pkg_info->tags.pattern.empty()) {
579+
git_tag = pkg_info->tags.pattern;
580+
size_t pos = git_tag.find("{version}");
581+
if (pos != std::string::npos) {
582+
git_tag.replace(pos, 9, resolved_version);
583+
}
584+
}
585+
}
586+
587+
lock_file << "[dependency." << key << "]\n";
588+
lock_file << "source_type = \"index\"\n";
589+
lock_file << "version = \"" << resolved_version << "\"\n";
590+
if (!repository.empty()) {
591+
lock_file << "url = \"" << repository << "\"\n";
592+
}
593+
if (!git_tag.empty()) {
594+
lock_file << "resolved = \"" << git_tag << "\"\n";
595+
}
596+
lock_file << "\n";
597+
has_deps = true;
598+
599+
if (verbose) {
600+
logger::print_verbose("Locked " + key + " @ " + resolved_version);
601+
}
602+
}
603+
604+
// Also handle git dependencies
605+
for (const auto &key : config.get_table_keys("dependencies.git")) {
606+
std::string url = config.get_string("dependencies.git." + key + ".url", "");
607+
std::string tag = config.get_string("dependencies.git." + key + ".tag", "");
608+
std::string branch = config.get_string("dependencies.git." + key + ".branch", "");
609+
std::string commit = config.get_string("dependencies.git." + key + ".commit", "");
610+
611+
lock_file << "[dependency." << key << "]\n";
612+
lock_file << "source_type = \"git\"\n";
613+
if (!url.empty()) lock_file << "url = \"" << url << "\"\n";
614+
if (!tag.empty()) lock_file << "version = \"" << tag << "\"\n";
615+
if (!branch.empty()) lock_file << "branch = \"" << branch << "\"\n";
616+
if (!commit.empty()) lock_file << "resolved = \"" << commit << "\"\n";
617+
lock_file << "\n";
618+
has_deps = true;
619+
}
620+
621+
lock_file.close();
622+
623+
if (!has_deps) {
624+
// No dependencies, remove empty lock file
625+
std::filesystem::remove(lock_path);
626+
return true;
627+
}
628+
629+
return true;
630+
}
631+
517632
} // namespace cforge

src/core/command_add.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -322,18 +322,26 @@ static bool add_dependency_to_section(const std::filesystem::path &config_file,
322322
int section_end = -1;
323323

324324
// Read all lines and find the section
325+
std::string section_header = "[" + section + "]";
325326
while (std::getline(file, line)) {
326327
lines.push_back(line);
327328

328-
// Check if this is our section
329-
if (line.find("[" + section + "]") != std::string::npos) {
329+
// Trim whitespace for comparison
330+
std::string trimmed = line;
331+
size_t start = trimmed.find_first_not_of(" \t");
332+
if (start != std::string::npos) {
333+
trimmed = trimmed.substr(start);
334+
}
335+
336+
// Check if this is exactly our section (not a subsection like [dependencies.git])
337+
if (trimmed == section_header) {
330338
in_section = true;
331339
section_found = true;
332340
continue;
333341
}
334342

335343
// Check if we're leaving the section (new section starts)
336-
if (in_section && !line.empty() && line[0] == '[') {
344+
if (in_section && !trimmed.empty() && trimmed[0] == '[') {
337345
section_end = lines.size() - 1;
338346
in_section = false;
339347
}
@@ -345,8 +353,11 @@ static bool add_dependency_to_section(const std::filesystem::path &config_file,
345353
if (verbose) {
346354
logger::print_verbose("Creating new section: [" + section + "]");
347355
}
348-
lines.push_back(""); // Add blank line before new section
349-
lines.push_back("[" + section + "]");
356+
// Add blank line before new section if file doesn't end with blank line
357+
if (!lines.empty() && !lines.back().empty()) {
358+
lines.push_back("");
359+
}
360+
lines.push_back(section_header);
350361
section_end = lines.size();
351362
}
352363

src/core/command_build.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -660,13 +660,8 @@ static bool run_cmake_configure(const std::vector<std::string> &cmake_args,
660660
formatted_errors = format_build_errors(pr.stdout_output);
661661
}
662662
if (!formatted_errors.empty()) {
663-
std::istringstream iss(formatted_errors);
664-
std::string line;
665-
while (std::getline(iss, line)) {
666-
if (!line.empty()) {
667-
logger::print_error(line);
668-
}
669-
}
663+
// Print formatted errors directly (they already contain "error" prefix from Rust-style formatting)
664+
fmt::print("{}", formatted_errors);
670665
} else {
671666
// Fallback: print raw outputs
672667
if (!pr.stderr_output.empty()) {
@@ -824,10 +819,16 @@ static bool build_project(const std::filesystem::path &project_dir,
824819

825820
// Generate/update lock file after dependencies are resolved
826821
{
822+
bool use_fetch_content = project_config.get_bool("dependencies.fetch_content", true);
827823
std::string deps_dir_str =
828824
project_config.get_string("dependencies.directory", "deps");
829825
std::filesystem::path deps_path = project_dir / deps_dir_str;
830-
if (std::filesystem::exists(deps_path)) {
826+
827+
if (use_fetch_content) {
828+
// FetchContent mode: generate lock file from cforge.toml + registry
829+
generate_lockfile_from_config(project_dir, project_config, verbose);
830+
} else if (std::filesystem::exists(deps_path)) {
831+
// Clone mode: scan deps directory
831832
update_lockfile(project_dir, deps_path, verbose);
832833
}
833834
}

src/core/command_lock.cpp

Lines changed: 114 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
#include "core/commands.hpp"
1313
#include "core/constants.h"
1414
#include "core/lockfile.hpp"
15+
#include "core/registry.hpp"
1516
#include "core/toml_reader.hpp"
1617
#include "core/workspace.hpp"
1718

1819
#include <cstring>
1920
#include <filesystem>
21+
#include <fstream>
2022
#include <string>
2123

2224
using namespace cforge;
@@ -108,9 +110,9 @@ cforge_int_t cforge_cmd_lock(const cforge_context_t *ctx) {
108110
return 1;
109111
}
110112

111-
// Get dependencies directory
113+
// Get dependencies directory (default: deps)
112114
std::string deps_dir_str =
113-
config.get_string("dependencies.directory", "vendor");
115+
config.get_string("dependencies.directory", "deps");
114116
std::filesystem::path deps_dir = current_dir / deps_dir_str;
115117

116118
// Handle --verify option
@@ -153,6 +155,116 @@ cforge_int_t cforge_cmd_lock(const cforge_context_t *ctx) {
153155
// Generate/update lock file
154156
logger::print_action("Generating", "lock file");
155157

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
156268
if (!std::filesystem::exists(deps_dir)) {
157269
logger::print_warning("Dependencies directory not found: " +
158270
deps_dir.string());

0 commit comments

Comments
 (0)