[Bf-blender-cvs] [ce9949f7fa6] blender-projects-basics: Support active project, set when loading or writing a file (+ tests)

Julian Eisel noreply at git.blender.org
Thu Sep 29 14:37:34 CEST 2022


Commit: ce9949f7fa689e8d9d0c12894fb973cd1da2fffe
Author: Julian Eisel
Date:   Thu Sep 29 14:25:54 2022 +0200
Branches: blender-projects-basics
https://developer.blender.org/rBce9949f7fa689e8d9d0c12894fb973cd1da2fffe

Support active project, set when loading or writing a file (+ tests)

The active project is determined via the path of the .blend file. So if
that changes (on write) or when a new .blend file is opend, the active
project is updated.

Some of the added tests require a latest checkout of the libraries SVN
repository (see rBL63043).

===================================================================

A	source/blender/blenkernel/BKE_blender_project.h
R055	source/blender/blenkernel/BKE_project_settings.hh	source/blender/blenkernel/BKE_blender_project.hh
M	source/blender/blenkernel/BKE_context.h
M	source/blender/blenkernel/CMakeLists.txt
A	source/blender/blenkernel/intern/blender_project.cc
R062	source/blender/blenkernel/intern/project_settings_test.cc	source/blender/blenkernel/intern/blender_project_test.cc
M	source/blender/blenkernel/intern/blendfile.c
M	source/blender/blenkernel/intern/context.c
D	source/blender/blenkernel/intern/project_settings.cc
M	source/blender/blenloader/intern/writefile.cc

===================================================================

diff --git a/source/blender/blenkernel/BKE_blender_project.h b/source/blender/blenkernel/BKE_blender_project.h
new file mode 100644
index 00000000000..8fdda3e18ea
--- /dev/null
+++ b/source/blender/blenkernel/BKE_blender_project.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bke
+ */
+
+#pragma once
+
+#include "DNA_space_types.h"
+
+#include "BLI_compiler_attrs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* C-handle for #bke::BlenderProject. */
+typedef struct BlenderProject BlenderProject;
+
+BlenderProject *BKE_project_active_get(void) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \note: When unsetting an active project, the previously active one will be destroyed, so
+ *        pointers may dangle.
+ */
+void BKE_project_active_unset(void);
+/**
+ * Attempt to load and activate a project based on the given path. If the path doesn't lead into a
+ * project, the active project is unset. Note that the project will be unset on any failure when
+ * loading the project.
+ *
+ * \note: When setting an active project, the previously active one will be destroyed, so pointers
+ *        may dangle.
+ */
+BlenderProject *BKE_project_active_load_from_path(const char *path) ATTR_NONNULL();
+
+const char *BKE_project_root_path_get(const BlenderProject *project) ATTR_WARN_UNUSED_RESULT
+    ATTR_NONNULL();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/BKE_project_settings.hh b/source/blender/blenkernel/BKE_blender_project.hh
similarity index 55%
rename from source/blender/blenkernel/BKE_project_settings.hh
rename to source/blender/blenkernel/BKE_blender_project.hh
index 646a38196bb..9f775009aff 100644
--- a/source/blender/blenkernel/BKE_project_settings.hh
+++ b/source/blender/blenkernel/BKE_blender_project.hh
@@ -12,6 +12,34 @@
 
 namespace blender::bke {
 
+class ProjectSettings;
+
+class BlenderProject {
+  inline static std::unique_ptr<BlenderProject> instance_;
+
+  std::unique_ptr<ProjectSettings> settings_;
+
+ public:
+  static auto get_active [[nodiscard]] () -> BlenderProject *;
+  static auto set_active_from_settings(std::unique_ptr<ProjectSettings> settings)
+      -> BlenderProject *;
+
+  /**
+   * Check if \a path points into a project and return the root directory path of that project (the
+   * one containing the .blender_project directory). Walks "upwards" through the path and returns
+   * the first project found, so if a project is nested inside another one, the nested project is
+   * used.
+   * Both Unix and Windows style slashes are allowed.
+   * \return the project root path or an empty path if not found.
+   */
+  static auto project_root_path_find_from_path [[nodiscard]] (StringRef path) -> StringRef;
+
+  auto get_settings [[nodiscard]] () const -> ProjectSettings &;
+
+ private:
+  explicit BlenderProject(std::unique_ptr<ProjectSettings> settings);
+};
+
 class ProjectSettings {
   /* Path to the project root using slashes in the OS native format. */
   std::string project_root_path_;
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index b7068720469..f3edce7709c 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -22,6 +22,7 @@ extern "C" {
 
 struct ARegion;
 struct Base;
+struct BlenderProject;
 struct CacheFile;
 struct Collection;
 struct Depsgraph;
@@ -173,6 +174,7 @@ struct ARegion *CTX_wm_menu(const bContext *C);
 struct wmGizmoGroup *CTX_wm_gizmo_group(const bContext *C);
 struct wmMsgBus *CTX_wm_message_bus(const bContext *C);
 struct ReportList *CTX_wm_reports(const bContext *C);
+struct BlenderProject *CTX_wm_project(void);
 
 struct View3D *CTX_wm_view3d(const bContext *C);
 struct RegionView3D *CTX_wm_region_view3d(const bContext *C);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 5d8f19fe009..02f604b657c 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -81,6 +81,7 @@ set(SRC
   intern/autoexec.c
   intern/blender.c
   intern/blender_copybuffer.c
+  intern/blender_project.cc
   intern/blender_undo.c
   intern/blender_user_menu.c
   intern/blendfile.c
@@ -254,7 +255,6 @@ set(SRC
   intern/pointcache.c
   intern/pointcloud.cc
   intern/preferences.c
-  intern/project_settings.cc
   intern/report.c
   intern/rigidbody.c
   intern/scene.cc
@@ -330,6 +330,8 @@ set(SRC
   BKE_autoexec.h
   BKE_blender.h
   BKE_blender_copybuffer.h
+  BKE_blender_project.h
+  BKE_blender_project.hh
   BKE_blender_undo.h
   BKE_blender_user_menu.h
   BKE_blender_version.h
@@ -454,7 +456,6 @@ set(SRC
   BKE_pointcache.h
   BKE_pointcloud.h
   BKE_preferences.h
-  BKE_project_settings.hh
   BKE_report.h
   BKE_rigidbody.h
   BKE_scene.h
@@ -835,6 +836,7 @@ if(WITH_GTESTS)
     intern/asset_library_service_test.cc
     intern/asset_library_test.cc
     intern/asset_test.cc
+    intern/blender_project_test.cc
     intern/bpath_test.cc
     intern/cryptomatte_test.cc
     intern/curves_geometry_test.cc
@@ -847,11 +849,11 @@ if(WITH_GTESTS)
     intern/lib_id_remapper_test.cc
     intern/lib_id_test.cc
     intern/lib_remap_test.cc
-    intern/project_settings_test.cc
     intern/tracking_test.cc
   )
   set(TEST_INC
     ../editors/include
+    ../blenloader/tests
   )
   include(GTestTesting)
   blender_add_test_lib(bf_blenkernel_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/blenkernel/intern/blender_project.cc b/source/blender/blenkernel/intern/blender_project.cc
new file mode 100644
index 00000000000..8016b78fd81
--- /dev/null
+++ b/source/blender/blenkernel/intern/blender_project.cc
@@ -0,0 +1,175 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_blender_project.h"
+#include "BKE_blender_project.hh"
+
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "DNA_space_types.h"
+
+#include "BLI_fileops.h"
+#include "BLI_path_util.h"
+
+namespace blender::bke {
+
+static StringRef path_strip_trailing_native_slash(StringRef path);
+static bool path_contains_project_settings(StringRef path);
+
+BlenderProject::BlenderProject(std::unique_ptr<ProjectSettings> settings)
+    : settings_(std::move(settings))
+{
+}
+
+BlenderProject *BlenderProject::set_active_from_settings(std::unique_ptr<ProjectSettings> settings)
+{
+  if (settings) {
+    instance_ = std::make_unique<BlenderProject>(BlenderProject(std::move(settings)));
+  }
+  else {
+    instance_ = nullptr;
+  }
+
+  return instance_.get();
+}
+
+BlenderProject *BlenderProject::get_active()
+{
+  return instance_.get();
+}
+
+StringRef BlenderProject::project_root_path_find_from_path(StringRef path)
+{
+  std::string path_native = path;
+  BLI_path_slash_native(path_native.data());
+
+  StringRef cur_path = path;
+
+  while (cur_path.size()) {
+    std::string pa = StringRef(path_native.c_str(), cur_path.size());
+    if (bke::path_contains_project_settings(pa)) {
+      return path.substr(0, cur_path.size());
+    }
+
+    /* Walk "up the path" (check the parent next). */
+    const int64_t pos_last_slash = cur_path.find_last_of(SEP);
+    if (pos_last_slash == StringRef::not_found) {
+      break;
+    }
+    cur_path = cur_path.substr(0, pos_last_slash);
+  }
+
+  return "";
+}
+
+ProjectSettings &BlenderProject::get_settings() const
+{
+  BLI_assert(settings_ != nullptr);
+  return *settings_;
+}
+
+/* ---------------------------------------------------------------------- */
+
+ProjectSettings::ProjectSettings(StringRef project_root_path)
+    : project_root_path_(project_root_path)
+{
+}
+
+bool ProjectSettings::create_settings_directory(StringRef project_root_path)
+{
+  std::string project_root_path_native = project_root_path;
+  BLI_path_slash_native(project_root_path_native.data());
+
+  return BLI_dir_create_recursive(
+      std::string(project_root_path_native + SEP + SETTINGS_DIRNAME).c_str());
+}
+
+static StringRef path_strip_trailing_native_slash(StringRef path)
+{
+  const int64_t pos_before_trailing_slash = path.find_last_not_of(SEP);
+  return (pos_before_trailing_slash == StringRef::not_found) ?
+             path :
+             path.substr(0, pos_before_trailing_slash + 1);
+}
+
+static bool path_contains_project_settings(StringRef path)
+{
+  path = path_strip_trailing_native_slash(path);
+  return BLI_exists(std::string(path + SEP_STR + ProjectSettings::SETTINGS_DIRNAME).c_str());
+}
+
+std::unique_ptr<ProjectSettings> ProjectSettings::load_from_disk(StringRef project_path)
+{
+  std::string project_path_native = project_path;
+  BLI_path_slash_native(project_path_native.data());
+
+  if (!BLI_exists(project_path_native.c_str())) {
+    return nullptr;
+  }
+
+  StringRef project_root_path = project_path_native;
+
+  const StringRef path_no_trailing_slashes = path_strip_trailing_native_slash(project_path_native);
+  if (path_no_trailing_slashes.endswith(SETTINGS_DIRNAME)) {
+    project_root_path = StringRef(project_path_native).drop_suffix(SETTINGS_DIRNAME.size() + 1);
+  }
+
+  if (!path_contains_project_settings(project_root_path)) {
+    return nullptr;
+  }
+
+  return std::make_unique<ProjectSettings>(project_root_path);
+}
+
+StringRefNull ProjectSettings::project_root_path() const
+{
+  return project_root_path_;
+}
+
+}  // namespace blender::bke
+
+/* ---------------------------------------------------------------------- */
+
+using namespace blender;
+
+BlenderProject *BKE_project_active_get(void)
+{
+  return reinterpret_cast<BlenderProject *>(bke::BlenderProject::get_active());
+}
+
+void BKE_project_active_unset(void)
+{
+  bke::BlenderProject::set_active_from_settings(nullptr);
+}
+
+BlenderProject *BKE_project_active_load_from_path(const char *path)
+{
+  /* Project should be unset if the path doesn't contain a project root. Unset in the beginning so
+   * early exiting behaves correctly. */
+  BKE_project_active_unset();
+
+  StringRef project_root = bke::BlenderProject::project_root_path_find_from_path(path);
+  if (project_root.is_empty()) {
+    return nullptr;
+  }
+
+  std::unique_ptr project_settings = bke::ProjectSettings::load_from_disk(project_root);
+  if (!project

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list