|
#!/usr/bin/env python |
|
|
|
""" |
|
git-merge-android-manifest |
|
|
|
matt@mplewis.com, created 2015-03-27 |
|
License: The MIT License |
|
|
|
Git merge strategy for Android Manifest files. See main() for more info. |
|
|
|
To use: |
|
|
|
- Add this script to your path |
|
|
|
- Install bzrlib: |
|
pip install bzrlib |
|
|
|
- Add this to .git/config or ~/.gitconfig: |
|
[merge "android-manifest"] |
|
name = Android Manifest merge driver |
|
driver = git-merge-android-manifest %O %A %B |
|
recursive = text |
|
|
|
- Add this to .gitattributes (use the correct path to your project's manifest): |
|
app/src/main/AndroidManifest.xml merge=android-manifest |
|
|
|
- Merge simply and with much happiness! |
|
|
|
Thanks to github.com/mezis for git-merge-po.sh: |
|
https://gist.github.com/mezis/1605647 |
|
""" |
|
|
|
from bzrlib import merge3 |
|
|
|
import sys |
|
import re |
|
|
|
|
|
def main(): |
|
""" |
|
Git merge strategy for AndroidManifest.xml files. |
|
|
|
Take in paths to files to merge: |
|
git-merge-android-manifest $ancestor $mine $theirs |
|
|
|
If there are conflicts in the Android version code, it selects the one with |
|
the highest integer version code. Other conflicts are left in the file |
|
as-is for the user to resolve. |
|
|
|
Save the data to $mine and exit cleanly if there are no other conflicts. |
|
""" |
|
filenames = sys.argv[1:] |
|
filedata = [] |
|
for filename in filenames: |
|
with open(filename) as f: |
|
filedata.append(f.readlines()) |
|
ancestor, mine, theirs = filedata |
|
|
|
conflicts_present = False |
|
lines = [] |
|
m3 = merge3.Merge3(ancestor, mine, theirs) |
|
for r in m3.merge_groups(): |
|
type, results = r[0], r[1:] |
|
|
|
if type == 'conflict': |
|
attempts = results[1:] |
|
resolved, selected_lines = resolve_conflict(attempts) |
|
if not resolved: |
|
conflicts_present = True |
|
else: |
|
selected_lines = results[0] |
|
|
|
for line in selected_lines: |
|
lines.append(line) |
|
|
|
final = ''.join(lines) |
|
mine_name = filenames[1] |
|
with open(mine_name, 'w') as f: |
|
f.write(final) |
|
|
|
if conflicts_present: |
|
sys.exit(1) |
|
|
|
sys.exit(0) |
|
|
|
|
|
def resolve_conflict(attempts): |
|
""" |
|
If the conflict contains an android:versionCode tag, pick the attempt with |
|
the highest version code. |
|
|
|
Otherwise, merge the two attempts into a conflict section with markers |
|
(>>>>>>>, =======, <<<<<<<). |
|
|
|
Returns a tuple: (resolved, lines) |
|
resolved: true if the conflict was resolved via version code tag |
|
lines: a new list of lines for the conflicting section |
|
""" |
|
VERSION_CODE_REGEX = 'android:versionCode="([0-9]+?)"' |
|
|
|
selected_attempt = None |
|
selected_version = None |
|
for attempt in attempts: |
|
for line in attempt: |
|
found = re.search(VERSION_CODE_REGEX, line) |
|
if found: |
|
try: |
|
version_code = int(found.group(1)) |
|
except TypeError: |
|
pass |
|
if not selected_version or version_code > selected_version: |
|
selected_attempt = attempt |
|
selected_version = version_code |
|
|
|
resolved = True |
|
if not selected_attempt: |
|
resolved = False |
|
selected_attempt = conflict_markers(attempts) |
|
|
|
return resolved, selected_attempt |
|
|
|
|
|
def conflict_markers(attempts): |
|
"""Append conflict markers to two conflict resolution attempts.""" |
|
mine, theirs = attempts |
|
lines = [] |
|
lines.append('<<<<<<< MINE\n') |
|
for line in mine: |
|
lines.append(line) |
|
lines.append('=======\n') |
|
for line in theirs: |
|
lines.append(line) |
|
lines.append('>>>>>>> THEIRS\n') |
|
return(lines) |
|
|
|
|
|
if __name__ == '__main__': |
|
main() |
in macOS, I managed to install bzr by
pip install bzr