Fix #99549: Remember Previous Status #104217
@ -10,6 +10,7 @@ bugs in actually-released versions.
|
|||||||
- Improve logging of job deletion.
|
- Improve logging of job deletion.
|
||||||
- Add Worker Cluster support. Workers can be members of any number of clusters. Workers will only work on jobs that are assigned to that cluster. Jobs that do not have a cluster will be available to all workers, regardless of their cluster assignment. As a result, clusterless workers will only work on clusterless jobs.
|
- Add Worker Cluster support. Workers can be members of any number of clusters. Workers will only work on jobs that are assigned to that cluster. Jobs that do not have a cluster will be available to all workers, regardless of their cluster assignment. As a result, clusterless workers will only work on clusterless jobs.
|
||||||
- Fix limitation where a job could have no more than 1000 tasks ([#104201](https://projects.blender.org/studio/flamenco/issues/104201))
|
- Fix limitation where a job could have no more than 1000 tasks ([#104201](https://projects.blender.org/studio/flamenco/issues/104201))
|
||||||
|
- Add support for finding the top-level 'project' directory. When submitting files to Flamenco, the add-on will try to retain the directory structure of your Blender project as precisely as possible. This new feature allows the add-on to find the top-level directory of your project by finding a `.blender_project`, `.git`, or `.subversion` directory. This can be configured in the add-on preferences.
|
||||||
|
|
||||||
|
|
||||||
## 3.2 - released 2023-02-21
|
## 3.2 - released 2023-02-21
|
||||||
|
@ -19,7 +19,15 @@ from pathlib import Path
|
|||||||
|
|
||||||
__is_first_load = "operators" not in locals()
|
__is_first_load = "operators" not in locals()
|
||||||
if __is_first_load:
|
if __is_first_load:
|
||||||
from . import operators, gui, job_types, comms, preferences, worker_clusters
|
from . import (
|
||||||
|
operators,
|
||||||
|
gui,
|
||||||
|
job_types,
|
||||||
|
comms,
|
||||||
|
preferences,
|
||||||
|
projects,
|
||||||
|
worker_clusters,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
@ -28,6 +36,7 @@ else:
|
|||||||
job_types = importlib.reload(job_types)
|
job_types = importlib.reload(job_types)
|
||||||
comms = importlib.reload(comms)
|
comms = importlib.reload(comms)
|
||||||
preferences = importlib.reload(preferences)
|
preferences = importlib.reload(preferences)
|
||||||
|
projects = importlib.reload(projects)
|
||||||
worker_clusters = importlib.reload(worker_clusters)
|
worker_clusters = importlib.reload(worker_clusters)
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
@ -381,8 +381,9 @@ class FLAMENCO_OT_submit_job(FlamencoOpMixin, bpy.types.Operator):
|
|||||||
"""
|
"""
|
||||||
from .bat import interface as bat_interface
|
from .bat import interface as bat_interface
|
||||||
|
|
||||||
# TODO: get project path from addon preferences / project definition on Manager.
|
# Get project path from addon preferences.
|
||||||
project_path = blendfile.parent
|
prefs = preferences.get(context)
|
||||||
|
project_path: Path = prefs.project_root()
|
||||||
try:
|
try:
|
||||||
project_path = Path(bpy.path.abspath(str(project_path))).resolve()
|
project_path = Path(bpy.path.abspath(str(project_path))).resolve()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
@ -395,7 +396,6 @@ class FLAMENCO_OT_submit_job(FlamencoOpMixin, bpy.types.Operator):
|
|||||||
datetime.datetime.now().isoformat("-").replace(":", ""),
|
datetime.datetime.now().isoformat("-").replace(":", ""),
|
||||||
self.job_name,
|
self.job_name,
|
||||||
)
|
)
|
||||||
prefs = preferences.get(context)
|
|
||||||
pack_target_dir = Path(prefs.job_storage) / unique_dir
|
pack_target_dir = Path(prefs.job_storage) / unique_dir
|
||||||
|
|
||||||
# TODO: this should take the blendfile location relative to the project path into account.
|
# TODO: this should take the blendfile location relative to the project path into account.
|
||||||
@ -438,9 +438,12 @@ class FLAMENCO_OT_submit_job(FlamencoOpMixin, bpy.types.Operator):
|
|||||||
assert self.job is not None
|
assert self.job is not None
|
||||||
self.log.info("Sending BAT pack to Shaman")
|
self.log.info("Sending BAT pack to Shaman")
|
||||||
|
|
||||||
|
prefs = preferences.get(context)
|
||||||
|
project_path: Path = prefs.project_root()
|
||||||
|
|
||||||
self.packthread = bat_interface.copy(
|
self.packthread = bat_interface.copy(
|
||||||
base_blendfile=blendfile,
|
base_blendfile=blendfile,
|
||||||
project=blendfile.parent, # TODO: get from preferences/GUI.
|
project=project_path,
|
||||||
target="/", # Target directory irrelevant for Shaman transfers.
|
target="/", # Target directory irrelevant for Shaman transfers.
|
||||||
exclusion_filter="", # TODO: get from GUI.
|
exclusion_filter="", # TODO: get from GUI.
|
||||||
relative_only=True, # TODO: get from GUI.
|
relative_only=True, # TODO: get from GUI.
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
# <pep8 compliant>
|
# <pep8 compliant>
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
|
from . import projects
|
||||||
|
|
||||||
|
|
||||||
def discard_flamenco_client(context):
|
def discard_flamenco_client(context):
|
||||||
"""Discard any cached Flamenco client after the Manager URL changes."""
|
"""Discard any cached Flamenco client after the Manager URL changes."""
|
||||||
@ -34,10 +38,15 @@ def _manager_url_updated(prefs, context):
|
|||||||
comms.ping_manager_with_report(context.window_manager, api_client, prefs)
|
comms.ping_manager_with_report(context.window_manager, api_client, prefs)
|
||||||
|
|
||||||
|
|
||||||
|
_project_finder_enum_items = [
|
||||||
|
(key, info.label, info.description) for key, info in projects.finders.items()
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class WorkerCluster(bpy.types.PropertyGroup):
|
class WorkerCluster(bpy.types.PropertyGroup):
|
||||||
id: bpy.props.StringProperty(name="id")
|
id: bpy.props.StringProperty(name="id") # type: ignore
|
||||||
name: bpy.props.StringProperty(name="Name")
|
name: bpy.props.StringProperty(name="Name") # type: ignore
|
||||||
description: bpy.props.StringProperty(name="Description")
|
description: bpy.props.StringProperty(name="Description") # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class FlamencoPreferences(bpy.types.AddonPreferences):
|
class FlamencoPreferences(bpy.types.AddonPreferences):
|
||||||
@ -50,6 +59,13 @@ class FlamencoPreferences(bpy.types.AddonPreferences):
|
|||||||
update=_manager_url_updated,
|
update=_manager_url_updated,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
project_finder: bpy.props.EnumProperty( # type: ignore
|
||||||
|
name="Project Finder",
|
||||||
|
description="Strategy for Flamenco to find the top level directory of your project",
|
||||||
|
default=_project_finder_enum_items[0][0],
|
||||||
|
items=_project_finder_enum_items,
|
||||||
|
)
|
||||||
|
|
||||||
is_shaman_enabled: bpy.props.BoolProperty( # type: ignore
|
is_shaman_enabled: bpy.props.BoolProperty( # type: ignore
|
||||||
name="Shaman Enabled",
|
name="Shaman Enabled",
|
||||||
description="Whether this Manager has the Shaman protocol enabled",
|
description="Whether this Manager has the Shaman protocol enabled",
|
||||||
@ -114,6 +130,28 @@ class FlamencoPreferences(bpy.types.AddonPreferences):
|
|||||||
text_row(col, "Shaman enabled")
|
text_row(col, "Shaman enabled")
|
||||||
col.prop(self, "job_storage_for_gui", text="Job Storage")
|
col.prop(self, "job_storage_for_gui", text="Job Storage")
|
||||||
|
|
||||||
|
# Project Root
|
||||||
|
col = layout.column(align=True)
|
||||||
|
col.prop(self, "project_finder")
|
||||||
|
try:
|
||||||
|
project_root = self.project_root()
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
text_row(col, str(project_root))
|
||||||
|
|
||||||
|
def project_root(self) -> Path:
|
||||||
|
"""Use the configured project finder to find the project root directory."""
|
||||||
|
|
||||||
|
if not self.project_finder:
|
||||||
|
# Just a sanity fallback for missing preferences. It should be
|
||||||
|
# covered by the 'default=...' of the property, but just to be sure.
|
||||||
|
self.project_finder = "BLENDER_PROJECT"
|
||||||
|
|
||||||
|
# It is assumed that the blendfile is saved.
|
||||||
|
blendfile = Path(bpy.data.filepath)
|
||||||
|
return projects.for_blendfile(blendfile, self.project_finder)
|
||||||
|
|
||||||
|
|
||||||
def get(context: bpy.types.Context) -> FlamencoPreferences:
|
def get(context: bpy.types.Context) -> FlamencoPreferences:
|
||||||
"""Return the add-on preferences."""
|
"""Return the add-on preferences."""
|
||||||
|
91
addon/flamenco/projects.py
Normal file
91
addon/flamenco/projects.py
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
# <pep8 compliant>
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Callable, TypeAlias
|
||||||
|
import dataclasses
|
||||||
|
|
||||||
|
|
||||||
|
def for_blendfile(blendfile: Path, strategy: str) -> Path:
|
||||||
|
"""Return what is considered to be the project directory containing the given file.
|
||||||
|
|
||||||
|
If none can be found, the directory containing the current blend file is returned.
|
||||||
|
If the current blend file has no path (because it was not saved), a ValueError is raised.
|
||||||
|
|
||||||
|
:param blendfile: the path of the blend file for which to find the project.
|
||||||
|
:param strategy: the name of the finder to use, see `finders`.
|
||||||
|
"""
|
||||||
|
if blendfile.is_dir():
|
||||||
|
msg = f"{blendfile} is not a blend file, cannot find project directory"
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
try:
|
||||||
|
finder_info = finders[strategy]
|
||||||
|
except KeyError:
|
||||||
|
msg = f"Unknown strategy {strategy!r}, cannot find project directory"
|
||||||
|
raise ValueError(msg) from None
|
||||||
|
|
||||||
|
return finder_info.finder(blendfile)
|
||||||
|
|
||||||
|
|
||||||
|
def _finder_blender_project(blendfile: Path) -> Path:
|
||||||
|
return _search_path_marker(blendfile, ".blender_project")
|
||||||
|
|
||||||
|
|
||||||
|
def _finder_git(blendfile: Path) -> Path:
|
||||||
|
return _search_path_marker(blendfile, ".git")
|
||||||
|
|
||||||
|
|
||||||
|
def _finder_subversion(blendfile: Path) -> Path:
|
||||||
|
return _search_path_marker(blendfile, ".svn")
|
||||||
|
|
||||||
|
|
||||||
|
def _search_path_marker(blendfile: Path, marker_path: str) -> Path:
|
||||||
|
"""Go up the directory hierarchy until a file or directory 'marker_path' is found."""
|
||||||
|
|
||||||
|
blendfile_dir = blendfile.absolute().parent
|
||||||
|
|
||||||
|
directory = blendfile_dir
|
||||||
|
while True:
|
||||||
|
marker: Path = directory / marker_path
|
||||||
|
if marker.exists():
|
||||||
|
return directory
|
||||||
|
|
||||||
|
parent = directory.parent
|
||||||
|
if directory == parent:
|
||||||
|
# If a directory is its own parent, we're at the root and cannot go
|
||||||
|
# up further.
|
||||||
|
break
|
||||||
|
directory = parent
|
||||||
|
|
||||||
|
# Could not find the marker, so use the directory containing the blend file.
|
||||||
|
return blendfile_dir
|
||||||
|
|
||||||
|
|
||||||
|
Finder: TypeAlias = Callable[[Path], Path]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class FinderInfo:
|
||||||
|
label: str
|
||||||
|
description: str
|
||||||
|
finder: Finder
|
||||||
|
|
||||||
|
|
||||||
|
finders: dict[str, FinderInfo] = {
|
||||||
|
"BLENDER_PROJECT": FinderInfo(
|
||||||
|
"Blender Project",
|
||||||
|
"Find a .blend_project directory and use that as indicator for the top level project directory.",
|
||||||
|
_finder_blender_project,
|
||||||
|
),
|
||||||
|
"GIT": FinderInfo(
|
||||||
|
"Git",
|
||||||
|
"Find a .git directory and use that as indicator for the top level project directory.",
|
||||||
|
_finder_git,
|
||||||
|
),
|
||||||
|
"SUBVERSION": FinderInfo(
|
||||||
|
"Subversion",
|
||||||
|
"Find a .svn directory and use that as indicator for the top level project directory.",
|
||||||
|
_finder_subversion,
|
||||||
|
),
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user