/stdhome

To get this branch, use:
bzr branch http://bzr.ed.am/stdhome

« back to all changes in this revision

Viewing changes to lib/stdhome/walker/copy_base.py

  • Committer: Tim Marston
  • Date: 2016-04-10 20:20:56 UTC
  • Revision ID: tim@ed.am-20160410202056-x0mo1ktjbjgqe2pr
added symlink to executable

Show diffs side-by-side

added added

removed removed

21
21
 
22
22
import filecmp, os, shutil
23
23
from walker import Walker
24
 
import stdhome.the as the
 
24
from stdhome import the
 
25
from stdhome import util
25
26
 
26
27
 
27
28
class CopyBaseWalker( Walker ):
28
29
        """The copy-base walker traverses a walklist ruthlessly mirroring src to dst.
29
30
        It is designed to be the base class of both the copy-in and copy-out walker,
30
31
        both of which are specialisations of this purpose.  See them for more
31
 
        information.
 
32
        information.  The print_op method, derived in those classes, takes, in
 
33
        addition to the relative filename, a source file type, an operation, and a
 
34
        sestination file type.  Valid file types are f (file), l (symlink), d
 
35
        (directory) and _ (non-existant).  Valid operations are * (modify), = (skip:
 
36
        same), @ (skip: symlink substitute) and # (skip: ignored).
32
37
        """
33
38
 
34
39
 
42
47
 
43
48
                # ignore?
44
49
                if self.check_dst_ignores and the.config.ignores.matches( rel_file ):
45
 
                        if the.verbose >= 2:
46
 
                                self.print_op( rel_file, '%s#%s' % ( src.type, dst.type ) )
 
50
                        self.print_op( rel_file, src.type, '#', dst.type )
47
51
                        return True
48
52
 
49
53
                # src entity is directory
52
56
                        # if dst entity doesn't exist, create directory (no need to recurse,
53
57
                        # since we're copying the whole directory)
54
58
                        if dst.type == '_':
55
 
                                if the.verbose >= 2: self.print_op( rel_file, 'd>_' )
 
59
                                self.print_op( rel_file, 'd', '*', '_' )
56
60
                                shutil.copytree( src.file, dst.file, True )
57
61
 
58
62
                        # if dst entity is a directory, copy permissions, as required (and
59
63
                        # recurse)
60
64
                        elif dst.type == 'd':
61
 
                                # TODO: should check permission and only do as necessary
62
 
                                if the.verbose >= 2: self.print_op( rel_file, 'd>d' )
63
 
                                shutil.copystat( src.file, dst.file )
 
65
                                if os.stat( src.file ).st_mode != os.stat( dst.file ).st_mode:
 
66
                                        self.print_op( rel_file, 'd', '*', 'd' )
 
67
                                        shutil.copystat( src.file, dst.file )
 
68
                                else:
 
69
                                        self.print_op( rel_file, 'd', '=', 'd' )
64
70
                                return True
65
71
 
66
72
                        # if dst entity is a symlink to a directory, and this is an
67
73
                        # acceptable substitute, just recurse
68
74
                        elif self.check_dst_symlinks and dst.link_type == 'd' and \
69
75
                                        the.config.symlinks.matches( rel_file ):
70
 
                                if the.verbose >= 2: self.print_op( rel_file, 'd@d' )
 
76
                                self.print_op( rel_file, 'd', '@', 'd' )
71
77
                                return True
72
78
 
73
79
                        # if dst entity is a file or symlink in home dir, replace it with
74
80
                        # directory (no need to recurse, since we're copying the whole
75
81
                        # directory)
76
82
                        elif dst.type == 'f' or dst.type == 'l':
77
 
                                if the.verbose >= 2: self.print_op( rel_file, 'd>' + dst.type )
 
83
                                self.print_op( rel_file, 'd', '*', dst.type )
78
84
                                os.unlink( dst.file )
79
85
                                shutil.copytree( src.file, dst.file, True )
80
86
 
86
92
 
87
93
                        # if dst entity doesn't exist, copy file
88
94
                        if dst.type == '_':
89
 
                                if the.verbose >= 2: self.print_op( rel_file, 'f>_' )
 
95
                                self.print_op( rel_file, 'f', '*', '_' )
90
96
                                shutil.copy( src.file, dst.file )
91
97
                                shutil.copystat( src.file, dst.file )
92
98
 
93
99
                        # if dst entity is a file, replace it only if it differs
94
100
                        elif dst.type == 'f':
95
101
                                if not filecmp.cmp( src.file, dst.file ):
96
 
                                        if the.verbose >= 2: self.print_op( rel_file, 'f>f' )
 
102
                                        self.print_op( rel_file, 'f', '*', 'f' )
97
103
                                        os.unlink( dst.file )
98
104
                                        shutil.copy( src.file, dst.file )
99
105
                                        shutil.copystat( src.file, dst.file )
100
106
                                else:
101
 
                                        if the.verbose >= 2: self.print_op( rel_file, 'f=f' )
 
107
                                        self.print_op( rel_file, 'f', '=', 'f' )
102
108
 
103
109
                        # if dst entity is a directory, replace it with file
104
110
                        elif dst.type == 'd':
105
 
                                if the.verbose >= 2: self.print_op( rel_file, 'f>d' )
 
111
                                self.print_op( rel_file, 'f', '*', 'd' )
106
112
                                shutil.rmtree( dst.file )
107
113
                                shutil.copy( src.file, dst.file )
108
114
                                shutil.copystat( src.file, dst.file )
109
115
 
110
116
                        # if dst entity is a symlink, replace it with file
111
117
                        elif dst.type == 'l':
112
 
                                if the.verbose >= 2: self.print_op( rel_file, 'f>l' )
 
118
                                self.print_op( rel_file, 'f', '*', 'l' )
113
119
                                os.unlink( dst.file )
114
120
                                shutil.copy( src.file, dst.file )
115
121
                                shutil.copystat( src.file, dst.file )
122
128
 
123
129
                        # if dst entity doesn't exist, copy symlink
124
130
                        if dst.type == '_':
125
 
                                if the.verbose >= 2: self.print_op( rel_file, 'l>_' )
 
131
                                self.print_op( rel_file, 'l', '*', '_' )
126
132
                                os.symlink( os.readlink( src.file ), dst.file )
127
133
 
128
134
                        # if dst entity is a symlink, replace it only if it differs
129
135
                        elif dst.type == 'l':
130
136
                                if os.readlink( src.file ) != os.readlink( dst.file ):
131
 
                                        if the.verbose >= 2: self.print_op( rel_file, 'l>l' )
 
137
                                        self.print_op( rel_file, 'l', '*', 'l' )
132
138
                                        os.unlink( dst.file )
133
139
                                        os.symlink( os.readlink( src.file ), dst.file )
134
140
                                else:
135
 
                                        if the.verbose >= 2: self.print_op( rel_file, 'l=l' )
 
141
                                        self.print_op( rel_file, 'l', '=', 'l' )
136
142
 
137
143
                        # if dst entity is a file, replace it with symlink
138
144
                        elif dst.type == 'f':
139
 
                                if the.verbose >= 2: self.print_op( rel_file, 'l>f' )
 
145
                                self.print_op( rel_file, 'l', '*', 'f' )
140
146
                                os.unlink( dst.file )
141
147
                                os.symlink( os.readlink( src.file ), dst.file )
142
148
 
147
153
                                # acceptable substitute, just recurse
148
154
                                if self.check_src_symlinks and src.link_type == 'd' and \
149
155
                                                the.config.symlinks.matches( rel_file ):
150
 
                                        if the.verbose >= 2: self.print_op( rel_file, 'd@d' )
 
156
                                        self.print_op( rel_file, 'd', '@', 'd' )
151
157
                                        return True
152
158
 
153
159
                                # else replace it with a symlink
154
 
                                if the.verbose >= 2: self.print_op( rel_file, 'l>d' )
 
160
                                self.print_op( rel_file, 'l', '*', 'd' )
155
161
                                shutil.rmtree( dst.file )
156
162
                                os.symlink( os.readlink( src.file ), dst.file )
157
163
 
167
173
 
168
174
                        # if dst entity is a file or symlink, delete it
169
175
                        elif dst.type == 'f' or dst.type == 'l':
170
 
                                if the.verbose >= 2: self.print_op( rel_file, '_>' + dst.type )
 
176
                                self.print_op( rel_file, '_', '*', dst.type )
171
177
                                os.unlink( dst.file )
172
178
 
173
179
                        # if dst entity is a directory, delete it
174
180
                        elif dst.type == 'd':
175
 
                                if the.verbose >= 2: self.print_op( rel_file, '_>d' )
 
181
                                self.print_op( rel_file, '_', '*', 'd' )
176
182
                                shutil.rmtree( dst.file )
177
183
 
178
184
                        else: