mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
291 lines
7.7 KiB
Python
Executable file
291 lines
7.7 KiB
Python
Executable file
#!/usr/bin/python -O
|
|
|
|
import re, os, sys, pacman, getopt
|
|
|
|
############################################################
|
|
|
|
# Define some classes we need
|
|
class Version:
|
|
def __init__(self):
|
|
self.version = None
|
|
self.file = None
|
|
|
|
class Package:
|
|
def __init__(self):
|
|
self.name = None
|
|
self.old = None
|
|
self.new = None
|
|
|
|
############################################################
|
|
# Functions for walking the file trees
|
|
############################################################
|
|
|
|
def filesForRegexp(topdir, regexp):
|
|
retval = []
|
|
def matchfile(regexp, dirpath, namelist):
|
|
for name in namelist:
|
|
if (regexp.match(name)):
|
|
retval.append(os.path.join(dirpath, name))
|
|
os.path.walk(topdir, matchfile, regexp)
|
|
return retval
|
|
|
|
def packagesInTree(topdir):
|
|
return filesForRegexp(topdir, re.compile("^.*\.pkg\.tar\.gz$"))
|
|
|
|
def pkgbuildsInTree(topdir):
|
|
return filesForRegexp(topdir, re.compile("^PKGBUILD$"))
|
|
|
|
############################################################
|
|
# Function for testing if two files are identical
|
|
############################################################
|
|
|
|
def areFilesIdentical(file_a, file_b):
|
|
command = "cmp '" + file_a + "' '" + file_b + "' >/dev/null"
|
|
retval = os.system(command)
|
|
if (retval == 0):
|
|
return True
|
|
return False
|
|
|
|
############################################################
|
|
# Function for fetching info from PKGBUILDs and packages
|
|
############################################################
|
|
|
|
def infoFromPackageFile(filename):
|
|
pkg = pacman.load(filename)
|
|
return pkg.name, pkg.version + "-" + pkg.release
|
|
|
|
def infoFromPkgbuildFile(filename):
|
|
# open and source the file
|
|
pf_stdin, pf_stdout = os.popen2("/bin/bash", 't', 0)
|
|
print >>pf_stdin, ". " + filename
|
|
|
|
# get pkgname
|
|
print >>pf_stdin, 'echo $pkgname'
|
|
pkgname = pf_stdout.readline().strip()
|
|
|
|
# get pkgver
|
|
print >>pf_stdin, 'echo $pkgver'
|
|
pkgver = pf_stdout.readline().strip()
|
|
|
|
# get pkgrel
|
|
print >>pf_stdin, 'echo $pkgrel'
|
|
pkgrel = pf_stdout.readline().strip()
|
|
|
|
# clean up
|
|
pf_stdin.close()
|
|
pf_stdout.close()
|
|
|
|
return pkgname, pkgver + "-" + pkgrel
|
|
|
|
############################################################
|
|
# Functions for doing the final steps of execution
|
|
############################################################
|
|
|
|
def execute(command):
|
|
global switches
|
|
print(command)
|
|
if not (switches.get("-n") == True):
|
|
os.system(command)
|
|
|
|
def copyFileToRepo(filename, repodir):
|
|
destfile = os.path.join(repodir, os.path.basename(filename))
|
|
command = "cp -p '" + filename + "' '" + destfile + "'"
|
|
execute(command)
|
|
|
|
def deleteFile(filename):
|
|
command = "rm '" + filename + "'"
|
|
execute(command)
|
|
|
|
def runGensync(repo, pkgbuild):
|
|
target = os.path.join(repo, os.path.basename(repo) + ".db.tar.gz")
|
|
command = "gensync '" + pkgbuild_dir + "' '" + target + "'"
|
|
execute(command)
|
|
|
|
############################################################
|
|
# Functions for error handling
|
|
############################################################
|
|
|
|
def warning(string):
|
|
print >>sys.stderr, string + "\n"
|
|
|
|
had_error = 0
|
|
def error(string):
|
|
global had_error
|
|
warning(string)
|
|
had_error = 1
|
|
|
|
############################################################
|
|
# MAIN
|
|
############################################################
|
|
|
|
# ARGUMENTS
|
|
#
|
|
# tupkgupdate [-n] [--delete] [--paranoid] <repo_dir> <pkgbuild_dir> <build_dir>
|
|
|
|
# First call getopt
|
|
switch_list,args_proper = getopt.getopt(sys.argv[1:], 'n',
|
|
[ "delete", "paranoid" ])
|
|
switches = {}
|
|
for switch in switch_list:
|
|
switches[switch[0]] = 1
|
|
|
|
# Then handle the remaining arguments
|
|
if (len(args_proper) < 3):
|
|
print >>sys.stderr, "syntax: tupkgupdate [-n] [--delete] [--paranoid] <repo_dir> <pkgbuild_tree> <build_tree>"
|
|
sys.exit(-1)
|
|
|
|
repo_dir, pkgbuild_dir, build_dir = args_proper
|
|
|
|
# Set up the lists and tables
|
|
packages = dict()
|
|
copy = list()
|
|
delete = list()
|
|
|
|
# PASS 1: PARSING/LOCATING
|
|
#
|
|
# A) Go through the PKGBUILD tree
|
|
# For each PKGBUILD, create a Package with new Version containing
|
|
# parsed version and and None for file
|
|
|
|
a_files = pkgbuildsInTree(pkgbuild_dir)
|
|
for a_file in a_files:
|
|
pkgname, ver = infoFromPkgbuildFile(a_file)
|
|
|
|
# Error (and skip) if we encounter any invalid PKGBUILD files
|
|
if (pkgname == None or ver == None):
|
|
error("Pkgbuild '" + a_file + "' is invalid!")
|
|
continue
|
|
|
|
# Error (and skip) if we encounter any duplicate package names
|
|
# in the PKGBUILDs
|
|
if (packages.get(pkgname)):
|
|
error("Pkgbuild '" + a_file + "' is a duplicate!")
|
|
continue
|
|
|
|
version = Version()
|
|
version.version = ver
|
|
version.file = None
|
|
|
|
package = Package()
|
|
package.name = pkgname
|
|
package.new = version
|
|
|
|
packages[pkgname] = package
|
|
|
|
# B) Go through the old repo dir
|
|
# For each package file we encounter, create a Package with old
|
|
# Version containing parsed version and filepath
|
|
|
|
b_files = packagesInTree(repo_dir)
|
|
for b_file in b_files:
|
|
pkgname, ver = infoFromPackageFile(b_file)
|
|
|
|
version = Version()
|
|
version.version = ver
|
|
version.file = b_file
|
|
|
|
package = packages.get(pkgname)
|
|
if (package == None):
|
|
package = Package()
|
|
package.name = pkgname
|
|
packages[pkgname] = package
|
|
package.old = version
|
|
|
|
# C) Go through the build tree
|
|
# For each package file we encounter:
|
|
# 1 - look up the package name; if it fails, ignore the file (no error)
|
|
# 2 - if package.new == None, ignore the package (no error)
|
|
# 3 - if package.new.version doesn't match, then skip (no error)
|
|
# 4 - if package.new.file == None, point it to this file
|
|
# otherwise, log an error (and skip)
|
|
|
|
c_files = packagesInTree(build_dir)
|
|
for c_file in c_files:
|
|
pkgname, ver = infoFromPackageFile(c_file)
|
|
|
|
# 1
|
|
package = packages.get(pkgname)
|
|
if (package == None):
|
|
continue
|
|
|
|
# 2
|
|
if (package.new == None):
|
|
continue
|
|
|
|
# 3
|
|
if (package.new.version != ver):
|
|
continue
|
|
|
|
# 4
|
|
if (package.new.file == None):
|
|
package.new.file = c_file
|
|
continue
|
|
else:
|
|
error("Duplicate new file '" + c_file + "'")
|
|
continue
|
|
|
|
# PASS 2: CHECKING
|
|
#
|
|
# Go through the package collection
|
|
# 1 - if package has no new, place its old file on the "delete" list
|
|
# 2 - if package has a new but no new.file, error and skip
|
|
# 3 - if package has no old, add new file to "copy" list into repo dir
|
|
# 4 - if old > new, error and skip
|
|
# 5 - if new == old, compare them and error and skip if files not the same
|
|
# 6 - add entry to "delete" list for old file and "copy" list for
|
|
# new file into repo dir
|
|
|
|
for package in packages.values():
|
|
# 1
|
|
if (package.new == None):
|
|
delete.append(package.old.file)
|
|
continue
|
|
|
|
# 2
|
|
if (package.new.file == None):
|
|
error("No new package supplied for " + package.name + " " + package.new.version + "!")
|
|
continue
|
|
|
|
# 3
|
|
if (package.old == None):
|
|
copy.append(package.new.file)
|
|
continue
|
|
|
|
# 4
|
|
if (package.old.version < package.new.version):
|
|
delete.append(package.old.file)
|
|
copy.append(package.new.file)
|
|
continue
|
|
|
|
# 5
|
|
if (package.old.version == package.new.version):
|
|
if (switches.get("--paranoid") == True):
|
|
if not (areFilesIdentical(package.old.file, package.new.file)):
|
|
warning("New package file with identical version '" +
|
|
package.new.file + "' is different than the old one:")
|
|
if (switches.get("--delete") == True):
|
|
warning(" Deleting the new file.")
|
|
else:
|
|
warning(" Ignoring the new file.")
|
|
continue
|
|
|
|
# 6
|
|
delete.append(package.old.file)
|
|
copy.append(package.new.file)
|
|
continue
|
|
|
|
## IF WE HAVE HAD ANY ERRORS AT THIS POINT, ABORT! ##
|
|
if (had_error == 1):
|
|
error("Aborting due to errors.")
|
|
sys.exit(-1)
|
|
|
|
# PASS 3: EXECUTION
|
|
#
|
|
# Copy
|
|
for file in copy:
|
|
copyFileToRepo(file, repo_dir)
|
|
# Delete (second, for safety's sake)
|
|
for file in delete:
|
|
deleteFile(file)
|
|
# Run gensync to build the repo index
|
|
runGensync(repo_dir, pkgbuild_dir)
|