Fix #99549: Remember Previous Status #104217

Merged
Sybren A. Stüvel merged 16 commits from Evelinealy/flamenco:web-api-upgrade into main 2023-06-02 22:50:10 +02:00
5 changed files with 150 additions and 8 deletions
Showing only changes of commit 58a5e55a52 - Show all commits

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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."""

View 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,
),
}