/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_out.py

  • Committer: Tim Marston
  • Date: 2014-04-05 17:30:19 UTC
  • Revision ID: tim@ed.am-20140405173019-5eoi82r8i3etgn4j
added file matcher (for symlink accept and/or ignore lists)

Show diffs side-by-side

added added

removed removed

 
1
# copy_out.py
 
2
#
 
3
# Copyright (C) 2013 to 2014 Tim Marston <tim@edm.am>
 
4
#
 
5
# This file is part of stdhome (hereafter referred to as "this program").
 
6
# See http://ed.am/dev/stdhome for more information.
 
7
#
 
8
# This program is free software: you can redistribute it and/or modify
 
9
# it under the terms of the GNU General Public License as published by
 
10
# the Free Software Foundation, either version 3 of the License, or
 
11
# (at your option) any later version.
 
12
#
 
13
# This program is distributed in the hope that it will be useful,
 
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
# GNU General Public License for more details.
 
17
#
 
18
# You should have received a copy of the GNU General Public License
 
19
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
 
 
21
 
 
22
import filecmp, os, shutil
 
23
from walker import Walker
 
24
import stdhome.the as the
 
25
 
 
26
 
 
27
class CopyOutWalker( Walker ):
 
28
        """The copy-out walker traverses the repo, copying its content to the home
 
29
        directory.  It is run *after* checking for conflicts that might occur during
 
30
        copy-out, so any conflicts that exist can be assumed to be unimportant and
 
31
        disposable.  In other words, this will happily overwrite stuff in the home
 
32
        directory, without regard to its content.
 
33
 
 
34
        Walker source:       repo
 
35
        Walker destination:  home dir
 
36
        Walker traversing:   repo (or a provided file list, which may include stuff
 
37
                                                        that no longer exists in the repo
 
38
        """
 
39
 
 
40
        def __init__( self, updated_files = None ):
 
41
                self.src_dir = the.repo.full_dir
 
42
                self.dst_dir = the.full_home_dir
 
43
                self.walk_list = updated_files if updated_files is not None else \
 
44
                                                 self.generate_walk_list( the.repo.full_dir )
 
45
 
 
46
                self.accept_symlinks = list()
 
47
 
 
48
 
 
49
        def process( self, rel_file, src, dst ):
 
50
 
 
51
                # directory (in repo)
 
52
                if src.type == 'd':
 
53
 
 
54
                        # if entity doesn't exist in home dir, create directory (no need to
 
55
                        # recurse, since we're copying the whole directory)
 
56
                        if dst.type == '_':
 
57
                                if the.verbose > 1: print "  _<d " + rel_file
 
58
                                os.mkdir( dst.file )
 
59
                                shutil.copystat( src.file, dst.file )
 
60
                                return False
 
61
 
 
62
                        # if entity is a directory in home dir, copy permissions, as
 
63
                        # required (and recurse)
 
64
                        elif dst.type == 'd':
 
65
                                # TODO: should check permission and only do as necessary
 
66
                                if the.verbose > 1: print "  d<d " + rel_file
 
67
                                shutil.copystat( src.file, dst.file )
 
68
                                return True
 
69
 
 
70
                        # TODO: if entity is a symlink to a directory, and this is
 
71
                        # acceptable, just recurse
 
72
#                       elif dst.link_type == 'd' and self.accept_list.match( rel_file ):
 
73
#                               if the.verbose > 1: print "  d@=d " + rel_file
 
74
#                               return True
 
75
 
 
76
                        # if entity is a file or symlink in home dir, replace it with
 
77
                        # directory (no need to recurse, since we're copying the whole
 
78
                        # directory)
 
79
                        elif dst.type == 'f' or dst.type == 'l':
 
80
                                if the.verbose > 1: print "  %s<d %s" % ( dst.type, rel_file )
 
81
                                os.unlink( dst.file )
 
82
                                os.mkdir( dst.file )
 
83
                                shutil.copystat( src.file, dst.file )
 
84
                                return False
 
85
 
 
86
                        else:
 
87
                                raise NotImplementedError()
 
88
 
 
89
                # file (in repo)
 
90
                if src.type == 'f':
 
91
 
 
92
                        # if entity doesn't exist in home dir, copy file
 
93
                        if dst.type == '_':
 
94
                                if the.verbose > 1: print "  _<f " + rel_file
 
95
                                shutil.copy( src.file, dst.file )
 
96
                                shutil.copystat( src.file, dst.file )
 
97
 
 
98
                        # if entity is a file in home dir, replace it only if it differs
 
99
                        elif dst.type == 'f':
 
100
                                if not filecmp.cmp( src.file, dst.file ):
 
101
                                        if the.verbose > 1: print "  f<f " + rel_file
 
102
                                        os.unlink( dst.file )
 
103
                                        shutil.copy( src.file, dst.file )
 
104
                                        shutil.copystat( src.file, dst.file )
 
105
                                else:
 
106
                                        if the.verbose > 1: print "  f=f " + rel_file
 
107
 
 
108
                        # if entity is a directory in home dir, replace it with file
 
109
                        elif dst.type == 'd':
 
110
                                if the.verbose > 1: print "  d<f " + rel_file
 
111
                                shutil.rmtree( dst.file )
 
112
                                shutil.copy( src.file, dst.file )
 
113
                                shutil.copystat( src.file, dst.file )
 
114
 
 
115
                        # if entity is a symlink in home dir, replace it with file
 
116
                        elif dst.type == 'l':
 
117
                                if the.verbose > 1: print "  l<f " + rel_file
 
118
                                os.unlink( dst.file )
 
119
                                shutil.copy( src.file, dst.file )
 
120
                                shutil.copystat( src.file, dst.file )
 
121
 
 
122
                        else:
 
123
                                raise NotImplementedError()
 
124
 
 
125
                # link (in repo)
 
126
                if src.type == 'l':
 
127
 
 
128
                        # if entity doesn't exist in home dir, copy symlink
 
129
                        if dst.type == '_':
 
130
                                if the.verbose > 1: print "  _<l " + rel_file
 
131
                                os.symlink( os.readlink( src.file ), dst.file )
 
132
 
 
133
                        # if entity is a symlink in home dir, replace it only if it differs
 
134
                        elif dst.type == 'l':
 
135
                                if os.readlink( src.file ) != os.readlink( dst.file ):
 
136
                                        if the.verbose > 1: print "  l<l " + rel_file
 
137
                                        os.unlink( dst.file )
 
138
                                        os.symlink( os.readlink( src.file ), dst.file )
 
139
                                else:
 
140
                                        if the.verbose > 1: print "  l=l " + rel_file
 
141
 
 
142
                        # if entity is a file in home dir, replace it with file
 
143
                        elif dst.type == 'f':
 
144
                                if the.verbose > 1: print "  f<l " + rel_file
 
145
                                os.unlink( dst.file )
 
146
                                os.symlink( os.readlink( src.file ), dst.file )
 
147
 
 
148
                        # if entity is a directory in home dir, replace it with file
 
149
                        elif dst.type == 'd':
 
150
                                if the.verbose > 1: print "  d<l " + rel_file
 
151
                                shutil.rmtree( dst.file )
 
152
                                os.symlink( os.readlink( src.file ), dst.file )
 
153
 
 
154
                        else:
 
155
                                raise NotImplementedError()
 
156
 
 
157
                # deleted file (in repo)
 
158
                if src.type == '_':
 
159
 
 
160
                        # if entity doesn't exist in home dir, we're good
 
161
                        if dst.type == '_':
 
162
                                pass;
 
163
 
 
164
                        # if entity is a file or symlink in home dir, delete it
 
165
                        if dst.type == 'f' or dst.type == 'l':
 
166
                                if the.verbose > 1: print "  %s<_ %s" % ( dst.type, rel_file )
 
167
                                os.unlink( dst.file )
 
168
 
 
169
                        # if entity is a directory in home dir, delete it
 
170
                        elif dst.type == 'd':
 
171
                                if the.verbose > 1: print "  d<_ " + rel_file
 
172
                                shutil.rmtree( dst.file )
 
173
 
 
174
                        else:
 
175
                                raise NotImplementedError()
 
176
 
 
177
                # non-directories can not be recursed in to
 
178
                return False