#!/usr/bin/python

# $Id: splitdistro,v 1.5 2002/11/07 13:02:53 luigi Exp $
######
#
#   Copyright 2002 Luigi Bitonti
#   
#   Copyright 2002 Redhat Inc.
#
#   This program is a modified version of the splitdistro
#   script included in anaconda 7.3.7 (Redhat Linux installer).
#
#   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, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#



# These dirs, along with RPMS, make up disc 2
disc2dirs = [ "preview" ]

# These files appear on all binary CDs
jointfiles = [ "EULA", "RPM-GPG-KEY", "README", "autorun" ]

targetSize = 640 * 1024.0 * 1024.0

# Leave about 1.2MB of space on the disc
fudgeFactor = 1.2 * 1024 * 1024

#-----------------

import sys
import os
import os.path
import string
import getopt
import time
import types

def stamp(path, releasestr, name, arch, startedAt):
    f = open("%s/.%s-%s" % (path, name, arch), "w")
    f.write("%f\n" % startedAt)
    f.write("%s %s\n" % (releasestr, name))
    f.close()

def moveFiles(srcDir, destDir, files):
    for fn in files:
	src = "%s/%s" % (srcDir, fn)
	dest = "%s/%s" % (destDir, fn)
	try:
		os.rename(src, dest)
	except:
		print "in moveFiles, src was %s, dest was %s" % (src, dest)
		raise RuntimeError

def excessFiles(path, fileList, maxSize):
    total = 0
    moveList = []
    found = 0

    for fns in fileList:
	if type(fns) == types.StringType:
	    fns = [ fns ]

	size = 0
	for fn in fns:
	    thisSize = os.path.getsize(path + "/" + fn)
	    size = size + thisSize + ((thisSize + 2047) % 2048)

	if size + total  < maxSize:
	    total = total + size
	else:
	    # once we're done, we're done
            if found == 0:
#                print "straw was %s" % (fns,)
                found = 1
	    total = maxSize
	    moveList.extend(fns)

    return moveList

class DirectoryIterator:
    def __init__(self):
        self.inodes = {}
    
    def traverse (self, arg, dirname, names):
        for name in names:
            sb = os.lstat (dirname + "/" + name)
            if not self.inodes.has_key(sb[1]):
                self.inodes[sb[1]] = sb[6]

    def total(self):
        total = 0
        for size in self.inodes.values():
            total = total + size
	return total

def spaceUsed(path):
    foo = DirectoryIterator()
    os.path.walk (path, foo.traverse, None)
    return foo.total()

startedAt = time.time()

fns = {}

(args, extra) = getopt.getopt(sys.argv[1:], '', [ 'fileorder=', 'release=' ])

if len(extra) != 2:
    print "splitdistro --fileorder <file> [--release <comment>] <toppath> <arch>"
    sys.exit(1)

releasestr = ""
packageOrderFile = None
for n in args:
    (str, arg) = n
    if str == '--fileorder':
	packageOrderFile = arg
    if str == '--release':
	releasestr = arg

if not packageOrderFile:
    print "splitdistro --fileorder <file> [--release <comment>] <toppath> <arch>"
    sys.exit(1)


arch = extra[1]
distDir = os.path.normpath(extra[0] + "/" + arch)
srcDir = os.path.normpath(extra[0] + "/SRPMS")

if not os.path.isdir(distDir):
    print "error: %s is not a directory" % distDir
    sys.exit(1)

# If there's no SRPMS directory we don't include any source package
if not os.path.isdir(srcDir):
	includeSRPMS = 0
else:
	includeSRPMS = 1
# The original version had following lines:
#    print "error: %s is not a directory" % srcDir
#    sys.exit(1)

disc1Dir = distDir + "-disc1"
disc2Dir = distDir + "-disc2"
disc3Dir = distDir + "-disc3"
disc1SrcDir = distDir + "-disc4"
disc2SrcDir = distDir + "-disc5"
# we have leftover space on the third disc to use for sources
disc3SrcDir = distDir + "-disc3"

id = 0

files = os.listdir(distDir + "/RedHat/RPMS")
files.sort()
packages = {}
for file in files:
    l = string.split(file, ".")
    pkg = string.join(l[:-2], ".")
    if packages.has_key(pkg):
	packages[pkg].append(file)
    else:
	packages[pkg] = [ file ]

f = open(packageOrderFile, "r")
binPkgList = []
for pkg in f.readlines():
    # chop
    pkg = pkg[:len(pkg) - 1]
    if pkg[0:8] != "warning:":
	binPkgList.append(packages[pkg])

del f

print "Splitting tree..."

totalsize = spaceUsed(distDir)
rpmsize = spaceUsed(distDir + "/RedHat/RPMS")
dirsize = 0
for dir in disc2dirs:
    what = distDir + "/" + dir
    if os.access(what, os.R_OK):
        dirsize = dirsize + spaceUsed(distDir + "/" + dir)

disc1used = totalsize - rpmsize - dirsize

os.system("rm -rf %s %s %s %s %s" % ( disc1Dir, disc2Dir, disc1SrcDir,
				   disc2SrcDir, disc3SrcDir))
os.system("mkdir -p %s %s/SRPMS %s/SRPMS %s/RedHat/RPMS %s/RedHat/RPMS %s/SRPMS" % 
	    (disc1Dir, disc1SrcDir, disc2SrcDir, disc2Dir, 
             disc3Dir, disc3SrcDir))

print "Creating disc1..."

os.system("cp -al %s/. %s" % (distDir, disc1Dir))
stamp(disc1Dir, releasestr, "disc1", arch, startedAt)

print "Creating disc2..."
stamp(disc2Dir, releasestr, "disc2", arch, startedAt)

for file in jointfiles:
    src = "%s/%s" % (disc1Dir, file)
    dest = "%s/%s" %(disc2Dir, file)
    try:
	os.link(src, dest)
    except OSError, (errno, msg):
	print "**** WARNING linking %s to %s: %s" % (src, dest, msg)

disc2pkgs = excessFiles(distDir + "/RedHat/RPMS", binPkgList, 
			targetSize - disc1used - fudgeFactor)

moveFiles("%s/RedHat/RPMS" % disc1Dir, 
	  "%s/RedHat/RPMS" % disc2Dir, 
	  disc2pkgs);
disc1Size = spaceUsed(disc1Dir)

print "Creating disc3..."
stamp(disc3Dir, releasestr, "disc3", arch, startedAt)

for file in jointfiles:
    src = "%s/%s" % (disc1Dir, file)
    dest = "%s/%s" %(disc3Dir, file)
    try:
	os.link(src, dest)
    except OSError, (errno, msg):
	print "**** WARNING linking %s to %s: %s" % (src, dest, msg)

disc3pkgs = excessFiles(distDir + "/RedHat/RPMS", binPkgList, 
			targetSize + disc1Size - disc1used - fudgeFactor)

moveFiles("%s/RedHat/RPMS" % disc2Dir, 
	  "%s/RedHat/RPMS" % disc3Dir, 
	  disc3pkgs);

# Conditional inclusion of the SRPMS files
if includeSRPMS:
	print "Creating first source disc..."
	os.system("cp -al %s/. %s/SRPMS" % (srcDir, disc1SrcDir))
	stamp(disc1SrcDir, releasestr, "disc4", arch, startedAt)

	print "Creating second source disc..."
	stamp(disc2SrcDir, releasestr, "disc5", arch, startedAt)

	srcPkgList = os.listdir("%s/SRPMS" % disc1SrcDir)
	srcPkgList.sort()
	disc2pkgs = excessFiles(srcDir, srcPkgList,
			targetSize - fudgeFactor)
	moveFiles("%s/SRPMS" % disc1SrcDir, 
		  "%s/SRPMS" % disc2SrcDir, 
	  	disc2pkgs);
	srcDisc1Size = spaceUsed(disc1SrcDir)

	print "Dropping remainder of sources on third disc..."
	disc3pkgs = excessFiles(srcDir, srcPkgList,
        	                srcDisc1Size + targetSize - fudgeFactor)
	moveFiles("%s/SRPMS" % disc2SrcDir,
        	  "%s/SRPMS" % disc3SrcDir,
          	disc3pkgs)

#sys.exit(0)

sys.stdout.flush()

os.system("du -sh %s %s %s %s %s" % (disc1Dir, disc2Dir, disc3Dir,
                                     disc1SrcDir, disc2SrcDir))
