From 4792d55dc85e41e77744d21e31b2854b2f8dfe23 Mon Sep 17 00:00:00 2001 From: Faik Uygur Date: Fri, 23 Nov 2007 12:34:47 +0000 Subject: [PATCH] Merge branch 'pisi-db' --- ApiPlan | 115 ++ RefactorPlan | 4 - TODO | 30 + pisi-cli | 6 +- pisi/.gitignore | 1 + pisi/__init__.py | 43 +- pisi/api.py | 582 +++--- pisi/archive.py | 15 +- pisi/atomicoperations.py | 167 +- pisi/cli/__init__.py | 12 +- pisi/cli/addrepo.py | 69 + pisi/cli/build.py | 119 ++ pisi/cli/check.py | 77 + pisi/cli/clean.py | 32 + pisi/cli/command.py | 269 +++ pisi/cli/commands.py | 1688 ----------------- pisi/cli/configurepending.py | 46 + pisi/cli/deletecache.py | 35 + pisi/cli/delta.py | 67 + pisi/cli/emerge.py | 66 + pisi/cli/graph.py | 92 + pisi/cli/help.py | 59 + pisi/cli/index.py | 73 + pisi/cli/info.py | 160 ++ pisi/cli/install.py | 81 + pisi/cli/listavailable.py | 90 + pisi/cli/listcomponents.py | 60 + pisi/cli/listinstalled.py | 76 + pisi/cli/listpending.py | 43 + pisi/cli/listrepo.py | 38 + pisi/cli/listsources.py | 60 + pisi/cli/listupgrades.py | 80 + pisi/cli/pisicli.py | 49 +- pisi/cli/rebuilddb.py | 52 + pisi/cli/remove.py | 65 + pisi/cli/removerepo.py | 38 + pisi/cli/search.py | 87 + pisi/cli/searchfile.py | 69 + pisi/cli/updaterepo.py | 59 + pisi/cli/upgrade.py | 141 ++ pisi/component.py | 5 - pisi/config.py | 11 +- pisi/configfile.py | 11 +- pisi/conflict.py | 2 +- pisi/constants.py | 6 +- pisi/context.py | 47 +- pisi/db/__init__.py | 1 + pisi/db/componentdb.py | 269 ++- pisi/db/dbshelve.py | 311 --- pisi/db/filesdb.py | 118 +- pisi/db/installdb.py | 270 ++- pisi/db/itembyrepo.py | 95 + pisi/db/itembyrepodb.py | 214 --- pisi/db/lazydb.py | 41 + pisi/db/lockeddbshelve.py | 174 -- pisi/db/packagedb.py | 266 ++- pisi/db/repodb.py | 197 +- pisi/db/sourcedb.py | 126 +- pisi/dependency.py | 16 +- pisi/files.py | 2 - pisi/index.py | 32 +- pisi/metadata.py | 2 +- pisi/operations.py | 819 -------- .../actions.py => pisi/operations/__init__.py | 15 +- pisi/{ => operations}/build.py | 26 +- pisi/{ => operations}/delta.py | 0 pisi/operations/emerge.py | 146 ++ pisi/operations/helper.py | 108 ++ pisi/operations/install.py | 239 +++ pisi/operations/remove.py | 143 ++ pisi/operations/upgrade.py | 261 +++ pisi/package.py | 4 +- pisi/pgraph.py | 23 +- pisi/pxml/autoxml.py | 6 +- pisi/relation.py | 13 +- pisi/specfile.py | 7 +- pisi/ui.py | 2 +- scripts/lspisi | 2 - scripts/unpisi | 3 - setup.py | 2 +- tests/README | 14 +- tests/a.xml | 22 - tests/actionsapitests.py | 338 ---- tests/actionsapitests/brokenlink | 1 - tests/actionsapitests/file | 6 - tests/actionsapitests/linkeddir/file | 6 - tests/actionsapitests/linktoadirectory | 1 - tests/actionsapitests/linktoafile | 1 - tests/archivetests.py | 114 -- tests/autoxmltests.py | 102 - tests/build.sh | 41 - tests/buildtests.py | 59 - tests/buildtests/a/actions.py-1 | 20 - tests/buildtests/a/actions.py-2 | 20 - tests/buildtests/a/pspec.xml | 39 - tests/configfiletests.py | 61 - tests/constantstests.py | 67 - tests/database/.gitignore | 1 + tests/database/__init__.py | 11 + tests/database/componentdbtest.py | 83 + tests/database/filesdbtest.py | 68 + tests/database/installdbtest.py | 111 ++ tests/database/itembyrepotest.py | 91 + tests/database/lazydbtest.py | 41 + tests/database/packagedbtest.py | 76 + tests/database/repodbtest.py | 62 + tests/database/sourcedbtest.py | 58 + tests/database/testcase.py | 21 + tests/dependencytests.py | 47 - tests/distribution.xml | 6 - tests/fetchertests.py | 51 - tests/filestests.py | 31 - tests/filetests.py | 33 - tests/graphtests.py | 33 - tests/helloworld/actions.py | 102 - tests/helloworld/hello-1.3.tar.gz.part | Bin 11520 -> 0 bytes tests/helloworld/pspec.xml | 35 - tests/installdbtests.py | 40 - tests/light.sh | 23 - tests/metadatatests.py | 51 - tests/ootests.py | 39 - tests/packagedbtests.py | 41 - tests/packagetests.py | 50 - tests/pccts/actions.py | 53 - tests/pccts/files/pccts-1.33.33-gentoo.diff | 69 - tests/pccts/pspec.xml | 42 - tests/pisi.conf | 6 - tests/popt/files.xml | 507 ----- tests/popt/files/popt-1.7-uclibc.patch.gz | Bin 891 -> 0 bytes tests/popt/metadata.xml | 51 - tests/popt/pspec.xml | 80 - tests/remoterepo.sh | 25 - tests/repodbtests.py | 30 - tests/repos/createrepo.py | 263 +++ tests/run.py | 52 - tests/runtests.py | 37 + tests/sourcedbtests.py | 38 - tests/specfiletests.py | 69 - tests/stress/comp/ab/actions.py | 24 - tests/stress/comp/ab/comar/package.py | 6 - .../comp/ab/files/bc-1.06-info-fix.diff | 101 - .../comp/ab/files/bc-1.06-longopts.patch | 28 - .../comp/ab/files/bc-1.06-readline42.diff | 12 - .../comp/ab/files/bc-1.06-static-save.patch | 16 - tests/stress/comp/ab/pspec.xml | 46 - tests/stress/comp/bc/actions.py | 22 - .../comp/bc/files/bc-1.06-info-fix.diff | 101 - .../comp/bc/files/bc-1.06-longopts.patch | 28 - .../comp/bc/files/bc-1.06-readline42.diff | 12 - .../comp/bc/files/bc-1.06-static-save.patch | 16 - tests/stress/comp/bc/pspec.xml | 49 - tests/stress/comp/cd/actions.py | 24 - .../comp/cd/files/bc-1.06-info-fix.diff | 101 - .../comp/cd/files/bc-1.06-longopts.patch | 28 - .../comp/cd/files/bc-1.06-readline42.diff | 12 - .../comp/cd/files/bc-1.06-static-save.patch | 16 - tests/stress/comp/cd/pspec.xml | 51 - tests/stress/comp/component.xml | 6 - tests/stress/component.xml | 6 - tests/stress/lang/component.xml | 6 - tests/stress/lang/de/actions.py | 24 - .../lang/de/files/bc-1.06-info-fix.diff | 101 - .../lang/de/files/bc-1.06-longopts.patch | 28 - .../lang/de/files/bc-1.06-readline42.diff | 12 - .../lang/de/files/bc-1.06-static-save.patch | 16 - tests/stress/lang/de/pspec.xml | 49 - tests/stress/lang/ef/actions.py | 24 - .../lang/ef/files/bc-1.06-info-fix.diff | 101 - .../lang/ef/files/bc-1.06-longopts.patch | 28 - .../lang/ef/files/bc-1.06-readline42.diff | 12 - .../lang/ef/files/bc-1.06-static-save.patch | 16 - tests/stress/lang/ef/pspec.xml | 49 - tests/stress/stress.sh | 37 - tests/testcase.py | 30 - tests/unzip/actions.py | 35 - tests/unzip/files/unzip-5.50-dotdot.patch | 85 - tests/unzip/pspec.xml | 48 - tests/unzip2/actions.py | 37 - tests/unzip2/files/unzip-5.50-dotdot.patch | 85 - tests/unzip2/pspec.xml | 48 - tests/upgrade.sh | 24 - tests/utilfiles/arfilewithtimestamps.a | Bin 74536 -> 0 bytes tests/utilfiles/directory/file_74536 | Bin 74536 -> 0 bytes tests/utilfiles/linktoarfile | 1 - tests/utilfiles/linktonowhere | 1 - tests/utiltests.py | 86 - tests/{versiontests.py => versiontest.py} | 3 - tests/xmlexttests.py | 45 - tests/zip/actions.py | 32 - tests/zip/files/zcrypt.patch | 752 -------- .../files/zip-2.3-unix_configure-pic.patch | 12 - tests/zip/files/zip-CAN-2004-1010.patch | 25 - tests/zip/pspec.xml | 49 - tests/zip2/actions.py | 34 - tests/zip2/files/zcrypt.patch | 752 -------- .../files/zip-2.3-unix_configure-pic.patch | 12 - tests/zip2/files/zip-CAN-2004-1010.patch | 25 - tests/zip2/pspec.xml | 50 - 198 files changed, 5386 insertions(+), 10482 deletions(-) create mode 100644 ApiPlan create mode 100644 TODO create mode 100644 pisi/.gitignore create mode 100644 pisi/cli/addrepo.py create mode 100644 pisi/cli/build.py create mode 100644 pisi/cli/check.py create mode 100644 pisi/cli/clean.py create mode 100644 pisi/cli/command.py delete mode 100644 pisi/cli/commands.py create mode 100644 pisi/cli/configurepending.py create mode 100644 pisi/cli/deletecache.py create mode 100644 pisi/cli/delta.py create mode 100644 pisi/cli/emerge.py create mode 100644 pisi/cli/graph.py create mode 100644 pisi/cli/help.py create mode 100644 pisi/cli/index.py create mode 100644 pisi/cli/info.py create mode 100644 pisi/cli/install.py create mode 100644 pisi/cli/listavailable.py create mode 100644 pisi/cli/listcomponents.py create mode 100644 pisi/cli/listinstalled.py create mode 100644 pisi/cli/listpending.py create mode 100644 pisi/cli/listrepo.py create mode 100644 pisi/cli/listsources.py create mode 100644 pisi/cli/listupgrades.py create mode 100644 pisi/cli/rebuilddb.py create mode 100644 pisi/cli/remove.py create mode 100644 pisi/cli/removerepo.py create mode 100644 pisi/cli/search.py create mode 100644 pisi/cli/searchfile.py create mode 100644 pisi/cli/updaterepo.py create mode 100644 pisi/cli/upgrade.py delete mode 100644 pisi/db/dbshelve.py create mode 100644 pisi/db/itembyrepo.py delete mode 100644 pisi/db/itembyrepodb.py create mode 100644 pisi/db/lazydb.py delete mode 100644 pisi/db/lockeddbshelve.py delete mode 100644 pisi/operations.py rename tests/popt/actions.py => pisi/operations/__init__.py (55%) rename pisi/{ => operations}/build.py (98%) rename pisi/{ => operations}/delta.py (100%) create mode 100644 pisi/operations/emerge.py create mode 100644 pisi/operations/helper.py create mode 100644 pisi/operations/install.py create mode 100644 pisi/operations/remove.py create mode 100644 pisi/operations/upgrade.py delete mode 100644 tests/a.xml delete mode 100644 tests/actionsapitests.py delete mode 120000 tests/actionsapitests/brokenlink delete mode 100644 tests/actionsapitests/file delete mode 100644 tests/actionsapitests/linkeddir/file delete mode 120000 tests/actionsapitests/linktoadirectory delete mode 120000 tests/actionsapitests/linktoafile delete mode 100644 tests/archivetests.py delete mode 100644 tests/autoxmltests.py delete mode 100755 tests/build.sh delete mode 100644 tests/buildtests.py delete mode 100644 tests/buildtests/a/actions.py-1 delete mode 100644 tests/buildtests/a/actions.py-2 delete mode 100644 tests/buildtests/a/pspec.xml delete mode 100644 tests/configfiletests.py delete mode 100644 tests/constantstests.py create mode 100644 tests/database/.gitignore create mode 100644 tests/database/__init__.py create mode 100644 tests/database/componentdbtest.py create mode 100644 tests/database/filesdbtest.py create mode 100644 tests/database/installdbtest.py create mode 100644 tests/database/itembyrepotest.py create mode 100644 tests/database/lazydbtest.py create mode 100644 tests/database/packagedbtest.py create mode 100644 tests/database/repodbtest.py create mode 100644 tests/database/sourcedbtest.py create mode 100644 tests/database/testcase.py delete mode 100644 tests/dependencytests.py delete mode 100644 tests/distribution.xml delete mode 100644 tests/fetchertests.py delete mode 100644 tests/filestests.py delete mode 100644 tests/filetests.py delete mode 100644 tests/graphtests.py delete mode 100644 tests/helloworld/actions.py delete mode 100644 tests/helloworld/hello-1.3.tar.gz.part delete mode 100644 tests/helloworld/pspec.xml delete mode 100644 tests/installdbtests.py delete mode 100755 tests/light.sh delete mode 100644 tests/metadatatests.py delete mode 100644 tests/ootests.py delete mode 100644 tests/packagedbtests.py delete mode 100644 tests/packagetests.py delete mode 100644 tests/pccts/actions.py delete mode 100644 tests/pccts/files/pccts-1.33.33-gentoo.diff delete mode 100644 tests/pccts/pspec.xml delete mode 100644 tests/pisi.conf delete mode 100644 tests/popt/files.xml delete mode 100644 tests/popt/files/popt-1.7-uclibc.patch.gz delete mode 100644 tests/popt/metadata.xml delete mode 100644 tests/popt/pspec.xml delete mode 100755 tests/remoterepo.sh delete mode 100644 tests/repodbtests.py create mode 100755 tests/repos/createrepo.py delete mode 100755 tests/run.py create mode 100755 tests/runtests.py delete mode 100644 tests/sourcedbtests.py delete mode 100644 tests/specfiletests.py delete mode 100644 tests/stress/comp/ab/actions.py delete mode 100644 tests/stress/comp/ab/comar/package.py delete mode 100644 tests/stress/comp/ab/files/bc-1.06-info-fix.diff delete mode 100644 tests/stress/comp/ab/files/bc-1.06-longopts.patch delete mode 100644 tests/stress/comp/ab/files/bc-1.06-readline42.diff delete mode 100644 tests/stress/comp/ab/files/bc-1.06-static-save.patch delete mode 100644 tests/stress/comp/ab/pspec.xml delete mode 100644 tests/stress/comp/bc/actions.py delete mode 100644 tests/stress/comp/bc/files/bc-1.06-info-fix.diff delete mode 100644 tests/stress/comp/bc/files/bc-1.06-longopts.patch delete mode 100644 tests/stress/comp/bc/files/bc-1.06-readline42.diff delete mode 100644 tests/stress/comp/bc/files/bc-1.06-static-save.patch delete mode 100644 tests/stress/comp/bc/pspec.xml delete mode 100644 tests/stress/comp/cd/actions.py delete mode 100644 tests/stress/comp/cd/files/bc-1.06-info-fix.diff delete mode 100644 tests/stress/comp/cd/files/bc-1.06-longopts.patch delete mode 100644 tests/stress/comp/cd/files/bc-1.06-readline42.diff delete mode 100644 tests/stress/comp/cd/files/bc-1.06-static-save.patch delete mode 100644 tests/stress/comp/cd/pspec.xml delete mode 100644 tests/stress/comp/component.xml delete mode 100644 tests/stress/component.xml delete mode 100644 tests/stress/lang/component.xml delete mode 100644 tests/stress/lang/de/actions.py delete mode 100644 tests/stress/lang/de/files/bc-1.06-info-fix.diff delete mode 100644 tests/stress/lang/de/files/bc-1.06-longopts.patch delete mode 100644 tests/stress/lang/de/files/bc-1.06-readline42.diff delete mode 100644 tests/stress/lang/de/files/bc-1.06-static-save.patch delete mode 100644 tests/stress/lang/de/pspec.xml delete mode 100644 tests/stress/lang/ef/actions.py delete mode 100644 tests/stress/lang/ef/files/bc-1.06-info-fix.diff delete mode 100644 tests/stress/lang/ef/files/bc-1.06-longopts.patch delete mode 100644 tests/stress/lang/ef/files/bc-1.06-readline42.diff delete mode 100644 tests/stress/lang/ef/files/bc-1.06-static-save.patch delete mode 100644 tests/stress/lang/ef/pspec.xml delete mode 100755 tests/stress/stress.sh delete mode 100644 tests/testcase.py delete mode 100644 tests/unzip/actions.py delete mode 100644 tests/unzip/files/unzip-5.50-dotdot.patch delete mode 100644 tests/unzip/pspec.xml delete mode 100644 tests/unzip2/actions.py delete mode 100644 tests/unzip2/files/unzip-5.50-dotdot.patch delete mode 100644 tests/unzip2/pspec.xml delete mode 100755 tests/upgrade.sh delete mode 100644 tests/utilfiles/arfilewithtimestamps.a delete mode 100644 tests/utilfiles/directory/file_74536 delete mode 120000 tests/utilfiles/linktoarfile delete mode 120000 tests/utilfiles/linktonowhere delete mode 100644 tests/utiltests.py rename tests/{versiontests.py => versiontest.py} (97%) delete mode 100644 tests/xmlexttests.py delete mode 100644 tests/zip/actions.py delete mode 100644 tests/zip/files/zcrypt.patch delete mode 100644 tests/zip/files/zip-2.3-unix_configure-pic.patch delete mode 100644 tests/zip/files/zip-CAN-2004-1010.patch delete mode 100644 tests/zip/pspec.xml delete mode 100644 tests/zip2/actions.py delete mode 100644 tests/zip2/files/zcrypt.patch delete mode 100644 tests/zip2/files/zip-2.3-unix_configure-pic.patch delete mode 100644 tests/zip2/files/zip-CAN-2004-1010.patch delete mode 100644 tests/zip2/pspec.xml diff --git a/ApiPlan b/ApiPlan new file mode 100644 index 00000000..c6156738 --- /dev/null +++ b/ApiPlan @@ -0,0 +1,115 @@ +API Plan +======== + +Pisi does not have a usable api. All the projects use its internal modules to do their +jobs. This file holds a list of these usages by project as a guide for a new competent +pisi api. + +PiSi +==== + +Below are pisi's internal calls that they may help to figure out common api calls. + +* packagedb.remove_repo +* sourcedb.remove_repo +* packagedb.which_repo +* repodb.get_repo +* packagedb.get_package +* installdb.is_installed +* packagedb.get_rev_deps +* installdb.get_version +* packagedb.has_package +* packagedb.add_package +* componentdb.add_package +* filesdb.has_file +* filesdb.get_file +* installdb.get_info +* installdb.files +* installdb.pkg_dir +* installdb.install +* filesdb.add_files +* componentdb.add_spec +* sourcedb.add_spec +* componentdb.get_union_comp +* componentdb.remove_spec +* installdb.get_version +* componentdb.remove_repo +* componentdb.remove_package +* componentdb.update_component +* componentdb.add_package +* installdb.remove +* filesdb.remove_files +* sourcedb.pkgtosrc +* sourcedb.get_spec +* sourcedb.get_source +* sourcedb.get_spec_repo +* repodb.get_repo +* componentdb.has_component +* componentdb.get_component +* installdb.is_installed +* packagedb.list_packages +* installdb.list_installed +* componentdb.get_union_packages +* componentdb.list_components +* repodb.list +* sourcedb.list +* installdb.list_pending +* filesdb.match_files + +Package Manager +=============== + +Below are the pisi modules used internally by package-manager. Package-manager should use pisi +api. + +* repodb.get_repo +* packagedb.get_package + pm still uses the old packagedb with pisi.itemsbyrepo.installed or pisi.itemsbyrepo.repos params +* componentdb.list_components +* repodb.list +* componentdb.get_union_comp +* componentdb.get_union_packages + +Yali +==== + +Below are the pisi modules used internally by Yali. Yali should use pisi api. + +* api.add_repo +* api.update_repo +* api.remove_repo +* api.install +* packagedb.list_packages +* installdb.list_pending +* api.configure_pending +* packagedb.get_package + +Buildfarm +========= + +Below are the pisi modules used internally by Buildfarm. + +* api.create_delta_package + +PackageKit +========== + +Below are the pisi modules used internally by PackageKit. + +* installdb.has_package +* installdb.get_package +* packagedb.has_package +* packagedb.get_package +* installdb.get_rev_deps +* packagedb.get_rev_deps +* installdb.get_package.runtimeDependencies +* packagedb.get_package.runtimeDependencies +* api.install +* api.upgrade +* api.remove +* api.list_upgradable +* api.update_repo +* api.list_repos +* repodb.get_repo.indexuri.get_uri +* version.Version +* util.any diff --git a/RefactorPlan b/RefactorPlan index f3a5c14e..1913d365 100644 --- a/RefactorPlan +++ b/RefactorPlan @@ -96,10 +96,6 @@ used. (see remove_unused_attributes.patch) ones named tmpDir/tmp_dir/target_dir) are redundant now. See http://liste.uludag.org.tr/uludag-commits/2007-February/010070.html -* conflict.py -conflicts method takes a pkg_name parameter but doesn't use it at all - - ==> Fixes (that need API breakage) * http://liste.uludag.org.tr/uludag-commits/2007-February/010117.html diff --git a/TODO b/TODO new file mode 100644 index 00000000..c46cf546 --- /dev/null +++ b/TODO @@ -0,0 +1,30 @@ +* Create meaningful Exception classes. Remove "Error" exceptions + +* Humanized error messages after Exception work done + +* Pisi command outputs overhaul + +* If possible remove context from pisi + +* autoxml is hairy and not maintainable. If possible replace it with a simpler and + faster xml objectifier implementation. + +* We need to update some state file during the pisi operation to implement a transaction + like system. And take some actions after last failure of pisi for some reason. + +* Messages in log file are not very helpful. Log messages overhaul needed. We need detailed + logging. + +* Tidy pisi.api to satisfy necessary functions + +* Write a new unit test suite + +* Refactor code after unit tests are finished. Divide long functions. Rename + necessary function and variable names (like A, B_C, D_, C) to understandable + ones + +* Add documentation to all module functions + +* Performance and memory usage optimizations + +* Version validator diff --git a/pisi-cli b/pisi-cli index 0dab058c..6ca202f6 100755 --- a/pisi-cli +++ b/pisi-cli @@ -32,10 +32,6 @@ def sig_handler(sig, frame): exit() def exit(): - try: - pisi.api.finalize() - except KeyboardInterrupt: # raised pending interrupt - pass sys.exit(1) def handle_exception(exception, value, tb): @@ -73,7 +69,7 @@ Please file a bug report. (http://bugs.uludag.org.tr)""")) ui.info(_("Traceback:")) traceback.print_tb(tb) else: - if not exception is pisicli.Error: + if not exception is pisi.Error: ui.info(_("Use --debug to see a traceback.")) exit() diff --git a/pisi/.gitignore b/pisi/.gitignore new file mode 100644 index 00000000..0d20b648 --- /dev/null +++ b/pisi/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/pisi/__init__.py b/pisi/__init__.py index 7aa9dcf9..92269cf6 100644 --- a/pisi/__init__.py +++ b/pisi/__init__.py @@ -12,10 +12,11 @@ # PiSi version -__version__ = "1.1.5" +import os +import atexit +import logging -__dbversion__ = "1.1.5" -__filesdbversion__ = "1.0.5" # yes, this is the real bottleneck +__version__ = "1.1.5" __all__ = [ 'api', 'configfile', 'db'] @@ -35,6 +36,38 @@ class Error(Exception): pass import pisi.api +import pisi.config +import pisi.context as ctx -# FIXME: can't do this due to name clashes in config and other singletons booo -#pisi.api import * +def init_logging(): + log_dir = os.path.join(ctx.config.dest_dir(), ctx.config.log_dir()) + if os.access(log_dir, os.W_OK): + handler = logging.handlers.RotatingFileHandler('%s/pisi.log' % log_dir) + formatter = logging.Formatter('%(asctime)-12s: %(levelname)-8s %(message)s') + handler.setFormatter(formatter) + ctx.log = logging.getLogger('pisi') + ctx.log.addHandler(handler) + ctx.loghandler = handler + ctx.log.setLevel(logging.DEBUG) + +def _cleanup(): + """Close the database cleanly and do other cleanup.""" + ctx.disable_keyboard_interrupts() + if ctx.log: + ctx.loghandler.flush() + ctx.log.removeHandler(ctx.loghandler) + + filesdb = pisi.db.filesdb.FilesDB() + if filesdb.is_initialized(): + filesdb.close() + + if ctx.build_leftover and os.path.exists(ctx.build_leftover): + os.unlink(ctx.build_leftover) + + ctx.ui.close() + ctx.enable_keyboard_interrupts() + +atexit.register(_cleanup) + +ctx.config = pisi.config.Config(pisi.config.Options()) +init_logging() diff --git a/pisi/api.py b/pisi/api.py index df6eb0b3..2f5e2953 100644 --- a/pisi/api.py +++ b/pisi/api.py @@ -9,10 +9,7 @@ # # Please read the COPYING file. -"""Top level PiSi interfaces. a facade to the entire PiSi system""" - import os -import sys import logging import logging.handlers @@ -32,140 +29,237 @@ import pisi.db.filesdb import pisi.db.installdb import pisi.db.sourcedb import pisi.db.componentdb -import pisi.db.lockeddbshelve as shelve import pisi.index import pisi.config import pisi.metadata import pisi.file -import pisi.version -import pisi.operations -import pisi.build import pisi.atomicoperations -import pisi.delta +import pisi.operations.delta +import pisi.operations.remove +import pisi.operations.upgrade +import pisi.operations.install +import pisi.operations.helper +import pisi.operations.emerge +import pisi.operations.build import pisi.comariface -import pisi.signalhandler -class Error(pisi.Error): - pass - -def init(database = True, write = True, - options = pisi.config.Options(), ui = None, comar = True, - stdout = None, stderr = None, - comar_sockname = None, - signal_handling = True): - """Initialize PiSi subsystem. - - You should call finalize() when your work is finished. Otherwise - you can left the database in a bad state. - +def set_userinterface(ui): + """ + Set the user interface where the status information will be send + @param ui: User interface """ + ctx.ui = ui - # UI comes first - - if ui is None: - # FIXME: api importing and using pisi.cli ???? - import pisi.cli - if options: - ctx.ui = pisi.cli.CLI(options.debug, options.verbose) - else: - ctx.ui = pisi.cli.CLI() - else: - ctx.ui = ui - - # FIXME: something is wrong here... see __init__.py also. Why do we import pisi.api in __init__.py - import pisi.config - ctx.config = pisi.config.Config(options) - - if os.access('%s/var/log' % ctx.config.log_dir(), os.W_OK): - handler = logging.handlers.RotatingFileHandler('%s/var/log/pisi.log' % ctx.config.log_dir()) - #handler.setLevel(logging.DEBUG) - formatter = logging.Formatter('%(asctime)-12s: %(levelname)-8s %(message)s') - handler.setFormatter(formatter) - ctx.log = logging.getLogger('pisi') - ctx.log.addHandler(handler) - ctx.loghandler = handler - ctx.log.setLevel(logging.DEBUG) - else: - ctx.log = None - - # If given define stdout and stderr. Needed by buildfarm currently - # but others can benefit from this too. +def set_io_streams(stdout=None, stderr=None): + """ + Set standart i/o streams + Used by Buildfarm + @param stdout: Standart output + @param stderr: Standart input + """ if stdout: ctx.stdout = stdout if stderr: ctx.stderr = stderr - if signal_handling: - ctx.sig = pisi.signalhandler.SignalHandler() +def set_comar(enable): + """ + Set comar usage + False means no preremove and postinstall scripts will be run + @param enable: Flag indicating comar usage + """ + ctx.comar = enable - # TODO: this is definitely not dynamic beyond this point! - ctx.comar = comar and not ctx.config.get_option('ignore_comar') - # This is for YALI, used in comariface.py - ctx.comar_sockname = comar_sockname +def set_comar_sockname(sockname): + """ + Set comar socket file + Used by YALI + @param sockname: Path to comar socket file + """ + ctx.comar_sockname = sockname - # initialize repository databases - ctx.database = database - if database: - shelve.init_dbenv(write=write) - ctx.repodb = pisi.db.repodb.init() - ctx.installdb = pisi.db.installdb.init() - ctx.filesdb = pisi.db.filesdb.init() - ctx.componentdb = pisi.db.componentdb.init() - ctx.packagedb = pisi.db.packagedb.init() - ctx.sourcedb = pisi.db.sourcedb.init() - else: - ctx.repodb = None - ctx.installdb = None - ctx.filesdb = None - ctx.componentdb = None - ctx.packagedb = None - ctx.sourcedb = None - ctx.ui.debug('PiSi API initialized') - ctx.initialized = True +def set_options(options): + """ + Set various options of pisi + @param options: option set + + >>> options = pisi.config.Options() + + options.destdir # pisi destination directory where operations will take effect + options.username # username that for reaching remote repository + options.password # password that for reaching remote repository + options.debug # flag controlling debug output + options.verbose # flag controlling verbosity of the output messages + """ + ctx.config = pisi.config.Config(options) -def finalize(): - """Close the database cleanly and do other cleanup.""" - if ctx.initialized: - ctx.disable_keyboard_interrupts() - if ctx.log: - ctx.loghandler.flush() - ctx.log.removeHandler(ctx.loghandler) - - - pisi.db.repodb.finalize() - pisi.db.installdb.finalize() - pisi.db.filesdb.finalize() - pisi.db.componentdb.finalize() - pisi.db.packagedb.finalize() - pisi.db.sourcedb.finalize() - - if ctx.dbenv: - ctx.dbenv.close() - ctx.dbenv_lock.close() - if ctx.build_leftover and os.path.exists(ctx.build_leftover): - os.unlink(ctx.build_leftover) - - ctx.ui.debug('PiSi API finalized') - ctx.ui.close() - ctx.initialized = False - ctx.enable_keyboard_interrupts() +def list_pending(): + """ + Return a list of configuration pending packages -> list_of_strings + """ + return pisi.db.installdb.InstallDB().list_pending() def list_installed(): - """Return a set of installed package names.""" - return set(ctx.installdb.list_installed()) + """ + Return a list of installed packages -> list_of_strings + """ + return pisi.db.installdb.InstallDB().list_installed() -def list_replaces(repo = None): - """Returns a dict of the replaced packages.""" - return ctx.packagedb.get_replaces(repo = repo) +def list_replaces(repo=None): + """ + Return a dictionary of the replaced packages in the given repository + @param repo: Repository of the replaced packages. If repo is None than returns + a dictionary of all the replaced packages in all the repositories + + {'gaim':'pidgin, 'actioncube':'assaultcube'} + + gaim replaced by pidgin and actioncube replaced by assaultcube + """ + return pisi.db.packagedb.PackageDB().get_replaces(repo) -def list_available(repo = None): - """Return a set of available package names.""" - return set(ctx.packagedb.list_packages(repo = repo)) +def list_available(repo=None): + """ + Return a list of available packages in the given repository -> list_of_strings + @param repo: Repository of the packages. If repo is None than returns + a list of all the available packages in all the repositories + """ + return pisi.db.packagedb.PackageDB().list_packages(repo) def list_upgradable(): - return filter(pisi.operations.is_upgradable, ctx.installdb.list_installed()) + ctx.packagedb.get_replaces().keys() + """ + Return a list of packages that are upgraded in the repository -> list_of_strings + """ + installdb = pisi.db.installdb.InstallDB() -def package_graph(A, repo = pisi.db.itembyrepodb.installed, ignore_installed = False): + upgradable = filter(pisi.operations.upgrade.is_upgradable, installdb.list_installed()) + # replaced packages can not pass is_upgradable test, so we add them manually + upgradable.extend(list_replaces()) + return upgradable + +def list_repos(): + """ + Return a list of the repositories -> list_of_strings + """ + return pisi.db.repodb.RepoDB().list_repos() + +def get_install_order(packages): + """ + Return a list of packages in the installation order with extra needed + dependencies -> list_of_strings + @param packages: list of package names -> list_of_strings + """ + install_order = pisi.operations.install.plan_install_pkg_names + i_graph, order = install_order(packages, ignore_package_conflicts=True) + return order + +def get_remove_order(packages): + """ + Return a list of packages in the remove order -> list_of_strings + @param packages: list of package names -> list_of_strings + """ + remove_order = pisi.operations.remove.plan_remove + i_graph, order = remove_order(packages) + return order + +def get_upgrade_order(packages): + """ + Return a list of packages in the upgrade order with extra needed + dependencies -> list_of_strings + @param packages: list of package names -> list_of_strings + """ + upgrade_order = pisi.operations.upgrade.plan_upgrade + i_graph, order = upgrade_order(packages) + return order + +def get_base_upgrade_order(packages): + """ + Return a list of packages of the system.base component that needs to be upgraded + or installed in install order -> list_of_strings + All the packages of the system.base component must be installed on the system + @param packages: list of package names -> list_of_strings + """ + upgrade_order = pisi.operations.upgrade.upgrade_base + order = upgrade_order(packages, ignore_package_conflicts=True) + return list(order) + +def get_conflicts(packages): + """ + Return a tuple of the conflicting packages information -> tuple + @param packages: list of package names -> list_of_strings + + >>> (pkgs, within, pairs) = pisi.api.get_conflicts(packages) + >>> + >>> pkgs # list of packages that are installed and conflicts with the + # given packages list -> list_of_strings + >>> [...] + >>> within # list of packages that already conflict with each other + # in the given packages list -> list_of_strings + >>> [...] + >>> pairs # dictionary of conflict information that contains which package in the + # given packages list conflicts with which of the installed packages + + >>> {'imlib2': , 'valgrind': , + 'libmp4v2':'} + + >>> print map(lambda c:str(pairs[c]), pairs) + >>> ['imblib', 'callgrind', 'faad2 release >= 3'] + """ + return pisi.conflict.calculate_conflicts(packages, pisi.db.packagedb.PackageDB()) + +def search_package(terms, lang=None, repo=None): + """ + Return a list of packages that contains all the given terms either in its name, summary or + description -> list_of_strings + @param terms: a list of terms used to search package -> list_of_strings + @param lang: language of the summary and description + @param repo: Repository of the packages. If repo is None than returns a list of all the packages + in all the repositories that meets the search + """ + packagedb = pisi.db.packagedb.PackageDB() + return packagedb.search_package(terms, lang, repo) + +def search_source(terms, lang=None, repo=None): + """ + Return a list of source packages that contains all the given terms either in its name, summary or + description -> list_of_strings + @param terms: a list of terms used to search source package -> list_of_strings + @param lang: language of the summary and description + @param repo: Repository of the source packages. If repo is None than returns a list of all the source + packages in all the repositories that meets the search + """ + sourcedb = pisi.db.sourcedb.SourceDB() + return sourcedb.search_spec(terms, lang, repo) + +def search_component(terms, lang=None, repo=None): + """ + Return a list of components that contains all the given terms either in its name, summary or + description -> list_of_strings + @param terms: a list of terms used to search components -> list_of_strings + @param lang: language of the summary and description + @param repo: Repository of the components. If repo is None than returns a list of all the components + in all the repositories that meets the search + """ + componentdb = pisi.db.componentdb.ComponentDB() + return componentdb.search_component(terms, lang, repo) + +def search_file(term): + """ + Returns a tuple of package and matched files list that matches the files of the installed + packages -> list_of_tuples + @param term: used to search file -> list_of_strings + + >>> files = pisi.api.search_file("kvm-") + + >>> print files + + >>> [("kvm", (["lib/modules/2.6.18.8-86/extra/kvm-amd.ko","lib/modules/2.6.18.8-86/extra/kvm-intel.ko"])),] + """ + filesdb = pisi.db.filesdb.FilesDB() + if term.startswith("/"): # FIXME: why? why? + term = term[1:] + return filesdb.search_file(term) + +def package_graph(A, packagedb, ignore_installed = False): """Construct a package relations graph. Graph will contain all dependencies of packages A, if ignore_installed @@ -178,7 +272,7 @@ def package_graph(A, repo = pisi.db.itembyrepodb.installed, ignore_installed = F # try to construct a pisi graph of packages to # install / reinstall - G_f = pgraph.PGraph(ctx.packagedb, repo) # construct G_f + G_f = pgraph.PGraph(packagedb) # construct G_f # find the "install closure" graph of G_f by package # set A using packagedb @@ -189,7 +283,7 @@ def package_graph(A, repo = pisi.db.itembyrepodb.installed, ignore_installed = F while len(B) > 0: Bp = set() for x in B: - pkg = ctx.packagedb.get_package(x, repo) + pkg = packagedb.get_package(x) #print pkg for dep in pkg.runtimeDependencies(): if ignore_installed: @@ -201,62 +295,30 @@ def package_graph(A, repo = pisi.db.itembyrepodb.installed, ignore_installed = F B = Bp return G_f -def generate_install_order(A): - # returns the install order of the given install package list with any extra - # dependency that is also going to be installed - G_f, order = plan_install(A, ignore_package_conflicts = True) - return order - -def generate_remove_order(A): - # returns the remove order of the given removal package list with any extra - # reverse dependency that is also going to be removed - G_f, order = plan_remove(A) - return order - -def generate_upgrade_order(A): - # returns the upgrade order of the given upgrade package list with any needed extra - # dependency - G_f, order = plan_upgrade(A) - return order - -def generate_base_upgrade(A): - # all the packages of the system.base must be installed on the system. - # method returns the currently needed system.base component install and - # upgrade needs - base = upgrade_base(A, ignore_package_conflicts = True) - return list(base) - -def generate_conflicts(A): - # returns the conflicting packages list of the to be installed packages. - # @conflicting_pkgs: conflicting and must be removed packages list to proceed - # @conflicts_inorder: list of the conflicting packages _with each other_ in the to be installed list - # @conflicting_pairs: dictionary that contains which package in the to be installed list conflicts - # with which packages - - (conflicting_pkgs, conflicts_inorder, conflicting_pairs) = pisi.conflict.calculate_conflicts(A, ctx.packagedb) - return (conflicting_pkgs, conflicts_inorder, conflicting_pairs) - def generate_pending_order(A): # returns pending package list in reverse topological order of dependency - G_f = pgraph.PGraph(ctx.packagedb, pisi.db.itembyrepodb.installed) # construct G_f - for x in A.keys(): + installdb = pisi.db.installdb.InstallDB() + G_f = pgraph.PGraph(installdb) # construct G_f + for x in A: G_f.add_package(x) B = A while len(B) > 0: Bp = set() - for x in B.keys(): - pkg = ctx.packagedb.get_package(x, pisi.db.itembyrepodb.installed) + for x in B: + pkg = installdb.get_package(x) for dep in pkg.runtimeDependencies(): if dep.package in G_f.vertices(): G_f.add_dep(x, dep) B = Bp if ctx.get_option('debug'): + import sys G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() order.reverse() + componentdb = pisi.db.componentdb.ComponentDB() # Bug 4211 - if ctx.componentdb.has_component('system.base'): + if componentdb.has_component('system.base'): order = reorder_base_packages(order) return order @@ -264,18 +326,18 @@ def generate_pending_order(A): def configure_pending(): # start with pending packages # configure them in reverse topological order of dependency - A = ctx.installdb.list_pending() + installdb = pisi.db.installdb.InstallDB() + A = installdb.list_pending() order = generate_pending_order(A) try: for x in order: - if ctx.installdb.is_installed(x): - pkginfo = A[x] + if installdb.has_package(x): + pkginfo = installdb.get_package(x) pkgname = pisi.util.package_name(x, pkginfo.version, pkginfo.release, False, False) - pkg_path = pisi.util.join_path(ctx.config.lib_dir(), - 'package', pkgname) + pkg_path = pisi.util.join_path(ctx.config.packages_dir(), pkgname) m = pisi.metadata.MetaData() metadata_path = pisi.util.join_path(pkg_path, ctx.const.metadata_xml) m.read(metadata_path) @@ -294,9 +356,9 @@ def configure_pending(): m.package.release ) ctx.ui.notify(pisi.ui.configured, package = pkginfo, files = None) - ctx.installdb.clear_pending(x) + installdb.clear_pending(x) except ImportError: - raise Error(_("comar package is not fully installed")) + raise pisi.Error(_("comar package is not fully installed")) def info(package, installed = False): if package.endswith(ctx.const.package_suffix): @@ -308,28 +370,31 @@ def info(package, installed = False): def info_file(package_fn): if not os.path.exists(package_fn): - raise Error (_('File %s not found') % package_fn) + raise pisi.Error (_('File %s not found') % package_fn) package = pisi.package.Package(package_fn) package.read() return package.metadata, package.files -def info_name(package_name, installed=False): +def info_name(package_name, useinstalldb=False): """Fetch package information for the given package.""" - if installed: - package = ctx.packagedb.get_package(package_name, pisi.db.itembyrepodb.installed) + + installdb = pisi.db.installdb.InstallDB() + packagedb = pisi.db.packagedb.PackageDB() + if useinstalldb: + package = installdb.get_package(package_name) repo = None else: - package, repo = ctx.packagedb.get_package_repo(package_name, pisi.db.itembyrepodb.repos) + package, repo = packagedb.get_package_repo(package_name) metadata = pisi.metadata.MetaData() metadata.package = package #FIXME: get it from sourcedb if available metadata.source = None #TODO: fetch the files from server if possible (wow, you maniac -- future exa) - if installed and ctx.installdb.is_installed(package.name): + if useinstalldb and installdb.has_package(package.name): try: - files = ctx.installdb.files(package.name) + files = installdb.get_files(package.name) except pisi.Error, e: ctx.ui.warning(e) files = None @@ -337,26 +402,6 @@ def info_name(package_name, installed=False): files = None return metadata, files, repo -def search_package_terms(terms, repo = pisi.db.itembyrepodb.all): - return search_in_packages(terms, ctx.packagedb.list_packages(repo), repo) - -def search_in_packages(terms, packages, repo = pisi.db.itembyrepodb.all): - - def search(package, term): - term = unicode(term).lower() - if term in unicode(package.name).lower() or \ - term in unicode(package.summary).lower() or \ - term in unicode(package.description).lower(): - return True - - found = [] - for name in packages: - pkg = ctx.packagedb.get_package(name, repo) - if terms == filter(lambda x:search(pkg, x), terms): - found.append(name) - - return found - def check(package): md, files = info(package, True) corrupt = [] @@ -392,31 +437,30 @@ def index(dirs=None, output='pisi-index.xml', skip_sources=False, skip_signing=F ctx.ui.info(_('* Index file written')) def add_repo(name, indexuri, at = None): - if ctx.repodb.has_repo(name): - raise Error(_('Repo %s already present.') % name) + repodb = pisi.db.repodb.RepoDB() + if repodb.has_repo(name): + raise pisi.Error(_('Repo %s already present.') % name) else: repo = pisi.db.repodb.Repo(pisi.uri.URI(indexuri)) - ctx.repodb.add_repo(name, repo, at = at) + repodb.add_repo(name, repo, at = at) ctx.ui.info(_('Repo %s added to system.') % name) def remove_repo(name): - if ctx.repodb.has_repo(name): - ctx.repodb.remove_repo(name) - pisi.util.clean_dir(os.path.join(ctx.config.index_dir(), name)) + repodb = pisi.db.repodb.RepoDB() + if repodb.has_repo(name): + repodb.remove_repo(name) ctx.ui.info(_('Repo %s removed from system.') % name) else: - ctx.ui.error(_('Repository %s does not exist. Cannot remove.') + raise pisi.Error(_('Repository %s does not exist. Cannot remove.') % name) -def list_repos(): - return ctx.repodb.list() - def update_repo(repo, force=False): ctx.ui.info(_('* Updating repository: %s') % repo) ctx.ui.notify(pisi.ui.updatingrepo, name = repo) + repodb = pisi.db.repodb.RepoDB() index = pisi.index.Index() - if ctx.repodb.has_repo(repo): - repouri = ctx.repodb.get_repo(repo).indexuri.get_uri() + if repodb.has_repo(repo): + repouri = repodb.get_repo(repo).indexuri.get_uri() try: index.read_uri_of_repo(repouri, repo) except pisi.file.AlreadyHaveException, e: @@ -432,21 +476,21 @@ def update_repo(repo, force=False): except pisi.file.NoSignatureFound, e: ctx.ui.warning(e) - ctx.txn_proc(lambda txn : index.update_db(repo, txn=txn)) ctx.ui.info(_('* Package database updated.')) else: - raise Error(_('No repository named %s found.') % repo) + raise pisi.Error(_('No repository named %s found.') % repo) def delete_cache(): - pisi.util.clean_dir(ctx.config.packages_dir()) + pisi.util.clean_dir(ctx.config.cached_packages_dir()) pisi.util.clean_dir(ctx.config.archives_dir()) pisi.util.clean_dir(ctx.config.tmp_dir()) def rebuild_repo(repo): ctx.ui.info(_('* Rebuilding \'%s\' named repo... ') % repo) - if ctx.repodb.has_repo(repo): - repouri = pisi.uri.URI(ctx.repodb.get_repo(repo).indexuri.get_uri()) + repodb = pisi.db.repodb.RepoDB() + if repodb.has_repo(repo): + repouri = pisi.uri.URI(repodb.get_repo(repo).indexuri.get_uri()) indexname = repouri.filename() index = pisi.index.Index() indexpath = pisi.util.join_path(ctx.config.index_dir(), repo, indexname) @@ -458,95 +502,38 @@ def rebuild_repo(repo): except IOError, e: ctx.ui.warning(_("Input/Output error while reading %s: %s") % (indexpath, unicode(e))) return - ctx.txn_proc(lambda txn : index.update_db(repo, txn=txn)) else: - raise Error(_('No repository named %s found.') % repo) + raise pisi.Error(_('No repository named %s found.') % repo) +# FIXME: rebuild_db is only here for filesdb and it really is ugly. we should not need any rebuild. def rebuild_db(files=False): - assert not ctx.database + filesdb = pisi.db.filesdb.FilesDB() + installdb = pisi.db.installdb.InstallDB() - # Bug 2596 - # finds and cleans duplicate package directories under '/var/lib/pisi/package' - # deletes the _older_ versioned package directories. - def clean_duplicates(): - i_version = {} # installed versions - replica = [] - for pkg in os.listdir(pisi.util.join_path(pisi.api.ctx.config.lib_dir(), 'package')): - (name, ver) = pisi.util.parse_package_name(pkg) - if i_version.has_key(name): - if pisi.version.Version(ver) > pisi.version.Version(i_version[name]): - # found a greater version, older one is a replica - replica.append(name + '-' + i_version[name]) - i_version[name] = ver - else: - # found an older version which is a replica - replica.append(name + '-' + ver) - else: - i_version[name] = ver - - for pkg in replica: - pisi.util.clean_dir(pisi.util.join_path(pisi.api.ctx.config.lib_dir(), 'package', pkg)) - - def destroy(files): - #TODO: either don't delete version files here, or remove force flag... - import bsddb3.db - for db in os.listdir(ctx.config.db_dir()): - if db.endswith('.bdb'):# or db.startswith('log'): # delete only db files - if db.startswith('files') or db.startswith('filesdbversion'): - clean = files - else: - clean = True - if clean: - fn = pisi.util.join_path(ctx.config.db_dir(), db) - #NB: there is a parameter bug with python-bsddb3, fixed in pardus - ctx.dbenv.dbremove(file=fn, flags=bsddb3.db.DB_AUTO_COMMIT) - - def reload_packages(files, txn): - packages = os.listdir(pisi.util.join_path(ctx.config.lib_dir(), 'package')) - progress = ctx.ui.Progress(len(packages)) - processed = 0 - for package_fn in packages: - if not package_fn == "scripts": - ctx.ui.debug('Resurrecting %s' % package_fn) - pisi.api.resurrect_package(package_fn, files, txn) - processed += 1 - ctx.ui.display_progress(operation = "rebuilding-db", - percent = progress.update(processed), - info = _("Rebuilding package database")) - - def reload_indices(): - index_dir = ctx.config.index_dir() - if os.path.exists(index_dir): # it may have been erased, or we may be upgrading from a previous version -- exa - for repo in os.listdir(index_dir): - indexuri = pisi.util.join_path(ctx.config.lib_dir(), 'index', repo, 'uri') - indexuri = open(indexuri, 'r').readline() - pisi.api.add_repo(repo, indexuri) - pisi.api.rebuild_repo(repo) - - # check db schema versions - try: - shelve.check_dbversion('filesdbversion', pisi.__filesdbversion__, write=False) - except KeyboardInterrupt: - raise - except Exception: #FIXME: what exception could we catch here, replace with that. - files = True # exception means the files db version was wrong - shelve.init_dbenv(write=True, writeversion=True) - destroy(files) # bye bye + def rebuild_filesdb(): + for pkg in list_installed(): + ctx.ui.info(_('* Adding \'%s\' to db... ') % pkg, noln=True) + files = installdb.get_files(pkg) + filesdb.add_files(pkg, files) + ctx.ui.info(_('OK.')) # save parameters and shutdown pisi options = ctx.config.options ui = ctx.ui comar = ctx.comar - finalize() + pisi._cleanup() + + filesdb.destroy() + filesdb.init() + + # reinitialize everything + set_userinterface(ui) + set_options(options) + set_comar(comar) # construct new database - init(database=True, options=options, ui=ui, comar=comar) - clean_duplicates() - txn = ctx.dbenv.txn_begin() - reload_packages(files, txn) - reload_indices() - txn.commit() + rebuild_filesdb() ############# FIXME: this was a quick fix. ############################## @@ -560,44 +547,29 @@ def rebuild_db(files=False): # from pisi.atomicoperations import resurrect_package, build def install(*args, **kw): - return pisi.operations.install(*args, **kw) + return pisi.operations.install.install(*args, **kw) def remove(*args, **kw): - return pisi.operations.remove(*args, **kw) + return pisi.operations.remove.remove(*args, **kw) def upgrade(*args, **kw): - return pisi.operations.upgrade(*args, **kw) + return pisi.operations.upgrade.upgrade(*args, **kw) def emerge(*args, **kw): - return pisi.operations.emerge(*args, **kw) - -def plan_install(*args, **kw): - return pisi.operations.plan_install_pkg_names(*args, **kw) - -def plan_remove(*args, **kw): - return pisi.operations.plan_remove(*args, **kw) - -def plan_upgrade(*args, **kw): - return pisi.operations.plan_upgrade(*args, **kw) - -def upgrade_base(*args, **kw): - return pisi.operations.upgrade_base(*args, **kw) + return pisi.operations.emerge.emerge(*args, **kw) def calculate_conflicts(*args, **kw): return pisi.conflict.calculate_conflicts(*args, **kw) def reorder_base_packages(*args, **kw): - return pisi.operations.reorder_base_packages(*args, **kw) + return pisi.operations.helper.reorder_base_packages(*args, **kw) def build_until(*args, **kw): - return pisi.build.build_until(*args, **kw) + return pisi.operations.build.build_until(*args, **kw) def build(*args, **kw): return pisi.atomicoperations.build(*args, **kw) -def resurrect_package(*args, **kw): - return pisi.atomicoperations.resurrect_package(*args, **kw) - ######################################################################## ## Deletes the cached pisi packages to keep the package cache dir within cache limits @@ -655,7 +627,7 @@ def clearCache(all=False): except exceptions.OSError: pass - cacheDir = ctx.config.packages_dir() + cacheDir = ctx.config.cached_packages_dir() pkgList = map(lambda x: os.path.basename(x).split(".pisi")[0], glob.glob("%s/*.pisi" % cacheDir)) if not all: diff --git a/pisi/archive.py b/pisi/archive.py index 15118602..c2a24ef2 100644 --- a/pisi/archive.py +++ b/pisi/archive.py @@ -29,12 +29,11 @@ import pisi import pisi.util as util import pisi.context as ctx -class ArchiveError(pisi.Error): +class UnknownArchiveType(Exception): pass -class LZMAError(pisi.Error): - def __init__(self, err): - pisi.Error.__init__(self, _("An error has occured while running LZMA:\n%s") % err) +class LzmaRuntimeError(Exception): + pass class ArchiveBase(object): """Base class for Archive classes.""" @@ -118,9 +117,9 @@ class ArchiveTar(ArchiveBase): ret, out, err = util.run_batch("lzma d %s %s" % (self.file_path + ctx.const.lzma_suffix, self.file_path)) if ret != 0: - raise LZMAError(err) + raise LzmaRuntimeError(err) else: - raise ArchiveError(_("Archive type not recognized")) + raise UnknownArchiveType self.tar = tarfile.open(self.file_path, rmode) oldwd = os.getcwd() @@ -180,7 +179,7 @@ class ArchiveTar(ArchiveBase): wmode = 'w:' self.file_path = self.file_path.rstrip(ctx.const.lzma_suffix) else: - raise ArchiveError(_("Archive type not recognized")) + raise UnknownArchiveType self.tar = tarfile.open(self.file_path, wmode) self.tar.add(file_name, arc_name) @@ -197,7 +196,7 @@ class ArchiveTar(ArchiveBase): ret, out, err = util.run_batch(batch) if ret != 0: - raise LZMAError(err) + raise LzmaRunTimeError(err) class MyZipFile(zipfile.ZipFile): diff --git a/pisi/atomicoperations.py b/pisi/atomicoperations.py index 0d93265a..c3141fb6 100644 --- a/pisi/atomicoperations.py +++ b/pisi/atomicoperations.py @@ -16,7 +16,6 @@ __trans = gettext.translation('pisi', fallback=True) _ = __trans.ugettext import os -import bsddb3.db as db import shutil import pisi @@ -28,8 +27,8 @@ import pisi.files import pisi.uri import pisi.ui import pisi.version -import pisi.delta -import pisi.db.packagedb +import pisi.operations.delta +import pisi.db class Error(pisi.Error): pass @@ -58,18 +57,22 @@ class Install(AtomicOperation): @staticmethod def from_name(name, ignore_dep = None): + packagedb = pisi.db.packagedb.PackageDB() # download package and return an installer object # find package in repository - repo = ctx.packagedb.which_repo(name) + repo = packagedb.which_repo(name) if repo: + repodb = pisi.db.repodb.RepoDB() ctx.ui.info(_("Package %s found in repository %s") % (name, repo)) - repo = ctx.repodb.get_repo(repo) - pkg = ctx.packagedb.get_package(name) + + repo = repodb.get_repo(repo) + pkg = packagedb.get_package(name) delta = None + installdb = pisi.db.installdb.InstallDB() # Package is installed. This is an upgrade. Check delta. - if ctx.installdb.is_installed(pkg.name): - (version, release, build) = ctx.installdb.get_version(pkg.name) + if installdb.has_package(pkg.name): + (version, release, build) = installdb.get_version(pkg.name) delta = pkg.get_delta(buildFrom=build) # If delta exists than use the delta uri. @@ -103,6 +106,8 @@ class Install(AtomicOperation): self.metadata = self.package.metadata self.files = self.package.files self.pkginfo = self.metadata.package + self.filesdb = pisi.db.filesdb.FilesDB() + self.installdb = pisi.db.installdb.InstallDB() def install(self, ask_reinstall = True): if ctx.get_option('fetch_only'): @@ -123,13 +128,7 @@ class Install(AtomicOperation): self.store_pisi_files() self.postinstall() - txn = ctx.dbenv.txn_begin() - try: - self.update_databases(txn) - txn.commit() - except db.DBError, e: - txn.abort() - raise e + self.update_databases() ctx.enable_keyboard_interrupts() @@ -156,11 +155,6 @@ class Install(AtomicOperation): raise Error(_("%s package cannot be installed unless the dependencies are satisfied") % self.pkginfo.name) - # check if package is in database - # If it is not, put it into 3rd party packagedb - if not ctx.packagedb.has_package(self.pkginfo.name): - ctx.packagedb.add_package(self.pkginfo, pisi.db.itembyrepodb.thirdparty) - # If it is explicitly specified that package conflicts with this package and also # we passed check_conflicts tests in operations.py than this means a non-conflicting # pkg is in "order" to be installed that has no file conflict problem with this package. @@ -174,15 +168,15 @@ class Install(AtomicOperation): # check file conflicts file_conflicts = [] for f in self.files.list: - if ctx.filesdb.has_file(f.path): - pkg, existing_file = ctx.filesdb.get_file(f.path) + if self.filesdb.has_file(f.path): + pkg, existing_file = self.filesdb.get_file(f.path) dst = pisi.util.join_path(ctx.config.dest_dir(), f.path) if pkg != self.pkginfo.name and not os.path.isdir(dst) and really_conflicts(pkg): file_conflicts.append( (pkg, existing_file) ) if file_conflicts: file_conflicts_str = "" for (pkg, existing_file) in file_conflicts: - file_conflicts_str += _("/%s from %s package\n") % (existing_file.path, pkg) + file_conflicts_str += _("/%s from %s package\n") % (existing_file, pkg) msg = _('File conflicts:\n%s') % file_conflicts_str if self.ignore_file_conflicts: ctx.ui.warning(msg) @@ -196,14 +190,10 @@ class Install(AtomicOperation): self.reinstall = False self.upgrade = False - if ctx.installdb.is_installed(pkg.name): # is this a reinstallation? - - #FIXME: consider REPOSITORY instead of DISTRIBUTION -- exa - #ipackage = ctx.packagedb.get_package(pkg.name, pisi.db.itembyrepodb.installed) - ipkg = ctx.installdb.get_info(pkg.name) + if self.installdb.has_package(pkg.name): # is this a reinstallation? + ipkg = self.installdb.get_info(pkg.name) repomismatch = ipkg.distribution != pkg.distribution - - (iversion, irelease, ibuild) = ctx.installdb.get_version(pkg.name) + (iversion, irelease, ibuild) = self.installdb.get_version(pkg.name) # determine if same version self.same_ver = False @@ -249,8 +239,8 @@ class Install(AtomicOperation): raise Error(_('Package downgrade declined')) # schedule for reinstall - self.old_files = ctx.installdb.files(pkg.name) - self.old_path = ctx.installdb.pkg_dir(pkg.name, iversion, irelease) + self.old_files = self.installdb.get_files(pkg.name) + self.old_path = self.installdb.pkg_dir(pkg.name, iversion, irelease) self.reinstall = True self.remove_old = Remove(pkg.name) self.remove_old.run_preremove() @@ -341,7 +331,7 @@ class Install(AtomicOperation): # of these files may be relocated to some other directory in the new package. # We handle these cases here. def relocate_files(): - for old_file, new_file in pisi.delta.find_relocations(self.old_files, self.files): + for old_file, new_file in pisi.operations.delta.find_relocations(self.old_files, self.files): old_path, new_path = ("/" + old_file.path, "/" + new_file.path) destdir = os.path.dirname(new_path) @@ -417,26 +407,19 @@ class Install(AtomicOperation): ctx.ui.info(_('Storing %s') % fpath, verbose=True) self.package.extract_file(fpath, self.package.pkg_dir()) - def update_databases(self, txn): + def update_databases(self): "update databases" if self.reinstall: - self.remove_old.remove_db(txn) + self.remove_old.remove_db() - # installdb - ctx.installdb.install(self.metadata.package.name, - self.metadata.package.version, - self.metadata.package.release, - self.metadata.package.build, - self.metadata.package.distribution, - config_later = self.config_later, - txn = txn) + if self.config_later: + self.installdb.mark_pending(self.pkginfo.name) # filesdb - ctx.filesdb.add_files(self.metadata.package.name, self.files, txn=txn) + self.filesdb.add_files(self.metadata.package.name, self.files) # installed packages - ctx.packagedb.add_package(self.pkginfo, pisi.db.itembyrepodb.installed, txn=txn) - + self.installdb.add_package(self.pkginfo) def install_single(pkg, upgrade = False): """install a single package from URI or ID""" @@ -463,10 +446,12 @@ class Remove(AtomicOperation): def __init__(self, package_name, ignore_dep = None): super(Remove, self).__init__(ignore_dep) + self.installdb = pisi.db.installdb.InstallDB() + self.filesdb = pisi.db.filesdb.FilesDB() self.package_name = package_name - self.package = ctx.packagedb.get_package(self.package_name, pisi.db.itembyrepodb.installed) + self.package = self.installdb.get_package(self.package_name) try: - self.files = ctx.installdb.files(self.package_name) + self.files = self.installdb.get_files(self.package_name) except pisi.Error, e: # for some reason file was deleted, we still allow removes! ctx.ui.error(unicode(e)) @@ -478,7 +463,7 @@ class Remove(AtomicOperation): ctx.ui.status(_('Removing package %s') % self.package_name) ctx.ui.notify(pisi.ui.removing, package = self.package, files = self.files) - if not ctx.installdb.is_installed(self.package_name): + if not self.installdb.has_package(self.package_name): raise Exception(_('Trying to remove nonexistent package ') + self.package_name) @@ -488,13 +473,7 @@ class Remove(AtomicOperation): for fileinfo in self.files.list: self.remove_file(fileinfo, self.package_name) - txn = ctx.dbenv.txn_begin() - try: - self.remove_db(txn) - txn.commit() - except db.DBError, e: - txn.abort() - raise e + self.remove_db() self.remove_pisi_files() ctx.ui.close() @@ -511,12 +490,13 @@ class Remove(AtomicOperation): def remove_file(fileinfo, package_name): fpath = pisi.util.join_path(ctx.config.dest_dir(), fileinfo.path) + filesdb = pisi.db.filesdb.FilesDB() # we should check if the file belongs to another # package (this can legitimately occur while upgrading # two packages such that a file has moved from one package to # another as in #2911) - if ctx.filesdb.has_file(fileinfo.path): - pkg, existing_file = ctx.filesdb.get_file(fileinfo.path) + if filesdb.has_file(fileinfo.path): + pkg, existing_file = filesdb.get_file(fileinfo.path) if pkg != package_name: ctx.ui.warning(_('Not removing conflicted file : %s') % fpath) return @@ -559,11 +539,12 @@ class Remove(AtomicOperation): def remove_pisi_files(self): util.clean_dir(self.package.pkg_dir()) - def remove_db(self, txn): - ctx.installdb.remove(self.package_name, txn) - ctx.filesdb.remove_files(self.files, txn) - # FIXME: something goes wrong here, if we use ctx operations ends up with segmentation fault! - pisi.db.packagedb.remove_tracking_package(self.package_name, txn) + def remove_db(self): + self.installdb.remove_package(self.package_name) + self.filesdb.remove_files(self.files.list) +# FIX:DB +# # FIXME: something goes wrong here, if we use ctx operations ends up with segmentation fault! +# pisi.db.packagedb.remove_tracking_package(self.package_name) def remove_single(package_name): @@ -571,61 +552,5 @@ def remove_single(package_name): def build(package): # wrapper for build op - import pisi.build - return pisi.build.build(package) - -def virtual_install(metadata, files, txn): - """Recreate the package info for rebuilddb command""" - # installdb - ctx.installdb.install(metadata.package.name, - metadata.package.version, - metadata.package.release, - metadata.package.build, - metadata.package.distribution, - rebuild=True, - txn=txn) - - # filesdb - if files: - ctx.filesdb.add_files(metadata.package.name, files, txn=txn) - - # installed packages - ctx.packagedb.add_package(metadata.package, pisi.db.itembyrepodb.installed, txn=txn) - -def resurrect_package(package_fn, write_files, txn = None): - """Resurrect the package from xml files""" - - metadata_xml = util.join_path(ctx.config.lib_dir(), 'package', - package_fn, ctx.const.metadata_xml) - if not os.path.exists(metadata_xml): - raise Error, _("Metadata XML '%s' cannot be found") % metadata_xml - - metadata = pisi.metadata.MetaData() - metadata.read(metadata_xml) - - errs = metadata.errors() - if errs: - util.print_errors(errs) - raise Error, _("MetaData format wrong (%s)") % package_fn - - ctx.ui.info(_('* Adding \'%s\' to db... ') % (metadata.package.name), noln=True) - - if write_files: - files_xml = util.join_path(ctx.config.lib_dir(), 'package', - package_fn, ctx.const.files_xml) - if not os.path.exists(files_xml): - raise Error, _("Files XML '%s' cannot be found") % files_xml - - files = pisi.files.Files() - files.read(files_xml) - if files.errors(): - raise Error, _("Invalid %s") % ctx.const.files_xml - else: - files = None - - #import pisi.atomicoperations - def f(t): - pisi.atomicoperations.virtual_install(metadata, files, t) - ctx.txn_proc(f, txn) - - ctx.ui.info(_('OK.')) + import pisi.operations.build + return pisi.operations.build.build(package) diff --git a/pisi/cli/__init__.py b/pisi/cli/__init__.py index a0efcbc3..996fedf6 100644 --- a/pisi/cli/__init__.py +++ b/pisi/cli/__init__.py @@ -121,20 +121,20 @@ class CLI(pisi.ui.UI): return False - def display_progress(self, operation, percent, info="", **ka): + def display_progress(self, **ka): """ display progress of any operation """ - if operation in ["removing", "rebuilding-db"]: + if ka['operation'] in ["removing", "rebuilding-db"]: return - elif operation == "fetching": + elif ka['operation'] == "fetching": totalsize = '%.1f %s' % pisi.util.human_readable_size(ka['total_size']) out = '\r%-30.30s (%s)%3d%% %9.2f %s [%s]' % \ - (ka['filename'], totalsize, percent, + (ka['filename'], totalsize, ka['percent'], ka['rate'], ka['symbol'], ka['eta']) self.output(out) else: - self.output("\r%s (%d%%)" % (info, percent)) + self.output("\r%s (%d%%)" % (ka['info'], ka['percent'])) - if percent == 100: + if ka['percent'] == 100: self.output(pisi.util.colorize(_(' [complete]\n'), 'gray')) def status(self, msg = None): diff --git a/pisi/cli/addrepo.py b/pisi/cli/addrepo.py new file mode 100644 index 00000000..e90dea39 --- /dev/null +++ b/pisi/cli/addrepo.py @@ -0,0 +1,69 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.api +import pisi.cli.command as command +import pisi.context as ctx + +class AddRepo(command.Command): + """Add a repository + +Usage: add-repo + +: name of repository to add +: URI of index file + +If no repo is given, add-repo pardus-devel repo is added by default + +NB: We support only local files (e.g., /a/b/c) and http:// URIs at the moment +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(AddRepo, self).__init__(args) + + name = ("add-repo", "ar") + + def options(self): + + group = optparse.OptionGroup(self.parser, _("add-repo options")) + group.add_option("--at", action="store", + type="int", default=None, + help=_("Add repository at given position (0 is first)")) + self.parser.add_option_group(group) + + def run(self): + + if len(self.args)==2 or len(self.args)==0: + self.init() + if len(self.args)==2: + name = self.args[0] + indexuri = self.args[1] + else: + name = 'pardus-2007' + indexuri = 'http://paketler.pardus.org.tr/pardus-2007/pisi-index.xml.bz2' + pisi.api.add_repo(name, indexuri, ctx.get_option('at')) + if ctx.ui.confirm(_('Update PiSi database for repository %s?') % name): + try: + pisi.api.update_repo(name) + except pisi.fetcher.FetchError: + ctx.ui.warning(_("%s repository could not be reached. Removing %s from system.") % (name, name)) + pisi.api.remove_repo(name) + else: + self.help() + return diff --git a/pisi/cli/build.py b/pisi/cli/build.py new file mode 100644 index 00000000..15f356ea --- /dev/null +++ b/pisi/cli/build.py @@ -0,0 +1,119 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.api +import pisi.cli.command as command +import pisi.context as ctx + +class Build(command.Command): + """Build PiSi packages + +Usage: build [ | ] ... + +You can give a URI of the pspec.xml file. PiSi will +fetch all necessary files and build the package for you. + +Alternatively, you can give the name of a source package +to be downloaded from a repository containing sources. +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(Build, self).__init__(args) + self.comar = True + + name = ("build", "bi") + + package_formats = ('1.0', '1.1') + + def options(self): + + self.add_steps_options() + group = optparse.OptionGroup(self.parser, _("build options")) + self.add_options(group) + self.parser.add_option_group(group) + + def add_options(self, group): + group.add_option("--ignore-build-no", action="store_true", + default=False, + help=_("Do not take build no into account.")) + group.add_option("--ignore-dependency", action="store_true", + default=False, + help=_("Do not take dependency information into account")) + group.add_option("-O", "--output-dir", action="store", default=None, + help=_("Output directory for produced packages")) + group.add_option("--ignore-action-errors", + action="store_true", default=False, + help=_("Bypass errors from ActionsAPI")) + group.add_option("--ignore-safety", action="store_true", + default=False, help=_("Bypass safety switch")) + group.add_option("--ignore-check", action="store_true", + default=False, help=_("Bypass testing step")) + group.add_option("--create-static", action="store_true", + default=False, help=_("Create a static package with ar files")) + group.add_option("--no-install", action="store_true", + default=False, help=_("Do not install build dependencies, fail if a build dependency is present")) + group.add_option("-F", "--package-format", action="store", default='1.1', + help=_("PiSi binary package formats: '1.0', '1.1' (default)")) + group.add_option("--use-quilt", action="store_true", default=False, + help=_("Use quilt patch management system instead of GNU patch")) + group.add_option("--enable-sandbox", action="store_true", default=False, + help=_("Constrain build process inside the build folder")) + + def add_steps_options(self): + group = optparse.OptionGroup(self.parser, _("build steps")) + group.add_option("--fetch", dest="until", action="store_const", + const="fetch", help=_("Break build after fetching the source archive")) + group.add_option("--unpack", dest="until", action="store_const", + const="unpack", help=_("Break build after unpacking the source archive, checking sha1sum and applying patches")) + group.add_option("--setup", dest="until", action="store_const", + const="setup", help=_("Break build after running configure step")) + group.add_option("--build", dest="until", action="store_const", + const="build", help=_("Break build after running compile step")) + group.add_option("--check", dest="until", action="store_const", + const="check", help=_("Break build after running check step")) + group.add_option("--install", dest="until", action="store_const", + const="install", help=_("Break build after running install step")) + group.add_option("--package", dest="until", action="store_const", + const="package", help=_("create PiSi package")) + self.parser.add_option_group(group) + + def run(self): + if not self.args: + self.help() + return + + if self.options.no_install: + self.init(database=True, write=False) + else: + self.init() + + if ctx.get_option('package_format') not in Build.package_formats: + raise Error(_('package_format must be one of %s ') % pisi.util.strlist(Build.package_formats)) + + if ctx.get_option('output_dir'): + ctx.ui.info(_('Output directory: %s') % ctx.config.options.output_dir) + else: + ctx.ui.info(_('Outputting packages in the working directory.')) + ctx.config.options.output_dir = '.' + + for x in self.args: + if ctx.get_option('until'): + pisi.api.build_until(x, ctx.get_option('until')) + else: + pisi.api.build(x) diff --git a/pisi/cli/check.py b/pisi/cli/check.py new file mode 100644 index 00000000..3ff72942 --- /dev/null +++ b/pisi/cli/check.py @@ -0,0 +1,77 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.api +import pisi.cli.command as command +import pisi.context as ctx +import pisi.db + +class Check(command.Command): + """Verify installation + +Usage: check [ ... ] + +: package name + +A cryptographic checksum is stored for each installed +file. Check command uses the checksums to verify a package. +Just give the names of packages. + +If no packages are given, checks all installed packages. +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(Check, self).__init__(args) + self.installdb = pisi.db.installdb.InstallDB() + self.componentdb = pisi.db.componentdb.ComponentDB() + + name = ("check", None) + + def options(self): + group = optparse.OptionGroup(self.parser, _("check options")) + group.add_option("-c", "--component", action="store", + default=None, help=_("Check installed packages under given component")) + self.parser.add_option_group(group) + + def run(self): + self.init(database = True, write = False) + + component = ctx.get_option('component') + if component: + #FIXME: pisi api is insufficient to do this + from sets import Set as set + installed = pisi.api.list_installed() + component_pkgs = self.componentdb.get_union_packages(component, walk=True) + pkgs = list(set(installed) & set(component_pkgs)) + elif self.args: + pkgs = self.args + else: + ctx.ui.info(_('Checking all installed packages')) + pkgs = pisi.api.list_installed() + + for pkg in pkgs: + ctx.ui.info(_('* Checking %s... ') % pkg, noln=True) + if self.installdb.has_package(pkg): + corrupt = pisi.api.check(pkg) + if corrupt: + ctx.ui.info(_('\nPackage %s is corrupt.') % pkg) + else: + ctx.ui.info(_("OK"), verbose=False) + else: + ctx.ui.info(_('Package %s not installed') % pkg) diff --git a/pisi/cli/clean.py b/pisi/cli/clean.py new file mode 100644 index 00000000..3c2ae74d --- /dev/null +++ b/pisi/cli/clean.py @@ -0,0 +1,32 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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.cli.command as command + +class Clean(command.Command): + """Clean stale locks + +Usage: clean + +PiSi uses filesystem locks for managing database access. +This command deletes unused locks from the database directory.""" + + __metaclass__ = command.autocommand + + def __init__(self, args=None): + super(Clean, self).__init__(args) + + name = ("clean", None) + + def run(self): + self.init() + diff --git a/pisi/cli/command.py b/pisi/cli/command.py new file mode 100644 index 00000000..ab149477 --- /dev/null +++ b/pisi/cli/command.py @@ -0,0 +1,269 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 sys +import optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.api +import pisi.context as ctx + +class autocommand(type): + def __init__(cls, name, bases, dict): + super(autocommand, cls).__init__(name, bases, dict) + Command.cmd.append(cls) + name = getattr(cls, 'name', None) + if name is None: + raise pisi.cli.Error(_('Command lacks name')) + longname, shortname = name + def add_cmd(cmd): + if Command.cmd_dict.has_key(cmd): + raise pisi.cli.Error(_('Duplicate command %s') % cmd) + else: + Command.cmd_dict[cmd] = cls + add_cmd(longname) + if shortname: + add_cmd(shortname) + +class Command(object): + """generic help string for any command""" + + # class variables + + cmd = [] + cmd_dict = {} + + @staticmethod + def commands_string(): + s = '' + l = [x.name[0] for x in Command.cmd] + l.sort() + for name in l: + commandcls = Command.cmd_dict[name] + trans = gettext.translation('pisi', fallback=True) + summary = trans.ugettext(commandcls.__doc__).split('\n')[0] + name = commandcls.name[0] + if commandcls.name[1]: + name += ' (%s)' % commandcls.name[1] + s += '%21s - %s\n' % (name, summary) + return s + + @staticmethod + def get_command(cmd, fail=False, args=None): + + if Command.cmd_dict.has_key(cmd): + return Command.cmd_dict[cmd](args) + + if fail: + raise Error(_("Unrecognized command: %s") % cmd) + else: + return None + + # instance variabes + + def __init__(self, args = None): + # now for the real parser + import pisi + self.comar = False + self.parser = optparse.OptionParser(usage=getattr(self, "__doc__"), + version="%prog " + pisi.__version__, + formatter=PisiHelpFormatter()) + self.options() + self.commonopts() + (self.options, self.args) = self.parser.parse_args(args) + if self.args: + self.args.pop(0) # exclude command arg + + self.process_opts() + + def commonopts(self): + '''common options''' + p = self.parser + + group = optparse.OptionGroup(self.parser, _("general options")) + + group.add_option("-D", "--destdir", action="store", default = None, + help = _("Change the system root for PiSi commands")) + group.add_option("-y", "--yes-all", action="store_true", + default=False, help = _("Assume yes in all yes/no queries")) + group.add_option("-u", "--username", action="store") + group.add_option("-p", "--password", action="store") + group.add_option("-v", "--verbose", action="store_true", + dest="verbose", default=False, + help=_("Detailed output")) + group.add_option("-d", "--debug", action="store_true", + default=False, help=_("Show debugging information")) + group.add_option("-N", "--no-color", action="store_true", default=False, + help = _("Suppresses all coloring of PiSi's output")) + + p.add_option_group(group) + + return p + + def options(self): + """This is a fall back function. If the implementer module provides an + options function it will be called""" + pass + + def process_opts(self): + self.check_auth_info() + + # make destdir absolute + if self.options.destdir: + d = str(self.options.destdir) + import os.path + if not os.path.exists(d): + pisi.cli.printu(_('Destination directory %s does not exist. Creating directory.\n') % d) + os.makedirs(d) + self.options.destdir = os.path.realpath(d) + + def check_auth_info(self): + username = self.options.username + password = self.options.password + + # TODO: We'll get the username, password pair from a configuration + # file from users home directory. Currently we need user to + # give it from the user interface. + # if not username and not password: + # if someauthconfig.username and someauthconfig.password: + # self.authInfo = (someauthconfig.username, + # someauthconfig.password) + # return + if username and password: + self.options.authinfo = (username, password) + return + + if username and not password: + from getpass import getpass + password = getpass(_("Password: ")) + self.options.authinfo = (username, password) + else: + self.options.authinfo = None + + def init(self, database = True, write = True): + """initialize PiSi components""" + + if self.options: + ui = pisi.cli.CLI(self.options.debug, self.options.verbose) + else: + ui = pisi.cli.CLI() + + pisi.api.set_userinterface(ui) + pisi.api.set_options(self.options) + pisi.api.set_comar(self.comar and not ctx.get_option('ignore_comar')) + + def get_name(self): + return self.__class__.name + + def format_name(self): + (name, shortname) = self.get_name() + if shortname: + return "%s (%s)" % (name, shortname) + else: + return name + + def help(self): + """print help for the command""" + trans = gettext.translation('pisi', fallback=True) + print "%s: %s\n" % (self.format_name(), trans.ugettext(self.__doc__)) + print self.parser.format_option_help() + + def die(self): + """exit program""" + #FIXME: not called from anywhere? + ctx.ui.error(_('Command terminated abnormally.')) + sys.exit(-1) + +class PackageOp(Command): + """Abstract package operation command""" + + def __init__(self, args): + super(PackageOp, self).__init__(args) + self.comar = True + + def options(self, group): + group.add_option("--ignore-dependency", action="store_true", + default=False, + help=_("Do not take dependency information into account")) + group.add_option("--ignore-comar", action="store_true", + default=False, help=_("Bypass comar configuration agent")) + group.add_option("--ignore-safety", action="store_true", + default=False, help=_("Bypass safety switch")) + group.add_option("-n", "--dry-run", action="store_true", default=False, + help = _("Do not perform any action, just show what would be done")) + + def init(self, database=True, write=True): + super(PackageOp, self).init(database, write) + +class PisiHelpFormatter(optparse.HelpFormatter): + def __init__(self, + indent_increment=1, + max_help_position=32, + width=None, + short_first=1): + optparse.HelpFormatter.__init__( + self, indent_increment, max_help_position, width, short_first) + + self._short_opt_fmt = "%s" + self._long_opt_fmt = "%s" + + def format_usage(self, usage): + return _("usage: %s\n") % usage + + def format_heading(self, heading): + return "%*s%s:\n" % (self.current_indent, "", heading) + + def format_option_strings(self, option): + """Return a comma-separated list of option strings & metavariables.""" + if option.takes_value(): + short_opts = [self._short_opt_fmt % sopt + for sopt in option._short_opts] + long_opts = [self._long_opt_fmt % lopt + for lopt in option._long_opts] + else: + short_opts = option._short_opts + long_opts = option._long_opts + + if long_opts and short_opts: + opt = "%s [%s]" % (short_opts[0], long_opts[0]) + else: + opt = long_opts[0] or short_opts[0] + + if option.takes_value(): + opt += " arg" + + return opt + + def format_option(self, option): + import textwrap + result = [] + opts = self.option_strings[option] + opt_width = self.help_position - self.current_indent - 2 + if len(opts) > opt_width: + opts = "%*s%s\n" % (self.current_indent, "", opts) + indent_first = self.help_position + else: # start help on same line as opts + opts = "%*s%-*s " % (self.current_indent, "", opt_width, opts) + indent_first = 0 + result.append(opts) + if option.help: + help_text = self.expand_default(option) + help_lines = textwrap.wrap(help_text, self.help_width) + result.append(": %*s%s\n" % (indent_first, "", help_lines[0])) + result.extend([" %*s%s\n" % (self.help_position, "", line) + for line in help_lines[1:]]) + elif opts[-1] != "\n": + result.append("\n") + return "".join(result) diff --git a/pisi/cli/commands.py b/pisi/cli/commands.py deleted file mode 100644 index 886888dc..00000000 --- a/pisi/cli/commands.py +++ /dev/null @@ -1,1688 +0,0 @@ -# -*- coding:utf-8 -*- -# -# Copyright (C) 2005 - 2007, 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 sys -from optparse import OptionParser, OptionGroup, HelpFormatter - -import gettext -__trans = gettext.translation('pisi', fallback=True) -_ = __trans.ugettext - -import pisi -import pisi.cli -import pisi.context as ctx -from pisi.uri import URI -import pisi.util as util - -class Error(pisi.Error): - pass - -class PisiHelpFormatter(HelpFormatter): - def __init__(self, - indent_increment=1, - max_help_position=32, - width=None, - short_first=1): - HelpFormatter.__init__( - self, indent_increment, max_help_position, width, short_first) - - self._short_opt_fmt = "%s" - self._long_opt_fmt = "%s" - - def format_usage(self, usage): - return _("usage: %s\n") % usage - - def format_heading(self, heading): - return "%*s%s:\n" % (self.current_indent, "", heading) - - def format_option_strings(self, option): - """Return a comma-separated list of option strings & metavariables.""" - if option.takes_value(): - short_opts = [self._short_opt_fmt % sopt - for sopt in option._short_opts] - long_opts = [self._long_opt_fmt % lopt - for lopt in option._long_opts] - else: - short_opts = option._short_opts - long_opts = option._long_opts - - if long_opts and short_opts: - opt = "%s [%s]" % (short_opts[0], long_opts[0]) - else: - opt = long_opts[0] or short_opts[0] - - if option.takes_value(): - opt += " arg" - - return opt - - def format_option(self, option): - import textwrap - result = [] - opts = self.option_strings[option] - opt_width = self.help_position - self.current_indent - 2 - if len(opts) > opt_width: - opts = "%*s%s\n" % (self.current_indent, "", opts) - indent_first = self.help_position - else: # start help on same line as opts - opts = "%*s%-*s " % (self.current_indent, "", opt_width, opts) - indent_first = 0 - result.append(opts) - if option.help: - help_text = self.expand_default(option) - help_lines = textwrap.wrap(help_text, self.help_width) - result.append(": %*s%s\n" % (indent_first, "", help_lines[0])) - result.extend([" %*s%s\n" % (self.help_position, "", line) - for line in help_lines[1:]]) - elif opts[-1] != "\n": - result.append("\n") - return "".join(result) - - -class Command(object): - """generic help string for any command""" - - # class variables - - cmd = [] - cmd_dict = {} - - @staticmethod - def commands_string(): - s = '' - l = [x.name[0] for x in Command.cmd] - l.sort() - for name in l: - commandcls = Command.cmd_dict[name] - trans = gettext.translation('pisi', fallback=True) - summary = trans.ugettext(commandcls.__doc__).split('\n')[0] - name = commandcls.name[0] - if commandcls.name[1]: - name += ' (%s)' % commandcls.name[1] - s += '%21s - %s\n' % (name, summary) - return s - - @staticmethod - def get_command(cmd, fail=False, args=None): - - if Command.cmd_dict.has_key(cmd): - return Command.cmd_dict[cmd](args) - - if fail: - raise Error(_("Unrecognized command: %s") % cmd) - else: - return None - - # instance variabes - - def __init__(self, args = None): - # now for the real parser - import pisi - self.comar = False - self.parser = OptionParser(usage=getattr(self, "__doc__"), - version="%prog " + pisi.__version__, - formatter=PisiHelpFormatter()) - self.options() - self.commonopts() - (self.options, self.args) = self.parser.parse_args(args) - if self.args: - self.args.pop(0) # exclude command arg - - self.process_opts() - - def commonopts(self): - '''common options''' - p = self.parser - - group = OptionGroup(self.parser, _("general options")) - - group.add_option("-D", "--destdir", action="store", default = None, - help = _("Change the system root for PiSi commands")) - group.add_option("-y", "--yes-all", action="store_true", - default=False, help = _("Assume yes in all yes/no queries")) - group.add_option("-u", "--username", action="store") - group.add_option("-p", "--password", action="store") - group.add_option("-L", "--bandwidth-limit", action="store", default = 0, - help = _("Keep bandwidth usage under specified KB's")) - group.add_option("-v", "--verbose", action="store_true", - dest="verbose", default=False, - help=_("Detailed output")) - group.add_option("-d", "--debug", action="store_true", - default=False, help=_("Show debugging information")) - group.add_option("-N", "--no-color", action="store_true", default=False, - help = _("Suppresses all coloring of PiSi's output")) - - p.add_option_group(group) - - return p - - def options(self): - """This is a fall back function. If the implementer module provides an - options function it will be called""" - pass - - def process_opts(self): - self.check_auth_info() - - # make destdir absolute - if self.options.destdir: - d = str(self.options.destdir) - import os.path - if not os.path.exists(d): - pisi.cli.printu(_('Destination directory %s does not exist. Creating directory.\n') % d) - os.makedirs(d) - self.options.destdir = os.path.realpath(d) - - def check_auth_info(self): - username = self.options.username - password = self.options.password - - # TODO: We'll get the username, password pair from a configuration - # file from users home directory. Currently we need user to - # give it from the user interface. - # if not username and not password: - # if someauthconfig.username and someauthconfig.password: - # self.authInfo = (someauthconfig.username, - # someauthconfig.password) - # return - if username and password: - self.options.authinfo = (username, password) - return - - if username and not password: - from getpass import getpass - password = getpass(_("Password: ")) - self.options.authinfo = (username, password) - else: - self.options.authinfo = None - - def init(self, database = True, write = True): - """initialize PiSi components""" - - # NB: command imports here or in the command class run fxns - import pisi.api - pisi.api.init(database = database, write = write, options = self.options, - comar = self.comar) - - def finalize(self): - """do cleanup work for PiSi components""" - pisi.api.finalize() - - def get_name(self): - return self.__class__.name - - def format_name(self): - (name, shortname) = self.get_name() - if shortname: - return "%s (%s)" % (name, shortname) - else: - return name - - def help(self): - """print help for the command""" - trans = gettext.translation('pisi', fallback=True) - print "%s: %s\n" % (self.format_name(), trans.ugettext(self.__doc__)) - print self.parser.format_option_help() - - def die(self): - """exit program""" - #FIXME: not called from anywhere? - ctx.ui.error(_('Command terminated abnormally.')) - sys.exit(-1) - - -class autocommand(type): - def __init__(cls, name, bases, dict): - super(autocommand, cls).__init__(name, bases, dict) - Command.cmd.append(cls) - name = getattr(cls, 'name', None) - if name is None: - raise pisi.cli.Error(_('Command lacks name')) - longname, shortname = name - def add_cmd(cmd): - if Command.cmd_dict.has_key(cmd): - raise pisi.cli.Error(_('Duplicate command %s') % cmd) - else: - Command.cmd_dict[cmd] = cls - add_cmd(longname) - if shortname: - add_cmd(shortname) - - -class Help(Command): - """Prints help for given commands - -Usage: help [ ... ] - -If run without parameters, it prints the general help.""" - - __metaclass__ = autocommand - - def __init__(self, args = None): - #TODO? Discard Help's own usage doc in favor of general usage doc - #self.__doc__ = usage_text - #self.__doc__ += commands_string() - super(Help, self).__init__(args) - - name = ("help", "?") - - def run(self): - - if not self.args: - self.parser.set_usage(usage_text) - pisi.cli.printu(self.parser.format_help()) - return - - self.init(database = False, write = False) - - for arg in self.args: - obj = Command.get_command(arg, True) - obj.help() - ctx.ui.info('') - - self.finalize() - - -class Clean(Command): - """Clean stale locks - -Usage: clean - -PiSi uses filesystem locks for managing database access. -This command deletes unused locks from the database directory.""" - - __metaclass__ = autocommand - - def __init__(self, args=None): - super(Clean, self).__init__(args) - - name = ("clean", None) - - def run(self): - self.init() - self.finalize() - -class DeleteCache(Command): - """Delete cache files - -Usage: delete-cache - -Sources, packages and temporary files are stored -under /var directory. Since these accumulate they can -consume a lot of disk space.""" - - __metaclass__ = autocommand - - def __init__(self, args=None): - super(DeleteCache, self).__init__(args) - - name = ("delete-cache", "dc") - - def run(self): - self.init(database=False, write=True) - pisi.api.delete_cache() - - -class Graph(Command): - """Graph package relations - -Usage: graph [ ...] - -Write a graph of package relations, tracking dependency and -conflicts relations starting from given packages. By default -shows the package relations among repository packages, and writes -the package in graphviz format to 'pgraph.dot'. -""" - - __metaclass__ = autocommand - - def __init__(self, args=None): - super(Graph, self).__init__(args) - - def options(self): - - group = OptionGroup(self.parser, _("graph options")) - - group.add_option("-r", "--repository", action="store", - default=None, - help=_("Specify a particular repository")) - group.add_option("-i", "--installed", action="store_true", - default=False, - help=_("Graph of installed packages")) - group.add_option("--ignore-installed", action="store_true", - default=False, - help=_("Do not show installed packages")) - group.add_option("-o", "--output", action="store", - default='pgraph.dot', - help=_("Dot output file")) - - self.parser.add_option_group(group) - - name = ("graph", None) - - def run(self): - self.init(write=False) - if not ctx.get_option('installed'): - if ctx.get_option('repository'): - repo = ctx.get_option('repository') - ctx.ui.info(_('Plotting packages in repository %s') % repo) - else: - repo = pisi.db.itembyrepodb.repos - if self.args: - a = self.args - else: - ctx.ui.info(_('Plotting a graph of relations among all repository packages')) - a = ctx.packagedb.list_packages(repo) - else: - if self.args: - a = self.args - else: - # if A is empty, then graph all packages - ctx.ui.info(_('Plotting a graph of relations among all installed packages')) - a = ctx.installdb.list_installed() - repo = pisi.db.itembyrepodb.installed - g = pisi.api.package_graph(a, repo = repo, - ignore_installed = ctx.get_option('ignore_installed')) - g.write_graphviz(file(ctx.get_option('output'), 'w')) - self.finalize() - -# option mixins -def buildno_opts(self, group): - group.add_option("--ignore-build-no", action="store_true", - default=False, - help=_("Do not take build no into account.")) - -def ignoredep_opt(self, group): - group.add_option("--ignore-dependency", action="store_true", - default=False, - help=_("Do not take dependency information into account")) - - -class Build(Command): - """Build PiSi packages - -Usage: build [ | ] ... - -You can give a URI of the pspec.xml file. PiSi will -fetch all necessary files and build the package for you. - -Alternatively, you can give the name of a source package -to be downloaded from a repository containing sources. -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(Build, self).__init__(args) - self.comar = True - - name = ("build", "bi") - - package_formats = ('1.0', '1.1') - - def options(self): - - self.add_steps_options() - group = OptionGroup(self.parser, _("build options")) - self.add_options(group) - self.parser.add_option_group(group) - - def add_options(self, group): - buildno_opts(self, group) - ignoredep_opt(self, group) - group.add_option("-O", "--output-dir", action="store", default=None, - help=_("Output directory for produced packages")) - group.add_option("--ignore-action-errors", - action="store_true", default=False, - help=_("Bypass errors from ActionsAPI")) - group.add_option("--ignore-safety", action="store_true", - default=False, help=_("Bypass safety switch")) - group.add_option("--ignore-check", action="store_true", - default=False, help=_("Bypass testing step")) - group.add_option("--create-static", action="store_true", - default=False, help=_("Create a static package with ar files")) - group.add_option("--no-install", action="store_true", - default=False, help=_("Do not install build dependencies, fail if a build dependency is present")) - group.add_option("-F", "--package-format", action="store", default='1.1', - help=_("PiSi binary package formats: '1.0', '1.1' (default)")) - group.add_option("--use-quilt", action="store_true", default=False, - help=_("Use quilt patch management system instead of GNU patch")) - group.add_option("--ignore-sandbox", action="store_true", default=False, - help=_("Do not constrain build process inside the build folder")) - - def add_steps_options(self): - group = OptionGroup(self.parser, _("build steps")) - group.add_option("--fetch", dest="until", action="store_const", - const="fetch", help=_("Break build after fetching the source archive")) - group.add_option("--unpack", dest="until", action="store_const", - const="unpack", help=_("Break build after unpacking the source archive, checking sha1sum and applying patches")) - group.add_option("--setup", dest="until", action="store_const", - const="setup", help=_("Break build after running configure step")) - group.add_option("--build", dest="until", action="store_const", - const="build", help=_("Break build after running compile step")) - group.add_option("--check", dest="until", action="store_const", - const="check", help=_("Break build after running check step")) - group.add_option("--install", dest="until", action="store_const", - const="install", help=_("Break build after running install step")) - group.add_option("--package", dest="until", action="store_const", - const="package", help=_("create PiSi package")) - self.parser.add_option_group(group) - - def run(self): - if not self.args: - self.help() - return - - if self.options.no_install: - self.init(database=True, write=False) - else: - self.init() - - if ctx.get_option('package_format') not in Build.package_formats: - raise Error(_('package_format must be one of %s ') % pisi.util.strlist(Build.package_formats)) - - if ctx.get_option('output_dir'): - ctx.ui.info(_('Output directory: %s') % ctx.config.options.output_dir) - else: - ctx.ui.info(_('Outputting packages in the working directory.')) - ctx.config.options.output_dir = '.' - - for x in self.args: - if ctx.get_option('until'): - pisi.api.build_until(x, ctx.get_option('until')) - else: - pisi.api.build(x) - self.finalize() - -class Delta(Command): - """Creates delta PiSi packages - -Usage: delta oldpackage newpackage - -Delta command finds the changed files between the given packages by comparing the sha1sum of the files -and creates a delta pisi package with the changed files between two releases. - -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(Delta, self).__init__(args) - - name = ("delta", "dt") - - def options(self): - - group = OptionGroup(self.parser, _("delta options")) - self.add_options(group) - self.parser.add_option_group(group) - - def add_options(self, group): - group.add_option("-O", "--output-dir", action="store", default=None, - help=_("Output directory for produced packages")) - - def run(self): - - from pisi.delta import create_delta_package - - self.init(database=False, write=False) - - if len(self.args) != 2: - self.help() - return - - if ctx.get_option('output_dir'): - ctx.ui.info(_('Output directory: %s') % ctx.config.options.output_dir) - else: - ctx.ui.info(_('Outputting packages in the working directory.')) - ctx.config.options.output_dir = '.' - - oldpackage = self.args[0] - newpackage = self.args[1] - - create_delta_package(oldpackage, newpackage) - - self.finalize() - -class Emerge(Build): - """Build and install PiSi source packages from repository - -Usage: emerge ... - -You should give the name of a source package to be -downloaded from a repository containing sources. - -You can also give the name of a component. -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(Emerge, self).__init__(args) - self.comar = True - - name = ("emerge", "em") - - def options(self): - - group = OptionGroup(self.parser, _("emerge options")) - super(Emerge, self).add_options(group) - group.add_option("--ignore-file-conflicts", action="store_true", - default=False, help=_("Ignore file conflicts")) - group.add_option("--ignore-package-conflicts", action="store_true", - default=False, help=_("Ignore package conflicts")) - group.add_option("--ignore-comar", action="store_true", - default=False, help=_("Bypass comar configuration agent")) - self.parser.add_option_group(group) - - def run(self): - if not self.args: - self.help() - return - - self.init(database = True) - if ctx.get_option('output_dir'): - ctx.ui.info(_('Output directory: %s') % ctx.config.options.output_dir) - else: - ctx.ui.info(_('Outputting binary packages in the package cache.')) - ctx.config.options.output_dir = ctx.config.packages_dir() - - pisi.api.emerge(self.args) - self.finalize() - - -class PackageOp(Command): - """Abstract package operation command""" - - def __init__(self, args): - super(PackageOp, self).__init__(args) - self.comar = True - - def options(self, group): - ignoredep_opt(self, group) - group.add_option("--ignore-comar", action="store_true", - default=False, help=_("Bypass comar configuration agent")) - group.add_option("--ignore-safety", action="store_true", - default=False, help=_("Bypass safety switch")) - group.add_option("-n", "--dry-run", action="store_true", default=False, - help = _("Do not perform any action, just show what would be done")) - - def init(self, database=True, write=True): - super(PackageOp, self).init(database, write) - - def finalize(self): - pisi.api.finalize() - -class Install(PackageOp): - """Install PiSi packages - -Usage: install ... - -You may use filenames, URI's or package names for packages. If you have -specified a package name, it should exist in a specified repository. - -You can also specify components instead of package names, which will be -expanded to package names. -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(Install, self).__init__(args) - - name = "install", "it" - - def options(self): - group = OptionGroup(self.parser, _("install options")) - - super(Install, self).options(group) - buildno_opts(self, group) - group.add_option("--reinstall", action="store_true", - default=False, help=_("Reinstall already installed packages")) - group.add_option("--ignore-file-conflicts", action="store_true", - default=False, help=_("Ignore file conflicts")) - group.add_option("--ignore-package-conflicts", action="store_true", - default=False, help=_("Ignore package conflicts")) - group.add_option("-c", "--component", action="append", - default=None, help=_("Install component's and recursive components' packages")) - group.add_option("-f", "--fetch-only", action="store_true", - default=False, help=_("Fetch upgrades but do not install.")) - self.parser.add_option_group(group) - - def run(self): - - if self.options.fetch_only: - self.init(database=True, write=False) - else: - self.init() - - components = ctx.get_option('component') - if not components and not self.args: - self.help() - return - - packages = [] - if components: - for name in components: - if ctx.componentdb.has_component(name): - packages.extend(ctx.componentdb.get_union_packages(name, walk=True)) - packages.extend(self.args) - - pisi.api.install(packages, ctx.get_option('reinstall')) - self.finalize() - - -class Upgrade(PackageOp): - """Upgrade PiSi packages - -Usage: Upgrade [ ... ] - -: package name - -Upgrades the entire system if no package names are given - -You may use only package names to specify packages because -the package upgrade operation is defined only with respect -to repositories. If you have specified a package name, it -should exist in the package repositories. If you just want to -reinstall a package from a PiSi file, use the install command. - -You can also specify components instead of package names, which will be -expanded to package names. -""" - - __metaclass__ = autocommand - - def __init__(self, args): - super(Upgrade, self).__init__(args) - - name = ("upgrade", "up") - - def options(self): - group = OptionGroup(self.parser, _("upgrade options")) - - super(Upgrade, self).options(group) - buildno_opts(self, group) - group.add_option("--security-only", action="store_true", - default=False, help=_("Security related package upgrades only")) - group.add_option("-r", "--bypass-update-repo", action="store_true", - default=False, help=_("Do not update repositories")) - group.add_option("--ignore-file-conflicts", action="store_true", - default=False, help=_("Ignore file conflicts")) - group.add_option("--ignore-package-conflicts", action="store_true", - default=False, help=_("Ignore package conflicts")) - group.add_option("-c", "--component", action="append", - default=None, help=_("Upgrade component's and recursive components' packages")) - group.add_option("-f", "--fetch-only", action="store_true", - default=False, help=_("Fetch upgrades but do not install.")) - group.add_option("-x", "--exclude", action="append", - default=None, help=_("When upgrading system, ignore packages and components whose basenames match pattern.")) - group.add_option("--exclude-from", action="store", - default=None, help=_("When upgrading system, ignore packages and components whose basenames \ - match any pattern contained in file.")) - - self.parser.add_option_group(group) - - def exclude_from(self, packages): - import os - - patterns = [] - f = ctx.get_option('exclude_from') - if os.path.exists(f): - for line in open(f, "r").readlines(): - if not line.startswith('#') and not line == '\n': - patterns.append(line.strip()) - if patterns: - return self.exclude(packages, patterns) - - return packages - - def exclude(self, packages, patterns): - from sets import Set as set - import fnmatch - - packages = set(packages) - for pattern in patterns: - # match pattern in package names - match = fnmatch.filter(packages, pattern) - packages = packages - set(match) - - if not match: - # match pattern in component names - for compare in fnmatch.filter(ctx.componentdb.list_components(), pattern): - packages = packages - set(ctx.componentdb.get_union_packages(compare, walk=True)) - - return list(packages) - - def run(self): - - if self.options.fetch_only: - self.init(database=True, write=False) - else: - self.init() - - if not ctx.get_option('bypass_update_repo'): - ctx.ui.info(_('Updating repositories')) - repos = ctx.repodb.list() - for repo in repos: - pisi.api.update_repo(repo) - else: - ctx.ui.info(_('Will not update repositories')) - - components = ctx.get_option('component') - packages = [] - if components: - for name in components: - if ctx.componentdb.has_component(name): - packages.extend(ctx.componentdb.get_union_packages(name, walk=True)) - packages.extend(self.args) - - if packages == []: - packages = ctx.installdb.list_installed() - - if ctx.get_option('exclude_from'): - packages = self.exclude_from(packages) - - if ctx.get_option('exclude'): - patterns = ctx.get_option('exclude') - packages = self.exclude(packages, patterns) - - pisi.api.upgrade(packages) - self.finalize() - - -class Remove(PackageOp): - """Remove PiSi packages - -Usage: remove ... - -Remove package(s) from your system. Just give the package names to remove. - -You can also specify components instead of package names, which will be -expanded to package names. -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(Remove, self).__init__(args) - - name = ("remove", "rm") - - def options(self): - group = OptionGroup(self.parser, _("remove options")) - super(Remove, self).options(group) - group.add_option("-c", "--component", action="append", - default=None, help=_("Remove component's and recursive components' packages")) - self.parser.add_option_group(group) - - def run(self): - self.init() - - components = ctx.get_option('component') - if not components and not self.args: - self.help() - return - - packages = [] - if components: - for name in components: - if ctx.componentdb.has_component(name): - packages.extend(ctx.componentdb.get_union_packages(name, walk=True)) - packages.extend(self.args) - - pisi.api.remove(packages) - self.finalize() - -class ConfigurePending(PackageOp): - """Configure pending packages - -If COMAR configuration of some packages were not -done at installation time, they are added to a list -of packages waiting to be configured. This command -configures those packages. -""" - - __metaclass__ = autocommand - - def __init__(self, args): - super(ConfigurePending, self).__init__(args) - - name = ("configure-pending", "cp") - - def options(self): - group = OptionGroup(self.parser, _("configure-pending options")) - super(ConfigurePending, self).options(group) - self.parser.add_option_group(group) - - def run(self): - - self.init() - pisi.api.configure_pending() - self.finalize() - - -class Info(Command): - """Display package information - -Usage: info ... - - is either a package name or a .pisi file, -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(Info, self).__init__(args) - - name = ("info", None) - - def options(self): - - group = OptionGroup(self.parser, _("info options")) - self.add_options(group) - self.parser.add_option_group(group) - - def add_options(self, group): - group.add_option("-f", "--files", action="store_true", - default=False, - help=_("Show a list of package files.")) - group.add_option("-c", "--component", action="append", - default=None, help=_("Info about the given component")) - group.add_option("-F", "--files-path", action="store_true", - default=False, - help=_("Show only paths.")) - group.add_option("-s", "--short", action="store_true", - default=False, help=_("Do not show details")) - group.add_option("--xml", action="store_true", - default=False, help=_("Output in xml format")) - - def run(self): - - self.init(database = True, write = False) - - components = ctx.get_option('component') - if not components and not self.args: - self.help() - return - - index = pisi.index.Index() - index.distribution = None - - # info of components - if components: - for name in components: - if ctx.componentdb.has_component(name): - component = ctx.componentdb.get_union_comp(name) - if self.options.xml: - index.add_component(component) - else: - if not self.options.short: - ctx.ui.info(unicode(component)) - else: - ctx.ui.info("%s - %s" % (component.name, component.summary)) - - # info of packages - for arg in self.args: - if self.options.xml: - index.packages.append(pisi.api.info(arg)[0].package) - else: - self.info_package(arg) - - if self.options.xml: - errs = [] - index.newDocument() - index.encode(index.rootNode(), errs) - index.writexmlfile(sys.stdout) - sys.stdout.write('\n') - self.finalize() - - - def info_package(self, arg): - if arg.endswith(ctx.const.package_suffix): - metadata, files = pisi.api.info_file(arg) - ctx.ui.info(_('Package file: %s') % arg) - self.print_pkginfo(metadata, files) - else: - if ctx.installdb.is_installed(arg): - metadata, files, repo = pisi.api.info_name(arg, True) - if self.options.short: - ctx.ui.info(_('[inst] '), noln=True) - else: - ctx.ui.info(_('Installed package:')) - self.print_pkginfo(metadata, files,pisi.db.itembyrepodb.installed) - - if ctx.packagedb.has_package(arg): - metadata, files, repo = pisi.api.info_name(arg, False) - if self.options.short: - ctx.ui.info(_('[repo] '), noln=True) - else: - ctx.ui.info(_('Package found in %s repository:') % repo) - self.print_pkginfo(metadata, files, pisi.db.itembyrepodb.repos) - - if not ctx.packagedb.has_package(arg): - ctx.ui.info(_("%s is not found in repositories") % arg) - - if not ctx.installdb.is_installed(arg): - ctx.ui.info(_("%s is not installed") % arg) - - def print_pkginfo(self, metadata, files, repo = None): - if ctx.get_option('short'): - pkg = metadata.package - ctx.ui.info('%15s - %s' % (pkg.name, unicode(pkg.summary))) - else: - ctx.ui.info(unicode(metadata.package)) - if repo: - revdeps = [x[0] for x in - ctx.packagedb.get_rev_deps(metadata.package.name, repo)] - print _('Reverse Dependencies:'), util.strlist(revdeps) - if self.options.files or self.options.files_path: - if files: - print _('\nFiles:') - files.list.sort(key = lambda x:x.path) - for fileinfo in files.list: - if self.options.files: - print fileinfo - else: - print "/" + fileinfo.path - else: - ctx.ui.warning(_('File information not available')) - if not self.options.short: - print - - -class Check(Command): - """Verify installation - -Usage: check [ ... ] - -: package name - -A cryptographic checksum is stored for each installed -file. Check command uses the checksums to verify a package. -Just give the names of packages. - -If no packages are given, checks all installed packages. -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(Check, self).__init__(args) - - name = ("check", None) - - def options(self): - group = OptionGroup(self.parser, _("check options")) - group.add_option("-c", "--component", action="store", - default=None, help=_("Check installed packages under given component")) - self.parser.add_option_group(group) - - def run(self): - self.init(database = True, write = False) - - component = ctx.get_option('component') - if component: - #FIXME: pisi api is insufficient to do this - from sets import Set as set - installed = ctx.installdb.list_installed() - component_pkgs = ctx.componentdb.get_union_packages(component, walk=True) - pkgs = list(set(installed) & set(component_pkgs)) - elif self.args: - pkgs = self.args - else: - ctx.ui.info(_('Checking all installed packages')) - pkgs = ctx.installdb.list_installed() - - for pkg in pkgs: - ctx.ui.info(_('* Checking %s... ') % pkg, noln=True) - if ctx.installdb.is_installed(pkg): - corrupt = pisi.api.check(pkg) - if corrupt: - ctx.ui.info(_('\nPackage %s is corrupt.') % pkg) - else: - ctx.ui.info(_("OK"), verbose=False) - else: - ctx.ui.info(_('Package %s not installed') % pkg) - self.finalize() - - -class Index(Command): - """Index PiSi files in a given directory - -Usage: index ... - -This command searches for all PiSi files in a directory, collects PiSi -tags from them and accumulates the information in an output XML file, -named by default 'pisi-index.xml'. In particular, it indexes both -source and binary packages. - -If you give multiple directories, the command still works, but puts -everything in a single index file. -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(Index, self).__init__(args) - - name = ("index", "ix") - - def options(self): - - group = OptionGroup(self.parser, _("index options")) - - group.add_option("-a", "--absolute-urls", action="store_true", - default=False, - help=_("Store absolute links for indexed files.")) - group.add_option("-o", "--output", action="store", - default='pisi-index.xml', - help=_("Index output file")) - group.add_option("--skip-sources", action="store_true", - default=False, - help=_("Do not index PiSi spec files.")) - group.add_option("--skip-signing", action="store_true", - default=False, - help=_("Do not sign index.")) - - self.parser.add_option_group(group) - - def run(self): - - self.init(database = True, write = False) - from pisi.api import index - if len(self.args)>0: - index(self.args, ctx.get_option('output'), - skip_sources = ctx.get_option('skip_sources'), - skip_signing = ctx.get_option('skip_signing')) - elif len(self.args)==0: - ctx.ui.info(_('Indexing current directory.')) - index(['.'], ctx.get_option('output'), - skip_sources = ctx.get_option('skip_sources'), - skip_signing = ctx.get_option('skip_signing')) - self.finalize() - - -class ListInstalled(Command): - """Print the list of all installed packages - -Usage: list-installed -""" - - __metaclass__ = autocommand - - def __init__(self, args): - super(ListInstalled, self).__init__(args) - - name = ("list-installed", "li") - - def options(self): - - group = OptionGroup(self.parser, _("list-installed options")) - - group.add_option("-l", "--long", action="store_true", - default=False, help=_("Show in long format")) - group.add_option("-c", "--component", action="store", - default=None, help=_("List installed packages under given component")) - group.add_option("-i", "--install-info", action="store_true", - default=False, help=_("Show detailed install info")) - - self.parser.add_option_group(group) - - def run(self): - self.init(database = True, write = False) - installed = ctx.installdb.list_installed() - - component = ctx.get_option('component') - if component: - #FIXME: pisi api is insufficient to do this - from sets import Set as set - component_pkgs = ctx.componentdb.get_union_packages(component, walk=True) - installed = list(set(installed) & set(component_pkgs)) - - installed.sort() - if self.options.install_info: - ctx.ui.info(_('Package Name |St| Version| Rel.| Build| Distro| Date')) - print '========================================================================' - for pkg in installed: - package = ctx.packagedb.get_package(pkg, pisi.db.itembyrepodb.installed) - inst_info = ctx.installdb.get_info(pkg) - if self.options.long: - ctx.ui.info(unicode(package)) - ctx.ui.info(unicode(inst_info)) - elif self.options.install_info: - ctx.ui.info('%-15s |%s' % (package.name, inst_info.one_liner())) - else: - ctx.ui.info('%15s - %s' % (package.name, unicode(package.summary))) - self.finalize() - -class RebuildDb(Command): - """Rebuild Databases - -Usage: rebuilddb [ ... ] - -Rebuilds the PiSi databases - -If package specs are given, they should be the names of package -dirs under /var/lib/pisi -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(RebuildDb, self).__init__(args) - - name = ("rebuild-db", "rdb") - - def options(self): - - group = OptionGroup(self.parser, _("rebuild-db options")) - - group.add_option("-f", "--files", action="store_true", - default=False, help=_("Rebuild files database")) - - self.parser.add_option_group(group) - - def run(self): - if self.args: - self.init(database=True) - for package_fn in self.args: - pisi.api.resurrect_package(package_fn, ctx.get_option('files`')) - else: - self.init(database=False) - if ctx.ui.confirm(_('Rebuild PiSi databases?')): - pisi.api.rebuild_db(ctx.get_option('files')) - - self.finalize() - - -class UpdateRepo(Command): - """Update repository databases - -Usage: update-repo [ ... ] - -: repository name - -Synchronizes the PiSi databases with the current repository. -If no repository is given, all repositories are updated. -""" - __metaclass__ = autocommand - - def __init__(self,args): - super(UpdateRepo, self).__init__(args) - - name = ("update-repo", "ur") - - def options(self): - - group = OptionGroup(self.parser, _("update-repo options")) - - group.add_option("-f", "--force", action="store_true", - default=False, - help=_("Update database in any case")) - - self.parser.add_option_group(group) - - def run(self): - self.init(database = True) - - if self.args: - repos = self.args - else: - repos = ctx.repodb.list() - - for repo in repos: - pisi.api.update_repo(repo, ctx.get_option('force')) - self.finalize() - - -class AddRepo(Command): - """Add a repository - -Usage: add-repo - -: name of repository to add -: URI of index file - -If no repo is given, add-repo pardus-devel repo is added by default - -NB: We support only local files (e.g., /a/b/c) and http:// URIs at the moment -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(AddRepo, self).__init__(args) - - name = ("add-repo", "ar") - - def options(self): - - group = OptionGroup(self.parser, _("add-repo options")) - group.add_option("--at", action="store", - type="int", default=None, - help=_("Add repository at given position (0 is first)")) - self.parser.add_option_group(group) - - def run(self): - - if len(self.args)==2 or len(self.args)==0: - self.init() - if len(self.args)==2: - name = self.args[0] - indexuri = self.args[1] - else: - name = 'pardus-2007' - indexuri = 'http://paketler.pardus.org.tr/pardus-2007/pisi-index.xml.bz2' - pisi.api.add_repo(name, indexuri, ctx.get_option('at')) - if ctx.ui.confirm(_('Update PiSi database for repository %s?') % name): - try: - pisi.api.update_repo(name) - except pisi.fetcher.FetchError: - ctx.ui.warning(_("%s repository could not be reached. Removing %s from system.") % (name, name)) - pisi.api.remove_repo(name) - self.finalize() - else: - self.help() - return - - -class RemoveRepo(Command): - """Remove repositories - -Usage: remove-repo ... - -Remove all repository information from the system. -""" - __metaclass__ = autocommand - - def __init__(self,args): - super(RemoveRepo, self).__init__(args) - - name = ("remove-repo", "rr") - - def run(self): - - if len(self.args)>=1: - self.init() - for repo in self.args: - pisi.api.remove_repo(repo) - self.finalize() - else: - self.help() - return - - -class ListRepo(Command): - """List repositories - -Usage: list-repo - -Lists currently tracked repositories. -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(ListRepo, self).__init__(args) - - name = ("list-repo", "lr") - - def run(self): - - self.init(database = True, write = False) - for repo in ctx.repodb.list(): - ctx.ui.info(repo) - print ' ', ctx.repodb.get_repo(repo).indexuri.get_uri() - self.finalize() - - -class ListAvailable(Command): - """List available packages in the repositories - -Usage: list-available [ ... repon ] - -Gives a brief list of PiSi packages published in the specified -repositories. If no repository is specified, we list packages in -all repositories. -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(ListAvailable, self).__init__(args) - - name = ("list-available", "la") - - def options(self): - - group = OptionGroup(self.parser, _("list-available options")) - group.add_option("-l", "--long", action="store_true", - default=False, help=_("Show in long format")) - group.add_option("-c", "--component", action="store", - default=None, help=_("List available packages under given component")) - group.add_option("-U", "--uninstalled", action="store_true", - default=False, help=_("Show uninstalled packages only")) - self.parser.add_option_group(group) - - def run(self): - - self.init(database = True, write = False) - - if not (ctx.get_option('no_color') or ctx.config.get_option('uninstalled')): - ctx.ui.info(util.colorize(_('Installed packages are shown in this color'), 'green')) - - if self.args: - for arg in self.args: - self.print_packages(arg) - else: - # print for all repos - for repo in ctx.repodb.list(): - ctx.ui.info(_("Repository : %s\n") % repo) - self.print_packages(repo) - self.finalize() - - def print_packages(self, repo): - - component = ctx.get_option('component') - if component: - l = ctx.componentdb.get_packages(component, walk=True, repo=repo) - else: - l = ctx.packagedb.list_packages(repo) - installed_list = ctx.installdb.list_installed() - l.sort() - for p in l: - package = ctx.packagedb.get_package(p) - if self.options.long: - ctx.ui.info(unicode(package)) - else: - lenp = len(p) - if p in installed_list: - if ctx.config.get_option('uninstalled'): - continue - p = util.colorize(p, 'green') - p = p + ' ' * max(0, 15 - lenp) - ctx.ui.info('%s - %s ' % (p, unicode(package.summary))) - -class ListComponents(Command): - """List available components - -Usage: list-components - -Gives a brief list of PiSi components published in the -repositories. -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(ListComponents, self).__init__(args) - - name = ("list-components", "lc") - - def options(self): - group = OptionGroup(self.parser, _("list-components options")) - group.add_option("-l", "--long", action="store_true", - default=False, help=_("Show in long format")) - self.parser.add_option_group(group) - - def run(self): - - self.init(database = True, write = False) - - l = ctx.componentdb.list_components() - l.sort() - for p in l: - component = ctx.componentdb.get_component(p) - if self.options.long: - ctx.ui.info(unicode(component)) - else: - lenp = len(p) - #if p in installed_list: - # p = util.colorize(p, 'cyan') - p = p + ' ' * max(0, 15 - lenp) - ctx.ui.info('%s - %s ' % (component.name, unicode(component.summary))) - self.finalize() - - -class ListSources(Command): - """List available sources - -Usage: list-sources - -Gives a brief list of sources published in the repositories. -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(ListSources, self).__init__(args) - - name = ("list-sources", "ls") - - def options(self): - group = OptionGroup(self.parser, _("list-sources options")) - group.add_option("-l", "--long", action="store_true", - default=False, help=_("Show in long format")) - self.parser.add_option_group(group) - - def run(self): - - self.init(database = True, write = False) - - l = ctx.sourcedb.list() - l.sort() - for p in l: - sf, repo = ctx.sourcedb.get_spec_repo(p) - if self.options.long: - ctx.ui.info('[Repository: ' + repo + ']') - ctx.ui.info(unicode(sf.source)) - else: - lenp = len(p) - #if p in installed_list: - # p = util.colorize(p, 'cyan') - p = p + ' ' * max(0, 15 - lenp) - ctx.ui.info('%s - %s' % (sf.source.name, unicode(sf.source.summary))) - self.finalize() - -class ListUpgrades(Command): - """List packages to be upgraded - -Usage: list-upgrades - -Lists the packages that will be upgraded. -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(ListUpgrades, self).__init__(args) - - name = ("list-upgrades", "lu") - - def options(self): - group = OptionGroup(self.parser, _("list-upgrades options")) - buildno_opts(self, group) - group.add_option("-l", "--long", action="store_true", - default=False, help=_("Show in long format")) - group.add_option("-c", "--component", action="store", - default=None, help=_("List upgradable packages under given component")) - group.add_option("-i", "--install-info", action="store_true", - default=False, help=_("Show detailed install info")) - self.parser.add_option_group(group) - - def run(self): - self.init(database = True, write = False) - upgradable_pkgs = pisi.api.list_upgradable() - - component = ctx.get_option('component') - if component: - #FIXME: PiSi api is insufficient to do this - from sets import Set as set - component_pkgs = ctx.componentdb.get_union_packages(component, walk=True) - upgradable_pkgs = list(set(upgradable_pkgs) & set(component_pkgs)) - - if not upgradable_pkgs: - ctx.ui.info(_('No packages to upgrade.')) - - upgradable_pkgs.sort() - if self.options.install_info: - ctx.ui.info(_('Package Name |St| Version| Rel.| Build| Distro| Date')) - print '========================================================================' - for pkg in upgradable_pkgs: - package = ctx.packagedb.get_package(pkg, pisi.db.itembyrepodb.installed) - inst_info = ctx.installdb.get_info(pkg) - if self.options.long: - ctx.ui.info(package) - print inst_info - elif self.options.install_info: - ctx.ui.info('%-15s | %s ' % (package.name, inst_info.one_liner())) - else: - ctx.ui.info('%15s - %s ' % (package.name, package.summary)) - self.finalize() - - -class ListPending(Command): - """List pending packages - -Lists packages waiting to be configured. -""" - - __metaclass__ = autocommand - - def __init__(self, args): - super(ListPending, self).__init__(args) - - name = ("list-pending", "lp") - - def run(self): - self.init(database = True, write = False) - - A = ctx.installdb.list_pending() - order = pisi.api.generate_pending_order(A) - - if len(order): - for p in order: - print p - else: - ctx.ui.info(_('There are no packages waiting to be configured')) - self.finalize() - - -class Search(Info): - """Search packages - -Usage: search ... - -Finds a package containing specified search terms -in summary, description, and package name fields. -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(Search, self).__init__(args) - - name = ("search", "sr") - - def options(self): - group = OptionGroup(self.parser, _("search options")) - super(Search, self).add_options(group) - group.remove_option("--component") - group.remove_option("--short") - group.remove_option("--xml") - group.add_option("-l", "--long", action="store_true", - default=False, help=_("Show details")) - self.parser.add_option_group(group) - - def run(self): - - self.init(database = True, write = False) - - if not self.args: - self.help() - return - - r = pisi.api.search_package_terms(self.args) - ctx.ui.info(_('%s packages found') % len(r)) - - ctx.config.options.short = not ctx.config.options.long - for pkg in r: - self.info_package(pkg) - - self.finalize() - -class SearchFile(Command): - """Search for a file - -Usage: search-file ... - -Finds the installed package which contains the specified file. -""" - __metaclass__ = autocommand - - def __init__(self, args): - super(SearchFile, self).__init__(args) - - name = ("search-file", "sf") - - def options(self): - group = OptionGroup(self.parser, _("search-file options")) - group.add_option("-l", "--long", action="store_true", - default=False, help=_("Show in long format")) - group.add_option("-f", "--fuzzy", action="store_true", - default=False, help=_("Fuzzy search")) - group.add_option("-q", "--quiet", action="store_true", - default=False, help=_("Show only package name")) - self.parser.add_option_group(group) - - # what does exact mean? -- exa - @staticmethod - def search_exact(path): - files = [] - path = path.lstrip('/') #FIXME: this shouldn't be necessary :/ - - if not ctx.config.options.fuzzy: - if ctx.filesdb.has_file(path): - files.append(ctx.filesdb.get_file(path)) - else: - #FIXME: this linear search thing is not working well -- exa - files = ctx.filesdb.match_files(path) - - if files: - for (pkg_name, file_info) in files: - if ctx.config.options.quiet: - ctx.ui.info(pkg_name) - else: - ctx.ui.info(_("Package %s has file %s") % (pkg_name, file_info.path)) - if ctx.config.options.long: - ctx.ui.info(_('Type: %s, Hash: %s') % (file_info.type, - file_info.hash)) - else: - ctx.ui.error(_("Path '%s' does not belong to an installed package") % path) - - def run(self): - - self.init(database = True, write = False) - - if not self.args: - self.help() - return - - # search among existing files - for path in self.args: - if not ctx.config.options.quiet: - ctx.ui.info(_('Searching for %s') % path) - import os.path - if os.path.exists(path): - path = os.path.realpath(path) - self.search_exact(path) - - self.finalize() - -# texts - -usage_text1 = _("""%prog [options] [arguments] - -where is one of: - -""") - -usage_text2 = _(""" -Use \"%prog help \" for help on a specific command. -""") - -usage_text = (usage_text1 + Command.commands_string() + usage_text2) diff --git a/pisi/cli/configurepending.py b/pisi/cli/configurepending.py new file mode 100644 index 00000000..82b7154e --- /dev/null +++ b/pisi/cli/configurepending.py @@ -0,0 +1,46 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.api +import pisi.cli.command as command + +class ConfigurePending(command.PackageOp): + """Configure pending packages + +If COMAR configuration of some packages were not +done at installation time, they are added to a list +of packages waiting to be configured. This command +configures those packages. +""" + + __metaclass__ = command.autocommand + + def __init__(self, args): + super(ConfigurePending, self).__init__(args) + + name = ("configure-pending", "cp") + + def options(self): + group = optparse.OptionGroup(self.parser, _("configure-pending options")) + super(ConfigurePending, self).options(group) + self.parser.add_option_group(group) + + def run(self): + + self.init() + pisi.api.configure_pending() diff --git a/pisi/cli/deletecache.py b/pisi/cli/deletecache.py new file mode 100644 index 00000000..e044365f --- /dev/null +++ b/pisi/cli/deletecache.py @@ -0,0 +1,35 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 +import pisi.api +import pisi.cli.command as command + +class DeleteCache(command.Command): + """Delete cache files + +Usage: delete-cache + +Sources, packages and temporary files are stored +under /var directory. Since these accumulate they can +consume a lot of disk space.""" + + __metaclass__ = command.autocommand + + def __init__(self, args=None): + super(DeleteCache, self).__init__(args) + + name = ("delete-cache", "dc") + + def run(self): + self.init(database=False, write=True) + pisi.api.delete_cache() diff --git a/pisi/cli/delta.py b/pisi/cli/delta.py new file mode 100644 index 00000000..a238013a --- /dev/null +++ b/pisi/cli/delta.py @@ -0,0 +1,67 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.context as ctx + +class Delta(command.Command): + """Creates delta PiSi packages + +Usage: delta oldpackage newpackage + +Delta command finds the changed files between the given packages by comparing the sha1sum of the files +and creates a delta pisi package with the changed files between two releases. + +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(Delta, self).__init__(args) + + name = ("delta", "dt") + + def options(self): + + group = optparse.OptionGroup(self.parser, _("delta options")) + self.add_options(group) + self.parser.add_option_group(group) + + def add_options(self, group): + group.add_option("-O", "--output-dir", action="store", default=None, + help=_("Output directory for produced packages")) + + def run(self): + + from pisi.operations.delta import create_delta_package + + self.init(database=False, write=False) + + if len(self.args) != 2: + self.help() + return + + if ctx.get_option('output_dir'): + ctx.ui.info(_('Output directory: %s') % ctx.config.options.output_dir) + else: + ctx.ui.info(_('Outputting packages in the working directory.')) + ctx.config.options.output_dir = '.' + + oldpackage = self.args[0] + newpackage = self.args[1] + + create_delta_package(oldpackage, newpackage) diff --git a/pisi/cli/emerge.py b/pisi/cli/emerge.py new file mode 100644 index 00000000..8b2d01ac --- /dev/null +++ b/pisi/cli/emerge.py @@ -0,0 +1,66 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.cli.build as build +import pisi.context as ctx +import pisi.api + +class Emerge(build.Build): + """Build and install PiSi source packages from repository + +Usage: emerge ... + +You should give the name of a source package to be +downloaded from a repository containing sources. + +You can also give the name of a component. +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(Emerge, self).__init__(args) + self.comar = True + + name = ("emerge", "em") + + def options(self): + + group = optparse.OptionGroup(self.parser, _("emerge options")) + super(Emerge, self).add_options(group) + group.add_option("--ignore-file-conflicts", action="store_true", + default=False, help=_("Ignore file conflicts")) + group.add_option("--ignore-package-conflicts", action="store_true", + default=False, help=_("Ignore package conflicts")) + group.add_option("--ignore-comar", action="store_true", + default=False, help=_("Bypass comar configuration agent")) + self.parser.add_option_group(group) + + def run(self): + if not self.args: + self.help() + return + + self.init(database = True) + if ctx.get_option('output_dir'): + ctx.ui.info(_('Output directory: %s') % ctx.config.options.output_dir) + else: + ctx.ui.info(_('Outputting binary packages in the package cache.')) + ctx.config.options.output_dir = ctx.config.cached_packages_dir() + + pisi.api.emerge(self.args) diff --git a/pisi/cli/graph.py b/pisi/cli/graph.py new file mode 100644 index 00000000..1dc0c4ab --- /dev/null +++ b/pisi/cli/graph.py @@ -0,0 +1,92 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi +import pisi.api +import pisi.cli.command as command +import pisi.context as ctx +import pisi.db + +class Graph(command.Command): + """Graph package relations + +Usage: graph [ ...] + +Write a graph of package relations, tracking dependency and +conflicts relations starting from given packages. By default +shows the package relations among repository packages, and writes +the package in graphviz format to 'pgraph.dot'. +""" + + __metaclass__ = command.autocommand + + def __init__(self, args=None): + super(Graph, self).__init__(args) + + def options(self): + + group = optparse.OptionGroup(self.parser, _("graph options")) + + group.add_option("-r", "--repository", action="store", + default=None, + help=_("Specify a particular repository")) + group.add_option("-i", "--installed", action="store_true", + default=False, + help=_("Graph of installed packages")) + group.add_option("--ignore-installed", action="store_true", + default=False, + help=_("Do not show installed packages")) + group.add_option("-o", "--output", action="store", + default='pgraph.dot', + help=_("Dot output file")) + + self.parser.add_option_group(group) + + name = ("graph", None) + + def run(self): + self.init(write=False) + if not ctx.get_option('installed'): + # Graph from package database + packagedb = pisi.db.packagedb.PackageDB() + + if ctx.get_option('repository'): + repo = ctx.get_option('repository') + ctx.ui.info(_('Plotting packages in repository %s') % repo) + else: + repo = None + ctx.ui.info(_('Plotting a graph of relations among all repository packages')) + + if self.args: + a = self.args + else: + a = pisi.api.list_available(repo) + else: + # Graph from installed packages database + packagedb = pisi.db.installdb.InstallDB() + + if self.args: + a = self.args + else: + # if A is empty, then graph all packages + ctx.ui.info(_('Plotting a graph of relations among all installed packages')) + a = pisi.api.list_installed() + + g = pisi.api.package_graph(a, packagedb, + ignore_installed = ctx.get_option('ignore_installed')) + g.write_graphviz(file(ctx.get_option('output'), 'w')) diff --git a/pisi/cli/help.py b/pisi/cli/help.py new file mode 100644 index 00000000..987a1518 --- /dev/null +++ b/pisi/cli/help.py @@ -0,0 +1,59 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli +import pisi.cli.command as command +import pisi.context as ctx + +class Help(command.Command): + """Prints help for given commands + +Usage: help [ ... ] + +If run without parameters, it prints the general help.""" + + __metaclass__ = command.autocommand + + def __init__(self, args = None): + super(Help, self).__init__(args) + + name = ("help", "?") + + def run(self): + + if not self.args: + self.parser.set_usage(usage_text) + pisi.cli.printu(self.parser.format_help()) + return + + self.init(database = False, write = False) + + for arg in self.args: + obj = command.Command.get_command(arg, True) + obj.help() + ctx.ui.info('') + +usage_text1 = _("""%prog [options] [arguments] + +where is one of: + +""") + +usage_text2 = _(""" +Use \"%prog help \" for help on a specific command. +""") + +usage_text = (usage_text1 + command.Command.commands_string() + usage_text2) diff --git a/pisi/cli/index.py b/pisi/cli/index.py new file mode 100644 index 00000000..6b136b46 --- /dev/null +++ b/pisi/cli/index.py @@ -0,0 +1,73 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.context as ctx + +class Index(command.Command): + """Index PiSi files in a given directory + +Usage: index ... + +This command searches for all PiSi files in a directory, collects PiSi +tags from them and accumulates the information in an output XML file, +named by default 'pisi-index.xml'. In particular, it indexes both +source and binary packages. + +If you give multiple directories, the command still works, but puts +everything in a single index file. +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(Index, self).__init__(args) + + name = ("index", "ix") + + def options(self): + + group = optparse.OptionGroup(self.parser, _("index options")) + + group.add_option("-a", "--absolute-urls", action="store_true", + default=False, + help=_("Store absolute links for indexed files.")) + group.add_option("-o", "--output", action="store", + default='pisi-index.xml', + help=_("Index output file")) + group.add_option("--skip-sources", action="store_true", + default=False, + help=_("Do not index PiSi spec files.")) + group.add_option("--skip-signing", action="store_true", + default=False, + help=_("Do not sign index.")) + + self.parser.add_option_group(group) + + def run(self): + + self.init(database = True, write = False) + from pisi.api import index + if len(self.args)>0: + index(self.args, ctx.get_option('output'), + skip_sources = ctx.get_option('skip_sources'), + skip_signing = ctx.get_option('skip_signing')) + elif len(self.args)==0: + ctx.ui.info(_('Indexing current directory.')) + index(['.'], ctx.get_option('output'), + skip_sources = ctx.get_option('skip_sources'), + skip_signing = ctx.get_option('skip_signing')) diff --git a/pisi/cli/info.py b/pisi/cli/info.py new file mode 100644 index 00000000..9c503474 --- /dev/null +++ b/pisi/cli/info.py @@ -0,0 +1,160 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.context as ctx +import pisi.util as util +import pisi.api +import pisi.db + +class Info(command.Command): + """Display package information + +Usage: info ... + + is either a package name or a .pisi file, +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(Info, self).__init__(args) + self.installdb = pisi.db.installdb.InstallDB() + self.componentdb = pisi.db.componentdb.ComponentDB() + self.packagedb = pisi.db.packagedb.PackageDB() + + name = ("info", None) + + def options(self): + + group = optparse.OptionGroup(self.parser, _("info options")) + self.add_options(group) + self.parser.add_option_group(group) + + def add_options(self, group): + group.add_option("-f", "--files", action="store_true", + default=False, + help=_("Show a list of package files.")) + group.add_option("-c", "--component", action="append", + default=None, help=_("Info about the given component")) + group.add_option("-F", "--files-path", action="store_true", + default=False, + help=_("Show only paths.")) + group.add_option("-s", "--short", action="store_true", + default=False, help=_("Do not show details")) + group.add_option("--xml", action="store_true", + default=False, help=_("Output in xml format")) + + def run(self): + + self.init(database = True, write = False) + + components = ctx.get_option('component') + if not components and not self.args: + self.help() + return + + index = pisi.index.Index() + index.distribution = None + + # info of components + if components: + for name in components: + if self.componentdb.has_component(name): + component = self.componentdb.get_union_component(name) + if self.options.xml: + index.add_component(component) + else: + if not self.options.short: + ctx.ui.info(unicode(component)) + else: + ctx.ui.info("%s - %s" % (component.name, component.summary)) + + # info of packages + for arg in self.args: + if self.options.xml: + index.packages.append(pisi.api.info(arg)[0].package) + else: + self.info_package(arg) + + if self.options.xml: + errs = [] + index.newDocument() + index.encode(index.rootNode(), errs) + index.writexmlfile(sys.stdout) + sys.stdout.write('\n') + + def info_package(self, arg): + + if arg.endswith(ctx.const.package_suffix): + self.pisifile_info(arg) + return + + self.installdb_info(arg) + self.packagedb_info(arg) + + def print_files(self, files): + files.list.sort(key = lambda x:x.path) + for fileinfo in files.list: + if self.options.files: + print fileinfo + else: + print "/" + fileinfo.path + + def print_metadata(self, metadata, packagedb): + if ctx.get_option('short'): + pkg = metadata.package + ctx.ui.info('%15s - %s' % (pkg.name, unicode(pkg.summary))) + else: + ctx.ui.info(unicode(metadata.package)) + + revdeps = [name for name, dep in packagedb.get_rev_deps(metadata.package.name)] + print _('Reverse Dependencies:'), util.strlist(revdeps) + print + + def pisifile_info(self, package): + metadata, files = pisi.api.info_file(package) + ctx.ui.info(_('Package file: %s') % package) + self.print_pkginfo(metadata, files) + + def installdb_info(self, package): + if self.installdb.has_package(package): + metadata, files, repo = pisi.api.info_name(package, True) + + if self.options.files or self.options.files_path: + self.print_files(files) + return + + if self.options.short: + ctx.ui.info(_('[inst] '), noln=True) + else: + ctx.ui.info(_('Installed package:')) + + self.print_metadata(metadata, self.installdb) + else: + ctx.ui.info(_("%s is not installed") % package) + + def packagedb_info(self, package): + if self.packagedb.has_package(package): + metadata, files, repo = pisi.api.info_name(package, False) + if self.options.short: + ctx.ui.info(_('[repo] '), noln=True) + else: + ctx.ui.info(_('Package found in %s repository:') % repo) + self.print_metadata(metadata, self.packagedb) + else: + ctx.ui.info(_("%s is not found in repositories") % package) diff --git a/pisi/cli/install.py b/pisi/cli/install.py new file mode 100644 index 00000000..0d85737f --- /dev/null +++ b/pisi/cli/install.py @@ -0,0 +1,81 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.context as ctx +import pisi.api +import pisi.db + +class Install(command.PackageOp): + """Install PiSi packages + +Usage: install ... + +You may use filenames, URI's or package names for packages. If you have +specified a package name, it should exist in a specified repository. + +You can also specify components instead of package names, which will be +expanded to package names. +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(Install, self).__init__(args) + self.componentdb = pisi.db.componentdb.ComponentDB() + + name = "install", "it" + + def options(self): + group = optparse.OptionGroup(self.parser, _("install options")) + + super(Install, self).options(group) + group.add_option("--ignore-build-no", action="store_true", + default=False, + help=_("Do not take build no into account.")) + group.add_option("--reinstall", action="store_true", + default=False, help=_("Reinstall already installed packages")) + group.add_option("--ignore-file-conflicts", action="store_true", + default=False, help=_("Ignore file conflicts")) + group.add_option("--ignore-package-conflicts", action="store_true", + default=False, help=_("Ignore package conflicts")) + group.add_option("-c", "--component", action="append", + default=None, help=_("Install component's and recursive components' packages")) + group.add_option("-f", "--fetch-only", action="store_true", + default=False, help=_("Fetch upgrades but do not install.")) + self.parser.add_option_group(group) + + def run(self): + + if self.options.fetch_only: + self.init(database=True, write=False) + else: + self.init() + + components = ctx.get_option('component') + if not components and not self.args: + self.help() + return + + packages = [] + if components: + for name in components: + if self.componentdb.has_component(name): + packages.extend(self.componentdb.get_union_packages(name, walk=True)) + packages.extend(self.args) + + pisi.api.install(packages, ctx.get_option('reinstall')) diff --git a/pisi/cli/listavailable.py b/pisi/cli/listavailable.py new file mode 100644 index 00000000..f0c85dae --- /dev/null +++ b/pisi/cli/listavailable.py @@ -0,0 +1,90 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.context as ctx +import pisi.util as util +import pisi.api +import pisi.db + +class ListAvailable(command.Command): + """List available packages in the repositories + +Usage: list-available [ ... repon ] + +Gives a brief list of PiSi packages published in the specified +repositories. If no repository is specified, we list packages in +all repositories. +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(ListAvailable, self).__init__(args) + self.componentdb = pisi.db.componentdb.ComponentDB() + self.packagedb = pisi.db.packagedb.PackageDB() + + name = ("list-available", "la") + + def options(self): + + group = optparse.OptionGroup(self.parser, _("list-available options")) + group.add_option("-l", "--long", action="store_true", + default=False, help=_("Show in long format")) + group.add_option("-c", "--component", action="store", + default=None, help=_("List available packages under given component")) + group.add_option("-U", "--uninstalled", action="store_true", + default=False, help=_("Show uninstalled packages only")) + self.parser.add_option_group(group) + + def run(self): + + self.init(database = True, write = False) + + if not (ctx.get_option('no_color') or ctx.config.get_option('uninstalled')): + ctx.ui.info(util.colorize(_('Installed packages are shown in this color'), 'green')) + + if self.args: + for arg in self.args: + self.print_packages(arg) + else: + # print for all repos + for repo in pisi.api.list_repos(): + ctx.ui.info(_("Repository : %s\n") % repo) + self.print_packages(repo) + + def print_packages(self, repo): + + component = ctx.get_option('component') + if component: + l = self.componentdb.get_packages(component, repo=repo, walk=True) + else: + l = pisi.api.list_available(repo) + installed_list = pisi.api.list_installed() + l.sort() + for p in l: + package = self.packagedb.get_package(p, repo) + if self.options.long: + ctx.ui.info(unicode(package)) + else: + lenp = len(p) + if p in installed_list: + if ctx.config.get_option('uninstalled'): + continue + p = util.colorize(p, 'green') + p = p + ' ' * max(0, 15 - lenp) + ctx.ui.info('%s - %s ' % (p, unicode(package.summary))) diff --git a/pisi/cli/listcomponents.py b/pisi/cli/listcomponents.py new file mode 100644 index 00000000..0d6a6b1c --- /dev/null +++ b/pisi/cli/listcomponents.py @@ -0,0 +1,60 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.context as ctx +import pisi.db + +class ListComponents(command.Command): + """List available components + +Usage: list-components + +Gives a brief list of PiSi components published in the +repositories. +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(ListComponents, self).__init__(args) + self.componentdb = pisi.db.componentdb.ComponentDB() + + name = ("list-components", "lc") + + def options(self): + group = optparse.OptionGroup(self.parser, _("list-components options")) + group.add_option("-l", "--long", action="store_true", + default=False, help=_("Show in long format")) + self.parser.add_option_group(group) + + def run(self): + + self.init(database = True, write = False) + + l = self.componentdb.list_components() + l.sort() + for p in l: + component = self.componentdb.get_component(p) + if self.options.long: + ctx.ui.info(unicode(component)) + else: + lenp = len(p) + #if p in installed_list: + # p = util.colorize(p, 'cyan') + p = p + ' ' * max(0, 15 - lenp) + ctx.ui.info('%s - %s ' % (component.name, unicode(component.summary))) diff --git a/pisi/cli/listinstalled.py b/pisi/cli/listinstalled.py new file mode 100644 index 00000000..c6971691 --- /dev/null +++ b/pisi/cli/listinstalled.py @@ -0,0 +1,76 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.context as ctx +import pisi.api +import pisi.db + +class ListInstalled(command.Command): + """Print the list of all installed packages + +Usage: list-installed +""" + + __metaclass__ = command.autocommand + + def __init__(self, args): + super(ListInstalled, self).__init__(args) + self.installdb = pisi.db.installdb.InstallDB() + self.componentdb = pisi.db.componentdb.ComponentDB() + + name = ("list-installed", "li") + + def options(self): + + group = optparse.OptionGroup(self.parser, _("list-installed options")) + + group.add_option("-l", "--long", action="store_true", + default=False, help=_("Show in long format")) + group.add_option("-c", "--component", action="store", + default=None, help=_("List installed packages under given component")) + group.add_option("-i", "--install-info", action="store_true", + default=False, help=_("Show detailed install info")) + + self.parser.add_option_group(group) + + def run(self): + self.init(database = True, write = False) + installed = self.installdb.list_installed() + + component = ctx.get_option('component') + if component: + #FIXME: pisi api is insufficient to do this + from sets import Set as set + component_pkgs = self.componentdb.get_union_packages(component, walk=True) + installed = list(set(installed) & set(component_pkgs)) + + installed.sort() + if self.options.install_info: + ctx.ui.info(_('Package Name |St| Version| Rel.| Build| Distro| Date')) + print '========================================================================' + for pkg in installed: + package = self.installdb.get_package(pkg) + inst_info = self.installdb.get_info(pkg) + if self.options.long: + ctx.ui.info(unicode(package)) + ctx.ui.info(unicode(inst_info)) + elif self.options.install_info: + ctx.ui.info('%-15s |%s' % (package.name, inst_info.one_liner())) + else: + ctx.ui.info('%15s - %s' % (package.name, unicode(package.summary))) diff --git a/pisi/cli/listpending.py b/pisi/cli/listpending.py new file mode 100644 index 00000000..262b60ae --- /dev/null +++ b/pisi/cli/listpending.py @@ -0,0 +1,43 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.context as ctx +import pisi.api + +class ListPending(command.Command): + """List pending packages + +Lists packages waiting to be configured. +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(ListPending, self).__init__(args) + + name = ("list-pending", "lp") + + def run(self): + self.init(database = True, write = False) + + A = pisi.api.list_pending() + order = pisi.api.generate_pending_order(A) + + if len(order): + for p in order: + print p + else: + ctx.ui.info(_('There are no packages waiting to be configured')) diff --git a/pisi/cli/listrepo.py b/pisi/cli/listrepo.py new file mode 100644 index 00000000..6ed81951 --- /dev/null +++ b/pisi/cli/listrepo.py @@ -0,0 +1,38 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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.cli.command as command +import pisi.context as ctx +import pisi.db + +class ListRepo(command.Command): + """List repositories + +Usage: list-repo + +Lists currently tracked repositories. +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(ListRepo, self).__init__(args) + self.repodb = pisi.db.repodb.RepoDB() + + name = ("list-repo", "lr") + + def run(self): + + self.init(database = True, write = False) + for repo in self.repodb.list_repos(): + ctx.ui.info(repo) + #FIXME: repodb.get_repo(repo).indexuri.get_uri()??? ick! + print ' ', self.repodb.get_repo(repo).indexuri.get_uri() diff --git a/pisi/cli/listsources.py b/pisi/cli/listsources.py new file mode 100644 index 00000000..d3dfd27b --- /dev/null +++ b/pisi/cli/listsources.py @@ -0,0 +1,60 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.context as ctx +import pisi.db + +class ListSources(command.Command): + """List available sources + +Usage: list-sources + +Gives a brief list of sources published in the repositories. +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(ListSources, self).__init__(args) + self.sourcedb = pisi.db.sourcedb.SourceDB() + + name = ("list-sources", "ls") + + def options(self): + group = optparse.OptionGroup(self.parser, _("list-sources options")) + group.add_option("-l", "--long", action="store_true", + default=False, help=_("Show in long format")) + self.parser.add_option_group(group) + + def run(self): + + self.init(database = True, write = False) + + l = self.sourcedb.list_sources() + l.sort() + for p in l: + sf, repo = self.sourcedb.get_spec_repo(p) + if self.options.long: + ctx.ui.info('[Repository: ' + repo + ']') + ctx.ui.info(unicode(sf.source)) + else: + lenp = len(p) + #if p in installed_list: + # p = util.colorize(p, 'cyan') + p = p + ' ' * max(0, 15 - lenp) + ctx.ui.info('%s - %s' % (sf.source.name, unicode(sf.source.summary))) diff --git a/pisi/cli/listupgrades.py b/pisi/cli/listupgrades.py new file mode 100644 index 00000000..fbea07cd --- /dev/null +++ b/pisi/cli/listupgrades.py @@ -0,0 +1,80 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.context as ctx +import pisi.api +import pisi.db + +class ListUpgrades(command.Command): + """List packages to be upgraded + +Usage: list-upgrades + +Lists the packages that will be upgraded. +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(ListUpgrades, self).__init__(args) + self.componentdb = pisi.db.componentdb.ComponentDB() + self.installdb = pisi.db.installdb.InstallDB() + + name = ("list-upgrades", "lu") + + def options(self): + group = optparse.OptionGroup(self.parser, _("list-upgrades options")) + group.add_option("--ignore-build-no", action="store_true", + default=False, + help=_("Do not take build no into account.")) + group.add_option("-l", "--long", action="store_true", + default=False, help=_("Show in long format")) + group.add_option("-c", "--component", action="store", + default=None, help=_("List upgradable packages under given component")) + group.add_option("-i", "--install-info", action="store_true", + default=False, help=_("Show detailed install info")) + self.parser.add_option_group(group) + + def run(self): + self.init(database = True, write = False) + upgradable_pkgs = pisi.api.list_upgradable() + + component = ctx.get_option('component') + if component: + #FIXME: PiSi api is insufficient to do this + from sets import Set as set + component_pkgs = self.componentdb.get_union_packages(component, walk=True) + upgradable_pkgs = list(set(upgradable_pkgs) & set(component_pkgs)) + + if not upgradable_pkgs: + ctx.ui.info(_('No packages to upgrade.')) + + upgradable_pkgs.sort() + if self.options.install_info: + ctx.ui.info(_('Package Name |St| Version| Rel.| Build| Distro| Date')) + print '========================================================================' + for pkg in upgradable_pkgs: + package = self.installdb.get_package(pkg) + inst_info = self.installdb.get_info(pkg) + if self.options.long: + ctx.ui.info(package) + print inst_info + elif self.options.install_info: + ctx.ui.info('%-15s | %s ' % (package.name, inst_info.one_liner())) + else: + ctx.ui.info('%15s - %s ' % (package.name, package.summary)) diff --git a/pisi/cli/pisicli.py b/pisi/cli/pisicli.py index a47fe8d8..ba16b820 100644 --- a/pisi/cli/pisicli.py +++ b/pisi/cli/pisicli.py @@ -11,7 +11,7 @@ # import sys -from optparse import OptionParser +import optparse import gettext __trans = gettext.translation('pisi', fallback=True) @@ -19,18 +19,45 @@ _ = __trans.ugettext import pisi import pisi.cli -from pisi.cli import printu -from pisi.uri import URI -from pisi.cli.commands import * +import pisi.cli.command as command +import pisi.cli.addrepo +import pisi.cli.build +import pisi.cli.check +import pisi.cli.clean +import pisi.cli.configurepending +import pisi.cli.deletecache +import pisi.cli.delta +import pisi.cli.emerge +import pisi.cli.graph +import pisi.cli.index +import pisi.cli.info +import pisi.cli.install +import pisi.cli.listavailable +import pisi.cli.listcomponents +import pisi.cli.listinstalled +import pisi.cli.listpending +import pisi.cli.listrepo +import pisi.cli.listsources +import pisi.cli.listupgrades +import pisi.cli.rebuilddb +import pisi.cli.remove +import pisi.cli.removerepo +import pisi.cli.searchfile +import pisi.cli.search +import pisi.cli.updaterepo +import pisi.cli.upgrade + +#FIXME: why does this has to be imported last +import pisi.cli.help class ParserError(pisi.Exception): pass -class PreParser(OptionParser): +class PreParser(optparse.OptionParser): """consumes any options, and finds arguments from command line""" def __init__(self, version): - OptionParser.__init__(self, usage=usage_text, version=version) + optparse.OptionParser.__init__(self, usage=pisi.cli.help.usage_text, version=version) def error(self, msg): raise ParserError, msg @@ -91,17 +118,17 @@ class PisiCLI(object): sys.exit(0) elif 'help' in opts or 'h' in opts: self.die() - raise Error(_('No command given')) + raise pisi.cli.Error(_('No command given')) cmd_name = args[0] except ParserError: - raise Error(_('Command line parsing error')) + raise pisi.cli.Error(_('Command line parsing error')) - self.command = Command.get_command(cmd_name, args=orig_args) + self.command = command.Command.get_command(cmd_name, args=orig_args) if not self.command: - raise Error(_("Unrecognized command: %s") % cmd_name) + raise pisi.cli.Error(_("Unrecognized command: %s") % cmd_name) def die(self): - printu('\n' + self.parser.format_help()) + pisi.cli.printu('\n' + self.parser.format_help()) sys.exit(1) def run_command(self): diff --git a/pisi/cli/rebuilddb.py b/pisi/cli/rebuilddb.py new file mode 100644 index 00000000..fdabf305 --- /dev/null +++ b/pisi/cli/rebuilddb.py @@ -0,0 +1,52 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.context as ctx +import pisi.api + +class RebuildDb(command.Command): + """Rebuild Databases + +Usage: rebuilddb [ ... ] + +Rebuilds the PiSi databases + +If package specs are given, they should be the names of package +dirs under /var/lib/pisi +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(RebuildDb, self).__init__(args) + + name = ("rebuild-db", "rdb") + + def options(self): + + group = optparse.OptionGroup(self.parser, _("rebuild-db options")) + + group.add_option("-f", "--files", action="store_true", + default=False, help=_("Rebuild files database")) + + self.parser.add_option_group(group) + + def run(self): + self.init(database=True) + if ctx.ui.confirm(_('Rebuild PiSi databases?')): + pisi.api.rebuild_db(ctx.get_option('files')) diff --git a/pisi/cli/remove.py b/pisi/cli/remove.py new file mode 100644 index 00000000..6fbeb543 --- /dev/null +++ b/pisi/cli/remove.py @@ -0,0 +1,65 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.context as ctx +import pisi.api +import pisi.db + +class Remove(command.PackageOp): + """Remove PiSi packages + +Usage: remove ... + +Remove package(s) from your system. Just give the package names to remove. + +You can also specify components instead of package names, which will be +expanded to package names. +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(Remove, self).__init__(args) + self.component = pisi.db.componentdb.ComponentDB() + + name = ("remove", "rm") + + def options(self): + group = optparse.OptionGroup(self.parser, _("remove options")) + super(Remove, self).options(group) + group.add_option("-c", "--component", action="append", + default=None, help=_("Remove component's and recursive components' packages")) + self.parser.add_option_group(group) + + def run(self): + self.init() + + components = ctx.get_option('component') + if not components and not self.args: + self.help() + return + + packages = [] + if components: + for name in components: + if self.componentdb.has_component(name): + packages.extend(self.componentdb.get_union_packages(name, walk=True)) + packages.extend(self.args) + + pisi.api.remove(packages) + diff --git a/pisi/cli/removerepo.py b/pisi/cli/removerepo.py new file mode 100644 index 00000000..06f97a08 --- /dev/null +++ b/pisi/cli/removerepo.py @@ -0,0 +1,38 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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.cli.command as command +import pisi.api + +class RemoveRepo(command.Command): + """Remove repositories + +Usage: remove-repo ... + +Remove all repository information from the system. +""" + __metaclass__ = command.autocommand + + def __init__(self,args): + super(RemoveRepo, self).__init__(args) + + name = ("remove-repo", "rr") + + def run(self): + + if len(self.args)>=1: + self.init() + for repo in self.args: + pisi.api.remove_repo(repo) + else: + self.help() + return diff --git a/pisi/cli/search.py b/pisi/cli/search.py new file mode 100644 index 00000000..fa3d8982 --- /dev/null +++ b/pisi/cli/search.py @@ -0,0 +1,87 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.context as ctx +import pisi.db + +class Search(command.Command): + """Search packages + +Usage: search ... + +Finds a package containing specified search terms +in summary, description, and package name fields. +Default search is done in package database. Use +options to search in install database or source +database. +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(Search, self).__init__(args) + + name = ("search", "sr") + + def options(self): + group = optparse.OptionGroup(self.parser, _("search options")) + group.add_option("-l", "--language", action="store", + type="string", default=None, help=_('Summary and description language')) + group.add_option("-r", "--repository", action="store", + type="string", default=None, help=_('Name of the source or package repository')) + group.add_option("-i", "--installdb", action="store_true", + default=False, help=_("Search in installdb")) + group.add_option("-s", "--sourcedb", action="store_true", + default=False, help=_("Search in sourcedb")) + self.parser.add_option_group(group) + + def run(self): + + self.init(database = True, write = False) + + if not self.args: + self.help() + return + + lang = ctx.get_option('language') + repo = ctx.get_option('repository') + + if ctx.get_option('installdb'): + db = pisi.db.installdb.InstallDB() + pkgs = db.search_package(self.args, lang) + get_info = db.get_package + get_name_sum = lambda pkg:(pkg.name, pkg.summary) + elif ctx.get_option('sourcedb'): + db = pisi.db.sourcedb.SourceDB() + pkgs = db.search_spec(self.args, lang, repo) + get_info = db.get_spec + get_name_sum = lambda pkg:(pkg.source.name, pkg.source.summary) + else: + db = pisi.db.packagedb.PackageDB() + pkgs = db.search_package(self.args, lang, repo) + get_info = db.get_package + get_name_sum = lambda pkg:(pkg.name, pkg.summary) + + for pkg in pkgs: + pkg_info = get_info(pkg) + name, summary = get_name_sum(pkg_info) + if lang and summary.has_key(lang): + print "%s - %s" % (name, summary[lang]) + else: + print "%s - %s" % (name, summary) + diff --git a/pisi/cli/searchfile.py b/pisi/cli/searchfile.py new file mode 100644 index 00000000..b594d157 --- /dev/null +++ b/pisi/cli/searchfile.py @@ -0,0 +1,69 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi +import pisi.context as ctx +import pisi.cli.command as command + +class SearchFile(command.Command): + """Search for a file + +Usage: search-file ... + +Finds the installed package which contains the specified file. +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(SearchFile, self).__init__(args) + + name = ("search-file", "sf") + + def options(self): + group = optparse.OptionGroup(self.parser, _("search-file options")) + group.add_option("-l", "--long", action="store_true", + default=False, help=_("Show in long format")) + group.add_option("-q", "--quiet", action="store_true", + default=False, help=_("Show only package name")) + self.parser.add_option_group(group) + + def search_file(self, path): + found = pisi.api.search_file(path) + for pkg, files in found: + for pkg_file in files: + ctx.ui.info(_("Package %s has file /%s") % (pkg, pkg_file)) + + if not found: + ctx.ui.error(_("Path '%s' does not belong to an installed package") % path) + + def run(self): + + self.init(database = True, write = False) + + if not self.args: + self.help() + return + + # search among existing files + for path in self.args: + if not ctx.config.options.quiet: + ctx.ui.info(_('Searching for %s') % path) + import os.path + if os.path.exists(path): + path = os.path.realpath(path) + self.search_file(path) diff --git a/pisi/cli/updaterepo.py b/pisi/cli/updaterepo.py new file mode 100644 index 00000000..eb697337 --- /dev/null +++ b/pisi/cli/updaterepo.py @@ -0,0 +1,59 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.context as ctx +import pisi.api + +class UpdateRepo(command.Command): + """Update repository databases + +Usage: update-repo [ ... ] + +: repository name + +Synchronizes the PiSi databases with the current repository. +If no repository is given, all repositories are updated. +""" + __metaclass__ = command.autocommand + + def __init__(self,args): + super(UpdateRepo, self).__init__(args) + + name = ("update-repo", "ur") + + def options(self): + + group = optparse.OptionGroup(self.parser, _("update-repo options")) + + group.add_option("-f", "--force", action="store_true", + default=False, + help=_("Update database in any case")) + + self.parser.add_option_group(group) + + def run(self): + self.init(database = True) + + if self.args: + repos = self.args + else: + repos = pisi.api.list_repos() + + for repo in repos: + pisi.api.update_repo(repo, ctx.get_option('force')) diff --git a/pisi/cli/upgrade.py b/pisi/cli/upgrade.py new file mode 100644 index 00000000..028e9dba --- /dev/null +++ b/pisi/cli/upgrade.py @@ -0,0 +1,141 @@ +# -*- coding:utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 optparse + +import os +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.cli.command as command +import pisi.context as ctx +import pisi.api +import pisi.db + +class Upgrade(command.PackageOp): + """Upgrade PiSi packages + +Usage: Upgrade [ ... ] + +: package name + +Upgrades the entire system if no package names are given + +You may use only package names to specify packages because +the package upgrade operation is defined only with respect +to repositories. If you have specified a package name, it +should exist in the package repositories. If you just want to +reinstall a package from a PiSi file, use the install command. + +You can also specify components instead of package names, which will be +expanded to package names. +""" + __metaclass__ = command.autocommand + + def __init__(self, args): + super(Upgrade, self).__init__(args) + self.componentdb = pisi.db.componentdb.ComponentDB() + + name = ("upgrade", "up") + + def options(self): + group = optparse.OptionGroup(self.parser, _("upgrade options")) + + super(Upgrade, self).options(group) + group.add_option("--ignore-build-no", action="store_true", + default=False, + help=_("Do not take build no into account.")) + group.add_option("--security-only", action="store_true", + default=False, help=_("Security related package upgrades only")) + group.add_option("-r", "--bypass-update-repo", action="store_true", + default=False, help=_("Do not update repositories")) + group.add_option("--ignore-file-conflicts", action="store_true", + default=False, help=_("Ignore file conflicts")) + group.add_option("--ignore-package-conflicts", action="store_true", + default=False, help=_("Ignore package conflicts")) + group.add_option("-c", "--component", action="append", + default=None, help=_("Upgrade component's and recursive components' packages")) + group.add_option("-f", "--fetch-only", action="store_true", + default=False, help=_("Fetch upgrades but do not install.")) + group.add_option("-x", "--exclude", action="append", + default=None, help=_("When upgrading system, ignore packages and components whose basenames match pattern.")) + group.add_option("--exclude-from", action="store", + default=None, help=_("When upgrading system, ignore packages and components whose basenames \ + match any pattern contained in file.")) + + self.parser.add_option_group(group) + + def exclude_from(self, packages, exfrom): + patterns = [] + if os.path.exists(exfrom): + for line in open(exfrom, "r").readlines(): + if not line.startswith('#') and not line == '\n': + patterns.append(line.strip()) + if patterns: + return self.exclude(packages, patterns) + + return packages + + def exclude(self, packages, patterns): + from sets import Set as set + import fnmatch + + packages = set(packages) + for pattern in patterns: + # match pattern in package names + match = fnmatch.filter(packages, pattern) + packages = packages - set(match) + + if not match: + # match pattern in component names + for compare in fnmatch.filter(self.componentdb.list_components(), pattern): + packages = packages - set(self.componentdb.get_union_packages(compare, walk=True)) + + return list(packages) + + def run(self): + + if self.options.fetch_only: + self.init(database=True, write=False) + else: + self.init() + + if not ctx.get_option('bypass_update_repo'): + ctx.ui.info(_('Updating repositories')) + repos = pisi.api.list_repos() + for repo in repos: + pisi.api.update_repo(repo) + else: + ctx.ui.info(_('Will not update repositories')) + + components = ctx.get_option('component') + packages = [] + if components: + for name in components: + if self.componentdb.has_component(name): + packages.extend(self.componentdb.get_union_packages(name, walk=True)) + packages.extend(self.args) + + if packages == []: + packages = pisi.api.list_installed() + + if os.path.exists(ctx.const.blacklist): + packages = self.exclude_from(packages, ctx.const.blacklist) + + if ctx.get_option('exclude_from'): + packages = self.exclude_from(packages, ctx.get_option('exclude_from')) + + if ctx.get_option('exclude'): + packages = self.exclude(packages, ctx.get_option('exclude')) + + pisi.api.upgrade(packages) diff --git a/pisi/component.py b/pisi/component.py index 64d5ff6f..ea536258 100644 --- a/pisi/component.py +++ b/pisi/component.py @@ -18,8 +18,6 @@ import pisi import pisi.context as ctx import pisi.pxml.xmlfile as xmlfile import pisi.pxml.autoxml as autoxml -import pisi.db.lockeddbshelve as shelve -import pisi.db.itembyrepodb class Error(pisi.Error): pass @@ -73,9 +71,6 @@ class Component(xmlfile.XmlFile): t_Icon = [ autoxml.String, autoxml.optional] t_VisibleTo = [autoxml.String, autoxml.optional] - # Dependencies to other components - t_Dependencies = [ [autoxml.String], autoxml.optional, "Dependencies/Component"] - # the parts of this component. # to be filled by the component database, thus it is optional. t_Packages = [ [autoxml.String], autoxml.optional, "Parts/Package"] diff --git a/pisi/config.py b/pisi/config.py index e21a53d7..c1d589cd 100644 --- a/pisi/config.py +++ b/pisi/config.py @@ -92,14 +92,17 @@ class Config(object): def lib_dir(self): return self.subdir(self.values.dirs.lib_dir) - def db_dir(self): - return self.subdir(self.values.dirs.db_dir) + def info_dir(self): + return self.subdir(self.values.dirs.info_dir) + + def packages_dir(self): + return self.subdir(self.values.dirs.packages_dir) def archives_dir(self): return self.subdir(self.values.dirs.archives_dir) - def packages_dir(self): - return self.subdir(self.values.dirs.packages_dir) + def cached_packages_dir(self): + return self.subdir(self.values.dirs.cached_packages_dir) def compiled_packages_dir(self): return self.subdir(self.values.dirs.compiled_packages_dir) diff --git a/pisi/configfile.py b/pisi/configfile.py index 05bc4100..23950b5e 100644 --- a/pisi/configfile.py +++ b/pisi/configfile.py @@ -35,11 +35,12 @@ # #[directories] #lib_dir = /var/lib/pisi -#db_dir = /var/db/pisi +#info_dir = "/var/lib/pisi/info" #archives_dir = /var/cache/pisi/archives -#packages_dir = /var/cache/pisi/packages +#cached_packages_dir = /var/cache/pisi/packages #compiled_packages_dir = "/var/cache/pisi/packages" #index_dir = /var/cache/pisi/index +#packages_dir = /var/cache/pisi/package #tmp_dir = /var/pisi #kde_dir = /usr/kde/3.5 #qt_dir = /usr/qt/3 @@ -64,6 +65,7 @@ class GeneralDefaults: autoclean = False distribution = "Pardus" distribution_release = "2007" + architecture = "i686" http_proxy = os.getenv("HTTP_PROXY") or None https_proxy = os.getenv("HTTPS_PROXY") or None ftp_proxy = os.getenv("FTP_PROXY") or None @@ -87,10 +89,11 @@ class DirectoriesDefaults: "Default values for [directories] section" lib_dir = "/var/lib/pisi" log_dir = "/var/log" - db_dir = "/var/db/pisi" + info_dir = "/var/lib/pisi/info" archives_dir = "/var/cache/pisi/archives" - packages_dir = "/var/cache/pisi/packages" + cached_packages_dir = "/var/cache/pisi/packages" compiled_packages_dir = "/var/cache/pisi/packages" + packages_dir = "/var/lib/pisi/package" index_dir = "/var/lib/pisi/index" tmp_dir = "/var/pisi" kde_dir = "/usr/kde/3.5" diff --git a/pisi/conflict.py b/pisi/conflict.py index 6b3032cf..08884885 100644 --- a/pisi/conflict.py +++ b/pisi/conflict.py @@ -43,7 +43,7 @@ given conflicting spec""" def package_conflicts(pkg, confs): for c in confs: - if pkg.name == c.package and c.satisfies_relation(pkg.name, pkg.version, pkg.release): + if pkg.name == c.package and c.satisfies_relation(pkg.version, pkg.release): return c return None diff --git a/pisi/constants.py b/pisi/constants.py index 0d593df6..a2960c1b 100644 --- a/pisi/constants.py +++ b/pisi/constants.py @@ -80,7 +80,11 @@ class Constants: self.__c.install_tar = "install.tar" self.__c.install_tar_lzma = "install.tar.lzma" self.__c.mirrors_conf = "/etc/pisi/mirrors.conf" - + self.__c.blacklist = "/etc/pisi/blacklist" + self.__c.config_pending = "configpending" + self.__c.files_db = "files.db" + self.__c.repos = "repos" + #file/directory permissions self.__c.umask = 0022 diff --git a/pisi/context.py b/pisi/context.py index 3a3688be..3da73019 100644 --- a/pisi/context.py +++ b/pisi/context.py @@ -16,9 +16,10 @@ import signal import pisi.constants import pisi.signalhandler +import pisi.ui const = pisi.constants.Constants() -sig = None +sig = pisi.signalhandler.SignalHandler() config = None @@ -30,61 +31,21 @@ def set_option(opt, val): def get_option(opt): return config and config.get_option(opt) -# default UI is CLI -ui = None # not now +ui = pisi.ui.UI() # stdout, stderr for PiSi API stdout = None stderr = None -dbenv = None -installdb = None -packagedb = None -repodb = None -sourcedb = None -filesdb = None -componentdb = None -invidx = None - -comar = None +comar = True comar_sockname = None -initialized = False - # Bug #2879 # FIXME: Maybe we can create a simple rollback mechanism. There are other # places which need this, too. # this is needed in build process to clean after if something goes wrong. build_leftover = None -#def register(_impl): -# """ Register a UI implementation""" -# ui = _impl - -import bsddb3.db as db - -# copy of DBShelve.txn_proc, the only difference is it doesn't need a shelf object -#FIXME: remove this redundancy, and move all this stuff to database.py -def txn_proc(proc, txn = None): - # can be used to txn protect a method automatically - if not txn: - if dbenv: - autotxn = dbenv.txn_begin() - try: - retval = proc(autotxn) - except db.DBError, e: - autotxn.abort() - raise e - except Exception, e: - autotxn.abort() - raise e - autotxn.commit() - else: - retval = proc(None) - return retval - else: - return proc(txn) - def disable_keyboard_interrupts(): sig and sig.disable_signal(signal.SIGINT) diff --git a/pisi/db/__init__.py b/pisi/db/__init__.py index 31121064..fb7bf1bd 100644 --- a/pisi/db/__init__.py +++ b/pisi/db/__init__.py @@ -9,3 +9,4 @@ # # Please read the COPYING file. # + diff --git a/pisi/db/componentdb.py b/pisi/db/componentdb.py index 2f647f51..4c26aa3c 100644 --- a/pisi/db/componentdb.py +++ b/pisi/db/componentdb.py @@ -10,198 +10,145 @@ # Please read the COPYING file. # +import re import gettext __trans = gettext.translation('pisi', fallback=True) _ = __trans.ugettext +import piksemel + import pisi -import pisi.db.lockeddbshelve as shelve -import pisi.context as ctx +import pisi.db.repodb +import pisi.db.itembyrepo import pisi.component +import pisi.db.lazydb as lazydb -class Error(pisi.Error): - pass +class ComponentDB(lazydb.LazyDB): -class ComponentDB(object): - """a database of components""" + def init(self): - def __init__(self): - self.d = pisi.db.itembyrepodb.ItemByRepoDB('component') + component_nodes = {} + component_packages = {} + component_sources = {} - def close(self): - self.d.close() + self.repodb = pisi.db.repodb.RepoDB() - def destroy(self): - self.d.destroy() + for repo in self.repodb.list_repos(): + doc = self.repodb.get_repo_doc(repo) + component_nodes[repo] = self.__generate_components(doc) + component_packages[repo] = self.__generate_packages(doc) + component_sources[repo] = self.__generate_sources(doc) - def has_component(self, name, repo = pisi.db.itembyrepodb.repos, txn = None): - name = str(name) - return self.d.has_key(name, repo, txn) + self.cdb = pisi.db.itembyrepo.ItemByRepo(component_nodes) + self.cpdb = pisi.db.itembyrepo.ItemByRepo(component_packages) + self.csdb = pisi.db.itembyrepo.ItemByRepo(component_sources) - def get_component(self, name, repo=None, txn = None): - try: - return self.d.get_item(name, repo, txn=txn) - except pisi.db.itembyrepodb.NotfoundError, e: - raise Error(_('Component %s not found') % name) + def __generate_packages(self, doc): + components = {} + for pkg in doc.tags("Package"): + components.setdefault(pkg.getTagData("PartOf"), []).append(pkg.getTagData("Name")) + return components - def get_component_repo(self, name, repo=None, txn = None): - try: - return self.d.get_item_repo(name, repo, txn=txn) - except pisi.db.itembyrepodb.NotfoundError, e: - raise Error(_('Component %s not found') % name) + def __generate_sources(self, doc): + components = {} + for spec in doc.tags("SpecFile"): + src = spec.getTag("Source") + components.setdefault(src.getTagData("PartOf"), []).append(src.getTagData("Name")) + return components + + def __generate_components(self, doc): + return dict(map(lambda x: (x.getTagData("Name"), x.toString()), doc.tags("Component"))) - def get_union_comp(self, name, txn = None, repo = pisi.db.itembyrepodb.repos ): - """get a union of all repository components packages, not just the first repo in order. - get only basic repo info from the first repo""" - def proc(txn): - s = self.d.d.get(name, txn=txn) - pkgs = set() - srcs = set() - for repostr in self.d.order(repo = repo): - if s.has_key(repostr): - pkgs |= set(s[repostr].packages) - srcs |= set(s[repostr].sources) - comp = self.get_component(name) - comp.packages = list(pkgs) - comp.sources = list(srcs) - return comp - return self.d.txn_proc(proc, txn) + def has_component(self, name, repo = None): + return self.cdb.has_item(name, repo) def list_components(self, repo=None): - return self.d.list(repo) + return self.cdb.get_item_keys(repo) - # walk: walks through the underlying components' packages - def get_union_packages(self, component_name, walk=False, repo=pisi.db.itembyrepodb.repos, txn = None): - """returns union of all repository component's packages, not just the first repo's - component's in order""" + def search_component(self, terms, lang=None, repo=None): + rename = '.*?%s.*?' + resum = '.*?%s.*?' + redesc = '.*?%s.*?' + + if not lang: + lang = pisi.pxml.autoxml.LocalText.get_lang() + found = [] + for name, xml in self.cdb.get_items_iter(repo): + if name not in found and terms == filter(lambda term: re.compile(rename % (lang, term), re.I).search(xml) or \ + re.compile(resum % (lang, term), re.I).search(xml) or \ + re.compile(redesc % (lang, term), re.I).search(xml), terms): + found.append(name) + return found + + # Returns the component in given repo or first found component in repo order if repo is None + def get_component(self, component_name, repo = None): + + if not self.has_component(component_name, repo): + raise Exception(_('Component %s not found') % component_name) + + component = pisi.component.Component() + component.parse(self.cdb.get_item(component_name, repo)) + + try: + component.packages = self.cpdb.get_item(component_name, repo) + component.sources = self.csdb.get_item(component_name, repo) + except Exception: #FIXME: what exception could we catch here, replace with that. + pass + + return component + + # Returns the component with combined packages and sources from all repos that contain this component + def get_union_component(self, component_name): + + component = pisi.component.Component() + component.parse(self.cdb.get_item(component_name)) - component = self.get_union_comp(component_name, txn, repo) + for repo in self.repodb.list_repos(): + try: + component.packages.extend(self.cpdb.get_item(component_name, repo)) + component.sources.extend(self.csdb.get_item(component_name, repo)) + except Exception: #FIXME: what exception could we catch here, replace with that. + pass + + return component + + # Returns packages of given component from given repo or first found component's packages in repo + # order if repo is None. + # If walk is True than also the sub components' packages are returned + def get_packages(self, component_name, repo=None, walk=False): + + component = self.get_component(component_name, repo) if not walk: return component.packages packages = [] packages.extend(component.packages) - for dep in component.dependencies: - packages.extend(self.get_union_packages(dep, walk, repo, txn)) + + sub_components = filter(lambda x:x.startswith(component_name+"."), self.list_components(repo)) + for sub in sub_components: + try: + packages.extend(self.get_component(sub, repo).packages) + except Exception: #FIXME: what exception could we catch here, replace with that. + pass return packages - # walk: walks through the underlying components' packages - def get_packages(self, component_name, walk=False, repo=None, txn = None): - """returns the given component's and underlying recursive components' packages""" - - component = self.get_component(component_name, repo, txn) + # Returns the component with combined packages and sources from all repos that contain this component + # If walk is True than also the sub components' packages from all repos are returned + def get_union_packages(self, component_name, walk=False): + + component = self.get_union_component(component_name) if not walk: return component.packages packages = [] packages.extend(component.packages) - for dep in component.dependencies: - packages.extend(self.get_packages(dep, walk, repo, txn)) + + sub_components = filter(lambda x:x.startswith(component_name+"."), self.list_components()) + for sub in sub_components: + try: + packages.extend(self.get_union_component(sub).packages) + except Exception: #FIXME: what exception could we catch here, replace with that. + pass return packages - - def add_child(self, component, repo, txn = None): - """update component tree""" - parent_name = ".".join(component.name.split(".")[:-1]) - if not parent_name: # root component - return - - if self.has_component(parent_name, repo, txn): - parent = self.get_component(parent_name, repo, txn) - else: - parent = pisi.component.Component(name = parent_name) - - if component.name not in parent.dependencies: - parent.dependencies.append(component.name) - self.d.add_item(parent_name, parent, repo, txn) - - def update_component(self, component, repo, txn = None): - def proc(txn): - if self.has_component(component.name, repo, txn): - # preserve list of sources, packages and dependencies - current = self.d.get_item(component.name, repo, txn) - component.packages = current.packages - component.sources = current.sources - component.dependencies = current.dependencies - self.d.add_item(component.name, component, repo, txn) - self.add_child(component, repo, txn) - self.d.txn_proc(proc, txn) - - def add_package(self, component_name, package, repo, txn = None): - def proc(txn): - assert component_name - if self.has_component(component_name, repo, txn): - component = self.get_component(component_name, repo, txn) - else: - component = pisi.component.Component( name = component_name ) - if not package in component.packages: - component.packages.append(package) - self.d.add_item(component_name, component, repo, txn) # update - self.add_child(component, repo, txn) - self.d.txn_proc(proc, txn) - - def remove_package(self, component_name, package, repo = None, txn = None): - def proc(txn, repo): - if not self.has_component(component_name, repo, txn): - raise Error(_('Information for component %s not available') % component_name) - if not repo: - repo = self.d.which_repo(component_name, txn=txn) # get default repo then - component = self.get_component(component_name, repo, txn) - if package in component.packages: - component.packages.remove(package) - self.d.add_item(component_name, component, repo, txn) # update - - ctx.txn_proc(lambda x: proc(txn, repo), txn) - - def add_spec(self, component_name, spec, repo, txn = None): - def proc(txn): - assert component_name - if self.has_component(component_name, repo, txn): - component = self.get_component(component_name, repo, txn) - else: - component = pisi.component.Component( name = component_name ) - if not spec in component.sources: - component.sources.append(spec) - self.d.add_item(component_name, component, repo, txn) # update - self.add_child(component, repo, txn) - self.d.txn_proc(proc, txn) - - def remove_spec(self, component_name, spec, repo = None, txn = None): - def proc(txn, repo): - if not self.has_component(component_name, repo, txn): - raise Error(_('Information for component %s not available') % component_name) - if not repo: - repo = self.d.which_repo(component_name, txn=txn) # get default repo then - component = self.get_component(component_name, repo, txn) - if spec in component.sources: - component.sources.remove(spec) - self.d.add_item(component_name, component, repo, txn) # update - - ctx.txn_proc(lambda x: proc(txn, repo), txn) - - def clear(self, txn = None): - self.d.clear(txn) - - def remove_component(self, name, repo = None, txn = None): - name = str(name) - self.d.remove_item(name, repo, txn) - - def remove_repo(self, repo, txn = None): - self.d.remove_repo(repo, txn=txn) - -componentdb = None - -def init(): - global componentdb - if componentdb is not None: - return componentdb - - componentdb = ComponentDB() - return componentdb - -def finalize(): - global componentdb - if componentdb is not None: - componentdb.close() - componentdb = None diff --git a/pisi/db/dbshelve.py b/pisi/db/dbshelve.py deleted file mode 100644 index 13ffbde7..00000000 --- a/pisi/db/dbshelve.py +++ /dev/null @@ -1,311 +0,0 @@ -#------------------------------------------------------------------------ -# Copyright (c) 1997-2001 by Total Control Software -# All Rights Reserved -#------------------------------------------------------------------------ -# -# Module Name: dbShelve.py -# -# Description: A reimplementation of the standard shelve.py that -# forces the use of cPickle, and DB. -# -# Creation Date: 11/3/97 3:39:04PM -# -# License: This is free software. You may use this software for any -# purpose including modification/redistribution, so long as -# this header remains intact and that you do not claim any -# rights of ownership or authorship of this software. This -# software has been tested, but no warranty is expressed or -# implied. -# -# 13-Dec-2000: Updated to be used with the new bsddb3 package. -# Added DBShelfCursor class. -# -# 13-Dec-2005: Minor hacking by exa to make it work better with PiSi -#------------------------------------------------------------------------ - -"""Manage shelves of pickled objects using bsddb database files for the -storage. - -Add transaction processing by default to dictionary ops also -Also other minor improvements -- exa - -Now added support for overriding the marshalling method -""" - -#------------------------------------------------------------------------ - -import cPickle -import bsddb3.db as db -import bsddb3.dbobj as dbobj -import string -import pisi - -class CodingError(pisi.Error): - pass - -class DBShelf: - """A shelf to hold pickled objects, built upon a bsddb DB object. It - automatically pickles/unpickles data objects going to/from the DB. - """ - def __init__(self, dbenv = None): - self.dbenv = dbenv - # how lame is bsddb3? - if self.dbenv: - self.db = dbobj.DB(dbenv) - else: - self.db = db.DB(None) - - # it is better to explicitly close a shelf - #def __del__(self): - # self.close() - - def has_key(self, key, txn = None): - if txn: - return self.db.has_key(key, txn) - else: - return self.db.has_key(key) - - def txn_proc(self, proc, txn): - # can be used to txn protect a method automatically - if not txn: - if self.dbenv: - autotxn = self.dbenv.txn_begin() - try: - retval = proc(autotxn) - except db.DBError, e: - autotxn.abort() - raise pisi.Error, e - autotxn.commit() - else: # execute without transactions - retval = proc(None) - return retval - else: - return proc(txn) - - def decode(self, data): - try: - return cPickle.loads(data) - except cPickle.UnpicklingError: - raise CodingError() - - def encode(self, obj): - return cPickle.dumps(obj, 1) - - def clear(self, txn = None): - def proc(txn): - for x in self.keys(txn): - self.db.delete(x, txn) - self.txn_proc(proc, txn) - - def delete(self, x, txn): - def proc(txn): - self.db.delete(x, txn) - self.txn_proc(proc, txn) - - # another lame pythonic implementation method: - #def __getattr__(self, name): - # """Many methods we can just pass through to the DB object. - # (See below) - # """ - # print 'aptal bsddb3', name - # return getattr(self.db, name) - - #----------------------------------- - # Dictionary access methods - - def __len__(self): - return len(self.db) - - def __getitem__(self, key): - def proc(txn): - data = self.db.get(key) - return self.decode(data) - return self.txn_proc(proc, None) - - def __setitem__(self, key, value): - # hyperdandik transactions - def proc(txn): - data = self.encode(value) - self.db.put(key,data,txn) - return self.txn_proc(proc, None) - - def __delitem__(self, key): - txn = self.dbenv.txn_begin() - try: - self.db.delete(key, txn) - except db.DBError, e: - txn.abort() - raise e - txn.commit() - - def keys(self, txn=None): - if txn != None: - return self.db.keys(txn) - else: - return self.db.keys() - - def items(self, txn=None): - if txn != None: - items = self.db.items(txn) - else: - items = self.db.items() - newitems = [] - - for k, v in items: - newitems.append( (k, self.decode(v) ) ) - return newitems - - def values(self, txn=None): - if txn != None: - values = self.db.values(txn) - else: - values = self.db.values() - - return map(lambda x : self.decode(x), values) - - #----------------------------------- - # Other methods - - def __append(self, value, txn=None): - data = self.encode(value) - return self.db.append(data, txn) - - def append(self, value, txn=None): - if self.get_type() != db.DB_RECNO: - self.append = self.__append - return self.append(value, txn=txn) - raise db.DBError, "append() only supported when dbshelve opened with filetype=dbshelve.db.DB_RECNO" - - - def associate(self, secondaryDB, callback, flags=0): - def _shelf_callback(priKey, priData, realCallback=callback): - data = self.decode(priData) - return realCallback(priKey, data) - return self.db.associate(secondaryDB, _shelf_callback, flags) - - - #def get(self, key, default=None, txn=None, flags=0): - def get(self, *args, **kw): - # We do it with *args and **kw so if the default value wasn't - # given nothing is passed to the extension module. That way - # an exception can be raised if set_get_returns_none is turned - # off. - data = apply(self.db.get, args, kw) - try: - return self.decode(data) - except (TypeError, CodingError): - return data # we may be getting the default value, or None, - # so it doesn't need unpickled. - - def get_both(self, key, value, txn=None, flags=0): - data = self.encode(value) - data = self.db.get(key, data, txn, flags) - return self.decode(data) - - def cursor(self, txn=None, flags=0): - c = DBShelfCursor(self.db.cursor(txn, flags)) - c.binary = self.binary - return c - - def put(self, key, value, txn=None, flags=0): - data = self.encode(value) - return self.db.put(key, data, txn, flags) - - def join(self, cursorList, flags=0): - raise NotImplementedError - - #---------------------------------------------- - # Methods allowed to pass-through to self.db - # - # close, delete, fd, get_byteswapped, get_type, has_key, - # key_range, open, remove, rename, stat, sync, - # upgrade, verify, and all set_* methods. - - -#--------------------------------------------------------------------------- - -class DBShelfCursor: - """ - """ - def __init__(self, cursor): - self.dbc = cursor - - def __del__(self): - self.close() - - def __getattr__(self, name): - """Some methods we can just pass through to the cursor object. (See below)""" - return getattr(self.dbc, name) - - #---------------------------------------------- - - def dup(self, flags=0): - return DBShelfCursor(self.dbc.dup(flags)) - - def put(self, key, value, flags=0): - data = self.encode(value) - return self.dbc.put(key, data, flags) - - - def get(self, *args): - count = len(args) # a method overloading hack - method = getattr(self, 'get_%d' % count) - apply(method, args) - - def get_1(self, flags): - rec = self.dbc.get(flags) - return self._extract(rec) - - def get_2(self, key, flags): - rec = self.dbc.get(key, flags) - return self._extract(rec) - - def get_3(self, key, value, flags): - data = self.encode(value) - rec = self.dbc.get(key, flags) - return self._extract(rec) - - - def current(self, flags=0): return self.get_1(flags|db.DB_CURRENT) - def first(self, flags=0): return self.get_1(flags|db.DB_FIRST) - def last(self, flags=0): return self.get_1(flags|db.DB_LAST) - def next(self, flags=0): return self.get_1(flags|db.DB_NEXT) - def prev(self, flags=0): return self.get_1(flags|db.DB_PREV) - def consume(self, flags=0): return self.get_1(flags|db.DB_CONSUME) - def next_dup(self, flags=0): return self.get_1(flags|db.DB_NEXT_DUP) - def next_nodup(self, flags=0): return self.get_1(flags|db.DB_NEXT_NODUP) - def prev_nodup(self, flags=0): return self.get_1(flags|db.DB_PREV_NODUP) - - def get_both(self, key, value, flags=0): - data = self.encode(value) - rec = self.dbc.get_both(key, flags) - return self._extract(rec) - - def set(self, key, flags=0): - rec = self.dbc.set(key, flags) - return self._extract(rec) - - def set_range(self, key, flags=0): - rec = self.dbc.set_range(key, flags) - return self._extract(rec) - - def set_recno(self, recno, flags=0): - rec = self.dbc.set_recno(recno, flags) - return self._extract(rec) - - set_both = get_both - - def _extract(self, rec): - if rec is None: - return None - else: - key, data = rec - return key, self.decode(data) - - #---------------------------------------------- - # Methods allowed to pass-through to self.dbc - # - # close, count, delete, get_recno, join_item - - -#--------------------------------------------------------------------------- diff --git a/pisi/db/filesdb.py b/pisi/db/filesdb.py index 6d21fa7e..c68e7af8 100644 --- a/pisi/db/filesdb.py +++ b/pisi/db/filesdb.py @@ -9,81 +9,79 @@ # # Please read the COPYING file. # - import gettext __trans = gettext.translation('pisi', fallback=True) _ = __trans.ugettext +import os +import re +import shelve +import md5 + import pisi -import pisi.db.lockeddbshelve as shelve +import pisi.context as ctx +import pisi.db.lazydb as lazydb -class Error(pisi.Error): - pass +# FIXME: +# We could traverse through files.xml files of the packages to find the path and +# the package - a linear search - as some well known package managers do. But the current +# file conflict mechanism of pisi prevents this and needs a fast has_file function. +# So currently filesdb is the only db and we cant still get rid of rebuild-db :/ -class FilesDB(shelve.LockedDBShelf): +class FilesDB(lazydb.LazyDB): - def __init__(self): - shelve.LockedDBShelf.__init__(self, 'files') + def init(self): + self.filesdb = {} + self.__check_filesdb() + + def has_file(self, path): + return self.filesdb.has_key(md5.new(path).digest()) - def add_files(self, pkg_name, files, txn = None): - def proc(txn): - for x in files.list: - path = x.path - del x.path # don't store redundant attribute in db - self.put(path, (pkg_name, x), txn) - x.path = path # store it back in - self.txn_proc(proc, txn) + def get_file(self, path): + return self.filesdb[md5.new(path).digest()], path - def remove_files(self, files, txn = None): - def proc(txn): - for x in files.list: - if self.has_key(x.path): - self.delete(x.path, txn) - self.txn_proc(proc, txn) + def search_file(self, term): + installdb = pisi.db.installdb.InstallDB() + found = [] + for pkg in installdb.list_installed(): + files_xml = open(os.path.join(installdb.package_path(pkg), ctx.const.files_xml)).read() + paths = re.compile('(.*?%s.*?)' % term, re.I).findall(files_xml) + if paths: + found.append((pkg, paths)) + return found - def has_file(self, path, txn = None): - return self.has_key(str(path), txn) + def add_files(self, pkg, files): - def get_file(self, path, txn = None): - path = str(path) - def proc(txn): - if not self.has_key(path, txn): - return None - else: - (name, fileinfo) = self.get(path, txn) - fileinfo.path = path - return (name, fileinfo) - return self.txn_proc(proc, txn) + self.__check_filesdb() - def match_files(self, glob): - # NB: avoid using, this reads the entire db - import fnmatch - glob = str(glob) - infos = [] - for key in self.keys(): - if fnmatch.fnmatch(key, glob): + for f in files.list: + self.filesdb[md5.new(f.path).digest()] = pkg - # FIXME: Why should we assign path attribute manually - # in fileinfo? This is also done in get_file(), seems - # like a dirty workaround... - baris - name = self[key][0] - fileinfo = self[key][1] - fileinfo.path = key - infos.append((name, fileinfo)) - return infos + def remove_files(self, files): + for f in files: + if self.filesdb.has_key(md5.new(f.path).digest()): + del self.filesdb[md5.new(f.path).digest()] -filesdb = None + def destroy(self): + files_db = os.path.join(ctx.config.info_dir(), ctx.const.files_db) + if os.path.exists(files_db): + os.unlink(files_db) + + def close(self): + if isinstance(self.filesdb, shelve.DbfilenameShelf): + self.filesdb.close() -def init(): - global filesdb - if filesdb is not None: - return filesdb + def __check_filesdb(self): + if isinstance(self.filesdb, shelve.DbfilenameShelf): + return - filesdb = FilesDB() - return filesdb + files_db = os.path.join(ctx.config.info_dir(), ctx.const.files_db) -def finalize(): - global filesdb - if filesdb is not None: - filesdb.close() - filesdb = None + if not os.path.exists(files_db): + flag = "n" + elif os.access(files_db, os.W_OK): + flag = "w" + else: + flag = "r" + + self.filesdb = shelve.open(files_db, flag) diff --git a/pisi/db/installdb.py b/pisi/db/installdb.py index d55d3cb5..a4a1df64 100644 --- a/pisi/db/installdb.py +++ b/pisi/db/installdb.py @@ -13,25 +13,29 @@ # installation database # +import os +import re import gettext __trans = gettext.translation('pisi', fallback=True) _ = __trans.ugettext +import piksemel + # PiSi import pisi import pisi.context as ctx -import pisi.db.lockeddbshelve as shelve +import pisi.dependency import pisi.files import pisi.util +import pisi.db.lazydb as lazydb class InstallDBError(pisi.Error): pass class InstallInfo: - # some data is replicated from packagedb - # we store as an object, hey, we can waste O(1) space. - # this is also easier to modify in the future, without - # requiring database upgrades! wow! + + state_map = { 'i': _('installed'), 'ip':_('installed-pending') } + def __init__(self, state, version, release, build, distribution, time): self.state = state self.version = version @@ -48,9 +52,6 @@ class InstallInfo: time_str) return s - state_map = { 'i': _('installed'), 'ip':_('installed-pending'), - 'r':_('removed'), 'p': _('purged') } - def __str__(self): s = _("State: %s\nVersion: %s, Release: %s, Build: %s\n") % \ (InstallInfo.state_map[self.state], self.version, @@ -61,150 +62,147 @@ class InstallInfo: time_str) return s +class InstallDB(lazydb.LazyDB): -class InstallDB: + def init(self): + self.installed_db = self.__generate_installed_pkgs() + self.confing_pending_db = self.__generate_config_pending() + self.rev_deps_db = self.__generate_revdeps() - def __init__(self): - self.d = shelve.LockedDBShelf('install') - self.dp = shelve.LockedDBShelf('configpending') - self.files_dir = pisi.util.join_path(ctx.config.db_dir(), 'files') + def __generate_installed_pkgs(self): + return dict(map(lambda x:pisi.util.parse_package_name(x), os.listdir(ctx.config.packages_dir()))) - def close(self): - self.d.close() - self.dp.close() + def __generate_config_pending(self): + pending_info_path = os.path.join(ctx.config.info_dir(), ctx.const.config_pending) + if os.path.exists(pending_info_path): + return open(pending_info_path, "r").read().split() + return [] - def files_name(self, pkg, version, release): - pkg_dir = self.pkg_dir(pkg, version, release) - return pisi.util.join_path(pkg_dir, ctx.const.files_xml) + def __add_to_revdeps(self, package, revdeps): + metadata_xml = os.path.join(self.package_path(package), ctx.const.metadata_xml) + meta_doc = piksemel.parse(metadata_xml) + name = meta_doc.getTag("Package").getTagData('Name') + deps = meta_doc.getTag("Package").getTag('RuntimeDependencies') + if deps: + for dep in deps.tags("Dependency"): + revdeps.setdefault(dep.firstChild().data(), set()).add((name, dep.toString())) - def files(self, pkg): - pkg = str(pkg) - pkginfo = self.d[pkg] + def __generate_revdeps(self): + revdeps = {} + for package in self.list_installed(): + self.__add_to_revdeps(package, revdeps) + return revdeps + + def list_installed(self): + return self.installed_db.keys() + + def has_package(self, package): + return self.installed_db.has_key(package) + + def get_version(self, package): + metadata_xml = os.path.join(self.package_path(package), ctx.const.metadata_xml) + + meta_doc = piksemel.parse(metadata_xml) + history = meta_doc.getTag("Package").getTag("History") + build = meta_doc.getTag("Package").getTagData("Build") + version = history.getTag("Update").getTagData("Version") + release = history.getTag("Update").getAttribute("release") + + return version, release, build and int(build) + + def get_files(self, package): files = pisi.files.Files() - files.read(self.files_name(pkg,pkginfo.version,pkginfo.release)) + files_xml = os.path.join(self.package_path(package), ctx.const.files_xml) + files.read(files_xml) return files + def search_package(self, terms, lang=None): + resum = '.*?%s.*?' + redesc = '.*?%s.*?' + if not lang: + lang = pisi.pxml.autoxml.LocalText.get_lang() + found = [] + for name in self.list_installed(): + xml = open(os.path.join(self.package_path(name), ctx.const.metadata_xml)).read() + if terms == filter(lambda term: re.compile(term, re.I).search(name) or \ + re.compile(resum % (lang, term), re.I).search(xml) or \ + re.compile(redesc % (lang, term), re.I).search(xml), terms): + found.append(name) + return found + + def get_info(self, package): + files_xml = os.path.join(self.package_path(package), ctx.const.files_xml) + ctime = pisi.util.creation_time(files_xml) + pkg = self.get_package(package) + state = "i" + if pkg.name in self.list_pending(): + state = "ip" + + info = InstallInfo(state, + pkg.version, + pkg.release, + pkg.build, + pkg.distribution, + ctime) + return info + + def get_rev_deps(self, name): + + rev_deps = [] + + if self.rev_deps_db.has_key(name): + for pkg, dep in self.rev_deps_db[name]: + node = piksemel.parseString(dep) + dependency = pisi.dependency.Dependency() + dependency.package = node.firstChild().data() + if node.attributes(): + attr = node.attributes()[0] + dependency.__dict__[attr] = node.getAttribute(attr) + rev_deps.append((pkg, dependency)) + + return rev_deps + def pkg_dir(self, pkg, version, release): - return pisi.util.join_path(ctx.config.lib_dir(), 'package', - pkg + '-' + version + '-' + release) + return pisi.util.join_path(ctx.config.packages_dir(), pkg + '-' + version + '-' + release) - def is_recorded(self, pkg, txn = None): - pkg = str(pkg) - def proc(txn): - return self.d.has_key(pkg) - return self.d.txn_proc(proc, txn) + def get_package(self, package): + metadata = pisi.metadata.MetaData() + metadata_xml = os.path.join(self.package_path(package), ctx.const.metadata_xml) + metadata.read(metadata_xml) + return metadata.package - def is_installed(self, pkg, txn = None): - pkg = str(pkg) - def proc(txn): - if self.is_recorded(pkg, txn): - info = self.d.get(pkg, txn) - return info.state=='i' or info.state=='ip' - else: - return False - return self.d.txn_proc(proc, txn) + def mark_pending(self, package): + if package not in self.confing_pending_db: + self.confing_pending_db.append(package) + self.__write_config_pending() - def list_installed(self, txn = None): - def proc(txn): - l = [] - for (pkg, info) in self.d.items(txn): - if info.state=='i' or info.state=='ip': - l.append(pkg) - return l - return self.d.txn_proc(proc, txn) + def add_package(self, pkginfo): + self.installed_db[pkginfo.name] = "%s-%s" % (pkginfo.version, pkginfo.release) + self.__add_to_revdeps(pkginfo.name, self.rev_deps_db) + + def remove_package(self, package_name): + if self.installed_db.has_key(package_name): + del self.installed_db[package_name] + self.clear_pending(package_name) def list_pending(self): - # warning: reads the entire db - d = {} - for (pkg, x) in self.dp.items(): - pkginfo = self.d[pkg] - d[pkg] = pkginfo - return d + return self.confing_pending_db - def get_info(self, pkg): - pkg = str(pkg) - return self.d[pkg] + def clear_pending(self, package): + if package in self.confing_pending_db: + self.confing_pending_db.remove(package) + self.__write_config_pending() - def get_version(self, pkg): - pkg = str(pkg) - info = self.d[pkg] - return (info.version, info.release, info.build) + def __write_config_pending(self): + pending_info_file = os.path.join(ctx.config.info_dir(), ctx.const.config_pending) + pending = open(pending_info_file, "w") + for pkg in set(self.confing_pending_db): + pending.write("%s\n" % pkg) + pending.close() - def is_removed(self, pkg): - pkg = str(pkg) - if self.is_recorded(pkg): - info = self.d[pkg] - return info.state=='r' - else: - return False + def package_path(self, package): - def install(self, pkg, version, release, build, distro = "", - config_later = False, rebuild=False, txn = None): - """install package with specific version, release, build""" - pkg = str(pkg) - def proc(txn): - if self.is_installed(pkg, txn): - raise InstallDBError(_("Already installed")) - if config_later: - state = 'ip' - self.dp.put(pkg, True, txn) - else: - state = 'i' + if self.installed_db.has_key(package): + return os.path.join(ctx.config.packages_dir(), "%s-%s" % (package, self.installed_db[package])) - # FIXME: it might be more appropriate to pass date - # as an argument, or installation data afterwards - # to do this -- exa - if not rebuild: - import time - ctime = time.localtime() - else: - files_xml = self.files_name(pkg, version, release) - ctime = pisi.util.creation_time(files_xml) - - self.d.put(pkg, InstallInfo(state, version, release, build, distro, ctime), txn) - - self.d.txn_proc(proc,txn) - - def clear_pending(self, pkg, txn = None): - pkg = str(pkg) - def proc(txn): - info = self.d.get(pkg, txn) - if self.is_installed(pkg, txn): - assert info.state == 'ip' - info.state = 'i' - self.d.put(pkg, info, txn) - self.dp.delete(pkg, txn) - self.d.txn_proc(proc,txn) - - def remove(self, pkg, txn = None): - pkg = str(pkg) - def proc(txn): - info = self.d.get(pkg, txn) - info.state = 'r' - self.d.put(pkg, info, txn) - if self.dp.has_key(pkg): - self.dp.delete(pkg, txn) - self.d.txn_proc(proc, txn) - - def purge(self, pkg, txn = None): - pkg = str(pkg) - def proc(txn): - if self.d.has_key(pkg, txn): - self.d.delete(pkg, txn) - self.d.txn_proc(proc, txn) - -db = None - -def init(): - global db - if db is not None: - return db - - db = InstallDB() - return db - -def finalize(): - global db - if db is not None: - db.close() - db = None + raise Exception(_('Package %s is not installed') % package) diff --git a/pisi/db/itembyrepo.py b/pisi/db/itembyrepo.py new file mode 100644 index 00000000..abf581cb --- /dev/null +++ b/pisi/db/itembyrepo.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007, 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 gzip +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi.db + +class ItemByRepo: + def __init__(self, dbobj, compressed=False): + self.dbobj = dbobj + self.compressed = compressed + self.repodb = pisi.db.repodb.RepoDB() + + def has_repo(self, repo): + return self.dbobj.has_key(repo) + + def has_item(self, item, repo=None): + for r in self.item_repos(repo): + if self.dbobj.has_key(r) and self.dbobj[r].has_key(item): + return True + + return False + + def which_repo(self, item): + for r in self.repodb.list_repos(): + if self.dbobj.has_key(r) and self.dbobj[r].has_key(item): + return r + + raise Exception(_("Item not found")) + + def get_item_repo(self, item, repo=None): + for r in self.item_repos(repo): + if self.dbobj.has_key(r) and self.dbobj[r].has_key(item): + if self.compressed: + return gzip.zlib.decompress(self.dbobj[r][item]), r + else: + return self.dbobj[r][item], r + + raise Exception(_("Repo item not found")) + + def get_item(self, item, repo=None): + item, repo = self.get_item_repo(item, repo) + return item + + def get_item_keys(self, repo=None): + items = [] + for r in self.item_repos(repo): + if not self.has_repo(r): + raise Exception(_('Repository %s does not exist.') % repo) + + if self.dbobj.has_key(r): + items.extend(self.dbobj[r].keys()) + + return list(set(items)) + + def get_list_item(self, repo=None): + items = [] + for r in self.item_repos(repo): + if not self.has_repo(r): + raise Exception(_('Repository %s does not exist.') % repo) + + if self.dbobj.has_key(r): + items.extend(self.dbobj[r]) + + return list(set(items)) + + def get_items_iter(self, repo=None): + for r in self.item_repos(repo): + if not self.has_repo(r): + raise Exception(_('Repository %s does not exist.') % repo) + + if self.compressed: + for item in self.dbobj[r].keys(): + yield item, gzip.zlib.decompress(self.dbobj[r][item]) + else: + for item in self.dbobj[r].keys(): + yield item, self.dbobj[r][item] + + def item_repos(self, repo=None): + repos = self.repodb.list_repos() + if repo: + repos = [repo] + return repos diff --git a/pisi/db/itembyrepodb.py b/pisi/db/itembyrepodb.py deleted file mode 100644 index 7ac7bd3c..00000000 --- a/pisi/db/itembyrepodb.py +++ /dev/null @@ -1,214 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2005 - 2007, 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 gettext -__trans = gettext.translation('pisi', fallback=True) -_ = __trans.ugettext - -import pisi -import pisi.context as ctx -import pisi.db.lockeddbshelve as shelve - -installed, thirdparty, repos, all = range(1, 5) - -"""installed and thirdparty are special databases to keep track -of already installed stuff and third party stuff not in any real repository. -repos means search in repositories only, and all means search in -repositories and special databases (called tracking databases) -""" - -class Error(pisi.Error): - pass - -class NotfoundError(pisi.Error): - pass - -class ItemByRepoDB(object): - - def __init__(self, name): - self.d = shelve.LockedDBShelf(name) - #self.dbyrepo = shelve.LockedDBShelf(name + '-byrepo') - - def close(self): - self.d.close() - - def clear(self, txn = None): - self.d.clear(txn=txn) - - def txn_proc(self, proc, txn): - return self.d.txn_proc(proc, txn) - - def items(self): - return self.d.items() - - @staticmethod - def not_just_tracking(data): - keys = data.keys() - if len(keys)==1: - if 'trdparty' in keys or 'inst' in keys: - return False - elif len(keys)==2: - if 'trdparty' in keys and 'inst' in keys: - return False - return True - #below is a slower way - #for x in data.keys(): - # if x.startsWith('repo-'): - # return True - #return False - - def list_if(self, pred): - return [ k for k,data in self.d.items() if pred(k, data)] - - def list(self, repo = None): - if repo == None: - repo = repos - if repo not in [repos, all]: - return [ k for k,data in self.d.items() if data.has_key(self.repo_str(repo))] - else: - if repo == all: - return [ pkg for pkg in self.d.keys() ] - else: - return self.list_if( lambda k,data: ItemByRepoDB.not_just_tracking(data) ) - - # TODO: carry this to repodb, really :/ - def order(self, repo = None): - if repo == None: - repo = repos - assert repo in [all, repos] - order = [ 'repo-' + x for x in ctx.repodb.list() ] - if repo == all: - order += ['trdparty', 'inst'] - return order - -# def list_repo(self, repo): -# return self.dbyrepo[repo] - - def repo_str(self, repo): - if repo==thirdparty: - repo='trdparty' - elif repo==installed: - repo='inst' - else: - assert type(repo) == type("") - repo='repo-'+repo - return repo - - def str_repo(self, str): - if str.startswith('repo-'): - return str[5:] - elif str=='trdparty': - return thirdparty - elif str=='inst': - return installed - else: - raise Error(_('Invalid repository string')) - - def has_key(self, name, repo = None, txn = None): - name = str(name) - if repo == None: - repo = repos - haskey = self.d.has_key(name, txn) - if repo == all: - return haskey - elif repo == repos: - data = self.d.get(name, txn) - return haskey and ItemByRepoDB.not_just_tracking(data) - else: - repostr = self.repo_str(repo) - return haskey and self.d.get(name, txn).has_key(repostr) - - def get_item_repo(self, name, repo = None, txn = None): - name = str(name) - if repo == None: - repo = repos - def proc(txn): - if not self.d.has_key(name, txn=txn): - raise NotfoundError(_('Key %s not found') % name) - s = self.d.get(name, txn=txn) - if repo in [repos, all]: - for repostr in self.order(repo): - if s.has_key(repostr): - return (s[repostr], self.str_repo(repostr)) - else: - repostr = self.repo_str(repo) - if s.has_key(repostr): - return (s[repostr], repo) - raise NotfoundError(_('Key %s in repo %s not found') % (name, repo)) - #return None - - return self.d.txn_proc(proc, txn) - - def get_item(self, name, repo = None, txn = None): - if repo == None: - repo = repos - x = self.get_item_repo(name, repo, txn) - if x: - item, repo = x - # discard repo, not always needed - return item - else: - return None - - def which_repo(self, name, txn = None): - x = self.get_item_repo(name, txn=txn) - if x: - item, repo = x - return repo - else: - return None - - def add_item(self, name, obj, repo, txn = None): - assert not repo in [all, repos] - repostr = self.repo_str(repo) - def proc(txn): - if not self.d.has_key(name): - s = dict() - else: - s = self.d.get(name, txn) - s[ repostr ] = obj - self.d.put(name, s, txn) - self.d.txn_proc(proc, txn) - - def remove_item_repo(self, name, repo, txn = None): - assert not repo in [all, repos] - name = str(name) - def p(txn): - s = self.d.get(name, txn) - repostr = self.repo_str(repo) - if s.has_key(repostr): - del s[repostr] - if not len(s): - self.d.delete(name, txn) - else: - self.d.put(name, s, txn) - self.d.txn_proc(p, txn) - - def remove_item_only(self, name, txn = None): - def p(txn): - repo = self.which_repo(name, txn=txn) - self.remove_item_repo(name, repo, txn=txn) - self.d.txn_proc(p, txn) - - def remove_item(self, name, repo=None, txn=None): - if repo == None: - repo = repos - if not repo in [all, repos]: - self.remove_item_repo(name, repo,txn=txn) - else: - self.remove_item_only(name,txn=txn) - - def remove_repo(self, repo, txn = None): - def proc(txn): - for key in self.d.keys(): - self.remove_item_repo(key, repo, txn=txn) - self.d.txn_proc(proc, txn) diff --git a/pisi/db/lazydb.py b/pisi/db/lazydb.py new file mode 100644 index 00000000..326a9834 --- /dev/null +++ b/pisi/db/lazydb.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007, 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 time +import pisi.context as ctx + +class Singleton(object): + def __new__(type): + if not '_the_instance' in type.__dict__: + type._the_instance = object.__new__(type) + return type._the_instance + +class LazyDB(Singleton): + def __init__(self): + if not self.__dict__.has_key("initialized"): + self.initialized = False + + def is_initialized(self): + return self.initialized + + def __getattr__(self, attr): + if not self.initialized: + start = time.time() + self.init() + end = time.time() + ctx.ui.debug("%s initialized in %s." % (self.__class__.__name__, end - start)) + self.initialized = True + + if not self.__dict__.has_key(attr): + raise AttributeError, attr + + return self.__dict__[attr] diff --git a/pisi/db/lockeddbshelve.py b/pisi/db/lockeddbshelve.py deleted file mode 100644 index 83db0339..00000000 --- a/pisi/db/lockeddbshelve.py +++ /dev/null @@ -1,174 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2005 - 2007, 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 os -import fcntl -import types - -import bsddb3.db as db -import bsddb3.dbobj as dbobj -import pisi.db.dbshelve as shelve - -import gettext -__trans = gettext.translation('pisi', fallback=True) -_ = __trans.ugettext - -import pisi -import pisi.context as ctx -import pisi.util -import pisi.version - -class Error(pisi.Error): - pass - -# check database version -# if write is given it knows it has write access -# if force is given it updates the specified db version -def check_dbversion(versionfile, ver, write=False, update=False): - verfn = pisi.util.join_path(pisi.context.config.db_dir(), versionfile) - firsttime = False - if os.path.exists(verfn): - verfile = file(verfn, 'r') - ls = verfile.readlines() - currver = pisi.version.Version(ls[0]) - dbver = pisi.version.Version(ver) - if currver < dbver: - if not update: - raise Error(_('Database version for %s insufficient. Please run rebuild-db command.') % versionfile) - else: - pass # continue to update, then - elif currver > dbver: - raise Error(_('Database version for %s greater than PiSi version. You need a newer PiSi.') % versionfile) - elif not update: - return True # db version is OK - else: - firsttime = True - if write and (update or firsttime): - if os.access(pisi.context.config.db_dir(), os.W_OK): - verfile = file(verfn, 'w') - verfile.write(ver) - verfile.close() - else: - raise Error(_('Cannot attain write access to database environment')) - else: - raise Error(_('Database version %s not present.') % versionfile) - -def lock_dbenv(): - ctx.dbenv_lock = file(pisi.util.join_path(pisi.context.config.db_dir(), 'dbenv.lock'), 'w') - try: - fcntl.flock(ctx.dbenv_lock, fcntl.LOCK_EX | fcntl.LOCK_NB) - except IOError: - raise Error(_("Another instance of PiSi is running. Only one instance is allowed to modify the PiSi database at a time.")) - -# write: write access to database environment -# writeversion: would you like to be able -def init_dbenv(write=False, writeversion=False): - if os.access(pisi.context.config.db_dir(), os.R_OK): - # try to read version - check_dbversion('dbversion', pisi.__dbversion__, write=write, update=writeversion) - check_dbversion('filesdbversion', pisi.__filesdbversion__, write=write, update=writeversion) - else: - raise Error(_('Cannot attain read access to database environment')) - if write: - if os.access(pisi.context.config.db_dir(), os.W_OK): - lock_dbenv() - ctx.dbenv = dbobj.DBEnv() - flags = (db.DB_INIT_MPOOL | # cache - db.DB_INIT_TXN | # transaction subsystem - db.DB_INIT_LOG | # logging subsystem - db.DB_RECOVER | # run normal recovery - db.DB_CREATE) # allow db to create files - ctx.dbenv.set_cachesize(0, 4*1024*1024) - ctx.dbenv.open(pisi.context.config.db_dir(), flags) - ctx.dbenv.set_flags(db.DB_LOG_AUTOREMOVE, 1) # clear inactive logs automatically - else: - raise Error(_("Cannot attain write access to PiSi database. You have to be root for this operation.")) - else: - ctx.dbenv = None # read-only access to database - -class LockedDBShelf(shelve.DBShelf): - """A simple wrapper to implement locking for bsddb's dbshelf""" - - def __init__(self, dbname, mode=0644, - filetype=db.DB_BTREE, dbenv = None): - if dbenv == None: - dbenv = ctx.dbenv - shelve.DBShelf.__init__(self, dbenv) - filename = pisi.util.join_path(pisi.context.config.db_dir(), dbname + '.bdb') - if dbenv and os.access(os.path.dirname(filename), os.W_OK): - flags = 'w' - elif os.access(filename, os.R_OK): - flags = 'r' - else: - raise Error(_('Cannot attain read or write access to database %s') % dbname) - self.open(filename, dbname, filetype, flags, mode) - - def destroy(self): - os.unlink(self.filename) - - def __del__(self): - # superclass does something funky, we don't need that - pass - - def open(self, filename, dbname, filetype, flags=db.DB_CREATE, mode=0644): - self.filename = filename - self.closed = False - if type(flags) == type(''): - sflag = flags - if sflag == 'r': - flags = db.DB_RDONLY - elif sflag == 'rw': - flags = 0 - elif sflag == 'w': - flags = db.DB_CREATE - elif sflag == 'c': - flags = db.DB_CREATE - elif sflag == 'n': - flags = db.DB_TRUNCATE | db.DB_CREATE - else: - raise Error, _("Flags should be one of 'r', 'w', 'c' or 'n' or use the bsddb.db.DB_* flags") - self.flags = flags - if self.flags & db.DB_RDONLY == 0: - flags |= db.DB_AUTO_COMMIT # use txn subsystem in write mode - self.lock() - filename = os.path.realpath(filename) # we give absolute path due to dbenv - #print 'opening', filename, filetype, flags, mode - return self.db.open(filename, None, filetype, flags, mode) - - def lock(self): - self.lockfile = file(self.filename + '.lock', 'w') - try: - fcntl.flock(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB) - except IOError: - raise Error(_("Another instance of PiSi is running. Only one instance is allowed to modify the PiSi database at a time.")) - - def close(self): - if self.closed: - return - self.db.close() - if self.flags & db.DB_RDONLY == 0: - self.unlock() - self.closed = True - - def unlock(self): - self.lockfile.close() - os.unlink(self.filename + '.lock') - - @staticmethod - def encodekey(key): - '''utility method for dbs that must store unicodes in keys''' - if type(key)==types.UnicodeType: - return key.encode('utf-8') - elif type(key)==types.StringType: - return key - else: - raise Error('Key must be either string or unicode') diff --git a/pisi/db/packagedb.py b/pisi/db/packagedb.py index 135975d9..37cff6c0 100644 --- a/pisi/db/packagedb.py +++ b/pisi/db/packagedb.py @@ -17,182 +17,140 @@ we basically store everything in PackageInfo class yes, we are cheap """ +import re +import gzip import gettext __trans = gettext.translation('pisi', fallback=True) _ = __trans.ugettext -import pisi -import pisi.context as ctx -import pisi.db.itembyrepodb +import piksemel -class Error(pisi.Error): - pass +import pisi.db +import pisi.metadata +import pisi.dependency +import pisi.db.itembyrepo +import pisi.db.lazydb as lazydb -class NotfoundError(pisi.Error): - def __init__(self, pkg): - pisi.Error.__init__("Package %s not found" % pkg) - self.pkg = pkg +class PackageDB(lazydb.LazyDB): -class PackageDB(object): - """PackageDB class provides an interface to the package database - using shelf objects""" + def init(self): - def __init__(self): - self.d = pisi.db.itembyrepodb.ItemByRepoDB('package') - self.dr = pisi.db.itembyrepodb.ItemByRepoDB('revdep') - self.do = pisi.db.itembyrepodb.ItemByRepoDB('obsoleted') - self.drp = pisi.db.itembyrepodb.ItemByRepoDB('replaces') + self.__package_nodes = {} # Packages + self.__revdeps = {} # Reverse dependencies + self.__obsoletes = {} # Obsoletes + self.__replaces = {} # Replaces - def close(self): - self.d.close() - self.dr.close() - self.do.close() - self.drp.close() + repodb = pisi.db.repodb.RepoDB() - def destroy(self): - self.d.destroy() - self.dr.destroy() - self.do.destroy() - self.drp.destroy() + for repo in repodb.list_repos(): + doc = repodb.get_repo_doc(repo) + self.__package_nodes[repo] = self.__generate_packages(doc) + self.__revdeps[repo] = self.__generate_revdeps(doc) + self.__obsoletes[repo] = self.__generate_obsoletes(doc) + self.__replaces[repo] = self.__generate_replaces(doc) - def has_package(self, name, repo=None, txn = None): - return self.d.has_key(name, repo, txn=txn) + self.pdb = pisi.db.itembyrepo.ItemByRepo(self.__package_nodes, compressed=True) + self.rvdb = pisi.db.itembyrepo.ItemByRepo(self.__revdeps) + self.odb = pisi.db.itembyrepo.ItemByRepo(self.__obsoletes) + self.rpdb = pisi.db.itembyrepo.ItemByRepo(self.__replaces) - def get_package(self, name, repo=None, txn = None): - try: - return self.d.get_item(name, repo, txn=txn) - except pisi.db.itembyrepodb.NotfoundError: - raise Error(_('Package %s not found') % name) + def __generate_replaces(self, doc): + return [x.getTagData("Name") for x in doc.tags("Package") if x.getTagData("Replaces")] + + def __generate_obsoletes(self, doc): + distribution = doc.getTag("Distribution") + obsoletes = distribution and distribution.getTag("Obsoletes") - def get_package_repo(self, name, repo=None, txn = None): - return self.d.get_item_repo(name, repo, txn=txn) + if not obsoletes: + return [] - def which_repo(self, name, txn = None): - return self.d.which_repo(name, txn=txn) + return map(lambda x: x.firstChild().data(), obsoletes.tags("Package")) + + def __generate_packages(self, doc): + return dict(map(lambda x: (x.getTagData("Name"), gzip.zlib.compress(x.toString())), doc.tags("Package"))) + + def __generate_revdeps(self, doc): + revdeps = {} + for node in doc.tags("Package"): + name = node.getTagData('Name') + deps = node.getTag('RuntimeDependencies') + if deps: + for dep in deps.tags("Dependency"): + revdeps.setdefault(dep.firstChild().data(), set()).add((name, dep.toString())) + return revdeps + + def has_package(self, name, repo=None): + return self.pdb.has_item(name, repo) + + def get_package(self, name, repo=None): + pkg, repo = self.get_package_repo(name, repo) + return pkg + + def search_package(self, terms, lang=None, repo=None): + resum = '.*?%s.*?' + redesc = '.*?%s.*?' + if not lang: + lang = pisi.pxml.autoxml.LocalText.get_lang() + found = [] + for name, xml in self.pdb.get_items_iter(repo): + if terms == filter(lambda term: re.compile(term, re.I).search(name) or \ + re.compile(resum % (lang, term), re.I).search(xml) or \ + re.compile(redesc % (lang, term), re.I).search(xml), terms): + found.append(name) + return found + + def get_version(self, name, repo): + if not self.has_package(name, repo): + raise Exception(_('Package %s not found.') % name) + + pkg_doc = piksemel.parseString(self.pdb.get_item(name, repo)) + history = pkg_doc.getTag("History") + build = pkg_doc.getTagData("Build") + version = history.getTag("Update").getTagData("Version") + release = history.getTag("Update").getAttribute("release") + + return version, release, build and int(build) + + def get_package_repo(self, name, repo=None): + pkg, repo = self.pdb.get_item_repo(name, repo) + package = pisi.metadata.Package() + package.parse(pkg) + return package, repo + + def which_repo(self, name): + return self.pdb.which_repo(name) def get_obsoletes(self, repo=None): - obsoletes = [] - for r in self.do.list(repo): - obsoletes.extend(self.do.get_item(r, repo)) - - replaces = self.get_replaces(repo) - return set(str(o) for o in obsoletes) - set(replaces.keys()) + return self.odb.get_list_item(repo) + def get_rev_deps(self, name, repo=None): + try: + rvdb = self.rvdb.get_item(name, repo) + except Exception: #FIXME: what exception could we catch here, replace with that. + return [] + + rev_deps = [] + for pkg, dep in rvdb: + node = piksemel.parseString(dep) + dependency = pisi.dependency.Dependency() + dependency.package = node.firstChild().data() + if node.attributes(): + attr = node.attributes()[0] + dependency.__dict__[attr] = node.getAttribute(attr) + rev_deps.append((pkg, dependency)) + return rev_deps + # replacesdb holds the info about the replaced packages (ex. gaim -> pidgin) - def get_replaces(self, repo = None): + def get_replaces(self, repo=None): pairs = {} - for pkg_name in self.drp.list(repo): - replaces = self.drp.get_item(pkg_name, repo) + + for pkg_name in self.rpdb.get_list_item(): + replaces = self.get_package(pkg_name).replaces for r in replaces: if pisi.replace.installed_package_replaced(r): pairs[r.package] = pkg_name return pairs - - def get_rev_deps(self, name, repo = None, txn = None): - if self.dr.has_key(name, repo, txn=txn): - return self.dr.get_item(name, repo, txn=txn) - else: - return [] - def get_deps(self, name, repo = None, txn = None): - if self.d.has_key(name, repo, txn=txn): - pinfo = self.d.get_item(name, repo, txn=txn) - return pinfo.packageDependencies - else: - return [] - - def list_packages(self, repo=None): - return self.d.list(repo) - - def add_obsoletes(self, obsoletes, repo, txn = None): - def proc(txn): - self.do.add_item(repo, obsoletes, repo, txn) - ctx.txn_proc(proc, txn) - - def add_package(self, package_info, repo, txn = None): - name = str(package_info.name) - - def proc(txn): - self.d.add_item(name, package_info, repo, txn) - for dep in package_info.runtimeDependencies(): - dep_name = str(dep.package) - if self.dr.has_key(dep_name, repo, txn): - revdep = self.dr.get_item(dep_name, repo, txn) - revdep = filter(lambda (n,d):n!=name, revdep) - revdep.append( (name, dep) ) - self.dr.add_item(dep_name, revdep, repo, txn) - else: - self.dr.add_item(dep_name, [ (name, dep) ], repo, txn) - - if package_info.replaces: - self.drp.add_item(name, package_info.replaces, repo, txn) - - # add component - ctx.componentdb.add_package(package_info.partOf, package_info.name, repo, txn) - - ctx.txn_proc(proc, txn) - - def clear(self, txn = None): - self.d.clear() - self.dr.clear() - self.do.clear() - self.drp.clear() - - def remove_package(self, name, repo = None, txn = None): - name = str(name) - def proc(txn): - package_info = self.d.get_item(name, repo, txn=txn) - self.d.remove_item(name, repo, txn=txn) - for dep in package_info.runtimeDependencies(): - dep_name = str(dep.package) - if self.dr.has_key(dep_name, repo, txn): - revdep = self.dr.get_item(dep_name, repo, txn) - revdep = filter(lambda (n,d):n!=name, revdep) - if revdep: - self.dr.add_item(dep_name, revdep, repo, txn) - else: - # Bug 3558: removal of revdep list of a package from revdepdb - # should only be done by the list members (dep. packages), not - # the package itself. So if a package is removed, it is removed - # from packagedb but its revdepdb part may still exist, until - # all the list members are removed. - self.dr.remove_item(dep_name, repo, txn=txn) - - # remove from component - ctx.componentdb.remove_package(package_info.partOf, package_info.name, repo, txn) - - self.d.txn_proc(proc, txn) - - def remove_repo(self, repo, txn = None): - def proc(txn): - self.d.remove_repo(repo, txn=txn) - self.dr.remove_repo(repo, txn=txn) - self.do.remove_repo(repo, txn=txn) - self.drp.remove_repo(repo, txn=txn) - self.d.txn_proc(proc, txn) - -def remove_tracking_package(name, txn = None): - # remove the guy from the tracking databases - if pkgdb.has_package(name, pisi.db.itembyrepodb.installed, txn=txn): - pkgdb.remove_package(name, pisi.db.itembyrepodb.installed, txn=txn) - if pkgdb.has_package(name, pisi.db.itembyrepodb.thirdparty, txn=txn): - pkgdb.remove_package(name, pisi.db.itembyrepodb.thirdparty, txn=txn) - -pkgdb = None - -def init(): - global pkgdb - - if pkgdb is not None: - return pkgdb - - pkgdb = PackageDB() - return pkgdb - -def finalize(): - global pkgdb - - if pkgdb is not None: - pkgdb.close() - pkgdb = None + def list_packages(self, repo): + return self.pdb.get_item_keys(repo) diff --git a/pisi/db/repodb.py b/pisi/db/repodb.py index 2274e49c..eda29d35 100644 --- a/pisi/db/repodb.py +++ b/pisi/db/repodb.py @@ -10,115 +10,136 @@ # Please read the COPYING file. # -import gettext -__trans = gettext.translation('pisi', fallback=True) -_ = __trans.ugettext +import os + +import piksemel import pisi -import pisi.db.lockeddbshelve as shelve +import pisi.uri +import pisi.util +import pisi.index import pisi.context as ctx - -class Error(pisi.Error): - pass +import pisi.db.lazydb as lazydb class Repo: def __init__(self, indexuri): self.indexuri = indexuri -#class HttpRepo +medias = (cd, usb, remote, local) = range(4) -#class FtpRepo +class RepoOrder: -#class RemovableRepo + def __init__(self): + self.repos = self._get_repos() + def add(self, repo_name, repo_url, repo_type="remote"): + repo_doc = self._get_doc() -class RepoDB(object): - """RepoDB maps repo ids to repository information""" + try: + node = [x for x in repo_doc.tags("Repo")][-1] + repo_node = node.appendTag("Repo") + except IndexError: + repo_node = repo_doc.insertTag("Repo") + + name_node = repo_node.insertTag("Name") + name_node.insertData(repo_name) - def __init__(self, txn = None): - self.d = shelve.LockedDBShelf("repo") - def proc(txn): - if not self.d.has_key("order", txn): - self.d.put("order", [], txn) - self.d.txn_proc(proc, txn) + url_node = repo_node.insertTag("Url") + url_node.insertData(repo_url) - def close(self): - self.d.close() + media_node = repo_node.insertTag("Media") + media_node.insertData(repo_type) - def repo_name(self, ix): - l = self.list() - return l[ix] + self._update(repo_doc) + + def remove(self, repo_name): + repo_doc = self._get_doc() + + for r in repo_doc.tags("Repo"): + if r.getTagData("Name") == repo_name: + r.hide() + + self._update(repo_doc) + + def get_order(self): + order = [] + + #FIXME: get media order from pisi.conf + for m in ["cd", "usb", "remote", "local"]: + if self.repos.has_key(m): + order.extend(self.repos[m]) + + return order + + def _update(self, doc): + repos_file = os.path.join(ctx.config.info_dir(), ctx.const.repos) + open(repos_file, "w").write("%s\n" % doc.toPrettyString()) + self.repos = self._get_repos() + + def _get_doc(self): + repos_file = os.path.join(ctx.config.info_dir(), ctx.const.repos) + if not os.path.exists(repos_file): + return piksemel.newDocument("REPOS") + return piksemel.parse(repos_file) + + def _get_repos(self): + repo_doc = self._get_doc() + order = {} + + for r in repo_doc.tags("Repo"): + media = r.getTagData("Media") + name = r.getTagData("Name") + order.setdefault(media, []).append(name) + + return order + +class RepoDB(lazydb.LazyDB): + + def init(self): + self.repoorder = RepoOrder() def has_repo(self, name): - name = str(name) - return self.d.has_key("repo-" + name) + return name in self.list_repos() - def get_repo(self, name): - name = str(name) - return self.d["repo-" + name] + def get_repo_doc(self, repo_name): + repo = self.get_repo(repo_name) + index = os.path.basename(repo.indexuri.get_uri()) + index_path = pisi.util.join_path(ctx.config.index_dir(), repo_name, index) - def set_default_repo(self, name, txn = None): - name = str(name) - def proc(txn): - order = self.d.get("order", txn) - try: - index = order.index(name) - order[0], order[index] = order[index], order[0] - self.d.put("order", order, txn) - except ValueError: - raise Error(_('No repository named %s exists') % name) - self.d.txn_proc(proc, txn) + if index_path.endswith("bz2"): + index_path = index_path.split(".bz2")[0] - def add_repo(self, name, repo_info, txn = None, at = None): - """add repository with name and repo_info at a given optional position""" - name = str(name) - assert (isinstance(repo_info,Repo)) - def proc(txn): - if self.d.has_key("repo-" + name, txn): - raise Error(_('Repository %s already exists') % name) - self.d.put("repo-" + name, repo_info, txn) - order = self.d.get("order", txn) - if at == None: - order.append(name) - else: - if at<0 or at>len(order): - raise Error(_("Cannot add repository at position %s") % at) - order.insert(at, name) - self.d.put("order", order, txn) - self.d.txn_proc(proc, txn) + return piksemel.parse(index_path) + + def get_repo(self, repo): + urifile_path = pisi.util.join_path(ctx.config.index_dir(), repo, "uri") + uri = open(urifile_path, "r").read() + return Repo(pisi.uri.URI(uri)) + + def add_repo(self, name, repo_info, at = None): + repo_path = pisi.util.join_path(ctx.config.index_dir(), name) + os.makedirs(repo_path) + urifile_path = pisi.util.join_path(ctx.config.index_dir(), name, "uri") + uri = open(urifile_path, "w").write(repo_info.indexuri.get_uri()) + self.repoorder.add(name, repo_info.indexuri.get_uri()) - def list(self): - return self.d["order"] + def remove_repo(self, name): + pisi.util.clean_dir(os.path.join(ctx.config.index_dir(), name)) + self.repoorder.remove(name) - def clear(self): - self.d.clear() + def get_source_repos(self): + repos = [] + for r in self.list_repos(): + if self.get_repo_doc(r).getTag("SpecFile"): + repos.append(r) + return repos - def remove_repo(self, name, txn = None): - name = str(name) - def proc(txn): - self.d.delete("repo-" + name, txn) - l = self.d.get("order", txn) - l.remove(name) - self.d.put("order", l, txn) - ctx.packagedb.remove_repo(name, txn=txn) - ctx.sourcedb.remove_repo(name, txn=txn) - ctx.componentdb.remove_repo(name, txn=txn) - self.d.txn_proc(proc, txn) + def get_binary_repos(self): + repos = [] + for r in self.list_repos(): + if not self.get_repo_doc(r).getTag("SpecFile"): + repos.append(r) + return repos -db = None - -def init(): - global db - - if db is not None: - return db - - db = RepoDB() - return db - -def finalize(): - global db - - if db is not None: - db.close() - db = None + def list_repos(self): + return self.repoorder.get_order() diff --git a/pisi/db/sourcedb.py b/pisi/db/sourcedb.py index 4d67ed91..a9a58643 100644 --- a/pisi/db/sourcedb.py +++ b/pisi/db/sourcedb.py @@ -10,97 +10,75 @@ # Please read the COPYING file. # -""" -package source database -interface for update/query to local package repository -we basically store everything in sourceinfo class -yes, we are cheap -to handle multiple repositories, for sources, we -store a set of repositories in which the source appears. -the actual guy to take is determined from the repo order. -""" - +import re +import gzip import gettext __trans = gettext.translation('pisi', fallback=True) _ = __trans.ugettext -import pisi.context as ctx -import pisi.db.itembyrepodb +import piksemel -class NotfoundError(pisi.Error): - pass +import pisi +import pisi.specfile +import pisi.db.lazydb as lazydb -class SourceDB(object): +class SourceDB(lazydb.LazyDB): - def __init__(self): - self.d = pisi.db.itembyrepodb.ItemByRepoDB('source') - self.dpkgtosrc = pisi.db.itembyrepodb.ItemByRepoDB('pkgtosrc') + def init(self): - def close(self): - self.d.close() - self.dpkgtosrc.close() + self.__source_nodes = {} + self.__pkgstosrc = {} - def list(self): - return self.d.list() + repodb = pisi.db.repodb.RepoDB() - def has_spec(self, name, repo=None, txn=None): - return self.d.has_key(name, repo, txn) + for repo in repodb.list_repos(): + doc = repodb.get_repo_doc(repo) + self.__source_nodes[repo], self.__pkgstosrc[repo] = self.__generate_sources(doc) - def get_spec(self, name, repo=None, txn = None): - try: - return self.d.get_item(name, repo, txn) - except pisi.db.itembyrepodb.NotfoundError: - raise NotfoundError(_("Source package %s not found") % name) + self.sdb = pisi.db.itembyrepo.ItemByRepo(self.__source_nodes, compressed=True) + self.psdb = pisi.db.itembyrepo.ItemByRepo(self.__pkgstosrc) - def get_spec_repo(self, name, repo=None, txn = None): - try: - return self.d.get_item_repo(name, repo, txn) - except pisi.db.itembyrepodb.NotfoundError: - raise NotfoundError(_("Source package %s not found") % name) + def __generate_sources(self, doc): - def pkgtosrc(self, name, txn = None): - return self.dpkgtosrc.get_item(name, txn=txn) + sources = {} + pkgstosrc = {} - def add_spec(self, spec, repo, txn = None): - assert not spec.errors() - name = str(spec.source.name) - def proc(txn): - self.d.add_item(name, spec, repo, txn) - for pkg in spec.packages: - self.dpkgtosrc.add_item(pkg.name, name, repo, txn) - ctx.componentdb.add_spec(spec.source.partOf, spec.source.name, repo, txn) - self.d.txn_proc(proc, txn) + for spec in doc.tags("SpecFile"): + src_name = spec.getTag("Source").getTagData("Name") + sources[src_name] = gzip.zlib.compress(spec.toString()) + for package in spec.tags("Package"): + pkgstosrc[package.getTagData("Name")] = src_name + + return sources, pkgstosrc - def remove_spec(self, name, repo, txn = None): - name = str(name) - def proc(txn): - assert self.has_spec(name, txn=txn) - spec = self.d.get_item(name, repo, txn) - self.d.remove_item(name, txn=txn) - for pkg in spec.packages: - self.dpkgtosrc.remove_item_repo(pkg.name, repo, txn) - ctx.componentdb.remove_spec(spec.source.partOf, spec.source.name, repo, txn) + def list_sources(self, repo=None): + return self.sdb.get_item_keys(repo) - self.d.txn_proc(proc, txn) + def has_spec(self, name, repo=None): + return self.sdb.has_item(name, repo) - def remove_repo(self, repo, txn = None): - def proc(txn): - self.d.remove_repo(repo, txn=txn) - self.dpkgtosrc.remove_repo(repo, txn=txn) - self.d.txn_proc(proc, txn) + def get_spec(self, name, repo=None): + spec, repo = self.get_spec_repo(name, repo) + return spec -srcdb = None + def search_spec(self, terms, lang=None, repo=None): + resum = '.*?%s.*?' + redesc = '.*?%s.*?' + if not lang: + lang = pisi.pxml.autoxml.LocalText.get_lang() + found = [] + for name, xml in self.sdb.get_items_iter(repo): + if terms == filter(lambda term: re.compile(term, re.I).search(name) or \ + re.compile(resum % (lang, term), re.I).search(xml) or \ + re.compile(redesc % (lang, term), re.I).search(xml), terms): + found.append(name) + return found -def init(): - global srcdb - if srcdb is not None: - return srcdb + def get_spec_repo(self, name, repo=None): + src, repo = self.sdb.get_item_repo(name, repo) + spec = pisi.specfile.SpecFile() + spec.parse(src) + return spec, repo - srcdb = SourceDB() - return srcdb - -def finalize(): - global srcdb - if srcdb is not None: - srcdb.close() - srcdb = None + def pkgtosrc(self, name, repo=None): + return self.psdb.get_item(name, repo) diff --git a/pisi/dependency.py b/pisi/dependency.py index 804206f1..f4f0dfca 100644 --- a/pisi/dependency.py +++ b/pisi/dependency.py @@ -18,6 +18,7 @@ _ = __trans.ugettext import pisi.context as ctx import pisi.relation +import pisi.db """ Dependency relation """ class Dependency(pisi.relation.Relation): @@ -45,7 +46,7 @@ def dict_satisfies_dep(dict, depinfo): else: pkg = dict[pkg_name] (version, release) = (pkg.version, pkg.release) - return depinfo.satisfies_relation(pkg_name, version, release) + return depinfo.satisfies_relation(version, release) def installed_satisfies_dep(depinfo): """determine if a package in *repository* satisfies given @@ -55,13 +56,14 @@ dependency spec""" def repo_satisfies_dep(depinfo): """determine if a package in *repository* satisfies given dependency spec""" + packagedb = pisi.db.packagedb.PackageDB() pkg_name = depinfo.package - if not ctx.packagedb.has_package(pkg_name): + if not packagedb.has_package(pkg_name): return False else: - pkg = ctx.packagedb.get_package(pkg_name) + pkg = packagedb.get_package(pkg_name) (version, release) = (pkg.version, pkg.release) - return depinfo.satisfies_relation(pkg_name, version, release) + return depinfo.satisfies_relation(version, release) def satisfies_dependencies(pkg, deps, sat = installed_satisfies_dep): for dep in deps: @@ -72,13 +74,15 @@ def satisfies_dependencies(pkg, deps, sat = installed_satisfies_dep): return True def satisfies_runtime_deps(pkg): - deps = ctx.packagedb.get_package(pkg).runtimeDependencies() + packagedb = pisi.db.packagedb.PackageDB() + deps = packagedb.get_package(pkg).runtimeDependencies() return satisfies_dependencies(pkg, deps) def installable(pkg): """calculate if pkg name is installable currently which means it has to satisfy both install and runtime dependencies""" - if not ctx.packagedb.has_package(pkg): + packagedb = pisi.db.packagedb.PackageDB() + if not packagedb.has_package(pkg): ctx.ui.info(_("Package %s is not present in the package database") % pkg); return False elif satisfies_runtime_deps(pkg): diff --git a/pisi/files.py b/pisi/files.py index 7af885ca..67560e3a 100644 --- a/pisi/files.py +++ b/pisi/files.py @@ -15,8 +15,6 @@ during the build process of a package and used in installation.''' import pisi.pxml.autoxml as autoxml -import pisi.db.lockeddbshelve as shelve - class FileInfo: """File holds the information for a File node/tag in files.xml""" diff --git a/pisi/index.py b/pisi/index.py index 763331f0..b94bc2ed 100644 --- a/pisi/index.py +++ b/pisi/index.py @@ -49,7 +49,7 @@ class Index(xmlfile.XmlFile): def read_uri(self, uri, tmpdir, force = False): self.read(uri, tmpDir=tmpdir, sha1sum=not force, - compress=pisi.file.File.auto, sign=pisi.file.File.detached, copylocal = True) + compress=pisi.file.File.auto, sign=pisi.file.File.detached, copylocal = True, nodecode = True) # read index for a given repo, force means download even if remote not updated def read_uri_of_repo(self, uri, repo = None, force = False): @@ -109,32 +109,6 @@ class Index(xmlfile.XmlFile): ctx.ui.info(_('Adding %s to package index') % pkg) self.add_package(pkg, deltas, repo_uri) - def update_db(self, repo, txn = None): - # FIXME: updating db takes too much time. So a notify mechanism is used to inform the status - # of the operation. - - self.progress = ctx.ui.Progress(len(self.packages)+len(self.specs)) - self.processed = 0 - - def update_progress(): - self.processed += 1 - ctx.ui.display_progress(operation = "updatingrepo", - percent = self.progress.update(self.processed), - info = _("Updating package database of %s") % repo) - - ctx.componentdb.remove_repo(repo, txn=txn) - for comp in self.components: - ctx.componentdb.update_component(comp, repo, txn) - ctx.packagedb.remove_repo(repo, txn=txn) - ctx.packagedb.add_obsoletes(self.distribution.obsoletes, repo, txn=txn) - for pkg in self.packages: - ctx.packagedb.add_package(pkg, repo, txn=txn) - update_progress() - ctx.sourcedb.remove_repo(repo, txn=txn) - for sf in self.specs: - ctx.sourcedb.add_spec(sf, repo, txn=txn) - update_progress() - def add_package(self, path, deltas, repo_uri): package = pisi.package.Package(path, 'r') md = package.get_metadata() @@ -187,10 +161,10 @@ class Index(xmlfile.XmlFile): #ctx.ui.error(str(Error(*errs))) def add_spec(self, path, repo_uri): - import pisi.build + import pisi.operations.build ctx.ui.info(_('Adding %s to source index') % path) #TODO: may use try/except to handle this - builder = pisi.build.Builder(path) + builder = pisi.operations.build.Builder(path) #ctx.ui.error(_('SpecFile in %s is corrupt, skipping...') % path) #ctx.ui.error(str(Error(*errs))) builder.fetch_component() diff --git a/pisi/metadata.py b/pisi/metadata.py index 55e2b8f5..18c4861c 100644 --- a/pisi/metadata.py +++ b/pisi/metadata.py @@ -42,7 +42,7 @@ class Source: t_Homepage = [autoxml.String, autoxml.optional] t_Packager = [specfile.Packager, autoxml.mandatory] -class Package(specfile.Package): +class Package(specfile.Package, xmlfile.XmlFile): __metaclass__ = autoxml.autoxml t_Build = [ autoxml.Integer, autoxml.optional] diff --git a/pisi/operations.py b/pisi/operations.py deleted file mode 100644 index 1dbbf1cc..00000000 --- a/pisi/operations.py +++ /dev/null @@ -1,819 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2005 - 2007, 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 os -import sys - -import gettext -__trans = gettext.translation('pisi', fallback=True) -_ = __trans.ugettext - -import pisi -import pisi.package -import pisi.context as ctx -import pisi.util as util -import pisi.dependency as dependency -import pisi.conflict -import pisi.pgraph as pgraph -import pisi.cli -import pisi.atomicoperations as atomicoperations -import pisi.ui as ui - -class Error(pisi.Error): - pass - -def upgrade_pisi(): - """forces to reload pisi modules and runs rebuild-db if needed.""" - import pisi - import pisi.context as ctx - import pisi.version - - old_filesdbversion = pisi.__filesdbversion__ - old_dbversion = pisi.__dbversion__ - # we have to keep old_ui or by calling raw init, we lose it - old_ui = ctx.ui - - def rebuild_db(): - """rebuild_db is necessary if database structures has changed.""" - if pisi.version.Version(pisi.__filesdbversion__) > pisi.version.Version(old_filesdbversion) or \ - pisi.version.Version(pisi.__dbversion__) > pisi.version.Version(old_dbversion): - - pisi.api.init(database=False, ui=old_ui) - #FIXME: we can not use _( ) here or NoneType object is not callable error is seen from package-manager - ctx.ui.info("* PiSi database version has changed. Rebuilding database...") - pisi.api.rebuild_db(files=True) - ctx.ui.info("* Database rebuild operation is completed succesfully.") - pisi.api.finalize() - - def reload_pisi(): - for module in sys.modules.keys(): - if not module.startswith("pisi.ui") and not module.startswith("pisi.cli") and module.startswith("pisi."): - """removal from sys.modules forces reload via import""" - del(sys.modules[module]) - - pisi.api.finalize() - reload_pisi() - reload(pisi) - rebuild_db() - pisi.api.init(ui=old_ui) - -# high level operations - -def install(packages, reinstall = False, ignore_file_conflicts=False): - """install a list of packages (either files/urls, or names)""" - - if not ctx.get_option('ignore_file_conflicts'): - ctx.set_option('ignore_file_conflicts', ignore_file_conflicts) - - # determine if this is a list of files/urls or names - if packages and packages[0].endswith(ctx.const.package_suffix): # they all have to! - return install_pkg_files(packages) - else: - return install_pkg_names(packages, reinstall) - -def reorder_base_packages(order): - """system.base packages must be first in order""" - systembase = ctx.componentdb.get_union_comp('system.base').packages - - systembase_order = [] - nonbase_order = [] - for pkg in order: - if pkg in systembase: - systembase_order.append(pkg) - else: - nonbase_order.append(pkg) - - return systembase_order + nonbase_order - -def install_pkg_files(package_URIs): - """install a number of pisi package files""" - - ctx.ui.debug('A = %s' % str(package_URIs)) - - for x in package_URIs: - if not x.endswith(ctx.const.package_suffix): - raise Error(_('Mixing file names and package names not supported yet.')) - - if ctx.config.get_option('ignore_dependency'): - # simple code path then - for x in package_URIs: - atomicoperations.install_single_file(x) - return # short circuit - - # read the package information into memory first - # regardless of which distribution they come from - d_t = {} - dfn = {} - for x in package_URIs: - package = pisi.package.Package(x) - package.read() - name = str(package.metadata.package.name) - d_t[name] = package.metadata.package - dfn[name] = x - - def satisfiesDep(dep): - # is dependency satisfied among available packages - # or packages to be installed? - return dependency.installed_satisfies_dep(dep) \ - or dependency.dict_satisfies_dep(d_t, dep) - - # for this case, we have to determine the dependencies - # that aren't already satisfied and try to install them - # from the repository - dep_unsatis = [] - for name in d_t.keys(): - pkg = d_t[name] - deps = pkg.runtimeDependencies() - for dep in deps: - if not satisfiesDep(dep): - dep_unsatis.append(dep) - - # now determine if these unsatisfied dependencies could - # be satisfied by installing packages from the repo - - # if so, then invoke install_pkg_names - extra_packages = [x.package for x in dep_unsatis] - if extra_packages: - ctx.ui.info(_("""The following packages will be installed -in the respective order to satisfy extra dependencies: -""") + util.strlist(extra_packages)) - if not ctx.ui.confirm(_('Do you want to continue?')): - raise Error(_('External dependencies not satisfied')) - install_pkg_names(extra_packages) - - class PackageDB: - def get_package(self, key, repo = None): - return d_t[str(key)] - - packagedb = PackageDB() - - A = d_t.keys() - - if len(A)==0: - ctx.ui.info(_('No packages to install.')) - return - - # try to construct a pisi graph of packages to - # install / reinstall - - G_f = pgraph.PGraph(packagedb) # construct G_f - - # find the "install closure" graph of G_f by package - # set A using packagedb - for x in A: - G_f.add_package(x) - B = A - while len(B) > 0: - Bp = set() - for x in B: - pkg = packagedb.get_package(x) - for dep in pkg.runtimeDependencies(): - if dependency.dict_satisfies_dep(d_t, dep): - if not dep.package in G_f.vertices(): - Bp.add(str(dep.package)) - G_f.add_dep(x, dep) - B = Bp - if ctx.config.get_option('debug'): - G_f.write_graphviz(sys.stdout) - order = G_f.topological_sort() - if not ctx.get_option('ignore_package_conflicts'): - conflicts = check_conflicts(order, packagedb) - if conflicts: - remove_conflicting_packages(conflicts) - order.reverse() - ctx.ui.info(_('Installation order: ') + util.strlist(order) ) - - if ctx.get_option('dry_run'): - return - - ctx.ui.notify(ui.packagestogo, order = order) - - for x in order: - atomicoperations.install_single_file(dfn[x]) - - pisi_installed = ctx.installdb.is_installed('pisi') - - if 'pisi' in order and pisi_installed: - upgrade_pisi() - -# FIXME: this should be done in atomicoperations automatically. -def remove_replaced_packages(order, replaces): - - replaced = [] - inorder = set(order).intersection(replaces.values()) - - if inorder: - for pkg in replaces.keys(): - if replaces[pkg] in inorder: - replaced.append(pkg) - - if replaced: - if remove(replaced, ignore_dep=True, ignore_safety=True): - raise Error(_("Replaced package remains")) - -def remove_conflicting_packages(conflicts): - if remove(conflicts, ignore_dep=True, ignore_safety=True): - raise Error(_("Conflicts remain")) - -def remove_obsoleted_packages(): - obsoletes = filter(ctx.installdb.is_installed, ctx.packagedb.get_obsoletes()) - if obsoletes: - if remove(obsoletes, ignore_dep=True, ignore_safety=True): - raise Error(_("Obsoleted packages remaining")) - -def check_conflicts(order, packagedb): - """check if upgrading to the latest versions will cause havoc - done in a simple minded way without regard for dependencies of - conflicts, etc.""" - - (C, D, pkg_conflicts) = pisi.conflict.calculate_conflicts(order, packagedb) - - if D: - raise Error(_("Selected packages [%s] are in conflict with each other.") % - util.strlist(list(D))) - - if pkg_conflicts: - conflicts = "" - for pkg in pkg_conflicts.keys(): - conflicts += _("[%s conflicts with: %s]\n") % (pkg, util.strlist(pkg_conflicts[pkg])) - - ctx.ui.info(_("The following packages have conflicts:\n%s") % - conflicts) - - if not ctx.ui.confirm(_('Remove the following conflicting packages?')): - raise Error(_("Conflicts remain")) - - return list(C) - -def is_upgradable(name, ignore_build = False): - if not ctx.installdb.is_installed(name): - return False - (version, release, build) = ctx.installdb.get_version(name) - try: - pkg = ctx.packagedb.get_package(name) - except KeyboardInterrupt: - raise - except Exception, e: #FIXME: what exception could we catch here, replace with that. - return False - - if ignore_build or (not build) or (not pkg.build): - return pisi.version.Version(release) < pisi.version.Version(pkg.release) - else: - return build < pkg.build - -def upgrade_base(A = set(), ignore_package_conflicts = False): - ignore_build = ctx.get_option('ignore_build_no') - if not ctx.get_option('ignore_safety'): - if ctx.componentdb.has_component('system.base'): - systembase = set(ctx.componentdb.get_union_comp('system.base').packages) - extra_installs = filter(lambda x: not ctx.installdb.is_installed(x), systembase - set(A)) - if extra_installs: - ctx.ui.warning(_('Safety switch: Following packages in system.base will be installed: ') + - util.strlist(extra_installs)) - G_f, install_order = plan_install_pkg_names(extra_installs, ignore_package_conflicts) - extra_upgrades = filter(lambda x: is_upgradable(x, ignore_build), systembase - set(install_order)) - upgrade_order = [] - if extra_upgrades: - ctx.ui.warning(_('Safety switch: Following packages in system.base will be upgraded: ') + - util.strlist(extra_upgrades)) - G_f, upgrade_order = plan_upgrade(extra_upgrades) - # return packages that must be added to any installation - return set(install_order + upgrade_order) - else: - ctx.ui.warning(_('Safety switch: the component system.base cannot be found')) - return set() - -def install_pkg_names(A, reinstall = False): - """This is the real thing. It installs packages from - the repository, trying to perform a minimum number of - installs""" - - A = [str(x) for x in A] #FIXME: why do we still get unicode input here? :/ -- exa - # A was a list, remove duplicates - A_0 = A = set(A) - - # filter packages that are already installed - if not reinstall: - Ap = set(filter(lambda x: not ctx.installdb.is_installed(x), A)) - d = A - Ap - if len(d) > 0: - ctx.ui.warning(_("The following package(s) are already installed and are not going to be installed again:\n") + - util.strlist(d)) - A = Ap - - if len(A)==0: - ctx.ui.info(_('No packages to install.')) - return - - A |= upgrade_base(A) - - if not ctx.config.get_option('ignore_dependency'): - G_f, order = plan_install_pkg_names(A) - else: - G_f = None - order = list(A) - - # Bug 4211 - if ctx.componentdb.has_component('system.base'): - order = reorder_base_packages(order) - - if len(order) > 1: - ctx.ui.info(_("Following packages will be installed in the respective " - "order to satisfy dependencies:\n") + util.strlist(order)) - - total_size, cached_size = calculate_download_sizes(order) - total_size, symbol = util.human_readable_size(total_size) - ctx.ui.info(_('Total size of package(s): %.2f %s') % (total_size, symbol)) - - if ctx.get_option('dry_run'): - return - - if set(order) - A_0: - if not ctx.ui.confirm(_('There are extra packages due to dependencies. Do you want to continue?')): - return False - - ctx.ui.notify(ui.packagestogo, order = order) - - pisi_installed = ctx.installdb.is_installed('pisi') - - for x in order: - atomicoperations.install_single_name(x, True) # allow reinstalls here - - if 'pisi' in order and pisi_installed: - upgrade_pisi() - -def plan_install_pkg_names(A, ignore_package_conflicts = False): - # try to construct a pisi graph of packages to - # install / reinstall - - G_f = pgraph.PGraph(ctx.packagedb) # construct G_f - - # find the "install closure" graph of G_f by package - # set A using packagedb - for x in A: - G_f.add_package(x) - B = A - - while len(B) > 0: - Bp = set() - for x in B: - pkg = ctx.packagedb.get_package(x) - for dep in pkg.runtimeDependencies(): - ctx.ui.debug('checking %s' % str(dep)) - # we don't deal with already *satisfied* dependencies - if not dependency.installed_satisfies_dep(dep): - if not dep.package in G_f.vertices(): - Bp.add(str(dep.package)) - G_f.add_dep(x, dep) - B = Bp - if ctx.config.get_option('debug'): - G_f.write_graphviz(sys.stdout) - order = G_f.topological_sort() - order.reverse() - if not ctx.get_option('ignore_package_conflicts') and not ignore_package_conflicts: - conflicts = check_conflicts(order, ctx.packagedb) - if conflicts: - remove_conflicting_packages(conflicts) - return G_f, order - -def upgrade(A): - upgrade_pkg_names(A) - -def upgrade_pkg_names(A = []): - """Re-installs packages from the repository, trying to perform - a minimum or maximum number of upgrades according to options.""" - - ignore_build = ctx.get_option('ignore_build_no') - security_only = ctx.get_option('security_only') - - replaced = [] - replaces = ctx.packagedb.get_replaces() - - if not A: - # if A is empty, then upgrade all packages - A = ctx.installdb.list_installed() - - A_0 = A = set(A) - - Ap = [] - for x in A: - if x.endswith(ctx.const.package_suffix): - ctx.ui.debug(_("Warning: package *name* ends with '.pisi'")) - - # Handling of replacement packages - if x in replaces.values(): - Ap.append(x) - continue - - if x in replaces.keys(): - Ap.append(replaces[x]) - continue - - if not ctx.installdb.is_installed(x): - ctx.ui.info(_('Package %s is not installed.') % x, True) - continue - (version, release, build) = ctx.installdb.get_version(x) - if ctx.packagedb.has_package(x): - pkg = ctx.packagedb.get_package(x) - else: - ctx.ui.info(_('Package %s is not available in repositories.') % x, True) - continue - - if security_only: - updates = [i for i in pkg.history if pisi.version.Version(i.release) > pisi.version.Version(release)] - if not pisi.util.any(lambda i:i.type == 'security', updates): - continue - - if ignore_build or (not build) or (not pkg.build): - if pisi.version.Version(release) < pisi.version.Version(pkg.release): - Ap.append(x) - else: - ctx.ui.info(_('Package %s is already at the latest release %s.') - % (pkg.name, pkg.release), True) - else: - if build < pkg.build: - Ap.append(x) - else: - ctx.ui.info(_('Package %s is already at the latest build %s.') - % (pkg.name, pkg.build), True) - - - A = set(Ap) - - if len(A)==0: - ctx.ui.info(_('No packages to upgrade.')) - return True - - A |= upgrade_base(A) - - ctx.ui.debug('A = %s' % str(A)) - - if not ctx.config.get_option('ignore_dependency'): - G_f, order = plan_upgrade(A) - else: - G_f = None - order = list(A) - - # Bug 4211 - if ctx.componentdb.has_component('system.base'): - order = reorder_base_packages(order) - - if not ctx.get_option('ignore_package_conflicts'): - conflicts = check_conflicts(order, ctx.packagedb) - - ctx.ui.info(_('The following packages will be upgraded: ') + - util.strlist(order)) - - total_size, cached_size = calculate_download_sizes(order) - total_size, symbol = util.human_readable_size(total_size) - ctx.ui.info(_('Total size of package(s): %.2f %s') % (total_size, symbol)) - - if ctx.get_option('dry_run'): - return - - if set(order) - A_0 - set(replaces.values()): - if not ctx.ui.confirm(_('There are extra packages due to dependencies. Do you want to continue?')): - return False - - ctx.ui.notify(ui.packagestogo, order = order) - - paths = [] - for x in order: - ctx.ui.info(util.colorize(_("Downloading %d / %d") % (order.index(x)+1, len(order)), "yellow")) - install_op = atomicoperations.Install.from_name(x) - paths.append(install_op.package_fname) - - # fetch to be upgraded packages but do not install them. - if ctx.get_option('fetch_only'): - return - - if not ctx.get_option('ignore_package_conflicts'): - if conflicts: - remove_conflicting_packages(conflicts) - - if replaces: - remove_replaced_packages(order, replaces) - - remove_obsoleted_packages() - - for path in paths: - ctx.ui.info(util.colorize(_("Installing %d / %d") % (paths.index(path)+1, len(paths)), "yellow")) - install_op = atomicoperations.Install(path, ignore_file_conflicts = True) - install_op.install(True) - - if 'pisi' in order: - upgrade_pisi() - -def plan_upgrade(A): - # try to construct a pisi graph of packages to - # install / reinstall - - packagedb = ctx.packagedb - - G_f = pgraph.PGraph(packagedb) # construct G_f - - # find the "install closure" graph of G_f by package - # set A using packagedb - for x in A: - G_f.add_package(x) - B = A - - # TODO: conflicts - - while len(B) > 0: - Bp = set() - for x in B: - pkg = packagedb.get_package(x) - for dep in pkg.runtimeDependencies(): - # add packages that can be upgraded - if ctx.installdb.is_installed(dep.package) and dependency.installed_satisfies_dep(dep): - continue - - if dependency.repo_satisfies_dep(dep): - if not dep.package in G_f.vertices(): - Bp.add(str(dep.package)) - G_f.add_dep(x, dep) - else: - ctx.ui.error(_('Dependency %s of %s cannot be satisfied') % (dep, x)) - raise Error(_("Upgrade is not possible.")) - - B = Bp - # now, search reverse dependencies to see if anything - # should be upgraded - B = A - while len(B) > 0: - Bp = set() - for x in B: - pkg = packagedb.get_package(x) - rev_deps = packagedb.get_rev_deps(x) - for (rev_dep, depinfo) in rev_deps: - # add only installed but unsatisfied reverse dependencies - if ctx.installdb.is_installed(rev_dep) and \ - (not dependency.installed_satisfies_dep(depinfo)): - if not dependency.repo_satisfies_dep(depinfo): - raise Error(_('Reverse dependency %s of %s cannot be satisfied') % (rev_dep, x)) - if not rev_dep in G_f.vertices(): - Bp.add(rev_dep) - G_f.add_plain_dep(rev_dep, x) - B = Bp - - if ctx.config.get_option('debug'): - G_f.write_graphviz(sys.stdout) - order = G_f.topological_sort() - order.reverse() - return G_f, order - -def remove(A, ignore_dep = False, ignore_safety = False): - """remove set A of packages from system (A is a list of package names)""" - - A = [str(x) for x in A] - - # filter packages that are not installed - A_0 = A = set(A) - - if not ctx.get_option('ignore_safety') and not ignore_safety: - if ctx.componentdb.has_component('system.base'): - systembase = set(ctx.componentdb.get_union_comp('system.base').packages) - refused = A.intersection(systembase) - if refused: - ctx.ui.warning(_('Safety switch: cannot remove the following packages in system.base: ') + - util.strlist(refused)) - A = A - systembase - else: - ctx.ui.warning(_('Safety switch: the component system.base cannot be found')) - - Ap = [] - for x in A: - if ctx.installdb.is_installed(x): - Ap.append(x) - else: - ctx.ui.info(_('Package %s does not exist. Cannot remove.') % x) - A = set(Ap) - - if len(A)==0: - ctx.ui.info(_('No packages to remove.')) - return False - - if not ctx.config.get_option('ignore_dependency') and not ignore_dep: - G_f, order = plan_remove(A) - else: - G_f = None - order = A - - ctx.ui.info(_("""The following minimal list of packages will be removed -in the respective order to satisfy dependencies: -""") + util.strlist(order)) - if len(order) > len(A_0): - if not ctx.ui.confirm(_('Do you want to continue?')): - ctx.ui.warning(_('Package removal declined')) - return False - - if ctx.get_option('dry_run'): - return - - ctx.ui.notify(ui.packagestogo, order = order) - - for x in order: - if ctx.installdb.is_installed(x): - atomicoperations.remove_single(x) - else: - ctx.ui.info(_('Package %s is not installed. Cannot remove.') % x) - -def plan_remove(A): - # try to construct a pisi graph of packages to - # install / reinstall - - G_f = pgraph.PGraph(ctx.packagedb, pisi.db.itembyrepodb.installed) # construct G_f - - # find the (install closure) graph of G_f by package - # set A using packagedb - for x in A: - G_f.add_package(x) - B = A - while len(B) > 0: - Bp = set() - for x in B: - rev_deps = ctx.packagedb.get_rev_deps(x, pisi.db.itembyrepodb.installed) - for (rev_dep, depinfo) in rev_deps: - # we don't deal with uninstalled rev deps - # and unsatisfied dependencies (this is important, too) - if ctx.packagedb.has_package(rev_dep, pisi.db.itembyrepodb.installed) and \ - dependency.installed_satisfies_dep(depinfo): - if not rev_dep in G_f.vertices(): - Bp.add(rev_dep) - G_f.add_plain_dep(rev_dep, x) - B = Bp - if ctx.config.get_option('debug'): - G_f.write_graphviz(sys.stdout) - order = G_f.topological_sort() - return G_f, order - -def expand_src_components(A): - Ap = set() - for x in A: - if ctx.componentdb.has_component(x): - Ap = Ap.union(ctx.componentdb.get_union_comp(x).sources) - else: - Ap.add(x) - return Ap - -def emerge(A): - - # A was a list, remove duplicates and expand components - A = [str(x) for x in A] - A_0 = A = expand_src_components(set(A)) - ctx.ui.debug('A = %s' % str(A)) - - if len(A)==0: - ctx.ui.info(_('No packages to emerge.')) - return - - #A |= upgrade_base(A) - - # FIXME: Errr... order_build changes type conditionally and this - # is not good. - baris - if not ctx.config.get_option('ignore_dependency'): - G_f, order_inst, order_build = plan_emerge(A) - else: - G_f = None - order_inst = [] - order_build = A - - if order_inst: - ctx.ui.info(_("""The following minimal list of packages will be installed -from repository in the respective order to satisfy dependencies: -""") + util.strlist(order_inst)) - ctx.ui.info(_("""The following minimal list of packages will be built and -installed in the respective order to satisfy dependencies: -""") + util.strlist(order_build)) - - if ctx.get_option('dry_run'): - return - - if len(order_inst) + len(order_build) > len(A_0): - if not ctx.ui.confirm(_('There are extra packages due to dependencies. Do you want to continue?')): - return False - - ctx.ui.notify(ui.packagestogo, order = order_inst) - - pisi_installed = ctx.installdb.is_installed('pisi') - - for x in order_inst: - atomicoperations.install_single_name(x) - - #ctx.ui.notify(ui.packagestogo, order = order_build) - - for x in order_build: - package_names = atomicoperations.build(x)[0] - install_pkg_files(package_names) # handle inter-package deps here - - # FIXME: take a look at the fixme above :(, we have to be sure - # that order_build is a known type... - U = set(order_build) - U.update(order_inst) - if 'pisi' in order_build or (('pisi' in U) and pisi_installed): - upgrade_pisi() - -def plan_emerge(A): - - # try to construct a pisi graph of packages to - # install / reinstall - - G_f = pisi.graph.Digraph() - - def get_spec(name): - if ctx.sourcedb.has_spec(name): - return ctx.sourcedb.get_spec(name) - else: - raise Error(_('Cannot find source package: %s') % name) - def get_src(name): - return get_spec(name).source - def add_src(src): - if not str(src.name) in G_f.vertices(): - G_f.add_vertex(str(src.name), (src.version, src.release)) - def pkgtosrc(pkg): - return ctx.sourcedb.pkgtosrc(pkg) - - # setup first - #specfiles = [ ctx.sourcedb.get_source(x)[1] for x in A ] - #pkgtosrc = {} - B = A - - install_list = set() - - while len(B) > 0: - Bp = set() - for x in B: - sf = get_spec(x) - src = sf.source - add_src(src) - - # add dependencies - - def process_dep(dep): - if not dependency.installed_satisfies_dep(dep): - if dependency.repo_satisfies_dep(dep): - install_list.add(dep.package) - return - srcdep = pkgtosrc(dep.package) - if not srcdep in G_f.vertices(): - Bp.add(srcdep) - add_src(get_src(srcdep)) - if not src.name == srcdep: # firefox - firefox-devel thing - G_f.add_edge(src.name, srcdep) - - for builddep in src.buildDependencies: - process_dep(builddep) - - for pkg in sf.packages: - for rtdep in pkg.packageDependencies: - process_dep(rtdep) - B = Bp - - if ctx.config.get_option('debug'): - G_f.write_graphviz(sys.stdout) - order_build = G_f.topological_sort() - order_build.reverse() - - G_f2, order_inst = plan_install_pkg_names(install_list) - - return G_f, order_inst, order_build - -def calculate_download_sizes(order): - total_size = cached_size = 0 - - for pkg in [ctx.packagedb.get_package(name) for name in order]: - - delta = None - if ctx.installdb.is_installed(pkg.name): - (version, release, build) = ctx.installdb.get_version(pkg.name) - delta = pkg.get_delta(buildFrom=build) - - if delta: - fn = os.path.basename(delta.packageURI) - pkg_hash = delta.packageHash - pkg_size = delta.packageSize - else: - fn = os.path.basename(pkg.packageURI) - pkg_hash = pkg.packageHash - pkg_size = pkg.packageSize - - path = util.join_path(ctx.config.packages_dir(), fn) - - # check the file and sha1sum to be sure it _is_ the cached package - if os.path.exists(path) and util.sha1_file(path) == pkg_hash: - cached_size += pkg_size - - total_size += pkg_size - - ctx.ui.notify(ui.cached, total=total_size, cached=cached_size) - return total_size, cached_size diff --git a/tests/popt/actions.py b/pisi/operations/__init__.py similarity index 55% rename from tests/popt/actions.py rename to pisi/operations/__init__.py index 2be6f570..f82202a3 100644 --- a/tests/popt/actions.py +++ b/pisi/operations/__init__.py @@ -1,7 +1,6 @@ -#!/usr/bin/python # -*- coding: utf-8 -*- # -# Copyright (C) 2005 - 2007, TUBITAK/UEKAE +# Copyright (C) 2007, 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 @@ -11,15 +10,3 @@ # Please read the COPYING file. # -from pisi.actionsapi import autotools - -WorkDir='popt-1.7' - -def setup(): - autotools.configure( '--with-nls' ) - -def build(): - autotools.make() - -def install(): - autotools.install() diff --git a/pisi/build.py b/pisi/operations/build.py similarity index 98% rename from pisi/build.py rename to pisi/operations/build.py index b4275527..fb0baa90 100644 --- a/pisi/build.py +++ b/pisi/operations/build.py @@ -29,7 +29,7 @@ import pisi.util import pisi.file import pisi.context as ctx import pisi.dependency as dependency -import pisi.operations as operations +import pisi.operations.install as install import pisi.sourcearchive import pisi.files import pisi.fetcher @@ -39,12 +39,11 @@ import pisi.package import pisi.component as component import pisi.archive as archive import pisi.actionsapi.variables - +import pisi.db class Error(pisi.Error): pass - # Helper Functions def get_file_type(path, pinfo_list, install_dir): """Return the file type of a path according to the given PathInfo @@ -93,9 +92,11 @@ class Builder: @staticmethod def from_name(name): + repodb = pisi.db.repodb.RepoDB() + sourcedb = pisi.db.sourcedb.SourceDB() # download package and return an installer object # find package in repository - sf, reponame = ctx.sourcedb.get_spec_repo(name) + sf, reponame = sourcedb.get_spec_repo(name) src = sf.source if src: @@ -103,7 +104,7 @@ class Builder: if src_uri.is_absolute_path(): src_path = str(src_uri) else: - repo = ctx.repodb.get_repo(reponame) + repo = repodb.get_repo(reponame) #FIXME: don't use dirname to work on URLs src_path = os.path.join(os.path.dirname(repo.indexuri.get_uri()), str(src_uri.path())) @@ -138,6 +139,9 @@ class Builder: self.actionGlobals = None self.srcDir = None + self.componentdb = pisi.db.componentdb.ComponentDB() + self.installdb = pisi.db.installdb.InstallDB() + def set_spec_file(self, specuri): if not specuri.is_remote_file(): specuri = pisi.uri.URI(os.path.realpath(specuri.get_uri())) # FIXME: doesn't work for file:// @@ -429,7 +433,7 @@ class Builder: os.chdir(self.srcDir) if func in self.actionLocals: - if ctx.get_option('ignore_sandbox'): + if not ctx.get_option('enable_sandbox'): self.actionLocals[func]() else: import catbox @@ -464,11 +468,11 @@ class Builder: build_deps = self.spec.source.buildDependencies if not ctx.get_option('ignore_safety'): - if ctx.componentdb.has_component('system.devel'): + if self.componentdb.has_component('system.devel'): build_deps_names = set([x.package for x in build_deps]) - devel_deps_names = set(ctx.componentdb.get_component('system.devel').packages) + devel_deps_names = set(self.componentdb.get_component('system.devel').packages) extra_names = devel_deps_names - build_deps_names - extra_names = filter(lambda x: not ctx.installdb.is_installed(x), extra_names) + extra_names = filter(lambda x: not self.installdb.has_package(x), extra_names) if extra_names: ctx.ui.warning(_('Safety switch: following extra packages in system.devel will be installed: ') + pisi.util.strlist(extra_names)) @@ -502,7 +506,7 @@ class Builder: if ctx.ui.confirm( _('Do you want to install the unsatisfied build dependencies')): ctx.ui.info(_('Installing build dependencies.')) - operations.install([dep.package for dep in dep_unsatis]) + install.install([dep.package for dep in dep_unsatis]) else: fail() else: @@ -607,7 +611,7 @@ class Builder: metadata.package.distribution = ctx.config.values.general.distribution metadata.package.distributionRelease = ctx.config.values.general.distribution_release - metadata.package.architecture = "Any" + metadata.package.architecture = ctx.config.values.general.architecture metadata.package.packageFormat = ctx.get_option('package_format') size = 0 diff --git a/pisi/delta.py b/pisi/operations/delta.py similarity index 100% rename from pisi/delta.py rename to pisi/operations/delta.py diff --git a/pisi/operations/emerge.py b/pisi/operations/emerge.py new file mode 100644 index 00000000..cfda2d6f --- /dev/null +++ b/pisi/operations/emerge.py @@ -0,0 +1,146 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 sys + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi +import pisi.operations +import pisi.context as ctx +import pisi.util as util +import pisi.atomicoperations as atomicoperations +import pisi.dependency as dependency +import pisi.ui as ui +import pisi.db + +def emerge(A): + + # A was a list, remove duplicates and expand components + A = [str(x) for x in A] + A_0 = A = pisi.operations.helper.expand_src_components(set(A)) + ctx.ui.debug('A = %s' % str(A)) + + if len(A)==0: + ctx.ui.info(_('No packages to emerge.')) + return + + #A |= upgrade_base(A) + + # FIXME: Errr... order_build changes type conditionally and this + # is not good. - baris + if not ctx.config.get_option('ignore_dependency'): + G_f, order_inst, order_build = plan_emerge(A) + else: + G_f = None + order_inst = [] + order_build = A + + if order_inst: + ctx.ui.info(_("""The following minimal list of packages will be installed +from repository in the respective order to satisfy dependencies: +""") + util.strlist(order_inst)) + ctx.ui.info(_("""The following minimal list of packages will be built and +installed in the respective order to satisfy dependencies: +""") + util.strlist(order_build)) + + if ctx.get_option('dry_run'): + return + + if len(order_inst) + len(order_build) > len(A_0): + if not ctx.ui.confirm(_('There are extra packages due to dependencies. Do you want to continue?')): + return False + + ctx.ui.notify(ui.packagestogo, order = order_inst) + + for x in order_inst: + atomicoperations.install_single_name(x) + + #ctx.ui.notify(ui.packagestogo, order = order_build) + + for x in order_build: + package_names = atomicoperations.build(x)[0] + pisi.operations.install.install_pkg_files(package_names) # handle inter-package deps here + + # FIXME: take a look at the fixme above :(, we have to be sure + # that order_build is a known type... + U = set(order_build) + U.update(order_inst) + +def plan_emerge(A): + + sourcedb = pisi.db.sourcedb.SourceDB() + + # try to construct a pisi graph of packages to + # install / reinstall + + G_f = pisi.graph.Digraph() + + def get_spec(name): + if sourcedb.has_spec(name): + return sourcedb.get_spec(name) + else: + raise Exception(_('Cannot find source package: %s') % name) + def get_src(name): + return get_spec(name).source + def add_src(src): + if not str(src.name) in G_f.vertices(): + G_f.add_vertex(str(src.name), (src.version, src.release)) + def pkgtosrc(pkg): + return sourcedb.pkgtosrc(pkg) + + # setup first + #specfiles = [ sourcedb.get_source(x)[1] for x in A ] + #pkgtosrc = {} + B = A + + install_list = set() + + while len(B) > 0: + Bp = set() + for x in B: + sf = get_spec(x) + src = sf.source + add_src(src) + + # add dependencies + + def process_dep(dep): + if not dependency.installed_satisfies_dep(dep): + if dependency.repo_satisfies_dep(dep): + install_list.add(dep.package) + return + srcdep = pkgtosrc(dep.package) + if not srcdep in G_f.vertices(): + Bp.add(srcdep) + add_src(get_src(srcdep)) + if not src.name == srcdep: # firefox - firefox-devel thing + G_f.add_edge(src.name, srcdep) + + for builddep in src.buildDependencies: + process_dep(builddep) + + for pkg in sf.packages: + for rtdep in pkg.packageDependencies: + process_dep(rtdep) + B = Bp + + if ctx.config.get_option('debug'): + G_f.write_graphviz(sys.stdout) + order_build = G_f.topological_sort() + order_build.reverse() + + G_f2, order_inst = pisi.operations.install.plan_install_pkg_names(install_list) + + return G_f, order_inst, order_build diff --git a/pisi/operations/helper.py b/pisi/operations/helper.py new file mode 100644 index 00000000..0cd62ba4 --- /dev/null +++ b/pisi/operations/helper.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 os + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi +import pisi.context as ctx +import pisi.util as util +import pisi.ui as ui +import pisi.conflict +import pisi.db + +def reorder_base_packages(order): + + componentdb = pisi.db.componentdb.ComponentDB() + + """system.base packages must be first in order""" + systembase = componentdb.get_union_component('system.base').packages + + systembase_order = [] + nonbase_order = [] + for pkg in order: + if pkg in systembase: + systembase_order.append(pkg) + else: + nonbase_order.append(pkg) + + return systembase_order + nonbase_order + +def check_conflicts(order, packagedb): + """check if upgrading to the latest versions will cause havoc + done in a simple minded way without regard for dependencies of + conflicts, etc.""" + + (C, D, pkg_conflicts) = pisi.conflict.calculate_conflicts(order, packagedb) + + if D: + raise Exception(_("Selected packages [%s] are in conflict with each other.") % + util.strlist(list(D))) + + if pkg_conflicts: + conflicts = "" + for pkg in pkg_conflicts.keys(): + conflicts += _("[%s conflicts with: %s]\n") % (pkg, util.strlist(pkg_conflicts[pkg])) + + ctx.ui.info(_("The following packages have conflicts:\n%s") % + conflicts) + + if not ctx.ui.confirm(_('Remove the following conflicting packages?')): + raise Exception(_("Conflicts remain")) + + return list(C) + +def expand_src_components(A): + componentdb = pisi.db.componentdb.ComponentDB() + Ap = set() + for x in A: + if componentdb.has_component(x): + Ap = Ap.union(componentdb.get_union_component(x).sources) + else: + Ap.add(x) + return Ap + +def calculate_download_sizes(order): + total_size = cached_size = 0 + + installdb = pisi.db.installdb.InstallDB() + packagedb = pisi.db.packagedb.PackageDB() + + for pkg in [packagedb.get_package(name) for name in order]: + + delta = None + if installdb.has_package(pkg.name): + (version, release, build) = installdb.get_version(pkg.name) + delta = pkg.get_delta(buildFrom=build) + + if delta: + fn = os.path.basename(delta.packageURI) + pkg_hash = delta.packageHash + pkg_size = delta.packageSize + else: + fn = os.path.basename(pkg.packageURI) + pkg_hash = pkg.packageHash + pkg_size = pkg.packageSize + + path = util.join_path(ctx.config.cached_packages_dir(), fn) + + # check the file and sha1sum to be sure it _is_ the cached package + if os.path.exists(path) and util.sha1_file(path) == pkg_hash: + cached_size += pkg_size + + total_size += pkg_size + + ctx.ui.notify(ui.cached, total=total_size, cached=cached_size) + return total_size, cached_size diff --git a/pisi/operations/install.py b/pisi/operations/install.py new file mode 100644 index 00000000..6ddded74 --- /dev/null +++ b/pisi/operations/install.py @@ -0,0 +1,239 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 sys + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi +import pisi.context as ctx +import pisi.util as util +import pisi.atomicoperations as atomicoperations +import pisi.operations as operations +import pisi.pgraph as pgraph +import pisi.dependency as dependency +import pisi.ui as ui +import pisi.db + +def install(packages, reinstall = False, ignore_file_conflicts=False): + """install a list of packages (either files/urls, or names)""" + + if not ctx.get_option('ignore_file_conflicts'): + ctx.set_option('ignore_file_conflicts', ignore_file_conflicts) + + # determine if this is a list of files/urls or names + if packages and packages[0].endswith(ctx.const.package_suffix): # they all have to! + return install_pkg_files(packages) + else: + return install_pkg_names(packages, reinstall) + +def install_pkg_names(A, reinstall = False): + """This is the real thing. It installs packages from + the repository, trying to perform a minimum number of + installs""" + + installdb = pisi.db.installdb.InstallDB() + + A = [str(x) for x in A] #FIXME: why do we still get unicode input here? :/ -- exa + # A was a list, remove duplicates + A_0 = A = set(A) + + # filter packages that are already installed + if not reinstall: + Ap = set(filter(lambda x: not installdb.has_package(x), A)) + d = A - Ap + if len(d) > 0: + ctx.ui.warning(_("The following package(s) are already installed and are not going to be installed again:\n") + + util.strlist(d)) + A = Ap + + if len(A)==0: + ctx.ui.info(_('No packages to install.')) + return + + A |= operations.upgrade.upgrade_base(A) + + if not ctx.config.get_option('ignore_dependency'): + G_f, order = plan_install_pkg_names(A) + else: + G_f = None + order = list(A) + + componentdb = pisi.db.componentdb.ComponentDB() + + # Bug 4211 + if componentdb.has_component('system.base'): + order = operations.helper.reorder_base_packages(order) + + if len(order) > 1: + ctx.ui.info(_("Following packages will be installed in the respective " + "order to satisfy dependencies:\n") + util.strlist(order)) + + total_size, cached_size = operations.helper.calculate_download_sizes(order) + total_size, symbol = util.human_readable_size(total_size) + ctx.ui.info(_('Total size of package(s): %.2f %s') % (total_size, symbol)) + + if ctx.get_option('dry_run'): + return + + if set(order) - A_0: + if not ctx.ui.confirm(_('There are extra packages due to dependencies. Do you want to continue?')): + return False + + ctx.ui.notify(ui.packagestogo, order = order) + + for x in order: + atomicoperations.install_single_name(x, True) # allow reinstalls here + +def install_pkg_files(package_URIs): + """install a number of pisi package files""" + + ctx.ui.debug('A = %s' % str(package_URIs)) + + for x in package_URIs: + if not x.endswith(ctx.const.package_suffix): + raise Exception(_('Mixing file names and package names not supported yet.')) + + if ctx.config.get_option('ignore_dependency'): + # simple code path then + for x in package_URIs: + atomicoperations.install_single_file(x) + return # short circuit + + # read the package information into memory first + # regardless of which distribution they come from + d_t = {} + dfn = {} + for x in package_URIs: + package = pisi.package.Package(x) + package.read() + name = str(package.metadata.package.name) + d_t[name] = package.metadata.package + dfn[name] = x + + def satisfiesDep(dep): + # is dependency satisfied among available packages + # or packages to be installed? + return dependency.installed_satisfies_dep(dep) \ + or dependency.dict_satisfies_dep(d_t, dep) + + # for this case, we have to determine the dependencies + # that aren't already satisfied and try to install them + # from the repository + dep_unsatis = [] + for name in d_t.keys(): + pkg = d_t[name] + deps = pkg.runtimeDependencies() + for dep in deps: + if not satisfiesDep(dep): + dep_unsatis.append(dep) + + # now determine if these unsatisfied dependencies could + # be satisfied by installing packages from the repo + + # if so, then invoke install_pkg_names + extra_packages = [x.package for x in dep_unsatis] + if extra_packages: + ctx.ui.info(_("""The following packages will be installed +in the respective order to satisfy extra dependencies: +""") + util.strlist(extra_packages)) + if not ctx.ui.confirm(_('Do you want to continue?')): + raise Exception(_('External dependencies not satisfied')) + install_pkg_names(extra_packages) + + class PackageDB: + def get_package(self, key, repo = None): + return d_t[str(key)] + + packagedb = PackageDB() + + A = d_t.keys() + + if len(A)==0: + ctx.ui.info(_('No packages to install.')) + return + + # try to construct a pisi graph of packages to + # install / reinstall + + G_f = pgraph.PGraph(packagedb) # construct G_f + + # find the "install closure" graph of G_f by package + # set A using packagedb + for x in A: + G_f.add_package(x) + B = A + while len(B) > 0: + Bp = set() + for x in B: + pkg = packagedb.get_package(x) + for dep in pkg.runtimeDependencies(): + if dependency.dict_satisfies_dep(d_t, dep): + if not dep.package in G_f.vertices(): + Bp.add(str(dep.package)) + G_f.add_dep(x, dep) + B = Bp + if ctx.config.get_option('debug'): + G_f.write_graphviz(sys.stdout) + order = G_f.topological_sort() + if not ctx.get_option('ignore_package_conflicts'): + conflicts = operations.helper.check_conflicts(order, packagedb) + if conflicts: + operations.remove.remove_conflicting_packages(conflicts) + order.reverse() + ctx.ui.info(_('Installation order: ') + util.strlist(order) ) + + if ctx.get_option('dry_run'): + return + + ctx.ui.notify(ui.packagestogo, order = order) + + for x in order: + atomicoperations.install_single_file(dfn[x]) + +def plan_install_pkg_names(A, ignore_package_conflicts = False): + # try to construct a pisi graph of packages to + # install / reinstall + + packagedb = pisi.db.packagedb.PackageDB() + + G_f = pgraph.PGraph(packagedb) # construct G_f + + # find the "install closure" graph of G_f by package + # set A using packagedb + for x in A: + G_f.add_package(x) + B = A + + while len(B) > 0: + Bp = set() + for x in B: + pkg = packagedb.get_package(x) + for dep in pkg.runtimeDependencies(): + ctx.ui.debug('checking %s' % str(dep)) + # we don't deal with already *satisfied* dependencies + if not dependency.installed_satisfies_dep(dep): + if not dep.package in G_f.vertices(): + Bp.add(str(dep.package)) + G_f.add_dep(x, dep) + B = Bp + if ctx.config.get_option('debug'): + G_f.write_graphviz(sys.stdout) + order = G_f.topological_sort() + order.reverse() + if not ctx.get_option('ignore_package_conflicts') and not ignore_package_conflicts: + conflicts = operations.helper.check_conflicts(order, packagedb) + if conflicts: + operations.remove.remove_conflicting_packages(conflicts) + return G_f, order diff --git a/pisi/operations/remove.py b/pisi/operations/remove.py new file mode 100644 index 00000000..616ec4f5 --- /dev/null +++ b/pisi/operations/remove.py @@ -0,0 +1,143 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 sys + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi +import pisi.context as ctx +import pisi.atomicoperations as atomicoperations +import pisi.dependency as dependency +import pisi.pgraph as pgraph +import pisi.util as util +import pisi.ui as ui +import pisi.db + +def remove(A, ignore_dep = False, ignore_safety = False): + """remove set A of packages from system (A is a list of package names)""" + + componentdb = pisi.db.componentdb.ComponentDB() + installdb = pisi.db.installdb.InstallDB() + + A = [str(x) for x in A] + + # filter packages that are not installed + A_0 = A = set(A) + + if not ctx.get_option('ignore_safety') and not ignore_safety: + if componentdb.has_component('system.base'): + systembase = set(componentdb.get_union_component('system.base').packages) + refused = A.intersection(systembase) + if refused: + raise pisi.Error(_('Safety switch: cannot remove the following packages in system.base: ') + + util.strlist(refused)) + A = A - systembase + else: + ctx.ui.warning(_('Safety switch: the component system.base cannot be found')) + + Ap = [] + for x in A: + if installdb.has_package(x): + Ap.append(x) + else: + ctx.ui.info(_('Package %s does not exist. Cannot remove.') % x) + A = set(Ap) + + if len(A)==0: + ctx.ui.info(_('No packages to remove.')) + return False + + if not ctx.config.get_option('ignore_dependency') and not ignore_dep: + G_f, order = plan_remove(A) + else: + G_f = None + order = A + + ctx.ui.info(_("""The following minimal list of packages will be removed +in the respective order to satisfy dependencies: +""") + util.strlist(order)) + if len(order) > len(A_0): + if not ctx.ui.confirm(_('Do you want to continue?')): + ctx.ui.warning(_('Package removal declined')) + return False + + if ctx.get_option('dry_run'): + return + + ctx.ui.notify(ui.packagestogo, order = order) + + for x in order: + if installdb.has_package(x): + atomicoperations.remove_single(x) + else: + ctx.ui.info(_('Package %s is not installed. Cannot remove.') % x) + +def plan_remove(A): + # try to construct a pisi graph of packages to + # install / reinstall + + installdb = pisi.db.installdb.InstallDB() + + G_f = pgraph.PGraph(installdb) # construct G_f + + # find the (install closure) graph of G_f by package + # set A using packagedb + for x in A: + G_f.add_package(x) + B = A + while len(B) > 0: + Bp = set() + for x in B: + rev_deps = installdb.get_rev_deps(x) + for (rev_dep, depinfo) in rev_deps: + # we don't deal with uninstalled rev deps + # and unsatisfied dependencies (this is important, too) + if installdb.has_package(rev_dep) and dependency.installed_satisfies_dep(depinfo): + if not rev_dep in G_f.vertices(): + Bp.add(rev_dep) + G_f.add_plain_dep(rev_dep, x) + B = Bp + if ctx.config.get_option('debug'): + G_f.write_graphviz(sys.stdout) + order = G_f.topological_sort() + return G_f, order + +# FIXME: this should be done in atomicoperations automatically. +def remove_replaced_packages(order, replaces): + + replaced = [] + inorder = set(order).intersection(replaces.values()) + + if inorder: + for pkg in replaces.keys(): + if replaces[pkg] in inorder: + replaced.append(pkg) + + if replaced: + if remove(replaced, ignore_dep=True, ignore_safety=True): + raise Exception(_("Replaced package remains")) + +def remove_conflicting_packages(conflicts): + if remove(conflicts, ignore_dep=True, ignore_safety=True): + raise Exception(_("Conflicts remain")) + +def remove_obsoleted_packages(): + + installdb = pisi.db.installdb.InstallDB() + packagedb = pisi.db.packagedb.PackageDB() + obsoletes = filter(installdb.has_package, packagedb.get_obsoletes()) + if obsoletes: + if remove(obsoletes, ignore_dep=True, ignore_safety=True): + raise Exception(_("Obsoleted packages remaining")) diff --git a/pisi/operations/upgrade.py b/pisi/operations/upgrade.py new file mode 100644 index 00000000..97876307 --- /dev/null +++ b/pisi/operations/upgrade.py @@ -0,0 +1,261 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2005 - 2007, 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 sys + +import gettext +__trans = gettext.translation('pisi', fallback=True) +_ = __trans.ugettext + +import pisi +import pisi.ui as ui +import pisi.context as ctx +import pisi.pgraph as pgraph +import pisi.atomicoperations as atomicoperations +import pisi.operations as operations +import pisi.util as util +import pisi.dependency as dependency +import pisi.db + +def upgrade(A): + upgrade_pkg_names(A) + +def upgrade_pkg_names(A = []): + """Re-installs packages from the repository, trying to perform + a minimum or maximum number of upgrades according to options.""" + + ignore_build = ctx.get_option('ignore_build_no') + security_only = ctx.get_option('security_only') + + packagedb = pisi.db.packagedb.PackageDB() + replaces = packagedb.get_replaces() + + installdb = pisi.db.installdb.InstallDB() + + if not A: + # if A is empty, then upgrade all packages + A = installdb.list_installed() + + A_0 = A = set(A) + + Ap = [] + for x in A: + if x.endswith(ctx.const.package_suffix): + ctx.ui.debug(_("Warning: package *name* ends with '.pisi'")) + + # Handling of replacement packages + if x in replaces.values(): + Ap.append(x) + continue + + if x in replaces.keys(): + Ap.append(replaces[x]) + continue + + if not installdb.has_package(x): + ctx.ui.info(_('Package %s is not installed.') % x, True) + continue + (version, release, build) = installdb.get_version(x) + if packagedb.has_package(x): + pkg = packagedb.get_package(x) + else: + ctx.ui.info(_('Package %s is not available in repositories.') % x, True) + continue + + if security_only: + updates = [i for i in pkg.history if pisi.version.Version(i.release) > pisi.version.Version(release)] + if not pisi.util.any(lambda i:i.type == 'security', updates): + continue + + if ignore_build or (not build) or (not pkg.build): + if pisi.version.Version(release) < pisi.version.Version(pkg.release): + Ap.append(x) + else: + ctx.ui.info(_('Package %s is already at the latest release %s.') + % (pkg.name, pkg.release), True) + else: + if build < pkg.build: + Ap.append(x) + else: + ctx.ui.info(_('Package %s is already at the latest build %s.') + % (pkg.name, pkg.build), True) + + + A = set(Ap) + + if len(A)==0: + ctx.ui.info(_('No packages to upgrade.')) + return True + + A |= upgrade_base(A) + + ctx.ui.debug('A = %s' % str(A)) + + if not ctx.config.get_option('ignore_dependency'): + G_f, order = plan_upgrade(A) + else: + G_f = None + order = list(A) + + componentdb = pisi.db.componentdb.ComponentDB() + + # Bug 4211 + if componentdb.has_component('system.base'): + order = operations.helper.reorder_base_packages(order) + + if not ctx.get_option('ignore_package_conflicts'): + conflicts = operations.helper.check_conflicts(order, packagedb) + + ctx.ui.info(_('The following packages will be upgraded: ') + + util.strlist(order)) + + total_size, cached_size = operations.helper.calculate_download_sizes(order) + total_size, symbol = util.human_readable_size(total_size) + ctx.ui.info(_('Total size of package(s): %.2f %s') % (total_size, symbol)) + + if ctx.get_option('dry_run'): + return + + if set(order) - A_0 - set(replaces.values()): + if not ctx.ui.confirm(_('There are extra packages due to dependencies. Do you want to continue?')): + return False + + ctx.ui.notify(ui.packagestogo, order = order) + + paths = [] + for x in order: + ctx.ui.info(util.colorize(_("Downloading %d / %d") % (order.index(x)+1, len(order)), "yellow")) + install_op = atomicoperations.Install.from_name(x) + paths.append(install_op.package_fname) + + # fetch to be upgraded packages but do not install them. + if ctx.get_option('fetch_only'): + return + + if not ctx.get_option('ignore_package_conflicts'): + if conflicts: + operations.remove.remove_conflicting_packages(conflicts) + + if replaces: + operations.remove.remove_replaced_packages(order, replaces) + + operations.remove.remove_obsoleted_packages() + + for path in paths: + ctx.ui.info(util.colorize(_("Installing %d / %d") % (paths.index(path)+1, len(paths)), "yellow")) + install_op = atomicoperations.Install(path, ignore_file_conflicts = True) + install_op.install(True) + +def plan_upgrade(A): + # try to construct a pisi graph of packages to + # install / reinstall + + packagedb = pisi.db.packagedb.PackageDB() + + G_f = pgraph.PGraph(packagedb) # construct G_f + + # find the "install closure" graph of G_f by package + # set A using packagedb + for x in A: + G_f.add_package(x) + B = A + + installdb = pisi.db.installdb.InstallDB() + + while len(B) > 0: + Bp = set() + for x in B: + pkg = packagedb.get_package(x) + for dep in pkg.runtimeDependencies(): + # add packages that can be upgraded + if installdb.has_package(dep.package) and dependency.installed_satisfies_dep(dep): + continue + + if dependency.repo_satisfies_dep(dep): + if not dep.package in G_f.vertices(): + Bp.add(str(dep.package)) + G_f.add_dep(x, dep) + else: + ctx.ui.error(_('Dependency %s of %s cannot be satisfied') % (dep, x)) + raise Exception(_("Upgrade is not possible.")) + + B = Bp + # now, search reverse dependencies to see if anything + # should be upgraded + B = A + while len(B) > 0: + Bp = set() + for x in B: + pkg = packagedb.get_package(x) + rev_deps = packagedb.get_rev_deps(x) + for (rev_dep, depinfo) in rev_deps: + # add only installed but unsatisfied reverse dependencies + if installdb.has_package(rev_dep) and \ + (not dependency.installed_satisfies_dep(depinfo)): + if not dependency.repo_satisfies_dep(depinfo): + raise Exception(_('Reverse dependency %s of %s cannot be satisfied') % (rev_dep, x)) + if not rev_dep in G_f.vertices(): + Bp.add(rev_dep) + G_f.add_plain_dep(rev_dep, x) + B = Bp + + if ctx.config.get_option('debug'): + G_f.write_graphviz(sys.stdout) + order = G_f.topological_sort() + order.reverse() + return G_f, order + +def upgrade_base(A = set(), ignore_package_conflicts = False): + installdb = pisi.db.installdb.InstallDB() + componentdb = pisi.db.componentdb.ComponentDB() + ignore_build = ctx.get_option('ignore_build_no') + if not ctx.get_option('ignore_safety'): + if componentdb.has_component('system.base'): + systembase = set(componentdb.get_union_component('system.base').packages) + extra_installs = filter(lambda x: not installdb.has_package(x), systembase - set(A)) + if extra_installs: + ctx.ui.warning(_('Safety switch: Following packages in system.base will be installed: ') + + util.strlist(extra_installs)) + G_f, install_order = operations.install.plan_install_pkg_names(extra_installs, ignore_package_conflicts) + extra_upgrades = filter(lambda x: is_upgradable(x, ignore_build), systembase - set(install_order)) + upgrade_order = [] + if extra_upgrades: + ctx.ui.warning(_('Safety switch: Following packages in system.base will be upgraded: ') + + util.strlist(extra_upgrades)) + G_f, upgrade_order = plan_upgrade(extra_upgrades) + # return packages that must be added to any installation + return set(install_order + upgrade_order) + else: + ctx.ui.warning(_('Safety switch: the component system.base cannot be found')) + return set() + +def is_upgradable(name, ignore_build = False): + + installdb = pisi.db.installdb.InstallDB() + packagedb = pisi.db.packagedb.PackageDB() + + if not installdb.has_package(name): + return False + + (version, release, build) = installdb.get_version(name) + + try: + pkg_version, pkg_release, pkg_build = packagedb.get_version(name, packagedb.which_repo(name)) + except KeyboardInterrupt: + raise + except Exception: #FIXME: what exception could we catch here, replace with that. + return False + + if ignore_build or (not build) or (not pkg_build): + return pisi.version.Version(release) < pisi.version.Version(pkg_release) + else: + return build < pkg_build diff --git a/pisi/package.py b/pisi/package.py index 0e1a3d4e..34b1e017 100644 --- a/pisi/package.py +++ b/pisi/package.py @@ -44,7 +44,7 @@ class Package: self.impl = archive.ArchiveZip(self.filepath, 'zip', mode) def fetch_remote_file(self, url): - dest = ctx.config.packages_dir() + dest = ctx.config.cached_packages_dir() self.filepath = os.path.join(dest, url.filename()) if not os.path.exists(self.filepath): @@ -145,7 +145,7 @@ class Package: + self.metadata.package.version + '-' \ + self.metadata.package.release - return os.path.join( ctx.config.lib_dir(), 'package', packageDir) + return os.path.join(ctx.config.packages_dir(), packageDir) def comar_dir(self): return os.path.join(self.pkg_dir(), ctx.const.comar_dir) diff --git a/pisi/pgraph.py b/pisi/pgraph.py index 352fa58b..6a60212f 100644 --- a/pisi/pgraph.py +++ b/pisi/pgraph.py @@ -15,29 +15,30 @@ import string import pisi +import pisi.db +import pisi.context as ctx import graph # Cache the results from packagedb queries in a graph class PGraph(graph.Digraph): - def __init__(self, packagedb, repo = pisi.db.itembyrepodb.repos): + def __init__(self, packagedb): super(PGraph, self).__init__() self.packagedb = packagedb - self.repo = repo def add_package(self, pkg): - pkg1 = self.packagedb.get_package(pkg, self.repo) + pkg1 = self.packagedb.get_package(pkg) self.add_vertex(str(pkg), (pkg1.version, pkg1.release)) def add_plain_dep(self, pkg1name, pkg2name): pkg1data = None if not pkg1name in self.vertices(): - pkg1 = self.packagedb.get_package(pkg1name, self.repo) + pkg1 = self.packagedb.get_package(pkg1name) pkg1data = (pkg1.version, pkg1.release) pkg2data = None if not pkg2name in self.vertices(): - pkg2 = self.packagedb.get_package(pkg2name, self.repo) + pkg2 = self.packagedb.get_package(pkg2name) pkg2data = (pkg2.version, pkg2.release) self.add_edge(str(pkg1name), str(pkg2name), ('d', None), pkg1data, pkg2data ) @@ -45,11 +46,11 @@ class PGraph(graph.Digraph): def add_dep(self, pkg, depinfo): pkg1data = None if not pkg in self.vertices(): - pkg1 = self.packagedb.get_package(pkg, self.repo) + pkg1 = self.packagedb.get_package(pkg) pkg1data = (pkg1.version, pkg1.release) pkg2data = None if not depinfo.package in self.vertices(): - pkg2 = self.packagedb.get_package(depinfo.package, self.repo) + pkg2 = self.packagedb.get_package(depinfo.package) pkg2data = (pkg2.version, pkg2.release) self.add_edge(str(pkg), str(depinfo.package), ('d', depinfo), pkg1data, pkg2data ) @@ -57,11 +58,11 @@ class PGraph(graph.Digraph): def add_rev_dep(self, depinfo, pkg): pkg1data = None if not pkg in self.vertices(): - pkg1 = self.packagedb.get_package(depinfo.package, self.repo) + pkg1 = self.packagedb.get_package(depinfo.package) pkg1data = (pkg1.version, pkg1.release) pkg2data = None if not depinfo.package in self.vertices(): - pkg2 = self.packagedb.get_package(pkg, self.repo) + pkg2 = self.packagedb.get_package(pkg) pkg2data = (pkg2.version, pkg2.release) self.add_edge(str(depinfo.package), str(pkg), ('d', depinfo), pkg1data, pkg2data ) @@ -69,11 +70,11 @@ class PGraph(graph.Digraph): def add_conflict(self, pkg, conflinfo): pkg1data = None if not pkg in self.vertices(): - pkg1 = self.packagedb.get_package(pkg, self.repo) + pkg1 = self.packagedb.get_package(pkg) pkg1data = (pkg1.version, pkg1.release) pkg2data = None if not pkg in self.vertices(): - pkg2 = self.packagedb.get_package(conflinfo.package, self.repo) + pkg2 = self.packagedb.get_package(conflinfo.package) pkg2data = (pkg2.version, pkg2.release) # FIXME: WTF? /usr/lib/pardus/pisi/pgraph.py:80: Invalid arguments to (add_biedge), got 5, expected between 2 and 3 / caglar diff --git a/pisi/pxml/autoxml.py b/pisi/pxml/autoxml.py index 27c9909c..5ca1e792 100644 --- a/pisi/pxml/autoxml.py +++ b/pisi/pxml/autoxml.py @@ -438,10 +438,14 @@ class autoxml(oo.autosuper, oo.autoprop): errs.append(_("autoxml.parse: String '%s' has errors") % xml) def read(self, uri, keepDoc = False, tmpDir = '/tmp', - sha1sum = False, compress = None, sign = None, copylocal = False): + sha1sum = False, compress = None, sign = None, copylocal = False, nodecode = False): "read XML file and decode it into a python object" self.readxml(uri, tmpDir, sha1sum=sha1sum, compress=compress, sign=sign, copylocal=copylocal) + + if nodecode: + return + errs = [] self.decode(self.rootNode(), errs) if errs: diff --git a/pisi/relation.py b/pisi/relation.py index c2e09cee..f4f9ac4e 100644 --- a/pisi/relation.py +++ b/pisi/relation.py @@ -14,10 +14,10 @@ import gettext __trans = gettext.translation('pisi', fallback=True) _ = __trans.ugettext -import pisi.context as ctx +import pisi import pisi.version +import pisi.db import pisi.pxml.autoxml as autoxml -import pisi.db.itembyrepodb class Relation: @@ -31,7 +31,7 @@ class Relation: a_releaseFrom = [autoxml.String, autoxml.optional] a_releaseTo = [autoxml.String, autoxml.optional] - def satisfies_relation(self, pkg_name, version, release): + def satisfies_relation(self, version, release): ret = True v = pisi.version.Version(version) if self.version: @@ -50,10 +50,11 @@ class Relation: return ret def installed_package_satisfies(relation): + installdb = pisi.db.installdb.InstallDB() pkg_name = relation.package - if not ctx.installdb.is_installed(pkg_name): + if not installdb.has_package(pkg_name): return False else: - pkg = ctx.packagedb.get_package(pkg_name, pisi.db.itembyrepodb.installed) + pkg = installdb.get_package(pkg_name) (version, release) = (pkg.version, pkg.release) - return relation.satisfies_relation(pkg_name, version, release) + return relation.satisfies_relation(version, release) diff --git a/pisi/specfile.py b/pisi/specfile.py index 918112df..f290668b 100644 --- a/pisi/specfile.py +++ b/pisi/specfile.py @@ -33,7 +33,7 @@ import pisi.replace import pisi.conflict import pisi.component as component import pisi.util as util - +import pisi.db class Error(pisi.Error): pass @@ -182,8 +182,9 @@ class Package: debug_package = False def runtimeDependencies(self): + componentdb = pisi.db.componentdb.ComponentDB() deps = self.packageDependencies - deps += [ ctx.componentdb.get_component[x].packages for x in self.componentDependencies ] + deps += [ componentdb.get_component[x].packages for x in self.componentDependencies ] return deps def pkg_dir(self): @@ -191,7 +192,7 @@ class Package: + self.version + '-' \ + self.release - return util.join_path( ctx.config.lib_dir(), 'package', packageDir) + return util.join_path(ctx.config.packages_dir(), packageDir) def installable(self): """calculate if pkg is installable currently""" diff --git a/pisi/ui.py b/pisi/ui.py index 52d51c57..2343591b 100644 --- a/pisi/ui.py +++ b/pisi/ui.py @@ -74,7 +74,7 @@ class UI(object): "ask a yes/no question" pass - def display_progress(self, pd): + def display_progress(self, **ka): "display progress" pass diff --git a/scripts/lspisi b/scripts/lspisi index ecc621f5..3a7b042c 100755 --- a/scripts/lspisi +++ b/scripts/lspisi @@ -15,9 +15,7 @@ import sys import pisi def show_info(filename): - pisi.api.init(database=False, comar=False) metadata, files = pisi.api.info_file(filename) - pisi.api.finalize() paths = [fileinfo.path for fileinfo in files.list] paths.sort() diff --git a/scripts/unpisi b/scripts/unpisi index ee7478d5..8d7bd128 100755 --- a/scripts/unpisi +++ b/scripts/unpisi @@ -34,8 +34,6 @@ def main(): if len(sys.argv) < 2: usage("PiSi package required..") - pisi.api.init(database=False, options='') - try: arc = ArchiveZip(sys.argv[1], 'zip', 'r') except BadZipfile, e: @@ -53,7 +51,6 @@ def main(): os.unlink(tar_file) os.unlink(tar_file.rstrip('.lzma')) - pisi.api.finalize() return 0 if __name__ == "__main__": diff --git a/setup.py b/setup.py index 9881a82b..9d20d1d6 100755 --- a/setup.py +++ b/setup.py @@ -93,7 +93,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.scenarioapi', 'pisi.db'], + packages = ['pisi', 'pisi.cli', 'pisi.operations', 'pisi.actionsapi', 'pisi.pxml', 'pisi.scenarioapi', 'pisi.db'], scripts = ['pisi-cli', 'scripts/lspisi', 'scripts/unpisi', 'scripts/check-newconfigs.py', 'scripts/revdep-rebuild'], cmdclass = {'install' : Install} ) diff --git a/tests/README b/tests/README index 35feab83..2c3a66f5 100644 --- a/tests/README +++ b/tests/README @@ -1,11 +1,13 @@ -PISI test suite ---------------- +PiSi UnitTests +############## -There are python unit tests and shell scripts in this directory. +Before running unittests you need to first go to repos directory and +create test repositories. -Run the python tests with +>>> pisi@pardus tests/repos# python createrepos.py -$ tests/run.py +Now you can return to tests folder and run tests. + +>>> pisi@pardus tests # python runtests.py -Shell scripts use the CLIs to perform package operations. diff --git a/tests/a.xml b/tests/a.xml deleted file mode 100644 index ee6a6e29..00000000 --- a/tests/a.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - cıvık mantardır bu - Eray Ozkural - 868 - Lazy Tin - Tembel Teneke - pisi - noatun - kdevelop - - 18071976 - AI - - Baris - Gurer - Caglar - Meren - - - diff --git a/tests/actionsapitests.py b/tests/actionsapitests.py deleted file mode 100644 index 85fb5252..00000000 --- a/tests/actionsapitests.py +++ /dev/null @@ -1,338 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2005 - 2007, 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 unittest -import zipfile -import shutil -import os -import pwd -import grp -import time - -import testcase - -class ActionsAPITestCase(testcase.TestCase): - def setUp(self): - from pisi.actionsapi.variables import initVariables - - testcase.TestCase.setUp(self) - initVariables() - #FIXME: test incomplete - return - self.f = zipfile.ZipFile("helloworld-0.1-1.pisi", "r") - self.filelist = [] - - for file in self.f.namelist(): - self.filelist.append(file) - - def testFileList(self): - #FIXME: test incomplete - return - fileContent = ["files.xml", \ - "install/bin/helloworld", \ - "install/opt/PARDUS", \ - "install/opt/helloworld/helloworld", \ - "install/opt/uludag", \ - "install/sbin/helloworld", \ - "install/sys/PARDUS", \ - "install/sys/uludag", \ - "install/usr/bin/goodbye", \ - "install/usr/bin/helloworld", \ - "install/usr/lib/helloworld.o", \ - "install/usr/sbin/goodbye", \ - "install/usr/sbin/helloworld", \ - "install/usr/share/doc/helloworld-0.1-1/Makefile.am", \ - "install/usr/share/doc/helloworld-0.1-1/goodbyeworld.cpp", \ - "install/usr/share/info/Makefile.am", \ - "install/usr/share/info/Makefile.cvs", \ - "install/usr/share/info/Makefile.in", \ - "install/var/goodbye", \ - "install/var/hello", \ - "metadata.xml"] - - '''check number of files in package''' - self.assertEqual(fileContent.__len__(), self.filelist.__len__()) - - '''check file content''' - for file in self.filelist: - self.assert_(fileContent.__contains__(file)) - - def testShelltoolsCanAccessFile(self): - from pisi.actionsapi.shelltools import can_access_file - - self.assert_(can_access_file('tests/actionsapitests/file')) - self.assert_(not can_access_file('tests/actionsapitests/fileX')) - self.assert_(can_access_file('tests/actionsapitests/linktoafile')) - - def testShelltoolsCanAccessDir(self): - from pisi.actionsapi.shelltools import can_access_directory - - self.assert_(can_access_directory('tests/actionsapitests/adirectory')) - self.assert_(not can_access_directory('tests/actionsapitests/adirectoryX')) - self.assert_(can_access_directory('tests/actionsapitests/linktoadirectory')) - - def testShelltoolsMakedirs(self): - from pisi.actionsapi.shelltools import makedirs - - makedirs('tests/actionsapitests/testdirectory/into/a/directory') - self.assertEqual(os.path.exists('tests/actionsapitests/testdirectory/into/a/directory'), True) - shutil.rmtree('tests/actionsapitests/testdirectory') - - def testShelltoolsEcho(self): - from pisi.actionsapi.shelltools import echo - - echo('tests/actionsapitests/echo-file', 'hububat fiyatları') - self.assertEqual(os.path.exists('tests/actionsapitests/echo-file'), True) - self.assertEqual(open('tests/actionsapitests/echo-file').readlines()[0].strip(), "hububat fiyatları") - echo('tests/actionsapitests/echo-file', 'fiyat hububatları') - self.assertEqual(open('tests/actionsapitests/echo-file').readlines()[1].strip(), "fiyat hububatları") - os.remove('tests/actionsapitests/echo-file') - - def testShelltoolsChmod(self): - from pisi.actionsapi.shelltools import chmod - - chmod('tests/actionsapitests/file') - self.assertEqual(oct(os.stat('tests/actionsapitests/file').st_mode)[-3:], '755') - chmod('tests/actionsapitests/file', 0644) - self.assertEqual(oct(os.stat('tests/actionsapitests/file').st_mode)[-3:], '644') - - def testShelltoolsChown(self): - from pisi.actionsapi.shelltools import chown - - f = open('tests/actionsapitests/chowntest', 'w') - f.close() - chown('tests/actionsapitests/chowntest') - self.assertEqual(os.stat('tests/actionsapitests/chowntest').st_uid, pwd.getpwnam('root')[2]) - self.assertEqual(os.stat('tests/actionsapitests/chowntest').st_gid, grp.getgrnam('root')[2]) - chown('tests/actionsapitests/chowntest', 'daemon', 'wheel') - self.assertEqual(os.stat('tests/actionsapitests/chowntest').st_uid, pwd.getpwnam('daemon')[2]) - self.assertEqual(os.stat('tests/actionsapitests/chowntest').st_gid, grp.getgrnam('wheel')[2]) - os.remove('tests/actionsapitests/chowntest') - - def testShelltoolsSym(self): - from pisi.actionsapi.shelltools import sym - - sym('tests/actionsapitests/file', 'tests/actionsapitests/filelnk') - self.assert_(os.path.islink('tests/actionsapitests/filelnk')) - self.assertEqual(os.readlink('tests/actionsapitests/filelnk'), 'tests/actionsapitests/file') - os.remove('tests/actionsapitests/filelnk') - - def testShelltoolsUnlink(self): - from pisi.actionsapi.shelltools import unlink - - f = open('tests/actionsapitests/unlinktest', 'w') - f.close() - os.symlink('tests/actionsapitests/unlinktest', 'tests/actionsapitests/unlinktest-sym') - unlink('tests/actionsapitests/unlinktest') - self.assert_(not os.path.exists('tests/actionsapitests/unlinktest')) - - unlink('tests/actionsapitests/unlinktest-sym') - self.assert_(not os.path.exists('tests/actionsapitests/unlinktest-sym')) - - def testShelltoolsUnlinkDir(self): - from pisi.actionsapi.shelltools import unlinkDir - - os.mkdir('tests/actionsapitests/unlinkdir') - f = open('tests/actionsapitests/unlinkdir/unlinktest', 'w') - f.close() - - #FIXME: unlinkDir cannot unlink a link to a directory. - #Instead it deletes content of linked directory, then leaves directory and link - #unlinkDir('tests/actionsapitests/linktoadirectory') - #self.assert_(not os.path.exists('tests/actionsapitests/linktoadirectory')) - #os.symlink('tests/actionsapitests/linkeddir', 'tests/actionsapitests/linktoadirectory') - - unlinkDir('tests/actionsapitests/unlinkdir') - self.assert_(not os.path.exists('tests/actionsapitests/unlinkdir')) - - def testShelltoolsMove(self): - from pisi.actionsapi.shelltools import move - - move('tests/actionsapitests/brokenlink', 'tests/actionsapitests/brokenlink-move') - self.assert_(os.path.islink('tests/actionsapitests/brokenlink-move')) - self.assertEqual(os.readlink('tests/actionsapitests/brokenlink-move'), '/no/such/place') - self.assert_(not os.path.exists('tests/actionsapitests/brokenlink')) - shutil.move('tests/actionsapitests/brokenlink-move', 'tests/actionsapitests/brokenlink') - - move('tests/actionsapitests/brokenlink', 'tests/actionsapitests/adirectory/brokenlink-move') - self.assert_(os.path.islink('tests/actionsapitests/adirectory/brokenlink-move')) - self.assertEqual(os.readlink('tests/actionsapitests/adirectory/brokenlink-move'), '/no/such/place') - self.assert_(not os.path.exists('tests/actionsapitests/brokenlink')) - shutil.move('tests/actionsapitests/adirectory/brokenlink-move', 'tests/actionsapitests/brokenlink') - - move('tests/actionsapitests/file', 'tests/actionsapitests/adirectory') - self.assert_(os.path.isfile('tests/actionsapitests/adirectory/file')) - self.assertEqual(os.path.getsize('tests/actionsapitests/adirectory/file'), 321) - self.assert_(not os.path.exists('tests/actionsapitests/file')) - shutil.move('tests/actionsapitests/adirectory/file', 'tests/actionsapitests/') - - move('tests/actionsapitests/file', 'tests/actionsapitests/file-move') - self.assert_(os.path.isfile('tests/actionsapitests/file-move')) - self.assertEqual(os.path.getsize('tests/actionsapitests/file-move'), 321) - self.assert_(not os.path.exists('tests/actionsapitests/file')) - shutil.move('tests/actionsapitests/file-move', 'tests/actionsapitests/file') - - move('tests/actionsapitests/file', 'tests/actionsapitests/adirectory/filewithanothername') - self.assert_(os.path.exists('tests/actionsapitests/adirectory/filewithanothername')) - self.assertEqual(os.path.getsize('tests/actionsapitests/adirectory/filewithanothername'), 321) - self.assert_(not os.path.exists('tests/actionsapitests/file')) - shutil.move('tests/actionsapitests/adirectory/filewithanothername', 'tests/actionsapitests/file') - - #FIXME: this type of moving (without changing name) doesn't work - #And I'm not sure the right way is to use 'tests/actionsapitests/adirectory/linkeddir' as dest. - #move('tests/actionsapitests/linkeddir', 'tests/actionsapitests/adirectory') - #self.assert_(os.path.exists('tests/actionsapitests/adirectory/linkeddir/file')) - #self.assertEqual(os.path.getsize('tests/actionsapitests/adirectory/linkeddir/file'), 321) - #shutil.move('tests/actionsapitests/adirectory/linkeddir', 'tests/actionsapitests/linkeddir') - - move('tests/actionsapitests/linkeddir', 'tests/actionsapitests/adirectory/withanothername') - self.assert_(os.path.exists('tests/actionsapitests/adirectory/withanothername/file')) - self.assertEqual(os.path.getsize('tests/actionsapitests/adirectory/withanothername/file'), 321) - shutil.move('tests/actionsapitests/adirectory/withanothername', 'tests/actionsapitests/linkeddir') - - def testShelltoolsCopy(self): - from pisi.actionsapi.shelltools import copy - - copy('tests/actionsapitests/brokenlink', 'tests/actionsapitests/brokenlink-copy') - self.assertEqual(os.path.islink('tests/actionsapitests/brokenlink-copy'), True) - os.remove('tests/actionsapitests/brokenlink-copy') - - copy('tests/actionsapitests/brokenlink', 'tests/actionsapitests/adirectory') - self.assertEqual(os.path.islink('tests/actionsapitests/adirectory/brokenlink'), True) - - copy('tests/actionsapitests/brokenlink', 'tests/actionsapitests/adirectory/brknlnk') - self.assertEqual(os.path.islink('tests/actionsapitests/adirectory/brknlnk'), True) - os.remove('tests/actionsapitests/adirectory/brknlnk') - - self.assertEqual(os.readlink('tests/actionsapitests/adirectory/brokenlink'), '/no/such/place') - os.remove('tests/actionsapitests/adirectory/brokenlink') - - copy('tests/actionsapitests/linktoadirectory', 'tests/actionsapitests/adirectory/', False) - self.assertEqual(os.path.exists('tests/actionsapitests/adirectory/linktoadirectory/file'), True) - self.assertEqual(os.path.getsize('tests/actionsapitests/adirectory/linktoadirectory/file'), 321) - shutil.rmtree('tests/actionsapitests/adirectory/linktoadirectory') - - copy('tests/actionsapitests/file', 'tests/actionsapitests/adirectory') - self.assertEqual(os.path.isfile('tests/actionsapitests/adirectory/file'), True) - #overwrite.. - copy('tests/actionsapitests/file', 'tests/actionsapitests/adirectory') - os.remove('tests/actionsapitests/adirectory/file') - - copy('tests/actionsapitests/linktoafile', 'tests/actionsapitests/adirectory', False) - ourguy = 'tests/actionsapitests/%s' % os.readlink('tests/actionsapitests/linktoafile') - self.assert_(os.path.exists(ourguy)) - - copy('tests/actionsapitests/file', 'tests/actionsapitests/file-copy') - self.assertEqual(os.path.exists('tests/actionsapitests/file-copy'), True) - os.remove('tests/actionsapitests/file-copy') - - copy('tests/actionsapitests/file', 'tests/actionsapitests/adirectory/filewithanothername') - self.assertEqual(os.path.exists('tests/actionsapitests/adirectory/filewithanothername'), True) - os.remove('tests/actionsapitests/adirectory/filewithanothername') - - copy('tests/actionsapitests/linkeddir', 'tests/actionsapitests/adirectory') - self.assertEqual(os.path.exists('tests/actionsapitests/adirectory/linkeddir/file'), True) - shutil.rmtree('tests/actionsapitests/adirectory/linkeddir') - - copy('tests/actionsapitests/linkeddir', 'tests/actionsapitests/adirectory/withanothername') - self.assertEqual(os.path.exists('tests/actionsapitests/adirectory/withanothername/file'), True) - shutil.rmtree('tests/actionsapitests/adirectory/withanothername') - - def testShelltoolsCopyTree(self): - from pisi.actionsapi.shelltools import copytree - - copytree('tests/actionsapitests/linkeddir', 'tests/actionsapitests/adirectory') - self.assert_(os.path.exists('tests/actionsapitests/linkeddir/file')) - self.assertEqual(os.path.getsize('tests/actionsapitests/linkeddir/file'), 321) - self.assert_(os.path.exists('tests/actionsapitests/adirectory/linkeddir/file')) - self.assertEqual(os.path.getsize('tests/actionsapitests/adirectory/linkeddir/file'), 321) - shutil.rmtree('tests/actionsapitests/adirectory/linkeddir') - - copytree('tests/actionsapitests/linkeddir', 'tests/actionsapitests/adirectory/withanothername') - self.assert_(os.path.exists('tests/actionsapitests/linkeddir/file')) - self.assertEqual(os.path.getsize('tests/actionsapitests/linkeddir/file'), 321) - self.assert_(os.path.exists('tests/actionsapitests/adirectory/withanothername/file')) - self.assertEqual(os.path.getsize('tests/actionsapitests/adirectory/withanothername/file'), 321) - shutil.rmtree('tests/actionsapitests/adirectory/withanothername') - - def testShelltoolsTouch(self): - from pisi.actionsapi.shelltools import touch - - touch('tests/actionsapitests/file-touch') - self.assert_(os.path.exists('tests/actionsapitests/file-touch')) - os.remove('tests/actionsapitests/file-touch') - - atime = int(time.time()) - touch('tests/actionsapitests/file') - self.assertEqual(os.path.getsize('tests/actionsapitests/file'), 321) - self.assert_(atime <= os.stat('tests/actionsapitests/file').st_atime) - - def testShelltoolsCd(self): - from pisi.actionsapi.shelltools import cd - - current = os.getcwd() - cd('tests/actionsapitests') - self.assertEqual(os.path.getsize('file'), 321) - cd() - self.assertEqual(os.path.getsize('actionsapitests/file'), 321) - os.chdir(current) - - def testShelltoolsLs(self): - from pisi.actionsapi.shelltools import ls - - self.assertEqual(os.listdir('tests/actionsapitests'), ls('tests/actionsapitests')) - - self.assertEqual(os.listdir('tests/actionsapitests/linkeddir'), ls('tests/actionsapitests/linktoadirectory')) - - self.assertEqual(['tests/actionsapitests/file'], ls('tests/actionsapitests/f*')) - - def testShelltoolsExport(self): - from pisi.actionsapi.shelltools import export - - export('hububat', 'fiyatları') - self.assertEqual(os.environ['hububat'], 'fiyatları') - del(os.environ['hububat']) - - def testShelltoolsIsLink(self): - from pisi.actionsapi.shelltools import isLink - - self.assert_(isLink('tests/actionsapitests/linktoadirectory')) - self.assert_(isLink('tests/actionsapitests/linktoafile')) - self.assert_(isLink('tests/actionsapitests/brokenlink')) - self.assert_(not isLink('tests/actionsapitests/file')) - self.assert_(not isLink('tests/actionsapitests/adirectory')) - - def testShelltoolsIsFile(self): - from pisi.actionsapi.shelltools import isFile - - self.assert_(not isFile('tests/actionsapitests/linktoadirectory')) - self.assert_(not isFile('tests/actionsapitests/linktoafile')) - self.assert_(not isFile('tests/actionsapitests/brokenlink')) - self.assert_(isFile('tests/actionsapitests/file')) - self.assert_(not isFile('tests/actionsapitests/adirectory')) - - def testShelltoolsIsDirectory(self): - from pisi.actionsapi.shelltools import isDirectory - - self.assert_(not isDirectory('tests/actionsapitests/linktoadirectory')) - self.assert_(not isDirectory('tests/actionsapitests/linktoafile')) - self.assert_(not isDirectory('tests/actionsapitests/brokenlink')) - self.assert_(not isDirectory('tests/actionsapitests/file')) - self.assert_(isDirectory('tests/actionsapitests/adirectory')) - - def testShelltoolsSystem(self): - from pisi.actionsapi.shelltools import system as s - - self.assertEqual(os.path.exists('tests/actionsapitests/systest'), False) - s('touch tests/actionsapitests/systest') - self.assertEqual(os.path.exists('tests/actionsapitests/systest'), True) - os.remove('tests/actionsapitests/systest') - -suite = unittest.makeSuite(ActionsAPITestCase) diff --git a/tests/actionsapitests/brokenlink b/tests/actionsapitests/brokenlink deleted file mode 120000 index 8f608d48..00000000 --- a/tests/actionsapitests/brokenlink +++ /dev/null @@ -1 +0,0 @@ -/no/such/place \ No newline at end of file diff --git a/tests/actionsapitests/file b/tests/actionsapitests/file deleted file mode 100644 index 2c435ef3..00000000 --- a/tests/actionsapitests/file +++ /dev/null @@ -1,6 +0,0 @@ -toplam 4 -drwxr-xr-x 2 meren users 4096 Mar 10 12:55 adirectory -lrwxrwxrwx 1 meren users 14 Mar 10 12:41 brokenlink -> /no/such/place --rw-r--r-- 1 meren users 0 Mar 10 12:57 file -lrwxrwxrwx 1 meren users 4 Mar 10 12:42 linktoadirectory -> /etc -lrwxrwxrwx 1 meren users 11 Mar 10 12:42 linktoafile -> /etc/passwd diff --git a/tests/actionsapitests/linkeddir/file b/tests/actionsapitests/linkeddir/file deleted file mode 100644 index 2c435ef3..00000000 --- a/tests/actionsapitests/linkeddir/file +++ /dev/null @@ -1,6 +0,0 @@ -toplam 4 -drwxr-xr-x 2 meren users 4096 Mar 10 12:55 adirectory -lrwxrwxrwx 1 meren users 14 Mar 10 12:41 brokenlink -> /no/such/place --rw-r--r-- 1 meren users 0 Mar 10 12:57 file -lrwxrwxrwx 1 meren users 4 Mar 10 12:42 linktoadirectory -> /etc -lrwxrwxrwx 1 meren users 11 Mar 10 12:42 linktoafile -> /etc/passwd diff --git a/tests/actionsapitests/linktoadirectory b/tests/actionsapitests/linktoadirectory deleted file mode 120000 index 38d37cf7..00000000 --- a/tests/actionsapitests/linktoadirectory +++ /dev/null @@ -1 +0,0 @@ -linkeddir/ \ No newline at end of file diff --git a/tests/actionsapitests/linktoafile b/tests/actionsapitests/linktoafile deleted file mode 120000 index 1a010b1c..00000000 --- a/tests/actionsapitests/linktoafile +++ /dev/null @@ -1 +0,0 @@ -file \ No newline at end of file diff --git a/tests/archivetests.py b/tests/archivetests.py deleted file mode 100644 index a4ea534e..00000000 --- a/tests/archivetests.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os -from os.path import exists as pathexists -from os.path import basename, islink, join - -import pisi.context as ctx -import pisi.api -from pisi import archive -from pisi import sourcearchive -from pisi import fetcher -from pisi import util -from pisi.specfile import SpecFile -from pisi import uri - -import testcase - -class ArchiveFileTestCase(testcase.TestCase): - - def testUnpackTar(self): - spec = SpecFile("tests/popt/pspec.xml") - targetDir = '/tmp/pisitest' - achv = sourcearchive.SourceArchive(spec, targetDir) - - assert spec.source.archive.type == "targz" - - # skip fetching and directly unpack the previously fetched (by - # fetchertests) archive - if not achv.is_cached(interactive=False): - achv.fetch(interactive=False) - achv.unpack() - - # but testing is hard - # "var/tmp/pisi/popt-1.7-3/work" (targetDir) - assert pathexists(targetDir + "/popt-1.7") - - testfile = targetDir + "/popt-1.7/Makefile.am" - assert pathexists(testfile) - - # check file integrity - self.assertEqual(util.sha1_file(testfile), - "5af9dd7d754f788cf511c57ce0af3d555fed009d") - - def testUnpackZip(self): - spec = SpecFile("tests/pccts/pspec.xml") - targetDir = '/tmp/pisitest' - - assert spec.source.archive.type == "zip" - - achv = sourcearchive.SourceArchive(spec, targetDir) - achv.fetch(interactive=False) - achv.unpack(clean_dir=True) - - assert pathexists(targetDir + "/pccts") - - testfile = targetDir + "/pccts/history.txt" - assert pathexists(testfile) - - # check file integrity - self.assertEqual(util.sha1_file(testfile), - "f2be0f9783e84e98fe4e2b8201a8f506fcc07a4d") - -# TODO: no link file in pccts package. Need to find a ZIP file -# containing a symlink - # check for symbolic links -# testfile = targetDir + "/sandbox/testdir/link1" -# assert islink(testfile) - - def testMakeZip(self): - # first unpack our dear sandbox.zip - spec = SpecFile("tests/pccts/pspec.xml") - targetDir = '/tmp/pisitest' - achv = sourcearchive.SourceArchive(spec, targetDir) - achv.fetch(interactive=False) - achv.unpack(clean_dir=True) - del achv - - newZip = targetDir + "/new.zip" - zip = archive.ArchiveZip(newZip, 'zip', 'w') - sourceDir = targetDir + "/pccts" - zip.add_to_archive(sourceDir) - zip.close() - - #TODO: do some more work to test the integrity of new zip file - - def testUnpackZipCond(self): - spec = SpecFile("tests/pccts/pspec.xml") - targetDir = '/tmp' - achv = sourcearchive.SourceArchive(spec, targetDir) - url = uri.URI(spec.source.archive.uri) - filePath = join(ctx.config.archives_dir(), url.filename()) - - # check cached - if util.sha1_file(filePath) != spec.source.archive.sha1sum: - fetch = fetcher.Fetcher(spec.source.archive.uri, targetDir) - fetch.fetch() - assert spec.source.archive.type == "zip" - - achv = archive.Archive(filePath, spec.source.archive.type) - achv.unpack_files(["pccts/history.txt"], targetDir) - assert pathexists(targetDir + "/pccts") - testfile = targetDir + "/pccts/history.txt" - assert pathexists(testfile) - -suite = unittest.makeSuite(ArchiveFileTestCase) diff --git a/tests/autoxmltests.py b/tests/autoxmltests.py deleted file mode 100644 index 836169dd..00000000 --- a/tests/autoxmltests.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os -import xml.dom.minidom as mdom -from xml.parsers.expat import ExpatError -import types - -import pisi -import pisi.api -from pisi.pxml import xmlfile -from pisi.pxml import autoxml -import pisi.util as util - -class AutoXmlTestCase(unittest.TestCase): - - def setUp(self): - - class OtherInfo: - __metaclass__ = autoxml.autoxml - t_BirthDate = [types.StringType, autoxml.mandatory] - t_Interest = [types.StringType, autoxml.optional] - t_CodesWith = [ [types.StringType], autoxml.optional, 'CodesWith/Person'] - - class A(xmlfile.XmlFile): - __metaclass__ = autoxml.autoxml - t_Name = [types.StringType, autoxml.mandatory] - t_Description = [autoxml.LocalText, autoxml.mandatory] - t_Number = [types.IntType, autoxml.optional] - t_Email = [types.StringType, autoxml.optional] - a_href = [types.StringType, autoxml.mandatory] - t_Projects = [ [types.StringType], autoxml.mandatory, 'Project'] - t_OtherInfo = [ OtherInfo, autoxml.optional ] - s_Comment = [ autoxml.Text, autoxml.mandatory] - - self.A = A - - def testDeclaration(self): - self.assertEqual(len(self.A.decoders), 8) # how many fields in A? - self.assert_(hasattr(self.A, 'encode')) - - def testReadWrite(self): - a = self.A() - - # test initializer - self.assertEqual(a.href, None) - - # test read - a.read('tests/a.xml') - self.assert_(a.href.startswith('http')) - self.assertEqual(a.number, 868) - self.assertEqual(a.name, 'Eray Ozkural') - self.assertEqual(len(a.projects), 3) - self.assertEqual(len(a.otherInfo.codesWith), 4) - - self.assert_(not a.errors()) - - a.print_text(file('/tmp/a', 'w')) - la = file('/tmp/a').readlines() - self.assert_( util.any(lambda x:x.find('18071976')!=-1, la) ) - a.write('/tmp/a.xml') - - def testWriteRead(self): - a = self.A() - a.name = "Baris Metin" - a.email = "baris@uludag.org.tr" - a.description['tr'] = u'Melek, melek' - a.comment = u'Bu da zibidi aslinda ama caktirmiyor' - a.href = 'http://cekirdek.uludag.org.tr/~baris' - a.otherInfo.birthDate = '30101979' - a.projects = [ 'pisi', 'tasma', 'plasma' ] - errs = a.errors() - if errs: - self.fail( 'We got a bunch of errors: ' + str(errs)) - a.write('/tmp/a2.xml') - a2 = self.A() - a2.read('/tmp/a2.xml') - self.assertEqual(a, a2) - -class LocalTextTestCase(unittest.TestCase): - - def setUp(self): - a = autoxml.LocalText() - a['tr'] = u'Zibidi' - a['en'] = u'ingiliz hiyarlari ne anlar zibididen' - self.a = a - - def testStr(self): - s = str(self.a) - self.assert_(s!= None and len(s)>=6) - -suite1 = unittest.makeSuite(AutoXmlTestCase) -suite2 = unittest.makeSuite(LocalTextTestCase) -suite = unittest.TestSuite((suite1, suite2)) diff --git a/tests/build.sh b/tests/build.sh deleted file mode 100755 index a1276006..00000000 --- a/tests/build.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh - -echo "beta functionality test script" -echo "working directory:" `pwd` -echo "cleaning destination dir: tmp" -PATH=$PATH:. -set -x # xtrace -set -e # errexit -rm -rf tmp -#echo "*** build tests" -pisi-cli -Dtmp build http://svn.uludag.org.tr/pardus/devel/system/base/zip/pspec.xml http://svn.uludag.org.tr/pardus/devel/system/base/unzip/pspec.xml - -#partial-builds -pisi-cli -Dtmp build --until=setup http://svn.uludag.org.tr/pardus/devel/system/base/hdparm/pspec.xml -pisi-cli -Dtmp build --until=build http://svn.uludag.org.tr/pardus/devel/system/base/hdparm/pspec.xml -pisi-cli -Dtmp build --until=install http://svn.uludag.org.tr/pardus/devel/system/base/hdparm/pspec.xml -pisi-cli -Dtmp build --until=package http://svn.uludag.org.tr/pardus/devel/system/base/hdparm/pspec.xml - -#echo "*** repository tests" - -pisi-cli -Dtmp index . -pisi-cli -Dtmp add-repo repo1 pisi-index.xml -pisi-cli -Dtmp update-repo repo1 -pisi-cli -Dtmp list-repo - -#echo "*** package ops" -pisi-cli -Dtmp info *.pisi -# pisi-cli list-available -pisi-cli -Dtmp install --ignore-comar zip -pisi-cli -Dtmp list-installed -pisi-cli -Dtmp remove --ignore-comar unzip -pisi-cli -Dtmp install --ignore-comar zip*.pisi -pisi-cli -Dtmp install --ignore-comar hdparm*.pisi flex*.pisi grep*.pisi -pisi-cli -Dtmp remove-repo repo1 -# pisi-cli list-available - -echo "*** database contents" -for x in `find tmp -iname '*.bdb'`; do - echo "contents of database " $x; - tools/cat-db.py $x; -done diff --git a/tests/buildtests.py b/tests/buildtests.py deleted file mode 100644 index c9a8e205..00000000 --- a/tests/buildtests.py +++ /dev/null @@ -1,59 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2005 - 2007, 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 unittest -import shutil -import glob -import os - -import testcase -from pisi.build import * - -class BuildTestCase(testcase.TestCase): - - def cleanOutput(self): - for x in glob.glob('tmp/a*.pisi'): - os.unlink(x) - - def setUp(self): - options = pisi.config.Options() - options.ignore_build_no = False - options.output_dir = 'tmp' - self.cleanOutput() - testcase.TestCase.setUp(self, options = options) - pisi.context.config.values.build.buildno = True - - def testBasicBuild(self): - shutil.copy('tests/buildtests/a/actions.py-1', 'tests/buildtests/a/actions.py') - pspec = 'tests/buildtests/a/pspec.xml' - pb = Builder(pspec) - pb.build() - self.assert_(os.path.exists('tmp/a-1.0-1-1.pisi')) - - def testBuildNumber(self): - self.cleanOutput() - self.testBasicBuild() - - pspec = 'tests/buildtests/a/pspec.xml' - shutil.copy('tests/buildtests/a/actions.py-2', 'tests/buildtests/a/actions.py') - pb = Builder(pspec) - pb.build() - self.assert_(os.path.exists('tmp/a-1.0-1-2.pisi')) - - pb = Builder(pspec) - pb.build() - # because nothing is changed - self.assert_(not os.path.exists('tmp/a-1.0-1-3.pisi')) - - os.remove('tests/buildtests/a/actions.py') - os.remove('tmp/a-1.0-1-2.pisi') - -suite = unittest.makeSuite(BuildTestCase) diff --git a/tests/buildtests/a/actions.py-1 b/tests/buildtests/a/actions.py-1 deleted file mode 100644 index 5a87e4b4..00000000 --- a/tests/buildtests/a/actions.py-1 +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright 2005 TUBITAK/UEKAE -# Licensed under the GNU General Public License, version 2. -# See the file http://www.gnu.org/copyleft/gpl.txt. -# -# A. Murat Eren - -from pisi.actionsapi import pisitools - -WorkDir = "merhaba-pisi-1.0" - -def install(): - pisitools.dobin("merhaba-pisi.py") - - pisitools.rename("/usr/bin/merhaba-pisi.py", "merhaba-pisi") - - pisitools.dosym("./merhaba-pisi", "/usr/bin/justasysmlink") - pisitools.dosym("/thre/is/no/such/place", "/usr/bin/justabrokensymlink") diff --git a/tests/buildtests/a/actions.py-2 b/tests/buildtests/a/actions.py-2 deleted file mode 100644 index c8575662..00000000 --- a/tests/buildtests/a/actions.py-2 +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright 2005 TUBITAK/UEKAE -# Licensed under the GNU General Public License, version 2. -# See the file http://www.gnu.org/copyleft/gpl.txt. -# -# A. Murat Eren - -from pisi.actionsapi import pisitools - -WorkDir = "merhaba-pisi-1.0" - -def install(): - pisitools.dobin("merhaba-pisi.py") - - pisitools.rename("/usr/bin/merhaba-pisi.py", "merhaba-pisi") - - pisitools.dosym("./merhaba-pisi", "/usr/bin/justasysmlink") - pisitools.dosym("/thre/is/no/such", "/usr/bin/justabrokensymlink") diff --git a/tests/buildtests/a/pspec.xml b/tests/buildtests/a/pspec.xml deleted file mode 100644 index cb49b179..00000000 --- a/tests/buildtests/a/pspec.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - a - http://cekirdek.uludag.org.tr/~meren/merhaba-pisi.php - - A. Murat Eren - meren@uludag.org.tr - - As-Is - None - app:console - PiSi Hello World Application.. - PiSi için merhaba dünya uygulaması, süper bir konsol uygulaması - Just a basic application. Nothing to describe. - Sadece basit bir uygulama, açıklayacak bir şey yok - http://cekirdek.uludag.org.tr/~meren/merhaba-pisi-1.0.tar.gz - - - - a - - /usr/bin/ - - - - - - - 2006-02-01 - 1.0 - First release. - A. Murat Eren - meren@uludag.org.tr - - - diff --git a/tests/configfiletests.py b/tests/configfiletests.py deleted file mode 100644 index 95c0637d..00000000 --- a/tests/configfiletests.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest - -from pisi.configfile import ConfigurationFile - -# NB: no need for pisi testcase in these things that do well without pisi init -class ConfigFileTestCase(unittest.TestCase): - - def setUp(self): - self.cf = ConfigurationFile("tests/pisi.conf") - - def testSections(self): - cf = self.cf - if not cf.general: - self.fail("No 'general' section found in ConfigurationFile") - if not cf.build: - self.fail("No 'build' section found in ConfigurationFile") - if not cf.dirs: - self.fail("No 'dirs' section found in ConfigurationFile") - - def testValues(self): - cf = self.cf - - # test values from pisi.conf file - self.assertEqual(cf.general.destinationdirectory, "/testing") - self.assertEqual(cf.dirs.archives_dir, "/disk2/pisi/archives") - - # test default values - self.assertEqual(cf.dirs.tmp_dir, "/var/pisi") - - def testAccessMethods(self): - cf = self.cf - - self.assertEqual(cf.build.host, cf.build["host"]) - self.assertEqual(cf.dirs.index_dir, cf.dirs["index_dir"]) - - def testFlagsExists(self): - cf = self.cf - - #build - self.assert_(cf.build.cflags) - self.assert_(cf.build.cxxflags) - - #general - self.assert_(cf.general.destinationdirectory) - - #dirs - self.assert_(cf.dirs.index_dir) - self.assert_(cf.dirs.tmp_dir) - self.assert_(cf.dirs.packages_dir) - -suite = unittest.makeSuite(ConfigFileTestCase) diff --git a/tests/constantstests.py b/tests/constantstests.py deleted file mode 100644 index 77c1cc3e..00000000 --- a/tests/constantstests.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest - -import pisi.context as ctx - -class ContextTestCase(unittest.TestCase): - - def testConstness(self): - const = ctx.const - - # test if we can get a const attribute? - try: - test = const.package_suffix - self.assertNotEqual(test, "") - except AttributeError: - self.fail("Couldn't get const attribute") - - # test binding a new constant - const.test = "test binding" - - # test re-binding (which is illegal) - try: - const.test = "test rebinding" - # we shouldn't reach here - self.fail("Rebinding a constant works. Something is wrong!") - except: - # we achived our goal with this error. infact, this is a - # ConstError but we can't catch it directly here - pass - - # test unbinding (which is also illegal) - try: - del const.test - # we shouldn't reach here - self.fail("Unbinding a constant works. Something is wrong!") - except: - # we achived our goal with this error. infact, this is a - # ConstError but we can't catch it directly here - pass - - def testConstValues(self): - const = ctx.const - - constDict = { - "actions_file": "actions.py", - "setup_func": "setup", - "metadata_xml": "metadata.xml" - } - - for k in constDict.keys(): - if hasattr(const, k): - value = getattr(const, k) - self.assertEqual(value, constDict[k]) - else: - self.fail("Constants does not have an attribute named %s" % k) - - -suite = unittest.makeSuite(ContextTestCase) diff --git a/tests/database/.gitignore b/tests/database/.gitignore new file mode 100644 index 00000000..0d20b648 --- /dev/null +++ b/tests/database/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/tests/database/__init__.py b/tests/database/__init__.py new file mode 100644 index 00000000..e38d4de3 --- /dev/null +++ b/tests/database/__init__.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007, 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. +# diff --git a/tests/database/componentdbtest.py b/tests/database/componentdbtest.py new file mode 100644 index 00000000..ba0b63af --- /dev/null +++ b/tests/database/componentdbtest.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007, 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 testcase +import pisi + +class ComponentDBTestCase(testcase.TestCase): + + componentdb = pisi.db.componentdb.ComponentDB() + + def testHasComponent(self): + assert self.componentdb.has_component("system.base", "pardus-2007") + assert not self.componentdb.has_component("hede.hodo", "pardus-2007") + assert self.componentdb.has_component("applications.network", "contrib-2007") + assert not self.componentdb.has_component("hede.hodo", "contrib-2007") + assert self.componentdb.has_component("applications.network") + + def testListComponents(self): + assert set(self.componentdb.list_components("pardus-2007")) == set(["system", "system.base", + "applications", "applications.network"]) + assert set(self.componentdb.list_components("contrib-2007")) == set(["applications", "applications.util", + "applications.network"]) + assert set(self.componentdb.list_components()) == set(["system", "system.base", + "applications", "applications.network", + "applications.util"]) + + def testGetComponent(self): + component = self.componentdb.get_component("applications.network") + assert component.name == "applications.network" + assert "ncftp" in component.packages + assert "lynx" not in component.packages + + component = self.componentdb.get_component("applications.network", "contrib-2007") + assert component.name == "applications.network" + assert "lynx" in component.packages + assert "ncftp" not in component.packages + + def testGetUnionComponent(self): + component = self.componentdb.get_union_component("applications.network") + assert component.name == "applications.network" + assert "lynx" in component.packages + assert "ncftp" in component.packages + + def testGetPackages(self): + packages = self.componentdb.get_packages("applications.network") + assert "ncftp" in packages + assert "lynx" not in packages + + packages = self.componentdb.get_packages("applications.network", "contrib-2007") + assert "lynx" in packages + assert "ncftp" not in packages + + packages = self.componentdb.get_packages("applications", "contrib-2007", walk = True) + assert "cpulimit" and "lynx" in packages + assert "ncftp" not in packages + + def testGetUnionPackages(self): + packages = self.componentdb.get_union_packages("applications.network") + assert "ncftp" in packages + assert "lynx" in packages + assert "cpulimit" not in packages + + packages = self.componentdb.get_union_packages("applications", walk = True) + assert "ncftp" and "lynx" and "cpulimit" in packages + + def testSearchComponent(self): + packages = self.componentdb.search_component(["applic"]) + assert set(packages) == set(['applications', 'applications.network', 'applications.util']) + + packages = self.componentdb.search_component(["system", "base"], repo="pardus-2007") + assert set(packages) == set(["system.base"]) + + packages = self.componentdb.search_component(["system", "base"], repo="contrib-2007") + assert not packages diff --git a/tests/database/filesdbtest.py b/tests/database/filesdbtest.py new file mode 100644 index 00000000..2aaf87aa --- /dev/null +++ b/tests/database/filesdbtest.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007, 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 testcase +import pisi + +class FilesDBTestCase(testcase.TestCase): + + filesdb = pisi.db.filesdb.FilesDB() + + def testHasFile(self): + assert not self.filesdb.has_file("usr/bin/ethtool") + pisi.api.install(["ethtool"]) + assert self.filesdb.has_file("usr/bin/ethtool") + pisi.api.remove(["ethtool"]) + assert not self.filesdb.has_file("usr/bin/ethtool") + + def testGetFile(self): + pisi.api.install(["ethtool"]) + pkg, path = self.filesdb.get_file("usr/bin/ethtool") + assert pkg == "ethtool" + assert path == "usr/bin/ethtool" + pisi.api.remove(["ethtool"]) + assert not self.filesdb.has_file("usr/bin/ethtool") + + def testAddRemoveFiles(self): + fileinfo1 = pisi.files.FileInfo() + fileinfo1.path = "etc/pisi/pisi.conf" + fileinfo2 = pisi.files.FileInfo() + fileinfo2.path = "etc/pisi/mirrors.conf" + + files = pisi.files.Files() + files.list.append(fileinfo1) + files.list.append(fileinfo2) + + assert not self.filesdb.has_file("etc/pisi/pisi.conf") + assert not self.filesdb.has_file("etc/pisi/mirrors.conf") + + self.filesdb.add_files("pisi", files) + + assert self.filesdb.has_file("etc/pisi/pisi.conf") + assert self.filesdb.has_file("etc/pisi/mirrors.conf") + + pkg, path = self.filesdb.get_file("etc/pisi/pisi.conf") + assert pkg == "pisi" + + # FIXME: inconsistency in filesdb.py add_remove and remove_remove parameters + self.filesdb.remove_files(files.list) + + assert not self.filesdb.has_file("etc/pisi/pisi.conf") + assert not self.filesdb.has_file("etc/pisi/mirrors.conf") + + def testSearchFile(self): + assert not self.filesdb.search_file("ethtool") + pisi.api.install(["ethtool"]) + found = self.filesdb.search_file("ethtool") + pkg, files = found[0] + assert set(files) == set(['usr/bin/ethtool']) + pisi.api.remove(["ethtool"]) diff --git a/tests/database/installdbtest.py b/tests/database/installdbtest.py new file mode 100644 index 00000000..81c21cba --- /dev/null +++ b/tests/database/installdbtest.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007, 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 testcase +import pisi + +class InstallDBTestCase(testcase.TestCase): + + installdb = pisi.db.installdb.InstallDB() + + def testGetPackage(self): + pisi.api.install(["ethtool"]) + pkg = self.installdb.get_package("ethtool") + assert type(pkg) == pisi.metadata.Package + assert pkg.name == "ethtool" + pisi.api.remove(["ethtool"]) + + def testHasPackage(self): + pisi.api.install(["ethtool"]) + assert not self.installdb.has_package("hedehodo") + assert self.installdb.has_package("ethtool") + pisi.api.remove(["ethtool"]) + + def testListInstalled(self): + pisi.api.install(["ethtool"]) + assert set(self.installdb.list_installed()) == set(['zlib', 'pam', 'shadow', + 'jpeg', 'libidn', 'db4', + 'cracklib', 'openssl', + 'curl', 'bash', 'ethtool']) + pisi.api.remove(["ethtool"]) + + def testGetVersion(self): + pisi.api.install(["ethtool"]) + version, release, build = self.installdb.get_version("zlib") + assert version == "0.3" + assert release == "1" + assert build == None + pisi.api.remove(["ethtool"]) + + def testGetFiles(self): + pisi.api.install(["ethtool"]) + files = self.installdb.get_files("ethtool") + assert files.list[0].path == "usr/bin/ethtool" + pisi.api.remove(["ethtool"]) + + def testGetInfo(self): + pisi.api.install(["ethtool"]) + info = self.installdb.get_info("ethtool") + assert info.__class__ == pisi.db.installdb.InstallInfo + assert info.distribution == "Pardus" + pisi.api.remove(["ethtool"]) + + def testGetReverseDependencies(self): + pisi.api.install(["ethtool"]) + pisi.api.install(["ctorrent"]) + + revdeps = self.installdb.get_rev_deps("openssl") + assert set(["ctorrent", "curl"]) == set(map(lambda x:x[0], revdeps)) + + pisi.api.remove(["ctorrent"]) + pisi.api.remove(["ethtool"]) + + def testAddRemovePackage(self): + pisi.api.install(["ctorrent"]) + assert self.installdb.has_package("ctorrent") + assert not self.installdb.has_package("ethtool") + pisi.api.install(["ethtool"]) + assert self.installdb.has_package("ctorrent") + assert self.installdb.has_package("ethtool") + pisi.api.remove(["ctorrent"]) + pisi.api.remove(["ethtool"]) + + def testMarkListPending(self): + pisi.api.set_comar(False) + assert not self.installdb.has_package("ethtool") + pisi.api.install(["ethtool"]) + assert "ethtool" in self.installdb.list_pending() + pisi.api.remove(["ethtool"]) + assert "ethtool" not in self.installdb.list_pending() + pisi.api.set_comar(True) + + def testClearPending(self): + pisi.api.set_comar(False) + assert not self.installdb.has_package("ethtool") + pisi.api.install(["ethtool"]) + assert "ethtool" in self.installdb.list_pending() + self.installdb.clear_pending("ethtool") + assert "ethtool" not in self.installdb.list_pending() + pisi.api.remove(["ethtool"]) + assert "ethtool" not in self.installdb.list_pending() + pisi.api.set_comar(True) + + def testSearchPackage(self): + pisi.api.set_comar(False) + + assert not self.installdb.has_package("ethtool") + assert not self.installdb.search_package(["ethtool"]) + pisi.api.install(["ethtool"]) + assert self.installdb.search_package(["et", "tool", "h"]) == ["ethtool"] + pisi.api.remove(["ethtool"]) + + pisi.api.set_comar(True) diff --git a/tests/database/itembyrepotest.py b/tests/database/itembyrepotest.py new file mode 100644 index 00000000..205fb4db --- /dev/null +++ b/tests/database/itembyrepotest.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007, 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 testcase +import pisi.db.itembyrepo + +class TestDB: + def __init__(self): + self.packages = {} + self.obsoletes = {} + + self.packages["pardus-2007"] = {"aggdraw":"package aggdraw", + "acpica":"package acpica"} + self.packages["contrib-2007"] = {"kdiff3":"package kdiff3", + "kmess":"package kmess"} + + self.obsoletes["pardus-2007"] = ["wengophone", "rar"] + self.obsoletes["contrib-2007"] = ["xara"] + + self.tdb = pisi.db.itembyrepo.ItemByRepo(self.packages) + self.odb = pisi.db.itembyrepo.ItemByRepo(self.obsoletes) + + # original item_repos in ItemByRepo uses repodb.list_repos + def item_repos(repo=None): + repos = ["pardus-2007", "contrib-2007"] + if repo: + repos = [repo] + return repos + + self.tdb.item_repos = item_repos + self.odb.item_repos = item_repos + +class ItemByRepoTestCase(testcase.TestCase): + + testdb = TestDB() + + def testHasRepository(self): + assert self.testdb.tdb.has_repo("pardus-2007") + assert self.testdb.tdb.has_repo("contrib-2007") + assert not self.testdb.tdb.has_repo("hedehodo") + + def testHasItem(self): + assert self.testdb.tdb.has_item("kdiff3", "contrib-2007") + assert not self.testdb.tdb.has_item("kdiff3", "pardus-2007") + assert self.testdb.tdb.has_item("acpica") + + def testWhichRepo(self): + assert self.testdb.tdb.which_repo("acpica") == "pardus-2007" + assert self.testdb.tdb.which_repo("kmess") == "contrib-2007" + + def testGetItemAndRepository(self): + pkg, repo = self.testdb.tdb.get_item_repo("acpica") + assert pkg == "package acpica" + assert repo == "pardus-2007" + + pkg, repo = self.testdb.tdb.get_item_repo("kmess") + assert pkg == "package kmess" + assert repo == "contrib-2007" + + def testItemRepos(self): + db = pisi.db.itembyrepo.ItemByRepo({}) + assert db.item_repos("caracal") == ["caracal"] + # repos were created by testcase.py + assert db.item_repos() == ['pardus-2007', 'contrib-2007', 'pardus-2007-src'] + + def testGetItem(self): + assert self.testdb.tdb.get_item("acpica") == "package acpica" + assert self.testdb.tdb.get_item("kmess") == "package kmess" + + def testGetItemOfRepository(self): + assert self.testdb.tdb.get_item("acpica", "pardus-2007") == "package acpica" + assert self.testdb.tdb.get_item("kmess", "contrib-2007") == "package kmess" + + def testGetItemKeys(self): + assert set(self.testdb.tdb.get_item_keys("pardus-2007")) == set(["aggdraw", "acpica"]) + assert set(self.testdb.tdb.get_item_keys("contrib-2007")) == set(["kdiff3", "kmess"]) + assert set(self.testdb.tdb.get_item_keys()) == set(["kdiff3", "kmess", "aggdraw", "acpica"]) + + def testGetListItem(self): + assert set(self.testdb.odb.get_list_item("pardus-2007")) == set(['rar', 'wengophone']) + assert set(self.testdb.odb.get_list_item("contrib-2007")) == set(['xara']) + assert set(self.testdb.odb.get_list_item()) == set(['rar', 'xara', 'wengophone']) diff --git a/tests/database/lazydbtest.py b/tests/database/lazydbtest.py new file mode 100644 index 00000000..01fc0af8 --- /dev/null +++ b/tests/database/lazydbtest.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007, 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 unittest +import pisi.db.lazydb as lazydb + +class TestDB(lazydb.LazyDB): + + def init(self): + self.testfield = True + + def getTestField(self): + return self.testfield + +class LazyDBTestCase(unittest.TestCase): + + def testDatabaseMethodForcingInit(self): + db = TestDB() + db.getTestField() + assert db.__dict__.has_key("testfield") + del TestDB._the_instance + + def testDatabaseWithoutInit(self): + db = TestDB() + assert not db.__dict__.has_key("testfield") + del TestDB._the_instance + + def testSingletonBehaviour(self): + db = TestDB() + db2 = TestDB() + assert id(db) == id(db2) + diff --git a/tests/database/packagedbtest.py b/tests/database/packagedbtest.py new file mode 100644 index 00000000..fe6e56cb --- /dev/null +++ b/tests/database/packagedbtest.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007, 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 testcase +import pisi + +class PackageDBTestCase(testcase.TestCase): + + packagedb = pisi.db.packagedb.PackageDB() + + def testGetPackage(self): + pkg = self.packagedb.get_package("ncftp", "pardus-2007") + assert pkg.name == "ncftp" + + pkg = self.packagedb.get_package("lynx", "contrib-2007") + assert pkg.name == "lynx" + + pkg = self.packagedb.get_package("cpulimit") + assert pkg.name == "cpulimit" + + def testHasPackage(self): + assert self.packagedb.has_package("ncftp", "pardus-2007") + assert not self.packagedb.has_package("ncftp", "contrib-2007") + assert self.packagedb.has_package("lynx") + + def testGetVersion(self): + version, release, build = self.packagedb.get_version("lynx", "contrib-2007") + assert version == "0.3" + assert release == "1" + + def testWhichRepo(self): + assert self.packagedb.which_repo("lynx") == "contrib-2007" + + def testGetPackageAndRepository(self): + pkg, repo = self.packagedb.get_package_repo("cpulimit") + assert pkg.name == "cpulimit" + assert repo == "contrib-2007" + + def testGetObsoletes(self): + assert set(self.packagedb.get_obsoletes("pardus-2007")) == set(["wengophone", "rar"]) + assert set(self.packagedb.get_obsoletes("contrib-2007")) == set(["xara"]) + assert set(self.packagedb.get_obsoletes()) == set(["wengophone", "rar", "xara"]) + + def testGetReverseDependencies(self): + pkg, dep = self.packagedb.get_rev_deps("openssl")[0] + assert pkg == "curl" + assert str(dep) == "openssl" + + def testGetReplaces(self): + # FIXME: update createrepo.py to generate replaces + assert not self.packagedb.get_replaces() + + def testListPackages(self): + assert set(self.packagedb.list_packages("pardus-2007")) == set(['nfdump', 'ethtool', 'ncftp', + 'libidn', 'zlib', 'db4', 'openssl', + 'jpeg', 'pam', 'shadow', 'bogofilter', + 'curl', 'gsl', 'bash', 'cracklib']) + + assert set(self.packagedb.list_packages("contrib-2007")) == set(['libpcap', 'ctorrent', 'lft', 'lynx', + 'iat', 'cpulimit', 'rpl']) + + def testSearchPackage(self): + packages = self.packagedb.search_package(["bogo", "filter"]) + packages = ["bogofilter"] + + packages = self.packagedb.search_package(["cpu", "limit"], repo="contrib-2007") + packages = ["cpulimit"] diff --git a/tests/database/repodbtest.py b/tests/database/repodbtest.py new file mode 100644 index 00000000..f5bcb1c4 --- /dev/null +++ b/tests/database/repodbtest.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007, 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 testcase +import pisi + +class RepoDBTestCase(testcase.TestCase): + + repodb = pisi.db.repodb.RepoDB() + + def testAddRemoveRepo(self): + assert "contrib-2007-src" not in self.repodb.list_repos() + repo = pisi.db.repodb.Repo(pisi.uri.URI("repos/contrib-2007/pisi-index.xml.bz2")) + self.repodb.add_repo("contrib-2007-src", repo) + assert "contrib-2007-src" in self.repodb.list_repos() + self.repodb.remove_repo("contrib-2007-src") + assert "contrib-2007" in self.repodb.list_repos() + assert "pardus-2007" in self.repodb.list_repos() + assert "contrib-2007-src" not in self.repodb.list_repos() + + def testAddRemoveCycle(self): + for r in range(30): + assert "test-repo" not in self.repodb.list_repos() + repo = pisi.db.repodb.Repo(pisi.uri.URI("http://test-repo/pisi-index.xml.bz2")) + self.repodb.add_repo("test-repo", repo) + assert "test-repo" in self.repodb.list_repos() + self.repodb.remove_repo("test-repo") + + assert "test-repo" not in self.repodb.list_repos() + + def testListRepos(self): + assert set(self.repodb.list_repos()) == set(['pardus-2007', 'contrib-2007', 'pardus-2007-src']) + + def testGetSourceRepos(self): + assert set(self.repodb.get_source_repos()) == set(['pardus-2007-src']) + + def testGetBinaryRepos(self): + assert set(self.repodb.get_binary_repos()) == set(['pardus-2007', 'contrib-2007']) + + def testGetRepo(self): + repo = self.repodb.get_repo("pardus-2007") + uri = repo.indexuri + assert uri.get_uri() == "repos/pardus-2007-bin/pisi-index.xml.bz2" + + def testRepoOrder(self): + repoorder = pisi.db.repodb.RepoOrder() + assert repoorder.get_order() == ['pardus-2007', 'contrib-2007', 'pardus-2007-src'] + + repoorder.add("test-repo", "http://test-repo/pisi-index.xml.bz2") + assert repoorder.get_order() == ['pardus-2007', 'contrib-2007', 'pardus-2007-src', 'test-repo'] + + repoorder.remove("test-repo") + assert repoorder.get_order() == ['pardus-2007', 'contrib-2007', 'pardus-2007-src'] diff --git a/tests/database/sourcedbtest.py b/tests/database/sourcedbtest.py new file mode 100644 index 00000000..4295db34 --- /dev/null +++ b/tests/database/sourcedbtest.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007, 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 testcase +import pisi + +class SourceDBTestCase(testcase.TestCase): + + sourcedb = pisi.db.sourcedb.SourceDB() + + def testListSources(self): + assert set(self.sourcedb.list_sources()) == set(['ethtool', 'nfdump', 'shadow', 'libidn', + 'zlib', 'db4', 'openssl', 'jpeg', 'gsl', + 'curl', 'bogofilter', 'ncftp', 'pam', + 'bash', 'cracklib']) + + def testHasSpec(self): + assert self.sourcedb.has_spec("ethtool") + assert not self.sourcedb.has_spec("hedehodo") + + def testGetSpec(self): + spec = self.sourcedb.get_spec("ethtool") + assert spec.source.name == "ethtool" + assert spec.source.partOf == "applications.network" + + def testGetSpecOfRepository(self): + spec = self.sourcedb.get_spec("ethtool", "pardus-2007-src") + assert spec.source.name == "ethtool" + assert spec.source.partOf == "applications.network" + + def testGetSpecAndRepository(self): + spec, repo = self.sourcedb.get_spec_repo("ethtool") + assert spec.source.name == "ethtool" + assert spec.source.partOf == "applications.network" + assert repo == "pardus-2007-src" + + def testGetSourceFromPackage(self): + # FIXME: Add multi package from source to createrepo.py + pkg = self.sourcedb.pkgtosrc("cracklib") + assert pkg == "cracklib" + + def testSearchPackage(self): + packages = self.sourcedb.search_spec(["open", "ssl"]) + assert set(["openssl"]) == set(packages) + + packages = self.sourcedb.search_spec(["bogo", "filter"], repo="pardus-2007-src") + assert set(["bogofilter"]) == set(packages) + + diff --git a/tests/database/testcase.py b/tests/database/testcase.py new file mode 100644 index 00000000..765b1367 --- /dev/null +++ b/tests/database/testcase.py @@ -0,0 +1,21 @@ +import unittest + +import pisi + +class TestCase(unittest.TestCase): + + def setUp(self): + options = pisi.config.Options() + options.ignore_build_no = False + options.destdir = 'repos/tmp' + pisi.api.set_options(options) + pisi.api.set_comar(False) + + if not pisi.api.list_repos(): + pisi.api.add_repo("pardus-2007", "repos/pardus-2007-bin/pisi-index.xml.bz2") + pisi.api.add_repo("contrib-2007", "repos/contrib-2007-bin/pisi-index.xml.bz2") + pisi.api.add_repo("pardus-2007-src", "repos/pardus-2007/pisi-index.xml.bz2") + pisi.api.update_repo("pardus-2007") + pisi.api.update_repo("contrib-2007") + pisi.api.update_repo("pardus-2007-src") + diff --git a/tests/dependencytests.py b/tests/dependencytests.py deleted file mode 100644 index 25452fc2..00000000 --- a/tests/dependencytests.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os - -from pisi.dependency import * - -class DependencyTestCase(unittest.TestCase): - def setUp(self): - pass - - def testVersionFrom(self): - # a real life story bug #603 - gtkmmdep = Dependency() - gtkmmdep.versionFrom = '1.9.1' - gtkmmdep.package = 'atk' - self.assert_( not gtkmmdep.satisfies_relation('atk', '1.8.0', '1') ) - self.assert_( gtkmmdep.satisfies_relation('atk', '1.9.1', '2') ) - self.assert_( gtkmmdep.satisfies_relation('atk', '1.10.5', '3') ) - - def testReleaseFrom(self): - # releaseFrom isn't taken into account #2294 - dep = Dependency() - dep.releaseFrom = '121' - dep.package = 'dbus' - self.assert_(not dep.satisfies_relation('dbus', '1.2', '2')) - - def testReleaseTo(self): - dep = Dependency() - dep.releaseTo = '22' - dep.package = 'dbus' - self.assert_(not dep.satisfies_relation('dbus', '1.2', '25')) - - def testReleaseIs(self): - dep = Dependency() - dep.release = '42' - dep.package = 'dbus' - self.assert_(dep.satisfies_relation('dbus', '1.2', '42')) - -suite = unittest.makeSuite(DependencyTestCase) diff --git a/tests/distribution.xml b/tests/distribution.xml deleted file mode 100644 index ff3f04d6..00000000 --- a/tests/distribution.xml +++ /dev/null @@ -1,6 +0,0 @@ - - Pardus-Devel - 1.1 - Devel - Core - diff --git a/tests/fetchertests.py b/tests/fetchertests.py deleted file mode 100644 index 80272ec1..00000000 --- a/tests/fetchertests.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import shutil -import os - -import pisi.context as ctx -import pisi.api -from pisi.specfile import SpecFile -from pisi import fetcher -from pisi import util -from pisi import uri - -import testcase -class FetcherTestCase(testcase.TestCase): - def setUp(self): - testcase.TestCase.setUp(self, database = False) - - self.spec = SpecFile() - self.spec.read("tests/helloworld/pspec.xml") - self.url = uri.URI(self.spec.source.archive.uri) - self.destpath = ctx.config.archives_dir() - self.fetch = fetcher.Fetcher(self.url, self.destpath) - - def testFetch(self): - self.fetch.fetch() - fetchedFile = os.path.join(self.destpath, self.url.filename()) - if os.access(fetchedFile, os.R_OK): - self.assertEqual(util.sha1_file(fetchedFile), - self.spec.source.archive.sha1sum) - os.remove(fetchedFile) - - def testResume(self): - resume_test_file = "tests/helloworld/hello-1.3.tar.gz.part" - shutil.copy(resume_test_file, ctx.config.archives_dir()) - self.fetch.fetch() - fetchedFile = os.path.join(self.destpath, self.url.filename()) - if os.access(fetchedFile, os.R_OK): - self.assertEqual(util.sha1_file(fetchedFile), - self.spec.source.archive.sha1sum) - os.remove(fetchedFile) - -suite = unittest.makeSuite(FetcherTestCase) diff --git a/tests/filestests.py b/tests/filestests.py deleted file mode 100644 index a784d330..00000000 --- a/tests/filestests.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os - -import pisi.context as ctx -import pisi.api -import pisi.installdb -import pisi.files as files -from pisi import util - -import testcase - -class FilesTestCase(testcase.TestCase): - - def setUp(self): - testcase.TestCase.setUp(self, database=False) - - def testFileInfo(self): - f1 = files.FileInfo(path = '/usr/bin/zibidi') - f2 = files.FileInfo(path = '/usr/bin/kopus', type='exec', size=13, hash="abugubu") - -suite = unittest.makeSuite(FilesTestCase) diff --git a/tests/filetests.py b/tests/filetests.py deleted file mode 100644 index 75524d90..00000000 --- a/tests/filetests.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os - -from pisi.file import File - -import testcase - -class FileTestCase(testcase.TestCase): - - def setUp(self): - testcase.TestCase.setUp(self, database = False) - - def testLocalFile(self): - f = File("tests/popt/pspec.xml", File.read) - x = f.readlines() - self.assert_(len(x)>0) - - def testRemoteRead(self): - f = File("http://uludag.org.tr/haberler/rootfs0.2.html", File.read) - x = f.readlines() - self.assert_(len(x)>0) - -suite = unittest.makeSuite(FileTestCase) diff --git a/tests/graphtests.py b/tests/graphtests.py deleted file mode 100644 index 62d1ca42..00000000 --- a/tests/graphtests.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os - -from pisi import graph - -class GraphTestCase(unittest.TestCase): - def setUp(self): - self.g0 = graph.Digraph() - self.g0.from_list([ (1,2), (1,3), (2,3), (3,4), (4, 5), (4,1)]) - - self.g1 = graph.Digraph() - self.g1.from_list([ (0,2), (0,3), (3,4), (2,4), (0,5), (5,4) ]) - - def testCycle(self): - self.assert_(not self.g0.cycle_free()) - self.assert_(self.g1.cycle_free()) - - def testTopologicalSort(self): - order = self.g1.topological_sort() - self.assertEqual(order[0], 0) - self.assertEqual(order[len(order)-1], 4) - -suite = unittest.makeSuite(GraphTestCase) diff --git a/tests/helloworld/actions.py b/tests/helloworld/actions.py deleted file mode 100644 index 443847a5..00000000 --- a/tests/helloworld/actions.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright (C) 2005 - 2007, 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. - -from pisi.actionsapi import autotools -from pisi.actionsapi import pisitools -from pisi.actionsapi import shelltools -from pisi.actionsapi import libtools -from pisi.actionsapi import get - -WorkDir = "hello-1.3" - -def setup(): - autotools.configure() - -def build(): - autotools.make() - -def install(): - autotools.install() - - '''/opt/helloworld/''' - pisitools.dodir("/opt/helloworld") - - '''/usr/share/doc/helloworld-0.1-1/Makefile.am''' - pisitools.dodoc("Makefile.am") - - '''/opt/helloworld/helloworld''' - pisitools.doexe("src/helloworld", "/opt/helloworld") - - '''/usr/share/info/Makefile.am''' - '''/usr/share/info/Makefile.cvs''' - '''/usr/share/info/Makefile.in''' - pisitools.doinfo("Makefile.*") - - '''/usr/lib/helloworld.o''' - pisitools.dolib("src/helloworld.o") - - '''/opt/hello''' - pisitools.insinto("/opt/", "src/helloworld", "hello") - '''/opt/hi''' - pisitools.insinto("/opt/", "src/helloworld", "hi") - - '''/opt/hello -> /var/hello''' - pisitools.domove("/opt/hello", "/var/") - '''/opt/hi -> /var/goodbye''' - pisitools.domove("/opt/hi", "/var/", "goodbye") - - '''/usr/bin/helloworld''' - pisitools.dobin("src/helloworld") - '''/bin/helloworld''' - pisitools.dobin("src/helloworld", "/bin") - - '''/usr/sbin/helloworld''' - pisitools.dosbin("src/helloworld") - '''/sbin/helloworld''' - pisitools.dosbin("src/helloworld", "/sbin") - - '''Hello, world! -> Goodbye, world!''' - pisitools.dosed("src/helloworld.cpp", "Hello, world!", "Goodbye, world!") - - '''/usr/sbin/goodbye --> helloworld''' - pisitools.dosym("helloworld", "/usr/sbin/goodbye") - '''/usr/bin/goodbye --> helloworld''' - pisitools.dosym("helloworld", "/usr/bin/goodbye") - - '''/home/pardus/''' - pisitools.dodir("/home/pardus") - '''delete pardus''' - pisitools.removeDir("/home/pardus") - '''delete home''' - pisitools.removeDir("/home") - - '''src/helloworld.cpp --> /usr/share/doc/helloworld-0.1-1/goodbyeworld.cpp''' - pisitools.newdoc("src/helloworld.cpp", "goodbyeworld.cpp") - - '''/opt/pardus''' - shelltools.touch("%s/opt/pardus" % get.installDIR()) - - '''/opt/pardus --> /opt/uludag''' - shelltools.copy("%s/opt/pardus" % get.installDIR(), "%s/opt/uludag" % get.installDIR()) - '''/opt/pardus --> /opt/Pardus''' - shelltools.move("%s/opt/pardus" % get.installDIR(), "%s/opt/PARDUS" % get.installDIR()) - - '''/opt/ --> /sys/''' - shelltools.copytree("%s/opt/" % get.installDIR(), "%s/sys/" % get.installDIR()) - - '''delete /sys/helloworld/helloworld''' - shelltools.unlink("%s/sys/helloworld/helloworld" % get.installDIR()) - '''delete /sys/helloworld''' - shelltools.unlinkDir("%s/sys/helloworld" % get.installDIR()) - - '''generate /usr/lib/helloworld.o''' - libtools.gen_usr_ldscript("helloworld.o") diff --git a/tests/helloworld/hello-1.3.tar.gz.part b/tests/helloworld/hello-1.3.tar.gz.part deleted file mode 100644 index 0ecf0493b3b99450f4595dff4a6ea5d129b87d7b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11520 zcmV+bE&tLViwFRR)&4601MFLSa~n63&%a{rhk%(%NLoW#4?p54PEL_!TXnMJqo_D8 z$3+ciKyspaa0fG_=&Zi`^#j0Q_;7N&+1%BYnOGz-K%>#!`1J$eM8?VHej?!G2!|*=(WGIG22S;pT`%uUTp66mFa|PeUz9)c*wqGEhxyYv2tAk|xbRlBD zsQRv7ZMCRSL@7-^$)>P?3DATk&7(LLLn%rnM`i3G3Fs`|p7vi|T=m7#`8)CUsMk9> z@4q{Q&c!5yr*bBlRFq8P2q?ocaz8B=AQ7bS`lNUK3Wgm0czSl)e}_wWaoRsWxx5rF zE_&ifygBOiPmiz8j(XzFRqxHk<;ji^mlD~MNZ=C^9g$K%YN0IrC|11ecc4WDyv3oI z_%jLG3}iF|&U_Jo)%?DuNThKFriY7!&XpJsMKls=R(N8bM_?R9wyHxMzHEJ-c>Ls% zcs0YPjD%EPUD*U3}I-Q602ASt+onUh;3ozxK zNfRd?!LAw!>eZ09V9}{SG@yn zxV=$Mn*1z_7*<5Pb7&faiJy!63CV@pd1fTFOvW(t>gcDF!DYX9dj4|os>TiA+1PTk z@`UABTbLkPFOJXqXEjozAT462yW9Kn-R0oL>DftrZcqvt#>y01#tIr=B9M)?j0v!r z=&$Xx109ED6ax?sxJ^J~U9c~YkFDidNgSP>T^t|PxZ&|DdZ~4{gor7$-nvQ*4>gq_ z73itQ+U9kH?L*6S!>pOMQG2h`XnIT=g$pQVBp?^(b*3?V8qIaR*IzhmD%F zG>7j$Ksz;*=tprKqIrcMzZG98@xD7LX2}P5?;_Lm!C{KNYfAJP+4=BG+B`%-0mKDb zHHeU@pGatjE!%)@DLAWq9C!l$&d5;-+RfN_$X~Tq;W=`Nvc(P{Zt8%aC%`SNaK>*1 zza{(@XW#_r(?@(eMEEysKm(E8#nl_h-@t~0KJy7|3ej%kJkXC3Xh4YXaO{B=K{8Fx znt&(T$kP3e*zI)0y=UU&;svjZtwIO|9wV3tqTFe0{npqDeBcpmj;9ZXC%5nbj2RI z4%iPtG9}T>-gBQ1ARGmTkmbz|OW-3D7XtS-QKK3E@eiS?en&*>;)0F%Cf5LuzI-{- zqaDg!M-&$VS%7!w?XfX?R^J_MQ5wtl^mn_q*@l@-bd{FLQ0AYUvH6wy1^2riVrNA1 z_rwJB&2#TA&pp{NH|{qu@=>;7#bu#HyGdaj{Eq?4D~yso(SLPP#mB@Zf1ns;2bn}I zqdgMqmeW5hL^HP#-H9g{8Gb47zc)HOS7nm;xs9e6ELlD)lUiB@(sIBB30{GfI8D{M zAi7KZ!dc9wHCggAB(JsOa*GVs_53@0CP)Z@&ZR<8H#M#qyhig@&6_hB_CRbTN!>_H z2olAp7*E_EmLvEJSS8aLIY40n6?=_BPXq>5g?3>G(D28!>Ni7_p^wNlUmu;GHR~2_ zx-pIkQA7I>LQwLETg)`8Ml>IkDu1A+Sr$KFzg2%yZ`jSlXA0r?JOs}Le~89(UP3U~hEMd~ z=^UC7Oba>!DU`<6dU*I&yq&;ihKvM^TwZKVluQHGk009i!}hVECp-*oDxSY*|}I(A8!DQ9t-ffpqVOY!=lzcrO4! z$ZS)0%*CMh{NnuVo#}dK!T>Ykndp+gYg4v?-%rjjPR{%2!`!C+^V1%g#+}*w7}sz8 zk%^t{<<4q$*p%I%9m}jbCUfTy7}4f#o4xf#5SHf&FouGFBCMDptXd|dEg5;oA)3{is@Jnz;p<+<-4_+5T}{ZuH9QkB#(8>s zPcsz+OybYt!bDI`-1CuvTzeBpPAE^G_*1Y81wKEQJB+ksH#~Et)M%;k0lFdmf!T1C z|GP!a&#yoHn%MfkDPaEjCjjD;^?!l2e_Q`Q*n12OPYxbE{#^h6D_-?-1=c5=WXDAA zU>?oG&wKj+aK^#dt_So&!b!VN!Fo+$kI29H_tEQS>QKgMaf<3~FQ zB^xLv&#R;DJA6)xJU2ZyC?ps^Gclkd4@b<_JT_5 zzdAjCX|@^cE_3;qx34Z=)(&&qmp}C$)>{Sx zHOn7@bl|o5?9HCE(h1v!qc#18t1`o@GqiPUWkn4JbVNF+u>}&w`UEtco)2CgA6tRa z11okQN(xP0+okLCh{GHNhh0ZhHf@HiUn${ttOP7%f6{9^E?chSGF zlR7P%kGzqY<19%e9!P<8f(+QMgDj*(e=e!gS1L4XvrCU*V``s-RbK1>tkW(HFtd#p zFg}?^u^FUY7#O>f@n}aQAgRV-? z&KE~QU?9D*8`GKE2Xutg8@woh=JFyn*GQu+)l>!%Ee)g+6+BphQOVGB?7+-DpO^v! zPZ8{pAOJEf9Y{8Wu;@?TN)^c4HSf$4q}c5uz;(eVcY$WmBHlCb&3ybY{8a`8p^EbK z4IN-ZA<*NTnfSE?2nsV^qXr=bzA0d6mVPi1s)Rq)O^T(f6lbSD9@B#vCy5Zc{`~$LgB9-?@HKvl~4|Up5$M z6y2(!Hl5P14#Fj#j>OB8{>7U!AMS)V37I_wy zpl_dI5b&8@j08g+odEeCwJZvK;)b9DPX6@goqgK1aRkAF$F{}cAW3E7V<8PNf;j{R z4barN)ZCMKm_P|6e$8?OuBTJ!=gK(h0K@@C6Gu0wMlg3j55-j)-P#c*>H&s^65|Jq zn?@s<17^W)L>(a^ERaKp3>xAH5u`j<_KCJX5D&04g@4jL&@*9$)R5xm;}RiJ$1g{! zVt=0HH;SYKR1%2Xcn%p$8h}eZ>b?94V|9$;Xqyta@Lq+$9pVf|*=qVJMnqs%gcKY> zpj8o0mWrdF7$pZbN->Oq5k=UG*CA2_Mpz->P6*NeD3-U;FqU>H5at2k@Omy~Q5d9? z=`6~#l)B7dv-miO%;D@EsI=ERIqoC8V!P67CKh%$pw+P^X(j?y5Vj&7fp=S2jqkNp`dF*;bkckGUkYC!O@d!E)sO}28{r`L5e6s))KWh^YhO?i@n|51MmUL zUuZcc7)^j`_e`#WK^M-);m`1^kD5o6!AW+QF$dN=WN2s6?%lLF;b%_>2$-FPp z66DFZ776CrZXn--4Qfe}Pg)2+ocU=$P+BRVw%4?TYqtup6MkZe9g`tI6jz{x$yAA5 z@>Y{*sAIp{-65PFw@I0TILn!l?lFdGD=}FUcPz>(ZvsQzz%B+r6y1*&XyN34Ei&udWsI}`b#>Z1VU)!z zV3YsEvCA&h4c^|I^j=@}PuL~lCTGs-^x5vX&}TJ5fhz`ldfjv;2$nN78U>e15Q(J{ zS8j&m*@ z&N`@UEE5T6e2pW9*Jb0?iZxQz(5w{)cJ)@8SdBFgF@G&oqd1zjHECT(Zd6Cp$*hUj zDj9O%rLi1>ubny&=}tQ81j8LiSe1hfL3t~BZ;uOgWW_cRqKW5{^J%JR6{y6FT>9-4 zvp<9^V=pzoPZ_D*+WyRsVv;%{;wpVjTXU#suf|KY4OHWwIuX5qL@|Waz-$^5o*2y) z^NjTnnvMLa_=ExhrPFL;wiY4*&1#t>z6!=Dt=}W-y<)@aZZfRjwJNd&GIZk(m$!l` z>Pn%D0~M2$kO4#o9PmjLsF|Zn4iUM_+5ga|2d=Z2*E87Ml$$?ma{KAJ=`AOv{AsJ=9>yf|s|vLNKFEZwt>b+)u1`XEm7et9#Y|Qs4K7+b!SDc zU1$HwsxR@!u=2zY@=Wg)#$QbObfDt=4q(lXA9SvtECv)AZsDckN$$1}vEtoUdEkjq zL7JU*wi1~H(}ifap`qgme28ypNB;zYe)lNB^-`8mo4jYO2aGzude`J!AkTE8LDUMUJ7raP%HXw=)<>V^tCg5 zT)z^7H)XIDZzU1MEp3-=rq>Y_Mf|wEy>jto7q7h-UQsR$BUsVKxENye%oEOy9+zM2 zP`j63WDft;bszi|;S;)r7*U8TBJmw}5z+QG6ECv&5gz6vUHF8o>Cz6o)>n7vOyLzL z>P|*Y$hMT9y1@_be^V+Y$HnMtjM#Nf^aN`qyk9Wzzlo+(siz#+|H-^neVL6ZM~So>E$KxkFvP|3fSGDU3F zqR?Ahx(|^%>$%>$vwF@<9o{P#{aQ(`bN5!FHF26e%J>0xnzf0YxjY8kj<;q)>pE>o zhyppBf=XHiZ)b-i@{C5Uiz7Pj;iRH(Fc{l0k!g^-IM=Iy2*GLO_Sscbt ztkM?@#M#VLa%=lj8cnvHU&-jZ(AZLKIc8N2aF@ZZYCHUkZq0T&;y&%gY-FM1&|cHK z4kmQ+;W< z_@`@Dx|C)a(3PI0;!ky2zy${i$Ce8!Sv_}hYY#eTO*6hKu_7#QweWZiL3^vJxZ4%| zzVlvAtoUjPTc0&8(0vplP;>J~*YA z*?2&EOf1J>rU@d&nk3)uuoYqJf<|p|nAdU9(N68LGAV{^{m|0R%l@(q_pV!I;~jxl zkd!P)=J2?svvIB%u2klTm2x`G*>~f)71kCCyvS3{T)_pqE0;;S1x0qH@2!K7V!X9N zi{q*g=EXj$h|dzLvW07s1)8)u1IAyfxZ0)K3*VKxwP){kEFCx0db>vk5gQ;(jEQM~ zo-v1tm|HsYpyS+ZH zwvglR=UFH+z5n*T$9QjpN^6 zU9Zm{QEi(B97zVeq+^FP7?Xr?csoYoq!-%EeBFJP%g++=M0v+wVcp6;#!PTdu zaALjsUIr?o9Y!ROm|=&Co`}jD_TTHxxU$-a(zRVp_8UNDSzaDp;8vBDcjLz|S|0iF4%59VJb?g$a$_@66W2lX zEsh~^$GQ&WDR*=b!7DeKC=>!UAi^f*7$POK@@J-a(rwpeV9uR>t!0^6)7!au^o z!1bYaB(nU7wBxIA>jKLiyRCZ9L|RTOSU?DaF16=f6f7|~ z9!)&I69+0-sd<%!%+Pux$D>L=DQ_e%y?pWZ*)#W^g-dcOooY?(N9t1iP%|K11@P$w zdk#$gvGNlJ4t7HwC|zso^}CP#3_trU0I|sFw7KEWni~!-&<|+ZZzYEebjO^}&FBkV#7H4IpzFpU_&0LJc2&wZ;%eH@k*oaNtblW^t z$gcxt+uYQhgoZVYA!}r9Fh$Rxr`xU$rV%v$DF(+s|2ca6lYyr?qk6HBm(#F-NSt_G zjEyUrsGSAl_jP$*5K!X;vf3)^x$q0Y0_glDT7g}S>6nLA_9MB(?6LMMq4MrB3Ycf8v9I{g1w^{^X%RO|v7@I&03*tN{|c+|ysZJ?-hUYkG==)pb)oYFZas z>OvZSW1f)Z#$|w6c2%bmVNs@3g@>WVBtjBKuaR<$Xo?%@F1DOUs*Wf zKt~m*vNN%UHqs$F{=+rFfKfBKb6vW2ns6Mp_)i)?=8D)c?Ka}ZD3)@|_xqij_-sTy zTzz_Gc37wdKM(gR+VTJy!Oqdi(WASrCH4x=lI8{3*r9RaBt^#0jrKZQHDTHCkpb<>2Yh~=B@ zm{+}_lxr{VmOXLCt74(8--m$Ai?#zXNcfKUELc}1Z?M=+%SLotJ-$=Ds`iTAn%RA6 zg4b*20(3oK%RFl`A08U^TqwW~*w!5TizBwEOy#bQR+^r}I6+P6UkOmfwfy9Sj z=2aAb3)*dH$~@l~a$}+;_^rkURD72jV3S-q>ek)j5W5&`crMA7mI52wTx{6`I6t?q_~;9W)po_4K6|m4~P^*bL8| zIqE6^S%0qT4U6?jJr<60D4O709c9%!pme4zziP$KLtE@p(1Ya5N-n2Ev^5UmzEG607LlHvp4;`#&ZT$n$4<#hHRzCbgA zn@5Z3U-`d}nilVRJYl3r5n%x|V6w(0%o^?o1nu>GxD$T`vexI5Y~U8&+n@OnTQH`m z_@%$9w=w`KR1EBvW_pI2y2QKU1#w!LFao)*x;ov$*q}fZSEkWbfp&FNjwh(7Y7Dg} zSgf3q6QrecG7)hqR0D2|+=3sZqZjy|cY~WpbrbFPFQDeAsy9gtMBYw{wj5m2&6itr z@a7P{NdvZQK2r_;7m769X>unihT`BDUx5=pqF2U?v%S`qdUhD`sayAUKR0h)do4?S zk)bA#;!GmI?77CTW7N5O)ZQ_Y92%}803eU@jJ+%vCwVmp938*<%?TXgjWz#g^(+g zy^QwHj{nTA@y9j)(eo|liKAJ?gtFwI=oCkA_A?;5FX#s=bNCD51@=Jdv z-64+mvJ5n6VwP7|0?8^_oogr6L^J&MsW>T?2;Rl^&dZCTaLwMEoyC~BUT^inU`=(| zIZb@=^2ig=yzIr`2tL;CDVjj1tcKxB&0=mOX zjbf|ibj200i~#mR0;~o>EI4pT%HcO=LVTFlgOY@Aws+rH;2ChzLdmwD;ysSJ1YO>sLEN4%tSxRmQdpMKu>t7ApoJr*@`I!Fo zuYNt66KOQ1yl|b&vv_%wdLV96of8DOHWsS%W~+vaU1e9whm4+y106*3VjM$A;olMe zu^#_(^hV8`gm~~Ui2r#nMf~5D`+vm${5}2%{K6zW;FRma9*thYI_b*7 zgjxtH0QX15;QS*1=N|z${|5x%{1tI6o73+7wy=$VL{I!9dgA{R(G%-s=7%kujQ|jY zhUJKhZ0KRE*(pQCCLn6e-B>8&3WT~H z4fF^sQi)Gc{GAVqxE2NM^bFndzjg0dW$%BBAf)MD`EM_>@O45}YiJ3j?*FrCMr|E6 z)u@c&#>LI7*CRG>RZ@Lkw)hpY3H4lBP<`9W5nZxgmad6|vdZg)yJL7R*WUtx*BbC? zMx8LPK{C^nKXXPr6DV9_!1;5ySifF~v(hLf;8bDJ0*Af*)bUB4lzA89lZc5H`~u-8 zw-$;RYK-=*(BTis(*FXE161+L#d+ir|D+;&FT5jOTB7kRABJx`zMau)c8mi zPEJFYs~0xgw8Fu}MlGp@%D%KSo(|iS;+QRMy6=gL75$t@(ZKA_nd5Y1K}&n=3U*d# z$aFYw4XaTx7Rg|*sJhdt@-Dl7>!knDN&i+J4J(<=R!J8G9I>hP-#RZRG}bryaEM5Q zU;bw~+31e5^A0iEU$L*b3H>nkE&9SiJ7{s8$Grw=VRn2p&ed*+LsJhSc(7Q`77W75XR+w`dZ|}?)hVQ<3jKuVFdJYtW1VSot5ut zHZD5Ap$hG~(1VY>IY4dCC0)(?JRkAyjM?X^FR|r$Tidp~J&k=O5-Qy;ldHOzFJg)< zHqSk3H6J^v2}1#kae|N@!b_f%U5oh3fO(Wp$B5+K6($vIlXZxg$ec=Af^n9hh{OXa zhsXpV!uF0WOAsJFSS38OeE3!u#6NR^9zle(bkcMMTZfhFQDwOz_vAH^2r;nU*-`P; zVOjRlqL*h_0uEpA+AA0+ESL6BK&~7Rd0viMX+G(8P>17#ria=109|&=0fLQsm&1>i zdx|lQ2R%M0-)wDZ%yKY2i?YCwJOx4{&LE?CDXiQ4IO|sSAj}*(FcGCh9Mwpk3~N>@ z2z89zx_J{zK`6e(*)_X=)Y}QWpQIqZZkJ^w1QiUY)#)^i=#1v1+fpnN zY;}D+V9%4;R%hC$*8k3O7%MjT>VgjHlj?14Mr`#76u$j>Di#&Vh+LLti(fg~>%(xy0+)CJum zI?Y^1!%O;zA(jC_iBDX+LViX_WzJ-bspP4d=o!CR& zSX9$-2;k|_b@|5LeBtDm_Q0Ob&+uRqi!SUyh5zVkl%FlXc7t8sEmO zl(LHmTTL|EFi7^J;r(PendS*{=18;wq31Q=A;Ru~%>vzekaJKcw9Ig5LFkl^3YZ;U zj;)p`ZqG7&Qv;Q60LDZIzkTz=-Fs`g%(}FR#Rv|9hfjwUK_UlYw%FhvBhx}172S=m!S4SNTn%?j}Evw&IQ1;82vR`Uh z^E#WE#SkNt3XFp|k_uZ|EiEbJEz@_oLAQhtv>osvhIoEM#YluR*qA*;7EydFQzXfq z|C(JVG)}ARO0ay5=t-B}kdrzV%B~w!IZ3;O>voaKRJ$q|PLd-!KH9q-`1mcjI!&-d zl;1%ismXXGpK$^|3G^0qKMOU6AQ8NLUGF&=8-ickRrp!zLT^jYo)(KxFFr3V*&Z&V z)n(hlW=NY`g~4Q9z~u22YaUniu5E8CiPpj=jw63oVyz-ZBQwLclnM^Ge2j0b&1Y$C zO_rUjLdZ1Q!_)02Z@+oBv$C=YT-Btou9=N+^>=(^9HSV%3QDadj{K6#dpg#{oA}yZ zZSlY95AEl#L>R@7Khh&6tJ-D3YAR&W)pXFotZ#J$#Q5mmnu6o>_&`&@6vqx}BibX1 z1xQmXXH|aaD(?c;sjBleVX+!FF;nsA^w`z=mN-5_lGw20Z0zZ|nM&9kS8L1eOYK#L zx&&NIgW~QT`E%)$u&EqYN-)+G8I#DNilI0TF>?srCt+@vy$76W+awJdoGXhPw1CkO zBdtm4*dyQAQw}MJdAm2AWg##%A~{Pq0t>beAGc&DU0GXMNtep*BpWP)Cg@ciZ{`WP zi2##B5qgLcy);;MT}~%}P$8HQgsSi2(*_$91DlTUosO^uZPh<8uAgKFd5G4m8)LNP zRkY;#~zh=7MG>+O3AiMr;))a#_gW9PUVmvUm`#>nM+l?zluJ z$kJ19a$1d*2c#=9AD?K#N?bWjW!FBm>||8*99_sR$2(8CG`;6N>7~cSRTb@d13NsK zj%JpMt7r{^33$YDHiGGBcCE(Q`9D7YsbRdV@4%aE+&!A9m#svbmaWE*@s?)y;>Y{( zo+;0{4TgClWalcjEZ^iurRXTwZUqq>7HIA8I4_9)H30Cki mj`@Hl?#6Xy>_oo*oi4jKPPwK?MwZ)QlJ_9UCo%FMGG2)%8B2`- diff --git a/tests/helloworld/pspec.xml b/tests/helloworld/pspec.xml deleted file mode 100644 index 0e6b2c28..00000000 --- a/tests/helloworld/pspec.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - helloworld - http://www.uludag.org.tr - - S.Çağlar Onur - caglar@uludag.org.tr - - GPL-2 - category - component - Dummy HelloWorld for testing ActionsAPI - Dummy HelloWorld for testing ActionsAPI - http://ftp.club.cc.cmu.edu/pub/gnu/hello/hello-1.3.tar.gz - - - - helloworld - - / - - - - - - 2005-08-21 - 0.1 - - - - diff --git a/tests/installdbtests.py b/tests/installdbtests.py deleted file mode 100644 index 082ff1e4..00000000 --- a/tests/installdbtests.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os - -import pisi.context as ctx -import pisi.api -import pisi.installdb -from pisi import util - -import testcase -class InstallDBTestCase(testcase.TestCase): - - def testRemoveDummy(self): - ctx.installdb.remove('installtest') - self.assert_(not ctx.installdb.is_installed('installtest')) - - def testInstall(self): - ctx.installdb.purge('installtest') - ctx.installdb.install('installtest', '0.1', '2', '3') - self.assert_(ctx.installdb.is_recorded('installtest')) - self.assert_(ctx.installdb.is_installed('installtest')) - - def testRemovePurge(self): - ctx.installdb.install('installtest', '0.1', '2', '3') - self.assert_(ctx.installdb.is_installed('installtest')) - ctx.installdb.remove('installtest') - self.assert_(ctx.installdb.is_removed('installtest')) - ctx.installdb.purge('installtest') - self.assert_(not ctx.installdb.is_recorded('installtest')) - -suite = unittest.makeSuite(InstallDBTestCase) diff --git a/tests/light.sh b/tests/light.sh deleted file mode 100755 index 37d616a4..00000000 --- a/tests/light.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -pwd -PATH=$PATH:. -set -x -rm -rf tmp -mkdir tmp -set -e -pisi-cli -Dtmp -E --ignore-build-no build tests/zip/pspec.xml tests/unzip/pspec.xml -pisi-cli -Dtmp index . -pisi-cli -Dtmp -d add-repo repo1 pisi-index.xml -pisi-cli -Dtmp list-repo -pisi-cli -Dtmp update-repo repo1 -pisi-cli -Dtmp list-available -pisi-cli -Dtmp --ignore-comar -y install zip -pisi-cli -Dtmp list-installed -pisi-cli -Dtmp --ignore-comar -y remove unzip -pisi-cli -Dtmp info zip*.pisi -pisi-cli -d -Dtmp --ignore-comar -y install zip*.pisi -pisi-cli -Dtmp list-pending -pisi-cli -Dtmp configure-pending -pisi-cli -Dtmp remove-repo repo1 -pisi-cli -Dtmp clean diff --git a/tests/metadatatests.py b/tests/metadatatests.py deleted file mode 100644 index d2c6f0a5..00000000 --- a/tests/metadatatests.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os - -from pisi import metadata -from pisi import util -from pisi import specfile - -class MetaDataTestCase(unittest.TestCase): - - def testRead(self): - md = metadata.MetaData() - md.read('tests/popt/metadata.xml') - - self.assertEqual(md.package.license, ["as-is"]) - - self.assertEqual(md.package.version, "1.7") - - self.assertEqual(md.package.installedSize, 15982) - return md - - def testWrite(self): - md = self.testRead() - md.write('/tmp/metadata-test.xml') - - def testVerify(self): - md = self.testRead() - if md.errors(): - self.fail("Couldn't verify!") - - def testFromSpec(self): - specmd = metadata.MetaData() - spec = specfile.SpecFile('tests/popt/pspec.xml') - specmd.from_spec(spec.source, spec.packages[0], spec.history) - md = metadata.MetaData() - md.read('tests/popt/metadata.xml') - for key in md.package.__dict__.keys(): - if key not in ('installedSize', 'packageFormat', 'distributionRelease', - 'license', 'architecture', 'distribution', 'partOf'): - self.assertEqual(md.package.__dict__[key], specmd.package.__dict__[key]) - -suite = unittest.makeSuite(MetaDataTestCase) diff --git a/tests/ootests.py b/tests/ootests.py deleted file mode 100644 index ac2b335f..00000000 --- a/tests/ootests.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os - -from pisi import version -from pisi.oo import * - -class OOTestCase(unittest.TestCase): - def setUp(self): - pass - - def testautosuper(self): - class A: - __metaclass__ = autosuper - def meth(self): - return "A" - class B(A): - def meth(self): - return "B" + self.__super.meth() - class C(A): - def meth(self): - return "C" + self.__super.meth() - class D(C, B): - def meth(self): - return "D" + self.__super.meth() - - self.assert_( D().meth() == "DCBA" ) - -suite = unittest.makeSuite(OOTestCase) - diff --git a/tests/packagedbtests.py b/tests/packagedbtests.py deleted file mode 100644 index 4c315b7a..00000000 --- a/tests/packagedbtests.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os - -import pisi.context as ctx -import pisi.api -from pisi.packagedb import PackageDB -from pisi import util -from pisi.specfile import SpecFile - -import testcase -class PackageDBTestCase(testcase.TestCase): - - def setUp(self): - testcase.TestCase.setUp(self) - self.spec = SpecFile() - self.spec.read('tests/popt/pspec.xml') - self.spec.check() - - def testAdd(self): - if not ctx.repodb.has_repo('test'): - ctx.repodb.add_repo('test', pisi.repodb.Repo(pisi.uri.URI('fakerepo.xml')) ) - ctx.packagedb.add_package(self.spec.packages[1], 'test') - self.assert_(ctx.packagedb.has_package('popt-libs')) - # close the database and remove lock - #self.pdb.close() - - def testRemove(self): - ctx.packagedb.remove_package('popt-libs', 'test') - self.assert_(not ctx.packagedb.has_package('popt-libs', 'test')) - -suite = unittest.makeSuite(PackageDBTestCase) diff --git a/tests/packagetests.py b/tests/packagetests.py deleted file mode 100644 index e6fb0366..00000000 --- a/tests/packagetests.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os - -from pisi import util -import pisi.context as ctx -import pisi.package - -import testcase -class PackageTestCase(testcase.TestCase): - - def setUp(self): - testcase.TestCase.setUp(self) - self.pkgName = util.package_name("testing", - "5.1", - "2", 3) - - def testAddExtract(self): - cur = os.getcwd() - tmpdir = ctx.config.tmp_dir() - testdir = os.path.join(cur, "tests/popt") - - pkg_path = os.path.join(tmpdir, self.pkgName) - pkg = pisi.package.Package(pkg_path, "w") - - os.chdir(testdir) - pkg.add_to_package("files.xml") - pkg.add_to_package("metadata.xml") - os.chdir(cur) - - pkg.close() - - pkg = pisi.package.Package(pkg_path) - pkg.extract_file("files.xml", cur) - if not os.path.exists("files.xml"): - self.fail("Package extract error") - - os.remove("files.xml") - os.remove(pkg_path) - -suite = unittest.makeSuite(PackageTestCase) diff --git a/tests/pccts/actions.py b/tests/pccts/actions.py deleted file mode 100644 index 184a6599..00000000 --- a/tests/pccts/actions.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright (C) 2005 - 2007, 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. -# Timu EREN - -from pisi.actionsapi import autotools -from pisi.actionsapi import get -from pisi.actionsapi import pisitools -from pisi.actionsapi import shelltools - -WorkDir = "pccts" - -def setup(): - shelltools.export("COPT", get.CFLAGS()) - -def build(): -# autotools.make("COPT=%s" % (get.CFLAGS())) - autotools.make() - -def install(): - #autotools.install("") - - pisitools.dobin("bin/antlr") - pisitools.dobin("bin/dlg") - pisitools.dobin("bin/genmk") - pisitools.dobin("bin/sor") - - pisitools.insinto("/usr/include/pccts","h/*.h") - pisitools.insinto("/usr/include/pccts","h/*.c") - pisitools.insinto("/usr/include/pccts","h/*.cpp") - - - pisitools.insinto("/usr/include/pccts/sorcerer","sorcerer/h/*.h") - pisitools.insinto("/usr/include/pccts/sorcerer","sorcerer/h/*.c") - pisitools.insinto("/usr/include/pccts/sorcerer","sorcerer/h/*.cpp") - - - pisitools.insinto("/usr/include/pccts/sorcerer/lib","sorcerer/lib/*.h") - pisitools.insinto("/usr/include/pccts/sorcerer/lib","sorcerer/lib/*.c") - pisitools.insinto("/usr/include/pccts/sorcerer/lib","sorcerer/lib/*.cpp") - - pisitools.dodoc("CHANGES*", "KNOWN_PROBLEMS*", "README", "RIGHTS", "history.txt", "history.ps") - pisitools.dodoc("sorcerer/README", "sorcerer/UPDATES") - - pisitools.doman("dlg/dlg.1", "antlr/antlr.1") diff --git a/tests/pccts/files/pccts-1.33.33-gentoo.diff b/tests/pccts/files/pccts-1.33.33-gentoo.diff deleted file mode 100644 index 1594cd96..00000000 --- a/tests/pccts/files/pccts-1.33.33-gentoo.diff +++ /dev/null @@ -1,69 +0,0 @@ ---- pccts-1.33.33/support/genmk/genmk.c Fri Aug 3 17:12:51 2001 -+++ pccts-1.33.33/support/genmk/genmk-gentoo.c Fri Aug 3 17:12:14 2001 -@@ -7,6 +7,11 @@ - * U of MN - */ - -+/* modified 20010803 by Peter Kadau -+ * for better fhs-compliance -+ * i.e. from "none" to "hmmm soso" ;-) -+ */ -+ - #include - #include - #include "pcctscfg.h" /* be sensitive to what ANTLR/DLG call the files */ -@@ -65,7 +70,7 @@ - static int nondef_comp = 0; /* 1=compiler is non default */ - static char *compilerCCC="CC"; - static char *compilerCC="cc"; --static char *pccts_path="/usr/local/pccts"; -+static char *pccts_path="/usr/include/pccts"; - - #ifdef __STDC__ - void help(void); -@@ -356,7 +361,7 @@ - { "-cfiles",1,pCFiles, "Additional files in C or C++ to compile"}, - { "-sor",0,pSor, "Start of sorcerer group"}, - { "-pccts_path",1,ppccts_path, -- "Path for $PCCTS directory (default is /usr/local/pccts)"}, -+ "Path for $PCCTS directory (default is /usr/include/pccts)"}, - { "-compiler",1,pCompiler, - "Default compiler (default is CC/cc)"}, - { "*", 0,pFile, "" }, /* anything else is a file */ -@@ -495,13 +500,13 @@ - else printf("SCAN = %s%s\n", DIR(), dlg_class); - - printf("PCCTS = %s\n",pccts_path); -- printf("ANTLR_H = $(PCCTS)%sh\n", DirectorySymbol); -+ printf("ANTLR_H = $(PCCTS)\n"); - if (num_sors>0) { -- printf("SOR_H = $(PCCTS)%ssorcerer%sh\n", DirectorySymbol, DirectorySymbol); -+ printf("SOR_H = $(PCCTS)%ssorcerer\n", DirectorySymbol); - printf("SOR_LIB = $(PCCTS)%ssorcerer%slib\n", - DirectorySymbol, DirectorySymbol); - } -- printf("BIN = $(PCCTS)%sbin\n", DirectorySymbol); -+ printf("BIN = %susr%sbin\n", DirectorySymbol, DirectorySymbol); - printf("ANTLR = $(BIN)%santlr\n", DirectorySymbol); - printf("DLG = $(BIN)%sdlg\n", DirectorySymbol); - if (num_sors>0) printf("SOR = $(BIN)%ssor\n", DirectorySymbol); ---- pccts-1.33.33/sorcerer/lib/sorlist.c 1999-06-30 03:15:56.000000000 +0200 -+++ pccts-1.33.33/sorcerer/lib/sorlist.c.new 2003-05-23 11:11:09.000000000 +0200 -@@ -28,6 +28,7 @@ - */ - #include - #include -+#include "pcctscfg.h" - - #ifdef PCCTS_USE_STDARG - #include ---- pccts-1.33.33/sorcerer/lib/sintstack.c 1999-06-30 15:08:06.000000000 +0200 -+++ pccts-1.33.33/sorcerer/lib/sintstack.c.new 2003-05-23 12:54:26.000000000 +0200 -@@ -28,6 +28,7 @@ - */ - #include - #include -+#include "pcctscfg.h" - - #ifdef PCCTS_USE_STDARG - #include diff --git a/tests/pccts/pspec.xml b/tests/pccts/pspec.xml deleted file mode 100644 index 7bbc03eb..00000000 --- a/tests/pccts/pspec.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - pccts - http://www.polhode.com - - Timu EREN - selamtux@gmail.com - - BSD - category - component - Purdue Compiler Construction Tool Set is an embedded C/C++ parser generator - Purdue Compiler Construction Tool Set is an embedded C/C++ parser generator - http://www.polhode.com/pccts133mr33.zip - - pccts-1.33.33-gentoo.diff - - - unzip - patch - - - - pccts - - /usr/include - /usr/share/doc - /usr/bin - /usr/share/man - - - - - - 2005-09-16 - 1.33.33 - - - - diff --git a/tests/pisi.conf b/tests/pisi.conf deleted file mode 100644 index 560e8567..00000000 --- a/tests/pisi.conf +++ /dev/null @@ -1,6 +0,0 @@ -[general] -destinationdirectory = /testing - -[directories] -archives_dir = /disk2/pisi/archives - diff --git a/tests/popt/files.xml b/tests/popt/files.xml deleted file mode 100644 index 34564b0c..00000000 --- a/tests/popt/files.xml +++ /dev/null @@ -1,507 +0,0 @@ - - - - - usr/share/locale/es/LC_MESSAGES/popt.mo - - - localedata - - - 1593 - - - 29481dbd4051e5c6a0f000436664ba00e47572ae - - - - - usr/share/locale/de/LC_MESSAGES/popt.mo - - - localedata - - - 345 - - - 6ceb513b02af4f612a20b49e5d615c158fdcee31 - - - - - usr/share/locale/is/LC_MESSAGES/popt.mo - - - localedata - - - 1793 - - - edbcbb430b122626216ea9f6bba268d5de8454b6 - - - - - usr/lib/libpopt.la - - - sharedLib - - - 699 - - - 04bac6fce89f2c84d4bb1c5adced729f7d312980 - - - - - usr/share/locale/sl/LC_MESSAGES/popt.mo - - - localedata - - - 514 - - - 2031bdefffcf57121e46f3f68f0747fe6b7f1fcc - - - - - usr/share/locale/fr/LC_MESSAGES/popt.mo - - - localedata - - - 345 - - - 6ceb513b02af4f612a20b49e5d615c158fdcee31 - - - - - usr/share/locale/it/LC_MESSAGES/popt.mo - - - localedata - - - 345 - - - 6ceb513b02af4f612a20b49e5d615c158fdcee31 - - - - - usr/share/locale/eu_ES/LC_MESSAGES/popt.mo - - - localedata - - - 345 - - - 6ceb513b02af4f612a20b49e5d615c158fdcee31 - - - - - usr/share/locale/da/LC_MESSAGES/popt.mo - - - localedata - - - 1599 - - - 3ae14880a8bc2cddd9dd0a03861a55d663ac8b0d - - - - - usr/share/locale/ko/LC_MESSAGES/popt.mo - - - localedata - - - 1916 - - - 2079233b9e3284c866e5d17e5aca001f678d4c23 - - - - - usr/share/locale/ja/LC_MESSAGES/popt.mo - - - localedata - - - 345 - - - 6ceb513b02af4f612a20b49e5d615c158fdcee31 - - - - - usr/share/locale/pt/LC_MESSAGES/popt.mo - - - localedata - - - 1870 - - - 7db5d457fa3cc169fea2f747f25ba0353ed5fb69 - - - - - usr/lib/libpopt.so - - - sharedLib - - - 38532 - - - 617c2afa4e79faee954cb95715470f875c044e5a - - - - - usr/share/locale/no/LC_MESSAGES/popt.mo - - - localedata - - - 1800 - - - b33d41a1fbde6b879f0cce06cf2d8395012cc0ec - - - - - usr/lib/libpopt.a - - - sharedLib - - - 36100 - - - f067421ebdb9a68f89c90526feb64a70763c95cf - - - - - usr/share/locale/wa/LC_MESSAGES/popt.mo - - - localedata - - - 517 - - - 92f1f582ae24dbf5631fee1ace8bfc99cb5c1b66 - - - - - usr/share/locale/tr/LC_MESSAGES/popt.mo - - - localedata - - - 1601 - - - 16e3e8e12af497102c75ccbb52edf8d1783545c3 - - - - - usr/share/locale/zh/LC_MESSAGES/popt.mo - - - localedata - - - 345 - - - 6ceb513b02af4f612a20b49e5d615c158fdcee31 - - - - - usr/share/locale/id/LC_MESSAGES/popt.mo - - - localedata - - - 345 - - - 6ceb513b02af4f612a20b49e5d615c158fdcee31 - - - - - usr/share/locale/ro/LC_MESSAGES/popt.mo - - - localedata - - - 1150 - - - 914729e4200d68e5c55d114e6a083c74e692707b - - - - - usr/share/locale/sr/LC_MESSAGES/popt.mo - - - localedata - - - 345 - - - 6ceb513b02af4f612a20b49e5d615c158fdcee31 - - - - - usr/share/locale/hu/LC_MESSAGES/popt.mo - - - localedata - - - 496 - - - 236bf8c1fea44a5a93c6e18e0c88b3dae1762264 - - - - - usr/share/locale/pt_BR/LC_MESSAGES/popt.mo - - - localedata - - - 345 - - - 6ceb513b02af4f612a20b49e5d615c158fdcee31 - - - - - usr/share/locale/sv/LC_MESSAGES/popt.mo - - - localedata - - - 1844 - - - 63517df43bd74c84496441d8894f2b67533c6060 - - - - - usr/lib/libpopt.so.0.0.0 - - - sharedLib - - - 38532 - - - 1f2d3c41ba8e4d6b1c4979225cdf2dd97d4a0aea - - - - - usr/share/locale/ru/LC_MESSAGES/popt.mo - - - localedata - - - 1955 - - - 4742785bd5235eb437922f76a9faa30ec314d09b - - - - - usr/share/locale/zh_CN.GB2312/LC_MESSAGES/popt.mo - - - localedata - - - 468 - - - 5e0a688794619278a452c851a3fc86b50b7f781e - - - - - usr/lib/libpopt.so.0 - - - sharedLib - - - 38532 - - - 617c2afa4e79faee954cb95715470f875c044e5a - - - - - usr/include/popt.h - - - header - - - 15982 - - - 091692391fd1c539b19298f30e8ae074e3210459 - - - - - usr/share/locale/sk/LC_MESSAGES/popt.mo - - - localedata - - - 510 - - - f7e081a22577eb5429809b7ce999b8b1e2b1f9b3 - - - - - usr/share/locale/pl/LC_MESSAGES/popt.mo - - - localedata - - - 345 - - - 6ceb513b02af4f612a20b49e5d615c158fdcee31 - - - - - usr/share/locale/uk/LC_MESSAGES/popt.mo - - - localedata - - - 504 - - - f91c695161926679401201fdaf3edcef4664f6ca - - - - - usr/share/locale/cs/LC_MESSAGES/popt.mo - - - localedata - - - 1806 - - - 920f5b99199361f1d169430bf13d2bfac1a02fab - - - - - usr/share/man/man3/popt.3 - - - doc - - - 31011 - - - 5c0014442b4ef38d71733c952884573071978328 - - - - - usr/share/locale/gl/LC_MESSAGES/popt.mo - - - localedata - - - 1636 - - - 8486430a6ecbb006b5d374cbcb109e8303c7d5f8 - - - - - usr/share/locale/fi/LC_MESSAGES/popt.mo - - - localedata - - - 345 - - - 6ceb513b02af4f612a20b49e5d615c158fdcee31 - - - diff --git a/tests/popt/files/popt-1.7-uclibc.patch.gz b/tests/popt/files/popt-1.7-uclibc.patch.gz deleted file mode 100644 index 83bbae58fcb13d6d70a3f408cf7ee02484e4e350..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 891 zcmV->1BCn^iwFqvtfoQ$18{F}bS*J1H!XEzY-wU+E^uLVV`u>FR&8(FHW2zerCsUIZ}hwCI-FQRW;pF9CSNtUP6Q}EmxMS!|e$o9RzlkH?Y003?%vuoK9c1?0o za#GQqV5H%uadP^OvqC|DN!vf088tab{siTB7UAq{-~kN0EjGhU<05LR$@ zMJnDDDobl>454LtFnd4>?S;d3fjt)(1|WH}HCb1b$iX=f^6c_ALf|6|FD}4;20ni7 zG_UV=et{t4*MV%y@(h}SOV_r=JpOsQ1aC2)C%B?27dFO^@J3Txn1xvScJYg z4h_pQJcE%5{@VOBoA|Rnv(4CwoAEH%L>6=t2O~VR?(kj7r>j+HnS$$L8YlNKCEH6{ z;i;hditBXr`-`{1r8R*v!=o7W9JrSO*IXN+Bx&|FPu;fFO3pKc+mc%IT)a=Ey3_U! zy$WqK)q8>oa6?SZSvneiK&@4L8h+5cZ&)2Hrp!to`S8yZB61LoR99e_BMR#=r$nPV>&U4FA&+(EVFr(5sa%qvX z9{Po9_!{Y63k1uxstydA0+kt5bdSk4)|1w?R<#zi=@Kib#(rfSLpI8C!lZj{I^1(( zT1>h%LhkGxh3@{}5)wK>I+(9GdeU1uf}ZrV!aJT7N7OW}RK{xWp{D=kG^eaojFz)1 z`TjT$SN}fF4;T-g=h1SpvV*B#{||#{9z{z#nB4j}m>vhy<6!!Vn(m=D54(rnJWd`T RdJlT&{R522x}2U1004y>xIO>? diff --git a/tests/popt/metadata.xml b/tests/popt/metadata.xml deleted file mode 100644 index 995fe8de..00000000 --- a/tests/popt/metadata.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - popt - http://www.rpm.org/ - - Kırmızı kafalar - hotmail@redhat.com - - - - popt - Command line option parsing library - Komut satırı seçenekleri işleme kütüphanesi - library files for popt - app:console - system.base - as-is - - gettext - - - /usr/lib - /usr/share/doc - /usr/share/man - /usr/share/locale - /usr/include/popt.h - - - - 2005-06-14 - 1.7 - First release. - Kırmızı kafalar - hotmail@redhat.com - - - Pardus - 2007 - Any - 15982 - 1.1 - - popt - http://www.rpm.org/ - - Kırmızı kafalar - hotmail@redhat.com - - - - \ No newline at end of file diff --git a/tests/popt/pspec.xml b/tests/popt/pspec.xml deleted file mode 100644 index f74769e1..00000000 --- a/tests/popt/pspec.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - popt - http://www.rpm.org/ - - Kırmızı kafalar - hotmail@redhat.com - - as-is - app:console - system.base - Popt command line option parser - Command line option parsing library. - While it is similiar to getopt(3), it contains a number of enhancements, including: - - 1) popt is fully reentrant - 2) popt can parse arbitrary argv[] style arrays while - getopt(2) makes this quite difficult - 3) popt allows users to alias command line arguments - 4) popt provides convience functions for parsing strings - into argv[] style arrays - - ftp://ftp.pardus.org.tr/pub/pisi/source/popt-1.7.tar.gz - - popt-1.7-uclibc.patch.gz - - - make - - - - - popt - library files for popt - Command line option parsing library - Komut satırı seçenekleri işleme kütüphanesi - - gettext - - - /usr/lib - /usr/share/doc - /usr/share/man - /usr/share/locale - /usr/include/popt.h - - - - - popt-libs - Command line option parsing library - Komut satırı seçenekleri işleme kütüphanesi - - gettext - - library files for popt - - /usr/lib - /usr/share/doc - /usr/share/man - /usr/share/locale - /usr/include/popt.h - - - acpid.rc6 - - - - - - 2005-06-14 - 1.7 - First release. - Kırmızı kafalar - hotmail@redhat.com - - - diff --git a/tests/remoterepo.sh b/tests/remoterepo.sh deleted file mode 100755 index 1459ddd1..00000000 --- a/tests/remoterepo.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -export PATH=$PATH:. -set -x # xtrace -set -e # errexit - -echo "beta functionality test script for testing remote repos" -echo "working directory:" `pwd` -echo "cleaning destination dir: tmp" -rm -rf tmp -#echo "*** repository tests" -pisi-cli -Dtmp add-repo pardus http://paketler.uludag.org.tr/pardus-1-test/pisi-index.xml -pisi-cli -Dtmp update-repo pardus -pisi-cli -Dtmp list-repo - -#echo "*** package ops" -pisi-cli -Dtmp list-available -pisi-cli -Dtmp info python -pisi-cli -Dtmp -By install python - -echo "*** database contents" -for x in `find tmp -iname '*.bdb'`; do - echo "contents of database " $x; - tools/cat-db.py $x; -done diff --git a/tests/repodbtests.py b/tests/repodbtests.py deleted file mode 100644 index 463f7b3d..00000000 --- a/tests/repodbtests.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os - -import pisi.context as ctx -import pisi.api -import pisi.installdb -from pisi import util - -import testcase -class RepoDBTestCase(testcase.TestCase): - - def testAddRemoveCycle(self): - # written by cartman the celebrity, for bug #1909 - - for i in range(2): - print '\nTest %d\n' % (i) - pisi.api.add_repo("foo","bar") - pisi.api.remove_repo("foo") - -suite = unittest.makeSuite(RepoDBTestCase) diff --git a/tests/repos/createrepo.py b/tests/repos/createrepo.py new file mode 100755 index 00000000..fd24cd74 --- /dev/null +++ b/tests/repos/createrepo.py @@ -0,0 +1,263 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007, 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 os +import shutil +import time + +pspecTemplate = """ + + + + %(package)s + %(homepage)s + + %(packager_name)s + %(packager_email)s + + GPL-2 + app:gui + %(summary)s + %(description)s + %(archive)s + + + + %(package)s + + %(runtimedeps)s + + + /usr/bin + + + + + + %(date)s + 0.3 + First release + %(packager_name)s + %(packager_email)s + + + +""" + +componentTemplate = """ + + %(name)s + %(local_name)s + %(summary)s + %(description)s + + Joe Packager + joe@pardus.org.tr + + +""" + +actionsTemplate = """ +from pisi.actionsapi import pisitools + +WorkDir = "skeleton" + +def install(): + pisitools.dobin("skeleton.py") + pisitools.rename("/usr/bin/skeleton.py", "%s") +""" + +distributionTemplate = """ + + %(sourcename)s + 1.1 + %(description)s + Core + + %(obsoletes)s + + +""" + +class Component: + def __init__(self, name): + self.name = name + + def get_comp_template(self, subcomp): + return componentTemplate % {"name":subcomp, + "local_name":subcomp, + "summary":subcomp, + "description":subcomp} + + def get_comp_path(self): + return "/".join(self.name.split(".")) + + def create(self): + component_path = self.get_comp_path() + if not os.path.exists(component_path): + os.makedirs(component_path) + + cur_dir = os.getcwd() + cur_comp = '' + for subcomp in self.name.split("."): + os.chdir(subcomp) + + if not cur_comp: + cur_comp = subcomp + else: + cur_comp = ".".join([cur_comp, subcomp]) + + open("component.xml", "w").write(self.get_comp_template(cur_comp)) + os.chdir(cur_dir) + +class Package: + + def __init__(self, name, partof, deps): + self.name = name + self.partof = partof + self.deps = deps + self.component = Component(self.partof) + + def get_spec_template(self): + package = self.name + homepage = "www.pardus.org.tr" + packager_name = "Joe Packager" + packager_email = "joe@pardus.org.tr" + summary = "%s is a very useful package" % self.name + description = "%s is a very useful package that is known for its usefulness." % self.name + sha1sum = "cc64dfa6e068fe1f6fb68a635878b1ea21acfac7" + archive = "http://cekirdek.uludag.org.tr/~faik/pisi/skeleton.tar.gz" + date = time.strftime("%Y-%m-%d") + partof = self.partof + + runtimedeps = "" + for dep in self.deps: + runtimedeps += " %s\n" % dep + + return pspecTemplate % locals() + + def create(self): + self.component.create() + cur_dir = os.getcwd() + os.chdir(self.component.get_comp_path()) + os.makedirs(self.name) + os.chdir(self.name) + open("pspec.xml", "w").write(self.get_spec_template()) + open("actions.py", "w").write(actionsTemplate % self.name) + os.chdir(cur_dir) + +class PackageFactory: + def getPackage(self, name, runtimeDeps = [], component = "system.base"): + return Package(name, component, runtimeDeps) + + def getPackageBundle(self, component, *packages): + pkgs = [] + for pkg in packages: + pkgs.append(Package(pkg, component, [])) + return pkgs + +class Repository: + def __init__(self, name, packages, obsoletes): + self.name = name + self.packages = packages + self.obsoletes = obsoletes + + def get_dist_template(self): + obsoletes = "" + for obs in self.obsoletes: + obsoletes += " %s\n" % obs + + return distributionTemplate % {"sourcename":self.name, + "description":self.name, + "obsoletes":obsoletes} + + def create(self): + cur_dir = os.getcwd() + os.makedirs(self.name) + os.chdir(self.name) + open("distribution.xml", "w").write(self.get_dist_template()) + + for pkg in self.packages: + pkg.create() + + os.chdir(cur_dir) + +class Pardus2007Repo(Repository): + def __init__(self): + Repository.__init__(self, "pardus-2007", [], ["wengophone", "rar"]) + + def create(self): + + pf = PackageFactory() + + self.packages = [ + # system.base + pf.getPackage("bash"), + pf.getPackage("curl", ["libidn", "zlib", "openssl"]), + pf.getPackage("shadow", ["db4","pam", "cracklib"]), + pf.getPackage("jpeg"), + + # applications.network + pf.getPackage("ncftp", [], "applications.network"), + pf.getPackage("bogofilter", ["gsl"], "applications.network"), + pf.getPackage("gsl", [], "applications.network"), + ] + + # system.base + self.packages.extend(pf.getPackageBundle("system.base", "libidn", "zlib", "openssl", "db4", "pam", "cracklib")) + + # applications.network + self.packages.extend(pf.getPackageBundle("applications.network", "ethtool", "nfdump")) + + Repository.create(self) + +class Contrib2007Repo(Repository): + def __init__(self): + Repository.__init__(self, "contrib-2007", [], ["xara"]) + + def create(self): + + pf = PackageFactory() + + self.packages = [ + # applications.network + pf.getPackage("lynx", [], "applications.network"), + pf.getPackage("ctorrent", ["openssl"], "applications.network"), + pf.getPackage("lft", ["libpcap"], "applications.network"), + pf.getPackage("libpcap", [], "applications.network"), + ] + + # applications.util + self.packages.extend(pf.getPackageBundle("applications.util", "iat", "rpl", "cpulimit")) + + Repository.create(self) + +class BuildFarm: + def create_index(self, repo): + binrepo = "%s-bin" % repo + shutil.copy("%s/distribution.xml" % repo, binrepo) + os.system("pisi index %s --skip-signing -o %s/pisi-index.xml" % (repo, repo)) + os.system("pisi index --skip-sources --skip-signing -o %s/pisi-index.xml %s %s" % (binrepo, binrepo, repo)) + + def build(self, repos): + for repo in repos: + binrepo = "%s-bin" % repo + os.mkdir(binrepo) + for root, dirs, files in os.walk(repo): + if "pspec.xml" in files: + os.system("pisi build %s/%s -O %s" % (root, "pspec.xml", binrepo)) + self.create_index(repo) + +if __name__ == "__main__": + Pardus2007Repo().create() + Contrib2007Repo().create() + BuildFarm().build(["pardus-2007", "contrib-2007"]) diff --git a/tests/run.py b/tests/run.py deleted file mode 100755 index 9bb3f59d..00000000 --- a/tests/run.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/python -# -# Copyright (C) 2005 - 2007, 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 unittest -import sys -import os -import locale - -sys.path.insert(0, '.') -sys.path.insert(0, '..') - -import pisi.api -import pisi.context as ctx - -def run_test_suite(testsuite): - unittest.TextTestRunner(verbosity=2).run(testsuite) - if ctx.initialized: - pisi.api.finalize() - -def run_all(): - - print '** Running all tests' - #testsuite = unittest.TestSuite() - for root, dirs, files in os.walk('tests'): - testsources = filter(lambda x:x.endswith('tests.py'), files) - for testsource in testsources: - module = __import__(testsource[:len(testsource)-3]) - print '\n* Running tests in', testsource - run_test_suite(module.suite) - -if __name__ == "__main__": - - locale.setlocale(locale.LC_ALL, '') - args = sys.argv - if len(args) > 1: # run modules given from the command line - tests = sys.argv[1:] - for test in tests: - test += 'tests' - module = __import__(test) - print "* Running tests in", test - run_test_suite(module.suite) - else: # run all tests - run_all() diff --git a/tests/runtests.py b/tests/runtests.py new file mode 100755 index 00000000..4b22934c --- /dev/null +++ b/tests/runtests.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007, 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 unittest +import database + +from database.repodbtest import RepoDBTestCase +from database.packagedbtest import PackageDBTestCase +from database.sourcedbtest import SourceDBTestCase +from database.installdbtest import InstallDBTestCase +from database.componentdbtest import ComponentDBTestCase +from database.filesdbtest import FilesDBTestCase +from database.lazydbtest import LazyDBTestCase +from database.itembyrepotest import ItemByRepoTestCase +from versiontest import VersionTestCase + +suite = unittest.TestSuite() + +# Database related test cases +suite.addTests([LazyDBTestCase, RepoDBTestCase, ItemByRepoTestCase, + PackageDBTestCase, InstallDBTestCase, ComponentDBTestCase, + FilesDBTestCase, SourceDBTestCase]) + +# Pisi class tests +suite.addTests([VersionTestCase]) + +if __name__ == '__main__': + unittest.main() diff --git a/tests/sourcedbtests.py b/tests/sourcedbtests.py deleted file mode 100644 index 3f273ad0..00000000 --- a/tests/sourcedbtests.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os - -import pisi.context as ctx -import pisi.api -import pisi.sourcedb -from pisi import util -from pisi.specfile import SpecFile - -import testcase -class SourceDBTestCase(testcase.TestCase): - - def setUp(self): - testcase.TestCase.setUp(self) - - self.sourcedb = pisi.sourcedb.init() - self.spec = SpecFile() - self.spec.read("tests/popt/pspec.xml") - if not ctx.repodb.has_repo('test'): - ctx.repodb.add_repo('test', pisi.repodb.Repo(pisi.uri.URI('fakerepo.xml')) ) - - def testAddRemove(self): - self.sourcedb.add_spec(self.spec, 'test') - self.assert_(self.sourcedb.has_spec("popt")) - self.sourcedb.remove_spec("popt", 'test') - self.assert_(not self.sourcedb.has_spec("popt")) - -suite = unittest.makeSuite(SourceDBTestCase) diff --git a/tests/specfiletests.py b/tests/specfiletests.py deleted file mode 100644 index 74673baa..00000000 --- a/tests/specfiletests.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os - -import pisi.specfile as specfile -import pisi.util as util - -class SpecFileNewTestCase(unittest.TestCase): - - def setUp(self): - self.spec = specfile.SpecFile() - self.spec.read("tests/popt/pspec.xml") - - def testFields(self): - self.assertEqual(self.spec.source.name, "popt") - - self.assertEqual(self.spec.getSourceVersion(), "1.7") - - self.assertEqual(self.spec.getSourceRelease(), "1") - - self.assertEqual(self.spec.source.archive.sha1sum, - "66f3c77b87a160951b180447f4a6dce68ad2f71b") - - patches = self.spec.source.patches - self.assertEqual(len(patches), 1) - patch = patches[0] #get first and the only patch - self.assertEqual(patch.filename, "popt-1.7-uclibc.patch.gz") - self.assertEqual(patch.compressionType, "gz") - - packages = self.spec.packages - self.assertEqual(len(packages), 2) - package = packages[1] - self.assertEqual(package.name, "popt-libs") - - # search for a path in package.paths - pn = "/usr/lib" - matched = [p for p in package.files if p.path == pn] - if not matched: - self.fail("Failed to match pathname: %s" %pn) - - def testIsAPartOf(self): - # test existence in Source - - if not "app:console" in self.spec.source.isA: - self.fail("Failed to match IsA in Source") - if not isinstance(self.spec.source.isA, list): - self.fail("source.isA is not a list, but it must be...") - - if "system.base" != self.spec.source.partOf: - self.fail("Failed to match PartOf in Source") - - def testVerify(self): - if self.spec.errors(): - self.fail("Failed to verify specfile") - - def testCopy(self): - self.spec.read("tests/popt/pspec.xml") - self.spec.write('/tmp/popt-copy.pspec.xml') - -suite = unittest.makeSuite(SpecFileNewTestCase) diff --git a/tests/stress/comp/ab/actions.py b/tests/stress/comp/ab/actions.py deleted file mode 100644 index 43687b2e..00000000 --- a/tests/stress/comp/ab/actions.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright © 2005 TUBITAK/UEKAE -# Licensed under the GNU General Public License, version 2. -# See the file http://www.gnu.org/copyleft/gpl.txt. - -from pisi.actionsapi import autotools -from pisi.actionsapi import pisitools - -WorkDir = "bc-1.06" - -def setup(): - autotools.configure("--with-readline") - -def build(): - autotools.make() - -def install(): - pisitools.dobin("bc/bc") - pisitools.dobin("dc/dc") - pisitools.doman("man/*.1") - pisitools.doinfo("doc/*.info") - pisitools.dodoc("AUTHORS", "FAQ", "NEWS", "README", "ChangeLog") diff --git a/tests/stress/comp/ab/comar/package.py b/tests/stress/comp/ab/comar/package.py deleted file mode 100644 index b38b1bbf..00000000 --- a/tests/stress/comp/ab/comar/package.py +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/python - -import os - -def postInstall(): - os.system("ls -al > /tmp/SIK") diff --git a/tests/stress/comp/ab/files/bc-1.06-info-fix.diff b/tests/stress/comp/ab/files/bc-1.06-info-fix.diff deleted file mode 100644 index e70736c0..00000000 --- a/tests/stress/comp/ab/files/bc-1.06-info-fix.diff +++ /dev/null @@ -1,101 +0,0 @@ -diff -r -C2 bc-1.06.orig/doc/bc.texi bc-1.06/doc/bc.texi -*** bc-1.06.orig/doc/bc.texi Wed Sep 27 20:22:24 2000 ---- bc-1.06/doc/bc.texi Fri Aug 3 16:44:49 2001 -*************** -*** 14,29 **** - @c end tex - -! @titlepage -! @title @command{bc} -! @subtitle an arbitrary precision calculator language -! @subtitle version 1.06 -! -! @author Philip A. Nelson -! @page - - This manual documents @command{bc}, an arbitrary precision calculator language. - - This manual is part of GNU @command{bc}.@* -! @sp4 - Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ---- 14,26 ---- - @c end tex - -! @ifinfo -! @direntry -! * bc: (bc). An arbitrary precision calculator language. -! @end direntry - - This manual documents @command{bc}, an arbitrary precision calculator language. - - This manual is part of GNU @command{bc}.@* -! - Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -*************** -*** 33,42 **** - are preserved on all copies. - -! @iftex - Permission is granted to process this file through TeX and print the - results, provided the printed document carries copying permission - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). -! @end iftex - - Permission is granted to copy and distribute modified versions of this ---- 30,39 ---- - are preserved on all copies. - -! @ignore - Permission is granted to process this file through TeX and print the - results, provided the printed document carries copying permission - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). -! @end ignore - - Permission is granted to copy and distribute modified versions of this -*************** -*** 49,52 **** ---- 46,59 ---- - except that this permission notice may be stated in a translation approved - by the Foundation. -+ @end ifinfo -+ -+ @titlepage -+ @title @command{bc} -+ @subtitle an arbitrary precision calculator language -+ @subtitle version 1.06 -+ -+ @author Philip A. Nelson -+ @page -+ - - You may contact the author by: -diff -r -C2 bc-1.06.orig/doc/dc.texi bc-1.06/doc/dc.texi -*** bc-1.06.orig/doc/dc.texi Thu Aug 31 11:57:43 2000 ---- bc-1.06/doc/dc.texi Fri Aug 3 16:42:34 2001 -*************** -*** 42,47 **** - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). -- - @end ignore - Permission is granted to copy and distribute modified versions of this - manual under the conditions for verbatim copying, provided that the entire ---- 42,47 ---- - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). - @end ignore -+ - Permission is granted to copy and distribute modified versions of this - manual under the conditions for verbatim copying, provided that the entire -*************** -*** 86,90 **** - - @end titlepage -- @page - - @node Top, Introduction, (dir), (dir) ---- 86,89 ---- diff --git a/tests/stress/comp/ab/files/bc-1.06-longopts.patch b/tests/stress/comp/ab/files/bc-1.06-longopts.patch deleted file mode 100644 index f450e3fa..00000000 --- a/tests/stress/comp/ab/files/bc-1.06-longopts.patch +++ /dev/null @@ -1,28 +0,0 @@ -a bug in the argument processing of 'bc' (v1.06) prevents it from properly -reading long-format options. - -patch by joe bruin - -http://bugs.gentoo.org/show_bug.cgi?id=51525 - ---- bc-1.06.orig/bc/main.c -+++ bc-1.06/bc/main.c -@@ -63,7 +63,7 @@ - printf ("usage: %s [options] [file ...]\n%s%s%s%s%s%s%s", progname, - " -h --help print this usage and exit\n", - " -i --interactive force interactive mode\n", -- " -l --mathlib use the predefine math routnes\n", -+ " -l --mathlib use the predefined math routines\n", - " -q --quiet don't print initial banner\n", - " -s --standard non-standard bc constructs are errors\n", - " -w --warn warn about non-standard bc constructs\n", -@@ -93,6 +93,9 @@ - - switch (optch) - { -+ case 0: /* Long option setting a var. */ -+ break; -+ - case 'c': /* compile only */ - compile_only = TRUE; - break; diff --git a/tests/stress/comp/ab/files/bc-1.06-readline42.diff b/tests/stress/comp/ab/files/bc-1.06-readline42.diff deleted file mode 100644 index 97856d58..00000000 --- a/tests/stress/comp/ab/files/bc-1.06-readline42.diff +++ /dev/null @@ -1,12 +0,0 @@ -this lets bc use readline-4.2, borrowed from redhat apparently. :) - ---- bc-1.06/bc/scan.l.sux Fri May 11 14:27:20 2001 -+++ bc-1.06/bc/scan.l Fri May 11 14:27:32 2001 -@@ -143,7 +143,6 @@ - - /* Definitions for readline access. */ - extern FILE *rl_instream; --_PROTOTYPE(char *readline, (char *)); - - /* rl_input puts upto MAX characters into BUF with the number put in - BUF placed in *RESULT. If the yy input file is the same as diff --git a/tests/stress/comp/ab/files/bc-1.06-static-save.patch b/tests/stress/comp/ab/files/bc-1.06-static-save.patch deleted file mode 100644 index 0ee543b2..00000000 --- a/tests/stress/comp/ab/files/bc-1.06-static-save.patch +++ /dev/null @@ -1,16 +0,0 @@ -ripped from fedora ! - ---- bc-1.06/bc/load.c.s390 Wed Sep 13 20:22:38 2000 -+++ bc-1.06/bc/load.c Wed Sep 5 16:10:18 2001 -@@ -156,7 +156,10 @@ - long label_no; - long vaf_name; /* variable, array or function number. */ - long func; -- program_counter save_adr; -+ /* Make save_adr static. Otherwise the whole address save stuff doesn't make -+ any sense at all and break e.g. on S390. -+ 09/05/01 Phil Knirsch */ -+ static program_counter save_adr; - - /* Initialize. */ - str = code; diff --git a/tests/stress/comp/ab/pspec.xml b/tests/stress/comp/ab/pspec.xml deleted file mode 100644 index f9782fef..00000000 --- a/tests/stress/comp/ab/pspec.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - ab - http://www.gnu.org/software/bc/bc.htm - - Pardus Testcioğlu - bilgi@uludag.org.tr - - GPL-2 - category - Handy console-based calculator utility - Şık görünümlü bir konsol temelli hesap makinesı - Handy console-based calculator utility - Konsolda çalışan şık görünümlü bir hesap makinesı - ftp://ftp.ulak.net.tr/gnu/gnu/bc/bc-1.06.tar.gz - - bc-1.06-info-fix.diff - bc-1.06-longopts.patch - bc-1.06-readline42.diff - bc-1.06-static-save.patch - - - - - ab - - / - - - System.Package - - - - - - 2005-12-18 - 1.06 - First release. - Pardus Testcioğlu - bilgi@uludag.org.tr - - - diff --git a/tests/stress/comp/bc/actions.py b/tests/stress/comp/bc/actions.py deleted file mode 100644 index b7978f35..00000000 --- a/tests/stress/comp/bc/actions.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright © 2005 TUBITAK/UEKAE -# Licensed under the GNU General Public License, version 2. -# See the file http://www.gnu.org/copyleft/gpl.txt. - -from pisi.actionsapi import autotools -from pisi.actionsapi import pisitools - -def setup(): - autotools.configure("--with-readline") - -def build(): - autotools.make() - -def install(): - pisitools.dobin("bc/bc") - pisitools.dobin("dc/dc") - pisitools.doman("man/*.1") - pisitools.doinfo("doc/*.info") - pisitools.dodoc("AUTHORS", "FAQ", "NEWS", "README", "ChangeLog") diff --git a/tests/stress/comp/bc/files/bc-1.06-info-fix.diff b/tests/stress/comp/bc/files/bc-1.06-info-fix.diff deleted file mode 100644 index e70736c0..00000000 --- a/tests/stress/comp/bc/files/bc-1.06-info-fix.diff +++ /dev/null @@ -1,101 +0,0 @@ -diff -r -C2 bc-1.06.orig/doc/bc.texi bc-1.06/doc/bc.texi -*** bc-1.06.orig/doc/bc.texi Wed Sep 27 20:22:24 2000 ---- bc-1.06/doc/bc.texi Fri Aug 3 16:44:49 2001 -*************** -*** 14,29 **** - @c end tex - -! @titlepage -! @title @command{bc} -! @subtitle an arbitrary precision calculator language -! @subtitle version 1.06 -! -! @author Philip A. Nelson -! @page - - This manual documents @command{bc}, an arbitrary precision calculator language. - - This manual is part of GNU @command{bc}.@* -! @sp4 - Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ---- 14,26 ---- - @c end tex - -! @ifinfo -! @direntry -! * bc: (bc). An arbitrary precision calculator language. -! @end direntry - - This manual documents @command{bc}, an arbitrary precision calculator language. - - This manual is part of GNU @command{bc}.@* -! - Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -*************** -*** 33,42 **** - are preserved on all copies. - -! @iftex - Permission is granted to process this file through TeX and print the - results, provided the printed document carries copying permission - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). -! @end iftex - - Permission is granted to copy and distribute modified versions of this ---- 30,39 ---- - are preserved on all copies. - -! @ignore - Permission is granted to process this file through TeX and print the - results, provided the printed document carries copying permission - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). -! @end ignore - - Permission is granted to copy and distribute modified versions of this -*************** -*** 49,52 **** ---- 46,59 ---- - except that this permission notice may be stated in a translation approved - by the Foundation. -+ @end ifinfo -+ -+ @titlepage -+ @title @command{bc} -+ @subtitle an arbitrary precision calculator language -+ @subtitle version 1.06 -+ -+ @author Philip A. Nelson -+ @page -+ - - You may contact the author by: -diff -r -C2 bc-1.06.orig/doc/dc.texi bc-1.06/doc/dc.texi -*** bc-1.06.orig/doc/dc.texi Thu Aug 31 11:57:43 2000 ---- bc-1.06/doc/dc.texi Fri Aug 3 16:42:34 2001 -*************** -*** 42,47 **** - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). -- - @end ignore - Permission is granted to copy and distribute modified versions of this - manual under the conditions for verbatim copying, provided that the entire ---- 42,47 ---- - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). - @end ignore -+ - Permission is granted to copy and distribute modified versions of this - manual under the conditions for verbatim copying, provided that the entire -*************** -*** 86,90 **** - - @end titlepage -- @page - - @node Top, Introduction, (dir), (dir) ---- 86,89 ---- diff --git a/tests/stress/comp/bc/files/bc-1.06-longopts.patch b/tests/stress/comp/bc/files/bc-1.06-longopts.patch deleted file mode 100644 index f450e3fa..00000000 --- a/tests/stress/comp/bc/files/bc-1.06-longopts.patch +++ /dev/null @@ -1,28 +0,0 @@ -a bug in the argument processing of 'bc' (v1.06) prevents it from properly -reading long-format options. - -patch by joe bruin - -http://bugs.gentoo.org/show_bug.cgi?id=51525 - ---- bc-1.06.orig/bc/main.c -+++ bc-1.06/bc/main.c -@@ -63,7 +63,7 @@ - printf ("usage: %s [options] [file ...]\n%s%s%s%s%s%s%s", progname, - " -h --help print this usage and exit\n", - " -i --interactive force interactive mode\n", -- " -l --mathlib use the predefine math routnes\n", -+ " -l --mathlib use the predefined math routines\n", - " -q --quiet don't print initial banner\n", - " -s --standard non-standard bc constructs are errors\n", - " -w --warn warn about non-standard bc constructs\n", -@@ -93,6 +93,9 @@ - - switch (optch) - { -+ case 0: /* Long option setting a var. */ -+ break; -+ - case 'c': /* compile only */ - compile_only = TRUE; - break; diff --git a/tests/stress/comp/bc/files/bc-1.06-readline42.diff b/tests/stress/comp/bc/files/bc-1.06-readline42.diff deleted file mode 100644 index 97856d58..00000000 --- a/tests/stress/comp/bc/files/bc-1.06-readline42.diff +++ /dev/null @@ -1,12 +0,0 @@ -this lets bc use readline-4.2, borrowed from redhat apparently. :) - ---- bc-1.06/bc/scan.l.sux Fri May 11 14:27:20 2001 -+++ bc-1.06/bc/scan.l Fri May 11 14:27:32 2001 -@@ -143,7 +143,6 @@ - - /* Definitions for readline access. */ - extern FILE *rl_instream; --_PROTOTYPE(char *readline, (char *)); - - /* rl_input puts upto MAX characters into BUF with the number put in - BUF placed in *RESULT. If the yy input file is the same as diff --git a/tests/stress/comp/bc/files/bc-1.06-static-save.patch b/tests/stress/comp/bc/files/bc-1.06-static-save.patch deleted file mode 100644 index 0ee543b2..00000000 --- a/tests/stress/comp/bc/files/bc-1.06-static-save.patch +++ /dev/null @@ -1,16 +0,0 @@ -ripped from fedora ! - ---- bc-1.06/bc/load.c.s390 Wed Sep 13 20:22:38 2000 -+++ bc-1.06/bc/load.c Wed Sep 5 16:10:18 2001 -@@ -156,7 +156,10 @@ - long label_no; - long vaf_name; /* variable, array or function number. */ - long func; -- program_counter save_adr; -+ /* Make save_adr static. Otherwise the whole address save stuff doesn't make -+ any sense at all and break e.g. on S390. -+ 09/05/01 Phil Knirsch */ -+ static program_counter save_adr; - - /* Initialize. */ - str = code; diff --git a/tests/stress/comp/bc/pspec.xml b/tests/stress/comp/bc/pspec.xml deleted file mode 100644 index bd02bfca..00000000 --- a/tests/stress/comp/bc/pspec.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - bc - http://www.gnu.org/software/bc/bc.htm - - Pardus Testcioğlu - bilgi@uludag.org.tr - - GPL-2 - category - Handy console-based calculator utility - Şık görünümlü bir konsol temelli hesap makinesı - Handy console-based calculator utility - Konsolda çalışan şık görünümlü bir hesap makinesı - ftp://ftp.ulak.net.tr/gnu/gnu/bc/bc-1.06.tar.gz - - ab - - - bc-1.06-info-fix.diff - bc-1.06-longopts.patch - bc-1.06-readline42.diff - bc-1.06-static-save.patch - - - - - bc - - ab - - - / - - - - - - 2005-12-18 - 1.06 - First release. - Pardus Testcioğlu - bilgi@uludag.org.tr - - - diff --git a/tests/stress/comp/cd/actions.py b/tests/stress/comp/cd/actions.py deleted file mode 100644 index 43687b2e..00000000 --- a/tests/stress/comp/cd/actions.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright © 2005 TUBITAK/UEKAE -# Licensed under the GNU General Public License, version 2. -# See the file http://www.gnu.org/copyleft/gpl.txt. - -from pisi.actionsapi import autotools -from pisi.actionsapi import pisitools - -WorkDir = "bc-1.06" - -def setup(): - autotools.configure("--with-readline") - -def build(): - autotools.make() - -def install(): - pisitools.dobin("bc/bc") - pisitools.dobin("dc/dc") - pisitools.doman("man/*.1") - pisitools.doinfo("doc/*.info") - pisitools.dodoc("AUTHORS", "FAQ", "NEWS", "README", "ChangeLog") diff --git a/tests/stress/comp/cd/files/bc-1.06-info-fix.diff b/tests/stress/comp/cd/files/bc-1.06-info-fix.diff deleted file mode 100644 index e70736c0..00000000 --- a/tests/stress/comp/cd/files/bc-1.06-info-fix.diff +++ /dev/null @@ -1,101 +0,0 @@ -diff -r -C2 bc-1.06.orig/doc/bc.texi bc-1.06/doc/bc.texi -*** bc-1.06.orig/doc/bc.texi Wed Sep 27 20:22:24 2000 ---- bc-1.06/doc/bc.texi Fri Aug 3 16:44:49 2001 -*************** -*** 14,29 **** - @c end tex - -! @titlepage -! @title @command{bc} -! @subtitle an arbitrary precision calculator language -! @subtitle version 1.06 -! -! @author Philip A. Nelson -! @page - - This manual documents @command{bc}, an arbitrary precision calculator language. - - This manual is part of GNU @command{bc}.@* -! @sp4 - Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ---- 14,26 ---- - @c end tex - -! @ifinfo -! @direntry -! * bc: (bc). An arbitrary precision calculator language. -! @end direntry - - This manual documents @command{bc}, an arbitrary precision calculator language. - - This manual is part of GNU @command{bc}.@* -! - Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -*************** -*** 33,42 **** - are preserved on all copies. - -! @iftex - Permission is granted to process this file through TeX and print the - results, provided the printed document carries copying permission - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). -! @end iftex - - Permission is granted to copy and distribute modified versions of this ---- 30,39 ---- - are preserved on all copies. - -! @ignore - Permission is granted to process this file through TeX and print the - results, provided the printed document carries copying permission - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). -! @end ignore - - Permission is granted to copy and distribute modified versions of this -*************** -*** 49,52 **** ---- 46,59 ---- - except that this permission notice may be stated in a translation approved - by the Foundation. -+ @end ifinfo -+ -+ @titlepage -+ @title @command{bc} -+ @subtitle an arbitrary precision calculator language -+ @subtitle version 1.06 -+ -+ @author Philip A. Nelson -+ @page -+ - - You may contact the author by: -diff -r -C2 bc-1.06.orig/doc/dc.texi bc-1.06/doc/dc.texi -*** bc-1.06.orig/doc/dc.texi Thu Aug 31 11:57:43 2000 ---- bc-1.06/doc/dc.texi Fri Aug 3 16:42:34 2001 -*************** -*** 42,47 **** - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). -- - @end ignore - Permission is granted to copy and distribute modified versions of this - manual under the conditions for verbatim copying, provided that the entire ---- 42,47 ---- - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). - @end ignore -+ - Permission is granted to copy and distribute modified versions of this - manual under the conditions for verbatim copying, provided that the entire -*************** -*** 86,90 **** - - @end titlepage -- @page - - @node Top, Introduction, (dir), (dir) ---- 86,89 ---- diff --git a/tests/stress/comp/cd/files/bc-1.06-longopts.patch b/tests/stress/comp/cd/files/bc-1.06-longopts.patch deleted file mode 100644 index f450e3fa..00000000 --- a/tests/stress/comp/cd/files/bc-1.06-longopts.patch +++ /dev/null @@ -1,28 +0,0 @@ -a bug in the argument processing of 'bc' (v1.06) prevents it from properly -reading long-format options. - -patch by joe bruin - -http://bugs.gentoo.org/show_bug.cgi?id=51525 - ---- bc-1.06.orig/bc/main.c -+++ bc-1.06/bc/main.c -@@ -63,7 +63,7 @@ - printf ("usage: %s [options] [file ...]\n%s%s%s%s%s%s%s", progname, - " -h --help print this usage and exit\n", - " -i --interactive force interactive mode\n", -- " -l --mathlib use the predefine math routnes\n", -+ " -l --mathlib use the predefined math routines\n", - " -q --quiet don't print initial banner\n", - " -s --standard non-standard bc constructs are errors\n", - " -w --warn warn about non-standard bc constructs\n", -@@ -93,6 +93,9 @@ - - switch (optch) - { -+ case 0: /* Long option setting a var. */ -+ break; -+ - case 'c': /* compile only */ - compile_only = TRUE; - break; diff --git a/tests/stress/comp/cd/files/bc-1.06-readline42.diff b/tests/stress/comp/cd/files/bc-1.06-readline42.diff deleted file mode 100644 index 97856d58..00000000 --- a/tests/stress/comp/cd/files/bc-1.06-readline42.diff +++ /dev/null @@ -1,12 +0,0 @@ -this lets bc use readline-4.2, borrowed from redhat apparently. :) - ---- bc-1.06/bc/scan.l.sux Fri May 11 14:27:20 2001 -+++ bc-1.06/bc/scan.l Fri May 11 14:27:32 2001 -@@ -143,7 +143,6 @@ - - /* Definitions for readline access. */ - extern FILE *rl_instream; --_PROTOTYPE(char *readline, (char *)); - - /* rl_input puts upto MAX characters into BUF with the number put in - BUF placed in *RESULT. If the yy input file is the same as diff --git a/tests/stress/comp/cd/files/bc-1.06-static-save.patch b/tests/stress/comp/cd/files/bc-1.06-static-save.patch deleted file mode 100644 index 0ee543b2..00000000 --- a/tests/stress/comp/cd/files/bc-1.06-static-save.patch +++ /dev/null @@ -1,16 +0,0 @@ -ripped from fedora ! - ---- bc-1.06/bc/load.c.s390 Wed Sep 13 20:22:38 2000 -+++ bc-1.06/bc/load.c Wed Sep 5 16:10:18 2001 -@@ -156,7 +156,10 @@ - long label_no; - long vaf_name; /* variable, array or function number. */ - long func; -- program_counter save_adr; -+ /* Make save_adr static. Otherwise the whole address save stuff doesn't make -+ any sense at all and break e.g. on S390. -+ 09/05/01 Phil Knirsch */ -+ static program_counter save_adr; - - /* Initialize. */ - str = code; diff --git a/tests/stress/comp/cd/pspec.xml b/tests/stress/comp/cd/pspec.xml deleted file mode 100644 index 904a8cf4..00000000 --- a/tests/stress/comp/cd/pspec.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - cd - http://www.gnu.org/software/bc/bc.htm - - Pardus Testcioğlu - bilgi@uludag.org.tr - - GPL-2 - category - Handy console-based calculator utility - Şık görünümlü bir konsol temelli hesap makinesı - Handy console-based calculator utility - Konsolda çalışan şık görünümlü bir hesap makinesı - ftp://ftp.ulak.net.tr/gnu/gnu/bc/bc-1.06.tar.gz - - ab - bc - - - bc-1.06-info-fix.diff - bc-1.06-longopts.patch - bc-1.06-readline42.diff - bc-1.06-static-save.patch - - - - - cd - - ab - bc - - - / - - - - - - 2005-12-18 - 1.06 - First release. - Pardus Testcioğlu - bilgi@uludag.org.tr - - - diff --git a/tests/stress/comp/component.xml b/tests/stress/comp/component.xml deleted file mode 100644 index c8511b01..00000000 --- a/tests/stress/comp/component.xml +++ /dev/null @@ -1,6 +0,0 @@ - - test.comp - ... - ... - ... - diff --git a/tests/stress/component.xml b/tests/stress/component.xml deleted file mode 100644 index 4a3a79fb..00000000 --- a/tests/stress/component.xml +++ /dev/null @@ -1,6 +0,0 @@ - - test - ... - ... - ... - diff --git a/tests/stress/lang/component.xml b/tests/stress/lang/component.xml deleted file mode 100644 index 2f75377a..00000000 --- a/tests/stress/lang/component.xml +++ /dev/null @@ -1,6 +0,0 @@ - - test.lang - ... - ... - ... - diff --git a/tests/stress/lang/de/actions.py b/tests/stress/lang/de/actions.py deleted file mode 100644 index 43687b2e..00000000 --- a/tests/stress/lang/de/actions.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright © 2005 TUBITAK/UEKAE -# Licensed under the GNU General Public License, version 2. -# See the file http://www.gnu.org/copyleft/gpl.txt. - -from pisi.actionsapi import autotools -from pisi.actionsapi import pisitools - -WorkDir = "bc-1.06" - -def setup(): - autotools.configure("--with-readline") - -def build(): - autotools.make() - -def install(): - pisitools.dobin("bc/bc") - pisitools.dobin("dc/dc") - pisitools.doman("man/*.1") - pisitools.doinfo("doc/*.info") - pisitools.dodoc("AUTHORS", "FAQ", "NEWS", "README", "ChangeLog") diff --git a/tests/stress/lang/de/files/bc-1.06-info-fix.diff b/tests/stress/lang/de/files/bc-1.06-info-fix.diff deleted file mode 100644 index e70736c0..00000000 --- a/tests/stress/lang/de/files/bc-1.06-info-fix.diff +++ /dev/null @@ -1,101 +0,0 @@ -diff -r -C2 bc-1.06.orig/doc/bc.texi bc-1.06/doc/bc.texi -*** bc-1.06.orig/doc/bc.texi Wed Sep 27 20:22:24 2000 ---- bc-1.06/doc/bc.texi Fri Aug 3 16:44:49 2001 -*************** -*** 14,29 **** - @c end tex - -! @titlepage -! @title @command{bc} -! @subtitle an arbitrary precision calculator language -! @subtitle version 1.06 -! -! @author Philip A. Nelson -! @page - - This manual documents @command{bc}, an arbitrary precision calculator language. - - This manual is part of GNU @command{bc}.@* -! @sp4 - Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ---- 14,26 ---- - @c end tex - -! @ifinfo -! @direntry -! * bc: (bc). An arbitrary precision calculator language. -! @end direntry - - This manual documents @command{bc}, an arbitrary precision calculator language. - - This manual is part of GNU @command{bc}.@* -! - Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -*************** -*** 33,42 **** - are preserved on all copies. - -! @iftex - Permission is granted to process this file through TeX and print the - results, provided the printed document carries copying permission - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). -! @end iftex - - Permission is granted to copy and distribute modified versions of this ---- 30,39 ---- - are preserved on all copies. - -! @ignore - Permission is granted to process this file through TeX and print the - results, provided the printed document carries copying permission - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). -! @end ignore - - Permission is granted to copy and distribute modified versions of this -*************** -*** 49,52 **** ---- 46,59 ---- - except that this permission notice may be stated in a translation approved - by the Foundation. -+ @end ifinfo -+ -+ @titlepage -+ @title @command{bc} -+ @subtitle an arbitrary precision calculator language -+ @subtitle version 1.06 -+ -+ @author Philip A. Nelson -+ @page -+ - - You may contact the author by: -diff -r -C2 bc-1.06.orig/doc/dc.texi bc-1.06/doc/dc.texi -*** bc-1.06.orig/doc/dc.texi Thu Aug 31 11:57:43 2000 ---- bc-1.06/doc/dc.texi Fri Aug 3 16:42:34 2001 -*************** -*** 42,47 **** - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). -- - @end ignore - Permission is granted to copy and distribute modified versions of this - manual under the conditions for verbatim copying, provided that the entire ---- 42,47 ---- - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). - @end ignore -+ - Permission is granted to copy and distribute modified versions of this - manual under the conditions for verbatim copying, provided that the entire -*************** -*** 86,90 **** - - @end titlepage -- @page - - @node Top, Introduction, (dir), (dir) ---- 86,89 ---- diff --git a/tests/stress/lang/de/files/bc-1.06-longopts.patch b/tests/stress/lang/de/files/bc-1.06-longopts.patch deleted file mode 100644 index f450e3fa..00000000 --- a/tests/stress/lang/de/files/bc-1.06-longopts.patch +++ /dev/null @@ -1,28 +0,0 @@ -a bug in the argument processing of 'bc' (v1.06) prevents it from properly -reading long-format options. - -patch by joe bruin - -http://bugs.gentoo.org/show_bug.cgi?id=51525 - ---- bc-1.06.orig/bc/main.c -+++ bc-1.06/bc/main.c -@@ -63,7 +63,7 @@ - printf ("usage: %s [options] [file ...]\n%s%s%s%s%s%s%s", progname, - " -h --help print this usage and exit\n", - " -i --interactive force interactive mode\n", -- " -l --mathlib use the predefine math routnes\n", -+ " -l --mathlib use the predefined math routines\n", - " -q --quiet don't print initial banner\n", - " -s --standard non-standard bc constructs are errors\n", - " -w --warn warn about non-standard bc constructs\n", -@@ -93,6 +93,9 @@ - - switch (optch) - { -+ case 0: /* Long option setting a var. */ -+ break; -+ - case 'c': /* compile only */ - compile_only = TRUE; - break; diff --git a/tests/stress/lang/de/files/bc-1.06-readline42.diff b/tests/stress/lang/de/files/bc-1.06-readline42.diff deleted file mode 100644 index 97856d58..00000000 --- a/tests/stress/lang/de/files/bc-1.06-readline42.diff +++ /dev/null @@ -1,12 +0,0 @@ -this lets bc use readline-4.2, borrowed from redhat apparently. :) - ---- bc-1.06/bc/scan.l.sux Fri May 11 14:27:20 2001 -+++ bc-1.06/bc/scan.l Fri May 11 14:27:32 2001 -@@ -143,7 +143,6 @@ - - /* Definitions for readline access. */ - extern FILE *rl_instream; --_PROTOTYPE(char *readline, (char *)); - - /* rl_input puts upto MAX characters into BUF with the number put in - BUF placed in *RESULT. If the yy input file is the same as diff --git a/tests/stress/lang/de/files/bc-1.06-static-save.patch b/tests/stress/lang/de/files/bc-1.06-static-save.patch deleted file mode 100644 index 0ee543b2..00000000 --- a/tests/stress/lang/de/files/bc-1.06-static-save.patch +++ /dev/null @@ -1,16 +0,0 @@ -ripped from fedora ! - ---- bc-1.06/bc/load.c.s390 Wed Sep 13 20:22:38 2000 -+++ bc-1.06/bc/load.c Wed Sep 5 16:10:18 2001 -@@ -156,7 +156,10 @@ - long label_no; - long vaf_name; /* variable, array or function number. */ - long func; -- program_counter save_adr; -+ /* Make save_adr static. Otherwise the whole address save stuff doesn't make -+ any sense at all and break e.g. on S390. -+ 09/05/01 Phil Knirsch */ -+ static program_counter save_adr; - - /* Initialize. */ - str = code; diff --git a/tests/stress/lang/de/pspec.xml b/tests/stress/lang/de/pspec.xml deleted file mode 100644 index a381fd1e..00000000 --- a/tests/stress/lang/de/pspec.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - de - http://www.gnu.org/software/bc/bc.htm - - Pardus Testcioğlu - bilgi@uludag.org.tr - - GPL-2 - category - Handy console-based calculator utility - Şık görünümlü bir konsol temelli hesap makinesı - Handy console-based calculator utility - Konsolda çalışan şık görünümlü bir hesap makinesı - ftp://ftp.ulak.net.tr/gnu/gnu/bc/bc-1.06.tar.gz - - cd - - - bc-1.06-info-fix.diff - bc-1.06-longopts.patch - bc-1.06-readline42.diff - bc-1.06-static-save.patch - - - - - de - - ab - - - / - - - - - - 2005-12-18 - 1.06 - First release. - Pardus Testcioğlu - bilgi@uludag.org.tr - - - diff --git a/tests/stress/lang/ef/actions.py b/tests/stress/lang/ef/actions.py deleted file mode 100644 index 43687b2e..00000000 --- a/tests/stress/lang/ef/actions.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright © 2005 TUBITAK/UEKAE -# Licensed under the GNU General Public License, version 2. -# See the file http://www.gnu.org/copyleft/gpl.txt. - -from pisi.actionsapi import autotools -from pisi.actionsapi import pisitools - -WorkDir = "bc-1.06" - -def setup(): - autotools.configure("--with-readline") - -def build(): - autotools.make() - -def install(): - pisitools.dobin("bc/bc") - pisitools.dobin("dc/dc") - pisitools.doman("man/*.1") - pisitools.doinfo("doc/*.info") - pisitools.dodoc("AUTHORS", "FAQ", "NEWS", "README", "ChangeLog") diff --git a/tests/stress/lang/ef/files/bc-1.06-info-fix.diff b/tests/stress/lang/ef/files/bc-1.06-info-fix.diff deleted file mode 100644 index e70736c0..00000000 --- a/tests/stress/lang/ef/files/bc-1.06-info-fix.diff +++ /dev/null @@ -1,101 +0,0 @@ -diff -r -C2 bc-1.06.orig/doc/bc.texi bc-1.06/doc/bc.texi -*** bc-1.06.orig/doc/bc.texi Wed Sep 27 20:22:24 2000 ---- bc-1.06/doc/bc.texi Fri Aug 3 16:44:49 2001 -*************** -*** 14,29 **** - @c end tex - -! @titlepage -! @title @command{bc} -! @subtitle an arbitrary precision calculator language -! @subtitle version 1.06 -! -! @author Philip A. Nelson -! @page - - This manual documents @command{bc}, an arbitrary precision calculator language. - - This manual is part of GNU @command{bc}.@* -! @sp4 - Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ---- 14,26 ---- - @c end tex - -! @ifinfo -! @direntry -! * bc: (bc). An arbitrary precision calculator language. -! @end direntry - - This manual documents @command{bc}, an arbitrary precision calculator language. - - This manual is part of GNU @command{bc}.@* -! - Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -*************** -*** 33,42 **** - are preserved on all copies. - -! @iftex - Permission is granted to process this file through TeX and print the - results, provided the printed document carries copying permission - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). -! @end iftex - - Permission is granted to copy and distribute modified versions of this ---- 30,39 ---- - are preserved on all copies. - -! @ignore - Permission is granted to process this file through TeX and print the - results, provided the printed document carries copying permission - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). -! @end ignore - - Permission is granted to copy and distribute modified versions of this -*************** -*** 49,52 **** ---- 46,59 ---- - except that this permission notice may be stated in a translation approved - by the Foundation. -+ @end ifinfo -+ -+ @titlepage -+ @title @command{bc} -+ @subtitle an arbitrary precision calculator language -+ @subtitle version 1.06 -+ -+ @author Philip A. Nelson -+ @page -+ - - You may contact the author by: -diff -r -C2 bc-1.06.orig/doc/dc.texi bc-1.06/doc/dc.texi -*** bc-1.06.orig/doc/dc.texi Thu Aug 31 11:57:43 2000 ---- bc-1.06/doc/dc.texi Fri Aug 3 16:42:34 2001 -*************** -*** 42,47 **** - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). -- - @end ignore - Permission is granted to copy and distribute modified versions of this - manual under the conditions for verbatim copying, provided that the entire ---- 42,47 ---- - notice identical to this one except for the removal of this paragraph - (this paragraph not being relevant to the printed manual). - @end ignore -+ - Permission is granted to copy and distribute modified versions of this - manual under the conditions for verbatim copying, provided that the entire -*************** -*** 86,90 **** - - @end titlepage -- @page - - @node Top, Introduction, (dir), (dir) ---- 86,89 ---- diff --git a/tests/stress/lang/ef/files/bc-1.06-longopts.patch b/tests/stress/lang/ef/files/bc-1.06-longopts.patch deleted file mode 100644 index f450e3fa..00000000 --- a/tests/stress/lang/ef/files/bc-1.06-longopts.patch +++ /dev/null @@ -1,28 +0,0 @@ -a bug in the argument processing of 'bc' (v1.06) prevents it from properly -reading long-format options. - -patch by joe bruin - -http://bugs.gentoo.org/show_bug.cgi?id=51525 - ---- bc-1.06.orig/bc/main.c -+++ bc-1.06/bc/main.c -@@ -63,7 +63,7 @@ - printf ("usage: %s [options] [file ...]\n%s%s%s%s%s%s%s", progname, - " -h --help print this usage and exit\n", - " -i --interactive force interactive mode\n", -- " -l --mathlib use the predefine math routnes\n", -+ " -l --mathlib use the predefined math routines\n", - " -q --quiet don't print initial banner\n", - " -s --standard non-standard bc constructs are errors\n", - " -w --warn warn about non-standard bc constructs\n", -@@ -93,6 +93,9 @@ - - switch (optch) - { -+ case 0: /* Long option setting a var. */ -+ break; -+ - case 'c': /* compile only */ - compile_only = TRUE; - break; diff --git a/tests/stress/lang/ef/files/bc-1.06-readline42.diff b/tests/stress/lang/ef/files/bc-1.06-readline42.diff deleted file mode 100644 index 97856d58..00000000 --- a/tests/stress/lang/ef/files/bc-1.06-readline42.diff +++ /dev/null @@ -1,12 +0,0 @@ -this lets bc use readline-4.2, borrowed from redhat apparently. :) - ---- bc-1.06/bc/scan.l.sux Fri May 11 14:27:20 2001 -+++ bc-1.06/bc/scan.l Fri May 11 14:27:32 2001 -@@ -143,7 +143,6 @@ - - /* Definitions for readline access. */ - extern FILE *rl_instream; --_PROTOTYPE(char *readline, (char *)); - - /* rl_input puts upto MAX characters into BUF with the number put in - BUF placed in *RESULT. If the yy input file is the same as diff --git a/tests/stress/lang/ef/files/bc-1.06-static-save.patch b/tests/stress/lang/ef/files/bc-1.06-static-save.patch deleted file mode 100644 index 0ee543b2..00000000 --- a/tests/stress/lang/ef/files/bc-1.06-static-save.patch +++ /dev/null @@ -1,16 +0,0 @@ -ripped from fedora ! - ---- bc-1.06/bc/load.c.s390 Wed Sep 13 20:22:38 2000 -+++ bc-1.06/bc/load.c Wed Sep 5 16:10:18 2001 -@@ -156,7 +156,10 @@ - long label_no; - long vaf_name; /* variable, array or function number. */ - long func; -- program_counter save_adr; -+ /* Make save_adr static. Otherwise the whole address save stuff doesn't make -+ any sense at all and break e.g. on S390. -+ 09/05/01 Phil Knirsch */ -+ static program_counter save_adr; - - /* Initialize. */ - str = code; diff --git a/tests/stress/lang/ef/pspec.xml b/tests/stress/lang/ef/pspec.xml deleted file mode 100644 index d422dd74..00000000 --- a/tests/stress/lang/ef/pspec.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - ef - http://www.gnu.org/software/bc/bc.htm - - Pardus Testcioğlu - bilgi@uludag.org.tr - - GPL-2 - category - Handy console-based calculator utility - Şık görünümlü bir konsol temelli hesap makinesı - Handy console-based calculator utility - Konsolda çalışan şık görünümlü bir hesap makinesı - ftp://ftp.ulak.net.tr/gnu/gnu/bc/bc-1.06.tar.gz - - de - - - bc-1.06-info-fix.diff - bc-1.06-longopts.patch - bc-1.06-readline42.diff - bc-1.06-static-save.patch - - - - - ef - - de - - - / - - - - - - 2005-12-18 - 1.06 - First release. - Pardus Testcioğlu - bilgi@uludag.org.tr - - - diff --git a/tests/stress/stress.sh b/tests/stress/stress.sh deleted file mode 100755 index b2eb802a..00000000 --- a/tests/stress/stress.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash - -rm -rf minime -mkdir minime -rm -f *.pisi - -pisi build comp/ab/pspec.xml -D./minime -pisi it ab-1.06-1.pisi -D./minime - -pisi build comp/bc/pspec.xml -D./minime -pisi it bc-1.06-1.pisi -D./minime - -pisi build comp/cd/pspec.xml -D./minime -pisi it cd-1.06-1.pisi -D./minime - -for i in `seq 1 10` -do - pisi it ab-1.06-1.pisi -D./minime --yes-all -done - -for i in `seq 1 10` -do - pisi remove cd -D./minime - pisi it cd-1.06-1.pisi -D./minime -done - -pisi build lang/de/pspec.xml -D./minime -pisi it de-1.06-1.pisi -D./minime - -pisi build lang/ef/pspec.xml -D./minime -pisi it ef-1.06-1.pisi -D./minime - -pisi rebuild-db -D./minime --yes-all - -pisi remove ab -D./minime --yes-all - -pisi li -D./minime diff --git a/tests/testcase.py b/tests/testcase.py deleted file mode 100644 index f6d5406d..00000000 --- a/tests/testcase.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os - -import pisi -import pisi.api -import pisi.util -import pisi.config - -class TestCase(unittest.TestCase): - - def setUp(self, comar = False, database = True, options = None): - if not options: - options = pisi.config.Options() - options.ignore_build_no = False - options.destdir = 'tmp' - pisi.api.init(options = options, comar = comar, - database = database, write = database) - - def tearDown(self, ): - pisi.api.finalize() diff --git a/tests/unzip/actions.py b/tests/unzip/actions.py deleted file mode 100644 index 2f22dce4..00000000 --- a/tests/unzip/actions.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright (C) 2005 - 2007, 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. -# - -from pisi.actionsapi import autotools -from pisi.actionsapi import get -from pisi.actionsapi import pisitools - -def setup(): - pisitools.dosed("unix/Makefile", "-O3", get.CFLAGS()) - pisitools.dosed("unix/Makefile", "CC=gcc LD=gcc", "CC=${CC:-gcc} LD=${CC:-gcc}") - pisitools.dosed("unix/Makefile", "-O ", get.CFLAGS()) - pass - -def build(): - autotools.make("-f unix/Makefile linux") - -def install(): - pisitools.insinto("/usr/bin/", "unzip") - pisitools.insinto("/usr/bin/", "funzip") - pisitools.insinto("/usr/bin/", "unzipsfx") - pisitools.insinto("/usr/bin/", "unix/zipgrep") - - pisitools.dosym("/usr/bin/unzip", "/usr/bin/zipinfo") - pisitools.doman("man/*.1") - pisitools.dodoc("BUGS", "History*", "README", "ToDo", "WHERE") diff --git a/tests/unzip/files/unzip-5.50-dotdot.patch b/tests/unzip/files/unzip-5.50-dotdot.patch deleted file mode 100644 index 73441f7b..00000000 --- a/tests/unzip/files/unzip-5.50-dotdot.patch +++ /dev/null @@ -1,85 +0,0 @@ -Only in unzip-5.50-lhh/: cscope.files -Only in unzip-5.50-lhh/: cscope.out -diff -ur unzip-5.50/unix/unix.c unzip-5.50-lhh/unix/unix.c ---- unzip-5.50/unix/unix.c 2002-01-21 17:54:42.000000000 -0500 -+++ unzip-5.50-lhh/unix/unix.c 2003-06-11 18:35:38.000000000 -0400 -@@ -421,7 +421,8 @@ - */ - { - char pathcomp[FILNAMSIZ]; /* path-component buffer */ -- char *pp, *cp=(char *)NULL; /* character pointers */ -+ char *pp, *cp=(char *)NULL, /* character pointers */ -+ *dp=(char *)NULL; - char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */ - #ifdef ACORN_FTYPE_NFS - char *lastcomma=(char *)NULL; /* pointer to last comma in pathcomp */ -@@ -429,6 +430,7 @@ - #endif - int quote = FALSE; /* flags */ - int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */ -+ int snarf_ddot = FALSE; /* Is set while scanning for "../" */ - int error = MPN_OK; - register unsigned workch; /* hold the character being tested */ - -@@ -467,6 +469,9 @@ - while ((workch = (uch)*cp++) != 0) { - - if (quote) { /* if character quoted, */ -+ if ((pp == pathcomp) && (workch == '.')) -+ /* Oh no you don't... */ -+ goto ddot_hack; - *pp++ = (char)workch; /* include it literally */ - quote = FALSE; - } else -@@ -481,15 +486,44 @@ - break; - - case '.': -- if (pp == pathcomp) { /* nothing appended yet... */ -+ if (pp == pathcomp) { -+ddot_hack: -+ /* nothing appended yet... */ - if (*cp == '/') { /* don't bother appending "./" to */ - ++cp; /* the path: skip behind the '/' */ - break; -- } else if (!uO.ddotflag && *cp == '.' && cp[1] == '/') { -- /* "../" dir traversal detected */ -- cp += 2; /* skip over behind the '/' */ -- killed_ddot = TRUE; /* set "show message" flag */ -- break; -+ } else if (!uO.ddotflag) { -+ -+ /* -+ * SECURITY: Skip past control characters if the user -+ * didn't OK use of absolute pathnames. lhh - this is -+ * a very quick, ugly, inefficient fix. -+ */ -+ dp = cp; -+ do { -+ workch = (uch)(*dp); -+ if (workch == '/' && snarf_ddot) { -+ /* "../" dir traversal detected */ -+ cp = dp + 1; /* skip past the '/' */ -+ killed_ddot = TRUE; /* set "show msg" flag */ -+ break; -+ } else if (workch == '.' && !snarf_ddot) { -+ snarf_ddot = TRUE; -+ } else if (isprint(workch) || -+ ((workch > 127) && (workch <= 254))) { -+ /* -+ * Since we found a printable, non-ctrl char, -+ * we can stop looking for '../', the amount -+ * in ../! -+ */ -+ break; -+ } -+ -+ dp++; -+ } while (*dp != 0); -+ -+ if (killed_ddot) -+ break; - } - } - *pp++ = '.'; -Only in unzip-5.50-lhh/unix: .unix.c.swp diff --git a/tests/unzip/pspec.xml b/tests/unzip/pspec.xml deleted file mode 100644 index ed4188a0..00000000 --- a/tests/unzip/pspec.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - unzip - ftp://ftp.info-zip.org/pub/infozip/UnZip.html - - A. Murat Eren - meren@uludag.org.tr - - Info-ZIP - category - component - Unzipper for pkzip-compressed files - Unzipper for pkzip-compressed files - ftp://ftp.linux.org.tr/pub/mirrors/gentoo/distfiles/unzip550.tar.gz - - unzip-5.50-dotdot.patch - - - libc - sed - patch - - - - - unzip - - - - - /usr/bin - /usr/share/doc - /usr/share/man - - - - - 2005-07-15 - 5.50 - - - - - diff --git a/tests/unzip2/actions.py b/tests/unzip2/actions.py deleted file mode 100644 index 85e0098e..00000000 --- a/tests/unzip2/actions.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright (C) 2005 - 2007, 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. -# - -from pisi.actionsapi import autotools -from pisi.actionsapi import get -from pisi.actionsapi import pisitools - -WorkDir="unzip-5.50" - -def setup(): - pisitools.dosed("unix/Makefile", "-O3", get.CFLAGS()) - pisitools.dosed("unix/Makefile", "CC=gcc LD=gcc", "CC=${CC:-gcc} LD=${CC:-gcc}") - pisitools.dosed("unix/Makefile", "-O ", get.CFLAGS()) - pass - -def build(): - autotools.make("-f unix/Makefile linux") - -def install(): - pisitools.insinto("/usr/bin/", "unzip") - pisitools.insinto("/usr/bin/", "funzip") - pisitools.insinto("/usr/bin/", "unzipsfx") - pisitools.insinto("/usr/bin/", "unix/zipgrep") - - pisitools.dosym("/usr/bin/unzip", "/usr/bin/zipinfo") - pisitools.doman("man/*.1") - pisitools.dodoc("BUGS", "History*", "README", "ToDo", "WHERE") diff --git a/tests/unzip2/files/unzip-5.50-dotdot.patch b/tests/unzip2/files/unzip-5.50-dotdot.patch deleted file mode 100644 index 73441f7b..00000000 --- a/tests/unzip2/files/unzip-5.50-dotdot.patch +++ /dev/null @@ -1,85 +0,0 @@ -Only in unzip-5.50-lhh/: cscope.files -Only in unzip-5.50-lhh/: cscope.out -diff -ur unzip-5.50/unix/unix.c unzip-5.50-lhh/unix/unix.c ---- unzip-5.50/unix/unix.c 2002-01-21 17:54:42.000000000 -0500 -+++ unzip-5.50-lhh/unix/unix.c 2003-06-11 18:35:38.000000000 -0400 -@@ -421,7 +421,8 @@ - */ - { - char pathcomp[FILNAMSIZ]; /* path-component buffer */ -- char *pp, *cp=(char *)NULL; /* character pointers */ -+ char *pp, *cp=(char *)NULL, /* character pointers */ -+ *dp=(char *)NULL; - char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */ - #ifdef ACORN_FTYPE_NFS - char *lastcomma=(char *)NULL; /* pointer to last comma in pathcomp */ -@@ -429,6 +430,7 @@ - #endif - int quote = FALSE; /* flags */ - int killed_ddot = FALSE; /* is set when skipping "../" pathcomp */ -+ int snarf_ddot = FALSE; /* Is set while scanning for "../" */ - int error = MPN_OK; - register unsigned workch; /* hold the character being tested */ - -@@ -467,6 +469,9 @@ - while ((workch = (uch)*cp++) != 0) { - - if (quote) { /* if character quoted, */ -+ if ((pp == pathcomp) && (workch == '.')) -+ /* Oh no you don't... */ -+ goto ddot_hack; - *pp++ = (char)workch; /* include it literally */ - quote = FALSE; - } else -@@ -481,15 +486,44 @@ - break; - - case '.': -- if (pp == pathcomp) { /* nothing appended yet... */ -+ if (pp == pathcomp) { -+ddot_hack: -+ /* nothing appended yet... */ - if (*cp == '/') { /* don't bother appending "./" to */ - ++cp; /* the path: skip behind the '/' */ - break; -- } else if (!uO.ddotflag && *cp == '.' && cp[1] == '/') { -- /* "../" dir traversal detected */ -- cp += 2; /* skip over behind the '/' */ -- killed_ddot = TRUE; /* set "show message" flag */ -- break; -+ } else if (!uO.ddotflag) { -+ -+ /* -+ * SECURITY: Skip past control characters if the user -+ * didn't OK use of absolute pathnames. lhh - this is -+ * a very quick, ugly, inefficient fix. -+ */ -+ dp = cp; -+ do { -+ workch = (uch)(*dp); -+ if (workch == '/' && snarf_ddot) { -+ /* "../" dir traversal detected */ -+ cp = dp + 1; /* skip past the '/' */ -+ killed_ddot = TRUE; /* set "show msg" flag */ -+ break; -+ } else if (workch == '.' && !snarf_ddot) { -+ snarf_ddot = TRUE; -+ } else if (isprint(workch) || -+ ((workch > 127) && (workch <= 254))) { -+ /* -+ * Since we found a printable, non-ctrl char, -+ * we can stop looking for '../', the amount -+ * in ../! -+ */ -+ break; -+ } -+ -+ dp++; -+ } while (*dp != 0); -+ -+ if (killed_ddot) -+ break; - } - } - *pp++ = '.'; -Only in unzip-5.50-lhh/unix: .unix.c.swp diff --git a/tests/unzip2/pspec.xml b/tests/unzip2/pspec.xml deleted file mode 100644 index b8841dcb..00000000 --- a/tests/unzip2/pspec.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - unzip - ftp://ftp.info-zip.org/pub/infozip/UnZip.html - - A. Murat Eren - meren@uludag.org.tr - - Info-ZIP - category - component - Unzipper for pkzip-compressed files - Unzipper for pkzip-compressed files - ftp://ftp.linux.org.tr/pub/mirrors/gentoo/distfiles/unzip550.tar.gz - - unzip-5.50-dotdot.patch - - - libc - sed - patch - - - - - unzip - - - - - /usr/bin - /usr/share/doc - /usr/share/man - - - - - 2005-08-10 - 5.52 - - - - - diff --git a/tests/upgrade.sh b/tests/upgrade.sh deleted file mode 100755 index 6241c301..00000000 --- a/tests/upgrade.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -pwd -PATH=$PATH:. -set -x -e - -pisi-cli -Dtmp -E --ignore-build-no build tests/zip/pspec.xml tests/unzip/pspec.xml -pisi-cli -Dtmp --yes-all --ignore-comar install unzip-5.50-1.pisi zip-2.3-1.pisi - -mkdir -p myrepo -cd myrepo -mkdir -p tmp -../pisi-cli -Dtmp -E --ignore-build-no build ../tests/zip2/pspec.xml ../tests/unzip2/pspec.xml -cd .. -pisi-cli -Dtmp --absolute-uris index myrepo -pisi-cli -Dtmp remove-repo repo1 -pisi-cli -Dtmp add-repo repo1 pisi-index.xml -pisi-cli -Dtmp list-repo -pisi-cli -Dtmp update-repo repo1 -pisi-cli -Dtmp list-available -pisi-cli -Dtmp --install-info list-installed -pisi-cli -Dtmp list-upgrades -pisi-cli -Dtmp --ignore-comar upgrade zip -pisi-cli -Dtmp --install-info list-installed diff --git a/tests/utilfiles/arfilewithtimestamps.a b/tests/utilfiles/arfilewithtimestamps.a deleted file mode 100644 index cf93fc0fd5637ea83a403c67e32c6f3c6a375321..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74536 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 diff --git a/tests/utilfiles/directory/file_74536 b/tests/utilfiles/directory/file_74536 deleted file mode 100644 index 9f46a5728cea7129aa9830be9cec7df9cda12ff4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74536 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 -1: - svn_paths.append(os.path.join(root, d)) - continue - continue - return svn_paths - -def move_svn_paths(paths): - [shutil.move(d, 'tmp/' + os.path.dirname(d).replace('/', '_')) for d in paths] - -def restore_svn_paths(paths): - [shutil.move('tmp/' + os.path.dirname(d).replace('/', '_'), d) for d in paths] - - -class UtilTestCase(testcase.TestCase): - - def setUp(self): - testcase.TestCase.setUp(self, database = False) - - def testSubPath(self): - self.assert_(subpath('usr', 'usr')) - self.assert_(subpath('usr', 'usr/local/src')) - self.assert_(not subpath('usr/local', 'usr')) - - def testRemovePathPrefix(self): - a = removepathprefix('usr/local', 'usr/local/lib') - self.assertEqual(a, 'lib') - - a = removepathprefix('usr/local/', 'usr/local/lib') - self.assertEqual(a, 'lib') - - def testCleanArTimestamp(self): - shutil.copy('tests/utilfiles/arfilewithtimestamps.a', 'tests/utilfiles/cleanedarfile.a') - clean_ar_timestamps('tests/utilfiles/cleanedarfile.a') - for line in open('tests/utilfiles/cleanedarfile.a').readlines(): - pos = line.rfind(chr(32) + chr(96)) - if pos > -1 and line[pos-57:pos + 2].find(chr(47)) > -1: - self.assertEqual(line[pos-41:pos].split()[0], "0000000000") - - os.remove('tests/utilfiles/cleanedarfile.a') - - def testDirSize(self): - svn_paths = get_svn_paths('tests/utilfiles') - move_svn_paths(svn_paths) - self.assertEqual(dir_size('tests/utilfiles/arfilewithtimestamps.a'), 74536) - self.assertEqual(dir_size('tests/utilfiles/linktonowhere'), 23) - self.assertEqual(dir_size('tests/utilfiles/directory'), 74536) - self.assertEqual(dir_size('tests/utilfiles/linktoarfile'), 22) - self.assertEqual(dir_size('tests/utilfiles/'), 149072) - restore_svn_paths(svn_paths) - - def testGetFileHashes(self): - svn_paths = get_svn_paths('tests/utilfiles') - move_svn_paths(svn_paths) - self.assertEqual(len([x for x in get_file_hashes('tests/utilfiles/')]), 4) - for tpl in get_file_hashes('tests/utilfiles/'): - if os.path.basename(tpl[0]) == 'linktonowhere': - self.assertEqual(tpl[1], '2d3732ababb24b5dd040a192dc72841cb9684d4e') - if os.path.basename(tpl[0]) == 'linktoarfile': - self.assertEqual(tpl[1], '8be108bc4bfb7d18a10da6d6b76060f0409dc7c6') - restore_svn_paths(svn_paths) - -suite = unittest.makeSuite(UtilTestCase) diff --git a/tests/versiontests.py b/tests/versiontest.py similarity index 97% rename from tests/versiontests.py rename to tests/versiontest.py index b9ccd3eb..ac7cbe10 100644 --- a/tests/versiontests.py +++ b/tests/versiontest.py @@ -9,7 +9,6 @@ # import unittest -import os from pisi.version import Version @@ -74,5 +73,3 @@ class VersionTestCase(unittest.TestCase): v2 = Version('1.9.1') self.assert_( not v1 > v2 ) self.assert_( not v1 >= v2 ) - -suite = unittest.makeSuite(VersionTestCase) diff --git a/tests/xmlexttests.py b/tests/xmlexttests.py deleted file mode 100644 index b5b7f14d..00000000 --- a/tests/xmlexttests.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (C) 2005 - 2007, 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 unittest -import os - -import pisi -import pisi.api -import pisi.context as ctx -import pisi.util as util -from pisi.pxml import xmlext - -import testcase - -class XmlExtTestCase(testcase.TestCase): - - def setUp(self): - testcase.TestCase.setUp(self, database=False) - - def testGet(self): - self.doc = xmlext.parse('tests/a.xml') - #self.doc = self.a.documentElement - self.assertEqual(xmlext.getNodeText(self.doc, 'Number'), '868') - self.assertEqual(xmlext.getNodeText(self.doc, 'OtherInfo/BirthDate'), '18071976') - codeswith = xmlext.getAllNodes(self.doc, 'OtherInfo/CodesWith/Person') - self.assertEqual(len(codeswith), 4) - self.assertEqual(xmlext.getNodeText(codeswith[2]), 'Caglar') - - def testAdd(self): - node = xmlext.newDocument('pardus') - #node = a.documentElement - xmlext.addText(node, 'team/coder', 'zibidi1') - xmlext.addText(node, 'team/coder', 'zibidi2') - xmlext.addText(node, 'team/coder', 'zibidi3') - reada = xmlext.getAllNodes(node, 'team/coder') - self.assertEqual(len(reada), 3) - -suite = unittest.makeSuite(XmlExtTestCase) diff --git a/tests/zip/actions.py b/tests/zip/actions.py deleted file mode 100644 index 0d48caae..00000000 --- a/tests/zip/actions.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright (C) 2005 - 2007, 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. -# - -from pisi.actionsapi import autotools -from pisi.actionsapi import get -from pisi.actionsapi import pisitools - -def setup(): - pisitools.dosed("unix/Makefile", "-O2", get.CFLAGS()) - -def build(): - autotools.make("-f unix/Makefile CC=%s CPP=%s generic" % (get.CC(), get.CXX())) - -def install(): - pisitools.dobin("zip") - pisitools.dobin("zipcloak") - pisitools.dobin("zipnote") - pisitools.dobin("zipsplit") - - pisitools.doman("man/*.1") - pisitools.dodoc("BUGS", "CHANGES", "MANUAL", "README", "TODO", "WHATSNEW", "WHERE") - diff --git a/tests/zip/files/zcrypt.patch b/tests/zip/files/zcrypt.patch deleted file mode 100644 index 6b696af5..00000000 --- a/tests/zip/files/zcrypt.patch +++ /dev/null @@ -1,752 +0,0 @@ -diff -ur zip-2.3.orig/crypt.c zip-2.3/crypt.c ---- zip-2.3.orig/crypt.c 1999-10-09 23:09:26.000000000 +0300 -+++ zip-2.3/crypt.c 2005-07-15 16:19:00.000000000 +0300 -@@ -1,20 +1,577 @@ - /* -- Copyright (c) 1990-1999 Info-ZIP. All rights reserved. -+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved. - -- See the accompanying file LICENSE, version 1999-Oct-05 or later -+ See the accompanying file LICENSE, version 2000-Apr-09 or later - (the contents of which are also included in zip.h) for terms of use. -- If, for some reason, both of these files are missing, the Info-ZIP license -- also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html -+ If, for some reason, all these files are missing, the Info-ZIP license -+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html - */ - /* -- crypt.c (dummy version) by Info-ZIP. Last revised: 15 Aug 98 -+ crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] - -- This is a non-functional version of Info-ZIP's crypt.c encryption/ -- decryption code for Zip, ZipCloak, UnZip and fUnZip. This file is -- not copyrighted and may be distributed freely. :-) See the "WHERE" -- file for sites from which to obtain the full encryption/decryption -- sources (zcrypt28.zip or later). -+ The encryption/decryption parts of this source code (as opposed to the -+ non-echoing password parts) were originally written in Europe. The -+ whole source package can be freely distributed, including from the USA. -+ (Prior to January 2000, re-export from the US was a violation of US law.) - */ - -+/* -+ This encryption code is a direct transcription of the algorithm from -+ Roger Schlafly, described by Phil Katz in the file appnote.txt. This -+ file (appnote.txt) is distributed with the PKZIP program (even in the -+ version without encryption capabilities). -+ */ -+ -+#define ZCRYPT_INTERNAL -+#include "zip.h" -+#include "crypt.h" -+#include "ttyio.h" -+ -+#if CRYPT -+ -+#ifndef FALSE -+# define FALSE 0 -+#endif -+ -+#ifdef ZIP -+ /* For the encoding task used in Zip (and ZipCloak), we want to initialize -+ the crypt algorithm with some reasonably unpredictable bytes, see -+ the crypthead() function. The standard rand() library function is -+ used to supply these `random' bytes, which in turn is initialized by -+ a srand() call. The srand() function takes an "unsigned" (at least 16bit) -+ seed value as argument to determine the starting point of the rand() -+ pseudo-random number generator. -+ This seed number is constructed as "Seed = Seed1 .XOR. Seed2" with -+ Seed1 supplied by the current time (= "(unsigned)time()") and Seed2 -+ as some (hopefully) nondeterministic bitmask. On many (most) systems, -+ we use some "process specific" number, as the PID or something similar, -+ but when nothing unpredictable is available, a fixed number may be -+ sufficient. -+ NOTE: -+ 1.) This implementation requires the availability of the following -+ standard UNIX C runtime library functions: time(), rand(), srand(). -+ On systems where some of them are missing, the environment that -+ incorporates the crypt routines must supply suitable replacement -+ functions. -+ 2.) It is a very bad idea to use a second call to time() to set the -+ "Seed2" number! In this case, both "Seed1" and "Seed2" would be -+ (almost) identical, resulting in a (mostly) "zero" constant seed -+ number passed to srand(). -+ -+ The implementation environment defined in the "zip.h" header should -+ supply a reasonable definition for ZCR_SEED2 (an unsigned number; for -+ most implementations of rand() and srand(), only the lower 16 bits are -+ significant!). An example that works on many systems would be -+ "#define ZCR_SEED2 (unsigned)getpid()". -+ The default definition for ZCR_SEED2 supplied below should be regarded -+ as a fallback to allow successful compilation in "beta state" -+ environments. -+ */ -+# include /* time() function supplies first part of crypt seed */ -+ /* "last resort" source for second part of crypt seed pattern */ -+# ifndef ZCR_SEED2 -+# define ZCR_SEED2 (unsigned)3141592654L /* use PI as default pattern */ -+# endif -+# ifdef GLOBAL /* used in Amiga system headers, maybe others too */ -+# undef GLOBAL -+# endif -+# define GLOBAL(g) g -+#else /* !ZIP */ -+# define GLOBAL(g) G.g -+#endif /* ?ZIP */ -+ -+ -+#ifdef UNZIP -+ /* char *key = (char *)NULL; moved to globals.h */ -+# ifndef FUNZIP -+ local int testp OF((__GPRO__ ZCONST uch *h)); -+ local int testkey OF((__GPRO__ ZCONST uch *h, ZCONST char *key)); -+# endif -+#endif /* UNZIP */ -+ -+#ifndef UNZIP /* moved to globals.h for UnZip */ -+ local ulg keys[3]; /* keys defining the pseudo-random sequence */ -+#endif /* !UNZIP */ -+ -+#ifndef Trace -+# ifdef CRYPT_DEBUG -+# define Trace(x) fprintf x -+# else -+# define Trace(x) -+# endif -+#endif -+ -+#ifndef CRC_32_TAB -+# define CRC_32_TAB crc_32_tab -+#endif -+ -+#define CRC32(c, b) (CRC_32_TAB[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8)) -+ -+/*********************************************************************** -+ * Return the next byte in the pseudo-random sequence -+ */ -+int decrypt_byte(__G) -+ __GDEF -+{ -+ unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an -+ * unpredictable manner on 16-bit systems; not a problem -+ * with any known compiler so far, though */ -+ -+ temp = ((unsigned)GLOBAL(keys[2]) & 0xffff) | 2; -+ return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); -+} -+ -+/*********************************************************************** -+ * Update the encryption keys with the next byte of plain text -+ */ -+int update_keys(__G__ c) -+ __GDEF -+ int c; /* byte of plain text */ -+{ -+ GLOBAL(keys[0]) = CRC32(GLOBAL(keys[0]), c); -+ GLOBAL(keys[1]) += GLOBAL(keys[0]) & 0xff; -+ GLOBAL(keys[1]) = GLOBAL(keys[1]) * 134775813L + 1; -+ { -+ register int keyshift = (int)(GLOBAL(keys[1]) >> 24); -+ GLOBAL(keys[2]) = CRC32(GLOBAL(keys[2]), keyshift); -+ } -+ return c; -+} -+ -+ -+/*********************************************************************** -+ * Initialize the encryption keys and the random header according to -+ * the given password. -+ */ -+void init_keys(__G__ passwd) -+ __GDEF -+ ZCONST char *passwd; /* password string with which to modify keys */ -+{ -+ GLOBAL(keys[0]) = 305419896L; -+ GLOBAL(keys[1]) = 591751049L; -+ GLOBAL(keys[2]) = 878082192L; -+ while (*passwd != '\0') { -+ update_keys(__G__ (int)*passwd); -+ passwd++; -+ } -+} -+ -+ -+#ifdef ZIP -+ -+/*********************************************************************** -+ * Write encryption header to file zfile using the password passwd -+ * and the cyclic redundancy check crc. -+ */ -+void crypthead(passwd, crc, zfile) -+ ZCONST char *passwd; /* password string */ -+ ulg crc; /* crc of file being encrypted */ -+ FILE *zfile; /* where to write header */ -+{ -+ int n; /* index in random header */ -+ int t; /* temporary */ -+ int c; /* random byte */ -+ int ztemp; /* temporary for zencoded value */ -+ uch header[RAND_HEAD_LEN-2]; /* random header */ -+ static unsigned calls = 0; /* ensure different random header each time */ -+ -+ /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the -+ * output of rand() to get less predictability, since rand() is -+ * often poorly implemented. -+ */ -+ if (++calls == 1) { -+ srand((unsigned)time(NULL) ^ ZCR_SEED2); -+ } -+ init_keys(passwd); -+ for (n = 0; n < RAND_HEAD_LEN-2; n++) { -+ c = (rand() >> 7) & 0xff; -+ header[n] = (uch)zencode(c, t); -+ } -+ /* Encrypt random header (last two bytes is high word of crc) */ -+ init_keys(passwd); -+ for (n = 0; n < RAND_HEAD_LEN-2; n++) { -+ ztemp = zencode(header[n], t); -+ putc(ztemp, zfile); -+ } -+ ztemp = zencode((int)(crc >> 16) & 0xff, t); -+ putc(ztemp, zfile); -+ ztemp = zencode((int)(crc >> 24) & 0xff, t); -+ putc(ztemp, zfile); -+} -+ -+ -+#ifdef UTIL -+ -+/*********************************************************************** -+ * Encrypt the zip entry described by z from file source to file dest -+ * using the password passwd. Return an error code in the ZE_ class. -+ */ -+int zipcloak(z, source, dest, passwd) -+ struct zlist far *z; /* zip entry to encrypt */ -+ FILE *source, *dest; /* source and destination files */ -+ ZCONST char *passwd; /* password string */ -+{ -+ int c; /* input byte */ -+ int res; /* result code */ -+ ulg n; /* holds offset and counts size */ -+ ush flag; /* previous flags */ -+ int t; /* temporary */ -+ int ztemp; /* temporary storage for zencode value */ -+ -+ /* Set encrypted bit, clear extended local header bit and write local -+ header to output file */ -+ if ((n = (ulg)ftell(dest)) == (ulg)-1L) return ZE_TEMP; -+ z->off = n; -+ flag = z->flg; -+ z->flg |= 1, z->flg &= ~8; -+ z->lflg |= 1, z->lflg &= ~8; -+ z->siz += RAND_HEAD_LEN; -+ if ((res = putlocal(z, dest)) != ZE_OK) return res; -+ -+ /* Initialize keys with password and write random header */ -+ crypthead(passwd, z->crc, dest); -+ -+ /* Skip local header in input file */ -+ if (fseek(source, (long)(4 + LOCHEAD + (ulg)z->nam + (ulg)z->ext), -+ SEEK_CUR)) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ -+ /* Encrypt data */ -+ for (n = z->siz - RAND_HEAD_LEN; n; n--) { -+ if ((c = getc(source)) == EOF) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ ztemp = zencode(c, t); -+ putc(ztemp, dest); -+ } -+ /* Skip extended local header in input file if there is one */ -+ if ((flag & 8) != 0 && fseek(source, 16L, SEEK_CUR)) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ if (fflush(dest) == EOF) return ZE_TEMP; -+ return ZE_OK; -+} -+ -+/*********************************************************************** -+ * Decrypt the zip entry described by z from file source to file dest -+ * using the password passwd. Return an error code in the ZE_ class. -+ */ -+int zipbare(z, source, dest, passwd) -+ struct zlist far *z; /* zip entry to encrypt */ -+ FILE *source, *dest; /* source and destination files */ -+ ZCONST char *passwd; /* password string */ -+{ -+ int c0, c1; /* last two input bytes */ -+ ulg offset; /* used for file offsets */ -+ ulg size; /* size of input data */ -+ int r; /* size of encryption header */ -+ int res; /* return code */ -+ ush flag; /* previous flags */ -+ -+ /* Save position and skip local header in input file */ -+ if ((offset = (ulg)ftell(source)) == (ulg)-1L || -+ fseek(source, (long)(4 + LOCHEAD + (ulg)z->nam + (ulg)z->ext), -+ SEEK_CUR)) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ /* Initialize keys with password */ -+ init_keys(passwd); -+ -+ /* Decrypt encryption header, save last two bytes */ -+ c1 = 0; -+ for (r = RAND_HEAD_LEN; r; r--) { -+ c0 = c1; -+ if ((c1 = getc(source)) == EOF) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ Trace((stdout, " (%02x)", c1)); -+ zdecode(c1); -+ Trace((stdout, " %02x", c1)); -+ } -+ Trace((stdout, "\n")); -+ -+ /* If last two bytes of header don't match crc (or file time in the -+ * case of an extended local header), back up and just copy. For -+ * pkzip 2.0, the check has been reduced to one byte only. -+ */ -+#ifdef ZIP10 -+ if ((ush)(c0 | (c1<<8)) != -+ (z->flg & 8 ? (ush) z->tim & 0xffff : (ush)(z->crc >> 16))) { -+#else -+ c0++; /* avoid warning on unused variable */ -+ if ((ush)c1 != (z->flg & 8 ? (ush) z->tim >> 8 : (ush)(z->crc >> 24))) { -+#endif -+ if (fseek(source, offset, SEEK_SET)) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ if ((res = zipcopy(z, source, dest)) != ZE_OK) return res; -+ return ZE_MISS; -+ } -+ -+ /* Clear encrypted bit and local header bit, and write local header to -+ output file */ -+ if ((offset = (ulg)ftell(dest)) == (ulg)-1L) return ZE_TEMP; -+ z->off = offset; -+ flag = z->flg; -+ z->flg &= ~9; -+ z->lflg &= ~9; -+ z->siz -= RAND_HEAD_LEN; -+ if ((res = putlocal(z, dest)) != ZE_OK) return res; -+ -+ /* Decrypt data */ -+ for (size = z->siz; size; size--) { -+ if ((c1 = getc(source)) == EOF) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ zdecode(c1); -+ putc(c1, dest); -+ } -+ /* Skip extended local header in input file if there is one */ -+ if ((flag & 8) != 0 && fseek(source, 16L, SEEK_CUR)) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ if (fflush(dest) == EOF) return ZE_TEMP; -+ -+ return ZE_OK; -+} -+ -+ -+#else /* !UTIL */ -+ -+/*********************************************************************** -+ * If requested, encrypt the data in buf, and in any case call fwrite() -+ * with the arguments to zfwrite(). Return what fwrite() returns. -+ */ -+unsigned zfwrite(buf, item_size, nb, f) -+ zvoid *buf; /* data buffer */ -+ extent item_size; /* size of each item in bytes */ -+ extent nb; /* number of items */ -+ FILE *f; /* file to write to */ -+{ -+ int t; /* temporary */ -+ -+ if (key != (char *)NULL) { /* key is the global password pointer */ -+ ulg size; /* buffer size */ -+ char *p = (char*)buf; /* steps through buffer */ -+ -+ /* Encrypt data in buffer */ -+ for (size = item_size*(ulg)nb; size != 0; p++, size--) { -+ *p = (char)zencode(*p, t); -+ } -+ } -+ /* Write the buffer out */ -+ return fwrite(buf, item_size, nb, f); -+} -+ -+#endif /* ?UTIL */ -+#endif /* ZIP */ -+ -+ -+#if (defined(UNZIP) && !defined(FUNZIP)) -+ -+/*********************************************************************** -+ * Get the password and set up keys for current zipfile member. -+ * Return PK_ class error. -+ */ -+int decrypt(__G__ passwrd) -+ __GDEF -+ ZCONST char *passwrd; -+{ -+ ush b; -+ int n, r; -+ uch h[RAND_HEAD_LEN]; -+ -+ Trace((stdout, "\n[incnt = %d]: ", GLOBAL(incnt))); -+ -+ /* get header once (turn off "encrypted" flag temporarily so we don't -+ * try to decrypt the same data twice) */ -+ GLOBAL(pInfo->encrypted) = FALSE; -+ defer_leftover_input(__G); -+ for (n = 0; n < RAND_HEAD_LEN; n++) { -+ b = NEXTBYTE; -+ h[n] = (uch)b; -+ Trace((stdout, " (%02x)", h[n])); -+ } -+ undefer_input(__G); -+ GLOBAL(pInfo->encrypted) = TRUE; -+ -+ if (GLOBAL(newzip)) { /* this is first encrypted member in this zipfile */ -+ GLOBAL(newzip) = FALSE; -+ if (passwrd != (char *)NULL) { /* user gave password on command line */ -+ if (!GLOBAL(key)) { -+ if ((GLOBAL(key) = (char *)malloc(strlen(passwrd)+1)) == -+ (char *)NULL) -+ return PK_MEM2; -+ strcpy(GLOBAL(key), passwrd); -+ GLOBAL(nopwd) = TRUE; /* inhibit password prompting! */ -+ } -+ } else if (GLOBAL(key)) { /* get rid of previous zipfile's key */ -+ free(GLOBAL(key)); -+ GLOBAL(key) = (char *)NULL; -+ } -+ } -+ -+ /* if have key already, test it; else allocate memory for it */ -+ if (GLOBAL(key)) { -+ if (!testp(__G__ h)) -+ return PK_COOL; /* existing password OK (else prompt for new) */ -+ else if (GLOBAL(nopwd)) -+ return PK_WARN; /* user indicated no more prompting */ -+ } else if ((GLOBAL(key) = (char *)malloc(IZ_PWLEN+1)) == (char *)NULL) -+ return PK_MEM2; -+ -+ /* try a few keys */ -+ n = 0; -+ do { -+ r = (*G.decr_passwd)((zvoid *)&G, &n, GLOBAL(key), IZ_PWLEN+1, -+ GLOBAL(zipfn), GLOBAL(filename)); -+ if (r == IZ_PW_ERROR) { /* internal error in fetch of PW */ -+ free (GLOBAL(key)); -+ GLOBAL(key) = NULL; -+ return PK_MEM2; -+ } -+ if (r != IZ_PW_ENTERED) { /* user replied "skip" or "skip all" */ -+ *GLOBAL(key) = '\0'; /* We try the NIL password, ... */ -+ n = 0; /* and cancel fetch for this item. */ -+ } -+ if (!testp(__G__ h)) -+ return PK_COOL; -+ if (r == IZ_PW_CANCELALL) /* User replied "Skip all" */ -+ GLOBAL(nopwd) = TRUE; /* inhibit any further PW prompt! */ -+ } while (n > 0); -+ -+ return PK_WARN; -+ -+} /* end function decrypt() */ -+ -+ -+ -+/*********************************************************************** -+ * Test the password. Return -1 if bad, 0 if OK. -+ */ -+local int testp(__G__ h) -+ __GDEF -+ ZCONST uch *h; -+{ -+ int r; -+ char *key_translated; -+ -+ /* On systems with "obscure" native character coding (e.g., EBCDIC), -+ * the first test translates the password to the "main standard" -+ * character coding. */ -+ -+#ifdef STR_TO_CP1 -+ /* allocate buffer for translated password */ -+ if ((key_translated = malloc(strlen(GLOBAL(key)) + 1)) == (char *)NULL) -+ return -1; -+ /* first try, test password translated "standard" charset */ -+ r = testkey(__G__ h, STR_TO_CP1(key_translated, GLOBAL(key))); -+#else /* !STR_TO_CP1 */ -+ /* first try, test password as supplied on the extractor's host */ -+ r = testkey(__G__ h, GLOBAL(key)); -+#endif /* ?STR_TO_CP1 */ -+ -+#ifdef STR_TO_CP2 -+ if (r != 0) { -+#ifndef STR_TO_CP1 -+ /* now prepare for second (and maybe third) test with translated pwd */ -+ if ((key_translated = malloc(strlen(GLOBAL(key)) + 1)) == (char *)NULL) -+ return -1; -+#endif -+ /* second try, password translated to alternate ("standard") charset */ -+ r = testkey(__G__ h, STR_TO_CP2(key_translated, GLOBAL(key))); -+#ifdef STR_TO_CP3 -+ if (r != 0) -+ /* third try, password translated to another "standard" charset */ -+ r = testkey(__G__ h, STR_TO_CP3(key_translated, GLOBAL(key))); -+#endif -+#ifndef STR_TO_CP1 -+ free(key_translated); -+#endif -+ } -+#endif /* STR_TO_CP2 */ -+ -+#ifdef STR_TO_CP1 -+ free(key_translated); -+ if (r != 0) { -+ /* last resort, test password as supplied on the extractor's host */ -+ r = testkey(__G__ h, GLOBAL(key)); -+ } -+#endif /* STR_TO_CP1 */ -+ -+ return r; -+ -+} /* end function testp() */ -+ -+ -+local int testkey(__G__ h, key) -+ __GDEF -+ ZCONST uch *h; /* decrypted header */ -+ ZCONST char *key; /* decryption password to test */ -+{ -+ ush b; -+#ifdef ZIP10 -+ ush c; -+#endif -+ int n; -+ uch *p; -+ uch hh[RAND_HEAD_LEN]; /* decrypted header */ -+ -+ /* set keys and save the encrypted header */ -+ init_keys(__G__ key); -+ memcpy(hh, h, RAND_HEAD_LEN); -+ -+ /* check password */ -+ for (n = 0; n < RAND_HEAD_LEN; n++) { -+ zdecode(hh[n]); -+ Trace((stdout, " %02x", hh[n])); -+ } -+ -+ Trace((stdout, -+ "\n lrec.crc= %08lx crec.crc= %08lx pInfo->ExtLocHdr= %s\n", -+ GLOBAL(lrec.crc32), GLOBAL(pInfo->crc), -+ GLOBAL(pInfo->ExtLocHdr) ? "true":"false")); -+ Trace((stdout, " incnt = %d unzip offset into zipfile = %ld\n", -+ GLOBAL(incnt), -+ GLOBAL(cur_zipfile_bufstart)+(GLOBAL(inptr)-GLOBAL(inbuf)))); -+ -+ /* same test as in zipbare(): */ -+ -+#ifdef ZIP10 /* check two bytes */ -+ c = hh[RAND_HEAD_LEN-2], b = hh[RAND_HEAD_LEN-1]; -+ Trace((stdout, -+ " (c | (b<<8)) = %04x (crc >> 16) = %04x lrec.time = %04x\n", -+ (ush)(c | (b<<8)), (ush)(GLOBAL(lrec.crc32) >> 16), -+ ((ush)GLOBAL(lrec.last_mod_dos_datetime) & 0xffff)))); -+ if ((ush)(c | (b<<8)) != (GLOBAL(pInfo->ExtLocHdr) ? -+ ((ush)GLOBAL(lrec.last_mod_dos_datetime) & 0xffff) : -+ (ush)(GLOBAL(lrec.crc32) >> 16))) -+ return -1; /* bad */ -+#else -+ b = hh[RAND_HEAD_LEN-1]; -+ Trace((stdout, " b = %02x (crc >> 24) = %02x (lrec.time >> 8) = %02x\n", -+ b, (ush)(GLOBAL(lrec.crc32) >> 24), -+ ((ush)GLOBAL(lrec.last_mod_dos_datetime) >> 8) & 0xff)); -+ if (b != (GLOBAL(pInfo->ExtLocHdr) ? -+ ((ush)GLOBAL(lrec.last_mod_dos_datetime) >> 8) & 0xff : -+ (ush)(GLOBAL(lrec.crc32) >> 24))) -+ return -1; /* bad */ -+#endif -+ /* password OK: decrypt current buffer contents before leaving */ -+ for (n = (long)GLOBAL(incnt) > GLOBAL(csize) ? -+ (int)GLOBAL(csize) : GLOBAL(incnt), -+ p = GLOBAL(inptr); n--; p++) -+ zdecode(*p); -+ return 0; /* OK */ -+ -+} /* end function testkey() */ -+ -+#endif /* UNZIP && !FUNZIP */ -+ -+#else /* !CRYPT */ -+ - /* something "externally visible" to shut up compiler/linker warnings */ - int zcr_dummy; -+ -+#endif /* ?CRYPT */ -diff -ur zip-2.3.orig/crypt.h zip-2.3/crypt.h ---- zip-2.3.orig/crypt.h 1999-10-09 23:10:00.000000000 +0300 -+++ zip-2.3/crypt.h 2005-07-15 16:19:00.000000000 +0300 -@@ -1,19 +1,13 @@ - /* -- Copyright (c) 1990-1999 Info-ZIP. All rights reserved. -+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved. - -- See the accompanying file LICENSE, version 1999-Oct-05 or later -+ See the accompanying file LICENSE, version 2000-Apr-09 or later - (the contents of which are also included in zip.h) for terms of use. -- If, for some reason, both of these files are missing, the Info-ZIP license -- also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html -+ If, for some reason, all these files are missing, the Info-ZIP license -+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html - */ - /* -- crypt.h (dummy version) by Info-ZIP. Last revised: 15 Aug 98 -- -- This is a non-functional version of Info-ZIP's crypt.h encryption/ -- decryption header file for Zip, ZipCloak, UnZip and fUnZip. This -- file is not copyrighted and may be distributed without restriction. -- See the "WHERE" file for sites from which to obtain the full crypt -- sources (zcrypt28.zip or later). -+ crypt.h (full version) by Info-ZIP. Last revised: [see CR_VERSION_DATE] - */ - - #ifndef __crypt_h /* don't include more than once */ -@@ -22,11 +16,131 @@ - #ifdef CRYPT - # undef CRYPT - #endif --#define CRYPT 0 /* dummy version */ -+ -+#if !defined(NO_CRYPT) -+# define CRYPT 1 /* full version */ -+#else -+# define CRYPT 0 /* dummy version */ -+#endif -+ -+#if CRYPT -+/* full version */ -+ -+#ifdef CR_BETA -+# undef CR_BETA /* this is not a beta release */ -+#endif -+ -+#define CR_MAJORVER 2 -+#define CR_MINORVER 9 -+#ifdef CR_BETA -+# define CR_BETA_VER "a BETA" -+# define CR_VERSION_DATE "9 April 2000" /* last real code change */ -+#else -+# define CR_BETA_VER "" -+# define CR_VERSION_DATE "22 April 2000" /* last public release date */ -+# define CR_RELEASE -+#endif -+ -+#ifndef __G /* UnZip only, for now (DLL stuff) */ -+# define __G -+# define __G__ -+# define __GDEF -+# define __GPRO void -+# define __GPRO__ -+#endif -+ -+#if defined(MSDOS) || defined(OS2) || defined(WIN32) -+# ifndef DOS_OS2_W32 -+# define DOS_OS2_W32 -+# endif -+#endif -+ -+#if defined(DOS_OS2_W32) || defined(__human68k__) -+# ifndef DOS_H68_OS2_W32 -+# define DOS_H68_OS2_W32 -+# endif -+#endif -+ -+#if defined(VM_CMS) || defined(MVS) -+# ifndef CMS_MVS -+# define CMS_MVS -+# endif -+#endif -+ -+/* To allow combining of Zip and UnZip static libraries in a single binary, -+ * the Zip and UnZip versions of the crypt core functions have to be named -+ * differently. -+ */ -+#ifdef ZIP -+# ifdef REALLY_SHORT_SYMS -+# define decrypt_byte zdcrby -+# else -+# define decrypt_byte zp_decrypt_byte -+# endif -+# define update_keys zp_update_keys -+# define init_keys zp_init_keys -+#else /* !ZIP */ -+# ifdef REALLY_SHORT_SYMS -+# define decrypt_byte dcrbyt -+# endif -+#endif /* ?ZIP */ -+ -+#define IZ_PWLEN 80 /* input buffer size for reading encryption key */ -+#ifndef PWLEN /* for compatibility with previous zcrypt release... */ -+# define PWLEN IZ_PWLEN -+#endif -+#define RAND_HEAD_LEN 12 /* length of encryption random header */ -+ -+/* the crc_32_tab array has to be provided externally for the crypt calculus */ -+#ifndef CRC_32_TAB /* UnZip provides this in globals.h */ -+# if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB)) -+ extern ZCONST ulg near *crc_32_tab; -+# else -+ extern ZCONST ulg Far *crc_32_tab; -+# endif -+#endif /* !CRC_32_TAB */ -+ -+/* encode byte c, using temp t. Warning: c must not have side effects. */ -+#define zencode(c,t) (t=decrypt_byte(__G), update_keys(c), t^(c)) -+ -+/* decode byte c in place */ -+#define zdecode(c) update_keys(__G__ c ^= decrypt_byte(__G)) -+ -+int decrypt_byte OF((__GPRO)); -+int update_keys OF((__GPRO__ int c)); -+void init_keys OF((__GPRO__ ZCONST char *passwd)); -+ -+#ifdef ZIP -+ void crypthead OF((ZCONST char *, ulg, FILE *)); -+# ifdef UTIL -+ int zipcloak OF((struct zlist far *, FILE *, FILE *, ZCONST char *)); -+ int zipbare OF((struct zlist far *, FILE *, FILE *, ZCONST char *)); -+# else -+ unsigned zfwrite OF((zvoid *, extent, extent, FILE *)); -+ extern char *key; -+# endif -+#endif /* ZIP */ -+ -+#if (defined(UNZIP) && !defined(FUNZIP)) -+ int decrypt OF((__GPRO__ ZCONST char *passwrd)); -+#endif -+ -+#ifdef FUNZIP -+ extern int encrypted; -+# ifdef NEXTBYTE -+# undef NEXTBYTE -+# endif -+# define NEXTBYTE \ -+ (encrypted? update_keys(__G__ getc(G.in)^decrypt_byte(__G)) : getc(G.in)) -+#endif /* FUNZIP */ -+ -+#else /* !CRYPT */ -+/* dummy version */ - - #define zencode - #define zdecode - - #define zfwrite fwrite - -+#endif /* ?CRYPT */ - #endif /* !__crypt_h */ diff --git a/tests/zip/files/zip-2.3-unix_configure-pic.patch b/tests/zip/files/zip-2.3-unix_configure-pic.patch deleted file mode 100644 index 45b137b0..00000000 --- a/tests/zip/files/zip-2.3-unix_configure-pic.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- unix/configure.orig 2004-09-28 06:45:33.000000000 +0000 -+++ unix/configure 2004-09-28 06:54:53.000000000 +0000 -@@ -29,6 +29,9 @@ - - echo Check if we can use asm code - OBJA="" -+piclib="$(echo | $CPP -dM $CFLAGS - | grep -i __pic__)" -+echo "Checking if compiler wants to create pic code" -+[ "$piclib" == "" ] && \ - if eval "$CPP match.S > _match.s 2>/dev/null"; then - if test ! -s _match.s || grep error < _match.s > /dev/null; then - : diff --git a/tests/zip/files/zip-CAN-2004-1010.patch b/tests/zip/files/zip-CAN-2004-1010.patch deleted file mode 100644 index 150d6407..00000000 --- a/tests/zip/files/zip-CAN-2004-1010.patch +++ /dev/null @@ -1,25 +0,0 @@ ---- zip-2.3/unix/unix.c.orig 2004-11-05 15:44:41.000000000 -0500 -+++ zip-2.3/unix/unix.c 2004-11-05 15:50:28.000000000 -0500 -@@ -319,8 +319,8 @@ iztimes *t; /* return value: - a file size of -1 */ - { - struct stat s; /* results of stat() */ -- char name[FNMAX]; -- int len = strlen(f); -+ char *name; -+ size_t len = strlen(f); - - if (f == label) { - if (a != NULL) -@@ -331,6 +331,11 @@ iztimes *t; /* return value: - t->atime = t->mtime = t->ctime = label_utim; - return label_time; - } -+ -+ name = malloc(len+1); -+ if (!name) -+ return 0; -+ - strcpy(name, f); - if (name[len - 1] == '/') - name[len - 1] = '\0'; diff --git a/tests/zip/pspec.xml b/tests/zip/pspec.xml deleted file mode 100644 index 513655ba..00000000 --- a/tests/zip/pspec.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - zip - ftp://ftp.freesoftware.com/pub/infozip/Zip.html - - zibidi - himini@gmail.com - - Info-ZIP - category - component - Info ZIP (encryption support) - Info ZIP (şifre şeysi) - Info ZIP (encryption support) - ftp://ftp.linux.org.tr/pub/mirrors/gentoo/distfiles/zip23.tar.gz - - zip-2.3-unix_configure-pic.patch - zip-CAN-2004-1010.patch - zcrypt.patch - - - patch - - - - - zip - - unzip - - - /usr/bin - /usr/share/doc - /usr/share/man - - - - - 2005-07-15 - 2.3 - - - - - diff --git a/tests/zip2/actions.py b/tests/zip2/actions.py deleted file mode 100644 index 0726d844..00000000 --- a/tests/zip2/actions.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright (C) 2005 - 2007, 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. -# - -from pisi.actionsapi import autotools -from pisi.actionsapi import get -from pisi.actionsapi import pisitools - -WorkDir="zip-2.3" - -def setup(): - pisitools.dosed("unix/Makefile", "-O2", get.CFLAGS()) - -def build(): - autotools.make("-f unix/Makefile CC=%s CPP=%s generic" % (get.CC(), get.CXX())) - -def install(): - pisitools.dobin("zip") - pisitools.dobin("zipcloak") - pisitools.dobin("zipnote") - pisitools.dobin("zipsplit") - - pisitools.doman("man/*.1") - pisitools.dodoc("BUGS", "CHANGES", "MANUAL", "README", "TODO", "WHATSNEW", "WHERE") - diff --git a/tests/zip2/files/zcrypt.patch b/tests/zip2/files/zcrypt.patch deleted file mode 100644 index 6b696af5..00000000 --- a/tests/zip2/files/zcrypt.patch +++ /dev/null @@ -1,752 +0,0 @@ -diff -ur zip-2.3.orig/crypt.c zip-2.3/crypt.c ---- zip-2.3.orig/crypt.c 1999-10-09 23:09:26.000000000 +0300 -+++ zip-2.3/crypt.c 2005-07-15 16:19:00.000000000 +0300 -@@ -1,20 +1,577 @@ - /* -- Copyright (c) 1990-1999 Info-ZIP. All rights reserved. -+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved. - -- See the accompanying file LICENSE, version 1999-Oct-05 or later -+ See the accompanying file LICENSE, version 2000-Apr-09 or later - (the contents of which are also included in zip.h) for terms of use. -- If, for some reason, both of these files are missing, the Info-ZIP license -- also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html -+ If, for some reason, all these files are missing, the Info-ZIP license -+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html - */ - /* -- crypt.c (dummy version) by Info-ZIP. Last revised: 15 Aug 98 -+ crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] - -- This is a non-functional version of Info-ZIP's crypt.c encryption/ -- decryption code for Zip, ZipCloak, UnZip and fUnZip. This file is -- not copyrighted and may be distributed freely. :-) See the "WHERE" -- file for sites from which to obtain the full encryption/decryption -- sources (zcrypt28.zip or later). -+ The encryption/decryption parts of this source code (as opposed to the -+ non-echoing password parts) were originally written in Europe. The -+ whole source package can be freely distributed, including from the USA. -+ (Prior to January 2000, re-export from the US was a violation of US law.) - */ - -+/* -+ This encryption code is a direct transcription of the algorithm from -+ Roger Schlafly, described by Phil Katz in the file appnote.txt. This -+ file (appnote.txt) is distributed with the PKZIP program (even in the -+ version without encryption capabilities). -+ */ -+ -+#define ZCRYPT_INTERNAL -+#include "zip.h" -+#include "crypt.h" -+#include "ttyio.h" -+ -+#if CRYPT -+ -+#ifndef FALSE -+# define FALSE 0 -+#endif -+ -+#ifdef ZIP -+ /* For the encoding task used in Zip (and ZipCloak), we want to initialize -+ the crypt algorithm with some reasonably unpredictable bytes, see -+ the crypthead() function. The standard rand() library function is -+ used to supply these `random' bytes, which in turn is initialized by -+ a srand() call. The srand() function takes an "unsigned" (at least 16bit) -+ seed value as argument to determine the starting point of the rand() -+ pseudo-random number generator. -+ This seed number is constructed as "Seed = Seed1 .XOR. Seed2" with -+ Seed1 supplied by the current time (= "(unsigned)time()") and Seed2 -+ as some (hopefully) nondeterministic bitmask. On many (most) systems, -+ we use some "process specific" number, as the PID or something similar, -+ but when nothing unpredictable is available, a fixed number may be -+ sufficient. -+ NOTE: -+ 1.) This implementation requires the availability of the following -+ standard UNIX C runtime library functions: time(), rand(), srand(). -+ On systems where some of them are missing, the environment that -+ incorporates the crypt routines must supply suitable replacement -+ functions. -+ 2.) It is a very bad idea to use a second call to time() to set the -+ "Seed2" number! In this case, both "Seed1" and "Seed2" would be -+ (almost) identical, resulting in a (mostly) "zero" constant seed -+ number passed to srand(). -+ -+ The implementation environment defined in the "zip.h" header should -+ supply a reasonable definition for ZCR_SEED2 (an unsigned number; for -+ most implementations of rand() and srand(), only the lower 16 bits are -+ significant!). An example that works on many systems would be -+ "#define ZCR_SEED2 (unsigned)getpid()". -+ The default definition for ZCR_SEED2 supplied below should be regarded -+ as a fallback to allow successful compilation in "beta state" -+ environments. -+ */ -+# include /* time() function supplies first part of crypt seed */ -+ /* "last resort" source for second part of crypt seed pattern */ -+# ifndef ZCR_SEED2 -+# define ZCR_SEED2 (unsigned)3141592654L /* use PI as default pattern */ -+# endif -+# ifdef GLOBAL /* used in Amiga system headers, maybe others too */ -+# undef GLOBAL -+# endif -+# define GLOBAL(g) g -+#else /* !ZIP */ -+# define GLOBAL(g) G.g -+#endif /* ?ZIP */ -+ -+ -+#ifdef UNZIP -+ /* char *key = (char *)NULL; moved to globals.h */ -+# ifndef FUNZIP -+ local int testp OF((__GPRO__ ZCONST uch *h)); -+ local int testkey OF((__GPRO__ ZCONST uch *h, ZCONST char *key)); -+# endif -+#endif /* UNZIP */ -+ -+#ifndef UNZIP /* moved to globals.h for UnZip */ -+ local ulg keys[3]; /* keys defining the pseudo-random sequence */ -+#endif /* !UNZIP */ -+ -+#ifndef Trace -+# ifdef CRYPT_DEBUG -+# define Trace(x) fprintf x -+# else -+# define Trace(x) -+# endif -+#endif -+ -+#ifndef CRC_32_TAB -+# define CRC_32_TAB crc_32_tab -+#endif -+ -+#define CRC32(c, b) (CRC_32_TAB[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8)) -+ -+/*********************************************************************** -+ * Return the next byte in the pseudo-random sequence -+ */ -+int decrypt_byte(__G) -+ __GDEF -+{ -+ unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an -+ * unpredictable manner on 16-bit systems; not a problem -+ * with any known compiler so far, though */ -+ -+ temp = ((unsigned)GLOBAL(keys[2]) & 0xffff) | 2; -+ return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); -+} -+ -+/*********************************************************************** -+ * Update the encryption keys with the next byte of plain text -+ */ -+int update_keys(__G__ c) -+ __GDEF -+ int c; /* byte of plain text */ -+{ -+ GLOBAL(keys[0]) = CRC32(GLOBAL(keys[0]), c); -+ GLOBAL(keys[1]) += GLOBAL(keys[0]) & 0xff; -+ GLOBAL(keys[1]) = GLOBAL(keys[1]) * 134775813L + 1; -+ { -+ register int keyshift = (int)(GLOBAL(keys[1]) >> 24); -+ GLOBAL(keys[2]) = CRC32(GLOBAL(keys[2]), keyshift); -+ } -+ return c; -+} -+ -+ -+/*********************************************************************** -+ * Initialize the encryption keys and the random header according to -+ * the given password. -+ */ -+void init_keys(__G__ passwd) -+ __GDEF -+ ZCONST char *passwd; /* password string with which to modify keys */ -+{ -+ GLOBAL(keys[0]) = 305419896L; -+ GLOBAL(keys[1]) = 591751049L; -+ GLOBAL(keys[2]) = 878082192L; -+ while (*passwd != '\0') { -+ update_keys(__G__ (int)*passwd); -+ passwd++; -+ } -+} -+ -+ -+#ifdef ZIP -+ -+/*********************************************************************** -+ * Write encryption header to file zfile using the password passwd -+ * and the cyclic redundancy check crc. -+ */ -+void crypthead(passwd, crc, zfile) -+ ZCONST char *passwd; /* password string */ -+ ulg crc; /* crc of file being encrypted */ -+ FILE *zfile; /* where to write header */ -+{ -+ int n; /* index in random header */ -+ int t; /* temporary */ -+ int c; /* random byte */ -+ int ztemp; /* temporary for zencoded value */ -+ uch header[RAND_HEAD_LEN-2]; /* random header */ -+ static unsigned calls = 0; /* ensure different random header each time */ -+ -+ /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the -+ * output of rand() to get less predictability, since rand() is -+ * often poorly implemented. -+ */ -+ if (++calls == 1) { -+ srand((unsigned)time(NULL) ^ ZCR_SEED2); -+ } -+ init_keys(passwd); -+ for (n = 0; n < RAND_HEAD_LEN-2; n++) { -+ c = (rand() >> 7) & 0xff; -+ header[n] = (uch)zencode(c, t); -+ } -+ /* Encrypt random header (last two bytes is high word of crc) */ -+ init_keys(passwd); -+ for (n = 0; n < RAND_HEAD_LEN-2; n++) { -+ ztemp = zencode(header[n], t); -+ putc(ztemp, zfile); -+ } -+ ztemp = zencode((int)(crc >> 16) & 0xff, t); -+ putc(ztemp, zfile); -+ ztemp = zencode((int)(crc >> 24) & 0xff, t); -+ putc(ztemp, zfile); -+} -+ -+ -+#ifdef UTIL -+ -+/*********************************************************************** -+ * Encrypt the zip entry described by z from file source to file dest -+ * using the password passwd. Return an error code in the ZE_ class. -+ */ -+int zipcloak(z, source, dest, passwd) -+ struct zlist far *z; /* zip entry to encrypt */ -+ FILE *source, *dest; /* source and destination files */ -+ ZCONST char *passwd; /* password string */ -+{ -+ int c; /* input byte */ -+ int res; /* result code */ -+ ulg n; /* holds offset and counts size */ -+ ush flag; /* previous flags */ -+ int t; /* temporary */ -+ int ztemp; /* temporary storage for zencode value */ -+ -+ /* Set encrypted bit, clear extended local header bit and write local -+ header to output file */ -+ if ((n = (ulg)ftell(dest)) == (ulg)-1L) return ZE_TEMP; -+ z->off = n; -+ flag = z->flg; -+ z->flg |= 1, z->flg &= ~8; -+ z->lflg |= 1, z->lflg &= ~8; -+ z->siz += RAND_HEAD_LEN; -+ if ((res = putlocal(z, dest)) != ZE_OK) return res; -+ -+ /* Initialize keys with password and write random header */ -+ crypthead(passwd, z->crc, dest); -+ -+ /* Skip local header in input file */ -+ if (fseek(source, (long)(4 + LOCHEAD + (ulg)z->nam + (ulg)z->ext), -+ SEEK_CUR)) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ -+ /* Encrypt data */ -+ for (n = z->siz - RAND_HEAD_LEN; n; n--) { -+ if ((c = getc(source)) == EOF) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ ztemp = zencode(c, t); -+ putc(ztemp, dest); -+ } -+ /* Skip extended local header in input file if there is one */ -+ if ((flag & 8) != 0 && fseek(source, 16L, SEEK_CUR)) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ if (fflush(dest) == EOF) return ZE_TEMP; -+ return ZE_OK; -+} -+ -+/*********************************************************************** -+ * Decrypt the zip entry described by z from file source to file dest -+ * using the password passwd. Return an error code in the ZE_ class. -+ */ -+int zipbare(z, source, dest, passwd) -+ struct zlist far *z; /* zip entry to encrypt */ -+ FILE *source, *dest; /* source and destination files */ -+ ZCONST char *passwd; /* password string */ -+{ -+ int c0, c1; /* last two input bytes */ -+ ulg offset; /* used for file offsets */ -+ ulg size; /* size of input data */ -+ int r; /* size of encryption header */ -+ int res; /* return code */ -+ ush flag; /* previous flags */ -+ -+ /* Save position and skip local header in input file */ -+ if ((offset = (ulg)ftell(source)) == (ulg)-1L || -+ fseek(source, (long)(4 + LOCHEAD + (ulg)z->nam + (ulg)z->ext), -+ SEEK_CUR)) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ /* Initialize keys with password */ -+ init_keys(passwd); -+ -+ /* Decrypt encryption header, save last two bytes */ -+ c1 = 0; -+ for (r = RAND_HEAD_LEN; r; r--) { -+ c0 = c1; -+ if ((c1 = getc(source)) == EOF) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ Trace((stdout, " (%02x)", c1)); -+ zdecode(c1); -+ Trace((stdout, " %02x", c1)); -+ } -+ Trace((stdout, "\n")); -+ -+ /* If last two bytes of header don't match crc (or file time in the -+ * case of an extended local header), back up and just copy. For -+ * pkzip 2.0, the check has been reduced to one byte only. -+ */ -+#ifdef ZIP10 -+ if ((ush)(c0 | (c1<<8)) != -+ (z->flg & 8 ? (ush) z->tim & 0xffff : (ush)(z->crc >> 16))) { -+#else -+ c0++; /* avoid warning on unused variable */ -+ if ((ush)c1 != (z->flg & 8 ? (ush) z->tim >> 8 : (ush)(z->crc >> 24))) { -+#endif -+ if (fseek(source, offset, SEEK_SET)) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ if ((res = zipcopy(z, source, dest)) != ZE_OK) return res; -+ return ZE_MISS; -+ } -+ -+ /* Clear encrypted bit and local header bit, and write local header to -+ output file */ -+ if ((offset = (ulg)ftell(dest)) == (ulg)-1L) return ZE_TEMP; -+ z->off = offset; -+ flag = z->flg; -+ z->flg &= ~9; -+ z->lflg &= ~9; -+ z->siz -= RAND_HEAD_LEN; -+ if ((res = putlocal(z, dest)) != ZE_OK) return res; -+ -+ /* Decrypt data */ -+ for (size = z->siz; size; size--) { -+ if ((c1 = getc(source)) == EOF) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ zdecode(c1); -+ putc(c1, dest); -+ } -+ /* Skip extended local header in input file if there is one */ -+ if ((flag & 8) != 0 && fseek(source, 16L, SEEK_CUR)) { -+ return ferror(source) ? ZE_READ : ZE_EOF; -+ } -+ if (fflush(dest) == EOF) return ZE_TEMP; -+ -+ return ZE_OK; -+} -+ -+ -+#else /* !UTIL */ -+ -+/*********************************************************************** -+ * If requested, encrypt the data in buf, and in any case call fwrite() -+ * with the arguments to zfwrite(). Return what fwrite() returns. -+ */ -+unsigned zfwrite(buf, item_size, nb, f) -+ zvoid *buf; /* data buffer */ -+ extent item_size; /* size of each item in bytes */ -+ extent nb; /* number of items */ -+ FILE *f; /* file to write to */ -+{ -+ int t; /* temporary */ -+ -+ if (key != (char *)NULL) { /* key is the global password pointer */ -+ ulg size; /* buffer size */ -+ char *p = (char*)buf; /* steps through buffer */ -+ -+ /* Encrypt data in buffer */ -+ for (size = item_size*(ulg)nb; size != 0; p++, size--) { -+ *p = (char)zencode(*p, t); -+ } -+ } -+ /* Write the buffer out */ -+ return fwrite(buf, item_size, nb, f); -+} -+ -+#endif /* ?UTIL */ -+#endif /* ZIP */ -+ -+ -+#if (defined(UNZIP) && !defined(FUNZIP)) -+ -+/*********************************************************************** -+ * Get the password and set up keys for current zipfile member. -+ * Return PK_ class error. -+ */ -+int decrypt(__G__ passwrd) -+ __GDEF -+ ZCONST char *passwrd; -+{ -+ ush b; -+ int n, r; -+ uch h[RAND_HEAD_LEN]; -+ -+ Trace((stdout, "\n[incnt = %d]: ", GLOBAL(incnt))); -+ -+ /* get header once (turn off "encrypted" flag temporarily so we don't -+ * try to decrypt the same data twice) */ -+ GLOBAL(pInfo->encrypted) = FALSE; -+ defer_leftover_input(__G); -+ for (n = 0; n < RAND_HEAD_LEN; n++) { -+ b = NEXTBYTE; -+ h[n] = (uch)b; -+ Trace((stdout, " (%02x)", h[n])); -+ } -+ undefer_input(__G); -+ GLOBAL(pInfo->encrypted) = TRUE; -+ -+ if (GLOBAL(newzip)) { /* this is first encrypted member in this zipfile */ -+ GLOBAL(newzip) = FALSE; -+ if (passwrd != (char *)NULL) { /* user gave password on command line */ -+ if (!GLOBAL(key)) { -+ if ((GLOBAL(key) = (char *)malloc(strlen(passwrd)+1)) == -+ (char *)NULL) -+ return PK_MEM2; -+ strcpy(GLOBAL(key), passwrd); -+ GLOBAL(nopwd) = TRUE; /* inhibit password prompting! */ -+ } -+ } else if (GLOBAL(key)) { /* get rid of previous zipfile's key */ -+ free(GLOBAL(key)); -+ GLOBAL(key) = (char *)NULL; -+ } -+ } -+ -+ /* if have key already, test it; else allocate memory for it */ -+ if (GLOBAL(key)) { -+ if (!testp(__G__ h)) -+ return PK_COOL; /* existing password OK (else prompt for new) */ -+ else if (GLOBAL(nopwd)) -+ return PK_WARN; /* user indicated no more prompting */ -+ } else if ((GLOBAL(key) = (char *)malloc(IZ_PWLEN+1)) == (char *)NULL) -+ return PK_MEM2; -+ -+ /* try a few keys */ -+ n = 0; -+ do { -+ r = (*G.decr_passwd)((zvoid *)&G, &n, GLOBAL(key), IZ_PWLEN+1, -+ GLOBAL(zipfn), GLOBAL(filename)); -+ if (r == IZ_PW_ERROR) { /* internal error in fetch of PW */ -+ free (GLOBAL(key)); -+ GLOBAL(key) = NULL; -+ return PK_MEM2; -+ } -+ if (r != IZ_PW_ENTERED) { /* user replied "skip" or "skip all" */ -+ *GLOBAL(key) = '\0'; /* We try the NIL password, ... */ -+ n = 0; /* and cancel fetch for this item. */ -+ } -+ if (!testp(__G__ h)) -+ return PK_COOL; -+ if (r == IZ_PW_CANCELALL) /* User replied "Skip all" */ -+ GLOBAL(nopwd) = TRUE; /* inhibit any further PW prompt! */ -+ } while (n > 0); -+ -+ return PK_WARN; -+ -+} /* end function decrypt() */ -+ -+ -+ -+/*********************************************************************** -+ * Test the password. Return -1 if bad, 0 if OK. -+ */ -+local int testp(__G__ h) -+ __GDEF -+ ZCONST uch *h; -+{ -+ int r; -+ char *key_translated; -+ -+ /* On systems with "obscure" native character coding (e.g., EBCDIC), -+ * the first test translates the password to the "main standard" -+ * character coding. */ -+ -+#ifdef STR_TO_CP1 -+ /* allocate buffer for translated password */ -+ if ((key_translated = malloc(strlen(GLOBAL(key)) + 1)) == (char *)NULL) -+ return -1; -+ /* first try, test password translated "standard" charset */ -+ r = testkey(__G__ h, STR_TO_CP1(key_translated, GLOBAL(key))); -+#else /* !STR_TO_CP1 */ -+ /* first try, test password as supplied on the extractor's host */ -+ r = testkey(__G__ h, GLOBAL(key)); -+#endif /* ?STR_TO_CP1 */ -+ -+#ifdef STR_TO_CP2 -+ if (r != 0) { -+#ifndef STR_TO_CP1 -+ /* now prepare for second (and maybe third) test with translated pwd */ -+ if ((key_translated = malloc(strlen(GLOBAL(key)) + 1)) == (char *)NULL) -+ return -1; -+#endif -+ /* second try, password translated to alternate ("standard") charset */ -+ r = testkey(__G__ h, STR_TO_CP2(key_translated, GLOBAL(key))); -+#ifdef STR_TO_CP3 -+ if (r != 0) -+ /* third try, password translated to another "standard" charset */ -+ r = testkey(__G__ h, STR_TO_CP3(key_translated, GLOBAL(key))); -+#endif -+#ifndef STR_TO_CP1 -+ free(key_translated); -+#endif -+ } -+#endif /* STR_TO_CP2 */ -+ -+#ifdef STR_TO_CP1 -+ free(key_translated); -+ if (r != 0) { -+ /* last resort, test password as supplied on the extractor's host */ -+ r = testkey(__G__ h, GLOBAL(key)); -+ } -+#endif /* STR_TO_CP1 */ -+ -+ return r; -+ -+} /* end function testp() */ -+ -+ -+local int testkey(__G__ h, key) -+ __GDEF -+ ZCONST uch *h; /* decrypted header */ -+ ZCONST char *key; /* decryption password to test */ -+{ -+ ush b; -+#ifdef ZIP10 -+ ush c; -+#endif -+ int n; -+ uch *p; -+ uch hh[RAND_HEAD_LEN]; /* decrypted header */ -+ -+ /* set keys and save the encrypted header */ -+ init_keys(__G__ key); -+ memcpy(hh, h, RAND_HEAD_LEN); -+ -+ /* check password */ -+ for (n = 0; n < RAND_HEAD_LEN; n++) { -+ zdecode(hh[n]); -+ Trace((stdout, " %02x", hh[n])); -+ } -+ -+ Trace((stdout, -+ "\n lrec.crc= %08lx crec.crc= %08lx pInfo->ExtLocHdr= %s\n", -+ GLOBAL(lrec.crc32), GLOBAL(pInfo->crc), -+ GLOBAL(pInfo->ExtLocHdr) ? "true":"false")); -+ Trace((stdout, " incnt = %d unzip offset into zipfile = %ld\n", -+ GLOBAL(incnt), -+ GLOBAL(cur_zipfile_bufstart)+(GLOBAL(inptr)-GLOBAL(inbuf)))); -+ -+ /* same test as in zipbare(): */ -+ -+#ifdef ZIP10 /* check two bytes */ -+ c = hh[RAND_HEAD_LEN-2], b = hh[RAND_HEAD_LEN-1]; -+ Trace((stdout, -+ " (c | (b<<8)) = %04x (crc >> 16) = %04x lrec.time = %04x\n", -+ (ush)(c | (b<<8)), (ush)(GLOBAL(lrec.crc32) >> 16), -+ ((ush)GLOBAL(lrec.last_mod_dos_datetime) & 0xffff)))); -+ if ((ush)(c | (b<<8)) != (GLOBAL(pInfo->ExtLocHdr) ? -+ ((ush)GLOBAL(lrec.last_mod_dos_datetime) & 0xffff) : -+ (ush)(GLOBAL(lrec.crc32) >> 16))) -+ return -1; /* bad */ -+#else -+ b = hh[RAND_HEAD_LEN-1]; -+ Trace((stdout, " b = %02x (crc >> 24) = %02x (lrec.time >> 8) = %02x\n", -+ b, (ush)(GLOBAL(lrec.crc32) >> 24), -+ ((ush)GLOBAL(lrec.last_mod_dos_datetime) >> 8) & 0xff)); -+ if (b != (GLOBAL(pInfo->ExtLocHdr) ? -+ ((ush)GLOBAL(lrec.last_mod_dos_datetime) >> 8) & 0xff : -+ (ush)(GLOBAL(lrec.crc32) >> 24))) -+ return -1; /* bad */ -+#endif -+ /* password OK: decrypt current buffer contents before leaving */ -+ for (n = (long)GLOBAL(incnt) > GLOBAL(csize) ? -+ (int)GLOBAL(csize) : GLOBAL(incnt), -+ p = GLOBAL(inptr); n--; p++) -+ zdecode(*p); -+ return 0; /* OK */ -+ -+} /* end function testkey() */ -+ -+#endif /* UNZIP && !FUNZIP */ -+ -+#else /* !CRYPT */ -+ - /* something "externally visible" to shut up compiler/linker warnings */ - int zcr_dummy; -+ -+#endif /* ?CRYPT */ -diff -ur zip-2.3.orig/crypt.h zip-2.3/crypt.h ---- zip-2.3.orig/crypt.h 1999-10-09 23:10:00.000000000 +0300 -+++ zip-2.3/crypt.h 2005-07-15 16:19:00.000000000 +0300 -@@ -1,19 +1,13 @@ - /* -- Copyright (c) 1990-1999 Info-ZIP. All rights reserved. -+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved. - -- See the accompanying file LICENSE, version 1999-Oct-05 or later -+ See the accompanying file LICENSE, version 2000-Apr-09 or later - (the contents of which are also included in zip.h) for terms of use. -- If, for some reason, both of these files are missing, the Info-ZIP license -- also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html -+ If, for some reason, all these files are missing, the Info-ZIP license -+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html - */ - /* -- crypt.h (dummy version) by Info-ZIP. Last revised: 15 Aug 98 -- -- This is a non-functional version of Info-ZIP's crypt.h encryption/ -- decryption header file for Zip, ZipCloak, UnZip and fUnZip. This -- file is not copyrighted and may be distributed without restriction. -- See the "WHERE" file for sites from which to obtain the full crypt -- sources (zcrypt28.zip or later). -+ crypt.h (full version) by Info-ZIP. Last revised: [see CR_VERSION_DATE] - */ - - #ifndef __crypt_h /* don't include more than once */ -@@ -22,11 +16,131 @@ - #ifdef CRYPT - # undef CRYPT - #endif --#define CRYPT 0 /* dummy version */ -+ -+#if !defined(NO_CRYPT) -+# define CRYPT 1 /* full version */ -+#else -+# define CRYPT 0 /* dummy version */ -+#endif -+ -+#if CRYPT -+/* full version */ -+ -+#ifdef CR_BETA -+# undef CR_BETA /* this is not a beta release */ -+#endif -+ -+#define CR_MAJORVER 2 -+#define CR_MINORVER 9 -+#ifdef CR_BETA -+# define CR_BETA_VER "a BETA" -+# define CR_VERSION_DATE "9 April 2000" /* last real code change */ -+#else -+# define CR_BETA_VER "" -+# define CR_VERSION_DATE "22 April 2000" /* last public release date */ -+# define CR_RELEASE -+#endif -+ -+#ifndef __G /* UnZip only, for now (DLL stuff) */ -+# define __G -+# define __G__ -+# define __GDEF -+# define __GPRO void -+# define __GPRO__ -+#endif -+ -+#if defined(MSDOS) || defined(OS2) || defined(WIN32) -+# ifndef DOS_OS2_W32 -+# define DOS_OS2_W32 -+# endif -+#endif -+ -+#if defined(DOS_OS2_W32) || defined(__human68k__) -+# ifndef DOS_H68_OS2_W32 -+# define DOS_H68_OS2_W32 -+# endif -+#endif -+ -+#if defined(VM_CMS) || defined(MVS) -+# ifndef CMS_MVS -+# define CMS_MVS -+# endif -+#endif -+ -+/* To allow combining of Zip and UnZip static libraries in a single binary, -+ * the Zip and UnZip versions of the crypt core functions have to be named -+ * differently. -+ */ -+#ifdef ZIP -+# ifdef REALLY_SHORT_SYMS -+# define decrypt_byte zdcrby -+# else -+# define decrypt_byte zp_decrypt_byte -+# endif -+# define update_keys zp_update_keys -+# define init_keys zp_init_keys -+#else /* !ZIP */ -+# ifdef REALLY_SHORT_SYMS -+# define decrypt_byte dcrbyt -+# endif -+#endif /* ?ZIP */ -+ -+#define IZ_PWLEN 80 /* input buffer size for reading encryption key */ -+#ifndef PWLEN /* for compatibility with previous zcrypt release... */ -+# define PWLEN IZ_PWLEN -+#endif -+#define RAND_HEAD_LEN 12 /* length of encryption random header */ -+ -+/* the crc_32_tab array has to be provided externally for the crypt calculus */ -+#ifndef CRC_32_TAB /* UnZip provides this in globals.h */ -+# if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB)) -+ extern ZCONST ulg near *crc_32_tab; -+# else -+ extern ZCONST ulg Far *crc_32_tab; -+# endif -+#endif /* !CRC_32_TAB */ -+ -+/* encode byte c, using temp t. Warning: c must not have side effects. */ -+#define zencode(c,t) (t=decrypt_byte(__G), update_keys(c), t^(c)) -+ -+/* decode byte c in place */ -+#define zdecode(c) update_keys(__G__ c ^= decrypt_byte(__G)) -+ -+int decrypt_byte OF((__GPRO)); -+int update_keys OF((__GPRO__ int c)); -+void init_keys OF((__GPRO__ ZCONST char *passwd)); -+ -+#ifdef ZIP -+ void crypthead OF((ZCONST char *, ulg, FILE *)); -+# ifdef UTIL -+ int zipcloak OF((struct zlist far *, FILE *, FILE *, ZCONST char *)); -+ int zipbare OF((struct zlist far *, FILE *, FILE *, ZCONST char *)); -+# else -+ unsigned zfwrite OF((zvoid *, extent, extent, FILE *)); -+ extern char *key; -+# endif -+#endif /* ZIP */ -+ -+#if (defined(UNZIP) && !defined(FUNZIP)) -+ int decrypt OF((__GPRO__ ZCONST char *passwrd)); -+#endif -+ -+#ifdef FUNZIP -+ extern int encrypted; -+# ifdef NEXTBYTE -+# undef NEXTBYTE -+# endif -+# define NEXTBYTE \ -+ (encrypted? update_keys(__G__ getc(G.in)^decrypt_byte(__G)) : getc(G.in)) -+#endif /* FUNZIP */ -+ -+#else /* !CRYPT */ -+/* dummy version */ - - #define zencode - #define zdecode - - #define zfwrite fwrite - -+#endif /* ?CRYPT */ - #endif /* !__crypt_h */ diff --git a/tests/zip2/files/zip-2.3-unix_configure-pic.patch b/tests/zip2/files/zip-2.3-unix_configure-pic.patch deleted file mode 100644 index 45b137b0..00000000 --- a/tests/zip2/files/zip-2.3-unix_configure-pic.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- unix/configure.orig 2004-09-28 06:45:33.000000000 +0000 -+++ unix/configure 2004-09-28 06:54:53.000000000 +0000 -@@ -29,6 +29,9 @@ - - echo Check if we can use asm code - OBJA="" -+piclib="$(echo | $CPP -dM $CFLAGS - | grep -i __pic__)" -+echo "Checking if compiler wants to create pic code" -+[ "$piclib" == "" ] && \ - if eval "$CPP match.S > _match.s 2>/dev/null"; then - if test ! -s _match.s || grep error < _match.s > /dev/null; then - : diff --git a/tests/zip2/files/zip-CAN-2004-1010.patch b/tests/zip2/files/zip-CAN-2004-1010.patch deleted file mode 100644 index 150d6407..00000000 --- a/tests/zip2/files/zip-CAN-2004-1010.patch +++ /dev/null @@ -1,25 +0,0 @@ ---- zip-2.3/unix/unix.c.orig 2004-11-05 15:44:41.000000000 -0500 -+++ zip-2.3/unix/unix.c 2004-11-05 15:50:28.000000000 -0500 -@@ -319,8 +319,8 @@ iztimes *t; /* return value: - a file size of -1 */ - { - struct stat s; /* results of stat() */ -- char name[FNMAX]; -- int len = strlen(f); -+ char *name; -+ size_t len = strlen(f); - - if (f == label) { - if (a != NULL) -@@ -331,6 +331,11 @@ iztimes *t; /* return value: - t->atime = t->mtime = t->ctime = label_utim; - return label_time; - } -+ -+ name = malloc(len+1); -+ if (!name) -+ return 0; -+ - strcpy(name, f); - if (name[len - 1] == '/') - name[len - 1] = '\0'; diff --git a/tests/zip2/pspec.xml b/tests/zip2/pspec.xml deleted file mode 100644 index 5c439849..00000000 --- a/tests/zip2/pspec.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - zip - ftp://ftp.freesoftware.com/pub/infozip/Zip.html - - PACKAGER - PACKAGER_EMAIL - - Info-ZIP - category - component - Info ZIP (encryption support) - Info ZIP (encryption support) - ftp://ftp.linux.org.tr/pub/mirrors/gentoo/distfiles/zip23.tar.gz - - zip-2.3-unix_configure-pic.patch - - zcrypt.patch - - - unzip - patch - - - - - zip - - unzip - - - /usr/bin - /usr/share/doc - /usr/share/man - - - - - - 2005-08-11 - 2.4 - - - - -