diff --git a/Makefile b/Makefile index 53f4388f..c62a9d45 100644 --- a/Makefile +++ b/Makefile @@ -9,3 +9,6 @@ install: clean: -rm -rf build + +test: + /usr/bin/lorax -p FEDORA -v RAWHIDE -r 2010 -s /rawrepo /root/rawhide diff --git a/etc/config.i386 b/etc/config.i386 deleted file mode 100644 index 4b33a229..00000000 --- a/etc/config.i386 +++ /dev/null @@ -1,4 +0,0 @@ -[lorax] - -packages: - kernel-PAE grub memtest86+ diff --git a/etc/config.noarch b/etc/config.noarch deleted file mode 100644 index 828b64e6..00000000 --- a/etc/config.noarch +++ /dev/null @@ -1,51 +0,0 @@ -[lorax] - -packages: - anaconda anaconda-yum-plugins yum yum-metadata-parser - kernel *firmware* man-db - rsyslog ethtool openssh openssh-server strace - udev hal dbus dbus-python dbus-x11 - xorg-x11-server-Xorg xorg-x11-server-utils xorg-x11-drivers - xorg-x11-xauth xorg-x11-font-utils xorg-x11-fonts-misc - dejavu-sans-fonts dejavu-sans-mono-fonts fontconfig freetype - fonts-ISO8859-2 - gtk2 gtk2-engines gnome-themes metacity pango cairo echo-icon-theme - device-mapper device-mapper-libs - device-mapper-multipath device-mapper-multipath-libs - mdadm lvm2 dmraid dmraid-libs - selinux-policy-targeted fcoe-utils - libselinux libselinux-python libsemanage libsemanage-python - lohit-assamese-fonts lohit-bengali-fonts lohit-gujarati-fonts - lohit-hindi-fonts lohit-kashmiri-fonts lohit-kannada-fonts - lohit-maithili-fonts lohit-marathi-fonts lohit-oriya-fonts - lohit-punjabi-fonts lohit-sindhi-fonts lohit-tamil-fonts lohit-telugu-fonts - bitmap-fonts-cjk cjkuni-uming-fonts smc-meera-fonts taipeifonts - un-core-dotum-fonts urw-fonts vlgothic-fonts lklug-fonts - coreutils bzip2 bzip2-libs cpio - cracklib cracklib-dicts cracklib-python cryptsetup-luks - GConf2 gnome-python2-gconf gnome-python2-canvas - /etc/gtk-2.0/gtkrc ORBit2 - comps-extras - NetworkManager NetworkManager-gnome - firstboot setup newt newt-python report-gtk report-newt - parted pyparted dosfstools e2fsprogs e2fsprogs-libs gfs2-utils jfsutils - nfs-utils ntfs-3g reiserfs-utils xfsprogs samba-client - tigervnc-server tigervnc-server-module vim-minimal wget - kbd ncurses - notification-daemon - gobject-introspection - syslinux - -modules: - sunrpc lockd floppy cramfs loop edd pcspkr squashfs - ipv6 virtio_pci ohci-hcd uhci-hcd ehci-hcd usbhid mousedev usb-storage - sd_mod sr_mod ub appletouch ohci1394 sbp2 fw-ohci fw-sbp2 firewire-sbp2 - firewire-ohci mmc-block sdhci sdhci-pci ide-cd ide-cd_mod sr_mod sg st - sd_mod scsi_mod iscsi_tcp iscsi_ibft fat msdos vfat ext2 ext3 ext4 reiserfs - jfs xfs gfs2 cifs nfs fuse btrfs dm-mod dm-zero dm-snapshot dm-mirror - dm-multipath dm-round-robin dm-crypt raid0 raid1 raid5 raid6 raid456 raid10 - linear sha256_generic cbc xts lrw aes_generic crypto_blkcipher crc32c ecb - arc4 yenta_socket i82365 tcic pcmcia =scsi =net =drm - -initrd_template = templates/initrd.ltmpl -install_template = templates/install.ltmpl diff --git a/etc/ignore_errors b/etc/lorax.conf similarity index 100% rename from etc/ignore_errors rename to etc/lorax.conf diff --git a/etc/templates/initrd.ltmpl b/etc/templates/initrd.ltmpl deleted file mode 100644 index 0404bf3b..00000000 --- a/etc/templates/initrd.ltmpl +++ /dev/null @@ -1,243 +0,0 @@ -## create required directories -makedirs "sbin" -symlink "sbin" "bin" -makedirs "dev" -makedirs "etc" -makedirs "proc" -makedirs "selinux" -makedirs "sys" -makedirs "tmp" -makedirs "var" - -## copy etc stuff -copy "etc/passwd" -copy "etc/group" -copy "etc/hosts" -copy "etc/nsswitch.conf" - -## copy mount/umount files -copy "bin/mount" -copy "bin/umount" -copy "sbin/mount.*" -copy "sbin/umount.*" - -## copy udev stuff -copy "sbin/udevd" -copy "sbin/udevadm" -symlink "udevadm" "sbin/udevinfo" - -## copy udev conf and rules -copy "etc/udev/udev.conf" -copy "etc/udev/rules.d/*.rules" -copy "lib/udev/*" -remove "lib/udev/rules.d/*generator*" - -## copy bash -copy "bin/bash" -symlink "bash" "bin/sh" - -## other -copy "sbin/consoletype" -copy "usr/bin/logger" "bin" - -## copy init functions -copy "etc/rc.d/init.d/functions" -copy "etc/sysconfig/network-scripts/network-functions*" - -## create init.d symlink -symlink "/etc/rc.d/init.d" "etc/init.d" - -## dhcp client daemons and support programs -copy "sbin/dhclient" -copy "sbin/dhclient-script" -copy "sbin/arping" -copy "sbin/ifconfig" -copy "sbin/ip" -copy "bin/ipcalc" -copy "bin/hostname" -copy "sbin/ethtool" -copy "sbin/route" -touch "etc/resolv.conf" -makedirs "etc/dhcp" - -## hwdata -copy "usr/share/hwdata/pci.ids" -copy "usr/share/hwdata/usb.ids" - -## hal -copy "usr/sbin/hald" "sbin" -copy "usr/libexec/hald-runner" -copy "usr/libexec/hald-generate-fdi-cache" -copy "usr/libexec/hal*storage*" -copy "usr/share/hal/fdi/*" -copy "etc/hal/fdi/*" -copy "etc/dbus-1/system.d/hal.conf" -makedirs "var/run" -touch "var/run/hald.acl-list" - -## policykit -copy "etc/polkit-1" -copy "usr/share/dbus-1/system-services/org.freedesktop.PolicyKit1.service" -copy "usr/share/polkit-1/actions/org.freedesktop.policykit.policy" - -## dbus -copy "bin/dbus-uuidgen" -copy "bin/dbus-daemon" -copy "etc/dbus-1/system.conf" -copy "${libdir}/dbus-1/dbus-daemon-launch-helper" -makedirs "var/lib/dbus" -makedirs "var/run/dbus" - -## wpa_supplicant -copy "usr/sbin/wpa_passphrase" -copy "usr/sbin/wpa_supplicant" -copy "etc/dbus-1/system.d/wpa_supplicant.conf" -copy "etc/wpa_supplicant/wpa_supplicant.conf" -copy "usr/share/dbus-1/system-services/fi.epitest.hostap.WPASupplicant.service" - -## networkmanager -copy "usr/sbin/NetworkManager" -makedirs "etc/NetworkManager/dispatcher.d" -copy "etc/NetworkManager/nm-system-settings.conf" -copy "etc/dbus-1/system.d/NetworkManager.conf" -copy "etc/dbus-1/system.d/nm-*.conf" -copy "usr/${libdir}/NetworkManager/libnm-*" -copy "usr/libexec/nm-*" -copy "usr/share/dbus-1/system-services/org.freedesktop.nm_dispatcher.service" - -## modprobe -makedirs "etc/modprobe.d" -copy "sbin/modprobe" -copy "sbin/insmod" -copy "sbin/rmmod" -copy "sbin/depmod" - -## terminfos -copy "usr/share/terminfo/a/ansi" -copy "usr/share/terminfo/d/dumb" -copy "usr/share/terminfo/l/linux" -copy "usr/share/terminfo/s/screen" -copy "usr/share/terminfo/v/vt100" -copy "usr/share/terminfo/v/vt100-nav" -copy "usr/share/terminfo/v/vt102" -copy "usr/share/terminfo/x/xterm" -copy "usr/share/terminfo/x/xterm-color" -copy "usr/share/terminfo/g/gnome" - -## misc -copy "bin/awk" -copy "bin/grep" -copy "bin/egrep" -copy "bin/fgrep" -copy "bin/kill" -copy "bin/ln" -copy "usr/bin/readlink" "bin" -copy "bin/rm" -copy "bin/rmdir" -copy "bin/sed" -copy "bin/sleep" -copy "bin/touch" -copy "usr/sbin/dmidecode" "sbin" -copy "sbin/load_policy" -copy "sbin/mdadm" -copy "sbin/mdmon" -copy "bin/mkdir" -copy "usr/bin/wget" "bin" - -## misc symlinks -symlink "/sbin/init" "init" -symlink "/proc/mounts" "etc/mtab" -makedirs "var/lib" -symlink "../../tmp" "var/lib/xkb" - -## loader -copy "usr/${libdir}/anaconda/loader" "sbin" -copy "usr/share/anaconda/loader.tr" "etc" - -## ld-linux -% if basearch in ("i386",): - copy "${libdir}/ld-linux.so.2" -% elif basearch in ("x86_64",): - copy "${libdir}/ld-linux-x86-64.so.2" -% endif - -## indirect dependencies -copy "${libdir}/libcom_err.so.2" -copy "${libdir}/libgcc_s.so.1" -copy "${libdir}/libnss_dns.so.2" -copy "${libdir}/libnss_files.so.2" -copy "usr/${libdir}/libsqlite3.so.0" - -## langtable -copy "usr/share/anaconda/lang-table" "etc" - -## arch bits -edit "etc/arch" "${buildarch}" - -## rsyslogd -copy "sbin/rsyslogd" -copy "${libdir}/rsyslog/*" -copy "etc/rsyslog.conf" - - -## missing files -copy "usr/sbin/sshd" -copy "usr/bin/ssh-keygen" -copy "usr/bin/strace" - -makedirs "var/empty" -makedirs "var/empty/sshd" -makedirs "var/lock" -makedirs "var/lock/rpm" -makedirs "var/run/NetworkManager" -makedirs "var/run/wpa_supplicant" -makedirs "var/run/hald" -makedirs "var/lib/dhclient" - - -## security libraries -makedirs "${libdir}/security" -copy "${libdir}/security/*" - - -## architecture specific code -% if basearch in ("i386", "x86_64"): - copy "usr/${libdir}/anaconda/init" "sbin" - symlink "init" "sbin/reboot" - symlink "init" "sbin/halt" - symlink "init" "sbin/poweroff" - - ## screenfont - copy "usr/share/anaconda/screenfont-${basearch}.gz" "etc" - rename "etc/screenfont-${basearch}.gz" "etc/screenfont.gz" -% endif - -% if basearch in ("s390", "s390x"): - makedirs "etc/ssh" - makedirs "etc/security" - makedirs "${libdir}/security" - makedirs "var/empty/sshd" - symlink "../../tmp" "var/state/xkb" - - copy "${libdir}/libpam_misc.so*" - copy "${libdir}/libwrap*.so*" - - copy "usr/${libdir}/anaconda/shutdown" "sbin" - copy "usr/${libdir}/anaconda/linuxrc.s390" "sbin" - rename "sbin/linuxrc.s390" "sbin/init" - copy "usr/${libdir}/anaconda/lsznet.raw" "sbin" - rename "sbin/lsznet.raw" "sbin/lsznet" - copy "usr/${libdir}/anaconda/controlunits.sh" "sbin" - rename "sbin/controlunits.sh" "sbin/controlunits" - - copy "${libdir}/security/pam*.so" - copy "etc/pam.d/other" - copy "etc/security/limits.conf" - copy "etc/security/pam_env.conf" - - copy "bin/login" - copy "usr/sbin/dasdfmt" - copy "usr/sbin/sshd" - copy "usr/bin/xauth" - copy "usr/sbin/cmsfs*" -% endif diff --git a/etc/templates/install.ltmpl b/etc/templates/install.ltmpl deleted file mode 100644 index 865594ca..00000000 --- a/etc/templates/install.ltmpl +++ /dev/null @@ -1,259 +0,0 @@ -## packages to remove -removepkg "acl" -removepkg "aic94xx-firmware" -removepkg "alsa-firmware" -removepkg "alsa-lib" -removepkg "alsa-tools-firmware" -removepkg "ar9170-firmware" -removepkg "atmel-firmware" -removepkg "authconfig-gtk" -removepkg "avahi-autoipd" -removepkg "avahi-libs" -removepkg "basesystem" -removepkg "bfa-firmware" -removepkg "checkpolicy" -removepkg "chkconfig" -removepkg "control-center-filesystem" -removepkg "coreutils-libs" -removepkg "cracklib-dicts" "/usr/lib/*" -removepkg "cracklib-dicts" "/usr/sbin/*" -removepkg "cronie" -removepkg "cronie-anacron" -removepkg "crontabs" -removepkg "crystalhd-firmware" -removepkg "cups-libs" -removepkg "curl" -removepkg "cx18-firmware" -removepkg "dash" -removepkg "db4-utils" -removepkg "dejavu-fonts-common" -removepkg "deltarpm" -removepkg "desktop-file-utils" -removepkg "device-mapper-event" -removepkg "diffutils" -removepkg "dmraid-events" -removepkg "dracut" -removepkg "echo-icon-theme" -removepkg "exim" -removepkg "fedora-release" -removepkg "fedora-release-rawhide" -removepkg "file" -removepkg "filesystem" -removepkg "fipscheck" -removepkg "firmware-addon-dell" -removepkg "firmware-tools" -removepkg "firstboot" -removepkg "flac" -removepkg "fontpackages-filesystem" -removepkg "fxload" -removepkg "gamin" -removepkg "genisoimage" -removepkg "gnome-python2" -removepkg "gnupg2" -removepkg "grubby" -removepkg "gstreamer" -removepkg "gstreamer-tools" -removepkg "hal" -removepkg "hal-filesystem" -removepkg "hal-info" -removepkg "hal-libs" -removepkg "info" -removepkg "iptables" -removepkg "iptables-ipv6" -removepkg "ipw2100-firmware" -removepkg "ipw2200-firmware" -removepkg "iscan-firmware" -removepkg "isight-firmware-tools" -removepkg "iso8859-2-fonts-common" -removepkg "iso8859-2-misc-fonts" -removepkg "isomd5sum" -removepkg "ivtv-firmware" -removepkg "iwl1000-firmware" -removepkg "iwl3945-firmware" -removepkg "iwl4965-firmware" -removepkg "iwl5000-firmware" -removepkg "iwl5150-firmware" -removepkg "iwl6000-firmware" -removepkg "iwl6050-firmware" -removepkg "jasper-libs" -removepkg "kbd-misc" -removepkg "kernel" -removepkg "kernel-PAE" -removepkg "libasyncns" -removepkg "libcgroup" -removepkg "libcrystalhd" -removepkg "libdaemon" -removepkg "libertas-sd8686-firmware" -removepkg "libertas-usb8388-firmware" -removepkg "libevent" -removepkg "libhbaapi" -removepkg "libhbalinux" -removepkg "libIDL" -removepkg "libmcpp" -removepkg "libmount" -removepkg "libnih" -removepkg "libpcap" -removepkg "libselinux-utils" -removepkg "libsmbios" -removepkg "libsndfile" -removepkg "libtiff" -removepkg "libutempter" -removepkg "libwnck" -removepkg "libx86" -removepkg "libXmu" -removepkg "libXres" -removepkg "libXt" -removepkg "libXv" -removepkg "libXvMC" -removepkg "libXxf86misc" -removepkg "libXxf86vm" -removepkg "linux-atm-libs" -removepkg "linux-firmware" -removepkg "logrotate" -removepkg "lvm2-libs" -removepkg "m4" -removepkg "makebootfat" -##removepkg "man-db" -removepkg "mcpp" -removepkg "memtest86+" -removepkg "midisport-firmware" -removepkg "mingetty" -removepkg "mobile-broadband-provider-info" -removepkg "nfs-utils-lib" -removepkg "notification-daemon" -removepkg "nss-sysinit" -removepkg "ntp" -removepkg "ntpdate" -removepkg "passwd" -removepkg "perl" -removepkg "perl-Crypt-PasswdMD5" -removepkg "perl-Digest-SHA1" -removepkg "perl-libs" -removepkg "perl-Module-Pluggable" -removepkg "perl-Pod-Escapes" -removepkg "perl-Pod-Simple" -removepkg "pinentry" -removepkg "pkgconfig" -removepkg "plymouth" -removepkg "plymouth-core-libs" -removepkg "plymouth-scripts" -removepkg "pm-utils" -removepkg "ppp" -removepkg "pth" -removepkg "pulseaudio-libs" -removepkg "python-smbios" -removepkg "ql2100-firmware" -removepkg "ql2200-firmware" -removepkg "ql23xx-firmware" -removepkg "ql2400-firmware" -removepkg "ql2500-firmware" -removepkg "radeontool" -removepkg "rpcbind" -removepkg "rt61pci-firmware" -removepkg "rt73usb-firmware" -removepkg "samba-client" -removepkg "samba-common" -removepkg "samba-winbind-clients" -removepkg "selinux-policy" -removepkg "setuptool" -removepkg "sgml-common" -removepkg "sgpio" -removepkg "shadow-utils" -removepkg "shared-mime-info" -removepkg "smbios-utils" -removepkg "smbios-utils-bin" -removepkg "smbios-utils-python" -removepkg "smc-fonts-common" -removepkg "sound-theme-freedesktop" -removepkg "squashfs-tools" -removepkg "system-config-firewall-base" -removepkg "system-config-users" -removepkg "systemd-units" -removepkg "system-setup-keyboard" -removepkg "taipeifonts" -removepkg "ueagle-atm4-firmware" -removepkg "un-core-fonts-common" -removepkg "upstart" -removepkg "upstart-sysvinit" -removepkg "urw-fonts" -removepkg "usermode" -removepkg "usermode-gtk" -removepkg "vbetool" -removepkg "vlgothic-fonts-common" -removepkg "which" -removepkg "xdg-utils" -removepkg "xml-common" -removepkg "xorg-x11-drivers" -removepkg "xorg-x11-font-utils" -removepkg "xorg-x11-server-common" -removepkg "xorg-x11-xauth" -removepkg "yum-utils" -removepkg "zd1211-firmware" - -## files to remove -remove "boot" -remove "cgroup" -remove "dev" -remove "home" -remove "media" -remove "mnt" -remove "opt" -remove "pungi" -remove "root" -remove "selinux" -remove "srv" -remove "sys" -remove "tmp" - -remove "var/cache" -remove "var/db" -remove "var/empty" -remove "var/games" -remove "var/lib/NetworkManager" -remove "var/lib/alternatives" -remove "var/lib/authconfig" -remove "var/lib/dhclient" -remove "var/lib/dnsmasq" -remove "var/lib/games" -remove "var/lib/iscsi" -remove "var/lib/misc" -remove "var/lib/nfs" -remove "var/lib/ntp" -remove "var/lib/plymouth" -remove "var/lib/rpcbind" -remove "var/lib/rpm" -remove "var/lib/rpm-state" -remove "var/lib/samba" -remove "var/lib/statless" -remove "var/lib/yum" -remove "var/local" -remove "var/lock" -remove "var/log" -remove "var/nis" -remove "var/opt" -remove "var/preserve" -remove "var/report" -remove "var/run/ConsoleKit" -remove "var/run/NetworkManager" -remove "var/run/console" -remove "var/run/hald" -remove "var/run/mdadm" -remove "var/run/netreport" -remove "var/run/plymouth" -remove "var/run/pm-utils" -remove "var/run/ppp" -remove "var/run/sepermit" -remove "var/run/setrans" -remove "var/run/wpa_supplicant" -remove "var/run/utmp" -remove "var/spool" -remove "var/tmp" -remove "var/yp" - -remove "usr/share/alsa" -remove "usr/share/doc" -remove "usr/share/gnome/help" -remove "usr/share/man" -remove "usr/share/mime" -remove "usr/share/selinux" -remove "usr/share/sgml" diff --git a/pungi/pypungi.patch b/pungi/pypungi.patch deleted file mode 100644 index dab8a357..00000000 --- a/pungi/pypungi.patch +++ /dev/null @@ -1,69 +0,0 @@ ---- __init__.py.orig 2010-04-15 01:23:43.000000000 +0200 -+++ __init__.py 2010-08-13 15:17:39.011410249 +0200 -@@ -754,44 +754,30 @@ - def doBuildinstall(self): - """Run anaconda-runtime's buildinstall on the tree.""" - -+ # initialize yum object -+ self._inityum() - -- # setup the buildinstall call -- buildinstall = ['/usr/lib/anaconda-runtime/buildinstall'] -- #buildinstall.append('TMPDIR=%s' % self.workdir) # TMPDIR broken in buildinstall -+ # get the required stuff for lorax -+ yb = self.ayum -+ installtree = self.ayum._conf.installroot -+ outputdir = self.topdir -+ -+ product = self.config.get('pungi', 'name') -+ version = self.config.get('pungi', 'version') -+ release = "%s %s" % (product, version) -+ -+ workdir = self.workdir -+ -+ variant = self.config.get('pungi', 'flavor') -+ bugurl = self.config.get('pungi', 'bugurl') -+ -+ # run lorax -+ import pylorax -+ lorax = pylorax.Lorax(yb, installtree, outputdir, -+ product, version, release, -+ workdir, variant, bugurl) - -- buildinstall.append('--product') -- buildinstall.append(self.config.get('pungi', 'name')) -- -- if not self.config.get('pungi', 'flavor') == "": -- buildinstall.append('--variant') -- buildinstall.append(self.config.get('pungi', 'flavor')) -- -- buildinstall.append('--version') -- buildinstall.append(self.config.get('pungi', 'version')) -- -- buildinstall.append('--release') -- buildinstall.append('%s %s' % (self.config.get('pungi', 'name'), self.config.get('pungi', 'version'))) -- -- if self.config.has_option('pungi', 'bugurl'): -- buildinstall.append('--bugurl') -- buildinstall.append(self.config.get('pungi', 'bugurl')) -- -- buildinstall.append('--output') -- buildinstall.append(self.topdir) -- -- for mirrorlist in self.mirrorlists: -- buildinstall.append('--mirrorlist') -- buildinstall.append(mirrorlist) -- -- buildinstall.append(self.topdir) -- -- # Add any extra repos of baseurl type -- for repo in self.repos: -- buildinstall.append(repo) -- -- # run the command -- # TMPDIR is still broken with buildinstall. -- pypungi.util._doRunCommand(buildinstall, self.logger) #, env={"TMPDIR": self.workdir}) -+ lorax.run() - - # write out the tree data for snake - self.writeinfo('tree: %s' % self.mkrelative(self.topdir)) diff --git a/setup.py b/setup.py index 499f7955..f00406ef 100644 --- a/setup.py +++ b/setup.py @@ -5,11 +5,10 @@ from glob import glob import os -data_files = [("/etc/lorax", glob("etc/config.*")), - ("/etc/lorax", ["etc/ignore_errors"]), - ("/etc/lorax/templates", glob("etc/templates/*")) - ] +# config file +data_files = [("/etc/lorax", ["etc/lorax.conf"])] +# shared files for root, dnames, fnames in os.walk("share"): for fname in fnames: data_files.append((root.replace("share", "/usr/share/lorax", 1), diff --git a/share/etc/libuser.conf b/share/etc/libuser.conf deleted file mode 100644 index a7a0ef00..00000000 --- a/share/etc/libuser.conf +++ /dev/null @@ -1,10 +0,0 @@ -[defaults] -skeleton = /mnt/sysimage/etc/skel -mailspooldir = /mnt/sysimage/var/mail -crypt_style = md5 -modules = files shadow -create_modules = files shadow -[files] -directory = /mnt/sysimage/etc -[shadow] -directory = /mnt/sysimage/etc diff --git a/share/etc/selinux/config b/share/etc/selinux/config deleted file mode 100644 index eac67ab1..00000000 --- a/share/etc/selinux/config +++ /dev/null @@ -1,2 +0,0 @@ -SELINUX=permissive -SELINUXTYPE=targeted diff --git a/share/ignorelist b/share/ignorelist new file mode 100644 index 00000000..e69de29b diff --git a/share/lorax-s1.ltmpl b/share/lorax-s1.ltmpl new file mode 100644 index 00000000..5ff94397 --- /dev/null +++ b/share/lorax-s1.ltmpl @@ -0,0 +1,795 @@ +## lorax template file + +## anaconda package +install "anaconda" + +## other required packages +install "NetworkManager-gnome" +install "at-spi" +install "at-spi-python" +install "audit" +install "bind-libs-lite" +install "bind-utils" +install "bitmap-fangsongti-fonts" +install "btrfs-progs" +install "cjkuni-uming-fonts" +install "dcbd" +install "dejavu-sans-fonts" +install "dejavu-sans-mono-fonts" +install "dogtail" +install "dump" +install "efibootmgr" +install "ethtool" +install "fedora-gnome-theme" +install "fedora-icon-theme" +install "firstaidkit-engine" +install "ftp" +install "gdk-pixbuf" +install "generic-logos" +install "gfs2-utils" +install "gir-repository" +install "glib" +install "gnome-bluetooth-libs" +install "gnome-keyring" +install "gnome-python2-gconf" +install "gnome-themes-legacy" +install "groff" +install "grub" +install "gtk+" +install "hdparm" +install "jfsutils" +install "lcms-libs" +install "libbonobo" +install "libgnome-keyring" +install "libgssglue" +install "libjpeg" +install "libmlx4" +install "libsemanage-python" +install "libsysfs" +install "libtirpc" +install "lklug-fonts" +install "lohit-assamese-fonts" +install "lohit-bengali-fonts" +install "lohit-devanagari-fonts" +install "lohit-gujarati-fonts" +install "lohit-kannada-fonts" +install "lohit-oriya-fonts" +install "lohit-punjabi-fonts" +install "lohit-tamil-fonts" +install "lohit-telugu-fonts" +install "lsof" +install "lvm2-cluster" +install "madan-fonts" +install "man-db" +install "mt-st" +install "mtr" +install "network-manager-netbook" +install "nfs-utils" +install "notification-daemon" +install "ntfs-3g" +install "ntfsprogs" +install "openssh-server" +install "pciutils" +install "pciutils-libs" +install "pcmciautils" +install "polkit-desktop-policy" +install "python-epdb" +install "python-imaging" +install "python-volume_key" +install "reiserfs-utils" +install "rsh" +install "rsync" +install "rsyslog" +install "samba-common" +install "samba-winbind-clients" +install "selinux-policy-targeted" +install "smartmontools" +install "smc-meera-fonts" +install "strace" +install "systemd-sysvinit" +install "tigervnc-server-minimal" +install "tigervnc-server-module" +install "un-core-dotum-fonts" +install "usbutils" +install "vim-minimal" +install "vlgothic-fonts" +install "volume_key" +install "volume_key-libs" +install "wget" +install "xfsprogs" +install "xorg-x11-drv-acecad" +install "xorg-x11-drv-aiptek" +install "xorg-x11-drv-apm" +install "xorg-x11-drv-ast" +install "xorg-x11-drv-ati" +install "xorg-x11-drv-cirrus" +install "xorg-x11-drv-dummy" +install "xorg-x11-drv-elographics" +install "xorg-x11-drv-evdev" +install "xorg-x11-drv-fbdev" +install "xorg-x11-drv-fpit" +install "xorg-x11-drv-glint" +install "xorg-x11-drv-hyperpen" +install "xorg-x11-drv-i128" +install "xorg-x11-drv-i740" +install "xorg-x11-drv-intel" +install "xorg-x11-drv-keyboard" +install "xorg-x11-drv-mach64" +install "xorg-x11-drv-mga" +install "xorg-x11-drv-mouse" +install "xorg-x11-drv-mutouch" +install "xorg-x11-drv-nouveau" +install "xorg-x11-drv-nv" +install "xorg-x11-drv-openchrome" +install "xorg-x11-drv-penmount" +install "xorg-x11-drv-qxl" +install "xorg-x11-drv-r128" +install "xorg-x11-drv-rendition" +install "xorg-x11-drv-s3virge" +install "xorg-x11-drv-savage" +install "xorg-x11-drv-siliconmotion" +install "xorg-x11-drv-sis" +install "xorg-x11-drv-sisusb" +install "xorg-x11-drv-synaptics" +install "xorg-x11-drv-tdfx" +install "xorg-x11-drv-trident" +install "xorg-x11-drv-v4l" +install "xorg-x11-drv-vesa" +install "xorg-x11-drv-vmmouse" +install "xorg-x11-drv-vmware" +install "xorg-x11-drv-void" +install "xorg-x11-drv-voodoo" +install "xorg-x11-drv-wacom" +install "xorg-x11-fonts-ethiopic" +install "xorg-x11-server-Xorg" +install "xorg-x11-server-utils" +##install "${product}-logos" +##install "${product}-release" + +## required firmware +install "aic94xx-firmware" +install "ar9170-firmware" +install "atmel-firmware" +install "ipw2100-firmware" +install "ipw2200-firmware" +install "iwl1000-firmware" +install "iwl3945-firmware" +install "iwl4965-firmware" +install "iwl5000-firmware" +install "iwl5150-firmware" +install "iwl6000-firmware" +install "iwl6050-firmware" +install "ql2100-firmware" +install "ql2200-firmware" +install "ql23xx-firmware" +install "ql2400-firmware" +install "ql2500-firmware" +install "zd1211-firmware" + +## not required packages installed as dependencies +remove "ConsoleKit-x11" +remove "alsa-lib" +remove "augeas-libs" +remove "authconfig-gtk" +remove "avahi-autoipd" +remove "avahi-libs" +remove "basesystem" +remove "checkpolicy" +remove "chkconfig" +remove "clusterlib" +remove "clutter" +remove "clutter-gesture" +remove "clutter-imcontext" +remove "cman" +remove "control-center-filesystem" +remove "coreutils-libs" +remove "corosync" +remove "corosynclib" +remove "cronie" +remove "cronie-anacron" +remove "crontabs" +remove "cups-libs" +remove "curl" +remove "cyrus-sasl" +remove "cyrus-sasl-md5" +remove "dash" +remove "db4-utils" +remove "dejavu-fonts-common" +remove "deltarpm" +remove "desktop-file-utils" +remove "device-mapper-event" +remove "diffutils" +remove "dmraid-events" +remove "dracut" +remove "fedora-release" +remove "fedora-release-rawhide" +remove "fence-agents" +remove "fence-virt" +remove "file" +remove "filesystem" +remove "fipscheck" +remove "firstaidkit" +remove "firstboot" +remove "flac" +remove "fontpackages-filesystem" +remove "gamin" +remove "genisoimage" +remove "gnome-python2" +remove "gnupg2" +remove "grubby" +remove "gstreamer-tools" +remove "info" +remove "ipmitool" +remove "iptables" +remove "iptables-ipv6" +remove "isomd5sum" +remove "jasper-libs" +remove "json-glib" +remove "kbd-misc" +remove "libIDL" +remove "libXScrnSaver" +remove "libXmu" +remove "libXres" +remove "libXt" +remove "libXv" +remove "libXvMC" +remove "libXxf86misc" +remove "libXxf86vm" +remove "libassuan" +remove "libasyncns" +remove "libccss" +remove "libcgroup" +remove "libcroco" +remove "libdaemon" +remove "libevent" +remove "libhbaapi" +remove "libhbalinux" +remove "libibverbs" +remove "libmcpp" +remove "libmodman" +remove "libmount" +remove "libmx" +remove "libnih" +remove "libpcap" +remove "libproxy" +remove "librdmacm" +remove "librsvg2" +remove "libselinux-utils" +remove "libsndfile" +remove "libsoup" +remove "libtiff" +remove "libusb1" +remove "libutempter" +remove "libvirt-client" +remove "libwnck" +remove "libxslt" +remove "linux-atm-libs" +remove "llvm" +remove "lm_sensors-libs" +remove "logrotate" +remove "lvm2-libs" +remove "m4" +remove "mailx" +remove "makebootfat" +remove "mcpp" +remove "mesa-dri-drivers" +remove "mesa-libGL" +remove "mingetty" +remove "mobile-broadband-provider-info" +remove "modcluster" +remove "mutter-mbl" +remove "mutter-moblin" +remove "nbtk" +remove "nc" +remove "net-snmp-libs" +remove "net-snmp-utils" +remove "netcf-libs" +remove "nfs-utils-lib" +remove "nss-sysinit" +remove "nss-tools" +remove "ntp" +remove "ntpdate" +remove "numactl" +remove "oddjob" +remove "openais" +remove "openaislib" +remove "passwd" +remove "perl" +remove "perl-Module-Pluggable" +remove "perl-Net-Telnet" +remove "perl-Pod-Escapes" +remove "perl-Pod-Simple" +remove "perl-libs" +remove "pexpect" +remove "pinentry" +remove "pkgconfig" +remove "plymouth" +remove "plymouth-core-libs" +remove "plymouth-scripts" +remove "ppp" +remove "pth" +remove "pulseaudio-libs" +remove "redhat-menus" +remove "ricci" +remove "rmt" +remove "rpcbind" +remove "setuptool" +remove "sg3_utils" +remove "sg3_utils-libs" +remove "sgml-common" +remove "sgpio" +remove "shadow-utils" +remove "shared-mime-info" +remove "smc-fonts-common" +remove "sound-theme-freedesktop" +remove "squashfs-tools" +remove "system-config-firewall-base" +remove "system-config-users" +remove "systemd-units" +remove "telnet" +remove "tigervnc-license" +remove "ttmkfdir" +remove "un-core-fonts-common" +remove "usermode" +remove "usermode-gtk" +remove "vlgothic-fonts-common" +remove "which" +remove "xdg-utils" +remove "xen-libs" +remove "xen-licenses" +remove "xml-common" +remove "xorg-x11-font-utils" +remove "xorg-x11-server-common" +remove "xorg-x11-xauth" +remove "xorg-x11-xinit" +remove "yajl" +remove "yum-utils" + +## required modules +module "8021q" +module "=drm" +module "=net" +module "=scsi" +module "aes_generic" +module "appletouch" +module "arc4" +module "bcm5974" +module "btrfs" +module "cbc" +module "cifs" +module "cramfs" +module "crc32c" +module "crypto_blkcipher" +module "dm-crypt" +module "dm-mirror" +module "dm-mod" +module "dm-multipath" +module "dm-round-robin" +module "dm-snapshot" +module "dm-zero" +module "ecb" +module "edd" +module "ehci-hcd" +module "ext2" +module "ext3" +module "ext4" +module "fat" +module "firewire-ohci" +module "firewire-sbp2" +module "floppy" +module "fuse" +module "fw-ohci" +module "fw-sbp2" +module "gfs2" +module "hfsplus" +module "i82365" +module "ide-cd" +module "ide-cd_mod" +module "ipv6" +module "iscsi_ibft" +module "iscsi_tcp" +module "jfs" +module "linear" +module "lockd" +module "loop" +module "lrw" +module "mmc-block" +module "mousedev" +module "msdos" +module "netconsole" +module "nfs" +module "ohci-hcd" +module "ohci1394" +module "pcmcia" +module "pcspkr" +module "raid0" +module "raid1" +module "raid10" +module "raid456" +module "raid5" +module "raid6" +module "reiserfs" +module "sbp2" +module "scsi_mod" +module "scsi_wait_scan" +module "sd_mod" +module "sdhci" +module "sdhci-pci" +module "sg" +module "sha256_generic" +module "squashfs" +module "sr_mod" +module "st" +module "sunrpc" +module "tcic" +module "ub" +module "uhci-hcd" +module "ums-alauda" +module "ums-cypress" +module "ums-datafab" +module "ums-freecom" +module "ums-jumpshot" +module "ums-karma" +module "ums-onetouch" +module "ums-sddr09" +module "ums-sddr55" +module "ums-usbat" +module "usb-storage" +module "usbhid" +module "vfat" +module "virtio_pci" +module "xfs" +module "xts" +module "yenta_socket" + +## other removals +remove --path "/usr/share/doc" +remove --path "/usr/share/info" +remove --path "/usr/share/man" + +remove --path "/boot" +remove --path "/cgroup" +remove --path "/home" +remove --path "/media" +remove --path "/mnt" +remove --path "/opt" +remove --path "/srv" + +remove --path "/var/cache" +remove --path "/var/db" +remove --path "/var/games" +remove --path "/var/local" +remove --path "/var/log" +remove --path "/var/mail" +remove --path "/var/nis" +remove --path "/var/opt" +remove --path "/var/preserve" +remove --path "/var/report" +remove --path "/var/spool" +remove --path "/var/tmp" +remove --path "/var/yp" + +## other package specific removals +remove "ConsoleKit" "/etc/ConsoleKit*" +remove "ConsoleKit" "/etc/init/*" +remove "ConsoleKit" "/lib/systemd/*" +remove "ConsoleKit" "/usr/bin/*" +remove "ConsoleKit" "/usr/lib/*" +remove "ConsoleKit" "/usr/sbin/*" +remove "GConf2" "/etc/rpm/*" +remove "GConf2" "/etc/xdg/*" +remove "GConf2" "/usr/bin/*" +remove "GConf2" "/usr/share/GConf/*" +remove "GConf2" "/usr/share/locale/*" +remove "GConf2" "/usr/share/sgml/*" +remove "ModemManager" "/usr/${libdir}/*" +remove "ModemManager" "/usr/sbin/*" +remove "ModemManager" "/usr/share/icons/*" +remove "NetworkManager" "/etc/rc.d/*" +remove "NetworkManager" "/lib/systemd/*" +remove "NetworkManager" "/usr/bin/*" +remove "NetworkManager" "/usr/share/NetworkManager/*" +remove "NetworkManager-gnome" "/etc/xdg/*" +remove "NetworkManager-gnome" "/usr/${libdir}/*" +remove "NetworkManager-gnome" "/usr/share/applications/*" +remove "anaconda" "/etc/*" +remove "anaconda" "/usr/bin/*" +remove "anaconda" "/usr/share/applications/*" +remove "anaconda" "/usr/share/icons/*" +remove "at-spi" "/etc/xdg/*" +remove "at-spi" "/usr/share/locale/*" +remove "atk" "/usr/share/locale/*" +remove "audit" "/etc/*" +remove "audit" "/usr/bin/*" +remove "audit-libs" "/etc/*" +remove "authconfig" "/usr/sbin/*" +remove "authconfig" "/usr/share/*" +remove "bash" "/etc/*" +remove "bash" "/usr/bin/*" +remove "bash" "/usr/share/*" +remove "bitmap-fangsongti-fonts" "/usr/share/fonts/*" +remove "ca-certificates" "/etc/ssl/*" +remove "cjkuni-uming-fonts" "/etc/X11/*" +remove "coreutils" "/etc/*" +remove "coreutils" "/sbin/*" +remove "coreutils" "/usr/share/*" +remove "cpio" "/usr/share/*" +remove "cracklib" "/usr/sbin/*" +remove "cracklib-dicts" "/usr/${libdir}/*" +remove "cracklib-dicts" "/usr/sbin/*" +remove "createrepo" "/usr/bin/*" +remove "createrepo" "/usr/share/*" +remove "cryptsetup-luks" "/usr/share/*" +remove "cyrus-sasl-lib" "/usr/sbin/*" +remove "db4" "/usr/*" +remove "dbus" "/lib/systemd/*" +remove "dbus-glib" "/usr/bin/*" +remove "dbus-x11" "/etc/X11/*" +remove "dcbd" "/etc/*" +remove "device-mapper-multipath" "/etc/*" +remove "dhclient" "/usr/*" +remove "dmz-cursor-themes" "/usr/share/icons/dmz/*" +remove "dnsmasq" "/etc/rc.d/*" +remove "dnsmasq" "/usr/sbin/*" +remove "dogtail" "/usr/bin/*" +remove "dogtail" "/usr/share/applications/*" +remove "dogtail" "/usr/share/dogtail/*" +remove "dogtail" "/usr/share/icons/*" +remove "dump" "/etc/*" +remove "e2fsprogs" "/usr/sbin/*" +remove "e2fsprogs" "/usr/share/locale/*" +remove "elfutils-libelf" "/usr/share/locale/*" +remove "ethtool" "/usr/sbin/*" +remove "expat" "/usr/bin/*" +remove "fcoe-utils" "/etc/rc.d/*" +remove "fedora-gnome-theme" "/etc/gtk-3.0/*" +remove "fedora-gnome-theme" "/usr/share/themes/*" +remove "fedora-logos" "/etc/*" +remove "fedora-logos" "/usr/share/firstboot/*" +remove "fedora-logos" "/usr/share/gnome-screensaver/*" +remove "fedora-logos" "/usr/share/icons/Bluecurve/*" +remove "fedora-logos" "/usr/share/icons/hicolor/*" +remove "fedora-logos" "/usr/share/icons/oxygen/*" +remove "fedora-logos" "/usr/share/pixmaps/*" +remove "fedora-logos" "/usr/share/plymouth/*" +remove "file-libs" "/usr/share/*" +remove "findutils" "/usr/share/*" +remove "fontconfig" "/usr/bin/*" +remove "gawk" "/usr/bin/*" +remove "gawk" "/usr/libexec/*" +remove "gawk" "/usr/share/*" +remove "gdk-pixbuf2" "/usr/share/locale/*" +remove "generic-logos" "/usr/share/pixmaps/*" +remove "generic-logos" "/usr/share/plymouth/*" +remove "gfs2-utils" "/usr/sbin/*" +remove "glib2" "/etc/*" +remove "glib2" "/usr/bin/*" +remove "glib2" "/usr/share/locale/*" +remove "glibc" "/sbin/*" +remove "glibc" "/usr/libexec/*" +remove "glibc" "/usr/sbin/*" +remove "glibc-common" "/etc/*" +remove "glibc-common" "/usr/libexec/*" +remove "glibc-common" "/usr/share/i18n/*" +remove "gnome-bluetooth-libs" "/usr/share/*" +remove "gnome-keyring" "/etc/xdg/*" +remove "gnome-keyring" "/usr/bin/*" +remove "gnome-keyring" "/usr/${libdir}/*" +remove "gnome-keyring" "/usr/libexec/*" +remove "gnome-keyring" "/usr/share/GConf/*" +remove "gnome-keyring" "/usr/share/gcr-3/*" +remove "gnome-keyring" "/usr/share/glib-2.0/*" +remove "gnome-keyring" "/usr/share/gnome-keyring*" +remove "gnome-keyring" "/usr/share/locale/*" +remove "gnome-python2-gconf" "/usr/share/pygtk/*" +remove "gnome-themes" "/usr/share/icons/Crux/*" +remove "gnome-themes" "/usr/share/icons/HighContrast*" +remove "gnome-themes" "/usr/share/icons/LargePrint/*" +remove "gnome-themes" "/usr/share/locale/*" +remove "gnome-themes" "/usr/share/themes/Crux/*" +remove "gnome-themes" "/usr/share/themes/Glider/*" +remove "gnome-themes" "/usr/share/themes/Glossy/*" +remove "gnome-themes" "/usr/share/themes/HighContrast*" +remove "gnome-themes" "/usr/share/themes/Inverted/*" +remove "gnome-themes" "/usr/share/themes/LargePrint/*" +remove "gnome-themes" "/usr/share/themes/LowContrast*" +remove "gnome-themes" "/usr/share/themes/Mist/*" +remove "gnome-themes" "/usr/share/themes/Simple/*" +remove "gnutls" "/usr/share/locale/*" +remove "grep" "/etc/*" +remove "grep" "/usr/share/locale/*" +remove "groff" "/usr/share/*" +remove "gstreamer" "/usr/bin/*" +remove "gstreamer" "/usr/libexec/*" +remove "gstreamer" "/usr/share/locale/*" +remove "gtk+" "/etc/*" +remove "gtk+" "/usr/share/locale/*" +remove "gtk2" "/usr/share/themes/*" +remove "gtk2-engines" "/usr/share/gtk-engines/*" +remove "gtk2-engines" "/usr/share/locale/*" +remove "gtk2-engines" "/usr/share/themes/Crux/*" +remove "gtk2-engines" "/usr/share/themes/Industrial/*" +remove "gtk2-engines" "/usr/share/themes/Mist/*" +remove "gtk2-engines" "/usr/share/themes/ThinIce/*" +remove "gtk3" "/usr/share/*" +remove "gtk3-engines" "/usr/${libdir}/*" +remove "gtk3-engines" "/usr/share/gtk-engines/*" +remove "gtk3-engines" "/usr/share/locale/*" +remove "gtk3-engines" "/usr/share/themes/Crux/*" +remove "gtk3-engines" "/usr/share/themes/GNOME3/*" +remove "gtk3-engines" "/usr/share/themes/Industrial/*" +remove "gtk3-engines" "/usr/share/themes/Mist/*" +remove "gtk3-engines" "/usr/share/themes/Redmond/*" +remove "gtk3-engines" "/usr/share/themes/ThinIce/*" +remove "gzip" "/usr/bin/*" +remove "initscripts" "/etc/ppp/*" +remove "initscripts" "/lib/systemd/*" +remove "initscripts" "/usr/sbin/*" +remove "initscripts" "/usr/share/locale/*" +remove "iproute" "/etc/*" +remove "iproute" "/usr/*" +remove "iputils" "/etc/*" +remove "iputils" "/usr/sbin/*" +remove "iscsi-initiator-utils" "/etc/rc.d/*" +remove "kbd" "/usr/bin/*" +remove "kbd" "/usr/share/locale/*" +remove "krb5-libs" "/usr/${libdir}/*" +remove "less" "/etc/*" +remove "libbonobo" "/etc/*" +remove "libbonobo" "/usr/bin/*" +remove "libbonobo" "/usr/sbin/*" +remove "libbonobo" "/usr/share/locale/*" +remove "libcanberra" "/usr/${libdir}/libcanberra-*" +remove "libcanberra-gtk2" "/usr/${libdir}/gtk-2.0/*" +remove "libcanberra-gtk3" "/usr/bin/*" +remove "libcanberra-gtk3" "/usr/${libdir}/*" +remove "libcap" "/usr/sbin/*" +remove "libgnome-keyring" "/usr/share/locale/*" +remove "libgnomecanvas" "/usr/share/locale/*" +remove "libgpg-error" "/usr/bin/*" +remove "libgpg-error" "/usr/share/locale/*" +remove "libgssglue" "/etc/*" +remove "libidn" "/usr/bin/*" +remove "libidn" "/usr/share/locale/*" +remove "libjpeg" "/usr/bin/*" +remove "libmlx4" "/etc/rdma/*" +remove "libmlx4" "/usr/${libdir}/*" +remove "libnotify" "/usr/bin/*" +remove "libselinux" "/sbin/*" +remove "libsemanage" "/etc/selinux/*" +remove "libstdc++" "/usr/share/*" +remove "libthai" "/usr/share/libthai/*" +remove "libuser" "/usr/bin/*" +remove "libuser" "/usr/sbin/*" +remove "libuser" "/usr/share/locale/*" +remove "libxcb" "/usr/${libdir}/libxcb-*" +remove "libxml2" "/usr/bin/*" +remove "lldpad" "/etc/*" +remove "lua" "/usr/bin/*" +remove "lvm2" "/etc/*" +remove "man-db" "/etc/sysconfig/*" +remove "man-db" "/usr/bin/*" +remove "man-db" "/usr/libexec/*" +remove "man-db" "/usr/sbin/*" +remove "man-db" "/usr/share/locale/*" +remove "mdadm" "/etc/*" +remove "metacity" "/usr/share/applications/*" +remove "metacity" "/usr/share/gnome-control-center/*" +remove "metacity" "/usr/share/gnome/*" +remove "metacity" "/usr/share/locale/*" +remove "metacity" "/usr/share/metacity/*" +remove "metacity" "/usr/share/themes/AgingGorilla/*" +remove "metacity" "/usr/share/themes/Bright/*" +remove "metacity" "/usr/share/themes/Crux/*" +remove "metacity" "/usr/share/themes/Esco/*" +remove "metacity" "/usr/share/themes/Metabox/*" +remove "metacity" "/usr/share/themes/Simple/*" +remove "module-init-tools" "/etc/*" +remove "mt-st" "/etc/*" +remove "mt-st" "/sbin/*" +remove "mtools" "/etc/*" +remove "nettools" "/bin/*" +remove "nettools" "/etc/*" +remove "nettools" "/usr/share/locale/*" +remove "network-manager-netbook" "/etc/*" +remove "network-manager-netbook" "/usr/libexec/*" +remove "network-manager-netbook" "/usr/share/dbus-1/*" +remove "network-manager-netbook" "/usr/share/locale/*" +remove "network-manager-netbook" "/usr/share/network-manager-netbook/*" +remove "newt" "/usr/share/locale/*" +remove "nfsutils" "/etc/*" +remove "nfsutils" "/usr/sbin/*" +remove "nfsutils" "/var/lib/*" +remove "notification-daemon" "/usr/${libdir}/*" +remove "notification-daemon" "/usr/libexec/*" +remove "notification-daemon" "/usr/share/locale/*" +remove "nss" "/etc/pki/*" +remove "nss-softokn" "/usr/${libdir}/nss/*" +remove "ntfs-3g" "/usr/bin/*" +remove "ntfs-progs" "/sbin/*" +remove "openldap" "/etc/openldap/*" +remove "openssh" "/etc/ssh/*" +remove "openssh" "/usr/libexec/*" +remove "openssh-clients" "/etc/ssh/*" +remove "openssh-clients" "/usr/${libdir}/*" +remove "openssh-clients" "/usr/libexec/*" +remove "openssh-server" "/etc/ssh/*" +remove "openssh-server" "/usr/${libdir}/*" +remove "openssh-server" "/usr/libexec/*" +remove "openssl" "/etc/pki/*" +remove "openssl" "/usr/bin/*" +remove "openssl" "/usr/${libdir}/openssl/*" +remove "pam" "/sbin/*" +remove "pam" "/usr/share/locale/*" +remove "pciutils" "/usr/sbin/*" +remove "pcmciautils" "/sbin/*" +remove "pcre" "/usr/bin/*" +remove "pcre" "/usr/${libdir}/*" +remove "policycoreutils" "/etc/*" +remove "policycoreutils" "/usr/bin/*" +remove "policycoreutils" "/usr/share/locale/*" +remove "polkit" "/usr/bin/*" +remove "polkit-desktop-policy" "/var/lib/*" +remove "popt" "/usr/share/locale/*" +remove "procps" "/sbin/*" +remove "psmisc" "/sbin/*" +remove "psmisc" "/usr/share/locale/*" +remove "pygtk2" "/usr/bin/*" +remove "pygtk2" "/usr/${libdir}/pygtk/*" +remove "pykickstart" "/usr/bin/*" +remove "pykickstart" "/usr/share/locale/*" +remove "python-bugzilla" "/usr/bin/*" +remove "python-ethtool" "/usr/sbin/*" +remove "python-meh" "/usr/share/locale/*" +remove "readline" "/usr/${libdir}/*" +remove "report" "/usr/bin/*" +remove "report" "/usr/include/*" +remove "report" "/usr/${libdir}/libstrata_*" +remove "report" "/usr/share/locale/*" +remove "rpm" "/usr/bin/*" +remove "rpm" "/usr/lib/rpm/platform/*" +remove "rpm" "/usr/share/locale/*" +remove "rsync" "/etc/*" +remove "samba-common" "/etc/*" +remove "samba-common" "/usr/bin/*" +remove "samba-common" "/usr/include/*" +remove "samba-common" "/usr/${libdir}/*" +remove "samba-common" "/usr/share/locale/*" +remove "sed" "/usr/share/locale/*" +remove "selinux-policy-targeted" "/usr/share/selinux/*" +remove "smartmontools" "/etc/*" +remove "smartmontools" "/usr/share/smartmontools/*" +remove "sqlite" "/usr/bin/*" +remove "system-config-date" "/etc/*" +remove "system-config-date" "/usr/bin/*" +remove "system-config-date" "/usr/share/icons/*" +remove "system-config-keyboard" "/etc/*" +remove "system-config-keyboard" "/usr/bin/*" +remove "system-config-keyboard" "/usr/share/icons/*" +remove "systemd" "/bin/*" +remove "systemd" "/lib/systemd/*" +remove "systemd" "/usr/share/systemd/*" +remove "sysvinit-tools" "/bin/*" +remove "sysvinit-tools" "/usr/bin/*" +remove "tar" "/usr/share/locale/*" +remove "usbutils" "/usr/bin/*" +remove "util-linux-ng" "/usr/share/locale/*" +remove "volume_key-libs" "/usr/share/locale/*" +remove "wget" "/etc/*" +remove "wget" "/usr/share/locale/*" +remove "xfsprogs" "/${libdir}/*" +remove "xfsprogs" "/usr/share/locale/*" +remove "xkeyboard-config" "/usr/share/locale/*" +remove "xorg-x11-drv-intel" "/usr/${libdir}/libI*" +remove "xorg-x11-drv-openchrome" "/usr/${libdir}/libchrome*" +remove "xorg-x11-drv-synaptics" "/usr/bin/*" +remove "xorg-x11-drv-vmmouse" "/usr/bin/*" +remove "xorg-x11-drv-wacom" "/usr/bin/*" +remove "xorg-x11-fonts-ethiopic" "/etc/X11/*" +remove "xorg-x11-fonts-misc" "/etc/X11/*" +remove "xorg-x11-fonts-misc" "/usr/share/X11/fonts/encodings/*" +remove "yum" "etc/*" +remove "yum" "/usr/share/locale/*" +remove "yum" "/usr/share/yum-cli/*" +remove "zenity" "/usr/share/gnome/help/*" +remove "zenity" "/usr/share/omf/*" diff --git a/share/lorax-s2.ltmpl b/share/lorax-s2.ltmpl new file mode 100644 index 00000000..3f66ee9b --- /dev/null +++ b/share/lorax-s2.ltmpl @@ -0,0 +1,3 @@ +## locales.img template file + +move "/usr/share/locale" diff --git a/src/bin/lorax b/src/bin/lorax old mode 100644 new mode 100755 index 4962e713..a4ff3cd0 --- a/src/bin/lorax +++ b/src/bin/lorax @@ -27,15 +27,15 @@ import sys import os import tempfile from optparse import OptionParser, OptionGroup +import ConfigParser +import yum import pylorax -import pylorax.config -from pylorax.yumbase import get_yum_base_object def main(args): version = "{0} 0.1".format(os.path.basename(args[0])) - usage = "%prog -p PRODUCT -v VERSION -r RELEASE -o OUTPUTDIR REPOSITORY" + usage = "%prog -p PRODUCT -v VERSION -r RELEASE -s REPOSITORY OUTPUTDIR" parser = OptionParser(usage=usage) @@ -47,8 +47,9 @@ def main(args): metavar="STRING") required.add_option("-r", "--release", help="release information", metavar="STRING") - required.add_option("-o", "--outputdir", help="output directory", - metavar="PATHSPEC") + required.add_option("-s", "--source", + help="source repository (may be listed multibple times)", + metavar="REPOSITORY", action="append", default=[]) # optional arguments optional = OptionGroup(parser, "optional arguments") @@ -60,30 +61,10 @@ def main(args): optional.add_option("-b", "--bugurl", help="bug reporting URL for the product", metavar="URL", default="your distribution provided bug reporting tool") - optional.add_option("-u", "--updates", - help="directory containing updates", metavar="PATHSPEC") - - # output settings - output = OptionGroup(parser, "output settings") - output.add_option("--no-colors", help="disable color output", - action="store_false", default=True, dest="colors") - output.add_option("--encoding", help="set encoding", - metavar="STRING", default="utf-8") - output.add_option("-d", "--debug", help="enable debugging messages", - action="store_true", default=False) - - # lorax settings - settings = OptionGroup(parser, "lorax settings") - settings.add_option("--pedantic", help="don't ignore copy errors", - action="store_true", default=False) - settings.add_option("-c", "--cleanup", help="clean up on exit", - action="store_true", default=False) # add the option groups to the parser parser.add_option_group(required) parser.add_option_group(optional) - parser.add_option_group(output) - parser.add_option_group(settings) # add the show version option parser.add_option("-V", help="show program's version number and exit", @@ -91,7 +72,7 @@ def main(args): # parse the arguments opts, args = parser.parse_args() - repositories = args + outputdir = args[0] if opts.showver: print(version) @@ -99,7 +80,7 @@ def main(args): # check for the required arguments if not opts.product or not opts.version or not opts.release \ - or not opts.outputdir or not repositories: + or not opts.source or not outputdir: parser.error("missing one or more required arguments") # create the temporary directory for lorax @@ -111,7 +92,7 @@ def main(args): yumtempdir = os.path.join(tempdir, "yum") os.mkdir(yumtempdir) - yb = get_yum_base_object(installtree, repositories, opts.mirrorlist, + yb = get_yum_base_object(installtree, opts.source, opts.mirrorlist, yumtempdir) if yb is None: @@ -119,27 +100,94 @@ def main(args): shutil.rmtree(tempdir) sys.exit(1) - # configure lorax - config = pylorax.config.LoraxConfig() - config.colors = opts.colors - config.encoding = opts.encoding - config.debug = opts.debug - - config.pedantic = opts.pedantic - # run lorax - params = {"installtree": installtree, - "outputdir": opts.outputdir, - "product": opts.product, - "version": opts.version, - "release": opts.release, - "workdir": tempdir, - "variant": opts.variant, - "bugurl": opts.bugurl, - "updatesdir": opts.updates} + lorax = pylorax.Lorax() + lorax.configure() + lorax.run(yb, opts.product, opts.version, opts.release, + opts.variant, opts.bugurl, + workdir=tempdir, outputdir=outputdir) - lorax = pylorax.Lorax(yb, **params) - lorax.run() + +def get_yum_base_object(installroot, repositories, mirrorlists=[], + tempdir="/tmp"): + + def sanitize_repo(repo): + if repo.startswith("/"): + return "file://{0}".format(repo) + elif (repo.startswith("http://") or repo.startswith("ftp://") + or repo.startswith("file://")): + return repo + else: + return None + + # sanitize the repositories + repositories = map(sanitize_repo, repositories) + mirrorlists = map(sanitize_repo, mirrorlists) + + # remove invalid repositories + repositories = filter(bool, repositories) + mirrorlists = filter(bool, mirrorlists) + + #cachedir = os.path.join(tempdir, "yum.cache") + #if not os.path.isdir(cachedir): + # os.mkdir(cachedir) + + yumconf = os.path.join(tempdir, "yum.conf") + c = ConfigParser.ConfigParser() + + # add the main section + section = "main" + data = {#"cachedir": cachedir, + #"keepcache": 0, + "gpgcheck": 0, + "plugins": 0, + "reposdir": "", + "tsflags": "nodocs"} + + c.add_section(section) + map(lambda (key, value): c.set(section, key, value), data.items()) + + # add the main repository - the first repository from list + section = "lorax-repo" + data = {"name": "lorax repo", + "baseurl": repositories[0], + "enabled": 1} + + c.add_section(section) + map(lambda (key, value): c.set(section, key, value), data.items()) + + # add the extra repositories + for n, extra in enumerate(repositories[1:], start=1): + section = "lorax-extra-repo-{0:d}".format(n) + data = {"name": "lorax extra repo {0:d}".format(n), + "baseurl": extra, + "enabled": 1} + + c.add_section(section) + map(lambda (key, value): c.set(section, key, value), data.items()) + + # add the mirrorlists + for n, mirror in enumerate(mirrorlists, start=1): + section = "lorax-mirrorlist-{0:d}".format(n) + data = {"name": "lorax mirrorlist {0:d}".format(n), + "mirrorlist": mirror, + "enabled": 1 } + + c.add_section(section) + map(lambda (key, value): c.set(section, key, value), data.items()) + + # write the yum configuration file + with open(yumconf, "w") as f: + c.write(f) + + # create the yum base object + yb = yum.YumBase() + + yb.preconf.fn = yumconf + yb.preconf.root = installroot + #yb.repos.setCacheDir(cachedir) + + return yb if __name__ == "__main__": diff --git a/src/pylorax/__init__.py b/src/pylorax/__init__.py index ebfbf2e6..d0ffb04c 100644 --- a/src/pylorax/__init__.py +++ b/src/pylorax/__init__.py @@ -1,7 +1,7 @@ # # __init__.py # -# Copyright (C) 2009 Red Hat, Inc. +# Copyright (C) 2010 Red Hat, Inc. # # 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 @@ -20,401 +20,1050 @@ # David Cantrell # +# set up logging +import logging +logging.basicConfig(level=logging.DEBUG, filename="pylorax.log", filemode="w") + +sh = logging.StreamHandler() +sh.setLevel(logging.INFO) +logging.getLogger("").addHandler(sh) + +logger = logging.getLogger("pylorax") + + import sys import os import ConfigParser +import tempfile +import shutil +import gzip +import shlex +import fnmatch +import re +import itertools import glob import time import datetime -import shutil +import itertools +import subprocess +import operator +import math -import yum -import yum.callbacks -import yum.rpmtrans +from collections import namedtuple from base import BaseLoraxClass import output -import insttree -import images +import yum +import yumhelper +import ltmpl + +import constants from sysutils import * -# set up logging to file -import logging -LOG_FILENAME = "pylorax.log" -logging.basicConfig(level=logging.DEBUG, filename=LOG_FILENAME, filemode="w") - -# add the console handler -console = logging.StreamHandler() -console.setLevel(logging.INFO) -logging.getLogger("").addHandler(console) - -# get the logger -logger = logging.getLogger("pylorax") - - -# basearch efiarch 64bit -ARCHMAP = {"i386": ["i386", "IA32", False], - "i586": ["i386", "IA32", False], - "i686": ["i386", "IA32", False], - "x86_64": ["x86_64", "X64", True], - "ppc": ["ppc", "", False], - "ppc64": ["ppc", "", True], - "s390": ["s390", "", False], - "s390x": ["s390x", "", True], - "sparc": ["sparc", "", False], - "sparc64": ["sparc", "", True], - "ia64": ["ia64", "IA64", True]} +ARCHMAPS = { + "i386": {"base": "i386", "efi": "IA32", "is64": False}, + "i586": {"base": "i386", "efi": "IA32", "is64": False}, + "i686": {"base": "i386", "efi": "IA32", "is64": False}, + "x86_64": {"base": "x86_64", "efi": "X64", "is64": True}, + "ppc": {"base": "ppc", "efi": "", "is64": False}, + "ppc64": {"base": "ppc", "efi": "", "is64": True}, + "s390": {"base": "s390", "efi": "", "is64": False}, + "s390x": {"base": "s390x", "efi": "", "is64": True}, + "sparc": {"base": "sparc", "efi": "", "is64": False}, + "sparc64": {"base": "sparc", "efi": "", "is64": True}, + "ia64": {"base": "ia64", "efi": "IA64", "is64": True} + } LIB32 = "lib" LIB64 = "lib64" +# kernel types +K_NORMAL = 0 +K_PAE = 1 +K_XEN = 1 + + +# XXX kernel tuple +Kernel = namedtuple("Kernel", "fname fpath version type") + + class Lorax(BaseLoraxClass): - def __init__(self, yb, installtree, outputdir, - product, version, release, - workdir="/tmp", variant="", bugurl="", updatesdir=None): - + def __init__(self): BaseLoraxClass.__init__(self) + self._configured = False - # XXX do we have root privileges? - if not os.geteuid() == self.const.ROOT_UID: + def configure(self, conf_file="/etc/lorax/lorax.conf"): + self.conf = ConfigParser.SafeConfigParser() + + # set defaults + self.conf.add_section("lorax") + self.conf.set("lorax", "debug", "1") + self.conf.set("lorax", "sharedir", "/usr/share/lorax") + + self.conf.add_section("output") + self.conf.set("output", "colors", "1") + self.conf.set("output", "encoding", "utf-8") + self.conf.set("output", "ignorelist", "/usr/share/lorax/ignorelist") + + self.conf.add_section("templates") + self.conf.set("templates", "stage1", "lorax-s1.ltmpl") + self.conf.set("templates", "stage2", "lorax-s2.ltmpl") + + # read the config file + if os.path.isfile(conf_file): + self.conf.read(conf_file) + + # set up the output + debug = self.conf.getboolean("lorax", "debug") + output_level = output.DEBUG if debug else output.INFO + + colors = self.conf.getboolean("output", "colors") + encoding = self.conf.get("output", "encoding") + + self.output.basic_config(output_level=output_level, + colors=colors, encoding=encoding) + + ignorelist = self.conf.get("output", "ignorelist") + if os.path.isfile(ignorelist): + with open(ignorelist, "r") as fobj: + for line in fobj: + line = line.strip() + if line and not line.startswith("#"): + self.output.ignore(line) + + self._configured = True + + def run(self, yb, product, version, release, variant="", bugurl="", + workdir=None, outputdir=None): + + # XXX + assert self._configured + + # do we have root privileges? + logger.info("checking for root privileges") + if not os.geteuid() == 0: logger.critical("no root privileges") sys.exit(1) - # XXX do we have a proper yum base object? + # XXX do we have all lorax required commands? + self.lcmds = constants.LoraxRequiredCommands() + missing = self.lcmds.get_missing() + if missing: + logger.critical("missing required command: {0}".format(missing)) + sys.exit(1) + + # do we have a proper yum base object? + logger.info("checking yum base object") if not isinstance(yb, yum.YumBase): logger.critical("no yum base object") sys.exit(1) - # set up yum and the install tree - self.yum = YumHelper(yb) - self.installtree = insttree.InstallTree(yum=self.yum, - rootdir=installtree, - updatesdir=updatesdir) + # set up yum helper + logger.info("setting up yum helper") + self.yum = yumhelper.LoraxYumHelper(yb) + logger.debug("using install root: {0}".format(self.yum.installroot)) - # create the output directory - self.outputdir = outputdir - makedirs_(self.outputdir) - logger.debug("using output directory {0}".format(self.outputdir)) + # set up build architecture + logger.info("setting up build architecture") + self.buildarch = self.get_buildarch() + archmap = ARCHMAPS.get(self.buildarch) - # create the working directory - self.workdir = workdir - makedirs_(self.workdir) - logger.debug("using working directory {0}".format(self.workdir)) + # XXX + assert archmap is not None - # required parameters + self.basearch = archmap.get("base") + self.efiarch = archmap.get("efi") + self.libdir = LIB64 if archmap.get("is64") else LIB32 + + logger.debug("set buildarch = {0.buildarch}".format(self)) + logger.debug("set basearch = {0.basearch}".format(self)) + logger.debug("set efiarch = {0.efiarch}".format(self)) + logger.debug("set libdir = {0.libdir}".format(self)) + + # set up install tree + logger.info("setting up install tree") + self.installtree = LoraxInstallTree(self.yum, self.basearch) + + # set up required build parameters + logger.info("setting up build parameters") self.product = product self.version = version self.release = release - logger.debug("set product = {0}".format(self.product)) - logger.debug("set version = {0}".format(self.version)) - logger.debug("set release = {0}".format(self.release)) + logger.debug("set product = {0.product}".format(self)) + logger.debug("set version = {0.version}".format(self)) + logger.debug("set release = {0.release}".format(self)) - # optional parameters + # set up optional build parameters self.variant = variant self.bugurl = bugurl - logger.debug("set variant = {0}".format(self.variant)) - logger.debug("set bugurl = {0}".format(self.bugurl)) + logger.debug("set variant = {0.variant}".format(self)) + logger.debug("set bugurl = {0.bugurl}".format(self)) - # set up the output - output_level = output.INFO - if self.conf.debug: - output_level = output.DEBUG + # XXX set up work directory + logger.info("setting up work directory") + self.workdir = workdir or tempfile.mkdtemp(prefix="pylorax.work.") + if not os.path.isdir(self.workdir): + os.makedirs(self.workdir) + logger.debug("using work directory {0.workdir}".format(self)) - self.output.basic_config(colors=self.conf.colors, - encoding=self.conf.encoding, - output_level=output_level) + # parse the template + logger.info("parsing the template") + stage1 = joinpaths(self.conf.get("lorax", "sharedir"), + self.conf.get("templates", "stage1")) - # read which output messages to ignore - ignore_errors = set() - if os.path.isfile(self.conf.ignore_errors): - with open(self.conf.ignore_errors, "r") as f: - for line in f: - line = line.strip() - if line and not line.startswith("#"): - ignore_errors.add(line) + vars = { "basearch": self.basearch, + "libdir" : self.libdir, + "product": self.product.lower() } - self.output.ignore = ignore_errors + template = ltmpl.LoraxTemplate() + template = template.parse(stage1, vars) - def run(self): - # check if we have all required commands - for cmd in self.cmd.values(): - if not os.path.isfile(cmd): - err = "required command {0} does not exist" - self.pwarning(err.format(cmd)) + # get list of required packages + logger.info("getting list of required packages") + required = [f[1:] for f in template if f[0] == "install"] + required = itertools.chain.from_iterable(required) - # set the build architecture - self.pinfo(":: setting the build architecture") - self.conf.buildarch = self.get_buildarch() - basearch, efiarch, is64 = ARCHMAP[self.conf.buildarch] + # install packages + for package in required: + self.installtree.yum.install(package) + self.installtree.yum.process_transaction() - self.conf.basearch = basearch - self.conf.efiarch = efiarch + # write buildstamp + self.write_buildstamp(path=self.installtree.root) - # set the libdir - self.conf.libdir = LIB32 - if is64: - self.conf.libdir = LIB64 - # read the configuration files - self.pinfo(":: reading the configuration files") - c = self.get_config() - packages, modules, initrd_template, install_template = c - # add the branding - packages.add("{0}-logos".format(self.product.lower())) - packages.add("{0}-release".format(self.product.lower())) + # remove locales + logger.info("removing locales") + self.installtree.remove_locales() - # prepare the install tree - self.pinfo(":: preparing the install tree") - self.installtree.install_packages(packages=packages) + # create keymaps + logger.info("creating keymaps") + self.installtree.create_keymaps() + + # create screenfont + logger.info("creating screenfont") + self.installtree.create_screenfont() + + # move stubs + logger.info("moving stubs") + self.installtree.move_stubs() + + # cleanup python files + logger.info("cleaning up python files") + self.installtree.cleanup_python_files() + + # get the list of required modules + logger.info("getting list of required modules") + modules = [f[1:] for f in template if f[0] == "module"] + modules = itertools.chain.from_iterable(modules) + + for kernel in self.installtree.kernels: + logger.info("cleaning up kernel modules") + self.installtree.cleanup_kernel_modules(modules, kernel) + + logger.info("compressing modules") + self.installtree.compress_modules(kernel) + + logger.info("running depmod") + self.installtree.run_depmod(kernel) + + # set up output tree + logger.info("setting up output tree") + self.outputdir = outputdir or tempfile.mkdtemp(prefix="pylorax.out.") + if not os.path.isdir(self.outputdir): + os.makedirs(self.outputdir) + logger.debug("using output directory {0.outputdir}".format(self)) + + self.outputtree = LoraxOutputTree(self.outputdir, self.installtree, + self.product, self.version) + + self.outputtree.prepare() + self.outputtree.get_kernels() + self.outputtree.get_isolinux() + self.outputtree.get_msg_files() + self.outputtree.get_grub_conf() + + # write the .discinfo + self.write_discinfo(self.outputtree.root) + + ## create the install.img + #logger.info("creating install image") + #stage2 = joinpaths(self.conf.get("lorax", "sharedir"), + # self.conf.get("templates", "stage2")) + # + #vars = { "basearch": self.basearch, + # "product": self.product.lower() } + # + #template = ltmpl.LoraxTemplate() + #template = template.parse(stage2, vars) + # + ## get list of required paths + #logger.info("getting list of required paths") + #required = [f[1:] for f in template if f[0] == "move"] + #required = itertools.chain.from_iterable(required) + # + #installimg = self.installtree.create_install_img(required, + # workdir=self.workdir) + # + #if installimg is None: + # logger.critical("unable to create install image") + # sys.exit(1) + # + ## copy the install.img to imgdir + #shutil.copy2(installimg, self.outputtree.imgdir) # XXX - if not os.path.isdir("/tmp/pkglists"): - os.makedirs("/tmp/pkglists") + grubefi = joinpaths(self.installtree.root, "boot/efi/EFI/redhat", + "grub.efi") - for pkgobj in self.installtree.yum.installed_packages.values(): - with open("/tmp/pkglists/%s" % pkgobj.name, "w") as f: - for filename in pkgobj.filelist: - f.write("%s\n" % filename) + if os.path.isfile(grubefi): + shutil.move(grubefi, self.workdir) + grubefi = joinpaths(self.workdir, os.path.basename(grubefi)) + else: + grubefi = None - self.installtree.run_ldconfig() - self.installtree.copy_updates() - self.installtree.fix_problems() + splash = joinpaths(self.installtree.root, "boot/grub/", + "splash.xpm.gz") - # check the anaconda runtime directory - anarun = os.path.join(self.installtree.rootdir, - self.const.ANACONDA_RUNTIME) + shutil.move(splash, self.workdir) + splash = joinpaths(self.workdir, os.path.basename(splash)) - if not os.path.isdir(anarun): - self.pcritical("no anaconda runtime directory found") - sys.exit(1) - - # prepare the output directory - self.pinfo(":: preparing the output directory") - ok = self.prepare_outputdir() - if not ok: - self.pcritical("unable to prepare the output directory") - sys.exit(1) - - # write the treeinfo, discinfo and buildstamp - self.pinfo(":: creating the treeinfo, discinfo and buildstamp") - self.conf.treeinfo = self.write_treeinfo() - self.conf.discinfo = self.write_discinfo() - self.conf.buildstamp = self.write_buildstamp() - - # create the initrd images for all kernels in install tree - initrd = images.InitRD(self.installtree, modules, initrd_template, - self.workdir) - - # get all kernels and initrds - kernel_normal, kernel_pae, kernel_xen = [], [], [] - for kernel, initrd in initrd.create(): - if kernel.is_pae: - kernel_pae.append((kernel, initrd)) - elif kernel.is_xen: - kernel_xen.append((kernel, initrd)) - else: - kernel_normal.append((kernel, initrd)) - - # if we have a normal kernel, set it as the main kernel kernels = [] - try: - kernels.append(kernel_normal.pop(0)) - except IndexError: - pass + for kernel in self.installtree.kernels: + shutil.move(kernel.fpath, self.workdir) + kernels.append(Kernel(kernel.fname, + joinpaths(self.workdir, kernel.fname), + kernel.version, + kernel.type)) - # add pae and xen kernels to the list of kernels - kernels.extend(kernel_pae) - kernels.extend(kernel_xen) + # get list of not required packages + logger.info("getting list of not required packages") + remove = [f[1:] for f in template if f[0] == "remove"] - # check if we have at least one kernel - if not kernels: - self.pcritical("no kernel images found") + rdb = {} + order = [] + for item in remove: + package = None + pattern = None + + if item[0] == "--path": + # remove files + package = None + pattern = item[1] + else: + # remove package + package = item[0] + + try: + pattern = item[1] + except IndexError: + pattern = None + + if package not in rdb: + rdb[package] = [pattern] + order.append(package) + elif pattern not in rdb[package]: + rdb[package].append(pattern) + + for package in order: + pattern_list = rdb[package] + logger.debug("{0}\t{1}".format(package, pattern_list)) + self.installtree.yum.remove(package, pattern_list) + + # compress install tree + InitRD = namedtuple("InitRD", "fname fpath") + initrd = InitRD("initrd.img", joinpaths(self.workdir, "initrd.img")) + + logger.info("compressing install tree") + ok, elapsed = self.installtree.compress(initrd) + if not ok: + logger.error("error while compressing install tree") + else: + logger.info("took {0:.2f} seconds".format(elapsed)) + + # XXX copy initrd to isolinuxdir and pxebootdir + shutil.copy2(initrd.fpath, self.outputtree.isolinuxdir) + shutil.copy2(initrd.fpath, self.outputtree.pxebootdir) + + # create efi images + efiboot = None + if grubefi: + kernel = kernels[0] + + # create efiboot image with kernel + logger.info("creating efiboot image with kernel") + efiboot = self.create_efiboot(kernel, initrd, grubefi, splash, + include_kernel=True) + + if efiboot is None: + logger.critical("unable to create efiboot image") + sys.exit(1) + + # create efidisk image + logger.info("creating efidisk image") + efidisk = self.create_efidisk(efiboot) + if efidisk is None: + logger.critical("unable to create efidisk image") + sys.exit(1) + + # remove efiboot image with kernel + os.unlink(efiboot) + + # create efiboot image without kernel + logger.info("creating efiboot image without kernel") + efiboot = self.create_efiboot(kernel, initrd, grubefi, splash, + include_kernel=False) + + if efiboot is None: + logger.critical("unable to create efiboot image") + sys.exit(1) + + # XXX copy efiboot and efidisk to imgdir + shutil.copy2(efiboot, self.outputtree.imgdir) + shutil.copy2(efidisk, self.outputtree.imgdir) + + # create boot iso + logger.info("creating boot iso") + bootiso = self.create_bootiso(self.outputtree, efiboot) + if bootiso is None: + logger.critical("unable to create boot iso") sys.exit(1) - # main kernel - kernel, initrd = kernels.pop(0) - kernelfile = "vmlinuz" - initrdfile = "initrd.img" - - # add images section to treeinfo - section = "images-{0}".format(self.conf.basearch) - data = {"kernel": "images/pxeboot/{0}".format(kernelfile), - "initrd": "images/pxeboot/{0}".format(initrdfile)} - self.treeinfo_add_section(self.conf.treeinfo, section, data) - - if self.conf.basearch == "i386": - # add the xen section for x86 - section = "images-xen" - data = {"kernel": "images/pxeboot/{0}".format(kernelfile), - "initrd": "images/pxeboot/{0}".format(initrdfile)} - self.treeinfo_add_section(self.conf.treeinfo, section, data) - - # copy the kernel and initrd image to the isolinux directory - kdst = os.path.join(self.conf.isodir, kernelfile) - idst = os.path.join(self.conf.isodir, initrdfile) - shutil.copy2(kernel.path, kdst) - shutil.copy2(initrd, idst) - - # copy the kernel and initrd image to the pxe directory - kdst = os.path.join(self.conf.pxedir, kernelfile) - idst = os.path.join(self.conf.pxedir, initrdfile) - shutil.copy2(kernel.path, kdst) - shutil.copy2(initrd, idst) - - # create the efi images - if self.installtree.do_efi: - efi = images.EFI(self.installtree, kernel, initrd, - self.product, self.version, self.workdir) - - efiboot, efidisk = efi.create() - - # copy the efi images to the images directory - shutil.copy2(efiboot, self.conf.imgdir) - shutil.copy2(efidisk, self.conf.imgdir) - - # other kernels - for kernel, initrd in kernels: - if kernel.is_pae: - kernelfile = "vmlinuz-PAE" - initrdfile = "initrd-PAE.img" - # XXX add images section to treeinfo - section = "images-xen" - data = {"kernel": "images/pxeboot/{0}".format(kernelfile), - "initrd": "images/pxeboot/{0}".format(initrdfile)} - self.treeinfo_add_section(self.conf.treeinfo, section, data) - elif kernel.is_xen: - kernelfile = "vmlinuz-xen" - initrdfile = "initrd-xen.img" - # XXX add images section to treeinfo - section = "images-xen" - data = {"kernel": "images/pxeboot/{0}".format(kernelfile), - "initrd": "images/pxeboot/{0}".format(initrdfile)} - self.treeinfo_add_section(self.conf.treeinfo, section, data) - - # copy the kernel and initrd image to the pxe directory - kdst = os.path.join(self.conf.pxedir, kernelfile) - idst = os.path.join(self.conf.pxedir, initrdfile) - shutil.copy2(kernel.path, kdst) - shutil.copy2(initrd, idst) - - # create the install image - install = images.Install(self.installtree, install_template, - self.workdir) - - installimg = install.create() - if not installimg: - self.perror("unable to create the install image") - sys.exit(1) - - # add stage2 section to the treeinfo - section = "stage2" - data = {"mainimage": "images/install.img"} - self.treeinfo_add_section(self.conf.treeinfo, section, data) - - # move the install image to the images directory - dst = os.path.join(self.conf.imgdir, os.path.basename(installimg)) - if os.path.isfile(dst): - os.unlink(dst) - - shutil.move(installimg, self.conf.imgdir) - - # create the boot iso image - boot = images.Boot(self.product, self.workdir) - bootiso = boot.create() - - # add boot iso to the images section in treeinfo - section = "images-{0}".format(self.conf.basearch) - data = {"boot.iso": "images/boot.iso"} - self.treeinfo_add_section(self.conf.treeinfo, section, data) - - # move the boot iso to the images directory - dst = os.path.join(self.conf.imgdir, os.path.basename(bootiso)) - if os.path.isfile(dst): - os.unlink(dst) - - shutil.move(bootiso, self.conf.imgdir) - - # copy the treeinfo and discinfo to the output directory - shutil.copy2(self.conf.treeinfo, self.outputdir) - shutil.copy2(self.conf.discinfo, self.outputdir) - - # cleanup - self.cleanup() + shutil.move(bootiso, self.outputtree.imgdir) def get_buildarch(self): - # get the architecture of the anaconda package - installed, available = self.yum.search(self.const.ANACONDA_PACKAGE) + # get architecture of the available anaconda package + installed, available = self.yum.search("anaconda") - if installed: - anaconda = installed[0] if available: anaconda = available[0] - - try: buildarch = anaconda.arch - except: + else: # fallback to the system architecture - self.pwarning("using system architecture") + logger.warning("using system architecture") buildarch = os.uname()[4] return buildarch - def get_config(self): - generic = os.path.join(self.conf.confdir, "config.noarch") - specific = os.path.join(self.conf.confdir, - "config.{0}".format(self.conf.basearch)) + def write_buildstamp(self, path): + outfile = joinpaths(path, ".buildstamp") - packages, modules = set(), set() - initrd_template, install_template = None, None + now = datetime.datetime.now() + now = now.strftime("%Y%m%d%H%M") + uuid = "{0}.{1.buildarch}".format(now, self) - for f in (generic, specific): - if not os.path.isfile(f): - continue + with open(outfile, "w") as fobj: + fobj.write("{0}\n".format(uuid)) + fobj.write("{0.product}\n".format(self)) + fobj.write("{0.version}\n".format(self)) + fobj.write("{0.bugurl}\n".format(self)) - c = ConfigParser.ConfigParser() - c.read(f) + return outfile - if c.has_option("lorax", "packages"): - list = c.get("lorax", "packages").split() - for name in list: - if name.startswith("-"): - packages.discard(name) + def write_discinfo(self, path, discnum="ALL"): + outfile = joinpaths(path, ".discinfo") + + with open(outfile, "w") as fobj: + fobj.write("{0:f}\n".format(time.time())) + fobj.write("{0.release}\n".format(self)) + fobj.write("{0.basearch}\n".format(self)) + fobj.write("{0}\n".format(discnum)) + + return outfile + + def create_efiboot(self, kernel, initrd, grubefi, splash, + include_kernel=True): + + # create the efi tree directory + efitree = tempfile.mkdtemp(prefix="efitree.", dir=self.workdir) + + # copy kernel and initrd files to efi tree directory + if include_kernel: + shutil.copy2(kernel.fpath, efitree) + shutil.copy2(initrd.fpath, efitree) + efikernelpath = "/EFI/BOOT/{0}".format(kernel.fname) + efiinitrdpath = "/EFI/BOOT/{0}".format(initrd.fname) + else: + efikernelpath = "/images/pxeboot/{0}".format(kernel.fname) + efiinitrdpath = "/images/pxeboot/{0}".format(initrd.fname) + + efisplashpath = "/EFI/BOOT/splash.xpm.gz" + + # copy conf files to efi tree directory + src = joinpaths(self.installtree.root, "usr/share/anaconda/boot", + "*.conf") + + for fname in glob.glob(src): + shutil.copy2(fname, efitree) + + # edit the grub.conf file + grubconf = joinpaths(efitree, "grub.conf") + replace(grubconf, "@PRODUCT@", self.product) + replace(grubconf, "@VERSION@", self.version) + replace(grubconf, "@KERNELPATH@", efikernelpath) + replace(grubconf, "@INITRDPATH@", efiinitrdpath) + replace(grubconf, "@SPLASHPATH@", efisplashpath) + + if self.efiarch == "IA32": + shutil.copy2(grubconf, joinpaths(efitree, "BOOT.conf")) + + dst = joinpaths(efitree, "BOOT{0}.conf".format(self.efiarch)) + shutil.move(grubconf, dst) + + # copy grub.efi + if self.efiarch == "IA32": + shutil.copy2(grubefi, joinpaths(efitree, "BOOT.efi")) + + dst = joinpaths(efitree, "BOOT{0}.efi".format(self.efiarch)) + shutil.copy2(grubefi, dst) + + # copy splash.xpm.gz + shutil.copy2(splash, efitree) + + efiboot = joinpaths(self.workdir, "efiboot.img") + if os.path.isfile(efiboot): + os.unlink(efiboot) + + # XXX calculate the size of the efi tree directory + overhead = 512 * 1024 + + sizeinbytes = overhead + for root, dnames, fnames in os.walk(efitree): + for fname in fnames: + fpath = joinpaths(root, fname) + fsize = os.path.getsize(fpath) + + # round to multiplications of 4096 + fsize = math.ceil(fsize / 4096.0) * 4096 + sizeinbytes += fsize + + # mkdosfs needs the size in blocks of 1024 bytes + size = int(math.ceil(sizeinbytes / 1024.0)) + + cmd = [self.lcmds.MKDOSFS, "-n", "ANACONDA", "-C", efiboot, str(size)] + logger.debug(cmd) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + p.wait() + + # mount the efiboot image + efibootdir = tempfile.mkdtemp(prefix="efiboot.", dir=self.workdir) + + cmd = [self.lcmds.MOUNT, "-o", "loop,shortname=winnt,umask=0777", + "-t", "vfat", efiboot, efibootdir] + logger.debug(cmd) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + p.wait() + + # copy the files to the efiboot image + dst = joinpaths(efibootdir, "EFI/BOOT") + os.makedirs(dst) + + for fname in os.listdir(efitree): + fpath = joinpaths(efitree, fname) + shutil.copy2(fpath, dst) + + if not include_kernel: + shutil.copy2(fpath, self.outputtree.efibootdir) + + # unmount the efiboot image + cmd = [self.lcmds.UMOUNT, efibootdir] + logger.debug(cmd) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + p.wait() + + # remove the work directories + shutil.rmtree(efibootdir) + #shutil.rmtree(efitree) + + return efiboot + + def create_efidisk(self, efiboot): + efidisk = joinpaths(self.workdir, "efidisk.img") + if os.path.isfile(efidisk): + os.unlink(efidisk) + + partsize = os.path.getsize(efiboot) + disksize = 17408 + partsize + 17408 + disksize = disksize + (disksize % 512) + + # create efidisk file + with open(efidisk, "wb") as fobj: + fobj.truncate(disksize) + + # create loop device + loopdev = create_loop_dev(efidisk) + + if not loopdev: + os.unlink(efidisk) + return None + + # create dm device + dmdev = create_dm_dev("efiboot", disksize / 512, loopdev) + + if not dmdev: + remove_loop_dev(loopdev) + os.unlink(efidisk) + return None + + # create partition on dm device + cmd = [self.lcmds.PARTED, "--script", dmdev, "mklabel", "gpt", "unit", + "b", "mkpart", '\"EFI System Partition\"', "fat32", "17408", + str(partsize + 17408), "set", "1", "boot", "on"] + logger.debug(cmd) + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + rc = p.wait() + + if not rc == 0: + remove_dm_dev(dmdev) + remove_loop_dev(loopdev) + os.unlink(efidisk) + return None + + with open(efiboot, "rb") as f_from: + with open("{0}p1".format(dmdev), "wb") as f_to: + efidata = f_from.read(1024) + while efidata: + f_to.write(efidata) + efidata = f_from.read(1024) + + remove_dm_dev("{0}p1".format(dmdev)) + remove_dm_dev(dmdev) + remove_loop_dev(loopdev) + + return efidisk + + def create_bootiso(self, outputtree, efiboot=None): + + bootiso = joinpaths(self.workdir, "boot.iso") + if os.path.isfile(bootiso): + os.unlink(bootiso) + + if efiboot is not None: + efiargs = ["-eltorito-alt-boot", "-e", "images/efiboot.img", + "-no-emul-boot"] + efigraft = ["EFI/BOOT={0}".format(outputtree.efibootdir)] + else: + efiargs = [] + efigraft = [] + + cmd = [self.lcmds.MKISOFS, "-o", bootiso, + "-b", "isolinux/isolinux.bin", "-c", "isolinux/boot.cat", + "-no-emul-boot", "-boot-load-size", "4", + "-boot-info-table"] + efiargs + ["-R", "-J", "-V", self.product, + "-T", "-graft-points", + "isolinux={0}".format(outputtree.isolinuxdir), + "images={0}".format(outputtree.imgdir)] + efigraft + logger.debug(cmd) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + rc = p.wait() + + if not rc == 0: + return None + + # create hybrid iso + cmd = [self.lcmds.ISOHYBRID, bootiso] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + rc = p.wait() + + return bootiso + + +class LoraxInstallTree(BaseLoraxClass): + + def __init__(self, yum, basearch): + BaseLoraxClass.__init__(self) + self.yum = yum + self.root = self.yum.installroot + self.basearch = basearch + + self.lcmds = constants.LoraxRequiredCommands() + + def remove_locales(self): + chroot = lambda: os.chroot(self.root) + + # get locales we need to keep + langtable = joinpaths(self.root, "usr/share/anaconda/lang-table") + with open(langtable, "r") as fobj: + langs = fobj.readlines() + + langs = map(lambda l: l.split()[3].replace(".UTF-8", ".utf8"), langs) + langs = set(langs) + + # get locales from locale-archive + localearch = "/usr/lib/locale/locale-archive" + + cmd = [self.lcmds.LOCALEDEF, "--list-archive", localearch] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, preexec_fn=chroot) + output = p.stdout.read() + + remove = set(output.split()) - langs + + # remove not needed locales + cmd = [self.lcmds.LOCALEDEF, "-i", localearch, + "--delete-from-archive"] + list(remove) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, preexec_fn=chroot) + p.wait() + + localearch = joinpaths(self.root, localearch) + shutil.move(localearch, localearch + ".tmpl") + + p = subprocess.Popen([self.lcmds.BUILD_LOCALE_ARCHIVE], + preexec_fn=chroot) + p.wait() + + # remove unneeded locales from /usr/share/locale + with open(langtable, "r") as fobj: + langs = fobj.readlines() + + langs = map(lambda l: l.split()[1], langs) + + localedir = joinpaths(self.root, "usr/share/locale") + for fname in os.listdir(localedir): + fpath = joinpaths(localedir, fname) + if os.path.isdir(fpath) and fname not in langs: + shutil.rmtree(fpath) + + # move the lang-table to etc + shutil.move(langtable, joinpaths(self.root, "etc")) + + def create_keymaps(self): + keymaps = joinpaths(self.root, "etc/keymaps.gz") + + # look for override + override = "keymaps-override-{0.basearch}".format(self) + override = joinpaths(self.root, "usr/share/anaconda", override) + if os.path.isfile(override): + logger.debug("using keymaps override") + shutil.move(override, keymaps) + else: + # create keymaps + cmd = [joinpaths(self.root, "usr/share/anaconda", "getkeymaps"), + basearch, keymaps, self.root] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + p.wait() + + return True + + def create_screenfont(self): + dst = joinpaths(self.root, "etc/screenfont.gz") + + screenfont = "screenfont-{0.basearch}.gz".format(self) + screenfont = joinpaths(self.root, "usr/share/anaconda", screenfont) + if not os.path.isfile(screenfont): + return False + else: + shutil.move(screenfont, dst) + + return True + + def move_stubs(self): + stubs = ("list-harddrives", "loadkeys", "losetup", "mknod", + "raidstart", "raidstop") + + for stub in stubs: + src = joinpaths(self.root, "usr/share/anaconda", + "{0}-stub".format(stub)) + dst = joinpaths(self.root, "usr/bin", stub) + if os.path.isfile(src): + shutil.move(src, dst) + + # move restart-anaconda + src = joinpaths(self.root, "usr/share/anaconda", "restart-anaconda") + dst = joinpaths(self.root, "usr/bin") + shutil.move(src, dst) + + def cleanup_python_files(self): + for root, dnames, fnames in os.walk(self.root): + for fname in fnames: + if fname.endswith(".py"): + path = joinpaths(root, fname, follow_symlinks=False) + pyo, pyc = path + "o", path + "c" + if os.path.isfile(pyo): + os.unlink(pyo) + if os.path.isfile(pyc): + os.unlink(pyc) + + os.symlink("/dev/null", pyc) + + def cleanup_kernel_modules(self, keepmodules, kernel): + moddir = joinpaths(self.root, "lib/modules", kernel.version) + fwdir = joinpaths(self.root, "lib/firmware") + + # expand required modules + modules = set() + pattern = re.compile(r"\.ko$") + + for name in keepmodules: + if name.startswith("="): + group = name[1:] + if group in ("scsi", "ata"): + p = joinpaths(moddir, "modules.block") + elif group == "net": + p = joinpaths(moddir, "modules.networking") + else: + p = joinpaths(moddir, "modules.{0}".format(group)) + + if os.path.isfile(p): + with open(p, "r") as fobj: + for line in fobj: + module = pattern.sub("", line.strip()) + modules.add(module) + else: + modules.add(name) + + # resolve modules dependencies + moddep = joinpaths(moddir, "modules.dep") + with open(moddep, "r") as fobj: + lines = map(lambda line: line.strip(), fobj.readlines()) + + modpattern = re.compile(r"^.*/(?P.*)\.ko:(?P.*)$") + deppattern = re.compile(r"^.*/(?P.*)\.ko$") + unresolved = True + + while unresolved: + unresolved = False + for line in lines: + m = modpattern.match(line) + modname = m.group("name") + if modname in modules: + # add the dependencies + for dep in m.group("deps").split(): + m = deppattern.match(dep) + depname = m.group("name") + if depname not in modules: + unresolved = True + modules.add(depname) + + # required firmware + firmware = set() + + # remove not needed modules + for root, dnames, fnames in os.walk(moddir): + for fname in fnames: + path = os.path.join(root, fname) + name, ext = os.path.splitext(fname) + + if ext == ".ko": + if name not in modules: + os.unlink(path) + logger.debug("removed module {0}".format(path)) else: - packages.add(name) + # get the required firmware + cmd = [self.lcmds.MODINFO, "-F", "firmware", path] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + output = p.stdout.read() + firmware |= set(output.split()) - if c.has_option("lorax", "modules"): - list = c.get("lorax", "modules").split() - for name in list: - if name.startswith("-"): - modules.discard(name) - else: - modules.add(name) + # remove not needed firmware + firmware = map(lambda fw: joinpaths(fwdir, fw), list(firmware)) + for root, dnames, fnames in os.walk(fwdir): + for fname in fnames: + path = joinpaths(root, fname) + if path not in firmware: + os.unlink(path) + logger.debug("removed firmware {0}".format(path)) - if c.has_option("lorax", "initrd_template"): - initrd_template = c.get("lorax", "initrd_template") - initrd_template = os.path.join(self.conf.confdir, - initrd_template) + # get the modules paths + modpaths = {} + for root, dnames, fnames in os.walk(moddir): + for fname in fnames: + modpaths[fname] = joinpaths(root, fname) - if c.has_option("lorax", "install_template"): - install_template = c.get("lorax", "install_template") - install_template = os.path.join(self.conf.confdir, - install_template) + # create the modules list + modlist = {} + for modtype, fname in (("scsi", "modules.block"), + ("eth", "modules.networking")): - return packages, modules, initrd_template, install_template + fname = joinpaths(moddir, fname) + with open(fname, "r") as fobj: + lines = map(lambda l: l.strip(), fobj.readlines()) + lines = filter(lambda l: l, lines) - def prepare_outputdir(self): - imgdir = os.path.join(self.outputdir, "images") - makedirs_(imgdir) + for line in lines: + modname, ext = os.path.splitext(line) + if (line not in modpaths or + modname in ("floppy", "libiscsi", "scsi_mod")): + continue + + cmd = [self.lcmds.MODINFO, "-F", "description", modpaths[line]] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + output = p.stdout.read() + + try: + desc = output.splitlines()[0] + desc = desc.strip()[:65] + except IndexError: + desc = "{0} driver".format(modname) + + info = '{0}\n\t{1}\n\t"{2}"\n' + info = info.format(modname, modtype, desc) + modlist[modname] = info + + # write the module-info + moduleinfo = joinpaths(os.path.dirname(moddir), "module-info") + with open(moduleinfo, "w") as fobj: + fobj.write("Version 0\n") + for modname in sorted(modlist.keys()): + fobj.write(modlist[modname]) + + # remove *map files + mapfiles = joinpaths(moddir, "*map") + for fpath in glob.glob(mapfiles): + os.unlink(fpath) + + def compress_modules(self, kernel): + moddir = joinpaths(self.root, "lib/modules", kernel.version) + + for root, dnames, fnames in os.walk(moddir): + for fname in filter(lambda f: f.endswith(".ko"), fnames): + path = os.path.join(root, fname) + with open(path, "rb") as fobj: + data = fobj.read() + + gzipped = gzip.open("{0}.gz".format(path), "wb") + gzipped.write(data) + gzipped.close() + + os.unlink(path) + + def run_depmod(self, kernel): + systemmap = "System.map-{0.version}".format(kernel) + systemmap = joinpaths(self.root, "boot", systemmap) + + cmd = [self.lcmds.DEPMOD, "-a", "-F", systemmap, "-b", self.root, + kernel.version] + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + + def create_install_img(self, paths, type="squashfs", workdir="/tmp"): + tempdir = tempfile.mkdtemp(prefix="install.img.", dir=workdir) + + paths = map(lambda p: glob.iglob(p), paths) + paths = itertools.chain.from_iterable(paths) + + for path in paths: + fullpath = joinpaths(self.root, path) + + dirname = os.path.dirname(path) + targetdir = joinpaths(tempdir, dirname) + if not os.path.isdir(targetdir): + os.makedirs(targetdir) + + for expanded in glob.iglob(fullpath): + if os.path.islink(expanded): + # TODO + pass + + else: + shutil.move(expanded, targetdir) + + installimg = joinpaths(workdir, "install.img") + + if type == "squashfs": + cmd = [self.lcmds.MKSQUASHFS, tempdir, installimg, + "-all-root", "-no-fragments", "-no-progress"] + logger.debug(cmd) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + rc = p.wait() + if not rc == 0: + return None + else: + # TODO + raise NotImplementedError + + return installimg + + def compress(self, initrd): + chdir = lambda: os.chdir(self.root) + + start = time.time() + + find = subprocess.Popen([self.lcmds.FIND, "."], stdout=subprocess.PIPE, + preexec_fn=chdir) + + cpio = subprocess.Popen([self.lcmds.CPIO, "--quiet", "-c", "-o"], + stdin=find.stdout, stdout=subprocess.PIPE, + preexec_fn=chdir) + + gzipped = gzip.open(initrd.fpath, "wb") + gzipped.write(cpio.stdout.read()) + gzipped.close() + + elapsed = time.time() - start + + return True, elapsed + + @property + def kernels(self): + kerneldir = "boot" + if self.basearch == "ia64": + kerneldir = "boot/efi/EFI/redhat" + + kerneldir = joinpaths(self.root, kerneldir) + kpattern = re.compile(r"vmlinuz-(?P[-._0-9a-z]+?" + r"(?P(PAE)?)(?P(xen)?))$") + + kernels = [] + for fname in os.listdir(kerneldir): + m = kpattern.match(fname) + if m: + type = K_NORMAL + if m.group("pae"): + type = K_PAE + elif m.group("xen"): + type = K_XEN + + kernels.append(Kernel(fname, + joinpaths(kerneldir, fname), + m.group("ver"), + type)) + + kernels = sorted(kernels, key=operator.attrgetter("type")) + return kernels + + +class LoraxOutputTree(BaseLoraxClass): + + def __init__(self, root, installtree, product, version): + BaseLoraxClass.__init__(self) + self.root = root + self.installtree = installtree + + self.product = product + self.version = version + + def prepare(self): + imgdir = joinpaths(self.root, "images") + os.makedirs(imgdir) + logger.debug("created directory {0}".format(imgdir)) + + pxebootdir = joinpaths(self.root, "images/pxeboot") + os.makedirs(pxebootdir) + logger.debug("created directory {0}".format(pxebootdir)) + + isolinuxdir = joinpaths(self.root, "isolinux") + os.makedirs(isolinuxdir) + logger.debug("created directory {0}".format(isolinuxdir)) + + efibootdir = joinpaths(self.root, "EFI/BOOT") + os.makedirs(efibootdir) + logger.debug("created directory {0}".format(efibootdir)) + + self.imgdir = imgdir + self.pxebootdir = pxebootdir + self.isolinuxdir = isolinuxdir + self.efibootdir = efibootdir # write the images/README file text = """ This directory contains image files that can be used to create media -capable of starting the {0} installation process. +capable of starting the {0.product} installation process. The boot.iso file is an ISO 9660 image of a bootable CD-ROM. It is useful in cases where the CD-ROM installation method is not desired, but the @@ -424,12 +1073,9 @@ To use this image file, burn the file onto CD-R (or CD-RW) media as you normally would. """ - text = text.format(self.product) - with open(os.path.join(imgdir, "README"), "w") as f: - f.write(text) - - pxedir = os.path.join(imgdir, "pxeboot") - makedirs_(pxedir) + readme = joinpaths(imgdir, "README") + with open(readme, "w") as fobj: + fobj.write(text.format(self)) # write the images/pxeboot/README file text = """ @@ -438,61 +1084,58 @@ The files in this directory are useful for booting a machine via PXE. The following files are available: vmlinuz - the kernel used for the installer initrd.img - an initrd with support for all install methods and - drivers supported for installation of {0} + drivers supported for installation of {0.product} """ - text = text.format(self.product) - with open(os.path.join(pxedir, "README"), "w") as f: - f.write(text) + readme = joinpaths(pxebootdir, "README") + with open(readme, "w") as fobj: + fobj.write(text.format(self)) - efidir = os.path.join(self.outputdir, "EFI/BOOT") - makedirs_(efidir) + def get_kernels(self): + kernels = self.installtree.kernels[:] - isodir = os.path.join(self.outputdir, "isolinux") - makedirs_(isodir) + # get the main kernel + self.main_kernel = kernels.pop(0) - self.conf.imgdir = imgdir - self.conf.pxedir = pxedir - self.conf.efidir = efidir - self.conf.isodir = isodir + # copy to isolinuxdir + shutil.copy2(self.main_kernel.fpath, self.isolinuxdir) - isolinuxbin = os.path.join(self.installtree.rootdir, - self.const.ISOLINUXBIN) - syslinuxcfg = os.path.join(self.installtree.rootdir, - self.const.SYSLINUXCFG) + # copy to pxebootdir + shutil.copy2(self.main_kernel.fpath, self.pxebootdir) - if not os.path.isfile(isolinuxbin): - self.perror("no isolinux binary found") - return False + # other kernels + for kernel in self.installtree.kernels: + shutil.copy2(kernel.fpath, self.pxebootdir) - # copy the isolinux.bin file - shutil.copy2(isolinuxbin, self.conf.isodir) + def get_isolinux(self): + isolinuxbin = joinpaths(self.installtree.root, + "usr/share/syslinux/isolinux.bin") + syslinuxcfg = joinpaths(self.installtree.root, + "usr/share/anaconda/boot/syslinux.cfg") - # copy the syslinux.cfg - isolinuxcfg = os.path.join(self.conf.isodir, "isolinux.cfg") + # copy isolinux.bin + shutil.copy2(isolinuxbin, self.isolinuxdir) + + # copy syslinux.cfg + isolinuxcfg = joinpaths(self.isolinuxdir, "isolinux.cfg") shutil.copy2(syslinuxcfg, isolinuxcfg) - # set the product and version in isolinux.cfg - replace_(isolinuxcfg, r"@PRODUCT@", self.product) - replace_(isolinuxcfg, r"@VERSION@", self.version) + # set product and version in isolinux.cfg + replace(isolinuxcfg, r"@PRODUCT@", self.product) + replace(isolinuxcfg, r"@VERSION@", self.version) - # set up the label for finding stage2 with a hybrid iso - replace_(isolinuxcfg, r"initrd=initrd.img", - 'initrd=initrd.img stage2=hd:LABEL="{0}"'.format(self.product)) + # set the kernel name in isolinux.cfg + replace(isolinuxcfg, r"kernel vmlinuz", + "kernel {0}".format(self.main_kernel.fname)) - # copy the .msg files - msgfiles = os.path.join(self.const.ANACONDA_BOOTDIR, "*.msg") - msgfiles = os.path.join(self.installtree.rootdir, msgfiles) - for fname in glob.iglob(msgfiles): - shutil.copy2(fname, self.conf.isodir) - path = os.path.join(self.conf.isodir, os.path.basename(fname)) - replace_(path, r"@VERSION@", self.version) + # set label for finding stage2 with a hybrid iso + replace(isolinuxcfg, r"initrd=initrd.img", + 'initrd=initrd.img stage2=hd:LABEL="{0.product}"'.format(self)) - # copy the memtest - memtest = os.path.join(self.const.BOOTDIR, "memtest*") - memtest = os.path.join(self.installtree.rootdir, memtest) - for fname in glob.iglob(memtest): - shutil.copy2(fname, os.path.join(self.conf.isodir, "memtest")) + # copy memtest + memtest = joinpaths(self.installtree.root, "boot/memtest*") + for fname in glob.glob(memtest): + shutil.copy2(fname, joinpaths(self.isolinuxdir, "memtest")) text = """label memtest86 menu label ^Memory test @@ -501,189 +1144,53 @@ initrd.img - an initrd with support for all install methods and """ - with open(isolinuxcfg, "a") as f: - f.write(text) + with open(isolinuxcfg, "a") as fobj: + fobj.write(text) break - # copy the grub.conf - grubconf = os.path.join(self.installtree.rootdir, - self.const.ANACONDA_BOOTDIR, "grub.conf") - shutil.copy2(grubconf, isodir) + # get splash + vesasplash = joinpaths(self.installtree.root, + "usr/share/anaconda/syslinux-vesa-splash.jpg") + vesamenu = joinpaths(self.installtree.root, + "usr/share/syslinux/vesamenu.c32") - # copy the splash files - vesasplash = os.path.join(self.installtree.rootdir, - self.const.VESASPLASH) - vesamenu = os.path.join(self.installtree.rootdir, - self.const.VESAMENU) + splashtolss = joinpaths(self.installtree.root, + "usr/share/anaconda/splashtolss.sh") - splashtools = os.path.join(self.installtree.rootdir, - self.const.SPLASHTOOLS) - syslinuxsplash = os.path.join(self.installtree.rootdir, - self.const.SYSLINUXSPLASH) - splashlss = os.path.join(self.installtree.rootdir, - self.const.SPLASHLSS) + syslinuxsplash = joinpaths(self.installtree.root, + "usr/share/anaconda/boot/syslinux-splash.jpg") + splashlss = joinpaths(self.installtree.root, + "usr/share/anaconda/boot/splash.lss") if os.path.isfile(vesasplash): - shutil.copy2(vesasplash, os.path.join(isodir, "splash.jpg")) - shutil.copy2(vesamenu, isodir) - replace_(isolinuxcfg, r"default linux", "default vesamenu.c32") - replace_(isolinuxcfg, r"prompt 1", "#prompt 1") - else: - if os.path.isfile(splashtools): - cmd = "{0} {1} {2}".format(splashtools, - syslinuxsplash, - splashlss) - - err, stdout = commands.getstatusoutput(cmd) - if err: - self.pwarning(stdout) + shutil.copy2(vesasplash, joinpaths(self.isolinuxdir, "splash.jpg")) + shutil.copy2(vesamenu, self.isolinuxdir) + replace(isolinuxcfg, r"default linux", "default vesamenu.c32") + replace(isolinuxcfg, r"prompt 1", "#prompt 1") + elif os.path.isfile(splashtolss): + cmd = [splashtolss, syslinuxsplash, splashlss] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + p.wait() if os.path.isfile(splashlss): - shutil.copy2(splashlss, isodir) + shutil.copy2(splashlss, self.isolinuxdir) - return True + def get_msg_files(self): + msgfiles = joinpaths(self.installtree.root, + "usr/share/anaconda/boot/*.msg") - def write_treeinfo(self, discnum=1, totaldiscs=1, packagedir=""): - outfile = os.path.join(self.workdir, ".treeinfo") + for fname in glob.glob(msgfiles): + shutil.copy2(fname, self.isolinuxdir) + path = joinpaths(self.isolinuxdir, os.path.basename(fname)) + replace(path, r"@VERSION@", self.version) - c = ConfigParser.ConfigParser() + def get_grub_conf(self): + grubconf = joinpaths(self.installtree.root, + "usr/share/anaconda/boot/grub.conf") - variant = self.variant - if variant is None: - variant = "" + shutil.copy2(grubconf, self.isolinuxdir) - section = "general" - data = {"timestamp": time.time(), - "family": self.product, - "version": self.version, - "variant": variant, - "arch": self.conf.basearch, - "discnum": discnum, - "totaldiscs": totaldiscs, - "packagedir": packagedir} - - c.add_section(section) - map(lambda (key, value): c.set(section, key, value), data.items()) - - with open(outfile, "w") as f: - c.write(f) - - return outfile - - def treeinfo_add_section(self, treeinfo, section, data): - c = ConfigParser.ConfigParser() - c.read(treeinfo) - - if not c.has_section(section): - c.add_section(section) - - map(lambda (key, value): c.set(section, key, value), data.items()) - - with open(treeinfo, "w") as f: - c.write(f) - - def write_discinfo(self, discnum="ALL"): - outfile = os.path.join(self.workdir, ".discinfo") - - with open(outfile, "w") as f: - f.write("{0:f}\n".format(time.time())) - f.write("{0}\n".format(self.release)) - f.write("{0}\n".format(self.conf.basearch)) - f.write("{0}\n".format(discnum)) - - return outfile - - def write_buildstamp(self): - outfile = os.path.join(self.workdir, ".buildstamp") - - now = datetime.datetime.now() - uuid = "{0}.{1}" - uuid = uuid.format(now.strftime("%Y%m%d%H%M"), self.conf.buildarch) - - with open(outfile, "w") as f: - f.write("{0}\n".format(uuid)) - f.write("{0}\n".format(self.product)) - f.write("{0}\n".format(self.version)) - f.write("{0}\n".format(self.bugurl)) - - return outfile - - def cleanup(self): - # TODO - pass - - -class YumHelper(object): - - def __init__(self, yb): - self.yb = yb - - def install(self, pattern): - try: - self.yb.install(name=pattern) - except yum.Errors.InstallError: - try: - self.yb.install(pattern=pattern) - except yum.Errors.InstallError: - return False - - return True - - def process_transaction(self): - self.yb.resolveDeps() - self.yb.buildTransaction() - - cb = yum.callbacks.ProcessTransBaseCallback() - rpmcb = RpmCallback() - - self.yb.processTransaction(callback=cb, rpmDisplay=rpmcb) - - self.yb.closeRpmDB() - self.yb.close() - - def search(self, pattern): - pl = self.yb.doPackageLists(patterns=[pattern]) - return pl.installed, pl.available - - @property - def installed_packages(self): - pl = self.yb.doPackageLists() - - d = {} - for pkgobj in pl.installed: - d[pkgobj.name] = pkgobj - - return d - - def get_file_list(self, package): - return package.returnFileEntries() - - -class RpmCallback(yum.rpmtrans.SimpleCliCallBack): - - def __init__(self): - yum.rpmtrans.SimpleCliCallBack.__init__(self) - self.output = output.LoraxOutput() - - self.termwidth = 79 - - def event(self, package, action, te_current, te_total, - ts_current, ts_total): - - info = "({0:3d}/{1:3d}) [{2:3.0f}%] {3} " - info = info.format(ts_current, ts_total, - float(te_current) / float(te_total) * 100, - self.action[action]) - - pkg = "{0}".format(package) - - infolen = len(info) - pkglen = len(pkg) - if (infolen + pkglen) > self.termwidth: - pkg = "{0}...".format(pkg[:self.termwidth-infolen-3]) - - msg = "{0}{1}\r".format(info, pkg) - self.output.write(msg) - if te_current == te_total: - self.output.write("\n") + grubconf = joinpaths(self.isolinuxdir, "grub.conf") + replace(grubconf, r"@PRODUCT@", self.product) + replace(grubconf, r"@VERSION@", self.version) diff --git a/src/pylorax/base.py b/src/pylorax/base.py index a19979a3..b4278371 100644 --- a/src/pylorax/base.py +++ b/src/pylorax/base.py @@ -20,17 +20,9 @@ # from abc import ABCMeta, abstractmethod - import sys -import os -import shlex -import shutil -import config -import constants import output -import ltmpl -from sysutils import * class BaseLoraxClass(object): @@ -39,9 +31,6 @@ class BaseLoraxClass(object): @abstractmethod def __init__(self): - self.conf = config.LoraxConfig() - self.const = constants.LoraxConstants() - self.cmd = constants.LoraxCommands() self.output = output.LoraxOutput() def pcritical(self, msg, file=sys.stdout): @@ -58,97 +47,3 @@ class BaseLoraxClass(object): def pdebug(self, msg, file=sys.stdout): self.output.debug(msg, file) - - -class BaseImageClass(BaseLoraxClass): - - __metaclass__ = ABCMeta - - @abstractmethod - def __init__(self): - BaseLoraxClass.__init__(self) - self.srctree, self.dsttree = None, None - self.pkgs_to_remove = set() - - def parse_template(self, template_file, variables={}): - template = ltmpl.Template() - - for lineno, line in template.parse(template_file, variables): - fields = shlex.split(line) - func, args = fields[0], fields[1:] - - func = getattr(self, func, None) - - if not func: - err = "invalid command: {0}" - err = err.format(line) - self.perror(err) - else: - try: - msg = "{0}({1})".format(func.__name__, ", ".join(args)) - self.pdebug(msg) - func(*args) - except TypeError: - err = "invalid command syntax: {0}" - err = err.format(line) - self.perror(err) - - def makedirs(self, *dirs): - for dir in dirs: - dir = os.path.join(self.dsttree, dir) - makedirs_(dir) - - def remove(self, *fnames): - for fname in fnames: - fname = os.path.join(self.dsttree, fname) - remove_(fname) - - def removepkg(self, *args): - pkgname = args[0] - try: - mask = args[1] - except IndexError: - mask = "*" - - self.pkgs_to_remove.add((pkgname, mask)) - - def symlink(self, link_target, link_name): - link_name = os.path.join(self.dsttree, link_name) - symlink_(link_target, link_name) - - def touch(self, fname): - fname = os.path.join(self.dsttree, fname) - touch_(fname) - - def chown(self): - # TODO - raise NotImplementedError - - def chmod(self): - # TODO - raise NotImplementedError - - def replace(self): - # TODO - raise NotImplementedError - - def copy(self, fname, target=None): - dstdir = os.path.dirname(fname) - if target: - dstdir = target - - if dstdir: - makedirs_(os.path.join(self.dsttree, dstdir)) - - dcopy_(fname, dstdir, self.srctree, self.dsttree, - ignore_errors=not self.conf.pedantic) - - def rename(self, fname, target): - fname = os.path.join(self.dsttree, fname) - target = os.path.join(self.dsttree, target) - shutil.move(fname, target) - - def edit(self, fname, text): - fname = os.path.join(self.dsttree, fname) - with open(fname, "w") as f: - f.write(text) diff --git a/src/pylorax/config.py b/src/pylorax/config.py deleted file mode 100644 index 136088ad..00000000 --- a/src/pylorax/config.py +++ /dev/null @@ -1,44 +0,0 @@ -# -# config.py -# -# Copyright (C) 2009 Red Hat, Inc. -# -# 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 2 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 . -# -# Red Hat Author(s): Martin Gracik -# - -from decorators import singleton -import output - - -@singleton -class LoraxConfig(object): - - def __init__(self): - # output settings - self.colors = True - self.encoding = "utf-8" - self.debug = True - - self.pedantic = False - - self.confdir = "/etc/lorax" - self.datadir = "/usr/share/lorax" - - self.ignore_errors = "/etc/lorax/ignore_errors" - - def __setattr__(self, attr, value): - output.LoraxOutput().debug("[set {0}={1}]".format(attr, value)) - object.__setattr__(self, attr, value) diff --git a/src/pylorax/constants.py b/src/pylorax/constants.py index 70f479aa..75a68995 100644 --- a/src/pylorax/constants.py +++ b/src/pylorax/constants.py @@ -19,63 +19,44 @@ # Red Hat Author(s): Martin Gracik # -from os.path import join as pjoin +import os + +from sysutils import joinpaths -class LoraxConstants(object): - - ROOT_UID = 0 - - ANACONDA_PACKAGE = "anaconda" - ANACONDA_RUNTIME = "usr/share/anaconda" - ANACONDA_BOOTDIR = "usr/share/anaconda/boot" - - BOOTDIR = "boot" - BOOTDIR_IA64 = "boot/efi/EFI/redhat" - - EFIDIR = "boot/efi/EFI/redhat" - SPLASH = "boot/grub/splash.xpm.gz" - - VESASPLASH = "usr/lib/anaconda-runtime/syslinux-vesa-splash.jpg" - SYSLINUXSPLASH = pjoin(ANACONDA_BOOTDIR, "syslinux-splash.jpg") - SPLASHTOOLS = pjoin(ANACONDA_RUNTIME, "splashtools.sh") - SPLASHLSS = pjoin(ANACONDA_BOOTDIR, "splash.lss") - VESAMENU = "usr/share/syslinux/vesamenu.c32" - - MODDIR = "lib/modules" - FWDIR = "lib/firmware" - - MODDEPFILE = "modules.dep" - MODULEINFO = "module-info" - - LOCALEDIR = "usr/lib/locale" - LOCALES = "usr/share/locale" - LANGTABLE = "usr/share/anaconda/lang-table" - - ISOLINUXBIN = "usr/share/syslinux/isolinux.bin" - SYSLINUXCFG = "usr/share/anaconda/boot/syslinux.cfg" - - LDSOCONF = "etc/ld.so.conf" - MANCONF = "etc/man_db.conf" - - -class LoraxCommands(dict): +class LoraxRequiredCommands(dict): def __init__(self): - self["MODINFO"] = "/sbin/modinfo" - self["DEPMOD"] = "/sbin/depmod" - self["LOCALEDEF"] = "/usr/bin/localedef" - self["MKDOSFS"] = "/sbin/mkdosfs" - self["MKSQUASHFS"] = "/sbin/mksquashfs" - self["MKISOFS"] = "/usr/bin/mkisofs" - self["ISOHYBRID"] = "/usr/bin/isohybrid" - self["LOSETUP"] = "/sbin/losetup" - self["DMSETUP"] = "/sbin/dmsetup" - self["AWK"] = "/usr/bin/awk" - self["MOUNT"] = "/bin/mount" - self["UMOUNT"] = "/bin/umount" - self["LDCONFIG"] = "/sbin/ldconfig" - self["PARTED"] = "/sbin/parted" + self.__path = os.environ["PATH"].split(":") + + self["AWK"] = "awk" + self["BUILD_LOCALE_ARCHIVE"] = "build-locale-archive" + self["CPIO"] = "cpio" + self["DEPMOD"] = "depmod" + self["DMSETUP"] = "dmsetup" + self["FIND"] = "find" + self["ISOHYBRID"] = "isohybrid" + self["LDCONFIG"] = "ldconfig" + self["LOCALEDEF"] = "localedef" + self["LOSETUP"] = "losetup" + self["MKDOSFS"] = "mkdosfs" + self["MKISOFS"] = "mkisofs" + self["MKSQUASHFS"] = "mksquashfs" + self["MODINFO"] = "modinfo" + self["MOUNT"] = "mount" + self["PARTED"] = "parted" + self["UMOUNT"] = "umount" def __getattr__(self, attr): return self[attr] + + def get_missing(self): + missing = [] + for cmd in self.values(): + found = [joinpaths(path, cmd) for path in self.__path + if os.path.exists(joinpaths(path, cmd))] + + if not found: + missing.append(cmd) + + return missing diff --git a/src/pylorax/images.py b/src/pylorax/images.py deleted file mode 100644 index fd2696e7..00000000 --- a/src/pylorax/images.py +++ /dev/null @@ -1,915 +0,0 @@ -# -# images.py -# -# Copyright (C) 2009 Red Hat, Inc. -# -# 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 2 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 . -# -# Red Hat Author(s): Martin Gracik -# - -import sys -import os -import re -import shutil -import gzip -import commands -import tempfile -import math -import glob -import fnmatch - -from base import BaseImageClass -from sysutils import * - - -class InitRD(BaseImageClass): - - def __init__(self, installtree, modules, template_file, workdir="/tmp"): - BaseImageClass.__init__(self) - - self.installtree = installtree - self.modules = modules - self.template_file = template_file - self.workdir = workdir - - self.srctree = self.installtree.rootdir - self.dsttree = None - - def create(self): - for kernel in self.installtree.kernels: - msg = ":: creating the initrd image for {0}" - msg = msg.format(kernel.filename) - self.pinfo(msg) - - # prepare the working environment - self.pinfo("preparing the work environment") - self.prepare(kernel) - - # get the kernel modules - self.pinfo("getting the kernel modules") - self.get_kernel_modules(kernel, self.modules) - - # get keymaps - self.pinfo("creating keymaps") - ok = self.get_keymaps() - if not ok: - self.perror("could not create keymaps") - continue - - # create locales - self.pinfo("creating locales") - ok = self.create_locales() - if not ok: - self.perror("could not create locales") - continue - - # parse the template file - self.pinfo("parsing the template") - variables = {"buildarch": self.conf.buildarch, - "basearch": self.conf.basearch, - "libdir": self.conf.libdir} - self.parse_template(self.template_file, variables) - - # create the initrd file - self.pinfo("compressing the initrd image file") - initrdfile = self.compress(kernel) - if not initrdfile: - self.perror("could not create the initrd image file") - continue - - yield (kernel, initrdfile) - - def prepare(self, kernel): - # create the initrd working directory - dir = os.path.join(self.workdir, "initrd-{0}".format(kernel.version)) - if os.path.isdir(dir): - shutil.rmtree(dir) - os.mkdir(dir) - - # set the destination tree - self.dsttree = dir - - # copy the buildstamp - shutil.copy2(self.conf.buildstamp, self.dsttree) - - # create the .profile - profile = os.path.join(self.dsttree, ".profile") - text = """PS1="[anaconda \u@\h \W]\\$ " -PATH=/bin:/usr/bin:/usr/sbin:/mnt/sysimage/sbin:/mnt/sysimage/usr/sbin:/mnt/sysimage/bin:/mnt/sysimage/usr/bin -export PS1 PATH - -""" - - with open(profile, "w") as f: - f.write(text) - - # create the lib directories - os.mkdir(os.path.join(self.dsttree, self.conf.libdir)) - os.makedirs(os.path.join(self.dsttree, "usr", self.conf.libdir)) - - # XXX - def get_kernel_modules(self, kernel, modset): - moddir = os.path.join(self.const.MODDIR, kernel.version) - src_moddir = os.path.join(self.srctree, moddir) - dst_moddir = os.path.join(self.dsttree, "modules", kernel.version) - - # create the lib/modules symlink - libmod = os.path.join(self.dsttree, self.const.MODDIR) - libmoddir = os.path.dirname(libmod) - if not os.path.isdir(libmoddir): - os.makedirs(libmoddir) - os.symlink("../modules", libmod) - - # copy all modules to the initrd tree - os.makedirs(os.path.dirname(dst_moddir)) - shutil.copytree(src_moddir, dst_moddir) - - # expand modules - modules = set() - pattern = re.compile(r"\.ko$") - for name in modset: - if name.startswith("="): - group = name[1:] - if group in ("scsi", "ata"): - p = os.path.join(src_moddir, "modules.block") - elif group == "net": - p = os.path.join(src_moddir, "modules.networking") - else: - p = os.path.join(src_moddir, "modules.{0}".format(group)) - - if os.path.isfile(p): - with open(p, "r") as f: - for line in f: - module = pattern.sub("", line.strip()) - modules.add(module) - else: - modules.add(name) - - # resolve modules dependencies - moddep = os.path.join(src_moddir, self.const.MODDEPFILE) - with open(moddep, "r") as f: - lines = map(lambda line: line.strip(), f.readlines()) - - modpattern = re.compile(r"^.*/(?P.*)\.ko:(?P.*)$") - deppattern = re.compile(r"^.*/(?P.*)\.ko$") - unresolved = True - - while unresolved: - unresolved = False - for line in lines: - m = modpattern.match(line) - modname = m.group("name") - if modname in modules: - # add the dependencies - for dep in m.group("deps").split(): - m = deppattern.match(dep) - depname = m.group("name") - if depname not in modules: - unresolved = True - modules.add(depname) - - # remove not needed modules - for root, dirs, files in os.walk(dst_moddir): - for file in files: - path = os.path.join(root, file) - name, ext = os.path.splitext(file) - - if ext == ".ko": - if name not in modules: - os.unlink(path) - else: - # get the required firmware - cmd = "{0.MODINFO} -F firmware {1}" - cmd = cmd.format(self.cmd, path) - err, stdout = commands.getstatusoutput(cmd) - if err: - self.perror(stdout) - continue - - for fw in stdout.split(): - src = os.path.join(self.srctree, - self.const.FWDIR, fw) - if not os.path.exists(src): - msg = "missing firmware {0}".format(fw) - self.pwarning(msg) - continue - - # copy the firmware - dst = os.path.join(self.dsttree, "firmware", fw) - dir = os.path.dirname(dst) - makedirs_(dir) - shutil.copy2(src, dst) - - # create the lib/firmware symlink - libfw = os.path.join(self.dsttree, self.const.FWDIR) - libfwdir = os.path.dirname(libfw) - if not os.path.isdir(libfwdir): - os.makedirs(libfwdir) - os.symlink("../firmware", libfw) - - # copy additional firmware - fw = [("ipw2100", "ipw2100*"), - ("ipw2200", "ipw2200*"), - ("iwl3945", "iwlwifi-3945*"), - ("iwl4965", "iwlwifi-4965*"), - ("atmel", "atmel_*.bin"), - ("zd1211rw", "zd1211"), - ("qla2xxx", "ql*")] - - for module, fname in fw: - if module in modules: - scopy_(src_root=self.srctree, - src_path=os.path.join(self.const.FWDIR, fname), - dst_root=self.dsttree, - dst_path="firmware") - - # XXX - # remove empty directories - #empty_dirs = set() - #for root, dirs, files in os.walk(dst_moddir, topdown=False): - # if not dirs and not files: - # shutil.rmtree(root) - - # get the modules paths - modpaths = {} - for root, dirs, files in os.walk(dst_moddir): - for file in files: - modpaths[file] = os.path.join(root, file) - - # create the modules list - modlist = {} - for modtype, fname in {"scsi": "modules.block", - "eth": "modules.networking"}.items(): - - fname = os.path.join(dst_moddir, fname) - with open(fname, "r") as f: - for line in f: - line = line.strip() - if not line: - continue - - modname, ext = os.path.splitext(line) - if (line not in modpaths or - modname in ("floppy", "libiscsi", "scsi_mod")): - continue - - cmd = "{0.MODINFO} -F description {1}" - cmd = cmd.format(self.cmd, modpaths[line]) - err, stdout = commands.getstatusoutput(cmd) - if err: - self.pwarning(stdout) - desc = "" - else: - desc = stdout.split("\n")[0] - desc = desc.strip()[:65] - - if not desc: - desc = "{0} driver".format(modname) - - info = '{0}\n\t{1}\n\t"{2}"\n' - info = info.format(modname, modtype, desc) - modlist[modname] = info - - # write the module-info - moduleinfo = os.path.join(os.path.dirname(dst_moddir), - self.const.MODULEINFO) - - with open(moduleinfo, "w") as f: - f.write("Version 0\n") - for modname in sorted(modlist.keys()): - f.write(modlist[modname]) - - # compress modules - for root, dirs, files in os.walk(dst_moddir): - for file in filter(lambda f: f.endswith(".ko"), files): - path = os.path.join(root, file) - with open(path, "rb") as f: - data = f.read() - - gzipped = gzip.open("{0}.gz".format(path), "wb") - gzipped.write(data) - gzipped.close() - os.unlink(path) - - # run depmod - systemmap = os.path.join(self.srctree, self.const.BOOTDIR, - "System.map-{0}".format(kernel.version)) - - cmd = "{0.DEPMOD} -a -F {1} -b {2} {3}" - cmd = cmd.format(self.cmd, systemmap, - self.dsttree, kernel.version) - - err, stdout = commands.getstatusoutput(cmd) - if err: - self.perror(stdout) - - # remove *map files - remove_(os.path.join(dst_moddir, "*map")) - - def get_keymaps(self): - override = "keymaps-override-{0}".format(self.conf.basearch) - override = os.path.join(self.srctree, self.const.ANACONDA_RUNTIME, - override) - - getkeymaps = os.path.join(self.srctree, self.const.ANACONDA_RUNTIME, - "getkeymaps") - - dst = os.path.join(self.dsttree, "etc/keymaps.gz") - dir = os.path.dirname(dst) - if not os.path.isdir(dir): - os.makedirs(dir) - - if os.path.isfile(override): - self.pinfo("using keymaps override") - shutil.copy2(override, dst) - else: - cmd = "{0} {1} {2} {3}" - cmd = cmd.format(getkeymaps, self.conf.basearch, dst, self.srctree) - err, stdout = commands.getstatusoutput(cmd) - if err: - self.perror(stdout) - return False - - return True - - def create_locales(self): - localedir = os.path.join(self.dsttree, self.const.LOCALEDIR) - os.makedirs(localedir) - - cmd = "{0.LOCALEDEF} -c -i en_US -f UTF-8 --prefix {1} en_US" - cmd = cmd.format(self.cmd, self.dsttree) - err, stdout = commands.getstatusoutput(cmd) - if err: - self.perror(stdout) - return False - - return True - - def compress(self, kernel): - filename = "initrd-{0}.img".format(kernel.version) - filepath = os.path.join(self.workdir, filename) - - # create the cpio archive - cpioarchive = "{0}.cpio".format(filepath) - - cwd = os.getcwd() - os.chdir(self.dsttree) - - cmd = "find . | cpio --quiet -c -o > {0}".format(cpioarchive) - err, stdout = commands.getstatusoutput(cmd) - - os.chdir(cwd) - - if err: - self.perror(stdout) - return None - - # create the gzip archive - with open(cpioarchive, "rb") as f: - cpiodata = f.read() - - gzipped = gzip.open(filepath, "wb") - gzipped.write(cpiodata) - gzipped.close() - - # remove the cpio archive - os.unlink(cpioarchive) - - # remove the initrd tree - #shutil.rmtree(self.dsttree) - - return filepath - - -class EFI(BaseImageClass): - - def __init__(self, installtree, kernel, initrd, product, version, - workdir="/tmp"): - - BaseImageClass.__init__(self) - - self.srctree = installtree.rootdir - self.dsttree = None - - self.kernel = kernel - self.initrd = initrd - self.product = product - self.version = version - - self.workdir = workdir - - def create(self): - msg = ":: creating the efi images for {0}" - self.pinfo(msg.format(self.kernel.filename)) - - # create efiboot image with kernel - self.pinfo("creating efiboot image with kernel") - efiboot_kernel = self.create_efiboot(with_kernel=True) - if efiboot_kernel is None: - self.perror("unable to create the efiboot image") - return None, None - - # create the efidisk image - self.pinfo("creating efidisk image") - efidisk = self.create_efidisk(efiboot_kernel) - if efidisk is None: - self.perror("unable to create the efidisk image") - return None, None - - # remove the efiboot image with kernel - os.unlink(efiboot_kernel) - - # create efiboot image without kernel - self.pinfo("creating efiboot image without kernel") - efiboot_nokernel = self.create_efiboot(with_kernel=False) - if efiboot_nokernel is None: - self.perror("unable to create the efiboot image") - return None, None - - return efiboot_nokernel, efidisk - - def create_efiboot(self, with_kernel=True): - # create the efi tree directory - efitree = tempfile.mkdtemp(prefix="efitree.", dir=self.workdir) - - efikernelpath = "/images/pxeboot/vmlinuz" - efiinitrdpath = "/images/pxeboot/initrd.img" - efisplashpath = "/EFI/BOOT/splash.xpm.gz" - - # copy kernel and initrd files to efi tree directory - if with_kernel: - kpath = self.kernel.path - shutil.copy2(kpath, os.path.join(efitree, "vmlinuz")) - shutil.copy2(self.initrd, os.path.join(efitree, "initrd.img")) - efikernelpath = "/EFI/BOOT/vmlinuz" - efiinitrdpath = "/EFI/BOOT/initrd.img" - - # copy conf files to efi tree directory - srcdir = os.path.join(self.srctree, self.const.ANACONDA_BOOTDIR) - scopy_(src_root=srcdir, src_path="*.conf", - dst_root=efitree, dst_path="") - - # edit the grub.conf file - grubconf = os.path.join(efitree, "grub.conf") - replace_(grubconf, "@PRODUCT@", self.product) - replace_(grubconf, "@VERSION@", self.version) - replace_(grubconf, "@KERNELPATH@", efikernelpath) - replace_(grubconf, "@INITRDPATH@", efiinitrdpath) - replace_(grubconf, "@SPLASHPATH@", efisplashpath) - - if self.conf.efiarch == "IA32": - shutil.copy2(grubconf, os.path.join(efitree, "BOOT.conf")) - - dst = os.path.join(efitree, "BOOT{0}.conf".format(self.conf.efiarch)) - shutil.move(grubconf, dst) - - # copy grub.efi - grubefi = os.path.join(self.srctree, self.const.EFIDIR, "grub.efi") - - if self.conf.efiarch == "IA32": - shutil.copy2(grubefi, os.path.join(efitree, "BOOT.efi")) - - dst = os.path.join(efitree, "BOOT{0}.efi".format(self.conf.efiarch)) - shutil.copy2(grubefi, dst) - - # copy splash.xpm.gz - splash = os.path.join(self.srctree, self.const.SPLASH) - shutil.copy2(splash, efitree) - - efiboot = os.path.join(self.workdir, "efiboot.img") - if os.path.isfile(efiboot): - os.unlink(efiboot) - - # calculate the size of the efi tree directory - self.pdebug("calculating the efiboot image size") - fsoverhead = 100 * 1024 - self.pdebug("using {0} bytes for fs overhead".format(fsoverhead)) - - sizeinbytes = fsoverhead - for root, dirs, files in os.walk(efitree): - for file in files: - filepath = os.path.join(root, file) - filesize = os.path.getsize(filepath) - - # round to multiplications of 1024 - filesize = math.ceil(filesize / 1024.0) * 1024 - - self.pdebug("adding {0} bytes for file {1}".format(filesize, - filepath)) - - sizeinbytes += filesize - - self.pdebug("required size in bytes: {0}".format(sizeinbytes)) - - # mkdosfs needs the size in blocks of 1024 bytes - size = int(math.ceil(sizeinbytes / 1024.0)) - self.pdebug("required size in 1024 byte blocks: {0}".format(size)) - - cmd = "{0.MKDOSFS} -n ANACONDA -C {1} {2} > /dev/null" - cmd = cmd.format(self.cmd, efiboot, size) - err, stdout = commands.getstatusoutput(cmd) - if err: - self.perror(stdout) - return None - - # mount the efiboot image - efibootdir = tempfile.mkdtemp(prefix="efiboot.", dir=self.workdir) - - cmd = "mount -o loop,shortname=winnt,umask=0777 -t vfat {0} {1}" - cmd = cmd.format(efiboot, efibootdir) - err, stdout = commands.getstatusoutput(cmd) - if err: - self.perror(stdout) - return None - - # copy the files to the efiboot image - dstdir = os.path.join(efibootdir, "EFI/BOOT") - os.makedirs(dstdir) - - scopy_(src_root=efitree, src_path="*", - dst_root=dstdir, dst_path="") - - # unmount the efiboot image - cmd = "umount {0}".format(efibootdir) - err, stdout = commands.getstatusoutput(cmd) - if err: - self.pwarning(stdout) - - # remove the working directories - shutil.rmtree(efibootdir) - #shutil.rmtree(efitree) - - # XXX copy the conf files and splash.xpm.gz to the output directory - if not with_kernel: - scopy_(src_root=efitree, src_path="*.conf", - dst_root=self.conf.efidir, dst_path="") - shutil.copy2(splash, self.conf.efidir) - - return efiboot - - def create_efidisk(self, efiboot): - efidisk = os.path.join(self.workdir, "efidisk.img") - if os.path.isfile(efidisk): - os.unlink(efidisk) - - partsize = os.path.getsize(efiboot) - disksize = 17408 + partsize + 17408 - disksize = disksize + (disksize % 512) - - # create the efidisk file - with open(efidisk, "wb") as f: - f.truncate(disksize) - - # create the loop device - cmd = "{0.LOSETUP} -v -f {1} | {0.AWK} '{{print $4}}'" - cmd = cmd.format(self.cmd, efidisk) - err, loop = commands.getstatusoutput(cmd) - if err: - self.perror(loop) - os.unlink(efidisk) - return None - - # create the dm device - dmdev = "efiboot" - cmd = '{0.DMSETUP} create {1} --table "0 {2} linear {3} 0"' - cmd = cmd.format(self.cmd, dmdev, disksize / 512, loop) - err, stdout = commands.getstatusoutput(cmd) - if err: - self.perror(stdout) - self.remove_loop_dev(loop) - os.unlink(efidisk) - return None - - cmd = ("{0.PARTED} --script /dev/mapper/{1} " - "mklabel gpt unit b mkpart '\"EFI System Partition\"' " - "fat32 17408 {2} set 1 boot on") - cmd = cmd.format(self.cmd, dmdev, partsize + 17408) - err, stdout = commands.getstatusoutput(cmd) - if err: - self.perror(stdout) - self.remove_dm_dev(dmdev) - self.remove_loop_dev(loop) - os.unlink(efidisk) - return None - - with open(efiboot, "rb") as f_from: - with open("/dev/mapper/{0}p1".format(dmdev), "wb") as f_to: - efidata = f_from.read(1024) - while efidata: - f_to.write(efidata) - efidata = f_from.read(1024) - - self.remove_dm_dev("{0}p1".format(dmdev)) - self.remove_dm_dev(dmdev) - self.remove_loop_dev(loop) - - return efidisk - - def remove_loop_dev(self, dev): - cmd = "{0.LOSETUP} -d {1}".format(self.cmd, dev) - err, stdout = commands.getstatusoutput(cmd) - if err: - self.pwarning(stdout) - - def remove_dm_dev(self, dev): - cmd = "{0.DMSETUP} remove /dev/mapper/{1}".format(self.cmd, dev) - err, stdout = commands.getstatusoutput(cmd) - if err: - self.pwarning(stdout) - - -class Install(BaseImageClass): - - def __init__(self, installtree, template_file, workdir="/tmp"): - BaseImageClass.__init__(self) - - self.installtree = installtree - self.srctree = installtree.rootdir - self.dsttree = installtree.rootdir - self.template_file = template_file - self.workdir = workdir - - def create(self, type="squashfs"): - self.pinfo(":: creating the install image") - - # copy the .buildstamp - shutil.copy2(self.conf.buildstamp, self.srctree) - - # parse the template file - self.pinfo("parsing the template") - variables = {"buildarch": self.conf.buildarch, - "basearch": self.conf.basearch, - "libdir": self.conf.libdir} - self.parse_template(self.template_file, variables) - - # XXX remove packages - installed_packages = self.installtree.yum.installed_packages - for pkgname, mask in self.pkgs_to_remove: - if pkgname not in installed_packages: - continue - - self.pinfo("removing files from package %s matching mask %s" \ - % (pkgname, mask)) - - pkgobj = installed_packages.get(pkgname) - for fname in pkgobj.filelist: - if fnmatch.fnmatch(fname, mask): - self.pdebug("removing file %s%s" \ - % (self.srctree, fname)) - remove_("%s%s" % (self.srctree, fname)) - - self.copy_stubs() - self.copy_bootloaders() - self.rename_repos() - self.move_anaconda_files() - self.create_modules_symlinks() - self.fix_man_pages() - self.remove_locales() - self.remove_unnecessary_files() - self.move_bins() - - # copy custom files - self.pinfo("copying custom files") - self.copy_custom_files() - - installimg = os.path.join(self.workdir, "install.img") - if os.path.isfile(installimg): - os.unlink(installimg) - - if type == "squashfs": - self.pinfo("using squash filesystem") - cmd = "{0.MKSQUASHFS} {1} {2} -all-root -no-fragments -no-progress" - cmd = cmd.format(self.cmd, self.srctree, installimg) - err, stdout = commands.getstatusoutput(cmd) - if err: - self.perror(stdout) - return None - elif type == "cramfs": - # TODO - raise NotImplementedError - elif type == "ext2": - # TODO - raise NotImplementedError - - return installimg - - def copy_stubs(self): - stubs = ("raidstart", "raidstop", "losetup", "list-harddrives", - "loadkeys", "mknod", "syslogd") - - for stub in map(lambda s: "{0}-stub".format(s), stubs): - src = os.path.join(self.srctree, "usr/lib/anaconda", stub) - dst = os.path.join(self.srctree, "usr/bin", stub) - if os.path.isfile(src): - shutil.copy2(src, dst) - - def copy_bootloaders(self): - srcdir = os.path.join(self.srctree, self.const.BOOTDIR) - dstdir = os.path.join(self.srctree, self.const.ANACONDA_BOOTDIR) - - if self.conf.buildarch in ("i386", "i586", "i686", "x86_64"): - for f in glob.iglob(os.path.join(srcdir, "memtest*")): - shutil.copy2(f, dstdir) - - elif self.conf.buildarch in ("ppc", "ppc64"): - f = os.path.join(srcdir, "efika.forth") - shutil.copy2(f, dstdir) - - elif self.conf.buildarch in ("sparc", "sparc64"): - for f in glob.iglob(os.path.join(srcdir, "*.b")): - shutil.copy2(f, dstdir) - - elif self.conf.buildarch == "ia64": - srcdir = os.path.join(self.srctree, self.const.BOOTDIR_IA64) - for f in glob.iglob(os.path.join(srcdir, "*")): - shutil.copy2(dstdir) - - def rename_repos(self): - src = os.path.join(self.srctree, "etc/yum.repos.d") - dst = os.path.join(self.srctree, "etc/anaconda.repos.d") - shutil.move(src, dst) - - def move_anaconda_files(self): - # move anaconda executable - src = os.path.join(self.srctree, "usr/sbin/anaconda") - dst = os.path.join(self.srctree, "usr/bin/anaconda") - shutil.move(src, dst) - - # move anaconda libraries - srcdir = os.path.join(self.srctree, self.const.ANACONDA_RUNTIME) - dstdir = os.path.join(self.srctree, "usr", self.conf.libdir) - for f in glob.iglob(os.path.join(srcdir, "lib*")): - shutil.move(f, dstdir) - - def create_modules_symlinks(self): - mkdir_(os.path.join(self.srctree, "modules")) - mkdir_(os.path.join(self.srctree, "firmware")) - remove_(os.path.join(self.srctree, self.const.MODDIR)) - remove_(os.path.join(self.srctree, self.const.FWDIR)) - os.symlink("/modules", os.path.join(self.srctree, self.const.MODDIR)) - os.symlink("/firmware", os.path.join(self.srctree, self.const.FWDIR)) - - def fix_man_pages(self): - # fix up some links for man page related stuff - for file in ("nroff", "groff", "iconv", "geqn", "gtbl", "gpic", - "grefer"): - - target = os.path.join("/mnt/sysimage/usr/bin", file) - name = os.path.join(self.srctree, "usr/bin", file) - if not os.path.isfile(name): - os.symlink(target, name) - - # fix /etc/man.config to point into /mnt/sysimage - manconf = os.path.join(self.srctree, self.const.MANCONF) - replace_(manconf, r"^MANPATH\s+(\S+)", "MANPATH\t/mnt/sysimage\g<1>") - replace_(manconf, r"^MANPATH_MAP\s+(\S+)\s+(\S+)", - "MANPATH_MAP\t\g<1>\t/mnt/sysimage\g<2>") - - def remove_locales(self): - langtable = os.path.join(self.srctree, self.const.LANGTABLE) - localepath = os.path.join(self.srctree, self.const.LOCALES) - - if os.path.isfile(langtable): - keep = set() - - with open(langtable, "r") as f: - lines = f.readlines() - - for line in lines: - line = line.strip() - if not line or line.startswith("#"): - continue - - fields = line.split("\t") - - dir = os.path.join(localepath, fields[1]) - if os.path.isdir(dir): - keep.add(fields[1]) - - locale = fields[3].split(".")[0] - dir = os.path.join(localepath, locale) - if os.path.isdir(dir): - keep.add(locale) - - for locale in os.listdir(localepath): - if locale not in keep: - path = os.path.join(localepath, locale) - remove_(path) - - def remove_unnecessary_files(self): - for root, dirs, files in os.walk(self.srctree): - for file in files: - path = os.path.join(root, file) - - if (fnmatch.fnmatch(path, "*.a") and - not path.count("kernel-wrapper/wrapper.a")): - os.unlink(path) - - if (fnmatch.fnmatch(path, "lib*.la") and - not path.count("gtk-2.0")): - os.unlink(path) - - if fnmatch.fnmatch(path, "*.py"): - pyo, pyc = path + "o", path + "c" - if os.path.isfile(pyo): - os.unlink(pyo) - if os.path.isfile(pyc): - os.unlink(pyc) - - os.symlink("/dev/null", pyc) - - # remove libunicode-lite - remove_(os.path.join(self.srctree, "usr", self.conf.libdir, - "libunicode-lite*")) - - def move_bins(self): - # move bin to usr/bin - scopy_(src_root=self.srctree, src_path="bin/*", - dst_root=self.srctree, dst_path="usr/bin", - ignore_errors=not self.conf.pedantic) - remove_(os.path.join(self.srctree, "bin")) - - # move sbin to /usr/sbin - scopy_(src_root=self.srctree, src_path="sbin/*", - dst_root=self.srctree, dst_path="usr/sbin", - ignore_errors=not self.conf.pedantic) - remove_(os.path.join(self.srctree, "sbin")) - - # fix broken links - brokenlinks = [] - for dir in ("bin", "sbin"): - dir = os.path.join(self.srctree, "usr", dir) - for root, dnames, fnames in os.walk(dir): - for fname in fnames: - fname = os.path.join(root, fname) - if os.path.islink(fname) and not os.path.exists(fname): - brokenlinks.append(fname) - - pattern = re.compile(r"^\.\./\.\./(bin|sbin)/(.*)$") - for link in brokenlinks: - target = os.readlink(link) - newtarget = pattern.sub(r"../\g<1>/\g<2>", target) - if newtarget != target: - os.unlink(link) - os.symlink(newtarget, link) - - def copy_custom_files(self): - scopy_(src_root=self.conf.datadir, src_path="*", - dst_root=self.dsttree, dst_path="") - - -class Boot(BaseImageClass): - - def __init__(self, product, workdir="/tmp"): - BaseImageClass.__init__(self) - self.product = product - self.workdir = workdir - - self.efiboot = os.path.join(self.conf.imgdir, "efiboot.img") - - def create(self): - self.pinfo(":: creating the boot iso image") - bootiso = os.path.join(self.workdir, "boot.iso") - if os.path.isfile(bootiso): - os.unlink(bootiso) - - if os.path.isfile(self.efiboot): - self.pinfo("creating efi capable boot iso") - efiargs = "-eltorito-alt-boot -e images/efiboot.img -no-emul-boot" - efigraft = "EFI/BOOT={0}".format(self.conf.efidir) - else: - efiargs = "" - efigraft = "" - - cmd = ("{0.MKISOFS} -U -A {1} -V {1} -volset {1} -J -joliet-long" - " -r -v -T -o {2} -b isolinux/isolinux.bin -c isolinux/boot.cat" - " -no-emul-boot -boot-load-size 4 -boot-info-table" - " {3} -graft-points isolinux={4} images={5} {6}") - cmd = cmd.format(self.cmd, self.product, bootiso, efiargs, - self.conf.isodir, self.conf.imgdir, efigraft) - - err, stdout = commands.getstatusoutput(cmd) - if err: - self.perror(stdout) - return None - - if os.path.isfile(self.cmd.ISOHYBRID): - self.pinfo("creating hybrid boot iso") - cmd = "{0.ISOHYBRID} {1}".format(self.cmd, bootiso) - err, stdout = commands.getstatusoutput(cmd) - if err: - self.pwarning(stdout) - - return bootiso diff --git a/src/pylorax/insttree.py b/src/pylorax/insttree.py deleted file mode 100644 index 740f8fc8..00000000 --- a/src/pylorax/insttree.py +++ /dev/null @@ -1,148 +0,0 @@ -# -# insttree.py -# -# Copyright (C) 2009 Red Hat, Inc. -# -# 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 2 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 . -# -# Red Hat Author(s): Martin Gracik -# - -import os -import re -import commands - -from base import BaseLoraxClass -from sysutils import * - - -class Kernel(object): - pass - - -class InstallTree(BaseLoraxClass): - - def __init__(self, yum, rootdir, updatesdir=None): - BaseLoraxClass.__init__(self) - self.yum = yum - self.rootdir = rootdir - self.updatesdir = updatesdir - - self.kpattern = re.compile(r"vmlinuz-(?P[-._0-9a-z]+?" - r"(?P(PAE)?)(?P(xen)?))$") - - def install_packages(self, packages): - for name in packages: - if not self.yum.install(name): - self.pwarning("no package {0} found".format(name)) - - self.yum.process_transaction() - - def run_ldconfig(self): - ldsoconf = os.path.join(self.rootdir, self.const.LDSOCONF) - - # XXX - with open(ldsoconf, "w") as f: - f.write("/usr/kerberos/{0}\n".format(self.conf.libdir)) - - procdir = os.path.join(self.rootdir, "proc") - mkdir_(procdir) - - # mount proc - cmd = "{0.MOUNT} -t proc proc {1}".format(self.cmd, procdir) - err, stdout = commands.getstatusoutput(cmd) - if err: - self.perror(stdout) - return - - cwd = os.getcwd() - - # chroot to the install tree directory, and run ldconfig - pid = os.fork() - if pid: - # parent - os.waitpid(pid, 0) - else: - # child - os.chroot(self.rootdir) - os.chdir("/") - - err, stdout = commands.getstatusoutput(self.cmd.LDCONFIG) - if err: - self.perror(stdout) - - os._exit(0) - - os.chdir(cwd) - - # umount proc - cmd = "{0.UMOUNT} {1}".format(self.cmd, procdir) - err, stdout = commands.getstatusoutput(cmd) - if err: - self.pwarning(stdout) - - # XXX - os.unlink(ldsoconf) - - def copy_updates(self): - if self.updatesdir and os.path.isdir(self.updatesdir): - scopy_(src_root=self.updatesdir, src_path="*", - dst_root=self.rootdir, dst_path="") - - @property - def kernels(self): - if self.conf.buildarch == "ia64": - kerneldir = self.const.BOOTDIR_IA64 - else: - kerneldir = self.const.BOOTDIR - - self.kerneldir = os.path.join(self.rootdir, kerneldir) - for filename in os.listdir(self.kerneldir): - m = self.kpattern.match(filename) - if m: - kernel = Kernel() - kernel.filename = filename - kernel.path = os.path.join(self.kerneldir, filename) - kernel.version = m.group("ver") - kernel.is_pae = bool(m.group("pae")) - kernel.is_xen = bool(m.group("xen")) - - yield kernel - - @property - def do_efi(self): - return os.path.isdir(os.path.join(self.rootdir, self.const.EFIDIR)) - - # XXX this should be just a temporary fix, - # should get fixed in the respective packages - def fix_problems(self): - # remove broken build and source links from the modules directory - for kernel in self.kernels: - moddir = os.path.join(self.rootdir, self.const.MODDIR, - kernel.version) - - build = os.path.join(moddir, "build") - if os.path.islink(build) and not os.path.exists(build): - os.unlink(build) - - source = os.path.join(moddir, "source") - if os.path.islink(source) and not os.path.exists(source): - os.unlink(source) - - # fix udev broken links - for fname in ("udevcontrol", "udevsettle", "udevtrigger"): - fname = os.path.join(self.rootdir, "sbin", fname) - if os.path.islink(fname): - os.unlink(fname) - os.symlink("udevadm", fname) diff --git a/src/pylorax/ltmpl.py b/src/pylorax/ltmpl.py index fab6d114..eeb20d67 100644 --- a/src/pylorax/ltmpl.py +++ b/src/pylorax/ltmpl.py @@ -19,21 +19,27 @@ # Red Hat Author(s): Martin Gracik # -from mako.template import Template as MakoTemplate -from mako.lookup import TemplateLookup as MakoTemplateLookup +import shlex + +from mako.template import Template +from mako.lookup import TemplateLookup -class Template(object): +class LoraxTemplate(object): def parse(self, template_file, variables): # we have to set the template lookup directories to ["/"], # otherwise the file includes will not work properly - lookup = MakoTemplateLookup(directories=["/"]) - template = MakoTemplate(filename=template_file, lookup=lookup) + lookup = TemplateLookup(directories=["/"]) + template = Template(filename=template_file, lookup=lookup) s = template.render(**variables) - # enumerate, strip and remove empty lines - lines = enumerate(s.splitlines(), start=1) - lines = map(lambda (n, line): (n, line.strip()), lines) - lines = filter(lambda (n, line): line, lines) + # split, strip and remove empty lines + lines = s.splitlines() + lines = map(lambda line: line.strip(), lines) + lines = filter(lambda line: line, lines) + + # split with shlex + lines = map(lambda line: shlex.split(line), lines) + return lines diff --git a/src/pylorax/output.py b/src/pylorax/output.py index b0630675..d3559db4 100644 --- a/src/pylorax/output.py +++ b/src/pylorax/output.py @@ -22,7 +22,16 @@ import sys import re -from decorators import singleton +import decorators + + +# output levels +CRITICAL = 50 +ERROR = 40 +WARNING = 30 +INFO = 20 +DEBUG = 10 +NOTSET = 0 # color codes @@ -48,48 +57,28 @@ TAGS = [(re.compile(r""), C_BOLD), (re.compile(r""), C_RED), (re.compile(r""), C_GREEN), (re.compile(r""), C_BLUE), - (re.compile(r""), C_RESET)] + (re.compile(r""), C_RESET)] -# output levels -CRITICAL = 50 -ERROR = 40 -WARNING = 30 -INFO = 20 -DEBUG = 10 -NOTSET = 0 - - -@singleton -class LoraxOutput(object): +@decorators.singleton +class LinuxTerminalOutput(object): def __init__(self): + self._output_level = INFO self._colors = True self._encoding = "utf-8" - self._output_level = INFO - self._ignore_msgs = set() + self._ignored_messages = set() self._indent_level = 0 - def basic_config(self, colors=None, encoding=None, output_level=None): - if colors is not None: - self._colors = colors + self.width = 79 - if encoding is not None: - self._encoding = encoding + def basic_config(self, output_level=None, colors=None, encoding=None): + self._output_level = output_level or self._output_level + self._colors = colors or self._colors + self._encoding = encoding or self._encoding - if output_level is not None: - self._output_level = output_level - - def ignore_message(self, messages): - if type(messages) is str: - self._ignore_msgs.add(messages) - else: - for msg in messages: - self.ignore_message(msg) - - @property - def ignore(self): - return self._ignore_msgs + def ignore(self, message): + self._ignored_messages.add(message) def indent(self): self._indent_level += 1 @@ -114,19 +103,19 @@ class LoraxOutput(object): def critical(self, s, file=sys.stdout): s = "** critical: {0}".format(s) if (self._output_level <= CRITICAL and - self.__raw(s) not in self.ignore): + self.__raw(s) not in self._ignored_messages): self.writeline(s, file=file) def error(self, s, file=sys.stdout): s = "** error: {0}".format(s) if (self._output_level <= ERROR and - self.__raw(s) not in self.ignore): + self.__raw(s) not in self._ignored_messages): self.writeline(s, file=file) def warning(self, s, file=sys.stdout): s = "** warning: {0}".format(s) if (self._output_level <= WARNING and - self.__raw(s) not in self.ignore): + self.__raw(s) not in self._ignored_messages): self.writeline(s, file=file) def info(self, s, file=sys.stdout): @@ -146,3 +135,7 @@ class LoraxOutput(object): for tag, ccode in TAGS: s = tag.sub("", s) return s + + +# set up the output type to be used by lorax +LoraxOutput = LinuxTerminalOutput diff --git a/src/pylorax/sysutils.py b/src/pylorax/sysutils.py index fd4123e5..386b2b2e 100644 --- a/src/pylorax/sysutils.py +++ b/src/pylorax/sysutils.py @@ -19,97 +19,27 @@ # Red Hat Author(s): Martin Gracik # -__all__ = ["mkdir_", "makedirs_", "remove_", "symlink_", "touch_", - "chown_", "chmod_", "replace_", "scopy_", "dcopy_"] +__all__ = ["joinpaths", "replace", "create_loop_dev", "remove_loop_dev", + "create_dm_dev", "remove_dm_dev"] import sys import os -import shutil -import glob -import fileinput import re -import pwd -import grp -import commands - -import logging -logger = logging.getLogger("sysutils") +import fileinput +import subprocess -class SysUtilsError(Exception): - pass +def joinpaths(*args, **kwargs): + path = os.path.sep.join(args) - -class SmartCopyError(SysUtilsError): - pass - - -class LinkerError(SysUtilsError): - pass - - -def mkdir_(dir): - if not os.path.isdir(dir): - os.mkdir(dir) - - -def makedirs_(dir): - if not os.path.isdir(dir): - os.makedirs(dir) - - -def remove_(path): - for fname in glob.iglob(path): - if os.path.islink(fname) or os.path.isfile(fname): - os.unlink(fname) - else: - shutil.rmtree(fname) - - -def symlink_(link_target, link_name, force=True): - if force and (os.path.islink(link_name) or os.path.isfile(link_name)): - os.unlink(link_name) - - os.symlink(link_target, link_name) - - -def touch_(fname): - if os.path.exists(fname): - os.utime(fname, None) + if kwargs.get("follow_symlinks"): + return os.path.realpath(path) else: - with open(fname, "w") as f: - pass + return path -def chown_(path, user=None, group=None, recursive=False): - uid = gid = -1 - - if user is not None: - uid = pwd.getpwnam(user)[2] - if group is not None: - gid = grp.getgrnam(group)[2] - - for fname in glob.iglob(path): - os.chown(fname, uid, gid) - - if recursive and os.path.isdir(fname): - for nested in os.listdir(fname): - nested = os.path.join(fname, nested) - chown_(nested, user, group, recursive) - - -def chmod_(path, mode, recursive=False): - for fname in glob.iglob(path): - os.chmod(fname, mode) - - if recursive and os.path.isdir(fname): - for nested in os.listdir(fname): - nested = os.path.join(fname, nested) - chmod_(nested, mode, recursive) - - -def replace_(fname, find, replace): +def replace(fname, find, replace): fin = fileinput.input(fname, inplace=1) pattern = re.compile(find) @@ -120,292 +50,43 @@ def replace_(fname, find, replace): fin.close() -def scopy_(src_path, dst_path, src_root="/", dst_root="/", symlinks=True, - ignore_errors=False): +def create_loop_dev(fname): + cmd = ["losetup", "-f"] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + rc = p.wait() + if not rc == 0: + return None - __copy(src_path, dst_path, src_root, dst_root, - symlinks, deps=False, ignore_errors=ignore_errors) + loopdev = p.stdout.read().strip() + cmd = ["losetup", loopdev, fname] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + rc = p.wait() + if not rc == 0: + return None -def dcopy_(src_path, dst_path, src_root="/", dst_root="/", symlinks=True, - ignore_errors=False): + return loopdev - __copy(src_path, dst_path, src_root, dst_root, - symlinks, deps=True, ignore_errors=ignore_errors) +def remove_loop_dev(dev): + cmd = ["losetup", "-d", dev] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + rc = p.wait() -def __copy(src_path, dst_path, src_root="/", dst_root="/", - symlinks=True, deps=False, ignore_errors=False): - if not src_root.endswith("/"): - src_root += "/" - if not dst_root.endswith("/"): - dst_root += "/" +def create_dm_dev(name, size, loopdev): + table = '0 {0} linear {1} 0'.format(size, loopdev) - smartcopy = SmartCopy(src_root, dst_root, symlinks, deps, ignore_errors) + cmd = ["dmsetup", "create", name, "--table", table] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + rc = p.wait() + if not rc == 0: + return None - src = os.path.join(src_root, src_path) - pattern = re.compile(r"(\*|\?|\[.*?\])") - if pattern.search(src): - fnames = glob.glob(src) - else: - fnames = [src] + return joinpaths("/dev/mapper", name) - if not fnames and not ignore_errors: - err_msg = "cannot stat '{0}': No such file or directory" - raise SysUtilsError(err_msg.format(src)) - for fname in fnames: - fname = fname.replace(src_root, "", 1) - smartcopy.copy(fname, dst_path) - - smartcopy.process() - - -# XXX -class SmartCopy(object): - - def __init__(self, src_root="/", dst_root="/", symlinks=True, deps=False, - ignore_errors=False): - - self.src_root = src_root - self.dst_root = dst_root - self.symlinks = symlinks - self.deps = deps - self.ignore_errors = ignore_errors - - self.linker = Linker(src_root) - - self.clear() - - def clear(self): - self.makedirs = [] - self.copyfiles = set() - self.links = set() - self.errors = [] - - def copy(self, src_path, dst_path): - src = os.path.normpath(os.path.join(self.src_root, src_path)) - dst = os.path.normpath(os.path.join(self.dst_root, dst_path)) - - # check if the source path exists - if not os.path.exists(src): - err_msg = "cannot stat '{0}': No such file or directory" - err_msg = err_msg.format(src) - if not self.ignore_errors: - raise SmartCopyError(err_msg) - else: - self.errors.append(err_msg) - return - - if os.path.isfile(src): - self.__copy_file(src_path, dst_path, src, dst) - elif os.path.isdir(src): - self.__copy_dir(src_path, dst_path, src, dst) - - def __copy_file(self, src_path, dst_path, src, dst): - # if destination is an existing directory, - # append the source filename to the destination - if os.path.isdir(dst): - dst = os.path.join(dst, os.path.basename(src)) - - # check if the new destination is still an existing directory - if os.path.isdir(dst): - err_msg = "cannot overwrite directory '{0}' with non-directory" - err_msg = err_msg.format(dst) - if not self.ignore_errors: - raise SmartCopyError(err_msg) - else: - self.errors.append(err_msg) - return - - if os.path.islink(src): - self.__copy_link(src_path, dst_path, src, dst) - else: - self.copyfiles.add((src, dst)) - - def __copy_dir(self, src_path, dst_path, src, dst): - # append the source directory name to the destination path - dirname = os.path.basename(src) - new_dst = os.path.join(dst, dirname) - - # remove the trailing "/" - if new_dst.endswith("/"): - new_dst = new_dst[:-1] - - if os.path.islink(src): - self.__copy_link(src_path, dst_path, src, new_dst, dir=True) - else: - # create the destination directory - if not os.path.isdir(new_dst): - makedirs_(new_dst) - elif os.path.isfile(new_dst): - err_msg = "cannot overwrite file '{0}' with directory" - err_msg = err_msg.format(new_dst) - if not self.ignore_errors: - raise SmartCopyError(err_msg) - else: - self.errors.append(err_msg) - return - - new_dst_path = os.path.join(dst_path, dirname) - - try: - fnames = os.listdir(src) - except OSError as why: - err_msg = "cannot list directory '{0}': {1}'" - err_msg = err_msg.format(src, why) - if not self.ignore_errors: - raise SmartCopyError(err_msg) - else: - self.errors.append(err_msg) - return - - for fname in fnames: - fname = os.path.join(src_path, fname) - self.copy(fname, new_dst_path) - - def __copy_link(self, src_path, dst_path, src, dst, dir=False): - if not self.symlinks: - # TODO - raise NotImplementedError - - # read the link target - link_target = os.readlink(src) - - # get the target source and destination paths - target_src_path = os.path.join(os.path.dirname(src_path), link_target) - target_dst_dir = os.path.join(dst_path, os.path.dirname(link_target)) - - # if the link target is an absolute path, - # make sure we copy it relative to the dst_root - if target_dst_dir.startswith("/"): - target_dst_dir = target_dst_dir[1:] - - # remove the trailing "/" - if target_dst_dir.endswith("/"): - target_dst_dir = target_dst_dir[:-1] - - # create the destination directory - target_dst = os.path.join(self.dst_root, target_dst_dir) - if not os.path.isdir(target_dst) and target_dst not in self.makedirs: - self.makedirs.append(target_dst) - - # copy the target along with the link - self.copy(target_src_path, target_dst_dir) - - # create the symlink named dst, pointing to link_target - self.links.add((link_target, dst)) - - def __get_deps(self): - deps = set() - - for src, dst in self.copyfiles: - if self.linker.is_elf(src): - deps = deps.union(self.linker.get_deps(src)) - - for src in deps: - src_path = src.replace(self.src_root, "", 1) - dst_path = os.path.dirname(src_path) - - # create the destination directory - dst_dir = os.path.join(self.dst_root, dst_path) - if not os.path.isdir(dst_dir) and dst_dir not in self.makedirs: - self.makedirs.append(dst_dir) - - self.copy(src_path, dst_path) - - def process(self): - if self.deps: - self.__get_deps() - - # create required directories - map(makedirs_, self.makedirs) - - # remove the dst, if it is a link to src - for src, dst in self.copyfiles: - if os.path.realpath(dst) == src: - os.unlink(dst) - - # copy all the files - for src, dst in self.copyfiles: - logger.debug("copying {0}".format(src)) - try: - shutil.copy2(src, dst) - except shutil.Error as why: - err_msg = "error copying file {0} -> {1}: {2}" - err_msg = err_msg.format(src, dst, why) - raise SmartCopyError(err_msg) - - # create symlinks - for target, name in self.links: - try: - symlink_(target, name) - except OSError as why: - err_msg = "error creating symlink {0} -> {1}: {2}" - err_msg = err_msg.format(name, target, why) - raise SmartCopyError(err_msg) - - -# XXX -class Linker(object): - - LIBDIRS = ("lib64", - "usr/lib64", - "lib", - "usr/lib") - - LDDBIN = "/usr/bin/ldd" - FILEBIN = "/usr/bin/file" - - def __init__(self, root="/"): - libdirs = map(lambda path: os.path.join(root, path), self.LIBDIRS) - libdirs = ":".join(libdirs) - - ld_linux = None - pattern = re.compile(r'^RTLDLIST="?(?P.*?)"?$') - - with open(self.LDDBIN, "r") as f: - for line in f: - m = pattern.match(line.strip()) - if m: - ld_linux = m.group("ld_linux") - break - - if ld_linux: - ld_linux = filter(os.path.isfile, ld_linux.split()) - - if not ld_linux: - raise LinkerError("cannot find the ld_linux executable") - - self.lddcmd = "LD_LIBRARY_PATH={0} {1} --list" - self.lddcmd = self.lddcmd.format(libdirs, ld_linux[0]) - - self.pattern = re.compile(r"^[-._/a-zA-Z0-9]+\s=>\s" - r"(?P[-._/a-zA-Z0-9]+)" - r"\s\(0x[0-9a-f]+\)$") - - def is_elf(self, fname): - cmd = "{0} --brief {1}".format(self.FILEBIN, fname) - err, stdout = commands.getstatusoutput(cmd) - if err: - raise LinkerError(stdout) - - if not stdout.count("ELF"): - return False - - return True - - def get_deps(self, fname): - cmd = "{0} {1}".format(self.lddcmd, fname) - err, stdout = commands.getstatusoutput(cmd) - if err: - raise LinkerError(stdout) - - deps = set() - for line in stdout.splitlines(): - m = self.pattern.match(line.strip()) - if m: - deps.add(m.group("lib")) - - return deps +def remove_dm_dev(dev): + cmd = ["dmsetup", "remove", dev] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + rc = p.wait() diff --git a/src/pylorax/yumbase.py b/src/pylorax/yumbase.py deleted file mode 100644 index c4110280..00000000 --- a/src/pylorax/yumbase.py +++ /dev/null @@ -1,107 +0,0 @@ -# -# yumbase.py -# -# Copyright (C) 2009 Red Hat, Inc. -# -# 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 2 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 . -# -# Red Hat Author(s): Martin Gracik -# - -import os -import ConfigParser - -import yum - - -def get_yum_base_object(installroot, repositories, mirrorlists=[], - tempdir="/tmp"): - - def sanitize_repo(repo): - if repo.startswith("/"): - return "file://{0}".format(repo) - elif (repo.startswith("http://") or repo.startswith("ftp://") - or repo.startswith("file://")): - return repo - else: - return None - - # sanitize the repositories - repositories = map(sanitize_repo, repositories) - mirrorlists = map(sanitize_repo, mirrorlists) - - # remove invalid repositories - repositories = filter(bool, repositories) - mirrorlists = filter(bool, mirrorlists) - - #cachedir = os.path.join(tempdir, "yum.cache") - #if not os.path.isdir(cachedir): - # os.mkdir(cachedir) - - yumconf = os.path.join(tempdir, "yum.conf") - c = ConfigParser.ConfigParser() - - # add the main section - section = "main" - data = {#"cachedir": cachedir, - #"keepcache": 0, - "gpgcheck": 0, - "plugins": 0, - "reposdir": "", - "tsflags": "nodocs"} - - c.add_section(section) - map(lambda (key, value): c.set(section, key, value), data.items()) - - # add the main repository - the first repository from list - section = "lorax-repo" - data = {"name": "lorax repo", - "baseurl": repositories[0], - "enabled": 1} - - c.add_section(section) - map(lambda (key, value): c.set(section, key, value), data.items()) - - # add the extra repositories - for n, extra in enumerate(repositories[1:], start=1): - section = "lorax-extra-repo-{0:d}".format(n) - data = {"name": "lorax extra repo {0:d}".format(n), - "baseurl": extra, - "enabled": 1} - - c.add_section(section) - map(lambda (key, value): c.set(section, key, value), data.items()) - - # add the mirrorlists - for n, mirror in enumerate(mirrorlists, start=1): - section = "lorax-mirrorlist-{0:d}".format(n) - data = {"name": "lorax mirrorlist {0:d}".format(n), - "mirrorlist": mirror, - "enabled": 1 } - - c.add_section(section) - map(lambda (key, value): c.set(section, key, value), data.items()) - - # write the yum configuration file - with open(yumconf, "w") as f: - c.write(f) - - # create the yum base object - yb = yum.YumBase() - - yb.preconf.fn = yumconf - yb.preconf.root = installroot - #yb.repos.setCacheDir(cachedir) - - return yb diff --git a/src/pylorax/yumhelper.py b/src/pylorax/yumhelper.py new file mode 100644 index 00000000..7c979202 --- /dev/null +++ b/src/pylorax/yumhelper.py @@ -0,0 +1,226 @@ +# +# yumhelper.py +# +# Copyright (C) 2010 Red Hat, Inc. +# +# 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 2 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 . +# +# Red Hat Author(s): Martin Gracik +# + +import logging +logger = logging.getLogger("pylorax.yumhelper") + +import sys +import os +import fnmatch +import glob +import shutil + +import yum +import yum.callbacks +import yum.rpmtrans + +import output +from sysutils import joinpaths + + +class LoraxYumHelper(object): + + def __init__(self, yb): + self.yb = yb + self.installroot = self.yb.conf.installroot + self.installed_packages = self.get_packages("installed") + + def install(self, pattern): + try: + self.yb.install(name=pattern) + except yum.Errors.InstallError: + try: + self.yb.install(pattern=pattern) + except yum.Errors.InstallError as e: + msg = "cannot install {0}: {1}" + logger.error(msg.format(pattern, e)) + return False + + return True + + def remove(self, package, pattern_list): + if package: + pkgobj = self.installed_packages.get(package) + if not pkgobj: + msg = "cannot erase {0}: Package not installed" + logger.error(msg.format(package)) + return False + + # XXX match every file if no pattern specified + if None in pattern_list: + if len(pattern_list) > 1: + msg = "redundant patterns specified, " \ + "removing whole package {0}" + logger.warning(msg.format(pkgobj.name)) + + pattern_list = ["*"] + + logger.debug("erasing package {0}".format(pkgobj.name)) + + total = len(pkgobj.filelist) + newline = False + count = 0 + for n, fname in enumerate(pkgobj.filelist, start=1): + msg = "[{0:3.0f}%] erasing {1.ui_envra}\r" + msg = msg.format(float(n) / float(total) * 100, pkgobj) + output.LoraxOutput().write(msg) + newline = True + + for pattern in pattern_list: + if fnmatch.fnmatch(fname, pattern): + fullpath = joinpaths(self.installroot, fname) + if os.path.isfile(fullpath): + os.unlink(fullpath) + logger.debug("removed {0}".format(fullpath)) + count += 1 + + if newline: + output.LoraxOutput().write("\n") + + if not count: + msg = "no files matched patterns {0}" + logger.warning(msg.format(pattern_list)) + + else: + for pattern in pattern_list: + msg = "erasing files matching pattern {0}" + logger.info(msg.format(pattern)) + + fullpattern = joinpaths(self.installroot, pattern) + count = 0 + for fname in glob.glob(fullpattern): + if os.path.isdir(fname): + shutil.rmtree(fname) + else: + os.unlink(fname) + + logger.debug("removed {0}".format(fname)) + count += 1 + + if not count: + msg = "no files matched pattern {0}" + logger.error(msg.format(pattern)) + + return True + + def process_transaction(self): + self.yb.buildTransaction() + + self.yb.repos.setProgressBar(LoraxDownloadCallback()) + + try: + self.yb.processTransaction(callback=LoraxTransactionCallback(), + rpmDisplay=LoraxRpmCallback()) + except yum.Errors.YumRPMCheckError as e: + logger.error("yum transaction error: {0}".format(e)) + sys.exit(1) + + self.yb.closeRpmDB() + + self.installed_packages = self.get_packages("installed") + + def search(self, pattern): + pl = self.yb.doPackageLists(patterns=[pattern]) + return pl.installed, pl.available + + def get_packages(self, type="available"): + if type not in ("available", "installed"): + raise TypeError + + pl = self.yb.doPackageLists(pkgnarrow=type) + + d = {} + for pkgobj in getattr(pl, type): + d[pkgobj.name] = pkgobj + + return d + + +class LoraxDownloadCallback(yum.callbacks.DownloadBaseCallback): + + def __init__(self): + yum.callbacks.DownloadBaseCallback.__init__(self) + self.output = output.LoraxOutput() + + def updateProgress(self, name, frac, fread, ftime): + """ + Update the progress bar + @param name: filename + @param frac: progress fraction (0 -> 1) + @param fread: formated string containing BytesRead + @param ftime: formated string containing remaining or elapsed time + """ + + # XXX + msg = "{0}; {1}; {2}; {3}\r".format(name, frac, fread, ftime) + + self.output.write(msg) + if frac == 1: + self.output.write("\n") + + +class LoraxTransactionCallback(object): + + def __init__(self): + self.output = output.LoraxOutput() + + def event(self, state, data=None): + # XXX + if state == yum.callbacks.PT_DOWNLOAD: + self.output.write("downloading packages\n") + elif state == yum.callbacks.PT_DOWNLOAD_PKGS: + pass + elif state == yum.callbacks.PT_GPGCHECK: + self.output.write("checking package signatures\n") + elif state == yum.callbacks.PT_TEST_TRANS: + self.output.write("running test transaction\n") + elif state == yum.callbacks.PT_TRANSACTION: + self.output.write("running transaction\n") + + +class LoraxRpmCallback(yum.rpmtrans.RPMBaseCallback): + + def __init__(self): + yum.rpmtrans.RPMBaseCallback.__init__(self) + self.output = output.LoraxOutput() + + def event(self, package, action, te_current, te_total, + ts_current, ts_total): + + info = "({0:3d}/{1:3d}) [{2:3.0f}%] {3} " + info = info.format(ts_current, ts_total, + float(te_current) / float(te_total) * 100, + self.action[action].lower()) + + pkg = "{0}".format(package) + + infolen, pkglen = len(info), len(pkg) + if (infolen + pkglen) > self.output.width: + pkg = "{0}...".format(pkg[:self.output.width-infolen-3]) + + msg = "{0}{1}\r".format(info, pkg) + self.output.write(msg) + if te_current == te_total: + self.output.write("\n") + + def filelog(self, package, action): + if self.fileaction.get(action) == "Installed": + logger.debug("{0} installed successfully".format(package))