"""Pulls changelists from Perforce into a Bazaar shared repository. For example, > pull.py //depot/project C:\\repo Requires that the P4PORT and P4USER environment variables are set. Requires that bzrp4 is installed as a Bazaar plugin. """ import os import os.path import P4 import subprocess import sys def p4_fast_export_path(): dir = os.path.dirname(__file__) return os.path.join(dir, 'p4-fast-export.py') def last_change_in_source_depot_path(src): p4 = P4.P4() p4.connect() result = p4.run_changes('-m', '1', p4_wildcard(src)) p4.disconnect() return result[0]['change'] def parse_change_from_marks_line(line): return int(line[1:line.find(' ')]) def last_change_in_marks_file(dest): last_change = 0 try: marks_file = open(marks_file_path(dest), 'r') for line in marks_file: if ':' == line[0]: change = parse_change_from_marks_line(line) if change > last_change: last_change = change except IOError: pass return last_change def range_begin(dest): last_change = last_change_in_marks_file(dest) return str(last_change) def range_end(src): return last_change_in_source_depot_path(src) def p4_wildcard(path): return '%s/...' % path def manual_range(src): return -1 != src.find('@') def computed_range(src): return not manual_range(src) def depot_path_and_range(src, dest): if manual_range(src): return src else: return '%s@%s,%s' % (src, range_begin(dest), range_end(src)) def marks_file_path(dest): return os.path.join(dest, 'marks.txt') def bzr_fast_import_command(dest): # TODO: Make this portable, not Windows-specific. command = ['bzr.bat', 'fast-import'] if os.path.exists(marks_file_path(dest)): command += ['--import-marks=%s' % marks_file_path(dest)] command += ['--export-marks=%s' % marks_file_path(dest), '-'] return command def pull(src, dest): print depot_path_and_range(src, dest) if computed_range(src) and range_begin(dest) >= range_end(src): return proc1 = subprocess.Popen(['python', p4_fast_export_path(), depot_path_and_range(src, dest)], stdout=subprocess.PIPE) proc2 = subprocess.Popen(bzr_fast_import_command(dest), stdin=proc1.stdout, stdout=subprocess.PIPE, cwd=dest) output = proc2.communicate()[0] print output def main(args): pull_src = args[0] pull_dest = args[1] pull(pull_src, pull_dest) if __name__ == '__main__': main(sys.argv[1:])