/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-04-05 22:26:17 UTC
  • Revision ID: tim@ed.am-20140405222617-4nf4alk3u2dxe430
removed reference to copy-in conflicts (which no longer exist)

Show diffs side-by-side

added added

removed removed

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
from stdhome.file_matcher import FileMatcher
 
25
import stdhome.the as the
26
26
 
27
27
 
28
28
class CopyBaseWalker( Walker ):
29
29
        """The copy-base walker traverses a walklist ruthlessly mirroring src to dst.
30
30
        It is designed to be the base class of both the copy-in and copy-out walker,
31
31
        both of which are specialisations of this purpose.  See them for more
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
        information.
37
33
        """
38
34
 
39
 
 
40
 
        def __init__( self ):
41
 
                self.check_src_symlinks = False
42
 
                self.check_dst_symlinks = False
43
 
                self.check_dst_ignores = False
 
35
        def __init__( self, updated_files = None ):
 
36
                self.accept_list = FileMatcher()
44
37
 
45
38
 
46
39
        def process( self, rel_file, src, dst ):
47
40
 
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
 
 
53
41
                # src entity is directory
54
42
                if src.type == 'd':
55
43
 
56
44
                        # if dst entity doesn't exist, create directory (no need to recurse,
57
45
                        # since we're copying the whole directory)
58
46
                        if dst.type == '_':
59
 
                                self.print_op( rel_file, 'd', '*', '_' )
60
 
                                shutil.copytree( src.file, dst.file, True )
 
47
                                if the.verbose > 1: self.print_op( rel_file, 'd>_' )
 
48
                                os.mkdir( dst.file )
 
49
                                shutil.copystat( src.file, dst.file )
 
50
                                return False
61
51
 
62
52
                        # if dst entity is a directory, copy permissions, as required (and
63
53
                        # recurse)
64
54
                        elif dst.type == 'd':
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' )
 
55
                                # TODO: should check permission and only do as necessary
 
56
                                if the.verbose > 1: self.print_op( rel_file, 'd>d' )
 
57
                                shutil.copystat( src.file, dst.file )
70
58
                                return True
71
59
 
72
 
                        # if dst entity is a symlink to a directory, and this is an
73
 
                        # acceptable substitute, just recurse
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' )
 
60
                        # TODO: if dst entity is a symlink to a directory, and rel_file is
 
61
                        # matched by the acceptable symlinks file matcher, just recurse
 
62
                        elif dst.link_type == 'd' and self.accept_list.match( rel_file ):
 
63
                                if the.verbose > 1: self.print_op( rel_file, 'd@d' )
77
64
                                return True
78
65
 
79
66
                        # if dst entity is a file or symlink in home dir, replace it with
80
67
                        # directory (no need to recurse, since we're copying the whole
81
68
                        # directory)
82
69
                        elif dst.type == 'f' or dst.type == 'l':
83
 
                                self.print_op( rel_file, 'd', '*', dst.type )
 
70
                                if the.verbose > 1: self.print_op( rel_file, 'd>' + dst.type )
84
71
                                os.unlink( dst.file )
85
 
                                shutil.copytree( src.file, dst.file, True )
 
72
                                os.mkdir( dst.file )
 
73
                                shutil.copystat( src.file, dst.file )
 
74
                                return False
86
75
 
87
76
                        else:
88
77
                                raise NotImplementedError()
89
78
 
90
79
                # src entity is file
91
 
                elif src.type == 'f':
 
80
                if src.type == 'f':
92
81
 
93
82
                        # if dst entity doesn't exist, copy file
94
83
                        if dst.type == '_':
95
 
                                self.print_op( rel_file, 'f', '*', '_' )
 
84
                                if the.verbose > 1: self.print_op( rel_file, 'f>_' )
96
85
                                shutil.copy( src.file, dst.file )
97
86
                                shutil.copystat( src.file, dst.file )
98
87
 
99
88
                        # if dst entity is a file, replace it only if it differs
100
89
                        elif dst.type == 'f':
101
90
                                if not filecmp.cmp( src.file, dst.file ):
102
 
                                        self.print_op( rel_file, 'f', '*', 'f' )
 
91
                                        if the.verbose > 1: self.print_op( rel_file, 'f>f' )
103
92
                                        os.unlink( dst.file )
104
93
                                        shutil.copy( src.file, dst.file )
105
94
                                        shutil.copystat( src.file, dst.file )
106
95
                                else:
107
 
                                        self.print_op( rel_file, 'f', '=', 'f' )
 
96
                                        if the.verbose > 1: self.print_op( rel_file, 'f=f' )
108
97
 
109
98
                        # if dst entity is a directory, replace it with file
110
99
                        elif dst.type == 'd':
111
 
                                self.print_op( rel_file, 'f', '*', 'd' )
 
100
                                if the.verbose > 1: self.print_op( rel_file, 'f>d' )
112
101
                                shutil.rmtree( dst.file )
113
102
                                shutil.copy( src.file, dst.file )
114
103
                                shutil.copystat( src.file, dst.file )
115
104
 
116
105
                        # if dst entity is a symlink, replace it with file
117
106
                        elif dst.type == 'l':
118
 
                                self.print_op( rel_file, 'f', '*', 'l' )
 
107
                                if the.verbose > 1: self.print_op( rel_file, 'f>l' )
119
108
                                os.unlink( dst.file )
120
109
                                shutil.copy( src.file, dst.file )
121
110
                                shutil.copystat( src.file, dst.file )
124
113
                                raise NotImplementedError()
125
114
 
126
115
                # src entity is a symlink
127
 
                elif src.type == 'l':
 
116
                if src.type == 'l':
128
117
 
129
118
                        # if dst entity doesn't exist, copy symlink
130
119
                        if dst.type == '_':
131
 
                                self.print_op( rel_file, 'l', '*', '_' )
 
120
                                if the.verbose > 1: self.print_op( rel_file, 'l>_' )
132
121
                                os.symlink( os.readlink( src.file ), dst.file )
133
122
 
134
123
                        # if dst entity is a symlink, replace it only if it differs
135
124
                        elif dst.type == 'l':
136
125
                                if os.readlink( src.file ) != os.readlink( dst.file ):
137
 
                                        self.print_op( rel_file, 'l', '*', 'l' )
 
126
                                        if the.verbose > 1: self.print_op( rel_file, 'l>l' )
138
127
                                        os.unlink( dst.file )
139
128
                                        os.symlink( os.readlink( src.file ), dst.file )
140
129
                                else:
141
 
                                        self.print_op( rel_file, 'l', '=', 'l' )
 
130
                                        if the.verbose > 1: self.print_op( rel_file, 'l=l' )
142
131
 
143
132
                        # if dst entity is a file, replace it with symlink
144
133
                        elif dst.type == 'f':
145
 
                                self.print_op( rel_file, 'l', '*', 'f' )
 
134
                                if the.verbose > 1: self.print_op( rel_file, 'l>f' )
146
135
                                os.unlink( dst.file )
147
136
                                os.symlink( os.readlink( src.file ), dst.file )
148
137
 
149
 
                        # if dst entity is a directory...
 
138
                        # if dst entity is a directory, replace it with symlink
150
139
                        elif dst.type == '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' )
 
140
                                if the.verbose > 1: self.print_op( rel_file, 'l>d' )
161
141
                                shutil.rmtree( dst.file )
162
142
                                os.symlink( os.readlink( src.file ), dst.file )
163
143
 
165
145
                                raise NotImplementedError()
166
146
 
167
147
                # src entity is missing
168
 
                elif src.type == '_':
 
148
                if src.type == '_':
169
149
 
170
150
                        # if dst entity doesn't exist, we're good
171
151
                        if dst.type == '_':
173
153
 
174
154
                        # if dst entity is a file or symlink, delete it
175
155
                        elif dst.type == 'f' or dst.type == 'l':
176
 
                                self.print_op( rel_file, '_', '*', dst.type )
 
156
                                if the.verbose > 1: self.print_op( rel_file, '_>' + dst.type )
177
157
                                os.unlink( dst.file )
178
158
 
179
159
                        # if dst entity is a directory, delete it
180
160
                        elif dst.type == 'd':
181
 
                                self.print_op( rel_file, '_', '*', 'd' )
 
161
                                if the.verbose > 1: self.print_op( rel_file, '_>d' )
182
162
                                shutil.rmtree( dst.file )
183
163
 
184
164
                        else:
185
165
                                raise NotImplementedError()
186
166
 
187
 
                # if we got here, we don't want to recurse...
 
167
                # non-directories can not be recursed in to
188
168
                return False