def main_merge(args):
    bfn = args.base
    lfn = args.local
    rfn = args.remote
    mfn = args.out

    from .args import process_diff_flags
    process_diff_flags(args)

    for fn in (bfn, lfn, rfn):
        if not os.path.exists(fn) and fn != EXPLICIT_MISSING_FILE:
            nbdime.log.error("Cannot find file '%s'", fn)
            return 1

    if lfn == rfn == EXPLICIT_MISSING_FILE:
        # Deleted both locally and remotely
        # Special case not well solved by routines below
        handle_agreed_deletion(bfn, mfn, args.decisions)
        # Agreed on deletion = no conflics = return 0
        return 0

    b = read_notebook(bfn, on_null='minimal')
    l = read_notebook(lfn, on_null='minimal')
    r = read_notebook(rfn, on_null='minimal')

    merged, decisions = merge_notebooks(b, l, r, args)
    conflicted = [d for d in decisions if d.conflict]

    returncode = 1 if conflicted else 0

    if conflicted:
        nbdime.log.warning("Conflicts occured during merge operation.")
    else:
        nbdime.log.debug(
            "Merge completed successfully with no unresolvable conflicts.")

    if args.decisions:
        # Print merge decisions (including unconflicted)
        out = io.StringIO()
        pretty_print_merge_decisions(b, decisions, out=out)
        nbdime.log.warning("Decisions:\n%s", out.getvalue())
    elif mfn:
        # Write partial or fully completed merge to given foo.ipynb filename
        with io.open(mfn, "w", encoding="utf8"):
            nbformat.write(merged, mfn)
        nbdime.log.info("Merge result written to %s", mfn)
    else:
        # Write merged notebook to terminal
        nbformat.write(merged, sys.stdout)
    return returncode
Beispiel #2
0
def main_merge(args):
    bfn = args.base
    lfn = args.local
    rfn = args.remote
    mfn = args.out

    from .args import process_diff_flags
    process_diff_flags(args)

    for fn in (bfn, lfn, rfn):
        if not os.path.exists(fn) and fn != EXPLICIT_MISSING_FILE:
            nbdime.log.error("Cannot find file '%s'", fn)
            return 1

    if lfn == rfn == EXPLICIT_MISSING_FILE:
        # Deleted both locally and remotely
        # Special case not well solved by routines below
        handle_agreed_deletion(bfn, mfn, args.decisions)
        # Agreed on deletion = no conflics = return 0
        return 0

    b = read_notebook(bfn, on_null='minimal')
    l = read_notebook(lfn, on_null='minimal')
    r = read_notebook(rfn, on_null='minimal')

    merged, decisions = merge_notebooks(b, l, r, args)
    conflicted = [d for d in decisions if d.conflict]

    returncode = 1 if conflicted else 0

    if conflicted:
        nbdime.log.warning("Conflicts occured during merge operation.")
    else:
        nbdime.log.debug("Merge completed successfully with no unresolvable conflicts.")

    if args.decisions:
        # Print merge decisions (including unconflicted)
        config = PrettyPrintConfig(out=io.StringIO())
        pretty_print_merge_decisions(b, decisions, config=config)
        nbdime.log.warning("Decisions:\n%s", config.out.getvalue())
    elif mfn:
        # Write partial or fully completed merge to given foo.ipynb filename
        with io.open(mfn, "w", encoding="utf8"):
            nbformat.write(merged, mfn)
        nbdime.log.info("Merge result written to %s", mfn)
    else:
        # Write merged notebook to terminal
        nbformat.write(merged, sys.stdout)
    return returncode
Beispiel #3
0
def main_patch(args):
    base_filename = args.base
    patch_filename = args.patch
    output_filename = args.output

    for fn in (base_filename, patch_filename):
        if not os.path.exists(fn) and fn != EXPLICIT_MISSING_FILE:
            print("Missing file {}".format(fn))
            return 1

    before = read_notebook(base_filename, on_null='empty')
    with io.open(patch_filename, encoding="utf8") as patch_file:
        diff = json.load(patch_file)
    diff = to_diffentry_dicts(diff)

    after = patch_notebook(before, diff)

    if output_filename:
        nbformat.write(after, output_filename)
    else:
        try:
            nbformat.validate(after, version=4)
        except nbformat.ValidationError:
            print("Patch result is not a valid notebook, printing as JSON:")
            json.dump(after, sys.stdout)
        else:
            pretty_print_notebook(after)

    return 0
Beispiel #4
0
def handle_agreed_deletion(base_fn, output_fn, print_decisions=False):
    """Handle merge when file has been deleted both locally and remotely"""
    assert base_fn != EXPLICIT_MISSING_FILE, (
        'sanity check failed: cannot have agreed decision on base %r' %
        base_fn)
    b = read_notebook(base_fn, on_null='minimal')
    if print_decisions:
        # Print merge decision (delete all)
        from nbdime.diffing.notebooks import diff_notebooks
        from nbdime.merging.decisions import MergeDecisionBuilder
        # Build diff for deleting all content:
        diff = diff_notebooks(b, {})
        # Make agreed decision from diff:
        bld = MergeDecisionBuilder()
        bld.agreement([], local_diff=diff, remote_diff=diff)
        decisions = bld.validated(b)
        # Print decition
        config = PrettyPrintConfig(out=io.StringIO())
        pretty_print_merge_decisions(b, decisions, config=config)
        nbdime.log.warning("Decisions:\n%s", out.getvalue())

    elif output_fn:
        # Delete file if existing, if not do nothing
        if os.path.exists(output_fn):
            os.remove(output_fn)
            nbdime.log.info("Output file deleted: %s", output_fn)
Beispiel #5
0
def handle_agreed_deletion(base_fn, output_fn, print_decisions=False):
    """Handle merge when file has been deleted both locally and remotely"""
    assert base_fn != EXPLICIT_MISSING_FILE, (
        'sanity check failed: cannot have agreed decision on base %r' % base_fn)
    b = read_notebook(base_fn, on_null='minimal')
    if print_decisions:
        # Print merge decision (delete all)
        from nbdime.diffing.notebooks import diff_notebooks
        from nbdime.merging.decisions import MergeDecisionBuilder
        # Build diff for deleting all content:
        diff = diff_notebooks(b, {})
        # Make agreed decision from diff:
        bld = MergeDecisionBuilder()
        bld.agreement([], local_diff=diff, remote_diff=diff)
        decisions = bld.validated(b)
        # Print decition
        config = PrettyPrintConfig(out=io.StringIO())
        pretty_print_merge_decisions(b, decisions, config=config)
        nbdime.log.warning("Decisions:\n%s", out.getvalue())

    elif output_fn:
        # Delete file if existing, if not do nothing
        if os.path.exists(output_fn):
            os.remove(output_fn)
            nbdime.log.info("Output file deleted: %s", output_fn)
def _handle_diff(base, remote, output, args):
    """Handles diffs of files, either as filenames or file-like objects"""
    # Check that if args are filenames they either exist, or are
    # explicitly marked as missing (added/removed):
    for fn in (base, remote):
        if (isinstance(fn, string_types) and not os.path.exists(fn)
                and fn != EXPLICIT_MISSING_FILE):
            print("Missing file {}".format(fn))
            return 1
    # Both files cannot be missing
    assert not (base == EXPLICIT_MISSING_FILE and remote
                == EXPLICIT_MISSING_FILE), ('cannot diff %r against %r' %
                                            (base, remote))

    # Perform actual work:
    a = read_notebook(base, on_null='empty')
    b = read_notebook(remote, on_null='empty')

    d = diff_notebooks(a, b)

    # Output as JSON to file, or print to stdout:
    if output:
        with open(output, "w") as df:
            # Compact version:
            #json.dump(d, df)
            # Verbose version:
            json.dump(d, df, indent=2, separators=(",", ": "))
    else:
        # This printer is to keep the unit tests passing,
        # some tests capture output with capsys which doesn't
        # pick up on sys.stdout.write()
        class Printer:
            def write(self, text):
                print(text, end="")

        # This sets up what to ignore:
        config = PrettyPrintConfig(out=Printer(),
                                   include=args,
                                   color_words=args.color_words)
        # Separate out filenames:
        base_name = base if isinstance(base, string_types) else base.name
        remote_name = remote if isinstance(remote,
                                           string_types) else remote.name
        pretty_print_notebook_diff(base_name, remote_name, a, d, config)

    return 0
Beispiel #7
0
def _handle_diff(base, remote, output, args):
    """Handles diffs of files, either as filenames or file-like objects"""
    # Check that if args are filenames they either exist, or are
    # explicitly marked as missing (added/removed):
    for fn in (base, remote):
        if (isinstance(fn, string_types) and not os.path.exists(fn) and
                fn != EXPLICIT_MISSING_FILE):
            print("Missing file {}".format(fn))
            return 1
    # Both files cannot be missing
    assert not (base == EXPLICIT_MISSING_FILE and remote == EXPLICIT_MISSING_FILE), (
        'cannot diff %r against %r' % (base, remote))

    # Perform actual work:
    a = read_notebook(base, on_null='empty')
    b = read_notebook(remote, on_null='empty')

    d = diff_notebooks(a, b)

    # Output as JSON to file, or print to stdout:
    if output:
        with open(output, "w") as df:
            # Compact version:
            #json.dump(d, df)
            # Verbose version:
            json.dump(d, df, indent=2, separators=(",", ": "))
    else:
        # This printer is to keep the unit tests passing,
        # some tests capture output with capsys which doesn't
        # pick up on sys.stdout.write()
        class Printer:
            def write(self, text):
                print(text, end="")
        # This sets up what to ignore:
        config = PrettyPrintConfig(out=Printer(), include=args, color_words=args.color_words)
        # Separate out filenames:
        base_name = base if isinstance(base, string_types) else base.name
        remote_name = remote if isinstance(remote, string_types) else remote.name
        pretty_print_notebook_diff(base_name, remote_name, a, d, config)

    return 0
Beispiel #8
0
def main_diff(args):
    # Get input notebooks:
    afn = args.base
    bfn = args.remote
    dfn = args.out

    process_diff_args(args)

    for fn in (afn, bfn):
        if not os.path.exists(fn) and fn != EXPLICIT_MISSING_FILE:
            print("Missing file {}".format(fn))
            return 1
    # Both files cannot be missing
    assert not (afn == EXPLICIT_MISSING_FILE and bfn == EXPLICIT_MISSING_FILE)

    a = read_notebook(afn, on_null='empty')
    b = read_notebook(bfn, on_null='empty')

    # Perform actual diff:
    d = diff_notebooks(a, b)

    # Output diff:
    if dfn:
        with open(dfn, "w") as df:
            # Compact version:
            #json.dump(d, df)
            # Verbose version:
            json.dump(d, df, indent=2, separators=(",", ": "))
    else:
        # This printer is to keep the unit tests passing,
        # some tests capture output with capsys which doesn't
        # pick up on sys.stdout.write()
        class Printer:
            def write(self, text):
                print(text, end="")

        pretty_print_notebook_diff(afn, bfn, a, d, Printer())

    return 0
Beispiel #9
0
def main_patch(args):
    base_filename = args.base
    patch_filename = args.patch
    output_filename = args.output

    for fn in (base_filename, patch_filename):
        if not os.path.exists(fn) and fn != EXPLICIT_MISSING_FILE:
            print("Missing file {}".format(fn))
            return 1

    before = read_notebook(base_filename, on_null='empty')
    with io.open(patch_filename, encoding="utf8") as patch_file:
        diff = json.load(patch_file)
    diff = to_diffentry_dicts(diff)

    after = patch_notebook(before, diff)

    if output_filename:
        nbformat.write(after, output_filename)
    else:
        try:
            nbformat.validate(after, version=4)
        except nbformat.ValidationError:
            print("Patch result is not a valid notebook, printing as JSON:")
            json.dump(after, sys.stdout)
        else:
            # This printer is to keep the unit tests passing,
            # some tests capture output with capsys which doesn't
            # pick up on sys.stdout.write()
            class Printer:
                def write(self, text):
                    print(text, end="")

            config = PrettyPrintConfig(out=Printer())

            pretty_print_notebook(after, config=config)

    return 0
Beispiel #10
0
def main_patch(args):
    base_filename = args.base
    patch_filename = args.patch
    output_filename = args.output

    for fn in (base_filename, patch_filename):
        if not os.path.exists(fn) and fn != EXPLICIT_MISSING_FILE:
            print("Missing file {}".format(fn))
            return 1

    before = read_notebook(base_filename, on_null='empty')
    with io.open(patch_filename, encoding="utf8") as patch_file:
        diff = json.load(patch_file)
    diff = to_diffentry_dicts(diff)

    after = patch_notebook(before, diff)

    if output_filename:
        nbformat.write(after, output_filename)
    else:
        try:
            nbformat.validate(after, version=4)
        except nbformat.ValidationError:
            print("Patch result is not a valid notebook, printing as JSON:")
            json.dump(after, sys.stdout)
        else:
            # This printer is to keep the unit tests passing,
            # some tests capture output with capsys which doesn't
            # pick up on sys.stdout.write()
            class Printer:
                def write(self, text):
                    print(text, end="")

            config = PrettyPrintConfig(out=Printer())

            pretty_print_notebook(after, config=config)

    return 0