p4cmd 2.7.0__tar.gz → 2.8.1__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.7.0 → p4cmd-2.8.1}/PKG-INFO +1 -1
  2. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/__init__.py +1 -1
  3. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/p4cmd.py +140 -62
  4. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd.egg-info/PKG-INFO +1 -1
  5. {p4cmd-2.7.0 → p4cmd-2.8.1}/LICENSE +0 -0
  6. {p4cmd-2.7.0 → p4cmd-2.8.1}/README.md +0 -0
  7. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/p4errors.py +0 -0
  8. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/p4file.py +0 -0
  9. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/__init__.py +0 -0
  10. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_DEPOT_ONLY.png +0 -0
  11. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_MOVED.png +0 -0
  12. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_NEED_SYNC.png +0 -0
  13. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_OPEN_FOR_ADD.png +0 -0
  14. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_OPEN_FOR_DELETE.png +0 -0
  15. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_OPEN_FOR_EDIT.png +0 -0
  16. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_UNKNOWN.png +0 -0
  17. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_UNTRACKED.png +0 -0
  18. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_UP_TO_DATE.png +0 -0
  19. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/utils.py +0 -0
  20. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd.egg-info/SOURCES.txt +0 -0
  21. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd.egg-info/dependency_links.txt +0 -0
  22. {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd.egg-info/top_level.txt +0 -0
  23. {p4cmd-2.7.0 → p4cmd-2.8.1}/setup.cfg +0 -0
  24. {p4cmd-2.7.0 → p4cmd-2.8.1}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: p4cmd
3
- Version: 2.7.0
3
+ Version: 2.8.1
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.7.0"
1
+ VERSION = "2.8.1"
2
2
 
3
3
  from .p4cmd import P4Client
4
4
  from .p4file import P4File
@@ -51,7 +51,7 @@ class P4Client(object):
51
51
  self.server = self.get_p4_setting("P4PORT")
52
52
  if self.server is None:
53
53
  raise p4errors.WorkSpaceError("Could not find P4PORT")
54
-
54
+
55
55
  self.depot_root = self.get_depot_paths([self.perforce_root])[0]
56
56
 
57
57
  @classmethod
@@ -73,6 +73,9 @@ class P4Client(object):
73
73
  """
74
74
  self.perforce_root = root
75
75
 
76
+ if not self.perforce_root:
77
+ raise p4errors.WorkSpaceError(f"self.perforce_root (value: {self.perforce_root}) is not set!")
78
+
76
79
  def set_max_parallel_connections(self, value):
77
80
  """
78
81
  Set the number of maximum parallel connections to use for sync/submit. Default class value is 4
@@ -94,12 +97,14 @@ class P4Client(object):
94
97
  :return: *list* of dictionaries with either the marshaled returns of the command or dictionaries with the
95
98
  raw output of the command
96
99
  """
100
+
101
+ if not self.perforce_root:
102
+ raise p4errors.WorkSpaceError(f"self.perforce_root (value: {self.perforce_root}) is not set!")
103
+
97
104
  if online_check:
98
- if not self.host_online():
99
- logging.warning("Can't connect to %s on port %s" % (self.__server_address(), self.__port_number()))
105
+ self.host_online()
100
106
 
101
- if self.perforce_root is not None:
102
- os.chdir(self.perforce_root)
107
+ os.chdir(self.perforce_root)
103
108
 
104
109
  file_list = [f'"{f}"' for f in file_list]
105
110
 
@@ -117,7 +122,8 @@ class P4Client(object):
117
122
 
118
123
  if len(command) > MAX_CMD_LEN:
119
124
  # This shouldn't happen, but just in case the command prefix end up really long
120
- logging.warning(f"Command length: {format(len(command))} exceeds MAX_CMD_LEN {MAX_CMD_LEN} on command: {MAX_CMD_LEN}")
125
+ logging.warning(
126
+ f"Command length: {format(len(command))} exceeds MAX_CMD_LEN {MAX_CMD_LEN} on command: {MAX_CMD_LEN}")
121
127
 
122
128
  with subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True) as pipe:
123
129
  output = pipe.stdout
@@ -268,7 +274,8 @@ class P4Client(object):
268
274
  if not complete_file_path in files:
269
275
  all_files.append(complete_file_path)
270
276
  else:
271
- all_files = [os.path.join(folder, file) for file in os.listdir(folder) if os.path.isfile(os.path.join(folder, file))]
277
+ all_files = [os.path.join(folder, file) for file in os.listdir(folder) if
278
+ os.path.isfile(os.path.join(folder, file))]
272
279
 
273
280
  return self.files_to_p4files(all_files)
274
281
 
@@ -281,12 +288,13 @@ class P4Client(object):
281
288
  """
282
289
  if not self.host_online():
283
290
  logging.warning("Can't connect to %s on port %s" % (self.__server_address(), self.__port_number()))
284
- #raise p4errors.ServerOffline("Can't connect to %s on port %s" % (self.__server_address(), self.__port_number()))
291
+ # raise p4errors.ServerOffline("Can't connect to %s on port %s" % (self.__server_address(), self.__port_number()))
285
292
  return
286
293
 
287
- output = subprocess.check_output('p4 --field "Description=%s" --field "Files=" change -o | p4 change -i' % description,
288
- stderr=subprocess.STDOUT,
289
- shell=True).decode()
294
+ output = subprocess.check_output(
295
+ 'p4 --field "Description=%s" --field "Files=" change -o | p4 change -i' % description,
296
+ stderr=subprocess.STDOUT,
297
+ shell=True).decode()
290
298
  changelist_number = output.split(" ")[1]
291
299
  return int(changelist_number)
292
300
 
@@ -302,7 +310,8 @@ class P4Client(object):
302
310
  return True
303
311
  else:
304
312
  changelist = str(changelist)
305
- changelists = self.get_pending_changelists(description_filter=changelist, perfect_match_only=True, case_sensitive=True)
313
+ changelists = self.get_pending_changelists(description_filter=changelist, perfect_match_only=True,
314
+ case_sensitive=True)
306
315
  if len(changelists):
307
316
  return True
308
317
  return False
@@ -315,24 +324,24 @@ class P4Client(object):
315
324
  :param new_description: *string* new description for the changelist
316
325
  :return: *bool* True if successful, False otherwise
317
326
  """
318
-
327
+
319
328
  # ... not super elegant, but it works
320
329
  try:
321
330
  changelist = self.__ensure_changelist(changelist)
322
-
331
+
323
332
  # do some formatting so that we have the proper indentation
324
333
  formatted_description = []
325
334
  for line in new_description.split('\n'):
326
335
  formatted_description.append(f"\t{line}")
327
336
  formatted_description = '\n'.join(formatted_description)
328
-
337
+
329
338
  output = subprocess.check_output(f'p4 change -o {changelist}', shell=True).decode()
330
-
339
+
331
340
  # Split the output into sections based on field names
332
341
  sections = []
333
342
  current_section = []
334
343
  current_field = None
335
-
344
+
336
345
  # take the output and start parsing it
337
346
  for line in output.split('\n'):
338
347
  # check if it's a new field
@@ -346,11 +355,11 @@ class P4Client(object):
346
355
  else:
347
356
  # if it's not a new field, add to the current section
348
357
  current_section.append(line)
349
-
358
+
350
359
  # add the last section
351
360
  if current_field:
352
361
  sections.append((current_field, current_section))
353
-
362
+
354
363
  # new remake the Description field with the update description
355
364
  new_output = []
356
365
  for field, section_lines in sections:
@@ -361,18 +370,18 @@ class P4Client(object):
361
370
  else:
362
371
  # keep everything else as-is
363
372
  new_output.extend(section_lines)
364
-
373
+
365
374
  updated_output = '\n'.join(new_output)
366
-
375
+
367
376
  # TODO: modify run_cmd to allow input so that commands like this can also run through it.
368
377
  result = subprocess.check_output(f'p4 change -i', input=updated_output.encode(), shell=True).decode()
369
-
378
+
370
379
  return True
371
380
  except Exception as e:
372
381
  if not self.silent:
373
382
  logging.error(f"Failed to update changelist description: {e}")
374
383
  return False
375
-
384
+
376
385
  @validate_not_empty
377
386
  def move_files_to_changelist(self, file_list, changelist="default"):
378
387
  """
@@ -410,7 +419,6 @@ class P4Client(object):
410
419
  result = self.move_files_to_changelist(files_to_move, target_changelist)
411
420
  return result
412
421
 
413
-
414
422
  def rename_file(self, old_file_path, new_file_path, changelist="default"):
415
423
  """
416
424
  P4 move-renames a file
@@ -438,7 +446,8 @@ class P4Client(object):
438
446
  """
439
447
  changelist = self.__ensure_changelist(changelist)
440
448
 
441
- info_dict = self.run_cmd("copy", args=["-c", str(changelist)], file_list=[original_file_path, copied_file_path])[0]
449
+ info_dict = \
450
+ self.run_cmd("copy", args=["-c", str(changelist)], file_list=[original_file_path, copied_file_path])[0]
442
451
  if self.__get_dict_value(info_dict, "code") != "error":
443
452
  return True
444
453
  return False
@@ -462,7 +471,6 @@ class P4Client(object):
462
471
 
463
472
  return info_dicts
464
473
 
465
-
466
474
  @validate_not_empty
467
475
  def revert_folders(self, folder_list, unchanged_only=False):
468
476
  """
@@ -514,7 +522,8 @@ class P4Client(object):
514
522
  if revert_unchanged_files:
515
523
  self.revert_changelist(unchanged_only=True, changelist=changelist)
516
524
 
517
- info_dicts = self.run_cmd("submit", args=["-c", changelist, "--parallel", f"threads={self.max_parallel_connections}"])
525
+ info_dicts = self.run_cmd("submit",
526
+ args=["-c", changelist, "--parallel", f"threads={self.max_parallel_connections}"])
518
527
  return info_dicts
519
528
 
520
529
  @validate_not_empty
@@ -536,7 +545,8 @@ class P4Client(object):
536
545
  folder += "/..."
537
546
  cleaned_folder_list.append(folder)
538
547
 
539
- info_dicts = self.run_cmd("sync", args=["--parallel", f"threads={self.max_parallel_connections}"], file_list=cleaned_folder_list)
548
+ info_dicts = self.run_cmd("sync", args=["--parallel", f"threads={self.max_parallel_connections}"],
549
+ file_list=cleaned_folder_list)
540
550
  return info_dicts
541
551
 
542
552
  @validate_not_empty
@@ -556,7 +566,8 @@ class P4Client(object):
556
566
  verify = False
557
567
  file_list = [f"{path}#{revision}" for path in file_list]
558
568
 
559
- initial_arg_list = ["-f", "--parallel", f"threads={self.max_parallel_connections}"] if force else ["--parallel", f"threads={self.max_parallel_connections}"]
569
+ initial_arg_list = ["-f", "--parallel", f"threads={self.max_parallel_connections}"] if force else ["--parallel",
570
+ f"threads={self.max_parallel_connections}"]
560
571
  if not self.silent:
561
572
  self.__validate_file_list(file_list)
562
573
 
@@ -629,16 +640,27 @@ class P4Client(object):
629
640
  info_dicts = self.run_cmd("delete", args=["-c", changelist], file_list=file_list)
630
641
  return info_dicts
631
642
 
632
- def delete_changelist(self, changelist="default", perfect_match_only=False, case_sensitive=False):
643
+ def delete_changelist(self, changelist, perfect_match_only=False, case_sensitive=False, delete_shelved_files=False,
644
+ obliterate=False):
633
645
  """
634
- Deletes a changelist via changelist number or description
646
+ Deletes a changelist via changelist number or description. Will fail if any files are checked out or shelved files exist.
635
647
  :param changelist: *string* or *int* change list number
636
648
  :param perfect_match_only: bool* only delete if there's a perfect match of the changelist description
637
649
  :param case_sensitive: *bool*
650
+ :param delete_shelved_files: *bool* If True, will delete all shelved files and then delete the CL.
651
+ :param obliterate: *bool* If True, will revert all files, deleted shelved files and then delete the CL
638
652
  """
639
653
  info_dicts = []
640
654
  cl_num = self.get_pending_changelists(changelist, perfect_match_only, case_sensitive)
641
655
  for cl in cl_num:
656
+ # revert all files, then make sure shelved files are also deleted
657
+ if obliterate:
658
+ info_dicts.append(self.revert_changelist(changelist=cl))
659
+ delete_shelved_files = True
660
+
661
+ if delete_shelved_files:
662
+ info_dicts.append(self.delete_shelf(cl))
663
+
642
664
  info_dicts.append(self.run_cmd('change', args=['-d', cl]))
643
665
  # TODO: Break down info dicts and look for errors
644
666
  return info_dicts
@@ -674,7 +696,7 @@ class P4Client(object):
674
696
  :return: *list* of info dictionaries
675
697
  """
676
698
  changelist = self.__ensure_changelist(changelist)
677
-
699
+
678
700
  # if no files specified, get all files in the changelist
679
701
  if file_list is None:
680
702
  file_list = self.get_files_in_changelist(changelist)
@@ -682,34 +704,35 @@ class P4Client(object):
682
704
  file_list = convert_to_list(file_list) if not isinstance(file_list, list) else file_list
683
705
  if not self.silent:
684
706
  self.__validate_file_list(file_list)
685
-
707
+
686
708
  # if there are no files to shelve, return empty list
687
709
  if not file_list:
688
710
  if not self.silent:
689
711
  logging.warning(f"No files to shelve in changelist {changelist}")
690
712
  return []
691
-
713
+
692
714
  # iuild args list based on options
693
715
  args = ["-c", str(changelist)]
694
716
  if force:
695
717
  args.append("-f")
696
-
718
+
697
719
  # run the shelve command
698
720
  info_dicts = self.run_cmd("shelve", args=args, file_list=file_list)
699
-
721
+
700
722
  for info_dict in info_dicts:
701
723
  if self.__get_dict_value(info_dict, "code") == "error" and not self.silent:
702
724
  logging.error(self.__get_dict_value(info_dict, "data"))
703
-
725
+
704
726
  # revert files if requested
705
727
  if revert_after_shelve and file_list:
706
728
  revert_info_dicts = self.revert_files(file_list)
707
729
  # add revert info to the return data
708
730
  info_dicts.extend(revert_info_dicts)
709
-
731
+
710
732
  return info_dicts
711
733
 
712
- def unshelve_files(self, changelist, file_list=None, target_changelist="default", force=False, delete_shelved_files=False):
734
+ def unshelve_files(self, changelist, file_list=None, target_changelist="default", force=False,
735
+ delete_shelved_files=False):
713
736
  """
714
737
  Unshelves files from a shelved changelist. If no files are specified, unshelves all files.
715
738
 
@@ -722,21 +745,21 @@ class P4Client(object):
722
745
  """
723
746
  source_changelist = self.__ensure_changelist(changelist)
724
747
  target_changelist = self.__ensure_changelist(target_changelist)
725
-
748
+
726
749
  # build the arguments list
727
750
  args = []
728
-
751
+
729
752
  # add force flag if requested
730
753
  if force:
731
754
  args.append("-f")
732
-
755
+
733
756
  # add source changelist (required)
734
757
  args.extend(["-s", str(source_changelist)])
735
-
758
+
736
759
  # add target changelist if specified and not default
737
760
  if target_changelist != "default":
738
761
  args.extend(["-c", str(target_changelist)])
739
-
762
+
740
763
  # prepare file list if provided
741
764
  if file_list is not None:
742
765
  file_list = convert_to_list(file_list) if not isinstance(file_list, list) else file_list
@@ -744,35 +767,77 @@ class P4Client(object):
744
767
  self.__validate_file_list(file_list)
745
768
  else:
746
769
  file_list = []
747
-
770
+
748
771
  # run the unshelve command
749
772
  info_dicts = self.run_cmd("unshelve", args=args, file_list=file_list)
750
-
773
+
751
774
  # check for errors in the unshelve operation
752
775
  has_error = False
753
776
  for info_dict in info_dicts:
754
777
  if self.__get_dict_value(info_dict, "code") == "error" and not self.silent:
755
778
  logging.error(self.__get_dict_value(info_dict, "data"))
756
779
  has_error = True
757
-
780
+
758
781
  # delete shelved files if requested and unshelve was successful
759
782
  if delete_shelved_files and not has_error:
760
783
  # build the arguments for the shelve -d command
761
784
  delete_args = ["-d", "-c", str(source_changelist)]
762
-
785
+
763
786
  # if file_list provided, use it for the delete operation as well
764
787
  delete_info_dicts = self.run_cmd("shelve", args=delete_args, file_list=file_list)
765
-
788
+
766
789
  # check for errors in the delete operation
767
790
  for info_dict in delete_info_dicts:
768
791
  if self.__get_dict_value(info_dict, "code") == "error" and not self.silent:
769
792
  logging.error(self.__get_dict_value(info_dict, "data"))
770
-
793
+
771
794
  # add the delete info to the return data
772
795
  info_dicts.extend(delete_info_dicts)
773
-
796
+
774
797
  return info_dicts
775
798
 
799
+ def delete_shelf(self, changelist):
800
+ """
801
+ Deletes all shelved files in a changelist without deleting the changelist itself.
802
+
803
+ :param changelist: *string* or *int* changelist number
804
+ :return: *list* of info dictionaries
805
+ """
806
+ try:
807
+ # Ensure the changelist exists and is a number
808
+ changelist = self.__ensure_changelist(changelist)
809
+
810
+ # Don't allow deleting shelves from the default changelist
811
+ if changelist == "default":
812
+ if not self.silent:
813
+ logging.error("Cannot delete shelved files from the default changelist")
814
+ return [{"code": "error", "data": "Cannot delete shelved files from the default changelist"}]
815
+
816
+ # Check if the changelist has shelved files
817
+ has_shelved_files = False
818
+ info_dicts = self.run_cmd("describe", args=["-S", str(changelist)])
819
+ for info_dict in info_dicts:
820
+ for key in info_dict.keys():
821
+ if b"depotFile" in key:
822
+ has_shelved_files = True
823
+ break
824
+ if has_shelved_files:
825
+ break
826
+
827
+ if not has_shelved_files:
828
+ if not self.silent:
829
+ logging.warning(f"No shelved files found in changelist {changelist}")
830
+ return [{"code": "info", "data": f"No shelved files found in changelist {changelist}"}]
831
+
832
+ # Delete all shelved files in the changelist
833
+ info_dicts = self.run_cmd("shelve", args=["-d", "-c", str(changelist)])
834
+ return info_dicts
835
+
836
+ except Exception as e:
837
+ if not self.silent:
838
+ logging.error(f"Failed to delete shelved files: {e}")
839
+ return [{"code": "error", "data": str(e)}]
840
+
776
841
  @validate_not_empty
777
842
  def add_or_edit_folders(self, folders, include_subfolders=True, changelist="default"):
778
843
  """
@@ -793,11 +858,11 @@ class P4Client(object):
793
858
  if not complete_file_path in files:
794
859
  all_files.append(complete_file_path)
795
860
  else:
796
- all_files.extend([os.path.join(folder, file) for file in os.listdir(folder) if os.path.isfile(os.path.join(folder, file))])
861
+ all_files.extend([os.path.join(folder, file) for file in os.listdir(folder) if
862
+ os.path.isfile(os.path.join(folder, file))])
797
863
 
798
864
  return self.add_or_edit_files(all_files, changelist=changelist)
799
865
 
800
-
801
866
  @validate_not_empty
802
867
  def add_or_edit_files(self, file_list, changelist="default"):
803
868
  """
@@ -919,7 +984,8 @@ class P4Client(object):
919
984
 
920
985
  return depot_paths
921
986
 
922
- def get_pending_changelists(self, description_filter="", perfect_match_only=False, case_sensitive=False, descriptions=False):
987
+ def get_pending_changelists(self, description_filter="", perfect_match_only=False, case_sensitive=False,
988
+ descriptions=False):
923
989
  """
924
990
  Returns all the pending change lists, filtered on the changelist description
925
991
 
@@ -986,7 +1052,7 @@ class P4Client(object):
986
1052
  case_sensitive=case_sensitive,
987
1053
  )
988
1054
 
989
- if len(changelists) > 1: # > 1 because "default" is always appended
1055
+ if len(changelists) > 1: # > 1 because "default" is always appended
990
1056
  return changelists[0]
991
1057
  else:
992
1058
  return self.make_new_changelist(description=changelist_description)
@@ -1024,7 +1090,6 @@ class P4Client(object):
1024
1090
  depot_paths = [self.__get_dict_value(info, "depotFile").rstrip("/...") for info in info_dicts]
1025
1091
  return depot_paths
1026
1092
 
1027
-
1028
1093
  @validate_not_empty
1029
1094
  def get_local_paths(self, paths):
1030
1095
  """
@@ -1064,7 +1129,7 @@ class P4Client(object):
1064
1129
 
1065
1130
  return info_dicts
1066
1131
 
1067
- def host_online(self):
1132
+ def host_online(self, timeout=0.001):
1068
1133
  """
1069
1134
  Checks if the host for this client is online
1070
1135
 
@@ -1074,10 +1139,16 @@ class P4Client(object):
1074
1139
  host = self.__server_address()
1075
1140
 
1076
1141
  try:
1077
- sock = socket.create_connection((host, port), timeout=2)
1078
- sock.close()
1079
- return True
1080
- except:
1142
+ with socket.create_connection((host, port), timeout=timeout):
1143
+ return True
1144
+ except socket.timeout:
1145
+ logging.warning(f"Connection to {host} on port {port} timed out after {timeout} seconds, the running command might not complete correctly")
1146
+ return False
1147
+ except ConnectionRefusedError:
1148
+ logging.warning(f"Connection to {host} on port {port} refused to connect, is the server still up?")
1149
+ return False
1150
+ except OSError as e:
1151
+ logging.warning(f"oserror: {e.strerror or e}")
1081
1152
  return False
1082
1153
 
1083
1154
  def __server_address(self):
@@ -1191,6 +1262,9 @@ class P4Client(object):
1191
1262
 
1192
1263
  :return: *bool*
1193
1264
  """
1265
+ if not self.perforce_root:
1266
+ raise p4errors.WorkSpaceError(f"self.perforce_root (value: {self.perforce_root}) is not set!")
1267
+
1194
1268
  starting_dir = self.perforce_root
1195
1269
  last_dir = ""
1196
1270
  current_dir = starting_dir
@@ -1213,11 +1287,15 @@ class P4Client(object):
1213
1287
  :param file_list: List of files to iterate
1214
1288
  :return:
1215
1289
  """
1290
+ if not self.perforce_root:
1291
+ raise p4errors.WorkSpaceError(f"self.perforce_root (value: {self.perforce_root}) is not set!")
1292
+
1216
1293
  file_list = convert_to_list(file_list) if not isinstance(file_list, list) else file_list
1217
1294
 
1218
1295
  # Easy utility to check that the file is underneath the correct perforce root
1219
1296
  # Quicker than waiting for the result of a p4 fstat
1220
1297
  for f in file_list:
1221
- if not f.lower().startswith(self.perforce_root.lower()) and not f.lower().startswith(self.depot_root.lower()):
1298
+ if not f.lower().startswith(self.perforce_root.lower()) and not f.lower().startswith(
1299
+ self.depot_root.lower()):
1222
1300
  raise Exception(f'{f} is not under perforce root: {self.perforce_root}, {self.depot_root}')
1223
1301
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: p4cmd
3
- Version: 2.7.0
3
+ Version: 2.8.1
4
4
  Summary: Simple P4 python module
5
5
  Home-page: https://github.com/nielsvaes/p4cmd
6
6
  Author: Niels Vaes
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