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.
 
 
36
                """Iterates over self.walk_list, calling process() for each entry in turn.  For
 
 
37
                directory entries, where process() returns False, subsequent entries in
 
 
38
                walk_list that fall under the directory are skipped.
 
 
43
                for rel_file in self.walk_list:
 
 
45
                        # if we're skipping, skip entries in subdirectories, or turn off
 
 
46
                        # skipping if it no longer matches
 
 
48
                                if skip == rel_file[ : len( skip ) ]:
 
 
53
                        src = Walker.File( os.path.join( self.src_dir, rel_file ) )
 
 
54
                        dst = Walker.File( os.path.join( self.dst_dir, rel_file ) )
 
 
57
                        recurse = self.process( rel_file, src, dst )
 
 
59
                        # Set up skipping, as required.  Note that we don't check to see if
 
 
60
                        # we're dealing with a directory here.  We can't, because we've no
 
 
61
                        # way of knowing what to check.  It could be src_type or dst_type
 
 
62
                        # (if src_dir or dst_dir was used to generate the walk list) or it
 
 
63
                        # could be neither (if the walk list came from somewhere else).  But
 
 
64
                        # it shouldn't matter.  We adding an os.pathset to the end of the
 
 
65
                        # filename, so it wuill only match files that are descendents of a
 
 
66
                        # directory with the name of this file.
 
 
67
                        if not recurse: skip = rel_file + os.sep
 
 
72
                def __init__( self, full_file ):
 
 
74
                        if not os.path.exists( self.file ):
 
 
76
                        elif os.path.isfile( self.file ):
 
 
78
                        elif os.path.isdir( self.file ):
 
 
82
                        if os.path.islink( self.file ):
 
 
83
                                self.link_type = self.type
 
 
86
                                self.link_type = False
 
 
88
                def get_type_name( self ):
 
 
89
                        if self.type == 'l': return 'symlink'
 
 
90
                        elif self.type == 'f': return 'file'
 
 
91
                        elif self.type == 'd': return 'directory'
 
 
92
                        elif self.type == '_': return 'missing'
 
 
93
                        else: return 'unknown'
 
 
97
                        if( self.link_type ): type += '/' + self.link_type
 
 
98
                        return 'File( %s (%s) )' % ( self.file, type )
 
 
102
        def generate_walk_list( rel_file = '', full_dir = None ):
 
 
103
                """Returns a list of files and directories in full_dir, specified as relative
 
 
104
                files (relative to full_dir), breadth first.
 
 
107
                # default place to walk
 
 
108
                if full_dir is None: full_dir = the.repo.full_dir
 
 
111
                if rel_file in [ '.bzr', '.bzrignore', '.stdhome', '.stdhomerc' ]:
 
 
114
                full_file = os.path.join( full_dir, rel_file )
 
 
116
                # files and links are returned
 
 
117
                if os.path.isfile( full_file ) or os.path.islink( full_file ):
 
 
120
                # directories are returned and recursed in to
 
 
121
                elif os.path.isdir( full_file ):
 
 
122
                        ret = [ rel_file ] if rel_file != '' else []
 
 
123
                        for file in os.listdir( full_file ):
 
 
124
                                ret.extend( Walker.generate_walk_list(
 
 
125
                                        os.path.join( rel_file, file ), full_dir ) )
 
 
128
                # other kinds are invalid
 
 
131
                                'unknown/exotic file: %s' % full_file )