Skip to content

Commit

Permalink
Merge pull request #4237 from mwichmann/doc/glob-updates
Browse files Browse the repository at this point in the history
[DOC] Update the Glob docs with more details
  • Loading branch information
bdbaddog authored Sep 25, 2022
2 parents fc2d4a4 + 7f18227 commit d003168
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 123 deletions.
3 changes: 2 additions & 1 deletion RELEASE.txt
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ DOCUMENTATION
- Updated the --hash-format manpage entry.
- EnsureSConsVersion, EnsurePythonVersion, Exit, GetLaunchDir and
SConscriptChdir are now listed as Global functions only.
- Updated the docs for Glob.
- Updated SHELL_ENV_GENERATORS description and added versionadded indicator.

DEVELOPMENT
Expand All @@ -83,4 +84,4 @@ Thanks to the following contributors listed below for their contributions to thi
==========================================================================================
.. code-block:: text

git shortlog --no-merges -ns 4.0.1..HEAD
git shortlog --no-merges -ns 4.4.0..HEAD
192 changes: 111 additions & 81 deletions SCons/Environment.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1901,123 +1901,150 @@ Nodes or strings representing path names.

<scons_function name="Glob">
<arguments>
(pattern, [ondisk, source, strings, exclude])
(pattern, [ondisk=True, source=False, strings=False, exclude=None])
</arguments>
<summary>
<para>
Returns Nodes (or strings) that match the specified
<parameter>pattern</parameter>,
relative to the directory of the current
&SConscript;
file.
Returns a possibly empty list of Nodes (or strings) that match
pathname specification <parameter>pattern</parameter>.
<parameter>pattern</parameter> can be absolute,
top-relative,
or (most commonly) relative to the directory of the current
&SConscript; file.
&f-Glob; matches both files stored on disk and Nodes
which &SCons; already knows about, even if any corresponding
file is not currently stored on disk.
The evironment method form (&f-env-Glob;)
performs string substition on
<parameter>pattern</parameter>
and returns whatever matches
the resulting expanded pattern.
and returns whatever matches the resulting expanded pattern.
The results are sorted, unlike for the similar &Python;
<systemitem>glob.glob</systemitem> function,
to ensure build order will be stable.
</para>

<para>
The specified
<parameter>pattern</parameter>
uses Unix shell style metacharacters for matching:
can contain POSIX-style shell metacharacters for matching:
</para>

<informaltable rowsep="1" colsep="1" frame="topbot">
<tgroup cols="2">
<thead>
<row>
<entry>Pattern</entry>
<entry>Meaning</entry>
</row>
</thead>
<tbody>
<row>
<entry><literal>*</literal></entry>
<entry>matches everything</entry>
</row>
<row>
<entry><literal>?</literal></entry>
<entry>matches any single character</entry>
</row>
<row>
<entry><literal>[seq]</literal></entry>
<entry>matches any character in <emphasis>seq</emphasis>
(can be a list or a range).</entry>
</row>
<row>
<entry><literal>[!seq]</literal></entry>
<entry>matches any character not in <emphasis>seq</emphasis></entry>
</row>
</tbody>
</tgroup>
</informaltable>

<para>
For a literal match, wrap the metacharacter in brackets to
escape the normal behavior.
For example, <literal>'[?]'</literal> matches the character
<literal>'?'</literal>.
</para>

<para>
Filenames starting with a dot are specially handled -
they can only be matched by patterns that start with a dot
(or have a dot immediately following a pathname separator
character, or slash), they are not not matched by the metacharacters.
Metacharacter matches also do not span directory separators.
</para>

<example_commands>
* matches everything
? matches any single character
[seq] matches any character in seq
[!seq] matches any char not in seq
</example_commands>

<para>
If the first character of a filename is a dot,
it must be matched explicitly.
Character matches do
<emphasis>not</emphasis>
span directory separators.
</para>

<para>
The
&f-Glob;
knows about
repositories
understands repositories
(see the
&f-link-Repository;
function)
and source directories
(see the
&f-link-VariantDir;
function)
and
returns a Node (or string, if so configured)
and returns a Node (or string, if so configured) match
in the local (SConscript) directory
if a matching Node is found
anywhere in a corresponding
repository or source directory.
</para>

<para>
The
If the optional
<parameter>ondisk</parameter>
argument may be set to a value which evaluates
<constant>False</constant>
to disable the search for matches on disk,
thereby only returning matches among
already-configured File or Dir Nodes.
The default behavior is to
return corresponding Nodes
for any on-disk matches found.
argument evaluates false,
the search for matches on disk is disabled,
and only matches from
already-configured File or Dir Nodes are returned.
The default is to return Nodes for
matches on disk as well.
</para>

<para>
The
If the optional
<parameter>source</parameter>
argument may be set to a value which evaluates
<constant>True</constant>
to specify that,
when the local directory is a
&f-VariantDir;,
the returned Nodes should be from the
corresponding source directory,
not the local directory.
argument evaluates true,
and the local directory is a variant directory,
then &f-Glob; returnes Nodes from
the corresponding source directory,
rather than the local directory.
<!-- XXX what about generated files that don't exist in src but will be sources? -->
</para>

<para>
The
If the optional
<parameter>strings</parameter>
argument may be set to a value which evaluates
<constant>True</constant>
to have the
argument evaluates true,
&f-Glob;
function return strings, not Nodes,
that represent the matched files or directories.
returns matches as strings, rather than Nodes.
The returned strings will be relative to
the local (SConscript) directory.
(Note that This may make it easier to perform
(Note that while this may make it easier to perform
arbitrary manipulation of file names,
but if the returned strings are
it loses the context &SCons; would have in the Node,
so if the returned strings are
passed to a different
&SConscript;
file,
any Node translation will be relative
to the other
any Node translation there will be relative
to that
&SConscript;
directory,
not the original
not to the original
&SConscript;
directory.)
</para>

<para>
The
The optional
<parameter>exclude</parameter>
argument may be set to a pattern or a list of patterns
(following the same Unix shell semantics)
which must be filtered out of returned elements.
Elements matching a least one pattern of
this list will be excluded.
descibing files or directories
to filter out of the match list.
Elements matching a least one specified pattern will be excluded.
These patterns use the same syntax as for
<parameter>pattern</parameter>.
</para>

<para>
Expand All @@ -2027,9 +2054,10 @@ Examples:
<example_commands>
Program("foo", Glob("*.c"))
Zip("/tmp/everything", Glob(".??*") + Glob("*"))
sources = Glob("*.cpp", exclude=["os_*_specific_*.cpp"]) + \
Glob( "os_%s_specific_*.cpp" % currentOS)
sources = Glob("*.cpp", exclude=["os_*_specific_*.cpp"]) \
+ Glob("os_%s_specific_*.cpp" % currentOS)
</example_commands>

</summary>
</scons_function>

Expand Down Expand Up @@ -2066,24 +2094,26 @@ to call all builders.
</arguments>
<summary>
<para>
The specified dependency file(s)
will be ignored when deciding if
the target file(s) need to be rebuilt.
</para>

<para>
You can also use
&f-Ignore;
to remove a target from the default build.
In order to do this you must specify the directory the target will
be built in as the target, and the file you want to skip building
as the dependency.
Ignores <parameter>dependency</parameter>
when deciding if
<parameter>target</parameter> needs to be rebuilt.
<parameter>target</parameter> and
<parameter>dependency</parameter>
can each be a single filename or Node
or a list of filenames or Nodes.
</para>

<para>
Note that this will only remove the dependencies listed from
the files built by default. It will still be built if that
dependency is needed by another object being built.
&f-Ignore; can also be used to
remove a target from the default build
by specifying the directory the target will be built in as
<parameter>target</parameter>
and the file you want to skip selecting for building as
<parameter>dependency</parameter>.
Note that this only removes the target from
the default target selection algorithm:
if it is a dependency of another object being
built &SCons; still builds it normally.
See the third and forth examples below.
</para>

Expand Down
66 changes: 35 additions & 31 deletions SCons/Node/FS.py
Original file line number Diff line number Diff line change
Expand Up @@ -2157,49 +2157,52 @@ def walk(self, func, arg):
for dirname in [n for n in names if isinstance(entries[n], Dir)]:
entries[dirname].walk(func, arg)

def glob(self, pathname, ondisk=True, source=False, strings=False, exclude=None):
"""
Returns a list of Nodes (or strings) matching a specified
pathname pattern.
def glob(self, pathname, ondisk=True, source=False, strings=False, exclude=None) -> list:
"""Returns a list of Nodes (or strings) matching a pathname pattern.
Pathname patterns follow UNIX shell semantics: * matches
any-length strings of any characters, ? matches any character,
and [] can enclose lists or ranges of characters. Matches do
not span directory separators.
Pathname patterns follow POSIX shell syntax::
The matches take into account Repositories, returning local
Nodes if a corresponding entry exists in a Repository (either
an in-memory Node or something on disk).
* matches everything
? matches any single character
[seq] matches any character in seq (ranges allowed)
[!seq] matches any char not in seq
By defafult, the glob() function matches entries that exist
on-disk, in addition to in-memory Nodes. Setting the "ondisk"
argument to False (or some other non-true value) causes the glob()
function to only match in-memory Nodes. The default behavior is
to return both the on-disk and in-memory Nodes.
The wildcard characters can be escaped by enclosing in brackets.
A leading dot is not matched by a wildcard, and needs to be
explicitly included in the pattern to be matched. Matches also
do not span directory separators.
The "source" argument, when true, specifies that corresponding
source Nodes must be returned if you're globbing in a build
directory (initialized with VariantDir()). The default behavior
is to return Nodes local to the VariantDir().
The matches take into account Repositories, returning a local
Node if a corresponding entry exists in a Repository (either
an in-memory Node or something on disk).
The "strings" argument, when true, returns the matches as strings,
not Nodes. The strings are path names relative to this directory.
The underlying algorithm is adapted from a rather old version
of :func:`glob.glob` function in the Python standard library
(heavily modified), and uses :func:`fnmatch.fnmatch` under the covers.
The "exclude" argument, if not None, must be a pattern or a list
of patterns following the same UNIX shell semantics.
Elements matching a least one pattern of this list will be excluded
from the result.
This is the internal implementation of the external Glob API.
Args:
pattern: pathname pattern to match.
ondisk: if false, restricts matches to in-memory Nodes.
By defafult, matches entries that exist on-disk in addition
to in-memory Nodes.
source: if true, corresponding source Nodes are returned if
globbing in a variant directory. The default behavior
is to return Nodes local to the variant directory.
strings: if true, returns the matches as strings instead of
Nodes. The strings are path names relative to this directory.
exclude: if not ``None``, must be a pattern or a list of patterns
following the same POSIX shell semantics. Elements matching at
least one pattern from *exclude* will be excluded from the result.
The underlying algorithm is adapted from the glob.glob() function
in the Python library (but heavily modified), and uses fnmatch()
under the covers.
"""
dirname, basename = os.path.split(pathname)
if not dirname:
result = self._glob1(basename, ondisk, source, strings)
else:
if has_glob_magic(dirname):
list = self.glob(dirname, ondisk, source, False, exclude)
list = self.glob(dirname, ondisk, source, strings=False, exclude=exclude)
else:
list = [self.Dir(dirname, create=True)]
result = []
Expand All @@ -2226,7 +2229,8 @@ def _glob1(self, pattern, ondisk=True, source=False, strings=False):
corresponding entries and returns a Node (or string) relative
to the current directory if an entry is found anywhere.
TODO: handle pattern with no wildcard
TODO: handle pattern with no wildcard. Python's glob.glob uses
a separate _glob0 function to do this.
"""
search_dir_list = self.get_all_rdirs()
for srcdir in self.srcdir_list():
Expand Down
Loading

0 comments on commit d003168

Please sign in to comment.