/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-18 14:42:00 UTC
  • Revision ID: tim@ed.am-20140418144200-ksbr3l58p2v3jhy2
fixed bugs in command.expand_files, where results could be not unique, nor
sorted, and make sure the last component of the files is not resolved if it is a
symlink

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