PERFORCE change 125068 for review

Ivan Voras ivoras at FreeBSD.org
Sat Aug 11 14:57:23 PDT 2007


http://perforce.freebsd.org/chv.cgi?CH=125068

Change 125068 by ivoras at ivoras_finstall on 2007/08/11 21:57:20

	- Integrated makeimage (ISO image creator), pybackend and the installer
	- pybackend now starts by default from the live CD
	- the liveCD "install" user now has a desktop icon pointing to the installer
	- fixed minor bugs in all three components

Affected files ...

.. //depot/projects/soc2007/ivoras_finstall/installer/finstall.py#9 edit
.. //depot/projects/soc2007/ivoras_finstall/makeimage/bundles/bundle-spec#4 edit
.. //depot/projects/soc2007/ivoras_finstall/makeimage/bundles/installer.desktop#1 add
.. //depot/projects/soc2007/ivoras_finstall/makeimage/bundles/prelogin#1 add
.. //depot/projects/soc2007/ivoras_finstall/makeimage/bundles/prelogin.txt#1 add
.. //depot/projects/soc2007/ivoras_finstall/makeimage/bundles/pybackend.sh#1 add
.. //depot/projects/soc2007/ivoras_finstall/makeimage/makeimage.py#10 edit
.. //depot/projects/soc2007/ivoras_finstall/pybackend/systoolengine.py#6 edit

Differences ...

==== //depot/projects/soc2007/ivoras_finstall/installer/finstall.py#9 (text+ko) ====

@@ -1,5 +1,28 @@
-import sys
-import time
+#!/usr/local/bin/python
+# Copyright (c) 2007. Ivan Voras <ivoras at freebsd.org>
+# Redistribution and use in source and binary forms, with or without 
+# modification, are permitted provided that the following conditions are met:
+#
+#   1. Redistributions of source code must retain the above copyright notice, 
+#      this list of conditions and the following disclaimer.
+#   2. Redistributions in binary form must reproduce the above copyright notice,
+#      this list of conditions and the following disclaimer in the 
+#      documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY 
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY 
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# finstall Installer
+
+import os,sys,time
 import logging
 from types import MethodType
 from xmlrpclib import ServerProxy
@@ -13,7 +36,9 @@
 	# Configured tracks
 	Steps_Novice = [
 		{ "tile" : "intro" },
-		{ "tile" : "ndisks" }
+		{ "tile" : "ndisks" },
+		{ "tile" : "nparts" },
+		{ "tile" : "nfilesys" }
 	]
 
 
@@ -27,6 +52,7 @@
 		self.step_current = 0
 		self.step_track = MainWin.Steps_Novice
 		self._load_tile_nr(self.step_current)
+		self.backtrack = []
 
 
 	def __getitem__(self, key):
@@ -65,6 +91,16 @@
 		self._load_tile(self.step_track[tile_nr]["tile"])
 
 
+	def _set_next_tile(self, tile):
+		found = False
+		for i, t in enumerate(self.step_track):
+			if t["tile"] == tile:
+				self.step_current = i-1		# Actually this is not a clean hack, but it'll do for now
+				found = True
+		if not found:
+			logging.error("_set_next_tile cannot set tile to %s. Bogosity ahead." % tile)
+
+
 	# Handlers for the main window elements (the window itself, Next/Previous
 	# buttons, etc.
 	def on_mainwin_delete_event(self, obj, data):
@@ -113,6 +149,7 @@
 			except:
 				logging.exception("Error executing on_next handler in %s" % self.step_track[self.step_current]["tile"])
 				return
+		self.backtrack.append(self.step_track[self.step_current]["tile"])
 		self.step_current += 1
 		if self.step_current >= len(self.step_track):
 			self.step_current = 0	# XXX: Fix by disabling next/previous
@@ -130,9 +167,19 @@
 			except:
 				logging.exception("Error executing on_previous in %s" % self.step_track[self.step_current]["tile"])
 				return
-		self.step_current -= 1
-		if self.step_current < 0:
-			self.step_current = len(self.step_track)-1	# XXX: fix by disabling next/previous
+		if len(self.backtrack) == 0 and self.step_current != 0:
+			self._show_message("Nothing to go back to!", "Error", p_type=gtk.MESSAGE_ERROR)
+			return
+		if len(self.backtrack) == 0:
+			self.step_current = 0
+		else:
+			tile = self.backtrack.pop()
+			self.step_current = -1
+			for i, t in enumerate(self.step_track):
+				if t["tile"] == tile:
+					self.step_current = i
+			if self.step_current < 0:
+				self._show_message("Cannot find tile %s" % tile, "Error", p_type.gtk.MESSAGE_ERROR)
 		self._load_tile_nr(self.step_current)
 
 
@@ -149,11 +196,13 @@
 
 	def intro_on_next(self):
 		if self["radio_novice"].get_active():
+			logging.info("track=Novice")
 			pass # The default track is Novice
 		elif self["radio_standard"].get_active():
 			print "standard"
 		elif self["radio_expert"].get_active():
 			print "expert"
+		self.trackdata = {}
 		return True
 
 
@@ -161,7 +210,7 @@
 	def ndisks_on_load(self):
 		self._load_label(self["label2"], "ndisks.txt")
 		drives = self.server.GetDrives()
-		if len(drives) < 0:
+		if len(drives) < 1:
 			self._show_message("No usable drives detected.\nThis is a fatal error and the Installer cannot continue.", "Error", p_type=gtk.MESSAGE_ERROR)
 			return
 
@@ -178,9 +227,46 @@
 		return True
 
 
-	# Handlers for "win1"
-	def win1_on_button1_clicked(self, obj):
-		print "clicked"
+	def ndisks_on_next(self):
+		row, col = self["disktree"].get_cursor()
+		if row == None or type(row) != type((1,)):
+			self._show_message("You need to pick a drive onto which FreeBSD will be installed.", "User intervention required")
+			return False
+		model = self["disktree"].get_model()
+		drive = model.get_value(model.get_iter(row), 0)
+		logging.info("ndisks.drive=%s" % drive)
+		self.trackdata["drive"] = drive
+		parts = self.server.GetDrivePartitions(drive)
+		if len(parts) == 0:
+			# The drive is not partitioned, so mark it for default configuration
+			self.trackdata["parts"] = None
+			logging.info("Drive %s is not partitioned" % drive)
+			self._set_next_tile("nfilesys")
+		else:
+			self.trackdata["parts"] = parts
+			logging.info("Drive %s is partitioned" % drive)
+			self._set_next_tile("nparts")
+
+		return True
+
+
+	def nparts_on_load(self):
+		parts = self.trackdata["parts"]
+		list = gtk.ListStore(str, str, str, str)
+		part_list = parts.keys()
+		part_list.sort()
+		for part in part_list:
+			list.append([part, parts[part]["fs_type"], "%d MB" % parts[part]["mediasize"]])
+		self["parttree"].set_model(list)
+		self["parttree"].append_column(self._make_column("Partition", 0, True))
+		self["parttree"].append_column(self._make_column("File system", 1))
+		self["parttree"].append_column(self._make_column("Size", 2, True))
+		self["parttree"].append_column(self._make_column("Valid target?", 3, True))
+		self["parttree"].set_cursor(0)
+		return True
+
+
+os.chdir(os.path.split(sys.argv[0])[0]) # attempt to chdir into the directory where the script is located
 
 logging.basicConfig(level=logging.DEBUG)
 w = MainWin()

==== //depot/projects/soc2007/ivoras_finstall/makeimage/bundles/bundle-spec#4 (text+ko) ====

@@ -4,6 +4,7 @@
 #	kw : expand keywords in the (text) file
 #	x  : set execute bit to destination file
 #	a  : append to destination file
+#	d  : directory (copy recursively)
 /boot/loader.conf=loader.conf;kw
 /etc/rc.conf=rc.conf;kw
 /etc/X11/xorg.conf=xorg.conf;kw
@@ -19,4 +20,8 @@
 /install/.config/autostart/xfce4-tips-autostart.desktop=xfce4-tips-autostart.desktop
 /install/.xinitrc=dot.xinitrc;kw
 /install/.config/xfce4/mcs_settings/gtk.xml=gtk.xml
+/install/installer=../../installer;d
+/install/pybackend=../../pybackend;d
+/install/Desktop/installer.desktop=installer.desktop
 /usr/local/etc/fonts/local.conf=font.local.conf;kw
+/usr/local/etc/rc.d/pybackend.sh=pybackend.sh;kw;x

==== //depot/projects/soc2007/ivoras_finstall/makeimage/makeimage.py#10 (text+ko) ====

@@ -22,7 +22,7 @@
 
 # finstall LiveCD image creator
 
-import os, os.path, sys, stat
+import os, os.path, sys, stat, shutil
 from time import strftime
 from getopt import getopt, GetoptError
 from util import nukedir, execute, printmsg, cmdout, readline, initutils, getpkgdeps, getpkgfullname
@@ -54,7 +54,9 @@
 	print "	-b		Do buildworld / buildkernel before proceeding"
 	print "	-c		Assume installworld / installkernel phase has been"
 	print "			done in WORKDIR/livecd and proceed with configuration"
-	print "			and ISO image build"
+	print "			and ISO image build. If specified only once, packages"
+	print "			will get built and installed, if specified twice,"
+	print "			packages will be skipped."
 	if exit:
 		sys.exit(1)
 	else:
@@ -66,6 +68,7 @@
 KERNEL = "GENERIC"
 DoBuild = False
 DoMakeRoot = True	# Create / install livecd tree
+DoMakePkgs = True
 LABEL = "FreeBSD7"	# ISO9660 Volume label
 BUNDLEDIR = "bundles"
 BUNDLEFILE = "bundle-spec"
@@ -95,7 +98,10 @@
 	elif o == "-b":
 		DoBuild = True
 	elif o == "-c":
-		DoMakeRoot = False
+		if DoMakeRoot:
+			DoMakeRoot = False
+		else:
+			DoMakePkgs = False # if -c is specified twice, skip packages
 	elif o == "-i":
 		ISO = a
 	elif o == "-x":
@@ -142,6 +148,10 @@
 if not os.path.exists("%s/%s" % (WORKDIR, ZIMAGE_IMGNAME)):
 	print "No %s" % ZIMAGE_IMGNAME
 	sys.exit(1)
+if os.path.exists("/dev/md60"):
+	if os.popen("/sbin/mount -p").read().find("/dev/md60") != -1:
+		execute("umount /dev/md60")
+	execute("mdconfig -d -u 60")
 execute("mdconfig -a -t vnode -f %s -u 60" % ZIMAGE_IMGNAME)
 if DoMakeRoot:
 	execute("newfs /dev/md60")
@@ -180,7 +190,7 @@
 str_time = strftime("%H:%M")
 str_date = strftime("%Y-%m-%d")
 
-if PKGLISTFILE != None:
+if PKGLISTFILE != None and DoMakePkgs:
 	# Install packages into the liveCD tree, using chroot
 	printmsg("Bundling packages")
 	master_pkglist = []
@@ -249,24 +259,33 @@
 			flags = []
 			dest_file, src_file = line.split("=", 1)
 		cflist.append(dest_file)
-		file_contents = file("%s/%s" % (BUNDLEDIR, src_file), "r").read()
-		if "kw" in flags:
-			file_contents = file_contents.replace("$label$", LABEL)
-			file_contents = file_contents.replace("$time$", str_time)
-			file_contents = file_contents.replace("$date$", str_date)
-			file_contents = file_contents.replace("$dest_file$", dest_file)
-			file_contents = file_contents.replace("$src_file$", src_file)
-		filename = "%s%s" % (DESTDIR, dest_file)
-		if not os.path.exists(os.path.dirname(filename)):
-			os.makedirs(os.path.dirname(filename))
-		if "a" in flags:
-			df = file(filename, "a")
-		else:
-			df = file(filename, "w")
-		df.write(file_contents)
-		df.close()
-		if "x" in flags:
-			os.chmod("%s%s" % (DESTDIR, dest_file), stat.S_IRUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
+		if not 'd' in flags: # regular file
+			file_contents = file("%s/%s" % (BUNDLEDIR, src_file), "r").read()
+			if "kw" in flags:
+				file_contents = file_contents.replace("$label$", LABEL)
+				file_contents = file_contents.replace("$time$", str_time)
+				file_contents = file_contents.replace("$date$", str_date)
+				file_contents = file_contents.replace("$dest_file$", dest_file)
+				file_contents = file_contents.replace("$src_file$", src_file)
+			filename = "%s%s" % (DESTDIR, dest_file)
+			if not os.path.exists(os.path.dirname(filename)):
+				os.makedirs(os.path.dirname(filename))
+			if "a" in flags:
+				df = file(filename, "a")
+			else:
+				df = file(filename, "w")
+			df.write(file_contents)
+			df.close()
+			if "x" in flags:
+				os.chmod("%s%s" % (DESTDIR, dest_file), stat.S_IRUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
+		else: # copy entire directory
+			src_dir_name = "%s/%s" % (BUNDLEDIR, src_file)
+			dst_dir_name = "%s%s" % (DESTDIR, dest_file)
+			if os.path.exists(dst_dir_name):
+				printmsg("Removing %s" % dst_dir_name)
+				shutil.rmtree(dst_dir_name)
+			printmsg("copytree %s -> %s" % (src_dir_name, dst_dir_name))
+			shutil.copytree(src_dir_name, dst_dir_name, True)
 	if len(cflist) != 0:
 		printmsg("LiveCD will contain config files: %s" % " ".join(cflist))
 	f.close()

==== //depot/projects/soc2007/ivoras_finstall/pybackend/systoolengine.py#6 (text+ko) ====

@@ -19,7 +19,7 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# SysToolD Engine 
+# SysToolD Engine: implements SysToolD XML-RPC methods
 
 import os, sys
 import re
@@ -104,13 +104,15 @@
 		found hardware.
 		RETURN VALUE:
 		The return value is a dictionary with device names
-		as keys and another dictionary as values.
-			{
-				"ad0" : {
-						"name": "ACME MegaDrive"
-						"mediasize": 300000  # (MB)
-					}
-			}"""
+		as keys and another dictionary as values, containing keys:
+			name, mediasize
+		For example:
+		{
+			"ad0" : {
+					"name": "ACME MegaDrive",
+					"mediasize": 300000  # (MB)
+				}
+		}"""
 		drive_list = freebsd.get_sysctl("kern.disks").split(" ")
 		dmesg = freebsd.get_dmesg()
 		drive_dict = {}
@@ -151,14 +153,25 @@
 		ARGUMENTS:
 		drive : The drive to inspect
 		RETURN VALUE:
-		The return value is a list of dictionaries."""
+		The return value is a dictionary whose keys are partition names
+		and values are dictionaries containing keys:
+			name, mediasize, sectorsize, type
+		For example:
+		{
+			"ad0s1a" : {
+				"name" : "ad0s1a",
+				"mediasize" : 100000, # MB
+				"sectorsize" : 512,
+				"type" : "BSD"
+				}
+		}"""
 		parts = {}
 		used_parts = []
 		geomxml = freebsd.get_geom_xml()
 		num_msdos_parts = 1
 		# enumerate MSDOS partitions
 		for cls in geomxml["mesh"]["class"]:
-			if cls["name"].data == "MBR":
+			if cls["name"].data == "MBR" and "geom" in cls:
 				for geom in tolist(cls["geom"]):
 					if geom["name"].data == drive:
 						for prov in tolist(geom["provider"]):
@@ -172,7 +185,7 @@
 							num_msdos_parts += 1
 		# process BSDlabels, both dedicated and inside MSDOS partitions
 		for cls in geomxml["mesh"]["class"]:
-			if cls["name"].data == "BSD":
+			if cls["name"].data == "BSD" and "geom" in cls:
 				for geom in tolist(cls["geom"]):
 					if geom["name"].data == drive:
 						# "raw" BSD partitions directly on the drive


More information about the p4-projects mailing list