/stdhome

To get this branch, use:
bzr branch http://bzr.ed.am/stdhome

« back to all changes in this revision

Viewing changes to lib/stdhome/walker/walker.py

  • Committer: Tim Marston
  • Date: 2013-12-08 19:28:11 UTC
  • Revision ID: tim@ed.am-20131208192811-r20qj7cgmn4duw11
initial commit; basic app startup and initial command-line processing

Show diffs side-by-side

added added

removed removed

1
 
# walker.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 os
23
 
import stdhome.the as the
24
 
 
25
 
 
26
 
class Walker:
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.
33
 
        """
34
 
 
35
 
        def walk( self ):
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.
39
 
                """
40
 
 
41
 
                if the.verbose >= 3: print "walking [%s]" % self.__class__.__name__
42
 
 
43
 
                skip = ''
44
 
                for rel_file in self.walk_list:
45
 
 
46
 
                        # if we're skipping, skip entries in subdirectories, or turn off
47
 
                        # skipping if it no longer matches
48
 
                        if skip:
49
 
                                if skip == rel_file[ : len( skip ) ]:
50
 
                                        continue
51
 
                                else:
52
 
                                        skip = ''
53
 
 
54
 
                        src = Walker.File( os.path.join( self.src_dir, rel_file ) )
55
 
                        dst = Walker.File( os.path.join( self.dst_dir, rel_file ) )
56
 
 
57
 
                        # process ths entry
58
 
                        recurse = self.process( rel_file, src, dst )
59
 
 
60
 
                        # Set up skipping, as required.  Note that we don't check to see if
61
 
                        # we're dealing with a directory here.  We can't, because we've no
62
 
                        # way of knowing what to check.  It could be src_type or dst_type
63
 
                        # (if src_dir or dst_dir was used to generate the walk list) or it
64
 
                        # could be neither (if the walk list came from somewhere else).  But
65
 
                        # it shouldn't matter: we add a path seperateor (os.sep) to the end
66
 
                        # of the filename, so it wuill only match files that are descendents
67
 
                        # of a directory with the name of this file.
68
 
                        if not recurse: skip = rel_file + os.sep
69
 
 
70
 
 
71
 
        class File:
72
 
 
73
 
                def __init__( self, full_file ):
74
 
                        self.file = full_file
75
 
                        if not os.path.exists( self.file ):
76
 
                                self.type = '_'
77
 
                        elif os.path.isfile( self.file ):
78
 
                                self.type = 'f'
79
 
                        elif os.path.isdir( self.file ):
80
 
                                self.type = 'd'
81
 
                        else:
82
 
                                self.type = '?'
83
 
                        if os.path.islink( self.file ):
84
 
                                self.link_type = self.type
85
 
                                self.type = 'l'
86
 
                        else:
87
 
                                self.link_type = False
88
 
 
89
 
                def get_type_name( self ):
90
 
                        if self.type == 'l': return 'symlink'
91
 
                        elif self.type == 'f': return 'file'
92
 
                        elif self.type == 'd': return 'directory'
93
 
                        elif self.type == '_': return 'missing'
94
 
                        else: return 'unknown'
95
 
 
96
 
                def __str__( self ):
97
 
                        type = self.type
98
 
                        if( self.link_type ): type += '/' + self.link_type
99
 
                        return 'File( %s (%s) )' % ( self.file, type )
100
 
 
101
 
 
102
 
        @staticmethod
103
 
        def generate_walk_list( rel_file = '', full_dir = None ):
104
 
                """Returns a list of files and directories in full_dir, specified as relative
105
 
                files (relative to full_dir), breadth first.
106
 
                """
107
 
 
108
 
                # default place to walk
109
 
                if full_dir is None: full_dir = the.repo.full_dir
110
 
 
111
 
                # ignore some files
112
 
                if rel_file in [ '.bzr', '.bzrignore', '.stdhome', '.stdhomerc' ]:
113
 
                        return list()
114
 
 
115
 
                full_file = os.path.join( full_dir, rel_file )
116
 
 
117
 
                # files and links are returned
118
 
                if os.path.isfile( full_file ) or os.path.islink( full_file ):
119
 
                        return [ rel_file ]
120
 
 
121
 
                # directories are returned and recursed in to
122
 
                elif os.path.isdir( full_file ):
123
 
                        ret = [ rel_file ] if rel_file != '' else []
124
 
                        for file in os.listdir( full_file ):
125
 
                                ret.extend( Walker.generate_walk_list(
126
 
                                        os.path.join( rel_file, file ), full_dir ) )
127
 
                        return sorted( ret )
128
 
 
129
 
                # other kinds are invalid
130
 
                else:
131
 
                        raise RuntimeError(
132
 
                                'unknown/exotic file: %s' % full_file )