p4cmd 2.4.13__tar.gz → 2.5.0__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 (24) hide show
  1. {p4cmd-2.4.13 → p4cmd-2.5.0}/PKG-INFO +2 -2
  2. {p4cmd-2.4.13 → p4cmd-2.5.0}/README.md +1 -1
  3. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd/__init__.py +1 -1
  4. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd/p4cmd.py +22 -48
  5. p4cmd-2.5.0/p4cmd/utils.py +77 -0
  6. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd.egg-info/PKG-INFO +2 -2
  7. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd.egg-info/SOURCES.txt +1 -0
  8. {p4cmd-2.4.13 → p4cmd-2.5.0}/LICENSE +0 -0
  9. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd/p4errors.py +0 -0
  10. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd/p4file.py +0 -0
  11. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd/resources/__init__.py +0 -0
  12. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd/resources/perforce_DEPOT_ONLY.png +0 -0
  13. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd/resources/perforce_MOVED.png +0 -0
  14. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd/resources/perforce_NEED_SYNC.png +0 -0
  15. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd/resources/perforce_OPEN_FOR_ADD.png +0 -0
  16. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd/resources/perforce_OPEN_FOR_DELETE.png +0 -0
  17. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd/resources/perforce_OPEN_FOR_EDIT.png +0 -0
  18. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd/resources/perforce_UNKNOWN.png +0 -0
  19. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd/resources/perforce_UNTRACKED.png +0 -0
  20. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd/resources/perforce_UP_TO_DATE.png +0 -0
  21. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd.egg-info/dependency_links.txt +0 -0
  22. {p4cmd-2.4.13 → p4cmd-2.5.0}/p4cmd.egg-info/top_level.txt +0 -0
  23. {p4cmd-2.4.13 → p4cmd-2.5.0}/setup.cfg +0 -0
  24. {p4cmd-2.4.13 → p4cmd-2.5.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: p4cmd
3
- Version: 2.4.13
3
+ Version: 2.5.0
4
4
  Summary: Simple P4 python module
5
5
  Home-page: https://github.com/nielsvaes/p4cmd
6
6
  Author: Niels Vaes
@@ -50,7 +50,7 @@ os.environ["P4ROOT"] = "~/nisse/projects/raw"
50
50
  client = p4cmd.P4Client.from_env()
51
51
  ```
52
52
 
53
- Most of the functions are pretty self explanatory and have docstrings about how they work.
53
+ Most of the functions are pretty self-explanatory and have docstrings about how they work.
54
54
 
55
55
  There are 2 functions called `file_to_p4files` and `folder_to_p4files` that use the `P4File` class in `p4file`.
56
56
 
@@ -29,7 +29,7 @@ os.environ["P4ROOT"] = "~/nisse/projects/raw"
29
29
  client = p4cmd.P4Client.from_env()
30
30
  ```
31
31
 
32
- Most of the functions are pretty self explanatory and have docstrings about how they work.
32
+ Most of the functions are pretty self-explanatory and have docstrings about how they work.
33
33
 
34
34
  There are 2 functions called `file_to_p4files` and `folder_to_p4files` that use the `P4File` class in `p4file`.
35
35
 
@@ -1,4 +1,4 @@
1
- VERSION = "2.4.13"
1
+ VERSION = "2.5.0"
2
2
 
3
3
  from .p4cmd import P4Client
4
4
  from .p4file import P4File
@@ -9,6 +9,7 @@ import logging
9
9
 
10
10
  from . import p4errors
11
11
  from .p4file import P4File, Status
12
+ from .utils import split_list_into_strings_of_length, convert_to_list, decode_dictionaries, validate_not_empty
12
13
 
13
14
  MAX_CMD_LEN = 8190
14
15
  MAX_ARG_LEN = 8000 # max length of args string when combined, close to max, but leaving some extra margin
@@ -206,6 +207,7 @@ class P4Client(object):
206
207
  else:
207
208
  raise p4errors.WorkSpaceError("Tried to set a workspace/client({}) that did not exist".format(workspace))
208
209
 
210
+ @validate_not_empty
209
211
  def files_to_p4files(self, file_list, allow_invalid_files=False):
210
212
  """
211
213
  Turns a list of files into P4File objects. If the Perforce server can't be reached, returns a list of P4Files
@@ -232,6 +234,7 @@ class P4Client(object):
232
234
  p4files.append(perforce_file)
233
235
  return p4files
234
236
 
237
+ @validate_not_empty
235
238
  def folder_to_p4files(self, folder, include_subfolders=True, allow_invalid_files=False):
236
239
  """
237
240
  Returns all the files in a folder as a list of P4File objects. Uses the files_to_p4files function if the host
@@ -301,7 +304,8 @@ class P4Client(object):
301
304
  if len(changelists):
302
305
  return True
303
306
  return False
304
-
307
+
308
+ @validate_not_empty
305
309
  def move_files_to_changelist(self, file_list, changelist="default"):
306
310
  """
307
311
  Moves the files in file_list to a changelist. Makes a new changelist if the given one doesn't exist.
@@ -371,6 +375,7 @@ class P4Client(object):
371
375
  return True
372
376
  return False
373
377
 
378
+ @validate_not_empty
374
379
  def revert_files(self, file_list, unchanged_only=False):
375
380
  """
376
381
  Reverts files in file_list
@@ -389,6 +394,8 @@ class P4Client(object):
389
394
 
390
395
  return info_dicts
391
396
 
397
+
398
+ @validate_not_empty
392
399
  def revert_folders(self, folder_list, unchanged_only=False):
393
400
  """
394
401
  Recursively reverts complete folders
@@ -442,6 +449,7 @@ class P4Client(object):
442
449
  info_dicts = self.run_cmd("submit", args=["-c", changelist, "--parallel", f"threads={self.max_parallel_connections}"])
443
450
  return info_dicts
444
451
 
452
+ @validate_not_empty
445
453
  def sync_folders(self, folder_list):
446
454
  """
447
455
  Recursively syncs complete folders
@@ -463,6 +471,7 @@ class P4Client(object):
463
471
  info_dicts = self.run_cmd("sync", args=["--parallel", f"threads={self.max_parallel_connections}"], file_list=cleaned_folder_list)
464
472
  return info_dicts
465
473
 
474
+ @validate_not_empty
466
475
  def sync_files(self, file_list, revision=-1, verify=True, force=False):
467
476
  """
468
477
  Syncs files
@@ -493,6 +502,7 @@ class P4Client(object):
493
502
 
494
503
  return info_dicts
495
504
 
505
+ @validate_not_empty
496
506
  def reconcile_offline_files(self, file_list, changelist="default"):
497
507
  """
498
508
  Adds, opens for edit or delete any files that were changed outside Perforce
@@ -508,6 +518,7 @@ class P4Client(object):
508
518
  info_dicts = self.run_cmd("reconcile", args=["-c", changelist], file_list=file_list)
509
519
  return info_dicts
510
520
 
521
+ @validate_not_empty
511
522
  def reconcile_offline_folders(self, folder_list, changelist="default"):
512
523
  """
513
524
  Adds, opens for edit or delete any files in the rootfolder + subfolders that were changed outside Perforce
@@ -532,6 +543,7 @@ class P4Client(object):
532
543
  info_dicts = self.run_cmd("reconcile", args=["-c", changelist], file_list=cleaned_folder_list)
533
544
  return info_dicts
534
545
 
546
+ @validate_not_empty
535
547
  def delete_files(self, file_list, changelist="default"):
536
548
  """
537
549
  Marks files for delete
@@ -582,6 +594,7 @@ class P4Client(object):
582
594
 
583
595
  return files_and_cl
584
596
 
597
+ @validate_not_empty
585
598
  def add_or_edit_folders(self, folders, include_subfolders=True, changelist="default"):
586
599
  """
587
600
  Marks a folder for add or edit
@@ -605,6 +618,8 @@ class P4Client(object):
605
618
 
606
619
  return self.add_or_edit_files(all_files, changelist=changelist)
607
620
 
621
+
622
+ @validate_not_empty
608
623
  def add_or_edit_files(self, file_list, changelist="default"):
609
624
  """
610
625
  Marks the files in file_list for add if they are new, or edit if they are already versioned
@@ -653,6 +668,7 @@ class P4Client(object):
653
668
  return int(self.__get_dict_value(info_dict, "change"))
654
669
  return -1
655
670
 
671
+ @validate_not_empty
656
672
  def edit_files(self, file_list, changelist="default"):
657
673
  """
658
674
  Marks the files in file_list for edit
@@ -673,6 +689,7 @@ class P4Client(object):
673
689
  logging.error(self.__get_dict_value(info_dict, "data"))
674
690
  return info_dicts
675
691
 
692
+ @validate_not_empty
676
693
  def add_files(self, file_list, changelist="default"):
677
694
  """
678
695
  Marks the files in file_list for add
@@ -808,6 +825,7 @@ class P4Client(object):
808
825
 
809
826
  return workspaces
810
827
 
828
+ @validate_not_empty
811
829
  def get_depot_paths(self, paths):
812
830
  """
813
831
  Returns the depot path of the given files or folders, based on the client
@@ -827,6 +845,8 @@ class P4Client(object):
827
845
  depot_paths = [self.__get_dict_value(info, "depotFile").rstrip("/...") for info in info_dicts]
828
846
  return depot_paths
829
847
 
848
+
849
+ @validate_not_empty
830
850
  def get_local_paths(self, paths):
831
851
  """
832
852
  Returns the local path of the given files or folders, based on the client
@@ -847,6 +867,7 @@ class P4Client(object):
847
867
  local_paths = [self.__get_dict_value(info, "path") for info in info_dicts]
848
868
  return local_paths
849
869
 
870
+ @validate_not_empty
850
871
  def get_history(self, paths):
851
872
  """
852
873
  Returns changes for the given paths
@@ -1021,50 +1042,3 @@ class P4Client(object):
1021
1042
  if not f.lower().startswith(self.perforce_root.lower()):
1022
1043
  raise Exception(f'{f} is not under perforce root: {self.perforce_root}')
1023
1044
 
1024
-
1025
- def split_list_into_strings_of_length(input_list, max_length=100):
1026
- """
1027
- From incoming list of strings, build joined together strings that are clamped to a max size
1028
-
1029
- :param input_list:
1030
- :param max_length: str clamp length
1031
- """
1032
- full_list_str = " ".join([str(arg) for arg in input_list])
1033
-
1034
- # if str is already below max length, just return it wrapped in a list
1035
- if not len(full_list_str) > max_length:
1036
- return [full_list_str]
1037
-
1038
- # Keep appending on the last string until we hit the max length
1039
- # then add a new entry to the list and keep appending
1040
- clamped_str_list = [""]
1041
- for arg in input_list:
1042
- current_str = clamped_str_list[-1]
1043
- new_str = "{}{} ".format(current_str, arg) # the space is deliberately placed, since the first item has no len
1044
-
1045
- # if new string is too long, just append the arg as a new item and skip to next arg
1046
- if len(new_str) >= max_length:
1047
- clamped_str_list.append("{} ".format(arg)) #
1048
- continue
1049
-
1050
- # set latest to updated string
1051
- clamped_str_list[-1] = new_str
1052
-
1053
- return clamped_str_list
1054
-
1055
- def decode_dictionaries(info_dicts):
1056
- """
1057
- Decode list of dictionary keys and values into unicode from bytes
1058
- """
1059
- decoded_dicts = []
1060
- for info_dict in info_dicts:
1061
- decoded_dict = {k.decode(): v.decode() for k, v in info_dict.items()}
1062
- decoded_dicts.append(decoded_dict)
1063
- return decoded_dicts
1064
-
1065
- def convert_to_list(value):
1066
- if isinstance(value, tuple):
1067
- converted = [v for v in value]
1068
- else:
1069
- converted = [value]
1070
- return converted
@@ -0,0 +1,77 @@
1
+ import logging
2
+
3
+ def split_list_into_strings_of_length(input_list, max_length=100):
4
+ """
5
+ From incoming list of strings, build joined together strings that are clamped to a max size
6
+
7
+ :param input_list:
8
+ :param max_length: str clamp length
9
+ """
10
+ full_list_str = " ".join([str(arg) for arg in input_list])
11
+
12
+ # if str is already below max length, just return it wrapped in a list
13
+ if not len(full_list_str) > max_length:
14
+ return [full_list_str]
15
+
16
+ # Keep appending on the last string until we hit the max length
17
+ # then add a new entry to the list and keep appending
18
+ clamped_str_list = [""]
19
+ for arg in input_list:
20
+ current_str = clamped_str_list[-1]
21
+ new_str = "{}{} ".format(current_str, arg) # the space is deliberately placed, since the first item has no len
22
+
23
+ # if new string is too long, just append the arg as a new item and skip to next arg
24
+ if len(new_str) >= max_length:
25
+ clamped_str_list.append("{} ".format(arg)) #
26
+ continue
27
+
28
+ # set latest to updated string
29
+ clamped_str_list[-1] = new_str
30
+
31
+ return clamped_str_list
32
+
33
+
34
+ def decode_dictionaries(info_dicts):
35
+ """
36
+ Decode list of dictionary keys and values into unicode from bytes
37
+ """
38
+ decoded_dicts = []
39
+ for info_dict in info_dicts:
40
+ decoded_dict = {k.decode(): v.decode() for k, v in info_dict.items()}
41
+ decoded_dicts.append(decoded_dict)
42
+ return decoded_dicts
43
+
44
+
45
+ def convert_to_list(value):
46
+ """
47
+ Converts a value to a list if it isn't already one.
48
+ :param value: input value
49
+ :return: list
50
+ """
51
+ if isinstance(value, tuple):
52
+ converted = [v for v in value]
53
+ else:
54
+ converted = [value]
55
+ return converted
56
+
57
+
58
+ def validate_not_empty(func):
59
+ """
60
+ Decorator to ensure file and folder lists are not empty before proceeding with Perforce operations
61
+ """
62
+
63
+ def wrapper(*args, **kwargs):
64
+ file_or_folder_list = args[1] if len(args) > 1 else None
65
+
66
+ if file_or_folder_list is not None and not isinstance(file_or_folder_list, list):
67
+ file_or_folder_list = convert_to_list(file_or_folder_list)
68
+
69
+ if not file_or_folder_list:
70
+ logging.warning(f"Empty file list provided to {func.__name__}, operation skipped.")
71
+ logging.warning(f"args: {args}")
72
+ logging.warning(f"kwargs: {kwargs}")
73
+ return []
74
+
75
+ return func(*args, **kwargs)
76
+
77
+ return wrapper
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: p4cmd
3
- Version: 2.4.13
3
+ Version: 2.5.0
4
4
  Summary: Simple P4 python module
5
5
  Home-page: https://github.com/nielsvaes/p4cmd
6
6
  Author: Niels Vaes
@@ -50,7 +50,7 @@ os.environ["P4ROOT"] = "~/nisse/projects/raw"
50
50
  client = p4cmd.P4Client.from_env()
51
51
  ```
52
52
 
53
- Most of the functions are pretty self explanatory and have docstrings about how they work.
53
+ Most of the functions are pretty self-explanatory and have docstrings about how they work.
54
54
 
55
55
  There are 2 functions called `file_to_p4files` and `folder_to_p4files` that use the `P4File` class in `p4file`.
56
56
 
@@ -5,6 +5,7 @@ p4cmd/__init__.py
5
5
  p4cmd/p4cmd.py
6
6
  p4cmd/p4errors.py
7
7
  p4cmd/p4file.py
8
+ p4cmd/utils.py
8
9
  p4cmd.egg-info/PKG-INFO
9
10
  p4cmd.egg-info/SOURCES.txt
10
11
  p4cmd.egg-info/dependency_links.txt
File without changes
File without changes
File without changes
File without changes
File without changes