/stdhome

To get this branch, use:
bzr branch http://bzr.ed.am/stdhome
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# copy_out_walker.py
#
# Copyright (C) 2013 to 2014 Tim Marston <tim@edm.am>
#
# This file is part of stdhome (hereafter referred to as "this program").
# See http://ed.am/dev/stdhome for more information.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


import filecmp, os, shutil
from walker import Walker
import stdhome.the as the


class CopyOutWalker( Walker ):
	"""The copy-out walker traverses the repo, copying its content to the home
	directory.  It is run *after* checking for conflicts that might occur during
	copy-out, so any conflicts that exist can be assumed to be unimportant and
	disposable.  In other words, this will happily overwrite stuff in the home
	directory, without regard to its content.

	Walker source:       repo
	Walker destination:  home dir
	Walker traversing:   repo (or a provided file list, which may include stuff
							that no longer exists in the repo
	"""

	def __init__( self, updated_files = None ):
		self.src_dir = the.repo.full_dir
		self.dst_dir = the.full_fsdir
		self.walk_list = updated_files if updated_files is not None else \
						 self.generate_walk_list( the.repo.full_dir )


	def process( self, rel_file, src_file, src_type, dst_file, dst_type ):

		# directory (in repo)
		if src_type == 'd':

			# if entity doesn't exist in home dir, create directory (no need to
			# recurse, since we're copying the whole directory)
			if dst_type == '_':
				if the.verbose: print "  _<d " + rel_file
				os.mkdir( dst_file )
				shutil.copystat( src_file, dst_file )
				return False

			# if entity is a file or symlink in home dir, replace it with
			# directory (no need to recurse, since we're copying the whole
			# directory)
			elif dst_type == 'f' or dst_type == 'l':
				if the.verbose: print "  %s<d %s" % ( dst_type, rel_file )
				os.unlink( dst_file )
				os.mkdir( dst_file )
				shutil.copystat( src_file, dst_file )
				return False

			# if entity is a directory in home dir, copy permissions, as
			# required (and recurse)
			elif dst_type == 'd':
				# TODO: should check permission and only do as necessary
				if the.verbose: print "  d<d " + rel_file
				shutil.copystat( src_file, dst_file )
				return True

			else:
				raise NotImplementedError()

		# file (in repo)
		if src_type == 'f':

			# if entity doesn't exist in home dir, copy file
			if dst_type == '_':
				if the.verbose: print "  _<f " + rel_file
				shutil.copy( src_file, dst_file )
				shutil.copystat( src_file, dst_file )

			# if entity is a symlink in home dir, replace it with file
			elif dst_type == 'l':
				if the.verbose: print "  l<f " + rel_file
				os.unlink( dst_file )
				shutil.copy( src_file, dst_file )
				shutil.copystat( src_file, dst_file )

			# if entity is a file in home dir, replace it only if it differs
			elif dst_type == 'f':
				if not filecmp.cmp( src_file, dst_file ):
					if the.verbose: print "  f<f " + rel_file
					os.unlink( dst_file )
					shutil.copy( src_file, dst_file )
					shutil.copystat( src_file, dst_file )
				else:
					if the.verbose: print "  f=f " + rel_file

			# if entity is a directory in home dir, replace it with file
			elif dst_type == 'd':
				if the.verbose: print "  d<f " + rel_file
				shutil.rmtree( dst_file )
				shutil.copy( src_file, dst_file )
				shutil.copystat( src_file, dst_file )

			else:
				raise NotImplementedError()

		# link (in repo)
		if src_type == 'l':

			# if entity doesn't exist in home dir, copy symlink
			if dst_type == '_':
				if the.verbose: print "  _<l " + rel_file
				os.symlink( os.readlink( src_file ), dst_file )

			# if entity is a symlink in home dir, replace it only if it differs
			elif dst_type == 'l':
				if os.readlink( src_file ) != os.readlink( dst_file ):
					if the.verbose: print "  l<l " + rel_file
					os.unlink( dst_file )
					os.symlink( os.readlink( src_file ), dst_file )
				else:
					if the.verbose: print "  l=l " + rel_file

			# if entity is a file in home dir, replace it with file
			elif dst_type == 'f':
				if the.verbose: print "  f<l " + rel_file
				os.unlink( dst_file )
				os.symlink( os.readlink( src_file ), dst_file )

			# if entity is a directory in home dir, replace it with file
			elif dst_type == 'd':
				if the.verbose: print "  d<l " + rel_file
				shutil.rmtree( dst_file )
				os.symlink( os.readlink( src_file ), dst_file )

			else:
				raise NotImplementedError()

		# TODO: handle files missing in repo -- we may or may not want to remove
		# them from home dir, depending on whether we wanted to delete them
		# remotely or whether we just wanted to remove them from version control

		# non-directories can not be recursed in to
		return False