common : prepare load_from_models_dir() for path conversion (#29674)

This is part of the fs::path modernization series.
That was also the opportunity to remove fs_list().

Signed-off-by: Adrien Gallouët <angt@huggingface.co>
This commit is contained in:
Adrien Gallouët
2026-10-04 10:35:33 +02:00
committed by GitHub
parent bf9a0ccce7
commit 6716df694b
3 changed files with 57 additions and 94 deletions
-41
View File
@@ -1033,47 +1033,6 @@ std::filesystem::path fs_get_cache_file(const std::string & filename) {
return cache_directory / std::filesystem::u8path(filename);
}
std::vector<common_file_info> fs_list(const std::string & path, bool include_directories) {
std::vector<common_file_info> files;
if (path.empty()) return files;
std::filesystem::path dir(path);
if (!std::filesystem::exists(dir) || !std::filesystem::is_directory(dir)) {
return files;
}
for (const auto & entry : std::filesystem::directory_iterator(dir)) {
try {
// Only include regular files (skip directories)
const auto & p = entry.path();
if (std::filesystem::is_regular_file(p)) {
common_file_info info;
info.path = p.string();
info.name = p.filename().string();
info.is_dir = false;
try {
info.size = static_cast<size_t>(std::filesystem::file_size(p));
} catch (const std::filesystem::filesystem_error &) {
info.size = 0;
}
files.push_back(std::move(info));
} else if (include_directories && std::filesystem::is_directory(p)) {
common_file_info info;
info.path = p.string();
info.name = p.filename().string();
info.size = 0; // Directories have no size
info.is_dir = true;
files.push_back(std::move(info));
}
} catch (const std::filesystem::filesystem_error &) {
// skip entries we cannot inspect
continue;
}
}
return files;
}
//
// TTY utils
//
-8
View File
@@ -930,14 +930,6 @@ std::filesystem::path fs_get_cache_directory();
std::filesystem::path fs_get_cache_file(const std::string & filename);
std::filesystem::path fs_get_config_directory();
struct common_file_info {
std::string path;
std::string name;
size_t size = 0; // in bytes
bool is_dir = false;
};
std::vector<common_file_info> fs_list(const std::string & path, bool include_directories);
void fs_write_atomic(const std::filesystem::path & path, const std::string & data);
//
+57 -45
View File
@@ -385,63 +385,75 @@ static bool is_draft_file(const std::string & fname) {
}
common_presets common_preset_context::load_from_models_dir(const std::string & models_dir) const {
if (!std::filesystem::exists(models_dir) || !std::filesystem::is_directory(models_dir)) {
const std::filesystem::path dir = std::filesystem::u8path(models_dir);
if (!std::filesystem::exists(dir) || !std::filesystem::is_directory(dir)) {
throw std::runtime_error(string_format("error: '%s' does not exist or is not a directory\n", models_dir.c_str()));
}
std::vector<local_model> models;
auto scan_subdir = [&models](const std::string & subdir_path, const std::string & name) {
auto files = fs_list(subdir_path, false);
common_file_info model_file;
common_file_info first_shard_file;
common_file_info mmproj_file;
common_file_info draft_file;
for (const auto & file : files) {
if (string_ends_with(file.name, ".gguf")) {
if (is_mmproj_file(file.name)) {
mmproj_file = file;
} else if (is_draft_file(file.name)) {
if (draft_file.path.empty()) {
draft_file = file; // first sidecar found wins
}
} else if (file.name.find("-00001-of-") != std::string::npos) {
first_shard_file = file;
} else {
model_file = file;
auto scan_subdir = [&models](const std::filesystem::path & subdir_path, const std::string & name) {
std::filesystem::path model_file;
std::filesystem::path first_shard_file;
std::filesystem::path mmproj_file;
std::filesystem::path draft_file;
std::error_code ec;
for (const auto & entry : std::filesystem::directory_iterator(subdir_path)) {
if (!entry.is_regular_file(ec)) {
continue;
}
const std::string fname = fs_path_to_utf8(entry.path().filename());
if (!string_ends_with(fname, ".gguf")) {
continue;
}
if (is_mmproj_file(fname)) {
mmproj_file = entry.path();
} else if (is_draft_file(fname)) {
if (draft_file.empty()) {
draft_file = entry.path(); // first sidecar found wins
}
} else if (fname.find("-00001-of-") != std::string::npos) {
first_shard_file = entry.path();
} else {
model_file = entry.path();
}
}
// single file model
local_model model{
/* name */ name,
/* path */ first_shard_file.path.empty() ? model_file.path : first_shard_file.path,
/* path_mmproj */ mmproj_file.path, // can be empty
/* path_draft */ draft_file.path // can be empty
};
if (!model.path.empty()) {
models.push_back(model);
const std::filesystem::path & path = first_shard_file.empty() ? model_file : first_shard_file;
if (!path.empty()) {
models.push_back({
/* name */ name,
/* path */ fs_path_to_utf8(path),
/* path_mmproj */ fs_path_to_utf8(mmproj_file), // can be empty
/* path_draft */ fs_path_to_utf8(draft_file) // can be empty
});
}
};
auto files = fs_list(models_dir, true);
for (const auto & file : files) {
if (file.is_dir) {
scan_subdir(file.path, file.name);
} else if (string_ends_with(file.name, ".gguf")) {
if (is_mmproj_file(file.name) || is_draft_file(file.name)) {
continue; // companion file, cannot be loaded as a model on its own
}
// single file model
std::string name = file.name;
string_replace_all(name, ".gguf", "");
local_model model{
/* name */ name,
/* path */ file.path,
/* path_mmproj */ "",
/* path_draft */ ""
};
models.push_back(model);
for (const auto & entry : std::filesystem::directory_iterator(dir)) {
std::error_code ec;
if (entry.is_directory(ec)) {
scan_subdir(entry.path(), fs_path_to_utf8(entry.path().filename()));
continue;
}
if (!entry.is_regular_file(ec)) {
continue;
}
const std::string fname = fs_path_to_utf8(entry.path().filename());
if (!string_ends_with(fname, ".gguf")) {
continue;
}
if (is_mmproj_file(fname) || is_draft_file(fname)) {
continue; // companion file, cannot be loaded as a model on its own
}
// single file model
std::string name = fname;
string_replace_all(name, ".gguf", "");
models.push_back({
/* name */ name,
/* path */ fs_path_to_utf8(entry.path()),
/* path_mmproj */ "",
/* path_draft */ ""
});
}
// convert local models to presets