#----------------------------------------------------------------- # [3.3] Create files with both decomposed and composed Unicode # filenames, and test compares and syncs in 3.2 and 3.3. # # Run in this script's folder; test folders are auto created. # Results for macOS are in _TEST-output.txt and in LOGS/*. # # Uses manual decoding, else open('nfd-Liñux.png') may depend on # platform defaults and cut/paste for text with Unicode variants. #----------------------------------------------------------------- import os, glob, shutil, time from os import system as cmd # edit me code = '/Users/me/MY-STUFF/Code' mergeall32 = '../../Mergeall-source' # edit me: 3.2 unzip mergeall33 = code + '/mergeall' # edit me: 3.3 production def mkfile(name, content): # name is NFC|NFD, decoded f = open(name, 'w', encoding='utf8') # encoding of content, not name f.write(content) f.close() def mklink(linkto, linkfrom, folder=False): os.symlink(linkto, linkfrom, target_is_directory=folder) # make alt-form filenames: {ndf, nfc} Liñux nfc = b'Li\xc3\xb1ux'.decode('utf-8') # decoded str, composed (NFC) nfd = b'Lin\xcc\x83ux'.decode('utf-8') # decoded str, decomposed (NFD) def populate(): for (folder, code) in [('FROM', nfd), ('TO', nfc)]: raw = code.encode('utf-8') if os.path.exists(folder): shutil.rmtree(folder) os.mkdir(folder) os.chdir(folder) mkfile('file1-%s.txt' % code, content='%s, %s' % (code, raw)) mkfile('file2-%s.txt' % code, content='%s, %s' % (code, raw)) mklink('file1-%s.txt' % code, linkfrom='link-%s' % code) os.mkdir('dir-%s' % code) mkfile( 'dir-%s/nested1-%s.txt' % (code, code), content='nested1, %s' % raw) mkfile( 'dir-%s/nested2-%s.txt' % (code, code), content='nested2, %s' % raw) mkfile('okay.txt', content='okay') mklink('okay.txt', linkfrom='okay-link1') mklink('okay.txt', linkfrom='okay-link2') os.mkdir('okay-dir') os.chdir('..') def dump(): # verify populate, sync print() for folder in ('FROM', 'TO'): print('[' + folder + ']') print(*[(name, name.encode('utf8')) for name in sorted(os.listdir(folder))], sep='\n') # both forms map to same file (on macOS) for code in (nfc, nfd): try: name = '%s/file1-%s.txt' % (folder, code) print(name, '=>', open(name).read()) except FileNotFoundError as E: print(b'file1-%s.txt' % code.encode('utf8'), 'not found', E) # either opened for decoded literal (on macOS) try: name = '%s/file1-Liñux.txt' % folder print(name, '=>', open(name).read()) except FileNotFoundError as E: print('default name not found', E) for name in glob.glob('%s/dir-%s/*' % (folder, code)): print(name, '=>', open(name).read().rstrip()) def compare(label): # test 3.2/3.3 diffs cmd('python3 %s/mergeall.py FROM TO -report -skipcruft' ' > LOGS/%s-mergeall-32.txt' % (mergeall32, label)) cmd('python3 %s/mergeall.py FROM TO -report -skipcruft' ' > LOGS/%s-mergeall-33.txt' % (mergeall33, label)) cmd('python3 %s/diffall.py FROM TO -skipcruft' ' > LOGS/%s-diffall-32.txt' % (mergeall32, label)) cmd('python3 %s/diffall.py FROM TO -skipcruft' ' > LOGS/%s-diffall-33.txt' % (mergeall33, label)) def modify(): # modify data time.sleep(3) # evade FAT 2 seconds cmd('touch -c FROM/file1-Liñux.txt') # do not create new cmd('touch -h FROM/link-Liñux') # touch link itself cmd('rm FROM/file2-Liñux.txt') # del: __added__.txt cmd('echo > FROM/file3-Liñux.txt') # add new file: composed! cmd('touch -c FROM/dir-Liñux/nested1-Liñux.txt') # mod cmd('rm FROM/dir-Liñux/nested2-Liñux.txt') # del cmd('echo > FROM/dir-Liñux/nested3-Liñux.txt') # add cmd('touch -c FROM/okay.txt') cmd('touch -h FROM/okay-link1') # 'normal' names cmd('rm -r FROM/okay-dir') cmd('rm FROM/okay-link2') def sync(): # sync trees with 3.3 and compare again cmd('python3 %s/mergeall.py FROM TO -auto -skipcruft' ' > LOGS/3-sync-mergeall-33.txt' % mergeall33) def deltas_create(): # save FROM deltas cmd('python3 %s/deltas.py DELTAS FROM TO -skipcruft' ' > LOGS/5-deltas-create-33.txt' % mergeall33) def deltas_apply(): # apply FROM deltas to TO (rm -quiet to see messages) cmd('python3 %s/mergeall.py DELTAS TO -restore -auto -backup -quiet -skipcruft' ' > LOGS/6-deltas-apply-33.txt' % mergeall33) if __name__ == '__main__': # go print('\nInitial populate') shutil.rmtree('LOGS', ignore_errors=True) os.mkdir('LOGS') populate() dump() compare('1-initial') input('\nPress enter to mod and sync') modify() compare('2-postmod') sync() compare('4-postsync') dump() input('\nPress enter to run deltas test') populate() modify() deltas_create() deltas_apply() compare('7-postdeltas') dump()