/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: 2021-07-05 20:27:11 UTC
  • Revision ID: tim@ed.am-20210705202711-vklvsctrh5yhgjj7
added staging commands; updated command helps

Show diffs side-by-side

added added

removed removed

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