summaryrefslogtreecommitdiff
path: root/build/docs/files-metadata.rst
blob: 5af4d96fdc3e6a38759b8b642920c31757822cbb (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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
.. _mozbuild_files_metadata:

==============
Files Metadata
==============

:ref:`mozbuild-files` provide a mechanism for attaching metadata to
files. Essentially, you define some flags to set on a file or file
pattern. Later, some tool or process queries for metadata attached to a
file of interest and it does something intelligent with that data.

Defining Metadata
=================

Files metadata is defined by using the
:ref:`Files Sub-Context <mozbuild_subcontext_Files>` in ``moz.build``
files. e.g.::

    with Files('**/Makefile.in'):
        BUG_COMPONENT = ('Core', 'Build Config')

This working example says, *for all Makefile.in files in every directory
underneath this one - including this directory - set the Bugzilla
component to Core :: Build Config*.

For more info, read the
:ref:`docs on Files <mozbuild_subcontext_Files>`.

How Metadata is Read
====================

``Files`` metadata is extracted in :ref:`mozbuild_fs_reading_mode`.

Reading starts by specifying a set of files whose metadata you are
interested in. For each file, the filesystem is walked to the root
of the source directory. Any ``moz.build`` encountered during this
walking are marked as relevant to the file.

Let's say you have the following filesystem content::

   /moz.build
   /root_file
   /dir1/moz.build
   /dir1/foo
   /dir1/subdir1/foo
   /dir2/foo

For ``/root_file``, the relevant ``moz.build`` files are just
``/moz.build``.

For ``/dir1/foo`` and ``/dir1/subdir1/foo``, the relevant files are
``/moz.build`` and ``/dir1/moz.build``.

For ``/dir2``, the relevant file is just ``/moz.build``.

Once the list of relevant ``moz.build`` files is obtained, each
``moz.build`` file is evaluated. Root ``moz.build`` file first,
leaf-most files last. This follows the rules of
:ref:`mozbuild_fs_reading_mode`, with the set of evaluated ``moz.build``
files being controlled by filesystem content, not ``DIRS`` variables.

The file whose metadata is being resolved maps to a set of ``moz.build``
files which in turn evaluates to a list of contexts. For file metadata,
we only care about one of these contexts:
:ref:`Files <mozbuild_subcontext_Files>`.

We start with an empty ``Files`` instance to represent the file. As
we encounter a *files sub-context*, we see if it is appropriate to
this file. If it is, we apply its values. This process is repeated
until all *files sub-contexts* have been applied or skipped. The final
state of the ``Files`` instance is used to represent the metadata for
this particular file.

It may help to visualize this. Say we have 2 ``moz.build`` files::

    # /moz.build
    with Files('*.cpp'):
        BUG_COMPONENT = ('Core', 'XPCOM')

    with Files('**/*.js'):
        BUG_COMPONENT = ('Firefox', 'General')

    # /foo/moz.build
    with Files('*.js'):
        BUG_COMPONENT = ('Another', 'Component')

Querying for metadata for the file ``/foo/test.js`` will reveal 3
relevant ``Files`` sub-contexts. They are evaluated as follows:

1. ``/moz.build - Files('*.cpp')``. Does ``/*.cpp`` match
   ``/foo/test.js``? **No**. Ignore this context.
2. ``/moz.build - Files('**/*.js')``. Does ``/**/*.js`` match
   ``/foo/test.js``? **Yes**. Apply ``BUG_COMPONENT = ('Firefox', 'General')``
   to us.
3. ``/foo/moz.build - Files('*.js')``. Does ``/foo/*.js`` match
   ``/foo/test.js``? **Yes**. Apply
   ``BUG_COMPONENT = ('Another', 'Component')``.

At the end of execution, we have
``BUG_COMPONENT = ('Another', 'Component')`` as the metadata for
``/foo/test.js``.

One way to look at file metadata is as a stack of data structures.
Each ``Files`` sub-context relevant to a given file is applied on top
of the previous state, starting from an empty state. The final state
wins.

.. _mozbuild_files_metadata_finalizing:

Finalizing Values
=================

The default behavior of ``Files`` sub-context evaluation is to apply new
values on top of old. In most circumstances, this results in desired
behavior. However, there are circumstances where this may not be
desired. There is thus a mechanism to *finalize* or *freeze* values.

Finalizing values is useful for scenarios where you want to prevent
wildcard matches from overwriting previously-set values. This is useful
for one-off files.

Let's take ``Makefile.in`` files as an example. The build system module
policy dictates that ``Makefile.in`` files are part of the ``Build
Config`` module and should be reviewed by peers of that module. However,
there exist ``Makefile.in`` files in many directories in the source
tree. Without finalization, a ``*`` or ``**`` wildcard matching rule
would match ``Makefile.in`` files and overwrite their metadata.

Finalizing of values is performed by setting the ``FINAL`` variable
on ``Files`` sub-contexts. See the
:ref:`Files documentation <mozbuild_subcontext_Files>` for more.

Here is an example with ``Makefile.in`` files, showing how it is
possible to finalize the ``BUG_COMPONENT`` value.::

    # /moz.build
    with Files('**/Makefile.in'):
        BUG_COMPONENT = ('Core', 'Build Config')
        FINAL = True

    # /foo/moz.build
    with Files('**'):
        BUG_COMPONENT = ('Another', 'Component')

If we query for metadata of ``/foo/Makefile.in``, both ``Files``
sub-contexts match the file pattern. However, since ``BUG_COMPONENT`` is
marked as finalized by ``/moz.build``, the assignment from
``/foo/moz.build`` is ignored. The final value for ``BUG_COMPONENT``
is ``('Core', 'Build Config')``.

Here is another example::

    with Files('*.cpp'):
        BUG_COMPONENT = ('One-Off', 'For C++')
        FINAL = True

    with Files('**'):
        BUG_COMPONENT = ('Regular', 'Component')

For every files except ``foo.cpp``, the bug component will be resolved
as ``Regular :: Component``. However, ``foo.cpp`` has its value of
``One-Off :: For C++`` preserved because it is finalized.

.. important::

   ``FINAL`` only applied to variables defined in a context.

   If you want to mark one variable as finalized but want to leave
   another mutable, you'll need to use 2 ``Files`` contexts.

Guidelines for Defining Metadata
================================

In general, values defined towards the root of the source tree are
generic and become more specific towards the leaves. For example,
the ``BUG_COMPONENT`` for ``/browser`` might be ``Firefox :: General``
whereas ``/browser/components/preferences`` would list
``Firefox :: Preferences``.