diff --git a/pyproject.toml b/pyproject.toml index 4621a6ac8..d8997316b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "truss" -version = "0.10.9rc1" +version = "0.10.9rc520" description = "A seamless bridge from model development to model delivery" authors = [ { name = "Pankaj Gupta", email = "no-reply@baseten.co" }, diff --git a/truss/contexts/image_builder/serving_image_builder.py b/truss/contexts/image_builder/serving_image_builder.py index 3835a4d48..515278800 100644 --- a/truss/contexts/image_builder/serving_image_builder.py +++ b/truss/contexts/image_builder/serving_image_builder.py @@ -809,9 +809,8 @@ def _render_dockerfile( data_dir_exists=data_dir.exists(), model_dir_exists=model_dir.exists(), bundled_packages_dir_exists=bundled_packages_dir.exists(), - truss_hash=directory_content_hash( - self._truss_dir, self._spec.hash_ignore_patterns - ), + # Create a sanitized copy of the truss directory for hash calculation + truss_hash=self._calculate_sanitized_truss_hash(build_dir), models=model_files, use_hf_secret=use_hf_secret, cached_files=cached_files, @@ -832,3 +831,26 @@ def _render_dockerfile( ).strip() docker_file_path = build_dir / MODEL_DOCKERFILE_NAME docker_file_path.write_text(dockerfile_contents) + + def _calculate_sanitized_truss_hash(self, build_dir: Path) -> str: + """Calculate hash from a sanitized copy of the truss directory with runtime fields cleared.""" + sanitized_truss_dir = build_dir / "build_model_scaffold" + + # Remove existing copy if it exists + if sanitized_truss_dir.exists(): + shutil.rmtree(sanitized_truss_dir) + + # Copy the entire truss directory + shutil.copytree(self._truss_dir, sanitized_truss_dir) + + # Clear runtime fields from the config + config_file_path = sanitized_truss_dir / "config.yaml" + if config_file_path.exists(): + truss_config = TrussConfig.from_yaml(config_file_path) + truss_config.clear_runtime_fields() + truss_config.write_to_yaml_file(config_file_path) + + # Calculate hash from the sanitized directory + return directory_content_hash( + sanitized_truss_dir, self._spec.hash_ignore_patterns + ) diff --git a/truss/truss_handle/patch/hash.py b/truss/truss_handle/patch/hash.py index 7fe35e87e..201c282d8 100644 --- a/truss/truss_handle/patch/hash.py +++ b/truss/truss_handle/patch/hash.py @@ -1,3 +1,4 @@ +import traceback from pathlib import Path from typing import Any, List, Optional @@ -19,6 +20,15 @@ def directory_content_hash( underneath. The (root) Directory will have the same hash, even if renamed. """ hasher = blake3() + print(f"Calculating hash for {root}, ignore_patterns: {ignore_patterns}") + + # Print caller chain + caller_chain = traceback.extract_stack() + if len(caller_chain) > 1: + print("Caller chain:") + for i, frame in enumerate(caller_chain[:-1]): # Skip the current function + print(f" {i + 1}. {frame.filename}:{frame.lineno} in {frame.name}") + paths = list(get_unignored_relative_paths_from_root(root, ignore_patterns)) paths.sort() for path in paths: @@ -26,7 +36,9 @@ def directory_content_hash( absolute_path = root / path if absolute_path.is_file(): hasher.update(file_content_hash(absolute_path)) - return hasher.hexdigest() + hash_str = hasher.hexdigest() + print(f"Hash for {root}: {hash_str}") + return hash_str def file_content_hash(file: Path) -> bytes: diff --git a/truss/truss_handle/truss_handle.py b/truss/truss_handle/truss_handle.py index c0710df61..89671396e 100644 --- a/truss/truss_handle/truss_handle.py +++ b/truss/truss_handle/truss_handle.py @@ -938,6 +938,9 @@ def _build_image( def _update_config(self, **fields_to_update): config = self._spec.config.model_copy(update=fields_to_update) + print( + f"Updating config: {fields_to_update}, writing to {self._spec.config_path}" + ) config.write_to_yaml_file(self._spec.config_path) self._spec = TrussSpec(self._truss_dir) # Reload. diff --git a/uv.lock b/uv.lock index d98a74fbb..dba98f535 100644 --- a/uv.lock +++ b/uv.lock @@ -3312,7 +3312,7 @@ wheels = [ [[package]] name = "truss" -version = "0.10.9rc1" +version = "0.10.9rc520" source = { editable = "." } dependencies = [ { name = "aiofiles" },