| 1 : |
tmcnulty
|
1.1
|
#!/usr/bin/python |
| 2 : |
|
|
# |
| 3 : |
|
|
# GKB - GNU Kernel Builder |
| 4 : |
tmcnulty
|
1.2
|
# Copyright (C) 2003-2004 Tobias McNulty, Mark Guertin |
| 5 : |
tmcnulty
|
1.1
|
# |
| 6 : |
|
|
# This program is free software; you can redistribute it and/or modify |
| 7 : |
|
|
# it under the terms of the GNU General Public License as published by |
| 8 : |
|
|
# the Free Software Foundation; either version 2 of the License, or |
| 9 : |
|
|
# (at your option) any later version. |
| 10 : |
|
|
# |
| 11 : |
|
|
# This program is distributed in the hope that it will be useful, |
| 12 : |
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 : |
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 : |
|
|
# GNU General Public License for more details. |
| 15 : |
|
|
# |
| 16 : |
|
|
# You should have received a copy of the GNU General Public License |
| 17 : |
|
|
# along with this program; if not, write to the Free Software |
| 18 : |
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 19 : |
|
|
# |
| 20 : |
|
|
# Ported from PHP version Copyright (c) Tobias McNulty 2000-2003 |
| 21 : |
|
|
|
| 22 : |
tmcnulty
|
1.20
|
import sys, os, ConfigParser, popen2 |
| 23 : |
tmcnulty
|
1.1
|
import xml.parsers.expat |
| 24 : |
tmcnulty
|
1.21
|
import md5, string |
| 25 : |
tmcnulty
|
1.1
|
from ftplib import FTP |
| 26 : |
|
|
from commands import getoutput |
| 27 : |
|
|
from shutil import copy, move |
| 28 : |
|
|
from string import split |
| 29 : |
|
|
from urllib2 import urlopen |
| 30 : |
|
|
from ClientForm import ParseResponse |
| 31 : |
|
|
|
| 32 : |
tmcnulty
|
1.29
|
|
| 33 : |
tmcnulty
|
1.1
|
debug=0 |
| 34 : |
tmcnulty
|
1.22
|
clean=1 |
| 35 : |
|
|
dont_build=0 |
| 36 : |
tmcnulty
|
1.1
|
verbose=1 |
| 37 : |
|
|
|
| 38 : |
|
|
# parse host-specific configuration information from gkb.cfg |
| 39 : |
|
|
config = ConfigParser.ConfigParser() |
| 40 : |
|
|
config.readfp(open('gkb-host.cfg')) |
| 41 : |
|
|
buildroot=config.get("options","buildroot") |
| 42 : |
|
|
host=config.get("options","host") |
| 43 : |
|
|
passwd=config.get("options","passwd") |
| 44 : |
|
|
|
| 45 : |
|
|
# this one is passed verbatim before the make command. might be useful for alternate toolchains, etc |
| 46 : |
|
|
# example: premake="HOST=powerpc-unknown-linux-gnu" |
| 47 : |
|
|
premake=config.get("options","premake") |
| 48 : |
|
|
# make options, passed verbatim after make command |
| 49 : |
|
|
makeopts=config.get("options","makeopts") |
| 50 : |
|
|
|
| 51 : |
|
|
# parse manager-related configuration from gkb-manager.cfg |
| 52 : |
|
|
config.readfp(open('gkb-manager.cfg')) |
| 53 : |
|
|
msite=config.get('options','msite') |
| 54 : |
|
|
|
| 55 : |
|
|
# these values will likely stay fairly static across different builds |
| 56 : |
|
|
patchdir="%s/patches" % buildroot # full path to patch file dir |
| 57 : |
|
|
configdir="%s/configs" % buildroot # path to where configs are to be stored |
| 58 : |
|
|
logdir="%s/logs" % buildroot # the logs will go here |
| 59 : |
|
|
bindir="%s/bin" % buildroot # the directory that binaries built will be sent for pkging |
| 60 : |
|
|
workdir="%s/work" % buildroot # work directory, where builds take place |
| 61 : |
|
|
|
| 62 : |
|
|
# setup the global dicts to hold build data, imported from xml |
| 63 : |
|
|
mastertrees={} |
| 64 : |
|
|
builds={} |
| 65 : |
|
|
|
| 66 : |
tmcnulty
|
1.7
|
class Error(Exception): |
| 67 : |
|
|
"""Base class for exceptions in this module.""" |
| 68 : |
|
|
pass |
| 69 : |
|
|
|
| 70 : |
|
|
class BuildError(Error): |
| 71 : |
|
|
"""Exception raised for build-level errors. |
| 72 : |
|
|
|
| 73 : |
|
|
Attributes: |
| 74 : |
|
|
message -- explanation of the error |
| 75 : |
|
|
""" |
| 76 : |
|
|
|
| 77 : |
|
|
def __init__(self, message): |
| 78 : |
|
|
self.message = message |
| 79 : |
|
|
|
| 80 : |
|
|
class FatalError(Error): |
| 81 : |
|
|
"""Exception for fatal errors that prevent program continuation. |
| 82 : |
|
|
|
| 83 : |
|
|
Attributes: |
| 84 : |
|
|
message -- explanation of why the specific transition is not allowed |
| 85 : |
|
|
""" |
| 86 : |
|
|
|
| 87 : |
tmcnulty
|
1.12
|
def __init__(self, message): |
| 88 : |
tmcnulty
|
1.7
|
self.message = message |
| 89 : |
|
|
|
| 90 : |
tmcnulty
|
1.1
|
def printverbose(myoutput): |
| 91 : |
|
|
"""Supporting method to output info to stdout if verbosity level is set""" |
| 92 : |
|
|
if verbose==1: |
| 93 : |
|
|
print myoutput |
| 94 : |
|
|
|
| 95 : |
tmcnulty
|
1.28
|
def cleantext(text): |
| 96 : |
tmcnulty
|
1.21
|
"""clean a string of passwords, etc. to make it suitable for logging""" |
| 97 : |
|
|
result = string.replace(text,passwd,"XXXXXXXX") |
| 98 : |
|
|
return result |
| 99 : |
|
|
|
| 100 : |
tmcnulty
|
1.16
|
def linkpipes(input, output): |
| 101 : |
tmcnulty
|
1.21
|
"""link two pipes together, writing all the data from input to output""" |
| 102 : |
tmcnulty
|
1.16
|
data = input.read(2048) |
| 103 : |
|
|
while data: |
| 104 : |
|
|
output.write(data) |
| 105 : |
tmcnulty
|
1.18
|
data = input.read(2048) |
| 106 : |
|
|
|
| 107 : |
tmcnulty
|
1.22
|
def runcmd(cmd, kinfo=None, outfile=None, append=False, infile=None): |
| 108 : |
tmcnulty
|
1.21
|
"""run the specified command, with the optional input and output documents""" |
| 109 : |
tmcnulty
|
1.28
|
log(" \_ running " + cleantext(cmd), kinfo) |
| 110 : |
tmcnulty
|
1.16
|
|
| 111 : |
tmcnulty
|
1.20
|
p4obj = popen2.Popen4(cmd) |
| 112 : |
tmcnulty
|
1.19
|
|
| 113 : |
|
|
pin = p4obj.tochild |
| 114 : |
|
|
pouterr = p4obj.fromchild |
| 115 : |
tmcnulty
|
1.16
|
|
| 116 : |
|
|
if infile != None: |
| 117 : |
|
|
inobj = open(infile, "r") |
| 118 : |
|
|
linkpipes(inobj, pin) |
| 119 : |
|
|
inobj.close() |
| 120 : |
|
|
|
| 121 : |
|
|
if outfile != None: |
| 122 : |
|
|
if append: |
| 123 : |
|
|
mode = "a" |
| 124 : |
|
|
else: |
| 125 : |
|
|
mode = "w" |
| 126 : |
|
|
|
| 127 : |
|
|
outobj = open(outfile, mode) |
| 128 : |
tmcnulty
|
1.18
|
linkpipes(pouterr,outobj) |
| 129 : |
tmcnulty
|
1.16
|
outobj.close() |
| 130 : |
|
|
|
| 131 : |
tmcnulty
|
1.19
|
err = p4obj.wait() |
| 132 : |
tmcnulty
|
1.16
|
|
| 133 : |
|
|
if err == None: |
| 134 : |
|
|
err = 0 |
| 135 : |
tmcnulty
|
1.17
|
|
| 136 : |
tmcnulty
|
1.25
|
log(" \_ exit code: %i" % err, kinfo) |
| 137 : |
tmcnulty
|
1.21
|
|
| 138 : |
tmcnulty
|
1.14
|
return err |
| 139 : |
|
|
|
| 140 : |
tmcnulty
|
1.1
|
def log(text,kinfo=0): |
| 141 : |
|
|
if kinfo: |
| 142 : |
|
|
printverbose(kinfo["name"] + " : " + text) |
| 143 : |
|
|
else: |
| 144 : |
|
|
printverbose("gkb : " + text) |
| 145 : |
|
|
|
| 146 : |
|
|
def verifydir(mydir,kinfo=0): |
| 147 : |
|
|
"""Supporting method to verify a given exists, if not it will create it""" |
| 148 : |
|
|
log("verifying directory " + mydir,kinfo) |
| 149 : |
|
|
if not os.path.isdir(mydir): |
| 150 : |
tmcnulty
|
1.25
|
log(" \_ %s doesn't exist, creating" % mydir,kinfo) |
| 151 : |
tmcnulty
|
1.1
|
os.mkdir(mydir) |
| 152 : |
|
|
return mydir |
| 153 : |
|
|
|
| 154 : |
|
|
def chdir(mydir,kinfo): |
| 155 : |
|
|
verifydir(mydir,kinfo) |
| 156 : |
|
|
log("entering "+mydir,kinfo) |
| 157 : |
|
|
os.chdir(mydir) |
| 158 : |
|
|
|
| 159 : |
|
|
def verifyfile(myfile,kinfo): |
| 160 : |
|
|
"""Supporting method to verify file exists, if not it will exit with error""" |
| 161 : |
|
|
if not os.path.isfile(myfile): |
| 162 : |
tmcnulty
|
1.7
|
raise BuildError("cannot find file expected at %s, exiting" % myfile) |
| 163 : |
tmcnulty
|
1.1
|
return myfile |
| 164 : |
|
|
|
| 165 : |
|
|
def md5sum(fileobj): |
| 166 : |
|
|
"""calculates the md5sum for fileobj and returns it in hexadecimal""" |
| 167 : |
|
|
md = md5.new() |
| 168 : |
|
|
data = fileobj.read(8192) |
| 169 : |
|
|
while (data): |
| 170 : |
|
|
md.update(data) |
| 171 : |
|
|
data = fileobj.read(8192) |
| 172 : |
|
|
|
| 173 : |
|
|
digest = md.hexdigest() |
| 174 : |
|
|
return digest |
| 175 : |
|
|
|
| 176 : |
tmcnulty
|
1.31
|
def krn_querymgr(command,kinfo,extra=""): |
| 177 : |
tmcnulty
|
1.1
|
"""queries the build host manager with a variety of commands, such as checkout, checkin, etc.""" |
| 178 : |
|
|
version=krn_localversion(kinfo) |
| 179 : |
|
|
log("querying distribution site manager with command '%s' (kernel version=%s)" % (command,version),kinfo) |
| 180 : |
tmcnulty
|
1.31
|
result=getoutput("wget --quiet --output-document=- \"%s/manager.php?cmd=%s&host=%s&pass=%s&build=%s&version=%s%s\"" % (msite,command,host,passwd,kinfo["name"],version,extra)) |
| 181 : |
tmcnulty
|
1.25
|
log(" \_ result: '"+result+"'",kinfo) |
| 182 : |
tmcnulty
|
1.1
|
return result=="1" |
| 183 : |
|
|
|
| 184 : |
tmcnulty
|
1.31
|
def krn_modulesenabled(kinfo): |
| 185 : |
|
|
"""Checks the source to see if modules are enabled""" |
| 186 : |
tmcnulty
|
1.32
|
output=getoutput("""awk -F '=' '/^CONFIG_MODULES/{v=$2} END { printf("%s\\n", v) }' """ + kinfo["workdir"] + """/.config | sed "s/ //g" """) |
| 187 : |
tmcnulty
|
1.31
|
if (output=='y'): |
| 188 : |
tmcnulty
|
1.32
|
result=1 |
| 189 : |
tmcnulty
|
1.31
|
else: |
| 190 : |
tmcnulty
|
1.32
|
result=0 |
| 191 : |
|
|
print "modules output=%s result=%s" % (output, result) |
| 192 : |
|
|
|
| 193 : |
tmcnulty
|
1.31
|
return result |
| 194 : |
|
|
|
| 195 : |
tmcnulty
|
1.1
|
def krn_localversion(kinfo): |
| 196 : |
|
|
"""Checks the version of the local source tree specified in kinfo""" |
| 197 : |
|
|
version=getoutput("""awk -F '=' '/^VERSION/{v=$2} /^PATCHLEVEL/{p=$2} /^SUBLEVEL/{s=$2} /^EXTRAVERSION/{e=$2} END { printf("%s.%s.%s%s\\n", v, p, s, e) }' """ + kinfo["workdir"] + """/Makefile | sed "s/ //g" """) |
| 198 : |
|
|
return version |
| 199 : |
|
|
|
| 200 : |
|
|
def gkb_build(root,kinfo): |
| 201 : |
|
|
"""performs actual kernel builds given root, kinfo (tuple containing relevant data) , premake and makeopts""" |
| 202 : |
|
|
|
| 203 : |
|
|
# make sure needed directoriess (for this build) exist, if not create them |
| 204 : |
|
|
|
| 205 : |
|
|
verifydir("%s/%s" % (logdir, kinfo["name"]),kinfo) |
| 206 : |
|
|
verifydir("%s/%s" % (patchdir, kinfo["name"]),kinfo) |
| 207 : |
|
|
|
| 208 : |
|
|
# sync the source to make sure we are up to date ... |
| 209 : |
tmcnulty
|
1.25
|
log("fetching latest source",kinfo) |
| 210 : |
tmcnulty
|
1.1
|
gkb_getsource(kinfo) |
| 211 : |
|
|
|
| 212 : |
tmcnulty
|
1.10
|
# go into the work directory |
| 213 : |
tmcnulty
|
1.27
|
#chdir(workdir, kinfo) |
| 214 : |
tmcnulty
|
1.10
|
|
| 215 : |
|
|
# archive the clean source for later uploading |
| 216 : |
tmcnulty
|
1.27
|
#log("archiving source to " + kinfo["mastertree"] + ".tar.bz2", kinfo) |
| 217 : |
|
|
#runcmd("tar cjf " + kinfo["mastertree"] + ".tar.bz2 " + kinfo["mastertree"], kinfo) |
| 218 : |
tmcnulty
|
1.10
|
|
| 219 : |
|
|
# now we'll go into the tree's work dir |
| 220 : |
tmcnulty
|
1.1
|
chdir(kinfo["workdir"],kinfo) |
| 221 : |
|
|
|
| 222 : |
|
|
# check for patches and apply if necessary |
| 223 : |
|
|
gkb_patch(kinfo) |
| 224 : |
|
|
|
| 225 : |
|
|
if kinfo["type"] == "kernel24": |
| 226 : |
|
|
krn_build24(kinfo) |
| 227 : |
|
|
elif kinfo["type"] == "kernel26": |
| 228 : |
|
|
krn_build24(kinfo) #run kernel24 for now, change later |
| 229 : |
|
|
|
| 230 : |
|
|
# Gerk comment: |
| 231 : |
|
|
# Do we need to change this with 24/26? we probably don't ... I'd rather see us define the list of make targets |
| 232 : |
|
|
# i.e. "dep","clean","vmlinux","modules","modules_install" or "clean","all","modules_install" for 2.6 |
| 233 : |
|
|
# also of note, make all is not what we will always want with 2.6 kernels ... i.e. zImage.prep, zImage.chrp, etc |
| 234 : |
|
|
# also for backward compat they will continue to support calling things individual .. the makefile just does |
| 235 : |
|
|
# this for us with 'all' |
| 236 : |
|
|
|
| 237 : |
|
|
|
| 238 : |
|
|
def krn_build24(kinfo): |
| 239 : |
|
|
"""build a kernel, version 2.4.x""" |
| 240 : |
|
|
|
| 241 : |
|
|
if krn_querymgr("checkout",kinfo): |
| 242 : |
tmcnulty
|
1.7
|
try: |
| 243 : |
|
|
myversion=krn_localversion(kinfo) |
| 244 : |
|
|
|
| 245 : |
|
|
# fetch and cp the config file to work/.config |
| 246 : |
|
|
krn_config(kinfo) |
| 247 : |
|
|
|
| 248 : |
|
|
# **Note** : we set the preprocessing command to premake inline instead |
| 249 : |
|
|
# of globally as it is only needed in this target |
| 250 : |
|
|
if dont_build==0: |
| 251 : |
|
|
gkb_runmake("oldconfig",kinfo,premake+" /bin/cat %s/newlines | " % buildroot,makeopts) |
| 252 : |
|
|
|
| 253 : |
|
|
# give option to only repackage for testing purposes, comment out clean=1 at top of this file to use this feature |
| 254 : |
|
|
if (clean==1 and dont_build==0): |
| 255 : |
|
|
gkb_runmake("clean", kinfo, premake, makeopts) |
| 256 : |
|
|
|
| 257 : |
|
|
if dont_build==0: |
| 258 : |
|
|
gkb_runmake("dep", kinfo, premake, makeopts) |
| 259 : |
|
|
gkb_runmake(kinfo["binname"], kinfo, premake, makeopts) |
| 260 : |
|
|
|
| 261 : |
|
|
# We should check to see if binary built ok, if not bail out |
| 262 : |
|
|
mybindir=bindir+"/linux-"+kinfo["name"]+"-"+myversion |
| 263 : |
|
|
verifydir(mybindir,kinfo) |
| 264 : |
|
|
verifydir(mybindir+"/boot",kinfo) |
| 265 : |
|
|
|
| 266 : |
|
|
kbinloc=kinfo["workdir"]+"/"+kinfo["binpath"]+"/"+kinfo["binname"] |
| 267 : |
|
|
if verifyfile(kbinloc,kinfo): |
| 268 : |
|
|
# the binary exists, so let's cp it to bin... |
| 269 : |
|
|
copy(kbinloc,mybindir+"/boot/"+kinfo["binname"]+"-"+myversion) |
| 270 : |
|
|
else: |
| 271 : |
|
|
# the binary is not there, inform user and bail out with error |
| 272 : |
|
|
raise BuildError("%s is not present, assuming build failure and exiting. See log for details." % kbinloc) |
| 273 : |
tmcnulty
|
1.31
|
|
| 274 : |
|
|
if krn_modulesenabled(kinfo): |
| 275 : |
|
|
# now that we know he binary built, let's continue |
| 276 : |
|
|
if dont_build==0: |
| 277 : |
|
|
gkb_runmake("modules",kinfo, premake, makeopts) |
| 278 : |
|
|
|
| 279 : |
|
|
# **Note** : we prepend the INSTALL_MOD_PATH to the makeopts inline instead |
| 280 : |
|
|
# of globally as it is only needed in this target |
| 281 : |
|
|
gkb_runmake("modules_install", kinfo, premake, "INSTALL_MOD_PATH=%s %s" % (mybindir, makeopts)) |
| 282 : |
|
|
else: |
| 283 : |
|
|
log("skipping make modules (disabled in .config)",kinfo) |
| 284 : |
|
|
|
| 285 : |
tmcnulty
|
1.10
|
# compress and upload source archive |
| 286 : |
|
|
chdir(kinfo["workdir"]+"/..",kinfo) |
| 287 : |
|
|
archive_name = "src-%s.tar.bz2" % kinfo["mastertree"], |
| 288 : |
|
|
|
| 289 : |
|
|
# compress and upload kernel binary |
| 290 : |
tmcnulty
|
1.7
|
chdir(bindir,kinfo) |
| 291 : |
|
|
archive_name = "linux-%s-%s.tar.bz2" % (kinfo["name"], myversion) |
| 292 : |
|
|
|
| 293 : |
|
|
log("compressing binary archive "+archive_name,kinfo) |
| 294 : |
|
|
|
| 295 : |
tmcnulty
|
1.21
|
if runcmd("tar cjf "+archive_name+" "+os.path.basename(mybindir), kinfo): |
| 296 : |
tmcnulty
|
1.7
|
raise BuildError("failed to `tar cjf %s`" % archive_name) |
| 297 : |
|
|
|
| 298 : |
tmcnulty
|
1.21
|
runcmd("rm -rf %s" % mybindir, kinfo) |
| 299 : |
tmcnulty
|
1.7
|
|
| 300 : |
tmcnulty
|
1.10
|
krn_upload(archive_name,"kernel",myversion,kinfo) |
| 301 : |
|
|
krn_querymgr("checkin",kinfo) |
| 302 : |
|
|
|
| 303 : |
tmcnulty
|
1.28
|
if os.fork() == 0: |
| 304 : |
tmcnulty
|
1.10
|
#in child |
| 305 : |
tmcnulty
|
1.28
|
try: |
| 306 : |
|
|
# sync the source to make sure we are up to date ... |
| 307 : |
|
|
log("re-fetching latest source",kinfo) |
| 308 : |
|
|
gkb_getsource(kinfo) |
| 309 : |
|
|
|
| 310 : |
|
|
# go into the work directory |
| 311 : |
|
|
chdir(workdir, kinfo) |
| 312 : |
|
|
|
| 313 : |
|
|
# archive the clean source for later uploading |
| 314 : |
|
|
log("archiving source to " + kinfo["mastertree"] + ".tar.bz2", kinfo) |
| 315 : |
|
|
runcmd("tar cjf " + kinfo["mastertree"] + ".tar.bz2 " + kinfo["mastertree"], kinfo) |
| 316 : |
|
|
|
| 317 : |
|
|
krn_upload(workdir + "/" + kinfo["mastertree"] + ".tar.bz2", "source", myversion, kinfo) |
| 318 : |
|
|
finally: |
| 319 : |
|
|
sys.exit(0) |
| 320 : |
tmcnulty
|
1.10
|
|
| 321 : |
tmcnulty
|
1.7
|
except BuildError, e: |
| 322 : |
|
|
log(e.message, kinfo) |
| 323 : |
tmcnulty
|
1.31
|
krn_querymgr("checkin",kinfo,"&failed=%s" % krn_localversion(kinfo)) |
| 324 : |
tmcnulty
|
1.8
|
except: |
| 325 : |
tmcnulty
|
1.31
|
krn_querymgr("checkin",kinfo,"&failed=%s" % krn_localversion(kinfo)) |
| 326 : |
tmcnulty
|
1.8
|
raise |
| 327 : |
|
|
|
| 328 : |
tmcnulty
|
1.1
|
def krn_build26(kinfo): |
| 329 : |
|
|
"""build a kernel, version 2.6""" |
| 330 : |
|
|
|
| 331 : |
|
|
# source get routines |
| 332 : |
|
|
def gkb_getsource(kinfo): |
| 333 : |
|
|
"""method to perform source sync on demand, currenty only supports rsync, but others can be added""" |
| 334 : |
|
|
|
| 335 : |
|
|
method=mastertrees[kinfo["mastertree"]]["method"] |
| 336 : |
|
|
|
| 337 : |
|
|
if method == "rsync": |
| 338 : |
|
|
get_rsync(kinfo) |
| 339 : |
|
|
elif method == "wget": |
| 340 : |
|
|
get_wget(kinfo) |
| 341 : |
|
|
elif method == "vanilla": |
| 342 : |
|
|
get_vanilla(kinfo) |
| 343 : |
|
|
|
| 344 : |
|
|
def get_rsync(kinfo): |
| 345 : |
|
|
"""sync the source using rsync""" |
| 346 : |
|
|
args=mastertrees[kinfo["mastertree"]]["args"] |
| 347 : |
|
|
|
| 348 : |
|
|
if clean==1: |
| 349 : |
|
|
syncoptions="rsync -azv --delete" |
| 350 : |
|
|
else: |
| 351 : |
|
|
syncoptions="rsync -azv" |
| 352 : |
|
|
|
| 353 : |
|
|
syncline=args+" "+kinfo["workdir"] |
| 354 : |
|
|
|
| 355 : |
tmcnulty
|
1.23
|
#logging now in runcmd |
| 356 : |
|
|
#log("running rsync : %s %s" % (syncoptions, syncline),kinfo) |
| 357 : |
tmcnulty
|
1.21
|
if runcmd("%s %s" % (syncoptions, syncline), kinfo, "%s/%s/rsync.log" % (logdir, kinfo["name"])): |
| 358 : |
tmcnulty
|
1.7
|
raise BuildError("sync failed, tried %s. See log for details." % syncline) |
| 359 : |
tmcnulty
|
1.1
|
|
| 360 : |
|
|
def get_wget(kinfo): |
| 361 : |
|
|
#needs work |
| 362 : |
|
|
"""sync the source using wget and a tar.bz2""" |
| 363 : |
|
|
args=mastertrees[kinfo["mastertree"]]["args"] |
| 364 : |
|
|
|
| 365 : |
|
|
log("fetching source archive " % args,kinfo) |
| 366 : |
|
|
mysourcefile="%s/%s.tar.bz2" % (kinfo["workdir"],kinfo["name"]) |
| 367 : |
|
|
|
| 368 : |
tmcnulty
|
1.21
|
if runcmd("wget --quiet --output-document=%s %s/configs/%s" % (myconfigfile,msite,kinfo["name"]), kinfo): |
| 369 : |
tmcnulty
|
1.7
|
raise BuildError("unable to download configfile, aborting.") |
| 370 : |
tmcnulty
|
1.1
|
|
| 371 : |
|
|
log("decompressing source file",kinfo) |
| 372 : |
tmcnulty
|
1.21
|
if runcmd("tar xjf " % (myconfigfile,msite,kinfo["name"]), kinfo): |
| 373 : |
tmcnulty
|
1.7
|
raise BuildError("unable to decompress source file, aborting.") |
| 374 : |
tmcnulty
|
1.1
|
|
| 375 : |
|
|
def get_vanilla(kinfo): |
| 376 : |
|
|
args=mastertrees[kinfo["mastertree"]]["args"] |
| 377 : |
|
|
|
| 378 : |
|
|
log("fetching source archive %s" % args) |
| 379 : |
|
|
mysourcefile="%s/%s.tar.bz2" % (workdir,kinfo["name"]) |
| 380 : |
|
|
|
| 381 : |
tmcnulty
|
1.21
|
if runcmd("wget -c --output-document=%s %s" % (mysourcefile,args), kinfo): |
| 382 : |
tmcnulty
|
1.7
|
raise BuildError("unable to download source file %s, aborting." % args) |
| 383 : |
tmcnulty
|
1.1
|
|
| 384 : |
|
|
log("decompressing source file %s" % mysourcefile,kinfo) |
| 385 : |
|
|
|
| 386 : |
|
|
#save the current working ectory |
| 387 : |
|
|
cwd=getoutput("pwd") |
| 388 : |
|
|
|
| 389 : |
|
|
chdir(workdir,kinfo) |
| 390 : |
|
|
pfd=os.popen("tar vxjf %s" % mysourcefile,"r") |
| 391 : |
|
|
trash=data=pfd.read(255) |
| 392 : |
|
|
|
| 393 : |
|
|
while trash: |
| 394 : |
|
|
trash=pfd.read(4096) |
| 395 : |
|
|
|
| 396 : |
|
|
if pfd.close(): |
| 397 : |
tmcnulty
|
1.7
|
raise BuildError("unable to decompress source file, aborting.") |
| 398 : |
tmcnulty
|
1.1
|
|
| 399 : |
|
|
fnames=split(data) |
| 400 : |
|
|
name=fnames[0] |
| 401 : |
|
|
|
| 402 : |
tmcnulty
|
1.21
|
runcmd("rm -rf %s" % kinfo["workdir"], kinfo) |
| 403 : |
tmcnulty
|
1.1
|
move(work + "/" + dirname, kinfo["workdir"]) |
| 404 : |
|
|
|
| 405 : |
|
|
#restore the previous working ectory |
| 406 : |
|
|
chdir(cwd,kinfo) |
| 407 : |
|
|
|
| 408 : |
|
|
def gkb_patch(kinfo): |
| 409 : |
|
|
"""method that applies patch found in kinfo config files for running kernel build""" |
| 410 : |
|
|
if kinfo["patches"]: |
| 411 : |
|
|
patches=split(kinfo["patches"],";") |
| 412 : |
|
|
|
| 413 : |
|
|
for patch in patches: |
| 414 : |
|
|
log("downloading patch %s" % patch,kinfo) |
| 415 : |
|
|
|
| 416 : |
|
|
#set a name for this patch file |
| 417 : |
|
|
mypatchfile="%s/%s/%s.patch" % (patchdir,kinfo["name"],patch) |
| 418 : |
|
|
|
| 419 : |
|
|
# download pathfile or bail |
| 420 : |
tmcnulty
|
1.21
|
if runcmd("wget --quiet --output-document=%s %s/patches/%s/%s" % (mypatchfile,msite,kinfo["name"],patch), kinfo): |
| 421 : |
tmcnulty
|
1.7
|
raise BuildError("unable to download patchfile %s, aborting." % patch) |
| 422 : |
tmcnulty
|
1.1
|
|
| 423 : |
|
|
# we have a patch file, apply it or bail |
| 424 : |
|
|
log("perfoming patch with %s" % patch,kinfo) |
| 425 : |
tmcnulty
|
1.16
|
|
| 426 : |
|
|
# former patchcommand was: |
| 427 : |
|
|
#patchcommand="patch -p1 < %s > %s/%s/patch-%s.log 2>&1" % (mypatchfile,logdir,kinfo["name"],patch) |
| 428 : |
|
|
#log("using %s from %s" % (patchcommand,kinfo["workdir"]),kinfo) |
| 429 : |
|
|
|
| 430 : |
tmcnulty
|
1.1
|
chdir(kinfo["workdir"],kinfo) |
| 431 : |
tmcnulty
|
1.21
|
if runcmd("patch -p1", kinfo, "%s/%s/patch-%s.log" % (logdir,kinfo["name"],patch), False, mypatchfile): |
| 432 : |
tmcnulty
|
1.7
|
raise BuildError("patchfile %s failed, aborting. See patch log for details." % patch) |
| 433 : |
tmcnulty
|
1.1
|
else: |
| 434 : |
|
|
log("no patchfiles, continuing",kinfo) |
| 435 : |
|
|
|
| 436 : |
|
|
def krn_config(kinfo): |
| 437 : |
|
|
"""method to fetch and place config file for running kernel build""" |
| 438 : |
|
|
|
| 439 : |
|
|
if kinfo["config"]==1: |
| 440 : |
|
|
log("fetching config file",kinfo) |
| 441 : |
|
|
myconfigfile="%s/%s.config" % (configdir,kinfo["name"]) |
| 442 : |
|
|
|
| 443 : |
tmcnulty
|
1.21
|
if runcmd("wget --quiet --output-document=%s %s/configs/%s" % (myconfigfile,msite,kinfo["name"]), kinfo): |
| 444 : |
tmcnulty
|
1.7
|
raise BuildError("unable to download configfile, aborting.") |
| 445 : |
tmcnulty
|
1.1
|
|
| 446 : |
|
|
log("copying config file to %s/.config" % kinfo["workdir"],kinfo) |
| 447 : |
|
|
copy(verifyfile(myconfigfile,kinfo),"%s/.config" % kinfo["workdir"]) |
| 448 : |
|
|
|
| 449 : |
|
|
# Methods to support build() |
| 450 : |
|
|
def gkb_runmake(command, kinfo, premake, makeopts): |
| 451 : |
|
|
"""Supporting method for build() ... a stub to run a make target and auto log it, given make target (command) and name (kernel name)""" |
| 452 : |
|
|
log("running make %s" % command,kinfo) |
| 453 : |
tmcnulty
|
1.31
|
|
| 454 : |
|
|
# check to see if we need to run a simple make |
| 455 : |
|
|
# for some reason 2.2 kernels can't handle premake, makeopts, etc. |
| 456 : |
|
|
localversion = krn_localversion(kinfo) |
| 457 : |
|
|
|
| 458 : |
|
|
if (string.find(localversion,"2.2") == 0): |
| 459 : |
|
|
if runcmd("%s make %s" % (premake,command), kinfo, "%s/%s/make-%s.log" % (logdir, kinfo["name"], command)): |
| 460 : |
|
|
raise BuildError("unable to run make %s, aborting." % command) |
| 461 : |
|
|
else: |
| 462 : |
|
|
if runcmd("%s make %s %s" % (premake, makeopts, command), kinfo, "%s/%s/make-%s.log" % (logdir, kinfo["name"], command)): |
| 463 : |
|
|
raise BuildError("unable to run make %s, aborting." % command) |
| 464 : |
tmcnulty
|
1.1
|
|
| 465 : |
|
|
def gkb_parsexml(name): |
| 466 : |
|
|
"""parse the xml build file into mastertrees and builds""" |
| 467 : |
|
|
def start_element(name, attrs): |
| 468 : |
|
|
#print "In start_element: %s %s" % (name, attrs) |
| 469 : |
|
|
if name=="mastertree": |
| 470 : |
|
|
mastertrees[attrs["name"]]=attrs |
| 471 : |
|
|
elif name=="build": |
| 472 : |
|
|
builds[attrs["name"]]=attrs |
| 473 : |
|
|
|
| 474 : |
|
|
p = xml.parsers.expat.ParserCreate() |
| 475 : |
|
|
p.StartElementHandler = start_element |
| 476 : |
|
|
p.ParseFile(open(name)) |
| 477 : |
tmcnulty
|
1.3
|
|
| 478 : |
tmcnulty
|
1.10
|
def krn_upload(file, type, version, kinfo): |
| 479 : |
tmcnulty
|
1.3
|
"""upload the indicated file to the distribution site (kernel archives)""" |
| 480 : |
tmcnulty
|
1.10
|
|
| 481 : |
|
|
if type=="kernel": |
| 482 : |
|
|
log("uploading kernel version "+version+" to "+msite,kinfo) |
| 483 : |
|
|
elif type=="source": |
| 484 : |
|
|
log("uploading source "+kinfo["mastertree"]+" to "+msite,kinfo) |
| 485 : |
|
|
else: |
| 486 : |
|
|
raise BuildException, "invalid file upload type: " + type |
| 487 : |
|
|
|
| 488 : |
|
|
forms = ParseResponse(urlopen(msite+"/upload.html")) |
| 489 : |
tmcnulty
|
1.3
|
form = forms[0] |
| 490 : |
|
|
|
| 491 : |
|
|
form["host"] = host |
| 492 : |
|
|
form["pass"] = passwd |
| 493 : |
tmcnulty
|
1.10
|
form["type"] = type |
| 494 : |
|
|
form["tree"] = kinfo["mastertree"] |
| 495 : |
tmcnulty
|
1.3
|
form["build"] = kinfo["name"] |
| 496 : |
|
|
form["version"] = version |
| 497 : |
|
|
|
| 498 : |
tmcnulty
|
1.5
|
form.add_file(open(file), "application/x-bzip2", os.path.basename(file)) |
| 499 : |
tmcnulty
|
1.10
|
|
| 500 : |
tmcnulty
|
1.3
|
# form.click() returns a urllib2.Request object |
| 501 : |
|
|
# (see HTMLForm.click.__doc__ if you don't have urllib2) |
| 502 : |
tmcnulty
|
1.10
|
response = urlopen(form.click("cmd")) |
| 503 : |
tmcnulty
|
1.3
|
|
| 504 : |
tmcnulty
|
1.10
|
if debug: |
| 505 : |
|
|
print response.geturl() |
| 506 : |
|
|
print response.info() # headers |
| 507 : |
|
|
print response.read() # body |
| 508 : |
|
|
|
| 509 : |
tmcnulty
|
1.30
|
log(" \_ response: " + response.read(),kinfo) |
| 510 : |
tmcnulty
|
1.3
|
|
| 511 : |
tmcnulty
|
1.10
|
response.close() |
| 512 : |
|
|
|
| 513 : |
tmcnulty
|
1.1
|
def main(): |
| 514 : |
|
|
""" main program gets executed here """ |
| 515 : |
|
|
|
| 516 : |
|
|
# get our working ectory |
| 517 : |
|
|
root=getoutput("pwd") |
| 518 : |
|
|
|
| 519 : |
|
|
today=getoutput("date +%D") |
| 520 : |
|
|
buildtime=getoutput("date +'%R:%S %Z'") |
| 521 : |
|
|
|
| 522 : |
tmcnulty
|
1.25
|
print "GNU Kernel Builder started %s %s" % (today,buildtime) |
| 523 : |
tmcnulty
|
1.1
|
|
| 524 : |
|
|
# verify the existence important directories, and create if necessary |
| 525 : |
|
|
verifydir(logdir) |
| 526 : |
|
|
verifydir(configdir) |
| 527 : |
|
|
verifydir(patchdir) |
| 528 : |
|
|
verifydir(bindir) |
| 529 : |
|
|
verifydir("%s/work" % buildroot) # build dir, make sure it exists |
| 530 : |
|
|
|
| 531 : |
|
|
# download the build jobs from the master site |
| 532 : |
tmcnulty
|
1.25
|
log("fetching build jobs from master site") |
| 533 : |
tmcnulty
|
1.22
|
if runcmd("wget --quiet --output-document=gkb.xml \"%s/manager.php?cmd=getjobs&host=%s&pass=%s\"" % (msite,host,passwd)): |
| 534 : |
tmcnulty
|
1.25
|
raise FatalError, "Unable to download build jobs from master site %s, aborting." % msite |
| 535 : |
tmcnulty
|
1.1
|
|
| 536 : |
|
|
# sets up 'mastertrees' and 'builds' dicts |
| 537 : |
|
|
gkb_parsexml('gkb.xml') |
| 538 : |
|
|
|
| 539 : |
|
|
for bdict in builds.values(): |
| 540 : |
|
|
myworkdir="%s/%s" % (workdir,bdict["mastertree"]) |
| 541 : |
|
|
bdict["workdir"]=myworkdir |
| 542 : |
|
|
|
| 543 : |
tmcnulty
|
1.9
|
try: |
| 544 : |
|
|
# for now just call the build |
| 545 : |
|
|
gkb_build(root, bdict) |
| 546 : |
|
|
except BuildError, e: |
| 547 : |
|
|
log(e.message, bdict) |
| 548 : |
tmcnulty
|
1.12
|
except KeyboardInterrupt, e: |
| 549 : |
|
|
log("Caught keyboard interrupt, exiting...") |
| 550 : |
|
|
break |
| 551 : |
tmcnulty
|
1.13
|
|
| 552 : |
tmcnulty
|
1.1
|
endtime=getoutput("date +'%R:%S %Z'") |
| 553 : |
|
|
|
| 554 : |
|
|
print "GKB finished %s %s" % (today,endtime) |
| 555 : |
|
|
|
| 556 : |
|
|
# and finally, call the mainloop to execute |
| 557 : |
|
|
main() |