collaboration.merge module

binaryninja.collaboration.merge.ConflictFormatter([...])

Helper class that turns json conflicts into pretty text for the ui to render

binaryninja.collaboration.merge.ConflictHandler([...])

Helper class that resolves conflicts

binaryninja.collaboration.merge.ConflictSplitter([...])

Helper class that takes one merge conflict and splits it into multiple conflicts Eg takes conflicts for View/symbols and splits to one conflict per symbol

binaryninja.collaboration.merge.CoreConflictFormatter([...])

FFI wrapper for conflict formatters

binaryninja.collaboration.merge.CoreConflictSplitter([...])

FFI wrapper for core-constructed splitters

binaryninja.collaboration.merge.FormattedConflict([...])

Class taking a merge conflict and producing a formatted text output.

binaryninja.collaboration.merge.FormatterList()

Mutable list of formatters for FFI purposes

binaryninja.collaboration.merge.MergeConflict(handle)

Structure representing an individual merge conflict

binaryninja.collaboration.merge.SplitterList()

Mutable list of splitters for FFI purposes

class ConflictFormatter(handle=None)[source]

Bases: object

Helper class that turns json conflicts into pretty text for the ui to render

abstract can_format(key: str, conflict: MergeConflict) bool[source]

Test if the formatter can format a specific conflict

Parameters:
  • key (str) – Unique key for the conflict

  • conflict (MergeConflict) – Conflict structure

Returns:

True if the formatter should try to format this conflict

Return type:

bool

abstract format(key: str, conflict: MergeConflict) FormattedConflict | None[source]

Format a conflict into a human-readable string

Parameters:
  • key (str) – Unique key for the conflict

  • conflict (MergeConflict) – Conflict structure

Returns:

Formatted conflict structure, if it could be formatted. None otherwise.

Return type:

FormattedConflict | None

get_name() str[source]

Get a friendly name for the formatter

Returns:

Name of the formatter

Return type:

str

property name

Get a friendly name for the formatter

Returns:

Name of the formatter

class ConflictHandler(handle=None)[source]

Bases: object

Helper class that resolves conflicts

abstract handle(conflicts: Dict[str, MergeConflict]) bool[source]

Handle any merge conflicts by calling their success() function with a merged value

Parameters:

conflicts (Dict[str, MergeConflict]) – Map of conflict id to conflict structure

Returns:

True if all conflicts were successfully merged

Return type:

bool

class ConflictSplitter(handle=None)[source]

Bases: object

Helper class that takes one merge conflict and splits it into multiple conflicts Eg takes conflicts for View/symbols and splits to one conflict per symbol

abstract can_split(key: str, conflict: MergeConflict) bool[source]

Test if the splitter applies to a given conflict (by key).

Parameters:
  • key (str) – Key of the conflicting field

  • conflict (MergeConflict) – Conflict data

Returns:

True if this splitter should be used on the conflict

Return type:

bool

get_name() str[source]

Get a friendly name for the splitter

Returns:

Name of the splitter

Return type:

str

abstract split(key: str, conflict: MergeConflict, result: KeyValueStore) Dict[str, MergeConflict] | None[source]

Split a field conflict into any number of alternate conflicts. Note: Returned conflicts will also be checked for splitting, beware infinite loops! If this function raises, it will be treated as returning None

Parameters:
  • key (str) – Original conflicting field’s key

  • conflict (MergeConflict) – Original conflict data

  • result (KeyValueStore) – Kvs structure containing the result of all splits. You should use the original conflict’s success() function in most cases unless you specifically want to write a new key to this.

Returns:

A collection of conflicts into which the original conflict was split, or None if this splitter cannot handle the conflict

Return type:

Dict[str, MergeConflict] | None

property name

Get a friendly name for the splitter

Returns:

Name of the splitter

class CoreConflictFormatter(handle=None)[source]

Bases: ConflictFormatter

FFI wrapper for conflict formatters

can_format(key: str, conflict: MergeConflict) bool[source]

Test if the formatter can format a specific conflict

Parameters:
  • key (str) – Unique key for the conflict

  • conflict (MergeConflict) – Conflict structure

Returns:

True if the formatter should try to format this conflict

Return type:

bool

format(key: str, conflict: MergeConflict) FormattedConflict | None[source]

Format a conflict into a human-readable string

Parameters:
  • key (str) – Unique key for the conflict

  • conflict (MergeConflict) – Conflict structure

Returns:

Formatted conflict structure, if it could be formatted. None otherwise.

Return type:

FormattedConflict | None

get_name() str[source]

Get a friendly name for the formatter

Returns:

Name of the formatter

Return type:

str

class CoreConflictSplitter(handle=None)[source]

Bases: ConflictSplitter

FFI wrapper for core-constructed splitters

can_split(key: str, conflict: MergeConflict) bool[source]

Test if the splitter applies to a given conflict (by key).

Parameters:
  • key (str) – Key of the conflicting field

  • conflict (MergeConflict) – Conflict data

Returns:

True if this splitter should be used on the conflict

Return type:

bool

get_name() str[source]

Get a friendly name for the splitter

Returns:

Name of the splitter

Return type:

str

split(key: str, conflict: MergeConflict, result: KeyValueStore) Dict[str, MergeConflict] | None[source]

Split a field conflict into any number of alternate conflicts. Note: Returned conflicts will also be checked for splitting, beware infinite loops! If this function raises, it will be treated as returning None

Parameters:
  • key (str) – Original conflicting field’s key

  • conflict (MergeConflict) – Original conflict data

  • result (KeyValueStore) – Kvs structure containing the result of all splits. You should use the original conflict’s success() function in most cases unless you specifically want to write a new key to this.

Returns:

A collection of conflicts into which the original conflict was split, or None if this splitter cannot handle the conflict

Return type:

Dict[str, MergeConflict] | None

class FormattedConflict(conflict: MergeConflict | None = None, type: FormattedConflictFormatType | None = None, name: str | None = None, base_text: str | None = None, first_text: str | None = None, second_text: str | None = None, base: Dict[str, object] | None = None, first: Dict[str, object] | None = None, second: Dict[str, object] | None = None, handle=None)[source]

Bases: object

Class taking a merge conflict and producing a formatted text output.

Parameters:
property base: Dict[str, object] | None

Json of base first of conflict

Returns:

Formatted Json value, if type = Code, else None

property base_text: str | None

Text of base version of conflict

Returns:

Formatted text, if type = Text, else None

property conflict: MergeConflict

Unformatted merge conflict structure

Returns:

Merge Conflict structure

property first: Dict[str, object] | None

Json of first first of conflict

Returns:

Formatted Json value, if type = Code, else None

property first_text: str | None

Text of first version of conflict

Returns:

Formatted text, if type = Text, else None

property name: str

Formatted name of conflict

Returns:

Name string

property second: Dict[str, object] | None

Json of second first of conflict

Returns:

Formatted Json value, if type = Code, else None

property second_text: str | None

Text of second version of conflict

Returns:

Formatted text, if type = Text, else None

property type: FormattedConflictFormatType

Type of formatted content (Text/Code)

Returns:

Type

class FormatterList[source]

Bases: MutableSequence

Mutable list of formatters for FFI purposes

insert(index: int, value: ConflictFormatter) None[source]

S.insert(index, value) – insert value before index

Parameters:
Return type:

None

class MergeConflict(handle)[source]

Bases: object

Structure representing an individual merge conflict

get_path_item(path_key: str) object | None[source]

Get item in the merge conflict’s path for a given key.

Parameters:

path_key (str) – Key for path item

Returns:

Path item, or an None if not found

Return type:

object | None

make_child(new_data_type, new_type: str, new_key: str, new_path_key: str, new_path_value: object, new_base: Dict[str, object] | None, new_first: Dict[str, object] | None, new_second: Dict[str, object] | None, new_success: Callable[[Dict[str, object] | None], bool])[source]

Convenience function for making a new merge conflict using the snapshots/storage from this one

Parameters:
  • new_data_type – Desired dataType of new conflict

  • new_type (str) – Desired type of new conflict

  • new_key (str) – Desired key of new conflict

  • new_path_key (str) – Key to add to path for new conflict

  • new_path_value (object) – Value for key added to path

  • new_base (Dict[str, object] | None) – Desired base of new conflict

  • new_first (Dict[str, object] | None) – Desired first of new conflict

  • new_second (Dict[str, object] | None) – Desired second of new conflict

  • new_success (Callable[[Dict[str, object] | None], bool]) – Success function for new conflict

Returns:

Created child object

success(value: Dict[str, object] | None) bool[source]

Call this when you’ve resolved the conflict to save the result

Parameters:

value (Dict[str, object] | None) – Resolved value

Returns:

True if successful

Return type:

bool

property base: Dict[str, object] | None

Json object for conflicting data in the base snapshot

Returns:

Python dictionary from parsed json

property base_file: FileMetadata | None

FileMetadata with contents of file for base snapshot This function is slow! Only use it if you really need it.

Returns:

FileMetadata object

property base_snapshot: Snapshot | None

Snapshot which is the parent of the two being merged

Returns:

Snapshot object

property data_type: MergeConflictDataType

Type of data in the conflict, Text/Json/Binary

Returns:

Conflict data type

property database: Database

Database backing all snapshots in the merge conflict

Returns:

Database object

property first: Dict[str, object] | None

Json object for conflicting data in the first snapshot

Returns:

Python dictionary from parsed json

property first_file: FileMetadata | None

FileMetadata with contents of file for first snapshot This function is slow! Only use it if you really need it.

Returns:

FileMetadata object

property first_snapshot: Snapshot | None

First snapshot being merged

Returns:

Snapshot object

property key: str

Lookup key for the merge conflict, ideally a tree path that contains the name of the conflict and all the recursive children leading up to this conflict.

Returns:

Key name

property second: Dict[str, object] | None

Json object for conflicting data in the second snapshot

Returns:

Python dictionary from parsed json

property second_file: FileMetadata | None

FileMetadata with contents of file for second snapshot This function is slow! Only use it if you really need it.

Returns:

FileMetadata object

property second_snapshot: Snapshot | None

Second snapshot being merged

Returns:

Snapshot object

property type: str

String representing the type name of the data, not the same as data_type. This is like “typeName” or “tag” depending on what object the conflict represents.

Returns:

Type name

class SplitterList[source]

Bases: MutableSequence

Mutable list of splitters for FFI purposes

insert(index: int, value: ConflictSplitter) None[source]

S.insert(index, value) – insert value before index

Parameters:
Return type:

None

diff_kvs(base: KeyValueStore, target: KeyValueStore) Dict[str, List[str]][source]

Calculate the difference between two KVS structures

Parameters:
Returns:

Map: {“added”: [added fields], “modified”: [modified fields], “removed”: [removed fields]}

Return type:

Dict[str, List[str]]

least_common_ancestor(first: Snapshot, second: Snapshot) Snapshot | None[source]

Get the least common ancestor snapshot between two snapshots. The two snapshots must be in the same database.

Parameters:
  • first (Snapshot) – First snapshot for ancestor searching

  • second (Snapshot) – First snapshot for ancestor searching

Returns:

Ancestor snapshot, or None if the snapshots are on disjoint trees

Return type:

Snapshot | None

merge_kvs(database: Database, base: Snapshot, first: Snapshot, second: Snapshot, conflict_handler: ConflictHandler, progress: Callable[[int, int], bool]) KeyValueStore | None[source]

Merge the underlying KVS data structure in two snapshots.

Parameters:
  • database (Database) – Owning database

  • base (Snapshot) – ancestor snapshot’s data

  • first (Snapshot) – First snapshot’s data

  • second (Snapshot) – Second snapshot’s data

  • conflict_handler (ConflictHandler) – Function to call when merge conflicts are encountered

  • progress (Callable[[int, int], bool]) – Function to call for progress updates and cancelling

Returns:

Merged KVS structure, or None if there was an error

Return type:

KeyValueStore | None

merge_snapshots(first: Snapshot, second: Snapshot, conflict_handler: ConflictHandler, progress: Callable[[int, int], bool]) Snapshot | None[source]

Merge a pair of snapshots and create a new snapshot with the result.

Parameters:
  • first (Snapshot) – First snapshot to merge

  • second (Snapshot) – Second snapshot to merge

  • conflict_handler (ConflictHandler) – Function to call when merge conflicts are encountered

  • progress (Callable[[int, int], bool]) – Function to call for progress updates and cancelling

Returns:

Result snapshot, or None if there was an error

Return type:

Snapshot | None