33 "# This is an Asset Catalog Definition file for Blender.\n"
35 "# Empty lines and lines starting with `#` will be ignored.\n"
36 "# The first non-ignored line should be the version indicator.\n"
37 "# Other lines are of the format \"UUID:catalog/path/for/assets:simple catalog name\"\n";
46 asset_library_root_(asset_library_root)
76 catalog_uptr->flags.has_unsaved_changes =
false;
89 catalog->flags.has_unsaved_changes =
true;
116 const std::unique_ptr<AssetCatalog> *catalog_uptr_ptr =
118 if (catalog_uptr_ptr ==
nullptr) {
121 return catalog_uptr_ptr->get();
132 if (catalog->path == path) {
133 ordered_catalogs.insert(catalog.get());
137 if (ordered_catalogs.empty()) {
141 MutableAssetCatalogOrderedSet::iterator best_choice_it = ordered_catalogs.begin();
142 return *best_choice_it;
156 matching_catalog_ids.
add(active_catalog_id);
167 matching_catalog_ids.
add(catalog_uptr->catalog_id);
169 known_catalog_ids.
add(catalog_uptr->catalog_id);
172 return AssetCatalogFilter(std::move(matching_catalog_ids), std::move(known_catalog_ids));
177 std::unique_ptr<AssetCatalog> *catalog_uptr_ptr =
catalog_collection_->catalogs_.lookup_ptr(
179 if (catalog_uptr_ptr ==
nullptr) {
217 for (
const CatalogID cat_id : catalogs_to_delete) {
227 BLI_assert_msg(catalog,
"trying to prune asset catalogs by the path of a non-existent catalog");
247 cat->
path = new_path;
261 catalog->flags.has_unsaved_changes =
true;
270 "duplicate catalog ID not supported");
290 asset_library_root.
data(),
303 if (
BLI_stat(file_or_directory_path.data(), &status) == -1) {
305 CLOG_WARN(&
LOG,
"path not found: %s", file_or_directory_path.data());
312 else if (
S_ISDIR(status.st_mode)) {
332 CLOG_INFO(&
LOG, 2,
"path not found: %s", file_path.data());
344 catalog_definition_file_path);
347 "Only loading of a single catalog definition file is supported.");
354 auto cdf = std::make_unique<AssetCatalogDefinitionFile>();
355 cdf->file_path = catalog_definition_file_path;
360 auto catalog_parsed_callback = [
this, catalog_definition_file_path, &seen_paths](
361 std::unique_ptr<AssetCatalog> catalog) {
364 std::cerr << catalog_definition_file_path <<
": multiple definitions of catalog "
365 << catalog->catalog_id <<
" in multiple files, ignoring this one." << std::endl;
370 catalog->flags.is_first_loaded = seen_paths.
add(catalog->path);
377 cdf->parse_catalog_file(cdf->file_path, catalog_parsed_callback);
394 auto catalog_parsed_callback = [
this, &cats_in_file](std::unique_ptr<AssetCatalog> catalog) {
395 const CatalogID catalog_id = catalog->catalog_id;
396 cats_in_file.
add(catalog_id);
419 if (catalogs_to_keep.
contains(cat_id)) {
426 cats_to_remove.
add(cat_id);
429 for (
CatalogID cat_id : cats_to_remove) {
441 const std::unique_ptr<AssetCatalog> *catalog_uptr_ptr =
443 if (!catalog_uptr_ptr) {
507 "A non-empty .blend file path is required to be able to determine where the "
508 "catalog definition file should be put");
513 blend_file_path.c_str(), suitable_root_path);
514 if (asset_lib_root_found) {
517 sizeof(asset_lib_cdf_path),
521 return asset_lib_cdf_path;
529 return cdf_path_next_to_blend;
535 auto cdf = std::make_unique<AssetCatalogDefinitionFile>();
536 cdf->file_path = file_path;
539 cdf->add_new(catalog.get());
552 auto tree = std::make_unique<AssetCatalogTree>();
556 tree->insert_item(*catalog);
571 std::set<AssetCatalogPath> paths_to_check;
573 paths_to_check.insert(catalog->path);
576 std::set<AssetCatalogPath> seen_paths;
581 while (!paths_to_check.empty()) {
584 paths_to_check.erase(paths_to_check.begin());
586 if (seen_paths.find(path) != seen_paths.end()) {
590 seen_paths.insert(path);
593 if (seen_paths.find(parent_path) != seen_paths.end()) {
602 paths_to_check.insert(parent_path);
647 auto copy = std::make_unique<AssetCatalogCollection>();
655 copy->catalogs_,
copy->deleted_catalogs_);
665 for (
const auto &orig_catalog_uptr : orig.
values()) {
666 auto copy_catalog_uptr = std::make_unique<AssetCatalog>(*orig_catalog_uptr);
667 copy.add_new(copy_catalog_uptr->catalog_id, std::move(copy_catalog_uptr));
679 : name_(name), catalog_id_(catalog_id), simple_name_(simple_name), parent_(parent)
728 for (
auto &[key, item] : children) {
730 foreach_item_recursive(item.children_,
callback);
751 "Malformed catalog path; should not start with a separator");
757 auto [key_and_item, was_inserted] = current_item_children->emplace(
760 is_last_component ? catalog.
catalog_id : nil_id,
767 if (is_last_component) {
769 item.catalog_id_ = catalog.catalog_id;
820 fstream infile(catalog_definition_file_path, std::ios::in);
822 if (!infile.is_open()) {
823 CLOG_ERROR(&
LOG,
"%s: unable to open file", catalog_definition_file_path.c_str());
826 bool seen_version_number =
false;
828 while (std::getline(infile, line)) {
830 if (trimmed_line.
is_empty() || trimmed_line[0] ==
'#') {
834 if (!seen_version_number) {
837 if (!is_valid_version) {
838 std::cerr << catalog_definition_file_path
839 <<
": first line should be version declaration; ignoring file." << std::endl;
842 seen_version_number =
true;
852 const bool keep_catalog = catalog_loaded_callback(std::move(catalog));
869 const int file_version = std::atoi(version_string.c_str());
877 const char delim =
':';
880 std::cerr <<
"Invalid catalog line in " << this->
file_path <<
": " << line << std::endl;
881 return std::unique_ptr<AssetCatalog>(
nullptr);
885 const std::string id_as_string = line.
substr(0, first_delim).
trim();
888 if (!uuid_parsed_ok) {
889 std::cerr <<
"Invalid UUID in " << this->
file_path <<
": " << line << std::endl;
890 return std::unique_ptr<AssetCatalog>(
nullptr);
897 std::string path_in_file;
898 std::string simple_name;
899 if (second_delim == 0) {
901 return std::unique_ptr<AssetCatalog>(
nullptr);
906 path_in_file = path_and_simple_name;
910 path_in_file = path_and_simple_name.
substr(0, second_delim);
911 simple_name = path_and_simple_name.
substr(second_delim + 1).
trim();
915 return std::make_unique<AssetCatalog>(catalog_id, catalog_path.
cleanup(), simple_name);
934 if (
BLI_rename(dest_file_path.c_str(), backup_path.c_str())) {
939 if (
BLI_rename(writable_path.c_str(), dest_file_path.c_str())) {
963 output <<
"" << std::endl;
965 output <<
"" << std::endl;
970 if (catalog->flags.is_deleted) {
973 catalogs_by_path.insert(catalog);
977 output << catalog->catalog_id <<
":" << catalog->path <<
":" << catalog->simple_name
989 if (directory_path.empty()) {
991 <<
"AssetCatalogService: no asset library root configured, unable to ensure it exists."
998 std::cerr <<
"AssetCatalogService: " << directory_path
999 <<
" exists but is not a directory, this is not a supported situation."
1009 std::error_code err_code;
1011 std::cerr <<
"AssetCatalogService: error creating directory " << directory_path <<
": "
1012 << err_code << std::endl;
1023 auto copy = std::make_unique<AssetCatalogDefinitionFile>(*
this);
1024 copy->catalogs_.clear();
1029 const std::unique_ptr<AssetCatalog> *remapped_catalog_uptr_ptr = catalogs.
lookup_ptr(
1031 if (remapped_catalog_uptr_ptr) {
1032 copy->catalogs_.add_new(catalog_id, remapped_catalog_uptr_ptr->get());
1036 remapped_catalog_uptr_ptr = deleted_catalogs.
lookup_ptr(catalog_id);
1037 if (remapped_catalog_uptr_ptr) {
1038 copy->catalogs_.add_new(catalog_id, remapped_catalog_uptr_ptr->get());
1042 BLI_assert(!
"A CDF should only reference known catalogs.");
1050 const std::string &simple_name)
1051 : catalog_id(catalog_id), path(path), simple_name(simple_name)
1060 auto catalog = std::make_unique<AssetCatalog>(cat_id, clean_path,
simple_name);
1071 std::string name =
path.
str();
1073 if (name.length() <
MAX_NAME - 1) {
1079 return "..." + name.substr(name.length() - 60);
1084 : matching_catalog_ids(
std::move(matching_catalog_ids)),
1085 known_catalog_ids(
std::move(known_catalog_ids))
bool BKE_asset_library_find_suitable_root_path_from_path(const char *input_path, char r_library_path[768])
#define BLI_assert_msg(a, msg)
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int BLI_stat(const char *path, BLI_stat_t *buffer) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int BLI_rename(const char *from, const char *to) ATTR_NONNULL()
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
bool BLI_dir_create_recursive(const char *dir) ATTR_NONNULL()
File and directory operations.
void BLI_split_dir_part(const char *string, char *dir, size_t dirlen)
size_t BLI_path_join(char *__restrict dst, size_t dst_len, const char *path_first,...) ATTR_NONNULL(1
void BLI_join_dirfile(char *__restrict dst, size_t maxlen, const char *__restrict dir, const char *__restrict file) ATTR_NONNULL()
bool BLI_uuid_parse_string(bUUID *uuid, const char *buffer) ATTR_NONNULL()
bool BLI_uuid_is_nil(bUUID uuid)
bUUID BLI_uuid_generate_random(void)
Compatibility-like things for windows.
#define CLOG_ERROR(clg_ref,...)
#define CLOG_WARN(clg_ref,...)
#define CLOG_INFO(clg_ref, level,...)
ValueIterator values() const
const Value * lookup_ptr(const Key &key) const
bool contains(const Key &key) const
static constexpr int64_t not_found
constexpr bool is_empty() const
constexpr StringRef substr(int64_t start, int64_t size) const
constexpr bool startswith(StringRef prefix) const
constexpr int64_t find_first_of(StringRef chars, int64_t pos=0) const
constexpr StringRef trim() const
constexpr const char * data() const
static OwningAssetCatalogMap copy_catalog_map(const OwningAssetCatalogMap &orig)
bool has_unsaved_changes_
OwningAssetCatalogMap deleted_catalogs_
std::unique_ptr< AssetCatalogCollection > deep_copy() const
OwningAssetCatalogMap catalogs_
std::unique_ptr< AssetCatalogDefinitionFile > catalog_definition_file_
void parse_catalog_file(const CatalogFilePath &catalog_definition_file_path, AssetCatalogParsedFn callback)
static const std::string VERSION_MARKER
bool parse_version_line(StringRef line)
bool ensure_directory_exists(const CatalogFilePath directory_path) const
void forget(CatalogID catalog_id)
void add_new(AssetCatalog *catalog)
bool contains(CatalogID catalog_id) const
bool write_to_disk_unsafe(const CatalogFilePath &dest_file_path) const
static const std::string HEADER
Map< CatalogID, AssetCatalog * > catalogs_
void add_overwrite(AssetCatalog *catalog)
bool write_to_disk() const
std::unique_ptr< AssetCatalog > parse_catalog_line(StringRef line)
CatalogFilePath file_path
std::unique_ptr< AssetCatalogDefinitionFile > copy_and_remap(const OwningAssetCatalogMap &catalogs, const OwningAssetCatalogMap &deleted_catalogs) const
static const int SUPPORTED_VERSION
const Set< CatalogID > matching_catalog_ids
bool is_known(CatalogID asset_catalog_id) const
const Set< CatalogID > known_catalog_ids
bool contains(CatalogID asset_catalog_id) const
AssetCatalogFilter(Set< CatalogID > &&matching_catalog_ids, Set< CatalogID > &&known_catalog_ids)
const std::string & str() const
AssetCatalogPath cleanup() const
static const char SEPARATOR
bool is_contained_in(const AssetCatalogPath &other_path) const
void iterate_components(ComponentIteratorFn callback) const
AssetCatalogPath rebase(const AssetCatalogPath &from_path, const AssetCatalogPath &to_path) const
AssetCatalogPath parent() const
void create_missing_catalogs()
void delete_catalog_by_id_hard(CatalogID catalog_id)
bool has_unsaved_changes() const
std::unique_ptr< AssetCatalogDefinitionFile > parse_catalog_file(const CatalogFilePath &catalog_definition_file_path)
void load_directory_recursive(const CatalogFilePath &directory_path)
std::unique_ptr< AssetCatalogTree > catalog_tree_
AssetCatalog * create_catalog(const AssetCatalogPath &catalog_path)
void delete_catalog_by_id_soft(CatalogID catalog_id)
void untag_has_unsaved_changes()
bool write_to_disk(const CatalogFilePath &blend_file_path)
AssetCatalog * find_catalog_by_path(const AssetCatalogPath &path) const
void update_catalog_path(CatalogID catalog_id, const AssetCatalogPath &new_catalog_path)
void tag_has_unsaved_changes(AssetCatalog *edited_catalog)
AssetCatalogDefinitionFile * get_catalog_definition_file()
AssetCatalogFilter create_catalog_filter(CatalogID active_catalog_id) const
void tag_all_catalogs_as_unsaved_changes()
bool is_redo_possbile() const
std::unique_ptr< AssetCatalogDefinitionFile > construct_cdf_in_memory(const CatalogFilePath &file_path)
AssetCatalog * find_catalog(CatalogID catalog_id) const
static CatalogFilePath find_suitable_cdf_path_for_writing(const CatalogFilePath &blend_file_path)
std::unique_ptr< AssetCatalogTree > read_into_tree()
CatalogFilePath asset_library_root_
void prune_catalogs_by_id(CatalogID catalog_id)
Vector< std::unique_ptr< AssetCatalogCollection > > undo_snapshots_
void load_single_file(const CatalogFilePath &catalog_definition_file_path)
bool is_catalog_known_with_unsaved_changes(CatalogID catalog_id) const
bool is_undo_possbile() const
std::unique_ptr< AssetCatalogCollection > catalog_collection_
AssetCatalogTree * get_catalog_tree()
void prepare_to_merge_on_write()
void prune_catalogs_by_path(const AssetCatalogPath &path)
OwningAssetCatalogMap & get_deleted_catalogs()
void purge_catalogs_not_listed(const Set< CatalogID > &catalogs_to_keep)
static const CatalogFilePath DEFAULT_CATALOG_FILENAME
OwningAssetCatalogMap & get_catalogs()
Vector< std::unique_ptr< AssetCatalogCollection > > redo_snapshots_
bool is_catalog_known(CatalogID catalog_id) const
bool write_to_disk_ex(const CatalogFilePath &blend_file_path)
AssetCatalogTreeItem(StringRef name, CatalogID catalog_id, StringRef simple_name, const AssetCatalogTreeItem *parent=nullptr)
StringRefNull get_name() const
AssetCatalogPath catalog_path() const
std::map< std::string, AssetCatalogTreeItem > ChildMap
int count_parents() const
void foreach_child(const ItemIterFn callback)
bool has_unsaved_changes_
const AssetCatalogTreeItem * parent_
bool has_children() const
bool has_unsaved_changes() const
StringRefNull get_simple_name() const
CatalogID get_catalog_id() const
CatalogPathComponent name_
void insert_item(const AssetCatalog &catalog)
void foreach_item(const AssetCatalogTreeItem::ItemIterFn callback)
void foreach_root_item(const ItemIterFn callback)
struct blender::bke::AssetCatalog::Flags flags
static std::unique_ptr< AssetCatalog > from_path(const AssetCatalogPath &path)
void simple_name_refresh()
static std::string sensible_simple_name_for_path(const AssetCatalogPath &path)
DEGForeachIDComponentCallback callback
ccl_global KernelShaderEvalInput ccl_global float * output
std::set< AssetCatalog *, AssetCatalogLessThan > MutableAssetCatalogOrderedSet
std::string CatalogFilePath
std::set< const AssetCatalog *, AssetCatalogLessThan > AssetCatalogOrderedSet
static std::string asset_definition_default_file_path_from_dir(StringRef asset_library_root)
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
Universally Unique Identifier according to RFC4122.