/stdhome

To get this branch, use:
bzr branch http://bzr.ed.am/stdhome
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
1
# copy_base.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 CopyBaseWalker( Walker ):
28
	"""The copy-base walker traverses a walklist ruthlessly mirroring src to dst.
29
	It is designed to be the base class of both the copy-in and copy-out walker,
30
	both of which are specialisations of this purpose.  See them for more
31
	information.
32
	"""
33
27 by Tim Marston
got symlink accept lists working; fixed some walker bugs
34
	accept_list = None
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
35
36
37
	def process( self, rel_file, src, dst ):
38
39
		# src entity is directory
40
		if src.type == 'd':
41
42
			# if dst entity doesn't exist, create directory (no need to recurse,
43
			# since we're copying the whole directory)
44
			if dst.type == '_':
32 by Tim Marston
make verbose levels clearer
45
				if the.verbose >= 2: self.print_op( rel_file, 'd>_' )
27 by Tim Marston
got symlink accept lists working; fixed some walker bugs
46
				shutil.copytree( src.file, dst.file, True )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
47
48
			# if dst entity is a directory, copy permissions, as required (and
49
			# recurse)
50
			elif dst.type == 'd':
51
				# TODO: should check permission and only do as necessary
32 by Tim Marston
make verbose levels clearer
52
				if the.verbose >= 2: self.print_op( rel_file, 'd>d' )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
53
				shutil.copystat( src.file, dst.file )
54
				return True
55
27 by Tim Marston
got symlink accept lists working; fixed some walker bugs
56
			# if dst entity is a symlink to a directory, and this is an
57
			# acceptable substitute, just recurse
58
			elif dst.link_type == 'd' and \
59
					self.accept_list and self.accept_list.match( rel_file ):
32 by Tim Marston
make verbose levels clearer
60
				if the.verbose >= 2: self.print_op( rel_file, 'd@d' )
23 by Tim Marston
implemented CopyInWalker in terms of CopyBaseWalker, changed implementation of
61
				return True
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
62
63
			# if dst entity is a file or symlink in home dir, replace it with
64
			# directory (no need to recurse, since we're copying the whole
65
			# directory)
66
			elif dst.type == 'f' or dst.type == 'l':
32 by Tim Marston
make verbose levels clearer
67
				if the.verbose >= 2: self.print_op( rel_file, 'd>' + dst.type )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
68
				os.unlink( dst.file )
27 by Tim Marston
got symlink accept lists working; fixed some walker bugs
69
				shutil.copytree( src.file, dst.file, True )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
70
71
			else:
72
				raise NotImplementedError()
73
74
		# src entity is file
27 by Tim Marston
got symlink accept lists working; fixed some walker bugs
75
		elif src.type == 'f':
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
76
77
			# if dst entity doesn't exist, copy file
78
			if dst.type == '_':
32 by Tim Marston
make verbose levels clearer
79
				if the.verbose >= 2: self.print_op( rel_file, 'f>_' )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
80
				shutil.copy( src.file, dst.file )
81
				shutil.copystat( src.file, dst.file )
82
83
			# if dst entity is a file, replace it only if it differs
84
			elif dst.type == 'f':
85
				if not filecmp.cmp( src.file, dst.file ):
32 by Tim Marston
make verbose levels clearer
86
					if the.verbose >= 2: self.print_op( rel_file, 'f>f' )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
87
					os.unlink( dst.file )
88
					shutil.copy( src.file, dst.file )
89
					shutil.copystat( src.file, dst.file )
90
				else:
32 by Tim Marston
make verbose levels clearer
91
					if the.verbose >= 2: self.print_op( rel_file, 'f=f' )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
92
93
			# if dst entity is a directory, replace it with file
94
			elif dst.type == 'd':
32 by Tim Marston
make verbose levels clearer
95
				if the.verbose >= 2: self.print_op( rel_file, 'f>d' )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
96
				shutil.rmtree( dst.file )
97
				shutil.copy( src.file, dst.file )
98
				shutil.copystat( src.file, dst.file )
99
100
			# if dst entity is a symlink, replace it with file
101
			elif dst.type == 'l':
32 by Tim Marston
make verbose levels clearer
102
				if the.verbose >= 2: self.print_op( rel_file, 'f>l' )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
103
				os.unlink( dst.file )
104
				shutil.copy( src.file, dst.file )
105
				shutil.copystat( src.file, dst.file )
106
107
			else:
108
				raise NotImplementedError()
109
110
		# src entity is a symlink
27 by Tim Marston
got symlink accept lists working; fixed some walker bugs
111
		elif src.type == 'l':
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
112
113
			# if dst entity doesn't exist, copy symlink
114
			if dst.type == '_':
32 by Tim Marston
make verbose levels clearer
115
				if the.verbose >= 2: self.print_op( rel_file, 'l>_' )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
116
				os.symlink( os.readlink( src.file ), dst.file )
117
118
			# if dst entity is a symlink, replace it only if it differs
119
			elif dst.type == 'l':
120
				if os.readlink( src.file ) != os.readlink( dst.file ):
32 by Tim Marston
make verbose levels clearer
121
					if the.verbose >= 2: self.print_op( rel_file, 'l>l' )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
122
					os.unlink( dst.file )
123
					os.symlink( os.readlink( src.file ), dst.file )
124
				else:
32 by Tim Marston
make verbose levels clearer
125
					if the.verbose >= 2: self.print_op( rel_file, 'l=l' )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
126
127
			# if dst entity is a file, replace it with symlink
128
			elif dst.type == 'f':
32 by Tim Marston
make verbose levels clearer
129
				if the.verbose >= 2: self.print_op( rel_file, 'l>f' )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
130
				os.unlink( dst.file )
131
				os.symlink( os.readlink( src.file ), dst.file )
132
27 by Tim Marston
got symlink accept lists working; fixed some walker bugs
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 ):
32 by Tim Marston
make verbose levels clearer
137
				if the.verbose >= 2: self.print_op( rel_file, 'd@d' )
27 by Tim Marston
got symlink accept lists working; fixed some walker bugs
138
				return True
139
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
140
			# if dst entity is a directory, replace it with symlink
141
			elif dst.type == 'd':
32 by Tim Marston
make verbose levels clearer
142
				if the.verbose >= 2: self.print_op( rel_file, 'l>d' )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
143
				shutil.rmtree( dst.file )
144
				os.symlink( os.readlink( src.file ), dst.file )
145
146
			else:
147
				raise NotImplementedError()
148
149
		# src entity is missing
27 by Tim Marston
got symlink accept lists working; fixed some walker bugs
150
		elif src.type == '_':
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
151
152
			# if dst entity doesn't exist, we're good
153
			if dst.type == '_':
154
				pass;
155
156
			# if dst entity is a file or symlink, delete it
23 by Tim Marston
implemented CopyInWalker in terms of CopyBaseWalker, changed implementation of
157
			elif dst.type == 'f' or dst.type == 'l':
32 by Tim Marston
make verbose levels clearer
158
				if the.verbose >= 2: self.print_op( rel_file, '_>' + dst.type )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
159
				os.unlink( dst.file )
160
161
			# if dst entity is a directory, delete it
162
			elif dst.type == 'd':
32 by Tim Marston
make verbose levels clearer
163
				if the.verbose >= 2: self.print_op( rel_file, '_>d' )
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
164
				shutil.rmtree( dst.file )
165
166
			else:
167
				raise NotImplementedError()
168
27 by Tim Marston
got symlink accept lists working; fixed some walker bugs
169
		# if we got here, we don't want to recurse...
20 by Tim Marston
moved funcitonality of copy-out walker in to base class and made copy-out walker
170
		return False