#!/usr/bin/env python
# Copyright 2001-6 Anthony Towns
# 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.
import sys , re , string , time , whrandom , math
import britney
if len ( sys . argv ) != 4 :
print " Must specify testing, unstable, testing-updates directories. "
sys . exit ( 1 )
testingdir = sys . argv [ 1 ]
unstabledir = sys . argv [ 2 ]
testingupdatesdir = sys . argv [ 3 ]
# Configuration information
expected_arches = 13
allarches = [ ' i386 ' , ' sparc ' , ' alpha ' , ' powerpc ' , ' armel ' , ' hppa ' , ' ia64 ' , ' mips ' , ' mipsel ' , ' s390 ' , ' amd64 ' , ' kfreebsd-i386 ' , ' kfreebsd-amd64 ' ]
mindays = { " low " : 10 , " medium " : 5 , " high " : 2 , " critical " : 0 ,
" emergency " : 0 }
defaulturgency = " low "
# if you're not in this list, arch: all packages are allowed to break on you
nobreakarchallarches = [ ' i386 ' ]
# if you're in this list, your packages may not stay in sync with the source
fuckedarches = [ ' kfreebsd-i386 ' , ' kfreebsd-amd64 ' ]
# if you're in this list, your uninstallability count may increase
breakarches = [ ' kfreebsd-i386 ' , ' kfreebsd-amd64 ' ]
# new architectures
newarches = [ ' kfreebsd-i386 ' , ' kfreebsd-amd64 ' ]
allarches . sort ( )
arches = [ x for x in allarches if x in nobreakarchallarches ]
arches + = [ x for x in allarches if x not in arches and x not in fuckedarches ]
arches + = [ x for x in allarches if x not in arches and x not in breakarches ]
arches + = [ x for x in allarches if x not in arches and x not in newarches ]
arches + = [ x for x in allarches if x not in arches ]
# Subs
def same_source ( sv1 , sv2 ) :
if sv1 == sv2 :
return 1
m = re . match ( r ' ^(.*) \ +b \ d+$ ' , sv1 )
if m : sv1 = m . group ( 1 )
m = re . match ( r ' ^(.*) \ +b \ d+$ ' , sv2 )
if m : sv2 = m . group ( 1 )
if sv1 == sv2 :
return 1
if re . search ( " - " , sv1 ) or re . search ( " - " , sv2 ) :
m = re . match ( r ' ^(.*-[^.]+) \ .0 \ . \ d+$ ' , sv1 )
if m : sv1 = m . group ( 1 )
m = re . match ( r ' ^(.*-[^.]+ \ .[^.]+) \ . \ d+$ ' , sv1 )
if m : sv1 = m . group ( 1 )
m = re . match ( r ' ^(.*-[^.]+) \ .0 \ . \ d+$ ' , sv2 )
if m : sv2 = m . group ( 1 )
m = re . match ( r ' ^(.*-[^.]+ \ .[^.]+) \ . \ d+$ ' , sv2 )
if m : sv2 = m . group ( 1 )
return ( sv1 == sv2 )
else :
m = re . match ( r ' ^([^-]+) \ .0 \ . \ d+$ ' , sv1 )
if m and sv2 == m . group ( 1 ) : return 1
m = re . match ( r ' ^([^-]+) \ .0 \ . \ d+$ ' , sv2 )
if m and sv1 == m . group ( 1 ) : return 1
return 0
def read_approvals ( dir , approver , approved ) :
f = open ( " %s / %s " % ( dir , approver ) )
line = f . readline ( )
while line :
l = string . split ( line )
if len ( l ) == 2 :
[ pkg , ver ] = l
approved [ " %s _ %s " % ( pkg , ver ) ] = approver
line = f . readline ( )
f . close ( )
def read_bugs ( file ) :
bugsperpkg = { }
f = open ( file )
line = f . readline ( )
while line :
l = string . split ( line )
if len ( l ) == 2 :
bugsperpkg [ l [ 0 ] ] = string . atoi ( l [ 1 ] )
line = f . readline ( )
f . close ( )
return bugsperpkg
def write_bugs ( file , bugs ) :
f = open ( file , ' w ' )
pkgs = bugs . keys ( )
pkgs . sort ( )
for pkg in pkgs :
if bugs [ pkg ] == 0 : continue
f . write ( " %s %d \n " % ( pkg , bugs [ pkg ] ) )
f . close ( )
def read_dates ( file ) :
dates = { }
f = open ( file )
line = f . readline ( )
while line :
l = string . split ( line )
if len ( l ) == 3 :
dates [ l [ 0 ] ] = ( l [ 1 ] , string . atoi ( l [ 2 ] ) )
line = f . readline ( )
f . close ( )
return dates
def write_dates ( file , dates ) :
f = open ( file , ' w ' )
pkgs = dates . keys ( )
pkgs . sort ( )
for pkg in dates . keys ( ) :
f . write ( " %s %s %d \n " % ( ( pkg , ) + dates [ pkg ] ) )
f . close ( )
def read_urgencies ( file , testing , unstable ) :
urgency = { }
f = open ( file )
line = f . readline ( )
while line :
l = string . split ( line )
if len ( l ) == 3 :
uo = urgency . get ( l [ 0 ] , defaulturgency )
mo = mindays . get ( uo , mindays [ defaulturgency ] )
mn = mindays . get ( l [ 2 ] , mindays [ defaulturgency ] )
if mo < = mn :
line = f . readline ( )
continue
tsrcv = testing . get_version ( l [ 0 ] )
if tsrcv and britney . versioncmp ( tsrcv , l [ 1 ] ) > = 0 :
line = f . readline ( )
continue
usrcv = unstable . get_version ( l [ 0 ] )
if not usrcv or britney . versioncmp ( usrcv , l [ 1 ] ) < 0 :
line = f . readline ( )
continue
urgency [ l [ 0 ] ] = l [ 2 ]
line = f . readline ( )
f . close ( )
return urgency
def read_hints ( dir , hinter , hints , allowed ) :
res = { }
for k in allowed :
res [ k ] = [ ]
try :
f = open ( " %s / %s " % ( dir , hinter ) )
except IOError :
return res
while 1 :
line = f . readline ( )
if not line : break
l = string . split ( line )
if len ( l ) == 0 or line [ 0 ] == " # " :
continue
type = l [ 0 ]
if type == " finished " :
break
if type not in allowed :
continue
def mysplit ( str ) :
x = str . rfind ( " / " )
if x == - 1 : return [ str ]
return [ str [ : x ] , str [ x + 1 : ] ]
if type in [ " easy " , " hint " , " force-hint " ] :
l = [ tuple ( mysplit ( y ) ) for y in l [ 1 : ] ]
l = [ k for k in l if len ( k ) == 2 ]
res [ type ] . append ( ( hinter , l ) )
if type in [ " block-all " ] :
l = [ ( y , hinter ) for y in l [ 1 : ] ]
res [ type ] . extend ( l )
if type in [ " block " ] :
l = [ ( y , hinter ) for y in l [ 1 : ] ]
res [ type ] . extend ( l )
if type in [ " remove " , " approve " , " unblock " , " force " , " urgent " ] :
l = [ tuple ( mysplit ( y ) + [ hinter ] ) for y in l [ 1 : ] ]
l = [ k for k in l if len ( k ) == 3 ]
l = [ ( p , ( v , h ) ) for ( p , v , h ) in l ]
res [ type ] . extend ( l )
f . close ( )
return res
class Excuse :
reemail = re . compile ( r " <.*?> " )
def __init__ ( self , name ) :
self . name = name
self . ver = ( " - " , " - " )
self . maint = None
self . pri = None
self . date = None
self . urgency = None
self . daysold = None
self . mindays = None
self . section = None
self . dontinvalidate = 0
self . invalid_deps = [ ]
self . deps = [ ]
self . break_deps = [ ]
self . bugs = [ ]
self . htmlline = [ ]
def set_vers ( self , tver , uver ) :
if tver : self . ver = ( tver , self . ver [ 1 ] )
if uver : self . ver = ( self . ver [ 0 ] , uver )
def set_maint ( self , maint ) :
self . maint = self . reemail . sub ( " " , maint )
# self.maint = maint
def set_section ( self , section ) :
self . section = section
def set_priority ( self , pri ) :
self . pri = pri
def set_date ( self , date ) :
self . date = date
def set_urgency ( self , date ) :
self . urgency = date
def add_dep ( self , name ) :
if name not in self . deps : self . deps . append ( name )
def add_break_dep ( self , name , arch ) :
if ( name , arch ) not in self . break_deps :
self . break_deps . append ( ( name , arch ) )
def invalidate_dep ( self , name ) :
if name not in self . invalid_deps : self . invalid_deps . append ( name )
def setdaysold ( self , daysold , mindays ) :
self . daysold = daysold
self . mindays = mindays
def addhtml ( self , note ) :
self . htmlline . append ( note )
def html ( self ) :
res = " <a id= \" %s \" name= \" %s \" > %s </a> ( %s to %s ) \n <ul> \n " % \
( self . name , self . name , self . name , self . ver [ 0 ] , self . ver [ 1 ] )
if self . maint :
res = res + " <li>Maintainer: %s \n " % ( self . maint )
if self . section and string . find ( self . section , " / " ) > - 1 :
res = res + " <li>Section: %s \n " % ( self . section )
if self . daysold != None :
if self . daysold < self . mindays :
res = res + ( " <li>Too young, only %d of %d days old \n " %
( self . daysold , self . mindays ) )
else :
res = res + ( " <li> %d days old (needed %d days) \n " %
( self . daysold , self . mindays ) )
for x in self . htmlline :
res = res + " <li> " + x + " \n "
for x in self . deps :
if x in self . invalid_deps :
res = res + " <li>Depends: %s <a href= \" # %s \" > %s </a> (not considered) \n " % ( self . name , x , x )
else :
res = res + " <li>Depends: %s <a href= \" # %s \" > %s </a> \n " % ( self . name , x , x )
for ( n , a ) in self . break_deps :
if n not in self . deps :
res + = " <li>Ignoring %s depends: <a href= \" # %s \" > %s </a> \n " % ( a , n , n )
res = res + " </ul> \n "
return res
def should_remove_source ( src , orig , new , excs ) :
if new . is_present ( src ) : return 0
okay = 1
exc = Excuse ( " - " + src )
exc . set_vers ( orig . get_version ( src ) , None )
m = orig . get_field ( src , " Maintainer " )
if m : exc . set_maint ( string . strip ( m ) )
s = orig . get_field ( src , " Section " )
if s : exc . set_section ( string . strip ( s ) )
if hints [ " block " ] . has_key ( " - " + src ) :
blocked = hints [ " block " ] [ " - " + src ]
exc . addhtml ( " Not touching package, as requested by %s (contact debian-release if update is needed) " % ( blocked ) )
okay = 0
if okay :
exc . addhtml ( " Valid candidate " )
else :
exc . addhtml ( " Not considered " )
excs . append ( exc )
return okay
def should_upgrade_srcarch ( src , arch , suite , tsrcv , orig , opkgsa , new , npkgsa , excs ) :
# binnmu this arch?
anywrongver = 0
anyworthdoing = 0
ref = " %s / %s " % ( src , arch )
if suite : ref = ref + " _ %s " % ( suite )
e = Excuse ( ref )
e . set_vers ( tsrcv , tsrcv )
m = new . get_field ( src , " Maintainer " )
if m : e . set_maint ( string . strip ( m ) )
s = new . get_field ( src , " Section " )
if s : e . set_section ( string . strip ( s ) )
if hints [ " remove " ] . has_key ( src ) :
if same_source ( tsrcv , hints [ " remove " ] [ src ] [ 0 ] ) :
e . addhtml ( " Removal request by %s " %
( hints [ " remove " ] [ src ] [ 1 ] ) )
e . addhtml ( " Trying to remove package, not update it " )
e . addhtml ( " Not considered " )
excs . append ( e )
return 0
for pkg in new . binaries ( src , arch ) :
pkgv = npkgsa . get_version ( pkg )
pkgsv = npkgsa . get_sourcever ( pkg )
if npkgsa . is_arch_all ( pkg ) :
e . addhtml ( " Ignoring %s %s (from %s ) as it is arch: all "
% ( pkg , pkgv , pkgsv ) )
continue
if not same_source ( tsrcv , pkgsv ) :
anywrongver = 1
e . addhtml ( " From wrong source: %s %s ( %s not %s ) " % (
pkg , pkgv , pkgsv , tsrcv ) )
break
excuse_unsat_deps ( pkg , arch , opkgsa , npkgsa , e , 0 )
if not opkgsa . is_present ( pkg ) :
e . addhtml ( " New binary: %s ( %s ) " % ( pkg , pkgv ) )
anyworthdoing = 1
continue
tpkgv = opkgsa . get_version ( pkg )
if britney . versioncmp ( tpkgv , pkgv ) > 0 :
anywrongver = 1
e . addhtml ( " Not downgrading: %s ( %s to %s ) " % (
pkg , tpkgv , pkgv ) )
break
elif britney . versioncmp ( tpkgv , pkgv ) < 0 :
e . addhtml ( " Updated binary: %s ( %s to %s ) " % (
pkg , tpkgv , pkgv ) )
anyworthdoing = 1
if not anywrongver and ( anyworthdoing or not new . is_fake ( src ) ) :
srcv = new . get_version ( src )
ssrc = same_source ( tsrcv , srcv )
for pkg in orig . binaries ( src , arch ) :
if opkgsa . is_arch_all ( pkg ) :
e . addhtml ( " Ignoring removal of %s as it is arch: all "
% ( pkg ) )
continue
if not npkgsa . is_present ( pkg ) :
tpkgv = opkgsa . get_version ( pkg )
e . addhtml ( " Removed binary: %s %s " % (
pkg , tpkgv ) )
if ssrc : anyworthdoing = 1
if not anywrongver and anyworthdoing :
e . addhtml ( " Valid candidate " )
excs . append ( e )
return 1
else :
if anyworthdoing :
e . addhtml ( " Not considered " )
excs . append ( e )
return 0
def excuse_unsat_deps ( pkg , arch , tpkgsarch , upkgsarch , exc , ignore_break = 0 ) :
for d in [ ' Pre-Depends ' , ' Depends ' ] :
udt = tpkgsarch . unsatisfiable_deps ( upkgsarch , pkg , d )
udu = upkgsarch . unsatisfiable_deps ( upkgsarch , pkg , d )
for t , u in map ( None , udt , udu ) :
if t [ 1 ] : continue
l = [ ]
for e in u [ 1 ] :
s = upkgsarch . get_source ( e )
if s not in l : l . append ( s )
if src in l : continue
if l == [ ] :
exc . addhtml ( " %s / %s unsatisfiable %s : %s " % ( pkg , arch , d , t [ 0 ] ) )
for s in l :
if ignore_break or arch not in breakarches :
exc . add_dep ( s )
else :
exc . add_break_dep ( s , arch )
def should_upgrade_src ( src , suite , orig , origpkgs , new , newpkgs , approvals ,
excs ) :
srcv = new . get_version ( src )
if orig . is_present ( src ) :
tsrcv = orig . get_version ( src )
if britney . versioncmp ( srcv , tsrcv ) == 0 :
# Candidate for binnmus only
return 0
else :
tsrcv = None
updatecand = 1
ref = src
if suite : ref = ref + " _tpu "
exc = Excuse ( ref )
exc . set_vers ( tsrcv , srcv )
m = new . get_field ( src , " Maintainer " )
if m : exc . set_maint ( string . strip ( m ) )
s = new . get_field ( src , " Section " )
if s : exc . set_section ( string . strip ( s ) )
if tsrcv and britney . versioncmp ( srcv , tsrcv ) < 0 :
# Version in unstable is older!
exc . addhtml ( " ALERT: %s is newer in testing ( %s %s ) " % ( src , tsrcv , srcv ) )
excs . append ( exc )
return 0
if unstable . is_fake ( src ) :
exc . addhtml ( " %s source package doesn ' t exist " % ( src ) )
updatecand = 0
urgency = unstableurg . get ( src , defaulturgency )
if not tsrcv and urgency != defaulturgency :
exc . addhtml ( " Ignoring %s urgency setting for NEW package " % ( urgency ) )
urgency = defaulturgency
if hints [ " remove " ] . has_key ( src ) :
if ( tsrcv and same_source ( tsrcv , hints [ " remove " ] [ src ] [ 0 ] ) ) or \
same_source ( srcv , hints [ " remove " ] [ src ] [ 0 ] ) :
exc . addhtml ( " Removal request by %s " %
( hints [ " remove " ] [ src ] [ 1 ] ) )
exc . addhtml ( " Trying to remove package, not update it " )
updatecand = 0
blocked = None
if hints [ " block " ] . has_key ( src ) :
blocked = hints [ " block " ] [ src ]
elif hints [ " block-all " ] . has_key ( " source " ) :
blocked = hints [ " block-all " ] [ " source " ]
if blocked :
ubv = hints [ " unblock " ] . get ( src , ( None , None ) ) [ 0 ]
if ubv != None and same_source ( ubv , srcv ) :
exc . addhtml ( " Ignoring request to block package by %s , due to unblock request by %s " % ( blocked , hints [ " unblock " ] [ src ] [ 1 ] ) )
else :
if ubv != None :
exc . addhtml ( " Unblock request by %s ignored due to version mismatch: %s " % ( hints [ " unblock " ] [ src ] [ 1 ] , hints [ " unblock " ] [ src ] [ 0 ] ) )
exc . addhtml ( " Not touching package, as requested by %s (contact debian-release if update is needed) " % ( blocked ) )
updatecand = 0
if suite == None :
if not unstabledates . has_key ( src ) :
unstabledates [ src ] = ( srcv , datenow )
elif not same_source ( unstabledates [ src ] [ 0 ] , srcv ) :
unstabledates [ src ] = ( srcv , datenow )
daysold = datenow - unstabledates [ src ] [ 1 ]
mymindays = mindays [ urgency ]
exc . setdaysold ( daysold , mymindays )
if daysold < mymindays :
if hints [ " urgent " ] . has_key ( src ) and same_source ( srcv , hints [ " urgent " ] [ src ] [ 0 ] ) :
exc . addhtml ( " Too young, but urgency pushed by %s " % ( hints [ " urgent " ] [ src ] [ 1 ] ) )
else :
updatecand = 0
pkgs = { src : [ " source " ] }
anybins = 0
for arch in arches :
oodbins = { }
for pkg in new . binaries ( src , arch ) :
anybins = 1
if not pkgs . has_key ( pkg ) : pkgs [ pkg ] = [ ]
pkgs [ pkg ] . append ( arch )
pkgsv = newpkgs [ arch ] . get_sourcever ( pkg )
if not same_source ( srcv , pkgsv ) :
if not oodbins . has_key ( pkgsv ) :
oodbins [ pkgsv ] = [ ]
oodbins [ pkgsv ] . append ( pkg )
continue
if newpkgs [ arch ] . isnt_arch_all ( pkg ) or \
arch in nobreakarchallarches :
excuse_unsat_deps ( pkg , arch ,
origpkgs [ arch ] , newpkgs [ arch ] , exc )
if oodbins :
oodtxt = " "
for v in oodbins . keys ( ) :
if oodtxt : oodtxt = oodtxt + " ; "
oodtxt = oodtxt + " %s (from <a href= \" http://buildd.debian.org/status/logs.php?arch= %s &pkg= %s &ver= %s \" target= \" _blank \" > %s </a>) " % \
( " , " . join ( oodbins [ v ] ) , arch , src , v , v )
text = " out of date on <a href= \" http://buildd.debian.org/status/logs.php?arch= %s &pkg= %s &ver= %s \" target= \" _blank \" > %s </a>: %s " % ( arch , src , srcv , arch , oodtxt )
if arch in fuckedarches :
text = text + " (but %s isn ' t keeping up, " % \
( arch ) + " so nevermind) "
else :
updatecand = 0
if datenow != unstabledates [ src ] [ 1 ] :
exc . addhtml ( text )
if not anybins :
exc . addhtml ( " %s has no binaries on any arch " % src )
updatecand = 0
if suite == None :
for pkg in pkgs . keys ( ) :
if not testingbugs . has_key ( pkg ) : testingbugs [ pkg ] = 0
if not unstablebugs . has_key ( pkg ) : unstablebugs [ pkg ] = 0
if unstablebugs [ pkg ] > testingbugs [ pkg ] :
exc . addhtml ( " %s ( %s ) is <a href= \" http://bugs.debian.org/cgi-bin/pkgreport.cgi?which=pkg&data= %s &sev-inc=critical&sev-inc=grave&sev-inc=serious \" target= \" _blank \" >buggy</a>! ( %d > %d ) " % \
( pkg , " , " . join ( pkgs [ pkg ] ) , pkg ,
unstablebugs [ pkg ] , testingbugs [ pkg ] ) )
updatecand = 0
elif unstablebugs [ pkg ] > 0 :
exc . addhtml ( " %s ( %s ) is (less) <a href= \" http://bugs.debian.org/cgi-bin/pkgreport.cgi?which=pkg&data= %s &sev-inc=critical&sev-inc=grave&sev-inc=serious \" target= \" _blank \" >buggy</a>! ( %d <= %d ) " % \
( pkg , " , " . join ( pkgs [ pkg ] ) , pkg ,
unstablebugs [ pkg ] , testingbugs [ pkg ] ) )
if not updatecand and hints [ " force " ] . has_key ( src ) and same_source ( srcv , hints [ " force " ] [ src ] [ 0 ] ) :
exc . dontinvalidate = 1
exc . addhtml ( " Should ignore, but forced by %s " % ( hints [ " force " ] [ src ] [ 1 ] ) )
updatecand = 1
if approvals :
if approvals . has_key ( " %s _ %s " % ( src , srcv ) ) :
exc . addhtml ( " Approved by %s " %
approvals [ " %s _ %s " % ( src , srcv ) ] )
else :
exc . addhtml ( " NEEDS APPROVAL BY RM " )
updatecand = 0
if updatecand :
exc . addhtml ( " Valid candidate " )
else :
exc . addhtml ( " Not considered " )
excuses . append ( exc )
return updatecand
###
# Brute force stuff
class UpgradeRun :
def __init__ ( self , sn , u , tu , ps ) :
self . srcsn = sn
self . unstable = u
self . testingupdates = tu
self . packages = ps
self . sortpkgs ( )
self . output = open ( " update.OUTPUT_py " , " w " ) ;
self . arches = [ x for x in arches if x in srcsn . arches ]
self . srcsnpkgs = { }
for arch in arches :
self . srcsnpkgs [ arch ] = self . srcsn . Packages ( arch )
#def __del__():
# self.output.close()
def sortpkgs ( self ) :
p = self . packages
p . sort ( )
self . packages = p
def writeout ( self , text ) :
self . output . write ( text )
sys . stdout . write ( text )
self . output . flush ( )
sys . stdout . flush ( )
def doop_source ( self , op ) :
# removals = "-<source>",
# arch = "<source>/<arch>",
# normal = "<source>"
which = self . unstable
if " _ " in op :
ind = string . index ( op , " _ " )
if op [ ind + 1 : ] == " tpu " :
which = self . testingupdates
op = op [ : ind ]
if op [ 0 ] == " - " :
self . srcsn . remove_source ( op [ 1 : ] )
elif " / " in op :
ind = string . index ( op , " / " )
self . srcsn . upgrade_arch ( which , op [ : ind ] , op [ ind + 1 : ] )
else :
self . srcsn . upgrade_source ( which , op )
def get_nuninst ( self ) :
nuninst = { }
for arch in self . arches :
con = self . srcsnpkgs [ arch ] . packages
if arch not in nobreakarchallarches :
con = filter (
self . srcsnpkgs [ arch ] . isnt_arch_all ,
con )
nuninst [ arch ] = filter (
self . srcsnpkgs [ arch ] . is_uninstallable ,
con )
return nuninst
def get_improved_nuninst ( self , old ) :
new = { }
for arch in self . arches :
con = self . srcsnpkgs [ arch ] . packages
if arch not in nobreakarchallarches :
con = filter (
self . srcsnpkgs [ arch ] . isnt_arch_all ,
con )
new [ arch ] = filter (
self . srcsnpkgs [ arch ] . is_uninstallable , con )
if arch in breakarches : continue
if len ( new [ arch ] ) > len ( old [ arch ] ) :
return ( 0 , new )
return ( 1 , new )
def arch_improved_nuninst ( self , old , arch ) :
new = old . copy ( )
if " _ " in arch : arch = arch [ : arch . index ( " _ " ) ]
con = self . srcsnpkgs [ arch ] . packages
if arch not in nobreakarchallarches :
con = filter ( self . srcsnpkgs [ arch ] . isnt_arch_all , con )
new [ arch ] = filter ( self . srcsnpkgs [ arch ] . is_uninstallable , con )
if arch not in newarches and len ( new [ arch ] ) > len ( old [ arch ] ) :
return ( 0 , new )
return ( 1 , new )
def is_nuninst_asgood ( self , old , new ) :
for arch in self . arches :
if arch in breakarches : continue
if len ( new [ arch ] ) > len ( old [ arch ] ) :
return 0
return 1
def is_nuninst_asgood_generous ( self , old , new ) :
diff = 0
for arch in self . arches :
if arch in breakarches : continue
diff = diff + ( len ( new [ arch ] ) - len ( old [ arch ] ) )
return diff < = 0
def eval_nuninst ( self , nuninst ) :
res = [ ]
total = 0
totalbreak = 0
for arch in self . arches :
if nuninst . has_key ( arch ) :
n = len ( nuninst [ arch ] )
if arch in breakarches :
totalbreak = totalbreak + n
else :
total = total + n
res . append ( " %s - %d " % ( arch [ 0 ] , n ) )
return " %d + %d : %s " % ( total , totalbreak , " : " . join ( res ) )
def slist_subtract ( self , base , sub ) :
res = [ ]
for x in base :
if x not in sub : res . append ( x )
return res
def newlyuninst ( self , nuold , nunew ) :
res = { }
for arch in self . arches :
if not nuold . has_key ( arch ) or not nunew . has_key ( arch ) :
continue
res [ arch ] = \
self . slist_subtract ( nunew [ arch ] , nuold [ arch ] )
return res
def eval_uninst ( self , nuninst ) :
res = " "
for arch in self . arches :
if nuninst . has_key ( arch ) and nuninst [ arch ] != [ ] :
res = res + " * %s : %s \n " % ( arch ,
" , " . join ( nuninst [ arch ] ) )
return res
def do_all ( self , maxdepth = 0 , init = [ ] ) :
self . selected = [ ]
self . selected_committed = 0
packages = self . packages [ : ]
earlyabort = 0
if maxdepth == " easy " :
earlyabort = 1
maxdepth = 0
# meaningless to try forcing something _and_ recurse
force = 0
if maxdepth < 0 :
force = 1
maxdepth = 0
earlyabort = 1
nuninst_start = self . get_nuninst ( )
if init :
self . writeout ( " leading: %s \n " % ( " , " . join ( init ) ) )
for x in init :
if x not in packages :
self . writeout ( " failed: %s \n " % ( x ) )
return None
y = packages . index ( x )
self . selected . append ( packages . pop ( y ) )
for x in init :
self . doop_source ( x )
if force :
self . nuninst_orig = self . get_nuninst ( )
else :
self . nuninst_orig = nuninst_start
self . writeout ( " start: %s \n " %
self . eval_nuninst ( nuninst_start ) )
self . writeout ( " orig: %s \n " %
self . eval_nuninst ( self . nuninst_orig ) )
if earlyabort :
nuninst_end = self . get_nuninst ( )
self . writeout ( " easy: %s \n " %
( self . eval_nuninst ( nuninst_end ) ) )
self . writeout ( self . eval_uninst (
self . newlyuninst ( self . nuninst_orig , nuninst_end ) ) )
self . writeout ( " \n " )
if not self . is_nuninst_asgood_generous (
self . nuninst_orig ,
nuninst_end ) :
nuninst_end , respackages = None , None
else :
respackages = packages [ : ]
self . selected_committed = len ( self . selected )
else :
nuninst_end , respackages = \
self . iter_some ( maxdepth , packages , [ ] )
if nuninst_end :
assert ( len ( self . selected ) == self . selected_committed )
self . writeout ( " final: %s \n " %
" , " . join ( self . selected ) )
self . writeout ( " start: %s \n " %
self . eval_nuninst ( nuninst_start ) )
self . writeout ( " orig: %s \n " %
self . eval_nuninst ( self . nuninst_orig ) )
self . writeout ( " end: %s \n " %
self . eval_nuninst ( nuninst_end ) )
if force :
self . writeout ( " force breaks: \n " )
self . writeout ( self . eval_uninst (
self . newlyuninst ( nuninst_start , nuninst_end ) ) )
self . writeout ( " \n " )
if not self . is_nuninst_asgood_generous (
self . nuninst_orig ,
nuninst_end ) :
print " NON-None RETURN THAT ' S NOT BETTER "
self . srcsn . commit_changes ( )
self . writeout ( " SUCCESS ( %d / %d ) \n " %
( len ( self . packages ) , len ( respackages ) ) )
self . packages = respackages
self . sortpkgs ( )
return self . selected
else :
assert ( len ( self . selected ) == len ( init ) )
assert ( self . selected_committed == 0 )
for x in init :
self . srcsn . undo_change ( )
if self . srcsn . can_undo :
print " MORE OPS LEFT TO UNDO THAN DONE "
self . writeout ( " FAILED \n " )
return None
def iter_end ( self , available ) :
extra = [ ]
count = 0
nuninst_comp = self . get_nuninst ( )
while available :
x = available . pop ( 0 )
self . writeout ( " trying: %s \n " % ( x ) )
self . doop_source ( x )
if " / " in x :
better , nuninst_new = self . arch_improved_nuninst (
nuninst_comp , x [ x . index ( " / " ) + 1 : ] )
else :
better , nuninst_new = self . get_improved_nuninst (
nuninst_comp )
if better :
self . selected . append ( x )
count = count + 1
available . extend ( extra )
extra = [ ]
self . writeout ( " accepted: %s \n " % ( x ) )
self . writeout ( " ori: %s \n " %
( self . eval_nuninst ( self . nuninst_orig ) ) )
self . writeout ( " pre: %s \n " %
( self . eval_nuninst ( nuninst_comp ) ) )
self . writeout ( " now: %s \n " %
( self . eval_nuninst ( nuninst_new ) ) )
if len ( self . selected ) < = 20 :
self . writeout ( " all: %s \n " % (
" " . join ( self . selected ) ) )
else :
self . writeout ( " most: ( %d ) .. %s \n " %
( len ( self . selected ) ,
" " . join ( self . selected [ - 20 : ] ) ) )
nuninst_comp = nuninst_new
else :
self . writeout ( " skipped: %s ( %d <- %d ) \n " % (
x , len ( extra ) , len ( available ) ) )
self . writeout ( " got: %s \n %s " % (
self . eval_nuninst ( nuninst_new ) ,
self . eval_uninst ( self . newlyuninst (
nuninst_comp , nuninst_new ) ) ) )
self . srcsn . undo_change ( )
extra . append ( x )
self . writeout ( " finish: [ %s ] \n " %
" , " . join ( self . selected [ self . selected_committed : ] ) )
self . writeout ( " endloop: %s \n " %
( self . eval_nuninst ( self . nuninst_orig ) ) )
self . writeout ( " now: %s \n " %
( self . eval_nuninst ( nuninst_comp ) ) )
self . writeout ( self . eval_uninst (
self . newlyuninst ( self . nuninst_orig , nuninst_comp ) ) )
self . writeout ( " \n " )
if self . is_nuninst_asgood_generous ( self . nuninst_orig ,
nuninst_comp ) :
self . writeout ( " Apparently successful \n " )
self . selected_committed = len ( self . selected )
return ( nuninst_comp , extra )
while count > 0 :
self . srcsn . undo_change ( )
self . selected . pop ( )
count = count - 1
return ( None , None )
def iter_some ( self , depth , available , extra ) :
self . writeout ( " recur: [ %s ] %s %d / %d \n " % (
" , " . join ( self . selected [ : self . selected_committed ] ) ,
" , " . join ( self . selected [ self . selected_committed : ] ) ,
len ( available ) , len ( extra ) ) )
if depth == 0 :
extra . extend ( available )
return self . iter_end ( extra )
nuninst = None
while len ( available ) > depth :
x = available . pop ( 0 )
if not skiphint ( x ) :
self . doop_source ( x )
self . selected . append ( x )
res = self . iter_some ( depth - 1 , available [ : ] , extra [ : ] )
if res [ 0 ] :
nuninst = res [ 0 ]
available = filter ( lambda x , y = res [ 1 ] : x in y ,
available + extra )
# reset nuninst_orig too
self . nuninst_orig = nuninst
extra = [ ]
continue
self . srcsn . undo_change ( )
self . selected . pop ( )
extra . append ( x )
return ( nuninst , extra )
# Package information
testing = britney . Sources ( testingdir , arches )
testingpkgs = { }
for arch in arches :
testingpkgs [ arch ] = testing . Packages ( arch )
testingbugs = read_bugs ( testingdir + " /Bugs " )
unstable = britney . Sources ( unstabledir , arches )
unstablepkgs = { }
for arch in arches :
unstablepkgs [ arch ] = unstable . Packages ( arch )
unstablebugs = read_bugs ( unstabledir + " /Bugs " )
unstabledates = read_dates ( testingdir + " /Dates " )
unstableurg = read_urgencies ( testingdir + " /Urgency " , testing , unstable )
testingupdates = britney . Sources ( testingupdatesdir , arches )
testingupdatespkgs = { }
for arch in arches :
testingupdatespkgs [ arch ] = testingupdates . Packages ( arch )
testingupdatesapproved = { } # pkg_ver -> who
for approver in [ " ajt " , " security-team " , " ftpmaster " , " cjwatson " , " vorlon " ] :
read_approvals ( testingupdatesdir + " /Approved " , approver ,
testingupdatesapproved )
hlphints = [ " easy " , " hint " , " remove " , " block " , " unblock " , " approve " ]
stdhints = [ " easy " , " hint " , " remove " , " block " , " unblock " , " urgent " , " approve " ]
allhints = [ " force " , " force-hint " , " block-all " ] + stdhints
hintsallowed = {
" ajt " : allhints ,
" rmurray " : allhints ,
" cjwatson " : allhints ,
" vorlon " : allhints ,
" aba " : allhints ,
" joeyh " : stdhints + [ " force " ] ,
" djpig " : stdhints ,
" he " : hlphints ,
" adeodato " : hlphints ,
" ballombe " : hlphints ,
" luk " : hlphints ,
" freeze " : [ " block " , " block-all " ] ,
" ftpteam " : [ " block " ]
}
hints = { " easy " : [ ] , " hint " : [ ] , " force-hint " : [ ] , " remove " : [ ] , " block " : [ ] , " block-all " : [ ] , " unblock " : [ ] , " force " : [ ] , " urgent " : [ ] , " approve " : [ ] }
for who in hintsallowed . keys ( ) :
h = read_hints ( unstabledir + " /Hints " , who , hints , hintsallowed [ who ] )
for k in hintsallowed [ who ] :
hints [ k ] . extend ( h [ k ] )
for x in [ " block " , " block-all " , " unblock " , " force " , " urgent " , " remove " ] :
z = { }
for a , b in hints [ x ] :
if z . has_key ( a ) :
print " Overriding %s [ %s ] = %s with %s " % ( x , a , z [ a ] , b )
z [ a ] = b
hints [ x ] = z
for p , vh in hints [ " approve " ] :
( v , h ) = vh
testingupdatesapproved [ " %s _ %s " % ( p , v ) ] = h
hints [ " unblock " ] [ " %s " % p ] = ( v , h )
def maxver ( pkg , source , pkgs ) :
maxver = source . get_version ( pkg )
for arch in arches :
pkgv = pkgs [ arch ] . get_version ( pkg )
if pkgv == None : continue
if maxver == None or britney . versioncmp ( pkgv , maxver ) > 0 :
maxver = pkgv
return maxver
for pkg in testingbugs . keys ( ) + unstablebugs . keys ( ) :
if not testingbugs . has_key ( pkg ) : testingbugs [ pkg ] = 0
if not unstablebugs . has_key ( pkg ) : unstablebugs [ pkg ] = 0
maxvert = maxver ( pkg , testing , testingpkgs )
if maxvert == None :
testingbugs [ pkg ] = 0
continue
if testingbugs [ pkg ] == unstablebugs [ pkg ] : continue
maxveru = maxver ( pkg , unstable , unstablepkgs )
if maxveru == None :
continue
if britney . versioncmp ( maxvert , maxveru ) > = 0 :
testingbugs [ pkg ] = unstablebugs [ pkg ]
datenow = int ( ( ( time . time ( ) / ( 60 * 60 ) ) - 15 ) / 24 ) ;
# Next, work out which packages are candidates to be changed.
upgrademe = [ ]
excuses = [ ]
# Packages to be removed
for src in testing . sources :
if should_remove_source ( src , testing , unstable , excuses ) :
upgrademe . append ( " - " + src )
# Packages to be upgraded from unstable:
for src in unstable . sources :
if testing . is_present ( src ) :
tsrcv = testing . get_version ( src ) # silly optimisation
for arch in arches :
if should_upgrade_srcarch ( src , arch , None , tsrcv ,
testing , testingpkgs [ arch ] ,
unstable , unstablepkgs [ arch ] ,
excuses ) :
upgrademe . append ( " %s / %s " % ( src , arch ) )
if should_upgrade_src ( src , None , testing , testingpkgs ,
unstable , unstablepkgs , None , excuses ) :
upgrademe . append ( src )
for src in testingupdates . sources :
if testing . is_present ( src ) :
tsrcv = testing . get_version ( src ) # silly optimisation
for arch in arches :
if should_upgrade_srcarch ( src , arch , " tpu " , tsrcv ,
testing , testingpkgs [ arch ] ,
testingupdates ,
testingupdatespkgs [ arch ] ,
excuses ) :
upgrademe . append ( " %s / %s _tpu " % ( src , arch ) )
if should_upgrade_src ( src , " tpu " , testing , testingpkgs ,
testingupdates , testingupdatespkgs ,
testingupdatesapproved , excuses ) :
upgrademe . append ( " %s _tpu " % src )
for src in hints [ " remove " ] . keys ( ) :
if src in upgrademe : continue
if ( " - " + src ) in upgrademe : continue
if not testing . is_present ( src ) : continue
tsrcv = testing . get_version ( src )
if not same_source ( tsrcv , hints [ " remove " ] [ src ] [ 0 ] ) : continue
upgrademe . append ( " - %s " % ( src ) )
exc = Excuse ( " - %s " % ( src ) )
exc . set_vers ( tsrcv , None )
exc . addhtml ( " Removal request by %s " % ( hints [ " remove " ] [ src ] [ 1 ] ) )
exc . addhtml ( " Package is broken, will try to remove " )
excuses . append ( exc )
def cmpexcuses ( el , er ) :
return cmp ( el . daysold , er . daysold ) or cmp ( el . name , er . name )
excuses . sort ( cmpexcuses )
def reversed_exc_deps ( excuses ) :
res = { }
for exc in excuses :
for d in exc . deps :
if not res . has_key ( d ) : res [ d ] = [ ]
res [ d ] . append ( exc . name )
return res
def invalidate ( excuses , valid , invalid ) :
i = 0
exclookup = { }
for e in excuses :
exclookup [ e . name ] = e
revdeps = reversed_exc_deps ( excuses )
while i < len ( invalid ) :
if not revdeps . has_key ( invalid [ i ] ) :
i + = 1
continue
if ( invalid [ i ] + " _tpu " ) in valid :
i + = 1
continue
for x in revdeps [ invalid [ i ] ] :
if x in valid and exclookup [ x ] . dontinvalidate :
continue
exclookup [ x ] . invalidate_dep ( invalid [ i ] )
if x in valid :
p = valid . index ( x )
invalid . append ( valid . pop ( p ) )
exclookup [ x ] . addhtml ( " Invalidated by dependency " )
exclookup [ x ] . addhtml ( " Not considered " )
i = i + 1
unconsidered = [ ]
for exc in excuses :
if exc . name not in upgrademe : unconsidered . append ( exc . name )
for exc in excuses :
for d in exc . deps :
if d not in upgrademe and d not in unconsidered :
exc . addhtml ( " Unpossible dep: %s -> %s " % ( exc . name , d ) )
invalidate ( excuses , upgrademe , unconsidered )
f = open ( " update.EXCUSES_py " , ' w ' )
f . write ( " <!DOCTYPE HTML PUBLIC \" -//W3C//DTD HTML 4.01//EN \" \" http://www.w3.org/TR/REC-html40/strict.dtd \" > \n " )
f . write ( " <html><head><title>excuses...</title> " )
f . write ( " <meta http-equiv= \" Content-Type \" content= \" text/html;charset=utf-8 \" ></head><body> \n " )
f . write ( " <p>Generated: " + time . strftime ( " % Y. % m. %d % H: % M: % S % z " , time . gmtime ( time . time ( ) ) ) + " </p> \n " )
f . write ( " <ul> \n " )
for exc in excuses :
f . write ( " <li> %s " % exc . html ( ) )
f . write ( " </ul></body></html> \n " )
f . close ( )
del excuses
# Changes
srcsn = britney . SourcesNote ( arches )
# Initialise new testing to be the old testing
for src in testing . sources :
srcsn . upgrade_source ( testing , src )
srcsn . commit_changes ( )
#print "Things to do:"
#for x in upgrademe:
# print " " + x
run = UpgradeRun ( srcsn , unstable , testingupdates , upgrademe )
def skiphint ( candidate ) :
if " / " in candidate and candidate [ candidate . rfind ( " / " ) + 1 : ] in breakarches :
return 1
return 0
def do_hint ( type , who , pkgvers ) :
hintinfo = { " easy " : " easy " ,
" hint " : 0 ,
" force-hint " : - 1 ,
}
hintdoall = hintinfo [ type ]
run . writeout ( " Trying %s from %s : %s \n " % ( type , who ,
" " . join ( [ " %s / %s " % ( p , v ) for ( p , v ) in pkgvers ] ) ) )
ok = 1
for xp , v in pkgvers :
# is this version of this package present in unstable?
# (if it's also present in testing, do_all will skip it)
if " / " in xp :
p = xp [ : xp . find ( " / " ) ]
else :
p = xp
if p [ 0 ] == " - " :
pass
elif p . endswith ( " _tpu " ) :
if britney . versioncmp ( run . testingupdates . get_version ( p [ : - 4 ] ) , v ) != 0 :
ok = 0
run . writeout ( " Version mismatch, %s %s != %s \n " %
( p , v , run . testingupdates . get_version ( p [ : - 4 ] ) ) )
elif run . unstable . get_version ( p ) == None :
ok = 0
run . writeout ( " Source %s has no version in unstable \n " % p )
elif britney . versioncmp ( run . unstable . get_version ( p ) , v ) != 0 :
ok = 0
run . writeout ( " Version mismatch, %s %s != %s \n " %
( p , v , run . unstable . get_version ( p ) ) )
if ok :
run . do_all ( hintdoall , map ( lambda hp : hp [ 0 ] , x [ 1 ] ) )
else :
run . writeout ( " Not using hint \n " )
return ok
run . writeout ( " Generated on: %s \n " % ( time . strftime ( " % Y. % m. %d % H: % M: % S % z " , time . gmtime ( time . time ( ) ) ) ) )
run . writeout ( " Arch order is: %s \n " % " , " . join ( arches ) )
for x in hints [ " easy " ] :
do_hint ( " easy " , x [ 0 ] , x [ 1 ] )
for x in hints [ " force-hint " ] :
do_hint ( " force-hint " , x [ 0 ] , x [ 1 ] )
allpackages = [ ]
normpackages = run . packages [ : ]
archpackages = { }
for a in breakarches :
la = len ( a ) + 1
archpackages [ a ] = [ p for p in normpackages if p [ - la : ] == " / " + a ]
normpackages = [ p for p in normpackages if p [ - la : ] != " / " + a ]
run . packages = normpackages
run . writeout ( " info: main run \n " ) ;
run . do_all ( )
allpackages + = run . packages
for a in breakarches :
x = breakarches
breakarches = [ ba for ba in breakarches if ba != a ]
run . packages = archpackages [ a ]
run . writeout ( " info: broken arch run for %s \n " % ( a ) )
run . do_all ( )
#run.do_all(1)
breakarches = x
allpackages + = run . packages
run . packages = allpackages
#run.do_all(0,["caudium", "sablotron"])
hintcnt = 1
rand = whrandom . whrandom ( )
rand . seed ( 23 , 187 , 96 )
for q in range ( datenow ) :
rand . random ( )
q = rand . random ( )
q = 1.0
run . writeout ( " Current value is %f \n " % ( q ) )
if q < 0.2 :
q = 0.2
run . writeout ( " Current value bumped to %f \n " % ( q ) )
maxloops = int ( math . ceil ( math . log ( 100 / ( q * * 0.5 ) ) / math . log ( 1 + len ( run . packages ) ) ) )
maxloops = 1
run . writeout ( " Max loops for q= %.2f is %d \n " % ( q , maxloops ) )
for x in hints [ " hint " ] :
if hintcnt > 50 :
run . writeout ( " Skipping remaining hints... " )
break
if len ( x [ 1 ] ) < maxloops :
run . writeout ( " Skipping simple hint from %s ( %d < %d ): %s \n "
% ( x [ 0 ] , len ( x [ 1 ] ) , maxloops , str ( x [ 1 ] ) ) )
continue
if do_hint ( " hint " , x [ 0 ] , x [ 1 ] ) :
hintcnt + = 1
for i in range ( 1 , maxloops ) :
run . do_all ( i )
if maxloops < = 1 and len ( run . packages ) < 500 :
# too many to do all of them, let's try 5 at random
num_at_random = 5
if len ( run . packages ) > num_at_random :
run . writeout ( " Trying %d at random \n " % num_at_random )
for k in range ( num_at_random ) :
special = rand . choice ( run . packages )
if skiphint ( special ) : continue
run . writeout ( " Randomly trying %s \n " % ( special ) )
run . do_all ( 0 , [ special ] )
run . srcsn . write_notes ( testingdir )
write_bugs ( testingdir + " /Bugs " , testingbugs )
write_dates ( testingdir + " /Dates " , unstabledates )
f = open ( testingdir + ' /HeidiResult ' , ' w ' )
for arch in arches :
pkgs = srcsn . Packages ( arch )
for pkg in pkgs . packages :
pkgv = pkgs . get_version ( pkg )
pkgarch = pkgs . get_field ( pkg , ' Architecture ' )
pkgsec = pkgs . get_field ( pkg , ' Section ' )
if pkgsec == None : pkgsec = ' unknown \n '
pkgarch = pkgarch [ : - 1 ]
pkgsec = pkgsec [ : - 1 ]
f . write ( ' %s %s %s %s \n ' % ( pkg , pkgv , pkgarch , pkgsec ) )
for src in srcsn . sources :
srcv = srcsn . get_version ( src )
srcsec = srcsn . get_field ( src , ' Section ' )
if srcsec == None : srcsec = ' unknown \n '
if srcsn . is_fake ( src ) : srcsec = ' faux \n '
srcsec = srcsec [ : - 1 ]
f . write ( ' %s %s source %s \n ' % ( src , srcv , srcsec ) )
f . close ( )
if len ( arches ) != expected_arches :
sys . exit ( 1 )