#!/usr/bin/python
# -*- coding: utf-8 -*-

import argparse
import logging
import os
import pipes
import subprocess
import sys
import time
import StringIO

devnull = open('/dev/null', 'w')

def cmd_str(cmd):
    return ' '.join([pipes.quote(s) for s in cmd])

def check_pkg_in_cache(pkg, version):
    cmd = ['apt-cache', 'show', pkg + '=' + version]
    logging.debug('running: ' + cmd_str(cmd))
    exit_code = subprocess.call(cmd, stdout=devnull, stderr=subprocess.STDOUT)
    return exit_code == 0

description = u'''
Проверить наличие информации о пакете в кэше apt (другими словами, можно его установить или нет). Запустить apt-get update и проверить ещё раз, если нужно.

# проверить и выйти с 0, если есть, не-0, если нет
{script} yandex-direct 1.5119610-1
# если не нашли, попытаться сделать apt-get update максимум 3 раза с перерывами по 10 секунд, после каждого запуска проверять, появился ли
{script} yandex-direct 1.5119610-1 --update-retries 3 --retries-delay 10
'''.format(script=os.path.basename(sys.argv[0]))

parser = argparse.ArgumentParser(description=description, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('package')
parser.add_argument('version')
parser.add_argument('--update-retries', type=int, default=0, help=u'сколько раз повторять apt-get update (0 -- вообще не запускать)')
parser.add_argument('--retries-delay', type=int, default=10, help=u'сколько секунд спать перед следующим запуском apt-get update')
parser.add_argument('--verbose', '-v', action='store_true')

args = parser.parse_args()
pkg = args.package
version = args.version
retries = args.update_retries
delay = args.retries_delay
logging.basicConfig(level=logging.INFO, format='%(message)s')
if args.verbose:
    logging.getLogger().setLevel(logging.DEBUG)

if check_pkg_in_cache(pkg, version):
    logging.debug('{}={} found in cache'.format(pkg, version))
    sys.exit(0)
else:
    logging.debug('{}={} NOT found in cache'.format(pkg, version))
for i in range(retries):
    if os.geteuid() != 0:
        sys.exit('error: must be root to run apt-get update')
    is_final_attempt = (i == retries-1)
    update_cmd_stdout = devnull
    if is_final_attempt:
       update_cmd_stdout = StringIO.StringIO() 
    logging.debug('updating apt cache, attempt #{}: running apt-get update'.format(i+1))
    try:
        out = subprocess.check_output(['apt-get', 'update'], stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as e:
        exit_code = e.returncode
        out = e.output
        if is_final_attempt:
            logging.info('apt-get update failed with code %d' % exit_code)
            logging.info('apt-get update output:')
            logging.info(out)
            sys.exit(exit_code)
            # Другой вариант обработки падения apt-get update: завершаться после первого же падения. Но если падает из-за занятого лока, лучше повторить, а так происходит чаще, чем какие-то принципиальные проблемы с update
        else:
            pass
    if check_pkg_in_cache(pkg, version):
        logging.debug('{}={} found in cache'.format(pkg, version))
        sys.exit(0)
    else:
        logging.debug('{}={} NOT found in cache'.format(pkg, version))
    logging.debug('sleeping for {} seconds'.format(delay))
    if not is_final_attempt:
        time.sleep(delay)
sys.exit(1)
