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
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
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
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
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
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
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