~ubuntu-branches/ubuntu/oneiric/lightning-extension/oneiric-updates

« back to all changes in this revision

Viewing changes to mozilla/build/pymake/pymake/data.py

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2012-11-08 10:00:06 UTC
  • mfrom: (1.3.8)
  • Revision ID: package-import@ubuntu.com-20121108100006-xpf89hktfitzuqc3
Tags: 1.9+build1-0ubuntu0.11.10.1
* New upstream stable release to support Thunderbird 17 (CALENDAR_1_9_BUILD1)
  - see LP: #1080212 for USN information

Show diffs side-by-side

added added

removed removed

Lines of Context:
62
62
        return t()
63
63
    return f()
64
64
 
65
 
class StringExpansion(object):
 
65
 
 
66
class BaseExpansion(object):
 
67
    """Base class for expansions.
 
68
 
 
69
    A make expansion is the parsed representation of a string, which may
 
70
    contain references to other elements.
 
71
    """
 
72
 
 
73
    @property
 
74
    def is_static_string(self):
 
75
        """Returns whether the expansion is composed of static string content.
 
76
 
 
77
        This is always True for StringExpansion. It will be True for Expansion
 
78
        only if all elements of that Expansion are static strings.
 
79
        """
 
80
        raise Exception('Must be implemented in child class.')
 
81
 
 
82
    def functions(self, descend=False):
 
83
        """Obtain all functions inside this expansion.
 
84
 
 
85
        This is a generator for pymake.functions.Function instances.
 
86
 
 
87
        By default, this only returns functions existing as the primary
 
88
        elements of this expansion. If `descend` is True, it will descend into
 
89
        child expansions and extract all functions in the tree.
 
90
        """
 
91
        # An empty generator. Yeah, it's weird.
 
92
        for x in []:
 
93
            yield x
 
94
 
 
95
    def variable_references(self, descend=False):
 
96
        """Obtain all variable references in this expansion.
 
97
 
 
98
        This is a generator for pymake.functionsVariableRef instances.
 
99
 
 
100
        To retrieve the names of variables, simply query the `vname` field on
 
101
        the returned instances. Most of the time these will be StringExpansion
 
102
        instances.
 
103
        """
 
104
        for f in self.functions(descend=descend):
 
105
            if not isinstance(f, functions.VariableRef):
 
106
                continue
 
107
 
 
108
            yield f
 
109
 
 
110
    @property
 
111
    def is_filesystem_dependent(self):
 
112
        """Whether this expansion may query the filesystem for evaluation.
 
113
 
 
114
        This effectively asks "is any function in this expansion dependent on
 
115
        the filesystem.
 
116
        """
 
117
        for f in self.functions(descend=True):
 
118
            if f.is_filesystem_dependent:
 
119
                return True
 
120
 
 
121
        return False
 
122
 
 
123
    @property
 
124
    def is_shell_dependent(self):
 
125
        """Whether this expansion may invoke a shell for evaluation."""
 
126
 
 
127
        for f in self.functions(descend=True):
 
128
            if isinstance(f, functions.ShellFunction):
 
129
                return True
 
130
 
 
131
        return False
 
132
 
 
133
 
 
134
class StringExpansion(BaseExpansion):
 
135
    """An Expansion representing a static string.
 
136
 
 
137
    This essentially wraps a single str instance.
 
138
    """
 
139
 
66
140
    __slots__ = ('loc', 's',)
67
141
    simple = True
68
 
    
 
142
 
69
143
    def __init__(self, s, loc):
70
144
        assert isinstance(s, str)
71
145
        self.s = s
94
168
        e.appendstr(self.s)
95
169
        return e
96
170
 
 
171
    @property
 
172
    def is_static_string(self):
 
173
        return True
 
174
 
97
175
    def __len__(self):
98
176
        return 1
99
177
 
104
182
    def __repr__(self):
105
183
        return "Exp<%s>(%r)" % (self.loc, self.s)
106
184
 
107
 
class Expansion(list):
108
 
    """
109
 
    A representation of expanded data, such as that for a recursively-expanded variable, a command, etc.
 
185
    def __eq__(self, other):
 
186
        """We only compare the string contents."""
 
187
        return self.s == other
 
188
 
 
189
    def __ne__(self, other):
 
190
        return not self.__eq__(other)
 
191
 
 
192
    def to_source(self, escape_variables=False, escape_comments=False):
 
193
        s = self.s
 
194
 
 
195
        if escape_comments:
 
196
            s = s.replace('#', '\\#')
 
197
 
 
198
        if escape_variables:
 
199
            return s.replace('$', '$$')
 
200
 
 
201
        return s
 
202
 
 
203
 
 
204
class Expansion(BaseExpansion, list):
 
205
    """A representation of expanded data.
 
206
 
 
207
    This is effectively an ordered list of StringExpansion and
 
208
    pymake.function.Function instances. Every item in the collection appears in
 
209
    the same context in a make file.
110
210
    """
111
211
 
112
212
    __slots__ = ('loc',)
232
332
    def resolvesplit(self, makefile, variables, setting=[]):
233
333
        return self.resolvestr(makefile, variables, setting).split()
234
334
 
 
335
    @property
 
336
    def is_static_string(self):
 
337
        """An Expansion is static if all its components are strings, not
 
338
        functions."""
 
339
        for e, is_func in self:
 
340
            if is_func:
 
341
                return False
 
342
 
 
343
        return True
 
344
 
 
345
    def functions(self, descend=False):
 
346
        for e, is_func in self:
 
347
            if is_func:
 
348
                yield e
 
349
 
 
350
            if descend:
 
351
                for exp in e.expansions(descend=True):
 
352
                    for f in exp.functions(descend=True):
 
353
                        yield f
 
354
 
235
355
    def __repr__(self):
236
356
        return "<Expansion with elements: %r>" % ([e for e, isfunc in self],)
237
357
 
 
358
    def to_source(self, escape_variables=False, escape_comments=False):
 
359
        parts = []
 
360
        for e, is_func in self:
 
361
            if is_func:
 
362
                parts.append(e.to_source())
 
363
                continue
 
364
 
 
365
            if escape_variables:
 
366
                parts.append(e.replace('$', '$$'))
 
367
                continue
 
368
 
 
369
            parts.append(e)
 
370
 
 
371
        return ''.join(parts)
 
372
 
 
373
    def __eq__(self, other):
 
374
        if not isinstance(other, (Expansion, StringExpansion)):
 
375
            return False
 
376
 
 
377
        # Expansions are equivalent if adjacent string literals normalize to
 
378
        # the same value. So, we must normalize before any comparisons are
 
379
        # made.
 
380
        a = self.clone().finish()
 
381
 
 
382
        if isinstance(other, StringExpansion):
 
383
            if isinstance(a, StringExpansion):
 
384
                return a == other
 
385
 
 
386
            # A normalized Expansion != StringExpansion.
 
387
            return False
 
388
 
 
389
        b = other.clone().finish()
 
390
 
 
391
        # b could be a StringExpansion now.
 
392
        if isinstance(b, StringExpansion):
 
393
            if isinstance(a, StringExpansion):
 
394
                return a == b
 
395
 
 
396
            # Our normalized Expansion != normalized StringExpansion.
 
397
            return False
 
398
 
 
399
        if len(a) != len(b):
 
400
            return False
 
401
 
 
402
        for i in xrange(len(self)):
 
403
            e1, is_func1 = a[i]
 
404
            e2, is_func2 = b[i]
 
405
 
 
406
            if is_func1 != is_func2:
 
407
                return False
 
408
 
 
409
            if type(e1) != type(e2):
 
410
                return False
 
411
 
 
412
            if e1 != e2:
 
413
                return False
 
414
 
 
415
        return True
 
416
 
 
417
    def __ne__(self, other):
 
418
        return not self.__eq__(other)
 
419
 
238
420
class Variables(object):
239
421
    """
240
422
    A mapping from variable names to variables. Variables have flavor, source, and value. The value is an 
1002
1184
            search += [util.normaljoin(dir, self.target).replace('\\', '/')
1003
1185
                       for dir in makefile.getvpath(self.target)]
1004
1186
 
1005
 
        for t in search:
 
1187
        targetandtime = self.searchinlocs(makefile, search)
 
1188
        if targetandtime is not None:
 
1189
            (self.vpathtarget, self.mtime) = targetandtime
 
1190
            return
 
1191
 
 
1192
        self.vpathtarget = self.target
 
1193
        self.mtime = None
 
1194
 
 
1195
    def searchinlocs(self, makefile, locs):
 
1196
        """
 
1197
        Look in the given locations relative to the makefile working directory
 
1198
        for a file. Return a pair of the target and the mtime if found, None
 
1199
        if not.
 
1200
        """
 
1201
        for t in locs:
1006
1202
            fspath = util.normaljoin(makefile.workdir, t).replace('\\', '/')
1007
1203
            mtime = getmtime(fspath)
1008
1204
#            _log.info("Searching %s ... checking %s ... mtime %r" % (t, fspath, mtime))
1009
1205
            if mtime is not None:
1010
 
                self.vpathtarget = t
1011
 
                self.mtime = mtime
1012
 
                return
 
1206
                return (t, mtime)
1013
1207
 
1014
 
        self.vpathtarget = self.target
1015
 
        self.mtime = None
 
1208
        return None
1016
1209
        
1017
1210
    def beingremade(self):
1018
1211
        """
1019
 
        When we remake ourself, we need to reset our mtime and vpathtarget.
1020
 
 
1021
 
        We store our old mtime so that $? can calculate out-of-date prerequisites.
 
1212
        When we remake ourself, we have to drop any vpath prefixes.
1022
1213
        """
1023
 
        self.realmtime = self.mtime
1024
 
        self.mtime = None
1025
1214
        self.vpathtarget = self.target
1026
1215
        self.wasremade = True
1027
1216
 
1028
1217
    def notifydone(self, makefile):
1029
1218
        assert self._state == MAKESTATE_WORKING, "State was %s" % self._state
 
1219
        # If we were remade then resolve mtime again
 
1220
        if self.wasremade:
 
1221
            targetandtime = self.searchinlocs(makefile, [self.target])
 
1222
            if targetandtime is not None:
 
1223
                (_, self.mtime) = targetandtime
 
1224
            else:
 
1225
                self.mtime = None
1030
1226
 
1031
1227
        self._state = MAKESTATE_FINISHED
1032
1228
        for cb in self._callbacks:
1133
1329
    prtargets = [makefile.gettarget(p) for p in prerequisites]
1134
1330
    prall = [pt.vpathtarget for pt in prtargets]
1135
1331
    proutofdate = [pt.vpathtarget for pt in withoutdups(prtargets)
1136
 
                   if target.realmtime is None or mtimeislater(pt.mtime, target.realmtime)]
 
1332
                   if target.mtime is None or mtimeislater(pt.mtime, target.mtime)]
1137
1333
    
1138
1334
    setautomatic(v, '@', [target.vpathtarget])
1139
1335
    if len(prall):
1204
1400
        _CommandWrapper.__init__(self, cline, ignoreErrors, loc, context,
1205
1401
                                 **kwargs)
1206
1402
        # get the module and method to call
1207
 
        parts, badchar = process.clinetoargv(cline)
 
1403
        parts, badchar = process.clinetoargv(cline, blacklist_gray=False)
1208
1404
        if parts is None:
1209
1405
            raise DataError("native command '%s': shell metacharacter '%s' in command line" % (cline, badchar), self.loc)
1210
1406
        if len(parts) < 2:
1542
1738
        if len(np.rules):
1543
1739
            self.context = process.getcontext(1)
1544
1740
 
 
1741
        flavor, source, value = self.variables.get('.DEFAULT_GOAL')
 
1742
        if value is not None:
 
1743
            self.defaulttarget = value.resolvestr(self, self.variables, ['.DEFAULT_GOAL']).strip()
 
1744
 
1545
1745
        self.error = False
1546
1746
 
1547
1747
    def include(self, path, required=True, weak=False, loc=None):