Skip to content

Commit

Permalink
Add analyser to detect remaining conflicts
Browse files Browse the repository at this point in the history
When the trust exit code is set to false (by default), use the analyser
to detect remaining conflicts.

Fixes #11
  • Loading branch information
xgouchet committed Apr 9, 2017
1 parent 6430634 commit 623e1c6
Show file tree
Hide file tree
Showing 8 changed files with 225 additions and 23 deletions.
63 changes: 50 additions & 13 deletions _amt_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ def test_merge_with_none(self):
cfg.set(SECT_AMT, OPT_VERBOSE, 'true')
args = create_args()
launcher = Mock()
analyser = Mock()

# When
result = merge_with_tool(tool, cfg, args, launcher)
result = merge_with_tool(tool, cfg, args, launcher, analyser)

# Then
self.assertEqual(result, ERROR_NO_TOOL)
Expand All @@ -50,9 +51,10 @@ def test_merge_with_bad_extensions(self):
args = create_args()
launcher_args = {'get_tool_extensions.return_value': 'bacon;spam'}
launcher = Mock(**launcher_args)
analyser = Mock()

# When
result = merge_with_tool(tool, cfg, args, launcher)
result = merge_with_tool(tool, cfg, args, launcher, analyser)

# Then
self.assertEqual(result, ERROR_EXTENSION)
Expand All @@ -69,9 +71,10 @@ def test_merge_with_ignored_extensions(self):
'get_tool_ignored_extensions.return_value': 'bacon;spam;ext'
}
launcher = Mock(**launcher_args)
analyser = Mock()

# When
result = merge_with_tool(tool, cfg, args, launcher)
result = merge_with_tool(tool, cfg, args, launcher, analyser)

# Then
self.assertEqual(result, ERROR_EXTENSION)
Expand All @@ -89,9 +92,10 @@ def test_merge_with_unknown_tool(self):
'get_tool_cmd.return_value': None
}
launcher = Mock(**launcher_args)
analyser = Mock()

# When
result = merge_with_tool(tool, cfg, args, launcher)
result = merge_with_tool(tool, cfg, args, launcher, analyser)

# Then
self.assertEqual(result, ERROR_UNKNOWN)
Expand All @@ -112,9 +116,10 @@ def test_merge_with_tool_success(self):
'invoke.return_value': 0
}
launcher = Mock(**launcher_args)
analyser = Mock()

# When
result = merge_with_tool(tool, cfg, args, launcher)
result = merge_with_tool(tool, cfg, args, launcher, analyser)

# Then
self.assertEqual(result, SUCCESSFUL_MERGE)
Expand All @@ -136,15 +141,16 @@ def test_merge_with_tool_remaining_conflicts(self):
'invoke.return_value': 6
}
launcher = Mock(**launcher_args)
analyser = Mock()

# When
result = merge_with_tool(tool, cfg, args, launcher)
result = merge_with_tool(tool, cfg, args, launcher, analyser)

# Then
self.assertEqual(result, ERROR_CONFLICTS)
launcher.invoke.assert_called_with('MY_CMD ' + args.merged)

def test_merge_with_tool_untrusted(self):
def test_merge_with_tool_untrusted_solved(self):
# Given
tool = FAKE_TOOL
cfg = configparser.ConfigParser()
Expand All @@ -159,12 +165,39 @@ def test_merge_with_tool_untrusted(self):
'invoke.return_value': 0
}
launcher = Mock(**launcher_args)
analyser_args = {'has_remaining_conflicts.return_value': False}
analyser = Mock(**analyser_args)

# When
result = merge_with_tool(tool, cfg, args, launcher)
result = merge_with_tool(tool, cfg, args, launcher, analyser)

# Then
self.assertEqual(result, ERROR_UNTRUSTED)
self.assertEqual(result, SUCCESSFUL_MERGE)
launcher.invoke.assert_called_with('MY_CMD ' + args.merged)

def test_merge_with_tool_untrusted_unsolved(self):
# Given
tool = FAKE_TOOL
cfg = configparser.ConfigParser()
cfg.add_section(SECT_AMT)
cfg.set(SECT_AMT, OPT_VERBOSE, 'true')
args = create_args()
launcher_args = {
'get_tool_trust.return_value': False,
'get_tool_extensions.return_value': None,
'get_tool_ignored_extensions.return_value': None,
'get_tool_cmd.return_value': 'MY_CMD $MERGED',
'invoke.return_value': 0
}
launcher = Mock(**launcher_args)
analyser_args = {'has_remaining_conflicts.return_value': True}
analyser = Mock(**analyser_args)

# When
result = merge_with_tool(tool, cfg, args, launcher, analyser)

# Then
self.assertEqual(result, ERROR_CONFLICTS)
launcher.invoke.assert_called_with('MY_CMD ' + args.merged)

def test_merge_with_tools_all_fail(self):
Expand All @@ -182,9 +215,10 @@ def test_merge_with_tools_all_fail(self):
'invoke.return_value': 1
}
launcher = Mock(**launcher_args)
analyser = Mock()

# When
result = merge(cfg, args, launcher)
result = merge(cfg, args, launcher, analyser)

# Then
self.assertEqual(result, ERROR_CONFLICTS)
Expand All @@ -209,9 +243,10 @@ def test_merge_with_tools_first_succeeds(self):
'invoke.return_value': 0
}
launcher = Mock(**launcher_args)
analyser = Mock()

# When
result = merge(cfg, args, launcher)
result = merge(cfg, args, launcher, analyser)

# Then
self.assertEqual(result, SUCCESSFUL_MERGE)
Expand All @@ -224,9 +259,10 @@ def test_merge_with_tools_empty(self):
cfg.set(SECT_AMT, OPT_TOOLS, '')
args = create_args()
launcher = Mock()
analyser = Mock()

# When
result = merge(cfg, args, launcher)
result = merge(cfg, args, launcher, analyser)

# Then
self.assertEqual(result, ERROR_NO_TOOL)
Expand All @@ -238,10 +274,11 @@ def test_merge_not_configured(self):
cfg.set(SECT_AMT, OPT_VERBOSE, 'true')
args = create_args()
launcher = Mock(side_effect=lambda cmd: 1)
analyser = Mock()

# When
with self.assertRaises(RuntimeError):
merge(cfg, args, launcher)
merge(cfg, args, launcher, analyser)

# Then
launcher.assert_not_called()
Expand Down
48 changes: 48 additions & 0 deletions _amtanalyser_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

import configparser
import unittest

from amtanalyser import *

CFA_PATH = 'tests/unit/analyser/{0}.txt'


class ConflictedFileAnalyserTest(unittest.TestCase):
def test_file_without_conflicts(self):
# Given
analyser = ConflictedFileAnalyser()
file_path = CFA_PATH.format('no_conflicts')

# When
remaining = analyser.has_remaining_conflicts(file_path)

# Then
self.assertEqual(remaining, False)

def test_file_with_1_conflict(self):
# Given
analyser = ConflictedFileAnalyser()
file_path = CFA_PATH.format('single_conflict')

# When
remaining = analyser.has_remaining_conflicts(file_path)

# Then
self.assertEqual(remaining, True)

def test_file_with_3_conflict(self):
# Given
analyser = ConflictedFileAnalyser()
file_path = CFA_PATH.format('three_conflicts')

# When
remaining = analyser.has_remaining_conflicts(file_path)

# Then
self.assertEqual(remaining, True)


if __name__ == '__main__':
unittest.main()
24 changes: 16 additions & 8 deletions amt.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import configparser

from amtlauncher import *
from amtanalyser import *

# CONSTANTS
GLOBAL_CONFIG = os.path.expanduser('~/.gitconfig')
Expand Down Expand Up @@ -92,7 +93,7 @@ def expand_arguments(cmd, args):
return cmd


def merge_with_tool(tool, config, args, launcher):
def merge_with_tool(tool, config, args, launcher, analyser):
"""
Run the given merge tool with the config and args
"""
Expand Down Expand Up @@ -146,19 +147,26 @@ def merge_with_tool(tool, config, args, launcher):
if invocation_result == 0:
if verbose:
print(" [AMT] ✓ {0} merged successfully".format(tool))
return 0
return SUCCESSFUL_MERGE
else:
if verbose:
print(" [AMT] ✗ {0} didn't solve all conflicts".format(tool))
return ERROR_CONFLICTS
else:
# TODO analyse the merged file and look for conflicts ?
if verbose:
print(" [AMT] ? {0} returned, but this should not be trusted".format(tool))
return ERROR_UNTRUSTED
has_remaining = analyser.has_remaining_conflicts(args.merged)
if has_remaining == 0:
if verbose:
print(" [AMT] ✓ {0} merged successfully".format(tool))
return SUCCESSFUL_MERGE
else:
if verbose:
print(" [AMT] ✗ {0} didn't solve all conflicts".format(tool))
return ERROR_CONFLICTS


def merge(config, args, launcher):
def merge(config, args, launcher, analyser):
"""
Handle the mergetools chain for the given argument
config -- the current amt configuration
Expand All @@ -172,7 +180,7 @@ def merge(config, args, launcher):
merge_result = ERROR_NO_TOOL

for tool in tools:
merge_result = merge_with_tool(tool, config, args, launcher)
merge_result = merge_with_tool(tool, config, args, launcher, analyser)
if merge_result == 0:
return 0

Expand All @@ -190,7 +198,6 @@ def clean_reports(merged):
return
print(" [AMT] * Cleaning up reports")
abs_path = os.path.abspath(merged)
base_name = os.path.basename(merged) + '.'
dir_path = os.path.dirname(abs_path)
for file in os.listdir(dir_path):
if file.startswith(base_name) and file.endswith('-report'):
Expand All @@ -203,7 +210,8 @@ def clean_reports(merged):
local_config = find_local_config(args.merged)
config = read_config(local_config)
launcher = ToolsLauncher(config)
result = merge(config, args, launcher)
analyser = ConflictedFileAnalyser()
result = merge(config, args, launcher, analyser)

if result == 0:
clean_reports(args.merged)
Expand Down
23 changes: 23 additions & 0 deletions amtanalyser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

from amtutils import *


class ConflictedFileAnalyser:
"""
"""

def __init__(self):
pass

def has_remaining_conflicts(self, file):
with open(file, 'r') as f:
for line in f:
if line.startswith(CONFLICT_START) \
or line.startswith(CONFLICT_SEP) \
or line.startswith(CONFLICT_BASE) \
or line.startswith(CONFLICT_END):
return True

return False
4 changes: 2 additions & 2 deletions amtutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def rewrite(self, content):
self.content = content

def is_rewritten(self):
return self.content != None
return self.content is not None

def is_resolved(self):
return self.resolved
Expand Down Expand Up @@ -136,7 +136,7 @@ def has_more_conflicts(self):
sections[section_index] += line
else:
self.merged_file.write(line)
if (eof):
if eof:
return False
else:
self.conflict = Conflict(sections[0], sections[1], sections[2], markers[0], markers[1])
Expand Down
18 changes: 18 additions & 0 deletions tests/unit/analyser/no_conflicts.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus
et magnis dis parturient montes, nascetur ridiculus mus.

Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel,
aliquet nec, vulputate eget, arcu.

In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras
dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus.

Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus.
Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum.

Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus,
tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum.

Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut
libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet
nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc,
26 changes: 26 additions & 0 deletions tests/unit/analyser/single_conflict.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus
et magnis dis parturient montes, nascetur ridiculus mus.

Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel,
aliquet nec, vulputate eget, arcu.

In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras
dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus.

<<<<<<< LOCAL
Nulla purus tortor, ornare at dolor quis, maximus pharetra neque. Pellentesque eget felis et orci rhoncus tempor. Nulla auctor posuere
nisl. Vivamus dignissim a nisl sit amet dapibus.
|||||||
=======
Sed sodales eros non leo iaculis laoreet. Nulla et lobortis massa. Pellentesque sit amet suscipit augue.
>>>>>>> REMOTE

Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus.
Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum.

Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus,
tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum.

Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut
libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet
nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc,

0 comments on commit 623e1c6

Please sign in to comment.