1 | """macostools - Various utility functions for MacOS. |
---|
2 | |
---|
3 | mkalias(src, dst) - Create a finder alias 'dst' pointing to 'src' |
---|
4 | copy(src, dst) - Full copy of 'src' to 'dst' |
---|
5 | """ |
---|
6 | |
---|
7 | from warnings import warnpy3k |
---|
8 | warnpy3k("In 3.x, the macostools module is removed.", stacklevel=2) |
---|
9 | |
---|
10 | from Carbon import Res |
---|
11 | from Carbon import File, Files |
---|
12 | import os |
---|
13 | import errno |
---|
14 | import MacOS |
---|
15 | try: |
---|
16 | openrf = MacOS.openrf |
---|
17 | except AttributeError: |
---|
18 | # Backward compatibility |
---|
19 | openrf = open |
---|
20 | |
---|
21 | Error = 'macostools.Error' |
---|
22 | |
---|
23 | BUFSIZ=0x80000 # Copy in 0.5Mb chunks |
---|
24 | |
---|
25 | COPY_FLAGS = (Files.kIsStationary|Files.kNameLocked|Files.kHasBundle| |
---|
26 | Files.kIsInvisible|Files.kIsAlias) |
---|
27 | |
---|
28 | # |
---|
29 | # Not guaranteed to be correct or stay correct (Apple doesn't tell you |
---|
30 | # how to do this), but it seems to work. |
---|
31 | # |
---|
32 | def mkalias(src, dst, relative=None): |
---|
33 | """Create a finder alias""" |
---|
34 | srcfsr = File.FSRef(src) |
---|
35 | # The next line will fail under unix-Python if the destination |
---|
36 | # doesn't exist yet. We should change this code to be fsref-based. |
---|
37 | dstdir, dstname = os.path.split(dst) |
---|
38 | if not dstdir: dstdir = os.curdir |
---|
39 | dstdirfsr = File.FSRef(dstdir) |
---|
40 | if relative: |
---|
41 | relativefsr = File.FSRef(relative) |
---|
42 | # ik mag er geen None in stoppen :-( |
---|
43 | alias = File.FSNewAlias(relativefsr, srcfsr) |
---|
44 | else: |
---|
45 | alias = srcfsr.FSNewAliasMinimal() |
---|
46 | |
---|
47 | dstfsr, dstfss = Res.FSCreateResourceFile(dstdirfsr, unicode(dstname), |
---|
48 | File.FSGetResourceForkName()) |
---|
49 | h = Res.FSOpenResourceFile(dstfsr, File.FSGetResourceForkName(), 3) |
---|
50 | resource = Res.Resource(alias.data) |
---|
51 | resource.AddResource('alis', 0, '') |
---|
52 | Res.CloseResFile(h) |
---|
53 | |
---|
54 | dstfinfo = dstfss.FSpGetFInfo() |
---|
55 | dstfinfo.Flags = dstfinfo.Flags|0x8000 # Alias flag |
---|
56 | dstfss.FSpSetFInfo(dstfinfo) |
---|
57 | |
---|
58 | def mkdirs(dst): |
---|
59 | """Make directories leading to 'dst' if they don't exist yet""" |
---|
60 | if dst == '' or os.path.exists(dst): |
---|
61 | return |
---|
62 | head, tail = os.path.split(dst) |
---|
63 | if os.sep == ':' and not ':' in head: |
---|
64 | head = head + ':' |
---|
65 | mkdirs(head) |
---|
66 | |
---|
67 | try: |
---|
68 | os.mkdir(dst, 0777) |
---|
69 | except OSError, e: |
---|
70 | # be happy if someone already created the path |
---|
71 | if e.errno != errno.EEXIST: |
---|
72 | raise |
---|
73 | |
---|
74 | |
---|
75 | def touched(dst): |
---|
76 | """Tell the finder a file has changed. No-op on MacOSX.""" |
---|
77 | import warnings |
---|
78 | warnings.warn("macostools.touched() has been deprecated", |
---|
79 | DeprecationWarning, 2) |
---|
80 | |
---|
81 | def touched_ae(dst): |
---|
82 | """Tell the finder a file has changed""" |
---|
83 | pardir = os.path.split(dst)[0] |
---|
84 | if not pardir: |
---|
85 | pardir = os.curdir |
---|
86 | import Finder |
---|
87 | f = Finder.Finder() |
---|
88 | f.update(File.FSRef(pardir)) |
---|
89 | |
---|
90 | def copy(src, dst, createpath=0, copydates=1, forcetype=None): |
---|
91 | """Copy a file, including finder info, resource fork, etc""" |
---|
92 | src = File.pathname(src) |
---|
93 | dst = File.pathname(dst) |
---|
94 | if createpath: |
---|
95 | mkdirs(os.path.split(dst)[0]) |
---|
96 | |
---|
97 | ifp = open(src, 'rb') |
---|
98 | ofp = open(dst, 'wb') |
---|
99 | d = ifp.read(BUFSIZ) |
---|
100 | while d: |
---|
101 | ofp.write(d) |
---|
102 | d = ifp.read(BUFSIZ) |
---|
103 | ifp.close() |
---|
104 | ofp.close() |
---|
105 | |
---|
106 | ifp = openrf(src, '*rb') |
---|
107 | ofp = openrf(dst, '*wb') |
---|
108 | d = ifp.read(BUFSIZ) |
---|
109 | while d: |
---|
110 | ofp.write(d) |
---|
111 | d = ifp.read(BUFSIZ) |
---|
112 | ifp.close() |
---|
113 | ofp.close() |
---|
114 | |
---|
115 | srcfss = File.FSSpec(src) |
---|
116 | dstfss = File.FSSpec(dst) |
---|
117 | sf = srcfss.FSpGetFInfo() |
---|
118 | df = dstfss.FSpGetFInfo() |
---|
119 | df.Creator, df.Type = sf.Creator, sf.Type |
---|
120 | if forcetype is not None: |
---|
121 | df.Type = forcetype |
---|
122 | df.Flags = (sf.Flags & COPY_FLAGS) |
---|
123 | dstfss.FSpSetFInfo(df) |
---|
124 | if copydates: |
---|
125 | srcfsr = File.FSRef(src) |
---|
126 | dstfsr = File.FSRef(dst) |
---|
127 | catinfo, _, _, _ = srcfsr.FSGetCatalogInfo(Files.kFSCatInfoAllDates) |
---|
128 | dstfsr.FSSetCatalogInfo(Files.kFSCatInfoAllDates, catinfo) |
---|
129 | |
---|
130 | def copytree(src, dst, copydates=1): |
---|
131 | """Copy a complete file tree to a new destination""" |
---|
132 | if os.path.isdir(src): |
---|
133 | mkdirs(dst) |
---|
134 | files = os.listdir(src) |
---|
135 | for f in files: |
---|
136 | copytree(os.path.join(src, f), os.path.join(dst, f), copydates) |
---|
137 | else: |
---|
138 | copy(src, dst, 1, copydates) |
---|