Commit 830a7732 authored by AlmAck's avatar AlmAck
Browse files

let's try to sort the packages with python

using bash is very slow, takes more then 1h to get the full dependencies tree of a group (like kde apps)
parent dc90504d
......@@ -167,11 +167,12 @@ function get_validpgpkeys() {
# Sort packages by dependency
# reorders $PACKAGES such that dependencies are built first
function sort_packages_by_dependency() {
local sorted_packages=()
for p in "${PACKAGES[@]}"; do
_build_add "${p}"
#local sorted_packages=()
#for p in "${PACKAGES[@]}"; do
# _build_add "${p}"
PACKAGES=$(python2 ./_chakra-gitlab-ci-scripts/lib/ ${PACKAGES[@]})
# determine the repository to build against
#! /usr/bin/env python2
# -*- coding: utf-8 -*-
# - find the order to build a list of packages
# Copyright (c) 2010 by Mark Pustjens <>
# Copyright (c) 2009 by Allan McRae <>
# 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
# 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, see <>.
import os, sys, re
from collections import deque
from optparse import OptionParser
def get_pkgs(pkgfile):
f = open(pkgfile)
except IOError:
print "Error: could not read packages file '%s'" % pkgfile
pkgs = set(
return pkgs
def find_pkgbuild(abspath, pkg):
cmd = 'find %s -wholename "*/%s/PKGBUILD" -print' % (abspath, pkg)
files = os.popen(cmd).readlines()
if len(files) >= 1:
return files[0][:-1]
return None
def get_deps_from_pkgbuild(pkgbuild_file):
pkgbuild = open(pkgbuild_file)
deps = set()
makedeps = set()
for line in pkgbuild.readlines():
m = re.match("^depends=\((.*)\)", line)
if m is not None:
for pkg in" "):
pkg = pkg.strip("'\"")
pkg = pkg.split(">")[0].split("<")[0].split("=")[0]
m = re.match("^makedepends=\((.*)\)", line)
if m is not None:
for pkg in" "):
pkg = pkg.strip("'\"")
pkg = pkg.split(">")[0].split("<")[0].split("=")[0]
return (deps, makedeps)
def get_deps_from_pacman(package):
deps = set()
pkginfo = os.popen("L_ALL=C pacman -Si " + package + " 2> /dev/null").read().split("\n")
if pkginfo != ['']:
found = False
for i in pkginfo:
if not found:
if i[0:10] == "Depends On":
deplist = i.split()[3:]
found = True
if i[0] != " ":
deplist += i.split()
for i in deplist:
pkg = i.split(">")[0].split("<")[0].split("=")[0]
return deps
def bfsa(G, D, R):
BFS Search on graph G, using the set R as the graph roots.
This BFS only visits a node if all its parents have been visisted.
D is the reverse adjacency list representation of G.
Nodes which are part of a cycle are not in the output.
Q = deque(R)
visited = set(R)
while Q:
v = Q.pop()
yield v
for w in G[v]:
if w not in visited and (D[w] & visited) == D[w]:
def main():
usage = "usage: %prog [options] -p <pkgfile>"
parser = OptionParser(usage)
parser.add_option('-p', '--pkg', dest="pkgfile", nargs=1,
metavar="<pkgfile>", help="File containing a list of packages.")
parser.add_option('-c', '--cycles', action="store_true", dest="cycles_only",
help="Show only packages which have circular dependencies.")
parser.add_option('-m', '--makedeps', action="store_true", dest="makedeps",
help="Automatically add makedeps to package list.")
parser.add_option('-a', '--abs', dest="abspath", nargs=1,
help="Path to ABS.")
parser.set_defaults(pkgfile=None, cycles_only=False, makedeps=False, abspath=".")
(options, args) = parser.parse_args()
#if options.pkgfile is None:
# parser.error("No package file name provided.")
# exit(1)
pkgs = set(args) #get_pkgs(options.pkgfile)
Q is a queue of all packages to be processed
G is the graph of dependencies (i depends on D[i])
D is the graph of requirements (i requires G[i]) (reversed G)
R is the list of graph roots of G
O is the ordered list of packages. Packages on top need to be compiled first.
O does not contain packages with circular dependencies.
Q = deque(pkgs)
G = {}
D = {}
R = []
M = set()
""" Fill G """
while Q:
pkg = Q.pop()
if pkg in G.keys():
pkgbuild = find_pkgbuild(options.abspath, pkg)
Determine all dependencies, including makedeps.
Try abs first and if that fails, use pacman.
This is because only abs includes makedeps.
if pkgbuild is not None:
(deps, makedeps) = get_deps_from_pkgbuild(pkgbuild)
except IOError:
makedeps = set()
deps = get_deps_from_pacman(pkg)
makedeps = set()
deps = get_deps_from_pacman(pkg)
if options.makedeps:
G[pkg] = (deps & pkgs) | makedeps # weed out deps not in the packages list, but keep makedeps
D[pkg] = set()
# we also need to process all makedeps (if requested on commandline)
for makedep in makedeps:
G[pkg] = deps & pkgs
D[pkg] = set()
""" Fill D """
for pkg in G.keys():
for dep in G[pkg]:
""" Fill R """
R = [key for key in G.keys() if len(G[key]) == 0]
""" Fill O """
O = list(bfsa(D, G, R))
if not options.cycles_only:
""" print O """
for pkg in O:
print pkg
""" print all packages not in O (i.e those whith circular dependencies) """
for pkg in G.keys():
if pkg not in O:
print pkg
if __name__ == "__main__":
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment