summaryrefslogtreecommitdiffstats
path: root/src/scons/Node/FS.py
blob: 7640a7a5a7087b417c18c8df86b5410b823f52fd (plain)
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
"""scons.Node.FS

File system nodes.

"""

__revision__ = "Node/FS.py __REVISION__ __DATE__ __DEVELOPER__"



import os
import os.path
from scons.Node import Node



Top = None
Root = {}



def init(path = None):
    """Initialize the Node.FS subsystem.

    The supplied path is the top of the source tree, where we
    expect to find the top-level build file.  If no path is
    supplied, the current directory is the default.
    """
    global Top
    if path == None:
	path = os.getcwd()
    Top = lookup(Dir, path, directory = None)
    Top.path = '.'

def lookup(fsclass, name, directory = Top):
    """Look up a file system node for a path name.  If the path
    name is relative, it will be looked up relative to the
    specified directory node, or to the top-level directory
    if no node was specified.  An initial '#' specifies that
    the name will be looked up relative to the top-level directory,
    regardless of the specified directory argument.  Returns the
    existing or newly-created node for the specified path name.
    The node returned will be of the specified fsclass (Dir or
    File).
    """
    global Top
    head, tail = os.path.split(name)
    if not tail:
	drive, path = os.path.splitdrive(head)
	if not Root.has_key(drive):
	    Root[drive] = Dir(head, None)
	    Root[drive].abspath = head
	    Root[drive].path = head
	return Root[drive]
    if tail[0] == '#':
	directory = Top
	tail = tail[1:]
    elif directory is None:
	directory = Top
    if head:
	directory = lookup(Dir, head, directory)
    try:
	self = directory.entries[tail]
    except AttributeError:
	# There was no "entries" attribute on the directory,
	# which essentially implies that it was a file.
	# Return it as a more descriptive exception.
	raise TypeError, directory
    except KeyError:
	# There was to entry for "tail," so create the new
	# node and link it in to the existing structure.
	self = fsclass(tail, directory)
	self.name = tail
	if self.path[0:2] == "./":
	    self.path = self.path[2:]
	directory.entries[tail] = self
    except:
	raise
    if self.__class__.__name__ != fsclass.__name__:
	# Here, we found an existing node for this path,
	# but it was the wrong type (a File when we were
	# looking for a Dir, or vice versa).
	raise TypeError, self
    return self



# XXX TODO?
# Annotate with the creator
# is_under
# rel_path
# srcpath / srcdir
# link / is_linked
# linked_targets
# is_accessible

class Dir(Node):
    """A class for directories in a file system.
    """

    def __init__(self, name, directory):
	self.entries = {}
	self.entries['.'] = self
	self.entries['..'] = directory
	if not directory is None:
	    self.abspath = os.path.join(directory.abspath, name, '')
	    self.path = os.path.join(directory.path, name, '')

    def up(self):
	return self.entries['..']


# XXX TODO?
# rfile
# precious
# no_rfile
# rpath
# rsrcpath
# source_exists
# derived_exists
# is_on_rpath
# local
# base_suf
# suffix
# addsuffix
# accessible
# ignore
# build
# bind
# is_under
# relpath

class File(Node):
    """A class for files in a file system.
    """

    def __init__(self, name, directory):
	self.abspath = os.path.join(directory.abspath, name)
	self.path = os.path.join(directory.path, name)