Other usage examples

This page contains some examples of Python scripts using Universum.

Export Perforce repository to Git

Here’s an example script that ports certain directory with commit history from Helix Perforce (P4) repository to Git. It sequentially reproduces directory state for each submitted CL, and submits this repository state to Git using the same commit description.

Note

To port the whole repository you just have to set Perforce source directory and Git destination directory to repository root

Command line description

--p4-port

Source Perforce repository; format equals to Perforce P4PORT environment variable and usually looks like example.com:1666

--p4-user

Perforce account used to download (sync) files from Perforce server

--p4-password

Corresponding password for –p4-user

--p4-client

Name of a temporary Perforce client (workspace) to be created automatically; this client will be deleted after the script finishes its work

--p4-depot-path

Particular folder in source Perforce repository to be ported; should be provided in Perforce-specific format, e.g. //depot/path/...

--p4-client-root

Local folder, where the source commits will be downloaded to; should be absolute path; should be anywhere inside destination Git repository

--git-repo

Destination Git repository; should be absolute path; repository should already exist

--git-user

Git account used to commit ported changes

--git-email

Mandatory Git parameter for committer; should correspond to –git-user

Note

--p4-client-root should not necessarily equal --git-repo; it just has to be somewhere inside repository

Preconditions

  • Git repository already exists. It can be cloned from remote or created via git init

  • Git account used for porting is authorized to commit

  • Perforce account used for porting is authorized to download (sync) source folder

  • Perforce client does not exist

Script

 1#!/usr/bin/env python
 2
 3import argparse
 4from P4 import P4
 5from universum import __main__ as universum
 6
 7
 8def main():
 9    parser = argparse.ArgumentParser()
10    parser.add_argument("--p4-port")
11    parser.add_argument("--p4-user")
12    parser.add_argument("--p4-password")
13    parser.add_argument("--p4-client")
14    parser.add_argument("--p4-depot-path")
15    parser.add_argument("--p4-client-root")
16    parser.add_argument("--git-repo")
17    parser.add_argument("--git-user")
18    parser.add_argument("--git-email")
19    args = parser.parse_args()
20
21    p4 = P4()
22
23    p4.port = args.p4_port
24    p4.user = args.p4_user
25    p4.password = args.p4_password
26    client_name = args.p4_client
27
28    p4.connect()
29
30    depot_path = args.p4_depot_path
31
32    client = p4.fetch_client(client_name)
33    client["Root"] = args.p4_client_root
34    client["View"] = [depot_path + " //" + client_name + "/..."]
35    p4.save_client(client)
36    p4.client = client_name
37
38    changes = p4.run_changes("-s", "submitted", depot_path)
39    cl_list = []
40    for change in changes:
41        cl_list.append(change["change"])
42    
43    for cl in reversed(cl_list):
44        line = depot_path + '@' + cl
45        p4.run_sync("-f", line)
46    
47        universum.main(["submit",
48                        "-ot", "term",
49                        "-vt", "git",
50                        "-cm", p4.run_describe(cl)[0]['desc'],
51                        "-gu", args.git_user,
52                        "-ge", args.git_email,
53                        "-pr", args.git_repo,
54                        "-gr", "file://" + args.git_repo,
55                        "-grs", "master"])
56
57    p4.delete_client(client_name)
58
59
60if __name__ == "__main__":
61    main()

Possible script modifications

In this example commit messages are preserved, but all changes are committed to Git from one user. To port commit users as well use p4.run_describe(cl)[0]['user'] to find P4 user and replace incoming parameters --git-user, --git-email with mapping of P4 users into Git user parameters (-gu, -ge) that are passed to submitter. See lines 52-53 for the reference.

Also this script only can process the contents of one P4 folder, creating a single mapping for it in client["View"]. To use multiple mappings, edit client["View"] accordingly instead of parsing --depot-path parameter. See line 35 for the reference.