Annotation of hatari/tools/atari-convert-dir.py, revision 1.1.1.2

1.1.1.2 ! root        1: #!/usr/bin/env python
1.1       root        2: """
                      3: Script to copy Atari files with (potentially) too long names from
                      4: source directory into target directory, using in latter file names
                      5: clipped to 8+3 characters.
                      6: 
                      7: Clipping is done like Atari GEMDOS functions would do it, so that
                      8: those file names can then be moved/copied to Atari media from another
                      9: OS.
                     10: 
                     11: If original long names work with Hatari GEMDOS HD emulation, the
                     12: clipped names should work with normal TOS on real harddisk (image)!
                     13: """
                     14: import sys, os, shutil
                     15: 
                     16: def debug(msg):
                     17:     sys.stderr.write("%s\n" % msg)
                     18: 
                     19: def error_exit(msg):
                     20:     name = os.path.basename(sys.argv[0])
                     21:     debug("\nUsage: %s <source dir> <target dir>" % name)
                     22:     debug(__doc__)
                     23:     debug("ERROR: %s!\n" % msg)
                     24:     sys.exit(1)
                     25: 
                     26: newnames = {}
                     27: 
                     28: def check_conflicts(srcdir, dstdir):
                     29:     # how much to clip from paths
                     30:     srcskip = len(srcdir)+1
                     31:     dstskip = len(dstdir)+1
1.1.1.2 ! root       32:     print("\nNames that aren't unique:")
1.1       root       33:     conflicts = False
                     34:     for key,names in newnames.items():
                     35:         if len(names) > 1:
                     36:             conflicts = True
1.1.1.2 ! root       37:             print("- %s: %s" % (key[dstskip:], [name[srcskip:] for name in names]))
1.1       root       38:     if not conflicts:
1.1.1.2 ! root       39:         print("- none, all OK!")
1.1       root       40: 
                     41: def hash_names(original, newname):
                     42:     if newname not in newnames:
                     43:         newnames[newname] = []
                     44:     newnames[newname].append(original)
                     45: 
                     46: def clip_name(name):
                     47:     dot = name.rfind('.')
                     48:     if dot >= 0:
                     49:         base = name[:dot]
                     50:         ext = name[dot+1:]
                     51:         name = "%s.%s" % (base[:8], ext[:3])
                     52:     else:
                     53:         name = name[:8]
                     54:     # TODO: map non-ASCII characters
                     55:     return name.upper()
                     56: 
1.1.1.2 ! root       57: def dirs_last(path):
        !            58:     # order first by type, then (case-insensitively) by name
        !            59:     return (os.path.isdir(path), path.upper())
1.1       root       60: 
                     61: def convert_dir(srcdir, dstdir):
1.1.1.2 ! root       62:     print("\n%s/ -> %s/:" % (srcdir, dstdir))
1.1       root       63:     try:
                     64:         os.mkdir(dstdir)
                     65:     except OSError:
                     66:         debug("ERROR: directory creation failed, name conflict???")
                     67:         return
                     68:     # directory sorting requires full names
                     69:     dircontents = [os.path.join(srcdir, x) for x in os.listdir(srcdir)]
1.1.1.2 ! root       70:     for original in sorted(dircontents, key=dirs_last):
1.1       root       71:         origname = os.path.basename(original)
                     72:         clipname = clip_name(origname)
                     73:         newname = os.path.join(dstdir, clipname)
                     74:         hash_names(original, newname)
                     75:         if os.path.isdir(original):
                     76:             convert_dir(original, newname)
                     77:         else:
1.1.1.2 ! root       78:             print("- %s -> %s" % (origname, clipname))
1.1       root       79:             try:
                     80:                 shutil.copyfile(original, newname)
                     81:             except IOError:
                     82:                 debug("ERROR: file copy failed, name conflict (with read-only file)???")
                     83:                 continue
                     84:             shutil.copystat(original, newname)
                     85: 
                     86: def main(args):
                     87:     if len(args) != 3:
                     88:         error_exit("too few arguments")
                     89:     srcdir = args[1]
                     90:     dstdir = args[2]
                     91:     if not os.path.isdir(srcdir):
                     92:         error_exit("source directory '%s' doesn't exist" % srcdir)
                     93:     if os.path.isdir(dstdir):
                     94:         error_exit("target directory '%s' exists, remove it to continue" % dstdir)
                     95:     if srcdir[-1] == os.path.sep:
                     96:         srcdir = srcdir[:-1]
                     97:     if dstdir[-1] == os.path.sep:
                     98:         dstdir = dstdir[:-1]
                     99:     if dstdir.startswith(srcdir+os.path.sep):
                    100:         error_exit("target directory '%s' is inside source directory '%s'" % (srcdir, dstdir))        
                    101:     convert_dir(srcdir, dstdir)
                    102:     check_conflicts(srcdir, dstdir)
                    103: 
                    104: if __name__ == '__main__':
                    105:     main(sys.argv)

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.