/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: 2014-07-17 18:17:18 UTC
  • Revision ID: tim@ed.am-20140717181718-gxi5lpi8qszsigxf
switch to using bzr+ssh, rather than sftp (to work around broken pimiko)

Show diffs side-by-side

added added

removed removed

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