#!/usr/bin/python

# Copyright 2003-2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2


from __future__ import print_function


__author__ = "Thomas de Grenier de Latour (tgl), " + \
	"modular re-write by: Brian Dolbec (dol-sen)"
__email__ = "degrenier@easyconnect.fr, " + \
	"brian.dolbec@gmail.com"
__version__ = "svn"
__productname__ = "eclean"
__description__ = "A cleaning tool for Gentoo distfiles and binaries."


import os
import sys
import re
import time
import getopt

import portage
from portage.output import white, yellow, turquoise, green, teal, red

import gentoolkit.pprinter as pp
from gentoolkit.eclean.search import (DistfilesSearch,
	findPackages, port_settings, pkgdir)
from gentoolkit.eclean.exclude import (parseExcludeFile,
	ParseExcludeFileException)
from gentoolkit.eclean.clean import CleanUp
from gentoolkit.eclean.output import OutputControl
#from gentoolkit.eclean.dbapi import Dbapi
from gentoolkit.eprefix import EPREFIX

def printVersion():
	"""Output the version info."""
	print( "%s (%s) - %s" \
			% (__productname__, __version__, __description__))
	print()
	print("Author: %s <%s>" % (__author__,__email__))
	print("Copyright 2003-2009 Gentoo Foundation")
	print("Distributed under the terms of the GNU General Public License v2")


def printUsage(_error=None, help=None):
	"""Print help message. May also print partial help to stderr if an
	error from {'options','actions'} is specified."""

	out = sys.stdout
	if _error:
		out = sys.stderr
	if not _error in ('actions', 'global-options', \
			'packages-options', 'distfiles-options', \
			'merged-packages-options', 'merged-distfiles-options', \
			'time', 'size'):
		_error = None
	if not _error and not help: help = 'all'
	if _error == 'time':
		print( pp.error("Wrong time specification"), file=out)
		print( "Time specification should be an integer followed by a"+
				" single letter unit.", file=out)
		print( "Available units are: y (years), m (months), w (weeks), "+
				"d (days) and h (hours).", file=out)
		print( "For instance: \"1y\" is \"one year\", \"2w\" is \"two"+
				" weeks\", etc. ", file=out)
		return
	if _error == 'size':
		print( pp.error("Wrong size specification"), file=out)
		print( "Size specification should be an integer followed by a"+
				" single letter unit.", file=out)
		print( "Available units are: G, M, K and B.", file=out)
		print("For instance: \"10M\" is \"ten megabytes\", \"200K\" "+
				"is \"two hundreds kilobytes\", etc.", file=out)
		return
	if _error in ('global-options', 'packages-options', 'distfiles-options', \
			'merged-packages-options', 'merged-distfiles-options',):
		print( pp.error("Wrong option on command line."), file=out)
		print( file=out)
	elif _error == 'actions':
		print( pp.error("Wrong or missing action name on command line."), file=out)
		print( file=out)
	print( white("Usage:"), file=out)
	if _error in ('actions','global-options', 'packages-options', \
			'distfiles-options') or help == 'all':
		print( " "+turquoise(__productname__),
			yellow("[global-option] ..."),
			green("<action>"),
			yellow("[action-option] ..."), file=out)
	if _error == 'merged-distfiles-options' or help in ('all','distfiles'):
		print( " "+turquoise(__productname__+'-dist'),
			yellow("[global-option, distfiles-option] ..."), file=out)
	if _error == 'merged-packages-options' or help in ('all','packages'):
		print( " "+turquoise(__productname__+'-pkg'),
			yellow("[global-option, packages-option] ..."), file=out)
	if _error in ('global-options', 'actions'):
		print( " "+turquoise(__productname__),
			yellow("[--help, --version]"), file=out)
	if help == 'all':
		print( " "+turquoise(__productname__+"(-dist,-pkg)"),
			yellow("[--help, --version]"), file=out)
	if _error == 'merged-packages-options' or help == 'packages':
		print( " "+turquoise(__productname__+'-pkg'),
			yellow("[--help, --version]"), file=out)
	if _error == 'merged-distfiles-options' or help == 'distfiles':
		print( " "+turquoise(__productname__+'-dist'),
			yellow("[--help, --version]"), file=out)
	print(file=out)
	if _error in ('global-options', 'merged-packages-options', \
	'merged-distfiles-options') or help:
		print( "Available global", yellow("options")+":", file=out)
		print( yellow(" -C, --nocolor")+
			"            - turn off colors on output", file=out)
		print( yellow(" -d, --destructive")+
			"        - only keep the minimum for a reinstallation", file=out)
		print( yellow(" -
e, --exclude-file=<path>")+
			" - path to the exclusion file", file=out)
		print( yellow(" -i, --interactive")+
			"        - ask confirmation before deletions", file=out)
		print( yellow(" -n, --package-names")+
			"      - protect all versions (when --destructive)", file=out)
		print( yellow(" -p, --pretend")+
			"            - only display what would be cleaned", file=out)
		print( yellow(" -q, --quiet")+
			"              - be as quiet as possible", file=out)
		print( yellow(" -t, 
--time-limit=<time>")+
			"   - don't delete files modified since "+yellow("<time>"), file=out)
		print( "   "+yellow("<time>"), "is a duration: \"1y\" is"+
				" \"one year\", \"2w\" is \"two weeks\", etc. ", file=out)
		print( "   "+"Units are: y (years), m (months), w (weeks), "+
				"d (days) and h (hours).", file=out)
		print( yellow(" -h, --help")+ \
			"               - display the help screen", file=out)
		print( yellow(" -V, --version")+
			"            - display version info", file=out)
		print( file=out)
	if _error == 'actions' or help == 'all':
		print( "Available", green("actions")+":", file=out)
		print( green(" packages")+
			"     - clean outdated binary packages from PKGDIR", file=out)
		print( green(" distfiles")+
			"    - clean outdated packages sources files from DISTDIR", file=out)
		print( file=out)
	if _error in ('packages-options','merged-packages-options') \
	or help in ('all','packages'):
		print( "Available", yellow("options"),"for the",
				green("packages"),"action:", file=out)
		print( yellow(" NONE  :)"), file=out)
		print( file=out)
	if _error in ('distfiles-options', 'merged-distfiles-options') \
	or help in ('all','distfiles'):
		print("Available", yellow("options"),"for the",
				green("distfiles"),"action:", file=out)
		print( yellow(" -f, --fetch-restricted")+
			"   - protect fetch-restricted files (when --destructive)", file=out)
		print( yellow(" -s, --size-limit=<size>")+
			"  - don't delete distfiles bigger than "+yellow("<size>"), file=out)
		print( "   "+yellow("<size>"), "is a size specification: "+
				"\"10M\" is \"ten megabytes\", \"200K\" is", file=out)
		print( "   "+"\"two hundreds kilobytes\", etc.  Units are: "+
				"G, M, K and B.", file=out)
		print( file=out)
	print( "More detailed instruction can be found in",
			turquoise("`man %s`" % __productname__), file=out)


class ParseArgsException(Exception):
	"""For parseArgs() -> main() communications."""
	def __init__(self, value):
		self.value = value # sdfgsdfsdfsd
	def __str__(self):
		return repr(self.value)


def parseSize(size):
	"""Convert a file size "Xu" ("X" is an integer, and "u" in
	[G,M,K,B]) into an integer (file size in Bytes).

	@raise ParseArgsException: in case of failure
	"""
	units = {
		'G': (1024**3),
		'M': (1024**2),
		'K': 1024,
		'B': 1
	}
	try:
		match = re.match(r"^(?P<value>\d+)(?P<unit>[GMKBgmkb])?$",size)
		size = int(match.group('value'))
		if match.group('unit'):
			size *= units[match.group('unit').capitalize()]
	except:
		raise ParseArgsException('size')
	return size


def parseTime(timespec):
	"""Convert a duration "Xu" ("X" is an int, and "u" a time unit in
	[Y,M,W,D,H]) into an integer which is a past EPOCH date.
	Raises ParseArgsException('time') in case of failure.
	(yep, big approximations inside... who cares?).
	"""
	units = {'H' : (60 * 60)}
	units['D'] = units['H'] * 24
	units['W'] = units['D'] * 7
	units['M'] = units['D'] * 30
	units['Y'] = units['D'] * 365
	try:
		# parse the time specification
		match = re.match(r"^(?P<value>\d+)(?P<unit>[YMWDHymwdh])?$",timespec)
		value = int(match.group('value'))
		if not match.group('unit'): unit = 'D'
		else: unit = match.group('unit').capitalize()
	except:
		raise ParseArgsE