|
|
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):
1.1.1.3 ! root 100: error_exit("target directory '%s' is inside source directory '%s'" % (srcdir, dstdir))
1.1 root 101: convert_dir(srcdir, dstdir)
102: check_conflicts(srcdir, dstdir)
103:
104: if __name__ == '__main__':
105: main(sys.argv)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.