Mercurial > hgrepos > Python > apps > py-cutils
comparison cutils/treesum.py @ 125:12d6ec1f8613
Implement "--logical" and "--physical" to control following symlinked directories when given on the commandline
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Thu, 02 Jan 2025 17:03:10 +0100 |
| parents | 3bd3f32b5e60 |
| children | 6a50d02fe0ca |
comparison
equal
deleted
inserted
replaced
| 124:3bd3f32b5e60 | 125:12d6ec1f8613 |
|---|---|
| 42 help="Append to the output file instead of overwriting it.") | 42 help="Append to the output file instead of overwriting it.") |
| 43 aparser.add_argument( | 43 aparser.add_argument( |
| 44 "--base64", action="store_true", | 44 "--base64", action="store_true", |
| 45 help="Output checksums in base64 notation, not hexadecimal (OpenBSD).") | 45 help="Output checksums in base64 notation, not hexadecimal (OpenBSD).") |
| 46 aparser.add_argument( | 46 aparser.add_argument( |
| 47 "--logical", "-L", dest="logical", action="store_true", default=None, | |
| 48 help="Follow symbolic links given on command line arguments." | |
| 49 " Note that this is a different setting as to follow symbolic" | |
| 50 " links to directories when traversing a directory tree.") | |
| 51 aparser.add_argument( | |
| 47 "--mmap", action="store_true", dest="mmap", default=None, | 52 "--mmap", action="store_true", dest="mmap", default=None, |
| 48 help="Use mmap if available. Default is to determine automatically " | 53 help="Use mmap if available. Default is to determine automatically " |
| 49 "from the filesize.") | 54 "from the filesize.") |
| 50 aparser.add_argument( | 55 aparser.add_argument( |
| 51 "--no-mmap", action="store_false", dest="mmap", default=None, | 56 "--no-mmap", action="store_false", dest="mmap", default=None, |
| 52 help="Dont use mmap.") | 57 help="Dont use mmap.") |
| 53 aparser.add_argument( | 58 aparser.add_argument( |
| 54 "--output", "-o", action="store", metavar="OUTPUT", | 59 "--output", "-o", action="store", metavar="OUTPUT", |
| 55 help="Put the checksum into given file. If not given of if it is given" | 60 help="Put the checksum into given file. If not given of if it is given" |
| 56 " as `-' then stdout is used.") | 61 " as `-' then stdout is used.") |
| 62 aparser.add_argument( | |
| 63 "--physical", "-P", dest="logical", action="store_false", default=None, | |
| 64 help="Do not follow symbolic links given on comment line arguments." | |
| 65 " This is the default.") | |
| 57 aparser.add_argument( | 66 aparser.add_argument( |
| 58 "--version", "-v", action="version", | 67 "--version", "-v", action="version", |
| 59 version="%s (rv:%s)" % (__version__, __revision__)) | 68 version="%s (rv:%s)" % (__version__, __revision__)) |
| 60 aparser.add_argument( | 69 aparser.add_argument( |
| 61 "directories", nargs="*", metavar="DIRECTORY") | 70 "directories", nargs="*", metavar="DIRECTORY") |
| 70 | 79 |
| 71 def gen_opts(directories=[], | 80 def gen_opts(directories=[], |
| 72 algorithm="BLAKE2b-256", | 81 algorithm="BLAKE2b-256", |
| 73 append_output=False, | 82 append_output=False, |
| 74 base64=False, | 83 base64=False, |
| 84 logical=None, | |
| 75 mmap=None, | 85 mmap=None, |
| 76 output=None): | 86 output=None): |
| 77 opts = argparse.Namespace(directories=directories, | 87 opts = argparse.Namespace(directories=directories, |
| 78 algorithm=(util.algotag2algotype(algorithm), | 88 algorithm=(util.algotag2algotype(algorithm), |
| 79 algorithm), | 89 algorithm), |
| 80 append_output=append_output, | 90 append_output=append_output, |
| 81 base64=base64, | 91 base64=base64, |
| 92 logical=logical, | |
| 82 mmap=mmap, | 93 mmap=mmap, |
| 83 output=output) | 94 output=output) |
| 84 return opts | 95 return opts |
| 85 | 96 |
| 86 | 97 |
| 105 out_cm = open(opts.output, "wb") | 116 out_cm = open(opts.output, "wb") |
| 106 | 117 |
| 107 with out_cm as outfp: | 118 with out_cm as outfp: |
| 108 for d in opts.directories: | 119 for d in opts.directories: |
| 109 generate_treesum_for_directory( | 120 generate_treesum_for_directory( |
| 110 outfp, d, opts.algorithm, opts.mmap, opts.base64) | 121 outfp, d, opts.algorithm, opts.mmap, opts.base64, opts.logical) |
| 111 | 122 |
| 112 | 123 |
| 113 def generate_treesum_for_directory( | 124 def generate_treesum_for_directory( |
| 114 outfp, root, algorithm, use_mmap, use_base64): | 125 outfp, root, algorithm, use_mmap, use_base64, handle_root_logical): |
| 115 """ | 126 """ |
| 116 | 127 |
| 117 :param outfp: a *binary* file with a "write()" and a "flush()" method | 128 :param outfp: a *binary* file with a "write()" and a "flush()" method |
| 118 | 129 |
| 119 """ | 130 """ |
| 120 outfp.write(format_bsd_line("ROOT", None, root, False)) | 131 outfp.write(format_bsd_line("ROOT", None, root, False)) |
| 121 outfp.flush() | 132 outfp.flush() |
| 133 | |
| 134 # Note given non-default flags that are relevant for directory traversal | |
| 135 flags = [] | |
| 136 if handle_root_logical: | |
| 137 flags.append(b"logical") | |
| 138 if flags: | |
| 139 outfp.write(format_bsd_line("FLAGS", None, b",".join(flags), False)) | |
| 140 | |
| 122 dir_digests = {} | 141 dir_digests = {} |
| 142 | |
| 143 if not handle_root_logical and os.path.islink(root): | |
| 144 linktgt = util.fsencode(os.readlink(root)) | |
| 145 linkdgst = algorithm[0]() | |
| 146 linkdgst.update(linktgt) | |
| 147 dir_dgst = algorithm[0]() | |
| 148 dir_dgst.update(b"1:S,4:/./@,") | |
| 149 dir_dgst.update(linkdgst.digest()) | |
| 150 outfp.write(format_bsd_line( | |
| 151 algorithm[1], | |
| 152 dir_dgst.digest(), | |
| 153 "/./@", | |
| 154 use_base64)) | |
| 155 outfp.flush() | |
| 156 return | |
| 123 | 157 |
| 124 for top, dirs, nondirs in walk.walk(root, follow_symlinks=False): | 158 for top, dirs, nondirs in walk.walk(root, follow_symlinks=False): |
| 125 dir_dgst = algorithm[0]() | 159 dir_dgst = algorithm[0]() |
| 126 for dn in dirs: | 160 for dn in dirs: |
| 127 if dn.is_symlink: | 161 if dn.is_symlink: |
