~ubuntu-branches/ubuntu/precise/enigmail/precise-security

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2012-11-12 16:36:01 UTC
  • mfrom: (0.12.15)
  • Revision ID: package-import@ubuntu.com-20121112163601-t8e8skdfi3ni9iqp
Tags: 2:1.4.6-0ubuntu0.12.04.1
* New upstream release v1.4.6
  - see LP: #1080212 for USN information
* Drop unneeded patches
  - remove debian/patches/correct-version-number.diff
  - remove debian/patches/dont_register_cids_multiple_times.diff
  - update debian/patches/series
* Support building in an objdir
  - update debian/rules

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
 
101
179
        assert i == 0
102
180
        return self.s, False
103
181
 
104
 
    def __str__(self):
 
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.
110
 
    """
111
 
 
112
 
    __slots__ = ('loc', 'hasfunc')
 
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.
 
210
    """
 
211
 
 
212
    __slots__ = ('loc',)
113
213
    simple = False
114
214
 
115
215
    def __init__(self, loc=None):
116
216
        # A list of (element, isfunc) tuples
117
217
        # element is either a string or a function
118
218
        self.loc = loc
119
 
        self.hasfunc = False
120
219
 
121
220
    @staticmethod
122
221
    def fromstring(s, path):
137
236
    def appendfunc(self, func):
138
237
        assert isinstance(func, functions.Function)
139
238
        self.append((func, True))
140
 
        self.hasfunc = True
141
239
 
142
240
    def concat(self, o):
143
241
        """Concatenate the other expansion on to this one."""
145
243
            self.appendstr(o.s)
146
244
        else:
147
245
            self.extend(o)
148
 
            self.hasfunc = self.hasfunc or o.hasfunc
149
246
 
150
247
    def isempty(self):
151
248
        return (not len(self)) or self[0] == ('', False)
179
276
            del self[-1]
180
277
 
181
278
    def finish(self):
182
 
        if self.hasfunc:
183
 
            return self
184
 
 
185
 
        return StringExpansion(''.join([i for i, isfunc in self]), self.loc)
 
279
        # Merge any adjacent literal strings:
 
280
        strings = []
 
281
        elements = []
 
282
        for (e, isfunc) in self:
 
283
            if isfunc:
 
284
                if strings:
 
285
                    s = ''.join(strings)
 
286
                    if s:
 
287
                        elements.append((s, False))
 
288
                    strings = []
 
289
                elements.append((e, True))
 
290
            else:
 
291
                strings.append(e)
 
292
 
 
293
        if not elements:
 
294
            # This can only happen if there were no function elements.
 
295
            return StringExpansion(''.join(strings), self.loc)
 
296
 
 
297
        if strings:
 
298
            s = ''.join(strings)
 
299
            if s:
 
300
                elements.append((s, False))
 
301
 
 
302
        if len(elements) < len(self):
 
303
            self[:] = elements
 
304
 
 
305
        return self
186
306
 
187
307
    def resolve(self, makefile, variables, fd, setting=[]):
188
308
        """
212
332
    def resolvesplit(self, makefile, variables, setting=[]):
213
333
        return self.resolvestr(makefile, variables, setting).split()
214
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
 
215
355
    def __repr__(self):
216
356
        return "<Expansion with elements: %r>" % ([e for e, isfunc in self],)
217
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
 
218
420
class Variables(object):
219
421
    """
220
422
    A mapping from variable names to variables. Variables have flavor, source, and value. The value is an 
694
896
            else:
695
897
                for d, weak in self.deps:
696
898
                    if mtimeislater(d.mtime, self.target.mtime):
697
 
                        self.target.beingremade()
 
899
                        if d.mtime is None:
 
900
                            self.target.beingremade()
 
901
                        else:
 
902
                            _log.info("%sNot remaking %s ubecause it would have no effect, even though %s is newer.", indent, self.target.target, d.target)
698
903
                        break
699
904
            cb(error=False)
700
905
            return
979
1184
            search += [util.normaljoin(dir, self.target).replace('\\', '/')
980
1185
                       for dir in makefile.getvpath(self.target)]
981
1186
 
982
 
        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:
983
1202
            fspath = util.normaljoin(makefile.workdir, t).replace('\\', '/')
984
1203
            mtime = getmtime(fspath)
985
1204
#            _log.info("Searching %s ... checking %s ... mtime %r" % (t, fspath, mtime))
986
1205
            if mtime is not None:
987
 
                self.vpathtarget = t
988
 
                self.mtime = mtime
989
 
                return
 
1206
                return (t, mtime)
990
1207
 
991
 
        self.vpathtarget = self.target
992
 
        self.mtime = None
 
1208
        return None
993
1209
        
994
1210
    def beingremade(self):
995
1211
        """
996
 
        When we remake ourself, we need to reset our mtime and vpathtarget.
997
 
 
998
 
        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.
999
1213
        """
1000
 
        self.realmtime = self.mtime
1001
 
        self.mtime = None
1002
1214
        self.vpathtarget = self.target
1003
1215
        self.wasremade = True
1004
1216
 
1005
1217
    def notifydone(self, makefile):
1006
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
1007
1226
 
1008
1227
        self._state = MAKESTATE_FINISHED
1009
1228
        for cb in self._callbacks:
1110
1329
    prtargets = [makefile.gettarget(p) for p in prerequisites]
1111
1330
    prall = [pt.vpathtarget for pt in prtargets]
1112
1331
    proutofdate = [pt.vpathtarget for pt in withoutdups(prtargets)
1113
 
                   if target.realmtime is None or mtimeislater(pt.mtime, target.realmtime)]
 
1332
                   if target.mtime is None or mtimeislater(pt.mtime, target.mtime)]
1114
1333
    
1115
1334
    setautomatic(v, '@', [target.vpathtarget])
1116
1335
    if len(prall):
1181
1400
        _CommandWrapper.__init__(self, cline, ignoreErrors, loc, context,
1182
1401
                                 **kwargs)
1183
1402
        # get the module and method to call
1184
 
        parts, badchar = process.clinetoargv(cline)
 
1403
        parts, badchar = process.clinetoargv(cline, blacklist_gray=False)
1185
1404
        if parts is None:
1186
1405
            raise DataError("native command '%s': shell metacharacter '%s' in command line" % (cline, badchar), self.loc)
1187
1406
        if len(parts) < 2:
1519
1738
        if len(np.rules):
1520
1739
            self.context = process.getcontext(1)
1521
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
 
1522
1745
        self.error = False
1523
1746
 
1524
1747
    def include(self, path, required=True, weak=False, loc=None):