codekingpro/portable-devtools
115k
1#!D:\code\apps\devtools\python\python.exe
2# -*- coding: utf-8 -*-3 4import sys5import os.path6import json7import jsonpatch8import tempfile9import argparse10 11 12parser = argparse.ArgumentParser(13 description='Apply a JSON patch on a JSON file')14parser.add_argument('ORIGINAL', type=argparse.FileType('r'),15 help='Original file')16parser.add_argument('PATCH', type=argparse.FileType('r'),17 nargs='?', default=sys.stdin,18 help='Patch file (read from stdin if omitted)')19parser.add_argument('--indent', type=int, default=None,20 help='Indent output by n spaces')21parser.add_argument('-b', '--backup', action='store_true',22 help='Back up ORIGINAL if modifying in-place')23parser.add_argument('-i', '--in-place', action='store_true',24 help='Modify ORIGINAL in-place instead of to stdout')25parser.add_argument('-v', '--version', action='version',26 version='%(prog)s ' + jsonpatch.__version__)27parser.add_argument('-u', '--preserve-unicode', action='store_true',28 help='Output Unicode character as-is without using Code Point')29 30def main():31 try:32 patch_files()33 except KeyboardInterrupt:34 sys.exit(1)35 36 37def patch_files():38 """ Diffs two JSON files and prints a patch """39 args = parser.parse_args()40 doc = json.load(args.ORIGINAL)41 patch = json.load(args.PATCH)42 result = jsonpatch.apply_patch(doc, patch)43 44 if args.in_place:45 dirname = os.path.abspath(os.path.dirname(args.ORIGINAL.name))46 47 try:48 # Attempt to replace the file atomically. We do this by49 # creating a temporary file in the same directory as the50 # original file so we can atomically move the new file over51 # the original later. (This is done in the same directory52 # because atomic renames do not work across mount points.)53 54 fd, pathname = tempfile.mkstemp(dir=dirname)55 fp = os.fdopen(fd, 'w')56 atomic = True57 58 except OSError:59 # We failed to create the temporary file for an atomic60 # replace, so fall back to non-atomic mode by backing up61 # the original (if desired) and writing a new file.62 63 if args.backup:64 os.rename(args.ORIGINAL.name, args.ORIGINAL.name + '.orig')65 fp = open(args.ORIGINAL.name, 'w')66 atomic = False67 68 else:69 # Since we're not replacing the original file in-place, write70 # the modified JSON to stdout instead.71 72 fp = sys.stdout73 74 # By this point we have some sort of file object we can write the 75 # modified JSON to.76 77 json.dump(result, fp, indent=args.indent, ensure_ascii=not(args.preserve_unicode))78 fp.write('\n')79 80 if args.in_place:81 # Close the new file. If we aren't replacing atomically, this82 # is our last step, since everything else is already in place.83 84 fp.close()85 86 if atomic:87 try:88 # Complete the atomic replace by linking the original89 # to a backup (if desired), fixing up the permissions90 # on the temporary file, and moving it into place.91 92 if args.backup:93 os.link(args.ORIGINAL.name, args.ORIGINAL.name + '.orig')94 os.chmod(pathname, os.stat(args.ORIGINAL.name).st_mode)95 os.rename(pathname, args.ORIGINAL.name)96 97 except OSError:98 # In the event we could not actually do the atomic99 # replace, unlink the original to move it out of the100 # way and finally move the temporary file into place.101 102 os.unlink(args.ORIGINAL.name)103 os.rename(pathname, args.ORIGINAL.name)104 105 106if __name__ == "__main__":107 main()108 