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):
Comment thread
jasugun marked this conversation as resolved.
Outdated
''' 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('...'):
Comment thread
jasugun marked this conversation as resolved.
Outdated
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:
Comment thread
jasugun marked this conversation as resolved.
Outdated
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+)'))
Comment thread
jasugun marked this conversation as resolved.
Outdated
except StopIteration as e:
revision = None
return revision

def print(self, p4_print_command_args):
Comment thread
jasugun marked this conversation as resolved.
Outdated
''' wrapper for p4 print command '''
output = self._run('print', f'{p4_print_command_args}', use_json_format=True)
Comment thread
jasugun marked this conversation as resolved.
Outdated
return self.parse_json_output_for_data(output)
Comment thread
jasugun marked this conversation as resolved.
Outdated

@staticmethod
def parse_json_output_for_data(output):
Comment thread
jasugun marked this conversation as resolved.
Outdated
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():
Comment thread
jasugun marked this conversation as resolved.
Outdated
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)
Comment thread
jasugun marked this conversation as resolved.
Outdated
return True
else:
_, _, error = nimp.sys.process.call(command, capture_output=True)

if error is not None and error != "":
Comment thread
jasugun marked this conversation as resolved.
Outdated
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):
Comment thread
jasugun marked this conversation as resolved.
Outdated
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
Copy Markdown
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