BKE link/append: Add optional blendfile handle to libraries.

This enables calling code to deal with the blendfile handle themselves,
BKE_blendfile_link then just borrows, uses this handle and does not
release it.

Needed e.g. for python's libcontext system to use new
BKE_blendfile_link_append code.

Part of T91414: Unify link/append between WM operators and BPY context
manager API, and cleanup usages of `BKE_library_make_local`.
This commit is contained in:
Bastien Montagne 2021-11-10 11:24:59 +01:00
parent f657356062
commit fbb4a7eb43
3 changed files with 87 additions and 27 deletions

View File

@ -23,6 +23,7 @@
extern "C" {
#endif
struct BlendHandle;
struct ID;
struct Library;
struct LibraryLink_Params;
@ -50,7 +51,8 @@ void BKE_blendfile_link_append_context_embedded_blendfile_clear(
struct BlendfileLinkAppendContext *lapp_context);
void BKE_blendfile_link_append_context_library_add(struct BlendfileLinkAppendContext *lapp_context,
const char *libname);
const char *libname,
struct BlendHandle *blo_handle);
struct BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add(
struct BlendfileLinkAppendContext *lapp_context,
const char *idname,

View File

@ -94,6 +94,15 @@ typedef struct BlendfileLinkAppendContextItem {
void *userdata;
} BlendfileLinkAppendContextItem;
/* A blendfile library entry in the `libraries` list of #BlendfileLinkAppendContext. */
typedef struct BlendfileLinkAppendContextLibrary {
char *path; /* Absolute .blend file path. */
BlendHandle *blo_handle; /* Blend file handle, if any. */
bool blo_handle_is_owned; /* Whether the blend file handle is owned, or borrowed. */
/* The blendfile report associated with the `blo_handle`, if owned. */
BlendFileReadReport bf_reports;
} BlendfileLinkAppendContextLibrary;
typedef struct BlendfileLinkAppendContext {
/** List of library paths to search IDs in. */
LinkNodePair libraries;
@ -140,6 +149,43 @@ enum {
LINK_APPEND_TAG_INDIRECT = 1 << 0,
};
static BlendHandle *link_append_context_library_blohandle_ensure(
BlendfileLinkAppendContext *lapp_context,
BlendfileLinkAppendContextLibrary *lib_context,
ReportList *reports)
{
if (reports != NULL) {
lib_context->bf_reports.reports = reports;
}
char *libname = lib_context->path;
BlendHandle *blo_handle = lib_context->blo_handle;
if (blo_handle == NULL) {
if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) {
blo_handle = BLO_blendhandle_from_memory(lapp_context->blendfile_mem,
(int)lapp_context->blendfile_memsize,
&lib_context->bf_reports);
}
else {
blo_handle = BLO_blendhandle_from_file(libname, &lib_context->bf_reports);
}
lib_context->blo_handle = blo_handle;
lib_context->blo_handle_is_owned = true;
}
return blo_handle;
}
static void link_append_context_library_blohandle_release(
BlendfileLinkAppendContext *UNUSED(lapp_context),
BlendfileLinkAppendContextLibrary *lib_context)
{
if (lib_context->blo_handle_is_owned && lib_context->blo_handle != NULL) {
BLO_blendhandle_close(lib_context->blo_handle);
lib_context->blo_handle = NULL;
}
}
/** Allocate and initialize a new context to link/append datablocks.
*
* \param flag a combination of #eFileSel_Params_Flag from DNA_space_types.h & #eBLOLibLinkFlags
@ -163,6 +209,12 @@ void BKE_blendfile_link_append_context_free(BlendfileLinkAppendContext *lapp_con
BLI_ghash_free(lapp_context->new_id_to_item, NULL, NULL);
}
for (LinkNode *liblink = lapp_context->libraries.list; liblink != NULL;
liblink = liblink->next) {
BlendfileLinkAppendContextLibrary *lib_context = liblink->link;
link_append_context_library_blohandle_release(lapp_context, lib_context);
}
BLI_assert(lapp_context->library_weak_reference_mapping == NULL);
BLI_memarena_free(lapp_context->memarena);
@ -208,19 +260,32 @@ void BKE_blendfile_link_append_context_embedded_blendfile_clear(
}
/** Add a new source library to search for items to be linked to the given link/append context.
*
* \param libname: the absolute path to the library blend file.
* \param blo_handle: the blend file handle of the library, NULL is not available. Note that this
* is only borrowed for linking purpose, no releasing or other management will
* be performed by #BKE_blendfile_link_append code on it.
*
* \note *Never* call BKE_blendfile_link_append_context_library_add() after having added some
* items. */
void BKE_blendfile_link_append_context_library_add(BlendfileLinkAppendContext *lapp_context,
const char *libname)
const char *libname,
BlendHandle *blo_handle)
{
BLI_assert(lapp_context->items.list == NULL);
BlendfileLinkAppendContextLibrary *lib_context = BLI_memarena_calloc(lapp_context->memarena,
sizeof(*lib_context));
size_t len = strlen(libname) + 1;
char *libpath = BLI_memarena_alloc(lapp_context->memarena, len);
BLI_strncpy(libpath, libname, len);
BLI_linklist_append_arena(&lapp_context->libraries, libpath, lapp_context->memarena);
lib_context->path = libpath;
lib_context->blo_handle = blo_handle;
lib_context->blo_handle_is_owned = (blo_handle == NULL);
BLI_linklist_append_arena(&lapp_context->libraries, lib_context, lapp_context->memarena);
lapp_context->num_libraries++;
}
@ -1076,7 +1141,6 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *
void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports)
{
Main *mainl;
BlendHandle *bh;
Library *lib;
LinkNode *liblink, *itemlink;
@ -1086,18 +1150,12 @@ void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *re
for (lib_idx = 0, liblink = lapp_context->libraries.list; liblink;
lib_idx++, liblink = liblink->next) {
char *libname = liblink->link;
BlendFileReadReport bf_reports = {.reports = reports};
BlendfileLinkAppendContextLibrary *lib_context = liblink->link;
char *libname = lib_context->path;
BlendHandle *blo_handle = link_append_context_library_blohandle_ensure(
lapp_context, lib_context, reports);
if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) {
bh = BLO_blendhandle_from_memory(
lapp_context->blendfile_mem, (int)lapp_context->blendfile_memsize, &bf_reports);
}
else {
bh = BLO_blendhandle_from_file(libname, &bf_reports);
}
if (bh == NULL) {
if (blo_handle == NULL) {
/* Unlikely since we just browsed it, but possible
* Error reports will have been made by BLO_blendhandle_from_file() */
continue;
@ -1111,7 +1169,7 @@ void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *re
* #loose_data_instantiate instead. */
lapp_context->params->flag &= ~BLO_LIBLINK_NEEDS_ID_TAG_DOIT;
mainl = BLO_library_link_begin(&bh, libname, lapp_context->params);
mainl = BLO_library_link_begin(&blo_handle, libname, lapp_context->params);
lib = mainl->curlib;
BLI_assert(lib);
UNUSED_VARS_NDEBUG(lib);
@ -1138,7 +1196,7 @@ void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *re
}
new_id = BLO_library_link_named_part(
mainl, &bh, item->idcode, item->name, lapp_context->params);
mainl, &blo_handle, item->idcode, item->name, lapp_context->params);
if (new_id) {
/* If the link is successful, clear item's libs 'todo' flags.
@ -1149,8 +1207,8 @@ void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *re
}
}
BLO_library_link_end(mainl, &bh, lapp_context->params);
BLO_blendhandle_close(bh);
BLO_library_link_end(mainl, &blo_handle, lapp_context->params);
link_append_context_library_blohandle_release(lapp_context, lib_context);
}
/* Instantiate newly linked IDs as needed, if no append is scheduled. */

View File

@ -309,7 +309,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
if (!BLI_ghash_haskey(libraries, libname)) {
BLI_ghash_insert(libraries, BLI_strdup(libname), POINTER_FROM_INT(lib_idx));
lib_idx++;
BKE_blendfile_link_append_context_library_add(lapp_context, libname);
BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL);
}
}
}
@ -341,7 +341,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
else {
BlendfileLinkAppendContextItem *item;
BKE_blendfile_link_append_context_library_add(lapp_context, libname);
BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL);
item = BKE_blendfile_link_append_context_item_add(
lapp_context, name, BKE_idtype_idcode_from_name(group), NULL);
BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0);
@ -530,7 +530,7 @@ static ID *wm_file_link_append_datablock_ex(Main *bmain,
BKE_blendfile_link_append_context_embedded_blendfile_set(
lapp_context, datatoc_startup_blend, datatoc_startup_blend_size);
BKE_blendfile_link_append_context_library_add(lapp_context, filepath);
BKE_blendfile_link_append_context_library_add(lapp_context, filepath, NULL);
BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add(
lapp_context, id_name, id_code, NULL);
BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0);
@ -651,7 +651,7 @@ void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
BKE_blendfile_link_append_context_library_add(lapp_context, lib->filepath_abs);
BKE_blendfile_link_append_context_library_add(lapp_context, lib->filepath_abs, NULL);
BKE_blendfile_library_relocate(lapp_context, reports, lib, true);
@ -736,7 +736,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
do_reload = true;
lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
BKE_blendfile_link_append_context_library_add(lapp_context, path);
BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL);
}
else {
int totfiles = 0;
@ -769,13 +769,13 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
}
CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path);
BKE_blendfile_link_append_context_library_add(lapp_context, path);
BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL);
}
RNA_END;
}
else {
CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path);
BKE_blendfile_link_append_context_library_add(lapp_context, path);
BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL);
}
}