inherit package

IMAGE_PKGTYPE ?= "rpm"

RPM="rpm"
RPMBUILD="rpmbuild"

PKGWRITEDIRRPM = "${WORKDIR}/deploy-rpms"

python package_rpm_fn () {
	bb.data.setVar('PKGFN', bb.data.getVar('PKG',d), d)
}

python package_rpm_install () {
	bb.fatal("package_rpm_install not implemented!")
}

#
# Update the Packages depsolver db in ${DEPLOY_DIR_RPM}
#
package_update_index_rpm () {
	rpmarchs="${PACKAGE_ARCHS}"

	if [ ! -z "${DEPLOY_KEEP_PACKAGES}" ]; then
		return
	fi

	packagedirs=""
	for arch in $rpmarchs ; do
		sdkarch=`echo $arch | sed -e 's/${HOST_ARCH}/${SDK_ARCH}/'`
		packagedirs="$packagedirs ${DEPLOY_DIR_RPM}/$arch ${DEPLOY_DIR_RPM}/$sdkarch-nativesdk"
	done

	packagedirs="$packagedirs ${DEPLOY_DIR_RPM}/${SDK_ARCH}-${TARGET_ARCH}-canadian"

	cat /dev/null > ${DEPLOY_DIR_RPM}/solvedb.conf
	for pkgdir in $packagedirs; do
		if [ -e $pkgdir/ ]; then
			echo "Generating solve db for $pkgdir..."
			rm -rf $pkgdir/solvedb
			mkdir -p $pkgdir/solvedb
			echo "# Dynamically generated solve manifest" >> $pkgdir/solvedb/manifest
			find $pkgdir -maxdepth 1 -type f >> $pkgdir/solvedb/manifest
			${RPM} -i --replacepkgs --replacefiles --oldpackage \
				-D "_dbpath $pkgdir/solvedb" --justdb \
				--noaid --nodeps --noorder --noscripts --notriggers --noparentdirs --nolinktos --stats \
				--ignoresize --nosignature --nodigest \
				-D "_dbi_tags_3 Packages:Name:Basenames:Providename:Nvra" \
				-D "__dbi_cdb create mp_mmapsize=128Mb mp_size=1Mb nofsync" \
				$pkgdir/solvedb/manifest
			echo $pkgdir/solvedb >> ${DEPLOY_DIR_RPM}/solvedb.conf
		fi
	done
}

#
# Generate an rpm configuration suitable for use against the
# generated depsolver db's...
#
package_generate_rpm_conf () {
	printf "_solve_dbpath " > ${DEPLOY_DIR_RPM}/solvedb.macro
	colon=false
	for each in `cat ${DEPLOY_DIR_RPM}/solvedb.conf` ; do
		if [ "$colon" == true ]; then
			printf ":" >> ${DEPLOY_DIR_RPM}/solvedb.macro
		fi
		printf "%s" $each >> ${DEPLOY_DIR_RPM}/solvedb.macro
		colon=true
	done
	printf "\n" >> ${DEPLOY_DIR_RPM}/solvedb.macro
}

python write_specfile () {
	# We need to change '-' in a version field to '+'
	# This needs to be done BEFORE the mapping_rename_hook
	def translate_vers(varname, d):
		depends = bb.data.getVar(varname, d, True)
		if depends:
			depends_dict = bb.utils.explode_dep_versions(depends)
			newdeps_dict = {}
			for dep in depends_dict:
				ver = depends_dict[dep]
				if dep and ver:
					if '-' in ver:
						subd = read_subpkgdata_dict(dep, d)
						pv = subd['PV']
						reppv = pv.replace('-', '+')
						ver = ver.replace(pv, reppv)
				newdeps_dict[dep] = ver
			depends = bb.utils.join_deps(newdeps_dict)
			bb.data.setVar(varname, depends.strip(), d)

	# We need to change the style the dependency from BB to RPM
	# This needs to happen AFTER the mapping_rename_hook
	def print_deps(variable, tag, array, d):
		depends = variable
		if depends:
			depends_dict = bb.utils.explode_dep_versions(depends)
			for dep in depends_dict:
				ver = depends_dict[dep]
				if dep and ver:
					ver = ver.replace('(', '')
					ver = ver.replace(')', '')
					array.append("%s: %s %s" % (tag, dep, ver))
				else:
					array.append("%s: %s" % (tag, dep))

	def walk_files(walkpath, target, conffiles):
		import os
		for rootpath, dirs, files in os.walk(walkpath):
			path = rootpath.replace(walkpath, "")
			for dir in dirs:
				# All packages own the directories their files are in...
				target.append("%dir " + path + "/" + dir)
			for file in files:
				if conffiles.count(path + "/" + file):
					target.append("%config " + path + "/" + file)
				else:
					target.append(path + "/" + file)

	packages = bb.data.getVar('PACKAGES', d, True)
	if not packages or packages == '':
		bb.debug(1, "No packages; nothing to do")
		return

	pkgdest = bb.data.getVar('PKGDEST', d, True)
	if not pkgdest:
		bb.fatal("No PKGDEST")
		return

	outspecfile = bb.data.getVar('OUTSPECFILE', d, True)
	if not outspecfile:
		bb.fatal("No OUTSPECFILE")
		return

	# Construct the SPEC file...
	srcname    = bb.data.getVar('PN', d, True)
	srcsummary = (bb.data.getVar('SUMMARY', d, True) or ".")
	srcversion = bb.data.getVar('PV', d, True).replace('-', '+')
	srcrelease = bb.data.getVar('PR', d, True)
	srcepoch   = (bb.data.getVar('PE', d, True) or "")
	srclicense = bb.data.getVar('LICENSE', d, True)
	srcsection = bb.data.getVar('SECTION', d, True)
	srcmaintainer  = bb.data.getVar('MAINTAINER', d, True)
	srchomepage    = bb.data.getVar('HOMEPAGE', d, True)
	srcdescription = bb.data.getVar('DESCRIPTION', d, True)

	srcdepends     = bb.data.getVar('DEPENDS', d, True)
	srcrdepends    = []
	srcrrecommends = []
	srcrsuggests   = []
	srcrprovides   = []
	srcrreplaces   = []
	srcrconflicts  = []
	srcrobsoletes  = []

	srcpreinst  = []
	srcpostinst = []
	srcprerm    = []
	srcpostrm   = []

	spec_preamble_top = []
	spec_preamble_bottom = []

	spec_scriptlets_top = []
	spec_scriptlets_bottom = []

	spec_files_top = []
	spec_files_bottom = []

	for pkg in packages.split():
		localdata = bb.data.createCopy(d)

		root = "%s/%s" % (pkgdest, pkg)

		lf = bb.utils.lockfile(root + ".lock")

		bb.data.setVar('ROOT', '', localdata)
		bb.data.setVar('ROOT_%s' % pkg, root, localdata)
		pkgname = bb.data.getVar('PKG_%s' % pkg, localdata, 1)
		if not pkgname:
			pkgname = pkg
		bb.data.setVar('PKG', pkgname, localdata)

		bb.data.setVar('OVERRIDES', pkg, localdata)

		bb.data.update_data(localdata)

		conffiles = (bb.data.getVar('CONFFILES', localdata, True) or "").split()

		splitname    = pkgname

		splitsummary = (bb.data.getVar('SUMMARY', d, True) or ".")
		splitversion = (bb.data.getVar('PV', localdata, True) or "").replace('-', '+')
		splitrelease = (bb.data.getVar('PR', localdata, True) or "")
		splitepoch   = (bb.data.getVar('PE', localdata, True) or "")
		splitlicense = (bb.data.getVar('LICENSE', localdata, True) or "")
		splitsection = (bb.data.getVar('SECTION', localdata, True) or "")
		splitdescription = (bb.data.getVar('DESCRIPTION', localdata, True) or "")

		translate_vers('RDEPENDS', localdata)
		translate_vers('RRECOMMENDS', localdata)
		translate_vers('RSUGGESTS', localdata)
		translate_vers('RPROVIDES', localdata)
		translate_vers('RREPLACES', localdata)
		translate_vers('RCONFLICTS', localdata)

		# Map the dependencies into their final form
		bb.build.exec_func("mapping_rename_hook", localdata)

		splitrdepends    = bb.data.getVar('RDEPENDS', localdata, True) or ""
		splitrrecommends = bb.data.getVar('RRECOMMENDS', localdata, True) or ""
		splitrsuggests   = bb.data.getVar('RSUGGESTS', localdata, True) or ""
		splitrprovides   = bb.data.getVar('RPROVIDES', localdata, True) or ""
		splitrreplaces   = bb.data.getVar('RREPLACES', localdata, True) or ""
		splitrconflicts  = bb.data.getVar('RCONFLICTS', localdata, True) or ""
		splitrobsoletes  = []

		# Gather special src/first package data
		if srcname == splitname:
			srcrdepends    = splitrdepends
			srcrrecommends = splitrrecommends
			srcrsuggests   = splitrsuggests
			srcrprovides   = splitrprovides
			srcrreplaces   = splitrreplaces
			srcrconflicts  = splitrconflicts

			srcpreinst  = bb.data.getVar('pkg_preinst', localdata, True)
			srcpostinst = bb.data.getVar('pkg_postinst', localdata, True)
			srcprerm    = bb.data.getVar('pkg_prerm', localdata, True)
			srcpostrm   = bb.data.getVar('pkg_postrm', localdata, True)

			file_list = []
			walk_files(root, file_list, conffiles)
			if not file_list and bb.data.getVar('ALLOW_EMPTY', localdata) != "1":
				bb.note("Not creating empty RPM package for %s" % splitname)
			else:
				bb.note("Creating RPM package for %s" % splitname)
				spec_files_top.append('%files')
				if file_list:
					spec_files_top.extend(file_list)
				spec_files_top.append('')

			bb.utils.unlockfile(lf)
			continue

		# Process subpackage data
		spec_preamble_bottom.append('%%package -n %s' % splitname)
		spec_preamble_bottom.append('Summary: %s' % splitsummary)
		if srcversion != splitversion:
			spec_preamble_bottom.append('Version: %s' % splitversion)
		if srcrelease != splitrelease:
			spec_preamble_bottom.append('Release: %s' % splitrelease)
		if srcepoch != splitepoch:
			spec_preamble_bottom.append('Epoch: %s' % splitepoch)
		if srclicense != splitlicense:
			spec_preamble_bottom.append('License: %s' % splitlicense)
		spec_preamble_bottom.append('Group: %s' % splitsection)

		# Replaces == Obsoletes && Provides
		if splitrreplaces and splitrreplaces.strip() != "":
			for dep in splitrreplaces.split(','):
				if splitrprovides:
					splitrprovides = splitrprovides + ", " + dep
				else:
					splitrprovides = dep
				if splitrobsoletes:
					splitrobsoletes = splitrobsoletes + ", " + dep
				else:
					splitrobsoletes = dep

		print_deps(splitrdepends,	"Requires", spec_preamble_bottom, d)
		# Suggests in RPM are like recommends in Poky!
		print_deps(splitrrecommends,	"Suggests", spec_preamble_bottom, d)
		# While there is no analog for suggests... (So call them recommends for now)
		print_deps(splitrsuggests, 	"Recommends", spec_preamble_bottom, d)
		print_deps(splitrprovides, 	"Provides", spec_preamble_bottom, d)
		print_deps(splitrobsoletes, 	"Obsoletes", spec_preamble_bottom, d)

		# conflicts can not be in a provide!  We will need to filter it.
		if splitrconflicts:
			depends_dict = bb.utils.explode_dep_versions(splitrconflicts)
			newdeps_dict = {}
			for dep in depends_dict:
				if dep not in splitrprovides:
					newdeps_dict[dep] = depends_dict[dep]
			if newdeps_dict:
				splitrconflicts = bb.utils.join_deps(newdeps_dict)
			else:
				splitrconflicts = ""

		print_deps(splitrconflicts, 	"Conflicts", spec_preamble_bottom, d)

		spec_preamble_bottom.append('')

		spec_preamble_bottom.append('%%description -n %s' % splitname)
		spec_preamble_bottom.append('%s' % splitdescription)

		spec_preamble_bottom.append('')

		# Now process scriptlets
		for script in ["preinst", "postinst", "prerm", "postrm"]:
			scriptvar = bb.data.getVar('pkg_%s' % script, localdata, True)
			if not scriptvar:
				continue
			if script == 'preinst':
				spec_scriptlets_bottom.append('%%pre -n %s' % splitname)
			elif script == 'postinst':
				spec_scriptlets_bottom.append('%%post -n %s' % splitname)
			elif script == 'prerm':
				spec_scriptlets_bottom.append('%%preun -n %s' % splitname)
			elif script == 'postrm':
				spec_scriptlets_bottom.append('%%postun -n %s' % splitname)
			spec_scriptlets_bottom.append(scriptvar)
			spec_scriptlets_bottom.append('')

		# Now process files
		file_list = []
		walk_files(root, file_list, conffiles)
		if not file_list and bb.data.getVar('ALLOW_EMPTY', localdata) != "1":
			bb.note("Not creating empty RPM package for %s" % splitname)
		else:
			bb.note("Creating RPM package for %s" % splitname)
			spec_files_bottom.append('%%files -n %s' % splitname)
			if file_list:
				spec_files_bottom.extend(file_list)
			spec_files_bottom.append('')

		del localdata
		bb.utils.unlockfile(lf)

	spec_preamble_top.append('Summary: %s' % srcsummary)
	spec_preamble_top.append('Name: %s' % srcname)
	spec_preamble_top.append('Version: %s' % srcversion)
	spec_preamble_top.append('Release: %s' % srcrelease)
	if srcepoch and srcepoch.strip() != "":
		spec_preamble_top.append('Epoch: %s' % srcepoch)
	spec_preamble_top.append('License: %s' % srclicense)
	spec_preamble_top.append('Group: %s' % srcsection)
	spec_preamble_top.append('Packager: %s' % srcmaintainer)
	spec_preamble_top.append('URL: %s' % srchomepage)

	# Replaces == Obsoletes && Provides
	if srcrreplaces and srcrreplaces.strip() != "":
		for dep in srcrreplaces.split(','):
			if srcrprovides:
				srcrprovides = srcrprovides + ", " + dep
			else:
				srcrprovides = dep
			if srcrobsoletes:
				srcrobsoletes = srcrobsoletes + ", " + dep
			else:
				srcrobsoletes = dep

	print_deps(srcdepends,		"BuildRequires", spec_preamble_top, d)
	print_deps(srcrdepends,		"Requires", spec_preamble_top, d)
	# Suggests in RPM are like recommends in Poky!
	print_deps(srcrrecommends,	"Suggests", spec_preamble_top, d)
	# While there is no analog for suggests... (So call them recommends for now)
	print_deps(srcrsuggests, 	"Recommends", spec_preamble_top, d)
	print_deps(srcrprovides, 	"Provides", spec_preamble_top, d)
	print_deps(srcrobsoletes, 	"Obsoletes", spec_preamble_top, d)

	# conflicts can not be in a provide!  We will need to filter it.
	if srcrconflicts:
		depends_dict = bb.utils.explode_dep_versions(srcrconflicts)
		newdeps_dict = {}
		for dep in depends_dict:
			if dep not in srcrprovides:
				newdeps_dict[dep] = depends_dict[dep]
		if newdeps_dict:
			srcrconflicts = bb.utils.join_deps(newdeps_dict)
		else:
			srcrconflicts = ""

	print_deps(srcrconflicts, 	"Conflicts", spec_preamble_top, d)

	spec_preamble_top.append('')

	spec_preamble_top.append('%description')
	spec_preamble_top.append('%s' % srcdescription)

	spec_preamble_top.append('')

	if srcpreinst:
		spec_scriptlets_top.append('%pre')
		spec_scriptlets_top.append(srcpreinst)
		spec_scriptlets_top.append('')
	if srcpostinst:
		spec_scriptlets_top.append('%post')
		spec_scriptlets_top.append(srcpostinst)
		spec_scriptlets_top.append('')
	if srcprerm:
		spec_scriptlets_top.append('%preun')
		spec_scriptlets_top.append(srcprerm)
		spec_scriptlets_top.append('')
	if srcpostrm:
		spec_scriptlets_top.append('%postun')
		spec_scriptlets_top.append(srcpostrm)
		spec_scriptlets_top.append('')

	# Write the SPEC file
	try:
		from __builtin__ import file
		specfile = file(outspecfile, 'w')
	except OSError:
		raise bb.build.FuncFailed("unable to open spec file for writing.")

	for line in spec_preamble_top:
		specfile.write(line + "\n")

	for line in spec_preamble_bottom:
		specfile.write(line + "\n")

	for line in spec_scriptlets_top:
		specfile.write(line + "\n")

	for line in spec_scriptlets_bottom:
		specfile.write(line + "\n")

	for line in spec_files_top:
		specfile.write(line + "\n")

	for line in spec_files_bottom:
		specfile.write(line + "\n")

	specfile.close()
}

python do_package_rpm () {
	import os

	workdir = bb.data.getVar('WORKDIR', d, True)
	outdir = bb.data.getVar('DEPLOY_DIR_IPK', d, True)
	dvar = bb.data.getVar('D', d, True)
	tmpdir = bb.data.getVar('TMPDIR', d, True)
	pkgd = bb.data.getVar('PKGD', d, True)
	pkgdest = bb.data.getVar('PKGDEST', d, True)
	if not workdir or not outdir or not dvar or not tmpdir:
		bb.error("Variables incorrectly set, unable to package")
		return

	if not os.path.exists(dvar):
		bb.debug(1, "Nothing installed, nothing to do")
		return

	packages = bb.data.getVar('PACKAGES', d, True)
	if not packages or packages == '':
		bb.debug(1, "No packages; nothing to do")
		return

	# Construct the spec file...
	srcname    = bb.data.getVar('PN', d, True)
	outspecfile = workdir + "/" + srcname + ".spec"
	bb.data.setVar('OUTSPECFILE', outspecfile, d)
	bb.build.exec_func('write_specfile', d)

	# Construct per file dependencies file
	def dump_filerdeps(varname, outfile, d):
		outfile.write("#!/bin/sh\n")
		outfile.write("\n# Dependency table\n")
		for pkg in packages.split():
			dependsflist_key = 'FILE' + varname + 'FLIST' + "_" + pkg
			dependsflist = (bb.data.getVar(dependsflist_key, d, True) or "")
			for dfile in dependsflist.split():
				key = "FILE" + varname + "_" + dfile + "_" + pkg
				depends_dict = bb.utils.explode_dep_versions(bb.data.getVar(key, d, True) or "")
				file = dfile.replace("@underscore@", "_")
				file = file.replace("@closebrace@", "]")
				file = file.replace("@openbrace@", "[")
				file = file.replace("@tab@", "\t")
				file = file.replace("@space@", " ")
				file = file.replace("@at@", "@")
				outfile.write("#" + pkgd + file + "\t")
				for dep in depends_dict:
					ver = depends_dict[dep]
					if dep and ver:
						ver = ver.replace("(","")
						ver = ver.replace(")","")
						outfile.write(dep + " " + ver + " ")
					else:
						outfile.write(dep + " ")
				outfile.write("\n")
		outfile.write("\n\nwhile read file_name ; do\n")
		outfile.write("\tlength=$(echo \"#${file_name}\t\" | wc -c )\n")
		outfile.write("\tline=$(grep \"^#${file_name}\t\" $0 | cut -c ${length}- )\n")
		outfile.write("\tprintf \"%s\\n\" ${line}\n")
		outfile.write("done\n")

	# Poky dependencies a.k.a. RPM requires
	outdepends = workdir + "/" + srcname + ".requires"

	try:
		from __builtin__ import file
		dependsfile = file(outdepends, 'w')
	except OSError:
		raise bb.build.FuncFailed("unable to open spec file for writing.")

	dump_filerdeps('RDEPENDS', dependsfile, d)

	dependsfile.close()
	os.chmod(outdepends, 0755)

	# Poky / RPM Provides
	outprovides = workdir + "/" + srcname + ".requires"

	try:
		from __builtin__ import file
		providesfile = file(outprovides, 'w')
	except OSError:
		raise bb.build.FuncFailed("unable to open spec file for writing.")

	dump_filerdeps('RPROVIDES', providesfile, d)

	providesfile.close()
	os.chmod(outprovides, 0755)

	# Setup the rpmbuild arguments...
	rpmbuild = bb.data.getVar('RPMBUILD', d, True)
	targetsys = bb.data.getVar('TARGET_SYS', d, True)
	pkgwritedir = bb.data.expand('${PKGWRITEDIRRPM}/${PACKAGE_ARCH}', d)
	pkgarch = bb.data.expand('${PACKAGE_ARCH}', d)
	bb.mkdirhier(pkgwritedir)
	os.chmod(pkgwritedir, 0755)

	cmd = rpmbuild
	cmd = cmd + " --nodeps --short-circuit --target " + pkgarch + " --buildroot " + pkgd
	cmd = cmd + " --define '_topdir " + workdir + "' --define '_rpmdir " + pkgwritedir + "'"
	cmd = cmd + " --define '_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm'"
	cmd = cmd + " --define '_use_internal_dependency_generator 0'"
	cmd = cmd + " --define '__find_requires " + outdepends + "'"
	cmd = cmd + " --define '__find_provides " + outprovides + "'"
	cmd = cmd + " -bb " + outspecfile

	# Build the spec file!
	bb.data.setVar('BUILDSPEC', cmd + "\n", d)
	bb.data.setVarFlag('BUILDSPEC', 'func', '1', d)
	bb.build.exec_func('BUILDSPEC', d)
}

python () {
    if bb.data.getVar('PACKAGES', d, True) != '':
        deps = (bb.data.getVarFlag('do_package_write_rpm', 'depends', d) or "").split()
        deps.append('rpm-native:do_populate_sysroot')
        deps.append('virtual/fakeroot-native:do_populate_sysroot')
        bb.data.setVarFlag('do_package_write_rpm', 'depends', " ".join(deps), d)
        bb.data.setVarFlag('do_package_write_rpm', 'fakeroot', 1, d)
}

SSTATETASKS += "do_package_write_rpm"
do_package_write_rpm[sstate-name] = "deploy-rpm"
do_package_write_rpm[sstate-inputdirs] = "${PKGWRITEDIRRPM}"
do_package_write_rpm[sstate-outputdirs] = "${DEPLOY_DIR_RPM}"

python do_package_write_rpm_setscene () {
	sstate_setscene(d)
}
#addtask do_package_write_rpm_setscene

python do_package_write_rpm () {
	bb.build.exec_func("read_subpackage_metadata", d)
	bb.build.exec_func("do_package_rpm", d)
}

do_package_write_rpm[dirs] = "${PKGWRITEDIRRPM}"
addtask package_write_rpm before do_package_write after do_package

