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.
- {p4cmd-2.7.0 → p4cmd-2.8.1}/PKG-INFO +1 -1
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/__init__.py +1 -1
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/p4cmd.py +140 -62
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd.egg-info/PKG-INFO +1 -1
- {p4cmd-2.7.0 → p4cmd-2.8.1}/LICENSE +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/README.md +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/p4errors.py +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/p4file.py +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/__init__.py +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_DEPOT_ONLY.png +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_MOVED.png +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_NEED_SYNC.png +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_OPEN_FOR_ADD.png +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_OPEN_FOR_DELETE.png +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_OPEN_FOR_EDIT.png +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_UNKNOWN.png +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_UNTRACKED.png +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/resources/perforce_UP_TO_DATE.png +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd/utils.py +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd.egg-info/SOURCES.txt +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd.egg-info/dependency_links.txt +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/p4cmd.egg-info/top_level.txt +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/setup.cfg +0 -0
- {p4cmd-2.7.0 → p4cmd-2.8.1}/setup.py +0 -0
|
@@ -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
|
-
|
|
99
|
-
logging.warning("Can't connect to %s on port %s" % (self.__server_address(), self.__port_number()))
|
|
105
|
+
self.host_online()
|
|
100
106
|
|
|
101
|
-
|
|
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(
|
|
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
|
|
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(
|
|
288
|
-
|
|
289
|
-
|
|
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,
|
|
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 =
|
|
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",
|
|
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}"],
|
|
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",
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
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:
|
|
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
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
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(
|
|
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
|
|
|
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
|
|
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
|