p4cmd 2.11.0__tar.gz → 2.11.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. {p4cmd-2.11.0 → p4cmd-2.11.2}/PKG-INFO +1 -1
  2. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd/__init__.py +1 -1
  3. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd/p4cmd.py +15 -0
  4. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd/p4file.py +0 -2
  5. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd.egg-info/PKG-INFO +1 -1
  6. {p4cmd-2.11.0 → p4cmd-2.11.2}/tests/test_p4client.py +36 -0
  7. {p4cmd-2.11.0 → p4cmd-2.11.2}/tests/test_p4file.py +20 -0
  8. {p4cmd-2.11.0 → p4cmd-2.11.2}/LICENSE +0 -0
  9. {p4cmd-2.11.0 → p4cmd-2.11.2}/README.md +0 -0
  10. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd/p4errors.py +0 -0
  11. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd/resources/__init__.py +0 -0
  12. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd/resources/perforce_DEPOT_ONLY.png +0 -0
  13. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd/resources/perforce_MOVED.png +0 -0
  14. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd/resources/perforce_NEED_SYNC.png +0 -0
  15. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd/resources/perforce_OPEN_FOR_ADD.png +0 -0
  16. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd/resources/perforce_OPEN_FOR_DELETE.png +0 -0
  17. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd/resources/perforce_OPEN_FOR_EDIT.png +0 -0
  18. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd/resources/perforce_UNKNOWN.png +0 -0
  19. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd/resources/perforce_UNTRACKED.png +0 -0
  20. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd/resources/perforce_UP_TO_DATE.png +0 -0
  21. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd/utils.py +0 -0
  22. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd.egg-info/SOURCES.txt +0 -0
  23. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd.egg-info/dependency_links.txt +0 -0
  24. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd.egg-info/requires.txt +0 -0
  25. {p4cmd-2.11.0 → p4cmd-2.11.2}/p4cmd.egg-info/top_level.txt +0 -0
  26. {p4cmd-2.11.0 → p4cmd-2.11.2}/setup.cfg +0 -0
  27. {p4cmd-2.11.0 → p4cmd-2.11.2}/setup.py +0 -0
  28. {p4cmd-2.11.0 → p4cmd-2.11.2}/tests/__init__.py +0 -0
  29. {p4cmd-2.11.0 → p4cmd-2.11.2}/tests/conftest.py +0 -0
  30. {p4cmd-2.11.0 → p4cmd-2.11.2}/tests/test_integration.py +0 -0
  31. {p4cmd-2.11.0 → p4cmd-2.11.2}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: p4cmd
3
- Version: 2.11.0
3
+ Version: 2.11.2
4
4
  Summary: Simple P4 python module
5
5
  Home-page: https://github.com/nielsvaes/p4cmd
6
6
  Author: Niels Vaes
@@ -1,4 +1,4 @@
1
- VERSION = "2.11.0"
1
+ VERSION = "2.11.2"
2
2
 
3
3
  from .p4cmd import P4Client
4
4
  from .p4file import P4File
@@ -635,10 +635,25 @@ class P4Client(object):
635
635
  info_dicts = self.run_cmd("sync", args=initial_arg_list, file_list=file_list)
636
636
 
637
637
  if verify:
638
+ # Files p4 itself deleted on this sync are EXPECTED to be absent from
639
+ # disk — don't warn for them. Normalize paths so platform-specific
640
+ # quirks (slash direction, case on Windows) don't cause false misses.
641
+ def _norm(p):
642
+ return os.path.normcase(os.path.normpath(p))
643
+
644
+ deleted_locals = {
645
+ _norm(self.__get_dict_value(d, "clientFile"))
646
+ for d in info_dicts
647
+ if self.__get_dict_value(d, "action") == "deleted"
648
+ and self.__get_dict_value(d, "clientFile") is not None
649
+ }
650
+
638
651
  local_file_paths = self.get_local_paths(file_list)
639
652
  for local_file_path in local_file_paths:
640
653
  if local_file_path is None:
641
654
  continue
655
+ if _norm(local_file_path) in deleted_locals:
656
+ continue
642
657
  if not os.path.isfile(local_file_path):
643
658
  _log.warning(f"File didn't exist after syncing, try force syncing it instead: {local_file_path}")
644
659
 
@@ -81,8 +81,6 @@ class P4File:
81
81
  return not (self._raw_data and "is not under client's root" in self._raw_data)
82
82
 
83
83
  def needs_syncing(self):
84
- if self.is_deleted() or self.is_moved_deleted():
85
- return False
86
84
  if self.is_open_for_add() or self.is_open_for_edit():
87
85
  return False
88
86
  if self._head_revision is None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: p4cmd
3
- Version: 2.11.0
3
+ Version: 2.11.2
4
4
  Summary: Simple P4 python module
5
5
  Home-page: https://github.com/nielsvaes/p4cmd
6
6
  Author: Niels Vaes
@@ -791,3 +791,39 @@ def test_silent_kwarg_default_no_warning(tmp_path):
791
791
  P4Client(str(tmp_path), user="u", client="c", server="s")
792
792
  assert not any(issubclass(w.category, DeprecationWarning) and "silent" in str(w.message)
793
793
  for w in caught), f"unexpected silent warning: {[str(w.message) for w in caught]}"
794
+
795
+
796
+ # ---------------------------------------------------------------------------
797
+ # sync_files verify — must not warn on files p4 itself deleted
798
+ # ---------------------------------------------------------------------------
799
+
800
+ def test_sync_files_no_warning_when_p4_deleted_file(p4client, caplog):
801
+ """If p4 sync reports action=deleted for a file, the post-sync verify
802
+ must not warn that the file is missing — its absence is expected."""
803
+ deleted_path = "C:/workspace/path/to/file.txt"
804
+ sync_result = [
805
+ {b"action": b"deleted", b"clientFile": deleted_path.encode(), b"code": b"stat"}
806
+ ]
807
+ with patch.object(p4client, "run_cmd", return_value=sync_result):
808
+ with patch.object(p4client, "get_local_paths", return_value=[deleted_path]):
809
+ with patch("p4cmd.p4cmd.os.path.isfile", return_value=False):
810
+ with caplog.at_level("WARNING", logger="p4cmd.p4cmd"):
811
+ p4client.sync_files([deleted_path])
812
+ assert "didn't exist after syncing" not in caplog.text, (
813
+ f"unexpected verify warning: {caplog.text}"
814
+ )
815
+
816
+
817
+ def test_sync_files_warns_when_file_missing_unexpectedly(p4client, caplog):
818
+ """Regression guard: when p4 did NOT delete the file but it's still missing
819
+ on disk, the existing 'try force syncing' warning must still fire."""
820
+ path = "C:/workspace/path/to/file.txt"
821
+ sync_result = [
822
+ {b"action": b"updated", b"clientFile": path.encode(), b"code": b"stat"}
823
+ ]
824
+ with patch.object(p4client, "run_cmd", return_value=sync_result):
825
+ with patch.object(p4client, "get_local_paths", return_value=[path]):
826
+ with patch("p4cmd.p4cmd.os.path.isfile", return_value=False):
827
+ with caplog.at_level("WARNING", logger="p4cmd.p4cmd"):
828
+ p4client.sync_files([path])
829
+ assert "didn't exist after syncing" in caplog.text
@@ -283,6 +283,26 @@ def test_needs_syncing_up_to_date_returns_false():
283
283
  assert f.needs_syncing() is False
284
284
 
285
285
 
286
+ def test_needs_syncing_deleted_at_head_with_old_have_returns_true():
287
+ # File deleted at head but user still has an older revision on disk —
288
+ # syncing will remove it. Previously the is_deleted() early-return
289
+ # masked this case, leaving orphaned files in the workspace.
290
+ f = P4File()
291
+ f.have_revision = "5"
292
+ f.head_revision = "6"
293
+ f.head_action = "delete"
294
+ assert f.needs_syncing() is True
295
+
296
+
297
+ def test_needs_syncing_moved_deleted_with_old_have_returns_true():
298
+ # Same case for move/delete at head.
299
+ f = P4File()
300
+ f.have_revision = "5"
301
+ f.head_revision = "6"
302
+ f.head_action = "move/delete"
303
+ assert f.needs_syncing() is True
304
+
305
+
286
306
  # ---------------------------------------------------------------------------
287
307
  # get_status
288
308
  # ---------------------------------------------------------------------------
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes