#!/usr/bin/python3

## live-build(7) - Live System Build Components
## Copyright (C) 2006-2014 Daniel Baumann <mail@daniel-baumann.ch>
##
## This program comes with ABSOLUTELY NO WARRANTY; for details see COPYING.
## This is free software, and you are welcome to redistribute it
## under certain conditions; see COPYING for details.


import argparse
import configparser
import glob
import os
import platform
import shutil
import subprocess
import sys
import urllib.request


# TODO:
#   * logfile output
#   * lockfile handling
#   * use gettext for i18n

def main():
	## early defaults detection
	architecture = platform.machine()

	if (architecture == 'x86_64'):
		architecture = 'amd64'

	## Parsing Arguments
	arguments = argparse.ArgumentParser(
		prog            = 'lb init',
		usage           = '%(prog)s [arguments]',
		description     = '''live-build contains the components to build a live system from a configuration directory.
		                     The init command creates an empty configuration directory or reinitialize an existing one.''',
		epilog          = 'See \'man lb-init\' for more information.',
		formatter_class = argparse.ArgumentDefaultsHelpFormatter
	)

	arguments.add_argument('--version',                       help='show program\'s version number and exit', action='version', version='live-build 4')
	arguments.add_argument('--verbose',                       help='set verbose option',                      action='store_true')

	arguments.add_argument('--project',                       help='set project defaults',                    default='debian')
	arguments.add_argument('--system',                        help='set system type',                         default='live')
	arguments.add_argument('--architecture',                  help='set system architecture',                 default=architecture)

	arguments.add_argument('--archive-areas',                 help='set default archive areas',               default='main')
	arguments.add_argument('--parent-archive-areas',          help='set default parent archive areas',        default='main')

	arguments.add_argument('--distribution',                  help='set default distribution',                default='jessie')
	arguments.add_argument('--parent-distribution',           help='set default parent distribution',         default='jessie')

	arguments.add_argument('--mirror-bootstrap',              help='set default bootstrap mirror',            default='http://ftp.debian.org/debian')
	arguments.add_argument('--parent-mirror-bootstrap',       help='set default parent bootstrap mirror',     default='http://ftp.debian.org/debian')

	arguments.add_argument('--mirror-chroot',                 help='set default chroot mirror',               default='http://ftp.debian.org/debian')
	arguments.add_argument('--parent-mirror-chroot',          help='set default parent chroot mirror',        default='http://ftp.debian.org/debian')

	arguments.add_argument('--mirror-chroot-security',        help='set default chroot mirror',               default='http://security.debian.org')
	arguments.add_argument('--parent-mirror-chroot-security', help='set default parent chroot mirror',        default='http://security.debian.org')

	arguments.add_argument('--mirror-installer',              help='set default installer mirror',            default='http://ftp.debian.org/debian')
	arguments.add_argument('--parent-mirror-installer',       help='set default parent installer mirror',     default='http://ftp.debian.org/debian')

	arguments.add_argument('--mirror-binary',                 help='set default binary mirror',               default='http://ftp.debian.org/debian')
	arguments.add_argument('--parent-mirror-binary',          help='set default parent binary mirror',        default='http://ftp.debian.org/debian')

	arguments.add_argument('--mirror-binary-security',        help='set default binary mirror',               default='http://security.debian.org')
	arguments.add_argument('--parent-mirror-binary-security', help='set default parent binary mirror',        default='http://security.debian.org')

	arguments.add_argument('--mirror-source',                 help='set default source mirror',               default='http://ftp.debian.org/debian')
	arguments.add_argument('--parent-mirror-source',          help='set default parent source mirror',        default='http://ftp.debian.org/debian')

	arguments.add_argument('--mirror-source-security',        help='set default source mirror',               default='http://security.debian.org')
	arguments.add_argument('--parent-mirror-source-security', help='set default parent source mirror',        default='http://security.debian.org')

	args = arguments.parse_args()

	# --verbose
	verbose = args.verbose

	# --project
	project = args.project

	# --system
	system = args.system

	# --architecture
	architecture = args.architecture

	# --archive-areas
	archive_areas = args.archive_areas

	# --parent-archive-areas
	parent_archive_areas = args.parent_archive_areas

	# --distribution
	distribution = args.distribution

	# --parent-distribution
	parent_distribution = args.parent_distribution

	# --mirror-bootstrap
	mirror_bootstrap = args.mirror_bootstrap

	# --parent-mirror-bootstrap
	parent_mirror_bootstrap = args.parent_mirror_bootstrap

	# --mirror-chroot
	mirror_chroot = args.mirror_chroot

	# --parent-mirror-chroot
	parent_mirror_chroot = args.parent_mirror_chroot

	# --mirror-chroot-security
	mirror_chroot_security = args.mirror_chroot_security

	# --parent-mirror-chroot-security
	parent_mirror_chroot_security = args.parent_mirror_chroot_security

	# --mirror-installer
	mirror_installer = args.mirror_installer

	# --parent-mirror-installer
	parent_mirror_installer = args.parent_mirror_installer

	# --mirror-binary
	mirror_binary = args.mirror_binary

	# --parent-mirror-binary
	parent_mirror_binary = args.parent_mirror_binary

	# --mirror-binary-security
	mirror_binary_security = args.mirror_binary_security

	# --parent-mirror-binary-security
	parent_mirror_binary_security = args.parent_mirror_binary_security

	# --mirror-source
	mirror_source = args.mirror_source

	# --parent-mirror-source
	parent_mirror_source = args.parent_mirror_source

	# --mirror-source-security
	mirror_source_security = args.mirror_source_security

	# --parent-mirror-source-security
	parent_mirror_source_security = args.parent_mirror_source_security

	## Setting defaults

	if not system:
		system = 'live'

	if not project:
		# FIXME: hardcoded project information
		project = 'debian'

	if not distribution:
		# FIXME hardcoded release information
		default_distribution = { 'debian' :         'jessie',
					 'progress-linux' : 'cairon',
		}

		distribution = default_distribution[project]

	## Setting derivative defaults
	if (project == 'progress-linux'):
		# parent-distribution
		if(distribution == 'artax'):
			parent_distribution = 'squeeze'
		if(distribution == 'artax-backports'):
			parent_distribution = 'squeeze'
		if(distribution == 'baureo'):
			parent_distribution = 'wheezy'
		if(distribution == 'baureo-backports'):
			parent_distribution = 'wheezy'
		if(distribution == 'cairon'):
			parent_distribution = 'jessie'
		if(distribution == 'cairon-backports'):
			parent_distribution = 'jessie'
	else:
		# parent-architecture
		parent_architecture = architecture

		# parent-distribution
		parent_distribution = distribution

		# parent-mirror-bootstrap
		parent_mirror_bootstrap = mirror_bootstrap

		# parent-mirror-chroot
		parent_mirror_chroot = mirror_chroot

		# parent-mirror-chroot-security
		parent_mirror_chroot_security = mirror_chroot_security

		# parent-mirror-installer
		parent_mirror_installer = mirror_installer

		# parent-mirror-binary
		parent_mirror_binary = mirror_binary

		# parent-mirror-binary-security
		parent_mirror_binary_security = mirror_binary_security

		# parent-mirror-source
		parent_mirror_source = mirror_source

		# parent-mirror-source-security
		parent_mirror_source_security = mirror_source_security

	## Creating configuration directory

	# stagefile
	if os.path.isdir('.build'):
		if verbose:
			print('I: configuration directory already initialized - nothing to do')

		# Notes:
		#   * until further tests, we do not allow to re-run lb init on an already initialized directory.
		sys.exit(0)

	# Print warning about live-build development version
	print('WARNING: THIS VERSION OF LIVE-BUILD IS EXPERIMENTAL\n')

	print('IT IS UNFINISHED AND CHANGES HEAVILY WITHOUT PRIOR NOTICE.')
	print('USER DISCRETION IS ADVISED.\n')

	print('Please also note that you are running a live-build development version')
	print('and that we are only supporting the newest development version.\n')

	print('Make sure you are using the newest version at all times.')

	## Writing main configuration file

	os.makedirs('config', exist_ok=True)

	config = configparser.ConfigParser()

	configfile = open("config/build.conf", 'w')

	config.add_section('build')

	config.set('build','architecture',                  architecture)

	config.set('build','archive-areas',                 archive_areas)
	config.set('build','parent-archive-areas',          parent_archive_areas)

	config.set('build','distribution',                  distribution)
	config.set('build','parent-distribution',           parent_distribution)

	config.set('build','mirror-bootstrap',              mirror_bootstrap)
	config.set('build','parent-mirror-bootstrap',       parent_mirror_bootstrap)

	config.set('build','mirror-chroot',                 mirror_chroot)
	config.set('build','parent-mirror-chroot',          parent_mirror_chroot)

	config.set('build','mirror-chroot-security',        mirror_chroot_security)
	config.set('build','parent-mirror-chroot-security', parent_mirror_chroot_security)

	config.set('build','mirror-installer',              mirror_installer)
	config.set('build','parent-mirror-installer',       parent_mirror_installer)

	config.set('build','mirror-binary',                 mirror_binary)
	config.set('build','parent-mirror-binary',          parent_mirror_binary)

	config.set('build','mirror-binary-security',        mirror_binary_security)
	config.set('build','parent-mirror-binary-security', parent_mirror_binary_security)

	config.set('build','mirror-source',                 mirror_source)
	config.set('build','parent-mirror-source',          parent_mirror_source)

	config.set('build','mirror-source-security',        mirror_source_security)
	config.set('build','parent-mirror-source-security', parent_mirror_source_security)

	config.set('build','project',                       project)
	config.set('build','system',                        system)

	config.add_section('meta')

	config.set('meta','version',                  '4.0')

	config.write(configfile)
	configfile.close()

	## Populating configuration directory

	# Configuring default archive-keys
	if (project == 'progress-linux'):
		# dependencies
		if not os.path.isfile('/usr/bin/gpgv'):
			print('E: /usr/bin/gpgv - no such file', file=sys.stderr)

			if verbose:
				print('I: gnupg can be obtained from:\n'
				      'I:   http://www.gnupg.org/\n'
				      'I: On Debian based systems, gnupg can be installed with:\n'
				      'I:   # sudo apt-get install gnupg')

			sys.exit(1)

		os.makedirs('config/archives', exist_ok=True)

		# FIXME hardcoded release information
		archive_keys_url = 'http://cdn.archive.progress-linux.org/packages/project/keys/'

		archive_keys = { 'artax' :            [ 'archive-key-1-artax.asc'  , 'archive-key-1+-artax-backports.asc'  ],
				 'artax-backports' :  [ 'archive-key-1-artax.asc'  , 'archive-key-1+-artax-backports.asc'  ],
				 'baureo' :           [ 'archive-key-2-baureo.asc' , 'archive-key-2+-baureo-backports.asc' ],
				 'baureo-backports' : [ 'archive-key-2-baureo.asc' , 'archive-key-2+-baureo-backports.asc' ],
				 'cairon' :           [ 'archive-key-3-cairon.asc' , 'archive-key-3+-cairon-backports.asc' ],
				 'cairon-backports' : [ 'archive-key-3-cairon.asc' , 'archive-key-3+-cairon-backports.asc' ],
		}

		keys = archive_keys[distribution]

		for key in keys:
			url = archive_keys_url + key
			target = os.path.splitext(os.path.basename(key))

			if verbose:
				print('I: Downloading ' + url)

			r = urllib.request.urlopen(url)
			f = open('config/archives/' + target[0] + '.key', 'w')

			f.write(r.read())

		# FIXME: download signatures and verify them against debian-keyring

	# Configuring default hooks
	os.makedirs('config/hooks', exist_ok=True)

	for hook in glob.glob('/usr/share/live/build/hooks/all/*.hook*'):
		os.symlink(hook, os.path.join('config/hooks/' + os.path.basename(hook)))

	if os.path.exists('/usr/share/live/build/hooks/' + system):
		for hook in glob.glob('/usr/share/live/build/hooks/' + system + '/*.hook*'):
			os.symlink(hook, os.path.join('config/hooks/' + os.path.basename(hook)))

	# Configuring default includes
	os.makedirs('config/includes', exist_ok=True)
	os.makedirs('config/includes.bootstrap', exist_ok=True)
	os.makedirs('config/includes.chroot', exist_ok=True)
	os.makedirs('config/includes.binary', exist_ok=True)
	os.makedirs('config/includes.source', exist_ok=True)

	# Ensure correct include directory permissions avoiding tainting of target system
	os.chmod('config/includes', 0o755)
	os.chmod('config/includes.bootstrap', 0o755)
	os.chmod('config/includes.chroot', 0o755)
	os.chmod('config/includes.binary', 0o755)
	os.chmod('config/includes.source', 0o755)

	# Configuring default package lists
	os.makedirs('config/package-lists', exist_ok=True)

	f = open('config/package-lists/live.list.chroot', 'w')

	f.write('live-boot\n'
		'live-config\n')

	if(parent_distribution == 'wheezy'):
		f.write('live-config-sysvinit\n')
	else:
		f.write('live-config-systemd\n')

	f.close()

	## stagefile
	os.makedirs('.build', exist_ok=True)


if __name__ == '__main__':
	main()