David Blume commited on 2017-02-16 22:55:09
Showing 3 changed files, with 142 additions and 0 deletions.
... | ... |
@@ -0,0 +1,21 @@ |
1 |
+The MIT License (MIT) |
|
2 |
+ |
|
3 |
+Copyright (c) 2017 David Blume |
|
4 |
+ |
|
5 |
+Permission is hereby granted, free of charge, to any person obtaining a copy |
|
6 |
+of this software and associated documentation files (the "Software"), to deal |
|
7 |
+in the Software without restriction, including without limitation the rights |
|
8 |
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
9 |
+copies of the Software, and to permit persons to whom the Software is |
|
10 |
+furnished to do so, subject to the following conditions: |
|
11 |
+ |
|
12 |
+The above copyright notice and this permission notice shall be included in all |
|
13 |
+copies or substantial portions of the Software. |
|
14 |
+ |
|
15 |
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
16 |
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
17 |
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
18 |
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
19 |
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
20 |
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
21 |
+SOFTWARE. |
... | ... |
@@ -0,0 +1,22 @@ |
1 |
+# same\_as\_p4\_reconcile.py |
|
2 |
+ |
|
3 |
+This is a Python 3 script that's nearly the same as simply running "p4 reconcile". |
|
4 |
+ |
|
5 |
+I'd already started writing it before I realized what a duplication of effort it was. So, of course, I decided to memorialize it here. |
|
6 |
+ |
|
7 |
+To preview how a reconcile would look, issue a command like so: |
|
8 |
+ |
|
9 |
+ same_as_p4_reconcile.py -c 48 -n source_dir/ p4_dir/ |
|
10 |
+ |
|
11 |
+Of course, issue the command with -h or --help to learn more. |
|
12 |
+ |
|
13 |
+ same_as_p4_reconcile.py --help |
|
14 |
+ |
|
15 |
+### Is it any good? |
|
16 |
+ |
|
17 |
+[Yes](https://news.ycombinator.com/item?id=3067434). |
|
18 |
+ |
|
19 |
+### Licence |
|
20 |
+ |
|
21 |
+This software uses the [MIT license](http://git.dlma.com/same_as_p4_reconcile.git/blob/master/LICENSE.txt). |
|
22 |
+ |
... | ... |
@@ -0,0 +1,99 @@ |
1 |
+#!/usr/bin/env python3 |
|
2 |
+# |
|
3 |
+# This is really similar to "p4 reconcile", except that it |
|
4 |
+# reconciles from an external directory, "source_dir", to |
|
5 |
+# the Perforce repo, "perforce_dir". |
|
6 |
+# |
|
7 |
+# Eg., to preview the changes that would be made: |
|
8 |
+# |
|
9 |
+# ./same_as_p4_reconcile.py -n -c 42 source_dir perforce_dir |
|
10 |
+# |
|
11 |
+# To perform the actual reconciliation, drop the "-n": |
|
12 |
+# |
|
13 |
+# ./same_as_p4_reconcile.py -c 42 source_dir perforce_dir |
|
14 |
+ |
|
15 |
+import os |
|
16 |
+from argparse import ArgumentParser |
|
17 |
+import subprocess |
|
18 |
+import shutil |
|
19 |
+import filecmp |
|
20 |
+ |
|
21 |
+ |
|
22 |
+def call(cmd_array, changelist, preview): |
|
23 |
+ """ If not preview, makes the call.""" |
|
24 |
+ ret = 0 |
|
25 |
+ if not preview: |
|
26 |
+ ret = subprocess.call(add_changelist_to_cmd(cmd_array, changelist)) |
|
27 |
+ if ret != 0: |
|
28 |
+ print("ERROR: Couldn't %s, ret = %d" % (str(cmd_array), ret)) |
|
29 |
+ else: |
|
30 |
+ print('#', ' '.join(cmd_array)) |
|
31 |
+ return ret |
|
32 |
+ |
|
33 |
+ |
|
34 |
+def add_changelist_to_cmd(cmd, changelist): |
|
35 |
+ """Injects "-c changelist" to the p4 command.""" |
|
36 |
+ if changelist is None: |
|
37 |
+ return cmd |
|
38 |
+ cmd.insert(2, '-c') |
|
39 |
+ cmd.insert(3, changelist) |
|
40 |
+ return cmd |
|
41 |
+ |
|
42 |
+ |
|
43 |
+def do_diff_by_name(preview, changelist, source_dir, p4_dir): |
|
44 |
+ do_diff(preview, changelist, filecmp.dircmp(p4_dir, source_dir)) |
|
45 |
+ delete_empty_directories(p4_dir) |
|
46 |
+ |
|
47 |
+ |
|
48 |
+def delete_empty_directories(top): |
|
49 |
+ """ p4 deletes could leave us with empty hierarchies. """ |
|
50 |
+ for root, dirs, files in os.walk(top, topdown=False): |
|
51 |
+ for name in dirs: |
|
52 |
+ try: |
|
53 |
+ os.rmdir(os.path.join(root,name)) |
|
54 |
+ except OSError as ex: |
|
55 |
+ pass |
|
56 |
+ |
|
57 |
+ |
|
58 |
+def do_diff(preview, changelist, d): |
|
59 |
+ for f in d.right_only: |
|
60 |
+ if os.path.isfile(os.path.join(d.right, f)): |
|
61 |
+ if not preview: |
|
62 |
+ shutil.copy(os.path.join(d.right, f), os.path.join(d.left, f)) |
|
63 |
+ call(['p4', 'add', os.path.join(d.left, f)], changelist, preview) |
|
64 |
+ else: |
|
65 |
+ # Can't add directory in one step. Do so by walking dir. |
|
66 |
+ if not preview: |
|
67 |
+ shutil.copytree(os.path.join(d.right, f), os.path.join(d.left, f)) |
|
68 |
+ for root, dirs, files in os.walk(os.path.join(d.left, f)): |
|
69 |
+ for f in files: |
|
70 |
+ call(['p4', 'add', os.path.join(root, f)], changelist, preview) |
|
71 |
+ else: |
|
72 |
+ print('# Adding hierarchy', os.path.join(d.right, f)) |
|
73 |
+ |
|
74 |
+ for f in d.left_only: |
|
75 |
+ if os.path.isfile(os.path.join(d.left, f)): |
|
76 |
+ call(['p4', 'delete', os.path.join(d.left, f)], changelist, preview) |
|
77 |
+ else: |
|
78 |
+ for root, dirs, files in os.walk(os.path.join(d.left, f)): |
|
79 |
+ for f in files: |
|
80 |
+ call(['p4', 'delete', os.path.join(root, f)], changelist, preview) |
|
81 |
+ |
|
82 |
+ for f in d.diff_files: |
|
83 |
+ if not call(['p4', 'edit', os.path.join(d.left, f)], changelist, preview): |
|
84 |
+ # call() returning 0 is a successful call |
|
85 |
+ if not preview: |
|
86 |
+ shutil.copy(os.path.join(d.right, f), os.path.join(d.left, f)) |
|
87 |
+ |
|
88 |
+ for sub in d.subdirs.values(): |
|
89 |
+ do_diff(preview, changelist, sub) |
|
90 |
+ |
|
91 |
+ |
|
92 |
+if __name__ == '__main__': |
|
93 |
+ parser = ArgumentParser(description='Similar to "p4 reconcile"') |
|
94 |
+ parser.add_argument('-c', '--changelist', help='Changelist to use') |
|
95 |
+ parser.add_argument('-n', '--preview', action='store_true') |
|
96 |
+ parser.add_argument('source_dir', help='The newer directory outside perforce') |
|
97 |
+ parser.add_argument('p4_dir', help='The perforce directory to be modified') |
|
98 |
+ args = parser.parse_args() |
|
99 |
+ do_diff_by_name(args.preview, args.changelist, args.source_dir, args.p4_dir) |
|
0 | 100 |