diff --git a/src/deadline/client/job_bundle/__init__.py b/src/deadline/client/job_bundle/__init__.py index 21732631..2aa7b99d 100644 --- a/src/deadline/client/job_bundle/__init__.py +++ b/src/deadline/client/job_bundle/__init__.py @@ -11,6 +11,7 @@ import datetime import glob import os +import sys from ..config import get_setting from ._yaml import deadline_yaml_dump @@ -34,10 +35,6 @@ def create_job_history_bundle_dir(submitter_name: str, job_name: str) -> str: char for char in submitter_name if char.isalnum() or char in " -_" ) - # Clean the job_name's characters and truncate for the filename - job_name_cleaned = "".join(char for char in job_name if char.isalnum() or char in " -_") - job_name_cleaned = job_name_cleaned[:128] - timestamp = datetime.datetime.now() month_tag = timestamp.strftime("%Y-%m") date_tag = timestamp.strftime("%Y-%m-%d") @@ -53,8 +50,22 @@ def create_job_history_bundle_dir(submitter_name: str, job_name: str) -> str: latest_dir = existing_dirs[-1] number = int(os.path.basename(latest_dir)[len(date_tag) + 1 :].split("-", 1)[0]) + 1 - result = os.path.join( - month_dir, f"{date_tag}-{number:02}-{submitter_name_cleaned}-{job_name_cleaned}" - ) + job_dir_prefix = f"{date_tag}-{number:02}-{submitter_name_cleaned}-" + + max_job_name_prefix = 128 # max job name from OpenJD spec + + # max path length - manifest file name + # 256 - len("\manifests\d2b2c3102af5a862db950a2e30255429_input") + # = 207 + if sys.platform in ["win32", "cygwin"]: + max_job_name_prefix = min( + 207 - len(os.path.abspath(os.path.join(month_dir, job_dir_prefix))), max_job_name_prefix + ) + + # Clean the job_name's characters and truncate for the filename + job_name_cleaned = "".join(char for char in job_name if char.isalnum() or char in " -_") + job_name_cleaned = job_name_cleaned[:max_job_name_prefix] + + result = os.path.join(month_dir, f"{job_dir_prefix}{job_name_cleaned}") os.makedirs(result) return result diff --git a/src/deadline/client/ui/dialogs/submit_job_to_deadline_dialog.py b/src/deadline/client/ui/dialogs/submit_job_to_deadline_dialog.py index a9d215b3..ab238934 100644 --- a/src/deadline/client/ui/dialogs/submit_job_to_deadline_dialog.py +++ b/src/deadline/client/ui/dialogs/submit_job_to_deadline_dialog.py @@ -417,7 +417,8 @@ def on_submit(self): deadline = api.get_boto3_client("deadline") self.job_history_bundle_dir = create_job_history_bundle_dir( - self.submitter_name, settings.name + self.submitter_name, + settings.name, ) if self.show_host_requirements_tab: diff --git a/test/unit/deadline_client/job_bundle/test_job_history_folders.py b/test/unit/deadline_client/job_bundle/test_job_history_folders.py index 947e20fb..ff604084 100644 --- a/test/unit/deadline_client/job_bundle/test_job_history_folders.py +++ b/test/unit/deadline_client/job_bundle/test_job_history_folders.py @@ -5,6 +5,7 @@ """ import os +import sys import tempfile import pytest @@ -55,6 +56,76 @@ def test_create_job_bundle_dir(fresh_deadline_config): assert sorted(os.listdir(os.path.join(tmpdir, "2023-04"))) == EXPECTED_DIRS[3:] +def test_job_history_dir_truncation(fresh_deadline_config): + # Use a temporary directory for the job history + with tempfile.TemporaryDirectory() as tmpdir, freeze_time("2024-12-27T12:34:56"): + tmpdir_path_length = len(os.path.abspath(tmpdir)) + long_tmpdir = os.path.join( + tmpdir, + "dir" + "1" * (140 - tmpdir_path_length), + ) + config.set_setting("settings.job_history_dir", long_tmpdir) + + job_name_127_chars = "job1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234" + output_path = job_bundle.create_job_history_bundle_dir( + "MySubmitter", + job_name_127_chars, + ) + + if sys.platform in ["win32", "cygwin"]: + assert len(os.path.abspath(output_path)) == 207 + assert str(os.path.abspath(output_path)).startswith( + str( + os.path.abspath( + os.path.join( + long_tmpdir, "2024-12", "2024-12-27-01-MySubmitter-job1234567890" + ) + ) + ) + ) + assert ( + len( + os.path.abspath( + os.path.join( + output_path, "manifests", "d2b2c3102af5a862db950a2e30255429_input" + ) + ) + ) + == 256 + ) + else: + assert output_path == os.path.join( + long_tmpdir, "2024-12", f"2024-12-27-01-MySubmitter-{job_name_127_chars}" + ) + assert len(output_path) > 256 + assert os.path.isdir(output_path) + + +def test_job_history_dir_truncation_from_job_name_with_129_chars(fresh_deadline_config): + # Use a temporary directory for the job history + if sys.platform in ["win32", "cygwin"]: + # Windows has a long tmp dir path so it will truncate anyway - we only want to test job name truncation + tmp_parent_dir = "C:\ProgramData" + else: + tmp_parent_dir = None + with tempfile.TemporaryDirectory(dir=tmp_parent_dir) as tmpdir, freeze_time( + "2024-08-26T18:42:05" + ): + config.set_setting("settings.job_history_dir", tmpdir) + + job_name_129_chars = "test12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345" + output_path = job_bundle.create_job_history_bundle_dir( + "SubmitterFour", + job_name_129_chars, + ) + assert output_path == os.path.join( + tmpdir, + "2024-08", + "2024-08-26-01-SubmitterFour-test1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234", + ) + assert os.path.isdir(output_path) + + @pytest.mark.parametrize( "submitter_name, job_name, freeze_date, expected_output_path", [