#!/usr/bin/python
#
# Copyright (C) 2007-2008 Julian Andres Klode <jak@jak-linux.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.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

'''Compare two app-install-data packages and create changelog and
changelog.verbose entries.'''

from os import listdir
from os.path import splitext
import os.path
from fnmatch import filter
from re import compile
from urllib2 import urlopen
import time
import sys
from debian_bundle.changelog import Changelog as dch

if len(sys.argv) != 3 or not os.path.exists(sys.argv[1]) or not os.path.exists(sys.argv[2]):
	print >> sys.stderr, 'Usage: %s old-dir new-dir' % sys.argv[0]
	print >> sys.stderr, '\nCreates the files changelog and changelog.verbose'
	print >> sys.stderr, 'in the current directory'
	sys.exit(1)
else:
	OLD = os.path.normpath(sys.argv[1]) + '/'
	NEW = os.path.normpath(sys.argv[2]) + '/'

def read_desktop(fname):
	'''Convert a .desktop file into a dict'''
	fobj = open(fname)
	contents = dict([k.strip().split("=", 1) for k in fobj.readlines() if "=" in k])
	fobj.close()
	return contents

def read_release():
	'''Convert a Release file into a dict, if key ends with "s", the value is a set'''
	matcher = compile('(.*): (.*)')
	return dict([(k, (k.endswith("s") and set(v.split()) or v)) for k, v in matcher.findall(urlopen("http://cdimage.debian.org/debian/dists/lenny/Release").read())])

class Changelog:
	'''Create changelog entries'''
	def __init__(self, item):
		self.item = item
		self.msgs = []
	def add(self, *add):
		mymsg = ""
		for msg in add:
			mymsg += " " + self.format(msg)
		self.msgs.append(mymsg)

	def format(self, msg):
		if type(msg) in (tuple, list, set):
			msg1 = str("; ".join(msg))
			msg2 = '\n      + ' + str('\n      + '.join(msg))
			return  len(msg1) > 0 and msg2 or msg1
		else:
			return str(msg)
			my.add_change('  * New snapshot')
	def write(self):
		ret=""
		self.len = len(self.msgs)
		self.msgs = sorted(self.msgs)
		if len(self.msgs) >= 1:
			ret = ('  * %s' % self.item) % self.__dict__ + "\n"
			for i in self.msgs:
				ret += '    -%s' % self.format(i) + "\n"
		elif len(self.msgs) > 0:
			ret = '  * %s:%s' % (self.item, self.format(self.msgs[0]))
		return ret[:-1]


all_archs  = set(('amd64', 'alpha', 'arm', 'armel', 'hppa', 'i386', 'ia64',
              'mips', 'mipsel', 'powerpc', 's390', 'sparc'))
archis     = Changelog('Changes in architectures support:')
pkgrenames = Changelog("Renamed Packages (%(len)s):")
codecs     = Changelog('New/Removed Codecs:')
icons      = Changelog('New/Removed/Changed in Icon keys in desktop files:')
new_desktop = Changelog('NEW Desktop files (%(len)s):')
removed_desktop = Changelog('Removed Desktop files (%(len)s):')

new_icons = Changelog('NEW Icons (%(len)s):')
removed_icons = Changelog('Removed Icons (%(len)s):')

for dname in (NEW + '/menu-data',  NEW + '/menu-data-additional'):
	new = set(filter(listdir(dname), '*.desktop'))
	old = set(filter(listdir(OLD + dname), '*.desktop'))
	both = new & old
	added = new - old
	remov = old - new
	try:
		new2_icons = set((splitext(i)[1] and splitext(i)[0] or i) for i in listdir(dname + "/icons"))
		old2_icons = set((splitext(i)[1] and splitext(i)[0] or i) for i in listdir(OLD  + dname + "/icons"))
	except:
		new2_icons = set()
		old2_icons = set()

	
	icons_added = new2_icons - old2_icons
	icons_remov = old2_icons - new2_icons
	
	if added:
		for i in sorted(added):
			new_desktop.add(i)
		
	if remov:
		for i in sorted(remov):
			removed_desktop.add(i)

	if icons_added:
		for i in sorted(icons_added):
			new_icons.add(i)

	
	if icons_remov:
		for i in sorted(icons_remov):
			removed_icons.add(i)


	# Build changed

	changes = {}
	for i in both:
		new_cont = read_desktop(dname + '/' + i)
		old_cont = read_desktop(OLD + '/' + dname + "/" + i)
		new_keys = set([key for key in new_cont])
		old_keys = set([key for key in old_cont])
		pkg      = new_cont['X-AppInstall-Package']
		for k in new_keys | old_keys:
			nval = k in new_cont and new_cont[k].strip() or None
			oval = k in old_cont and old_cont[k].strip() or None
			if nval:
				if ";" in nval:
					nval = ";".join(sorted(nval.split(";")))
				elif "," in nval:
					nval = ",".join(sorted(nval.split(",")))
			if oval:
				if ";" in oval:
					oval = ";".join(sorted(oval.split(";")))
				elif "," in oval:
					oval = ",".join(sorted(oval.split(",")))

			if (k.startswith("X-AppInstall") or k == 'Icon') and k != 'X-AppInstall-Popcon' and nval != oval:
				if not pkg in changes:
					changes[pkg] = set()
				changes[pkg].add(( k,  oval, nval))


	for pkg, items in sorted(changes.items()):
		#a  = Changelog(pkg)
		for key, old, new in items:
			if key == 'X-AppInstall-Package':
				pkgrenames.add('Renamed %s to %s' % ( old, new))
			elif key == 'X-AppInstall-Architectures':
				new = new and set(new.split(",")) or set()
				old = old and set(old.split(",")) or set()
	
				if not new:
					archis.add('%s now supports all architectures' % pkg)
				elif not old:
					archis.add('%s does not support:' % pkg, all_archs - new)
				else:
					if new - old:
						archis.add('%s now supports:' % pkg, new - old)
					if old - new:
						archis.add('%s does not support anymore:' % pkg, old - new)

			elif key == 'X-AppInstall-Codecs':
				new = new and set(new.split(";")) or set()
				old = old and set(old.split(";")) or set()
				if new - old:
					codecs.add('Added the following codecs to %s:' % pkg, new - old)
				if old - new:
					codecs.add('Removed the following codecs from %s:' % pkg, old - new)

			else:
				if not old:
					icons.add('%s: Added %s with value %s' % (pkg, key, new))
				elif not new:
					icons.add('%s: Removed %s' % (pkg, key))
				else:
					icons.add('%s: Changed %s from %s to %s' % (pkg, key, old, new))
		#a.write()
		


my = dch(open(OLD + '/debian/changelog.verbose').read())
aaa = time.strftime('%Y.%m.%d')
my.new_block(package=my.get_package(), version=aaa, distributions="unstable", urgency="low", author=my.author, date=time.strftime("%a, %d %b %Y %H:%M:%S +0100"))
my.add_change('')

for i in (new_desktop, removed_desktop, new_icons, removed_icons, archis, pkgrenames, codecs, icons):
	a = i.write()
	if a.strip():
		my.add_change(a)
my.add_change('')

my.write_to_open_file(open('changelog.verbose', 'w'))


my = dch(open(OLD + '/debian/changelog').read())
aaa = time.strftime('%Y.%m.%d')
my.new_block(package=my.get_package(), version=aaa, distributions="unstable", urgency="low", author=my.author, date=time.strftime("%a, %d %b %Y %H:%M:%S +0100"))
my.add_change('')
my.add_change('  * New snapshot')
my.add_change('    - Desktop files: %d added; %d removed' % (len(new_desktop.msgs), len(removed_desktop.msgs)))
my.add_change('    - Icons: %d added; %d removed' % (len(new_icons.msgs), len(removed_icons.msgs)) )
my.add_change('')
my.write_to_open_file(open('changelog', 'w'))
