Current File : //bin/deb-janitor
#!/usr/bin/python3
# Copyright (c) 2020 Jelmer Vernooij <jelmer@debian.org>
#
# 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 3
# 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.
#
# See file /usr/share/common-licenses/GPL-3 for more details.
#

"""
Command-line interface for the Debian Janitor.

See https://janitor.debian.net/
"""

import argparse
import json
import sys
from urllib.request import urlopen, Request
from urllib.error import HTTPError

import devscripts

DEFAULT_API_URL = 'https://janitor.debian.net/api/'
USER_AGENT = 'devscripts janitor cli (%s)' % (devscripts.version)
DEFAULT_URLLIB_TIMEOUT = 30


def _get_json_url(http_url: str, timeout: int = DEFAULT_URLLIB_TIMEOUT):
    headers = {'User-Agent': USER_AGENT, 'Accept': 'application/json'}
    with urlopen(Request(http_url, headers=headers), timeout=timeout) as resp:
        http_contents = resp.read()
    return json.loads(http_contents)


def schedule(source, suite, api_url=DEFAULT_API_URL):
    """Schedule a new run for a package.

    Args:
      source: the source package name
      suite: the suite to schedule for
    """
    url = '%s%s/pkg/%s/schedule' % (api_url, suite, source)
    headers = {'User-Agent': USER_AGENT}
    req = Request(url, headers=headers, method='POST')
    try:
        with urlopen(req) as resp:
            resp = json.load(resp)
    except HTTPError as err:
        if err.code == 404:
            raise NoSuchSource(json.loads(err.read())['reason']) from err
        raise
    estimated_duration = resp['estimated_duration_seconds']
    queue_position = resp['queue_position']
    queue_wait_time = resp['queue_wait_time']
    return (estimated_duration, queue_position, queue_wait_time)


class MissingDiffError(Exception):
    """There is no diff for the specified package/suite combination."""


class NoSuchSource(Exception):
    """There is no source package known with the specified name."""


def diff(source, suite, api_url=DEFAULT_API_URL):
    """Retrieve the source diff for a package/suite.

    Args:
      source: the source package name
      suite: the suite to retrieve
    Returns:
      the diff as a bytestring
    Raises:
      MissingDiffError: If the diff was missing
        (source not valid, suite not valid, no runs yet, etc)
    """
    url = '%s%s/pkg/%s/diff' % (api_url, suite, source)
    headers = {'User-Agent': USER_AGENT, 'Accept': 'text/plain'}
    req = Request(url, headers=headers)
    try:
        with urlopen(req) as resp:
            data = resp.read()
    except HTTPError as err:
        if err.code == 404:
            raise MissingDiffError(err.read().decode()) from err
        raise err
    else:
        return data


def main(argv):
    """Handle command-line arguments."""
    parser = argparse.ArgumentParser('janitor')
    parser.add_argument(
        '--api-url', type=str, help='API endpoint to talk to',
        default=DEFAULT_API_URL)
    subparsers = parser.add_subparsers(
        help='sub-command help', dest='subcommand')
    schedule_parser = subparsers.add_parser('schedule')
    schedule_parser.add_argument('source')
    schedule_parser.add_argument('suite')
    diff_parser = subparsers.add_parser('diff')
    diff_parser.add_argument('source', help='Source package name')
    diff_parser.add_argument('suite')
    args = parser.parse_args(argv)
    if args.subcommand == 'schedule':
        try:
            (est_duration, pos, wait_time) = schedule(
                args.source, args.suite, api_url=args.api_url)
        except NoSuchSource as err:
            sys.stderr.write('%s\n' % err.args[0])
            return 1
        print(
            'Scheduled. Estimated duration: %.2fs, '
            'queue position: %d (wait time: %.2f)' % (
                est_duration, pos, wait_time))
        return 0
    if args.subcommand == 'diff':
        try:
            sys.stdout.buffer.write(
                diff(args.source, args.suite, api_url=args.api_url))
            sys.stdout.flush()
        except MissingDiffError as err:
            sys.stderr.write('%s\n' % err.args[0])
            return 1
        else:
            return 0
    parser.print_usage()
    return 1


if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))