This file is indexed.

/usr/share/pyshared/webassets/version.py is in python-webassets 3:0.9-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
"""This module defines the Version classes, and the related Manifest
implementations.
"""

from __future__ import with_statement

import os
import pickle
from webassets import six

from webassets.bundle import has_placeholder, is_url, get_all_bundle_files
from webassets.merge import FileHunk
from webassets.utils import md5_constructor, RegistryMetaclass


__all__ = ('get_versioner', 'VersionIndeterminableError',
           'Version', 'TimestampVersion',
           'get_manifest', 'HashVersion', 'Manifest', 'FileManifest',)


class VersionIndeterminableError(Exception):
    pass


class Version(six.with_metaclass(RegistryMetaclass(
    clazz=lambda: Version, attribute='determine_version',
    desc='a version implementation'))):
    """A Version class that can be assigned to the ``Environment.versioner``
    attribute.

    Given a bundle, this must determine its "version". This version can then
    be used in the output filename of the bundle, or appended to the url as a
    query string, in order to expire cached assets.

    A version could be a timestamp, a content hash, or a git revision etc.

    As a user, all you need to care about, in most cases, is whether you want
    to set the ``Environment.versioner`` attribute to ``hash`` or ``timestamp``.

    A single instance can be used with different environments.
    """

    def determine_version(self, bundle, hunk=None, env=None):
        """Return a string that represents the current version of the given
        bundle.

        This method is called on two separate occasions:

        1) After a bundle has been built and is about to be saved. If the
           output filename contains a placeholder, this method is asked for the
           version. This mode is indicated by the ``hunk`` argument being
           available.

        2) When a version is required for an already built file, either
           because:

              *) An URL needs to be constructed.
              *) It needs to be determined if a bundle needs an update.

           *This will only occur* if *no manifest* is used. If there is a
           manifest, it would be used to determine the version instead.

        Support for option (2) is optional. If not supported, then in those
        cases a manifest needs to be configured. ``VersionIndeterminableError``
        should be raised with a message why.
        """
        raise NotImplementedError()

    def set_version(self, bundle, env, filename, version):
        """Hook called after a bundle has been built. Some version classes
        may need this.
        """


get_versioner = Version.resolve


class TimestampVersion(Version):
    """Uses the most recent 'last modified' timestamp of all source files
    as the version.

    Uses second-precision.
    """

    id = 'timestamp'

    def determine_version(self, bundle, env, hunk=None):
        # Only look at an existing output file if we are not about to
        # overwrite it with a new version. But if we can, simply using the
        # timestamp of the final file is the fastest way to do this.
        # Note that this works because of our ``save_done`` hook.
        if not hunk:
            if not has_placeholder(bundle.output):
                return self.get_timestamp(bundle.resolve_output(env))

        # If we need the timestamp for the file we just built (hunk!=None),
        # or if we need the timestamp for a bundle with a placeholder,
        # the way to get it is by looking at the source files.
        try:
            return self.find_recent_most_timestamp(bundle, env)
        except OSError:
            # Source files are missing. Under these circumstances, we cannot
            # return a proper version.
            assert hunk is None
            raise VersionIndeterminableError(
                'source files are missing and output target has a '
                'placeholder')

    def set_version(self, bundle, env, filename, version):
        # Update the mtime of the newly created file with the version
        os.utime(filename, (-1, version))

    @classmethod
    def get_timestamp(cls, filename):
        return int(os.stat(filename).st_mtime)    # Let OSError pass

    @classmethod
    def find_recent_most_timestamp(cls, bundle, env):
        # Recurse through the bundle hierarchy. Check the timestamp of all
        # the bundle source files, as well as any additional
        # dependencies that we are supposed to watch.
        most_recent = None
        for filename in get_all_bundle_files(bundle, env):
            if is_url(filename):
                continue
            timestamp = cls.get_timestamp(filename)
            if most_recent is None or timestamp > most_recent:
                most_recent = timestamp
        return most_recent


class HashVersion(Version):
    """Uses the MD5 hash of the content as the version.

    By default, only the first 8 characters of the hash are used, which
    should be sufficient. This can be changed by passing the appropriate
    ``length`` value to ``__init__`` (or ``None`` to use the full hash).

    You can also customize the hash used by passing the ``hash`` argument.
    All constructors from ``hashlib`` are supported.
    """

    id = 'hash'

    @classmethod
    def make(cls, length=None):
        args = [int(length)] if length else []
        return cls(*args)

    def __init__(self, length=8, hash=md5_constructor):
        self.length = length
        self.hasher = hash

    def determine_version(self, bundle, env, hunk=None):
        if not hunk:
            if not has_placeholder(bundle.output):
                hunk = FileHunk(bundle.resolve_output(env))
            else:
                # Can cannot determine the version of placeholder files.
                raise VersionIndeterminableError(
                    'output target has a placeholder')

        hasher = self.hasher()
        hasher.update(hunk.data().encode('utf-8'))
        return hasher.hexdigest()[:self.length]


class Manifest(six.with_metaclass(RegistryMetaclass(
    clazz=lambda: Manifest, desc='a manifest implementation'))):
    """Persists information about the versions bundles are at.

    The Manifest plays a role only if you insert the bundle version in your
    output filenames, or append the version as a querystring to the url (via
    the url_expire option). It serves two purposes:

        - Without a manifest, it may be impossible to determine the version
          at runtime. In a deployed app, the media files may be stored on
          a different server entirely, and be inaccessible from the application
          code. The manifest, if shipped with your application, is what still
          allows to construct the proper URLs.

        - Even if it were possible to determine the version at runtime without
          a manifest, it may be a costly process, and using a manifest may
          give you better performance. If you use a hash-based version for
          example, this hash would need to be recalculated every time a new
          process is started. (*)

    (*) It needs to happen only once per process, because Bundles are smart
        enough to cache their own version in memory.

    A special case is the ``Environment.auto_build`` option. A manifest
    implementation should re-read its data from its out-of-process data
    source on every request, if ``auto_build`` is enabled. Otherwise, if your
    application is served by multiple processes, then after an automatic
    rebuild in one process all other processes would continue to serve an old
    version of the file (or attach an old version to the query string).

    A manifest instance is currently not guaranteed to function correctly
    with multiple Environment instances.
    """

    def remember(self, bundle, env, version):
        raise NotImplementedError()

    def query(self, bundle, env):
        raise NotImplementedError()


get_manifest = Manifest.resolve


class FileManifest(Manifest):
    """Stores version data in a single file.

    Uses Python's pickle module to store a dict data structure. You should
    only use this when the manifest is read-only in production, since it is
    not multi-process safe. If you use ``auto_build`` in production, use
    ``CacheManifest`` instead.

    By default, the file is named ".webassets-manifest" and stored in
    ``Environment.directory``.
    """

    id = 'file'

    @classmethod
    def make(cls, env, filename=None):
        if not filename:
            filename = '.webassets-manifest'
        return cls(os.path.join(env.directory, filename))

    def __init__(self, filename):
        self.filename = filename
        self._load_manifest()

    def remember(self, bundle, env, version):
        self.manifest[bundle.output] = version
        self._save_manifest()

    def query(self, bundle, env):
        if env.auto_build:
            self._load_manifest()
        return self.manifest.get(bundle.output, None)

    def _load_manifest(self):
        if os.path.exists(self.filename):
            with open(self.filename, 'rb') as f:
                self.manifest = pickle.load(f)
        else:
            self.manifest = {}

    def _save_manifest(self):
        with open(self.filename, 'wb') as f:
            pickle.dump(self.manifest, f, protocol=2)


class JsonManifest(FileManifest):
    """Same as ``FileManifest``, but uses JSON instead of pickle."""

    id = 'json'

    def __init__(self, *a, **kw):
        try:
            import json
        except ImportError:
            import simplejson as json
        self.json = json
        super(JsonManifest, self).__init__(*a, **kw)

    def _load_manifest(self):
        if os.path.exists(self.filename):
            with open(self.filename, 'r') as f:
                self.manifest = self.json.load(f)
        else:
            self.manifest = {}

    def _save_manifest(self):
        with open(self.filename, 'w') as f:
            self.json.dump(self.manifest, f, indent=4, sort_keys=True)


class CacheManifest(Manifest):
    """Stores version data in the webassets cache.

    Since this has bad portability (you hardly want to copy your cache between
    machines), this only makes sense when you are building on the same machine
    where you're application code runs.

    When you are using ``auto_build`` in production, this is exactly what you
    want to use, since it is multi-process safe.
    """

    id = 'cache'

    def _check(self, env):
        if not env.cache:
            raise EnvironmentError(
                'You are using the cache manifest, but have not '
                'enabled the cache.')

    def remember(self, bundle, env, version):
        self._check(env)
        env.cache.set(('manifest', bundle.output), version)

    def query(self, bundle, env):
        self._check(env)
        return env.cache.get(('manifest', bundle.output))


class SymlinkManifest(Manifest):
    """Creates a symlink to the actual file.

    E.g. compressed-current.js -> compressed-1ebcdc5.js
    """

    # Implementation notes: Would presumably be Linux only initially,
    # could clean up after itself, may be hard to implement and maybe
    # shouldn't, would only we usable to resolve placeholders in filenames.

    def __init__(self):
        raise NotImplementedError()   # TODO