#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
#
# Univention Updater
#  merge repositories
#
# Copyright 2004-2014 Univention GmbH
#
# http://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <http://www.gnu.org/licenses/>.

import os
import shutil, sys
import getopt

import univention.config_registry as ucr
import univention.updater.repository as urepo
import univention.updater.tools
from univention.updater import UniventionMirror, UCS_Version

l_package={}
p_remove=[]
destination_dir=''

def usage(fd=sys.stdout):
	""" Print usage information """
	print >>fd, 'univention-repository-merge: tool for merging packages directories'
	print >>fd, 'copyright (c) 2004-@%@copyright_lastyear@%@ Univention GmbH, Germany'
	print >>fd, ''
	print >>fd, 'Syntax:'
	print >>fd, '  univention-repository-merge --dest <destination_dir> --src <source_dir> [--src <source_dir>]'
	print >>fd, '  univention-repository-merge [--help] '
	print >>fd, ''


def compare(version1, version2):
	""" Test if version1 is newer than version2 """
	resultCode=os.system('dpkg --compare-versions %s gt %s >/dev/null 2>&1' % (version1, version2))
	return resultCode == 0

def walking(arg, dirname, names):
	""" Update l_package hash with new and p_remove hash with obsolete .deb files """
	for f in names:
		file=os.path.join(dirname, f)

		if file.endswith('.deb'):
			out=os.popen('dpkg -I %s' % file )

			package=''
			version=''
			arch=''
			for line in out.readlines():
				line=line.strip()
				if line.startswith('Package: '):
					package = ' '.join(line.split(' ', 1)[1:])
				if line.startswith('Version: '):
					version = ' '.join(line.split(' ', 1)[1:])
				if line.startswith('Architecture: '):
					arch = ' '.join(line.split(' ', 1)[1:])

			key = (package, arch)
			record = l_package.get(key)
			if record:
				if compare(version, record[1]):
					p_remove.append(record[0])
					l_package[key]=[file, version, arg]
				else:
					p_remove.append(file)
			else:
				l_package[key]=[file, version, arg]

def cleanup_repository( directory ):
	""" Remove all .deb files recursively from directory """
	def _walk( fp_debug, dirname, names ):
		for name in names:
			filename = os.path.join( dirname, name )
			if os.path.isfile( filename ) and filename.endswith( '.deb' ):
				try:
					os.unlink( filename )
				except:
					fp_debug.write('Warning: failed to remove %s\n' % i)

	fp_debug = open( '/var/log/univention/repository.log', 'a+' )
	try:
		os.path.walk( directory, _walk, fp_debug )
	finally:
		fp_debug.close()

# parse options
if __name__ == '__main__':

	if len(sys.argv) < 2:
		usage()
		sys.exit(1)
		
	if sys.argv[1] in ['-h', '-?', '--help']:
		usage()
		sys.exit(0)


	longopts=['dest=', 'src=' ]
	try:
		opts, args=getopt.getopt(sys.argv[1:], '', longopts)
	except getopt.error, msg:
		print msg
		sys.exit(1)

	try:
		lock = univention.updater.tools.updater_lock_acquire()
	except univention.updater.tools.LockingError, e:
		print >>sys.stderr, e
		sys.exit(5)
	try:
		source_dirs=[]
		for opt, val in opts:
			if opt == '--dest':
				destination_dir=val
			elif opt == '--src':
				src = urepo.get_repo_basedir( val )
				source_dirs.append( src )

		if not destination_dir:
			usage()
			sys.exit(1)

		destination_dir = urepo.get_repo_basedir( destination_dir )

		if len(source_dirs) < 1:
			usage()
			sys.exit(1)

		os.path.walk(destination_dir, walking, 1)

		for dir in source_dirs:
			src = urepo.get_repo_basedir( dir )
			os.path.walk( src, walking, 0 )

		packages_dir=os.path.join(destination_dir)
		if not os.path.exists(packages_dir):
			os.mkdir(packages_dir)

		fp_debug=open('/var/log/univention/repository.log', 'a+')
		for k in l_package.keys():
			if l_package[k][2] == 0: #if not dest dir
				try:
					dest = os.path.join( packages_dir, k[ 1 ] )
					shutil.copy(l_package[k][0], dest )
				except:
					fp_debug.write('Error: faild to copy %s\n' % dest )

		for f in p_remove:
			try:
				os.remove(f)
			except:
				fp_debug.write('Warning: failed to remove %s\n' % f)

		save_dir=os.path.realpath(os.path.curdir)

		for dir in source_dirs:
			if dir == packages_dir:
				continue
			cleanup_repository( dir )

			urepo.update_indexes( dir, stdout = fp_debug, stderr = fp_debug )

		os.chdir(save_dir)
		os.chdir(packages_dir)
		urepo.update_indexes( packages_dir, stdout = fp_debug, stderr = fp_debug )
		fp_debug.close()
	finally:
		if not univention.updater.tools.updater_lock_release(lock):
			print 'WARNING: updater-lock already released!'
