3
# Copyright (C) 2013 to 2014 Tim Marston <tim@edm.am>
5
# This file is part of stdhome (hereafter referred to as "this program").
6
# See http://ed.am/dev/stdhome for more information.
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.
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.
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/>.
23
import stdhome.the as the
27
"""Classes which derive from the Walker class are intended to walk through
28
(traverse) a single list of filenames in two locations. They must provide
29
the two locations (src_dir and dst_dir) and a list of relative filenames
30
(walk_list). For each files in the walk list, the process() method is
31
called, allowing the deriving class to perform some kind of processing. See
32
process() for more information.
37
"""Iterates over self.walk_list, calling process() for each entry in turn. For
38
directory entries, where process() returns False, subsequent entries in
39
walk_list that fall under the directory are skipped.
43
print("walking [%s]" % self.__class__.__name__)
46
for rel_file in self.walk_list:
48
# if we're skipping, skip entries in subdirectories, or turn off
49
# skipping if it no longer matches
51
if skip == rel_file[ : len( skip ) ]:
56
src = Walker.File( os.path.join( self.src_dir, rel_file ) )
57
dst = Walker.File( os.path.join( self.dst_dir, rel_file ) )
60
recurse = self.process( rel_file, src, dst )
62
# Set up skipping, as required. Note that we don't check to see if
63
# we're dealing with a directory here. We can't, because we've no
64
# way of knowing what to check. It could be src_type or dst_type
65
# (if src_dir or dst_dir was used to generate the walk list) or it
66
# could be neither (if the walk list came from somewhere else). But
67
# it shouldn't matter: we add a path seperateor (os.sep) to the end
68
# of the filename, so it wuill only match files that are descendents
69
# of a directory with the name of this file.
70
if not recurse: skip = rel_file + os.sep
75
def __init__( self, full_file ):
77
if not os.path.exists( self.file ):
79
elif os.path.isfile( self.file ):
81
elif os.path.isdir( self.file ):
85
if os.path.islink( self.file ):
86
self.link_type = self.type
89
self.link_type = False
91
def get_type_name( self ):
92
if self.type == 'l': return 'symlink'
93
elif self.type == 'f': return 'file'
94
elif self.type == 'd': return 'directory'
95
elif self.type == '_': return 'missing'
96
else: return 'unknown'
100
if( self.link_type ): type += '/' + self.link_type
101
return 'File( %s (%s) )' % ( self.file, type )
105
def generate_walk_list( full_dir, rel_file = '', recurse = True ):
106
"""Returns a list of files and directories in full_dir, specified as relative
107
files (relative to full_dir), breadth first.
112
static_ignores = [ '.stdhome', '.stdhomerc' ] + \
113
the.repo.vcs.ignored_files
114
if rel_file in static_ignores:
117
full_file = os.path.join( full_dir, rel_file )
119
# files and links are returned
120
if os.path.isfile( full_file ) or os.path.islink( full_file ):
123
# directories are returned and recursed in to
124
elif os.path.isdir( full_file ):
125
ret = [ rel_file ] if rel_file != '' else []
127
for file in os.listdir( full_file ):
128
ret.extend( Walker.generate_walk_list(
129
full_dir, os.path.join( rel_file, file ) ) )
132
# other kinds are invalid
135
'unknown/exotic file: %s' % full_file )