From d4c2d306ab4c21ccd0d46c08a94994a59bb478de Mon Sep 17 00:00:00 2001 From: Faik Uygur Date: Sun, 20 Aug 2006 14:04:39 +0000 Subject: [PATCH] * Initial scenario tests api. --- pisi/scenarioapi/__init__.py | 27 +++++++ pisi/scenarioapi/actions.py | 31 ++++++++ pisi/scenarioapi/constants.py | 71 ++++++++++++++++++ pisi/scenarioapi/package.py | 94 ++++++++++++++++++++++++ pisi/scenarioapi/pisiops.py | 40 +++++++++++ pisi/scenarioapi/pspec.py | 131 ++++++++++++++++++++++++++++++++++ pisi/scenarioapi/repoops.py | 72 +++++++++++++++++++ pisi/scenarioapi/scenario.py | 28 ++++++++ pisi/scenarioapi/withops.py | 45 ++++++++++++ scenarios/bug3390scen.py | 49 +++++++++++++ scenarios/bug3465scen.py | 38 ++++++++++ scenarios/run.py | 57 +++++++++++++++ setup.py | 2 +- 13 files changed, 684 insertions(+), 1 deletion(-) create mode 100644 pisi/scenarioapi/__init__.py create mode 100644 pisi/scenarioapi/actions.py create mode 100644 pisi/scenarioapi/constants.py create mode 100644 pisi/scenarioapi/package.py create mode 100644 pisi/scenarioapi/pisiops.py create mode 100644 pisi/scenarioapi/pspec.py create mode 100644 pisi/scenarioapi/repoops.py create mode 100644 pisi/scenarioapi/scenario.py create mode 100644 pisi/scenarioapi/withops.py create mode 100644 scenarios/bug3390scen.py create mode 100644 scenarios/bug3465scen.py create mode 100755 scenarios/run.py diff --git a/pisi/scenarioapi/__init__.py b/pisi/scenarioapi/__init__.py new file mode 100644 index 00000000..cd339e0f --- /dev/null +++ b/pisi/scenarioapi/__init__.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2006, TUBITAK/UEKAE +# +# 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. +# +# Please read the COPYING file. +# + +import pisi + +class Error(pisi.Error): + pass + +class Exception(pisi.Exception): + pass + +import pisi.context as ctx + +def error(msg): + if ctx.config.get_option('ignore_action_errors'): + ctx.ui.error(msg) + else: + raise Error(msg) diff --git a/pisi/scenarioapi/actions.py b/pisi/scenarioapi/actions.py new file mode 100644 index 00000000..95139db6 --- /dev/null +++ b/pisi/scenarioapi/actions.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2006, TUBITAK/UEKAE +# +# 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. +# +# Please read the COPYING file. +# +# Authors: Faik Uygur + +class Actions: + + template = """ +from pisi.actionsapi import pisitools + +WorkDir = "skeleton" + +def install(): + pisitools.dobin("skeleton.py") + pisitools.rename("/usr/bin/skeleton.py", "%s") +""" + + def __init__(self, name, filepath): + self.name = name + self.filepath = filepath + + def write(self): + open(self.filepath, "w").write(self.template % self.name) diff --git a/pisi/scenarioapi/constants.py b/pisi/scenarioapi/constants.py new file mode 100644 index 00000000..7ab2aa82 --- /dev/null +++ b/pisi/scenarioapi/constants.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2006, TUBITAK/UEKAE +# +# 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. +# +# Please read the COPYING file. + +import locale +from os.path import join + +class _constant: + "Constant members implementation" + class ConstError(TypeError): + pass + + def __setattr__(self, name, value): + if self.__dict__.has_key(name): + raise self.ConstError, "Can't rebind constant: %s" % name + # Binding an attribute once to a const is available + self.__dict__[name] = value + + def __delattr__(self, name): + if self.__dict__.has_key(name): + raise self.ConstError, "Can't unbind constant: %s" % name + # we don't have an attribute by this name + raise NameError, name + +class Constants: + + __c = _constant() + + def __getattr__(self, attr): + return getattr(self.__c, attr) + + def __setattr__(self, attr, value): + setattr(self.__c, attr, value) + + def __delattr__(self, attr): + delattr(self.__c, attr) + +consts = Constants() + +consts.scenarios_path = "scenarios/" +consts.pisi_db = "db/" +consts.repo_name = "scenario-db" +consts.repo_path = "repo/" +consts.repo_url = consts.repo_path + "pisi-index.xml.bz2" + +consts.glob_pisis = "*.pisi" +consts.pisi_suffix = ".pisi" + +consts.pspec_path = "/tmp/pspec.xml" +consts.actionspy_path = "/tmp/actions.py" + +consts.packager_name = "Faik Uygur" +consts.packager_email = "faik@pardus.org.tr" + +consts.homepage = "http://cekirdek.uludag.org.tr/~faik/pisi" +consts.summary = "%s is a good application" +consts.description = "%s is a free software that can do anything it wants" +consts.license = ["GPL-2"] + +consts.skel_sha1sum = "cc64dfa6e068fe1f6fb68a635878b1ea21acfac7" +consts.skel_type = "targz" +consts.skel_uri = "http://cekirdek.uludag.org.tr/~faik/pisi/skeleton.tar.gz" +consts.skel_bindir = "/usr/bin" +consts.skel_dirtype = "executable" diff --git a/pisi/scenarioapi/package.py b/pisi/scenarioapi/package.py new file mode 100644 index 00000000..98f903c5 --- /dev/null +++ b/pisi/scenarioapi/package.py @@ -0,0 +1,94 @@ +#!/usr/bin/python +#-*- coding: utf-8 -*- +# +# Copyright (C) 2006, TUBITAK/UEKAE +# +# 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. +# +# Please read the COPYING file. +# +# Authors: Faik Uygur + +import os +import glob + +from pisi.scenarioapi.pspec import Pspec +from pisi.scenarioapi.actions import Actions +from pisi.scenarioapi.constants import * +from pisi.scenarioapi.withops import * + +class Package: + def __init__(self, name, deps = [], cons = [], date = "2006-18-18", ver = "1.0"): + self.name = name + self.dependencies = deps + self.conflicts = cons + self.version = ver + self.date = date + self.pspec = None + self.actions = None + self.create_package() + + def create_pisi(self): + os.system("pisi build %s -O %s > /dev/null 2>&1" % (consts.pspec_path, consts.repo_path)) + + def create_package(self): + pspec = Pspec(self.name, consts.pspec_path) + pspec.set_source(consts.homepage, consts.summary % self.name, consts.description % self.name, consts.license) + pspec.set_packager(consts.packager_name, consts.packager_email) + pspec.set_archive(consts.skel_sha1sum, consts.skel_type, consts.skel_uri) + pspec.set_package(self.dependencies, self.conflicts) + pspec.add_file_path(consts.skel_bindir, consts.skel_dirtype) + pspec.set_history(self.date, self.version) + + actions = Actions(self.name, consts.actionspy_path) + + self.pspec = pspec + self.actions = actions + self.pspec.write() + self.actions.write() + + self.create_pisi() + + def get_file_name(self): + # use glob. there may be buildnos at the end of the package name + pkg = glob.glob(consts.repo_path + + self.name + "-" + + self.version + "-" + + self.pspec.pspec.history[0].release + + consts.glob_pisis)[0] + + return os.path.basename(pkg) + + def version_bump(self, *args): + if args: + + if type(args[0]) == tuple: + withs = args[0] + else: + withs = args + + for with in withs: + if with.types == CONFLICT and with.action == ADDED: + self.pspec.add_conflicts(with.pkgs) + + if with.types == CONFLICT and with.action == REMOVED: + self.pspec.remove_conflicts(with.pkgs) + + if with.types == DEPENDENCY and with.action == ADDED: + self.pspec.add_dependencies(with.pkgs) + + if with.types == DEPENDENCY and with.action == REMOVED: + self.pspec.remove_dependencies(with.pkgs) + + self.pspec.update_history(self.date, self.version) + self.actions.name = self.name + self.actions.write() + self.create_pisi() + +if __name__ == "__main__": + p = Package("w0rmux", [], [], "0.7") + p.version_bump() + diff --git a/pisi/scenarioapi/pisiops.py b/pisi/scenarioapi/pisiops.py new file mode 100644 index 00000000..c1dff0f8 --- /dev/null +++ b/pisi/scenarioapi/pisiops.py @@ -0,0 +1,40 @@ +#!/usr/bin/python +#-*- coding: utf-8 -*- +# +# Copyright (C) 2006, TUBITAK/UEKAE +# +# 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. +# +# Please read the COPYING file. +# +# Authors: Faik Uygur + +import os +import pisi.util as util +from pisi.scenarioapi.constants import * + +def pisi_upgraded(): + os.system("pisi -D%s upgrade --ignore-file-conflicts" % consts.pisi_db) + +def pisi_removed(*pkg): + os.system("pisi -D%s remove %s" % (consts.pisi_db, util.strlist(pkg).rstrip())) + +def pisi_added_repo(name, url): + os.system("pisi -D%s add-repo -y %s %s" % (consts.pisi_db, name, url)) + +def pisi_updated_repo(): + os.system("pisi -D%s update-repo" % consts.pisi_db) + +def pisi_installed(*pkg): + if type(pkg[0]) == tuple: + packages = util.strlist(pkg[0]).rstrip() + else: + packages = util.strlist(pkg).rstrip() + os.system("pisi -D%s install %s" % (consts.pisi_db, packages)) + +def pisi_reinstalled(package): + os.system("pisi -D%s install --reinstall %s" % (consts.pisi_db, package)) + diff --git a/pisi/scenarioapi/pspec.py b/pisi/scenarioapi/pspec.py new file mode 100644 index 00000000..505aabbc --- /dev/null +++ b/pisi/scenarioapi/pspec.py @@ -0,0 +1,131 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2006, TUBITAK/UEKAE +# +# 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. +# +# Please read the COPYING file. +# +# Authors: Faik Uygur + +from pisi.specfile import SpecFile, Package, Update, Path +from pisi.dependency import Dependency +from pisi.pxml.autoxml import LocalText + +class Pspec: + def __init__(self, pkgname, filepath): + self.pspec = SpecFile() + self.package = Package() + self.update = Update() + self.filepath = filepath + self.name = pkgname + + @staticmethod + def read(filepath): + spec = SpecFile() + spec.read(filepath) + tmp = Pspec(spec.source.name, filepath) + + tmp.pspec.source.packager = spec.source.packager + tmp.pspec.source.homepage = spec.source.homepage + tmp.pspec.source.archive = spec.source.archive + tmp.pspec.source.name = spec.source.name + tmp.pspec.source.license = spec.source.license + tmp.pspec.source.partOf = spec.source.partOf + tmp.pspec.source.summary = spec.source.summary + tmp.pspec.source.description = spec.source.description + + for pkg in spec.packages: + p = Package() + p.name = pkg.name + p.files = pkg.files + p.conflicts = pkg.conflicts + p.packageDependencies = pkg.packageDependencies + tmp.pspec.packages.append(p) + + tmp.pspec.history = spec.history + return tmp + + def add_dependencies(self, dependencies): + for depname in dependencies: + dep = Dependency() + dep.package = depname + self.package.packageDependencies.append(dep) + + def remove_dependencies(self, dependencies): + for depname in dependencies: + for dep in self.package.packageDependencies: + if dep.package == depname: + self.package.packageDependencies.remove(dep) + + def add_conflicts(self, conflicts): + for con in conflicts: + self.package.conflicts.append(con) + + def remove_conflicts(self, conflicts): + for con in conflicts: + self.package.conflicts.remove(con) + + def update_history(self, date, version): + new = Update() + new.name = self.update.name + new.email = self.update.email + new.date = date + new.version = version + new.release = str(int(self.update.release) + 1) + self.update = new + self.pspec.history.append(self.update) + self.pspec.history.reverse() + self.write() + + def set_source(self, homepage, summary, description, license): + self.pspec.source.name = self.name + self.pspec.source.homepage = homepage + self.pspec.source.license = license + self.pspec.source.partOf = "None" + self.pspec.source.summary = LocalText("Summary") + self.pspec.source.description = LocalText("Description") + self.pspec.source.summary["en"] = summary + self.pspec.source.description["en"] = description + + def set_packager(self, name, email): + self.pspec.source.packager.name = unicode(name) + self.pspec.source.packager.email = email + self.update.name = unicode(name) + self.update.email = email + + def set_archive(self, sha1sum, type, uri): + self.pspec.source.archive.sha1sum = sha1sum + self.pspec.source.archive.type = type + self.pspec.source.archive.uri = uri + + def add_file_path(self, path, type): + p = Path() + p.path = path + p.fileType = type + self.pspec.packages[0].files.append(p) + + def set_package(self, dependencies, conflicts): + self.package.name = self.name + self.package.conflicts = conflicts + + if dependencies: + for depname in dependencies: + dep = Dependency() + dep.package = depname + self.package.packageDependencies.append(dep) + + self.pspec.packages.append(self.package) + + def set_history(self, date, version, comment = "No Comment", release = "1"): + self.update.date = date + self.update.version = version + self.update.comment = comment + self.update.release = release + self.pspec.history.append(self.update) + + def write(self): + self.pspec.write(self.filepath) diff --git a/pisi/scenarioapi/repoops.py b/pisi/scenarioapi/repoops.py new file mode 100644 index 00000000..7f196e3c --- /dev/null +++ b/pisi/scenarioapi/repoops.py @@ -0,0 +1,72 @@ +#!/usr/bin/python +#-*- coding: utf-8 -*- +# +# Copyright (C) 2006, TUBITAK/UEKAE +# +# 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. +# +# Please read the COPYING file. +# +# Authors: Faik Uygur + +import os + +from pisi.scenarioapi.package import Package +from pisi.scenarioapi.withops import * +from pisi.scenarioapi.constants import * + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +repodb = {} + +def repo_added_package(package, *args): + if repodb.has_key(package): + raise Exception(_("Repo already has package named %s.") % package) + + dependencies = None + conflicts = None + + if args: + for with in args: + if with.types == CONFLICT and with.action == INIT: + conflicts = with.pkgs + + if with.types == DEPENDENCY and with.action == INIT: + dependencies = with.pkgs + + repodb[package] = Package(package, dependencies, conflicts) + +def repo_removed_package(package): + if not repodb.has_key(package): + raise Exception(_("Repo does not have package named %s.") % package) + + os.unlink(os.path.join(consts.repo_path, repodb[package].get_file_name())) + del repodb[package] + +def repo_version_bumped(package, *args): + if not repodb.has_key(package): + raise Exception(_("Repo does not have package named %s.") % package) + + old_file = repodb[package].get_file_name() + + if args: + repodb[package].version_bump(args) + else: + repodb[package].version_bump() + + os.unlink(os.path.join(consts.repo_path, old_file)) + +def repo_updated_index(): + cur = os.getcwd() + path = os.path.join(cur, consts.repo_path) + os.chdir(consts.repo_path) + os.system("pisi index %s >/dev/null 2>&1" % path) + os.chdir(cur) + +def repo_get_url(): + return "." diff --git a/pisi/scenarioapi/scenario.py b/pisi/scenarioapi/scenario.py new file mode 100644 index 00000000..68f2a013 --- /dev/null +++ b/pisi/scenarioapi/scenario.py @@ -0,0 +1,28 @@ +#!/usr/bin/python +#-*- coding: utf-8 -*- +# +# Copyright (C) 2006, TUBITAK/UEKAE +# +# 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. +# +# Please read the COPYING file. +# +# Authors: Faik Uygur + +import os + +from pisi.scenarioapi.repoops import * +from pisi.scenarioapi.pisiops import * +from pisi.scenarioapi.constants import * + +def let_repo_had(package, *args): + repo_added_package(package, *args) + repo_updated_index() + +def let_pisi_had(*pkg): + url = os.path.join(os.getcwd(), consts.repo_url) + pisi_added_repo(consts.repo_name, url) + pisi_installed(pkg) diff --git a/pisi/scenarioapi/withops.py b/pisi/scenarioapi/withops.py new file mode 100644 index 00000000..12ffc8b0 --- /dev/null +++ b/pisi/scenarioapi/withops.py @@ -0,0 +1,45 @@ +#!/usr/bin/python +#-*- coding: utf-8 -*- +# +# Copyright (C) 2006, TUBITAK/UEKAE +# +# 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. +# +# Please read the COPYING file. +# +# Authors: Faik Uygur + +ADDED, REMOVED, INIT = range(3) +CONFLICT, DEPENDENCY = range(2) + +class with: + def __init__(self): + pass + +def with_action(types, action, pkgs): + w = with() + w.types = types + w.action = action + w.pkgs = pkgs + return w + +def with_conflicts(*cons): + return with_action(CONFLICT, INIT, cons) + +def with_dependencies(*deps): + return with_action(DEPENDENCY, INIT, deps) + +def with_added_conflicts(*cons): + return with_action(CONFLICT, ADDED, cons) + +def with_removed_conflicts(*cons): + return with_action(CONFLICT, REMOVED, cons) + +def with_added_dependencies(*deps): + return with_action(DEPENDENCY, ADDED, deps) + +def with_removed_dependencies(*deps): + return with_action(DEPENDENCY, REMOVED, deps) diff --git a/scenarios/bug3390scen.py b/scenarios/bug3390scen.py new file mode 100644 index 00000000..e21c4036 --- /dev/null +++ b/scenarios/bug3390scen.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# +# Scenario : bug3390scen.py +# +# Source : http://bugs.pardus.org.tr/show_bug.cgi?id=3390 +# +# Problem : Package reverse dependencies are not updated in pisi database +# +# caglar@zangetsu ~ $ pisi info valgrind +# Yüklü paket: +# Ad: valgrind, versiyon 3.2.0, sürüm 5, inşa 4 +# Özet: Valgrind, x86-GNU/Linux ve ppc-GNU/Linux için geliştirilmiş, bellek +# hatalarını ayıklayıcı, açık kaynaklı bir yazılımdır. +# Açıklama: Valgrind, x86-GNU/Linux ve ppc-GNU/Linux için geliştirilmiş, bellek +# hatalarını ayıklayıcı, açık kaynaklı bir yazılımdır. +# Bileşen: programming.tools +# Sağladıkları: +# Bağımlılıklar:xorg openmpi +# Dağıtım: Pardus, Dağıtım Sürümü: 1.1 +# Mimari: Any, Yerleşik Boyut: 19128120 +# Ters bağımlılıklar: kdesdk +# +# Problem Description: +# +# Valgrind package had a dependency of openmpi package. It is version bumped with removed +# dependeny of openmpi at the repository. Also openmpi is version bumped. After upgrading +# pisi repository and trying to remove openmpi, it is seen that openmpi still has a reverse +# dependency of valgrind. +# +# Expected: +# +# Pisi should have updated the reverse dependency informations correctly and should not show +# a reverse dependency of valgrind while removing openmpi, after a succesfull repository upgrade. + +from pisi.scenarioapi.scenario import * + +VALGRIND = "valgriind" +OPENMPI = "openmpii" + +let_repo_had(VALGRIND, with_dependencies(OPENMPI)) +let_repo_had(OPENMPI) +let_pisi_had(VALGRIND, OPENMPI) + +def run(): + repo_version_bumped(VALGRIND, with_removed_dependencies(OPENMPI)) + repo_version_bumped(OPENMPI) + repo_updated_index() + pisi_upgraded() + pisi_removed(OPENMPI) diff --git a/scenarios/bug3465scen.py b/scenarios/bug3465scen.py new file mode 100644 index 00000000..a11c9274 --- /dev/null +++ b/scenarios/bug3465scen.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# +# Scenario : bug3465scen.py +# +# Source : http://bugs.pardus.org.tr/show_bug.cgi?id=3465 +# +# Problem : Pisi does not warn the user about updated packages in the repository. +# +# sudo pisi it wormux --reinstall +# Bağımlılıkları sağlamak için bu paketler verilen sırada kurulacaktır: +# wormux +# Paketlerin toplam boyu: 17.62 MB +# Paket wormux, pardus-1.1 deposunda bulundu +# Program sonlandırıldı. +# http://paketler.pardus.org.tr/pardus-1.1/wormux-0.7-2-1.pisi indirilemiyor; HTTP +# Error 404: Not Found +# +# Problem Description: +# +# The user had not updated pisi's repository database for some time. Then, when pisi is asked +# to reinstall an installed package, it failed to fetch the requested version of the package. +# Because the package had been upgraded at the repository and the old package has been removed. +# +# Expected: +# +# Pisi should warn the user to update repository. + +from pisi.scenarioapi.scenario import * + +WORMUX = "w0rmux" + +let_repo_had(WORMUX) +let_pisi_had(WORMUX) + +def run(): + repo_version_bumped(WORMUX) + repo_updated_index() + pisi_reinstalled(WORMUX) diff --git a/scenarios/run.py b/scenarios/run.py new file mode 100755 index 00000000..cc624856 --- /dev/null +++ b/scenarios/run.py @@ -0,0 +1,57 @@ +#!/usr/bin/python +#-*- coding: utf-8 -*- +# +# Copyright (C) 2006, TUBITAK/UEKAE +# +# 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. +# +# Please read the COPYING file. +# +# Authors: Faik Uygur + +import os +import shutil +import glob +import sys + +from pisi.scenarioapi.constants import * + +def clean_out(): + for x in glob.glob(consts.repo_path + consts.glob_pisis): + os.unlink(x) + + if os.path.exists(consts.pisi_db): + shutil.rmtree(consts.pisi_db) + +def run_scen(scenario): + scenario() + +def run_all(): + print '** Running all scenarios' + for root, dirs, files in os.walk("."): + scensources = filter(lambda x:x.endswith('scen.py'), files) + for scensource in scensources: + clean_out() + running = "\n* Running scenario in %s\n" % scensource + print running + print len(running) * "=" + "\n" + module = __import__(scensource[:len(scensource)-3]) + run_scen(module.run) + +if __name__ == "__main__": + os.chdir(consts.scenarios_path) + + args = sys.argv + if len(args) > 1: + scens = sys.argv[1:] + for scen in scens: + clean_out() + scen += 'scen.py' + print "\n* Running scenario in %s\n" % scen + module = __import__(scen[:len(scen)-3]) + run_scen(module.run) + else: + run_all() diff --git a/setup.py b/setup.py index 2d79bee2..2703dae5 100755 --- a/setup.py +++ b/setup.py @@ -92,7 +92,7 @@ setup(name="pisi", author_email="pisi@pardus.org.tr", url="http://www.pardus.org.tr/eng/pisi/", package_dir = {'': ''}, - packages = ['pisi', 'pisi.cli', 'pisi.actionsapi', 'pisi.pxml', 'pisi.search'], + packages = ['pisi', 'pisi.cli', 'pisi.actionsapi', 'pisi.pxml', 'pisi.search', 'pisi.scenarioapi'], scripts = ['pisi-cli', 'scripts/repostats.py', 'scripts/find-lib-deps.py', 'scripts/lspisi', 'scripts/unpisi', 'scripts/calc-build-order.py', 'scripts/pisish', 'scripts/pisimedia'],