/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
# status.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
from .walker import Walker
import stdhome.the as the


class StatusWalker( Walker ):
	"""The status walker compares all files in the repo with those in the home
	directory and notes any that have been modified, are missing, or which have
	changed type.  It is run, for example, but the "stdhome status" comand.

	Walker source:       repo
	Walker destination:  home dir
	Walker traversing:   repo (unless a walk list is provided)
	"""

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

		self.modified = list()
		self.missing = list()
		self.changed = list()


	def process( self, rel_file, src, dst ):

		# entity is missing in home dir?
		if dst.type == '_':
			if the.verbose >= 2: print("  _|%s %s" % ( dst.type, rel_file ))
			if not the.config.ignores.matches( rel_file ):
				self.missing.append( rel_file )

			# if a directory is missing in the home dir, we only really want to
			# hear about that and not all the files it contains (which are also
			# obviously missing)
			return False

		# entity has changed type?
		elif dst.get_type_name() != src.get_type_name():

			# is it a directory that has changed to a symlnik to a directory and
			# is an acceptable substitution?
			if src.type == 'd' and dst.link_type == 'd' and \
					the.config.symlinks.matches( rel_file ):
				if the.verbose >= 2: print("  d@d " + rel_file)
				return True

			if the.verbose >= 2:
				print("  %s|%s %s" % ( dst.type, src.type, rel_file ))
			if not the.config.ignores.matches( rel_file ):
				self.changed.append( "%s (%s => %s)" % (
					rel_file, src.get_type_name(), dst.get_type_name() ) )

			# if an entity has changed to/from a directory, we don't care about
			# anything that directory does/did contain
			return False

		# entity is a file that has been modified?
		if src.type == 'f':
			if not filecmp.cmp( src.file, dst.file ):
				if the.verbose >= 2: print("  f|f " + rel_file)
				if not the.config.ignores.matches( rel_file ):
					self.modified.append( rel_file )
			else:
				if the.verbose >= 2: print("  f=f " + rel_file)
			return False

		# entity is a symlink that has been modified?
		elif dst.type == 'l':
			if os.readlink( src.file ) != os.readlink( dst.file ):
				if the.verbose >= 2: print("  l|l " + rel_file)
				if not the.config.ignores.matches( rel_file ):
					self.modified.append( rel_file )
			else:
				if the.verbose >= 2: print("  l=l " + rel_file)
			return False

		# TODO: check directory permission changes

		# nothing to see here
		if the.verbose >= 2:
			print("  %s=%s %s" % ( dst.type, src.type, rel_file ))
		return True