Skip to content
Open
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 75 additions & 6 deletions nimp/utils/p4.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
''' Perforce utilities '''

import argparse
import json
import logging
import os
import os.path
Expand Down Expand Up @@ -228,6 +229,23 @@ def reconcile(self, cl_number, *files):

return ret

def reconcile_workspace(self, cl_number=None, workspace_path_to_reconcile=None, dry_run=False):
''' Reconciles given workspace '''
p4_reconcile_args = ['reconcile', '-f', '-e', '-a', '-d']
if dry_run:
p4_reconcile_args.append('-n')
if cl_number:
p4_reconcile_args.extend(['-c', cl_number])
if workspace_path_to_reconcile:
if not workspace_path_to_reconcile.endswith('...'):
workspace_path_to_reconcile = os.path.join(workspace_path_to_reconcile, '...')
workspace_path_to_reconcile = nimp.system.sanitize_path(workspace_path_to_reconcile)
p4_reconcile_args.append(workspace_path_to_reconcile)

if self._run(*p4_reconcile_args) is None:
return False
return True

def get_changelist_description(self, cl_number):
''' Returns description of given changelist '''
desc, = next(self._parse_command_output(["describe", cl_number], r"\.\.\. desc (.*)"))
Expand All @@ -248,6 +266,29 @@ def get_last_synced_changelist(self):

return cl_number

def get_file_workspace_current_revision(self, file):
''' Returns the file revision currently synced in the workspace '''
try:
revision, = next(self._parse_command_output(['have', file], r'\.\.\. haveRev (\d+)'))
except StopIteration as e:
revision = None
return revision

def print(self, p4_print_command_args):
''' wrapper for p4 print command '''
output = self._run('print', f'{p4_print_command_args}', use_json_format=True)
return self.parse_json_output_for_data(output)

@staticmethod
def parse_json_output_for_data(output):
data = ''
output = [json_element for json_element in output.splitlines() if json_element]
for output_chunk in output:
output_chunk = json.loads(output_chunk)
if 'data' in output_chunk.keys():
data += output_chunk['data']
return data

def get_or_create_changelist(self, description):
''' Creates or returns changelist number if it's not already created '''
pending_changelists = self.get_pending_changelists()
Expand Down Expand Up @@ -335,6 +376,32 @@ def submit(self, cl_number):

return True

def submit_default_changelist(self, description=None, revert_unchanged=False, dry_run=False):
''' Submits given changelist '''
logging.info("Submitting default changelist...")
command = self._get_p4_command('submit', '-f')
if revert_unchanged:
command.append('revertunchanged')
# descriptions could be too long for perforce limitations
command_length = len(' '.join(command))
perforce_cmd_max_characters_limit = 8191
if description:
d_flag = 4 # accounts for ' -d ' string
description_max_characters_limit = perforce_cmd_max_characters_limit - command_length - d_flag
description = description[:description_max_characters_limit]
command.extend(['-d', description])
if dry_run:
logging.info(command)
return True
else:
_, _, error = nimp.sys.process.call(command, capture_output=True)

if error is not None and error != "":
logging.error("%s", error)
return False

return True

def sync(self, *files, cl_number = None):
''' Udpate given file '''
command = ["sync"]
Expand All @@ -357,8 +424,7 @@ def get_modified_files(self, *cl_numbers, root = '//...'):
for cl_number in cl_numbers:
for filename, action in self._parse_command_output(["fstat", "-e", cl_number , root],
r"^\.\.\. depotFile(.*)$",
r"^\.\.\. headAction(.*)",
hide_output=True):
r"^\.\.\. headAction(.*)"):
filename = os.path.normpath(filename) if filename is not None else ''
yield filename, action

Expand All @@ -370,8 +436,10 @@ def _escape_filename(name):
.replace('#', '%23') \
.replace('*', '%2A')

def _get_p4_command(self, *args):
def _get_p4_command(self, *args, use_json_format=False):
command = ['p4', '-z', 'tag']
if use_json_format:
command.append('-Mj')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's recommended to always use -ztag with -Mj

if self._port is not None:
command += ['-p', self._port]
if self._user is not None:
Expand All @@ -384,11 +452,12 @@ def _get_p4_command(self, *args):
command += list(args)
return command

def _run(self, *args, stdin=None, hide_output=False):
command = self._get_p4_command(*args)
def _run(self, *args, stdin=None, hide_output=False, use_json_format=False):
command = self._get_p4_command(*args, use_json_format=use_json_format)

for _ in range(5):
result, output, error = nimp.sys.process.call(command, stdin=stdin, encoding='cp437', capture_output=True, hide_output=hide_output)
result, output, error = nimp.sys.process.call(
command, stdin=stdin, encoding='cp437', capture_output=True, hide_output=hide_output)

if 'Operation took too long ' in error:
continue
Expand Down