/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-05-22 16:40:51 UTC
  • Revision ID: tim@ed.am-20160522164051-h2n54oaxg25c7x7c
updated todo

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
 
        accept_list = None
 
39
 
 
40
        def __init__( self ):
 
41
                self.check_src_symlinks = False
 
42
                self.check_dst_symlinks = False
 
43
                self.check_dst_ignores = False
35
44
 
36
45
 
37
46
        def process( self, rel_file, src, dst ):
38
47
 
 
48
                # ignore?
 
49
                if self.check_dst_ignores and the.config.ignores.matches( rel_file ):
 
50
                        self.print_op( rel_file, src.type, '#', dst.type )
 
51
                        return True
 
52
 
39
53
                # src entity is directory
40
54
                if src.type == 'd':
41
55
 
42
56
                        # if dst entity doesn't exist, create directory (no need to recurse,
43
57
                        # since we're copying the whole directory)
44
58
                        if dst.type == '_':
45
 
                                if the.verbose >= 2: self.print_op( rel_file, 'd>_' )
 
59
                                self.print_op( rel_file, 'd', '*', '_' )
46
60
                                shutil.copytree( src.file, dst.file, True )
47
61
 
48
62
                        # if dst entity is a directory, copy permissions, as required (and
49
63
                        # recurse)
50
64
                        elif dst.type == 'd':
51
 
                                # TODO: should check permission and only do as necessary
52
 
                                if the.verbose >= 2: self.print_op( rel_file, 'd>d' )
53
 
                                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' )
54
70
                                return True
55
71
 
56
72
                        # if dst entity is a symlink to a directory, and this is an
57
73
                        # acceptable substitute, just recurse
58
 
                        elif dst.link_type == 'd' and \
59
 
                                        self.accept_list and self.accept_list.match( rel_file ):
60
 
                                if the.verbose >= 2: self.print_op( rel_file, 'd@d' )
 
74
                        elif self.check_dst_symlinks and dst.link_type == 'd' and \
 
75
                                        the.config.symlinks.matches( rel_file ):
 
76
                                self.print_op( rel_file, 'd', '@', 'd' )
61
77
                                return True
62
78
 
63
79
                        # if dst entity is a file or symlink in home dir, replace it with
64
80
                        # directory (no need to recurse, since we're copying the whole
65
81
                        # directory)
66
82
                        elif dst.type == 'f' or dst.type == 'l':
67
 
                                if the.verbose >= 2: self.print_op( rel_file, 'd>' + dst.type )
 
83
                                self.print_op( rel_file, 'd', '*', dst.type )
68
84
                                os.unlink( dst.file )
69
85
                                shutil.copytree( src.file, dst.file, True )
70
86
 
76
92
 
77
93
                        # if dst entity doesn't exist, copy file
78
94
                        if dst.type == '_':
79
 
                                if the.verbose >= 2: self.print_op( rel_file, 'f>_' )
 
95
                                self.print_op( rel_file, 'f', '*', '_' )
80
96
                                shutil.copy( src.file, dst.file )
81
97
                                shutil.copystat( src.file, dst.file )
82
98
 
83
99
                        # if dst entity is a file, replace it only if it differs
84
100
                        elif dst.type == 'f':
85
101
                                if not filecmp.cmp( src.file, dst.file ):
86
 
                                        if the.verbose >= 2: self.print_op( rel_file, 'f>f' )
 
102
                                        self.print_op( rel_file, 'f', '*', 'f' )
87
103
                                        os.unlink( dst.file )
88
104
                                        shutil.copy( src.file, dst.file )
89
105
                                        shutil.copystat( src.file, dst.file )
90
106
                                else:
91
 
                                        if the.verbose >= 2: self.print_op( rel_file, 'f=f' )
 
107
                                        self.print_op( rel_file, 'f', '=', 'f' )
92
108
 
93
109
                        # if dst entity is a directory, replace it with file
94
110
                        elif dst.type == 'd':
95
 
                                if the.verbose >= 2: self.print_op( rel_file, 'f>d' )
 
111
                                self.print_op( rel_file, 'f', '*', 'd' )
96
112
                                shutil.rmtree( dst.file )
97
113
                                shutil.copy( src.file, dst.file )
98
114
                                shutil.copystat( src.file, dst.file )
99
115
 
100
116
                        # if dst entity is a symlink, replace it with file
101
117
                        elif dst.type == 'l':
102
 
                                if the.verbose >= 2: self.print_op( rel_file, 'f>l' )
 
118
                                self.print_op( rel_file, 'f', '*', 'l' )
103
119
                                os.unlink( dst.file )
104
120
                                shutil.copy( src.file, dst.file )
105
121
                                shutil.copystat( src.file, dst.file )
112
128
 
113
129
                        # if dst entity doesn't exist, copy symlink
114
130
                        if dst.type == '_':
115
 
                                if the.verbose >= 2: self.print_op( rel_file, 'l>_' )
 
131
                                self.print_op( rel_file, 'l', '*', '_' )
116
132
                                os.symlink( os.readlink( src.file ), dst.file )
117
133
 
118
134
                        # if dst entity is a symlink, replace it only if it differs
119
135
                        elif dst.type == 'l':
120
136
                                if os.readlink( src.file ) != os.readlink( dst.file ):
121
 
                                        if the.verbose >= 2: self.print_op( rel_file, 'l>l' )
 
137
                                        self.print_op( rel_file, 'l', '*', 'l' )
122
138
                                        os.unlink( dst.file )
123
139
                                        os.symlink( os.readlink( src.file ), dst.file )
124
140
                                else:
125
 
                                        if the.verbose >= 2: self.print_op( rel_file, 'l=l' )
 
141
                                        self.print_op( rel_file, 'l', '=', 'l' )
126
142
 
127
143
                        # if dst entity is a file, replace it with symlink
128
144
                        elif dst.type == 'f':
129
 
                                if the.verbose >= 2: self.print_op( rel_file, 'l>f' )
 
145
                                self.print_op( rel_file, 'l', '*', 'f' )
130
146
                                os.unlink( dst.file )
131
147
                                os.symlink( os.readlink( src.file ), dst.file )
132
148
 
133
 
                        # if dst entity is a directory, and src entity is a symlink to a
134
 
                        # directory, and this is an acceptable substitute, just recurse
135
 
                        elif dst.type == 'd' and src.link_type == 'd' and \
136
 
                                        self.accept_list and self.accept_list.match( rel_file ):
137
 
                                if the.verbose >= 2: self.print_op( rel_file, 'd@d' )
138
 
                                return True
139
 
 
140
 
                        # if dst entity is a directory, replace it with symlink
 
149
                        # if dst entity is a directory...
141
150
                        elif dst.type == 'd':
142
 
                                if the.verbose >= 2: self.print_op( rel_file, 'l>d' )
 
151
 
 
152
                                # if src entity is a symlink to a directory, and this is an
 
153
                                # acceptable substitute, just recurse
 
154
                                if self.check_src_symlinks and src.link_type == 'd' and \
 
155
                                                the.config.symlinks.matches( rel_file ):
 
156
                                        self.print_op( rel_file, 'd', '@', 'd' )
 
157
                                        return True
 
158
 
 
159
                                # else replace it with a symlink
 
160
                                self.print_op( rel_file, 'l', '*', 'd' )
143
161
                                shutil.rmtree( dst.file )
144
162
                                os.symlink( os.readlink( src.file ), dst.file )
145
163
 
155
173
 
156
174
                        # if dst entity is a file or symlink, delete it
157
175
                        elif dst.type == 'f' or dst.type == 'l':
158
 
                                if the.verbose >= 2: self.print_op( rel_file, '_>' + dst.type )
 
176
                                self.print_op( rel_file, '_', '*', dst.type )
159
177
                                os.unlink( dst.file )
160
178
 
161
179
                        # if dst entity is a directory, delete it
162
180
                        elif dst.type == 'd':
163
 
                                if the.verbose >= 2: self.print_op( rel_file, '_>d' )
 
181
                                self.print_op( rel_file, '_', '*', 'd' )
164
182
                                shutil.rmtree( dst.file )
165
183
 
166
184
                        else: