From: HyungKyu Song Date: Thu, 14 Feb 2013 13:16:44 +0000 (+0900) Subject: Tizen 2.0 Release X-Git-Tag: 2.0_release^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e8bc5ba7e4a15d3ac1fa429df434f09021174db9;p=tools%2Fkickstarter.git Tizen 2.0 Release --- diff --git a/Makefile b/Makefile index 404738b..a4da77f 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,14 @@ -# ex: set tabstop=4 noexpandtab: +VERSION = $(shell cat VERSION) +NAME=kickstarter +TAGVER = $(shell cat VERSION | sed -e "s/\([0-9\.]*\).*/\1/") + +ifeq ($(VERSION), $(TAGVER)) + TAG = $(TAGVER) +else + TAG = "HEAD" +endif + + PYTHON=python CHEETAH=cheetah TEMPLATES=$(wildcard *.tmpl) @@ -6,16 +16,38 @@ TEMPLATE_MODS=$(patsubst %.tmpl,%.py,$(TEMPLATES)) .SECONDARY: $(TEMPLATE_MODS) KS=$(wildcard *.ks) -all: $(TEMPLATE_MODS) +all: tmpls + python setup.py build + +tmpls: + cd kickstart; make + +install: tmpls + python setup.py build + python setup.py install %.py: %.tmpl $(CHEETAH) compile --settings='useStackFrames=False' $< +ks: $(TEMPLATES) configurations.yaml repos.yaml + kickstarter -c configurations.yaml -r repos.yaml + +tag: + git tag $(VERSION) + +dist-bz2: + git archive --format=tar --prefix=$(NAME)-$(TAGVER)/ $(TAG) | \ + bzip2 > $(NAME)-$(TAGVER).tar.bz2 + +dist-gz: + git archive --format=tar --prefix=$(NAME)-$(TAGVER)/ $(TAG) | \ + gzip > $(NAME)-$(TAGVER).tar.gz -ks: $(TEMPLATES) ../images.yaml - python kickstarter.py -m ../images.yaml +dist: dist-bz2 clean: rm -f $(TEMPLATE_MODS) rm -f $(addsuffix .bak,$(TEMPLATE_MODS)) rm -f *.pyc *.pyo + rm -rf dist/ build/ kickstart/kickstart.py kickstart/__init__.py *~ */*~ + rm -rf *.egg-info/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..ac2f925 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +kickstarter +=========== + +Kickstart file generator based on YAML formated meta data + +Installation +------------ + +Install cheetah (http://www.cheetahtemplate.org/) templating system, PyYAML. + +run make +sudo python setup.py install + +Usage +----- + +kickstarter -c -r + +Example: + + kickstarter --configs configurations.yaml --repos repos.yaml + +This configuration.yaml file is an example only, for meego kickstart files, +consult the image-configurations package + +Repo file +--------- + +This file contains a list of repositories to be used in the kickstart files + +Configurations file +------------------- + +This file has the definition of configurations. The Configurations inherit +from platforms first then from the DEFAULT section. The image configurations +override the all other settings (in DEFAULT and platform sections). diff --git a/TODO b/TODO index 031d3ee..124d39f 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,6 @@ - List of things to do: - - - Add support for build IDs - - Multi arch repos - - .. + - Support kickstart magic + Add addition options per image to describe how it should be created, i.e. image type and other options + The generated kickstart files should then have the line on top that can be evaluated by mic + - Make it act as a module, so it can be imported into other scripts and generate kickstart file + - diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..50c33df --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.15git diff --git a/demo/configurations.yaml b/demo/configurations.yaml new file mode 100644 index 0000000..b7d91ed --- /dev/null +++ b/demo/configurations.yaml @@ -0,0 +1,235 @@ +ExternalConfigs: + - netbook + +Default: + Active: True + Baseline: tizen-0.99 + Language: en_US.UTF-8 + Keyboard: us + PackageArgs: + SaveRepos: True + Timezone: America/Los_Angeles + RootPass: meego + DefaultUser: meego + DefaultUserPass: meego + PartSize: 1900 + FileSystem: ext3 + PostScripts: + - rpm + Groups: + - MeeGo Core + - MeeGo Compliance + +CORE: + PartSize: 1000 + BootloaderAppend: "quiet" + BootloaderTimeout: 0 + PostScripts: + - cleanup + Groups: + - MeeGo X Window System + NoChrootScripts: + - buildname +N900: + Part: n900 + BootloaderTimeout: + BootloaderAppend: + StartX: True + Groups: + - MeeGo Core + - Minimal MeeGo X Window System + - X for Handsets + - MeeGo Compliance + - MeeGo Handset Desktop + - MeeGo Handset Applications + - MeeGo Base Development + Kernel: kernel-adaptation-n900 + PostScripts: + - cleanup + NoChrootScripts: + - buildname + Architecture: armv7l + Repos: + - core + - handset + - non-oss +MFLD: + PartSize: 1700 + BootloaderAppend: "ro pci=noearly console=tty1 console=ttyS0 console=ttyMFD2 earlyprintk=mrst loglevel=8 s0ix_latency=160" + BootloaderTimeout: 2 + Bootloader: True + StartX: True + Groups: + - MeeGo Core + - Minimal MeeGo X Window System + - X for Handsets + - MeeGo Compliance + - MeeGo Handset Desktop + - MeeGo Handset Applications + - MeeGo Base Development + Kernel: kernel + PostScripts: + - prelink + - cleanup + NoChrootScripts: + - buildname + Architecture: ia32 + Repos: + - core + - handset + - non-oss +IVI: + PartSize: 2200 + Bootloader: True + BootloaderAppend: "quiet" + BootloaderTimeout: 0 + BootloaderOptions: --test + Session: "/usr/bin/startivi" + StartX: True + Groups: + - X for IVI + Kernel: kernel-adaptation-intel-automotive + PostScripts: + - prelink + - cleanup + NoChrootScripts: + - buildname + Architecture: ia32 +NETBOOK: + PartSize: 3000 + Bootloader: True + BootloaderAppend: "quiet" + BootloaderTimeout: 0 + StartX: True + Groups: + - X for Netbooks + - Virtual Machine Support + - Printing + - Games + - MeeGo Netbook Desktop + Kernel: kernel + PostScripts: + - prelink + - cleanup + NoChrootScripts: + - buildname + Architecture: ia32 + +Configurations: + - Name: MeeGo IVI Development + Active: True + Platform: IVI + Desktop: X-IVI + FileName: ivi-ia32 + Mic2Options: -f livecd + Groups: + - MeeGo IVI Desktop + - MeeGo Base Development + - MeeGo IVI Applications + - Development Tools + Repos: + - core + - ivi + ExtraPackages: + - mesa-libEGL + - Name: MeeGo IVI + Active: True + Platform: IVI + Desktop: X-IVI + FileName: ivi-ia32 + Mic2Options: -f livecd + Groups: + - MeeGo IVI Desktop + - MeeGo Base Development + - MeeGo IVI Applications + Repos: + - core + - ivi + ExtraPackages: + - mesa-libEGL + - Name: MeeGo Handset N900 Development + Part: n900-devel + Active: True + Platform: N900 + FileName: handset-armv7l-n900-devel + Mic2Options: -f raw --save-kernel --arch=armv7l + Architecture: armv7l + Desktop: DUI + Session: "/usr/bin/mcompositor" + Groups: + - Nokia N900 Support + - Nokia N900 Proprietary Support + - Development Tools + ExtraPackages: + - xorg-x11-utils-xev + - u-boot-tools + PostScripts: + - inittab-n900 + - fstab-n900 + - u-boot + - Name: MeeGo Handset N900 + Active: True + Platform: N900 + FileName: handset-armv7l-n900 + Mic2Options: -f raw --save-kernel --arch=armv7l + Architecture: armv7l + Desktop: DUI + Session: "/usr/bin/mcompositor" + Groups: + - Nokia N900 Support + - Nokia N900 Proprietary Support + ExtraPackages: + - xorg-x11-utils-xev + - u-boot-tools + PostScripts: + - inittab-n900 + - fstab-n900 + - u-boot + + - Name: MeeGo Handset MTF Development + PartSize: 2200 + Active: True + Platform: MFLD + FileName: handset-ia32-mtf-devel + Mic2Options: -f nand + Kernel: kernel-adaptation-medfield + Architecture: ia32 + Desktop: DUI + Session: "/usr/bin/mcompositor" + Groups: + - Moorestown Support + - Development Tools + PostScripts: + - kernel-handset + - kboot + - serial-mfld + - Name: MeeGo Handset MTF Pinetrail + Active: True + Platform: MFLD + FileName: handset-ia32-pinetrail-mtf + Mic2Options: -f livecd + Kernel: kernel + Architecture: ia32 + Desktop: DUI + Session: "/usr/bin/mcompositor" + - Name: MeeGo Handset MTF + Schedule: "* * * * 3" + Active: True + Platform: MFLD + FileName: handset-ia32-mtf + Mic2Options: -f nand + Kernel: kernel-adaptation-medfield + Architecture: ia32 + Desktop: DUI + Session: "/usr/bin/mcompositor" + Groups: + - Moorestown Support + PostScripts: + - kernel-handset + - kboot + - serial-mfld + PrePackages: + - Answer2theUltimateQuestionOfEverything + Attachment: + - ifwi + - /boot/vmlinuz-* diff --git a/demo/custom/part/custom b/demo/custom/part/custom new file mode 100644 index 0000000..d6c8b6b --- /dev/null +++ b/demo/custom/part/custom @@ -0,0 +1,2 @@ +part / --size 1300 --ondisk sda --grow --maxsize=1450 --fstype=ext3 +#part /home --size 1000 --grow --maxsize=1450 --ondisk sdb --fstype=ext3 diff --git a/demo/custom/part/n900 b/demo/custom/part/n900 new file mode 100644 index 0000000..bd7ac77 --- /dev/null +++ b/demo/custom/part/n900 @@ -0,0 +1,8 @@ +part / --size=1800 --ondisk mmcblk0p --fstype=btrfs + +# This is not used currently. It is here because the /boot partition +# needs to be the partition number 3 for the u-boot usage. +part swap --size=192 --ondisk mmcblk0p --fstype=swap + +# This partition is made so that u-boot can find the kernel +part /boot --size=64 --ondisk mmcblk0p --fstype=vfat diff --git a/demo/custom/part/n900-devel b/demo/custom/part/n900-devel new file mode 100644 index 0000000..e239fa8 --- /dev/null +++ b/demo/custom/part/n900-devel @@ -0,0 +1,8 @@ +part / --size=3400 --ondisk mmcblk0p --fstype=btrfs + +# This is not used currently. It is here because the /boot partition +# needs to be the partition number 3 for the u-boot usage. +part swap --size=256 --ondisk mmcblk0p --fstype=swap + +# This partition is made so that u-boot can find the kernel +part /boot --size=64 --ondisk mmcblk0p --fstype=vfat diff --git a/demo/custom/scripts/buildname.nochroot b/demo/custom/scripts/buildname.nochroot new file mode 100644 index 0000000..edd20a7 --- /dev/null +++ b/demo/custom/scripts/buildname.nochroot @@ -0,0 +1,3 @@ +if [ -n "$IMG_NAME" ]; then + echo "BUILD: $IMG_NAME" >> $INSTALL_ROOT/etc/meego-release +fi diff --git a/demo/custom/scripts/cleanup.post b/demo/custom/scripts/cleanup.post new file mode 100644 index 0000000..c36c2e4 --- /dev/null +++ b/demo/custom/scripts/cleanup.post @@ -0,0 +1,6 @@ + +# save a little bit of space at least... +rm -f /boot/initrd* + +# make sure there aren't core files lying around +rm -f /core* diff --git a/demo/custom/scripts/flash.post b/demo/custom/scripts/flash.post new file mode 100644 index 0000000..fe062d3 --- /dev/null +++ b/demo/custom/scripts/flash.post @@ -0,0 +1,5 @@ +# verify link of flash plugin +if [ -f /usr/lib/flash-plugin/setup ]; then + sh /usr/lib/flash-plugin/setup install + rm -f /root/oldflashplugins.tar.gz +fi diff --git a/demo/custom/scripts/fstab-n900.post b/demo/custom/scripts/fstab-n900.post new file mode 100644 index 0000000..03b6fc1 --- /dev/null +++ b/demo/custom/scripts/fstab-n900.post @@ -0,0 +1,5 @@ + +# Use eMMC swap partition as MeeGo swap as well. +# Because of the 2nd partition is swap for the partition numbering +# we can just change the current fstab entry to match the eMMC partition. +sed -i 's/mmcblk0p2/mmcblk1p3/g' /etc/fstab diff --git a/demo/custom/scripts/inittab-n900.post b/demo/custom/scripts/inittab-n900.post new file mode 100644 index 0000000..4650a2f --- /dev/null +++ b/demo/custom/scripts/inittab-n900.post @@ -0,0 +1,3 @@ + +# open serial line console for embedded system +echo "s0:235:respawn:/sbin/agetty -L 115200 ttyS2 vt100" >> /etc/inittab diff --git a/demo/custom/scripts/kboot.post b/demo/custom/scripts/kboot.post new file mode 100644 index 0000000..d5d5183 --- /dev/null +++ b/demo/custom/scripts/kboot.post @@ -0,0 +1,3 @@ +#Create Initrd if it does not exist and create symlinks for bzImage and initrd for kboot autoboot +echo "ro pci=noearly console=tty1 console=ttyS0 console=ttyMFD2 earlyprintk=mrst loglevel=8 s0ix_latency=160" > /boot/kboot.cmdline + diff --git a/demo/custom/scripts/kernel-handset.post b/demo/custom/scripts/kernel-handset.post new file mode 100644 index 0000000..cb07f6c --- /dev/null +++ b/demo/custom/scripts/kernel-handset.post @@ -0,0 +1,17 @@ +echo "Checking for kernel......." +Kernel_Name=`ls /boot | grep vmlinuz` +if [ -f /boot/$Kernel_Name ]; then + Kernel_Ver=`echo $Kernel_Name | sed s/vmlinuz-//` + if [ -f /boot/initrd* ]; then + echo "Initrd exists" > /dev/null + else + /usr/libexec/mkmrstinitrd /boot/initrd-$Kernel_Ver.img $Kernel_Ver + fi + #Create Symlinks + cd /boot + ln -s $Kernel_Name bzImage + ln -s initrd-$Kernel_Ver.img initrd + ln -s kboot.cmdline cmdline +else + echo "No Kernels were found" +fi diff --git a/demo/custom/scripts/prelink.post b/demo/custom/scripts/prelink.post new file mode 100644 index 0000000..527548c --- /dev/null +++ b/demo/custom/scripts/prelink.post @@ -0,0 +1,4 @@ +# Prelink can reduce boot time +if [ -x /usr/sbin/prelink ]; then + /usr/sbin/prelink -aRqm +fi diff --git a/demo/custom/scripts/rpm.post b/demo/custom/scripts/rpm.post new file mode 100644 index 0000000..6a07394 --- /dev/null +++ b/demo/custom/scripts/rpm.post @@ -0,0 +1,7 @@ +# work around for poor key import UI in PackageKit +rm -f /var/lib/rpm/__db* +rpm --rebuilddb + +if [ -f /etc/pki/rpm-gpg/RPM-GPG-KEY-meego ]; then + rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-meego +fi diff --git a/demo/custom/scripts/serial-mfld.post b/demo/custom/scripts/serial-mfld.post new file mode 100644 index 0000000..c3c62b0 --- /dev/null +++ b/demo/custom/scripts/serial-mfld.post @@ -0,0 +1,4 @@ +# open serial line console for embedded system +echo "s0:235:respawn:/sbin/agetty -L 115200 ttyS0 vt100" >> /etc/inittab +echo "s1:235:respawn:/sbin/agetty -L 115200 ttyMFD2 vt100" >> /etc/inittab +echo "ttyMFD2" >> /etc/securetty diff --git a/demo/custom/scripts/serial.post b/demo/custom/scripts/serial.post new file mode 100644 index 0000000..5961379 --- /dev/null +++ b/demo/custom/scripts/serial.post @@ -0,0 +1,2 @@ +# open serial line console for embedded system +echo "s0:235:respawn:/sbin/agetty -L 115200 ttyS0 vt100" >> /etc/inittab diff --git a/demo/custom/scripts/u-boot.post b/demo/custom/scripts/u-boot.post new file mode 100644 index 0000000..6377edc --- /dev/null +++ b/demo/custom/scripts/u-boot.post @@ -0,0 +1,4 @@ + + +# Create the /boot/uImage for u-boot support. +mkimage -A arm -O linux -T kernel -C none -a 80008000 -e 80008000 -n vmlinuz -d /boot/vmlinuz* /boot/uImage diff --git a/demo/netbook/meego-netbook.yaml b/demo/netbook/meego-netbook.yaml new file mode 100644 index 0000000..2c1e16a --- /dev/null +++ b/demo/netbook/meego-netbook.yaml @@ -0,0 +1,17 @@ +Name: MeeGo Netbook/Nettop +PartSize: 2580 +Active: True +Baseline: "1.1.80" +Platform: NETBOOK +Desktop: meego +FileName: netbook-ia32 +Mic2Options: -f livecd +Groups: + - MeeGo Netbook Desktop + - Base Double Byte IME Support + - MeeGo Base Development +Repos: + - core + - netbook +ExtraPackages: + - chromium diff --git a/demo/repos.yaml b/demo/repos.yaml new file mode 100644 index 0000000..38928c9 --- /dev/null +++ b/demo/repos.yaml @@ -0,0 +1,17 @@ +Repositories: + - Name: core-testing + Url: http://download.meego.com/testing/core/repos/@ARCH@/packages + - Name: netbook-testing + Url: http://download.meego.com/testing/netbook/repos/@ARCH@/packages + - Name: handset-testing + Url: http://download.meego.com/testing/handset/repos/@ARCH@/packages + - Name: core + Url: http://repo.meego.com/MeeGo/builds/@RELEASE@/@BUILD_ID@/core/repos/@ARCH@/packages + - Name: netbook + Url: http://repo.meego.com/MeeGo/builds/@RELEASE@/@BUILD_ID@/netbook/repos/@ARCH@/packages + - Name: handset + Url: http://repo.meego.com/MeeGo/builds/@RELEASE@/@BUILD_ID@/handset/repos/@ARCH@/packages + - Name: ivi + Url: http://repo.meego.com/MeeGo/builds/@RELEASE@/@BUILD_ID@/ivi/repos/@ARCH@/packages + - Name: non-oss + Url: http://repo.meego.com/MeeGo/builds/@RELEASE@/@BUILD_ID@/non-oss/repos/@ARCH@/packages diff --git a/kickstart/Makefile b/kickstart/Makefile new file mode 100644 index 0000000..ce2f89e --- /dev/null +++ b/kickstart/Makefile @@ -0,0 +1,20 @@ +# ex: set tabstop=4 noexpandtab: +PYTHON=python +CHEETAH=cheetah +TEMPLATES=$(wildcard *.tmpl) +TEMPLATE_MODS=$(patsubst %.tmpl,%.py,$(TEMPLATES)) +.SECONDARY: $(TEMPLATE_MODS) + +all: $(TEMPLATE_MODS) + +%.py: %.tmpl + $(CHEETAH) compile --settings='useStackFrames=False' $< + cp $@ __init__.py + +clean: + rm -f $(TEMPLATE_MODS) + rm -f $(addsuffix .bak,$(TEMPLATE_MODS)) + rm -f *.xsd *.wsdl + rm -f *.pyc *.pyo + rm -f *.py + rm -f *.bak diff --git a/kickstart/kickstart.tmpl b/kickstart/kickstart.tmpl new file mode 100644 index 0000000..2cfb83c --- /dev/null +++ b/kickstart/kickstart.tmpl @@ -0,0 +1,116 @@ +#if $metadata.has_key("Mic2Options") +# -*-mic2-options-*- ${metadata.Mic2Options} -*-mic2-options-*- + +#end if +# ############################################## +# Do not Edit! Generated by: +# kickstarter.py +# ############################################### + +lang ${metadata.Language} +keyboard ${metadata.Keyboard} +timezone --utc ${metadata.Timezone} +#if $metadata.Part == "" +part / --size ${metadata.PartSize} --ondisk sda --fstype=${metadata.FileSystem} +#else +${metadata.Part} +#end if +rootpw ${metadata.RootPass} +#if $metadata.has_key("StartX") +xconfig --startxonboot +#end if +#if $metadata.has_key("BootloaderTimeout") or $metadata.has_key("BootloaderAppend") or $metadata.has_key("BootloaderOptions") +bootloader #slurp +#end if +#if $metadata.has_key("BootloaderTimeout") + --timeout=${metadata.BootloaderTimeout} #slurp +#end if +#if $metadata.has_key("BootloaderAppend") + --append="${metadata.BootloaderAppend}" #slurp +#end if +#if $metadata.has_key("BootloaderOptions") + ${metadata.BootloaderOptions} +#end if + +#if $metadata.has_key("Desktop") +desktop --autologinuser=${metadata.DefaultUser} #slurp +#if $metadata.Desktop != "None" +--defaultdesktop=${metadata.Desktop} #slurp +#end if +#if $metadata.has_key("Session") +--session="${metadata.Session}" +#else + +#end if +#end if +user --name ${metadata.DefaultUser} --groups audio,video --password '${metadata.DefaultUserPass}' + +#set $options_global = "" +#if $metadata.SaveRepos +#set $options_global = "--save --debuginfo --source --gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-meego" +#end if +#for $r in $metadata.Repos +#for $rr in $repos +#if $rr.Name == $r +#set $options_repo = $options_global +#if $rr.has_key("Options") +#set $options_repo = $rr.Options +#end if +#if $rr.Name == "adobe" +#if $rr.has_key("Options") +repo --name=${r} --baseurl=${rr.Url} ${rr.Options} +#else +repo --name=${r} --baseurl=${rr.Url} +#end if +#else +repo --name=${r} --baseurl=${rr.Url} ${options_repo} +#end if +#end if +#end for +#end for + +#if $metadata.has_key("PackageArgs") +%packages --${metadata.PackageArgs} +#else +%packages +#end if + +#for $g in $metadata.Groups +@${g} +#end for + +#if $metadata.has_key("Kernel") +$metadata.Kernel +#end if + +#for $e in $metadata.ExtraPackages +${e} +#end for +#for $e in $metadata.RemovePackages +-${e} +#end for +%end + +#if $metadata.has_key("PrePackages") +%prepackages +#for $e in $metadata.PrePackages +${e} +#end for +%end +#end if + +#if $metadata.has_key("Attachment") +%attachment +#for $e in $metadata.Attachment +${e} +#end for +%end +#end if + +%post +${metadata.Post} +%end + +%post --nochroot +${metadata.NoChroot} +%end diff --git a/kswriter/KSWriter.py b/kswriter/KSWriter.py new file mode 100644 index 0000000..5e840ac --- /dev/null +++ b/kswriter/KSWriter.py @@ -0,0 +1,172 @@ +#!/usr/bin/python +import copy +import time +import yaml +import os, re +import sys +import errno +from urlparse import urlparse + +from kickstart import kickstart + +def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: # Python >2.5 + if exc.errno == errno.EEXIST: + pass + else: raise + +class KSWriter(): + def __init__(self, configs=None, repos=None, outdir=".", config=None, packages=False): + self.dist = None + self.arch = None + self.image_filename = os.path.abspath(os.path.expanduser(configs)) + self.repo_filename = repos + self.outdir = outdir + self.packages = packages + self.config = config + self.image_stream = file(self.image_filename, 'r') + self.repo_stream = file(self.repo_filename, 'r') + self.extra = {} + self.repo_meta = yaml.load(self.repo_stream) + self.image_meta = yaml.load(self.image_stream) + + def merge(*input): + return list(reduce(set.union, input, set())) + + def dump(self): + print yaml.dump(yaml.load(self.stream)) + + def parse(self, img): + conf = copy.copy(self.image_meta['Default']) + plat = copy.copy(self.image_meta[img['Platform']]) + conf.update(plat) + conf.update(img) + lval = ['Repos', 'Groups', 'PostScripts', 'NoChrootScripts', 'RemovePackages', 'ExtraPackages'] + lvald = {} + for l in lval: + full = [] + if self.image_meta['Default'].has_key(l) and self.image_meta['Default'][l]: + full = full + self.image_meta['Default'][l] + if plat.has_key(l) and plat[l]: + full = full + plat[l] + if img.has_key(l) and img[l]: + full = full + img[l] + lvald[l] = sorted(set(full), key=full.index) + conf.update(lvald) + postscript = "" + meta_root = os.path.dirname(self.image_filename) + for scr in conf['PostScripts']: + if os.path.exists('%s/custom/scripts/%s.post' %(meta_root, scr)): + f = open('%s/custom/scripts/%s.post' %(meta_root, scr), 'r') + postscript += f.read() + postscript += "\n" + f.close() + else: + print '%s/custom/scripts/%s.post not found, skipping.' %(meta_root,scr ) + + nochrootscript = "" + for scr in conf['NoChrootScripts']: + if os.path.exists('%s/custom/scripts/%s.nochroot' %(meta_root,scr)): + f = open('%s/custom/scripts/%s.nochroot' %(meta_root, scr ), 'r') + nochrootscript += f.read() + nochrootscript += "\n" + f.close() + else: + print '%s/custom/scripts/%s.nochroot not found, skipping.' %(meta_root, scr ) + + ptab = "" + for g in [ plat, img ]: + if g.has_key("Part"): + f = open("%s/custom/part/%s" %(meta_root, g['Part']) ) + ptab = f.read() + f.close() + + conf['Part'] = ptab + conf['Post'] = postscript + conf['NoChroot'] = nochrootscript + return conf + + def process_files(self, meta, repos): + new_repos = [] + if ( meta.has_key("Architecture") and meta['Architecture'] ) or ( meta.has_key("Distribution") and meta['Distribution']): + for repo in repos: + r = {} + r['Name'] = repo['Name'] + repourl = repo['Url'] + if repo.has_key('Options'): + r['Options'] = repo['Options'] + if meta.has_key("Architecture") or self.arch: + repourl = repourl.replace("@ARCH@", self.arch or meta['Architecture']) + if meta.has_key("Distribution") or self.dist: + repourl = repourl.replace("@DIST@", self.dist or meta['Distribution']) + + url = repourl.replace("@RELEASE@", meta['Baseline']) + o = urlparse(url) + new_url = "%s://" % o[0] + if repo.has_key('Username') and repo['Username']: + new_url = "%s%s" % (new_url, repo['Username'] ) + if repo.has_key('Password') and repo['Password']: + new_url = "%s:%s@" % (new_url, repo['Password'] ) + r['Url'] = "%s%s%s" % (new_url, o[1], o[2] ) + new_repos.append(r) + else: + new_repos = repos + + nameSpace = {'metadata': meta, 'repos': new_repos} + t = kickstart(searchList=[nameSpace]) + a = str(t) + if meta.has_key('FileName') and meta['FileName']: + f = None + if meta.has_key("Baseline"): + mkdir_p("%s/%s" %(self.outdir, meta['Baseline'])) + f = open("%s/%s/%s.ks" %( self.outdir, meta['Baseline'], meta['FileName'] ), 'w') + else: + f = open("%s/%s.ks" %( self.outdir, meta['FileName'] ), 'w') + f.write(a) + f.close() + + def generate(self): + out = {} + repos = self.repo_meta['Repositories'] + if self.image_meta.has_key('Configurations'): + for img in self.image_meta['Configurations']: + conf = self.parse(img) + if self.config: + if img.has_key('FileName') and self.config == img['FileName']: + print "Creating %s (%s.ks)" %(img['Name'], img['FileName'] ) + self.process_files(conf, repos) + break + else: + if conf.has_key('Active') and conf['Active'] : + print "Creating %s (%s.ks)" %(img['Name'], img['FileName'] ) + self.process_files(conf, repos) + else: + print "%s is inactive, not generating %s at this time" %(img['Name'], img['FileName'] ) + for path in self.image_meta['ExternalConfigs']: + external_config_dir = os.path.join(os.path.dirname(self.image_filename), path) + for f in os.listdir(external_config_dir): + if f.endswith('.yaml'): + fp = file('%s/%s' %(external_config_dir, f), 'r') + local = yaml.load(fp) + conf = self.parse(local) + if self.config: + if self.config == conf['FileName']: + if self.packages: + out['baseline'] = conf['Baseline'] + out['groups'] = conf['Groups'] + out['packages'] = conf['ExtraPackages'] + else: + print "Creating %s (%s.ks)" %(conf['Name'], conf['FileName'] ) + self.process_files(conf, repos) + break + else: + if conf.has_key('Active') and conf['Active']: + print "Creating %s (%s.ks)" %(conf['Name'], conf['FileName'] ) + self.process_files(conf, repos) + else: + print "%s is inactive, not generate %s this time" %(conf['Name'], conf['FileName'] ) + else: + print "WARNING: File '%s' ignored." % (f) + return out diff --git a/kswriter/__init__.py b/kswriter/__init__.py new file mode 100644 index 0000000..82212cb --- /dev/null +++ b/kswriter/__init__.py @@ -0,0 +1 @@ +from KSWriter import KSWriter diff --git a/packaging/kickstarter.manifest b/packaging/kickstarter.manifest new file mode 100644 index 0000000..017d22d --- /dev/null +++ b/packaging/kickstarter.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/kickstarter.spec b/packaging/kickstarter.spec new file mode 100644 index 0000000..765501f --- /dev/null +++ b/packaging/kickstarter.spec @@ -0,0 +1,47 @@ +%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} +Name: kickstarter +Summary: Create kickstart files for image creation +Version: 0.15 +Release: 1 +Group: System/Base +License: GPLv2 +BuildArch: noarch +URL: http://www.tizen.org +Source0: %{name}-%{version}.tar.bz2 +Source1001: packaging/kickstarter.manifest +Requires: python-yaml +Requires: python-cheetah +Requires: python-lxml +BuildRequires: python-devel +BuildRequires: python-cheetah + + +%description +Create Configuration files(kickstart) to build images + + +%prep +%setup -q -n %{name}-%{version} + + +%build +cp %{SOURCE1001} . +make tmpls + +CFLAGS="$RPM_OPT_FLAGS" %{__python} setup.py build + + +%install +rm -rf $RPM_BUILD_ROOT +%if 0%{?suse_version} +%{__python} setup.py install --root=$RPM_BUILD_ROOT --prefix=%{_prefix} +%else +%{__python} setup.py install --root=$RPM_BUILD_ROOT -O1 --prefix=%{_prefix} +%endif + + +%files +%manifest kickstarter.manifest +%defattr(-,root,root,-) +%{_bindir}/* +%{python_sitelib}/* diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..735a510 --- /dev/null +++ b/setup.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +import os, sys +from distutils.core import setup +try: + import setuptools + # enable "setup.py develop", optional +except ImportError: + pass + +MOD_NAME = 'kickstart' + +version_path = 'VERSION' +if not os.path.isfile(version_path): + print 'No VERSION file in topdir, abort' + sys.exit(1) + +try: + # first line should be the version number + version = open(version_path).readline().strip() + if not version: + print 'VERSION file is invalid, abort' + sys.exit(1) + + ver_file = open('%s/__version__.py' % MOD_NAME, 'w') + ver_file.write("VERSION = \"%s\"\n" % version) + ver_file.close() +except IOError: + print 'WARNING: Cannot write version number file' + +setup(name='kickstarter', + version = version, + description='Kickstarter', + author='Anas Nashif', + author_email='anas.nashif@intel.com', + url='http://meego.com/', + scripts=['tools/kickstarter'], + packages=['kickstart', 'kswriter'] + ) + diff --git a/tools/fetch-configs.py b/tools/fetch-configs.py new file mode 100755 index 0000000..653af7f --- /dev/null +++ b/tools/fetch-configs.py @@ -0,0 +1,29 @@ +#!/usr/bin/python + +import urllib2 +from datetime import date +from xml.etree.ElementTree import ElementTree + +url = "http://download.meego.com/snapshots/1.1.90.8.20110317.88/builddata/image-configs.xml" +f = urllib2.urlopen(url) +tree = ElementTree() +tree.parse(f) +configs = tree.findall('config') +for c in configs: + planned = False + name = c.find('name').text + dow = date.today().weekday() + if c.find('schedule').text != '': + schedule = c.find('schedule').text + if schedule == '*': + planned = True + elif schedule in ["0","1","2","3","4","5","6"] and int(schedule) == dow: + planned = True + else: + planned = False + + if planned: + print "%s is scheduled to be created today" %name + else: + print "%s is not scheduled to be created today" %name + diff --git a/tools/kickstarter b/tools/kickstarter new file mode 100755 index 0000000..861bdd4 --- /dev/null +++ b/tools/kickstarter @@ -0,0 +1,106 @@ +#!/usr/bin/python +# Anas Nashif +import yaml, sys +import re, os +from kswriter import KSWriter + +import copy +import time +import optparse +from time import gmtime, strftime +try: + from lxml import etree +except ImportError: + try: + # Python 2.5 + import xml.etree.cElementTree as etree + except ImportError: + try: + # Python 2.5 + import xml.etree.ElementTree as etree + except ImportError: + try: + # normal cElementTree install + import cElementTree as etree + except ImportError: + try: + # normal ElementTree install + import elementtree.ElementTree as etree + except ImportError: + print("Failed to import ElementTree from any known place") + + +def image_xml(root, img): + s = etree.Element("config") + c = etree.Element('name') + c.text = "%s.ks" %img['FileName'] + s.append(c) + cc = etree.Element('path') + cc.text = "image-configs/%s.ks" %img['FileName'] + s.append(cc) + cc = etree.Element('description') + cc.text = "%s" %img['Name'] + s.append(cc) + + if img.has_key('Architecture'): + cc = etree.Element('arch') + cc.text = "%s" %img['Architecture'] + s.append(cc) + + cc = etree.Element('md5') + cc.text = "" + s.append(cc) + + cc = etree.Element('schedule') + if img.has_key('Schedule'): + cc.text = img['Schedule'] + s.append(cc) + root.append(s) + +def create_xml(image_meta): + root = etree.Element("image-configs") + if image_meta.has_key('Configurations'): + for img in image_meta['Configurations']: + image_xml(root,img) + for path in image_meta['ExternalConfigs']: + for f in os.listdir(path): + if f.endswith('.yaml'): + fp = file('%s/%s' %(path, f), 'r') + local = yaml.load(fp) + conf = ks.parse(local) + if conf.has_key('Active') and conf['Active']: + image_xml(root,conf) + + str = etree.tostring(root, pretty_print=True) + return str + +if __name__ == '__main__': + parser = optparse.OptionParser() + + parser.add_option("-c", "--configs", type="string", dest="configsfile", + help="configuration meta file") + parser.add_option("-o", "--outdir", type="string", dest="outdir", default=".", + help="outdir") + parser.add_option("-r", "--repos", type="string", dest="repofile", + help="repo meta file") + parser.add_option("-i", "--index", type="string", dest="indexfile", + help="generate index file") + parser.add_option("-C", "--config", type="string", dest="config", default=None, + help="Limit to this configuration file") + parser.add_option("-p", "--packages", action="store_true", dest="packages", default=False, + help="return list of packages to be installed for this configuration") + + (options, args) = parser.parse_args() + + if options.configsfile is None or options.repofile is None: + print "you need to provide meta files with --configs and --repos" + sys.exit(1) + + ks = KSWriter(options.configsfile, options.repofile, options.outdir, options.config, options.packages) + ks.generate() + + if options.indexfile: + str = create_xml(ks.image_meta) + f = open(options.indexfile, 'w') + f.write(str) + f.close()