This file is indexed.

/usr/lib/python2.7/dist-packages/dput/util.py is in python-dput 1.8.

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
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# -*- coding: utf-8 -*-
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4

# Copyright (c) 2012 dput authors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
"""
Misc & helper functions
"""

import os
import json
import shlex
import importlib
import subprocess
from contextlib import contextmanager

import dput.core
from dput.core import logger
from dput.exceptions import (NoSuchConfigError, DputConfigurationError,
                             InvalidConfigError)


def load_obj(obj_path):
    """
    Dynamically load an object (class, method, etc) by name (such as
    `dput.core.ClassName`), and return that object to work with. This is
    useful for loading modules on the fly, without them being all loaded at
    once, or even in the same package.

    Call this routine with at least one dot in it -- it attempts to load the
    module (such as dput.core) and use getattr to load the thing - similar to
    how `from` works.
    """
    dput.core.mangle_sys()
    logger.trace("Loading object: %s" % (obj_path))
    module, obj = obj_path.rsplit(".", 1)
    mod = importlib.import_module(module)
    fltr = getattr(mod, obj)
    return fltr


def get_obj(cls, checker_method):  # checker_method is a bad name.
    """
    Get an object by plugin def (``checker_method``) in class ``cls`` (such
    as ``hooks``).
    """
    logger.trace("Attempting to resolve %s %s" % (cls, checker_method))
    try:
        config = load_config(cls, checker_method)
        validate_object('plugin', config, "%s/%s" % (cls, checker_method))

        if config is None or config == {}:
            raise NoSuchConfigError("No such config")
    except NoSuchConfigError:
        logger.debug("failed to resolve config %s" % (checker_method))
        return None
    path = config['path']
    logger.trace("loading %s %s" % (cls, path))
    try:
        return load_obj(path)
    except ImportError as e:
        logger.warning("failed to resolve path %s: %s" % (path, e))
        return None


def run_command(command):
    """
    Run a synchronized command. The argument must be a list of arguments.
    Returns a triple (stdout, stderr, exit_status)

    If there was a problem to start the supplied command, (None, None, -1) is
    returned
    """
    if not isinstance(command, list):
        command = shlex.split(command)
    try:
        pipe = subprocess.Popen(command,
                                shell=False,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
    except OSError as e:
        logger.error("Could not execute %s: %s" % (" ".join(command), e))
        return (None, None, -1)
    (output, stderr) = pipe.communicate()
    #if pipe.returncode != 0:
    #   error("Command %s returned failure: %s" % (" ".join(command), stderr))
    return (output, stderr, pipe.returncode)


def get_configs(cls):
    """
    Get all valid config targets for class ``cls``.
    """
    configs = set()
    for path in dput.core.CONFIG_LOCATIONS:
        path = "%s/%s" % (path, cls)
        if os.path.exists(path):
            for fil in os.listdir(path):
                xtn = ".json"
                if fil.endswith(xtn):
                    configs.add(fil[:-len(xtn)])
    return configs


def _config_cleanup(obj):
    """
    Handle merging plus, minus and set fields. Internal only.
    """
    def do_add(new, old):
        if not isinstance(new, list) and not isinstance(old, list):
            raise Exception("WTF NOT LIST")  # XXX: better exception

        nset = set(new)
        oset = set(old)
        nobj = oset | nset
        return list(nobj)

    def do_sub(new, old):
        if not isinstance(new, list) and not isinstance(old, list):
            raise Exception("WTF NOT LIST")  # XXX: better exception
        nset = set(new)
        oset = set(old)
        nobj = oset - nset
        return list(nobj)

    def do_eql(new, old):
        return new

    operators = {
        "+": do_add,
        "-": do_sub,
        "=": do_eql
    }

    ret = obj.copy()
    for key in obj:
        operator = key[0]
        if operator not in operators:
            continue

        kname = key[1:]
        op = operators[operator]

        if kname in ret:
            ret[kname] = op(ret[key], ret[kname])
        else:
            foo = op(ret[key], [])
            if foo != []:
                ret[kname] = foo
        ret.pop(key)
    return ret


def validate_object(schema, obj, name):
    sobj = None
    for root in dput.core.SCHEMA_DIRS:
        if sobj is not None:
            logger.debug("Skipping %s" % (root))
            continue

        logger.debug("Loading schema %s from %s" % (schema, root))
        spath = "%s/%s.json" % (
            root,
            schema
        )
        try:
            if os.path.exists(spath):
                sobj = json.load(open(spath, 'r'))
            else:
                logger.debug("No such config: %s" % (spath))
        except ValueError as e:
            raise DputConfigurationError("syntax error in %s: %s" % (
                spath,
                e
            ))

    if sobj is None:
        logger.critical("Schema not found: %s" % (schema))
        raise DputConfigurationError("No such schema: %s" % (schema))

    try:
        import validictory
        validictory.validate(obj, sobj)
    except ImportError:
        pass
    except validictory.validator.ValidationError as e:
        err = str(e)
        error = "Error with config file %s - %s" % (
            name,
            err
        )
        ex = InvalidConfigError(error)
        ex.obj = obj
        ex.root = e
        ex.config_name = name
        ex.sdir = dput.core.SCHEMA_DIRS
        ex.schema = schema
        raise ex


def load_config(config_class, config_name,
                default=None, configs=None, config_cleanup=True):
    """
    Load any dput configuration given a ``config_class`` (such as
    ``hooks``), and a ``config_name`` (such as
    ``lintian`` or ``tweet``).

    Optional kwargs:

        ``default`` is a default to return, in case the config file
        isn't found. If this isn't provided, this function will
        raise a :class:`dput.exceptions.NoSuchConfigError`.

        ``configs`` is a list of config files to check. When this
        isn't provided, we check dput.core.CONFIG_LOCATIONS.
    """

    logger.debug("Loading configuration: %s %s" % (
        config_class,
        config_name
    ))
    roots = []
    ret = {}
    found = False
    template_path = "%s/%s/%s.json"
    locations = configs or dput.core.CONFIG_LOCATIONS
    for config in locations:
        logger.trace("Checking for configuration: %s" % (config))
        path = template_path % (
            config,
            config_class,
            config_name
        )
        logger.trace("Checking - %s" % (path))
        try:
            if os.path.exists(path):
                found = True
                roots.append(path)
                ret.update(json.load(open(path, 'r')))
        except ValueError as e:
            raise DputConfigurationError("syntax error in %s: %s" % (
                path, e
            ))

    if not found:
        if default is not None:
            return default

        raise NoSuchConfigError("No such config: %s/%s" % (
            config_class,
            config_name
        ))

    if 'meta' in ret and (
        config_class != 'metas' or
        ret['meta'] != config_name
    ):
        metainfo = load_config(
            "metas",
            ret['meta'],
            default={}
        )  # configs=configs)
        # Erm, is this right? For some reason, I don't think it is. Meta
        # handling is a hemorrhoid in my ass. Fuck it, it works. Ship it.
        #   -- PRT
        for key in metainfo:
            if not key in ret:
                ret[key] = metainfo[key]
            else:
                logger.trace("Ignoring key %s for %s (%s)" % (
                    key,
                    ret['meta'],
                    metainfo[key]
                ))

    obj = ret
    if config_cleanup:
        obj = _config_cleanup(ret)

    if obj != {}:
        return obj

    if default is not None:
        return default

    logger.debug("Failed to load configuration %s" % (config_name))

    nsce = NoSuchConfigError("No such configuration: '%s' in class '%s'" % (
        config_name,
        config_class
    ))

    nsce.config_class = config_class
    nsce.config_name = config_name
    nsce.checked = dput.core.CONFIG_LOCATIONS
    raise nsce


def obj_docs(cls, ostr):
    """
    Get an object's docstring by name / class def.
    """
    obj = get_obj(cls, ostr)
    if obj is None:
        raise DputConfigurationError("No such object: `%s'" % (
            ostr
        ))
    return obj.__doc__


@contextmanager
def get_obj_by_name(cls, name, profile):
    """
    Run a function, defined by ``name``, filed in class ``cls``
    """
    logger.trace("running %s: %s" % (cls, name))
    obj = get_obj(cls, name)
    if obj is None:
        raise DputConfigurationError("No such obj: `%s'" % (
            name
        ))

    interface = 'cli'
    if 'interface' in profile:
        interface = profile['interface']
    logger.trace("Using interface %s" % (interface))
    interface_obj = get_obj('interfaces', interface)
    if interface_obj is None:
        raise DputConfigurationError("No such interface: `%s'" % (
            interface
        ))
    interface = interface_obj()
    interface.initialize()

    try:
        yield (obj, interface)
    finally:
        pass

    interface.shutdown()


def run_func_by_name(cls, name, changes, profile):
    """
    Run a function, defined by ``name``, filed in class ``cls``,
    with a :class:`dput.changes.Changes` (``changes``), and profile
    ``profile``.

    This is used to run the hooks, internally.
    """
    with get_obj_by_name(cls, name, profile) as(obj, interface):
        obj(changes, profile, interface)