Ejemplo n.º 1
0
    def merge(self, diff_other, diff_local, baseline, upwards):
        # Merge is possible if it does not matter
        # in which order we apply the two deltas
        build_up_ok = True
        try:
            one_way = dictdiffer.patch(diff_other, baseline)
            one_way = dictdiffer.patch(diff_local, one_way, in_place=True)

            other_way = dictdiffer.patch(diff_local, baseline)
            other_way = dictdiffer.patch(diff_other, other_way, in_place=True)
        except Exception as e:
            build_up_ok = False

        if build_up_ok and one_way == other_way:
            #return one_way
            return diff_other
        else:
            #print('merge failed')
            if not upwards:
                #return dictdiffer.patch(diff_other, baseline)
                #print('PROBLEM')
                return list(dictdiffer.diff(self.content,
                                            baseline)) + diff_other
            else:
                #return self.content
                return []
Ejemplo n.º 2
0
def move_to_commited(log_action, *args, **kwargs):
    sl = data.SL()
    item = next((i for i in sl if i.log_action == log_action), None)
    if item:
        resource_obj = resource.load(item.resource)
        commited = CommitedResource.get_or_create(item.resource)
        updated = resource_obj.db_obj.updated
        if item.action == CHANGES.remove.name:

            resource_obj.delete()
            commited.state = resource.RESOURCE_STATE.removed.name
        else:
            resource_obj.set_operational()
            commited.state = resource.RESOURCE_STATE.operational.name
            commited.base_path = item.base_path
            updated = resource_obj.db_obj.updated
            # required to update `updated` field
            resource_obj.db_obj.save()
        commited.inputs = patch(item.diff, commited.inputs)
        # TODO fix TagsWrp to return list
        # commited.tags = resource_obj.tags
        sorted_connections = sorted(commited.connections)
        commited.connections = patch(item.connections_diff, sorted_connections)
        commited.save()
        item.log = 'history'
        item.state = 'success'
        item.updated = updated
        item.save()
Ejemplo n.º 3
0
    def handle_conflict(self, to_save, key, local_doc, conflict_callback):
        last_good = self.last_known_good.get(key, {})
        remote_doc = self.load_specific(key)
        last_rev = remote_doc.pop('_rev')
        with do_not_track(to_save):
            local_doc.pop('_rev', None)

        remote_diff = list(dictdiffer.diff(last_good, remote_doc))
        local_diff = list(dictdiffer.diff(last_good, local_doc))

        one_way = dictdiffer.patch(remote_diff, last_good)
        one_way = dictdiffer.patch(local_diff, one_way)

        other_way = dictdiffer.patch(local_diff, last_good)
        other_way = dictdiffer.patch(remote_diff, other_way)

        eprint(one_way, other_way)

        if one_way == other_way:
            eprint('resolved')
            one_way['_rev'] = last_rev
            self.db.save(one_way)
            with do_not_track(to_save):
                to_save[key] = one_way
        else:
            eprint('no resolve')
            remote_doc['_rev'] = last_rev
            to_save[key] = remote_doc
Ejemplo n.º 4
0
    def test_add_list(self):
        first = {'a': [1]}
        second = {'a': [1, 2]}
        assert second == patch([('add', 'a', [(1, 2)])], first)

        first = {'a': {'b': [1]}}
        second = {'a': {'b': [1, 2]}}
        assert second == patch([('add', 'a.b', [(1, 2)])], first)
Ejemplo n.º 5
0
    def test_changes(self):
        first = {"a": "b"}
        second = {"a": "c"}
        assert second == patch([("change", "a", ("b", "c"))], first)

        first = {"a": {"b": {"c": "d"}}}
        second = {"a": {"b": {"c": "e"}}}
        assert second == patch([("change", "a.b.c", ("d", "e"))], first)
Ejemplo n.º 6
0
 def test_add_value(self):
     original = {'a': 1, 'b': 2}
     modified = {'a': 1, 'b': 2, 'c': 3}
     delta = list(diff(original, modified))
     new = patch(delta, original)
     self.assertEqual(new, modified)
     new = patch(delta, modified)
     self.assertEqual(new, modified)
Ejemplo n.º 7
0
    def test_push(self):
        first = {'a': [1]}
        second = {'a': [1, 2]}
        assert second == patch([('push', 'a', [2])], first)

        first = {'a': {'b': [1]}}
        second = {'a': {'b': [1, 2]}}
        assert second == patch([('push', 'a.b', [2])], first)
Ejemplo n.º 8
0
    def test_addition(self):
        first = {}
        second = {'a': 'b'}
        assert second == patch([('add', '', [('a', 'b')])], first)

        first = {'a': {'b': 'c'}}
        second = {'a': {'b': 'c', 'd': 'e'}}
        assert second == patch([('add', 'a', [('d', 'e')])], first)
Ejemplo n.º 9
0
    def test_addition(self):
        first = {}
        second = {"a": "b"}
        assert second == patch([("add", "", [("a", "b")])], first)

        first = {"a": {"b": "c"}}
        second = {"a": {"b": "c", "d": "e"}}
        assert second == patch([("add", "a", [("d", "e")])], first)
Ejemplo n.º 10
0
    def test_changes(self):
        first = {'a': 'b'}
        second = {'a': 'c'}
        assert second == patch([('change', 'a', ('b', 'c'))], first)

        first = {'a': {'b': {'c': 'd'}}}
        second = {'a': {'b': {'c': 'e'}}}
        assert second == patch([('change', 'a.b.c', ('d', 'e'))], first)
Ejemplo n.º 11
0
    def test_remove(self):
        first = {'a': {'b': 'c'}}
        second = {'a': {}}
        assert second == patch([('remove', 'a', [('b', 'c')])], first)

        first = {'a': 'b'}
        second = {}
        assert second == patch([('remove', '', [('a', 'b')])], first)
Ejemplo n.º 12
0
    def test_remove(self):
        first = {"a": {"b": "c"}}
        second = {"a": {}}
        assert second == patch([("remove", "a", [("b", "c")])], first)

        first = {"a": "b"}
        second = {}
        assert second == patch([("remove", "", [("a", "b")])], first)
Ejemplo n.º 13
0
    def test_add_list(self):
        first = {"a": [1]}
        second = {"a": [1, 2]}
        assert second == patch([("add", "a", [(1, 2)])], first)

        first = {"a": {"b": [1]}}
        second = {"a": {"b": [1, 2]}}
        assert second == patch([("add", "a.b", [(1, 2)])], first)
Ejemplo n.º 14
0
 def test_no_changes(self):
     original = {'a': 1, 'b': 2}
     modified = {'a': 1, 'b': 2}
     delta = list(diff(original, modified))
     new = patch(delta, original)
     self.assertEqual(new, modified)
     new = patch(delta, modified)
     self.assertEqual(new, modified)
Ejemplo n.º 15
0
    def test_remove_value(self):
        original = {'a': 1, 'b': 2, 'c': 3}
        modified = {'a': 1, 'b': 2}
        delta = list(diff(original, modified))
        new = patch(delta, original)
        self.assertEqual(new, modified)

        with self.assertRaises(KeyError) as cm:
            patch(delta, modified)
        self.assertEqual(cm.exception.args[0], 'c')
Ejemplo n.º 16
0
    def test_addition(self):
        first = {}
        second = {'a': 'b'}
        assert second == patch(
            [('add', '', [('a', 'b')])], first)

        first = {'a': {'b': 'c'}}
        second = {'a': {'b': 'c', 'd': 'e'}}
        assert second == patch(
            [('add', 'a', [('d', 'e')])], first)
Ejemplo n.º 17
0
 def redo(self):
     if self.active == 0:
         return self.active
     self.active -= 1
     delta = self[self.active]
     with self.handler.root:
         self.handler.track = False
         dictdiffer.patch(delta, self.handler.root, in_place=True)
         self.handler.track = True
     return self.active
Ejemplo n.º 18
0
    def test_changes(self):
        first = {'a': 'b'}
        second = {'a': 'c'}
        assert second == patch(
            [('change', 'a', ('b', 'c'))], first)

        first = {'a': {'b': {'c': 'd'}}}
        second = {'a': {'b': {'c': 'e'}}}
        assert second == patch(
            [('change', 'a.b.c', ('d', 'e'))], first)
Ejemplo n.º 19
0
    def test_push(self):
        first = {'a': [1]}
        second = {'a': [1, 2]}
        assert second == patch(
            [('push', 'a', [2])], first)

        first = {'a': {'b': [1]}}
        second = {'a': {'b': [1, 2]}}
        assert second == patch(
            [('push', 'a.b', [2])], first)
Ejemplo n.º 20
0
    def test_add_list(self):
        first = {'a': [1]}
        second = {'a': [1, 2]}
        assert second == patch(
            [('add', 'a', [(1, 2)])], first)

        first = {'a': {'b': [1]}}
        second = {'a': {'b': [1, 2]}}
        assert second == patch(
            [('add', 'a.b', [(1, 2)])], first)
Ejemplo n.º 21
0
    def test_remove(self):
        first = {'a': {'b': 'c'}}
        second = {'a': {}}
        assert second == patch(
            [('remove', 'a', [('b', 'c')])], first)

        first = {'a': 'b'}
        second = {}
        assert second == patch(
            [('remove', '', [('a', 'b')])], first)
Ejemplo n.º 22
0
 def test_in_place_patch_and_revert(self):
     first = {'a': 1}
     second = {'a': 2}
     changes = list(diff(first, second))
     patched_copy = patch(changes, first)
     assert first != patched_copy
     reverted_in_place = revert(changes, patched_copy, in_place=True)
     assert first == reverted_in_place
     assert patched_copy == reverted_in_place
     patched_in_place = patch(changes, first, in_place=True)
     assert first == patched_in_place
Ejemplo n.º 23
0
 def test_in_place_patch_and_revert(self):
     first = {'a': 1}
     second = {'a': 2}
     changes = list(diff(first, second))
     patched_copy = patch(changes, first)
     assert first != patched_copy
     reverted_in_place = revert(changes, patched_copy, in_place=True)
     assert first == reverted_in_place
     assert patched_copy == reverted_in_place
     patched_in_place = patch(changes, first, in_place=True)
     assert first == patched_in_place
Ejemplo n.º 24
0
    def test_change_list(self):
        first = {"a": ["b"]}
        second = {"a": ["c"]}
        assert second == patch([("change", "a.0", ("b", "c"))], first)

        first = {"a": {"b": {"c": ["d"]}}}
        second = {"a": {"b": {"c": ["e"]}}}
        assert second == patch([("change", "a.b.c.0", ("d", "e"))], first)

        first = {"a": {"b": {"c": [{"d": "e"}]}}}
        second = {"a": {"b": {"c": [{"d": "f"}]}}}
        assert second == patch([("change", "a.b.c.0.d", ("e", "f"))], first)
Ejemplo n.º 25
0
    def test_change_list(self):
        first = {'a': ['b']}
        second = {'a': ['c']}
        assert second == patch([('change', 'a.0', ('b', 'c'))], first)

        first = {'a': {'b': {'c': ['d']}}}
        second = {'a': {'b': {'c': ['e']}}}
        assert second == patch([('change', 'a.b.c.0', ('d', 'e'))], first)

        first = {'a': {'b': {'c': [{'d': 'e'}]}}}
        second = {'a': {'b': {'c': [{'d': 'f'}]}}}
        assert second == patch([('change', 'a.b.c.0.d', ('e', 'f'))], first)
Ejemplo n.º 26
0
    def test_change_list(self):
        first = {'a': ['b']}
        second = {'a': ['c']}
        assert second == patch(
            [('change', 'a.0', ('b', 'c'))], first)

        first = {'a': {'b': {'c': ['d']}}}
        second = {'a': {'b': {'c': ['e']}}}
        assert second == patch(
            [('change', 'a.b.c.0', ('d', 'e'))], first)

        first = {'a': {'b': {'c': [{'d': 'e'}]}}}
        second = {'a': {'b': {'c': [{'d': 'f'}]}}}
        assert second == patch(
            [('change', 'a.b.c.0.d', ('e', 'f'))], first)
Ejemplo n.º 27
0
def main():
	base_path = os.environ.get('BASE')
	local_path = os.environ.get('LOCAL')
	remote_path = os.environ.get('REMOTE')
	merged_path = os.environ.get('MERGED')
	
	print('BASE: %s' % (base_path,))
	print('LOCAL: %s' % (local_path,))
	print('REMOTE: %s' % (remote_path,))
	print('MERGED: %s' % (merged_path,))
	print()

	# Ensure paths have been provided
	for path in (base_path, local_path, remote_path, merged_path):
		if path is None:
			print('Missing path for base, local, remote or merged')
			sys.exit(1)
			return

	# Ensure source paths exist
	for path in (base_path, local_path, remote_path):
		if not os.path.exists(path):
			print('File doesn\'t exist at: %s' % (path,))
			sys.exit(1)
			return

	# Parse items
	base, _ = read(base_path)
	local, unix = read(local_path)
	remote, _ = read(remote_path)

	# Find changes between base and remote
	print('Finding change(s)...')
	
	changes = list(resolve(base, local, remote))

	# Apply changes to local
	print('Applying %d change(s)...' % (len(changes),))

	patch(changes, local, in_place=True)

	# Write result to file
	print('Writing result (unix: %r)...' % (unix,))

	write(
		merged_path, local,
		unix=unix
	)
Ejemplo n.º 28
0
def _compute_merge_results(refenv, ancestorHEAD, masterHEAD, devHEAD):
    '''Compute the diff of a 3-way merge and patch historical contents to get new state

    .. warning::

        This method is not robust, and will require a require in the future.

    Parameters
    ----------
    refenv : lmdb.Environment
        db where the commit records are stored
    ancestorHEAD : str
        commit hash of the common ancestor of dev and master merge branch
    masterHEAD : str
        commit hash of the merge master branch head
    devHEAD : str
        commit hash of the merge dev branch head

    Returns
    -------
    dict
        nested dict specifying datasets and metadata record specs of the new
        merge commit.
    '''
    a_contents = commiting.get_commit_ref_contents(refenv, ancestorHEAD)
    m_contents = commiting.get_commit_ref_contents(refenv, masterHEAD)
    d_contents = commiting.get_commit_ref_contents(refenv, devHEAD)

    ancestorToDevDiff = dictdiffer.diff(a_contents, d_contents)
    patchedMergeContents = dictdiffer.patch(ancestorToDevDiff, m_contents)
    return patchedMergeContents
Ejemplo n.º 29
0
    def send_update(self, receiver_id, upwards):
        #global debugging

        #self.to_file('start send_update')
        #with self.lock:
        state = self.get_state_for(receiver_id)
        #(baseline,
        #edits
        #) = self.get_values_for(receiver_id)

        if debugging:
            print(self.conduit.node_id[:8], '->', receiver_id[:8])
        #1
        #previous_version = int(edits[-1][0].split('-')[0])
        add_to_baseline = Sync.collapse_edits(state.edits)

        previous_value = dictdiffer.patch(add_to_baseline, state.baseline)
        with self.content:
            latest_edit = list(dictdiffer.diff(previous_value, self.content))
        latest_checksum = Sync.generate_checksum(self.content)
        #edits.append((str(previous_version+1)+'-'+str(latest_checksum), latest_edit))
        if len(latest_edit) > 0:
            state.edits.append((latest_checksum, latest_edit))

        if debugging:
            print('edits out', state.edits)

        #2
        message = {
            'upwards': upwards,
            'edits': copy.deepcopy(state.edits),
        }

        self.conduit.send_to(receiver_id, message)
Ejemplo n.º 30
0
def main(argv):
    parser = OptionParser(
        usage="usage clitool.py %prog -i file -o file.config...",
        description="""Make cli file to cmdconfig file , read example file
        """
    )
    parser.add_option("-i", "--input", dest="input_file", help="Input cli file", metavar="FILE")
    parser.add_option("-o", "--output", dest="output_file", help="Output file")
    
    (options, args) = parser.parse_args(argv)

    cli_line = load_file(options.input_file)
    root = cli_line[0].split()[0]
    out_file = clean_file(root, options.output_file)
    conf = Shconfig.config(name="", conffile=out_file)
    print conf
    if conf is None:
        print "output file is not correct format"
        return
    d = conf.dict
    main_dict = {root: {}}
    for cli in cli_line:
        cmd = cli.split()
        res = list_to_deep_dict(cmd)
        result = diff(main_dict, res, nodel=True)
        patched = patch(result, main_dict, set_remove=False)
        main_dict = patched
    print json.dumps(main_dict, indent=2)
    cof = conf.dict
    print cof
    cof[root] = main_dict[root]
    print cof
    print conf.save()
Ejemplo n.º 31
0
def main():
    first = {
        "title": "hello",
        "fork_count": 20,
        "stargazers": ["/users/20", "/users/30"],
        "settings": {
            "assignees": [100, 101, 201],
        }
    }

    second = {
        "title": "hellooo",
        "fork_count": 20,
        "stargazers": ["/users/20", "/users/30", "/users/40"],
        "settings": {
            "assignees": [100, 101, 202],
        }
    }

    # Calculate the diff
    result = diff(first, second)   # Return generator (yield)
    print(json.dumps(list(result))) 

    # Apply the diff like a patch
    patched = patch(result, first)
    print(json.dumps(patched))
    print(json.dumps(second))
Ejemplo n.º 32
0
    def _merge_dirs(self, ancestor_info, our_info, their_info):
        from operator import itemgetter

        from dictdiffer import patch

        ancestor = self._to_dict(ancestor_info)
        our = self._to_dict(our_info)
        their = self._to_dict(their_info)

        our_diff = self._diff(ancestor, our)
        if not our_diff:
            return self._from_dict(their)

        their_diff = self._diff(ancestor, their)
        if not their_diff:
            return self._from_dict(our)

        # make sure there are no conflicting files
        self._diff(our, their, allow_removed=True)

        merged = patch(our_diff + their_diff, ancestor, in_place=True)

        # Sorting the list by path to ensure reproducibility
        return sorted(self._from_dict(merged),
                      key=itemgetter(self.tree.PARAM_RELPATH))
Ejemplo n.º 33
0
def build_document_action_chain(action_cls: Type[BaseDocumentAction],
                                left_schema: Schema,
                                right_schema: Schema,
                                document_types: Iterable[str]) -> Iterable[BaseAction]:
    """
    Walk through schema changes, and produce chain of Action objects
    of given type which could handle schema changes from left to right
    :param action_cls: Action type to consider
    :param left_schema:
    :param right_schema:
    :param document_types: list of document types to inspect
    :return: iterable of suitable Action objects
    """
    for document_type in document_types:
        action_obj = action_cls.build_object(document_type, left_schema, right_schema)
        if action_obj is not None:
            try:
                left_schema = patch(action_obj.to_schema_patch(left_schema), left_schema)
            except (TypeError, ValueError, KeyError) as e:
                raise ActionError(
                    f"Unable to apply schema patch of {action_obj!r}. More likely that the "
                    f"schema is corrupted. You can use schema repair tools to fix this issue"
                ) from e

            yield action_obj
Ejemplo n.º 34
0
    def test_continue_run_multiple_conflicts_per_patch(self):
        lca = {'foo': [{'x': 1}, {'y': 2}]}
        first = {'foo': [{'x': 1}, {'y': 2}, {'z': 4}]}
        second = {'bar': 'baz'}

        expected = {
            'f': {
                'foo': [{
                    'x': 1
                }, {
                    'y': 2
                }, {
                    'z': 4
                }],
                'bar': 'baz'
            },
            's': {
                'bar': 'baz'
            }
        }

        for resolution, expected_value in expected.items():
            m = Merger(lca, first, second, {})
            try:
                m.run()
            except UnresolvedConflictsException as e:
                m.continue_run([resolution for _ in e.content])

            self.assertEqual(patch(m.unified_patches, lca), expected_value)
Ejemplo n.º 35
0
    def makemigrations(self):
        """
        Compare current mongoengine documents state and the last db
        state and make a migration file if needed
        """
        log.debug('Loading migration files...')
        graph = self.build_graph()
        log.debug('Loading schema from database...')
        db_schema = self.load_db_schema()

        # Obtain schema changes which migrations would make (including
        #  unapplied ones)
        # If mongoengine models schema was changed regarding db schema
        #  then try to guess which actions would reflect such changes
        for migration in graph.walk_down(graph.initial, unapplied_only=False):
            for action_object in migration.get_actions():
                try:
                    db_schema = patch(action_object.to_schema_patch(db_schema),
                                      db_schema)
                except (TypeError, ValueError, KeyError) as e:
                    raise ActionError(
                        f"Unable to apply schema patch of {action_object!r}. More likely that the "
                        f"schema is corrupted. You can use schema repair tools to fix this issue"
                    ) from e

        log.debug('Collecting schema from mongoengine documents...')
        models_schema = collect_models_schema()
        if db_schema == models_schema:
            log.info('No changes detected')
            return

        log.debug('Building actions chain...')
        actions_chain = build_actions_chain(db_schema, models_schema)

        import_expressions = {'from mongoengine_migrate.actions import *'}
        for action in actions_chain:
            # If `regex` is set in action, then we probably need 're'
            if isinstance(action.parameters.get('regex'), re.Pattern):
                import_expressions.add('import re')
                break

        log.debug('Writing migrations file...')
        env = Environment()
        env.filters['symbol_wrap'] = symbol_wrap
        tpl_ctx = {
            'graph': graph,
            'actions_chain': actions_chain,
            'policy_enum': MigrationPolicy,
            'import_expressions': import_expressions
        }
        tpl_path = Path(__file__).parent / 'migration_template.tpl'
        tpl = env.from_string(tpl_path.read_text())
        migration_source = tpl.render(tpl_ctx)

        seq_number = str(len(graph.migrations)).zfill(4)
        name = f'{seq_number}_auto_{datetime.now().strftime("%Y%m%d_%H%M")}.py'
        migration_file = Path(self.migration_dir) / name
        migration_file.write_text(migration_source)

        log.info('Migration file "%s" was created', migration_file)
Ejemplo n.º 36
0
def patch_dict(original_dict: dict, patch_dictionary: dict) -> dict:
    """Patches a dict with another. Patching means that any path defines in the
    patch is either added (if it does not exist), or replaces the existing value (if
    it exists). Nothing is removed from the original dict, only added/replaced.

    Parameters
    ----------
    original_dict : dict
        Base dictionary which will get paths added/changed
    patch_dictionary: dict
        Dictionary which will be overlaid on top of original_dict

    Examples
    --------
    >>> patch_dict({"highKey":{"lowkey1":1, "lowkey2":2}}, {"highKey":{"lowkey1":10}})
    {'highKey': {'lowkey1': 10, 'lowkey2': 2}}
    >>> patch_dict({"highKey":{"lowkey1":1, "lowkey2":2}}, {"highKey":{"lowkey3":3}})
    {'highKey': {'lowkey1': 1, 'lowkey2': 2, 'lowkey3': 3}}
    >>> patch_dict({"highKey":{"lowkey1":1, "lowkey2":2}}, {"highKey2":4})
    {'highKey': {'lowkey1': 1, 'lowkey2': 2}, 'highKey2': 4}

    Returns
    -------
    dict
        A new dictionary which is the result of overlaying `patch_dictionary` on top of
        `original_dict`

    """
    diff = dictdiffer.diff(original_dict, patch_dictionary)
    adds_and_mods = [(f, d, s) for (f, d, s) in diff if f != "remove"]
    return dictdiffer.patch(adds_and_mods, original_dict)
Ejemplo n.º 37
0
def build_actions_chain(left_schema: Schema,
                        right_schema: Schema) -> Iterable[BaseAction]:
    """
    Build full Action objects chain which suitable for such schema
    change.
    :param left_schema: current schema
    :param right_schema: schema collected from mongoengine models
    :return: iterable of Action objects
    """
    action_chain = []

    # Actions registry sorted by priority
    registry = list(sorted(actions_registry.values(),
                           key=lambda x: x.priority))

    left_schema = copy(left_schema)
    document_types = get_all_document_types(left_schema, right_schema)
    for action_cls in registry:
        if issubclass(action_cls, BaseDocumentAction):
            new_actions = list(
                build_document_action_chain(action_cls, left_schema,
                                            right_schema, document_types))
        elif issubclass(action_cls, BaseFieldAction):
            new_actions = list(
                build_field_action_chain(action_cls, left_schema, right_schema,
                                         document_types))
        elif issubclass(action_cls, BaseIndexAction):
            new_actions = list(
                build_index_action_chain(action_cls, left_schema, right_schema,
                                         document_types))
        else:
            continue

        for action in new_actions:
            log.debug('> %s', action)
            try:
                left_schema = patch(action.to_schema_patch(left_schema),
                                    left_schema)
            except (TypeError, ValueError, KeyError) as e:
                raise ActionError(
                    f"Unable to apply schema patch of {action!r}. More likely that the "
                    f"schema is corrupted. You can use schema repair tools to fix this issue"
                ) from e
        action_chain.extend(new_actions)
        document_types = get_all_document_types(left_schema, right_schema)

    if right_schema != left_schema:
        log.error(
            'Schema is still not reached the target state after applying all actions. '
            'Changes left to make (diff): %s',
            list(diff(left_schema, right_schema)))
        raise ActionError(
            'Could not reach target schema state after applying whole Action chain. '
            'This could be a problem in some Action which does not process schema '
            'properly or produces wrong schema diff. This is a programming error'
        )

    return action_chain
Ejemplo n.º 38
0
 def test_revert(self):
     first = {'a': [1, 2]}
     second = {'a': []}
     diffed = diff(first, second)
     patched = patch(diffed, first)
     assert patched == second
     diffed = diff(first, second)
     reverted = revert(diffed, second)
     assert reverted == first
Ejemplo n.º 39
0
 def test_revert(self):
     first = {'a': 'b'}
     second = {'a': 'c'}
     diffed = diff(first, second)
     patched = patch(diffed, first)
     assert patched == second
     diffed = diff(first, second)
     reverted = revert(diffed, second)
     assert reverted == first
Ejemplo n.º 40
0
 def test_revert(self):
     first = {"a": [1, 2]}
     second = {"a": []}
     diffed = diff(first, second)
     patched = patch(diffed, first)
     assert patched == second
     diffed = diff(first, second)
     reverted = revert(diffed, second)
     assert reverted == first
Ejemplo n.º 41
0
def commit_log_item(item):
    resource_obj = resource.load(item.resource)
    commited = CommitedResource.get_or_create(item.resource)
    if item.action == CHANGES.remove.name:
        resource_obj.delete()
        commited.state = resource.RESOURCE_STATE.removed.name
    else:
        resource_obj.set_operational()
        commited.state = resource.RESOURCE_STATE.operational.name
        commited.base_path = item.base_path
        resource_obj.db_obj.save_lazy()
    commited.inputs = patch(item.diff, commited.inputs)
    # TODO fix TagsWrp to return list
    # commited.tags = resource_obj.tags
    sorted_connections = sorted(commited.connections)
    commited.connections = patch(item.connections_diff, sorted_connections)
    commited.save_lazy()
    item.to_history().save_lazy()
    item.delete()
Ejemplo n.º 42
0
def merge_changes(deposition, dest, a, b):
    """Find changes between two dicts and apply them to a destination dict.

    This method is useful when A is a subset of the destination dictionary.
    """
    # Generate patch
    patch = dictdiffer.diff(a, b)

    # Apply patch (returns a deep copy of dest with patch applied)
    return dictdiffer.patch(patch, dest)
Ejemplo n.º 43
0
def move_to_commited(log_action, *args, **kwargs):
    sl = data.SL()
    item = next((i for i in sl if i.log_action == log_action), None)
    sl.pop(item.uid)
    if item:
        commited = data.CD()
        staged_data = patch(item.diff, commited.get(item.res, {}))
        cl = data.CL()
        item.state = data.STATES.success
        cl.append(item)
        commited[item.res] = staged_data
Ejemplo n.º 44
0
def revert(diff_result, destination):
    """
    A helper function that calles swap function to revert
    patched dictionary object.

        >>> first = {'a': 'b'}
        >>> second = {'a': 'c'}
        >>> revert(diff(first, second), second)
        {'a': 'b'}

    """
    return patch(swap(diff_result), destination)
Ejemplo n.º 45
0
    def _merge_dicts(self):
        self._backup_lists()

        non_list_merger = Merger(self.root, self.head, self.update, {})
        try:
            non_list_merger.run()
        except UnresolvedConflictsException as e:
            self._solve_dict_conflicts(non_list_merger, e.content)

        self._restore_lists()
        self.merged_root = patch(
            dedupe_list(non_list_merger.unified_patches),
            self.root
        )
Ejemplo n.º 46
0
def move_to_commited(log_action, *args, **kwargs):
    sl = data.SL()
    item = next((i for i in sl if i.log_action == log_action), None)
    if item:
        sl.pop(item.uid)
        resource_obj = resource.load(item.res)
        commited = orm.DBCommitedState.get_or_create(item.res)

        if item.action == CHANGES.remove.name:
            resource_obj.delete()
            commited.state = resource.RESOURCE_STATE.removed.name
        else:
            resource_obj.set_operational()
            commited.state = resource.RESOURCE_STATE.operational.name
            commited.inputs = patch(item.diff, commited.inputs)
            commited.tags = resource_obj.tags
            sorted_connections = sorted(commited.connections)
            commited.connections = patch(item.signals_diff, sorted_connections)
            commited.base_path = item.base_path

        commited.save()
        cl = data.CL()
        item.state = data.STATES.success
        cl.append(item)
Ejemplo n.º 47
0
 def merge_with_published(self):
     """Merge changes with latest published version."""
     pid, first = self.fetch_published()
     lca = first.revisions[self['_deposit']['pid']['revision_id']]
     # ignore _deposit and $schema field
     args = [lca.dumps(), first.dumps(), self.dumps()]
     for arg in args:
         del arg['$schema'], arg['_deposit']
     args.append({})
     m = Merger(*args)
     try:
         m.run()
     except UnresolvedConflictsException:
         raise MergeConflict()
     return patch(m.unified_patches, lca)
Ejemplo n.º 48
0
    def test_continue_run_multiple_conflicts_per_patch(self):
        lca = {'foo': [{'x': 1}, {'y': 2}]}
        first = {'foo': [{'x': 1}, {'y': 2}, {'z': 4}]}
        second = {'bar': 'baz'}

        expected = {
            'f': {'foo': [{'x': 1}, {'y': 2}, {'z': 4}],
                  'bar': 'baz'},
            's': {'bar': 'baz'}}

        for resolution, expected_value in expected.items():
            m = Merger(lca, first, second, {})
            try:
                m.run()
            except UnresolvedConflictsException as e:
                m.continue_run([resolution for _ in e.content])

            self.assertEqual(patch(m.unified_patches, lca),
                             expected_value)
Ejemplo n.º 49
0
 def test_dict_int_key(self):
     first = {0: 0}
     second = {0: 'a'}
     first_patch = [('change', [0], (0, 'a'))]
     assert second == patch(first_patch, first)
Ejemplo n.º 50
0
 def test_pull(self):
     first = {'a': [1, 2, 3]}
     second = {'a': [1, 2]}
     assert second == patch(
         [('pull', 'a', [3])], first)
Ejemplo n.º 51
0
 def test_remove_list(self):
     first = {'a': [1, 2, 3]}
     second = {'a': [1, ]}
     assert second == patch(
         [('remove', 'a', [(2, 3), (1, 2), ]), ], first)
Ejemplo n.º 52
0
    def _update(obj, eng):
        import dictdiffer

        from lxml import objectify, etree

        from invenio.base.globals import cfg
        from invenio_workflows.utils import convert_marcxml_to_bibfield
        from invenio_records.api import Record

        from inspire.utils.robotupload import make_robotupload_marcxml

        try:
            recid = obj.extra_data["recid"]
        except KeyError:
            obj.log.error("Cannot locate record ID")
            return

        callback_url = os.path.join(cfg["CFG_SITE_URL"],
                                    "callback/workflows/continue")

        search_url = "%s?p=recid:%s&of=xm" % (cfg["WORKFLOWS_MATCH_REMOTE_SERVER_URL"], recid)

        prod_data = objectify.parse(search_url)
        # remove controlfields
        root = prod_data.getroot()
        record = root['record']
        while True:
            try:
                record.remove(record['controlfield'])
            except AttributeError:
                break
        prod_data = etree.tostring(record)
        prod_data = convert_marcxml_to_bibfield(prod_data, model=["hep"])
        new_data = dict(obj.data.dumps(clean=True))
        prod_data = dict(prod_data.dumps(clean=True))
        updated_keys = []
        diff = dictdiffer.diff(prod_data, new_data)
        for diff_type, new_key, content in diff:
            if diff_type == 'add':
                if new_key:
                    if isinstance(new_key, list):
                        # ['subject_terms', 0]
                        updated_keys.append(new_key[0])
                    else:
                        # 'subject_terms'
                        updated_keys.append(new_key)
                else:
                    # content must be list of new adds
                    for key in content:
                        updated_keys.append(key)

        updates = dictdiffer.patch(diff, new_data)
        for key in updates.keys():
            if key not in updated_keys:
                del updates[key]
        if updates:
            updates['recid'] = recid
            marcxml = Record(updates).legacy_export_as_marc()
            result = make_robotupload_marcxml(
                url=url,
                marcxml=marcxml,
                callback_url=callback_url,
                mode='correct',
                nonce=obj.id
            )
            if "[INFO]" not in result.text:
                if "cannot use the service" in result.text:
                    # IP not in the list
                    obj.log.error("Your IP is not in "
                                  "CFG_BATCHUPLOADER_WEB_ROBOT_RIGHTS "
                                  "on host")
                    obj.log.error(result.text)
                from invenio_workflows.errors import WorkflowError
                txt = "Error while submitting robotupload: {0}".format(result.text)
                raise WorkflowError(txt, eng.uuid, obj.id)
            else:
                obj.log.info("Robotupload sent!")
                obj.log.info(result.text)
                eng.halt("Waiting for robotupload: {0}".format(result.text))
            obj.log.info("end of upload")
        else:
            obj.log.info("No updates to do.")
Ejemplo n.º 53
0
 def test_remove_set(self):
     first = {'a': set([1, 2, 3])}
     second = {'a': set([1])}
     assert second == patch(
         [('remove', 'a', [(0, set([2, 3]))])], first)
Ejemplo n.º 54
0
 def test_add_set(self):
     first = {'a': set([1])}
     second = {'a': set([1, 2])}
     assert second == patch(
         [('add', 'a', [(0, set([2]))])], first)
Ejemplo n.º 55
0
 def test_dict_combined_key_type(self):
     first = {0: {'1': {2: 3}}}
     second = {0: {'1': {2: '3'}}}
     first_patch = [('change', [0, '1', 2], (3, '3'))]
     assert second == patch(first_patch, first)
     assert first_patch[0] == list(diff(first, second))[0]
Ejemplo n.º 56
0
def test_verify_patch_creates_expected(staged, diff_for_update, commited):
    expected = patch(diff_for_update, commited)
    assert expected == staged