ctdb-daemon: Use ctdb_parse_node_address() in ctdbd
[samba4-gss.git] / third_party / waf / waflib / Node.py
blob2ad18466970a9a0963431c30143bd565b713bcbe
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Thomas Nagy, 2005-2018 (ita)
5 """
6 Node: filesystem structure
8 #. Each file/folder is represented by exactly one node.
10 #. Some potential class properties are stored on :py:class:`waflib.Build.BuildContext` : nodes to depend on, etc.
11 Unused class members can increase the `.wafpickle` file size sensibly.
13 #. Node objects should never be created directly, use
14 the methods :py:func:`Node.make_node` or :py:func:`Node.find_node` for the low-level operations
16 #. The methods :py:func:`Node.find_resource`, :py:func:`Node.find_dir` :py:func:`Node.find_or_declare` must be
17 used when a build context is present
19 #. Each instance of :py:class:`waflib.Context.Context` has a unique :py:class:`Node` subclass required for serialization.
20 (:py:class:`waflib.Node.Nod3`, see the :py:class:`waflib.Context.Context` initializer). A reference to the context
21 owning a node is held as *self.ctx*
22 """
24 import os, re, sys, shutil
25 from waflib import Utils, Errors
27 exclude_regs = '''
28 **/*~
29 **/#*#
30 **/.#*
31 **/%*%
32 **/._*
33 **/*.swp
34 **/CVS
35 **/CVS/**
36 **/.cvsignore
37 **/SCCS
38 **/SCCS/**
39 **/vssver.scc
40 **/.svn
41 **/.svn/**
42 **/BitKeeper
43 **/.git
44 **/.git/**
45 **/.gitignore
46 **/.bzr
47 **/.bzrignore
48 **/.bzr/**
49 **/.hg
50 **/.hg/**
51 **/_MTN
52 **/_MTN/**
53 **/.arch-ids
54 **/{arch}
55 **/_darcs
56 **/_darcs/**
57 **/.intlcache
58 **/.DS_Store'''
59 """
60 Ant patterns for files and folders to exclude while doing the
61 recursive traversal in :py:meth:`waflib.Node.Node.ant_glob`
62 """
64 def ant_matcher(s, ignorecase):
65 reflags = re.I if ignorecase else 0
66 ret = []
67 for x in Utils.to_list(s):
68 x = x.replace('\\', '/').replace('//', '/')
69 if x.endswith('/'):
70 x += '**'
71 accu = []
72 for k in x.split('/'):
73 if k == '**':
74 accu.append(k)
75 else:
76 k = k.replace('.', '[.]').replace('*', '.*').replace('?', '.').replace('+', '\\+')
77 k = '^%s$' % k
78 try:
79 exp = re.compile(k, flags=reflags)
80 except Exception as e:
81 raise Errors.WafError('Invalid pattern: %s' % k, e)
82 else:
83 accu.append(exp)
84 ret.append(accu)
85 return ret
87 def ant_sub_filter(name, nn):
88 ret = []
89 for lst in nn:
90 if not lst:
91 pass
92 elif lst[0] == '**':
93 ret.append(lst)
94 if len(lst) > 1:
95 if lst[1].match(name):
96 ret.append(lst[2:])
97 else:
98 ret.append([])
99 elif lst[0].match(name):
100 ret.append(lst[1:])
101 return ret
103 def ant_sub_matcher(name, pats):
104 nacc = ant_sub_filter(name, pats[0])
105 nrej = ant_sub_filter(name, pats[1])
106 if [] in nrej:
107 nacc = []
108 return [nacc, nrej]
110 class Node(object):
112 This class is organized in two parts:
114 * The basic methods meant for filesystem access (compute paths, create folders, etc)
115 * The methods bound to a :py:class:`waflib.Build.BuildContext` (require ``bld.srcnode`` and ``bld.bldnode``)
118 dict_class = dict
120 Subclasses can provide a dict class to enable case insensitivity for example.
123 __slots__ = ('name', 'parent', 'children', 'cache_abspath', 'cache_isdir')
124 def __init__(self, name, parent):
126 .. note:: Use :py:func:`Node.make_node` or :py:func:`Node.find_node` instead of calling this constructor
128 self.name = name
129 self.parent = parent
130 if parent:
131 if name in parent.children:
132 raise Errors.WafError('node %s exists in the parent files %r already' % (name, parent))
133 parent.children[name] = self
135 def __setstate__(self, data):
136 "Deserializes node information, used for persistence"
137 self.name = data[0]
138 self.parent = data[1]
139 if data[2] is not None:
140 # Issue 1480
141 self.children = self.dict_class(data[2])
143 def __getstate__(self):
144 "Serializes node information, used for persistence"
145 return (self.name, self.parent, getattr(self, 'children', None))
147 def __str__(self):
149 String representation (abspath), for debugging purposes
151 :rtype: string
153 return self.abspath()
155 def __repr__(self):
157 String representation (abspath), for debugging purposes
159 :rtype: string
161 return self.abspath()
163 def __copy__(self):
165 Provided to prevent nodes from being copied
167 :raises: :py:class:`waflib.Errors.WafError`
169 raise Errors.WafError('nodes are not supposed to be copied')
171 def read(self, flags='r', encoding='latin-1'):
173 Reads and returns the contents of the file represented by this node, see :py:func:`waflib.Utils.readf`::
175 def build(bld):
176 bld.path.find_node('wscript').read()
178 :param flags: Open mode
179 :type flags: string
180 :param encoding: encoding value for Python3
181 :type encoding: string
182 :rtype: string or bytes
183 :return: File contents
185 return Utils.readf(self.abspath(), flags, encoding)
187 def write(self, data, flags='w', encoding='latin-1'):
189 Writes data to the file represented by this node, see :py:func:`waflib.Utils.writef`::
191 def build(bld):
192 bld.path.make_node('foo.txt').write('Hello, world!')
194 :param data: data to write
195 :type data: string
196 :param flags: Write mode
197 :type flags: string
198 :param encoding: encoding value for Python3
199 :type encoding: string
201 Utils.writef(self.abspath(), data, flags, encoding)
203 def read_json(self, convert=True, encoding='utf-8'):
205 Reads and parses the contents of this node as JSON (Python ≥ 2.6)::
207 def build(bld):
208 bld.path.find_node('abc.json').read_json()
210 Note that this by default automatically decodes unicode strings on Python2, unlike what the Python JSON module does.
212 :type convert: boolean
213 :param convert: Prevents decoding of unicode strings on Python2
214 :type encoding: string
215 :param encoding: The encoding of the file to read. This default to UTF8 as per the JSON standard
216 :rtype: object
217 :return: Parsed file contents
219 import json # Python 2.6 and up
220 object_pairs_hook = None
221 if convert and sys.hexversion < 0x3000000:
222 try:
223 _type = unicode
224 except NameError:
225 _type = str
227 def convert(value):
228 if isinstance(value, list):
229 return [convert(element) for element in value]
230 elif isinstance(value, _type):
231 return str(value)
232 else:
233 return value
235 def object_pairs(pairs):
236 return dict((str(pair[0]), convert(pair[1])) for pair in pairs)
238 object_pairs_hook = object_pairs
240 return json.loads(self.read(encoding=encoding), object_pairs_hook=object_pairs_hook)
242 def write_json(self, data, pretty=True):
244 Writes a python object as JSON to disk (Python ≥ 2.6) as UTF-8 data (JSON standard)::
246 def build(bld):
247 bld.path.find_node('xyz.json').write_json(199)
249 :type data: object
250 :param data: The data to write to disk
251 :type pretty: boolean
252 :param pretty: Determines if the JSON will be nicely space separated
254 import json # Python 2.6 and up
255 indent = 2
256 separators = (',', ': ')
257 sort_keys = pretty
258 newline = os.linesep
259 if not pretty:
260 indent = None
261 separators = (',', ':')
262 newline = ''
263 output = json.dumps(data, indent=indent, separators=separators, sort_keys=sort_keys) + newline
264 self.write(output, encoding='utf-8')
266 def exists(self):
268 Returns whether the Node is present on the filesystem
270 :rtype: bool
272 return os.path.exists(self.abspath())
274 def isdir(self):
276 Returns whether the Node represents a folder
278 :rtype: bool
280 return os.path.isdir(self.abspath())
282 def chmod(self, val):
284 Changes the file/dir permissions::
286 def build(bld):
287 bld.path.chmod(493) # 0755
289 os.chmod(self.abspath(), val)
291 def delete(self, evict=True):
293 Removes the file/folder from the filesystem (equivalent to `rm -rf`), and remove this object from the Node tree.
294 Do not use this object after calling this method.
296 try:
297 try:
298 if os.path.isdir(self.abspath()):
299 shutil.rmtree(self.abspath())
300 else:
301 os.remove(self.abspath())
302 except OSError:
303 if os.path.exists(self.abspath()):
304 raise
305 finally:
306 if evict:
307 self.evict()
309 def evict(self):
311 Removes this node from the Node tree
313 del self.parent.children[self.name]
315 def suffix(self):
317 Returns the file rightmost extension, for example `a.b.c.d → .d`
319 :rtype: string
321 k = max(0, self.name.rfind('.'))
322 return self.name[k:]
324 def height(self):
326 Returns the depth in the folder hierarchy from the filesystem root or from all the file drives
328 :returns: filesystem depth
329 :rtype: integer
331 d = self
332 val = -1
333 while d:
334 d = d.parent
335 val += 1
336 return val
338 def listdir(self):
340 Lists the folder contents
342 :returns: list of file/folder names ordered alphabetically
343 :rtype: list of string
345 lst = Utils.listdir(self.abspath())
346 lst.sort()
347 return lst
349 def mkdir(self):
351 Creates a folder represented by this node. Intermediate folders are created as needed.
353 :raises: :py:class:`waflib.Errors.WafError` when the folder is missing
355 if self.isdir():
356 return
358 try:
359 self.parent.mkdir()
360 except OSError:
361 pass
363 if self.name:
364 try:
365 os.makedirs(self.abspath())
366 except OSError:
367 pass
369 if not self.isdir():
370 raise Errors.WafError('Could not create the directory %r' % self)
372 try:
373 self.children
374 except AttributeError:
375 self.children = self.dict_class()
377 def find_node(self, lst):
379 Finds a node on the file system (files or folders), and creates the corresponding Node objects if it exists
381 :param lst: relative path
382 :type lst: string or list of string
383 :returns: The corresponding Node object or None if no entry was found on the filesystem
384 :rtype: :py:class:´waflib.Node.Node´
387 if isinstance(lst, str):
388 lst = [x for x in Utils.split_path(lst) if x and x != '.']
390 if lst and lst[0].startswith('\\\\') and not self.parent:
391 node = self.ctx.root.make_node(lst[0])
392 node.cache_isdir = True
393 return node.find_node(lst[1:])
395 cur = self
396 for x in lst:
397 if x == '..':
398 cur = cur.parent or cur
399 continue
401 try:
402 ch = cur.children
403 except AttributeError:
404 cur.children = self.dict_class()
405 else:
406 try:
407 cur = ch[x]
408 continue
409 except KeyError:
410 pass
412 # optimistic: create the node first then look if it was correct to do so
413 cur = self.__class__(x, cur)
414 if not cur.exists():
415 cur.evict()
416 return None
418 if not cur.exists():
419 cur.evict()
420 return None
422 return cur
424 def make_node(self, lst):
426 Returns or creates a Node object corresponding to the input path without considering the filesystem.
428 :param lst: relative path
429 :type lst: string or list of string
430 :rtype: :py:class:´waflib.Node.Node´
432 if isinstance(lst, str):
433 lst = [x for x in Utils.split_path(lst) if x and x != '.']
435 cur = self
436 for x in lst:
437 if x == '..':
438 cur = cur.parent or cur
439 continue
441 try:
442 cur = cur.children[x]
443 except AttributeError:
444 cur.children = self.dict_class()
445 except KeyError:
446 pass
447 else:
448 continue
449 cur = self.__class__(x, cur)
450 return cur
452 def search_node(self, lst):
454 Returns a Node previously defined in the data structure. The filesystem is not considered.
456 :param lst: relative path
457 :type lst: string or list of string
458 :rtype: :py:class:´waflib.Node.Node´ or None if there is no entry in the Node datastructure
460 if isinstance(lst, str):
461 lst = [x for x in Utils.split_path(lst) if x and x != '.']
463 cur = self
464 for x in lst:
465 if x == '..':
466 cur = cur.parent or cur
467 else:
468 try:
469 cur = cur.children[x]
470 except (AttributeError, KeyError):
471 return None
472 return cur
474 def path_from(self, node):
476 Path of this node seen from the other::
478 def build(bld):
479 n1 = bld.path.find_node('foo/bar/xyz.txt')
480 n2 = bld.path.find_node('foo/stuff/')
481 n1.path_from(n2) # '../bar/xyz.txt'
483 :param node: path to use as a reference
484 :type node: :py:class:`waflib.Node.Node`
485 :returns: a relative path or an absolute one if that is better
486 :rtype: string
488 c1 = self
489 c2 = node
491 c1h = c1.height()
492 c2h = c2.height()
494 lst = []
495 up = 0
497 while c1h > c2h:
498 lst.append(c1.name)
499 c1 = c1.parent
500 c1h -= 1
502 while c2h > c1h:
503 up += 1
504 c2 = c2.parent
505 c2h -= 1
507 while not c1 is c2:
508 lst.append(c1.name)
509 up += 1
511 c1 = c1.parent
512 c2 = c2.parent
514 if c1.parent:
515 lst.extend(['..'] * up)
516 lst.reverse()
517 return os.sep.join(lst) or '.'
518 else:
519 return self.abspath()
521 def abspath(self):
523 Returns the absolute path. A cache is kept in the context as ``cache_node_abspath``
525 :rtype: string
527 try:
528 return self.cache_abspath
529 except AttributeError:
530 pass
531 # think twice before touching this (performance + complexity + correctness)
533 if not self.parent:
534 val = os.sep
535 elif not self.parent.name:
536 val = os.sep + self.name
537 else:
538 val = self.parent.abspath() + os.sep + self.name
539 self.cache_abspath = val
540 return val
542 if Utils.is_win32:
543 def abspath(self):
544 try:
545 return self.cache_abspath
546 except AttributeError:
547 pass
548 if not self.parent:
549 val = ''
550 elif not self.parent.name:
551 val = self.name + os.sep
552 else:
553 val = self.parent.abspath().rstrip(os.sep) + os.sep + self.name
554 self.cache_abspath = val
555 return val
557 def is_child_of(self, node):
559 Returns whether the object belongs to a subtree of the input node::
561 def build(bld):
562 node = bld.path.find_node('wscript')
563 node.is_child_of(bld.path) # True
565 :param node: path to use as a reference
566 :type node: :py:class:`waflib.Node.Node`
567 :rtype: bool
569 p = self
570 diff = self.height() - node.height()
571 while diff > 0:
572 diff -= 1
573 p = p.parent
574 return p is node
576 def ant_iter(self, accept=None, maxdepth=25, pats=[], dir=False, src=True, remove=True, quiet=False):
578 Recursive method used by :py:meth:`waflib.Node.ant_glob`.
580 :param accept: function used for accepting/rejecting a node, returns the patterns that can be still accepted in recursion
581 :type accept: function
582 :param maxdepth: maximum depth in the filesystem (25)
583 :type maxdepth: int
584 :param pats: list of patterns to accept and list of patterns to exclude
585 :type pats: tuple
586 :param dir: return folders too (False by default)
587 :type dir: bool
588 :param src: return files (True by default)
589 :type src: bool
590 :param remove: remove files/folders that do not exist (True by default)
591 :type remove: bool
592 :param quiet: disable build directory traversal warnings (verbose mode)
593 :type quiet: bool
594 :returns: A generator object to iterate from
595 :rtype: iterator
597 dircont = self.listdir()
599 try:
600 lst = set(self.children.keys())
601 except AttributeError:
602 self.children = self.dict_class()
603 else:
604 if remove:
605 for x in lst - set(dircont):
606 self.children[x].evict()
608 for name in dircont:
609 npats = accept(name, pats)
610 if npats and npats[0]:
611 accepted = [] in npats[0]
613 node = self.make_node([name])
615 isdir = node.isdir()
616 if accepted:
617 if isdir:
618 if dir:
619 yield node
620 elif src:
621 yield node
623 if isdir:
624 node.cache_isdir = True
625 if maxdepth:
626 for k in node.ant_iter(accept=accept, maxdepth=maxdepth - 1, pats=npats, dir=dir, src=src, remove=remove, quiet=quiet):
627 yield k
629 def ant_glob(self, *k, **kw):
631 Finds files across folders and returns Node objects:
633 * ``**/*`` find all files recursively
634 * ``**/*.class`` find all files ending by .class
635 * ``..`` find files having two dot characters
637 For example::
639 def configure(cfg):
640 # find all .cpp files
641 cfg.path.ant_glob('**/*.cpp')
642 # find particular files from the root filesystem (can be slow)
643 cfg.root.ant_glob('etc/*.txt')
644 # simple exclusion rule example
645 cfg.path.ant_glob('*.c*', excl=['*.c'], src=True, dir=False)
647 For more information about the patterns, consult http://ant.apache.org/manual/dirtasks.html
648 Please remember that the '..' sequence does not represent the parent directory::
650 def configure(cfg):
651 cfg.path.ant_glob('../*.h') # incorrect
652 cfg.path.parent.ant_glob('*.h') # correct
654 The Node structure is itself a filesystem cache, so certain precautions must
655 be taken while matching files in the build or installation phases.
656 Nodes objects that do have a corresponding file or folder are garbage-collected by default.
657 This garbage collection is usually required to prevent returning files that do not
658 exist anymore. Yet, this may also remove Node objects of files that are yet-to-be built.
660 This typically happens when trying to match files in the build directory,
661 but there are also cases when files are created in the source directory.
662 Run ``waf -v`` to display any warnings, and try consider passing ``remove=False``
663 when matching files in the build directory.
665 Since ant_glob can traverse both source and build folders, it is a best practice
666 to call this method only from the most specific build node::
668 def build(bld):
669 # traverses the build directory, may need ``remove=False``:
670 bld.path.ant_glob('project/dir/**/*.h')
671 # better, no accidental build directory traversal:
672 bld.path.find_node('project/dir').ant_glob('**/*.h') # best
674 In addition, files and folders are listed immediately. When matching files in the
675 build folders, consider passing ``generator=True`` so that the generator object
676 returned can defer computation to a later stage. For example::
678 def build(bld):
679 bld(rule='tar xvf ${SRC}', source='arch.tar')
680 bld.add_group()
681 gen = bld.bldnode.ant_glob("*.h", generator=True, remove=True)
682 # files will be listed only after the arch.tar is unpacked
683 bld(rule='ls ${SRC}', source=gen, name='XYZ')
686 :param incl: ant patterns or list of patterns to include
687 :type incl: string or list of strings
688 :param excl: ant patterns or list of patterns to exclude
689 :type excl: string or list of strings
690 :param dir: return folders too (False by default)
691 :type dir: bool
692 :param src: return files (True by default)
693 :type src: bool
694 :param maxdepth: maximum depth of recursion
695 :type maxdepth: int
696 :param ignorecase: ignore case while matching (False by default)
697 :type ignorecase: bool
698 :param generator: Whether to evaluate the Nodes lazily
699 :type generator: bool
700 :param remove: remove files/folders that do not exist (True by default)
701 :type remove: bool
702 :param quiet: disable build directory traversal warnings (verbose mode)
703 :type quiet: bool
704 :returns: The corresponding Node objects as a list or as a generator object (generator=True)
705 :rtype: by default, list of :py:class:`waflib.Node.Node` instances
707 src = kw.get('src', True)
708 dir = kw.get('dir')
709 excl = kw.get('excl', exclude_regs)
710 incl = k and k[0] or kw.get('incl', '**')
711 remove = kw.get('remove', True)
712 maxdepth = kw.get('maxdepth', 25)
713 ignorecase = kw.get('ignorecase', False)
714 quiet = kw.get('quiet', False)
715 pats = (ant_matcher(incl, ignorecase), ant_matcher(excl, ignorecase))
717 if kw.get('generator'):
718 return Utils.lazy_generator(self.ant_iter, (ant_sub_matcher, maxdepth, pats, dir, src, remove, quiet))
720 it = self.ant_iter(ant_sub_matcher, maxdepth, pats, dir, src, remove, quiet)
721 if kw.get('flat'):
722 # returns relative paths as a space-delimited string
723 # prefer Node objects whenever possible
724 return ' '.join(x.path_from(self) for x in it)
725 return list(it)
727 # ----------------------------------------------------------------------------
728 # the methods below require the source/build folders (bld.srcnode/bld.bldnode)
730 def is_src(self):
732 Returns True if the node is below the source directory. Note that ``!is_src() ≠ is_bld()``
734 :rtype: bool
736 cur = self
737 x = self.ctx.srcnode
738 y = self.ctx.bldnode
739 while cur.parent:
740 if cur is y:
741 return False
742 if cur is x:
743 return True
744 cur = cur.parent
745 return False
747 def is_bld(self):
749 Returns True if the node is below the build directory. Note that ``!is_bld() ≠ is_src()``
751 :rtype: bool
753 cur = self
754 y = self.ctx.bldnode
755 while cur.parent:
756 if cur is y:
757 return True
758 cur = cur.parent
759 return False
761 def get_src(self):
763 Returns the corresponding Node object in the source directory (or self if already
764 under the source directory). Use this method only if the purpose is to create
765 a Node object (this is common with folders but not with files, see ticket 1937)
767 :rtype: :py:class:`waflib.Node.Node`
769 cur = self
770 x = self.ctx.srcnode
771 y = self.ctx.bldnode
772 lst = []
773 while cur.parent:
774 if cur is y:
775 lst.reverse()
776 return x.make_node(lst)
777 if cur is x:
778 return self
779 lst.append(cur.name)
780 cur = cur.parent
781 return self
783 def get_bld(self):
785 Return the corresponding Node object in the build directory (or self if already
786 under the build directory). Use this method only if the purpose is to create
787 a Node object (this is common with folders but not with files, see ticket 1937)
789 :rtype: :py:class:`waflib.Node.Node`
791 cur = self
792 x = self.ctx.srcnode
793 y = self.ctx.bldnode
794 lst = []
795 while cur.parent:
796 if cur is y:
797 return self
798 if cur is x:
799 lst.reverse()
800 return self.ctx.bldnode.make_node(lst)
801 lst.append(cur.name)
802 cur = cur.parent
803 # the file is external to the current project, make a fake root in the current build directory
804 lst.reverse()
805 if lst and Utils.is_win32 and len(lst[0]) == 2 and lst[0].endswith(':'):
806 lst[0] = lst[0][0]
807 return self.ctx.bldnode.make_node(['__root__'] + lst)
809 def find_resource(self, lst):
811 Use this method in the build phase to find source files corresponding to the relative path given.
813 First it looks up the Node data structure to find any declared Node object in the build directory.
814 If None is found, it then considers the filesystem in the source directory.
816 :param lst: relative path
817 :type lst: string or list of string
818 :returns: the corresponding Node object or None
819 :rtype: :py:class:`waflib.Node.Node`
821 if isinstance(lst, str):
822 lst = [x for x in Utils.split_path(lst) if x and x != '.']
824 node = self.get_bld().search_node(lst)
825 if not node:
826 node = self.get_src().find_node(lst)
827 if node and node.isdir():
828 return None
829 return node
831 def find_or_declare(self, lst):
833 Use this method in the build phase to declare output files which
834 are meant to be written in the build directory.
836 This method creates the Node object and its parent folder
837 as needed.
839 :param lst: relative path
840 :type lst: string or list of string
842 if isinstance(lst, str) and os.path.isabs(lst):
843 node = self.ctx.root.make_node(lst)
844 else:
845 node = self.get_bld().make_node(lst)
846 node.parent.mkdir()
847 return node
849 def find_dir(self, lst):
851 Searches for a folder on the filesystem (see :py:meth:`waflib.Node.Node.find_node`)
853 :param lst: relative path
854 :type lst: string or list of string
855 :returns: The corresponding Node object or None if there is no such folder
856 :rtype: :py:class:`waflib.Node.Node`
858 if isinstance(lst, str):
859 lst = [x for x in Utils.split_path(lst) if x and x != '.']
861 node = self.find_node(lst)
862 if node and not node.isdir():
863 return None
864 return node
866 # helpers for building things
867 def change_ext(self, ext, ext_in=None):
869 Declares a build node with a distinct extension; this is uses :py:meth:`waflib.Node.Node.find_or_declare`
871 :return: A build node of the same path, but with a different extension
872 :rtype: :py:class:`waflib.Node.Node`
874 name = self.name
875 if ext_in is None:
876 k = name.rfind('.')
877 if k >= 0:
878 name = name[:k] + ext
879 else:
880 name = name + ext
881 else:
882 name = name[:- len(ext_in)] + ext
884 return self.parent.find_or_declare([name])
886 def bldpath(self):
888 Returns the relative path seen from the build directory ``src/foo.cpp``
890 :rtype: string
892 return self.path_from(self.ctx.bldnode)
894 def srcpath(self):
896 Returns the relative path seen from the source directory ``../src/foo.cpp``
898 :rtype: string
900 return self.path_from(self.ctx.srcnode)
902 def relpath(self):
904 If a file in the build directory, returns :py:meth:`waflib.Node.Node.bldpath`,
905 else returns :py:meth:`waflib.Node.Node.srcpath`
907 :rtype: string
909 cur = self
910 x = self.ctx.bldnode
911 while cur.parent:
912 if cur is x:
913 return self.bldpath()
914 cur = cur.parent
915 return self.srcpath()
917 def bld_dir(self):
919 Equivalent to self.parent.bldpath()
921 :rtype: string
923 return self.parent.bldpath()
925 def h_file(self):
927 See :py:func:`waflib.Utils.h_file`
929 :return: a hash representing the file contents
930 :rtype: string or bytes
932 return Utils.h_file(self.abspath())
934 def get_bld_sig(self):
936 Returns a signature (see :py:meth:`waflib.Node.Node.h_file`) for the purpose
937 of build dependency calculation. This method uses a per-context cache.
939 :return: a hash representing the object contents
940 :rtype: string or bytes
942 # previous behaviour can be set by returning self.ctx.node_sigs[self] when a build node
943 try:
944 cache = self.ctx.cache_sig
945 except AttributeError:
946 cache = self.ctx.cache_sig = {}
947 try:
948 ret = cache[self]
949 except KeyError:
950 p = self.abspath()
951 try:
952 ret = cache[self] = self.h_file()
953 except EnvironmentError:
954 if self.isdir():
955 # allow folders as build nodes, do not use the creation time
956 st = os.stat(p)
957 ret = cache[self] = Utils.h_list([p, st.st_ino, st.st_mode])
958 return ret
959 raise
960 return ret
962 pickle_lock = Utils.threading.Lock()
963 """Lock mandatory for thread-safe node serialization"""
965 class Nod3(Node):
966 """Mandatory subclass for thread-safe node serialization"""
967 pass # do not remove