aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'portage_with_autodep')
-rwxr-xr-xportage_with_autodep/bin/archive-conf111
-rwxr-xr-xportage_with_autodep/bin/banned-helper6
-rwxr-xr-xportage_with_autodep/bin/binhost-snapshot142
-rwxr-xr-xportage_with_autodep/bin/check-implicit-pointer-usage.py84
-rwxr-xr-xportage_with_autodep/bin/clean_locks47
-rwxr-xr-xportage_with_autodep/bin/dispatch-conf434
-rwxr-xr-xportage_with_autodep/bin/dohtml.py191
-rwxr-xr-xportage_with_autodep/bin/ebuild346
l---------portage_with_autodep/bin/ebuild-helpers/4/dodoc1
l---------portage_with_autodep/bin/ebuild-helpers/4/dohard1
l---------portage_with_autodep/bin/ebuild-helpers/4/dosed1
l---------portage_with_autodep/bin/ebuild-helpers/4/prepalldocs1
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/die7
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/dobin29
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/doconfd14
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/dodir10
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/dodoc31
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/doenvd14
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/doexe43
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/dohard13
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/dohtml14
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/doinfo24
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/doinitd14
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/doins155
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/dolib43
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/dolib.a6
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/dolib.so6
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/doman64
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/domo34
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/dosbin29
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/dosed35
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/dosym18
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/ecompress161
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/ecompressdir143
l---------portage_with_autodep/bin/ebuild-helpers/eerror1
l---------portage_with_autodep/bin/ebuild-helpers/einfo1
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/elog7
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/emake28
l---------portage_with_autodep/bin/ebuild-helpers/eqawarn1
l---------portage_with_autodep/bin/ebuild-helpers/ewarn1
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/fowners13
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/fperms13
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/newbin19
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/newconfd19
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/newdoc19
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/newenvd19
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/newexe19
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/newinitd19
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/newins35
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/newlib.a19
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/newlib.so19
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/newman19
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/newsbin19
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/portageq8
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/prepall23
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/prepalldocs15
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/prepallinfo9
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/prepallman19
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/prepallstrip5
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/prepinfo34
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/preplib28
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/prepman32
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/prepstrip193
-rwxr-xr-xportage_with_autodep/bin/ebuild-helpers/sed27
-rwxr-xr-xportage_with_autodep/bin/ebuild-ipc8
-rwxr-xr-xportage_with_autodep/bin/ebuild-ipc.py276
-rwxr-xr-xportage_with_autodep/bin/ebuild.sh2424
-rwxr-xr-xportage_with_autodep/bin/egencache851
-rwxr-xr-xportage_with_autodep/bin/emaint654
-rwxr-xr-xportage_with_autodep/bin/emerge66
-rwxr-xr-xportage_with_autodep/bin/emerge-webrsync457
-rwxr-xr-xportage_with_autodep/bin/env-update41
-rwxr-xr-xportage_with_autodep/bin/etc-update616
-rwxr-xr-xportage_with_autodep/bin/filter-bash-environment.py150
-rwxr-xr-xportage_with_autodep/bin/fixpackages45
-rwxr-xr-xportage_with_autodep/bin/glsa-check316
-rw-r--r--portage_with_autodep/bin/isolated-functions.sh630
-rwxr-xr-xportage_with_autodep/bin/lock-helper.py28
-rwxr-xr-xportage_with_autodep/bin/misc-functions.sh1002
-rwxr-xr-xportage_with_autodep/bin/portageq822
-rwxr-xr-xportage_with_autodep/bin/quickpkg291
-rwxr-xr-xportage_with_autodep/bin/regenworld144
-rwxr-xr-xportage_with_autodep/bin/repoman2672
-rwxr-xr-xportage_with_autodep/bin/xpak-helper.py68
-rw-r--r--portage_with_autodep/pym/_emerge/AbstractDepPriority.py29
-rw-r--r--portage_with_autodep/pym/_emerge/AbstractEbuildProcess.py266
-rw-r--r--portage_with_autodep/pym/_emerge/AbstractPollTask.py62
-rw-r--r--portage_with_autodep/pym/_emerge/AsynchronousLock.py288
-rw-r--r--portage_with_autodep/pym/_emerge/AsynchronousTask.py129
-rw-r--r--portage_with_autodep/pym/_emerge/AtomArg.py11
-rw-r--r--portage_with_autodep/pym/_emerge/Binpkg.py333
-rw-r--r--portage_with_autodep/pym/_emerge/BinpkgEnvExtractor.py66
-rw-r--r--portage_with_autodep/pym/_emerge/BinpkgExtractorAsync.py31
-rw-r--r--portage_with_autodep/pym/_emerge/BinpkgFetcher.py181
-rw-r--r--portage_with_autodep/pym/_emerge/BinpkgPrefetcher.py43
-rw-r--r--portage_with_autodep/pym/_emerge/BinpkgVerifier.py75
-rw-r--r--portage_with_autodep/pym/_emerge/Blocker.py15
-rw-r--r--portage_with_autodep/pym/_emerge/BlockerCache.py182
-rw-r--r--portage_with_autodep/pym/_emerge/BlockerDB.py124
-rw-r--r--portage_with_autodep/pym/_emerge/BlockerDepPriority.py13
-rw-r--r--portage_with_autodep/pym/_emerge/CompositeTask.py157
-rw-r--r--portage_with_autodep/pym/_emerge/DepPriority.py49
-rw-r--r--portage_with_autodep/pym/_emerge/DepPriorityNormalRange.py47
-rw-r--r--portage_with_autodep/pym/_emerge/DepPrioritySatisfiedRange.py85
-rw-r--r--portage_with_autodep/pym/_emerge/Dependency.py20
-rw-r--r--portage_with_autodep/pym/_emerge/DependencyArg.py33
-rw-r--r--portage_with_autodep/pym/_emerge/EbuildBinpkg.py46
-rw-r--r--portage_with_autodep/pym/_emerge/EbuildBuild.py426
-rw-r--r--portage_with_autodep/pym/_emerge/EbuildBuildDir.py109
-rw-r--r--portage_with_autodep/pym/_emerge/EbuildExecuter.py99
-rw-r--r--portage_with_autodep/pym/_emerge/EbuildFetcher.py302
-rw-r--r--portage_with_autodep/pym/_emerge/EbuildFetchonly.py32
-rw-r--r--portage_with_autodep/pym/_emerge/EbuildIpcDaemon.py108
-rw-r--r--portage_with_autodep/pym/_emerge/EbuildMerge.py56
-rw-r--r--portage_with_autodep/pym/_emerge/EbuildMetadataPhase.py133
-rw-r--r--portage_with_autodep/pym/_emerge/EbuildPhase.py350
-rw-r--r--portage_with_autodep/pym/_emerge/EbuildProcess.py21
-rw-r--r--portage_with_autodep/pym/_emerge/EbuildSpawnProcess.py16
-rw-r--r--portage_with_autodep/pym/_emerge/EventsAnalyser.py511
-rw-r--r--portage_with_autodep/pym/_emerge/EventsLogger.py180
-rw-r--r--portage_with_autodep/pym/_emerge/FakeVartree.py265
-rw-r--r--portage_with_autodep/pym/_emerge/FifoIpcDaemon.py81
-rw-r--r--portage_with_autodep/pym/_emerge/JobStatusDisplay.py292
-rw-r--r--portage_with_autodep/pym/_emerge/MergeListItem.py135
-rw-r--r--portage_with_autodep/pym/_emerge/MetadataRegen.py184
-rw-r--r--portage_with_autodep/pym/_emerge/MiscFunctionsProcess.py33
-rw-r--r--portage_with_autodep/pym/_emerge/Package.py700
-rw-r--r--portage_with_autodep/pym/_emerge/PackageArg.py19
-rw-r--r--portage_with_autodep/pym/_emerge/PackageMerge.py40
-rw-r--r--portage_with_autodep/pym/_emerge/PackageUninstall.py110
-rw-r--r--portage_with_autodep/pym/_emerge/PackageVirtualDbapi.py145
-rw-r--r--portage_with_autodep/pym/_emerge/PipeReader.py96
-rw-r--r--portage_with_autodep/pym/_emerge/PollConstants.py18
-rw-r--r--portage_with_autodep/pym/_emerge/PollScheduler.py398
-rw-r--r--portage_with_autodep/pym/_emerge/PollSelectAdapter.py73
-rw-r--r--portage_with_autodep/pym/_emerge/ProgressHandler.py22
-rw-r--r--portage_with_autodep/pym/_emerge/QueueScheduler.py116
-rw-r--r--portage_with_autodep/pym/_emerge/RootConfig.py34
-rw-r--r--portage_with_autodep/pym/_emerge/Scheduler.py1975
-rw-r--r--portage_with_autodep/pym/_emerge/SequentialTaskQueue.py89
-rw-r--r--portage_with_autodep/pym/_emerge/SetArg.py11
-rw-r--r--portage_with_autodep/pym/_emerge/SlotObject.py42
-rw-r--r--portage_with_autodep/pym/_emerge/SpawnProcess.py235
-rw-r--r--portage_with_autodep/pym/_emerge/SubProcess.py141
-rw-r--r--portage_with_autodep/pym/_emerge/Task.py42
-rw-r--r--portage_with_autodep/pym/_emerge/TaskScheduler.py25
-rw-r--r--portage_with_autodep/pym/_emerge/TaskSequence.py44
-rw-r--r--portage_with_autodep/pym/_emerge/UninstallFailure.py15
-rw-r--r--portage_with_autodep/pym/_emerge/UnmergeDepPriority.py41
-rw-r--r--portage_with_autodep/pym/_emerge/UseFlagDisplay.py122
-rw-r--r--portage_with_autodep/pym/_emerge/__init__.py2
-rw-r--r--portage_with_autodep/pym/_emerge/_find_deep_system_runtime_deps.py38
-rw-r--r--portage_with_autodep/pym/_emerge/_flush_elog_mod_echo.py15
-rw-r--r--portage_with_autodep/pym/_emerge/actions.py3123
-rw-r--r--portage_with_autodep/pym/_emerge/clear_caches.py19
-rw-r--r--portage_with_autodep/pym/_emerge/countdown.py22
-rw-r--r--portage_with_autodep/pym/_emerge/create_depgraph_params.py72
-rw-r--r--portage_with_autodep/pym/_emerge/create_world_atom.py92
-rw-r--r--portage_with_autodep/pym/_emerge/depgraph.py7029
-rw-r--r--portage_with_autodep/pym/_emerge/emergelog.py63
-rw-r--r--portage_with_autodep/pym/_emerge/getloadavg.py27
-rw-r--r--portage_with_autodep/pym/_emerge/help.py815
-rw-r--r--portage_with_autodep/pym/_emerge/is_valid_package_atom.py21
-rw-r--r--portage_with_autodep/pym/_emerge/main.py1910
-rw-r--r--portage_with_autodep/pym/_emerge/resolver/__init__.py2
-rw-r--r--portage_with_autodep/pym/_emerge/resolver/backtracking.py197
-rw-r--r--portage_with_autodep/pym/_emerge/resolver/circular_dependency.py267
-rw-r--r--portage_with_autodep/pym/_emerge/resolver/output.py888
-rw-r--r--portage_with_autodep/pym/_emerge/resolver/output_helpers.py576
-rw-r--r--portage_with_autodep/pym/_emerge/resolver/slot_collision.py978
-rw-r--r--portage_with_autodep/pym/_emerge/search.py385
-rw-r--r--portage_with_autodep/pym/_emerge/show_invalid_depstring_notice.py35
-rw-r--r--portage_with_autodep/pym/_emerge/stdout_spinner.py83
-rw-r--r--portage_with_autodep/pym/_emerge/sync/__init__.py2
-rw-r--r--portage_with_autodep/pym/_emerge/sync/getaddrinfo_validate.py29
-rw-r--r--portage_with_autodep/pym/_emerge/sync/old_tree_timestamp.py98
-rw-r--r--portage_with_autodep/pym/_emerge/unmerge.py578
-rw-r--r--portage_with_autodep/pym/_emerge/userquery.py55
-rw-r--r--portage_with_autodep/pym/portage/__init__.py610
-rw-r--r--portage_with_autodep/pym/portage/_global_updates.py250
-rw-r--r--portage_with_autodep/pym/portage/_legacy_globals.py81
-rw-r--r--portage_with_autodep/pym/portage/_selinux.py129
-rw-r--r--portage_with_autodep/pym/portage/_sets/__init__.py245
-rw-r--r--portage_with_autodep/pym/portage/_sets/base.py264
-rw-r--r--portage_with_autodep/pym/portage/_sets/dbapi.py383
-rw-r--r--portage_with_autodep/pym/portage/_sets/files.py341
-rw-r--r--portage_with_autodep/pym/portage/_sets/libs.py98
-rw-r--r--portage_with_autodep/pym/portage/_sets/profiles.py53
-rw-r--r--portage_with_autodep/pym/portage/_sets/security.py86
-rw-r--r--portage_with_autodep/pym/portage/_sets/shell.py44
-rw-r--r--portage_with_autodep/pym/portage/cache/__init__.py4
-rw-r--r--portage_with_autodep/pym/portage/cache/anydbm.py113
-rw-r--r--portage_with_autodep/pym/portage/cache/cache_errors.py62
-rw-r--r--portage_with_autodep/pym/portage/cache/ebuild_xattr.py171
-rw-r--r--portage_with_autodep/pym/portage/cache/flat_hash.py155
-rw-r--r--portage_with_autodep/pym/portage/cache/flat_list.py134
-rw-r--r--portage_with_autodep/pym/portage/cache/fs_template.py90
-rw-r--r--portage_with_autodep/pym/portage/cache/mappings.py485
-rw-r--r--portage_with_autodep/pym/portage/cache/metadata.py154
-rw-r--r--portage_with_autodep/pym/portage/cache/metadata_overlay.py105
-rw-r--r--portage_with_autodep/pym/portage/cache/sql_template.py301
-rw-r--r--portage_with_autodep/pym/portage/cache/sqlite.py245
-rw-r--r--portage_with_autodep/pym/portage/cache/template.py236
-rw-r--r--portage_with_autodep/pym/portage/cache/util.py170
-rw-r--r--portage_with_autodep/pym/portage/cache/volatile.py25
-rw-r--r--portage_with_autodep/pym/portage/checksum.py291
-rw-r--r--portage_with_autodep/pym/portage/const.py143
-rw-r--r--portage_with_autodep/pym/portage/cvstree.py293
-rw-r--r--portage_with_autodep/pym/portage/data.py122
-rw-r--r--portage_with_autodep/pym/portage/dbapi/_MergeProcess.py282
-rw-r--r--portage_with_autodep/pym/portage/dbapi/__init__.py302
-rw-r--r--portage_with_autodep/pym/portage/dbapi/_expand_new_virt.py72
-rw-r--r--portage_with_autodep/pym/portage/dbapi/bintree.py1366
-rw-r--r--portage_with_autodep/pym/portage/dbapi/cpv_expand.py106
-rw-r--r--portage_with_autodep/pym/portage/dbapi/dep_expand.py56
-rw-r--r--portage_with_autodep/pym/portage/dbapi/porttree.py1168
-rw-r--r--portage_with_autodep/pym/portage/dbapi/vartree.py4527
-rw-r--r--portage_with_autodep/pym/portage/dbapi/virtual.py131
-rw-r--r--portage_with_autodep/pym/portage/debug.py120
-rw-r--r--portage_with_autodep/pym/portage/dep/__init__.py2432
-rw-r--r--portage_with_autodep/pym/portage/dep/dep_check.py679
-rw-r--r--portage_with_autodep/pym/portage/dispatch_conf.py188
-rw-r--r--portage_with_autodep/pym/portage/eapi.py50
-rw-r--r--portage_with_autodep/pym/portage/eclass_cache.py123
-rw-r--r--portage_with_autodep/pym/portage/elog/__init__.py182
-rw-r--r--portage_with_autodep/pym/portage/elog/filtering.py15
-rw-r--r--portage_with_autodep/pym/portage/elog/messages.py172
-rw-r--r--portage_with_autodep/pym/portage/elog/mod_custom.py19
-rw-r--r--portage_with_autodep/pym/portage/elog/mod_echo.py46
-rw-r--r--portage_with_autodep/pym/portage/elog/mod_mail.py43
-rw-r--r--portage_with_autodep/pym/portage/elog/mod_mail_summary.py89
-rw-r--r--portage_with_autodep/pym/portage/elog/mod_save.py51
-rw-r--r--portage_with_autodep/pym/portage/elog/mod_save_summary.py59
-rw-r--r--portage_with_autodep/pym/portage/elog/mod_syslog.py32
-rw-r--r--portage_with_autodep/pym/portage/env/__init__.py3
-rw-r--r--portage_with_autodep/pym/portage/env/config.py105
-rw-r--r--portage_with_autodep/pym/portage/env/loaders.py319
-rw-r--r--portage_with_autodep/pym/portage/env/validators.py20
-rw-r--r--portage_with_autodep/pym/portage/exception.py186
-rw-r--r--portage_with_autodep/pym/portage/getbinpkg.py861
-rw-r--r--portage_with_autodep/pym/portage/glsa.py699
-rw-r--r--portage_with_autodep/pym/portage/localization.py20
-rw-r--r--portage_with_autodep/pym/portage/locks.py395
-rw-r--r--portage_with_autodep/pym/portage/mail.py177
-rw-r--r--portage_with_autodep/pym/portage/manifest.py538
-rw-r--r--portage_with_autodep/pym/portage/news.py351
-rw-r--r--portage_with_autodep/pym/portage/output.py794
-rw-r--r--portage_with_autodep/pym/portage/package/__init__.py2
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/__init__.py2
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_config/KeywordsManager.py284
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_config/LicenseManager.py236
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_config/LocationsManager.py182
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_config/MaskManager.py189
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_config/UseManager.py235
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_config/VirtualsManager.py233
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_config/__init__.py2
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_config/env_var_validation.py23
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_config/features_set.py128
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_config/helper.py64
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_config/special_env_vars.py185
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_ipc/ExitCommand.py27
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_ipc/IpcCommand.py9
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_ipc/QueryCommand.py98
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_ipc/__init__.py2
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/_spawn_nofetch.py82
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/config.py2224
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/deprecated_profile_check.py42
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/digestcheck.py167
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/digestgen.py202
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/doebuild.py1791
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/fetch.py1129
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/getmaskingreason.py124
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/getmaskingstatus.py174
-rw-r--r--portage_with_autodep/pym/portage/package/ebuild/prepare_build_dirs.py370
-rw-r--r--portage_with_autodep/pym/portage/process.py427
-rw-r--r--portage_with_autodep/pym/portage/proxy/__init__.py2
-rw-r--r--portage_with_autodep/pym/portage/proxy/lazyimport.py212
-rw-r--r--portage_with_autodep/pym/portage/proxy/objectproxy.py91
-rw-r--r--portage_with_autodep/pym/portage/repository/__init__.py2
-rw-r--r--portage_with_autodep/pym/portage/repository/config.py504
-rw-r--r--portage_with_autodep/pym/portage/tests/__init__.py244
-rw-r--r--portage_with_autodep/pym/portage/tests/bin/__init__.py0
-rw-r--r--portage_with_autodep/pym/portage/tests/bin/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/bin/setup_env.py85
-rw-r--r--portage_with_autodep/pym/portage/tests/bin/test_dobin.py16
-rw-r--r--portage_with_autodep/pym/portage/tests/bin/test_dodir.py16
-rw-r--r--portage_with_autodep/pym/portage/tests/dbapi/__init__.py2
-rw-r--r--portage_with_autodep/pym/portage/tests/dbapi/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/dbapi/test_fakedbapi.py58
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/__init__.py3
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/testAtom.py315
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/testCheckRequiredUse.py219
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/testExtendedAtomDict.py18
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/testExtractAffectingUSE.py75
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/testStandalone.py36
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/test_best_match_to_list.py43
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/test_dep_getcpv.py35
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/test_dep_getrepo.py29
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/test_dep_getslot.py28
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/test_dep_getusedeps.py35
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/test_get_operator.py33
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/test_get_required_use_flags.py42
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/test_isjustname.py24
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/test_isvalidatom.py146
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/test_match_from_list.py108
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/test_paren_reduce.py66
-rw-r--r--portage_with_autodep/pym/portage/tests/dep/test_use_reduce.py627
-rw-r--r--portage_with_autodep/pym/portage/tests/ebuild/__init__.py2
-rw-r--r--portage_with_autodep/pym/portage/tests/ebuild/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/ebuild/test_array_fromfile_eof.py43
-rw-r--r--portage_with_autodep/pym/portage/tests/ebuild/test_config.py198
-rw-r--r--portage_with_autodep/pym/portage/tests/ebuild/test_doebuild_spawn.py82
-rw-r--r--portage_with_autodep/pym/portage/tests/ebuild/test_ipc_daemon.py124
-rw-r--r--portage_with_autodep/pym/portage/tests/ebuild/test_pty_eof.py32
-rw-r--r--portage_with_autodep/pym/portage/tests/ebuild/test_spawn.py52
-rw-r--r--portage_with_autodep/pym/portage/tests/env/__init__.py4
-rw-r--r--portage_with_autodep/pym/portage/tests/env/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/env/config/__init__.py4
-rw-r--r--portage_with_autodep/pym/portage/tests/env/config/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/env/config/test_PackageKeywordsFile.py40
-rw-r--r--portage_with_autodep/pym/portage/tests/env/config/test_PackageMaskFile.py29
-rw-r--r--portage_with_autodep/pym/portage/tests/env/config/test_PackageUseFile.py37
-rw-r--r--portage_with_autodep/pym/portage/tests/env/config/test_PortageModulesFile.py39
-rw-r--r--portage_with_autodep/pym/portage/tests/lafilefixer/__init__.py0
-rw-r--r--portage_with_autodep/pym/portage/tests/lafilefixer/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/lafilefixer/test_lafilefixer.py145
-rw-r--r--portage_with_autodep/pym/portage/tests/lazyimport/__init__.py0
-rw-r--r--portage_with_autodep/pym/portage/tests/lazyimport/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/lazyimport/test_lazy_import_portage_baseline.py81
-rw-r--r--portage_with_autodep/pym/portage/tests/lazyimport/test_preload_portage_submodules.py16
-rw-r--r--portage_with_autodep/pym/portage/tests/lint/__init__.py0
-rw-r--r--portage_with_autodep/pym/portage/tests/lint/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/lint/test_bash_syntax.py42
-rw-r--r--portage_with_autodep/pym/portage/tests/lint/test_compile_modules.py46
-rw-r--r--portage_with_autodep/pym/portage/tests/lint/test_import_modules.py40
-rw-r--r--portage_with_autodep/pym/portage/tests/locks/__init__.py2
-rw-r--r--portage_with_autodep/pym/portage/tests/locks/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/locks/test_asynchronous_lock.py124
-rw-r--r--portage_with_autodep/pym/portage/tests/locks/test_lock_nonblock.py46
-rw-r--r--portage_with_autodep/pym/portage/tests/news/__init__.py3
-rw-r--r--portage_with_autodep/pym/portage/tests/news/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/news/test_NewsItem.py95
-rw-r--r--portage_with_autodep/pym/portage/tests/process/__init__.py2
-rw-r--r--portage_with_autodep/pym/portage/tests/process/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/process/test_poll.py39
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/ResolverPlayground.py690
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/__init__.py2
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_autounmask.py326
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_backtracking.py169
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_circular_dependencies.py84
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_depclean.py285
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_depth.py252
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_eapi.py115
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_merge_order.py453
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_missing_iuse_and_evaluated_atoms.py31
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_multirepo.py318
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_multislot.py40
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_old_dep_chain_display.py35
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_output.py88
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_rebuild.py138
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_required_use.py114
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_simple.py57
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_slot_collisions.py143
-rw-r--r--portage_with_autodep/pym/portage/tests/resolver/test_use_dep_defaults.py40
-rwxr-xr-xportage_with_autodep/pym/portage/tests/runTests46
-rw-r--r--portage_with_autodep/pym/portage/tests/sets/__init__.py0
-rw-r--r--portage_with_autodep/pym/portage/tests/sets/base/__init__.py0
-rw-r--r--portage_with_autodep/pym/portage/tests/sets/base/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/sets/base/testInternalPackageSet.py61
-rw-r--r--portage_with_autodep/pym/portage/tests/sets/files/__init__.py0
-rw-r--r--portage_with_autodep/pym/portage/tests/sets/files/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/sets/files/testConfigFileSet.py32
-rw-r--r--portage_with_autodep/pym/portage/tests/sets/files/testStaticFileSet.py27
-rw-r--r--portage_with_autodep/pym/portage/tests/sets/shell/__init__.py0
-rw-r--r--portage_with_autodep/pym/portage/tests/sets/shell/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/sets/shell/testShell.py28
-rw-r--r--portage_with_autodep/pym/portage/tests/unicode/__init__.py2
-rw-r--r--portage_with_autodep/pym/portage/tests/unicode/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/unicode/test_string_format.py108
-rw-r--r--portage_with_autodep/pym/portage/tests/util/__init__.py4
-rw-r--r--portage_with_autodep/pym/portage/tests/util/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/util/test_digraph.py201
-rw-r--r--portage_with_autodep/pym/portage/tests/util/test_getconfig.py29
-rw-r--r--portage_with_autodep/pym/portage/tests/util/test_grabdict.py11
-rw-r--r--portage_with_autodep/pym/portage/tests/util/test_normalizedPath.py14
-rw-r--r--portage_with_autodep/pym/portage/tests/util/test_stackDictList.py17
-rw-r--r--portage_with_autodep/pym/portage/tests/util/test_stackDicts.py36
-rw-r--r--portage_with_autodep/pym/portage/tests/util/test_stackLists.py19
-rw-r--r--portage_with_autodep/pym/portage/tests/util/test_uniqueArray.py24
-rw-r--r--portage_with_autodep/pym/portage/tests/util/test_varExpand.py92
-rw-r--r--portage_with_autodep/pym/portage/tests/versions/__init__.py3
-rw-r--r--portage_with_autodep/pym/portage/tests/versions/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/versions/test_cpv_sort_key.py16
-rw-r--r--portage_with_autodep/pym/portage/tests/versions/test_vercmp.py80
-rw-r--r--portage_with_autodep/pym/portage/tests/xpak/__init__.py3
-rw-r--r--portage_with_autodep/pym/portage/tests/xpak/__test__0
-rw-r--r--portage_with_autodep/pym/portage/tests/xpak/test_decodeint.py16
-rw-r--r--portage_with_autodep/pym/portage/update.py320
-rw-r--r--portage_with_autodep/pym/portage/util/ExtractKernelVersion.py76
-rw-r--r--portage_with_autodep/pym/portage/util/__init__.py1602
-rw-r--r--portage_with_autodep/pym/portage/util/_dyn_libs/LinkageMapELF.py805
-rw-r--r--portage_with_autodep/pym/portage/util/_dyn_libs/PreservedLibsRegistry.py172
-rw-r--r--portage_with_autodep/pym/portage/util/_dyn_libs/__init__.py2
-rw-r--r--portage_with_autodep/pym/portage/util/_pty.py212
-rw-r--r--portage_with_autodep/pym/portage/util/digraph.py342
-rw-r--r--portage_with_autodep/pym/portage/util/env_update.py293
-rw-r--r--portage_with_autodep/pym/portage/util/lafilefixer.py185
-rw-r--r--portage_with_autodep/pym/portage/util/listdir.py151
-rw-r--r--portage_with_autodep/pym/portage/util/movefile.py242
-rw-r--r--portage_with_autodep/pym/portage/util/mtimedb.py81
-rw-r--r--portage_with_autodep/pym/portage/versions.py403
-rw-r--r--portage_with_autodep/pym/portage/xml/__init__.py2
-rw-r--r--portage_with_autodep/pym/portage/xml/metadata.py376
-rw-r--r--portage_with_autodep/pym/portage/xpak.py497
-rw-r--r--portage_with_autodep/pym/repoman/__init__.py0
-rw-r--r--portage_with_autodep/pym/repoman/checks.py707
-rw-r--r--portage_with_autodep/pym/repoman/errors.py26
-rw-r--r--portage_with_autodep/pym/repoman/herdbase.py110
-rw-r--r--portage_with_autodep/pym/repoman/utilities.py511
421 files changed, 89247 insertions, 0 deletions
diff --git a/portage_with_autodep/bin/archive-conf b/portage_with_autodep/bin/archive-conf
new file mode 100755
index 0000000..5a03b85
--- /dev/null
+++ b/portage_with_autodep/bin/archive-conf
@@ -0,0 +1,111 @@
+#!/usr/bin/python
+# Copyright 1999-2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+#
+# archive-conf -- save off a config file in the dispatch-conf archive dir
+#
+# Written by Wayne Davison <gentoo@blorf.net> with code snagged from
+# Jeremy Wohl's dispatch-conf script and the portage chkcontents script.
+#
+
+from __future__ import print_function
+
+import sys
+try:
+ import portage
+except ImportError:
+ from os import path as osp
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
+ import portage
+
+from portage import os
+import dispatch_conf
+
+FIND_EXTANT_CONTENTS = "find %s -name CONTENTS"
+
+MANDATORY_OPTS = [ 'archive-dir' ]
+
+try:
+ import fchksum
+ def perform_checksum(filename): return fchksum.fmd5t(filename)
+except ImportError:
+ import md5
+ def md5_to_hex(md5sum):
+ hexform = ""
+ for ix in range(len(md5sum)):
+ hexform = hexform + "%02x" % ord(md5sum[ix])
+ return hexform.lower()
+
+ def perform_checksum(filename):
+ f = open(filename, 'rb')
+ blocksize=32768
+ data = f.read(blocksize)
+ size = 0
+ sum = md5.new()
+ while data:
+ sum.update(data)
+ size = size + len(data)
+ data = f.read(blocksize)
+ return (md5_to_hex(sum.digest()),size)
+
+def archive_conf():
+ args = []
+ content_files = []
+ md5_match_hash = {}
+
+ options = portage.dispatch_conf.read_config(MANDATORY_OPTS)
+
+ for conf in sys.argv[1:]:
+ if not os.path.isabs(conf):
+ conf = os.path.abspath(conf)
+ args += [ conf ]
+ md5_match_hash[conf] = ''
+
+ # Find all the CONTENT files in VDB_PATH.
+ content_files += os.popen(FIND_EXTANT_CONTENTS %
+ (os.path.join(portage.settings['EROOT'], portage.VDB_PATH))).readlines()
+
+ # Search for the saved md5 checksum of all the specified config files
+ # and see if the current file is unmodified or not.
+ try:
+ todo_cnt = len(args)
+ for file in content_files:
+ file = file.rstrip()
+ try:
+ contents = open(file, "r")
+ except IOError as e:
+ print('archive-conf: Unable to open %s: %s' % (file, e), file=sys.stderr)
+ sys.exit(1)
+ lines = contents.readlines()
+ for line in lines:
+ items = line.split()
+ if items[0] == 'obj':
+ for conf in args:
+ if items[1] == conf:
+ stored = items[2].lower()
+ real = perform_checksum(conf)[0].lower()
+ if stored == real:
+ md5_match_hash[conf] = conf
+ todo_cnt -= 1
+ if todo_cnt == 0:
+ raise StopIteration()
+ except StopIteration:
+ pass
+
+ for conf in args:
+ archive = os.path.join(options['archive-dir'], conf.lstrip('/'))
+ if options['use-rcs'] == 'yes':
+ portage.dispatch_conf.rcs_archive(archive, conf, md5_match_hash[conf], '')
+ if md5_match_hash[conf]:
+ portage.dispatch_conf.rcs_archive_post_process(archive)
+ else:
+ portage.dispatch_conf.file_archive(archive, conf, md5_match_hash[conf], '')
+ if md5_match_hash[conf]:
+ portage.dispatch_conf.file_archive_post_process(archive)
+
+# run
+if len(sys.argv) > 1:
+ archive_conf()
+else:
+ print('Usage: archive-conf /CONFIG/FILE [/CONFIG/FILE...]', file=sys.stderr)
diff --git a/portage_with_autodep/bin/banned-helper b/portage_with_autodep/bin/banned-helper
new file mode 100755
index 0000000..17ea991
--- /dev/null
+++ b/portage_with_autodep/bin/banned-helper
@@ -0,0 +1,6 @@
+#!/bin/bash
+# Copyright 2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+die "'${0##*/}' has been banned for EAPI '$EAPI'"
+exit 1
diff --git a/portage_with_autodep/bin/binhost-snapshot b/portage_with_autodep/bin/binhost-snapshot
new file mode 100755
index 0000000..9d2697d
--- /dev/null
+++ b/portage_with_autodep/bin/binhost-snapshot
@@ -0,0 +1,142 @@
+#!/usr/bin/python
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import io
+import optparse
+import os
+import sys
+import textwrap
+
+try:
+ from urllib.parse import urlparse
+except ImportError:
+ from urlparse import urlparse
+
+try:
+ import portage
+except ImportError:
+ from os import path as osp
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(
+ osp.realpath(__file__))), "pym"))
+ import portage
+
+def parse_args(argv):
+ prog_name = os.path.basename(argv[0])
+ usage = prog_name + ' [options] ' + \
+ '<src_pkg_dir> <snapshot_dir> <snapshot_uri> <binhost_dir>'
+
+ prog_desc = "This program will copy src_pkg_dir to snapshot_dir " + \
+ "and inside binhost_dir it will create a Packages index file " + \
+ "which refers to snapshot_uri. This is intended to solve race " + \
+ "conditions on binhosts as described at http://crosbug.com/3225."
+
+ usage += "\n\n"
+ for line in textwrap.wrap(prog_desc, 70):
+ usage += line + "\n"
+
+ usage += "\n"
+ usage += "Required Arguments:\n\n"
+ usage += " src_pkg_dir - the source $PKGDIR\n"
+ usage += " snapshot_dir - destination snapshot " + \
+ "directory (must not exist)\n"
+ usage += " snapshot_uri - URI which refers to " + \
+ "snapshot_dir from the\n" + \
+ " client side\n"
+ usage += " binhost_dir - directory in which to " + \
+ "write Packages index with\n" + \
+ " snapshot_uri"
+
+ parser = optparse.OptionParser(usage=usage)
+ parser.add_option('--hardlinks', help='create hardlinks (y or n, default is y)',
+ choices=('y', 'n'))
+ parser.set_defaults(hardlinks='y')
+ options, args = parser.parse_args(argv[1:])
+
+ if len(args) != 4:
+ parser.error("Required 4 arguments, got %d" % (len(args),))
+
+ return parser, options, args
+
+def main(argv):
+ parser, options, args = parse_args(argv)
+
+ src_pkg_dir, snapshot_dir, snapshot_uri, binhost_dir = args
+ src_pkgs_index = os.path.join(src_pkg_dir, 'Packages')
+
+ if not os.path.isdir(src_pkg_dir):
+ parser.error("src_pkg_dir is not a directory: '%s'" % (src_pkg_dir,))
+
+ if not os.path.isfile(src_pkgs_index):
+ parser.error("src_pkg_dir does not contain a " + \
+ "'Packages' index: '%s'" % (src_pkg_dir,))
+
+ parse_result = urlparse(snapshot_uri)
+ if not (parse_result.scheme and parse_result.netloc and parse_result.path):
+ parser.error("snapshot_uri is not a valid URI: '%s'" % (snapshot_uri,))
+
+ if os.path.isdir(snapshot_dir):
+ parser.error("snapshot_dir already exists: '%s'" % snapshot_dir)
+
+ try:
+ os.makedirs(os.path.dirname(snapshot_dir))
+ except OSError:
+ pass
+ if not os.path.isdir(os.path.dirname(snapshot_dir)):
+ parser.error("snapshot_dir parent could not be created: '%s'" % \
+ os.path.dirname(snapshot_dir))
+
+ try:
+ os.makedirs(binhost_dir)
+ except OSError:
+ pass
+ if not os.path.isdir(binhost_dir):
+ parser.error("binhost_dir could not be created: '%s'" % binhost_dir)
+
+ cp_opts = 'RP'
+ if options.hardlinks == 'n':
+ cp_opts += 'p'
+ else:
+ cp_opts += 'l'
+
+ cp_cmd = 'cp -%s %s %s' % (
+ cp_opts,
+ portage._shell_quote(src_pkg_dir),
+ portage._shell_quote(snapshot_dir)
+ )
+
+ ret = os.system(cp_cmd)
+ if not (os.WIFEXITED(ret) and os.WEXITSTATUS(ret) == os.EX_OK):
+ return 1
+
+ infile = io.open(portage._unicode_encode(src_pkgs_index,
+ encoding=portage._encodings['fs'], errors='strict'),
+ mode='r', encoding=portage._encodings['repo.content'],
+ errors='strict')
+
+ outfile = portage.util.atomic_ofstream(
+ os.path.join(binhost_dir, "Packages"),
+ encoding=portage._encodings['repo.content'],
+ errors='strict')
+
+ for line in infile:
+ if line[:4] == 'URI:':
+ # skip existing URI line
+ pass
+ else:
+ if not line.strip():
+ # end of header
+ outfile.write("URI: %s\n\n" % snapshot_uri)
+ break
+ outfile.write(line)
+
+ for line in infile:
+ outfile.write(line)
+
+ infile.close()
+ outfile.close()
+
+ return os.EX_OK
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv))
diff --git a/portage_with_autodep/bin/check-implicit-pointer-usage.py b/portage_with_autodep/bin/check-implicit-pointer-usage.py
new file mode 100755
index 0000000..8822c45
--- /dev/null
+++ b/portage_with_autodep/bin/check-implicit-pointer-usage.py
@@ -0,0 +1,84 @@
+#!/usr/bin/python
+
+# Ripped from HP and updated from Debian
+# Update by Gentoo to support unicode output
+
+#
+# Copyright (c) 2004 Hewlett-Packard Development Company, L.P.
+# David Mosberger <davidm@hpl.hp.com>
+#
+# Scan standard input for GCC warning messages that are likely to
+# source of real 64-bit problems. In particular, see whether there
+# are any implicitly declared functions whose return values are later
+# interpreted as pointers. Those are almost guaranteed to cause
+# crashes.
+#
+
+from __future__ import print_function
+
+import re
+import sys
+
+implicit_pattern = re.compile("([^:]*):(\d+): warning: implicit declaration "
+ + "of function [`']([^']*)'")
+pointer_pattern = (
+ "([^:]*):(\d+): warning: "
+ + "("
+ + "(assignment"
+ + "|initialization"
+ + "|return"
+ + "|passing arg \d+ of `[^']*'"
+ + "|passing arg \d+ of pointer to function"
+ + ") makes pointer from integer without a cast"
+ + "|"
+ + "cast to pointer from integer of different size)")
+
+if sys.hexversion < 0x3000000:
+ # Use encoded byte strings in python-2.x, since the python ebuilds are
+ # known to remove the encodings module when USE=build is enabled (thus
+ # disabling unicode decoding/encoding). The portage module has a
+ # workaround for this, but currently we don't import that here since we
+ # don't want to trigger potential sandbox violations due to stale pyc
+ # files for the portage module.
+ unicode_quote_open = '\xE2\x80\x98'
+ unicode_quote_close = '\xE2\x80\x99'
+ def write(msg):
+ sys.stdout.write(msg)
+else:
+ unicode_quote_open = '\u2018'
+ unicode_quote_close = '\u2019'
+ def write(msg):
+ sys.stdout.buffer.write(msg.encode('utf_8', 'backslashreplace'))
+
+pointer_pattern = re.compile(pointer_pattern)
+
+last_implicit_filename = ""
+last_implicit_linenum = -1
+last_implicit_func = ""
+
+while True:
+ if sys.hexversion >= 0x3000000:
+ line = sys.stdin.buffer.readline().decode('utf_8', 'replace')
+ else:
+ line = sys.stdin.readline()
+ if not line:
+ break
+ # translate unicode open/close quotes to ascii ones
+ line = line.replace(unicode_quote_open, "`")
+ line = line.replace(unicode_quote_close, "'")
+ m = implicit_pattern.match(line)
+ if m:
+ last_implicit_filename = m.group(1)
+ last_implicit_linenum = int(m.group(2))
+ last_implicit_func = m.group(3)
+ else:
+ m = pointer_pattern.match(line)
+ if m:
+ pointer_filename = m.group(1)
+ pointer_linenum = int(m.group(2))
+ if (last_implicit_filename == pointer_filename
+ and last_implicit_linenum == pointer_linenum):
+ write("Function `%s' implicitly converted to pointer at " \
+ "%s:%d\n" % (last_implicit_func,
+ last_implicit_filename,
+ last_implicit_linenum))
diff --git a/portage_with_autodep/bin/clean_locks b/portage_with_autodep/bin/clean_locks
new file mode 100755
index 0000000..8c4299c
--- /dev/null
+++ b/portage_with_autodep/bin/clean_locks
@@ -0,0 +1,47 @@
+#!/usr/bin/python -O
+# Copyright 1999-2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import sys, errno
+try:
+ import portage
+except ImportError:
+ from os import path as osp
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
+ import portage
+
+from portage import os
+
+if not sys.argv[1:] or "--help" in sys.argv or "-h" in sys.argv:
+ import portage
+ print()
+ print("You must specify directories with hardlink-locks to clean.")
+ print("You may optionally specify --force, which will remove all")
+ print("of the locks, even if we can't establish if they are in use.")
+ print("Please attempt cleaning without force first.")
+ print()
+ print("%s %s/.locks" % (sys.argv[0], portage.settings["DISTDIR"]))
+ print("%s --force %s/.locks" % (sys.argv[0], portage.settings["DISTDIR"]))
+ print()
+ sys.exit(1)
+
+force = False
+if "--force" in sys.argv[1:]:
+ force=True
+
+for x in sys.argv[1:]:
+ if x == "--force":
+ continue
+ try:
+ for y in portage.locks.hardlock_cleanup(x, remove_all_locks=force):
+ print(y)
+ print()
+
+ except OSError as e:
+ if e.errno in (errno.ENOENT, errno.ENOTDIR):
+ print("!!! %s is not a directory or does not exist" % x)
+ else:
+ raise
+ sys.exit(e.errno)
diff --git a/portage_with_autodep/bin/dispatch-conf b/portage_with_autodep/bin/dispatch-conf
new file mode 100755
index 0000000..1e21a52
--- /dev/null
+++ b/portage_with_autodep/bin/dispatch-conf
@@ -0,0 +1,434 @@
+#!/usr/bin/python -O
+# Copyright 1999-2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+#
+# dispatch-conf -- Integrate modified configs, post-emerge
+#
+# Jeremy Wohl (http://igmus.org)
+#
+# TODO
+# dialog menus
+#
+
+from __future__ import print_function
+
+from stat import ST_GID, ST_MODE, ST_UID
+from random import random
+import atexit, re, shutil, stat, sys
+
+try:
+ import portage
+except ImportError:
+ from os import path as osp
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
+ import portage
+
+from portage import os
+from portage import dispatch_conf
+from portage import _unicode_decode
+from portage.dispatch_conf import diffstatusoutput_len
+from portage.process import find_binary
+
+FIND_EXTANT_CONFIGS = "find '%s' %s -name '._cfg????_%s' ! -name '.*~' ! -iname '.*.bak' -print"
+DIFF_CONTENTS = "diff -Nu '%s' '%s'"
+DIFF_CVS_INTERP = "diff -Nu '%s' '%s' | grep '^[+-][^+-]' | grep -v '# .Header:.*'"
+DIFF_WSCOMMENTS = "diff -Nu '%s' '%s' | grep '^[+-][^+-]' | grep -v '^[-+]#' | grep -v '^[-+][:space:]*$'"
+
+# We need a secure scratch dir and python does silly verbose errors on the use of tempnam
+oldmask = os.umask(0o077)
+SCRATCH_DIR = None
+while SCRATCH_DIR is None:
+ try:
+ mydir = "/tmp/dispatch-conf."
+ for x in range(0,8):
+ if int(random() * 3) == 0:
+ mydir += chr(int(65+random()*26.0))
+ elif int(random() * 2) == 0:
+ mydir += chr(int(97+random()*26.0))
+ else:
+ mydir += chr(int(48+random()*10.0))
+ if os.path.exists(mydir):
+ continue
+ os.mkdir(mydir)
+ SCRATCH_DIR = mydir
+ except OSError as e:
+ if e.errno != 17:
+ raise
+os.umask(oldmask)
+
+# Ensure the scratch dir is deleted
+def cleanup(mydir=SCRATCH_DIR):
+ shutil.rmtree(mydir)
+atexit.register(cleanup)
+
+MANDATORY_OPTS = [ 'archive-dir', 'diff', 'replace-cvs', 'replace-wscomments', 'merge' ]
+
+class dispatch:
+ options = {}
+
+ def grind (self, config_paths):
+ confs = []
+ count = 0
+
+ config_root = '/'
+ self.options = portage.dispatch_conf.read_config(MANDATORY_OPTS)
+
+ if "log-file" in self.options:
+ if os.path.isfile(self.options["log-file"]):
+ shutil.copy(self.options["log-file"], self.options["log-file"] + '.old')
+ if os.path.isfile(self.options["log-file"]) \
+ or not os.path.exists(self.options["log-file"]):
+ open(self.options["log-file"], 'w').close() # Truncate it
+ os.chmod(self.options["log-file"], 0o600)
+ else:
+ self.options["log-file"] = "/dev/null"
+
+ #
+ # Build list of extant configs
+ #
+
+ for path in config_paths:
+ path = portage.normalize_path(path)
+ try:
+ mymode = os.stat(path).st_mode
+ except OSError:
+ continue
+ basename = "*"
+ find_opts = "-name '.*' -type d -prune -o"
+ if not stat.S_ISDIR(mymode):
+ path, basename = os.path.split(path)
+ find_opts = "-maxdepth 1"
+
+ confs += self.massage(os.popen(FIND_EXTANT_CONFIGS % (path, find_opts, basename)).readlines())
+
+ if self.options['use-rcs'] == 'yes':
+ for rcs_util in ("rcs", "ci", "co", "rcsmerge"):
+ if not find_binary(rcs_util):
+ print('dispatch-conf: Error finding all RCS utils and " + \
+ "use-rcs=yes in config; fatal', file=sys.stderr)
+ return False
+
+
+ # config file freezing support
+ frozen_files = set(self.options.get("frozen-files", "").split())
+ auto_zapped = []
+ protect_obj = portage.util.ConfigProtect(
+ config_root, config_paths,
+ portage.util.shlex_split(
+ portage.settings.get('CONFIG_PROTECT_MASK', '')))
+
+ #
+ # Remove new configs identical to current
+ # and
+ # Auto-replace configs a) whose differences are simply CVS interpolations,
+ # or b) whose differences are simply ws or comments,
+ # or c) in paths now unprotected by CONFIG_PROTECT_MASK,
+ #
+
+ def f (conf):
+ mrgconf = re.sub(r'\._cfg', '._mrg', conf['new'])
+ archive = os.path.join(self.options['archive-dir'], conf['current'].lstrip('/'))
+ if self.options['use-rcs'] == 'yes':
+ mrgfail = portage.dispatch_conf.rcs_archive(archive, conf['current'], conf['new'], mrgconf)
+ else:
+ mrgfail = portage.dispatch_conf.file_archive(archive, conf['current'], conf['new'], mrgconf)
+ if os.path.exists(archive + '.dist'):
+ unmodified = diffstatusoutput_len(DIFF_CONTENTS % (conf['current'], archive + '.dist'))[1] == 0
+ else:
+ unmodified = 0
+ if os.path.exists(mrgconf):
+ if mrgfail or diffstatusoutput_len(DIFF_CONTENTS % (conf['new'], mrgconf))[1] == 0:
+ os.unlink(mrgconf)
+ newconf = conf['new']
+ else:
+ newconf = mrgconf
+ else:
+ newconf = conf['new']
+
+ if newconf == mrgconf and \
+ self.options.get('ignore-previously-merged') != 'yes' and \
+ os.path.exists(archive+'.dist') and \
+ diffstatusoutput_len(DIFF_CONTENTS % (archive+'.dist', conf['new']))[1] == 0:
+ # The current update is identical to the archived .dist
+ # version that has previously been merged.
+ os.unlink(mrgconf)
+ newconf = conf['new']
+
+ mystatus, myoutput_len = diffstatusoutput_len(
+ DIFF_CONTENTS % (conf ['current'], newconf))
+ same_file = 0 == myoutput_len
+ if mystatus >> 8 == 2:
+ # Binary files differ
+ same_cvs = False
+ same_wsc = False
+ else:
+ same_cvs = 0 == diffstatusoutput_len(
+ DIFF_CVS_INTERP % (conf ['current'], newconf))[1]
+ same_wsc = 0 == diffstatusoutput_len(
+ DIFF_WSCOMMENTS % (conf ['current'], newconf))[1]
+
+ # Do options permit?
+ same_cvs = same_cvs and self.options['replace-cvs'] == 'yes'
+ same_wsc = same_wsc and self.options['replace-wscomments'] == 'yes'
+ unmodified = unmodified and self.options['replace-unmodified'] == 'yes'
+
+ if same_file:
+ os.unlink (conf ['new'])
+ self.post_process(conf['current'])
+ if os.path.exists(mrgconf):
+ os.unlink(mrgconf)
+ return False
+ elif conf['current'] in frozen_files:
+ """Frozen files are automatically zapped. The new config has
+ already been archived with a .new suffix. When zapped, it is
+ left with the .new suffix (post_process is skipped), since it
+ hasn't been merged into the current config."""
+ auto_zapped.append(conf['current'])
+ os.unlink(conf['new'])
+ try:
+ os.unlink(mrgconf)
+ except OSError:
+ pass
+ return False
+ elif unmodified or same_cvs or same_wsc or \
+ not protect_obj.isprotected(conf['current']):
+ self.replace(newconf, conf['current'])
+ self.post_process(conf['current'])
+ if newconf == mrgconf:
+ os.unlink(conf['new'])
+ elif os.path.exists(mrgconf):
+ os.unlink(mrgconf)
+ return False
+ else:
+ return True
+
+ confs = [x for x in confs if f(x)]
+
+ #
+ # Interactively process remaining
+ #
+
+ valid_input = "qhtnmlezu"
+
+ for conf in confs:
+ count = count + 1
+
+ newconf = conf['new']
+ mrgconf = re.sub(r'\._cfg', '._mrg', newconf)
+ if os.path.exists(mrgconf):
+ newconf = mrgconf
+ show_new_diff = 0
+
+ while 1:
+ clear_screen()
+ if show_new_diff:
+ cmd = self.options['diff'] % (conf['new'], mrgconf)
+ spawn_shell(cmd)
+ show_new_diff = 0
+ else:
+ cmd = self.options['diff'] % (conf['current'], newconf)
+ spawn_shell(cmd)
+
+ print()
+ print('>> (%i of %i) -- %s' % (count, len(confs), conf ['current']))
+ print('>> q quit, h help, n next, e edit-new, z zap-new, u use-new\n m merge, t toggle-merge, l look-merge: ', end=' ')
+
+ # In some cases getch() will return some spurious characters
+ # that do not represent valid input. If we don't validate the
+ # input then the spurious characters can cause us to jump
+ # back into the above "diff" command immediatly after the user
+ # has exited it (which can be quite confusing and gives an
+ # "out of control" feeling).
+ while True:
+ c = getch()
+ if c in valid_input:
+ sys.stdout.write('\n')
+ sys.stdout.flush()
+ break
+
+ if c == 'q':
+ sys.exit (0)
+ if c == 'h':
+ self.do_help ()
+ continue
+ elif c == 't':
+ if newconf == mrgconf:
+ newconf = conf['new']
+ elif os.path.exists(mrgconf):
+ newconf = mrgconf
+ continue
+ elif c == 'n':
+ break
+ elif c == 'm':
+ merged = SCRATCH_DIR+"/"+os.path.basename(conf['current'])
+ print()
+ ret = os.system (self.options['merge'] % (merged, conf ['current'], newconf))
+ ret = os.WEXITSTATUS(ret)
+ if ret < 2:
+ ret = 0
+ if ret:
+ print("Failure running 'merge' command")
+ continue
+ shutil.copyfile(merged, mrgconf)
+ os.remove(merged)
+ mystat = os.lstat(conf['new'])
+ os.chmod(mrgconf, mystat[ST_MODE])
+ os.chown(mrgconf, mystat[ST_UID], mystat[ST_GID])
+ newconf = mrgconf
+ continue
+ elif c == 'l':
+ show_new_diff = 1
+ continue
+ elif c == 'e':
+ if 'EDITOR' not in os.environ:
+ os.environ['EDITOR']='nano'
+ os.system(os.environ['EDITOR'] + ' ' + newconf)
+ continue
+ elif c == 'z':
+ os.unlink(conf['new'])
+ if os.path.exists(mrgconf):
+ os.unlink(mrgconf)
+ break
+ elif c == 'u':
+ self.replace(newconf, conf ['current'])
+ self.post_process(conf['current'])
+ if newconf == mrgconf:
+ os.unlink(conf['new'])
+ elif os.path.exists(mrgconf):
+ os.unlink(mrgconf)
+ break
+ else:
+ raise AssertionError("Invalid Input: %s" % c)
+
+ if auto_zapped:
+ print()
+ print(" One or more updates are frozen and have been automatically zapped:")
+ print()
+ for frozen in auto_zapped:
+ print(" * '%s'" % frozen)
+ print()
+
+ def replace (self, newconf, curconf):
+ """Replace current config with the new/merged version. Also logs
+ the diff of what changed into the configured log file."""
+ os.system((DIFF_CONTENTS % (curconf, newconf)) + '>>' + self.options["log-file"])
+ try:
+ os.rename(newconf, curconf)
+ except (IOError, os.error) as why:
+ print('dispatch-conf: Error renaming %s to %s: %s; fatal' % \
+ (newconf, curconf, str(why)), file=sys.stderr)
+
+
+ def post_process(self, curconf):
+ archive = os.path.join(self.options['archive-dir'], curconf.lstrip('/'))
+ if self.options['use-rcs'] == 'yes':
+ portage.dispatch_conf.rcs_archive_post_process(archive)
+ else:
+ portage.dispatch_conf.file_archive_post_process(archive)
+
+
+ def massage (self, newconfigs):
+ """Sort, rstrip, remove old versions, break into triad hash.
+
+ Triad is dictionary of current (/etc/make.conf), new (/etc/._cfg0003_make.conf)
+ and dir (/etc).
+
+ We keep ._cfg0002_conf over ._cfg0001_conf and ._cfg0000_conf.
+ """
+ h = {}
+ configs = []
+ newconfigs.sort ()
+
+ for nconf in newconfigs:
+ nconf = nconf.rstrip ()
+ conf = re.sub (r'\._cfg\d+_', '', nconf)
+ dirname = os.path.dirname(nconf)
+ conf_map = {
+ 'current' : conf,
+ 'dir' : dirname,
+ 'new' : nconf,
+ }
+
+ if conf in h:
+ mrgconf = re.sub(r'\._cfg', '._mrg', h[conf]['new'])
+ if os.path.exists(mrgconf):
+ os.unlink(mrgconf)
+ os.unlink(h[conf]['new'])
+ h[conf].update(conf_map)
+ else:
+ h[conf] = conf_map
+ configs.append(conf_map)
+
+ return configs
+
+
+ def do_help (self):
+ print(); print
+
+ print(' u -- update current config with new config and continue')
+ print(' z -- zap (delete) new config and continue')
+ print(' n -- skip to next config, leave all intact')
+ print(' e -- edit new config')
+ print(' m -- interactively merge current and new configs')
+ print(' l -- look at diff between pre-merged and merged configs')
+ print(' t -- toggle new config between merged and pre-merged state')
+ print(' h -- this screen')
+ print(' q -- quit')
+
+ print(); print('press any key to return to diff...', end=' ')
+
+ getch ()
+
+
+def getch ():
+ # from ASPN - Danny Yoo
+ #
+ import sys, tty, termios
+
+ fd = sys.stdin.fileno()
+ old_settings = termios.tcgetattr(fd)
+ try:
+ tty.setraw(sys.stdin.fileno())
+ ch = sys.stdin.read(1)
+ finally:
+ termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
+ return ch
+
+def clear_screen():
+ try:
+ import curses
+ try:
+ curses.setupterm()
+ sys.stdout.write(_unicode_decode(curses.tigetstr("clear")))
+ sys.stdout.flush()
+ return
+ except curses.error:
+ pass
+ except ImportError:
+ pass
+ os.system("clear 2>/dev/null")
+
+from portage.process import find_binary, spawn
+shell = os.environ.get("SHELL")
+if not shell or not os.access(shell, os.EX_OK):
+ shell = find_binary("sh")
+
+def spawn_shell(cmd):
+ if shell:
+ spawn([shell, "-c", cmd], env=os.environ,
+ fd_pipes = { 0 : sys.stdin.fileno(),
+ 1 : sys.stdout.fileno(),
+ 2 : sys.stderr.fileno()})
+ else:
+ os.system(cmd)
+
+# run
+d = dispatch ()
+
+if len(sys.argv) > 1:
+ # for testing
+ d.grind(sys.argv[1:])
+else:
+ d.grind(portage.util.shlex_split(
+ portage.settings.get('CONFIG_PROTECT', '')))
diff --git a/portage_with_autodep/bin/dohtml.py b/portage_with_autodep/bin/dohtml.py
new file mode 100755
index 0000000..00258ec
--- /dev/null
+++ b/portage_with_autodep/bin/dohtml.py
@@ -0,0 +1,191 @@
+#!/usr/bin/python
+# Copyright 1999-2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+#
+# Typical usage:
+# dohtml -r docs/*
+# - put all files and directories in docs into /usr/share/doc/${PF}/html
+# dohtml foo.html
+# - put foo.html into /usr/share/doc/${PF}/html
+#
+#
+# Detailed usage:
+# dohtml <list-of-files>
+# - will install the files in the list of files (space-separated list) into
+# /usr/share/doc/${PF}/html, provided the file ends in .htm, .html, .css,
+# .js, ,gif, .jpeg, .jpg, or .png.
+# dohtml -r <list-of-files-and-directories>
+# - will do as 'dohtml', but recurse into all directories, as long as the
+# directory name is not CVS
+# dohtml -A jpe,java [-r] <list-of-files[-and-directories]>
+# - will do as 'dohtml' but add .jpe,.java (default filter list is
+# added to your list)
+# dohtml -a png,gif,html,htm [-r] <list-of-files[-and-directories]>
+# - will do as 'dohtml' but filter on .png,.gif,.html,.htm (default filter
+# list is ignored)
+# dohtml -x CVS,SCCS,RCS -r <list-of-files-and-directories>
+# - will do as 'dohtml -r', but ignore directories named CVS, SCCS, RCS
+#
+
+from __future__ import print_function
+
+import os
+import sys
+
+def dodir(path):
+ os.spawnlp(os.P_WAIT, "install", "install", "-d", path)
+
+def dofile(src,dst):
+ os.spawnlp(os.P_WAIT, "install", "install", "-m0644", src, dst)
+
+def eqawarn(lines):
+ cmd = "source '%s/isolated-functions.sh' ; " % \
+ os.environ["PORTAGE_BIN_PATH"]
+ for line in lines:
+ cmd += "eqawarn \"%s\" ; " % line
+ os.spawnlp(os.P_WAIT, "bash", "bash", "-c", cmd)
+
+skipped_directories = []
+
+def install(basename, dirname, options, prefix=""):
+ fullpath = basename
+ if prefix:
+ fullpath = prefix + "/" + fullpath
+ if dirname:
+ fullpath = dirname + "/" + fullpath
+
+ if options.DOCDESTTREE:
+ destdir = options.D + "usr/share/doc/" + options.PF + "/" + options.DOCDESTTREE + "/" + options.doc_prefix + "/" + prefix
+ else:
+ destdir = options.D + "usr/share/doc/" + options.PF + "/html/" + options.doc_prefix + "/" + prefix
+
+ if not os.path.exists(fullpath):
+ sys.stderr.write("!!! dohtml: %s does not exist\n" % fullpath)
+ return False
+ elif os.path.isfile(fullpath):
+ ext = os.path.splitext(basename)[1]
+ if (len(ext) and ext[1:] in options.allowed_exts) or basename in options.allowed_files:
+ dodir(destdir)
+ dofile(fullpath, destdir + "/" + basename)
+ elif options.recurse and os.path.isdir(fullpath) and \
+ basename not in options.disallowed_dirs:
+ for i in os.listdir(fullpath):
+ pfx = basename
+ if prefix: pfx = prefix + "/" + pfx
+ install(i, dirname, options, pfx)
+ elif not options.recurse and os.path.isdir(fullpath):
+ global skipped_directories
+ skipped_directories.append(fullpath)
+ return False
+ else:
+ return False
+ return True
+
+
+class OptionsClass:
+ def __init__(self):
+ self.PF = ""
+ self.D = ""
+ self.DOCDESTTREE = ""
+
+ if "PF" in os.environ:
+ self.PF = os.environ["PF"]
+ if "D" in os.environ:
+ self.D = os.environ["D"]
+ if "_E_DOCDESTTREE_" in os.environ:
+ self.DOCDESTTREE = os.environ["_E_DOCDESTTREE_"]
+
+ self.allowed_exts = [ 'htm', 'html', 'css', 'js',
+ 'gif', 'jpeg', 'jpg', 'png' ]
+ self.allowed_files = []
+ self.disallowed_dirs = [ 'CVS' ]
+ self.recurse = False
+ self.verbose = False
+ self.doc_prefix = ""
+
+def print_help():
+ opts = OptionsClass()
+
+ print("dohtml [-a .foo,.bar] [-A .foo,.bar] [-f foo,bar] [-x foo,bar]")
+ print(" [-r] [-V] <file> [file ...]")
+ print()
+ print(" -a Set the list of allowed to those that are specified.")
+ print(" Default:", ",".join(opts.allowed_exts))
+ print(" -A Extend the list of allowed file types.")
+ print(" -f Set list of allowed extensionless file names.")
+ print(" -x Set directories to be excluded from recursion.")
+ print(" Default:", ",".join(opts.disallowed_dirs))
+ print(" -p Set a document prefix for installed files (empty by default).")
+ print(" -r Install files and directories recursively.")
+ print(" -V Be verbose.")
+ print()
+
+def parse_args():
+ options = OptionsClass()
+ args = []
+
+ x = 1
+ while x < len(sys.argv):
+ arg = sys.argv[x]
+ if arg in ["-h","-r","-V"]:
+ if arg == "-h":
+ print_help()
+ sys.exit(0)
+ elif arg == "-r":
+ options.recurse = True
+ elif arg == "-V":
+ options.verbose = True
+ elif sys.argv[x] in ["-A","-a","-f","-x","-p"]:
+ x += 1
+ if x == len(sys.argv):
+ print_help()
+ sys.exit(0)
+ elif arg == "-p":
+ options.doc_prefix = sys.argv[x]
+ else:
+ values = sys.argv[x].split(",")
+ if arg == "-A":
+ options.allowed_exts.extend(values)
+ elif arg == "-a":
+ options.allowed_exts = values
+ elif arg == "-f":
+ options.allowed_files = values
+ elif arg == "-x":
+ options.disallowed_dirs = values
+ else:
+ args.append(sys.argv[x])
+ x += 1
+
+ return (options, args)
+
+def main():
+
+ (options, args) = parse_args()
+
+ if options.verbose:
+ print("Allowed extensions:", options.allowed_exts)
+ print("Document prefix : '" + options.doc_prefix + "'")
+ print("Allowed files :", options.allowed_files)
+
+ success = False
+
+ for x in args:
+ basename = os.path.basename(x)
+ dirname = os.path.dirname(x)
+ success |= install(basename, dirname, options)
+
+ global skipped_directories
+ for x in skipped_directories:
+ eqawarn(["QA Notice: dohtml on directory " + \
+ "'%s' without recursion option" % x])
+
+ if success:
+ retcode = 0
+ else:
+ retcode = 1
+
+ sys.exit(retcode)
+
+if __name__ == "__main__":
+ main()
diff --git a/portage_with_autodep/bin/ebuild b/portage_with_autodep/bin/ebuild
new file mode 100755
index 0000000..f8b6d79
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild
@@ -0,0 +1,346 @@
+#!/usr/bin/python -O
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import signal
+import sys
+# This block ensures that ^C interrupts are handled quietly.
+try:
+
+ def exithandler(signum,frame):
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
+ sys.exit(128 + signum)
+
+ signal.signal(signal.SIGINT, exithandler)
+ signal.signal(signal.SIGTERM, exithandler)
+ # Prevent "[Errno 32] Broken pipe" exceptions when
+ # writing to a pipe.
+ signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+
+except KeyboardInterrupt:
+ sys.exit(128 + signal.SIGINT)
+
+def debug_signal(signum, frame):
+ import pdb
+ pdb.set_trace()
+signal.signal(signal.SIGUSR1, debug_signal)
+
+import imp
+import optparse
+import os
+
+description = "See the ebuild(1) man page for more info"
+usage = "Usage: ebuild <ebuild file> <command> [command] ..."
+parser = optparse.OptionParser(description=description, usage=usage)
+
+force_help = "When used together with the digest or manifest " + \
+ "command, this option forces regeneration of digests for all " + \
+ "distfiles associated with the current ebuild. Any distfiles " + \
+ "that do not already exist in ${DISTDIR} will be automatically fetched."
+
+parser.add_option("--force", help=force_help, action="store_true", dest="force")
+parser.add_option("--color", help="enable or disable color output",
+ type="choice", choices=("y", "n"))
+parser.add_option("--debug", help="show debug output",
+ action="store_true", dest="debug")
+parser.add_option("--ignore-default-opts",
+ action="store_true",
+ help="do not use the EBUILD_DEFAULT_OPTS environment variable")
+parser.add_option("--skip-manifest", help="skip all manifest checks",
+ action="store_true", dest="skip_manifest")
+
+opts, pargs = parser.parse_args(args=sys.argv[1:])
+
+if len(pargs) < 2:
+ parser.error("missing required args")
+
+if "merge" in pargs:
+ print("Disabling noauto in features... merge disables it. (qmerge doesn't)")
+ os.environ["FEATURES"] = os.environ.get("FEATURES", "") + " -noauto"
+
+os.environ["PORTAGE_CALLER"]="ebuild"
+try:
+ import portage
+except ImportError:
+ from os import path as osp
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
+ import portage
+
+portage.dep._internal_warnings = True
+from portage import os
+from portage import _encodings
+from portage import _shell_quote
+from portage import _unicode_decode
+from portage import _unicode_encode
+from portage.const import VDB_PATH
+from _emerge.Package import Package
+from _emerge.RootConfig import RootConfig
+
+if not opts.ignore_default_opts:
+ default_opts = portage.settings.get("EBUILD_DEFAULT_OPTS", "").split()
+ opts, pargs = parser.parse_args(default_opts + sys.argv[1:])
+
+debug = opts.debug
+force = opts.force
+
+import portage.util, portage.const
+
+# do this _after_ 'import portage' to prevent unnecessary tracing
+if debug and "python-trace" in portage.features:
+ import portage.debug
+ portage.debug.set_trace(True)
+
+if not opts.color == 'y' and \
+ (opts.color == 'n' or \
+ portage.settings.get('NOCOLOR') in ('yes', 'true') or \
+ portage.settings.get('TERM') == 'dumb' or \
+ not sys.stdout.isatty()):
+ portage.output.nocolor()
+ portage.settings.unlock()
+ portage.settings['NOCOLOR'] = 'true'
+ portage.settings.lock()
+
+ebuild = pargs.pop(0)
+
+pf = None
+if ebuild.endswith(".ebuild"):
+ pf = os.path.basename(ebuild)[:-7]
+
+if pf is None:
+ portage.writemsg("'%s' does not end with '.ebuild'.\n" % \
+ (ebuild,), noiselevel=-1)
+ sys.exit(1)
+
+if not os.path.isabs(ebuild):
+ mycwd = os.getcwd()
+ # Try to get the non-canonical path from the PWD evironment variable, since
+ # the canonical path returned from os.getcwd() may may be unusable in
+ # cases where the directory stucture is built from symlinks.
+ pwd = os.environ.get('PWD', '')
+ if sys.hexversion < 0x3000000:
+ pwd = _unicode_decode(pwd, encoding=_encodings['content'],
+ errors='strict')
+ if pwd and pwd != mycwd and \
+ os.path.realpath(pwd) == mycwd:
+ mycwd = portage.normalize_path(pwd)
+ ebuild = os.path.join(mycwd, ebuild)
+ebuild = portage.normalize_path(ebuild)
+# portdbapi uses the canonical path for the base of the portage tree, but
+# subdirectories of the base can be built from symlinks (like crossdev does).
+ebuild_portdir = os.path.realpath(
+ os.path.dirname(os.path.dirname(os.path.dirname(ebuild))))
+ebuild = os.path.join(ebuild_portdir, *ebuild.split(os.path.sep)[-3:])
+vdb_path = os.path.realpath(os.path.join(portage.settings['EROOT'], VDB_PATH))
+
+# Make sure that portdb.findname() returns the correct ebuild.
+if ebuild_portdir != vdb_path and \
+ ebuild_portdir not in portage.portdb.porttrees:
+ if sys.hexversion >= 0x3000000:
+ os.environ["PORTDIR_OVERLAY"] = \
+ os.environ.get("PORTDIR_OVERLAY","") + \
+ " " + _shell_quote(ebuild_portdir)
+ else:
+ os.environ["PORTDIR_OVERLAY"] = \
+ os.environ.get("PORTDIR_OVERLAY","") + \
+ " " + _unicode_encode(_shell_quote(ebuild_portdir),
+ encoding=_encodings['content'], errors='strict')
+
+ print("Appending %s to PORTDIR_OVERLAY..." % ebuild_portdir)
+ imp.reload(portage)
+
+# Constrain eclass resolution to the master(s)
+# that are specified in layout.conf (using an
+# approach similar to repoman's).
+myrepo = None
+if ebuild_portdir != vdb_path:
+ myrepo = portage.portdb.getRepositoryName(ebuild_portdir)
+ repo_info = portage.portdb._repo_info[ebuild_portdir]
+ portage.portdb.porttrees = list(repo_info.eclass_db.porttrees)
+
+if not os.path.exists(ebuild):
+ print("'%s' does not exist." % ebuild)
+ sys.exit(1)
+
+ebuild_split = ebuild.split("/")
+cpv = "%s/%s" % (ebuild_split[-3], pf)
+
+if not portage.catpkgsplit(cpv):
+ print("!!! %s does not follow correct package syntax." % (cpv))
+ sys.exit(1)
+
+if ebuild.startswith(vdb_path):
+ mytree = "vartree"
+ pkg_type = "installed"
+
+ portage_ebuild = portage.db[portage.root][mytree].dbapi.findname(cpv, myrepo=myrepo)
+
+ if os.path.realpath(portage_ebuild) != ebuild:
+ print("!!! Portage seems to think that %s is at %s" % (cpv, portage_ebuild))
+ sys.exit(1)
+
+else:
+ mytree = "porttree"
+ pkg_type = "ebuild"
+
+ portage_ebuild = portage.portdb.findname(cpv, myrepo=myrepo)
+
+ if not portage_ebuild or portage_ebuild != ebuild:
+ print("!!! %s does not seem to have a valid PORTDIR structure." % ebuild)
+ sys.exit(1)
+
+if len(pargs) > 1 and "config" in pargs:
+ print("config must be called on it's own, not combined with any other phase")
+ sys.exit(1)
+
+def discard_digests(myebuild, mysettings, mydbapi):
+ """Discard all distfiles digests for the given ebuild. This is useful when
+ upstream has changed the identity of the distfiles and the user would
+ otherwise have to manually remove the Manifest and files/digest-* files in
+ order to ensure correct results."""
+ try:
+ portage._doebuild_manifest_exempt_depend += 1
+ pkgdir = os.path.dirname(myebuild)
+ fetchlist_dict = portage.FetchlistDict(pkgdir, mysettings, mydbapi)
+ from portage.manifest import Manifest
+ mf = Manifest(pkgdir, mysettings["DISTDIR"],
+ fetchlist_dict=fetchlist_dict, manifest1_compat=False)
+ mf.create(requiredDistfiles=None,
+ assumeDistHashesSometimes=True, assumeDistHashesAlways=True)
+ distfiles = fetchlist_dict[cpv]
+ for myfile in distfiles:
+ try:
+ del mf.fhashdict["DIST"][myfile]
+ except KeyError:
+ pass
+ mf.write()
+ finally:
+ portage._doebuild_manifest_exempt_depend -= 1
+
+portage.settings.validate() # generate warning messages if necessary
+
+build_dir_phases = set(["setup", "unpack", "prepare", "configure", "compile",
+ "test", "install", "package", "rpm", "merge", "qmerge"])
+
+# If the current metadata is invalid then force the ebuild to be
+# sourced again even if $T/environment already exists.
+ebuild_changed = False
+if mytree == "porttree" and build_dir_phases.intersection(pargs):
+ metadata, st, emtime = \
+ portage.portdb._pull_valid_cache(cpv, ebuild, ebuild_portdir)
+ if metadata is None:
+ ebuild_changed = True
+
+tmpsettings = portage.config(clone=portage.settings)
+tmpsettings["PORTAGE_VERBOSE"] = "1"
+tmpsettings.backup_changes("PORTAGE_VERBOSE")
+
+if opts.skip_manifest:
+ tmpsettings["EBUILD_SKIP_MANIFEST"] = "1"
+ tmpsettings.backup_changes("EBUILD_SKIP_MANIFEST")
+
+if opts.skip_manifest or \
+ "digest" in tmpsettings.features or \
+ "digest" in pargs or \
+ "manifest" in pargs:
+ portage._doebuild_manifest_exempt_depend += 1
+
+if "test" in pargs:
+ # This variable is a signal to config.regenerate() to
+ # indicate that the test phase should be enabled regardless
+ # of problems such as masked "test" USE flag.
+ tmpsettings["EBUILD_FORCE_TEST"] = "1"
+ tmpsettings.backup_changes("EBUILD_FORCE_TEST")
+ tmpsettings.features.add("test")
+
+tmpsettings.features.discard("fail-clean")
+
+try:
+ metadata = dict(zip(Package.metadata_keys,
+ portage.db[portage.settings["ROOT"]][mytree].dbapi.aux_get(
+ cpv, Package.metadata_keys, myrepo=myrepo)))
+except KeyError:
+ # aux_get failure, message should have been shown on stderr.
+ sys.exit(1)
+
+root_config = RootConfig(portage.settings,
+ portage.db[portage.settings["ROOT"]], None)
+
+pkg = Package(built=(pkg_type != "ebuild"), cpv=cpv,
+ installed=(pkg_type=="installed"),
+ metadata=metadata, root_config=root_config,
+ type_name=pkg_type)
+
+# Apply package.env and repo-level settings. This allows per-package
+# FEATURES and other variables (possibly PORTAGE_TMPDIR) to be
+# available as soon as possible.
+tmpsettings.setcpv(pkg)
+
+def stale_env_warning():
+ if "clean" not in pargs and \
+ "noauto" not in tmpsettings.features and \
+ build_dir_phases.intersection(pargs):
+ portage.doebuild_environment(ebuild, "setup", portage.root,
+ tmpsettings, debug, 1, portage.portdb)
+ env_filename = os.path.join(tmpsettings["T"], "environment")
+ if os.path.exists(env_filename):
+ msg = ("Existing ${T}/environment for '%s' will be sourced. " + \
+ "Run 'clean' to start with a fresh environment.") % \
+ (tmpsettings["PF"], )
+ from textwrap import wrap
+ msg = wrap(msg, 70)
+ for x in msg:
+ portage.writemsg(">>> %s\n" % x)
+
+ if ebuild_changed:
+ open(os.path.join(tmpsettings['PORTAGE_BUILDDIR'],
+ '.ebuild_changed'), 'w')
+
+from portage.exception import PermissionDenied, \
+ PortagePackageException, UnsupportedAPIException
+
+if 'digest' in tmpsettings.features and \
+ not set(["digest", "manifest"]).intersection(pargs):
+ pargs = ['digest'] + pargs
+
+checked_for_stale_env = False
+
+for arg in pargs:
+ try:
+ if not checked_for_stale_env and arg not in ("digest","manifest"):
+ # This has to go after manifest generation since otherwise
+ # aux_get() might fail due to invalid ebuild digests.
+ stale_env_warning()
+ checked_for_stale_env = True
+
+ if arg in ("digest", "manifest") and force:
+ discard_digests(ebuild, tmpsettings, portage.portdb)
+ a = portage.doebuild(ebuild, arg, portage.root, tmpsettings,
+ debug=debug, tree=mytree,
+ vartree=portage.db[portage.root]['vartree'])
+ except KeyboardInterrupt:
+ print("Interrupted.")
+ a = 1
+ except KeyError:
+ # aux_get error
+ a = 1
+ except UnsupportedAPIException as e:
+ from textwrap import wrap
+ msg = wrap(str(e), 70)
+ del e
+ for x in msg:
+ portage.writemsg("!!! %s\n" % x, noiselevel=-1)
+ a = 1
+ except PortagePackageException as e:
+ portage.writemsg("!!! %s\n" % (e,), noiselevel=-1)
+ a = 1
+ except PermissionDenied as e:
+ portage.writemsg("!!! Permission Denied: %s\n" % (e,), noiselevel=-1)
+ a = 1
+ if a == None:
+ print("Could not run the required binary?")
+ a = 127
+ if a:
+ sys.exit(a)
diff --git a/portage_with_autodep/bin/ebuild-helpers/4/dodoc b/portage_with_autodep/bin/ebuild-helpers/4/dodoc
new file mode 120000
index 0000000..35080ad
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/4/dodoc
@@ -0,0 +1 @@
+../doins \ No newline at end of file
diff --git a/portage_with_autodep/bin/ebuild-helpers/4/dohard b/portage_with_autodep/bin/ebuild-helpers/4/dohard
new file mode 120000
index 0000000..1a6b57a
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/4/dohard
@@ -0,0 +1 @@
+../../banned-helper \ No newline at end of file
diff --git a/portage_with_autodep/bin/ebuild-helpers/4/dosed b/portage_with_autodep/bin/ebuild-helpers/4/dosed
new file mode 120000
index 0000000..1a6b57a
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/4/dosed
@@ -0,0 +1 @@
+../../banned-helper \ No newline at end of file
diff --git a/portage_with_autodep/bin/ebuild-helpers/4/prepalldocs b/portage_with_autodep/bin/ebuild-helpers/4/prepalldocs
new file mode 120000
index 0000000..1a6b57a
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/4/prepalldocs
@@ -0,0 +1 @@
+../../banned-helper \ No newline at end of file
diff --git a/portage_with_autodep/bin/ebuild-helpers/die b/portage_with_autodep/bin/ebuild-helpers/die
new file mode 100755
index 0000000..9869141
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/die
@@ -0,0 +1,7 @@
+#!/bin/bash
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+die "$@"
+exit 1
diff --git a/portage_with_autodep/bin/ebuild-helpers/dobin b/portage_with_autodep/bin/ebuild-helpers/dobin
new file mode 100755
index 0000000..e385455
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/dobin
@@ -0,0 +1,29 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ $# -lt 1 ]] ; then
+ helpers_die "${0##*/}: at least one argument needed"
+ exit 1
+fi
+
+if [[ ! -d ${D}${DESTTREE}/bin ]] ; then
+ install -d "${D}${DESTTREE}/bin" || { helpers_die "${0##*/}: failed to install ${D}${DESTTREE}/bin"; exit 2; }
+fi
+
+ret=0
+
+for x in "$@" ; do
+ if [[ -e ${x} ]] ; then
+ install -m0755 -o ${PORTAGE_INST_UID:-0} -g ${PORTAGE_INST_GID:-0} "${x}" "${D}${DESTTREE}/bin"
+ else
+ echo "!!! ${0##*/}: $x does not exist" 1>&2
+ false
+ fi
+ ((ret|=$?))
+done
+
+[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+exit ${ret}
diff --git a/portage_with_autodep/bin/ebuild-helpers/doconfd b/portage_with_autodep/bin/ebuild-helpers/doconfd
new file mode 100755
index 0000000..e146000
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/doconfd
@@ -0,0 +1,14 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+if [[ $# -lt 1 ]] ; then
+ source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+ helpers_die "${0##*/}: at least one argument needed"
+ exit 1
+fi
+
+exec \
+env \
+INSDESTTREE="/etc/conf.d/" \
+doins "$@"
diff --git a/portage_with_autodep/bin/ebuild-helpers/dodir b/portage_with_autodep/bin/ebuild-helpers/dodir
new file mode 100755
index 0000000..f40bee7
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/dodir
@@ -0,0 +1,10 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+install -d ${DIROPTIONS} "${@/#/${D}/}"
+ret=$?
+[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+exit $ret
diff --git a/portage_with_autodep/bin/ebuild-helpers/dodoc b/portage_with_autodep/bin/ebuild-helpers/dodoc
new file mode 100755
index 0000000..65713db
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/dodoc
@@ -0,0 +1,31 @@
+#!/bin/bash
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [ $# -lt 1 ] ; then
+ helpers_die "${0##*/}: at least one argument needed"
+ exit 1
+fi
+
+dir="${D}usr/share/doc/${PF}/${_E_DOCDESTTREE_}"
+if [ ! -d "${dir}" ] ; then
+ install -d "${dir}"
+fi
+
+ret=0
+for x in "$@" ; do
+ if [ -d "${x}" ] ; then
+ eqawarn "QA Notice: dodoc argument '${x}' is a directory"
+ elif [ -s "${x}" ] ; then
+ install -m0644 "${x}" "${dir}" || { ((ret|=1)); continue; }
+ ecompress --queue "${dir}/${x##*/}"
+ elif [ ! -e "${x}" ] ; then
+ echo "!!! ${0##*/}: $x does not exist" 1>&2
+ ((ret|=1))
+ fi
+done
+
+[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+exit ${ret}
diff --git a/portage_with_autodep/bin/ebuild-helpers/doenvd b/portage_with_autodep/bin/ebuild-helpers/doenvd
new file mode 100755
index 0000000..28ab5d2
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/doenvd
@@ -0,0 +1,14 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+if [[ $# -lt 1 ]] ; then
+ source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+ helpers_die "${0##*/}: at least one argument needed"
+ exit 1
+fi
+
+exec \
+env \
+INSDESTTREE="/etc/env.d/" \
+doins "$@"
diff --git a/portage_with_autodep/bin/ebuild-helpers/doexe b/portage_with_autodep/bin/ebuild-helpers/doexe
new file mode 100755
index 0000000..360800e
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/doexe
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ $# -lt 1 ]] ; then
+ helpers_die "${0##*/}: at least one argument needed"
+ exit 1
+fi
+
+if [[ ! -d ${D}${_E_EXEDESTTREE_} ]] ; then
+ install -d "${D}${_E_EXEDESTTREE_}"
+fi
+
+TMP=$T/.doexe_tmp
+mkdir "$TMP"
+
+ret=0
+
+for x in "$@" ; do
+ if [ -L "${x}" ] ; then
+ cp "$x" "$TMP"
+ mysrc=$TMP/${x##*/}
+ elif [ -d "${x}" ] ; then
+ vecho "doexe: warning, skipping directory ${x}"
+ continue
+ else
+ mysrc="${x}"
+ fi
+ if [ -e "$mysrc" ] ; then
+ install $EXEOPTIONS "$mysrc" "$D$_E_EXEDESTTREE_"
+ else
+ echo "!!! ${0##*/}: $mysrc does not exist" 1>&2
+ false
+ fi
+ ((ret|=$?))
+done
+
+rm -rf "$TMP"
+
+[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+exit $ret
diff --git a/portage_with_autodep/bin/ebuild-helpers/dohard b/portage_with_autodep/bin/ebuild-helpers/dohard
new file mode 100755
index 0000000..2270487
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/dohard
@@ -0,0 +1,13 @@
+#!/bin/bash
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+if [[ $# -ne 2 ]] ; then
+ echo "$0: two arguments needed" 1>&2
+ exit 1
+fi
+
+destdir=${2%/*}
+[[ ! -d ${D}${destdir} ]] && dodir "${destdir}"
+
+exec ln -f "${D}$1" "${D}$2"
diff --git a/portage_with_autodep/bin/ebuild-helpers/dohtml b/portage_with_autodep/bin/ebuild-helpers/dohtml
new file mode 100755
index 0000000..630629a
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/dohtml
@@ -0,0 +1,14 @@
+#!/bin/bash
+# Copyright 2009-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+PORTAGE_BIN_PATH=${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}
+PORTAGE_PYM_PATH=${PORTAGE_PYM_PATH:-/usr/lib/portage/pym}
+PYTHONPATH=$PORTAGE_PYM_PATH${PYTHONPATH:+:}$PYTHONPATH \
+ "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH/dohtml.py" "$@"
+
+ret=$?
+[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+exit $ret
diff --git a/portage_with_autodep/bin/ebuild-helpers/doinfo b/portage_with_autodep/bin/ebuild-helpers/doinfo
new file mode 100755
index 0000000..54fb8da
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/doinfo
@@ -0,0 +1,24 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z $1 ]] ; then
+ helpers_die "${0##*/}: at least one argument needed"
+ exit 1
+fi
+
+if [[ ! -d ${D}usr/share/info ]] ; then
+ install -d "${D}usr/share/info" || { helpers_die "${0##*/}: failed to install ${D}usr/share/info"; exit 1; }
+fi
+
+install -m0644 "$@" "${D}usr/share/info"
+rval=$?
+if [ $rval -ne 0 ] ; then
+ for x in "$@" ; do
+ [ -e "$x" ] || echo "!!! ${0##*/}: $x does not exist" 1>&2
+ done
+ helpers_die "${0##*/} failed"
+fi
+exit $rval
diff --git a/portage_with_autodep/bin/ebuild-helpers/doinitd b/portage_with_autodep/bin/ebuild-helpers/doinitd
new file mode 100755
index 0000000..b711e19
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/doinitd
@@ -0,0 +1,14 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+if [[ $# -lt 1 ]] ; then
+ source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+ helpers_die "${0##*/}: at least one argument needed"
+ exit 1
+fi
+
+exec \
+env \
+_E_EXEDESTTREE_="/etc/init.d/" \
+doexe "$@"
diff --git a/portage_with_autodep/bin/ebuild-helpers/doins b/portage_with_autodep/bin/ebuild-helpers/doins
new file mode 100755
index 0000000..7dec146
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/doins
@@ -0,0 +1,155 @@
+#!/bin/bash
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ ${0##*/} == dodoc ]] ; then
+ if [ $# -eq 0 ] ; then
+ # default_src_install may call dodoc with no arguments
+ # when DOC is defined but empty, so simply return
+ # sucessfully in this case.
+ exit 0
+ fi
+ export INSOPTIONS=-m0644
+ export INSDESTTREE=usr/share/doc/${PF}/${_E_DOCDESTTREE_}
+fi
+
+if [ $# -lt 1 ] ; then
+ helpers_die "${0##*/}: at least one argument needed"
+ exit 1
+fi
+
+if [[ "$1" == "-r" ]] ; then
+ DOINSRECUR=y
+ shift
+else
+ DOINSRECUR=n
+fi
+
+if [[ ${INSDESTTREE#${D}} != "${INSDESTTREE}" ]]; then
+ vecho "-------------------------------------------------------" 1>&2
+ vecho "You should not use \${D} with helpers." 1>&2
+ vecho " --> ${INSDESTTREE}" 1>&2
+ vecho "-------------------------------------------------------" 1>&2
+ helpers_die "${0##*/} used with \${D}"
+ exit 1
+fi
+
+case "$EAPI" in
+ 0|1|2|3|3_pre2)
+ PRESERVE_SYMLINKS=n
+ ;;
+ *)
+ PRESERVE_SYMLINKS=y
+ ;;
+esac
+
+export TMP=$T/.doins_tmp
+# Use separate directories to avoid potential name collisions.
+mkdir -p "$TMP"/{1,2}
+
+[[ ! -d ${D}${INSDESTTREE} ]] && dodir "${INSDESTTREE}"
+
+_doins() {
+ local mysrc="$1" mydir="$2" cleanup="" rval
+
+ if [ -L "$mysrc" ] ; then
+ # Our fake $DISTDIR contains symlinks that should
+ # not be reproduced inside $D. In order to ensure
+ # that things like dodoc "$DISTDIR"/foo.pdf work
+ # as expected, we dereference symlinked files that
+ # refer to absolute paths inside
+ # $PORTAGE_ACTUAL_DISTDIR/.
+ if [ $PRESERVE_SYMLINKS = y ] && \
+ ! [[ $(readlink "$mysrc") == "$PORTAGE_ACTUAL_DISTDIR"/* ]] ; then
+ rm -rf "$D$INSDESTTREE/$mydir/${mysrc##*/}" || return $?
+ cp -P "$mysrc" "$D$INSDESTTREE/$mydir/${mysrc##*/}"
+ return $?
+ else
+ cp "$mysrc" "$TMP/2/${mysrc##*/}" || return $?
+ mysrc="$TMP/2/${mysrc##*/}"
+ cleanup=$mysrc
+ fi
+ fi
+
+ install ${INSOPTIONS} "${mysrc}" "${D}${INSDESTTREE}/${mydir}"
+ rval=$?
+ [[ -n ${cleanup} ]] && rm -f "${cleanup}"
+ [ $rval -ne 0 ] && echo "!!! ${0##*/}: $mysrc does not exist" 1>&2
+ return $rval
+}
+
+_xdoins() {
+ local -i failed=0
+ while read -r -d $'\0' x ; do
+ _doins "$x" "${x%/*}"
+ ((failed|=$?))
+ done
+ return $failed
+}
+
+success=0
+failed=0
+
+for x in "$@" ; do
+ if [[ $PRESERVE_SYMLINKS = n && -d $x ]] || \
+ [[ $PRESERVE_SYMLINKS = y && -d $x && ! -L $x ]] ; then
+ if [ "${DOINSRECUR}" == "n" ] ; then
+ if [[ ${0##*/} == dodoc ]] ; then
+ echo "!!! ${0##*/}: $x is a directory" 1>&2
+ ((failed|=1))
+ fi
+ continue
+ fi
+
+ while [ "$x" != "${x%/}" ] ; do
+ x=${x%/}
+ done
+ if [ "$x" = "${x%/*}" ] ; then
+ pushd "$PWD" >/dev/null
+ else
+ pushd "${x%/*}" >/dev/null
+ fi
+ x=${x##*/}
+ x_orig=$x
+ # Follow any symlinks recursively until we've got
+ # a normal directory for 'find' to traverse. The
+ # name of the symlink will be used for the name
+ # of the installed directory, as discussed in
+ # bug #239529.
+ while [ -L "$x" ] ; do
+ pushd "$(readlink "$x")" >/dev/null
+ x=${PWD##*/}
+ pushd "${PWD%/*}" >/dev/null
+ done
+ if [[ $x != $x_orig ]] ; then
+ mv "$x" "$TMP/1/$x_orig"
+ pushd "$TMP/1" >/dev/null
+ fi
+ find "$x_orig" -type d -exec dodir "${INSDESTTREE}/{}" \;
+ find "$x_orig" \( -type f -or -type l \) -print0 | _xdoins
+ if [[ ${PIPESTATUS[1]} -eq 0 ]] ; then
+ # NOTE: Even if only an empty directory is installed here, it
+ # still counts as success, since an empty directory given as
+ # an argument to doins -r should not trigger failure.
+ ((success|=1))
+ else
+ ((failed|=1))
+ fi
+ if [[ $x != $x_orig ]] ; then
+ popd >/dev/null
+ mv "$TMP/1/$x_orig" "$x"
+ fi
+ while popd >/dev/null 2>&1 ; do true ; done
+ else
+ _doins "${x}"
+ if [[ $? -eq 0 ]] ; then
+ ((success|=1))
+ else
+ ((failed|=1))
+ fi
+ fi
+done
+rm -rf "$TMP"
+[[ $failed -ne 0 || $success -eq 0 ]] && { helpers_die "${0##*/} failed"; exit 1; } || exit 0
diff --git a/portage_with_autodep/bin/ebuild-helpers/dolib b/portage_with_autodep/bin/ebuild-helpers/dolib
new file mode 100755
index 0000000..87ade42
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/dolib
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+# Setup ABI cruft
+LIBDIR_VAR="LIBDIR_${ABI}"
+if [[ -n ${ABI} && -n ${!LIBDIR_VAR} ]] ; then
+ CONF_LIBDIR=${!LIBDIR_VAR}
+fi
+unset LIBDIR_VAR
+# we need this to default to lib so that things dont break
+CONF_LIBDIR=${CONF_LIBDIR:-lib}
+libdir="${D}${DESTTREE}/${CONF_LIBDIR}"
+
+
+if [[ $# -lt 1 ]] ; then
+ helpers_die "${0##*/}: at least one argument needed"
+ exit 1
+fi
+if [[ ! -d ${libdir} ]] ; then
+ install -d "${libdir}" || { helpers_die "${0##*/}: failed to install ${libdir}"; exit 1; }
+fi
+
+ret=0
+
+for x in "$@" ; do
+ if [[ -e ${x} ]] ; then
+ if [[ ! -L ${x} ]] ; then
+ install ${LIBOPTIONS} "${x}" "${libdir}"
+ else
+ ln -s "$(readlink "${x}")" "${libdir}/${x##*/}"
+ fi
+ else
+ echo "!!! ${0##*/}: ${x} does not exist" 1>&2
+ false
+ fi
+ ((ret|=$?))
+done
+
+[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+exit ${ret}
diff --git a/portage_with_autodep/bin/ebuild-helpers/dolib.a b/portage_with_autodep/bin/ebuild-helpers/dolib.a
new file mode 100755
index 0000000..d2279dc
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/dolib.a
@@ -0,0 +1,6 @@
+#!/bin/bash
+# Copyright 1999-2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+exec env LIBOPTIONS="-m0644" \
+ dolib "$@"
diff --git a/portage_with_autodep/bin/ebuild-helpers/dolib.so b/portage_with_autodep/bin/ebuild-helpers/dolib.so
new file mode 100755
index 0000000..4bdbfab
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/dolib.so
@@ -0,0 +1,6 @@
+#!/bin/bash
+# Copyright 1999-2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+exec env LIBOPTIONS="-m0755" \
+ dolib "$@"
diff --git a/portage_with_autodep/bin/ebuild-helpers/doman b/portage_with_autodep/bin/ebuild-helpers/doman
new file mode 100755
index 0000000..4561bef
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/doman
@@ -0,0 +1,64 @@
+#!/bin/bash
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ $# -lt 1 ]] ; then
+ helpers_die "${0##*/}: at least one argument needed"
+ exit 1
+fi
+
+i18n=""
+
+ret=0
+
+for x in "$@" ; do
+ if [[ ${x:0:6} == "-i18n=" ]] ; then
+ i18n=${x:6}/
+ continue
+ fi
+ if [[ ${x:0:6} == ".keep_" ]] ; then
+ continue
+ fi
+
+ suffix=${x##*.}
+
+ # These will be automatically decompressed by ecompressdir.
+ if has ${suffix} Z gz bz2 ; then
+ realname=${x%.*}
+ suffix=${realname##*.}
+ fi
+
+ if has "${EAPI:-0}" 2 3 || [[ -z ${i18n} ]] \
+ && ! has "${EAPI:-0}" 0 1 \
+ && [[ $x =~ (.*)\.([a-z][a-z](_[A-Z][A-Z])?)\.(.*) ]]
+ then
+ name=${BASH_REMATCH[1]##*/}.${BASH_REMATCH[4]}
+ mandir=${BASH_REMATCH[2]}/man${suffix:0:1}
+ else
+ name=${x##*/}
+ mandir=${i18n#/}man${suffix:0:1}
+ fi
+
+
+ if [[ ${mandir} == *man[0-9n] ]] ; then
+ if [[ -s ${x} ]] ; then
+ if [[ ! -d ${D}/usr/share/man/${mandir} ]] ; then
+ install -d "${D}/usr/share/man/${mandir}"
+ fi
+
+ install -m0644 "${x}" "${D}/usr/share/man/${mandir}/${name}"
+ ((ret|=$?))
+ elif [[ ! -e ${x} ]] ; then
+ echo "!!! ${0##*/}: $x does not exist" 1>&2
+ ((ret|=1))
+ fi
+ else
+ vecho "doman: '${x}' is probably not a man page; skipping" 1>&2
+ ((ret|=1))
+ fi
+done
+
+[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+exit ${ret}
diff --git a/portage_with_autodep/bin/ebuild-helpers/domo b/portage_with_autodep/bin/ebuild-helpers/domo
new file mode 100755
index 0000000..4737f44
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/domo
@@ -0,0 +1,34 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+mynum=${#}
+if [ ${mynum} -lt 1 ] ; then
+ helpers_die "${0}: at least one argument needed"
+ exit 1
+fi
+if [ ! -d "${D}${DESTTREE}/share/locale" ] ; then
+ install -d "${D}${DESTTREE}/share/locale/"
+fi
+
+ret=0
+
+for x in "$@" ; do
+ if [ -e "${x}" ] ; then
+ mytiny="${x##*/}"
+ mydir="${D}${DESTTREE}/share/locale/${mytiny%.*}/LC_MESSAGES"
+ if [ ! -d "${mydir}" ] ; then
+ install -d "${mydir}"
+ fi
+ install -m0644 "${x}" "${mydir}/${MOPREFIX}.mo"
+ else
+ echo "!!! ${0##*/}: $x does not exist" 1>&2
+ false
+ fi
+ ((ret|=$?))
+done
+
+[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+exit $ret
diff --git a/portage_with_autodep/bin/ebuild-helpers/dosbin b/portage_with_autodep/bin/ebuild-helpers/dosbin
new file mode 100755
index 0000000..87a3091
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/dosbin
@@ -0,0 +1,29 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ $# -lt 1 ]] ; then
+ helpers_die "${0##*/}: at least one argument needed"
+ exit 1
+fi
+
+if [[ ! -d ${D}${DESTTREE}/sbin ]] ; then
+ install -d "${D}${DESTTREE}/sbin" || { helpers_die "${0##*/}: failed to install ${D}${DESTTREE}/sbin"; exit 2; }
+fi
+
+ret=0
+
+for x in "$@" ; do
+ if [[ -e ${x} ]] ; then
+ install -m0755 -o ${PORTAGE_INST_UID:-0} -g ${PORTAGE_INST_GID:-0} "${x}" "${D}${DESTTREE}/sbin"
+ else
+ echo "!!! ${0##*/}: ${x} does not exist" 1>&2
+ false
+ fi
+ ((ret|=$?))
+done
+
+[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+exit ${ret}
diff --git a/portage_with_autodep/bin/ebuild-helpers/dosed b/portage_with_autodep/bin/ebuild-helpers/dosed
new file mode 100755
index 0000000..afc949b
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/dosed
@@ -0,0 +1,35 @@
+#!/bin/bash
+# Copyright 1999-2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+if [[ $# -lt 1 ]] ; then
+ echo "!!! ${0##*/}: at least one argument needed" >&2
+ exit 1
+fi
+
+ret=0
+file_found=0
+mysed="s:${D}::g"
+
+for x in "$@" ; do
+ y=$D${x#/}
+ if [ -e "${y}" ] ; then
+ if [ -f "${y}" ] ; then
+ file_found=1
+ sed -i -e "${mysed}" "${y}"
+ else
+ echo "${y} is not a regular file!" >&2
+ false
+ fi
+ ((ret|=$?))
+ else
+ mysed="${x}"
+ fi
+done
+
+if [ $file_found = 0 ] ; then
+ echo "!!! ${0##*/}: $y does not exist" 1>&2
+ ((ret|=1))
+fi
+
+exit $ret
diff --git a/portage_with_autodep/bin/ebuild-helpers/dosym b/portage_with_autodep/bin/ebuild-helpers/dosym
new file mode 100755
index 0000000..500dad0
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/dosym
@@ -0,0 +1,18 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ $# -ne 2 ]] ; then
+ helpers_die "${0##*/}: two arguments needed"
+ exit 1
+fi
+
+destdir=${2%/*}
+[[ ! -d ${D}${destdir} ]] && dodir "${destdir}"
+
+ln -snf "$1" "${D}$2"
+ret=$?
+[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+exit $ret
diff --git a/portage_with_autodep/bin/ebuild-helpers/ecompress b/portage_with_autodep/bin/ebuild-helpers/ecompress
new file mode 100755
index 0000000..b61421b
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/ecompress
@@ -0,0 +1,161 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z $1 ]] ; then
+ helpers_die "${0##*/}: at least one argument needed"
+ exit 1
+fi
+
+# setup compression stuff
+PORTAGE_COMPRESS=${PORTAGE_COMPRESS-bzip2}
+[[ -z ${PORTAGE_COMPRESS} ]] && exit 0
+
+if [[ ${PORTAGE_COMPRESS_FLAGS+set} != "set" ]] ; then
+ case ${PORTAGE_COMPRESS} in
+ bzip2|gzip) PORTAGE_COMPRESS_FLAGS="-9";;
+ esac
+fi
+
+# decompress_args(suffix, binary)
+# - suffix: the compression suffix to work with
+# - binary: the program to execute that'll compress/decompress
+# new_args: global array used to return revised arguments
+decompress_args() {
+ local suffix=$1 binary=$2
+ shift 2
+
+ # Initialize the global new_args array.
+ new_args=()
+ declare -a decompress_args=()
+ local x i=0 decompress_count=0
+ for x in "$@" ; do
+ if [[ ${x%$suffix} = $x ]] ; then
+ new_args[$i]=$x
+ else
+ new_args[$i]=${x%$suffix}
+ decompress_args[$decompress_count]=$x
+ ((decompress_count++))
+ fi
+ ((i++))
+ done
+
+ if [ $decompress_count -gt 0 ] ; then
+ ${binary} "${decompress_args[@]}"
+ if [ $? -ne 0 ] ; then
+ # Apparently decompression failed for one or more files, so
+ # drop those since we don't want to compress them twice.
+ new_args=()
+ local x i=0
+ for x in "$@" ; do
+ if [[ ${x%$suffix} = $x ]] ; then
+ new_args[$i]=$x
+ ((i++))
+ elif [[ -f ${x%$suffix} ]] ; then
+ new_args[$i]=${x%$suffix}
+ ((i++))
+ else
+ # Apparently decompression failed for this one, so drop
+ # it since we don't want to compress it twice.
+ true
+ fi
+ done
+ fi
+ fi
+}
+
+case $1 in
+ --suffix)
+ [[ -n $2 ]] && vecho "${0##*/}: --suffix takes no additional arguments" 1>&2
+
+ if [[ ! -e ${T}/.ecompress.suffix ]] ; then
+ set -e
+ tmpdir="${T}"/.ecompress$$.${RANDOM}
+ mkdir "${tmpdir}"
+ cd "${tmpdir}"
+ # we have to fill the file enough so that there is something
+ # to compress as some programs will refuse to do compression
+ # if it cannot actually compress the file
+ echo {0..1000} > compressme
+ ${PORTAGE_COMPRESS} ${PORTAGE_COMPRESS_FLAGS} compressme > /dev/null
+ # If PORTAGE_COMPRESS_FLAGS contains -k then we need to avoid
+ # having our glob match the uncompressed file here.
+ suffix=$(echo compressme.*)
+ [[ -z $suffix || "$suffix" == "compressme.*" ]] && \
+ suffix=$(echo compressme*)
+ suffix=${suffix#compressme}
+ cd /
+ rm -rf "${tmpdir}"
+ echo "${suffix}" > "${T}/.ecompress.suffix"
+ fi
+ cat "${T}/.ecompress.suffix"
+ ;;
+ --bin)
+ [[ -n $2 ]] && vecho "${0##*/}: --bin takes no additional arguments" 1>&2
+
+ echo "${PORTAGE_COMPRESS} ${PORTAGE_COMPRESS_FLAGS}"
+ ;;
+ --queue)
+ shift
+ ret=0
+ for x in "${@/%/.ecompress.file}" ; do
+ >> "$x"
+ ((ret|=$?))
+ done
+ [[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+ exit $ret
+ ;;
+ --dequeue)
+ [[ -n $2 ]] && vecho "${0##*/}: --dequeue takes no additional arguments" 1>&2
+ find "${D}" -name '*.ecompress.file' -print0 \
+ | sed -e 's:\.ecompress\.file::g' \
+ | ${XARGS} -0 ecompress
+ find "${D}" -name '*.ecompress.file' -print0 | ${XARGS} -0 rm -f
+ ;;
+ --*)
+ helpers_die "${0##*/}: unknown arguments '$*'"
+ exit 1
+ ;;
+ *)
+ # Since dodoc calls ecompress on files that are already compressed,
+ # perform decompression here (similar to ecompressdir behavior).
+ decompress_args ".Z" "gunzip -f" "$@"
+ set -- "${new_args[@]}"
+ decompress_args ".gz" "gunzip -f" "$@"
+ set -- "${new_args[@]}"
+ decompress_args ".bz2" "bunzip2 -f" "$@"
+ set -- "${new_args[@]}"
+
+ mask_ext_re=""
+ set -f
+ for x in $PORTAGE_COMPRESS_EXCLUDE_SUFFIXES ; do
+ mask_ext_re+="|$x"
+ done
+ set +f
+ mask_ext_re="^(${mask_ext_re:1})\$"
+ declare -a filtered_args=()
+ i=0
+ for x in "$@" ; do
+ [[ ${x##*.} =~ $mask_ext_re ]] && continue
+ [[ -s ${x} ]] || continue
+ filtered_args[$i]=$x
+ ((i++))
+ done
+ [ $i -eq 0 ] && exit 0
+ set -- "${filtered_args[@]}"
+
+ # If a compressed version of the file already exists, simply
+ # delete it so that the compressor doesn't whine (bzip2 will
+ # complain and skip, gzip will prompt for input)
+ suffix=$(ecompress --suffix)
+ [[ -n ${suffix} ]] && echo -n "${@/%/${suffix}$'\001'}" | \
+ tr '\001' '\000' | ${XARGS} -0 rm -f
+ # Finally, let's actually do some real work
+ "${PORTAGE_COMPRESS}" ${PORTAGE_COMPRESS_FLAGS} "$@"
+ ret=$?
+ [[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+ exit $ret
+ ;;
+esac
diff --git a/portage_with_autodep/bin/ebuild-helpers/ecompressdir b/portage_with_autodep/bin/ebuild-helpers/ecompressdir
new file mode 100755
index 0000000..7a95120
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/ecompressdir
@@ -0,0 +1,143 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z $1 ]] ; then
+ helpers_die "${0##*/}: at least one argument needed"
+ exit 1
+fi
+
+case $1 in
+ --ignore)
+ shift
+ for skip in "$@" ; do
+ [[ -d ${D}${skip} || -f ${D}${skip} ]] \
+ && >> "${D}${skip}.ecompress.skip"
+ done
+ exit 0
+ ;;
+ --queue)
+ shift
+ set -- "${@/%/.ecompress.dir}"
+ set -- "${@/#/${D}}"
+ ret=0
+ for x in "$@" ; do
+ >> "$x"
+ ((ret|=$?))
+ done
+ [[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+ exit $ret
+ ;;
+ --dequeue)
+ [[ -n $2 ]] && vecho "${0##*/}: --dequeue takes no additional arguments" 1>&2
+ find "${D}" -name '*.ecompress.dir' -print0 \
+ | sed -e 's:\.ecompress\.dir::g' -e "s:${D}:/:g" \
+ | ${XARGS} -0 ecompressdir
+ find "${D}" -name '*.ecompress.skip' -print0 | ${XARGS} -0 rm -f
+ exit 0
+ ;;
+ --*)
+ helpers_die "${0##*/}: unknown arguments '$*'"
+ exit 1
+ ;;
+esac
+
+# figure out the new suffix
+suffix=$(ecompress --suffix)
+
+# funk_up_dir(action, suffix, binary)
+# - action: compress or decompress
+# - suffix: the compression suffix to work with
+# - binary: the program to execute that'll compress/decompress
+# The directory we act on is implied in the ${dir} variable
+funk_up_dir() {
+ local act=$1 suffix=$2 binary=$3
+
+ local negate=""
+ [[ ${act} == "compress" ]] && negate="!"
+
+ # first we act on all the files
+ find "${dir}" -type f ${negate} -iname '*'${suffix} -print0 | ${XARGS} -0 ${binary}
+ ((ret|=$?))
+
+ find "${dir}" -type l -print0 | \
+ while read -r -d $'\0' brokenlink ; do
+ [[ -e ${brokenlink} ]] && continue
+ olddest=$(readlink "${brokenlink}")
+ [[ ${act} == "compress" ]] \
+ && newdest="${olddest}${suffix}" \
+ || newdest="${olddest%${suffix}}"
+ rm -f "${brokenlink}"
+ [[ ${act} == "compress" ]] \
+ && ln -snf "${newdest}" "${brokenlink}${suffix}" \
+ || ln -snf "${newdest}" "${brokenlink%${suffix}}"
+ ((ret|=$?))
+ done
+}
+
+# _relocate_skip_dirs(srctree, dsttree)
+# Move all files and directories we want to skip running compression
+# on from srctree to dsttree.
+_relocate_skip_dirs() {
+ local srctree="$1" dsttree="$2"
+
+ [[ -d ${srctree} ]] || return 0
+
+ find "${srctree}" -name '*.ecompress.skip' -print0 | \
+ while read -r -d $'\0' src ; do
+ src=${src%.ecompress.skip}
+ dst="${dsttree}${src#${srctree}}"
+ parent=${dst%/*}
+ mkdir -p "${parent}"
+ mv "${src}" "${dst}"
+ mv "${src}.ecompress.skip" "${dst}.ecompress.skip"
+ done
+}
+hide_skip_dirs() { _relocate_skip_dirs "${D}" "${T}"/ecompress-skip/ ; }
+restore_skip_dirs() { _relocate_skip_dirs "${T}"/ecompress-skip/ "${D}" ; }
+
+ret=0
+
+rm -rf "${T}"/ecompress-skip
+
+for dir in "$@" ; do
+ dir=${dir#/}
+ dir="${D}${dir}"
+ if [[ ! -d ${dir} ]] ; then
+ vecho "${0##*/}: /${dir#${D}} does not exist!"
+ continue
+ fi
+ cd "${dir}"
+ actual_dir=${dir}
+ dir=. # use relative path to avoid 'Argument list too long' errors
+
+ # hide all the stuff we want to skip
+ hide_skip_dirs "${dir}"
+
+ # since we've been requested to compress the whole dir,
+ # delete any individual queued requests
+ rm -f "${actual_dir}.ecompress.dir"
+ find "${dir}" -type f -name '*.ecompress.file' -print0 | ${XARGS} -0 rm -f
+
+ # not uncommon for packages to compress doc files themselves
+ funk_up_dir "decompress" ".Z" "gunzip -f"
+ funk_up_dir "decompress" ".gz" "gunzip -f"
+ funk_up_dir "decompress" ".bz2" "bunzip2 -f"
+
+ # forcibly break all hard links as some compressors whine about it
+ find "${dir}" -type f -links +1 -exec env file="{}" sh -c \
+ 'cp -p "${file}" "${file}.ecompress.break" ; mv -f "${file}.ecompress.break" "${file}"' \;
+
+ # now lets do our work
+ [[ -z ${suffix} ]] && continue
+ vecho "${0##*/}: $(ecompress --bin) /${actual_dir#${D}}"
+ funk_up_dir "compress" "${suffix}" "ecompress"
+
+ # finally, restore the skipped stuff
+ restore_skip_dirs
+done
+
+[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+exit ${ret}
diff --git a/portage_with_autodep/bin/ebuild-helpers/eerror b/portage_with_autodep/bin/ebuild-helpers/eerror
new file mode 120000
index 0000000..a403c75
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/eerror
@@ -0,0 +1 @@
+elog \ No newline at end of file
diff --git a/portage_with_autodep/bin/ebuild-helpers/einfo b/portage_with_autodep/bin/ebuild-helpers/einfo
new file mode 120000
index 0000000..a403c75
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/einfo
@@ -0,0 +1 @@
+elog \ No newline at end of file
diff --git a/portage_with_autodep/bin/ebuild-helpers/elog b/portage_with_autodep/bin/ebuild-helpers/elog
new file mode 100755
index 0000000..a2303af
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/elog
@@ -0,0 +1,7 @@
+#!/bin/bash
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+${0##*/} "$@"
diff --git a/portage_with_autodep/bin/ebuild-helpers/emake b/portage_with_autodep/bin/ebuild-helpers/emake
new file mode 100755
index 0000000..d842781
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/emake
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+#
+# emake: Supplies some default parameters to GNU make. At the moment the
+# only parameter supplied is -jN, where N is a number of
+# parallel processes that should be ideal for the running host
+# (e.g. on a single-CPU machine, N=2). The MAKEOPTS variable
+# is set in make.globals. We don't source make.globals
+# here because emake is only called from an ebuild.
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ $PORTAGE_QUIET != 1 ]] ; then
+ (
+ for arg in ${MAKE:-make} $MAKEOPTS $EXTRA_EMAKE "$@" ; do
+ [[ ${arg} == *" "* ]] \
+ && printf "'%s' " "${arg}" \
+ || printf "%s " "${arg}"
+ done
+ printf "\n"
+ ) >&2
+fi
+
+${MAKE:-make} ${MAKEOPTS} ${EXTRA_EMAKE} "$@"
+ret=$?
+[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+exit $ret
diff --git a/portage_with_autodep/bin/ebuild-helpers/eqawarn b/portage_with_autodep/bin/ebuild-helpers/eqawarn
new file mode 120000
index 0000000..a403c75
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/eqawarn
@@ -0,0 +1 @@
+elog \ No newline at end of file
diff --git a/portage_with_autodep/bin/ebuild-helpers/ewarn b/portage_with_autodep/bin/ebuild-helpers/ewarn
new file mode 120000
index 0000000..a403c75
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/ewarn
@@ -0,0 +1 @@
+elog \ No newline at end of file
diff --git a/portage_with_autodep/bin/ebuild-helpers/fowners b/portage_with_autodep/bin/ebuild-helpers/fowners
new file mode 100755
index 0000000..4cc6bfa
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/fowners
@@ -0,0 +1,13 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+# we can't prefix all arguments because
+# chown takes random options
+slash="/"
+chown "${@/#${slash}/${D}${slash}}"
+ret=$?
+[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+exit $ret
diff --git a/portage_with_autodep/bin/ebuild-helpers/fperms b/portage_with_autodep/bin/ebuild-helpers/fperms
new file mode 100755
index 0000000..0260bdc
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/fperms
@@ -0,0 +1,13 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+# we can't prefix all arguments because
+# chmod takes random options
+slash="/"
+chmod "${@/#${slash}/${D}${slash}}"
+ret=$?
+[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+exit $ret
diff --git a/portage_with_autodep/bin/ebuild-helpers/newbin b/portage_with_autodep/bin/ebuild-helpers/newbin
new file mode 100755
index 0000000..30f19b0
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/newbin
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z ${T} ]] || [[ -z ${2} ]] ; then
+ helpers_die "${0##*/}: Need two arguments, old file and new file"
+ exit 1
+fi
+
+if [ ! -e "$1" ] ; then
+ helpers_die "!!! ${0##*/}: $1 does not exist"
+ exit 1
+fi
+
+rm -rf "${T}/${2}" && \
+cp -f "${1}" "${T}/${2}" && \
+exec dobin "${T}/${2}"
diff --git a/portage_with_autodep/bin/ebuild-helpers/newconfd b/portage_with_autodep/bin/ebuild-helpers/newconfd
new file mode 100755
index 0000000..5752cfa
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/newconfd
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z ${T} ]] || [[ -z ${2} ]] ; then
+ helpers_die "${0##*/}: Need two arguments, old file and new file"
+ exit 1
+fi
+
+if [ ! -e "$1" ] ; then
+ helpers_die "!!! ${0##*/}: $1 does not exist"
+ exit 1
+fi
+
+rm -rf "${T}/${2}" && \
+cp -f "${1}" "${T}/${2}" && \
+exec doconfd "${T}/${2}"
diff --git a/portage_with_autodep/bin/ebuild-helpers/newdoc b/portage_with_autodep/bin/ebuild-helpers/newdoc
new file mode 100755
index 0000000..f97ce0d
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/newdoc
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z ${T} ]] || [[ -z ${2} ]] ; then
+ helpers_die "${0##*/}: Need two arguments, old file and new file"
+ exit 1
+fi
+
+if [ ! -e "$1" ] ; then
+ helpers_die "!!! ${0##*/}: $1 does not exist"
+ exit 1
+fi
+
+rm -rf "${T}/${2}" && \
+cp -f "${1}" "${T}/${2}" && \
+exec dodoc "${T}/${2}"
diff --git a/portage_with_autodep/bin/ebuild-helpers/newenvd b/portage_with_autodep/bin/ebuild-helpers/newenvd
new file mode 100755
index 0000000..83c556e
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/newenvd
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z ${T} ]] || [[ -z ${2} ]] ; then
+ helpers_die "${0##*/}: Need two arguments, old file and new file"
+ exit 1
+fi
+
+if [ ! -e "$1" ] ; then
+ helpers_die "!!! ${0##*/}: $1 does not exist"
+ exit 1
+fi
+
+rm -rf "${T}/${2}" && \
+cp -f "${1}" "${T}/${2}" && \
+exec doenvd "${T}/${2}"
diff --git a/portage_with_autodep/bin/ebuild-helpers/newexe b/portage_with_autodep/bin/ebuild-helpers/newexe
new file mode 100755
index 0000000..92dbe9f
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/newexe
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z ${T} ]] || [[ -z ${2} ]] ; then
+ helpers_die "${0##*/}: Need two arguments, old file and new file"
+ exit 1
+fi
+
+if [ ! -e "$1" ] ; then
+ helpers_die "!!! ${0##*/}: $1 does not exist"
+ exit 1
+fi
+
+rm -rf "${T}/${2}" && \
+cp -f "${1}" "${T}/${2}" && \
+exec doexe "${T}/${2}"
diff --git a/portage_with_autodep/bin/ebuild-helpers/newinitd b/portage_with_autodep/bin/ebuild-helpers/newinitd
new file mode 100755
index 0000000..fc6003a
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/newinitd
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z ${T} ]] || [[ -z ${2} ]] ; then
+ helpers_die "${0##*/}: Need two arguments, old file and new file"
+ exit 1
+fi
+
+if [ ! -e "$1" ] ; then
+ helpers_die "!!! ${0##*/}: $1 does not exist"
+ exit 1
+fi
+
+rm -rf "${T}/${2}" && \
+cp -f "${1}" "${T}/${2}" && \
+exec doinitd "${T}/${2}"
diff --git a/portage_with_autodep/bin/ebuild-helpers/newins b/portage_with_autodep/bin/ebuild-helpers/newins
new file mode 100755
index 0000000..065477f
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/newins
@@ -0,0 +1,35 @@
+#!/bin/bash
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z ${T} ]] || [[ -z ${2} ]] ; then
+ helpers_die "${0##*/}: Need two arguments, old file and new file"
+ exit 1
+fi
+
+if [ ! -e "$1" ] ; then
+ helpers_die "!!! ${0##*/}: $1 does not exist"
+ exit 1
+fi
+
+rm -rf "${T}/${2}" || exit $?
+case "$EAPI" in
+ 0|1|2|3|3_pre2)
+ cp "$1" "$T/$2" || exit $?
+ ;;
+ *)
+ cp -P "$1" "$T/$2"
+ ret=$?
+ if [[ $ret -ne 0 ]] ; then
+ helpers_die "${0##*/} failed"
+ exit $ret
+ fi
+ ;;
+esac
+doins "${T}/${2}"
+ret=$?
+rm -rf "${T}/${2}"
+[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed"
+exit $ret
diff --git a/portage_with_autodep/bin/ebuild-helpers/newlib.a b/portage_with_autodep/bin/ebuild-helpers/newlib.a
new file mode 100755
index 0000000..eef4104
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/newlib.a
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z ${T} ]] || [[ -z ${2} ]] ; then
+ helpers_die "${0##*/}: Need two arguments, old file and new file"
+ exit 1
+fi
+
+if [ ! -e "$1" ] ; then
+ helpers_die "!!! ${0##*/}: $1 does not exist"
+ exit 1
+fi
+
+rm -rf "${T}/${2}" && \
+cp -f "${1}" "${T}/${2}" && \
+exec dolib.a "${T}/${2}"
diff --git a/portage_with_autodep/bin/ebuild-helpers/newlib.so b/portage_with_autodep/bin/ebuild-helpers/newlib.so
new file mode 100755
index 0000000..c8696f3
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/newlib.so
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z ${T} ]] || [[ -z ${2} ]] ; then
+ helpers_die "${0##*/}: Need two arguments, old file and new file"
+ exit 1
+fi
+
+if [ ! -e "$1" ] ; then
+ helpers_die "!!! ${0##*/}: $1 does not exist"
+ exit 1
+fi
+
+rm -rf "${T}/${2}" && \
+cp -f "${1}" "${T}/${2}" && \
+exec dolib.so "${T}/${2}"
diff --git a/portage_with_autodep/bin/ebuild-helpers/newman b/portage_with_autodep/bin/ebuild-helpers/newman
new file mode 100755
index 0000000..ffb8a2d
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/newman
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z ${T} ]] || [[ -z ${2} ]] ; then
+ helpers_die "${0##*/}: Need two arguments, old file and new file"
+ exit 1
+fi
+
+if [ ! -e "$1" ] ; then
+ helpers_die "!!! ${0##*/}: $1 does not exist"
+ exit 1
+fi
+
+rm -rf "${T}/${2}" && \
+cp -f "${1}" "${T}/${2}" && \
+exec doman "${T}/${2}"
diff --git a/portage_with_autodep/bin/ebuild-helpers/newsbin b/portage_with_autodep/bin/ebuild-helpers/newsbin
new file mode 100755
index 0000000..82242aa
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/newsbin
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z ${T} ]] || [[ -z ${2} ]] ; then
+ helpers_die "${0##*/}: Need two arguments, old file and new file"
+ exit 1
+fi
+
+if [ ! -e "$1" ] ; then
+ helpers_die "!!! ${0##*/}: $1 does not exist"
+ exit 1
+fi
+
+rm -rf "${T}/${2}" && \
+cp -f "${1}" "${T}/${2}" && \
+exec dosbin "${T}/${2}"
diff --git a/portage_with_autodep/bin/ebuild-helpers/portageq b/portage_with_autodep/bin/ebuild-helpers/portageq
new file mode 100755
index 0000000..ec30b66
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/portageq
@@ -0,0 +1,8 @@
+#!/bin/bash
+# Copyright 2009-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+PORTAGE_BIN_PATH=${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}
+PORTAGE_PYM_PATH=${PORTAGE_PYM_PATH:-/usr/lib/portage/pym}
+PYTHONPATH=$PORTAGE_PYM_PATH${PYTHONPATH:+:}$PYTHONPATH \
+ exec "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH/portageq" "$@"
diff --git a/portage_with_autodep/bin/ebuild-helpers/prepall b/portage_with_autodep/bin/ebuild-helpers/prepall
new file mode 100755
index 0000000..701ecba
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/prepall
@@ -0,0 +1,23 @@
+#!/bin/bash
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if has chflags $FEATURES ; then
+ # Save all the file flags for restoration at the end of prepall.
+ mtree -c -p "${D}" -k flags > "${T}/bsdflags.mtree"
+ # Remove all the file flags so that prepall can do anything necessary.
+ chflags -R noschg,nouchg,nosappnd,nouappnd "${D}"
+ chflags -R nosunlnk,nouunlnk "${D}" 2>/dev/null
+fi
+
+prepallman
+prepallinfo
+
+prepallstrip
+
+if has chflags $FEATURES ; then
+ # Restore all the file flags that were saved at the beginning of prepall.
+ mtree -U -e -p "${D}" -k flags < "${T}/bsdflags.mtree" &> /dev/null
+fi
diff --git a/portage_with_autodep/bin/ebuild-helpers/prepalldocs b/portage_with_autodep/bin/ebuild-helpers/prepalldocs
new file mode 100755
index 0000000..fdc735d
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/prepalldocs
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -n $1 ]] ; then
+ vecho "${0##*/}: invalid usage; takes no arguments" 1>&2
+fi
+
+cd "${D}"
+[[ -d usr/share/doc ]] || exit 0
+
+ecompressdir --ignore /usr/share/doc/${PF}/html
+ecompressdir --queue /usr/share/doc
diff --git a/portage_with_autodep/bin/ebuild-helpers/prepallinfo b/portage_with_autodep/bin/ebuild-helpers/prepallinfo
new file mode 100755
index 0000000..0d97803
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/prepallinfo
@@ -0,0 +1,9 @@
+#!/bin/bash
+# Copyright 1999-2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+[[ ! -d ${D}usr/share/info ]] && exit 0
+
+exec prepinfo
diff --git a/portage_with_autodep/bin/ebuild-helpers/prepallman b/portage_with_autodep/bin/ebuild-helpers/prepallman
new file mode 100755
index 0000000..e50de6d
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/prepallman
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+# replaced by controllable compression in EAPI 4
+has "${EAPI}" 0 1 2 3 || exit 0
+
+ret=0
+
+find "${D}" -type d -name man > "${T}"/prepallman.filelist
+while read -r mandir ; do
+ mandir=${mandir#${D}}
+ prepman "${mandir%/man}"
+ ((ret|=$?))
+done < "${T}"/prepallman.filelist
+
+exit ${ret}
diff --git a/portage_with_autodep/bin/ebuild-helpers/prepallstrip b/portage_with_autodep/bin/ebuild-helpers/prepallstrip
new file mode 100755
index 0000000..ec12ce6
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/prepallstrip
@@ -0,0 +1,5 @@
+#!/bin/bash
+# Copyright 1999-2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+exec prepstrip "${D}"
diff --git a/portage_with_autodep/bin/ebuild-helpers/prepinfo b/portage_with_autodep/bin/ebuild-helpers/prepinfo
new file mode 100755
index 0000000..691fd13
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/prepinfo
@@ -0,0 +1,34 @@
+#!/bin/bash
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z $1 ]] ; then
+ infodir="/usr/share/info"
+else
+ if [[ -d ${D}$1/share/info ]] ; then
+ infodir="$1/share/info"
+ else
+ infodir="$1/info"
+ fi
+fi
+
+if [[ ! -d ${D}${infodir} ]] ; then
+ if [[ -n $1 ]] ; then
+ vecho "${0##*/}: '${infodir}' does not exist!"
+ exit 1
+ else
+ exit 0
+ fi
+fi
+
+find "${D}${infodir}" -type d -print0 | while read -r -d $'\0' x ; do
+ for f in "${x}"/.keepinfodir*; do
+ [[ -e ${f} ]] && continue 2
+ done
+ rm -f "${x}"/dir{,.info}{,.gz,.bz2}
+done
+
+has "${EAPI}" 0 1 2 3 || exit 0
+exec ecompressdir --queue "${infodir}"
diff --git a/portage_with_autodep/bin/ebuild-helpers/preplib b/portage_with_autodep/bin/ebuild-helpers/preplib
new file mode 100755
index 0000000..76aabe6
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/preplib
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Copyright 1999-2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+eqawarn "QA Notice: Deprecated call to 'preplib'"
+
+LIBDIR_VAR="LIBDIR_${ABI}"
+if [ -n "${ABI}" -a -n "${!LIBDIR_VAR}" ]; then
+ CONF_LIBDIR="${!LIBDIR_VAR}"
+fi
+unset LIBDIR_VAR
+
+if [ -z "${CONF_LIBDIR}" ]; then
+ # we need this to default to lib so that things dont break
+ CONF_LIBDIR="lib"
+fi
+
+if [ -z "$1" ] ; then
+ z="${D}usr/${CONF_LIBDIR}"
+else
+ z="${D}$1/${CONF_LIBDIR}"
+fi
+
+if [ -d "${z}" ] ; then
+ ldconfig -n -N "${z}"
+fi
diff --git a/portage_with_autodep/bin/ebuild-helpers/prepman b/portage_with_autodep/bin/ebuild-helpers/prepman
new file mode 100755
index 0000000..c9add8a
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/prepman
@@ -0,0 +1,32 @@
+#!/bin/bash
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+if [[ -z $1 ]] ; then
+ mandir="${D}usr/share/man"
+else
+ mandir="${D}$1/man"
+fi
+
+if [[ ! -d ${mandir} ]] ; then
+ eqawarn "QA Notice: prepman called with non-existent dir '${mandir#${D}}'"
+ exit 0
+fi
+
+# replaced by controllable compression in EAPI 4
+has "${EAPI}" 0 1 2 3 || exit 0
+
+shopt -s nullglob
+
+really_is_mandir=0
+
+# use some heuristics to test if this is a real mandir
+for subdir in "${mandir}"/man* "${mandir}"/*/man* ; do
+ [[ -d ${subdir} ]] && really_is_mandir=1 && break
+done
+
+[[ ${really_is_mandir} == 1 ]] && exec ecompressdir --queue "${mandir#${D}}"
+
+exit 0
diff --git a/portage_with_autodep/bin/ebuild-helpers/prepstrip b/portage_with_autodep/bin/ebuild-helpers/prepstrip
new file mode 100755
index 0000000..d25259d
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/prepstrip
@@ -0,0 +1,193 @@
+#!/bin/bash
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
+
+banner=false
+SKIP_STRIP=false
+if has nostrip ${FEATURES} || \
+ has strip ${RESTRICT}
+then
+ SKIP_STRIP=true
+ banner=true
+ has installsources ${FEATURES} || exit 0
+fi
+
+STRIP=${STRIP:-${CHOST}-strip}
+type -P -- ${STRIP} > /dev/null || STRIP=strip
+OBJCOPY=${OBJCOPY:-${CHOST}-objcopy}
+type -P -- ${OBJCOPY} > /dev/null || OBJCOPY=objcopy
+
+# We'll leave out -R .note for now until we can check out the relevance
+# of the section when it has the ALLOC flag set on it ...
+export SAFE_STRIP_FLAGS="--strip-unneeded"
+export PORTAGE_STRIP_FLAGS=${PORTAGE_STRIP_FLAGS-${SAFE_STRIP_FLAGS} -R .comment}
+prepstrip_sources_dir=/usr/src/debug/${CATEGORY}/${PF}
+
+if has installsources ${FEATURES} && ! type -P debugedit >/dev/null ; then
+ ewarn "FEATURES=installsources is enabled but the debugedit binary could not"
+ ewarn "be found. This feature will not work unless debugedit is installed!"
+fi
+
+unset ${!INODE_*}
+
+inode_var_name() {
+ if [[ $USERLAND = BSD ]] ; then
+ stat -f 'INODE_%d_%i' "$1"
+ else
+ stat -c 'INODE_%d_%i' "$1"
+ fi
+}
+
+save_elf_sources() {
+ has installsources ${FEATURES} || return 0
+ has installsources ${RESTRICT} && return 0
+ type -P debugedit >/dev/null || return 0
+
+ local x=$1
+ local inode=$(inode_var_name "$x")
+ [[ -n ${!inode} ]] && return 0
+ debugedit -b "${WORKDIR}" -d "${prepstrip_sources_dir}" \
+ -l "${T}"/debug.sources "${x}"
+}
+
+save_elf_debug() {
+ has splitdebug ${FEATURES} || return 0
+
+ local x=$1
+ local y="${D}usr/lib/debug/${x:${#D}}.debug"
+
+ # dont save debug info twice
+ [[ ${x} == *".debug" ]] && return 0
+
+ # this will recompute the build-id, but for now that's ok
+ local buildid="$( type -P debugedit >/dev/null && debugedit -i "${x}" )"
+
+ mkdir -p $(dirname "${y}")
+
+ local inode=$(inode_var_name "$x")
+ if [[ -n ${!inode} ]] ; then
+ ln "${D}usr/lib/debug/${!inode:${#D}}.debug" "$y"
+ else
+ eval $inode=\$x
+ ${OBJCOPY} --only-keep-debug "${x}" "${y}"
+ ${OBJCOPY} --add-gnu-debuglink="${y}" "${x}"
+ [[ -g ${x} ]] && chmod go-r "${y}"
+ [[ -u ${x} ]] && chmod go-r "${y}"
+ chmod a-x,o-w "${y}"
+ fi
+
+ if [[ -n ${buildid} ]] ; then
+ local buildid_dir="${D}usr/lib/debug/.build-id/${buildid:0:2}"
+ local buildid_file="${buildid_dir}/${buildid:2}"
+ mkdir -p "${buildid_dir}"
+ ln -s "../../${x:${#D}}.debug" "${buildid_file}.debug"
+ ln -s "/${x:${#D}}" "${buildid_file}"
+ fi
+}
+
+# The existance of the section .symtab tells us that a binary is stripped.
+# We want to log already stripped binaries, as this may be a QA violation.
+# They prevent us from getting the splitdebug data.
+if ! has binchecks ${RESTRICT} && \
+ ! has strip ${RESTRICT} ; then
+ log=$T/scanelf-already-stripped.log
+ qa_var="QA_PRESTRIPPED_${ARCH/-/_}"
+ [[ -n ${!qa_var} ]] && QA_PRESTRIPPED="${!qa_var}"
+ scanelf -yqRBF '#k%F' -k '!.symtab' "$@" | sed -e "s#^$D##" > "$log"
+ if [[ -n $QA_PRESTRIPPED && -s $log && \
+ ${QA_STRICT_PRESTRIPPED-unset} = unset ]] ; then
+ shopts=$-
+ set -o noglob
+ for x in $QA_PRESTRIPPED ; do
+ sed -e "s#^${x#/}\$##" -i "$log"
+ done
+ set +o noglob
+ set -$shopts
+ fi
+ sed -e "/^\$/d" -e "s#^#/#" -i "$log"
+ if [[ -s $log ]] ; then
+ vecho -e "\n"
+ eqawarn "QA Notice: Pre-stripped files found:"
+ eqawarn "$(<"$log")"
+ else
+ rm -f "$log"
+ fi
+fi
+
+# Now we look for unstripped binaries.
+for x in \
+ $(scanelf -yqRBF '#k%F' -k '.symtab' "$@") \
+ $(find "$@" -type f -name '*.a')
+do
+ if ! ${banner} ; then
+ vecho "strip: ${STRIP} ${PORTAGE_STRIP_FLAGS}"
+ banner=true
+ fi
+
+ f=$(file "${x}") || continue
+ [[ -z ${f} ]] && continue
+
+ if ! ${SKIP_STRIP} ; then
+ # The noglob funk is to support STRIP_MASK="/*/booga" and to keep
+ # the for loop from expanding the globs.
+ # The eval echo is to support STRIP_MASK="/*/{booga,bar}" sex.
+ set -o noglob
+ strip_this=true
+ for m in $(eval echo ${STRIP_MASK}) ; do
+ [[ /${x#${D}} == ${m} ]] && strip_this=false && break
+ done
+ set +o noglob
+ else
+ strip_this=false
+ fi
+
+ # only split debug info for final linked objects
+ # or kernel modules as debuginfo for intermediatary
+ # files (think crt*.o from gcc/glibc) is useless and
+ # actually causes problems. install sources for all
+ # elf types though cause that stuff is good.
+
+ if [[ ${f} == *"current ar archive"* ]] ; then
+ vecho " ${x:${#D}}"
+ if ${strip_this} ; then
+ # hmm, can we split debug/sources for .a ?
+ ${STRIP} -g "${x}"
+ fi
+ elif [[ ${f} == *"SB executable"* || ${f} == *"SB shared object"* ]] ; then
+ vecho " ${x:${#D}}"
+ save_elf_sources "${x}"
+ if ${strip_this} ; then
+ save_elf_debug "${x}"
+ ${STRIP} ${PORTAGE_STRIP_FLAGS} "${x}"
+ fi
+ elif [[ ${f} == *"SB relocatable"* ]] ; then
+ vecho " ${x:${#D}}"
+ save_elf_sources "${x}"
+ if ${strip_this} ; then
+ [[ ${x} == *.ko ]] && save_elf_debug "${x}"
+ ${STRIP} ${SAFE_STRIP_FLAGS} "${x}"
+ fi
+ fi
+done
+
+if [[ -s ${T}/debug.sources ]] && \
+ has installsources ${FEATURES} && \
+ ! has installsources ${RESTRICT} && \
+ type -P debugedit >/dev/null
+then
+ vecho "installsources: rsyncing source files"
+ [[ -d ${D}${prepstrip_sources_dir} ]] || mkdir -p "${D}${prepstrip_sources_dir}"
+ grep -zv '/<[^/>]*>$' "${T}"/debug.sources | \
+ (cd "${WORKDIR}"; LANG=C sort -z -u | \
+ rsync -tL0 --files-from=- "${WORKDIR}/" "${D}${prepstrip_sources_dir}/" )
+
+ # Preserve directory structure.
+ # Needed after running save_elf_sources.
+ # https://bugzilla.redhat.com/show_bug.cgi?id=444310
+ while read -r -d $'\0' emptydir
+ do
+ >> "$emptydir"/.keepdir
+ done < <(find "${D}${prepstrip_sources_dir}/" -type d -empty -print0)
+fi
diff --git a/portage_with_autodep/bin/ebuild-helpers/sed b/portage_with_autodep/bin/ebuild-helpers/sed
new file mode 100755
index 0000000..b21e856
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-helpers/sed
@@ -0,0 +1,27 @@
+#!/bin/bash
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+scriptpath=${BASH_SOURCE[0]}
+scriptname=${scriptpath##*/}
+
+if [[ sed == ${scriptname} ]] && [[ -n ${ESED} ]]; then
+ exec ${ESED} "$@"
+elif type -P g${scriptname} > /dev/null ; then
+ exec g${scriptname} "$@"
+else
+ old_IFS="${IFS}"
+ IFS=":"
+
+ for path in $PATH; do
+ [[ ${path}/${scriptname} == ${scriptpath} ]] && continue
+ if [[ -x ${path}/${scriptname} ]]; then
+ exec ${path}/${scriptname} "$@"
+ exit 0
+ fi
+ done
+
+ IFS="${old_IFS}"
+fi
+
+exit 1
diff --git a/portage_with_autodep/bin/ebuild-ipc b/portage_with_autodep/bin/ebuild-ipc
new file mode 100755
index 0000000..43e4a02
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-ipc
@@ -0,0 +1,8 @@
+#!/bin/bash
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+PORTAGE_BIN_PATH=${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}
+PORTAGE_PYM_PATH=${PORTAGE_PYM_PATH:-/usr/lib/portage/pym}
+PYTHONPATH=$PORTAGE_PYM_PATH${PYTHONPATH:+:}$PYTHONPATH \
+ exec "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH/ebuild-ipc.py" "$@"
diff --git a/portage_with_autodep/bin/ebuild-ipc.py b/portage_with_autodep/bin/ebuild-ipc.py
new file mode 100755
index 0000000..68ad985
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild-ipc.py
@@ -0,0 +1,276 @@
+#!/usr/bin/python
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+#
+# This is a helper which ebuild processes can use
+# to communicate with portage's main python process.
+
+import errno
+import logging
+import os
+import pickle
+import select
+import signal
+import sys
+import time
+
+def debug_signal(signum, frame):
+ import pdb
+ pdb.set_trace()
+signal.signal(signal.SIGUSR1, debug_signal)
+
+# Avoid sandbox violations after python upgrade.
+pym_path = os.path.join(os.path.dirname(
+ os.path.dirname(os.path.realpath(__file__))), "pym")
+if os.environ.get("SANDBOX_ON") == "1":
+ sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
+ if pym_path not in sandbox_write:
+ sandbox_write.append(pym_path)
+ os.environ["SANDBOX_WRITE"] = \
+ ":".join(filter(None, sandbox_write))
+
+import portage
+portage._disable_legacy_globals()
+
+class EbuildIpc(object):
+
+ # Timeout for each individual communication attempt (we retry
+ # as long as the daemon process appears to be alive).
+ _COMMUNICATE_RETRY_TIMEOUT_SECONDS = 15
+ _BUFSIZE = 4096
+
+ def __init__(self):
+ self.fifo_dir = os.environ['PORTAGE_BUILDDIR']
+ self.ipc_in_fifo = os.path.join(self.fifo_dir, '.ipc_in')
+ self.ipc_out_fifo = os.path.join(self.fifo_dir, '.ipc_out')
+ self.ipc_lock_file = os.path.join(self.fifo_dir, '.ipc_lock')
+
+ def _daemon_is_alive(self):
+ try:
+ builddir_lock = portage.locks.lockfile(self.fifo_dir,
+ wantnewlockfile=True, flags=os.O_NONBLOCK)
+ except portage.exception.TryAgain:
+ return True
+ else:
+ portage.locks.unlockfile(builddir_lock)
+ return False
+
+ def communicate(self, args):
+
+ # Make locks quiet since unintended locking messages displayed on
+ # stdout could corrupt the intended output of this program.
+ portage.locks._quiet = True
+ lock_obj = portage.locks.lockfile(self.ipc_lock_file, unlinkfile=True)
+
+ try:
+ return self._communicate(args)
+ finally:
+ portage.locks.unlockfile(lock_obj)
+
+ def _timeout_retry_msg(self, start_time, when):
+ time_elapsed = time.time() - start_time
+ portage.util.writemsg_level(
+ portage.localization._(
+ 'ebuild-ipc timed out %s after %d seconds,' + \
+ ' retrying...\n') % (when, time_elapsed),
+ level=logging.ERROR, noiselevel=-1)
+
+ def _no_daemon_msg(self):
+ portage.util.writemsg_level(
+ portage.localization._(
+ 'ebuild-ipc: daemon process not detected\n'),
+ level=logging.ERROR, noiselevel=-1)
+
+ def _wait(self, pid, pr, msg):
+ """
+ Wait on pid and return an appropriate exit code. This
+ may return unsuccessfully due to timeout if the daemon
+ process does not appear to be alive.
+ """
+
+ start_time = time.time()
+
+ while True:
+ try:
+ events = select.select([pr], [], [],
+ self._COMMUNICATE_RETRY_TIMEOUT_SECONDS)
+ except select.error as e:
+ portage.util.writemsg_level(
+ "ebuild-ipc: %s: %s\n" % \
+ (portage.localization._('during select'), e),
+ level=logging.ERROR, noiselevel=-1)
+ continue
+
+ if events[0]:
+ break
+
+ if self._daemon_is_alive():
+ self._timeout_retry_msg(start_time, msg)
+ else:
+ self._no_daemon_msg()
+ try:
+ os.kill(pid, signal.SIGKILL)
+ os.waitpid(pid, 0)
+ except OSError as e:
+ portage.util.writemsg_level(
+ "ebuild-ipc: %s\n" % (e,),
+ level=logging.ERROR, noiselevel=-1)
+ return 2
+
+ try:
+ wait_retval = os.waitpid(pid, 0)
+ except OSError as e:
+ portage.util.writemsg_level(
+ "ebuild-ipc: %s: %s\n" % (msg, e),
+ level=logging.ERROR, noiselevel=-1)
+ return 2
+
+ if not os.WIFEXITED(wait_retval[1]):
+ portage.util.writemsg_level(
+ "ebuild-ipc: %s: %s\n" % (msg,
+ portage.localization._('subprocess failure: %s') % \
+ wait_retval[1]),
+ level=logging.ERROR, noiselevel=-1)
+ return 2
+
+ return os.WEXITSTATUS(wait_retval[1])
+
+ def _receive_reply(self, input_fd):
+
+ # Timeouts are handled by the parent process, so just
+ # block until input is available. For maximum portability,
+ # use a single atomic read.
+ buf = None
+ while True:
+ try:
+ events = select.select([input_fd], [], [])
+ except select.error as e:
+ portage.util.writemsg_level(
+ "ebuild-ipc: %s: %s\n" % \
+ (portage.localization._('during select for read'), e),
+ level=logging.ERROR, noiselevel=-1)
+ continue
+
+ if events[0]:
+ # For maximum portability, use os.read() here since
+ # array.fromfile() and file.read() are both known to
+ # erroneously return an empty string from this
+ # non-blocking fifo stream on FreeBSD (bug #337465).
+ try:
+ buf = os.read(input_fd, self._BUFSIZE)
+ except OSError as e:
+ if e.errno != errno.EAGAIN:
+ portage.util.writemsg_level(
+ "ebuild-ipc: %s: %s\n" % \
+ (portage.localization._('read error'), e),
+ level=logging.ERROR, noiselevel=-1)
+ break
+ # Assume that another event will be generated
+ # if there's any relevant data.
+ continue
+
+ # Only one (atomic) read should be necessary.
+ if buf:
+ break
+
+ retval = 2
+
+ if not buf:
+
+ portage.util.writemsg_level(
+ "ebuild-ipc: %s\n" % \
+ (portage.localization._('read failed'),),
+ level=logging.ERROR, noiselevel=-1)
+
+ else:
+
+ try:
+ reply = pickle.loads(buf)
+ except SystemExit:
+ raise
+ except Exception as e:
+ # The pickle module can raise practically
+ # any exception when given corrupt data.
+ portage.util.writemsg_level(
+ "ebuild-ipc: %s\n" % (e,),
+ level=logging.ERROR, noiselevel=-1)
+
+ else:
+
+ (out, err, retval) = reply
+
+ if out:
+ portage.util.writemsg_stdout(out, noiselevel=-1)
+
+ if err:
+ portage.util.writemsg(err, noiselevel=-1)
+
+ return retval
+
+ def _communicate(self, args):
+
+ if not self._daemon_is_alive():
+ self._no_daemon_msg()
+ return 2
+
+ # Open the input fifo before the output fifo, in order to make it
+ # possible for the daemon to send a reply without blocking. This
+ # improves performance, and also makes it possible for the daemon
+ # to do a non-blocking write without a race condition.
+ input_fd = os.open(self.ipc_out_fifo,
+ os.O_RDONLY|os.O_NONBLOCK)
+
+ # Use forks so that the child process can handle blocking IO
+ # un-interrupted, while the parent handles all timeout
+ # considerations. This helps to avoid possible race conditions
+ # from interference between timeouts and blocking IO operations.
+ pr, pw = os.pipe()
+ pid = os.fork()
+
+ if pid == 0:
+ os.close(pr)
+
+ # File streams are in unbuffered mode since we do atomic
+ # read and write of whole pickles.
+ output_file = open(self.ipc_in_fifo, 'wb', 0)
+ output_file.write(pickle.dumps(args))
+ output_file.close()
+ os._exit(os.EX_OK)
+
+ os.close(pw)
+
+ msg = portage.localization._('during write')
+ retval = self._wait(pid, pr, msg)
+ os.close(pr)
+
+ if retval != os.EX_OK:
+ portage.util.writemsg_level(
+ "ebuild-ipc: %s: %s\n" % (msg,
+ portage.localization._('subprocess failure: %s') % \
+ retval), level=logging.ERROR, noiselevel=-1)
+ return retval
+
+ if not self._daemon_is_alive():
+ self._no_daemon_msg()
+ return 2
+
+ pr, pw = os.pipe()
+ pid = os.fork()
+
+ if pid == 0:
+ os.close(pr)
+ retval = self._receive_reply(input_fd)
+ os._exit(retval)
+
+ os.close(pw)
+ retval = self._wait(pid, pr, portage.localization._('during read'))
+ os.close(pr)
+ os.close(input_fd)
+ return retval
+
+def ebuild_ipc_main(args):
+ ebuild_ipc = EbuildIpc()
+ return ebuild_ipc.communicate(args)
+
+if __name__ == '__main__':
+ sys.exit(ebuild_ipc_main(sys.argv[1:]))
diff --git a/portage_with_autodep/bin/ebuild.sh b/portage_with_autodep/bin/ebuild.sh
new file mode 100755
index 0000000..d68e54b
--- /dev/null
+++ b/portage_with_autodep/bin/ebuild.sh
@@ -0,0 +1,2424 @@
+#!/bin/bash
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+PORTAGE_BIN_PATH="${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"
+PORTAGE_PYM_PATH="${PORTAGE_PYM_PATH:-/usr/lib/portage/pym}"
+
+if [[ $PORTAGE_SANDBOX_COMPAT_LEVEL -lt 22 ]] ; then
+ # Ensure that /dev/std* streams have appropriate sandbox permission for
+ # bug #288863. This can be removed after sandbox is fixed and portage
+ # depends on the fixed version (sandbox-2.2 has the fix but it is
+ # currently unstable).
+ export SANDBOX_WRITE="${SANDBOX_WRITE:+${SANDBOX_WRITE}:}/dev/stdout:/dev/stderr"
+ export SANDBOX_READ="${SANDBOX_READ:+${SANDBOX_READ}:}/dev/stdin"
+fi
+
+# Don't use sandbox's BASH_ENV for new shells because it does
+# 'source /etc/profile' which can interfere with the build
+# environment by modifying our PATH.
+unset BASH_ENV
+
+ROOTPATH=${ROOTPATH##:}
+ROOTPATH=${ROOTPATH%%:}
+PREROOTPATH=${PREROOTPATH##:}
+PREROOTPATH=${PREROOTPATH%%:}
+PATH=$PORTAGE_BIN_PATH/ebuild-helpers:$PREROOTPATH${PREROOTPATH:+:}/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin${ROOTPATH:+:}$ROOTPATH
+export PATH
+
+# This is just a temporary workaround for portage-9999 users since
+# earlier portage versions do not detect a version change in this case
+# (9999 to 9999) and therefore they try execute an incompatible version of
+# ebuild.sh during the upgrade.
+export PORTAGE_BZIP2_COMMAND=${PORTAGE_BZIP2_COMMAND:-bzip2}
+
+# These two functions wrap sourcing and calling respectively. At present they
+# perform a qa check to make sure eclasses and ebuilds and profiles don't mess
+# with shell opts (shopts). Ebuilds/eclasses changing shopts should reset them
+# when they are done.
+
+qa_source() {
+ local shopts=$(shopt) OLDIFS="$IFS"
+ local retval
+ source "$@"
+ retval=$?
+ set +e
+ [[ $shopts != $(shopt) ]] &&
+ eqawarn "QA Notice: Global shell options changed and were not restored while sourcing '$*'"
+ [[ "$IFS" != "$OLDIFS" ]] &&
+ eqawarn "QA Notice: Global IFS changed and was not restored while sourcing '$*'"
+ return $retval
+}
+
+qa_call() {
+ local shopts=$(shopt) OLDIFS="$IFS"
+ local retval
+ "$@"
+ retval=$?
+ set +e
+ [[ $shopts != $(shopt) ]] &&
+ eqawarn "QA Notice: Global shell options changed and were not restored while calling '$*'"
+ [[ "$IFS" != "$OLDIFS" ]] &&
+ eqawarn "QA Notice: Global IFS changed and was not restored while calling '$*'"
+ return $retval
+}
+
+EBUILD_SH_ARGS="$*"
+
+shift $#
+
+# Prevent aliases from causing portage to act inappropriately.
+# Make sure it's before everything so we don't mess aliases that follow.
+unalias -a
+
+# Unset some variables that break things.
+unset GZIP BZIP BZIP2 CDPATH GREP_OPTIONS GREP_COLOR GLOBIGNORE
+
+source "${PORTAGE_BIN_PATH}/isolated-functions.sh" &>/dev/null
+
+[[ $PORTAGE_QUIET != "" ]] && export PORTAGE_QUIET
+
+# sandbox support functions; defined prior to profile.bashrc srcing, since the profile might need to add a default exception (/usr/lib64/conftest fex)
+_sb_append_var() {
+ local _v=$1 ; shift
+ local var="SANDBOX_${_v}"
+ [[ -z $1 || -n $2 ]] && die "Usage: add$(echo ${_v} | \
+ LC_ALL=C tr [:upper:] [:lower:]) <colon-delimited list of paths>"
+ export ${var}="${!var:+${!var}:}$1"
+}
+# bash-4 version:
+# local var="SANDBOX_${1^^}"
+# addread() { _sb_append_var ${0#add} "$@" ; }
+addread() { _sb_append_var READ "$@" ; }
+addwrite() { _sb_append_var WRITE "$@" ; }
+adddeny() { _sb_append_var DENY "$@" ; }
+addpredict() { _sb_append_var PREDICT "$@" ; }
+
+addwrite "${PORTAGE_TMPDIR}"
+addread "/:${PORTAGE_TMPDIR}"
+[[ -n ${PORTAGE_GPG_DIR} ]] && addpredict "${PORTAGE_GPG_DIR}"
+
+# Avoid sandbox violations in temporary directories.
+if [[ -w $T ]] ; then
+ export TEMP=$T
+ export TMP=$T
+ export TMPDIR=$T
+elif [[ $SANDBOX_ON = 1 ]] ; then
+ for x in TEMP TMP TMPDIR ; do
+ [[ -n ${!x} ]] && addwrite "${!x}"
+ done
+ unset x
+fi
+
+# the sandbox is disabled by default except when overridden in the relevant stages
+export SANDBOX_ON=0
+
+lchown() {
+ chown -h "$@"
+}
+
+lchgrp() {
+ chgrp -h "$@"
+}
+
+esyslog() {
+ # Custom version of esyslog() to take care of the "Red Star" bug.
+ # MUST follow functions.sh to override the "" parameter problem.
+ return 0
+}
+
+useq() {
+ has $EBUILD_PHASE prerm postrm || eqawarn \
+ "QA Notice: The 'useq' function is deprecated (replaced by 'use')"
+ use ${1}
+}
+
+usev() {
+ if use ${1}; then
+ echo "${1#!}"
+ return 0
+ fi
+ return 1
+}
+
+use() {
+ local u=$1
+ local found=0
+
+ # if we got something like '!flag', then invert the return value
+ if [[ ${u:0:1} == "!" ]] ; then
+ u=${u:1}
+ found=1
+ fi
+
+ if [[ $EBUILD_PHASE = depend ]] ; then
+ # TODO: Add a registration interface for eclasses to register
+ # any number of phase hooks, so that global scope eclass
+ # initialization can by migrated to phase hooks in new EAPIs.
+ # Example: add_phase_hook before pkg_setup $ECLASS_pre_pkg_setup
+ #if [[ -n $EAPI ]] && ! has "$EAPI" 0 1 2 3 ; then
+ # die "use() called during invalid phase: $EBUILD_PHASE"
+ #fi
+ true
+
+ # Make sure we have this USE flag in IUSE
+ elif [[ -n $PORTAGE_IUSE && -n $EBUILD_PHASE ]] ; then
+ [[ $u =~ $PORTAGE_IUSE ]] || \
+ eqawarn "QA Notice: USE Flag '${u}' not" \
+ "in IUSE for ${CATEGORY}/${PF}"
+ fi
+
+ if has ${u} ${USE} ; then
+ return ${found}
+ else
+ return $((!found))
+ fi
+}
+
+# Return true if given package is installed. Otherwise return false.
+# Takes single depend-type atoms.
+has_version() {
+ if [ "${EBUILD_PHASE}" == "depend" ]; then
+ die "portageq calls (has_version calls portageq) are not allowed in the global scope"
+ fi
+
+ if [[ -n $PORTAGE_IPC_DAEMON ]] ; then
+ "$PORTAGE_BIN_PATH"/ebuild-ipc has_version "$ROOT" "$1"
+ else
+ PYTHONPATH=${PORTAGE_PYM_PATH}${PYTHONPATH:+:}${PYTHONPATH} \
+ "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}/portageq" has_version "${ROOT}" "$1"
+ fi
+ local retval=$?
+ case "${retval}" in
+ 0|1)
+ return ${retval}
+ ;;
+ *)
+ die "unexpected portageq exit code: ${retval}"
+ ;;
+ esac
+}
+
+portageq() {
+ if [ "${EBUILD_PHASE}" == "depend" ]; then
+ die "portageq calls are not allowed in the global scope"
+ fi
+
+ PYTHONPATH=${PORTAGE_PYM_PATH}${PYTHONPATH:+:}${PYTHONPATH} \
+ "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}/portageq" "$@"
+}
+
+
+# ----------------------------------------------------------------------------
+# ----------------------------------------------------------------------------
+# ----------------------------------------------------------------------------
+
+
+# Returns the best/most-current match.
+# Takes single depend-type atoms.
+best_version() {
+ if [ "${EBUILD_PHASE}" == "depend" ]; then
+ die "portageq calls (best_version calls portageq) are not allowed in the global scope"
+ fi
+
+ if [[ -n $PORTAGE_IPC_DAEMON ]] ; then
+ "$PORTAGE_BIN_PATH"/ebuild-ipc best_version "$ROOT" "$1"
+ else
+ PYTHONPATH=${PORTAGE_PYM_PATH}${PYTHONPATH:+:}${PYTHONPATH} \
+ "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}/portageq" 'best_version' "${ROOT}" "$1"
+ fi
+ local retval=$?
+ case "${retval}" in
+ 0|1)
+ return ${retval}
+ ;;
+ *)
+ die "unexpected portageq exit code: ${retval}"
+ ;;
+ esac
+}
+
+use_with() {
+ if [ -z "$1" ]; then
+ echo "!!! use_with() called without a parameter." >&2
+ echo "!!! use_with <USEFLAG> [<flagname> [value]]" >&2
+ return 1
+ fi
+
+ if ! has "${EAPI:-0}" 0 1 2 3 ; then
+ local UW_SUFFIX=${3+=$3}
+ else
+ local UW_SUFFIX=${3:+=$3}
+ fi
+ local UWORD=${2:-$1}
+
+ if use $1; then
+ echo "--with-${UWORD}${UW_SUFFIX}"
+ else
+ echo "--without-${UWORD}"
+ fi
+ return 0
+}
+
+use_enable() {
+ if [ -z "$1" ]; then
+ echo "!!! use_enable() called without a parameter." >&2
+ echo "!!! use_enable <USEFLAG> [<flagname> [value]]" >&2
+ return 1
+ fi
+
+ if ! has "${EAPI:-0}" 0 1 2 3 ; then
+ local UE_SUFFIX=${3+=$3}
+ else
+ local UE_SUFFIX=${3:+=$3}
+ fi
+ local UWORD=${2:-$1}
+
+ if use $1; then
+ echo "--enable-${UWORD}${UE_SUFFIX}"
+ else
+ echo "--disable-${UWORD}"
+ fi
+ return 0
+}
+
+register_die_hook() {
+ local x
+ for x in $* ; do
+ has $x $EBUILD_DEATH_HOOKS || \
+ export EBUILD_DEATH_HOOKS="$EBUILD_DEATH_HOOKS $x"
+ done
+}
+
+register_success_hook() {
+ local x
+ for x in $* ; do
+ has $x $EBUILD_SUCCESS_HOOKS || \
+ export EBUILD_SUCCESS_HOOKS="$EBUILD_SUCCESS_HOOKS $x"
+ done
+}
+
+# Ensure that $PWD is sane whenever possible, to protect against
+# exploitation of insecure search path for python -c in ebuilds.
+# See bug #239560.
+if ! has "$EBUILD_PHASE" clean cleanrm depend help ; then
+ cd "$PORTAGE_BUILDDIR" || \
+ die "PORTAGE_BUILDDIR does not exist: '$PORTAGE_BUILDDIR'"
+fi
+
+#if no perms are specified, dirs/files will have decent defaults
+#(not secretive, but not stupid)
+umask 022
+export DESTTREE=/usr
+export INSDESTTREE=""
+export _E_EXEDESTTREE_=""
+export _E_DOCDESTTREE_=""
+export INSOPTIONS="-m0644"
+export EXEOPTIONS="-m0755"
+export LIBOPTIONS="-m0644"
+export DIROPTIONS="-m0755"
+export MOPREFIX=${PN}
+declare -a PORTAGE_DOCOMPRESS=( /usr/share/{doc,info,man} )
+declare -a PORTAGE_DOCOMPRESS_SKIP=( /usr/share/doc/${PF}/html )
+
+# adds ".keep" files so that dirs aren't auto-cleaned
+keepdir() {
+ dodir "$@"
+ local x
+ if [ "$1" == "-R" ] || [ "$1" == "-r" ]; then
+ shift
+ find "$@" -type d -printf "${D}%p/.keep_${CATEGORY}_${PN}-${SLOT}\n" \
+ | tr "\n" "\0" | \
+ while read -r -d $'\0' ; do
+ >> "$REPLY" || \
+ die "Failed to recursively create .keep files"
+ done
+ else
+ for x in "$@"; do
+ >> "${D}${x}/.keep_${CATEGORY}_${PN}-${SLOT}" || \
+ die "Failed to create .keep in ${D}${x}"
+ done
+ fi
+}
+
+unpack() {
+ local srcdir
+ local x
+ local y
+ local myfail
+ local eapi=${EAPI:-0}
+ [ -z "$*" ] && die "Nothing passed to the 'unpack' command"
+
+ for x in "$@"; do
+ vecho ">>> Unpacking ${x} to ${PWD}"
+ y=${x%.*}
+ y=${y##*.}
+
+ if [[ ${x} == "./"* ]] ; then
+ srcdir=""
+ elif [[ ${x} == ${DISTDIR%/}/* ]] ; then
+ die "Arguments to unpack() cannot begin with \${DISTDIR}."
+ elif [[ ${x} == "/"* ]] ; then
+ die "Arguments to unpack() cannot be absolute"
+ else
+ srcdir="${DISTDIR}/"
+ fi
+ [[ ! -s ${srcdir}${x} ]] && die "${x} does not exist"
+
+ _unpack_tar() {
+ if [ "${y}" == "tar" ]; then
+ $1 -c -- "$srcdir$x" | tar xof -
+ assert_sigpipe_ok "$myfail"
+ else
+ local cwd_dest=${x##*/}
+ cwd_dest=${cwd_dest%.*}
+ $1 -c -- "${srcdir}${x}" > "${cwd_dest}" || die "$myfail"
+ fi
+ }
+
+ myfail="failure unpacking ${x}"
+ case "${x##*.}" in
+ tar)
+ tar xof "$srcdir$x" || die "$myfail"
+ ;;
+ tgz)
+ tar xozf "$srcdir$x" || die "$myfail"
+ ;;
+ tbz|tbz2)
+ ${PORTAGE_BUNZIP2_COMMAND:-${PORTAGE_BZIP2_COMMAND} -d} -c -- "$srcdir$x" | tar xof -
+ assert_sigpipe_ok "$myfail"
+ ;;
+ ZIP|zip|jar)
+ # unzip will interactively prompt under some error conditions,
+ # as reported in bug #336285
+ ( while true ; do echo n || break ; done ) | \
+ unzip -qo "${srcdir}${x}" || die "$myfail"
+ ;;
+ gz|Z|z)
+ _unpack_tar "gzip -d"
+ ;;
+ bz2|bz)
+ _unpack_tar "${PORTAGE_BUNZIP2_COMMAND:-${PORTAGE_BZIP2_COMMAND} -d}"
+ ;;
+ 7Z|7z)
+ local my_output
+ my_output="$(7z x -y "${srcdir}${x}")"
+ if [ $? -ne 0 ]; then
+ echo "${my_output}" >&2
+ die "$myfail"
+ fi
+ ;;
+ RAR|rar)
+ unrar x -idq -o+ "${srcdir}${x}" || die "$myfail"
+ ;;
+ LHa|LHA|lha|lzh)
+ lha xfq "${srcdir}${x}" || die "$myfail"
+ ;;
+ a)
+ ar x "${srcdir}${x}" || die "$myfail"
+ ;;
+ deb)
+ # Unpacking .deb archives can not always be done with
+ # `ar`. For instance on AIX this doesn't work out. If
+ # we have `deb2targz` installed, prefer it over `ar` for
+ # that reason. We just make sure on AIX `deb2targz` is
+ # installed.
+ if type -P deb2targz > /dev/null; then
+ y=${x##*/}
+ local created_symlink=0
+ if [ ! "$srcdir$x" -ef "$y" ] ; then
+ # deb2targz always extracts into the same directory as
+ # the source file, so create a symlink in the current
+ # working directory if necessary.
+ ln -sf "$srcdir$x" "$y" || die "$myfail"
+ created_symlink=1
+ fi
+ deb2targz "$y" || die "$myfail"
+ if [ $created_symlink = 1 ] ; then
+ # Clean up the symlink so the ebuild
+ # doesn't inadvertently install it.
+ rm -f "$y"
+ fi
+ mv -f "${y%.deb}".tar.gz data.tar.gz || die "$myfail"
+ else
+ ar x "$srcdir$x" || die "$myfail"
+ fi
+ ;;
+ lzma)
+ _unpack_tar "lzma -d"
+ ;;
+ xz)
+ if has $eapi 0 1 2 ; then
+ vecho "unpack ${x}: file format not recognized. Ignoring."
+ else
+ _unpack_tar "xz -d"
+ fi
+ ;;
+ *)
+ vecho "unpack ${x}: file format not recognized. Ignoring."
+ ;;
+ esac
+ done
+ # Do not chmod '.' since it's probably ${WORKDIR} and PORTAGE_WORKDIR_MODE
+ # should be preserved.
+ find . -mindepth 1 -maxdepth 1 ! -type l -print0 | \
+ ${XARGS} -0 chmod -fR a+rX,u+w,g-w,o-w
+}
+
+strip_duplicate_slashes() {
+ if [[ -n $1 ]] ; then
+ local removed=$1
+ while [[ ${removed} == *//* ]] ; do
+ removed=${removed//\/\///}
+ done
+ echo ${removed}
+ fi
+}
+
+hasg() {
+ local x s=$1
+ shift
+ for x ; do [[ ${x} == ${s} ]] && echo "${x}" && return 0 ; done
+ return 1
+}
+hasgq() { hasg "$@" >/dev/null ; }
+econf() {
+ local x
+
+ local phase_func=$(_ebuild_arg_to_phase "$EAPI" "$EBUILD_PHASE")
+ if [[ -n $phase_func ]] ; then
+ if has "$EAPI" 0 1 ; then
+ [[ $phase_func != src_compile ]] && \
+ eqawarn "QA Notice: econf called in" \
+ "$phase_func instead of src_compile"
+ else
+ [[ $phase_func != src_configure ]] && \
+ eqawarn "QA Notice: econf called in" \
+ "$phase_func instead of src_configure"
+ fi
+ fi
+
+ : ${ECONF_SOURCE:=.}
+ if [ -x "${ECONF_SOURCE}/configure" ]; then
+ if [[ -n $CONFIG_SHELL && \
+ "$(head -n1 "$ECONF_SOURCE/configure")" =~ ^'#!'[[:space:]]*/bin/sh([[:space:]]|$) ]] ; then
+ sed -e "1s:^#![[:space:]]*/bin/sh:#!$CONFIG_SHELL:" -i "$ECONF_SOURCE/configure" || \
+ die "Substition of shebang in '$ECONF_SOURCE/configure' failed"
+ fi
+ if [ -e /usr/share/gnuconfig/ ]; then
+ find "${WORKDIR}" -type f '(' \
+ -name config.guess -o -name config.sub ')' -print0 | \
+ while read -r -d $'\0' x ; do
+ vecho " * econf: updating ${x/${WORKDIR}\/} with /usr/share/gnuconfig/${x##*/}"
+ cp -f /usr/share/gnuconfig/"${x##*/}" "${x}"
+ done
+ fi
+
+ # EAPI=4 adds --disable-dependency-tracking to econf
+ if ! has "$EAPI" 0 1 2 3 3_pre2 && \
+ "${ECONF_SOURCE}/configure" --help 2>/dev/null | \
+ grep -q disable-dependency-tracking ; then
+ set -- --disable-dependency-tracking "$@"
+ fi
+
+ # if the profile defines a location to install libs to aside from default, pass it on.
+ # if the ebuild passes in --libdir, they're responsible for the conf_libdir fun.
+ local CONF_LIBDIR LIBDIR_VAR="LIBDIR_${ABI}"
+ if [[ -n ${ABI} && -n ${!LIBDIR_VAR} ]] ; then
+ CONF_LIBDIR=${!LIBDIR_VAR}
+ fi
+ if [[ -n ${CONF_LIBDIR} ]] && ! hasgq --libdir=\* "$@" ; then
+ export CONF_PREFIX=$(hasg --exec-prefix=\* "$@")
+ [[ -z ${CONF_PREFIX} ]] && CONF_PREFIX=$(hasg --prefix=\* "$@")
+ : ${CONF_PREFIX:=/usr}
+ CONF_PREFIX=${CONF_PREFIX#*=}
+ [[ ${CONF_PREFIX} != /* ]] && CONF_PREFIX="/${CONF_PREFIX}"
+ [[ ${CONF_LIBDIR} != /* ]] && CONF_LIBDIR="/${CONF_LIBDIR}"
+ set -- --libdir="$(strip_duplicate_slashes ${CONF_PREFIX}${CONF_LIBDIR})" "$@"
+ fi
+
+ set -- \
+ --prefix=/usr \
+ ${CBUILD:+--build=${CBUILD}} \
+ --host=${CHOST} \
+ ${CTARGET:+--target=${CTARGET}} \
+ --mandir=/usr/share/man \
+ --infodir=/usr/share/info \
+ --datadir=/usr/share \
+ --sysconfdir=/etc \
+ --localstatedir=/var/lib \
+ "$@" \
+ ${EXTRA_ECONF}
+ vecho "${ECONF_SOURCE}/configure" "$@"
+
+ if ! "${ECONF_SOURCE}/configure" "$@" ; then
+
+ if [ -s config.log ]; then
+ echo
+ echo "!!! Please attach the following file when seeking support:"
+ echo "!!! ${PWD}/config.log"
+ fi
+ die "econf failed"
+ fi
+ elif [ -f "${ECONF_SOURCE}/configure" ]; then
+ die "configure is not executable"
+ else
+ die "no configure script found"
+ fi
+}
+
+einstall() {
+ # CONF_PREFIX is only set if they didn't pass in libdir above.
+ local LOCAL_EXTRA_EINSTALL="${EXTRA_EINSTALL}"
+ LIBDIR_VAR="LIBDIR_${ABI}"
+ if [ -n "${ABI}" -a -n "${!LIBDIR_VAR}" ]; then
+ CONF_LIBDIR="${!LIBDIR_VAR}"
+ fi
+ unset LIBDIR_VAR
+ if [ -n "${CONF_LIBDIR}" ] && [ "${CONF_PREFIX:+set}" = set ]; then
+ EI_DESTLIBDIR="${D}/${CONF_PREFIX}/${CONF_LIBDIR}"
+ EI_DESTLIBDIR="$(strip_duplicate_slashes ${EI_DESTLIBDIR})"
+ LOCAL_EXTRA_EINSTALL="libdir=${EI_DESTLIBDIR} ${LOCAL_EXTRA_EINSTALL}"
+ unset EI_DESTLIBDIR
+ fi
+
+ if [ -f ./[mM]akefile -o -f ./GNUmakefile ] ; then
+ if [ "${PORTAGE_DEBUG}" == "1" ]; then
+ ${MAKE:-make} -n prefix="${D}usr" \
+ datadir="${D}usr/share" \
+ infodir="${D}usr/share/info" \
+ localstatedir="${D}var/lib" \
+ mandir="${D}usr/share/man" \
+ sysconfdir="${D}etc" \
+ ${LOCAL_EXTRA_EINSTALL} \
+ ${MAKEOPTS} ${EXTRA_EMAKE} -j1 \
+ "$@" install
+ fi
+ ${MAKE:-make} prefix="${D}usr" \
+ datadir="${D}usr/share" \
+ infodir="${D}usr/share/info" \
+ localstatedir="${D}var/lib" \
+ mandir="${D}usr/share/man" \
+ sysconfdir="${D}etc" \
+ ${LOCAL_EXTRA_EINSTALL} \
+ ${MAKEOPTS} ${EXTRA_EMAKE} -j1 \
+ "$@" install || die "einstall failed"
+ else
+ die "no Makefile found"
+ fi
+}
+
+_eapi0_pkg_nofetch() {
+ [ -z "${SRC_URI}" ] && return
+
+ elog "The following are listed in SRC_URI for ${PN}:"
+ local x
+ for x in $(echo ${SRC_URI}); do
+ elog " ${x}"
+ done
+}
+
+_eapi0_src_unpack() {
+ [[ -n ${A} ]] && unpack ${A}
+}
+
+_eapi0_src_compile() {
+ if [ -x ./configure ] ; then
+ econf
+ fi
+ _eapi2_src_compile
+}
+
+_eapi0_src_test() {
+ # Since we don't want emake's automatic die
+ # support (EAPI 4 and later), and we also don't
+ # want the warning messages that it produces if
+ # we call it in 'nonfatal' mode, we use emake_cmd
+ # to emulate the desired parts of emake behavior.
+ local emake_cmd="${MAKE:-make} ${MAKEOPTS} ${EXTRA_EMAKE}"
+ if $emake_cmd -j1 check -n &> /dev/null; then
+ vecho ">>> Test phase [check]: ${CATEGORY}/${PF}"
+ if ! $emake_cmd -j1 check; then
+ has test $FEATURES && die "Make check failed. See above for details."
+ has test $FEATURES || eerror "Make check failed. See above for details."
+ fi
+ elif $emake_cmd -j1 test -n &> /dev/null; then
+ vecho ">>> Test phase [test]: ${CATEGORY}/${PF}"
+ if ! $emake_cmd -j1 test; then
+ has test $FEATURES && die "Make test failed. See above for details."
+ has test $FEATURES || eerror "Make test failed. See above for details."
+ fi
+ else
+ vecho ">>> Test phase [none]: ${CATEGORY}/${PF}"
+ fi
+}
+
+_eapi1_src_compile() {
+ _eapi2_src_configure
+ _eapi2_src_compile
+}
+
+_eapi2_src_configure() {
+ if [[ -x ${ECONF_SOURCE:-.}/configure ]] ; then
+ econf
+ fi
+}
+
+_eapi2_src_compile() {
+ if [ -f Makefile ] || [ -f GNUmakefile ] || [ -f makefile ]; then
+ emake || die "emake failed"
+ fi
+}
+
+_eapi4_src_install() {
+ if [[ -f Makefile || -f GNUmakefile || -f makefile ]] ; then
+ emake DESTDIR="${D}" install
+ fi
+
+ if ! declare -p DOCS &>/dev/null ; then
+ local d
+ for d in README* ChangeLog AUTHORS NEWS TODO CHANGES \
+ THANKS BUGS FAQ CREDITS CHANGELOG ; do
+ [[ -s "${d}" ]] && dodoc "${d}"
+ done
+ elif [[ $(declare -p DOCS) == "declare -a "* ]] ; then
+ dodoc "${DOCS[@]}"
+ else
+ dodoc ${DOCS}
+ fi
+}
+
+ebuild_phase() {
+ declare -F "$1" >/dev/null && qa_call $1
+}
+
+ebuild_phase_with_hooks() {
+ local x phase_name=${1}
+ for x in {pre_,,post_}${phase_name} ; do
+ ebuild_phase ${x}
+ done
+}
+
+dyn_pretend() {
+ if [[ -e $PORTAGE_BUILDDIR/.pretended ]] ; then
+ vecho ">>> It appears that '$PF' is already pretended; skipping."
+ vecho ">>> Remove '$PORTAGE_BUILDDIR/.pretended' to force pretend."
+ return 0
+ fi
+ ebuild_phase pre_pkg_pretend
+ ebuild_phase pkg_pretend
+ >> "$PORTAGE_BUILDDIR/.pretended" || \
+ die "Failed to create $PORTAGE_BUILDDIR/.pretended"
+ ebuild_phase post_pkg_pretend
+}
+
+dyn_setup() {
+ if [[ -e $PORTAGE_BUILDDIR/.setuped ]] ; then
+ vecho ">>> It appears that '$PF' is already setup; skipping."
+ vecho ">>> Remove '$PORTAGE_BUILDDIR/.setuped' to force setup."
+ return 0
+ fi
+ ebuild_phase pre_pkg_setup
+ ebuild_phase pkg_setup
+ >> "$PORTAGE_BUILDDIR/.setuped" || \
+ die "Failed to create $PORTAGE_BUILDDIR/.setuped"
+ ebuild_phase post_pkg_setup
+}
+
+dyn_unpack() {
+ local newstuff="no"
+ if [ -e "${WORKDIR}" ]; then
+ local x
+ local checkme
+ for x in $A ; do
+ vecho ">>> Checking ${x}'s mtime..."
+ if [ "${PORTAGE_ACTUAL_DISTDIR:-${DISTDIR}}/${x}" -nt "${WORKDIR}" ]; then
+ vecho ">>> ${x} has been updated; recreating WORKDIR..."
+ newstuff="yes"
+ break
+ fi
+ done
+ if [ ! -f "${PORTAGE_BUILDDIR}/.unpacked" ] ; then
+ vecho ">>> Not marked as unpacked; recreating WORKDIR..."
+ newstuff="yes"
+ fi
+ fi
+ if [ "${newstuff}" == "yes" ]; then
+ # We don't necessarily have privileges to do a full dyn_clean here.
+ rm -rf "${PORTAGE_BUILDDIR}"/{.setuped,.unpacked,.prepared,.configured,.compiled,.tested,.installed,.packaged,build-info}
+ if ! has keepwork $FEATURES ; then
+ rm -rf "${WORKDIR}"
+ fi
+ if [ -d "${T}" ] && \
+ ! has keeptemp $FEATURES ; then
+ rm -rf "${T}" && mkdir "${T}"
+ fi
+ fi
+ if [ -e "${WORKDIR}" ]; then
+ if [ "$newstuff" == "no" ]; then
+ vecho ">>> WORKDIR is up-to-date, keeping..."
+ return 0
+ fi
+ fi
+
+ if [ ! -d "${WORKDIR}" ]; then
+ install -m${PORTAGE_WORKDIR_MODE:-0700} -d "${WORKDIR}" || die "Failed to create dir '${WORKDIR}'"
+ fi
+ cd "${WORKDIR}" || die "Directory change failed: \`cd '${WORKDIR}'\`"
+ ebuild_phase pre_src_unpack
+ vecho ">>> Unpacking source..."
+ ebuild_phase src_unpack
+ >> "$PORTAGE_BUILDDIR/.unpacked" || \
+ die "Failed to create $PORTAGE_BUILDDIR/.unpacked"
+ vecho ">>> Source unpacked in ${WORKDIR}"
+ ebuild_phase post_src_unpack
+}
+
+dyn_clean() {
+ if [ -z "${PORTAGE_BUILDDIR}" ]; then
+ echo "Aborting clean phase because PORTAGE_BUILDDIR is unset!"
+ return 1
+ elif [ ! -d "${PORTAGE_BUILDDIR}" ] ; then
+ return 0
+ fi
+ if has chflags $FEATURES ; then
+ chflags -R noschg,nouchg,nosappnd,nouappnd "${PORTAGE_BUILDDIR}"
+ chflags -R nosunlnk,nouunlnk "${PORTAGE_BUILDDIR}" 2>/dev/null
+ fi
+
+ rm -rf "${PORTAGE_BUILDDIR}/image" "${PORTAGE_BUILDDIR}/homedir"
+ rm -f "${PORTAGE_BUILDDIR}/.installed"
+
+ if [[ $EMERGE_FROM = binary ]] || \
+ ! has keeptemp $FEATURES && ! has keepwork $FEATURES ; then
+ rm -rf "${T}"
+ fi
+
+ if [[ $EMERGE_FROM = binary ]] || ! has keepwork $FEATURES; then
+ rm -f "$PORTAGE_BUILDDIR"/.{ebuild_changed,logid,pretended,setuped,unpacked,prepared} \
+ "$PORTAGE_BUILDDIR"/.{configured,compiled,tested,packaged} \
+ "$PORTAGE_BUILDDIR"/.die_hooks \
+ "$PORTAGE_BUILDDIR"/.ipc_{in,out,lock} \
+ "$PORTAGE_BUILDDIR"/.exit_status
+
+ rm -rf "${PORTAGE_BUILDDIR}/build-info"
+ rm -rf "${WORKDIR}"
+ fi
+
+ if [ -f "${PORTAGE_BUILDDIR}/.unpacked" ]; then
+ find "${PORTAGE_BUILDDIR}" -type d ! -regex "^${WORKDIR}" | sort -r | tr "\n" "\0" | $XARGS -0 rmdir &>/dev/null
+ fi
+
+ # do not bind this to doebuild defined DISTDIR; don't trust doebuild, and if mistakes are made it'll
+ # result in it wiping the users distfiles directory (bad).
+ rm -rf "${PORTAGE_BUILDDIR}/distdir"
+
+ # Some kernels, such as Solaris, return EINVAL when an attempt
+ # is made to remove the current working directory.
+ cd "$PORTAGE_BUILDDIR"/../..
+ rmdir "$PORTAGE_BUILDDIR" 2>/dev/null
+
+ true
+}
+
+into() {
+ if [ "$1" == "/" ]; then
+ export DESTTREE=""
+ else
+ export DESTTREE=$1
+ if [ ! -d "${D}${DESTTREE}" ]; then
+ install -d "${D}${DESTTREE}"
+ local ret=$?
+ if [[ $ret -ne 0 ]] ; then
+ helpers_die "${FUNCNAME[0]} failed"
+ return $ret
+ fi
+ fi
+ fi
+}
+
+insinto() {
+ if [ "$1" == "/" ]; then
+ export INSDESTTREE=""
+ else
+ export INSDESTTREE=$1
+ if [ ! -d "${D}${INSDESTTREE}" ]; then
+ install -d "${D}${INSDESTTREE}"
+ local ret=$?
+ if [[ $ret -ne 0 ]] ; then
+ helpers_die "${FUNCNAME[0]} failed"
+ return $ret
+ fi
+ fi
+ fi
+}
+
+exeinto() {
+ if [ "$1" == "/" ]; then
+ export _E_EXEDESTTREE_=""
+ else
+ export _E_EXEDESTTREE_="$1"
+ if [ ! -d "${D}${_E_EXEDESTTREE_}" ]; then
+ install -d "${D}${_E_EXEDESTTREE_}"
+ local ret=$?
+ if [[ $ret -ne 0 ]] ; then
+ helpers_die "${FUNCNAME[0]} failed"
+ return $ret
+ fi
+ fi
+ fi
+}
+
+docinto() {
+ if [ "$1" == "/" ]; then
+ export _E_DOCDESTTREE_=""
+ else
+ export _E_DOCDESTTREE_="$1"
+ if [ ! -d "${D}usr/share/doc/${PF}/${_E_DOCDESTTREE_}" ]; then
+ install -d "${D}usr/share/doc/${PF}/${_E_DOCDESTTREE_}"
+ local ret=$?
+ if [[ $ret -ne 0 ]] ; then
+ helpers_die "${FUNCNAME[0]} failed"
+ return $ret
+ fi
+ fi
+ fi
+}
+
+insopts() {
+ export INSOPTIONS="$@"
+
+ # `install` should never be called with '-s' ...
+ has -s ${INSOPTIONS} && die "Never call insopts() with -s"
+}
+
+diropts() {
+ export DIROPTIONS="$@"
+}
+
+exeopts() {
+ export EXEOPTIONS="$@"
+
+ # `install` should never be called with '-s' ...
+ has -s ${EXEOPTIONS} && die "Never call exeopts() with -s"
+}
+
+libopts() {
+ export LIBOPTIONS="$@"
+
+ # `install` should never be called with '-s' ...
+ has -s ${LIBOPTIONS} && die "Never call libopts() with -s"
+}
+
+docompress() {
+ has "${EAPI}" 0 1 2 3 && die "'docompress' not supported in this EAPI"
+
+ local f g
+ if [[ $1 = "-x" ]]; then
+ shift
+ for f; do
+ f=$(strip_duplicate_slashes "${f}"); f=${f%/}
+ [[ ${f:0:1} = / ]] || f="/${f}"
+ for g in "${PORTAGE_DOCOMPRESS_SKIP[@]}"; do
+ [[ ${f} = "${g}" ]] && continue 2
+ done
+ PORTAGE_DOCOMPRESS_SKIP[${#PORTAGE_DOCOMPRESS_SKIP[@]}]=${f}
+ done
+ else
+ for f; do
+ f=$(strip_duplicate_slashes "${f}"); f=${f%/}
+ [[ ${f:0:1} = / ]] || f="/${f}"
+ for g in "${PORTAGE_DOCOMPRESS[@]}"; do
+ [[ ${f} = "${g}" ]] && continue 2
+ done
+ PORTAGE_DOCOMPRESS[${#PORTAGE_DOCOMPRESS[@]}]=${f}
+ done
+ fi
+}
+
+abort_handler() {
+ local msg
+ if [ "$2" != "fail" ]; then
+ msg="${EBUILD}: ${1} aborted; exiting."
+ else
+ msg="${EBUILD}: ${1} failed; exiting."
+ fi
+ echo
+ echo "$msg"
+ echo
+ eval ${3}
+ #unset signal handler
+ trap - SIGINT SIGQUIT
+}
+
+abort_prepare() {
+ abort_handler src_prepare $1
+ rm -f "$PORTAGE_BUILDDIR/.prepared"
+ exit 1
+}
+
+abort_configure() {
+ abort_handler src_configure $1
+ rm -f "$PORTAGE_BUILDDIR/.configured"
+ exit 1
+}
+
+abort_compile() {
+ abort_handler "src_compile" $1
+ rm -f "${PORTAGE_BUILDDIR}/.compiled"
+ exit 1
+}
+
+abort_test() {
+ abort_handler "dyn_test" $1
+ rm -f "${PORTAGE_BUILDDIR}/.tested"
+ exit 1
+}
+
+abort_install() {
+ abort_handler "src_install" $1
+ rm -rf "${PORTAGE_BUILDDIR}/image"
+ exit 1
+}
+
+has_phase_defined_up_to() {
+ local phase
+ for phase in unpack prepare configure compile install; do
+ has ${phase} ${DEFINED_PHASES} && return 0
+ [[ ${phase} == $1 ]] && return 1
+ done
+ # We shouldn't actually get here
+ return 1
+}
+
+dyn_prepare() {
+
+ if [[ -e $PORTAGE_BUILDDIR/.prepared ]] ; then
+ vecho ">>> It appears that '$PF' is already prepared; skipping."
+ vecho ">>> Remove '$PORTAGE_BUILDDIR/.prepared' to force prepare."
+ return 0
+ fi
+
+ if [[ -d $S ]] ; then
+ cd "${S}"
+ elif has $EAPI 0 1 2 3 3_pre2 ; then
+ cd "${WORKDIR}"
+ elif [[ -z ${A} ]] && ! has_phase_defined_up_to prepare; then
+ cd "${WORKDIR}"
+ else
+ die "The source directory '${S}' doesn't exist"
+ fi
+
+ trap abort_prepare SIGINT SIGQUIT
+
+ ebuild_phase pre_src_prepare
+ vecho ">>> Preparing source in $PWD ..."
+ ebuild_phase src_prepare
+ >> "$PORTAGE_BUILDDIR/.prepared" || \
+ die "Failed to create $PORTAGE_BUILDDIR/.prepared"
+ vecho ">>> Source prepared."
+ ebuild_phase post_src_prepare
+
+ trap - SIGINT SIGQUIT
+}
+
+dyn_configure() {
+
+ if [[ -e $PORTAGE_BUILDDIR/.configured ]] ; then
+ vecho ">>> It appears that '$PF' is already configured; skipping."
+ vecho ">>> Remove '$PORTAGE_BUILDDIR/.configured' to force configuration."
+ return 0
+ fi
+
+ if [[ -d $S ]] ; then
+ cd "${S}"
+ elif has $EAPI 0 1 2 3 3_pre2 ; then
+ cd "${WORKDIR}"
+ elif [[ -z ${A} ]] && ! has_phase_defined_up_to configure; then
+ cd "${WORKDIR}"
+ else
+ die "The source directory '${S}' doesn't exist"
+ fi
+
+ trap abort_configure SIGINT SIGQUIT
+
+ ebuild_phase pre_src_configure
+
+ vecho ">>> Configuring source in $PWD ..."
+ ebuild_phase src_configure
+ >> "$PORTAGE_BUILDDIR/.configured" || \
+ die "Failed to create $PORTAGE_BUILDDIR/.configured"
+ vecho ">>> Source configured."
+
+ ebuild_phase post_src_configure
+
+ trap - SIGINT SIGQUIT
+}
+
+dyn_compile() {
+
+ if [[ -e $PORTAGE_BUILDDIR/.compiled ]] ; then
+ vecho ">>> It appears that '${PF}' is already compiled; skipping."
+ vecho ">>> Remove '$PORTAGE_BUILDDIR/.compiled' to force compilation."
+ return 0
+ fi
+
+ if [[ -d $S ]] ; then
+ cd "${S}"
+ elif has $EAPI 0 1 2 3 3_pre2 ; then
+ cd "${WORKDIR}"
+ elif [[ -z ${A} ]] && ! has_phase_defined_up_to compile; then
+ cd "${WORKDIR}"
+ else
+ die "The source directory '${S}' doesn't exist"
+ fi
+
+ trap abort_compile SIGINT SIGQUIT
+
+ if has distcc $FEATURES && has distcc-pump $FEATURES ; then
+ if [[ -z $INCLUDE_SERVER_PORT ]] || [[ ! -w $INCLUDE_SERVER_PORT ]] ; then
+ eval $(pump --startup)
+ trap "pump --shutdown" EXIT
+ fi
+ fi
+
+ ebuild_phase pre_src_compile
+
+ vecho ">>> Compiling source in $PWD ..."
+ ebuild_phase src_compile
+ >> "$PORTAGE_BUILDDIR/.compiled" || \
+ die "Failed to create $PORTAGE_BUILDDIR/.compiled"
+ vecho ">>> Source compiled."
+
+ ebuild_phase post_src_compile
+
+ trap - SIGINT SIGQUIT
+}
+
+dyn_test() {
+
+ if [[ -e $PORTAGE_BUILDDIR/.tested ]] ; then
+ vecho ">>> It appears that ${PN} has already been tested; skipping."
+ vecho ">>> Remove '${PORTAGE_BUILDDIR}/.tested' to force test."
+ return
+ fi
+
+ if [ "${EBUILD_FORCE_TEST}" == "1" ] ; then
+ # If USE came from ${T}/environment then it might not have USE=test
+ # like it's supposed to here.
+ ! has test ${USE} && export USE="${USE} test"
+ fi
+
+ trap "abort_test" SIGINT SIGQUIT
+ if [ -d "${S}" ]; then
+ cd "${S}"
+ else
+ cd "${WORKDIR}"
+ fi
+
+ if ! has test $FEATURES && [ "${EBUILD_FORCE_TEST}" != "1" ]; then
+ vecho ">>> Test phase [not enabled]: ${CATEGORY}/${PF}"
+ elif has test $RESTRICT; then
+ einfo "Skipping make test/check due to ebuild restriction."
+ vecho ">>> Test phase [explicitly disabled]: ${CATEGORY}/${PF}"
+ else
+ local save_sp=${SANDBOX_PREDICT}
+ addpredict /
+ ebuild_phase pre_src_test
+ ebuild_phase src_test
+ >> "$PORTAGE_BUILDDIR/.tested" || \
+ die "Failed to create $PORTAGE_BUILDDIR/.tested"
+ ebuild_phase post_src_test
+ SANDBOX_PREDICT=${save_sp}
+ fi
+
+ trap - SIGINT SIGQUIT
+}
+
+dyn_install() {
+ [ -z "$PORTAGE_BUILDDIR" ] && die "${FUNCNAME}: PORTAGE_BUILDDIR is unset"
+ if has noauto $FEATURES ; then
+ rm -f "${PORTAGE_BUILDDIR}/.installed"
+ elif [[ -e $PORTAGE_BUILDDIR/.installed ]] ; then
+ vecho ">>> It appears that '${PF}' is already installed; skipping."
+ vecho ">>> Remove '${PORTAGE_BUILDDIR}/.installed' to force install."
+ return 0
+ fi
+ trap "abort_install" SIGINT SIGQUIT
+ ebuild_phase pre_src_install
+ rm -rf "${PORTAGE_BUILDDIR}/image"
+ mkdir "${PORTAGE_BUILDDIR}/image"
+ if [[ -d $S ]] ; then
+ cd "${S}"
+ elif has $EAPI 0 1 2 3 3_pre2 ; then
+ cd "${WORKDIR}"
+ elif [[ -z ${A} ]] && ! has_phase_defined_up_to install; then
+ cd "${WORKDIR}"
+ else
+ die "The source directory '${S}' doesn't exist"
+ fi
+
+ vecho
+ vecho ">>> Install ${PF} into ${D} category ${CATEGORY}"
+ #our custom version of libtool uses $S and $D to fix
+ #invalid paths in .la files
+ export S D
+
+ # Reset exeinto(), docinto(), insinto(), and into() state variables
+ # in case the user is running the install phase multiple times
+ # consecutively via the ebuild command.
+ export DESTTREE=/usr
+ export INSDESTTREE=""
+ export _E_EXEDESTTREE_=""
+ export _E_DOCDESTTREE_=""
+
+ ebuild_phase src_install
+ >> "$PORTAGE_BUILDDIR/.installed" || \
+ die "Failed to create $PORTAGE_BUILDDIR/.installed"
+ vecho ">>> Completed installing ${PF} into ${D}"
+ vecho
+ ebuild_phase post_src_install
+
+ cd "${PORTAGE_BUILDDIR}"/build-info
+ set -f
+ local f x
+ IFS=$' \t\n\r'
+ for f in CATEGORY DEFINED_PHASES FEATURES INHERITED IUSE REQUIRED_USE \
+ PF PKGUSE SLOT KEYWORDS HOMEPAGE DESCRIPTION ; do
+ x=$(echo -n ${!f})
+ [[ -n $x ]] && echo "$x" > $f
+ done
+ if [[ $CATEGORY != virtual ]] ; then
+ for f in ASFLAGS CBUILD CC CFLAGS CHOST CTARGET CXX \
+ CXXFLAGS EXTRA_ECONF EXTRA_EINSTALL EXTRA_MAKE \
+ LDFLAGS LIBCFLAGS LIBCXXFLAGS ; do
+ x=$(echo -n ${!f})
+ [[ -n $x ]] && echo "$x" > $f
+ done
+ fi
+ echo "${USE}" > USE
+ echo "${EAPI:-0}" > EAPI
+ set +f
+
+ # local variables can leak into the saved environment.
+ unset f
+
+ save_ebuild_env --exclude-init-phases | filter_readonly_variables \
+ --filter-path --filter-sandbox --allow-extra-vars > environment
+ assert "save_ebuild_env failed"
+
+ ${PORTAGE_BZIP2_COMMAND} -f9 environment
+
+ cp "${EBUILD}" "${PF}.ebuild"
+ [ -n "${PORTAGE_REPO_NAME}" ] && echo "${PORTAGE_REPO_NAME}" > repository
+ if has nostrip ${FEATURES} ${RESTRICT} || has strip ${RESTRICT}
+ then
+ >> DEBUGBUILD
+ fi
+ trap - SIGINT SIGQUIT
+}
+
+dyn_preinst() {
+ if [ -z "${D}" ]; then
+ eerror "${FUNCNAME}: D is unset"
+ return 1
+ fi
+ ebuild_phase_with_hooks pkg_preinst
+}
+
+dyn_help() {
+ echo
+ echo "Portage"
+ echo "Copyright 1999-2010 Gentoo Foundation"
+ echo
+ echo "How to use the ebuild command:"
+ echo
+ echo "The first argument to ebuild should be an existing .ebuild file."
+ echo
+ echo "One or more of the following options can then be specified. If more"
+ echo "than one option is specified, each will be executed in order."
+ echo
+ echo " help : show this help screen"
+ echo " pretend : execute package specific pretend actions"
+ echo " setup : execute package specific setup actions"
+ echo " fetch : download source archive(s) and patches"
+ echo " digest : create a manifest file for the package"
+ echo " manifest : create a manifest file for the package"
+ echo " unpack : unpack sources (auto-dependencies if needed)"
+ echo " prepare : prepare sources (auto-dependencies if needed)"
+ echo " configure : configure sources (auto-fetch/unpack if needed)"
+ echo " compile : compile sources (auto-fetch/unpack/configure if needed)"
+ echo " test : test package (auto-fetch/unpack/configure/compile if needed)"
+ echo " preinst : execute pre-install instructions"
+ echo " postinst : execute post-install instructions"
+ echo " install : install the package to the temporary install directory"
+ echo " qmerge : merge image into live filesystem, recording files in db"
+ echo " merge : do fetch, unpack, compile, install and qmerge"
+ echo " prerm : execute pre-removal instructions"
+ echo " postrm : execute post-removal instructions"
+ echo " unmerge : remove package from live filesystem"
+ echo " config : execute package specific configuration actions"
+ echo " package : create a tarball package in ${PKGDIR}/All"
+ echo " rpm : build a RedHat RPM package"
+ echo " clean : clean up all source and temporary files"
+ echo
+ echo "The following settings will be used for the ebuild process:"
+ echo
+ echo " package : ${PF}"
+ echo " slot : ${SLOT}"
+ echo " category : ${CATEGORY}"
+ echo " description : ${DESCRIPTION}"
+ echo " system : ${CHOST}"
+ echo " c flags : ${CFLAGS}"
+ echo " c++ flags : ${CXXFLAGS}"
+ echo " make flags : ${MAKEOPTS}"
+ echo -n " build mode : "
+ if has nostrip ${FEATURES} ${RESTRICT} || has strip ${RESTRICT} ;
+ then
+ echo "debug (large)"
+ else
+ echo "production (stripped)"
+ fi
+ echo " merge to : ${ROOT}"
+ echo
+ if [ -n "$USE" ]; then
+ echo "Additionally, support for the following optional features will be enabled:"
+ echo
+ echo " ${USE}"
+ fi
+ echo
+}
+
+# debug-print() gets called from many places with verbose status information useful
+# for tracking down problems. The output is in $T/eclass-debug.log.
+# You can set ECLASS_DEBUG_OUTPUT to redirect the output somewhere else as well.
+# The special "on" setting echoes the information, mixing it with the rest of the
+# emerge output.
+# You can override the setting by exporting a new one from the console, or you can
+# set a new default in make.*. Here the default is "" or unset.
+
+# in the future might use e* from /etc/init.d/functions.sh if i feel like it
+debug-print() {
+ # if $T isn't defined, we're in dep calculation mode and
+ # shouldn't do anything
+ [[ $EBUILD_PHASE = depend || ! -d ${T} || ${#} -eq 0 ]] && return 0
+
+ if [[ ${ECLASS_DEBUG_OUTPUT} == on ]]; then
+ printf 'debug: %s\n' "${@}" >&2
+ elif [[ -n ${ECLASS_DEBUG_OUTPUT} ]]; then
+ printf 'debug: %s\n' "${@}" >> "${ECLASS_DEBUG_OUTPUT}"
+ fi
+
+ if [[ -w $T ]] ; then
+ # default target
+ printf '%s\n' "${@}" >> "${T}/eclass-debug.log"
+ # let the portage user own/write to this file
+ chgrp portage "${T}/eclass-debug.log" &>/dev/null
+ chmod g+w "${T}/eclass-debug.log" &>/dev/null
+ fi
+}
+
+# The following 2 functions are debug-print() wrappers
+
+debug-print-function() {
+ debug-print "${1}: entering function, parameters: ${*:2}"
+}
+
+debug-print-section() {
+ debug-print "now in section ${*}"
+}
+
+# Sources all eclasses in parameters
+declare -ix ECLASS_DEPTH=0
+inherit() {
+ ECLASS_DEPTH=$(($ECLASS_DEPTH + 1))
+ if [[ ${ECLASS_DEPTH} > 1 ]]; then
+ debug-print "*** Multiple Inheritence (Level: ${ECLASS_DEPTH})"
+ fi
+
+ if [[ -n $ECLASS && -n ${!__export_funcs_var} ]] ; then
+ echo "QA Notice: EXPORT_FUNCTIONS is called before inherit in" \
+ "$ECLASS.eclass. For compatibility with <=portage-2.1.6.7," \
+ "only call EXPORT_FUNCTIONS after inherit(s)." \
+ | fmt -w 75 | while read -r ; do eqawarn "$REPLY" ; done
+ fi
+
+ local location
+ local olocation
+ local x
+
+ # These variables must be restored before returning.
+ local PECLASS=$ECLASS
+ local prev_export_funcs_var=$__export_funcs_var
+
+ local B_IUSE
+ local B_REQUIRED_USE
+ local B_DEPEND
+ local B_RDEPEND
+ local B_PDEPEND
+ while [ "$1" ]; do
+ location="${ECLASSDIR}/${1}.eclass"
+ olocation=""
+
+ export ECLASS="$1"
+ __export_funcs_var=__export_functions_$ECLASS_DEPTH
+ unset $__export_funcs_var
+
+ if [ "${EBUILD_PHASE}" != "depend" ] && \
+ [[ ${EBUILD_PHASE} != *rm ]] && \
+ [[ ${EMERGE_FROM} != "binary" ]] ; then
+ # This is disabled in the *rm phases because they frequently give
+ # false alarms due to INHERITED in /var/db/pkg being outdated
+ # in comparison the the eclasses from the portage tree.
+ if ! has $ECLASS $INHERITED $__INHERITED_QA_CACHE ; then
+ eqawarn "QA Notice: ECLASS '$ECLASS' inherited illegally in $CATEGORY/$PF $EBUILD_PHASE"
+ fi
+ fi
+
+ # any future resolution code goes here
+ if [ -n "$PORTDIR_OVERLAY" ]; then
+ local overlay
+ for overlay in ${PORTDIR_OVERLAY}; do
+ olocation="${overlay}/eclass/${1}.eclass"
+ if [ -e "$olocation" ]; then
+ location="${olocation}"
+ debug-print " eclass exists: ${location}"
+ fi
+ done
+ fi
+ debug-print "inherit: $1 -> $location"
+ [ ! -e "$location" ] && die "${1}.eclass could not be found by inherit()"
+
+ if [ "${location}" == "${olocation}" ] && \
+ ! has "${location}" ${EBUILD_OVERLAY_ECLASSES} ; then
+ EBUILD_OVERLAY_ECLASSES="${EBUILD_OVERLAY_ECLASSES} ${location}"
+ fi
+
+ #We need to back up the value of DEPEND and RDEPEND to B_DEPEND and B_RDEPEND
+ #(if set).. and then restore them after the inherit call.
+
+ #turn off glob expansion
+ set -f
+
+ # Retain the old data and restore it later.
+ unset B_IUSE B_REQUIRED_USE B_DEPEND B_RDEPEND B_PDEPEND
+ [ "${IUSE+set}" = set ] && B_IUSE="${IUSE}"
+ [ "${REQUIRED_USE+set}" = set ] && B_REQUIRED_USE="${REQUIRED_USE}"
+ [ "${DEPEND+set}" = set ] && B_DEPEND="${DEPEND}"
+ [ "${RDEPEND+set}" = set ] && B_RDEPEND="${RDEPEND}"
+ [ "${PDEPEND+set}" = set ] && B_PDEPEND="${PDEPEND}"
+ unset IUSE REQUIRED_USE DEPEND RDEPEND PDEPEND
+ #turn on glob expansion
+ set +f
+
+ qa_source "$location" || die "died sourcing $location in inherit()"
+
+ #turn off glob expansion
+ set -f
+
+ # If each var has a value, append it to the global variable E_* to
+ # be applied after everything is finished. New incremental behavior.
+ [ "${IUSE+set}" = set ] && export E_IUSE="${E_IUSE} ${IUSE}"
+ [ "${REQUIRED_USE+set}" = set ] && export E_REQUIRED_USE="${E_REQUIRED_USE} ${REQUIRED_USE}"
+ [ "${DEPEND+set}" = set ] && export E_DEPEND="${E_DEPEND} ${DEPEND}"
+ [ "${RDEPEND+set}" = set ] && export E_RDEPEND="${E_RDEPEND} ${RDEPEND}"
+ [ "${PDEPEND+set}" = set ] && export E_PDEPEND="${E_PDEPEND} ${PDEPEND}"
+
+ [ "${B_IUSE+set}" = set ] && IUSE="${B_IUSE}"
+ [ "${B_IUSE+set}" = set ] || unset IUSE
+
+ [ "${B_REQUIRED_USE+set}" = set ] && REQUIRED_USE="${B_REQUIRED_USE}"
+ [ "${B_REQUIRED_USE+set}" = set ] || unset REQUIRED_USE
+
+ [ "${B_DEPEND+set}" = set ] && DEPEND="${B_DEPEND}"
+ [ "${B_DEPEND+set}" = set ] || unset DEPEND
+
+ [ "${B_RDEPEND+set}" = set ] && RDEPEND="${B_RDEPEND}"
+ [ "${B_RDEPEND+set}" = set ] || unset RDEPEND
+
+ [ "${B_PDEPEND+set}" = set ] && PDEPEND="${B_PDEPEND}"
+ [ "${B_PDEPEND+set}" = set ] || unset PDEPEND
+
+ #turn on glob expansion
+ set +f
+
+ if [[ -n ${!__export_funcs_var} ]] ; then
+ for x in ${!__export_funcs_var} ; do
+ debug-print "EXPORT_FUNCTIONS: $x -> ${ECLASS}_$x"
+ declare -F "${ECLASS}_$x" >/dev/null || \
+ die "EXPORT_FUNCTIONS: ${ECLASS}_$x is not defined"
+ eval "$x() { ${ECLASS}_$x \"\$@\" ; }" > /dev/null
+ done
+ fi
+ unset $__export_funcs_var
+
+ has $1 $INHERITED || export INHERITED="$INHERITED $1"
+
+ shift
+ done
+ ((--ECLASS_DEPTH)) # Returns 1 when ECLASS_DEPTH reaches 0.
+ if (( ECLASS_DEPTH > 0 )) ; then
+ export ECLASS=$PECLASS
+ __export_funcs_var=$prev_export_funcs_var
+ else
+ unset ECLASS __export_funcs_var
+ fi
+ return 0
+}
+
+# Exports stub functions that call the eclass's functions, thereby making them default.
+# For example, if ECLASS="base" and you call "EXPORT_FUNCTIONS src_unpack", the following
+# code will be eval'd:
+# src_unpack() { base_src_unpack; }
+EXPORT_FUNCTIONS() {
+ if [ -z "$ECLASS" ]; then
+ die "EXPORT_FUNCTIONS without a defined ECLASS"
+ fi
+ eval $__export_funcs_var+=\" $*\"
+}
+
+# this is a function for removing any directory matching a passed in pattern from
+# PATH
+remove_path_entry() {
+ save_IFS
+ IFS=":"
+ stripped_path="${PATH}"
+ while [ -n "$1" ]; do
+ cur_path=""
+ for p in ${stripped_path}; do
+ if [ "${p/${1}}" == "${p}" ]; then
+ cur_path="${cur_path}:${p}"
+ fi
+ done
+ stripped_path="${cur_path#:*}"
+ shift
+ done
+ restore_IFS
+ PATH="${stripped_path}"
+}
+
+# @FUNCTION: _ebuild_arg_to_phase
+# @DESCRIPTION:
+# Translate a known ebuild(1) argument into the precise
+# name of it's corresponding ebuild phase.
+_ebuild_arg_to_phase() {
+ [ $# -ne 2 ] && die "expected exactly 2 args, got $#: $*"
+ local eapi=$1
+ local arg=$2
+ local phase_func=""
+
+ case "$arg" in
+ pretend)
+ ! has $eapi 0 1 2 3 3_pre2 && \
+ phase_func=pkg_pretend
+ ;;
+ setup)
+ phase_func=pkg_setup
+ ;;
+ nofetch)
+ phase_func=pkg_nofetch
+ ;;
+ unpack)
+ phase_func=src_unpack
+ ;;
+ prepare)
+ ! has $eapi 0 1 && \
+ phase_func=src_prepare
+ ;;
+ configure)
+ ! has $eapi 0 1 && \
+ phase_func=src_configure
+ ;;
+ compile)
+ phase_func=src_compile
+ ;;
+ test)
+ phase_func=src_test
+ ;;
+ install)
+ phase_func=src_install
+ ;;
+ preinst)
+ phase_func=pkg_preinst
+ ;;
+ postinst)
+ phase_func=pkg_postinst
+ ;;
+ prerm)
+ phase_func=pkg_prerm
+ ;;
+ postrm)
+ phase_func=pkg_postrm
+ ;;
+ esac
+
+ [[ -z $phase_func ]] && return 1
+ echo "$phase_func"
+ return 0
+}
+
+_ebuild_phase_funcs() {
+ [ $# -ne 2 ] && die "expected exactly 2 args, got $#: $*"
+ local eapi=$1
+ local phase_func=$2
+ local default_phases="pkg_nofetch src_unpack src_prepare src_configure
+ src_compile src_install src_test"
+ local x y default_func=""
+
+ for x in pkg_nofetch src_unpack src_test ; do
+ declare -F $x >/dev/null || \
+ eval "$x() { _eapi0_$x \"\$@\" ; }"
+ done
+
+ case $eapi in
+
+ 0|1)
+
+ if ! declare -F src_compile >/dev/null ; then
+ case $eapi in
+ 0)
+ src_compile() { _eapi0_src_compile "$@" ; }
+ ;;
+ *)
+ src_compile() { _eapi1_src_compile "$@" ; }
+ ;;
+ esac
+ fi
+
+ for x in $default_phases ; do
+ eval "default_$x() {
+ die \"default_$x() is not supported with EAPI='$eapi' during phase $phase_func\"
+ }"
+ done
+
+ eval "default() {
+ die \"default() is not supported with EAPI='$eapi' during phase $phase_func\"
+ }"
+
+ ;;
+
+ *)
+
+ declare -F src_configure >/dev/null || \
+ src_configure() { _eapi2_src_configure "$@" ; }
+
+ declare -F src_compile >/dev/null || \
+ src_compile() { _eapi2_src_compile "$@" ; }
+
+ has $eapi 2 3 3_pre2 || declare -F src_install >/dev/null || \
+ src_install() { _eapi4_src_install "$@" ; }
+
+ if has $phase_func $default_phases ; then
+
+ _eapi2_pkg_nofetch () { _eapi0_pkg_nofetch "$@" ; }
+ _eapi2_src_unpack () { _eapi0_src_unpack "$@" ; }
+ _eapi2_src_prepare () { true ; }
+ _eapi2_src_test () { _eapi0_src_test "$@" ; }
+ _eapi2_src_install () { die "$FUNCNAME is not supported" ; }
+
+ for x in $default_phases ; do
+ eval "default_$x() { _eapi2_$x \"\$@\" ; }"
+ done
+
+ eval "default() { _eapi2_$phase_func \"\$@\" ; }"
+
+ case $eapi in
+ 2|3)
+ ;;
+ *)
+ eval "default_src_install() { _eapi4_src_install \"\$@\" ; }"
+ [[ $phase_func = src_install ]] && \
+ eval "default() { _eapi4_$phase_func \"\$@\" ; }"
+ ;;
+ esac
+
+ else
+
+ for x in $default_phases ; do
+ eval "default_$x() {
+ die \"default_$x() is not supported in phase $default_func\"
+ }"
+ done
+
+ eval "default() {
+ die \"default() is not supported with EAPI='$eapi' during phase $phase_func\"
+ }"
+
+ fi
+
+ ;;
+ esac
+}
+
+# Set given variables unless these variable have been already set (e.g. during emerge
+# invocation) to values different than values set in make.conf.
+set_unless_changed() {
+ if [[ $# -lt 1 ]]; then
+ die "${FUNCNAME}() requires at least 1 argument: VARIABLE=VALUE"
+ fi
+
+ local argument value variable
+ for argument in "$@"; do
+ if [[ ${argument} != *=* ]]; then
+ die "${FUNCNAME}(): Argument '${argument}' has incorrect syntax"
+ fi
+ variable="${argument%%=*}"
+ value="${argument#*=}"
+ if eval "[[ \${${variable}} == \$(env -u ${variable} portageq envvar ${variable}) ]]"; then
+ eval "${variable}=\"\${value}\""
+ fi
+ done
+}
+
+# Unset given variables unless these variable have been set (e.g. during emerge
+# invocation) to values different than values set in make.conf.
+unset_unless_changed() {
+ if [[ $# -lt 1 ]]; then
+ die "${FUNCNAME}() requires at least 1 argument: VARIABLE"
+ fi
+
+ local variable
+ for variable in "$@"; do
+ if eval "[[ \${${variable}} == \$(env -u ${variable} portageq envvar ${variable}) ]]"; then
+ unset ${variable}
+ fi
+ done
+}
+
+PORTAGE_BASHRCS_SOURCED=0
+
+# @FUNCTION: source_all_bashrcs
+# @DESCRIPTION:
+# Source a relevant bashrc files and perform other miscellaneous
+# environment initialization when appropriate.
+#
+# If EAPI is set then define functions provided by the current EAPI:
+#
+# * default_* aliases for the current EAPI phase functions
+# * A "default" function which is an alias for the default phase
+# function for the current phase.
+#
+source_all_bashrcs() {
+ [[ $PORTAGE_BASHRCS_SOURCED = 1 ]] && return 0
+ PORTAGE_BASHRCS_SOURCED=1
+ local x
+
+ local OCC="${CC}" OCXX="${CXX}"
+
+ if [[ $EBUILD_PHASE != depend ]] ; then
+ # source the existing profile.bashrcs.
+ save_IFS
+ IFS=$'\n'
+ local path_array=($PROFILE_PATHS)
+ restore_IFS
+ for x in "${path_array[@]}" ; do
+ [ -f "$x/profile.bashrc" ] && qa_source "$x/profile.bashrc"
+ done
+ fi
+
+ # We assume if people are changing shopts in their bashrc they do so at their
+ # own peril. This is the ONLY non-portage bit of code that can change shopts
+ # without a QA violation.
+ for x in "${PORTAGE_BASHRC}" "${PM_EBUILD_HOOK_DIR}"/${CATEGORY}/{${PN},${PN}:${SLOT},${P},${PF}}; do
+ if [ -r "${x}" ]; then
+ # If $- contains x, then tracing has already enabled elsewhere for some
+ # reason. We preserve it's state so as not to interfere.
+ if [ "$PORTAGE_DEBUG" != "1" ] || [ "${-/x/}" != "$-" ]; then
+ source "${x}"
+ else
+ set -x
+ source "${x}"
+ set +x
+ fi
+ fi
+ done
+
+ [ ! -z "${OCC}" ] && export CC="${OCC}"
+ [ ! -z "${OCXX}" ] && export CXX="${OCXX}"
+}
+
+# Hardcoded bash lists are needed for backward compatibility with
+# <portage-2.1.4 since they assume that a newly installed version
+# of ebuild.sh will work for pkg_postinst, pkg_prerm, and pkg_postrm
+# when portage is upgrading itself.
+
+PORTAGE_READONLY_METADATA="DEFINED_PHASES DEPEND DESCRIPTION
+ EAPI HOMEPAGE INHERITED IUSE REQUIRED_USE KEYWORDS LICENSE
+ PDEPEND PROVIDE RDEPEND RESTRICT SLOT SRC_URI"
+
+PORTAGE_READONLY_VARS="D EBUILD EBUILD_PHASE \
+ EBUILD_SH_ARGS ECLASSDIR EMERGE_FROM FILESDIR MERGE_TYPE \
+ PM_EBUILD_HOOK_DIR \
+ PORTAGE_ACTUAL_DISTDIR PORTAGE_ARCHLIST PORTAGE_BASHRC \
+ PORTAGE_BINPKG_FILE PORTAGE_BINPKG_TAR_OPTS PORTAGE_BINPKG_TMPFILE \
+ PORTAGE_BIN_PATH PORTAGE_BUILDDIR PORTAGE_BUNZIP2_COMMAND \
+ PORTAGE_BZIP2_COMMAND PORTAGE_COLORMAP PORTAGE_CONFIGROOT \
+ PORTAGE_DEBUG PORTAGE_DEPCACHEDIR PORTAGE_EBUILD_EXIT_FILE \
+ PORTAGE_GID PORTAGE_GRPNAME PORTAGE_INST_GID PORTAGE_INST_UID \
+ PORTAGE_IPC_DAEMON PORTAGE_IUSE PORTAGE_LOG_FILE \
+ PORTAGE_MUTABLE_FILTERED_VARS PORTAGE_PYM_PATH PORTAGE_PYTHON \
+ PORTAGE_READONLY_METADATA PORTAGE_READONLY_VARS \
+ PORTAGE_REPO_NAME PORTAGE_RESTRICT PORTAGE_SANDBOX_COMPAT_LEVEL \
+ PORTAGE_SAVED_READONLY_VARS PORTAGE_SIGPIPE_STATUS \
+ PORTAGE_TMPDIR PORTAGE_UPDATE_ENV PORTAGE_USERNAME \
+ PORTAGE_VERBOSE PORTAGE_WORKDIR_MODE PORTDIR PORTDIR_OVERLAY \
+ PROFILE_PATHS REPLACING_VERSIONS REPLACED_BY_VERSION T WORKDIR"
+
+PORTAGE_SAVED_READONLY_VARS="A CATEGORY P PF PN PR PV PVR"
+
+# Variables that portage sets but doesn't mark readonly.
+# In order to prevent changed values from causing unexpected
+# interference, they are filtered out of the environment when
+# it is saved or loaded (any mutations do not persist).
+PORTAGE_MUTABLE_FILTERED_VARS="AA HOSTNAME"
+
+# @FUNCTION: filter_readonly_variables
+# @DESCRIPTION: [--filter-sandbox] [--allow-extra-vars]
+# Read an environment from stdin and echo to stdout while filtering variables
+# with names that are known to cause interference:
+#
+# * some specific variables for which bash does not allow assignment
+# * some specific variables that affect portage or sandbox behavior
+# * variable names that begin with a digit or that contain any
+# non-alphanumeric characters that are not be supported by bash
+#
+# --filter-sandbox causes all SANDBOX_* variables to be filtered, which
+# is only desired in certain cases, such as during preprocessing or when
+# saving environment.bz2 for a binary or installed package.
+#
+# --filter-features causes the special FEATURES variable to be filtered.
+# Generally, we want it to persist between phases since the user might
+# want to modify it via bashrc to enable things like splitdebug and
+# installsources for specific packages. They should be able to modify it
+# in pre_pkg_setup() and have it persist all the way through the install
+# phase. However, if FEATURES exist inside environment.bz2 then they
+# should be overridden by current settings.
+#
+# --filter-locale causes locale related variables such as LANG and LC_*
+# variables to be filtered. These variables should persist between phases,
+# in case they are modified by the ebuild. However, the current user
+# settings should be used when loading the environment from a binary or
+# installed package.
+#
+# --filter-path causes the PATH variable to be filtered. This variable
+# should persist between phases, in case it is modified by the ebuild.
+# However, old settings should be overridden when loading the
+# environment from a binary or installed package.
+#
+# ---allow-extra-vars causes some extra vars to be allowd through, such
+# as ${PORTAGE_SAVED_READONLY_VARS} and ${PORTAGE_MUTABLE_FILTERED_VARS}.
+#
+# In bash-3.2_p20+ an attempt to assign BASH_*, FUNCNAME, GROUPS or any
+# readonly variable cause the shell to exit while executing the "source"
+# builtin command. To avoid this problem, this function filters those
+# variables out and discards them. See bug #190128.
+filter_readonly_variables() {
+ local x filtered_vars
+ local readonly_bash_vars="BASHOPTS BASHPID DIRSTACK EUID
+ FUNCNAME GROUPS PIPESTATUS PPID SHELLOPTS UID"
+ local bash_misc_vars="BASH BASH_.* COMP_WORDBREAKS HISTCMD
+ HISTFILE HOSTNAME HOSTTYPE IFS LINENO MACHTYPE OLDPWD
+ OPTERR OPTIND OSTYPE POSIXLY_CORRECT PS4 PWD RANDOM
+ SECONDS SHELL SHLVL"
+ local filtered_sandbox_vars="SANDBOX_ACTIVE SANDBOX_BASHRC
+ SANDBOX_DEBUG_LOG SANDBOX_DISABLED SANDBOX_LIB
+ SANDBOX_LOG SANDBOX_ON"
+ local misc_garbage_vars="_portage_filter_opts"
+ filtered_vars="$readonly_bash_vars $bash_misc_vars
+ $PORTAGE_READONLY_VARS $misc_garbage_vars"
+
+ # Don't filter/interfere with prefix variables unless they are
+ # supported by the current EAPI.
+ case "${EAPI:-0}" in
+ 0|1|2)
+ ;;
+ *)
+ filtered_vars+=" ED EPREFIX EROOT"
+ ;;
+ esac
+
+ if has --filter-sandbox $* ; then
+ filtered_vars="${filtered_vars} SANDBOX_.*"
+ else
+ filtered_vars="${filtered_vars} ${filtered_sandbox_vars}"
+ fi
+ if has --filter-features $* ; then
+ filtered_vars="${filtered_vars} FEATURES PORTAGE_FEATURES"
+ fi
+ if has --filter-path $* ; then
+ filtered_vars+=" PATH"
+ fi
+ if has --filter-locale $* ; then
+ filtered_vars+=" LANG LC_ALL LC_COLLATE
+ LC_CTYPE LC_MESSAGES LC_MONETARY
+ LC_NUMERIC LC_PAPER LC_TIME"
+ fi
+ if ! has --allow-extra-vars $* ; then
+ filtered_vars="
+ ${filtered_vars}
+ ${PORTAGE_SAVED_READONLY_VARS}
+ ${PORTAGE_MUTABLE_FILTERED_VARS}
+ "
+ fi
+
+ "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}"/filter-bash-environment.py "${filtered_vars}" || die "filter-bash-environment.py failed"
+}
+
+# @FUNCTION: preprocess_ebuild_env
+# @DESCRIPTION:
+# Filter any readonly variables from ${T}/environment, source it, and then
+# save it via save_ebuild_env(). This process should be sufficient to prevent
+# any stale variables or functions from an arbitrary environment from
+# interfering with the current environment. This is useful when an existing
+# environment needs to be loaded from a binary or installed package.
+preprocess_ebuild_env() {
+ local _portage_filter_opts="--filter-features --filter-locale --filter-path --filter-sandbox"
+
+ # If environment.raw is present, this is a signal from the python side,
+ # indicating that the environment may contain stale FEATURES and
+ # SANDBOX_{DENY,PREDICT,READ,WRITE} variables that should be filtered out.
+ # Otherwise, we don't need to filter the environment.
+ [ -f "${T}/environment.raw" ] || return 0
+
+ filter_readonly_variables $_portage_filter_opts < "${T}"/environment \
+ >> "$T/environment.filtered" || return $?
+ unset _portage_filter_opts
+ mv "${T}"/environment.filtered "${T}"/environment || return $?
+ rm -f "${T}/environment.success" || return $?
+ # WARNING: Code inside this subshell should avoid making assumptions
+ # about variables or functions after source "${T}"/environment has been
+ # called. Any variables that need to be relied upon should already be
+ # filtered out above.
+ (
+ export SANDBOX_ON=1
+ source "${T}/environment" || exit $?
+ # We have to temporarily disable sandbox since the
+ # SANDBOX_{DENY,READ,PREDICT,WRITE} values we've just loaded
+ # may be unusable (triggering in spurious sandbox violations)
+ # until we've merged them with our current values.
+ export SANDBOX_ON=0
+
+ # It's remotely possible that save_ebuild_env() has been overridden
+ # by the above source command. To protect ourselves, we override it
+ # here with our own version. ${PORTAGE_BIN_PATH} is safe to use here
+ # because it's already filtered above.
+ source "${PORTAGE_BIN_PATH}/isolated-functions.sh" || exit $?
+
+ # Rely on save_ebuild_env() to filter out any remaining variables
+ # and functions that could interfere with the current environment.
+ save_ebuild_env || exit $?
+ >> "$T/environment.success" || exit $?
+ ) > "${T}/environment.filtered"
+ local retval
+ if [ -e "${T}/environment.success" ] ; then
+ filter_readonly_variables --filter-features < \
+ "${T}/environment.filtered" > "${T}/environment"
+ retval=$?
+ else
+ retval=1
+ fi
+ rm -f "${T}"/environment.{filtered,raw,success}
+ return ${retval}
+}
+
+# === === === === === === === === === === === === === === === === === ===
+# === === === === === functions end, main part begins === === === === ===
+# === === === === === functions end, main part begins === === === === ===
+# === === === === === functions end, main part begins === === === === ===
+# === === === === === === === === === === === === === === === === === ===
+
+export SANDBOX_ON="1"
+export S=${WORKDIR}/${P}
+
+unset E_IUSE E_REQUIRED_USE E_DEPEND E_RDEPEND E_PDEPEND
+
+# Turn of extended glob matching so that g++ doesn't get incorrectly matched.
+shopt -u extglob
+
+if [[ ${EBUILD_PHASE} == depend ]] ; then
+ QA_INTERCEPTORS="awk bash cc egrep equery fgrep g++
+ gawk gcc grep javac java-config nawk perl
+ pkg-config python python-config sed"
+elif [[ ${EBUILD_PHASE} == clean* ]] ; then
+ unset QA_INTERCEPTORS
+else
+ QA_INTERCEPTORS="autoconf automake aclocal libtoolize"
+fi
+# level the QA interceptors if we're in depend
+if [[ -n ${QA_INTERCEPTORS} ]] ; then
+ for BIN in ${QA_INTERCEPTORS}; do
+ BIN_PATH=$(type -Pf ${BIN})
+ if [ "$?" != "0" ]; then
+ BODY="echo \"*** missing command: ${BIN}\" >&2; return 127"
+ else
+ BODY="${BIN_PATH} \"\$@\"; return \$?"
+ fi
+ if [[ ${EBUILD_PHASE} == depend ]] ; then
+ FUNC_SRC="${BIN}() {
+ if [ \$ECLASS_DEPTH -gt 0 ]; then
+ eqawarn \"QA Notice: '${BIN}' called in global scope: eclass \${ECLASS}\"
+ else
+ eqawarn \"QA Notice: '${BIN}' called in global scope: \${CATEGORY}/\${PF}\"
+ fi
+ ${BODY}
+ }"
+ elif has ${BIN} autoconf automake aclocal libtoolize ; then
+ FUNC_SRC="${BIN}() {
+ if ! has \${FUNCNAME[1]} eautoreconf eaclocal _elibtoolize \\
+ eautoheader eautoconf eautomake autotools_run_tool \\
+ autotools_check_macro autotools_get_subdirs \\
+ autotools_get_auxdir ; then
+ eqawarn \"QA Notice: '${BIN}' called by \${FUNCNAME[1]}: \${CATEGORY}/\${PF}\"
+ eqawarn \"Use autotools.eclass instead of calling '${BIN}' directly.\"
+ fi
+ ${BODY}
+ }"
+ else
+ FUNC_SRC="${BIN}() {
+ eqawarn \"QA Notice: '${BIN}' called by \${FUNCNAME[1]}: \${CATEGORY}/\${PF}\"
+ ${BODY}
+ }"
+ fi
+ eval "$FUNC_SRC" || echo "error creating QA interceptor ${BIN}" >&2
+ done
+ unset BIN_PATH BIN BODY FUNC_SRC
+fi
+
+# Subshell/helper die support (must export for the die helper).
+export EBUILD_MASTER_PID=$BASHPID
+trap 'exit 1' SIGTERM
+
+if ! has "$EBUILD_PHASE" clean cleanrm depend && \
+ [ -f "${T}"/environment ] ; then
+ # The environment may have been extracted from environment.bz2 or
+ # may have come from another version of ebuild.sh or something.
+ # In any case, preprocess it to prevent any potential interference.
+ preprocess_ebuild_env || \
+ die "error processing environment"
+ # Colon separated SANDBOX_* variables need to be cumulative.
+ for x in SANDBOX_DENY SANDBOX_READ SANDBOX_PREDICT SANDBOX_WRITE ; do
+ export PORTAGE_${x}=${!x}
+ done
+ PORTAGE_SANDBOX_ON=${SANDBOX_ON}
+ export SANDBOX_ON=1
+ source "${T}"/environment || \
+ die "error sourcing environment"
+ # We have to temporarily disable sandbox since the
+ # SANDBOX_{DENY,READ,PREDICT,WRITE} values we've just loaded
+ # may be unusable (triggering in spurious sandbox violations)
+ # until we've merged them with our current values.
+ export SANDBOX_ON=0
+ for x in SANDBOX_DENY SANDBOX_PREDICT SANDBOX_READ SANDBOX_WRITE ; do
+ y="PORTAGE_${x}"
+ if [ -z "${!x}" ] ; then
+ export ${x}=${!y}
+ elif [ -n "${!y}" ] && [ "${!y}" != "${!x}" ] ; then
+ # filter out dupes
+ export ${x}=$(printf "${!y}:${!x}" | tr ":" "\0" | \
+ sort -z -u | tr "\0" ":")
+ fi
+ export ${x}=${!x%:}
+ unset PORTAGE_${x}
+ done
+ unset x y
+ export SANDBOX_ON=${PORTAGE_SANDBOX_ON}
+ unset PORTAGE_SANDBOX_ON
+ [[ -n $EAPI ]] || EAPI=0
+fi
+
+if ! has "$EBUILD_PHASE" clean cleanrm ; then
+ if [[ $EBUILD_PHASE = depend || ! -f $T/environment || \
+ -f $PORTAGE_BUILDDIR/.ebuild_changed ]] || \
+ has noauto $FEATURES ; then
+ # The bashrcs get an opportunity here to set aliases that will be expanded
+ # during sourcing of ebuilds and eclasses.
+ source_all_bashrcs
+
+ # When EBUILD_PHASE != depend, INHERITED comes pre-initialized
+ # from cache. In order to make INHERITED content independent of
+ # EBUILD_PHASE during inherit() calls, we unset INHERITED after
+ # we make a backup copy for QA checks.
+ __INHERITED_QA_CACHE=$INHERITED
+
+ # *DEPEND and IUSE will be set during the sourcing of the ebuild.
+ # In order to ensure correct interaction between ebuilds and
+ # eclasses, they need to be unset before this process of
+ # interaction begins.
+ unset DEPEND RDEPEND PDEPEND INHERITED IUSE REQUIRED_USE \
+ ECLASS E_IUSE E_REQUIRED_USE E_DEPEND E_RDEPEND E_PDEPEND
+
+ if [[ $PORTAGE_DEBUG != 1 || ${-/x/} != $- ]] ; then
+ source "$EBUILD" || die "error sourcing ebuild"
+ else
+ set -x
+ source "$EBUILD" || die "error sourcing ebuild"
+ set +x
+ fi
+
+ if [[ "${EBUILD_PHASE}" != "depend" ]] ; then
+ RESTRICT=${PORTAGE_RESTRICT}
+ [[ -e $PORTAGE_BUILDDIR/.ebuild_changed ]] && \
+ rm "$PORTAGE_BUILDDIR/.ebuild_changed"
+ fi
+
+ [[ -n $EAPI ]] || EAPI=0
+
+ if has "$EAPI" 0 1 2 3 3_pre2 ; then
+ export RDEPEND=${RDEPEND-${DEPEND}}
+ debug-print "RDEPEND: not set... Setting to: ${DEPEND}"
+ fi
+
+ # add in dependency info from eclasses
+ IUSE="${IUSE} ${E_IUSE}"
+ DEPEND="${DEPEND} ${E_DEPEND}"
+ RDEPEND="${RDEPEND} ${E_RDEPEND}"
+ PDEPEND="${PDEPEND} ${E_PDEPEND}"
+ REQUIRED_USE="${REQUIRED_USE} ${E_REQUIRED_USE}"
+
+ unset ECLASS E_IUSE E_REQUIRED_USE E_DEPEND E_RDEPEND E_PDEPEND \
+ __INHERITED_QA_CACHE
+
+ # alphabetically ordered by $EBUILD_PHASE value
+ case "$EAPI" in
+ 0|1)
+ _valid_phases="src_compile pkg_config pkg_info src_install
+ pkg_nofetch pkg_postinst pkg_postrm pkg_preinst pkg_prerm
+ pkg_setup src_test src_unpack"
+ ;;
+ 2|3|3_pre2)
+ _valid_phases="src_compile pkg_config src_configure pkg_info
+ src_install pkg_nofetch pkg_postinst pkg_postrm pkg_preinst
+ src_prepare pkg_prerm pkg_setup src_test src_unpack"
+ ;;
+ *)
+ _valid_phases="src_compile pkg_config src_configure pkg_info
+ src_install pkg_nofetch pkg_postinst pkg_postrm pkg_preinst
+ src_prepare pkg_prerm pkg_pretend pkg_setup src_test src_unpack"
+ ;;
+ esac
+
+ DEFINED_PHASES=
+ for _f in $_valid_phases ; do
+ if declare -F $_f >/dev/null ; then
+ _f=${_f#pkg_}
+ DEFINED_PHASES+=" ${_f#src_}"
+ fi
+ done
+ [[ -n $DEFINED_PHASES ]] || DEFINED_PHASES=-
+
+ unset _f _valid_phases
+
+ if [[ $EBUILD_PHASE != depend ]] ; then
+
+ case "$EAPI" in
+ 0|1|2|3)
+ _ebuild_helpers_path="$PORTAGE_BIN_PATH/ebuild-helpers"
+ ;;
+ *)
+ _ebuild_helpers_path="$PORTAGE_BIN_PATH/ebuild-helpers/4:$PORTAGE_BIN_PATH/ebuild-helpers"
+ ;;
+ esac
+
+ PATH=$_ebuild_helpers_path:$PREROOTPATH${PREROOTPATH:+:}/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin${ROOTPATH:+:}$ROOTPATH
+ unset _ebuild_helpers_path
+
+ # Use default ABI libdir in accordance with bug #355283.
+ x=LIBDIR_${DEFAULT_ABI}
+ [[ -n $DEFAULT_ABI && -n ${!x} ]] && x=${!x} || x=lib
+
+ if has distcc $FEATURES ; then
+ PATH="/usr/$x/distcc/bin:$PATH"
+ [[ -n $DISTCC_LOG ]] && addwrite "${DISTCC_LOG%/*}"
+ fi
+
+ if has ccache $FEATURES ; then
+ PATH="/usr/$x/ccache/bin:$PATH"
+
+ if [[ -n $CCACHE_DIR ]] ; then
+ addread "$CCACHE_DIR"
+ addwrite "$CCACHE_DIR"
+ fi
+
+ [[ -n $CCACHE_SIZE ]] && ccache -M $CCACHE_SIZE &> /dev/null
+ fi
+
+ unset x
+
+ if [[ -n $QA_PREBUILT ]] ; then
+
+ # these ones support fnmatch patterns
+ QA_EXECSTACK+=" $QA_PREBUILT"
+ QA_TEXTRELS+=" $QA_PREBUILT"
+ QA_WX_LOAD+=" $QA_PREBUILT"
+
+ # these ones support regular expressions, so translate
+ # fnmatch patterns to regular expressions
+ for x in QA_DT_HASH QA_DT_NEEDED QA_PRESTRIPPED QA_SONAME ; do
+ if [[ $(declare -p $x 2>/dev/null) = declare\ -a* ]] ; then
+ eval "$x=(\"\${$x[@]}\" ${QA_PREBUILT//\*/.*})"
+ else
+ eval "$x+=\" ${QA_PREBUILT//\*/.*}\""
+ fi
+ done
+
+ unset x
+ fi
+
+ # This needs to be exported since prepstrip is a separate shell script.
+ [[ -n $QA_PRESTRIPPED ]] && export QA_PRESTRIPPED
+ eval "[[ -n \$QA_PRESTRIPPED_${ARCH/-/_} ]] && \
+ export QA_PRESTRIPPED_${ARCH/-/_}"
+ fi
+ fi
+fi
+
+# unset USE_EXPAND variables that contain only the special "*" token
+for x in ${USE_EXPAND} ; do
+ [ "${!x}" == "*" ] && unset ${x}
+done
+unset x
+
+if has nostrip ${FEATURES} ${RESTRICT} || has strip ${RESTRICT}
+then
+ export DEBUGBUILD=1
+fi
+
+#a reasonable default for $S
+[[ -z ${S} ]] && export S=${WORKDIR}/${P}
+
+# Note: readonly variables interfere with preprocess_ebuild_env(), so
+# declare them only after it has already run.
+if [ "${EBUILD_PHASE}" != "depend" ] ; then
+ declare -r $PORTAGE_READONLY_METADATA $PORTAGE_READONLY_VARS
+ case "$EAPI" in
+ 0|1|2)
+ ;;
+ *)
+ declare -r ED EPREFIX EROOT
+ ;;
+ esac
+fi
+
+ebuild_main() {
+
+ # Subshell/helper die support (must export for the die helper).
+ # Since this function is typically executed in a subshell,
+ # setup EBUILD_MASTER_PID to refer to the current $BASHPID,
+ # which seems to give the best results when further
+ # nested subshells call die.
+ export EBUILD_MASTER_PID=$BASHPID
+ trap 'exit 1' SIGTERM
+
+ if [[ $EBUILD_PHASE != depend ]] ; then
+ # Force configure scripts that automatically detect ccache to
+ # respect FEATURES="-ccache".
+ has ccache $FEATURES || export CCACHE_DISABLE=1
+
+ local phase_func=$(_ebuild_arg_to_phase "$EAPI" "$EBUILD_PHASE")
+ [[ -n $phase_func ]] && _ebuild_phase_funcs "$EAPI" "$phase_func"
+ unset phase_func
+ fi
+
+ source_all_bashrcs
+
+ case ${EBUILD_SH_ARGS} in
+ nofetch)
+ ebuild_phase_with_hooks pkg_nofetch
+ ;;
+ prerm|postrm|postinst|config|info)
+ if has "$EBUILD_SH_ARGS" config info && \
+ ! declare -F "pkg_$EBUILD_SH_ARGS" >/dev/null ; then
+ ewarn "pkg_${EBUILD_SH_ARGS}() is not defined: '${EBUILD##*/}'"
+ fi
+ export SANDBOX_ON="0"
+ if [ "${PORTAGE_DEBUG}" != "1" ] || [ "${-/x/}" != "$-" ]; then
+ ebuild_phase_with_hooks pkg_${EBUILD_SH_ARGS}
+ else
+ set -x
+ ebuild_phase_with_hooks pkg_${EBUILD_SH_ARGS}
+ set +x
+ fi
+ if [[ $EBUILD_PHASE == postinst ]] && [[ -n $PORTAGE_UPDATE_ENV ]]; then
+ # Update environment.bz2 in case installation phases
+ # need to pass some variables to uninstallation phases.
+ save_ebuild_env --exclude-init-phases | \
+ filter_readonly_variables --filter-path \
+ --filter-sandbox --allow-extra-vars \
+ | ${PORTAGE_BZIP2_COMMAND} -c -f9 > "$PORTAGE_UPDATE_ENV"
+ assert "save_ebuild_env failed"
+ fi
+ ;;
+ unpack|prepare|configure|compile|test|clean|install)
+ if [[ ${SANDBOX_DISABLED:-0} = 0 ]] ; then
+ export SANDBOX_ON="1"
+ else
+ export SANDBOX_ON="0"
+ fi
+
+ case "$EBUILD_SH_ARGS" in
+ configure|compile)
+
+ local x
+ for x in ASFLAGS CCACHE_DIR CCACHE_SIZE \
+ CFLAGS CXXFLAGS LDFLAGS LIBCFLAGS LIBCXXFLAGS ; do
+ [[ ${!x+set} = set ]] && export $x
+ done
+ unset x
+
+ has distcc $FEATURES && [[ -n $DISTCC_DIR ]] && \
+ [[ ${SANDBOX_WRITE/$DISTCC_DIR} = $SANDBOX_WRITE ]] && \
+ addwrite "$DISTCC_DIR"
+
+ x=LIBDIR_$ABI
+ [ -z "$PKG_CONFIG_PATH" -a -n "$ABI" -a -n "${!x}" ] && \
+ export PKG_CONFIG_PATH=/usr/${!x}/pkgconfig
+
+ if has noauto $FEATURES && \
+ [[ ! -f $PORTAGE_BUILDDIR/.unpacked ]] ; then
+ echo
+ echo "!!! We apparently haven't unpacked..." \
+ "This is probably not what you"
+ echo "!!! want to be doing... You are using" \
+ "FEATURES=noauto so I'll assume"
+ echo "!!! that you know what you are doing..." \
+ "You have 5 seconds to abort..."
+ echo
+
+ local x
+ for x in 1 2 3 4 5 6 7 8; do
+ LC_ALL=C sleep 0.25
+ done
+
+ sleep 3
+ fi
+
+ cd "$PORTAGE_BUILDDIR"
+ if [ ! -d build-info ] ; then
+ mkdir build-info
+ cp "$EBUILD" "build-info/$PF.ebuild"
+ fi
+
+ #our custom version of libtool uses $S and $D to fix
+ #invalid paths in .la files
+ export S D
+
+ ;;
+ esac
+
+ if [ "${PORTAGE_DEBUG}" != "1" ] || [ "${-/x/}" != "$-" ]; then
+ dyn_${EBUILD_SH_ARGS}
+ else
+ set -x
+ dyn_${EBUILD_SH_ARGS}
+ set +x
+ fi
+ export SANDBOX_ON="0"
+ ;;
+ help|pretend|setup|preinst)
+ #pkg_setup needs to be out of the sandbox for tmp file creation;
+ #for example, awking and piping a file in /tmp requires a temp file to be created
+ #in /etc. If pkg_setup is in the sandbox, both our lilo and apache ebuilds break.
+ export SANDBOX_ON="0"
+ if [ "${PORTAGE_DEBUG}" != "1" ] || [ "${-/x/}" != "$-" ]; then
+ dyn_${EBUILD_SH_ARGS}
+ else
+ set -x
+ dyn_${EBUILD_SH_ARGS}
+ set +x
+ fi
+ ;;
+ depend)
+ export SANDBOX_ON="0"
+ set -f
+
+ if [ -n "${dbkey}" ] ; then
+ if [ ! -d "${dbkey%/*}" ]; then
+ install -d -g ${PORTAGE_GID} -m2775 "${dbkey%/*}"
+ fi
+ # Make it group writable. 666&~002==664
+ umask 002
+ fi
+
+ auxdbkeys="DEPEND RDEPEND SLOT SRC_URI RESTRICT HOMEPAGE LICENSE
+ DESCRIPTION KEYWORDS INHERITED IUSE REQUIRED_USE PDEPEND PROVIDE EAPI
+ PROPERTIES DEFINED_PHASES UNUSED_05 UNUSED_04
+ UNUSED_03 UNUSED_02 UNUSED_01"
+
+ #the extra $(echo) commands remove newlines
+ [ -n "${EAPI}" ] || EAPI=0
+
+ if [ -n "${dbkey}" ] ; then
+ > "${dbkey}"
+ for f in ${auxdbkeys} ; do
+ echo $(echo ${!f}) >> "${dbkey}" || exit $?
+ done
+ else
+ for f in ${auxdbkeys} ; do
+ echo $(echo ${!f}) 1>&9 || exit $?
+ done
+ exec 9>&-
+ fi
+ set +f
+ ;;
+ _internal_test)
+ ;;
+ *)
+ export SANDBOX_ON="1"
+ echo "Unrecognized EBUILD_SH_ARGS: '${EBUILD_SH_ARGS}'"
+ echo
+ dyn_help
+ exit 1
+ ;;
+ esac
+}
+
+if [[ -s $SANDBOX_LOG ]] ; then
+ # We use SANDBOX_LOG to check for sandbox violations,
+ # so we ensure that there can't be a stale log to
+ # interfere with our logic.
+ x=
+ if [[ -n SANDBOX_ON ]] ; then
+ x=$SANDBOX_ON
+ export SANDBOX_ON=0
+ fi
+
+ rm -f "$SANDBOX_LOG" || \
+ die "failed to remove stale sandbox log: '$SANDBOX_LOG'"
+
+ if [[ -n $x ]] ; then
+ export SANDBOX_ON=$x
+ fi
+ unset x
+fi
+
+if [[ $EBUILD_PHASE = depend ]] ; then
+ ebuild_main
+elif [[ -n $EBUILD_SH_ARGS ]] ; then
+ (
+ # Don't allow subprocesses to inherit the pipe which
+ # emerge uses to monitor ebuild.sh.
+ exec 9>&-
+
+ ebuild_main
+
+ # Save the env only for relevant phases.
+ if ! has "$EBUILD_SH_ARGS" clean help info nofetch ; then
+ umask 002
+ save_ebuild_env | filter_readonly_variables \
+ --filter-features > "$T/environment"
+ assert "save_ebuild_env failed"
+ chown portage:portage "$T/environment" &>/dev/null
+ chmod g+w "$T/environment" &>/dev/null
+ fi
+ [[ -n $PORTAGE_EBUILD_EXIT_FILE ]] && > "$PORTAGE_EBUILD_EXIT_FILE"
+ if [[ -n $PORTAGE_IPC_DAEMON ]] ; then
+ [[ ! -s $SANDBOX_LOG ]]
+ "$PORTAGE_BIN_PATH"/ebuild-ipc exit $?
+ fi
+ exit 0
+ )
+ exit $?
+fi
+
+# Do not exit when ebuild.sh is sourced by other scripts.
+true
diff --git a/portage_with_autodep/bin/egencache b/portage_with_autodep/bin/egencache
new file mode 100755
index 0000000..1b4265d
--- /dev/null
+++ b/portage_with_autodep/bin/egencache
@@ -0,0 +1,851 @@
+#!/usr/bin/python
+# Copyright 2009-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import signal
+import sys
+# This block ensures that ^C interrupts are handled quietly.
+try:
+
+ def exithandler(signum,frame):
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
+ sys.exit(128 + signum)
+
+ signal.signal(signal.SIGINT, exithandler)
+ signal.signal(signal.SIGTERM, exithandler)
+
+except KeyboardInterrupt:
+ sys.exit(128 + signal.SIGINT)
+
+import io
+import logging
+import optparse
+import subprocess
+import time
+import textwrap
+import re
+
+try:
+ import portage
+except ImportError:
+ from os import path as osp
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
+ import portage
+
+from portage import os, _encodings, _unicode_encode, _unicode_decode
+from _emerge.MetadataRegen import MetadataRegen
+from portage.cache.cache_errors import CacheError, StatCollision
+from portage.manifest import guessManifestFileType
+from portage.util import cmp_sort_key, writemsg_level
+from portage import cpv_getkey
+from portage.dep import Atom, isjustname
+from portage.versions import pkgcmp, pkgsplit, vercmp
+
+try:
+ from xml.etree import ElementTree
+except ImportError:
+ pass
+else:
+ try:
+ from xml.parsers.expat import ExpatError
+ except ImportError:
+ pass
+ else:
+ from repoman.utilities import parse_metadata_use
+
+from repoman.utilities import FindVCS
+
+if sys.hexversion >= 0x3000000:
+ long = int
+
+def parse_args(args):
+ usage = "egencache [options] <action> ... [atom] ..."
+ parser = optparse.OptionParser(usage=usage)
+
+ actions = optparse.OptionGroup(parser, 'Actions')
+ actions.add_option("--update",
+ action="store_true",
+ help="update metadata/cache/ (generate as necessary)")
+ actions.add_option("--update-use-local-desc",
+ action="store_true",
+ help="update the use.local.desc file from metadata.xml")
+ actions.add_option("--update-changelogs",
+ action="store_true",
+ help="update the ChangeLog files from SCM logs")
+ parser.add_option_group(actions)
+
+ common = optparse.OptionGroup(parser, 'Common options')
+ common.add_option("--repo",
+ action="store",
+ help="name of repo to operate on (default repo is located at $PORTDIR)")
+ common.add_option("--config-root",
+ help="location of portage config files",
+ dest="portage_configroot")
+ common.add_option("--portdir",
+ help="override the portage tree location",
+ dest="portdir")
+ common.add_option("--tolerant",
+ action="store_true",
+ help="exit successfully if only minor errors occurred")
+ common.add_option("--ignore-default-opts",
+ action="store_true",
+ help="do not use the EGENCACHE_DEFAULT_OPTS environment variable")
+ parser.add_option_group(common)
+
+ update = optparse.OptionGroup(parser, '--update options')
+ update.add_option("--cache-dir",
+ help="location of the metadata cache",
+ dest="cache_dir")
+ update.add_option("--jobs",
+ action="store",
+ help="max ebuild processes to spawn")
+ update.add_option("--load-average",
+ action="store",
+ help="max load allowed when spawning multiple jobs",
+ dest="load_average")
+ update.add_option("--rsync",
+ action="store_true",
+ help="enable rsync stat collision workaround " + \
+ "for bug 139134 (use with --update)")
+ parser.add_option_group(update)
+
+ uld = optparse.OptionGroup(parser, '--update-use-local-desc options')
+ uld.add_option("--preserve-comments",
+ action="store_true",
+ help="preserve the comments from the existing use.local.desc file")
+ uld.add_option("--use-local-desc-output",
+ help="output file for use.local.desc data (or '-' for stdout)",
+ dest="uld_output")
+ parser.add_option_group(uld)
+
+ options, args = parser.parse_args(args)
+
+ if options.jobs:
+ jobs = None
+ try:
+ jobs = int(options.jobs)
+ except ValueError:
+ jobs = -1
+
+ if jobs < 1:
+ parser.error("Invalid: --jobs='%s'" % \
+ (options.jobs,))
+
+ options.jobs = jobs
+
+ else:
+ options.jobs = None
+
+ if options.load_average:
+ try:
+ load_average = float(options.load_average)
+ except ValueError:
+ load_average = 0.0
+
+ if load_average <= 0.0:
+ parser.error("Invalid: --load-average='%s'" % \
+ (options.load_average,))
+
+ options.load_average = load_average
+
+ else:
+ options.load_average = None
+
+ options.config_root = options.portage_configroot
+ if options.config_root is not None and \
+ not os.path.isdir(options.config_root):
+ parser.error("Not a directory: --config-root='%s'" % \
+ (options.config_root,))
+
+ if options.cache_dir is not None and not os.path.isdir(options.cache_dir):
+ parser.error("Not a directory: --cache-dir='%s'" % \
+ (options.cache_dir,))
+
+ for atom in args:
+ try:
+ atom = portage.dep.Atom(atom)
+ except portage.exception.InvalidAtom:
+ parser.error('Invalid atom: %s' % (atom,))
+
+ if not isjustname(atom):
+ parser.error('Atom is too specific: %s' % (atom,))
+
+ if options.update_use_local_desc:
+ try:
+ ElementTree
+ ExpatError
+ except NameError:
+ parser.error('--update-use-local-desc requires python with USE=xml!')
+
+ if options.uld_output == '-' and options.preserve_comments:
+ parser.error('--preserve-comments can not be used when outputting to stdout')
+
+ return parser, options, args
+
+class GenCache(object):
+ def __init__(self, portdb, cp_iter=None, max_jobs=None, max_load=None,
+ rsync=False):
+ self._portdb = portdb
+ # We can globally cleanse stale cache only if we
+ # iterate over every single cp.
+ self._global_cleanse = cp_iter is None
+ if cp_iter is not None:
+ self._cp_set = set(cp_iter)
+ cp_iter = iter(self._cp_set)
+ self._cp_missing = self._cp_set.copy()
+ else:
+ self._cp_set = None
+ self._cp_missing = set()
+ self._regen = MetadataRegen(portdb, cp_iter=cp_iter,
+ consumer=self._metadata_callback,
+ max_jobs=max_jobs, max_load=max_load)
+ self.returncode = os.EX_OK
+ metadbmodule = portdb.settings.load_best_module("portdbapi.metadbmodule")
+ self._trg_cache = metadbmodule(portdb.porttrees[0],
+ "metadata/cache", portage.auxdbkeys[:])
+ if rsync:
+ self._trg_cache.raise_stat_collision = True
+ try:
+ self._trg_cache.ec = \
+ portdb._repo_info[portdb.porttrees[0]].eclass_db
+ except AttributeError:
+ pass
+ self._existing_nodes = set()
+
+ def _metadata_callback(self, cpv, ebuild_path, repo_path, metadata):
+ self._existing_nodes.add(cpv)
+ self._cp_missing.discard(cpv_getkey(cpv))
+ if metadata is not None:
+ if metadata.get('EAPI') == '0':
+ del metadata['EAPI']
+ try:
+ try:
+ self._trg_cache[cpv] = metadata
+ except StatCollision as sc:
+ # If the content of a cache entry changes and neither the
+ # file mtime nor size changes, it will prevent rsync from
+ # detecting changes. Cache backends may raise this
+ # exception from _setitem() if they detect this type of stat
+ # collision. These exceptions are handled by bumping the
+ # mtime on the ebuild (and the corresponding cache entry).
+ # See bug #139134.
+ max_mtime = sc.mtime
+ for ec, (loc, ec_mtime) in metadata['_eclasses_'].items():
+ if max_mtime < ec_mtime:
+ max_mtime = ec_mtime
+ if max_mtime == sc.mtime:
+ max_mtime += 1
+ max_mtime = long(max_mtime)
+ try:
+ os.utime(ebuild_path, (max_mtime, max_mtime))
+ except OSError as e:
+ self.returncode |= 1
+ writemsg_level(
+ "%s writing target: %s\n" % (cpv, e),
+ level=logging.ERROR, noiselevel=-1)
+ else:
+ metadata['_mtime_'] = max_mtime
+ self._trg_cache[cpv] = metadata
+ self._portdb.auxdb[repo_path][cpv] = metadata
+
+ except CacheError as ce:
+ self.returncode |= 1
+ writemsg_level(
+ "%s writing target: %s\n" % (cpv, ce),
+ level=logging.ERROR, noiselevel=-1)
+
+ def run(self):
+
+ received_signal = []
+
+ def sighandler(signum, frame):
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
+ self._regen.terminate()
+ received_signal.append(128 + signum)
+
+ earlier_sigint_handler = signal.signal(signal.SIGINT, sighandler)
+ earlier_sigterm_handler = signal.signal(signal.SIGTERM, sighandler)
+
+ try:
+ self._regen.run()
+ finally:
+ # Restore previous handlers
+ if earlier_sigint_handler is not None:
+ signal.signal(signal.SIGINT, earlier_sigint_handler)
+ else:
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+ if earlier_sigterm_handler is not None:
+ signal.signal(signal.SIGTERM, earlier_sigterm_handler)
+ else:
+ signal.signal(signal.SIGTERM, signal.SIG_DFL)
+
+ if received_signal:
+ sys.exit(received_signal[0])
+
+ self.returncode |= self._regen.returncode
+ cp_missing = self._cp_missing
+
+ trg_cache = self._trg_cache
+ dead_nodes = set()
+ if self._global_cleanse:
+ try:
+ for cpv in trg_cache:
+ cp = cpv_getkey(cpv)
+ if cp is None:
+ self.returncode |= 1
+ writemsg_level(
+ "Unable to parse cp for '%s'\n" % (cpv,),
+ level=logging.ERROR, noiselevel=-1)
+ else:
+ dead_nodes.add(cpv)
+ except CacheError as ce:
+ self.returncode |= 1
+ writemsg_level(
+ "Error listing cache entries for " + \
+ "'%s/metadata/cache': %s, continuing...\n" % \
+ (self._portdb.porttree_root, ce),
+ level=logging.ERROR, noiselevel=-1)
+
+ else:
+ cp_set = self._cp_set
+ try:
+ for cpv in trg_cache:
+ cp = cpv_getkey(cpv)
+ if cp is None:
+ self.returncode |= 1
+ writemsg_level(
+ "Unable to parse cp for '%s'\n" % (cpv,),
+ level=logging.ERROR, noiselevel=-1)
+ else:
+ cp_missing.discard(cp)
+ if cp in cp_set:
+ dead_nodes.add(cpv)
+ except CacheError as ce:
+ self.returncode |= 1
+ writemsg_level(
+ "Error listing cache entries for " + \
+ "'%s/metadata/cache': %s, continuing...\n" % \
+ (self._portdb.porttree_root, ce),
+ level=logging.ERROR, noiselevel=-1)
+
+ if cp_missing:
+ self.returncode |= 1
+ for cp in sorted(cp_missing):
+ writemsg_level(
+ "No ebuilds or cache entries found for '%s'\n" % (cp,),
+ level=logging.ERROR, noiselevel=-1)
+
+ if dead_nodes:
+ dead_nodes.difference_update(self._existing_nodes)
+ for k in dead_nodes:
+ try:
+ del trg_cache[k]
+ except KeyError:
+ pass
+ except CacheError as ce:
+ self.returncode |= 1
+ writemsg_level(
+ "%s deleting stale cache: %s\n" % (k, ce),
+ level=logging.ERROR, noiselevel=-1)
+
+ if not trg_cache.autocommits:
+ try:
+ trg_cache.commit()
+ except CacheError as ce:
+ self.returncode |= 1
+ writemsg_level(
+ "committing target: %s\n" % (ce,),
+ level=logging.ERROR, noiselevel=-1)
+
+class GenUseLocalDesc(object):
+ def __init__(self, portdb, output=None,
+ preserve_comments=False):
+ self.returncode = os.EX_OK
+ self._portdb = portdb
+ self._output = output
+ self._preserve_comments = preserve_comments
+
+ def run(self):
+ repo_path = self._portdb.porttrees[0]
+ ops = {'<':0, '<=':1, '=':2, '>=':3, '>':4}
+
+ if self._output is None or self._output != '-':
+ if self._output is None:
+ prof_path = os.path.join(repo_path, 'profiles')
+ desc_path = os.path.join(prof_path, 'use.local.desc')
+ try:
+ os.mkdir(prof_path)
+ except OSError:
+ pass
+ else:
+ desc_path = self._output
+
+ try:
+ if self._preserve_comments:
+ # Probe in binary mode, in order to avoid
+ # potential character encoding issues.
+ output = open(_unicode_encode(desc_path,
+ encoding=_encodings['fs'], errors='strict'), 'r+b')
+ else:
+ output = io.open(_unicode_encode(desc_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='w', encoding=_encodings['repo.content'],
+ errors='backslashreplace')
+ except IOError as e:
+ if not self._preserve_comments or \
+ os.path.isfile(desc_path):
+ writemsg_level(
+ "ERROR: failed to open output file %s: %s\n" \
+ % (desc_path, e), level=logging.ERROR, noiselevel=-1)
+ self.returncode |= 2
+ return
+
+ # Open in r+b mode failed because the file doesn't
+ # exist yet. We can probably recover if we disable
+ # preserve_comments mode now.
+ writemsg_level(
+ "WARNING: --preserve-comments enabled, but " + \
+ "output file not found: %s\n" % (desc_path,),
+ level=logging.WARNING, noiselevel=-1)
+ self._preserve_comments = False
+ try:
+ output = io.open(_unicode_encode(desc_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='w', encoding=_encodings['repo.content'],
+ errors='backslashreplace')
+ except IOError as e:
+ writemsg_level(
+ "ERROR: failed to open output file %s: %s\n" \
+ % (desc_path, e), level=logging.ERROR, noiselevel=-1)
+ self.returncode |= 2
+ return
+ else:
+ output = sys.stdout
+
+ if self._preserve_comments:
+ while True:
+ pos = output.tell()
+ if not output.readline().startswith(b'#'):
+ break
+ output.seek(pos)
+ output.truncate()
+ output.close()
+
+ # Finished probing comments in binary mode, now append
+ # in text mode.
+ output = io.open(_unicode_encode(desc_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='a', encoding=_encodings['repo.content'],
+ errors='backslashreplace')
+ output.write(_unicode_decode('\n'))
+ else:
+ output.write(_unicode_decode('''
+# This file is deprecated as per GLEP 56 in favor of metadata.xml. Please add
+# your descriptions to your package's metadata.xml ONLY.
+# * generated automatically using egencache *
+
+'''.lstrip()))
+
+ # The cmp function no longer exists in python3, so we'll
+ # implement our own here under a slightly different name
+ # since we don't want any confusion given that we never
+ # want to rely on the builtin cmp function.
+ def cmp_func(a, b):
+ if a is None or b is None:
+ # None can't be compared with other types in python3.
+ if a is None and b is None:
+ return 0
+ elif a is None:
+ return -1
+ else:
+ return 1
+ return (a > b) - (a < b)
+
+ for cp in self._portdb.cp_all():
+ metadata_path = os.path.join(repo_path, cp, 'metadata.xml')
+ try:
+ metadata = ElementTree.parse(metadata_path)
+ except IOError:
+ pass
+ except (ExpatError, EnvironmentError) as e:
+ writemsg_level(
+ "ERROR: failed parsing %s/metadata.xml: %s\n" % (cp, e),
+ level=logging.ERROR, noiselevel=-1)
+ self.returncode |= 1
+ else:
+ try:
+ usedict = parse_metadata_use(metadata)
+ except portage.exception.ParseError as e:
+ writemsg_level(
+ "ERROR: failed parsing %s/metadata.xml: %s\n" % (cp, e),
+ level=logging.ERROR, noiselevel=-1)
+ self.returncode |= 1
+ else:
+ for flag in sorted(usedict):
+ def atomcmp(atoma, atomb):
+ # None is better than an atom, that's why we reverse the args
+ if atoma is None or atomb is None:
+ return cmp_func(atomb, atoma)
+ # Same for plain PNs (.operator is None then)
+ elif atoma.operator is None or atomb.operator is None:
+ return cmp_func(atomb.operator, atoma.operator)
+ # Version matching
+ elif atoma.cpv != atomb.cpv:
+ return pkgcmp(pkgsplit(atoma.cpv), pkgsplit(atomb.cpv))
+ # Versions match, let's fallback to operator matching
+ else:
+ return cmp_func(ops.get(atoma.operator, -1),
+ ops.get(atomb.operator, -1))
+
+ def _Atom(key):
+ if key is not None:
+ return Atom(key)
+ return None
+
+ resdict = usedict[flag]
+ if len(resdict) == 1:
+ resdesc = next(iter(resdict.items()))[1]
+ else:
+ try:
+ reskeys = dict((_Atom(k), k) for k in resdict)
+ except portage.exception.InvalidAtom as e:
+ writemsg_level(
+ "ERROR: failed parsing %s/metadata.xml: %s\n" % (cp, e),
+ level=logging.ERROR, noiselevel=-1)
+ self.returncode |= 1
+ resdesc = next(iter(resdict.items()))[1]
+ else:
+ resatoms = sorted(reskeys, key=cmp_sort_key(atomcmp))
+ resdesc = resdict[reskeys[resatoms[-1]]]
+
+ output.write(_unicode_decode(
+ '%s:%s - %s\n' % (cp, flag, resdesc)))
+
+ output.close()
+
+if sys.hexversion < 0x3000000:
+ _filename_base = unicode
+else:
+ _filename_base = str
+
+class _special_filename(_filename_base):
+ """
+ Helps to sort file names by file type and other criteria.
+ """
+ def __new__(cls, status_change, file_name):
+ return _filename_base.__new__(cls, status_change + file_name)
+
+ def __init__(self, status_change, file_name):
+ _filename_base.__init__(status_change + file_name)
+ self.status_change = status_change
+ self.file_name = file_name
+ self.file_type = guessManifestFileType(file_name)
+
+ def file_type_lt(self, a, b):
+ """
+ Defines an ordering between file types.
+ """
+ first = a.file_type
+ second = b.file_type
+ if first == second:
+ return False
+
+ if first == "EBUILD":
+ return True
+ elif first == "MISC":
+ return second in ("EBUILD",)
+ elif first == "AUX":
+ return second in ("EBUILD", "MISC")
+ elif first == "DIST":
+ return second in ("EBUILD", "MISC", "AUX")
+ elif first is None:
+ return False
+ else:
+ raise ValueError("Unknown file type '%s'" % first)
+
+ def __lt__(self, other):
+ """
+ Compare different file names, first by file type and then
+ for ebuilds by version and lexicographically for others.
+ EBUILD < MISC < AUX < DIST < None
+ """
+ if self.__class__ != other.__class__:
+ raise NotImplementedError
+
+ # Sort by file type as defined by file_type_lt().
+ if self.file_type_lt(self, other):
+ return True
+ elif self.file_type_lt(other, self):
+ return False
+
+ # Files have the same type.
+ if self.file_type == "EBUILD":
+ # Sort by version. Lowest first.
+ ver = "-".join(pkgsplit(self.file_name[:-7])[1:3])
+ other_ver = "-".join(pkgsplit(other.file_name[:-7])[1:3])
+ return vercmp(ver, other_ver) < 0
+ else:
+ # Sort lexicographically.
+ return self.file_name < other.file_name
+
+class GenChangeLogs(object):
+ def __init__(self, portdb):
+ self.returncode = os.EX_OK
+ self._portdb = portdb
+ self._wrapper = textwrap.TextWrapper(
+ width = 78,
+ initial_indent = ' ',
+ subsequent_indent = ' '
+ )
+
+ @staticmethod
+ def grab(cmd):
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ return _unicode_decode(p.communicate()[0],
+ encoding=_encodings['stdio'], errors='strict')
+
+ def generate_changelog(self, cp):
+ try:
+ output = io.open('ChangeLog',
+ mode='w', encoding=_encodings['repo.content'],
+ errors='backslashreplace')
+ except IOError as e:
+ writemsg_level(
+ "ERROR: failed to open ChangeLog for %s: %s\n" % (cp,e,),
+ level=logging.ERROR, noiselevel=-1)
+ self.returncode |= 2
+ return
+
+ output.write(_unicode_decode('''
+# ChangeLog for %s
+# Copyright 1999-%s Gentoo Foundation; Distributed under the GPL v2
+# $Header: $
+
+''' % (cp, time.strftime('%Y'))).lstrip())
+
+ # now grab all the commits
+ commits = self.grab(['git', 'rev-list', 'HEAD', '--', '.']).split()
+
+ for c in commits:
+ # Explaining the arguments:
+ # --name-status to get a list of added/removed files
+ # --no-renames to avoid getting more complex records on the list
+ # --format to get the timestamp, author and commit description
+ # --root to make it work fine even with the initial commit
+ # --relative to get paths relative to ebuilddir
+ # -r (recursive) to get per-file changes
+ # then the commit-id and path.
+
+ cinfo = self.grab(['git', 'diff-tree', '--name-status', '--no-renames',
+ '--format=%ct %cN <%cE>%n%B', '--root', '--relative', '-r',
+ c, '--', '.']).rstrip('\n').split('\n')
+
+ # Expected output:
+ # timestamp Author Name <author@email>
+ # commit message l1
+ # ...
+ # commit message ln
+ #
+ # status1 filename1
+ # ...
+ # statusn filenamen
+
+ changed = []
+ for n, l in enumerate(reversed(cinfo)):
+ if not l:
+ body = cinfo[1:-n-1]
+ break
+ else:
+ f = l.split()
+ if f[1] == 'Manifest':
+ pass # XXX: remanifest commits?
+ elif f[1] == 'ChangeLog':
+ pass
+ elif f[0].startswith('A'):
+ changed.append(_special_filename("+", f[1]))
+ elif f[0].startswith('D'):
+ changed.append(_special_filename("-", f[1]))
+ elif f[0].startswith('M'):
+ changed.append(_special_filename("", f[1]))
+ else:
+ writemsg_level(
+ "ERROR: unexpected git file status for %s: %s\n" % (cp,f,),
+ level=logging.ERROR, noiselevel=-1)
+ self.returncode |= 1
+
+ if not changed:
+ continue
+
+ (ts, author) = cinfo[0].split(' ', 1)
+ date = time.strftime('%d %b %Y', time.gmtime(float(ts)))
+
+ changed = [str(x) for x in sorted(changed)]
+
+ wroteheader = False
+ # Reverse the sort order for headers.
+ for c in reversed(changed):
+ if c.startswith('+') and c.endswith('.ebuild'):
+ output.write(_unicode_decode(
+ '*%s (%s)\n' % (c[1:-7], date)))
+ wroteheader = True
+ if wroteheader:
+ output.write(_unicode_decode('\n'))
+
+ # strip '<cp>: ', '[<cp>] ', and similar
+ body[0] = re.sub(r'^\W*' + re.escape(cp) + r'\W+', '', body[0])
+ # strip trailing newline
+ if not body[-1]:
+ body = body[:-1]
+ # strip git-svn id
+ if body[-1].startswith('git-svn-id:') and not body[-2]:
+ body = body[:-2]
+ # strip the repoman version/manifest note
+ if body[-1] == ' (Signed Manifest commit)' or body[-1] == ' (Unsigned Manifest commit)':
+ body = body[:-1]
+ if body[-1].startswith('(Portage version:') and body[-1].endswith(')'):
+ body = body[:-1]
+ if not body[-1]:
+ body = body[:-1]
+
+ # don't break filenames on hyphens
+ self._wrapper.break_on_hyphens = False
+ output.write(_unicode_decode(
+ self._wrapper.fill(
+ '%s; %s %s:' % (date, author, ', '.join(changed)))))
+ # but feel free to break commit messages there
+ self._wrapper.break_on_hyphens = True
+ output.write(_unicode_decode(
+ '\n%s\n\n' % '\n'.join(self._wrapper.fill(x) for x in body)))
+
+ output.close()
+
+ def run(self):
+ repo_path = self._portdb.porttrees[0]
+ os.chdir(repo_path)
+
+ if 'git' not in FindVCS():
+ writemsg_level(
+ "ERROR: --update-changelogs supported only in git repos\n",
+ level=logging.ERROR, noiselevel=-1)
+ self.returncode = 127
+ return
+
+ for cp in self._portdb.cp_all():
+ os.chdir(os.path.join(repo_path, cp))
+ # Determine whether ChangeLog is up-to-date by comparing
+ # the newest commit timestamp with the ChangeLog timestamp.
+ lmod = self.grab(['git', 'log', '--format=%ct', '-1', '.'])
+ if not lmod:
+ # This cp has not been added to the repo.
+ continue
+
+ try:
+ cmod = os.stat('ChangeLog').st_mtime
+ except OSError:
+ cmod = 0
+
+ if float(cmod) < float(lmod):
+ self.generate_changelog(cp)
+
+def egencache_main(args):
+ parser, options, atoms = parse_args(args)
+
+ config_root = options.config_root
+ if config_root is None:
+ config_root = '/'
+
+ # The calling environment is ignored, so the program is
+ # completely controlled by commandline arguments.
+ env = {}
+
+ if options.repo is None:
+ env['PORTDIR_OVERLAY'] = ''
+
+ if options.cache_dir is not None:
+ env['PORTAGE_DEPCACHEDIR'] = options.cache_dir
+
+ if options.portdir is not None:
+ env['PORTDIR'] = options.portdir
+
+ settings = portage.config(config_root=config_root,
+ target_root='/', local_config=False, env=env)
+
+ default_opts = None
+ if not options.ignore_default_opts:
+ default_opts = settings.get('EGENCACHE_DEFAULT_OPTS', '').split()
+
+ if default_opts:
+ parser, options, args = parse_args(default_opts + args)
+
+ if options.config_root is not None:
+ config_root = options.config_root
+
+ if options.cache_dir is not None:
+ env['PORTAGE_DEPCACHEDIR'] = options.cache_dir
+
+ settings = portage.config(config_root=config_root,
+ target_root='/', local_config=False, env=env)
+
+ if not options.update and not options.update_use_local_desc \
+ and not options.update_changelogs:
+ parser.error('No action specified')
+ return 1
+
+ if options.update and 'metadata-transfer' not in settings.features:
+ writemsg_level("ecachegen: warning: " + \
+ "automatically enabling FEATURES=metadata-transfer\n",
+ level=logging.WARNING, noiselevel=-1)
+ settings.features.add('metadata-transfer')
+
+ settings.lock()
+
+ portdb = portage.portdbapi(mysettings=settings)
+ if options.repo is not None:
+ repo_path = portdb.getRepositoryPath(options.repo)
+ if repo_path is None:
+ parser.error("Unable to locate repository named '%s'" % \
+ (options.repo,))
+ return 1
+
+ # Limit ebuilds to the specified repo.
+ portdb.porttrees = [repo_path]
+
+ ret = [os.EX_OK]
+
+ if options.update:
+ cp_iter = None
+ if atoms:
+ cp_iter = iter(atoms)
+
+ gen_cache = GenCache(portdb, cp_iter=cp_iter,
+ max_jobs=options.jobs,
+ max_load=options.load_average,
+ rsync=options.rsync)
+ gen_cache.run()
+ if options.tolerant:
+ ret.append(os.EX_OK)
+ else:
+ ret.append(gen_cache.returncode)
+
+ if options.update_use_local_desc:
+ gen_desc = GenUseLocalDesc(portdb,
+ output=options.uld_output,
+ preserve_comments=options.preserve_comments)
+ gen_desc.run()
+ ret.append(gen_desc.returncode)
+
+ if options.update_changelogs:
+ gen_clogs = GenChangeLogs(portdb)
+ gen_clogs.run()
+ ret.append(gen_clogs.returncode)
+
+ return max(ret)
+
+if __name__ == "__main__":
+ portage._disable_legacy_globals()
+ portage.util.noiselimit = -1
+ sys.exit(egencache_main(sys.argv[1:]))
diff --git a/portage_with_autodep/bin/emaint b/portage_with_autodep/bin/emaint
new file mode 100755
index 0000000..fdd01ed
--- /dev/null
+++ b/portage_with_autodep/bin/emaint
@@ -0,0 +1,654 @@
+#!/usr/bin/python -O
+# vim: noet :
+
+from __future__ import print_function
+
+import errno
+import re
+import signal
+import stat
+import sys
+import textwrap
+import time
+from optparse import OptionParser, OptionValueError
+
+try:
+ import portage
+except ImportError:
+ from os import path as osp
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
+ import portage
+
+from portage import os
+from portage.util import writemsg
+
+if sys.hexversion >= 0x3000000:
+ long = int
+
+class WorldHandler(object):
+
+ short_desc = "Fix problems in the world file"
+
+ def name():
+ return "world"
+ name = staticmethod(name)
+
+ def __init__(self):
+ self.invalid = []
+ self.not_installed = []
+ self.invalid_category = []
+ self.okay = []
+ from portage._sets import load_default_config
+ setconfig = load_default_config(portage.settings,
+ portage.db[portage.settings["ROOT"]])
+ self._sets = setconfig.getSets()
+
+ def _check_world(self, onProgress):
+ categories = set(portage.settings.categories)
+ myroot = portage.settings["ROOT"]
+ self.world_file = os.path.join(portage.settings["EROOT"], portage.const.WORLD_FILE)
+ self.found = os.access(self.world_file, os.R_OK)
+ vardb = portage.db[myroot]["vartree"].dbapi
+
+ from portage._sets import SETPREFIX
+ sets = self._sets
+ world_atoms = list(sets["selected"])
+ maxval = len(world_atoms)
+ if onProgress:
+ onProgress(maxval, 0)
+ for i, atom in enumerate(world_atoms):
+ if not isinstance(atom, portage.dep.Atom):
+ if atom.startswith(SETPREFIX):
+ s = atom[len(SETPREFIX):]
+ if s in sets:
+ self.okay.append(atom)
+ else:
+ self.not_installed.append(atom)
+ else:
+ self.invalid.append(atom)
+ if onProgress:
+ onProgress(maxval, i+1)
+ continue
+ okay = True
+ if not vardb.match(atom):
+ self.not_installed.append(atom)
+ okay = False
+ if portage.catsplit(atom.cp)[0] not in categories:
+ self.invalid_category.append(atom)
+ okay = False
+ if okay:
+ self.okay.append(atom)
+ if onProgress:
+ onProgress(maxval, i+1)
+
+ def check(self, onProgress=None):
+ self._check_world(onProgress)
+ errors = []
+ if self.found:
+ errors += ["'%s' is not a valid atom" % x for x in self.invalid]
+ errors += ["'%s' is not installed" % x for x in self.not_installed]
+ errors += ["'%s' has a category that is not listed in /etc/portage/categories" % x for x in self.invalid_category]
+ else:
+ errors.append(self.world_file + " could not be opened for reading")
+ return errors
+
+ def fix(self, onProgress=None):
+ world_set = self._sets["selected"]
+ world_set.lock()
+ try:
+ world_set.load() # maybe it's changed on disk
+ before = set(world_set)
+ self._check_world(onProgress)
+ after = set(self.okay)
+ errors = []
+ if before != after:
+ try:
+ world_set.replace(self.okay)
+ except portage.exception.PortageException:
+ errors.append("%s could not be opened for writing" % \
+ self.world_file)
+ return errors
+ finally:
+ world_set.unlock()
+
+class BinhostHandler(object):
+
+ short_desc = "Generate a metadata index for binary packages"
+
+ def name():
+ return "binhost"
+ name = staticmethod(name)
+
+ def __init__(self):
+ myroot = portage.settings["ROOT"]
+ self._bintree = portage.db[myroot]["bintree"]
+ self._bintree.populate()
+ self._pkgindex_file = self._bintree._pkgindex_file
+ self._pkgindex = self._bintree._load_pkgindex()
+
+ def _need_update(self, cpv, data):
+
+ if "MD5" not in data:
+ return True
+
+ size = data.get("SIZE")
+ if size is None:
+ return True
+
+ mtime = data.get("MTIME")
+ if mtime is None:
+ return True
+
+ pkg_path = self._bintree.getname(cpv)
+ try:
+ s = os.lstat(pkg_path)
+ except OSError as e:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
+ raise
+ # We can't update the index for this one because
+ # it disappeared.
+ return False
+
+ try:
+ if long(mtime) != s[stat.ST_MTIME]:
+ return True
+ if long(size) != long(s.st_size):
+ return True
+ except ValueError:
+ return True
+
+ return False
+
+ def check(self, onProgress=None):
+ missing = []
+ cpv_all = self._bintree.dbapi.cpv_all()
+ cpv_all.sort()
+ maxval = len(cpv_all)
+ if onProgress:
+ onProgress(maxval, 0)
+ pkgindex = self._pkgindex
+ missing = []
+ metadata = {}
+ for d in pkgindex.packages:
+ metadata[d["CPV"]] = d
+ for i, cpv in enumerate(cpv_all):
+ d = metadata.get(cpv)
+ if not d or self._need_update(cpv, d):
+ missing.append(cpv)
+ if onProgress:
+ onProgress(maxval, i+1)
+ errors = ["'%s' is not in Packages" % cpv for cpv in missing]
+ stale = set(metadata).difference(cpv_all)
+ for cpv in stale:
+ errors.append("'%s' is not in the repository" % cpv)
+ return errors
+
+ def fix(self, onProgress=None):
+ bintree = self._bintree
+ cpv_all = self._bintree.dbapi.cpv_all()
+ cpv_all.sort()
+ missing = []
+ maxval = 0
+ if onProgress:
+ onProgress(maxval, 0)
+ pkgindex = self._pkgindex
+ missing = []
+ metadata = {}
+ for d in pkgindex.packages:
+ metadata[d["CPV"]] = d
+
+ for i, cpv in enumerate(cpv_all):
+ d = metadata.get(cpv)
+ if not d or self._need_update(cpv, d):
+ missing.append(cpv)
+
+ stale = set(metadata).difference(cpv_all)
+ if missing or stale:
+ from portage import locks
+ pkgindex_lock = locks.lockfile(
+ self._pkgindex_file, wantnewlockfile=1)
+ try:
+ # Repopulate with lock held.
+ bintree._populate()
+ cpv_all = self._bintree.dbapi.cpv_all()
+ cpv_all.sort()
+
+ pkgindex = bintree._load_pkgindex()
+ self._pkgindex = pkgindex
+
+ metadata = {}
+ for d in pkgindex.packages:
+ metadata[d["CPV"]] = d
+
+ # Recount missing packages, with lock held.
+ del missing[:]
+ for i, cpv in enumerate(cpv_all):
+ d = metadata.get(cpv)
+ if not d or self._need_update(cpv, d):
+ missing.append(cpv)
+
+ maxval = len(missing)
+ for i, cpv in enumerate(missing):
+ try:
+ metadata[cpv] = bintree._pkgindex_entry(cpv)
+ except portage.exception.InvalidDependString:
+ writemsg("!!! Invalid binary package: '%s'\n" % \
+ bintree.getname(cpv), noiselevel=-1)
+
+ if onProgress:
+ onProgress(maxval, i+1)
+
+ for cpv in set(metadata).difference(
+ self._bintree.dbapi.cpv_all()):
+ del metadata[cpv]
+
+ # We've updated the pkgindex, so set it to
+ # repopulate when necessary.
+ bintree.populated = False
+
+ del pkgindex.packages[:]
+ pkgindex.packages.extend(metadata.values())
+ from portage.util import atomic_ofstream
+ f = atomic_ofstream(self._pkgindex_file)
+ try:
+ self._pkgindex.write(f)
+ finally:
+ f.close()
+ finally:
+ locks.unlockfile(pkgindex_lock)
+
+ if onProgress:
+ if maxval == 0:
+ maxval = 1
+ onProgress(maxval, maxval)
+ return None
+
+class MoveHandler(object):
+
+ def __init__(self, tree, porttree):
+ self._tree = tree
+ self._portdb = porttree.dbapi
+ self._update_keys = ["DEPEND", "RDEPEND", "PDEPEND", "PROVIDE"]
+ self._master_repo = \
+ self._portdb.getRepositoryName(self._portdb.porttree_root)
+
+ def _grab_global_updates(self):
+ from portage.update import grab_updates, parse_updates
+ retupdates = {}
+ errors = []
+
+ for repo_name in self._portdb.getRepositories():
+ repo = self._portdb.getRepositoryPath(repo_name)
+ updpath = os.path.join(repo, "profiles", "updates")
+ if not os.path.isdir(updpath):
+ continue
+
+ try:
+ rawupdates = grab_updates(updpath)
+ except portage.exception.DirectoryNotFound:
+ rawupdates = []
+ upd_commands = []
+ for mykey, mystat, mycontent in rawupdates:
+ commands, errors = parse_updates(mycontent)
+ upd_commands.extend(commands)
+ errors.extend(errors)
+ retupdates[repo_name] = upd_commands
+
+ if self._master_repo in retupdates:
+ retupdates['DEFAULT'] = retupdates[self._master_repo]
+
+ return retupdates, errors
+
+ def check(self, onProgress=None):
+ allupdates, errors = self._grab_global_updates()
+ # Matching packages and moving them is relatively fast, so the
+ # progress bar is updated in indeterminate mode.
+ match = self._tree.dbapi.match
+ aux_get = self._tree.dbapi.aux_get
+ if onProgress:
+ onProgress(0, 0)
+ for repo, updates in allupdates.items():
+ if repo == 'DEFAULT':
+ continue
+ if not updates:
+ continue
+
+ def repo_match(repository):
+ return repository == repo or \
+ (repo == self._master_repo and \
+ repository not in allupdates)
+
+ for i, update_cmd in enumerate(updates):
+ if update_cmd[0] == "move":
+ origcp, newcp = update_cmd[1:]
+ for cpv in match(origcp):
+ if repo_match(aux_get(cpv, ["repository"])[0]):
+ errors.append("'%s' moved to '%s'" % (cpv, newcp))
+ elif update_cmd[0] == "slotmove":
+ pkg, origslot, newslot = update_cmd[1:]
+ for cpv in match(pkg):
+ slot, prepo = aux_get(cpv, ["SLOT", "repository"])
+ if slot == origslot and repo_match(prepo):
+ errors.append("'%s' slot moved from '%s' to '%s'" % \
+ (cpv, origslot, newslot))
+ if onProgress:
+ onProgress(0, 0)
+
+ # Searching for updates in all the metadata is relatively slow, so this
+ # is where the progress bar comes out of indeterminate mode.
+ cpv_all = self._tree.dbapi.cpv_all()
+ cpv_all.sort()
+ maxval = len(cpv_all)
+ aux_update = self._tree.dbapi.aux_update
+ meta_keys = self._update_keys + ['repository']
+ from portage.update import update_dbentries
+ if onProgress:
+ onProgress(maxval, 0)
+ for i, cpv in enumerate(cpv_all):
+ metadata = dict(zip(meta_keys, aux_get(cpv, meta_keys)))
+ repository = metadata.pop('repository')
+ try:
+ updates = allupdates[repository]
+ except KeyError:
+ try:
+ updates = allupdates['DEFAULT']
+ except KeyError:
+ continue
+ if not updates:
+ continue
+ metadata_updates = update_dbentries(updates, metadata)
+ if metadata_updates:
+ errors.append("'%s' has outdated metadata" % cpv)
+ if onProgress:
+ onProgress(maxval, i+1)
+ return errors
+
+ def fix(self, onProgress=None):
+ allupdates, errors = self._grab_global_updates()
+ # Matching packages and moving them is relatively fast, so the
+ # progress bar is updated in indeterminate mode.
+ move = self._tree.dbapi.move_ent
+ slotmove = self._tree.dbapi.move_slot_ent
+ if onProgress:
+ onProgress(0, 0)
+ for repo, updates in allupdates.items():
+ if repo == 'DEFAULT':
+ continue
+ if not updates:
+ continue
+
+ def repo_match(repository):
+ return repository == repo or \
+ (repo == self._master_repo and \
+ repository not in allupdates)
+
+ for i, update_cmd in enumerate(updates):
+ if update_cmd[0] == "move":
+ move(update_cmd, repo_match=repo_match)
+ elif update_cmd[0] == "slotmove":
+ slotmove(update_cmd, repo_match=repo_match)
+ if onProgress:
+ onProgress(0, 0)
+
+ # Searching for updates in all the metadata is relatively slow, so this
+ # is where the progress bar comes out of indeterminate mode.
+ self._tree.dbapi.update_ents(allupdates, onProgress=onProgress)
+ return errors
+
+class MoveInstalled(MoveHandler):
+
+ short_desc = "Perform package move updates for installed packages"
+
+ def name():
+ return "moveinst"
+ name = staticmethod(name)
+ def __init__(self):
+ myroot = portage.settings["ROOT"]
+ MoveHandler.__init__(self, portage.db[myroot]["vartree"], portage.db[myroot]["porttree"])
+
+class MoveBinary(MoveHandler):
+
+ short_desc = "Perform package move updates for binary packages"
+
+ def name():
+ return "movebin"
+ name = staticmethod(name)
+ def __init__(self):
+ myroot = portage.settings["ROOT"]
+ MoveHandler.__init__(self, portage.db[myroot]["bintree"], portage.db[myroot]["porttree"])
+
+class VdbKeyHandler(object):
+ def name():
+ return "vdbkeys"
+ name = staticmethod(name)
+
+ def __init__(self):
+ self.list = portage.db["/"]["vartree"].dbapi.cpv_all()
+ self.missing = []
+ self.keys = ["HOMEPAGE", "SRC_URI", "KEYWORDS", "DESCRIPTION"]
+
+ for p in self.list:
+ mydir = os.path.join(portage.settings["EROOT"], portage.const.VDB_PATH, p)+os.sep
+ ismissing = True
+ for k in self.keys:
+ if os.path.exists(mydir+k):
+ ismissing = False
+ break
+ if ismissing:
+ self.missing.append(p)
+
+ def check(self):
+ return ["%s has missing keys" % x for x in self.missing]
+
+ def fix(self):
+
+ errors = []
+
+ for p in self.missing:
+ mydir = os.path.join(portage.settings["EROOT"], portage.const.VDB_PATH, p)+os.sep
+ if not os.access(mydir+"environment.bz2", os.R_OK):
+ errors.append("Can't access %s" % (mydir+"environment.bz2"))
+ elif not os.access(mydir, os.W_OK):
+ errors.append("Can't create files in %s" % mydir)
+ else:
+ env = os.popen("bzip2 -dcq "+mydir+"environment.bz2", "r")
+ envlines = env.read().split("\n")
+ env.close()
+ for k in self.keys:
+ s = [l for l in envlines if l.startswith(k+"=")]
+ if len(s) > 1:
+ errors.append("multiple matches for %s found in %senvironment.bz2" % (k, mydir))
+ elif len(s) == 0:
+ s = ""
+ else:
+ s = s[0].split("=",1)[1]
+ s = s.lstrip("$").strip("\'\"")
+ s = re.sub("(\\\\[nrt])+", " ", s)
+ s = " ".join(s.split()).strip()
+ if s != "":
+ try:
+ keyfile = open(mydir+os.sep+k, "w")
+ keyfile.write(s+"\n")
+ keyfile.close()
+ except (IOError, OSError) as e:
+ errors.append("Could not write %s, reason was: %s" % (mydir+k, e))
+
+ return errors
+
+class ProgressHandler(object):
+ def __init__(self):
+ self.curval = 0
+ self.maxval = 0
+ self.last_update = 0
+ self.min_display_latency = 0.2
+
+ def onProgress(self, maxval, curval):
+ self.maxval = maxval
+ self.curval = curval
+ cur_time = time.time()
+ if cur_time - self.last_update >= self.min_display_latency:
+ self.last_update = cur_time
+ self.display()
+
+ def display(self):
+ raise NotImplementedError(self)
+
+class CleanResume(object):
+
+ short_desc = "Discard emerge --resume merge lists"
+
+ def name():
+ return "cleanresume"
+ name = staticmethod(name)
+
+ def check(self, onProgress=None):
+ messages = []
+ mtimedb = portage.mtimedb
+ resume_keys = ("resume", "resume_backup")
+ maxval = len(resume_keys)
+ if onProgress:
+ onProgress(maxval, 0)
+ for i, k in enumerate(resume_keys):
+ try:
+ d = mtimedb.get(k)
+ if d is None:
+ continue
+ if not isinstance(d, dict):
+ messages.append("unrecognized resume list: '%s'" % k)
+ continue
+ mergelist = d.get("mergelist")
+ if mergelist is None or not hasattr(mergelist, "__len__"):
+ messages.append("unrecognized resume list: '%s'" % k)
+ continue
+ messages.append("resume list '%s' contains %d packages" % \
+ (k, len(mergelist)))
+ finally:
+ if onProgress:
+ onProgress(maxval, i+1)
+ return messages
+
+ def fix(self, onProgress=None):
+ delete_count = 0
+ mtimedb = portage.mtimedb
+ resume_keys = ("resume", "resume_backup")
+ maxval = len(resume_keys)
+ if onProgress:
+ onProgress(maxval, 0)
+ for i, k in enumerate(resume_keys):
+ try:
+ if mtimedb.pop(k, None) is not None:
+ delete_count += 1
+ finally:
+ if onProgress:
+ onProgress(maxval, i+1)
+ if delete_count:
+ mtimedb.commit()
+
+def emaint_main(myargv):
+
+ # Similar to emerge, emaint needs a default umask so that created
+ # files (such as the world file) have sane permissions.
+ os.umask(0o22)
+
+ # TODO: Create a system that allows external modules to be added without
+ # the need for hard coding.
+ modules = {
+ "world" : WorldHandler,
+ "binhost":BinhostHandler,
+ "moveinst":MoveInstalled,
+ "movebin":MoveBinary,
+ "cleanresume":CleanResume
+ }
+
+ module_names = list(modules)
+ module_names.sort()
+ module_names.insert(0, "all")
+
+ def exclusive(option, *args, **kw):
+ var = kw.get("var", None)
+ if var is None:
+ raise ValueError("var not specified to exclusive()")
+ if getattr(parser, var, ""):
+ raise OptionValueError("%s and %s are exclusive options" % (getattr(parser, var), option))
+ setattr(parser, var, str(option))
+
+
+ usage = "usage: emaint [options] COMMAND"
+
+ desc = "The emaint program provides an interface to system health " + \
+ "checks and maintenance. See the emaint(1) man page " + \
+ "for additional information about the following commands:"
+
+ usage += "\n\n"
+ for line in textwrap.wrap(desc, 65):
+ usage += "%s\n" % line
+ usage += "\n"
+ usage += " %s" % "all".ljust(15) + \
+ "Perform all supported commands\n"
+ for m in module_names[1:]:
+ usage += " %s%s\n" % (m.ljust(15), modules[m].short_desc)
+
+ parser = OptionParser(usage=usage, version=portage.VERSION)
+ parser.add_option("-c", "--check", help="check for problems",
+ action="callback", callback=exclusive, callback_kwargs={"var":"action"})
+ parser.add_option("-f", "--fix", help="attempt to fix problems",
+ action="callback", callback=exclusive, callback_kwargs={"var":"action"})
+ parser.action = None
+
+
+ (options, args) = parser.parse_args(args=myargv)
+ if len(args) != 1:
+ parser.error("Incorrect number of arguments")
+ if args[0] not in module_names:
+ parser.error("%s target is not a known target" % args[0])
+
+ if parser.action:
+ action = parser.action
+ else:
+ print("Defaulting to --check")
+ action = "-c/--check"
+
+ if args[0] == "all":
+ tasks = modules.values()
+ else:
+ tasks = [modules[args[0]]]
+
+
+ if action == "-c/--check":
+ status = "Checking %s for problems"
+ func = "check"
+ else:
+ status = "Attempting to fix %s"
+ func = "fix"
+
+ isatty = os.environ.get('TERM') != 'dumb' and sys.stdout.isatty()
+ for task in tasks:
+ print(status % task.name())
+ inst = task()
+ onProgress = None
+ if isatty:
+ progressBar = portage.output.TermProgressBar()
+ progressHandler = ProgressHandler()
+ onProgress = progressHandler.onProgress
+ def display():
+ progressBar.set(progressHandler.curval, progressHandler.maxval)
+ progressHandler.display = display
+ def sigwinch_handler(signum, frame):
+ lines, progressBar.term_columns = \
+ portage.output.get_term_size()
+ signal.signal(signal.SIGWINCH, sigwinch_handler)
+ result = getattr(inst, func)(onProgress=onProgress)
+ if isatty:
+ # make sure the final progress is displayed
+ progressHandler.display()
+ print()
+ signal.signal(signal.SIGWINCH, signal.SIG_DFL)
+ if result:
+ print()
+ print("\n".join(result))
+ print("\n")
+
+ print("Finished")
+
+if __name__ == "__main__":
+ emaint_main(sys.argv[1:])
diff --git a/portage_with_autodep/bin/emerge b/portage_with_autodep/bin/emerge
new file mode 100755
index 0000000..6f69244
--- /dev/null
+++ b/portage_with_autodep/bin/emerge
@@ -0,0 +1,66 @@
+#!/usr/bin/python
+# Copyright 2006-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import signal
+import sys
+# This block ensures that ^C interrupts are handled quietly.
+try:
+
+ def exithandler(signum,frame):
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
+ sys.exit(128 + signum)
+
+ signal.signal(signal.SIGINT, exithandler)
+ signal.signal(signal.SIGTERM, exithandler)
+ # Prevent "[Errno 32] Broken pipe" exceptions when
+ # writing to a pipe.
+ signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+
+except KeyboardInterrupt:
+ sys.exit(128 + signal.SIGINT)
+
+def debug_signal(signum, frame):
+ import pdb
+ pdb.set_trace()
+signal.signal(signal.SIGUSR1, debug_signal)
+
+try:
+ from _emerge.main import emerge_main
+except ImportError:
+ from os import path as osp
+ import sys
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
+ from _emerge.main import emerge_main
+
+if __name__ == "__main__":
+ import sys
+ from portage.exception import ParseError, PermissionDenied
+ try:
+ retval = emerge_main()
+ except PermissionDenied as e:
+ sys.stderr.write("Permission denied: '%s'\n" % str(e))
+ sys.exit(e.errno)
+ except ParseError as e:
+ sys.stderr.write("%s\n" % str(e))
+ sys.exit(1)
+ except SystemExit:
+ raise
+ except Exception:
+ # If an unexpected exception occurs then we don't want the mod_echo
+ # output to obscure the traceback, so dump the mod_echo output before
+ # showing the traceback.
+ import traceback
+ tb_str = traceback.format_exc()
+ try:
+ from portage.elog import mod_echo
+ except ImportError:
+ pass
+ else:
+ mod_echo.finalize()
+ sys.stderr.write(tb_str)
+ sys.exit(1)
+ sys.exit(retval)
diff --git a/portage_with_autodep/bin/emerge-webrsync b/portage_with_autodep/bin/emerge-webrsync
new file mode 100755
index 0000000..d933871
--- /dev/null
+++ b/portage_with_autodep/bin/emerge-webrsync
@@ -0,0 +1,457 @@
+#!/bin/bash
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# Author: Karl Trygve Kalleberg <karltk@gentoo.org>
+# Rewritten from the old, Perl-based emerge-webrsync script
+# Author: Alon Bar-Lev <alon.barlev@gmail.com>
+# Major rewrite from Karl's scripts.
+
+# TODO:
+# - all output should prob be converted to e* funcs
+# - add support for ROOT
+
+#
+# gpg key import
+# KEY_ID=0x239C75C4
+# gpg --homedir /etc/portage/gnupg --keyserver subkeys.pgp.net --recv-keys $KEY_ID
+# gpg --homedir /etc/portage/gnupg --edit-key $KEY_ID trust
+#
+
+# Only echo if in verbose mode
+vvecho() { [[ ${do_verbose} -eq 1 ]] && echo "$@" ; }
+# Only echo if not in verbose mode
+nvecho() { [[ ${do_verbose} -eq 0 ]] && echo "$@" ; }
+# warning echos
+wecho() { echo "${argv0}: warning: $*" 1>&2 ; }
+# error echos
+eecho() { echo "${argv0}: error: $*" 1>&2 ; }
+
+argv0=$0
+if ! type -P portageq > /dev/null ; then
+ eecho "could not find 'portageq'; aborting"
+ exit 1
+fi
+eval $(portageq envvar -v FEATURES FETCHCOMMAND GENTOO_MIRRORS \
+ PORTAGE_BIN_PATH PORTAGE_GPG_DIR \
+ PORTAGE_NICENESS PORTAGE_RSYNC_EXTRA_OPTS PORTAGE_TMPDIR PORTDIR \
+ SYNC http_proxy ftp_proxy)
+DISTDIR="${PORTAGE_TMPDIR}/emerge-webrsync"
+export http_proxy ftp_proxy
+
+# If PORTAGE_NICENESS is overriden via the env then it will
+# still pass through the portageq call and override properly.
+if [ -n "${PORTAGE_NICENESS}" ]; then
+ renice $PORTAGE_NICENESS $$ > /dev/null
+fi
+
+source "${PORTAGE_BIN_PATH}"/isolated-functions.sh || exit 1
+
+do_verbose=0
+do_debug=0
+
+if has webrsync-gpg ${FEATURES} ; then
+ WEBSYNC_VERIFY_SIGNATURE=1
+else
+ WEBSYNC_VERIFY_SIGNATURE=0
+fi
+if [ ${WEBSYNC_VERIFY_SIGNATURE} != 0 -a -z "${PORTAGE_GPG_DIR}" ]; then
+ eecho "please set PORTAGE_GPG_DIR in make.conf"
+ exit 1
+fi
+
+do_tar() {
+ local file=$1; shift
+ local decompressor
+ case ${file} in
+ *.xz) decompressor="xzcat" ;;
+ *.bz2) decompressor="bzcat" ;;
+ *.gz) decompressor="zcat" ;;
+ *) decompressor="cat" ;;
+ esac
+ ${decompressor} "${file}" | tar "$@"
+ _pipestatus=${PIPESTATUS[*]}
+ [[ ${_pipestatus// /} -eq 0 ]]
+}
+
+get_utc_date_in_seconds() {
+ date -u +"%s"
+}
+
+get_date_part() {
+ local utc_time_in_secs="$1"
+ local part="$2"
+
+ if [[ ${USERLAND} == BSD ]] ; then
+ date -r ${utc_time_in_secs} -u +"${part}"
+ else
+ date -d @${utc_time_in_secs} -u +"${part}"
+ fi
+}
+
+get_utc_second_from_string() {
+ local s="$1"
+ if [[ ${USERLAND} == BSD ]] ; then
+ date -juf "%Y%m%d" "$s" +"%s"
+ else
+ date -d "${s:0:4}-${s:4:2}-${s:6:2}" -u +"%s"
+ fi
+}
+
+get_portage_timestamp() {
+ local portage_current_timestamp=0
+
+ if [ -f "${PORTDIR}/metadata/timestamp.x" ]; then
+ portage_current_timestamp=$(cut -f 1 -d " " "${PORTDIR}/metadata/timestamp.x" )
+ fi
+
+ echo "${portage_current_timestamp}"
+}
+
+fetch_file() {
+ local URI="$1"
+ local FILE="$2"
+ local opts
+
+ if [ "${FETCHCOMMAND/wget/}" != "${FETCHCOMMAND}" ]; then
+ opts="--continue $(nvecho -q)"
+ elif [ "${FETCHCOMMAND/curl/}" != "${FETCHCOMMAND}" ]; then
+ opts="--continue-at - $(nvecho -s -f)"
+ else
+ rm -f "${FILE}"
+ fi
+
+ vecho "Fetching file ${FILE} ..."
+ # already set DISTDIR=
+ eval "${FETCHCOMMAND}" ${opts}
+ [ -s "${FILE}" ]
+}
+
+check_file_digest() {
+ local digest="$1"
+ local file="$2"
+ local r=1
+
+ vecho "Checking digest ..."
+
+ if type -P md5sum > /dev/null; then
+ md5sum -c $digest && r=0
+ elif type -P md5 > /dev/null; then
+ [ "$(md5 -q "${file}")" == "$(cut -d ' ' -f 1 "${digest}")" ] && r=0
+ else
+ eecho "cannot check digest: no suitable md5/md5sum binaries found"
+ fi
+
+ return "${r}"
+}
+
+check_file_signature() {
+ local signature="$1"
+ local file="$2"
+ local r=1
+
+ if [ ${WEBSYNC_VERIFY_SIGNATURE} != 0 ]; then
+
+ vecho "Checking signature ..."
+
+ if type -P gpg > /dev/null; then
+ gpg --homedir "${PORTAGE_GPG_DIR}" --verify "$signature" "$file" && r=0
+ else
+ eecho "cannot check signature: gpg binary not found"
+ fi
+ else
+ r=0
+ fi
+
+ return "${r}"
+}
+
+get_snapshot_timestamp() {
+ local file="$1"
+
+ do_tar "${file}" --to-stdout -xf - portage/metadata/timestamp.x | cut -f 1 -d " "
+}
+
+sync_local() {
+ local file="$1"
+
+ vecho "Syncing local tree ..."
+
+ if type -P tarsync > /dev/null ; then
+ local chown_opts="-o portage -g portage"
+ chown portage:portage portage > /dev/null 2>&1 || chown_opts=""
+ if ! tarsync $(vvecho -v) -s 1 ${chown_opts} \
+ -e /distfiles -e /packages -e /local "${file}" "${PORTDIR}"; then
+ eecho "tarsync failed; tarball is corrupt? (${file})"
+ return 1
+ fi
+ else
+ if ! do_tar "${file}" xf -; then
+ eecho "tar failed to extract the image. tarball is corrupt? (${file})"
+ rm -fr portage
+ return 1
+ fi
+
+ # Free disk space
+ rm -f "${file}"
+
+ chown portage:portage portage > /dev/null 2>&1 && \
+ chown -R portage:portage portage
+ cd portage
+ rsync -av --progress --stats --delete --delete-after \
+ --exclude='/distfiles' --exclude='/packages' \
+ --exclude='/local' ${PORTAGE_RSYNC_EXTRA_OPTS} . "${PORTDIR%%/}"
+ cd ..
+
+ vecho "Cleaning up ..."
+ rm -fr portage
+ fi
+
+ if has metadata-transfer ${FEATURES} ; then
+ vecho "Updating cache ..."
+ emerge --metadata
+ fi
+ [ -x /etc/portage/bin/post_sync ] && /etc/portage/bin/post_sync
+ return 0
+}
+
+do_snapshot() {
+ local ignore_timestamp="$1"
+ local date="$2"
+
+ local r=1
+
+ local base_file="portage-${date}.tar"
+
+ local have_files=0
+ local mirror
+
+ local compressions=""
+ # xz is not supported in app-arch/tarsync, so use
+ # bz2 format if we have tarsync.
+ if ! type -P tarsync > /dev/null ; then
+ type -P xzcat > /dev/null && compressions="${compressions} xz"
+ fi
+ type -P bzcat > /dev/null && compressions="${compressions} bz2"
+ type -P zcat > /dev/null && compressions="${compressions} gz"
+ if [[ -z ${compressions} ]] ; then
+ eecho "unable to locate any decompressors (xzcat or bzcat or zcat)"
+ exit 1
+ fi
+
+ for mirror in ${GENTOO_MIRRORS} ; do
+
+ vecho "Trying to retrieve ${date} snapshot from ${mirror} ..."
+
+ for compression in ${compressions} ; do
+ local file="portage-${date}.tar.${compression}"
+ local digest="${file}.md5sum"
+ local signature="${file}.gpgsig"
+
+ if [ -s "${file}" -a -s "${digest}" -a -s "${signature}" ] ; then
+ check_file_digest "${DISTDIR}/${digest}" "${DISTDIR}/${file}" && \
+ check_file_signature "${DISTDIR}/${signature}" "${DISTDIR}/${file}" && \
+ have_files=1
+ fi
+
+ if [ ${have_files} -eq 0 ] ; then
+ fetch_file "${mirror}/snapshots/${digest}" "${digest}" && \
+ fetch_file "${mirror}/snapshots/${signature}" "${signature}" && \
+ fetch_file "${mirror}/snapshots/${file}" "${file}" && \
+ check_file_digest "${DISTDIR}/${digest}" "${DISTDIR}/${file}" && \
+ check_file_signature "${DISTDIR}/${signature}" "${DISTDIR}/${file}" && \
+ have_files=1
+ fi
+
+ #
+ # If timestamp is invalid
+ # we want to try and retrieve
+ # from a different mirror
+ #
+ if [ ${have_files} -eq 1 ]; then
+
+ vecho "Getting snapshot timestamp ..."
+ local snapshot_timestamp=$(get_snapshot_timestamp "${file}")
+
+ if [ ${ignore_timestamp} == 0 ]; then
+ if [ ${snapshot_timestamp} -lt $(get_portage_timestamp) ]; then
+ wecho "portage is newer than snapshot"
+ have_files=0
+ fi
+ else
+ local utc_seconds=$(get_utc_second_from_string "${date}")
+
+ #
+ # Check that this snapshot
+ # is what it claims to be ...
+ #
+ if [ ${snapshot_timestamp} -lt ${utc_seconds} ] || \
+ [ ${snapshot_timestamp} -gt $((${utc_seconds}+ 2*86400)) ]; then
+
+ wecho "snapshot timestamp is not in acceptable period"
+ have_files=0
+ fi
+ fi
+ fi
+
+ if [ ${have_files} -eq 1 ]; then
+ break
+ else
+ #
+ # Remove files and use a different mirror
+ #
+ rm -f "${file}" "${digest}" "${signature}"
+ fi
+ done
+
+ [ ${have_files} -eq 1 ] && break
+ done
+
+ if [ ${have_files} -eq 1 ]; then
+ sync_local "${file}" && r=0
+ else
+ vecho "${date} snapshot was not found"
+ fi
+
+ rm -f "${file}" "${digest}" "${signature}"
+ return "${r}"
+}
+
+do_latest_snapshot() {
+ local attempts=0
+ local r=1
+
+ vecho "Fetching most recent snapshot ..."
+
+ # The snapshot for a given day is generated at 01:45 UTC on the following
+ # day, so the current day's snapshot (going by UTC time) hasn't been
+ # generated yet. Therefore, always start by looking for the previous day's
+ # snapshot (for attempts=1, subtract 1 day from the current UTC time).
+
+ # Timestamps that differ by less than 2 hours
+ # are considered to be approximately equal.
+ local min_time_diff=$(( 2 * 60 * 60 ))
+
+ local existing_timestamp=$(get_portage_timestamp)
+ local timestamp_difference
+ local timestamp_problem
+ local approx_snapshot_time
+ local start_time=$(get_utc_date_in_seconds)
+ local start_hour=$(get_date_part ${start_time} "%H")
+
+ # Daily snapshots are created at 1:45 AM and are not
+ # available until after 2 AM. Don't waste time trying
+ # to fetch a snapshot before it's been created.
+ if [ ${start_hour} -lt 2 ] ; then
+ (( start_time -= 86400 ))
+ fi
+ local snapshot_date=$(get_date_part ${start_time} "%Y%m%d")
+ local snapshot_date_seconds=$(get_utc_second_from_string ${snapshot_date})
+
+ while (( ${attempts} < 40 )) ; do
+ (( attempts++ ))
+ (( snapshot_date_seconds -= 86400 ))
+ # snapshots are created at 1:45 AM
+ (( approx_snapshot_time = snapshot_date_seconds + 86400 + 6300 ))
+ (( timestamp_difference = existing_timestamp - approx_snapshot_time ))
+ [ ${timestamp_difference} -lt 0 ] && (( timestamp_difference = -1 * timestamp_difference ))
+ snapshot_date=$(get_date_part ${snapshot_date_seconds} "%Y%m%d")
+
+ timestamp_problem=""
+ if [ ${timestamp_difference} -eq 0 ]; then
+ timestamp_problem="is identical to"
+ elif [ ${timestamp_difference} -lt ${min_time_diff} ]; then
+ timestamp_problem="is possibly identical to"
+ elif [ ${approx_snapshot_time} -lt ${existing_timestamp} ] ; then
+ timestamp_problem="is newer than"
+ fi
+
+ if [ -n "${timestamp_problem}" ]; then
+ ewarn "Latest snapshot date: ${snapshot_date}"
+ ewarn
+ ewarn "Approximate snapshot timestamp: ${approx_snapshot_time}"
+ ewarn " Current local timestamp: ${existing_timestamp}"
+ ewarn
+ echo -e "The current local timestamp" \
+ "${timestamp_problem} the" \
+ "timestamp of the latest" \
+ "snapshot. In order to force sync," \
+ "use the --revert option or remove" \
+ "the timestamp file located at" \
+ "'${PORTDIR}/metadata/timestamp.x'." | fmt -w 70 | \
+ while read -r line ; do
+ ewarn "${line}"
+ done
+ r=0
+ break
+ fi
+
+ if do_snapshot 0 "${snapshot_date}"; then
+ r=0
+ break;
+ fi
+ done
+
+ return "${r}"
+}
+
+usage() {
+ cat <<-EOF
+ Usage: $0 [options]
+
+ Options:
+ --revert=yyyymmdd Revert to snapshot
+ -q, --quiet Only output errors
+ -v, --verbose Enable verbose output
+ -x, --debug Enable debug output
+ -h, --help This help screen (duh!)
+ EOF
+ if [[ -n $* ]] ; then
+ printf "\nError: %s\n" "$*" 1>&2
+ exit 1
+ else
+ exit 0
+ fi
+}
+
+main() {
+ local arg
+ local revert_date
+
+ [ ! -d "${DISTDIR}" ] && mkdir -p "${DISTDIR}"
+ cd "${DISTDIR}"
+
+ for arg in "$@" ; do
+ local v=${arg#*=}
+ case ${arg} in
+ -h|--help) usage ;;
+ -q|--quiet) PORTAGE_QUIET=1 ;;
+ -v|--verbose) do_verbose=1 ;;
+ -x|--debug) do_debug=1 ;;
+ --revert=*) revert_date=${v} ;;
+ *) usage "Invalid option '${arg}'" ;;
+ esac
+ done
+
+ # This is a sanity check to help prevent people like funtoo users
+ # from accidentally wiping out their git tree.
+ if [[ -n $SYNC && ${SYNC#rsync:} = $SYNC ]] ; then
+ echo "The current SYNC variable setting does not refer to an rsync URI:" >&2
+ echo >&2
+ echo " SYNC=$SYNC" >&2
+ echo >&2
+ echo "If you intend to use emerge-webrsync then please" >&2
+ echo "adjust SYNC to refer to an rsync URI." >&2
+ echo "emerge-webrsync exiting due to abnormal SYNC setting." >&2
+ exit 1
+ fi
+
+ [[ ${do_debug} -eq 1 ]] && set -x
+
+ if [[ -n ${revert_date} ]] ; then
+ do_snapshot 1 "${revert_date}"
+ else
+ do_latest_snapshot
+ fi
+}
+
+main "$@"
diff --git a/portage_with_autodep/bin/env-update b/portage_with_autodep/bin/env-update
new file mode 100755
index 0000000..8a69f2b
--- /dev/null
+++ b/portage_with_autodep/bin/env-update
@@ -0,0 +1,41 @@
+#!/usr/bin/python -O
+# Copyright 1999-2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import errno
+import sys
+
+def usage(status):
+ print("Usage: env-update [--no-ldconfig]")
+ print("")
+ print("See the env-update(1) man page for more info")
+ sys.exit(status)
+
+if "-h" in sys.argv or "--help" in sys.argv:
+ usage(0)
+
+makelinks=1
+if "--no-ldconfig" in sys.argv:
+ makelinks=0
+ sys.argv.pop(sys.argv.index("--no-ldconfig"))
+
+if len(sys.argv) > 1:
+ print("!!! Invalid command line options!\n")
+ usage(1)
+
+try:
+ import portage
+except ImportError:
+ from os import path as osp
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
+ import portage
+try:
+ portage.env_update(makelinks)
+except IOError as e:
+ if e.errno == errno.EACCES:
+ print("env-update: Need superuser access")
+ sys.exit(1)
+ else:
+ raise
diff --git a/portage_with_autodep/bin/etc-update b/portage_with_autodep/bin/etc-update
new file mode 100755
index 0000000..42518ad
--- /dev/null
+++ b/portage_with_autodep/bin/etc-update
@@ -0,0 +1,616 @@
+#!/bin/bash
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Author Brandon Low <lostlogic@gentoo.org>
+#
+# Previous version (from which I've borrowed a few bits) by:
+# Jochem Kossen <j.kossen@home.nl>
+# Leo Lipelis <aeoo@gentoo.org>
+# Karl Trygve Kalleberg <karltk@gentoo.org>
+
+cd /
+
+if type -P gsed >/dev/null ; then
+ sed() { gsed "$@"; }
+fi
+
+get_config() {
+ # the sed here does:
+ # - strip off comments
+ # - match lines that set item in question
+ # - delete the "item =" part
+ # - store the actual value into the hold space
+ # - on the last line, restore the hold space and print it
+ # If there's more than one of the same configuration item, then
+ # the store to the hold space clobbers previous value so the last
+ # setting takes precedence.
+ local item=$1
+ eval echo $(sed -n \
+ -e 's:[[:space:]]*#.*$::' \
+ -e "/^[[:space:]]*$item[[:space:]]*=/{s:[^=]*=[[:space:]]*\([\"']\{0,1\}\)\(.*\)\1:\2:;h}" \
+ -e '${g;p}' \
+ "${PORTAGE_CONFIGROOT}"etc/etc-update.conf)
+}
+
+diff_command() {
+ local cmd=${diff_command//%file1/$1}
+ ${cmd//%file2/$2}
+}
+
+scan() {
+ echo "Scanning Configuration files..."
+ rm -rf ${TMP}/files > /dev/null 2>&1
+ mkdir ${TMP}/files || die "Failed mkdir command!" 1
+ count=0
+ input=0
+ local find_opts
+ local my_basename
+
+ for path in ${CONFIG_PROTECT} ; do
+ path="${ROOT}${path}"
+ # Do not traverse hidden directories such as .svn or .git.
+ find_opts="-name .* -type d -prune -o -name ._cfg????_*"
+ if [ ! -d "${path}" ]; then
+ [ ! -f "${path}" ] && continue
+ my_basename="${path##*/}"
+ path="${path%/*}"
+ find_opts="-maxdepth 1 -name ._cfg????_${my_basename}"
+ fi
+
+ ofile=""
+ # The below set -f turns off file name globbing in the ${find_opts} expansion.
+ for file in $(set -f ; find ${path}/ ${find_opts} \
+ ! -name '.*~' ! -iname '.*.bak' -print |
+ sed -e "s:\(^.*/\)\(\._cfg[0-9]*_\)\(.*$\):\1\2\3\%\1%\2\%\3:" |
+ sort -t'%' -k2,2 -k4,4 -k3,3 | LANG=POSIX LC_ALL=POSIX cut -f1 -d'%'); do
+
+ rpath=$(echo "${file/\/\///}" | sed -e "s:/[^/]*$::")
+ rfile=$(echo "${file/\/\///}" | sed -e "s:^.*/::")
+ for mpath in ${CONFIG_PROTECT_MASK}; do
+ mpath="${ROOT}${mpath}"
+ mpath=$(echo "${mpath/\/\///}")
+ if [[ "${rpath}" == "${mpath}"* ]]; then
+ mv ${rpath}/${rfile} ${rpath}/${rfile:10}
+ break
+ fi
+ done
+ if [[ ! -f ${file} ]] ; then
+ echo "Skipping non-file ${file} ..."
+ continue
+ fi
+
+ if [[ "${ofile:10}" != "${rfile:10}" ]] ||
+ [[ ${opath} != ${rpath} ]]; then
+ MATCHES=0
+ if [[ "${EU_AUTOMERGE}" == "yes" ]]; then
+ if [ ! -e "${rpath}/${rfile}" ] || [ ! -e "${rpath}/${rfile:10}" ]; then
+ MATCHES=0
+ else
+ diff -Bbua ${rpath}/${rfile} ${rpath}/${rfile:10} | egrep '^[+-]' | egrep -v '^[+-][\t ]*#|^--- |^\+\+\+ ' | egrep -qv '^[-+][\t ]*$'
+ MATCHES=$?
+ fi
+ elif [[ -z $(diff -Nua ${rpath}/${rfile} ${rpath}/${rfile:10}|
+ grep "^[+-][^+-]"|grep -v '# .Header:.*') ]]; then
+ MATCHES=1
+ fi
+ if [[ "${MATCHES}" == "1" ]]; then
+ echo "Automerging trivial changes in: ${rpath}/${rfile:10}"
+ mv ${rpath}/${rfile} ${rpath}/${rfile:10}
+ continue
+ else
+ count=${count}+1
+ echo "${rpath}/${rfile:10}" > ${TMP}/files/${count}
+ echo "${rpath}/${rfile}" >> ${TMP}/files/${count}
+ ofile="${rfile}"
+ opath="${rpath}"
+ continue
+ fi
+ fi
+
+ if [[ -z $(diff -Nua ${rpath}/${rfile} ${rpath}/${ofile}|
+ grep "^[+-][^+-]"|grep -v '# .Header:.*') ]]; then
+ mv ${rpath}/${rfile} ${rpath}/${ofile}
+ continue
+ else
+ echo "${rpath}/${rfile}" >> ${TMP}/files/${count}
+ ofile="${rfile}"
+ opath="${rpath}"
+ fi
+ done
+ done
+
+}
+
+sel_file() {
+ local -i isfirst=0
+ until [[ -f ${TMP}/files/${input} ]] || \
+ [[ ${input} == -1 ]] || \
+ [[ ${input} == -3 ]]
+ do
+ local numfiles=$(ls ${TMP}/files|wc -l)
+ local numwidth=${#numfiles}
+ for file in $(ls ${TMP}/files|sort -n); do
+ if [[ ${isfirst} == 0 ]] ; then
+ isfirst=${file}
+ fi
+ numshow=$(printf "%${numwidth}i${PAR} " ${file})
+ numupdates=$(( $(wc -l <${TMP}/files/${file}) - 1 ))
+ echo -n "${numshow}"
+ if [[ ${mode} == 0 ]] ; then
+ echo "$(head -n1 ${TMP}/files/${file}) (${numupdates})"
+ else
+ head -n1 ${TMP}/files/${file}
+ fi
+ done > ${TMP}/menuitems
+
+ if [ "${OVERWRITE_ALL}" == "yes" ]; then
+ input=0
+ elif [ "${DELETE_ALL}" == "yes" ]; then
+ input=0
+ else
+ [[ $CLEAR_TERM == yes ]] && clear
+ if [[ ${mode} == 0 ]] ; then
+ echo "The following is the list of files which need updating, each
+configuration file is followed by a list of possible replacement files."
+ else
+ local my_title="Please select a file to update"
+ fi
+
+ if [[ ${mode} == 0 ]] ; then
+ cat ${TMP}/menuitems
+ echo "Please select a file to edit by entering the corresponding number."
+ echo " (don't use -3, -5, -7 or -9 if you're unsure what to do)"
+ echo " (-1 to exit) (-3 to auto merge all remaining files)"
+ echo " (-5 to auto-merge AND not use 'mv -i')"
+ echo " (-7 to discard all updates)"
+ echo -n " (-9 to discard all updates AND not use 'rm -i'): "
+ input=$(read_int)
+ else
+ dialog --title "${title}" --menu "${my_title}" \
+ 0 0 0 $(echo -e "-1 Exit\n$(<${TMP}/menuitems)") \
+ 2> ${TMP}/input || die "User termination!" 0
+ input=$(<${TMP}/input)
+ fi
+ if [[ ${input} == -9 ]]; then
+ read -p "Are you sure that you want to delete all updates (type YES):" reply
+ if [[ ${reply} != "YES" ]]; then
+ continue
+ else
+ input=-7
+ export rm_opts=""
+ fi
+ fi
+ if [[ ${input} == -7 ]]; then
+ input=0
+ export DELETE_ALL="yes"
+ fi
+ if [[ ${input} == -5 ]] ; then
+ input=-3
+ export mv_opts=" ${mv_opts} "
+ mv_opts="${mv_opts// -i / }"
+ fi
+ if [[ ${input} == -3 ]] ; then
+ input=0
+ export OVERWRITE_ALL="yes"
+ fi
+ fi # -3 automerge
+ if [[ -z ${input} ]] || [[ ${input} == 0 ]] ; then
+ input=${isfirst}
+ fi
+ done
+}
+
+user_special() {
+ if [ -r ${PORTAGE_CONFIGROOT}etc/etc-update.special ]; then
+ if [ -z "$1" ]; then
+ echo "ERROR: user_special() called without arguments"
+ return 1
+ fi
+ while read -r pat; do
+ echo ${1} | grep "${pat}" > /dev/null && return 0
+ done < ${PORTAGE_CONFIGROOT}etc/etc-update.special
+ fi
+ return 1
+}
+
+read_int() {
+ # Read an integer from stdin. Continously loops until a valid integer is
+ # read. This is a workaround for odd behavior of bash when an attempt is
+ # made to store a value such as "1y" into an integer-only variable.
+ local my_input
+ while true; do
+ read my_input
+ # failed integer conversions will break a loop unless they're enclosed
+ # in a subshell.
+ echo "${my_input}" | ( declare -i x; read x) 2>/dev/null && break
+ echo -n "Value '$my_input' is not valid. Please enter an integer value:" >&2
+ done
+ echo ${my_input}
+}
+
+do_file() {
+ interactive_echo() { [ "${OVERWRITE_ALL}" != "yes" ] && [ "${DELETE_ALL}" != "yes" ] && echo; }
+ interactive_echo
+ local -i my_input
+ local -i fcount=0
+ until (( $(wc -l < ${TMP}/files/${input}) < 2 )); do
+ my_input=0
+ if (( $(wc -l < ${TMP}/files/${input}) == 2 )); then
+ my_input=1
+ fi
+ until (( ${my_input} > 0 )) && (( ${my_input} < $(wc -l < ${TMP}/files/${input}) )); do
+ fcount=0
+
+ if [ "${OVERWRITE_ALL}" == "yes" ]; then
+ my_input=0
+ elif [ "${DELETE_ALL}" == "yes" ]; then
+ my_input=0
+ else
+ for line in $(<${TMP}/files/${input}); do
+ if (( ${fcount} > 0 )); then
+ echo -n "${fcount}${PAR} "
+ echo "${line}"
+ else
+ if [[ ${mode} == 0 ]] ; then
+ echo "Below are the new config files for ${line}:"
+ else
+ local my_title="Please select a file to process for ${line}"
+ fi
+ fi
+ fcount=${fcount}+1
+ done > ${TMP}/menuitems
+
+ if [[ ${mode} == 0 ]] ; then
+ cat ${TMP}/menuitems
+ echo -n "Please select a file to process (-1 to exit this file): "
+ my_input=$(read_int)
+ else
+ dialog --title "${title}" --menu "${my_title}" \
+ 0 0 0 $(echo -e "$(<${TMP}/menuitems)\n${fcount} Exit") \
+ 2> ${TMP}/input || die "User termination!" 0
+ my_input=$(<${TMP}/input)
+ fi
+ fi # OVERWRITE_ALL
+
+ if [[ ${my_input} == 0 ]] ; then
+ my_input=1
+ elif [[ ${my_input} == -1 ]] ; then
+ input=0
+ return
+ elif [[ ${my_input} == ${fcount} ]] ; then
+ break
+ fi
+ done
+ if [[ ${my_input} == ${fcount} ]] ; then
+ break
+ fi
+
+ fcount=${my_input}+1
+
+ file=$(sed -e "${fcount}p;d" ${TMP}/files/${input})
+ ofile=$(head -n1 ${TMP}/files/${input})
+
+ do_cfg "${file}" "${ofile}"
+
+ sed -e "${fcount}!p;d" ${TMP}/files/${input} > ${TMP}/files/sed
+ mv ${TMP}/files/sed ${TMP}/files/${input}
+
+ if [[ ${my_input} == -1 ]] ; then
+ break
+ fi
+ done
+ interactive_echo
+ rm ${TMP}/files/${input}
+ count=${count}-1
+}
+
+do_cfg() {
+
+ local file="${1}"
+ local ofile="${2}"
+ local -i my_input=0
+
+ until (( ${my_input} == -1 )) || [ ! -f ${file} ]; do
+ if [[ "${OVERWRITE_ALL}" == "yes" ]] && ! user_special "${ofile}"; then
+ my_input=1
+ elif [[ "${DELETE_ALL}" == "yes" ]] && ! user_special "${ofile}"; then
+ my_input=2
+ else
+ [[ $CLEAR_TERM == yes ]] && clear
+ if [ "${using_editor}" == 0 ]; then
+ (
+ echo "Showing differences between ${ofile} and ${file}"
+ diff_command "${ofile}" "${file}"
+ ) | ${pager}
+ else
+ echo "Beginning of differences between ${ofile} and ${file}"
+ diff_command "${ofile}" "${file}"
+ echo "End of differences between ${ofile} and ${file}"
+ fi
+ if [ -L "${file}" ]; then
+ echo
+ echo "-------------------------------------------------------------"
+ echo "NOTE: File is a symlink to another file. REPLACE recommended."
+ echo " The original file may simply have moved. Please review."
+ echo "-------------------------------------------------------------"
+ echo
+ fi
+ echo -n "File: ${file}
+1) Replace original with update
+2) Delete update, keeping original as is
+3) Interactively merge original with update
+4) Show differences again
+5) Save update as example config
+Please select from the menu above (-1 to ignore this update): "
+ my_input=$(read_int)
+ fi
+
+ case ${my_input} in
+ 1) echo "Replacing ${ofile} with ${file}"
+ mv ${mv_opts} ${file} ${ofile}
+ [ -n "${OVERWRITE_ALL}" ] && my_input=-1
+ continue
+ ;;
+ 2) echo "Deleting ${file}"
+ rm ${rm_opts} ${file}
+ [ -n "${DELETE_ALL}" ] && my_input=-1
+ continue
+ ;;
+ 3) do_merge "${file}" "${ofile}"
+ my_input=${?}
+# [ ${my_input} == 255 ] && my_input=-1
+ continue
+ ;;
+ 4) continue
+ ;;
+ 5) do_distconf "${file}" "${ofile}"
+ ;;
+ *) continue
+ ;;
+ esac
+ done
+}
+
+do_merge() {
+ # make sure we keep the merged file in the secure tempdir
+ # so we dont leak any information contained in said file
+ # (think of case where the file has 0600 perms; during the
+ # merging process, the temp file gets umask perms!)
+
+ local file="${1}"
+ local ofile="${2}"
+ local mfile="${TMP}/${2}.merged"
+ local -i my_input=0
+ echo "${file} ${ofile} ${mfile}"
+
+ if [[ -e ${mfile} ]] ; then
+ echo "A previous version of the merged file exists, cleaning..."
+ rm ${rm_opts} "${mfile}"
+ fi
+
+ # since mfile will be like $TMP/path/to/original-file.merged, we
+ # need to make sure the full /path/to/ exists ahead of time
+ mkdir -p "${mfile%/*}"
+
+ until (( ${my_input} == -1 )); do
+ echo "Merging ${file} and ${ofile}"
+ $(echo "${merge_command}" |
+ sed -e "s:%merged:${mfile}:g" \
+ -e "s:%orig:${ofile}:g" \
+ -e "s:%new:${file}:g")
+ until (( ${my_input} == -1 )); do
+ echo -n "1) Replace ${ofile} with merged file
+2) Show differences between merged file and original
+3) Remerge original with update
+4) Edit merged file
+5) Return to the previous menu
+Please select from the menu above (-1 to exit, losing this merge): "
+ my_input=$(read_int)
+ case ${my_input} in
+ 1) echo "Replacing ${ofile} with ${mfile}"
+ if [[ ${USERLAND} == BSD ]] ; then
+ chown "$(stat -f %Su:%Sg "${ofile}")" "${mfile}"
+ chmod $(stat -f %Mp%Lp "${ofile}") "${mfile}"
+ else
+ chown --reference="${ofile}" "${mfile}"
+ chmod --reference="${ofile}" "${mfile}"
+ fi
+ mv ${mv_opts} "${mfile}" "${ofile}"
+ rm ${rm_opts} "${file}"
+ return 255
+ ;;
+ 2)
+ [[ $CLEAR_TERM == yes ]] && clear
+ if [ "${using_editor}" == 0 ]; then
+ (
+ echo "Showing differences between ${ofile} and ${mfile}"
+ diff_command "${ofile}" "${mfile}"
+ ) | ${pager}
+ else
+ echo "Beginning of differences between ${ofile} and ${mfile}"
+ diff_command "${ofile}" "${mfile}"
+ echo "End of differences between ${ofile} and ${mfile}"
+ fi
+ continue
+ ;;
+ 3) break
+ ;;
+ 4) ${EDITOR:-nano -w} "${mfile}"
+ continue
+ ;;
+ 5) rm ${rm_opts} "${mfile}"
+ return 0
+ ;;
+ *) continue
+ ;;
+ esac
+ done
+ done
+ rm ${rm_opts} "${mfile}"
+ return 255
+}
+
+do_distconf() {
+ # search for any previously saved distribution config
+ # files and number the current one accordingly
+
+ local file="${1}"
+ local ofile="${2}"
+ local -i count
+ local -i fill
+ local suffix
+ local efile
+
+ for ((count = 0; count <= 9999; count++)); do
+ suffix=".dist_"
+ for ((fill = 4 - ${#count}; fill > 0; fill--)); do
+ suffix+="0"
+ done
+ suffix+="${count}"
+ efile="${ofile}${suffix}"
+ if [[ ! -f ${efile} ]]; then
+ mv ${mv_opts} "${file}" "${efile}"
+ break
+ elif diff_command "${file}" "${efile}" &> /dev/null; then
+ # replace identical copy
+ mv "${file}" "${efile}"
+ break
+ fi
+ done
+}
+
+die() {
+ trap SIGTERM
+ trap SIGINT
+
+ if [ "$2" -eq 0 ]; then
+ echo "Exiting: ${1}"
+ scan > /dev/null
+ [ ${count} -gt 0 ] && echo "NOTE: ${count} updates remaining"
+ else
+ echo "ERROR: ${1}"
+ fi
+
+ rm -rf "${TMP}"
+ exit ${2}
+}
+
+usage() {
+ cat <<-EOF
+ etc-update: Handle configuration file updates
+
+ Usage: etc-update [options]
+
+ Options:
+ -d, --debug Enable shell debugging
+ -h, --help Show help and run away
+ -V, --version Show version and trundle away
+ EOF
+
+ [[ -n ${*:2} ]] && printf "\nError: %s\n" "${*:2}" 1>&2
+
+ exit ${1:-0}
+}
+
+#
+# Run the script
+#
+
+SET_X=false
+while [[ -n $1 ]] ; do
+ case $1 in
+ -d|--debug) SET_X=true;;
+ -h|--help) usage;;
+ -V|--version) emerge --version ; exit 0;;
+ *) usage 1 "Invalid option '$1'";;
+ esac
+ shift
+done
+${SET_X} && set -x
+
+type portageq > /dev/null || exit $?
+eval $(portageq envvar -v CONFIG_PROTECT \
+ CONFIG_PROTECT_MASK PORTAGE_CONFIGROOT PORTAGE_TMPDIR ROOT USERLAND)
+export PORTAGE_TMPDIR
+
+TMP="${PORTAGE_TMPDIR}/etc-update-$$"
+trap "die terminated 1" SIGTERM
+trap "die interrupted 1" SIGINT
+
+[ -w ${PORTAGE_CONFIGROOT}etc ] || die "Need write access to ${PORTAGE_CONFIGROOT}etc" 1
+#echo $PORTAGE_TMPDIR
+#echo $CONFIG_PROTECT
+#echo $CONFIG_PROTECT_MASK
+#export PORTAGE_TMPDIR=$(/usr/lib/portage/bin/portageq envvar PORTAGE_TMPDIR)
+
+rm -rf "${TMP}" 2> /dev/null
+mkdir "${TMP}" || die "failed to create temp dir" 1
+# make sure we have a secure directory to work in
+chmod 0700 "${TMP}" || die "failed to set perms on temp dir" 1
+chown ${UID:-0}:${GID:-0} "${TMP}" || die "failed to set ownership on temp dir" 1
+
+# I need the CONFIG_PROTECT value
+#CONFIG_PROTECT=$(/usr/lib/portage/bin/portageq envvar CONFIG_PROTECT)
+#CONFIG_PROTECT_MASK=$(/usr/lib/portage/bin/portageq envvar CONFIG_PROTECT_MASK)
+
+# load etc-config's configuration
+CLEAR_TERM=$(get_config clear_term)
+EU_AUTOMERGE=$(get_config eu_automerge)
+rm_opts=$(get_config rm_opts)
+mv_opts=$(get_config mv_opts)
+cp_opts=$(get_config cp_opts)
+pager=$(get_config pager)
+diff_command=$(get_config diff_command)
+using_editor=$(get_config using_editor)
+merge_command=$(get_config merge_command)
+declare -i mode=$(get_config mode)
+[[ -z ${mode} ]] && mode=0
+[[ -z ${pager} ]] && pager="cat"
+
+if [ "${using_editor}" == 0 ]; then
+ # Sanity check to make sure diff exists and works
+ echo > "${TMP}"/.diff-test-1
+ echo > "${TMP}"/.diff-test-2
+
+ if ! diff_command "${TMP}"/.diff-test-1 "${TMP}"/.diff-test-2 ; then
+ die "'${diff_command}' does not seem to work, aborting" 1
+ fi
+else
+ if ! type ${diff_command%% *} >/dev/null; then
+ die "'${diff_command}' does not seem to work, aborting" 1
+ fi
+fi
+
+if [[ ${mode} == "1" ]] ; then
+ if ! type dialog >/dev/null || ! dialog --help >/dev/null ; then
+ die "mode=1 and 'dialog' not found or not executable, aborting" 1
+ fi
+fi
+
+#echo "rm_opts: $rm_opts, mv_opts: $mv_opts, cp_opts: $cp_opts"
+#echo "pager: $pager, diff_command: $diff_command, merge_command: $merge_command"
+
+if (( ${mode} == 0 )); then
+ PAR=")"
+else
+ PAR=""
+fi
+
+declare -i count=0
+declare input=0
+declare title="Gentoo's etc-update tool!"
+
+scan
+
+until (( ${input} == -1 )); do
+ if (( ${count} == 0 )); then
+ die "Nothing left to do; exiting. :)" 0
+ fi
+ sel_file
+ if (( ${input} != -1 )); then
+ do_file
+ fi
+done
+
+die "User termination!" 0
diff --git a/portage_with_autodep/bin/filter-bash-environment.py b/portage_with_autodep/bin/filter-bash-environment.py
new file mode 100755
index 0000000..b9aec96
--- /dev/null
+++ b/portage_with_autodep/bin/filter-bash-environment.py
@@ -0,0 +1,150 @@
+#!/usr/bin/python
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import codecs
+import io
+import optparse
+import os
+import re
+import sys
+
+here_doc_re = re.compile(r'.*\s<<[-]?(\w+)$')
+func_start_re = re.compile(r'^[-\w]+\s*\(\)\s*$')
+func_end_re = re.compile(r'^\}$')
+
+var_assign_re = re.compile(r'(^|^declare\s+-\S+\s+|^declare\s+|^export\s+)([^=\s]+)=("|\')?.*$')
+close_quote_re = re.compile(r'(\\"|"|\')\s*$')
+readonly_re = re.compile(r'^declare\s+-(\S*)r(\S*)\s+')
+# declare without assignment
+var_declare_re = re.compile(r'^declare(\s+-\S+)?\s+([^=\s]+)\s*$')
+
+def have_end_quote(quote, line):
+ """
+ Check if the line has an end quote (useful for handling multi-line
+ quotes). This handles escaped double quotes that may occur at the
+ end of a line. The posix spec does not allow escaping of single
+ quotes inside of single quotes, so that case is not handled.
+ """
+ close_quote_match = close_quote_re.search(line)
+ return close_quote_match is not None and \
+ close_quote_match.group(1) == quote
+
+def filter_declare_readonly_opt(line):
+ readonly_match = readonly_re.match(line)
+ if readonly_match is not None:
+ declare_opts = ''
+ for i in (1, 2):
+ group = readonly_match.group(i)
+ if group is not None:
+ declare_opts += group
+ if declare_opts:
+ line = 'declare -%s %s' % \
+ (declare_opts, line[readonly_match.end():])
+ else:
+ line = 'declare ' + line[readonly_match.end():]
+ return line
+
+def filter_bash_environment(pattern, file_in, file_out):
+ # Filter out any instances of the \1 character from variable values
+ # since this character multiplies each time that the environment
+ # is saved (strange bash behavior). This can eventually result in
+ # mysterious 'Argument list too long' errors from programs that have
+ # huge strings of \1 characters in their environment. See bug #222091.
+ here_doc_delim = None
+ in_func = None
+ multi_line_quote = None
+ multi_line_quote_filter = None
+ for line in file_in:
+ if multi_line_quote is not None:
+ if not multi_line_quote_filter:
+ file_out.write(line.replace("\1", ""))
+ if have_end_quote(multi_line_quote, line):
+ multi_line_quote = None
+ multi_line_quote_filter = None
+ continue
+ if here_doc_delim is None and in_func is None:
+ var_assign_match = var_assign_re.match(line)
+ if var_assign_match is not None:
+ quote = var_assign_match.group(3)
+ filter_this = pattern.match(var_assign_match.group(2)) \
+ is not None
+ # Exclude the start quote when searching for the end quote,
+ # to ensure that the start quote is not misidentified as the
+ # end quote (happens if there is a newline immediately after
+ # the start quote).
+ if quote is not None and not \
+ have_end_quote(quote, line[var_assign_match.end(2)+2:]):
+ multi_line_quote = quote
+ multi_line_quote_filter = filter_this
+ if not filter_this:
+ line = filter_declare_readonly_opt(line)
+ file_out.write(line.replace("\1", ""))
+ continue
+ else:
+ declare_match = var_declare_re.match(line)
+ if declare_match is not None:
+ # declare without assignment
+ filter_this = pattern.match(declare_match.group(2)) \
+ is not None
+ if not filter_this:
+ line = filter_declare_readonly_opt(line)
+ file_out.write(line)
+ continue
+
+ if here_doc_delim is not None:
+ if here_doc_delim.match(line):
+ here_doc_delim = None
+ file_out.write(line)
+ continue
+ here_doc = here_doc_re.match(line)
+ if here_doc is not None:
+ here_doc_delim = re.compile("^%s$" % here_doc.group(1))
+ file_out.write(line)
+ continue
+ # Note: here-documents are handled before functions since otherwise
+ # it would be possible for the content of a here-document to be
+ # mistaken as the end of a function.
+ if in_func:
+ if func_end_re.match(line) is not None:
+ in_func = None
+ file_out.write(line)
+ continue
+ in_func = func_start_re.match(line)
+ if in_func is not None:
+ file_out.write(line)
+ continue
+ # This line is not recognized as part of a variable assignment,
+ # function definition, or here document, so just allow it to
+ # pass through.
+ file_out.write(line)
+
+if __name__ == "__main__":
+ description = "Filter out variable assignments for variable " + \
+ "names matching a given PATTERN " + \
+ "while leaving bash function definitions and here-documents " + \
+ "intact. The PATTERN is a space separated list of variable names" + \
+ " and it supports python regular expression syntax."
+ usage = "usage: %s PATTERN" % os.path.basename(sys.argv[0])
+ parser = optparse.OptionParser(description=description, usage=usage)
+ options, args = parser.parse_args(sys.argv[1:])
+ if len(args) != 1:
+ parser.error("Missing required PATTERN argument.")
+ file_in = sys.stdin
+ file_out = sys.stdout
+ if sys.hexversion >= 0x3000000:
+ file_in = codecs.iterdecode(sys.stdin.buffer.raw,
+ 'utf_8', errors='replace')
+ file_out = io.TextIOWrapper(sys.stdout.buffer,
+ 'utf_8', errors='backslashreplace')
+
+ var_pattern = args[0].split()
+
+ # Filter invalid variable names that are not supported by bash.
+ var_pattern.append(r'\d.*')
+ var_pattern.append(r'.*\W.*')
+
+ var_pattern = "^(%s)$" % "|".join(var_pattern)
+ filter_bash_environment(
+ re.compile(var_pattern), file_in, file_out)
+ file_out.flush()
diff --git a/portage_with_autodep/bin/fixpackages b/portage_with_autodep/bin/fixpackages
new file mode 100755
index 0000000..5e1df70
--- /dev/null
+++ b/portage_with_autodep/bin/fixpackages
@@ -0,0 +1,45 @@
+#!/usr/bin/python
+# Copyright 1999-2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import os,sys
+os.environ["PORTAGE_CALLER"]="fixpackages"
+try:
+ import portage
+except ImportError:
+ from os import path as osp
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
+ import portage
+
+from portage import os
+from portage.output import EOutput
+from textwrap import wrap
+from portage._global_updates import _global_updates
+mysettings = portage.settings
+mytrees = portage.db
+mtimedb = portage.mtimedb
+
+if mysettings['ROOT'] != "/":
+ out = EOutput()
+ msg = "The fixpackages program is not intended for use with " + \
+ "ROOT != \"/\". Instead use `emaint --fix movebin` and/or " + \
+ "`emaint --fix moveinst."
+ for line in wrap(msg, 72):
+ out.eerror(line)
+ sys.exit(1)
+
+try:
+ os.nice(int(mysettings.get("PORTAGE_NICENESS", "0")))
+except (OSError, ValueError) as e:
+ portage.writemsg("!!! Failed to change nice value to '%s'\n" % \
+ mysettings["PORTAGE_NICENESS"])
+ portage.writemsg("!!! %s\n" % str(e))
+ del e
+
+_global_updates(mytrees, mtimedb["updates"])
+
+print()
+print("Done.")
+print()
diff --git a/portage_with_autodep/bin/glsa-check b/portage_with_autodep/bin/glsa-check
new file mode 100755
index 0000000..2f2d555
--- /dev/null
+++ b/portage_with_autodep/bin/glsa-check
@@ -0,0 +1,316 @@
+#!/usr/bin/python
+# Copyright 2008-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import sys
+
+try:
+ import portage
+except ImportError:
+ from os import path as osp
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
+ import portage
+
+from portage import os
+from portage.output import *
+
+from optparse import OptionGroup, OptionParser
+
+__program__ = "glsa-check"
+__author__ = "Marius Mauch <genone@gentoo.org>"
+__version__ = "1.0"
+
+def cb_version(*args, **kwargs):
+ """Callback for --version"""
+ sys.stderr.write("\n"+ __program__ + ", version " + __version__ + "\n")
+ sys.stderr.write("Author: " + __author__ + "\n")
+ sys.stderr.write("This program is licensed under the GPL, version 2\n\n")
+ sys.exit(0)
+
+# option parsing
+parser = OptionParser(usage="%prog <option> [glsa-list]",
+ version="%prog "+ __version__)
+parser.epilog = "glsa-list can contain an arbitrary number of GLSA ids," \
+ " filenames containing GLSAs or the special identifiers" \
+ " 'all', 'new' and 'affected'"
+
+modes = OptionGroup(parser, "Modes")
+modes.add_option("-l", "--list", action="store_const",
+ const="list", dest="mode",
+ help="List all unapplied GLSA")
+modes.add_option("-d", "--dump", action="store_const",
+ const="dump", dest="mode",
+ help="Show all information about the given GLSA")
+modes.add_option("", "--print", action="store_const",
+ const="dump", dest="mode",
+ help="Alias for --dump")
+modes.add_option("-t", "--test", action="store_const",
+ const="test", dest="mode",
+ help="Test if this system is affected by the given GLSA")
+modes.add_option("-p", "--pretend", action="store_const",
+ const="pretend", dest="mode",
+ help="Show the necessary commands to apply this GLSA")
+modes.add_option("-f", "--fix", action="store_const",
+ const="fix", dest="mode",
+ help="Try to auto-apply this GLSA (experimental)")
+modes.add_option("-i", "--inject", action="store_const", dest="mode",
+ help="Inject the given GLSA into the checkfile")
+modes.add_option("-m", "--mail", action="store_const",
+ const="mail", dest="mode",
+ help="Send a mail with the given GLSAs to the administrator")
+parser.add_option_group(modes)
+
+parser.remove_option("--version")
+parser.add_option("-V", "--version", action="callback",
+ callback=cb_version, help="Some information about this tool")
+parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
+ help="Print more information")
+parser.add_option("-n", "--nocolor", action="callback",
+ callback=lambda *args, **kwargs: nocolor(),
+ help="Disable colors")
+parser.add_option("-e", "--emergelike", action="store_false", dest="least_change",
+ help="Do not use a least-change algorithm")
+parser.add_option("-c", "--cve", action="store_true", dest="list_cve",
+ help="Show CAN ids in listing mode")
+
+options, params = parser.parse_args()
+
+mode = options.mode
+least_change = options.least_change
+list_cve = options.list_cve
+verbose = options.verbose
+
+# Sanity checking
+if mode is None:
+ sys.stderr.write("No mode given: what should I do?\n")
+ parser.print_help()
+ sys.exit(1)
+elif mode != "list" and not params:
+ sys.stderr.write("\nno GLSA given, so we'll do nothing for now. \n")
+ sys.stderr.write("If you want to run on all GLSA please tell me so \n")
+ sys.stderr.write("(specify \"all\" as parameter)\n\n")
+ parser.print_help()
+ sys.exit(1)
+elif mode in ["fix", "inject"] and os.geteuid() != 0:
+ # we need root privileges for write access
+ sys.stderr.write("\nThis tool needs root access to "+options.mode+" this GLSA\n\n")
+ sys.exit(2)
+elif mode == "list" and not params:
+ params.append("new")
+
+# delay this for speed increase
+from portage.glsa import *
+
+vardb = portage.db[portage.settings["ROOT"]]["vartree"].dbapi
+portdb = portage.db["/"]["porttree"].dbapi
+
+# build glsa lists
+completelist = get_glsa_list(portage.settings)
+
+checklist = get_applied_glsas(portage.settings)
+todolist = [e for e in completelist if e not in checklist]
+
+glsalist = []
+if "new" in params:
+ glsalist = todolist
+ params.remove("new")
+
+if "all" in params:
+ glsalist = completelist
+ params.remove("all")
+if "affected" in params:
+ # replaced completelist with todolist on request of wschlich
+ for x in todolist:
+ try:
+ myglsa = Glsa(x, portage.settings, vardb, portdb)
+ except (GlsaTypeException, GlsaFormatException) as e:
+ if verbose:
+ sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (x, e)))
+ continue
+ if myglsa.isVulnerable():
+ glsalist.append(x)
+ params.remove("affected")
+
+# remove invalid parameters
+for p in params[:]:
+ if not (p in completelist or os.path.exists(p)):
+ sys.stderr.write(("(removing %s from parameter list as it isn't a valid GLSA specification)\n" % p))
+ params.remove(p)
+
+glsalist.extend([g for g in params if g not in glsalist])
+
+def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr):
+ fd2.write(white("[A]")+" means this GLSA was already applied,\n")
+ fd2.write(green("[U]")+" means the system is not affected and\n")
+ fd2.write(red("[N]")+" indicates that the system might be affected.\n\n")
+
+ myglsalist.sort()
+ for myid in myglsalist:
+ try:
+ myglsa = Glsa(myid, portage.settings, vardb, portdb)
+ except (GlsaTypeException, GlsaFormatException) as e:
+ if verbose:
+ fd2.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
+ continue
+ if myglsa.isApplied():
+ status = "[A]"
+ color = white
+ elif myglsa.isVulnerable():
+ status = "[N]"
+ color = red
+ else:
+ status = "[U]"
+ color = green
+
+ if verbose:
+ access = ("[%-8s] " % myglsa.access)
+ else:
+ access=""
+
+ fd1.write(color(myglsa.nr) + " " + color(status) + " " + color(access) + myglsa.title + " (")
+ if not verbose:
+ for pkg in list(myglsa.packages)[:3]:
+ fd1.write(" " + pkg + " ")
+ if len(myglsa.packages) > 3:
+ fd1.write("... ")
+ else:
+ for pkg in myglsa.packages:
+ mylist = vardb.match(pkg)
+ if len(mylist) > 0:
+ pkg = color(" ".join(mylist))
+ fd1.write(" " + pkg + " ")
+
+ fd1.write(")")
+ if list_cve:
+ fd1.write(" "+(",".join([r[:13] for r in myglsa.references if r[:4] in ["CAN-", "CVE-"]])))
+ fd1.write("\n")
+ return 0
+
+if mode == "list":
+ sys.exit(summarylist(glsalist))
+
+# dump, fix, inject and fix are nearly the same code, only the glsa method call differs
+if mode in ["dump", "fix", "inject", "pretend"]:
+ for myid in glsalist:
+ try:
+ myglsa = Glsa(myid, portage.settings, vardb, portdb)
+ except (GlsaTypeException, GlsaFormatException) as e:
+ if verbose:
+ sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
+ continue
+ if mode == "dump":
+ myglsa.dump()
+ elif mode == "fix":
+ sys.stdout.write("fixing "+myid+"\n")
+ mergelist = myglsa.getMergeList(least_change=least_change)
+ for pkg in mergelist:
+ sys.stdout.write(">>> merging "+pkg+"\n")
+ # using emerge for the actual merging as it contains the dependency
+ # code and we want to be consistent in behaviour. Also this functionality
+ # will be integrated in emerge later, so it shouldn't hurt much.
+ emergecmd = "emerge --oneshot " + portage.settings["EMERGE_OPTS"] + " =" + pkg
+ if verbose:
+ sys.stderr.write(emergecmd+"\n")
+ exitcode = os.system(emergecmd)
+ # system() returns the exitcode in the high byte of a 16bit integer
+ if exitcode >= 1<<8:
+ exitcode >>= 8
+ if exitcode:
+ sys.exit(exitcode)
+ myglsa.inject()
+ elif mode == "pretend":
+ sys.stdout.write("Checking GLSA "+myid+"\n")
+ mergelist = myglsa.getMergeList(least_change=least_change)
+ if mergelist:
+ sys.stdout.write("The following updates will be performed for this GLSA:\n")
+ for pkg in mergelist:
+ oldver = None
+ for x in vardb.match(portage.cpv_getkey(pkg)):
+ if vardb.aux_get(x, ["SLOT"]) == portdb.aux_get(pkg, ["SLOT"]):
+ oldver = x
+ if oldver == None:
+ raise ValueError("could not find old version for package %s" % pkg)
+ oldver = oldver[len(portage.cpv_getkey(oldver))+1:]
+ sys.stdout.write(" " + pkg + " (" + oldver + ")\n")
+ else:
+ sys.stdout.write("Nothing to do for this GLSA\n")
+ elif mode == "inject":
+ sys.stdout.write("injecting " + myid + "\n")
+ myglsa.inject()
+ sys.stdout.write("\n")
+ sys.exit(0)
+
+# test is a bit different as Glsa.test() produces no output
+if mode == "test":
+ outputlist = []
+ for myid in glsalist:
+ try:
+ myglsa = Glsa(myid, portage.settings, vardb, portdb)
+ except (GlsaTypeException, GlsaFormatException) as e:
+ if verbose:
+ sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
+ continue
+ if myglsa.isVulnerable():
+ outputlist.append(str(myglsa.nr))
+ if len(outputlist) > 0:
+ sys.stderr.write("This system is affected by the following GLSAs:\n")
+ if verbose:
+ summarylist(outputlist)
+ else:
+ sys.stdout.write("\n".join(outputlist)+"\n")
+ else:
+ sys.stderr.write("This system is not affected by any of the listed GLSAs\n")
+ sys.exit(0)
+
+# mail mode as requested by solar
+if mode == "mail":
+ import portage.mail, socket
+ from io import StringIO
+ from email.mime.text import MIMEText
+
+ # color doesn't make any sense for mail
+ nocolor()
+
+ if "PORTAGE_ELOG_MAILURI" in portage.settings:
+ myrecipient = portage.settings["PORTAGE_ELOG_MAILURI"].split()[0]
+ else:
+ myrecipient = "root@localhost"
+
+ if "PORTAGE_ELOG_MAILFROM" in portage.settings:
+ myfrom = portage.settings["PORTAGE_ELOG_MAILFROM"]
+ else:
+ myfrom = "glsa-check"
+
+ mysubject = "[glsa-check] Summary for %s" % socket.getfqdn()
+
+ # need a file object for summarylist()
+ myfd = StringIO()
+ myfd.write("GLSA Summary report for host %s\n" % socket.getfqdn())
+ myfd.write("(Command was: %s)\n\n" % " ".join(sys.argv))
+ summarylist(glsalist, fd1=myfd, fd2=myfd)
+ summary = str(myfd.getvalue())
+ myfd.close()
+
+ myattachments = []
+ for myid in glsalist:
+ try:
+ myglsa = Glsa(myid, portage.settings, vardb, portdb)
+ except (GlsaTypeException, GlsaFormatException) as e:
+ if verbose:
+ sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
+ continue
+ myfd = StringIO()
+ myglsa.dump(outstream=myfd)
+ myattachments.append(MIMEText(str(myfd.getvalue()), _charset="utf8"))
+ myfd.close()
+
+ mymessage = portage.mail.create_message(myfrom, myrecipient, mysubject, summary, myattachments)
+ portage.mail.send_mail(portage.settings, mymessage)
+
+ sys.exit(0)
+
+# something wrong here, all valid paths are covered with sys.exit()
+sys.stderr.write("nothing more to do\n")
+sys.exit(2)
diff --git a/portage_with_autodep/bin/isolated-functions.sh b/portage_with_autodep/bin/isolated-functions.sh
new file mode 100644
index 0000000..65bb1d5
--- /dev/null
+++ b/portage_with_autodep/bin/isolated-functions.sh
@@ -0,0 +1,630 @@
+#!/bin/bash
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# We need this next line for "die" and "assert". It expands
+# It _must_ preceed all the calls to die and assert.
+shopt -s expand_aliases
+alias save_IFS='[ "${IFS:-unset}" != "unset" ] && old_IFS="${IFS}"'
+alias restore_IFS='if [ "${old_IFS:-unset}" != "unset" ]; then IFS="${old_IFS}"; unset old_IFS; else unset IFS; fi'
+
+assert() {
+ local x pipestatus=${PIPESTATUS[*]}
+ for x in $pipestatus ; do
+ [[ $x -eq 0 ]] || die "$@"
+ done
+}
+
+assert_sigpipe_ok() {
+ # When extracting a tar file like this:
+ #
+ # bzip2 -dc foo.tar.bz2 | tar xof -
+ #
+ # For some tar files (see bug #309001), tar will
+ # close its stdin pipe when the decompressor still has
+ # remaining data to be written to its stdout pipe. This
+ # causes the decompressor to be killed by SIGPIPE. In
+ # this case, we want to ignore pipe writers killed by
+ # SIGPIPE, and trust the exit status of tar. We refer
+ # to the bash manual section "3.7.5 Exit Status"
+ # which says, "When a command terminates on a fatal
+ # signal whose number is N, Bash uses the value 128+N
+ # as the exit status."
+
+ local x pipestatus=${PIPESTATUS[*]}
+ for x in $pipestatus ; do
+ # Allow SIGPIPE through (128 + 13)
+ [[ $x -ne 0 && $x -ne ${PORTAGE_SIGPIPE_STATUS:-141} ]] && die "$@"
+ done
+
+ # Require normal success for the last process (tar).
+ [[ $x -eq 0 ]] || die "$@"
+}
+
+shopt -s extdebug
+
+# dump_trace([number of funcs on stack to skip],
+# [whitespacing for filenames],
+# [whitespacing for line numbers])
+dump_trace() {
+ local funcname="" sourcefile="" lineno="" s="yes" n p
+ declare -i strip=${1:-1}
+ local filespacing=$2 linespacing=$3
+
+ # The qa_call() function and anything before it are portage internals
+ # that the user will not be interested in. Therefore, the stack trace
+ # should only show calls that come after qa_call().
+ (( n = ${#FUNCNAME[@]} - 1 ))
+ (( p = ${#BASH_ARGV[@]} ))
+ while (( n > 0 )) ; do
+ [ "${FUNCNAME[${n}]}" == "qa_call" ] && break
+ (( p -= ${BASH_ARGC[${n}]} ))
+ (( n-- ))
+ done
+ if (( n == 0 )) ; then
+ (( n = ${#FUNCNAME[@]} - 1 ))
+ (( p = ${#BASH_ARGV[@]} ))
+ fi
+
+ eerror "Call stack:"
+ while (( n > ${strip} )) ; do
+ funcname=${FUNCNAME[${n} - 1]}
+ sourcefile=$(basename "${BASH_SOURCE[${n}]}")
+ lineno=${BASH_LINENO[${n} - 1]}
+ # Display function arguments
+ args=
+ if [[ -n "${BASH_ARGV[@]}" ]]; then
+ for (( j = 1 ; j <= ${BASH_ARGC[${n} - 1]} ; ++j )); do
+ newarg=${BASH_ARGV[$(( p - j - 1 ))]}
+ args="${args:+${args} }'${newarg}'"
+ done
+ (( p -= ${BASH_ARGC[${n} - 1]} ))
+ fi
+ eerror " $(printf "%${filespacing}s" "${sourcefile}"), line $(printf "%${linespacing}s" "${lineno}"): Called ${funcname}${args:+ ${args}}"
+ (( n-- ))
+ done
+}
+
+nonfatal() {
+ if has "${EAPI:-0}" 0 1 2 3 3_pre2 ; then
+ die "$FUNCNAME() not supported in this EAPI"
+ fi
+ if [[ $# -lt 1 ]]; then
+ die "$FUNCNAME(): Missing argument"
+ fi
+
+ PORTAGE_NONFATAL=1 "$@"
+}
+
+helpers_die() {
+ case "${EAPI:-0}" in
+ 0|1|2|3)
+ echo -e "$@" >&2
+ ;;
+ *)
+ die "$@"
+ ;;
+ esac
+}
+
+die() {
+ if [[ $PORTAGE_NONFATAL -eq 1 ]]; then
+ echo -e " $WARN*$NORMAL ${FUNCNAME[1]}: WARNING: $@" >&2
+ return 1
+ fi
+
+ set +e
+ if [ -n "${QA_INTERCEPTORS}" ] ; then
+ # die was called from inside inherit. We need to clean up
+ # QA_INTERCEPTORS since sed is called below.
+ unset -f ${QA_INTERCEPTORS}
+ unset QA_INTERCEPTORS
+ fi
+ local n filespacing=0 linespacing=0
+ # setup spacing to make output easier to read
+ (( n = ${#FUNCNAME[@]} - 1 ))
+ while (( n > 0 )) ; do
+ [ "${FUNCNAME[${n}]}" == "qa_call" ] && break
+ (( n-- ))
+ done
+ (( n == 0 )) && (( n = ${#FUNCNAME[@]} - 1 ))
+ while (( n > 0 )); do
+ sourcefile=${BASH_SOURCE[${n}]} sourcefile=${sourcefile##*/}
+ lineno=${BASH_LINENO[${n}]}
+ ((filespacing < ${#sourcefile})) && filespacing=${#sourcefile}
+ ((linespacing < ${#lineno})) && linespacing=${#lineno}
+ (( n-- ))
+ done
+
+ # When a helper binary dies automatically in EAPI 4 and later, we don't
+ # get a stack trace, so at least report the phase that failed.
+ local phase_str=
+ [[ -n $EBUILD_PHASE ]] && phase_str=" ($EBUILD_PHASE phase)"
+ eerror "ERROR: $CATEGORY/$PF failed${phase_str}:"
+ eerror " ${*:-(no error message)}"
+ eerror
+ # dump_trace is useless when the main script is a helper binary
+ local main_index
+ (( main_index = ${#BASH_SOURCE[@]} - 1 ))
+ if has ${BASH_SOURCE[$main_index]##*/} ebuild.sh misc-functions.sh ; then
+ dump_trace 2 ${filespacing} ${linespacing}
+ eerror " $(printf "%${filespacing}s" "${BASH_SOURCE[1]##*/}"), line $(printf "%${linespacing}s" "${BASH_LINENO[0]}"): Called die"
+ eerror "The specific snippet of code:"
+ # This scans the file that called die and prints out the logic that
+ # ended in the call to die. This really only handles lines that end
+ # with '|| die' and any preceding lines with line continuations (\).
+ # This tends to be the most common usage though, so let's do it.
+ # Due to the usage of appending to the hold space (even when empty),
+ # we always end up with the first line being a blank (thus the 2nd sed).
+ sed -n \
+ -e "# When we get to the line that failed, append it to the
+ # hold space, move the hold space to the pattern space,
+ # then print out the pattern space and quit immediately
+ ${BASH_LINENO[0]}{H;g;p;q}" \
+ -e '# If this line ends with a line continuation, append it
+ # to the hold space
+ /\\$/H' \
+ -e '# If this line does not end with a line continuation,
+ # erase the line and set the hold buffer to it (thus
+ # erasing the hold buffer in the process)
+ /[^\]$/{s:^.*$::;h}' \
+ "${BASH_SOURCE[1]}" \
+ | sed -e '1d' -e 's:^:RETAIN-LEADING-SPACE:' \
+ | while read -r n ; do eerror " ${n#RETAIN-LEADING-SPACE}" ; done
+ eerror
+ fi
+ eerror "If you need support, post the output of 'emerge --info =$CATEGORY/$PF',"
+ eerror "the complete build log and the output of 'emerge -pqv =$CATEGORY/$PF'."
+ if [[ -n ${EBUILD_OVERLAY_ECLASSES} ]] ; then
+ eerror "This ebuild used the following eclasses from overlays:"
+ local x
+ for x in ${EBUILD_OVERLAY_ECLASSES} ; do
+ eerror " ${x}"
+ done
+ fi
+ if [ "${EMERGE_FROM}" != "binary" ] && \
+ ! has ${EBUILD_PHASE} prerm postrm && \
+ [ "${EBUILD#${PORTDIR}/}" == "${EBUILD}" ] ; then
+ local overlay=${EBUILD%/*}
+ overlay=${overlay%/*}
+ overlay=${overlay%/*}
+ if [[ -n $PORTAGE_REPO_NAME ]] ; then
+ eerror "This ebuild is from an overlay named" \
+ "'$PORTAGE_REPO_NAME': '${overlay}/'"
+ else
+ eerror "This ebuild is from an overlay: '${overlay}/'"
+ fi
+ elif [[ -n $PORTAGE_REPO_NAME && -f "$PORTDIR"/profiles/repo_name ]] ; then
+ local portdir_repo_name=$(<"$PORTDIR"/profiles/repo_name)
+ if [[ -n $portdir_repo_name && \
+ $portdir_repo_name != $PORTAGE_REPO_NAME ]] ; then
+ eerror "This ebuild is from a repository" \
+ "named '$PORTAGE_REPO_NAME'"
+ fi
+ fi
+
+ if [[ "${EBUILD_PHASE/depend}" == "${EBUILD_PHASE}" ]] ; then
+ local x
+ for x in $EBUILD_DEATH_HOOKS; do
+ ${x} "$@" >&2 1>&2
+ done
+ > "$PORTAGE_BUILDDIR/.die_hooks"
+ fi
+
+ [[ -n ${PORTAGE_LOG_FILE} ]] \
+ && eerror "The complete build log is located at '${PORTAGE_LOG_FILE}'."
+ if [ -f "${T}/environment" ] ; then
+ eerror "The ebuild environment file is located at '${T}/environment'."
+ elif [ -d "${T}" ] ; then
+ {
+ set
+ export
+ } > "${T}/die.env"
+ eerror "The ebuild environment file is located at '${T}/die.env'."
+ fi
+ eerror "S: '${S}'"
+
+ [[ -n $PORTAGE_EBUILD_EXIT_FILE ]] && > "$PORTAGE_EBUILD_EXIT_FILE"
+ [[ -n $PORTAGE_IPC_DAEMON ]] && "$PORTAGE_BIN_PATH"/ebuild-ipc exit 1
+
+ # subshell die support
+ [[ $BASHPID = $EBUILD_MASTER_PID ]] || kill -s SIGTERM $EBUILD_MASTER_PID
+ exit 1
+}
+
+# We need to implement diefunc() since environment.bz2 files contain
+# calls to it (due to alias expansion).
+diefunc() {
+ die "${@}"
+}
+
+quiet_mode() {
+ [[ ${PORTAGE_QUIET} -eq 1 ]]
+}
+
+vecho() {
+ quiet_mode || echo "$@"
+}
+
+# Internal logging function, don't use this in ebuilds
+elog_base() {
+ local messagetype
+ [ -z "${1}" -o -z "${T}" -o ! -d "${T}/logging" ] && return 1
+ case "${1}" in
+ INFO|WARN|ERROR|LOG|QA)
+ messagetype="${1}"
+ shift
+ ;;
+ *)
+ vecho -e " ${BAD}*${NORMAL} Invalid use of internal function elog_base(), next message will not be logged"
+ return 1
+ ;;
+ esac
+ echo -e "$@" | while read -r ; do
+ echo "$messagetype $REPLY" >> \
+ "${T}/logging/${EBUILD_PHASE:-other}"
+ done
+ return 0
+}
+
+eqawarn() {
+ elog_base QA "$*"
+ [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo
+ echo -e "$@" | while read -r ; do
+ vecho " $WARN*$NORMAL $REPLY" >&2
+ done
+ LAST_E_CMD="eqawarn"
+ return 0
+}
+
+elog() {
+ elog_base LOG "$*"
+ [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo
+ echo -e "$@" | while read -r ; do
+ echo " $GOOD*$NORMAL $REPLY"
+ done
+ LAST_E_CMD="elog"
+ return 0
+}
+
+esyslog() {
+ local pri=
+ local tag=
+
+ if [ -x /usr/bin/logger ]
+ then
+ pri="$1"
+ tag="$2"
+
+ shift 2
+ [ -z "$*" ] && return 0
+
+ /usr/bin/logger -p "${pri}" -t "${tag}" -- "$*"
+ fi
+
+ return 0
+}
+
+einfo() {
+ elog_base INFO "$*"
+ [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo
+ echo -e "$@" | while read -r ; do
+ echo " $GOOD*$NORMAL $REPLY"
+ done
+ LAST_E_CMD="einfo"
+ return 0
+}
+
+einfon() {
+ elog_base INFO "$*"
+ [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo
+ echo -ne " ${GOOD}*${NORMAL} $*"
+ LAST_E_CMD="einfon"
+ return 0
+}
+
+ewarn() {
+ elog_base WARN "$*"
+ [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo
+ echo -e "$@" | while read -r ; do
+ echo " $WARN*$NORMAL $RC_INDENTATION$REPLY" >&2
+ done
+ LAST_E_CMD="ewarn"
+ return 0
+}
+
+eerror() {
+ elog_base ERROR "$*"
+ [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo
+ echo -e "$@" | while read -r ; do
+ echo " $BAD*$NORMAL $RC_INDENTATION$REPLY" >&2
+ done
+ LAST_E_CMD="eerror"
+ return 0
+}
+
+ebegin() {
+ local msg="$*" dots spaces=${RC_DOT_PATTERN//?/ }
+ if [[ -n ${RC_DOT_PATTERN} ]] ; then
+ dots=$(printf "%$(( COLS - 3 - ${#RC_INDENTATION} - ${#msg} - 7 ))s" '')
+ dots=${dots//${spaces}/${RC_DOT_PATTERN}}
+ msg="${msg}${dots}"
+ else
+ msg="${msg} ..."
+ fi
+ einfon "${msg}"
+ [[ ${RC_ENDCOL} == "yes" ]] && echo
+ LAST_E_LEN=$(( 3 + ${#RC_INDENTATION} + ${#msg} ))
+ LAST_E_CMD="ebegin"
+ return 0
+}
+
+_eend() {
+ local retval=${1:-0} efunc=${2:-eerror} msg
+ shift 2
+
+ if [[ ${retval} == "0" ]] ; then
+ msg="${BRACKET}[ ${GOOD}ok${BRACKET} ]${NORMAL}"
+ else
+ if [[ -n $* ]] ; then
+ ${efunc} "$*"
+ fi
+ msg="${BRACKET}[ ${BAD}!!${BRACKET} ]${NORMAL}"
+ fi
+
+ if [[ ${RC_ENDCOL} == "yes" ]] ; then
+ echo -e "${ENDCOL} ${msg}"
+ else
+ [[ ${LAST_E_CMD} == ebegin ]] || LAST_E_LEN=0
+ printf "%$(( COLS - LAST_E_LEN - 7 ))s%b\n" '' "${msg}"
+ fi
+
+ return ${retval}
+}
+
+eend() {
+ local retval=${1:-0}
+ shift
+
+ _eend ${retval} eerror "$*"
+
+ LAST_E_CMD="eend"
+ return ${retval}
+}
+
+KV_major() {
+ [[ -z $1 ]] && return 1
+
+ local KV=$@
+ echo "${KV%%.*}"
+}
+
+KV_minor() {
+ [[ -z $1 ]] && return 1
+
+ local KV=$@
+ KV=${KV#*.}
+ echo "${KV%%.*}"
+}
+
+KV_micro() {
+ [[ -z $1 ]] && return 1
+
+ local KV=$@
+ KV=${KV#*.*.}
+ echo "${KV%%[^[:digit:]]*}"
+}
+
+KV_to_int() {
+ [[ -z $1 ]] && return 1
+
+ local KV_MAJOR=$(KV_major "$1")
+ local KV_MINOR=$(KV_minor "$1")
+ local KV_MICRO=$(KV_micro "$1")
+ local KV_int=$(( KV_MAJOR * 65536 + KV_MINOR * 256 + KV_MICRO ))
+
+ # We make version 2.2.0 the minimum version we will handle as
+ # a sanity check ... if its less, we fail ...
+ if [[ ${KV_int} -ge 131584 ]] ; then
+ echo "${KV_int}"
+ return 0
+ fi
+
+ return 1
+}
+
+_RC_GET_KV_CACHE=""
+get_KV() {
+ [[ -z ${_RC_GET_KV_CACHE} ]] \
+ && _RC_GET_KV_CACHE=$(uname -r)
+
+ echo $(KV_to_int "${_RC_GET_KV_CACHE}")
+
+ return $?
+}
+
+unset_colors() {
+ COLS=80
+ ENDCOL=
+
+ GOOD=
+ WARN=
+ BAD=
+ NORMAL=
+ HILITE=
+ BRACKET=
+}
+
+set_colors() {
+ COLS=${COLUMNS:-0} # bash's internal COLUMNS variable
+ (( COLS == 0 )) && COLS=$(set -- $(stty size 2>/dev/null) ; echo $2)
+ (( COLS > 0 )) || (( COLS = 80 ))
+
+ # Now, ${ENDCOL} will move us to the end of the
+ # column; irregardless of character width
+ ENDCOL=$'\e[A\e['$(( COLS - 8 ))'C'
+ if [ -n "${PORTAGE_COLORMAP}" ] ; then
+ eval ${PORTAGE_COLORMAP}
+ else
+ GOOD=$'\e[32;01m'
+ WARN=$'\e[33;01m'
+ BAD=$'\e[31;01m'
+ HILITE=$'\e[36;01m'
+ BRACKET=$'\e[34;01m'
+ fi
+ NORMAL=$'\e[0m'
+}
+
+RC_ENDCOL="yes"
+RC_INDENTATION=''
+RC_DEFAULT_INDENT=2
+RC_DOT_PATTERN=''
+
+case "${NOCOLOR:-false}" in
+ yes|true)
+ unset_colors
+ ;;
+ no|false)
+ set_colors
+ ;;
+esac
+
+if [[ -z ${USERLAND} ]] ; then
+ case $(uname -s) in
+ *BSD|DragonFly)
+ export USERLAND="BSD"
+ ;;
+ *)
+ export USERLAND="GNU"
+ ;;
+ esac
+fi
+
+if [[ -z ${XARGS} ]] ; then
+ case ${USERLAND} in
+ BSD)
+ export XARGS="xargs"
+ ;;
+ *)
+ export XARGS="xargs -r"
+ ;;
+ esac
+fi
+
+hasq() {
+ has $EBUILD_PHASE prerm postrm || eqawarn \
+ "QA Notice: The 'hasq' function is deprecated (replaced by 'has')"
+ has "$@"
+}
+
+hasv() {
+ if has "$@" ; then
+ echo "$1"
+ return 0
+ fi
+ return 1
+}
+
+has() {
+ local needle=$1
+ shift
+
+ local x
+ for x in "$@"; do
+ [ "${x}" = "${needle}" ] && return 0
+ done
+ return 1
+}
+
+# @FUNCTION: save_ebuild_env
+# @DESCRIPTION:
+# echo the current environment to stdout, filtering out redundant info.
+#
+# --exclude-init-phases causes pkg_nofetch and src_* phase functions to
+# be excluded from the output. These function are not needed for installation
+# or removal of the packages, and can therefore be safely excluded.
+#
+save_ebuild_env() {
+ (
+
+ if has --exclude-init-phases $* ; then
+ unset S _E_DOCDESTTREE_ _E_EXEDESTTREE_
+ if [[ -n $PYTHONPATH ]] ; then
+ export PYTHONPATH=${PYTHONPATH/${PORTAGE_PYM_PATH}:}
+ [[ -z $PYTHONPATH ]] && unset PYTHONPATH
+ fi
+ fi
+
+ # misc variables inherited from the calling environment
+ unset COLORTERM DISPLAY EDITOR LESS LESSOPEN LOGNAME LS_COLORS PAGER \
+ TERM TERMCAP USER ftp_proxy http_proxy no_proxy
+
+ # other variables inherited from the calling environment
+ unset CVS_RSH ECHANGELOG_USER GPG_AGENT_INFO \
+ SSH_AGENT_PID SSH_AUTH_SOCK STY WINDOW XAUTHORITY
+
+ # CCACHE and DISTCC config
+ unset ${!CCACHE_*} ${!DISTCC_*}
+
+ # There's no need to bloat environment.bz2 with internally defined
+ # functions and variables, so filter them out if possible.
+
+ for x in pkg_setup pkg_nofetch src_unpack src_prepare src_configure \
+ src_compile src_test src_install pkg_preinst pkg_postinst \
+ pkg_prerm pkg_postrm ; do
+ unset -f default_$x _eapi{0,1,2,3,4}_$x
+ done
+ unset x
+
+ unset -f assert assert_sigpipe_ok dump_trace die diefunc \
+ quiet_mode vecho elog_base eqawarn elog \
+ esyslog einfo einfon ewarn eerror ebegin _eend eend KV_major \
+ KV_minor KV_micro KV_to_int get_KV unset_colors set_colors has \
+ has_phase_defined_up_to \
+ hasg hasgq hasv hasq qa_source qa_call \
+ addread addwrite adddeny addpredict _sb_append_var \
+ lchown lchgrp esyslog use usev useq has_version portageq \
+ best_version use_with use_enable register_die_hook \
+ keepdir unpack strip_duplicate_slashes econf einstall \
+ dyn_setup dyn_unpack dyn_clean into insinto exeinto docinto \
+ insopts diropts exeopts libopts docompress \
+ abort_handler abort_prepare abort_configure abort_compile \
+ abort_test abort_install dyn_prepare dyn_configure \
+ dyn_compile dyn_test dyn_install \
+ dyn_preinst dyn_help debug-print debug-print-function \
+ debug-print-section inherit EXPORT_FUNCTIONS remove_path_entry \
+ save_ebuild_env filter_readonly_variables preprocess_ebuild_env \
+ set_unless_changed unset_unless_changed source_all_bashrcs \
+ ebuild_main ebuild_phase ebuild_phase_with_hooks \
+ _ebuild_arg_to_phase _ebuild_phase_funcs default \
+ _pipestatus \
+ ${QA_INTERCEPTORS}
+
+ # portage config variables and variables set directly by portage
+ unset ACCEPT_LICENSE BAD BRACKET BUILD_PREFIX COLS \
+ DISTCC_DIR DISTDIR DOC_SYMLINKS_DIR \
+ EBUILD_FORCE_TEST EBUILD_MASTER_PID \
+ ECLASS_DEPTH ENDCOL FAKEROOTKEY \
+ GOOD HILITE HOME \
+ LAST_E_CMD LAST_E_LEN LD_PRELOAD MISC_FUNCTIONS_ARGS MOPREFIX \
+ NOCOLOR NORMAL PKGDIR PKGUSE PKG_LOGDIR PKG_TMPDIR \
+ PORTAGE_BASHRCS_SOURCED PORTAGE_NONFATAL PORTAGE_QUIET \
+ PORTAGE_SANDBOX_DENY PORTAGE_SANDBOX_PREDICT \
+ PORTAGE_SANDBOX_READ PORTAGE_SANDBOX_WRITE PREROOTPATH \
+ QA_INTERCEPTORS \
+ RC_DEFAULT_INDENT RC_DOT_PATTERN RC_ENDCOL RC_INDENTATION \
+ ROOT ROOTPATH RPMDIR TEMP TMP TMPDIR USE_EXPAND \
+ WARN XARGS _RC_GET_KV_CACHE
+
+ # user config variables
+ unset DOC_SYMLINKS_DIR INSTALL_MASK PKG_INSTALL_MASK
+
+ declare -p
+ declare -fp
+ if [[ ${BASH_VERSINFO[0]} == 3 ]]; then
+ export
+ fi
+ )
+}
+
+true
diff --git a/portage_with_autodep/bin/lock-helper.py b/portage_with_autodep/bin/lock-helper.py
new file mode 100755
index 0000000..5f3ea9f
--- /dev/null
+++ b/portage_with_autodep/bin/lock-helper.py
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import os
+import sys
+sys.path.insert(0, os.environ['PORTAGE_PYM_PATH'])
+import portage
+
+def main(args):
+
+ if args and sys.hexversion < 0x3000000 and not isinstance(args[0], unicode):
+ for i, x in enumerate(args):
+ args[i] = portage._unicode_decode(x, errors='strict')
+
+ # Make locks quiet since unintended locking messages displayed on
+ # stdout would corrupt the intended output of this program.
+ portage.locks._quiet = True
+ lock_obj = portage.locks.lockfile(args[0], wantnewlockfile=True)
+ sys.stdout.write('\0')
+ sys.stdout.flush()
+ sys.stdin.read(1)
+ portage.locks.unlockfile(lock_obj)
+ return portage.os.EX_OK
+
+if __name__ == "__main__":
+ rval = main(sys.argv[1:])
+ sys.exit(rval)
diff --git a/portage_with_autodep/bin/misc-functions.sh b/portage_with_autodep/bin/misc-functions.sh
new file mode 100755
index 0000000..8c191ff
--- /dev/null
+++ b/portage_with_autodep/bin/misc-functions.sh
@@ -0,0 +1,1002 @@
+#!/bin/bash
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+#
+# Miscellaneous shell functions that make use of the ebuild env but don't need
+# to be included directly in ebuild.sh.
+#
+# We're sourcing ebuild.sh here so that we inherit all of it's goodness,
+# including bashrc trickery. This approach allows us to do our miscellaneous
+# shell work withing the same env that ebuild.sh has, but without polluting
+# ebuild.sh itself with unneeded logic and shell code.
+#
+# XXX hack: clear the args so ebuild.sh doesn't see them
+MISC_FUNCTIONS_ARGS="$@"
+shift $#
+
+source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}/ebuild.sh"
+
+install_symlink_html_docs() {
+ cd "${D}" || die "cd failed"
+ #symlink the html documentation (if DOC_SYMLINKS_DIR is set in make.conf)
+ if [ -n "${DOC_SYMLINKS_DIR}" ] ; then
+ local mydocdir docdir
+ for docdir in "${HTMLDOC_DIR:-does/not/exist}" "${PF}/html" "${PF}/HTML" "${P}/html" "${P}/HTML" ; do
+ if [ -d "usr/share/doc/${docdir}" ] ; then
+ mydocdir="/usr/share/doc/${docdir}"
+ fi
+ done
+ if [ -n "${mydocdir}" ] ; then
+ local mysympath
+ if [ -z "${SLOT}" -o "${SLOT}" = "0" ] ; then
+ mysympath="${DOC_SYMLINKS_DIR}/${CATEGORY}/${PN}"
+ else
+ mysympath="${DOC_SYMLINKS_DIR}/${CATEGORY}/${PN}-${SLOT}"
+ fi
+ einfo "Symlinking ${mysympath} to the HTML documentation"
+ dodir "${DOC_SYMLINKS_DIR}/${CATEGORY}"
+ dosym "${mydocdir}" "${mysympath}"
+ fi
+ fi
+}
+
+# replacement for "readlink -f" or "realpath"
+canonicalize() {
+ local f=$1 b n=10 wd=$(pwd)
+ while (( n-- > 0 )); do
+ while [[ ${f: -1} = / && ${#f} -gt 1 ]]; do
+ f=${f%/}
+ done
+ b=${f##*/}
+ cd "${f%"${b}"}" 2>/dev/null || break
+ if [[ ! -L ${b} ]]; then
+ f=$(pwd -P)
+ echo "${f%/}/${b}"
+ cd "${wd}"
+ return 0
+ fi
+ f=$(readlink "${b}")
+ done
+ cd "${wd}"
+ return 1
+}
+
+prepcompress() {
+ local -a include exclude incl_d incl_f
+ local f g i real_f real_d
+
+ # Canonicalize path names and check for their existence.
+ real_d=$(canonicalize "${D}")
+ for (( i = 0; i < ${#PORTAGE_DOCOMPRESS[@]}; i++ )); do
+ real_f=$(canonicalize "${D}${PORTAGE_DOCOMPRESS[i]}")
+ f=${real_f#"${real_d}"}
+ if [[ ${real_f} != "${f}" ]] && [[ -d ${real_f} || -f ${real_f} ]]
+ then
+ include[${#include[@]}]=${f:-/}
+ elif [[ ${i} -ge 3 ]]; then
+ ewarn "prepcompress:" \
+ "ignoring nonexistent path '${PORTAGE_DOCOMPRESS[i]}'"
+ fi
+ done
+ for (( i = 0; i < ${#PORTAGE_DOCOMPRESS_SKIP[@]}; i++ )); do
+ real_f=$(canonicalize "${D}${PORTAGE_DOCOMPRESS_SKIP[i]}")
+ f=${real_f#"${real_d}"}
+ if [[ ${real_f} != "${f}" ]] && [[ -d ${real_f} || -f ${real_f} ]]
+ then
+ exclude[${#exclude[@]}]=${f:-/}
+ elif [[ ${i} -ge 1 ]]; then
+ ewarn "prepcompress:" \
+ "ignoring nonexistent path '${PORTAGE_DOCOMPRESS_SKIP[i]}'"
+ fi
+ done
+
+ # Remove redundant entries from lists.
+ # For the include list, remove any entries that are:
+ # a) contained in a directory in the include or exclude lists, or
+ # b) identical with an entry in the exclude list.
+ for (( i = ${#include[@]} - 1; i >= 0; i-- )); do
+ f=${include[i]}
+ for g in "${include[@]}"; do
+ if [[ ${f} == "${g%/}"/* ]]; then
+ unset include[i]
+ continue 2
+ fi
+ done
+ for g in "${exclude[@]}"; do
+ if [[ ${f} = "${g}" || ${f} == "${g%/}"/* ]]; then
+ unset include[i]
+ continue 2
+ fi
+ done
+ done
+ # For the exclude list, remove any entries that are:
+ # a) contained in a directory in the exclude list, or
+ # b) _not_ contained in a directory in the include list.
+ for (( i = ${#exclude[@]} - 1; i >= 0; i-- )); do
+ f=${exclude[i]}
+ for g in "${exclude[@]}"; do
+ if [[ ${f} == "${g%/}"/* ]]; then
+ unset exclude[i]
+ continue 2
+ fi
+ done
+ for g in "${include[@]}"; do
+ [[ ${f} == "${g%/}"/* ]] && continue 2
+ done
+ unset exclude[i]
+ done
+
+ # Split the include list into directories and files
+ for f in "${include[@]}"; do
+ if [[ -d ${D}${f} ]]; then
+ incl_d[${#incl_d[@]}]=${f}
+ else
+ incl_f[${#incl_f[@]}]=${f}
+ fi
+ done
+
+ # Queue up for compression.
+ # ecompress{,dir} doesn't like to be called with empty argument lists.
+ [[ ${#incl_d[@]} -gt 0 ]] && ecompressdir --queue "${incl_d[@]}"
+ [[ ${#incl_f[@]} -gt 0 ]] && ecompress --queue "${incl_f[@]/#/${D}}"
+ [[ ${#exclude[@]} -gt 0 ]] && ecompressdir --ignore "${exclude[@]}"
+ return 0
+}
+
+install_qa_check() {
+ local f x
+
+ cd "${D}" || die "cd failed"
+
+ export STRIP_MASK
+ prepall
+ has "${EAPI}" 0 1 2 3 || prepcompress
+ ecompressdir --dequeue
+ ecompress --dequeue
+
+ f=
+ for x in etc/app-defaults usr/man usr/info usr/X11R6 usr/doc usr/locale ; do
+ [[ -d $D/$x ]] && f+=" $x\n"
+ done
+
+ if [[ -n $f ]] ; then
+ eqawarn "QA Notice: This ebuild installs into the following deprecated directories:"
+ eqawarn
+ eqawarn "$f"
+ fi
+
+ # Now we look for all world writable files.
+ local i
+ for i in $(find "${D}/" -type f -perm -2); do
+ vecho "QA Security Notice:"
+ vecho "- ${i:${#D}:${#i}} will be a world writable file."
+ vecho "- This may or may not be a security problem, most of the time it is one."
+ vecho "- Please double check that $PF really needs a world writeable bit and file bugs accordingly."
+ sleep 1
+ done
+
+ if type -P scanelf > /dev/null && ! has binchecks ${RESTRICT}; then
+ local qa_var insecure_rpath=0 tmp_quiet=${PORTAGE_QUIET}
+ local x
+
+ # display warnings when using stricter because we die afterwards
+ if has stricter ${FEATURES} ; then
+ unset PORTAGE_QUIET
+ fi
+
+ # Make sure we disallow insecure RUNPATH/RPATHs.
+ # 1) References to PORTAGE_BUILDDIR are banned because it's a
+ # security risk. We don't want to load files from a
+ # temporary directory.
+ # 2) If ROOT != "/", references to ROOT are banned because
+ # that directory won't exist on the target system.
+ # 3) Null paths are banned because the loader will search $PWD when
+ # it finds null paths.
+ local forbidden_dirs="${PORTAGE_BUILDDIR}"
+ if [[ -n "${ROOT}" && "${ROOT}" != "/" ]]; then
+ forbidden_dirs+=" ${ROOT}"
+ fi
+ local dir l rpath_files=$(scanelf -F '%F:%r' -qBR "${D}")
+ f=""
+ for dir in ${forbidden_dirs}; do
+ for l in $(echo "${rpath_files}" | grep -E ":${dir}|::|: "); do
+ f+=" ${l%%:*}\n"
+ if ! has stricter ${FEATURES}; then
+ vecho "Auto fixing rpaths for ${l%%:*}"
+ TMPDIR="${dir}" scanelf -BXr "${l%%:*}" -o /dev/null
+ fi
+ done
+ done
+
+ # Reject set*id binaries with $ORIGIN in RPATH #260331
+ x=$(
+ find "${D}" -type f \( -perm -u+s -o -perm -g+s \) -print0 | \
+ xargs -0 scanelf -qyRF '%r %p' | grep '$ORIGIN'
+ )
+
+ # Print QA notice.
+ if [[ -n ${f}${x} ]] ; then
+ vecho -ne '\n'
+ eqawarn "QA Notice: The following files contain insecure RUNPATHs"
+ eqawarn " Please file a bug about this at http://bugs.gentoo.org/"
+ eqawarn " with the maintaining herd of the package."
+ eqawarn "${f}${f:+${x:+\n}}${x}"
+ vecho -ne '\n'
+ if [[ -n ${x} ]] || has stricter ${FEATURES} ; then
+ insecure_rpath=1
+ fi
+ fi
+
+ # TEXTRELs are baaaaaaaad
+ # Allow devs to mark things as ignorable ... e.g. things that are
+ # binary-only and upstream isn't cooperating (nvidia-glx) ... we
+ # allow ebuild authors to set QA_TEXTRELS_arch and QA_TEXTRELS ...
+ # the former overrides the latter ... regexes allowed ! :)
+ qa_var="QA_TEXTRELS_${ARCH/-/_}"
+ [[ -n ${!qa_var} ]] && QA_TEXTRELS=${!qa_var}
+ [[ -n ${QA_STRICT_TEXTRELS} ]] && QA_TEXTRELS=""
+ export QA_TEXTRELS="${QA_TEXTRELS} lib*/modules/*.ko"
+ f=$(scanelf -qyRF '%t %p' "${D}" | grep -v 'usr/lib/debug/')
+ if [[ -n ${f} ]] ; then
+ scanelf -qyRAF '%T %p' "${PORTAGE_BUILDDIR}"/ &> "${T}"/scanelf-textrel.log
+ vecho -ne '\n'
+ eqawarn "QA Notice: The following files contain runtime text relocations"
+ eqawarn " Text relocations force the dynamic linker to perform extra"
+ eqawarn " work at startup, waste system resources, and may pose a security"
+ eqawarn " risk. On some architectures, the code may not even function"
+ eqawarn " properly, if at all."
+ eqawarn " For more information, see http://hardened.gentoo.org/pic-fix-guide.xml"
+ eqawarn " Please include the following list of files in your report:"
+ eqawarn "${f}"
+ vecho -ne '\n'
+ die_msg="${die_msg} textrels,"
+ sleep 1
+ fi
+
+ # Also, executable stacks only matter on linux (and just glibc atm ...)
+ f=""
+ case ${CTARGET:-${CHOST}} in
+ *-linux-gnu*)
+ # Check for files with executable stacks, but only on arches which
+ # are supported at the moment. Keep this list in sync with
+ # http://hardened.gentoo.org/gnu-stack.xml (Arch Status)
+ case ${CTARGET:-${CHOST}} in
+ arm*|i?86*|ia64*|m68k*|s390*|sh*|x86_64*)
+ # Allow devs to mark things as ignorable ... e.g. things
+ # that are binary-only and upstream isn't cooperating ...
+ # we allow ebuild authors to set QA_EXECSTACK_arch and
+ # QA_EXECSTACK ... the former overrides the latter ...
+ # regexes allowed ! :)
+
+ qa_var="QA_EXECSTACK_${ARCH/-/_}"
+ [[ -n ${!qa_var} ]] && QA_EXECSTACK=${!qa_var}
+ [[ -n ${QA_STRICT_EXECSTACK} ]] && QA_EXECSTACK=""
+ qa_var="QA_WX_LOAD_${ARCH/-/_}"
+ [[ -n ${!qa_var} ]] && QA_WX_LOAD=${!qa_var}
+ [[ -n ${QA_STRICT_WX_LOAD} ]] && QA_WX_LOAD=""
+ export QA_EXECSTACK="${QA_EXECSTACK} lib*/modules/*.ko"
+ export QA_WX_LOAD="${QA_WX_LOAD} lib*/modules/*.ko"
+ f=$(scanelf -qyRAF '%e %p' "${D}" | grep -v 'usr/lib/debug/')
+ ;;
+ esac
+ ;;
+ esac
+ if [[ -n ${f} ]] ; then
+ # One more pass to help devs track down the source
+ scanelf -qyRAF '%e %p' "${PORTAGE_BUILDDIR}"/ &> "${T}"/scanelf-execstack.log
+ vecho -ne '\n'
+ eqawarn "QA Notice: The following files contain writable and executable sections"
+ eqawarn " Files with such sections will not work properly (or at all!) on some"
+ eqawarn " architectures/operating systems. A bug should be filed at"
+ eqawarn " http://bugs.gentoo.org/ to make sure the issue is fixed."
+ eqawarn " For more information, see http://hardened.gentoo.org/gnu-stack.xml"
+ eqawarn " Please include the following list of files in your report:"
+ eqawarn " Note: Bugs should be filed for the respective maintainers"
+ eqawarn " of the package in question and not hardened@g.o."
+ eqawarn "${f}"
+ vecho -ne '\n'
+ die_msg="${die_msg} execstacks"
+ sleep 1
+ fi
+
+ # Check for files built without respecting LDFLAGS
+ if [[ "${LDFLAGS}" == *,--hash-style=gnu* ]] && [[ "${PN}" != *-bin ]] ; then
+ qa_var="QA_DT_HASH_${ARCH/-/_}"
+ eval "[[ -n \${!qa_var} ]] && QA_DT_HASH=(\"\${${qa_var}[@]}\")"
+ f=$(scanelf -qyRF '%k %p' -k .hash "${D}" | sed -e "s:\.hash ::")
+ if [[ -n ${f} ]] ; then
+ echo "${f}" > "${T}"/scanelf-ignored-LDFLAGS.log
+ if [ "${QA_STRICT_DT_HASH-unset}" == unset ] ; then
+ if [[ ${#QA_DT_HASH[@]} -gt 1 ]] ; then
+ for x in "${QA_DT_HASH[@]}" ; do
+ sed -e "s#^${x#/}\$##" -i "${T}"/scanelf-ignored-LDFLAGS.log
+ done
+ else
+ local shopts=$-
+ set -o noglob
+ for x in ${QA_DT_HASH} ; do
+ sed -e "s#^${x#/}\$##" -i "${T}"/scanelf-ignored-LDFLAGS.log
+ done
+ set +o noglob
+ set -${shopts}
+ fi
+ fi
+ # Filter anything under /usr/lib/debug/ in order to avoid
+ # duplicate warnings for splitdebug files.
+ sed -e "s#^usr/lib/debug/.*##" -e "/^\$/d" -e "s#^#/#" \
+ -i "${T}"/scanelf-ignored-LDFLAGS.log
+ f=$(<"${T}"/scanelf-ignored-LDFLAGS.log)
+ if [[ -n ${f} ]] ; then
+ vecho -ne '\n'
+ eqawarn "${BAD}QA Notice: Files built without respecting LDFLAGS have been detected${NORMAL}"
+ eqawarn " Please include the following list of files in your report:"
+ eqawarn "${f}"
+ vecho -ne '\n'
+ sleep 1
+ else
+ rm -f "${T}"/scanelf-ignored-LDFLAGS.log
+ fi
+ fi
+ fi
+
+ # Save NEEDED information after removing self-contained providers
+ rm -f "$PORTAGE_BUILDDIR"/build-info/NEEDED{,.ELF.2}
+ scanelf -qyRF '%a;%p;%S;%r;%n' "${D}" | { while IFS= read -r l; do
+ arch=${l%%;*}; l=${l#*;}
+ obj="/${l%%;*}"; l=${l#*;}
+ soname=${l%%;*}; l=${l#*;}
+ rpath=${l%%;*}; l=${l#*;}; [ "${rpath}" = " - " ] && rpath=""
+ needed=${l%%;*}; l=${l#*;}
+ if [ -z "${rpath}" -o -n "${rpath//*ORIGIN*}" ]; then
+ # object doesn't contain $ORIGIN in its runpath attribute
+ echo "${obj} ${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED
+ echo "${arch:3};${obj};${soname};${rpath};${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2
+ else
+ dir=${obj%/*}
+ # replace $ORIGIN with the dirname of the current object for the lookup
+ opath=$(echo :${rpath}: | sed -e "s#.*:\(.*\)\$ORIGIN\(.*\):.*#\1${dir}\2#")
+ sneeded=$(echo ${needed} | tr , ' ')
+ rneeded=""
+ for lib in ${sneeded}; do
+ found=0
+ for path in ${opath//:/ }; do
+ [ -e "${D}/${path}/${lib}" ] && found=1 && break
+ done
+ [ "${found}" -eq 0 ] && rneeded="${rneeded},${lib}"
+ done
+ rneeded=${rneeded:1}
+ if [ -n "${rneeded}" ]; then
+ echo "${obj} ${rneeded}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED
+ echo "${arch:3};${obj};${soname};${rpath};${rneeded}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2
+ fi
+ fi
+ done }
+
+ if [[ ${insecure_rpath} -eq 1 ]] ; then
+ die "Aborting due to serious QA concerns with RUNPATH/RPATH"
+ elif [[ -n ${die_msg} ]] && has stricter ${FEATURES} ; then
+ die "Aborting due to QA concerns: ${die_msg}"
+ fi
+
+ # Check for shared libraries lacking SONAMEs
+ qa_var="QA_SONAME_${ARCH/-/_}"
+ eval "[[ -n \${!qa_var} ]] && QA_SONAME=(\"\${${qa_var}[@]}\")"
+ f=$(scanelf -ByF '%S %p' "${D}"{,usr/}lib*/lib*.so* | gawk '$2 == "" { print }' | sed -e "s:^[[:space:]]${D}:/:")
+ if [[ -n ${f} ]] ; then
+ echo "${f}" > "${T}"/scanelf-missing-SONAME.log
+ if [[ "${QA_STRICT_SONAME-unset}" == unset ]] ; then
+ if [[ ${#QA_SONAME[@]} -gt 1 ]] ; then
+ for x in "${QA_SONAME[@]}" ; do
+ sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-SONAME.log
+ done
+ else
+ local shopts=$-
+ set -o noglob
+ for x in ${QA_SONAME} ; do
+ sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-SONAME.log
+ done
+ set +o noglob
+ set -${shopts}
+ fi
+ fi
+ sed -e "/^\$/d" -i "${T}"/scanelf-missing-SONAME.log
+ f=$(<"${T}"/scanelf-missing-SONAME.log)
+ if [[ -n ${f} ]] ; then
+ vecho -ne '\n'
+ eqawarn "QA Notice: The following shared libraries lack a SONAME"
+ eqawarn "${f}"
+ vecho -ne '\n'
+ sleep 1
+ else
+ rm -f "${T}"/scanelf-missing-SONAME.log
+ fi
+ fi
+
+ # Check for shared libraries lacking NEEDED entries
+ qa_var="QA_DT_NEEDED_${ARCH/-/_}"
+ eval "[[ -n \${!qa_var} ]] && QA_DT_NEEDED=(\"\${${qa_var}[@]}\")"
+ f=$(scanelf -ByF '%n %p' "${D}"{,usr/}lib*/lib*.so* | gawk '$2 == "" { print }' | sed -e "s:^[[:space:]]${D}:/:")
+ if [[ -n ${f} ]] ; then
+ echo "${f}" > "${T}"/scanelf-missing-NEEDED.log
+ if [[ "${QA_STRICT_DT_NEEDED-unset}" == unset ]] ; then
+ if [[ ${#QA_DT_NEEDED[@]} -gt 1 ]] ; then
+ for x in "${QA_DT_NEEDED[@]}" ; do
+ sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-NEEDED.log
+ done
+ else
+ local shopts=$-
+ set -o noglob
+ for x in ${QA_DT_NEEDED} ; do
+ sed -e "s#^/${x#/}\$##" -i "${T}"/scanelf-missing-NEEDED.log
+ done
+ set +o noglob
+ set -${shopts}
+ fi
+ fi
+ sed -e "/^\$/d" -i "${T}"/scanelf-missing-NEEDED.log
+ f=$(<"${T}"/scanelf-missing-NEEDED.log)
+ if [[ -n ${f} ]] ; then
+ vecho -ne '\n'
+ eqawarn "QA Notice: The following shared libraries lack NEEDED entries"
+ eqawarn "${f}"
+ vecho -ne '\n'
+ sleep 1
+ else
+ rm -f "${T}"/scanelf-missing-NEEDED.log
+ fi
+ fi
+
+ PORTAGE_QUIET=${tmp_quiet}
+ fi
+
+ local unsafe_files=$(find "${D}" -type f '(' -perm -2002 -o -perm -4002 ')')
+ if [[ -n ${unsafe_files} ]] ; then
+ eqawarn "QA Notice: Unsafe files detected (set*id and world writable)"
+ eqawarn "${unsafe_files}"
+ die "Unsafe files found in \${D}. Portage will not install them."
+ fi
+
+ if [[ -d ${D}/${D} ]] ; then
+ declare -i INSTALLTOD=0
+ for i in $(find "${D}/${D}/"); do
+ eqawarn "QA Notice: /${i##${D}/${D}} installed in \${D}/\${D}"
+ ((INSTALLTOD++))
+ done
+ die "Aborting due to QA concerns: ${INSTALLTOD} files installed in ${D}/${D}"
+ unset INSTALLTOD
+ fi
+
+ # Sanity check syntax errors in init.d scripts
+ local d
+ for d in /etc/conf.d /etc/init.d ; do
+ [[ -d ${D}/${d} ]] || continue
+ for i in "${D}"/${d}/* ; do
+ [[ -L ${i} ]] && continue
+ # if empty conf.d/init.d dir exists (baselayout), then i will be "/etc/conf.d/*" and not exist
+ [[ ! -e ${i} ]] && continue
+ bash -n "${i}" || die "The init.d file has syntax errors: ${i}"
+ done
+ done
+
+ # this should help to ensure that all (most?) shared libraries are executable
+ # and that all libtool scripts / static libraries are not executable
+ local j
+ for i in "${D}"opt/*/lib{,32,64} \
+ "${D}"lib{,32,64} \
+ "${D}"usr/lib{,32,64} \
+ "${D}"usr/X11R6/lib{,32,64} ; do
+ [[ ! -d ${i} ]] && continue
+
+ for j in "${i}"/*.so.* "${i}"/*.so ; do
+ [[ ! -e ${j} ]] && continue
+ [[ -L ${j} ]] && continue
+ [[ -x ${j} ]] && continue
+ vecho "making executable: ${j#${D}}"
+ chmod +x "${j}"
+ done
+
+ for j in "${i}"/*.a "${i}"/*.la ; do
+ [[ ! -e ${j} ]] && continue
+ [[ -L ${j} ]] && continue
+ [[ ! -x ${j} ]] && continue
+ vecho "removing executable bit: ${j#${D}}"
+ chmod -x "${j}"
+ done
+
+ for j in "${i}"/*.{a,dll,dylib,sl,so}.* "${i}"/*.{a,dll,dylib,sl,so} ; do
+ [[ ! -e ${j} ]] && continue
+ [[ ! -L ${j} ]] && continue
+ linkdest=$(readlink "${j}")
+ if [[ ${linkdest} == /* ]] ; then
+ vecho -ne '\n'
+ eqawarn "QA Notice: Found an absolute symlink in a library directory:"
+ eqawarn " ${j#${D}} -> ${linkdest}"
+ eqawarn " It should be a relative symlink if in the same directory"
+ eqawarn " or a linker script if it crosses the /usr boundary."
+ fi
+ done
+ done
+
+ # When installing static libraries into /usr/lib and shared libraries into
+ # /lib, we have to make sure we have a linker script in /usr/lib along side
+ # the static library, or gcc will utilize the static lib when linking :(.
+ # http://bugs.gentoo.org/4411
+ abort="no"
+ local a s
+ for a in "${D}"usr/lib*/*.a ; do
+ s=${a%.a}.so
+ if [[ ! -e ${s} ]] ; then
+ s=${s%usr/*}${s##*/usr/}
+ if [[ -e ${s} ]] ; then
+ vecho -ne '\n'
+ eqawarn "QA Notice: Missing gen_usr_ldscript for ${s##*/}"
+ abort="yes"
+ fi
+ fi
+ done
+ [[ ${abort} == "yes" ]] && die "add those ldscripts"
+
+ # Make sure people don't store libtool files or static libs in /lib
+ f=$(ls "${D}"lib*/*.{a,la} 2>/dev/null)
+ if [[ -n ${f} ]] ; then
+ vecho -ne '\n'
+ eqawarn "QA Notice: Excessive files found in the / partition"
+ eqawarn "${f}"
+ vecho -ne '\n'
+ die "static archives (*.a) and libtool library files (*.la) do not belong in /"
+ fi
+
+ # Verify that the libtool files don't contain bogus $D entries.
+ local abort=no gentoo_bug=no always_overflow=no
+ for a in "${D}"usr/lib*/*.la ; do
+ s=${a##*/}
+ if grep -qs "${D}" "${a}" ; then
+ vecho -ne '\n'
+ eqawarn "QA Notice: ${s} appears to contain PORTAGE_TMPDIR paths"
+ abort="yes"
+ fi
+ done
+ [[ ${abort} == "yes" ]] && die "soiled libtool library files found"
+
+ # Evaluate misc gcc warnings
+ if [[ -n ${PORTAGE_LOG_FILE} && -r ${PORTAGE_LOG_FILE} ]] ; then
+ # In debug mode, this variable definition and corresponding grep calls
+ # will produce false positives if they're shown in the trace.
+ local reset_debug=0
+ if [[ ${-/x/} != $- ]] ; then
+ set +x
+ reset_debug=1
+ fi
+ local m msgs=(
+ ": warning: dereferencing type-punned pointer will break strict-aliasing rules"
+ ": warning: dereferencing pointer .* does break strict-aliasing rules"
+ ": warning: implicit declaration of function"
+ ": warning: incompatible implicit declaration of built-in function"
+ ": warning: is used uninitialized in this function" # we'll ignore "may" and "might"
+ ": warning: comparisons like X<=Y<=Z do not have their mathematical meaning"
+ ": warning: null argument where non-null required"
+ ": warning: array subscript is below array bounds"
+ ": warning: array subscript is above array bounds"
+ ": warning: attempt to free a non-heap object"
+ ": warning: .* called with .*bigger.* than .* destination buffer"
+ ": warning: call to .* will always overflow destination buffer"
+ ": warning: assuming pointer wraparound does not occur when comparing"
+ ": warning: hex escape sequence out of range"
+ ": warning: [^ ]*-hand operand of comma .*has no effect"
+ ": warning: converting to non-pointer type .* from NULL"
+ ": warning: NULL used in arithmetic"
+ ": warning: passing NULL to non-pointer argument"
+ ": warning: the address of [^ ]* will always evaluate as"
+ ": warning: the address of [^ ]* will never be NULL"
+ ": warning: too few arguments for format"
+ ": warning: reference to local variable .* returned"
+ ": warning: returning reference to temporary"
+ ": warning: function returns address of local variable"
+ # this may be valid code :/
+ #": warning: multi-character character constant"
+ # need to check these two ...
+ #": warning: assuming signed overflow does not occur when"
+ #": warning: comparison with string literal results in unspecified behav"
+ # yacc/lex likes to trigger this one
+ #": warning: extra tokens at end of .* directive"
+ # only gcc itself triggers this ?
+ #": warning: .*noreturn.* function does return"
+ # these throw false positives when 0 is used instead of NULL
+ #": warning: missing sentinel in function call"
+ #": warning: not enough variable arguments to fit a sentinel"
+ )
+ abort="no"
+ i=0
+ local grep_cmd=grep
+ [[ $PORTAGE_LOG_FILE = *.gz ]] && grep_cmd=zgrep
+ while [[ -n ${msgs[${i}]} ]] ; do
+ m=${msgs[$((i++))]}
+ # force C locale to work around slow unicode locales #160234
+ f=$(LC_ALL=C $grep_cmd "${m}" "${PORTAGE_LOG_FILE}")
+ if [[ -n ${f} ]] ; then
+ abort="yes"
+ # for now, don't make this fatal (see bug #337031)
+ #case "$m" in
+ # ": warning: call to .* will always overflow destination buffer") always_overflow=yes ;;
+ #esac
+ if [[ $always_overflow = yes ]] ; then
+ eerror
+ eerror "QA Notice: Package has poor programming practices which may compile"
+ eerror " fine but exhibit random runtime failures."
+ eerror
+ eerror "${f}"
+ eerror
+ eerror " Please file a bug about this at http://bugs.gentoo.org/"
+ eerror " with the maintaining herd of the package."
+ eerror
+ else
+ vecho -ne '\n'
+ eqawarn "QA Notice: Package has poor programming practices which may compile"
+ eqawarn " fine but exhibit random runtime failures."
+ eqawarn "${f}"
+ vecho -ne '\n'
+ fi
+ fi
+ done
+ local cat_cmd=cat
+ [[ $PORTAGE_LOG_FILE = *.gz ]] && cat_cmd=zcat
+ [[ $reset_debug = 1 ]] && set -x
+ f=$($cat_cmd "${PORTAGE_LOG_FILE}" | \
+ "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH"/check-implicit-pointer-usage.py || die "check-implicit-pointer-usage.py failed")
+ if [[ -n ${f} ]] ; then
+
+ # In the future this will be a forced "die". In preparation,
+ # increase the log level from "qa" to "eerror" so that people
+ # are aware this is a problem that must be fixed asap.
+
+ # just warn on 32bit hosts but bail on 64bit hosts
+ case ${CHOST} in
+ alpha*|hppa64*|ia64*|powerpc64*|mips64*|sparc64*|sparcv9*|x86_64*) gentoo_bug=yes ;;
+ esac
+
+ abort=yes
+
+ if [[ $gentoo_bug = yes ]] ; then
+ eerror
+ eerror "QA Notice: Package has poor programming practices which may compile"
+ eerror " but will almost certainly crash on 64bit architectures."
+ eerror
+ eerror "${f}"
+ eerror
+ eerror " Please file a bug about this at http://bugs.gentoo.org/"
+ eerror " with the maintaining herd of the package."
+ eerror
+ else
+ vecho -ne '\n'
+ eqawarn "QA Notice: Package has poor programming practices which may compile"
+ eqawarn " but will almost certainly crash on 64bit architectures."
+ eqawarn "${f}"
+ vecho -ne '\n'
+ fi
+
+ fi
+ if [[ ${abort} == "yes" ]] ; then
+ if [[ $gentoo_bug = yes || $always_overflow = yes ]] ; then
+ die "install aborted due to" \
+ "poor programming practices shown above"
+ else
+ echo "Please do not file a Gentoo bug and instead" \
+ "report the above QA issues directly to the upstream" \
+ "developers of this software." | fmt -w 70 | \
+ while read -r line ; do eqawarn "${line}" ; done
+ eqawarn "Homepage: ${HOMEPAGE}"
+ has stricter ${FEATURES} && die "install aborted due to" \
+ "poor programming practices shown above"
+ fi
+ fi
+ fi
+
+ # Portage regenerates this on the installed system.
+ rm -f "${D}"/usr/share/info/dir{,.gz,.bz2}
+
+ if has multilib-strict ${FEATURES} && \
+ [[ -x /usr/bin/file && -x /usr/bin/find ]] && \
+ [[ -n ${MULTILIB_STRICT_DIRS} && -n ${MULTILIB_STRICT_DENY} ]]
+ then
+ local abort=no dir file firstrun=yes
+ MULTILIB_STRICT_EXEMPT=$(echo ${MULTILIB_STRICT_EXEMPT} | sed -e 's:\([(|)]\):\\\1:g')
+ for dir in ${MULTILIB_STRICT_DIRS} ; do
+ [[ -d ${D}/${dir} ]] || continue
+ for file in $(find ${D}/${dir} -type f | grep -v "^${D}/${dir}/${MULTILIB_STRICT_EXEMPT}"); do
+ if file ${file} | egrep -q "${MULTILIB_STRICT_DENY}" ; then
+ if [[ ${firstrun} == yes ]] ; then
+ echo "Files matching a file type that is not allowed:"
+ firstrun=no
+ fi
+ abort=yes
+ echo " ${file#${D}//}"
+ fi
+ done
+ done
+ [[ ${abort} == yes ]] && die "multilib-strict check failed!"
+ fi
+
+ # ensure packages don't install systemd units automagically
+ if ! has systemd ${INHERITED} && \
+ [[ -d "${D}"/lib/systemd/system ]]
+ then
+ eqawarn "QA Notice: package installs systemd unit files (/lib/systemd/system)"
+ eqawarn " but does not inherit systemd.eclass."
+ has stricter ${FEATURES} \
+ && die "install aborted due to missing inherit of systemd.eclass"
+ fi
+}
+
+
+install_mask() {
+ local root="$1"
+ shift
+ local install_mask="$*"
+
+ # we don't want globbing for initial expansion, but afterwards, we do
+ local shopts=$-
+ set -o noglob
+ local no_inst
+ for no_inst in ${install_mask}; do
+ set +o noglob
+ quiet_mode || einfo "Removing ${no_inst}"
+ # normal stuff
+ rm -Rf "${root}"/${no_inst} >&/dev/null
+
+ # we also need to handle globs (*.a, *.h, etc)
+ find "${root}" \( -path "${no_inst}" -or -name "${no_inst}" \) \
+ -exec rm -fR {} \; >/dev/null 2>&1
+ done
+ # set everything back the way we found it
+ set +o noglob
+ set -${shopts}
+}
+
+preinst_mask() {
+ if [ -z "${D}" ]; then
+ eerror "${FUNCNAME}: D is unset"
+ return 1
+ fi
+
+ # Make sure $PWD is not ${D} so that we don't leave gmon.out files
+ # in there in case any tools were built with -pg in CFLAGS.
+ cd "${T}"
+
+ # remove man pages, info pages, docs if requested
+ local f
+ for f in man info doc; do
+ if has no${f} $FEATURES; then
+ INSTALL_MASK="${INSTALL_MASK} /usr/share/${f}"
+ fi
+ done
+
+ install_mask "${D}" "${INSTALL_MASK}"
+
+ # remove share dir if unnessesary
+ if has nodoc $FEATURES || has noman $FEATURES || has noinfo $FEATURES; then
+ rmdir "${D}usr/share" &> /dev/null
+ fi
+}
+
+preinst_sfperms() {
+ if [ -z "${D}" ]; then
+ eerror "${FUNCNAME}: D is unset"
+ return 1
+ fi
+ # Smart FileSystem Permissions
+ if has sfperms $FEATURES; then
+ local i
+ find "${D}" -type f -perm -4000 -print0 | \
+ while read -r -d $'\0' i ; do
+ if [ -n "$(find "$i" -perm -2000)" ] ; then
+ ebegin ">>> SetUID and SetGID: [chmod o-r] /${i#${D}}"
+ chmod o-r "$i"
+ eend $?
+ else
+ ebegin ">>> SetUID: [chmod go-r] /${i#${D}}"
+ chmod go-r "$i"
+ eend $?
+ fi
+ done
+ find "${D}" -type f -perm -2000 -print0 | \
+ while read -r -d $'\0' i ; do
+ if [ -n "$(find "$i" -perm -4000)" ] ; then
+ # This case is already handled
+ # by the SetUID check above.
+ true
+ else
+ ebegin ">>> SetGID: [chmod o-r] /${i#${D}}"
+ chmod o-r "$i"
+ eend $?
+ fi
+ done
+ fi
+}
+
+preinst_suid_scan() {
+ if [ -z "${D}" ]; then
+ eerror "${FUNCNAME}: D is unset"
+ return 1
+ fi
+ # total suid control.
+ if has suidctl $FEATURES; then
+ local i sfconf x
+ sfconf=${PORTAGE_CONFIGROOT}etc/portage/suidctl.conf
+ # sandbox prevents us from writing directly
+ # to files outside of the sandbox, but this
+ # can easly be bypassed using the addwrite() function
+ addwrite "${sfconf}"
+ vecho ">>> Performing suid scan in ${D}"
+ for i in $(find "${D}" -type f \( -perm -4000 -o -perm -2000 \) ); do
+ if [ -s "${sfconf}" ]; then
+ install_path=/${i#${D}}
+ if grep -q "^${install_path}\$" "${sfconf}" ; then
+ vecho "- ${install_path} is an approved suid file"
+ else
+ vecho ">>> Removing sbit on non registered ${install_path}"
+ for x in 5 4 3 2 1 0; do sleep 0.25 ; done
+ ls_ret=$(ls -ldh "${i}")
+ chmod ugo-s "${i}"
+ grep "^#${install_path}$" "${sfconf}" > /dev/null || {
+ vecho ">>> Appending commented out entry to ${sfconf} for ${PF}"
+ echo "## ${ls_ret%${D}*}${install_path}" >> "${sfconf}"
+ echo "#${install_path}" >> "${sfconf}"
+ # no delwrite() eh?
+ # delwrite ${sconf}
+ }
+ fi
+ else
+ vecho "suidctl feature set but you are lacking a ${sfconf}"
+ fi
+ done
+ fi
+}
+
+preinst_selinux_labels() {
+ if [ -z "${D}" ]; then
+ eerror "${FUNCNAME}: D is unset"
+ return 1
+ fi
+ if has selinux ${FEATURES}; then
+ # SELinux file labeling (needs to always be last in dyn_preinst)
+ # only attempt to label if setfiles is executable
+ # and 'context' is available on selinuxfs.
+ if [ -f /selinux/context -a -x /usr/sbin/setfiles -a -x /usr/sbin/selinuxconfig ]; then
+ vecho ">>> Setting SELinux security labels"
+ (
+ eval "$(/usr/sbin/selinuxconfig)" || \
+ die "Failed to determine SELinux policy paths.";
+
+ addwrite /selinux/context;
+
+ /usr/sbin/setfiles "${file_contexts_path}" -r "${D}" "${D}"
+ ) || die "Failed to set SELinux security labels."
+ else
+ # nonfatal, since merging can happen outside a SE kernel
+ # like during a recovery situation
+ vecho "!!! Unable to set SELinux security labels"
+ fi
+ fi
+}
+
+dyn_package() {
+ # Make sure $PWD is not ${D} so that we don't leave gmon.out files
+ # in there in case any tools were built with -pg in CFLAGS.
+ cd "${T}"
+ install_mask "${PORTAGE_BUILDDIR}/image" "${PKG_INSTALL_MASK}"
+ local tar_options=""
+ [[ $PORTAGE_VERBOSE = 1 ]] && tar_options+=" -v"
+ # Sandbox is disabled in case the user wants to use a symlink
+ # for $PKGDIR and/or $PKGDIR/All.
+ export SANDBOX_ON="0"
+ [ -z "${PORTAGE_BINPKG_TMPFILE}" ] && \
+ die "PORTAGE_BINPKG_TMPFILE is unset"
+ mkdir -p "${PORTAGE_BINPKG_TMPFILE%/*}" || die "mkdir failed"
+ tar $tar_options -cf - $PORTAGE_BINPKG_TAR_OPTS -C "${D}" . | \
+ $PORTAGE_BZIP2_COMMAND -c > "$PORTAGE_BINPKG_TMPFILE"
+ assert "failed to pack binary package: '$PORTAGE_BINPKG_TMPFILE'"
+ PYTHONPATH=${PORTAGE_PYM_PATH}${PYTHONPATH:+:}${PYTHONPATH} \
+ "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH"/xpak-helper.py recompose \
+ "$PORTAGE_BINPKG_TMPFILE" "$PORTAGE_BUILDDIR/build-info"
+ if [ $? -ne 0 ]; then
+ rm -f "${PORTAGE_BINPKG_TMPFILE}"
+ die "Failed to append metadata to the tbz2 file"
+ fi
+ local md5_hash=""
+ if type md5sum &>/dev/null ; then
+ md5_hash=$(md5sum "${PORTAGE_BINPKG_TMPFILE}")
+ md5_hash=${md5_hash%% *}
+ elif type md5 &>/dev/null ; then
+ md5_hash=$(md5 "${PORTAGE_BINPKG_TMPFILE}")
+ md5_hash=${md5_hash##* }
+ fi
+ [ -n "${md5_hash}" ] && \
+ echo ${md5_hash} > "${PORTAGE_BUILDDIR}"/build-info/BINPKGMD5
+ vecho ">>> Done."
+ cd "${PORTAGE_BUILDDIR}"
+ >> "$PORTAGE_BUILDDIR/.packaged" || \
+ die "Failed to create $PORTAGE_BUILDDIR/.packaged"
+}
+
+dyn_spec() {
+ local sources_dir=/usr/src/rpm/SOURCES
+ mkdir -p "${sources_dir}"
+ declare -a tar_args=("${EBUILD}")
+ [[ -d ${FILESDIR} ]] && tar_args=("${EBUILD}" "${FILESDIR}")
+ tar czf "${sources_dir}/${PF}.tar.gz" \
+ "${tar_args[@]}" || \
+ die "Failed to create base rpm tarball."
+
+ cat <<__END1__ > ${PF}.spec
+Summary: ${DESCRIPTION}
+Name: ${PN}
+Version: ${PV}
+Release: ${PR}
+Copyright: GPL
+Group: portage/${CATEGORY}
+Source: ${PF}.tar.gz
+Buildroot: ${D}
+%description
+${DESCRIPTION}
+
+${HOMEPAGE}
+
+%prep
+%setup -c
+
+%build
+
+%install
+
+%clean
+
+%files
+/
+__END1__
+
+}
+
+dyn_rpm() {
+ cd "${T}" || die "cd failed"
+ local machine_name=$(uname -m)
+ local dest_dir=/usr/src/rpm/RPMS/${machine_name}
+ addwrite /usr/src/rpm
+ addwrite "${RPMDIR}"
+ dyn_spec
+ rpmbuild -bb --clean --rmsource "${PF}.spec" || die "Failed to integrate rpm spec file"
+ install -D "${dest_dir}/${PN}-${PV}-${PR}.${machine_name}.rpm" \
+ "${RPMDIR}/${CATEGORY}/${PN}-${PV}-${PR}.rpm" || \
+ die "Failed to move rpm"
+}
+
+die_hooks() {
+ [[ -f $PORTAGE_BUILDDIR/.die_hooks ]] && return
+ local x
+ for x in $EBUILD_DEATH_HOOKS ; do
+ $x >&2
+ done
+ > "$PORTAGE_BUILDDIR/.die_hooks"
+}
+
+success_hooks() {
+ local x
+ for x in $EBUILD_SUCCESS_HOOKS ; do
+ $x
+ done
+}
+
+if [ -n "${MISC_FUNCTIONS_ARGS}" ]; then
+ source_all_bashrcs
+ [ "$PORTAGE_DEBUG" == "1" ] && set -x
+ for x in ${MISC_FUNCTIONS_ARGS}; do
+ ${x}
+ done
+ unset x
+ [[ -n $PORTAGE_EBUILD_EXIT_FILE ]] && > "$PORTAGE_EBUILD_EXIT_FILE"
+ if [[ -n $PORTAGE_IPC_DAEMON ]] ; then
+ [[ ! -s $SANDBOX_LOG ]]
+ "$PORTAGE_BIN_PATH"/ebuild-ipc exit $?
+ fi
+fi
+
+:
diff --git a/portage_with_autodep/bin/portageq b/portage_with_autodep/bin/portageq
new file mode 100755
index 0000000..57a7c39
--- /dev/null
+++ b/portage_with_autodep/bin/portageq
@@ -0,0 +1,822 @@
+#!/usr/bin/python -O
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import signal
+import sys
+# This block ensures that ^C interrupts are handled quietly.
+try:
+
+ def exithandler(signum, frame):
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
+ sys.exit(128 + signum)
+
+ signal.signal(signal.SIGINT, exithandler)
+ signal.signal(signal.SIGTERM, exithandler)
+
+except KeyboardInterrupt:
+ sys.exit(128 + signal.SIGINT)
+
+import os
+import types
+
+# Avoid sandbox violations after python upgrade.
+pym_path = os.path.join(os.path.dirname(
+ os.path.dirname(os.path.realpath(__file__))), "pym")
+if os.environ.get("SANDBOX_ON") == "1":
+ sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
+ if pym_path not in sandbox_write:
+ sandbox_write.append(pym_path)
+ os.environ["SANDBOX_WRITE"] = \
+ ":".join(filter(None, sandbox_write))
+ del sandbox_write
+
+try:
+ import portage
+except ImportError:
+ sys.path.insert(0, pym_path)
+ import portage
+del pym_path
+
+from portage import os
+from portage.util import writemsg, writemsg_stdout
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'subprocess',
+ '_emerge.Package:Package',
+ '_emerge.RootConfig:RootConfig',
+ 'portage.dbapi._expand_new_virt:expand_new_virt',
+)
+
+def eval_atom_use(atom):
+ if 'USE' in os.environ:
+ use = frozenset(os.environ['USE'].split())
+ atom = atom.evaluate_conditionals(use)
+ return atom
+
+#-----------------------------------------------------------------------------
+#
+# To add functionality to this tool, add a function below.
+#
+# The format for functions is:
+#
+# def function(argv):
+# """<list of options for this function>
+# <description of the function>
+# """
+# <code>
+#
+# "argv" is an array of the command line parameters provided after the command.
+#
+# Make sure you document the function in the right format. The documentation
+# is used to display help on the function.
+#
+# You do not need to add the function to any lists, this tool is introspective,
+# and will automaticly add a command by the same name as the function!
+#
+
+def has_version(argv):
+ """<root> <category/package>
+ Return code 0 if it's available, 1 otherwise.
+ """
+ if (len(argv) < 2):
+ print("ERROR: insufficient parameters!")
+ sys.exit(2)
+
+ warnings = []
+
+ try:
+ atom = portage.dep.Atom(argv[1])
+ except portage.exception.InvalidAtom:
+ if atom_validate_strict:
+ portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
+ noiselevel=-1)
+ return 2
+ else:
+ atom = argv[1]
+ else:
+ if atom_validate_strict:
+ try:
+ atom = portage.dep.Atom(argv[1], eapi=eapi)
+ except portage.exception.InvalidAtom as e:
+ warnings.append(
+ portage._unicode_decode("QA Notice: %s: %s") % \
+ ('has_version', e))
+ atom = eval_atom_use(atom)
+
+ if warnings:
+ elog('eqawarn', warnings)
+
+ try:
+ mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
+ if mylist:
+ sys.exit(0)
+ else:
+ sys.exit(1)
+ except KeyError:
+ sys.exit(1)
+ except portage.exception.InvalidAtom:
+ portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
+ noiselevel=-1)
+ return 2
+has_version.uses_root = True
+
+
+def best_version(argv):
+ """<root> <category/package>
+ Returns category/package-version (without .ebuild).
+ """
+ if (len(argv) < 2):
+ print("ERROR: insufficient parameters!")
+ sys.exit(2)
+
+ warnings = []
+
+ try:
+ atom = portage.dep.Atom(argv[1])
+ except portage.exception.InvalidAtom:
+ if atom_validate_strict:
+ portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1],
+ noiselevel=-1)
+ return 2
+ else:
+ atom = argv[1]
+ else:
+ if atom_validate_strict:
+ try:
+ atom = portage.dep.Atom(argv[1], eapi=eapi)
+ except portage.exception.InvalidAtom as e:
+ warnings.append(
+ portage._unicode_decode("QA Notice: %s: %s") % \
+ ('best_version', e))
+ atom = eval_atom_use(atom)
+
+ if warnings:
+ elog('eqawarn', warnings)
+
+ try:
+ mylist = portage.db[argv[0]]["vartree"].dbapi.match(atom)
+ print(portage.best(mylist))
+ except KeyError:
+ sys.exit(1)
+best_version.uses_root = True
+
+
+def mass_best_version(argv):
+ """<root> [<category/package>]+
+ Returns category/package-version (without .ebuild).
+ """
+ if (len(argv) < 2):
+ print("ERROR: insufficient parameters!")
+ sys.exit(2)
+ try:
+ for pack in argv[1:]:
+ mylist=portage.db[argv[0]]["vartree"].dbapi.match(pack)
+ print(pack+":"+portage.best(mylist))
+ except KeyError:
+ sys.exit(1)
+mass_best_version.uses_root = True
+
+def metadata(argv):
+ if (len(argv) < 4):
+ print("ERROR: insufficient parameters!", file=sys.stderr)
+ sys.exit(2)
+
+ root, pkgtype, pkgspec = argv[0:3]
+ metakeys = argv[3:]
+ type_map = {
+ "ebuild":"porttree",
+ "binary":"bintree",
+ "installed":"vartree"}
+ if pkgtype not in type_map:
+ print("Unrecognized package type: '%s'" % pkgtype, file=sys.stderr)
+ sys.exit(1)
+ trees = portage.db
+ if os.path.realpath(root) == os.path.realpath(portage.settings["ROOT"]):
+ root = portage.settings["ROOT"] # contains the normalized $ROOT
+ try:
+ values = trees[root][type_map[pkgtype]].dbapi.aux_get(
+ pkgspec, metakeys)
+ writemsg_stdout(''.join('%s\n' % x for x in values), noiselevel=-1)
+ except KeyError:
+ print("Package not found: '%s'" % pkgspec, file=sys.stderr)
+ sys.exit(1)
+
+metadata.__doc__ = """
+<root> <pkgtype> <category/package> [<key>]+
+Returns metadata values for the specified package.
+Available keys: %s
+""" % ','.join(sorted(x for x in portage.auxdbkeys \
+if not x.startswith('UNUSED_')))
+
+metadata.uses_root = True
+
+def contents(argv):
+ """<root> <category/package>
+ List the files that are installed for a given package, with
+ one file listed on each line. All file names will begin with
+ <root>.
+ """
+ if len(argv) != 2:
+ print("ERROR: expected 2 parameters, got %d!" % len(argv))
+ return 2
+
+ root, cpv = argv
+ vartree = portage.db[root]["vartree"]
+ if not vartree.dbapi.cpv_exists(cpv):
+ sys.stderr.write("Package not found: '%s'\n" % cpv)
+ return 1
+ cat, pkg = portage.catsplit(cpv)
+ db = portage.dblink(cat, pkg, root, vartree.settings,
+ treetype="vartree", vartree=vartree)
+ writemsg_stdout(''.join('%s\n' % x for x in sorted(db.getcontents())),
+ noiselevel=-1)
+contents.uses_root = True
+
+def owners(argv):
+ """<root> [<filename>]+
+ Given a list of files, print the packages that own the files and which
+ files belong to each package. Files owned by a package are listed on
+ the lines below it, indented by a single tab character (\\t). All file
+ paths must either start with <root> or be a basename alone.
+ Returns 1 if no owners could be found, and 0 otherwise.
+ """
+ if len(argv) < 2:
+ sys.stderr.write("ERROR: insufficient parameters!\n")
+ sys.stderr.flush()
+ return 2
+
+ from portage import catsplit, dblink
+ settings = portage.settings
+ root = settings["ROOT"]
+ vardb = portage.db[root]["vartree"].dbapi
+
+ cwd = None
+ try:
+ cwd = os.getcwd()
+ except OSError:
+ pass
+
+ files = []
+ orphan_abs_paths = set()
+ orphan_basenames = set()
+ for f in argv[1:]:
+ f = portage.normalize_path(f)
+ is_basename = os.sep not in f
+ if not is_basename and f[:1] != os.sep:
+ if cwd is None:
+ sys.stderr.write("ERROR: cwd does not exist!\n")
+ sys.stderr.flush()
+ return 2
+ f = os.path.join(cwd, f)
+ f = portage.normalize_path(f)
+ if not is_basename and not f.startswith(root):
+ sys.stderr.write("ERROR: file paths must begin with <root>!\n")
+ sys.stderr.flush()
+ return 2
+ if is_basename:
+ files.append(f)
+ orphan_basenames.add(f)
+ else:
+ files.append(f[len(root)-1:])
+ orphan_abs_paths.add(f)
+
+ owners = vardb._owners.get_owners(files)
+
+ msg = []
+ for pkg, owned_files in owners.items():
+ cpv = pkg.mycpv
+ msg.append("%s\n" % cpv)
+ for f in sorted(owned_files):
+ f_abs = os.path.join(root, f.lstrip(os.path.sep))
+ msg.append("\t%s\n" % (f_abs,))
+ orphan_abs_paths.discard(f_abs)
+ if orphan_basenames:
+ orphan_basenames.discard(os.path.basename(f_abs))
+
+ writemsg_stdout(''.join(msg), noiselevel=-1)
+
+ if orphan_abs_paths or orphan_basenames:
+ orphans = []
+ orphans.extend(orphan_abs_paths)
+ orphans.extend(orphan_basenames)
+ orphans.sort()
+ msg = []
+ msg.append("None of the installed packages claim these files:\n")
+ for f in orphans:
+ msg.append("\t%s\n" % (f,))
+ sys.stderr.write("".join(msg))
+ sys.stderr.flush()
+
+ if owners:
+ return 0
+ return 1
+
+owners.uses_root = True
+
+def is_protected(argv):
+ """<root> <filename>
+ Given a single filename, return code 0 if it's protected, 1 otherwise.
+ The filename must begin with <root>.
+ """
+ if len(argv) != 2:
+ sys.stderr.write("ERROR: expected 2 parameters, got %d!\n" % len(argv))
+ sys.stderr.flush()
+ return 2
+
+ root, filename = argv
+
+ err = sys.stderr
+ cwd = None
+ try:
+ cwd = os.getcwd()
+ except OSError:
+ pass
+
+ f = portage.normalize_path(filename)
+ if not f.startswith(os.path.sep):
+ if cwd is None:
+ err.write("ERROR: cwd does not exist!\n")
+ err.flush()
+ return 2
+ f = os.path.join(cwd, f)
+ f = portage.normalize_path(f)
+
+ if not f.startswith(root):
+ err.write("ERROR: file paths must begin with <root>!\n")
+ err.flush()
+ return 2
+
+ from portage.util import ConfigProtect
+
+ settings = portage.settings
+ protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
+ protect_mask = portage.util.shlex_split(
+ settings.get("CONFIG_PROTECT_MASK", ""))
+ protect_obj = ConfigProtect(root, protect, protect_mask)
+
+ if protect_obj.isprotected(f):
+ return 0
+ return 1
+
+is_protected.uses_root = True
+
+def filter_protected(argv):
+ """<root>
+ Read filenames from stdin and write them to stdout if they are protected.
+ All filenames are delimited by \\n and must begin with <root>.
+ """
+ if len(argv) != 1:
+ sys.stderr.write("ERROR: expected 1 parameter, got %d!\n" % len(argv))
+ sys.stderr.flush()
+ return 2
+
+ root, = argv
+ out = sys.stdout
+ err = sys.stderr
+ cwd = None
+ try:
+ cwd = os.getcwd()
+ except OSError:
+ pass
+
+ from portage.util import ConfigProtect
+
+ settings = portage.settings
+ protect = portage.util.shlex_split(settings.get("CONFIG_PROTECT", ""))
+ protect_mask = portage.util.shlex_split(
+ settings.get("CONFIG_PROTECT_MASK", ""))
+ protect_obj = ConfigProtect(root, protect, protect_mask)
+
+ protected = 0
+ errors = 0
+
+ for line in sys.stdin:
+ filename = line.rstrip("\n")
+ f = portage.normalize_path(filename)
+ if not f.startswith(os.path.sep):
+ if cwd is None:
+ err.write("ERROR: cwd does not exist!\n")
+ err.flush()
+ errors += 1
+ continue
+ f = os.path.join(cwd, f)
+ f = portage.normalize_path(f)
+
+ if not f.startswith(root):
+ err.write("ERROR: file paths must begin with <root>!\n")
+ err.flush()
+ errors += 1
+ continue
+
+ if protect_obj.isprotected(f):
+ protected += 1
+ out.write("%s\n" % filename)
+ out.flush()
+
+ if errors:
+ return 2
+
+ return 0
+
+filter_protected.uses_root = True
+
+def best_visible(argv):
+ """<root> [pkgtype] <atom>
+ Returns category/package-version (without .ebuild).
+ The pkgtype argument defaults to "ebuild" if unspecified,
+ otherwise it must be one of ebuild, binary, or installed.
+ """
+ if (len(argv) < 2):
+ writemsg("ERROR: insufficient parameters!\n", noiselevel=-1)
+ return 2
+
+ pkgtype = "ebuild"
+ if len(argv) > 2:
+ pkgtype = argv[1]
+ atom = argv[2]
+ else:
+ atom = argv[1]
+
+ type_map = {
+ "ebuild":"porttree",
+ "binary":"bintree",
+ "installed":"vartree"}
+
+ if pkgtype not in type_map:
+ writemsg("Unrecognized package type: '%s'\n" % pkgtype,
+ noiselevel=-1)
+ return 2
+
+ db = portage.db[portage.settings["ROOT"]][type_map[pkgtype]].dbapi
+
+ try:
+ atom = portage.dep_expand(atom, mydb=db, settings=portage.settings)
+ except portage.exception.InvalidAtom:
+ writemsg("ERROR: Invalid atom: '%s'\n" % atom,
+ noiselevel=-1)
+ return 2
+
+ root_config = RootConfig(portage.settings,
+ portage.db[portage.settings["ROOT"]], None)
+
+ try:
+ # reversed, for descending order
+ for cpv in reversed(db.match(atom)):
+ metadata = dict(zip(Package.metadata_keys,
+ db.aux_get(cpv, Package.metadata_keys, myrepo=atom.repo)))
+ pkg = Package(built=(pkgtype != "ebuild"), cpv=cpv,
+ installed=(pkgtype=="installed"), metadata=metadata,
+ root_config=root_config, type_name=pkgtype)
+ if pkg.visible:
+ writemsg_stdout("%s\n" % (pkg.cpv,), noiselevel=-1)
+ return os.EX_OK
+ except KeyError:
+ pass
+ return 1
+best_visible.uses_root = True
+
+
+def mass_best_visible(argv):
+ """<root> [<category/package>]+
+ Returns category/package-version (without .ebuild).
+ """
+ if (len(argv) < 2):
+ print("ERROR: insufficient parameters!")
+ sys.exit(2)
+ try:
+ for pack in argv[1:]:
+ mylist=portage.db[argv[0]]["porttree"].dbapi.match(pack)
+ print(pack+":"+portage.best(mylist))
+ except KeyError:
+ sys.exit(1)
+mass_best_visible.uses_root = True
+
+
+def all_best_visible(argv):
+ """<root>
+ Returns all best_visible packages (without .ebuild).
+ """
+ if len(argv) < 1:
+ sys.stderr.write("ERROR: insufficient parameters!\n")
+ sys.stderr.flush()
+ return 2
+
+ #print portage.db[argv[0]]["porttree"].dbapi.cp_all()
+ for pkg in portage.db[argv[0]]["porttree"].dbapi.cp_all():
+ mybest=portage.best(portage.db[argv[0]]["porttree"].dbapi.match(pkg))
+ if mybest:
+ print(mybest)
+all_best_visible.uses_root = True
+
+
+def match(argv):
+ """<root> <atom>
+ Returns a \\n separated list of category/package-version.
+ When given an empty string, all installed packages will
+ be listed.
+ """
+ if len(argv) != 2:
+ print("ERROR: expected 2 parameters, got %d!" % len(argv))
+ sys.exit(2)
+ root, atom = argv
+ if atom:
+ if atom_validate_strict and not portage.isvalidatom(atom):
+ portage.writemsg("ERROR: Invalid atom: '%s'\n" % atom,
+ noiselevel=-1)
+ return 2
+ results = portage.db[root]["vartree"].dbapi.match(atom)
+ else:
+ results = portage.db[root]["vartree"].dbapi.cpv_all()
+ results.sort()
+ for cpv in results:
+ print(cpv)
+match.uses_root = True
+
+def expand_virtual(argv):
+ """<root> <atom>
+ Returns a \\n separated list of atoms expanded from a
+ given virtual atom (GLEP 37 virtuals only),
+ excluding blocker atoms. Satisfied
+ virtual atoms are not included in the output, since
+ they are expanded to real atoms which are displayed.
+ Unsatisfied virtual atoms are displayed without
+ any expansion. The "match" command can be used to
+ resolve the returned atoms to specific installed
+ packages.
+ """
+ if len(argv) != 2:
+ writemsg("ERROR: expected 2 parameters, got %d!\n" % len(argv),
+ noiselevel=-1)
+ return 2
+
+ root, atom = argv
+
+ try:
+ results = list(expand_new_virt(
+ portage.db[root]["vartree"].dbapi, atom))
+ except portage.exception.InvalidAtom:
+ writemsg("ERROR: Invalid atom: '%s'\n" % atom,
+ noiselevel=-1)
+ return 2
+
+ results.sort()
+ for x in results:
+ if not x.blocker:
+ writemsg_stdout("%s\n" % (x,))
+
+ return os.EX_OK
+
+expand_virtual.uses_root = True
+
+def vdb_path(argv):
+ """
+ Returns the path used for the var(installed) package database for the
+ set environment/configuration options.
+ """
+ out = sys.stdout
+ out.write(os.path.join(portage.settings["EROOT"], portage.VDB_PATH) + "\n")
+ out.flush()
+ return os.EX_OK
+
+def gentoo_mirrors(argv):
+ """
+ Returns the mirrors set to use in the portage configuration.
+ """
+ print(portage.settings["GENTOO_MIRRORS"])
+
+
+def portdir(argv):
+ """
+ Returns the PORTDIR path.
+ """
+ print(portage.settings["PORTDIR"])
+
+
+def config_protect(argv):
+ """
+ Returns the CONFIG_PROTECT paths.
+ """
+ print(portage.settings["CONFIG_PROTECT"])
+
+
+def config_protect_mask(argv):
+ """
+ Returns the CONFIG_PROTECT_MASK paths.
+ """
+ print(portage.settings["CONFIG_PROTECT_MASK"])
+
+
+def portdir_overlay(argv):
+ """
+ Returns the PORTDIR_OVERLAY path.
+ """
+ print(portage.settings["PORTDIR_OVERLAY"])
+
+
+def pkgdir(argv):
+ """
+ Returns the PKGDIR path.
+ """
+ print(portage.settings["PKGDIR"])
+
+
+def distdir(argv):
+ """
+ Returns the DISTDIR path.
+ """
+ print(portage.settings["DISTDIR"])
+
+
+def envvar(argv):
+ """<variable>+
+ Returns a specific environment variable as exists prior to ebuild.sh.
+ Similar to: emerge --verbose --info | egrep '^<variable>='
+ """
+ verbose = "-v" in argv
+ if verbose:
+ argv.pop(argv.index("-v"))
+
+ if len(argv) == 0:
+ print("ERROR: insufficient parameters!")
+ sys.exit(2)
+
+ for arg in argv:
+ if verbose:
+ print(arg +"='"+ portage.settings[arg] +"'")
+ else:
+ print(portage.settings[arg])
+
+def get_repos(argv):
+ """<root>
+ Returns all repos with names (repo_name file) argv[0] = $ROOT
+ """
+ if len(argv) < 1:
+ print("ERROR: insufficient parameters!")
+ sys.exit(2)
+ print(" ".join(portage.db[argv[0]]["porttree"].dbapi.getRepositories()))
+
+def get_repo_path(argv):
+ """<root> <repo_id>+
+ Returns the path to the repo named argv[1], argv[0] = $ROOT
+ """
+ if len(argv) < 2:
+ print("ERROR: insufficient parameters!")
+ sys.exit(2)
+ for arg in argv[1:]:
+ path = portage.db[argv[0]]["porttree"].dbapi.getRepositoryPath(arg)
+ if path is None:
+ path = ""
+ print(path)
+
+def list_preserved_libs(argv):
+ """<root>
+ Print a list of libraries preserved during a package update in the form
+ package: path. Returns 1 if no preserved libraries could be found,
+ 0 otherwise.
+ """
+
+ if len(argv) != 1:
+ print("ERROR: wrong number of arguments")
+ sys.exit(2)
+ mylibs = portage.db[argv[0]]["vartree"].dbapi._plib_registry.getPreservedLibs()
+ rValue = 1
+ msg = []
+ for cpv in sorted(mylibs):
+ msg.append(cpv)
+ for path in mylibs[cpv]:
+ msg.append(' ' + path)
+ rValue = 0
+ msg.append('\n')
+ writemsg_stdout(''.join(msg), noiselevel=-1)
+ return rValue
+list_preserved_libs.uses_root = True
+
+#-----------------------------------------------------------------------------
+#
+# DO NOT CHANGE CODE BEYOND THIS POINT - IT'S NOT NEEDED!
+#
+
+if not portage.const._ENABLE_PRESERVE_LIBS:
+ del list_preserved_libs
+
+non_commands = frozenset(['elog', 'eval_atom_use',
+ 'exithandler', 'expand_new_virt', 'main',
+ 'usage', 'writemsg', 'writemsg_stdout'])
+commands = sorted(k for k, v in globals().items() \
+ if k not in non_commands and isinstance(v, types.FunctionType))
+
+def usage(argv):
+ print(">>> Portage information query tool")
+ print(">>> %s" % portage.VERSION)
+ print(">>> Usage: portageq <command> [<option> ...]")
+ print("")
+ print("Available commands:")
+
+ #
+ # Show our commands -- we do this by scanning the functions in this
+ # file, and formatting each functions documentation.
+ #
+ help_mode = '--help' in sys.argv
+ for name in commands:
+ # Drop non-functions
+ obj = globals()[name]
+
+ doc = obj.__doc__
+ if (doc == None):
+ print(" " + name)
+ print(" MISSING DOCUMENTATION!")
+ print("")
+ continue
+
+ lines = doc.lstrip("\n").split("\n")
+ print(" " + name + " " + lines[0].strip())
+ if (len(sys.argv) > 1):
+ if (not help_mode):
+ lines = lines[:-1]
+ for line in lines[1:]:
+ print(" " + line.strip())
+ if (len(sys.argv) == 1):
+ print("\nRun portageq with --help for info")
+
+atom_validate_strict = "EBUILD_PHASE" in os.environ
+eapi = None
+if atom_validate_strict:
+ eapi = os.environ.get('EAPI')
+
+ def elog(elog_funcname, lines):
+ cmd = "source '%s/isolated-functions.sh' ; " % \
+ os.environ["PORTAGE_BIN_PATH"]
+ for line in lines:
+ cmd += "%s %s ; " % (elog_funcname, portage._shell_quote(line))
+ subprocess.call([portage.const.BASH_BINARY, "-c", cmd])
+
+else:
+ def elog(elog_funcname, lines):
+ pass
+
+def main():
+
+ nocolor = os.environ.get('NOCOLOR')
+ if nocolor in ('yes', 'true'):
+ portage.output.nocolor()
+
+ if len(sys.argv) < 2:
+ usage(sys.argv)
+ sys.exit(os.EX_USAGE)
+
+ for x in sys.argv:
+ if x in ("-h", "--help"):
+ usage(sys.argv)
+ sys.exit(os.EX_OK)
+ elif x == "--version":
+ print("Portage", portage.VERSION)
+ sys.exit(os.EX_OK)
+
+ cmd = sys.argv[1]
+ function = globals().get(cmd)
+ if function is None or cmd not in commands:
+ usage(sys.argv)
+ sys.exit(os.EX_USAGE)
+ function = globals()[cmd]
+ uses_root = getattr(function, "uses_root", False) and len(sys.argv) > 2
+ if uses_root:
+ if not os.path.isdir(sys.argv[2]):
+ sys.stderr.write("Not a directory: '%s'\n" % sys.argv[2])
+ sys.stderr.write("Run portageq with --help for info\n")
+ sys.stderr.flush()
+ sys.exit(os.EX_USAGE)
+ os.environ["ROOT"] = sys.argv[2]
+
+ args = sys.argv[2:]
+ if args and sys.hexversion < 0x3000000 and not isinstance(args[0], unicode):
+ for i in range(len(args)):
+ args[i] = portage._unicode_decode(args[i])
+
+ try:
+ if uses_root:
+ args[0] = portage.settings["ROOT"]
+ retval = function(args)
+ if retval:
+ sys.exit(retval)
+ except portage.exception.PermissionDenied as e:
+ sys.stderr.write("Permission denied: '%s'\n" % str(e))
+ sys.exit(e.errno)
+ except portage.exception.ParseError as e:
+ sys.stderr.write("%s\n" % str(e))
+ sys.exit(1)
+ except portage.exception.AmbiguousPackageName as e:
+ # Multiple matches thrown from cpv_expand
+ pkgs = e.args[0]
+ # An error has occurred so we writemsg to stderr and exit nonzero.
+ portage.writemsg("You specified an unqualified atom that matched multiple packages:\n", noiselevel=-1)
+ for pkg in pkgs:
+ portage.writemsg("* %s\n" % pkg, noiselevel=-1)
+ portage.writemsg("\nPlease use a more specific atom.\n", noiselevel=-1)
+ sys.exit(1)
+
+main()
+
+#-----------------------------------------------------------------------------
diff --git a/portage_with_autodep/bin/quickpkg b/portage_with_autodep/bin/quickpkg
new file mode 100755
index 0000000..09723f5
--- /dev/null
+++ b/portage_with_autodep/bin/quickpkg
@@ -0,0 +1,291 @@
+#!/usr/bin/python
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import errno
+import math
+import optparse
+import signal
+import sys
+import tarfile
+
+try:
+ import portage
+except ImportError:
+ from os import path as osp
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
+ import portage
+
+from portage import os
+from portage import xpak
+from portage.dbapi.dep_expand import dep_expand
+from portage.dep import use_reduce
+from portage.exception import InvalidAtom, InvalidData, InvalidDependString, \
+ PackageSetNotFound, PermissionDenied
+from portage.util import ConfigProtect, ensure_dirs, shlex_split
+from portage.dbapi.vartree import dblink, tar_contents
+from portage.checksum import perform_md5
+from portage._sets import load_default_config, SETPREFIX
+
+def quickpkg_atom(options, infos, arg, eout):
+ settings = portage.settings
+ root = portage.settings["ROOT"]
+ trees = portage.db[root]
+ vartree = trees["vartree"]
+ vardb = vartree.dbapi
+ bintree = trees["bintree"]
+
+ include_config = options.include_config == "y"
+ include_unmodified_config = options.include_unmodified_config == "y"
+ fix_metadata_keys = ["PF", "CATEGORY"]
+
+ try:
+ atom = dep_expand(arg, mydb=vardb, settings=vartree.settings)
+ except ValueError as e:
+ # Multiple matches thrown from cpv_expand
+ eout.eerror("Please use a more specific atom: %s" % \
+ " ".join(e.args[0]))
+ del e
+ infos["missing"].append(arg)
+ return
+ except (InvalidAtom, InvalidData):
+ eout.eerror("Invalid atom: %s" % (arg,))
+ infos["missing"].append(arg)
+ return
+ if atom[:1] == '=' and arg[:1] != '=':
+ # dep_expand() allows missing '=' but it's really invalid
+ eout.eerror("Invalid atom: %s" % (arg,))
+ infos["missing"].append(arg)
+ return
+
+ matches = vardb.match(atom)
+ pkgs_for_arg = 0
+ for cpv in matches:
+ excluded_config_files = []
+ bintree.prevent_collision(cpv)
+ cat, pkg = portage.catsplit(cpv)
+ dblnk = dblink(cat, pkg, root,
+ vartree.settings, treetype="vartree",
+ vartree=vartree)
+ have_lock = False
+ try:
+ dblnk.lockdb()
+ have_lock = True
+ except PermissionDenied:
+ pass
+ try:
+ if not dblnk.exists():
+ # unmerged by a concurrent process
+ continue
+ iuse, use, restrict = vardb.aux_get(cpv,
+ ["IUSE","USE","RESTRICT"])
+ iuse = [ x.lstrip("+-") for x in iuse.split() ]
+ use = use.split()
+ try:
+ restrict = use_reduce(restrict, uselist=use, flat=True)
+ except InvalidDependString as e:
+ eout.eerror("Invalid RESTRICT metadata " + \
+ "for '%s': %s; skipping" % (cpv, str(e)))
+ del e
+ continue
+ if "bindist" in iuse and "bindist" not in use:
+ eout.ewarn("%s: package was emerged with USE=-bindist!" % cpv)
+ eout.ewarn("%s: it might not be legal to redistribute this." % cpv)
+ elif "bindist" in restrict:
+ eout.ewarn("%s: package has RESTRICT=bindist!" % cpv)
+ eout.ewarn("%s: it might not be legal to redistribute this." % cpv)
+ eout.ebegin("Building package for %s" % cpv)
+ pkgs_for_arg += 1
+ contents = dblnk.getcontents()
+ protect = None
+ if not include_config:
+ confprot = ConfigProtect(root,
+ shlex_split(settings.get("CONFIG_PROTECT", "")),
+ shlex_split(settings.get("CONFIG_PROTECT_MASK", "")))
+ def protect(filename):
+ if not confprot.isprotected(filename):
+ return False
+ if include_unmodified_config:
+ file_data = contents[filename]
+ if file_data[0] == "obj":
+ orig_md5 = file_data[2].lower()
+ cur_md5 = perform_md5(filename, calc_prelink=1)
+ if orig_md5 == cur_md5:
+ return False
+ excluded_config_files.append(filename)
+ return True
+ existing_metadata = dict(zip(fix_metadata_keys,
+ vardb.aux_get(cpv, fix_metadata_keys)))
+ category, pf = portage.catsplit(cpv)
+ required_metadata = {}
+ required_metadata["CATEGORY"] = category
+ required_metadata["PF"] = pf
+ update_metadata = {}
+ for k, v in required_metadata.items():
+ if v != existing_metadata[k]:
+ update_metadata[k] = v
+ if update_metadata:
+ vardb.aux_update(cpv, update_metadata)
+ xpdata = xpak.xpak(dblnk.dbdir)
+ binpkg_tmpfile = os.path.join(bintree.pkgdir,
+ cpv + ".tbz2." + str(os.getpid()))
+ ensure_dirs(os.path.dirname(binpkg_tmpfile))
+ tar = tarfile.open(binpkg_tmpfile, "w:bz2")
+ tar_contents(contents, root, tar, protect=protect)
+ tar.close()
+ xpak.tbz2(binpkg_tmpfile).recompose_mem(xpdata)
+ finally:
+ if have_lock:
+ dblnk.unlockdb()
+ bintree.inject(cpv, filename=binpkg_tmpfile)
+ binpkg_path = bintree.getname(cpv)
+ try:
+ s = os.stat(binpkg_path)
+ except OSError as e:
+ # Sanity check, shouldn't happen normally.
+ eout.eend(1)
+ eout.eerror(str(e))
+ del e
+ eout.eerror("Failed to create package: '%s'" % binpkg_path)
+ else:
+ eout.eend(0)
+ infos["successes"].append((cpv, s.st_size))
+ infos["config_files_excluded"] += len(excluded_config_files)
+ for filename in excluded_config_files:
+ eout.ewarn("Excluded config: '%s'" % filename)
+ if not pkgs_for_arg:
+ eout.eerror("Could not find anything " + \
+ "to match '%s'; skipping" % arg)
+ infos["missing"].append(arg)
+
+def quickpkg_set(options, infos, arg, eout):
+ root = portage.settings["ROOT"]
+ trees = portage.db[root]
+ vartree = trees["vartree"]
+
+ settings = vartree.settings
+ settings._init_dirs()
+ setconfig = load_default_config(settings, trees)
+ sets = setconfig.getSets()
+
+ set = arg[1:]
+ if not set in sets:
+ eout.eerror("Package set not found: '%s'; skipping" % (arg,))
+ infos["missing"].append(arg)
+ return
+
+ try:
+ atoms = setconfig.getSetAtoms(set)
+ except PackageSetNotFound as e:
+ eout.eerror("Failed to process package set '%s' because " % set +
+ "it contains the non-existent package set '%s'; skipping" % e)
+ infos["missing"].append(arg)
+ return
+
+ for atom in atoms:
+ quickpkg_atom(options, infos, atom, eout)
+
+def quickpkg_main(options, args, eout):
+ root = portage.settings["ROOT"]
+ trees = portage.db[root]
+ bintree = trees["bintree"]
+
+ try:
+ ensure_dirs(bintree.pkgdir)
+ except portage.exception.PortageException:
+ pass
+ if not os.access(bintree.pkgdir, os.W_OK):
+ eout.eerror("No write access to '%s'" % bintree.pkgdir)
+ return errno.EACCES
+
+ infos = {}
+ infos["successes"] = []
+ infos["missing"] = []
+ infos["config_files_excluded"] = 0
+ for arg in args:
+ if arg[0] == SETPREFIX:
+ quickpkg_set(options, infos, arg, eout)
+ else:
+ quickpkg_atom(options, infos, arg, eout)
+
+ if not infos["successes"]:
+ eout.eerror("No packages found")
+ return 1
+ print()
+ eout.einfo("Packages now in '%s':" % bintree.pkgdir)
+ units = {10:'K', 20:'M', 30:'G', 40:'T',
+ 50:'P', 60:'E', 70:'Z', 80:'Y'}
+ for cpv, size in infos["successes"]:
+ if not size:
+ # avoid OverflowError in math.log()
+ size_str = "0"
+ else:
+ power_of_2 = math.log(size, 2)
+ power_of_2 = 10*int(power_of_2/10)
+ unit = units.get(power_of_2)
+ if unit:
+ size = float(size)/(2**power_of_2)
+ size_str = "%.1f" % size
+ if len(size_str) > 4:
+ # emulate `du -h`, don't show too many sig figs
+ size_str = str(int(size))
+ size_str += unit
+ else:
+ size_str = str(size)
+ eout.einfo("%s: %s" % (cpv, size_str))
+ if infos["config_files_excluded"]:
+ print()
+ eout.ewarn("Excluded config files: %d" % infos["config_files_excluded"])
+ eout.ewarn("See --help if you would like to include config files.")
+ if infos["missing"]:
+ print()
+ eout.ewarn("The following packages could not be found:")
+ eout.ewarn(" ".join(infos["missing"]))
+ return 2
+ return os.EX_OK
+
+if __name__ == "__main__":
+ usage = "quickpkg [options] <list of package atoms or package sets>"
+ parser = optparse.OptionParser(usage=usage)
+ parser.add_option("--umask",
+ default="0077",
+ help="umask used during package creation (default is 0077)")
+ parser.add_option("--ignore-default-opts",
+ action="store_true",
+ help="do not use the QUICKPKG_DEFAULT_OPTS environment variable")
+ parser.add_option("--include-config",
+ type="choice",
+ choices=["y","n"],
+ default="n",
+ metavar="<y|n>",
+ help="include all files protected by CONFIG_PROTECT (as a security precaution, default is 'n')")
+ parser.add_option("--include-unmodified-config",
+ type="choice",
+ choices=["y","n"],
+ default="n",
+ metavar="<y|n>",
+ help="include files protected by CONFIG_PROTECT that have not been modified since installation (as a security precaution, default is 'n')")
+ options, args = parser.parse_args(sys.argv[1:])
+ if not options.ignore_default_opts:
+ default_opts = portage.settings.get("QUICKPKG_DEFAULT_OPTS","").split()
+ options, args = parser.parse_args(default_opts + sys.argv[1:])
+ if not args:
+ parser.error("no packages atoms given")
+ try:
+ umask = int(options.umask, 8)
+ except ValueError:
+ parser.error("invalid umask: %s" % options.umask)
+ # We need to ensure a sane umask for the packages that will be created.
+ old_umask = os.umask(umask)
+ eout = portage.output.EOutput()
+ def sigwinch_handler(signum, frame):
+ lines, eout.term_columns = portage.output.get_term_size()
+ signal.signal(signal.SIGWINCH, sigwinch_handler)
+ try:
+ retval = quickpkg_main(options, args, eout)
+ finally:
+ os.umask(old_umask)
+ signal.signal(signal.SIGWINCH, signal.SIG_DFL)
+ sys.exit(retval)
diff --git a/portage_with_autodep/bin/regenworld b/portage_with_autodep/bin/regenworld
new file mode 100755
index 0000000..6b5af4c
--- /dev/null
+++ b/portage_with_autodep/bin/regenworld
@@ -0,0 +1,144 @@
+#!/usr/bin/python
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import sys
+try:
+ import portage
+except ImportError:
+ from os import path as osp
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
+ import portage
+
+from portage import os
+from portage._sets.files import StaticFileSet, WorldSelectedSet
+
+import re
+import tempfile
+import textwrap
+
+__candidatematcher__ = re.compile("^[0-9]+: \\*\\*\\* emerge ")
+__noncandidatematcher__ = re.compile(" sync( |$)| clean( |$)| search( |$)|--oneshot|--fetchonly| unmerge( |$)")
+
+def issyspkg(pkgline):
+ return (pkgline[0] == "*")
+
+def iscandidate(logline):
+ return (__candidatematcher__.match(logline) \
+ and not __noncandidatematcher__.search(logline))
+
+def getpkginfo(logline):
+ logline = re.sub("^[0-9]+: \\*\\*\\* emerge ", "", logline)
+ logline = logline.strip()
+ logline = re.sub("(\\S+\\.(ebuild|tbz2))|(--\\S+)|inject ", "", logline)
+ return logline.strip()
+
+__uniqlist__ = []
+def isunwanted(pkgline):
+ if pkgline in ["world", "system", "depclean", "info", "regen", ""]:
+ return False
+ elif pkgline in __uniqlist__:
+ return False
+ elif not re.search("^[a-zA-Z<>=~]", pkgline):
+ return False
+ else:
+ __uniqlist__.append(pkgline)
+ return True
+
+root = portage.settings['ROOT']
+eroot = portage.settings['EROOT']
+world_file = os.path.join(eroot, portage.WORLD_FILE)
+
+# show a little description if we have arguments
+if len(sys.argv) >= 2 and sys.argv[1] in ["-h", "--help"]:
+ print("This script regenerates the portage world file by checking the portage")
+ print("logfile for all actions that you've done in the past. It ignores any")
+ print("arguments except --help. It is recommended that you make a backup of")
+ print("your existing world file (%s) before using this tool." % world_file)
+ sys.exit(0)
+
+worldlist = portage.grabfile(world_file)
+syslist = [x for x in portage.settings.packages if issyspkg(x)]
+
+logfile = portage.grabfile(os.path.join(eroot, "var/log/emerge.log"))
+biglist = [getpkginfo(x) for x in logfile if iscandidate(x)]
+tmplist = []
+for l in biglist:
+ tmplist += l.split()
+biglist = [x for x in tmplist if isunwanted(x)]
+#for p in biglist:
+# print(p)
+#sys.exit(0)
+
+# resolving virtuals
+realsyslist = []
+for mykey in syslist:
+ # drop the asterix
+ mykey = mykey[1:]
+ #print("candidate:",mykey)
+ mylist = portage.db[root]["vartree"].dbapi.match(mykey)
+ if mylist:
+ mykey=portage.cpv_getkey(mylist[0])
+ if mykey not in realsyslist:
+ realsyslist.append(mykey)
+
+for mykey in biglist:
+ #print("checking:",mykey)
+ try:
+ mylist = portage.db[root]["vartree"].dbapi.match(mykey)
+ except (portage.exception.InvalidAtom, KeyError):
+ if "--debug" in sys.argv:
+ print("* ignoring broken log entry for %s (likely injected)" % mykey)
+ except ValueError as e:
+ try:
+ print("* %s is an ambiguous package name, candidates are:\n%s" % (mykey, e))
+ except AttributeError:
+ # FIXME: Find out what causes this (bug #344845).
+ print("* %s is an ambiguous package name" % (mykey,))
+ continue
+ if mylist:
+ #print "mylist:",mylist
+ myfavkey=portage.cpv_getkey(mylist[0])
+ if (myfavkey not in realsyslist) and (myfavkey not in worldlist):
+ print("add to world:",myfavkey)
+ worldlist.append(myfavkey)
+
+if not worldlist:
+ pass
+else:
+ existing_set = WorldSelectedSet(eroot)
+ existing_set.load()
+
+ if not existing_set:
+ existing_set.replace(worldlist)
+ else:
+ old_world = existing_set._filename
+ fd, tmp_filename = tempfile.mkstemp(suffix=".tmp",
+ prefix=os.path.basename(old_world) + ".",
+ dir=os.path.dirname(old_world))
+ os.close(fd)
+
+ new_set = StaticFileSet(tmp_filename)
+ new_set.update(worldlist)
+
+ if existing_set.getAtoms() == new_set.getAtoms():
+ os.unlink(tmp_filename)
+ else:
+ new_set.write()
+
+ msg = "Please review differences between old and new files, " + \
+ "and replace the old file if desired."
+
+ portage.util.writemsg_stdout("\n",
+ noiselevel=-1)
+ for line in textwrap.wrap(msg, 65):
+ portage.util.writemsg_stdout("%s\n" % line,
+ noiselevel=-1)
+ portage.util.writemsg_stdout("\n",
+ noiselevel=-1)
+ portage.util.writemsg_stdout(" old: %s\n\n" % old_world,
+ noiselevel=-1)
+ portage.util.writemsg_stdout(" new: %s\n\n" % tmp_filename,
+ noiselevel=-1)
diff --git a/portage_with_autodep/bin/repoman b/portage_with_autodep/bin/repoman
new file mode 100755
index 0000000..f1fbc24
--- /dev/null
+++ b/portage_with_autodep/bin/repoman
@@ -0,0 +1,2672 @@
+#!/usr/bin/python -O
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Next to do: dep syntax checking in mask files
+# Then, check to make sure deps are satisfiable (to avoid "can't find match for" problems)
+# that last one is tricky because multiple profiles need to be checked.
+
+from __future__ import print_function
+
+import calendar
+import copy
+import errno
+import formatter
+import io
+import logging
+import optparse
+import re
+import signal
+import stat
+import sys
+import tempfile
+import time
+import platform
+
+try:
+ from urllib.request import urlopen as urllib_request_urlopen
+except ImportError:
+ from urllib import urlopen as urllib_request_urlopen
+
+from itertools import chain
+from stat import S_ISDIR
+
+try:
+ import portage
+except ImportError:
+ from os import path as osp
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
+ import portage
+portage._disable_legacy_globals()
+portage.dep._internal_warnings = True
+
+try:
+ import xml.etree.ElementTree
+ from xml.parsers.expat import ExpatError
+except ImportError:
+ msg = ["Please enable python's \"xml\" USE flag in order to use repoman."]
+ from portage.output import EOutput
+ out = EOutput()
+ for line in msg:
+ out.eerror(line)
+ sys.exit(1)
+
+from portage import os
+from portage import subprocess_getstatusoutput
+from portage import _encodings
+from portage import _unicode_encode
+from repoman.checks import run_checks
+from repoman import utilities
+from repoman.herdbase import make_herd_base
+from _emerge.Package import Package
+from _emerge.RootConfig import RootConfig
+from _emerge.userquery import userquery
+import portage.checksum
+import portage.const
+from portage import cvstree, normalize_path
+from portage import util
+from portage.exception import (FileNotFound, MissingParameter,
+ ParseError, PermissionDenied)
+from portage.manifest import Manifest
+from portage.process import find_binary, spawn
+from portage.output import bold, create_color_func, \
+ green, nocolor, red
+from portage.output import ConsoleStyleFile, StyleWriter
+from portage.util import cmp_sort_key, writemsg_level
+from portage.package.ebuild.digestgen import digestgen
+from portage.eapi import eapi_has_slot_deps, \
+ eapi_has_use_deps, eapi_has_strong_blocks, eapi_has_iuse_defaults, \
+ eapi_has_required_use, eapi_has_use_dep_defaults
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+util.initialize_logger()
+
+# 14 is the length of DESCRIPTION=""
+max_desc_len = 100
+allowed_filename_chars="a-zA-Z0-9._-+:"
+disallowed_filename_chars_re = re.compile(r'[^a-zA-Z0-9._\-+:]')
+pv_toolong_re = re.compile(r'[0-9]{19,}')
+bad = create_color_func("BAD")
+
+# A sane umask is needed for files that portage creates.
+os.umask(0o22)
+# Repoman sets it's own ACCEPT_KEYWORDS and we don't want it to
+# behave incrementally.
+repoman_incrementals = tuple(x for x in \
+ portage.const.INCREMENTALS if x != 'ACCEPT_KEYWORDS')
+repoman_settings = portage.config(local_config=False)
+repoman_settings.lock()
+
+if repoman_settings.get("NOCOLOR", "").lower() in ("yes", "true") or \
+ repoman_settings.get('TERM') == 'dumb' or \
+ not sys.stdout.isatty():
+ nocolor()
+
+def warn(txt):
+ print("repoman: " + txt)
+
+def err(txt):
+ warn(txt)
+ sys.exit(1)
+
+def exithandler(signum=None, frame=None):
+ logging.fatal("Interrupted; exiting...")
+ if signum is None:
+ sys.exit(1)
+ else:
+ sys.exit(128 + signum)
+
+signal.signal(signal.SIGINT,exithandler)
+
+class RepomanHelpFormatter(optparse.IndentedHelpFormatter):
+ """Repoman needs it's own HelpFormatter for now, because the default ones
+ murder the help text."""
+
+ def __init__(self, indent_increment=1, max_help_position=24, width=150, short_first=1):
+ optparse.HelpFormatter.__init__(self, indent_increment, max_help_position, width, short_first)
+
+ def format_description(self, description):
+ return description
+
+class RepomanOptionParser(optparse.OptionParser):
+ """Add the on_tail function, ruby has it, optionParser should too
+ """
+
+ def __init__(self, *args, **kwargs):
+ optparse.OptionParser.__init__(self, *args, **kwargs)
+ self.tail = ""
+
+ def on_tail(self, description):
+ self.tail += description
+
+ def format_help(self, formatter=None):
+ result = optparse.OptionParser.format_help(self, formatter)
+ result += self.tail
+ return result
+
+
+def ParseArgs(argv, qahelp):
+ """This function uses a customized optionParser to parse command line arguments for repoman
+ Args:
+ argv - a sequence of command line arguments
+ qahelp - a dict of qa warning to help message
+ Returns:
+ (opts, args), just like a call to parser.parse_args()
+ """
+
+ if argv and sys.hexversion < 0x3000000 and not isinstance(argv[0], unicode):
+ argv = [portage._unicode_decode(x) for x in argv]
+
+ modes = {
+ 'commit' : 'Run a scan then commit changes',
+ 'ci' : 'Run a scan then commit changes',
+ 'fix' : 'Fix simple QA issues (stray digests, missing digests)',
+ 'full' : 'Scan directory tree and print all issues (not a summary)',
+ 'help' : 'Show this screen',
+ 'manifest' : 'Generate a Manifest (fetches files if necessary)',
+ 'manifest-check' : 'Check Manifests for missing or incorrect digests',
+ 'scan' : 'Scan directory tree for QA issues'
+ }
+
+ mode_keys = list(modes)
+ mode_keys.sort()
+
+ parser = RepomanOptionParser(formatter=RepomanHelpFormatter(), usage="%prog [options] [mode]")
+ parser.description = green(" ".join((os.path.basename(argv[0]), "1.2")))
+ parser.description += "\nCopyright 1999-2007 Gentoo Foundation"
+ parser.description += "\nDistributed under the terms of the GNU General Public License v2"
+ parser.description += "\nmodes: " + " | ".join(map(green,mode_keys))
+
+ parser.add_option('-a', '--ask', dest='ask', action='store_true', default=False,
+ help='Request a confirmation before commiting')
+
+ parser.add_option('-m', '--commitmsg', dest='commitmsg',
+ help='specify a commit message on the command line')
+
+ parser.add_option('-M', '--commitmsgfile', dest='commitmsgfile',
+ help='specify a path to a file that contains a commit message')
+
+ parser.add_option('-p', '--pretend', dest='pretend', default=False,
+ action='store_true', help='don\'t commit or fix anything; just show what would be done')
+
+ parser.add_option('-q', '--quiet', dest="quiet", action="count", default=0,
+ help='do not print unnecessary messages')
+
+ parser.add_option('-f', '--force', dest='force', default=False, action='store_true',
+ help='Commit with QA violations')
+
+ parser.add_option('--vcs', dest='vcs',
+ help='Force using specific VCS instead of autodetection')
+
+ parser.add_option('-v', '--verbose', dest="verbosity", action='count',
+ help='be very verbose in output', default=0)
+
+ parser.add_option('-V', '--version', dest='version', action='store_true',
+ help='show version info')
+
+ parser.add_option('-x', '--xmlparse', dest='xml_parse', action='store_true',
+ default=False, help='forces the metadata.xml parse check to be carried out')
+
+ parser.add_option('-i', '--ignore-arches', dest='ignore_arches', action='store_true',
+ default=False, help='ignore arch-specific failures (where arch != host)')
+
+ parser.add_option('-I', '--ignore-masked', dest='ignore_masked', action='store_true',
+ default=False, help='ignore masked packages (not allowed with commit mode)')
+
+ parser.add_option('-d', '--include-dev', dest='include_dev', action='store_true',
+ default=False, help='include dev profiles in dependency checks')
+
+ parser.add_option('--unmatched-removal', dest='unmatched_removal', action='store_true',
+ default=False, help='enable strict checking of package.mask and package.unmask files for unmatched removal atoms')
+
+ parser.add_option('--without-mask', dest='without_mask', action='store_true',
+ default=False, help='behave as if no package.mask entries exist (not allowed with commit mode)')
+
+ parser.add_option('--mode', type='choice', dest='mode', choices=list(modes),
+ help='specify which mode repoman will run in (default=full)')
+
+ parser.on_tail("\n " + green("Modes".ljust(20) + " Description\n"))
+
+ for k in mode_keys:
+ parser.on_tail(" %s %s\n" % (k.ljust(20), modes[k]))
+
+ parser.on_tail("\n " + green("QA keyword".ljust(20) + " Description\n"))
+
+ sorted_qa = list(qahelp)
+ sorted_qa.sort()
+ for k in sorted_qa:
+ parser.on_tail(" %s %s\n" % (k.ljust(20), qahelp[k]))
+
+ opts, args = parser.parse_args(argv[1:])
+
+ if opts.mode == 'help':
+ parser.print_help(short=False)
+
+ for arg in args:
+ if arg in modes:
+ if not opts.mode:
+ opts.mode = arg
+ break
+ else:
+ parser.error("invalid mode: %s" % arg)
+
+ if not opts.mode:
+ opts.mode = 'full'
+
+ if opts.mode == 'ci':
+ opts.mode = 'commit' # backwards compat shortcut
+
+ if opts.mode == 'commit' and not (opts.force or opts.pretend):
+ if opts.ignore_masked:
+ parser.error('Commit mode and --ignore-masked are not compatible')
+ if opts.without_mask:
+ parser.error('Commit mode and --without-mask are not compatible')
+
+ # Use the verbosity and quiet options to fiddle with the loglevel appropriately
+ for val in range(opts.verbosity):
+ logger = logging.getLogger()
+ logger.setLevel(logger.getEffectiveLevel() - 10)
+
+ for val in range(opts.quiet):
+ logger = logging.getLogger()
+ logger.setLevel(logger.getEffectiveLevel() + 10)
+
+ return (opts, args)
+
+qahelp={
+ "CVS/Entries.IO_error":"Attempting to commit, and an IO error was encountered access the Entries file",
+ "desktop.invalid":"desktop-file-validate reports errors in a *.desktop file",
+ "ebuild.invalidname":"Ebuild files with a non-parseable or syntactically incorrect name (or using 2.1 versioning extensions)",
+ "ebuild.namenomatch":"Ebuild files that do not have the same name as their parent directory",
+ "changelog.ebuildadded":"An ebuild was added but the ChangeLog was not modified",
+ "changelog.missing":"Missing ChangeLog files",
+ "ebuild.notadded":"Ebuilds that exist but have not been added to cvs",
+ "ebuild.patches":"PATCHES variable should be a bash array to ensure white space safety",
+ "changelog.notadded":"ChangeLogs that exist but have not been added to cvs",
+ "dependency.unknown" : "Ebuild has a dependency that refers to an unknown package (which may be provided by an overlay)",
+ "file.executable":"Ebuilds, digests, metadata.xml, Manifest, and ChangeLog do note need the executable bit",
+ "file.size":"Files in the files directory must be under 20 KiB",
+ "file.size.fatal":"Files in the files directory must be under 60 KiB",
+ "file.name":"File/dir name must be composed of only the following chars: %s " % allowed_filename_chars,
+ "file.UTF8":"File is not UTF8 compliant",
+ "inherit.autotools":"Ebuild inherits autotools but does not call eautomake, eautoconf or eautoreconf",
+ "inherit.deprecated":"Ebuild inherits a deprecated eclass",
+ "java.eclassesnotused":"With virtual/jdk in DEPEND you must inherit a java eclass",
+ "wxwidgets.eclassnotused":"Ebuild DEPENDs on x11-libs/wxGTK without inheriting wxwidgets.eclass",
+ "KEYWORDS.dropped":"Ebuilds that appear to have dropped KEYWORDS for some arch",
+ "KEYWORDS.missing":"Ebuilds that have a missing or empty KEYWORDS variable",
+ "KEYWORDS.stable":"Ebuilds that have been added directly with stable KEYWORDS",
+ "KEYWORDS.stupid":"Ebuilds that use KEYWORDS=-* instead of package.mask",
+ "LICENSE.missing":"Ebuilds that have a missing or empty LICENSE variable",
+ "LICENSE.virtual":"Virtuals that have a non-empty LICENSE variable",
+ "DESCRIPTION.missing":"Ebuilds that have a missing or empty DESCRIPTION variable",
+ "DESCRIPTION.toolong":"DESCRIPTION is over %d characters" % max_desc_len,
+ "EAPI.definition":"EAPI is defined after an inherit call (must be defined before)",
+ "EAPI.deprecated":"Ebuilds that use features that are deprecated in the current EAPI",
+ "EAPI.incompatible":"Ebuilds that use features that are only available with a different EAPI",
+ "EAPI.unsupported":"Ebuilds that have an unsupported EAPI version (you must upgrade portage)",
+ "SLOT.invalid":"Ebuilds that have a missing or invalid SLOT variable value",
+ "HOMEPAGE.missing":"Ebuilds that have a missing or empty HOMEPAGE variable",
+ "HOMEPAGE.virtual":"Virtuals that have a non-empty HOMEPAGE variable",
+ "DEPEND.bad":"User-visible ebuilds with bad DEPEND settings (matched against *visible* ebuilds)",
+ "RDEPEND.bad":"User-visible ebuilds with bad RDEPEND settings (matched against *visible* ebuilds)",
+ "PDEPEND.bad":"User-visible ebuilds with bad PDEPEND settings (matched against *visible* ebuilds)",
+ "DEPEND.badmasked":"Masked ebuilds with bad DEPEND settings (matched against *all* ebuilds)",
+ "RDEPEND.badmasked":"Masked ebuilds with RDEPEND settings (matched against *all* ebuilds)",
+ "PDEPEND.badmasked":"Masked ebuilds with PDEPEND settings (matched against *all* ebuilds)",
+ "DEPEND.badindev":"User-visible ebuilds with bad DEPEND settings (matched against *visible* ebuilds) in developing arch",
+ "RDEPEND.badindev":"User-visible ebuilds with bad RDEPEND settings (matched against *visible* ebuilds) in developing arch",
+ "PDEPEND.badindev":"User-visible ebuilds with bad PDEPEND settings (matched against *visible* ebuilds) in developing arch",
+ "DEPEND.badmaskedindev":"Masked ebuilds with bad DEPEND settings (matched against *all* ebuilds) in developing arch",
+ "RDEPEND.badmaskedindev":"Masked ebuilds with RDEPEND settings (matched against *all* ebuilds) in developing arch",
+ "PDEPEND.badmaskedindev":"Masked ebuilds with PDEPEND settings (matched against *all* ebuilds) in developing arch",
+ "PDEPEND.suspect":"PDEPEND contains a package that usually only belongs in DEPEND.",
+ "DEPEND.syntax":"Syntax error in DEPEND (usually an extra/missing space/parenthesis)",
+ "RDEPEND.syntax":"Syntax error in RDEPEND (usually an extra/missing space/parenthesis)",
+ "PDEPEND.syntax":"Syntax error in PDEPEND (usually an extra/missing space/parenthesis)",
+ "DEPEND.badtilde":"DEPEND uses the ~ dep operator with a non-zero revision part, which is useless (the revision is ignored)",
+ "RDEPEND.badtilde":"RDEPEND uses the ~ dep operator with a non-zero revision part, which is useless (the revision is ignored)",
+ "PDEPEND.badtilde":"PDEPEND uses the ~ dep operator with a non-zero revision part, which is useless (the revision is ignored)",
+ "LICENSE.syntax":"Syntax error in LICENSE (usually an extra/missing space/parenthesis)",
+ "PROVIDE.syntax":"Syntax error in PROVIDE (usually an extra/missing space/parenthesis)",
+ "PROPERTIES.syntax":"Syntax error in PROPERTIES (usually an extra/missing space/parenthesis)",
+ "RESTRICT.syntax":"Syntax error in RESTRICT (usually an extra/missing space/parenthesis)",
+ "REQUIRED_USE.syntax":"Syntax error in REQUIRED_USE (usually an extra/missing space/parenthesis)",
+ "SRC_URI.syntax":"Syntax error in SRC_URI (usually an extra/missing space/parenthesis)",
+ "SRC_URI.mirror":"A uri listed in profiles/thirdpartymirrors is found in SRC_URI",
+ "ebuild.syntax":"Error generating cache entry for ebuild; typically caused by ebuild syntax error or digest verification failure",
+ "ebuild.output":"A simple sourcing of the ebuild produces output; this breaks ebuild policy.",
+ "ebuild.nesteddie":"Placing 'die' inside ( ) prints an error, but doesn't stop the ebuild.",
+ "variable.invalidchar":"A variable contains an invalid character that is not part of the ASCII character set",
+ "variable.readonly":"Assigning a readonly variable",
+ "variable.usedwithhelpers":"Ebuild uses D, ROOT, ED, EROOT or EPREFIX with helpers",
+ "LIVEVCS.stable":"This ebuild is a live checkout from a VCS but has stable keywords.",
+ "LIVEVCS.unmasked":"This ebuild is a live checkout from a VCS but has keywords and is not masked in the global package.mask.",
+ "IUSE.invalid":"This ebuild has a variable in IUSE that is not in the use.desc or its metadata.xml file",
+ "IUSE.missing":"This ebuild has a USE conditional which references a flag that is not listed in IUSE",
+ "IUSE.undefined":"This ebuild does not define IUSE (style guideline says to define IUSE even when empty)",
+ "LICENSE.invalid":"This ebuild is listing a license that doesnt exist in portages license/ dir.",
+ "KEYWORDS.invalid":"This ebuild contains KEYWORDS that are not listed in profiles/arch.list or for which no valid profile was found",
+ "RDEPEND.implicit":"RDEPEND is unset in the ebuild which triggers implicit RDEPEND=$DEPEND assignment (prior to EAPI 4)",
+ "RDEPEND.suspect":"RDEPEND contains a package that usually only belongs in DEPEND.",
+ "RESTRICT.invalid":"This ebuild contains invalid RESTRICT values.",
+ "digest.assumed":"Existing digest must be assumed correct (Package level only)",
+ "digest.missing":"Some files listed in SRC_URI aren't referenced in the Manifest",
+ "digest.unused":"Some files listed in the Manifest aren't referenced in SRC_URI",
+ "ebuild.nostable":"There are no ebuilds that are marked as stable for your ARCH",
+ "ebuild.allmasked":"All ebuilds are masked for this package (Package level only)",
+ "ebuild.majorsyn":"This ebuild has a major syntax error that may cause the ebuild to fail partially or fully",
+ "ebuild.minorsyn":"This ebuild has a minor syntax error that contravenes gentoo coding style",
+ "ebuild.badheader":"This ebuild has a malformed header",
+ "eprefixify.defined":"The ebuild uses eprefixify, but does not inherit the prefix eclass",
+ "manifest.bad":"Manifest has missing or incorrect digests",
+ "metadata.missing":"Missing metadata.xml files",
+ "metadata.bad":"Bad metadata.xml files",
+ "metadata.warning":"Warnings in metadata.xml files",
+ "portage.internal":"The ebuild uses an internal Portage function",
+ "virtual.oldstyle":"The ebuild PROVIDEs an old-style virtual (see GLEP 37)",
+ "usage.obsolete":"The ebuild makes use of an obsolete construct",
+ "upstream.workaround":"The ebuild works around an upstream bug, an upstream bug should be filed and tracked in bugs.gentoo.org"
+}
+
+qacats = list(qahelp)
+qacats.sort()
+
+qawarnings = set((
+"changelog.missing",
+"changelog.notadded",
+"dependency.unknown",
+"digest.assumed",
+"digest.unused",
+"ebuild.notadded",
+"ebuild.nostable",
+"ebuild.allmasked",
+"ebuild.nesteddie",
+"desktop.invalid",
+"DEPEND.badmasked","RDEPEND.badmasked","PDEPEND.badmasked",
+"DEPEND.badindev","RDEPEND.badindev","PDEPEND.badindev",
+"DEPEND.badmaskedindev","RDEPEND.badmaskedindev","PDEPEND.badmaskedindev",
+"DEPEND.badtilde", "RDEPEND.badtilde", "PDEPEND.badtilde",
+"DESCRIPTION.toolong",
+"EAPI.deprecated",
+"HOMEPAGE.virtual",
+"LICENSE.virtual",
+"KEYWORDS.dropped",
+"KEYWORDS.stupid",
+"KEYWORDS.missing",
+"IUSE.undefined",
+"PDEPEND.suspect",
+"RDEPEND.implicit",
+"RDEPEND.suspect",
+"RESTRICT.invalid",
+"SRC_URI.mirror",
+"ebuild.minorsyn",
+"ebuild.badheader",
+"ebuild.patches",
+"file.size",
+"inherit.autotools",
+"inherit.deprecated",
+"java.eclassesnotused",
+"wxwidgets.eclassnotused",
+"metadata.warning",
+"portage.internal",
+"usage.obsolete",
+"upstream.workaround",
+"virtual.oldstyle",
+"LIVEVCS.stable",
+"LIVEVCS.unmasked",
+))
+
+non_ascii_re = re.compile(r'[^\x00-\x7f]')
+
+missingvars = ["KEYWORDS", "LICENSE", "DESCRIPTION", "HOMEPAGE"]
+allvars = set(x for x in portage.auxdbkeys if not x.startswith("UNUSED_"))
+allvars.update(Package.metadata_keys)
+allvars = sorted(allvars)
+commitmessage=None
+for x in missingvars:
+ x += ".missing"
+ if x not in qacats:
+ logging.warn('* missingvars values need to be added to qahelp ("%s")' % x)
+ qacats.append(x)
+ qawarnings.add(x)
+
+valid_restrict = frozenset(["binchecks", "bindist",
+ "fetch", "installsources", "mirror",
+ "primaryuri", "strip", "test", "userpriv"])
+
+live_eclasses = frozenset([
+ "bzr",
+ "cvs",
+ "darcs",
+ "git",
+ "git-2",
+ "mercurial",
+ "subversion",
+ "tla",
+])
+
+suspect_rdepend = frozenset([
+ "app-arch/cabextract",
+ "app-arch/rpm2targz",
+ "app-doc/doxygen",
+ "dev-lang/nasm",
+ "dev-lang/swig",
+ "dev-lang/yasm",
+ "dev-perl/extutils-pkgconfig",
+ "dev-util/byacc",
+ "dev-util/cmake",
+ "dev-util/ftjam",
+ "dev-util/gperf",
+ "dev-util/gtk-doc",
+ "dev-util/gtk-doc-am",
+ "dev-util/intltool",
+ "dev-util/jam",
+ "dev-util/pkgconfig",
+ "dev-util/scons",
+ "dev-util/unifdef",
+ "dev-util/yacc",
+ "media-gfx/ebdftopcf",
+ "sys-apps/help2man",
+ "sys-devel/autoconf",
+ "sys-devel/automake",
+ "sys-devel/bin86",
+ "sys-devel/bison",
+ "sys-devel/dev86",
+ "sys-devel/flex",
+ "sys-devel/m4",
+ "sys-devel/pmake",
+ "virtual/linux-sources",
+ "x11-misc/bdftopcf",
+ "x11-misc/imake",
+])
+
+metadata_dtd_uri = 'http://www.gentoo.org/dtd/metadata.dtd'
+# force refetch if the local copy creation time is older than this
+metadata_dtd_ctime_interval = 60 * 60 * 24 * 7 # 7 days
+
+# file.executable
+no_exec = frozenset(["Manifest","ChangeLog","metadata.xml"])
+
+options, arguments = ParseArgs(sys.argv, qahelp)
+
+if options.version:
+ print("Portage", portage.VERSION)
+ sys.exit(0)
+
+# Set this to False when an extraordinary issue (generally
+# something other than a QA issue) makes it impossible to
+# commit (like if Manifest generation fails).
+can_force = True
+
+portdir, portdir_overlay, mydir = utilities.FindPortdir(repoman_settings)
+if portdir is None:
+ sys.exit(1)
+
+myreporoot = os.path.basename(portdir_overlay)
+myreporoot += mydir[len(portdir_overlay):]
+
+if options.vcs:
+ if options.vcs in ('cvs', 'svn', 'git', 'bzr', 'hg'):
+ vcs = options.vcs
+ else:
+ vcs = None
+else:
+ vcses = utilities.FindVCS()
+ if len(vcses) > 1:
+ print(red('*** Ambiguous workdir -- more than one VCS found at the same depth: %s.' % ', '.join(vcses)))
+ print(red('*** Please either clean up your workdir or specify --vcs option.'))
+ sys.exit(1)
+ elif vcses:
+ vcs = vcses[0]
+ else:
+ vcs = None
+
+# Note: We don't use ChangeLogs in distributed SCMs.
+# It will be generated on server side from scm log,
+# before package moves to the rsync server.
+# This is needed because we try to avoid merge collisions.
+check_changelog = vcs in ('cvs', 'svn')
+
+# Disable copyright/mtime check if vcs does not preserve mtime (bug #324075).
+vcs_preserves_mtime = vcs not in ('git',)
+
+vcs_local_opts = repoman_settings.get("REPOMAN_VCS_LOCAL_OPTS", "").split()
+vcs_global_opts = repoman_settings.get("REPOMAN_VCS_GLOBAL_OPTS")
+if vcs_global_opts is None:
+ if vcs in ('cvs', 'svn'):
+ vcs_global_opts = "-q"
+ else:
+ vcs_global_opts = ""
+vcs_global_opts = vcs_global_opts.split()
+
+if vcs == "cvs" and \
+ "commit" == options.mode and \
+ "RMD160" not in portage.checksum.hashorigin_map:
+ from portage.util import grablines
+ repo_lines = grablines("./CVS/Repository")
+ if repo_lines and \
+ "gentoo-x86" == repo_lines[0].strip().split(os.path.sep)[0]:
+ msg = "Please install " \
+ "pycrypto or enable python's ssl USE flag in order " \
+ "to enable RMD160 hash support. See bug #198398 for " \
+ "more information."
+ prefix = bad(" * ")
+ from textwrap import wrap
+ for line in wrap(msg, 70):
+ print(prefix + line)
+ sys.exit(1)
+ del repo_lines
+
+if options.mode == 'commit' and not options.pretend and not vcs:
+ logging.info("Not in a version controlled repository; enabling pretend mode.")
+ options.pretend = True
+
+# Ensure that PORTDIR_OVERLAY contains the repository corresponding to $PWD.
+repoman_settings = portage.config(local_config=False)
+repoman_settings['PORTDIR_OVERLAY'] = "%s %s" % \
+ (repoman_settings.get('PORTDIR_OVERLAY', ''), portdir_overlay)
+# We have to call the config constructor again so
+# that config.repositories is initialized correctly.
+repoman_settings = portage.config(local_config=False, env=dict(os.environ,
+ PORTDIR_OVERLAY=repoman_settings['PORTDIR_OVERLAY']))
+
+root = '/'
+trees = {
+ root : {'porttree' : portage.portagetree(root, settings=repoman_settings)}
+}
+portdb = trees[root]['porttree'].dbapi
+
+# Constrain dependency resolution to the master(s)
+# that are specified in layout.conf.
+portdir_overlay = os.path.realpath(portdir_overlay)
+repo_info = portdb._repo_info[portdir_overlay]
+portdb.porttrees = list(repo_info.eclass_db.porttrees)
+portdir = portdb.porttrees[0]
+
+# Generate an appropriate PORTDIR_OVERLAY value for passing into the
+# profile-specific config constructor calls.
+env = os.environ.copy()
+env['PORTDIR'] = portdir
+env['PORTDIR_OVERLAY'] = ' '.join(portdb.porttrees[1:])
+
+logging.info('Setting paths:')
+logging.info('PORTDIR = "' + portdir + '"')
+logging.info('PORTDIR_OVERLAY = "%s"' % env['PORTDIR_OVERLAY'])
+
+# It's confusing if these warnings are displayed without the user
+# being told which profile they come from, so disable them.
+env['FEATURES'] = env.get('FEATURES', '') + ' -unknown-features-warn'
+
+categories = []
+for path in set([portdir, portdir_overlay]):
+ categories.extend(portage.util.grabfile(
+ os.path.join(path, 'profiles', 'categories')))
+repoman_settings.categories = tuple(sorted(
+ portage.util.stack_lists([categories], incremental=1)))
+del categories
+
+portdb.settings = repoman_settings
+root_config = RootConfig(repoman_settings, trees[root], None)
+# We really only need to cache the metadata that's necessary for visibility
+# filtering. Anything else can be discarded to reduce memory consumption.
+portdb._aux_cache_keys.clear()
+portdb._aux_cache_keys.update(["EAPI", "KEYWORDS", "SLOT"])
+
+reposplit = myreporoot.split(os.path.sep)
+repolevel = len(reposplit)
+
+# check if it's in $PORTDIR/$CATEGORY/$PN , otherwise bail if commiting.
+# Reason for this is if they're trying to commit in just $FILESDIR/*, the Manifest needs updating.
+# this check ensures that repoman knows where it is, and the manifest recommit is at least possible.
+if options.mode == 'commit' and repolevel not in [1,2,3]:
+ print(red("***")+" Commit attempts *must* be from within a vcs co, category, or package directory.")
+ print(red("***")+" Attempting to commit from a packages files directory will be blocked for instance.")
+ print(red("***")+" This is intended behaviour, to ensure the manifest is recommitted for a package.")
+ print(red("***"))
+ err("Unable to identify level we're commiting from for %s" % '/'.join(reposplit))
+
+startdir = normalize_path(mydir)
+repodir = startdir
+for x in range(0, repolevel - 1):
+ repodir = os.path.dirname(repodir)
+repodir = os.path.realpath(repodir)
+
+def caterror(mycat):
+ err(mycat+" is not an official category. Skipping QA checks in this directory.\nPlease ensure that you add "+catdir+" to "+repodir+"/profiles/categories\nif it is a new category.")
+
+class ProfileDesc(object):
+ __slots__ = ('abs_path', 'arch', 'status', 'sub_path', 'tree_path',)
+ def __init__(self, arch, status, sub_path, tree_path):
+ self.arch = arch
+ self.status = status
+ if sub_path:
+ sub_path = normalize_path(sub_path.lstrip(os.sep))
+ self.sub_path = sub_path
+ self.tree_path = tree_path
+ if tree_path:
+ self.abs_path = os.path.join(tree_path, 'profiles', self.sub_path)
+ else:
+ self.abs_path = tree_path
+
+ def __str__(self):
+ if self.sub_path:
+ return self.sub_path
+ return 'empty profile'
+
+profile_list = []
+valid_profile_types = frozenset(['dev', 'exp', 'stable'])
+
+# get lists of valid keywords, licenses, and use
+kwlist = set()
+liclist = set()
+uselist = set()
+global_pmasklines = []
+
+for path in portdb.porttrees:
+ try:
+ liclist.update(os.listdir(os.path.join(path, "licenses")))
+ except OSError:
+ pass
+ kwlist.update(portage.grabfile(os.path.join(path,
+ "profiles", "arch.list")))
+
+ use_desc = portage.grabfile(os.path.join(path, 'profiles', 'use.desc'))
+ for x in use_desc:
+ x = x.split()
+ if x:
+ uselist.add(x[0])
+
+ expand_desc_dir = os.path.join(path, 'profiles', 'desc')
+ try:
+ expand_list = os.listdir(expand_desc_dir)
+ except OSError:
+ pass
+ else:
+ for fn in expand_list:
+ if not fn[-5:] == '.desc':
+ continue
+ use_prefix = fn[:-5].lower() + '_'
+ for x in portage.grabfile(os.path.join(expand_desc_dir, fn)):
+ x = x.split()
+ if x:
+ uselist.add(use_prefix + x[0])
+
+ global_pmasklines.append(portage.util.grabfile_package(
+ os.path.join(path, 'profiles', 'package.mask'), recursive=1, verify_eapi=True))
+
+ desc_path = os.path.join(path, 'profiles', 'profiles.desc')
+ try:
+ desc_file = io.open(_unicode_encode(desc_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'], errors='replace')
+ except EnvironmentError:
+ pass
+ else:
+ for i, x in enumerate(desc_file):
+ if x[0] == "#":
+ continue
+ arch = x.split()
+ if len(arch) == 0:
+ continue
+ if len(arch) != 3:
+ err("wrong format: \"" + bad(x.strip()) + "\" in " + \
+ desc_path + " line %d" % (i+1, ))
+ elif arch[0] not in kwlist:
+ err("invalid arch: \"" + bad(arch[0]) + "\" in " + \
+ desc_path + " line %d" % (i+1, ))
+ elif arch[2] not in valid_profile_types:
+ err("invalid profile type: \"" + bad(arch[2]) + "\" in " + \
+ desc_path + " line %d" % (i+1, ))
+ profile_desc = ProfileDesc(arch[0], arch[2], arch[1], path)
+ if not os.path.isdir(profile_desc.abs_path):
+ logging.error(
+ "Invalid %s profile (%s) for arch %s in %s line %d",
+ arch[2], arch[1], arch[0], desc_path, i+1)
+ continue
+ if os.path.exists(
+ os.path.join(profile_desc.abs_path, 'deprecated')):
+ continue
+ profile_list.append(profile_desc)
+ desc_file.close()
+
+repoman_settings['PORTAGE_ARCHLIST'] = ' '.join(sorted(kwlist))
+repoman_settings.backup_changes('PORTAGE_ARCHLIST')
+
+global_pmasklines = portage.util.stack_lists(global_pmasklines, incremental=1)
+global_pmaskdict = {}
+for x in global_pmasklines:
+ global_pmaskdict.setdefault(x.cp, []).append(x)
+del global_pmasklines
+
+def has_global_mask(pkg):
+ mask_atoms = global_pmaskdict.get(pkg.cp)
+ if mask_atoms:
+ pkg_list = [pkg]
+ for x in mask_atoms:
+ if portage.dep.match_from_list(x, pkg_list):
+ return x
+ return None
+
+# Ensure that profile sub_path attributes are unique. Process in reverse order
+# so that profiles with duplicate sub_path from overlays will override
+# profiles with the same sub_path from parent repos.
+profiles = {}
+profile_list.reverse()
+profile_sub_paths = set()
+for prof in profile_list:
+ if prof.sub_path in profile_sub_paths:
+ continue
+ profile_sub_paths.add(prof.sub_path)
+ profiles.setdefault(prof.arch, []).append(prof)
+
+# Use an empty profile for checking dependencies of
+# packages that have empty KEYWORDS.
+prof = ProfileDesc('**', 'stable', '', '')
+profiles.setdefault(prof.arch, []).append(prof)
+
+for x in repoman_settings.archlist():
+ if x[0] == "~":
+ continue
+ if x not in profiles:
+ print(red("\""+x+"\" doesn't have a valid profile listed in profiles.desc."))
+ print(red("You need to either \"cvs update\" your profiles dir or follow this"))
+ print(red("up with the "+x+" team."))
+ print()
+
+if not liclist:
+ logging.fatal("Couldn't find licenses?")
+ sys.exit(1)
+
+if not kwlist:
+ logging.fatal("Couldn't read KEYWORDS from arch.list")
+ sys.exit(1)
+
+if not uselist:
+ logging.fatal("Couldn't find use.desc?")
+ sys.exit(1)
+
+scanlist=[]
+if repolevel==2:
+ #we are inside a category directory
+ catdir=reposplit[-1]
+ if catdir not in repoman_settings.categories:
+ caterror(catdir)
+ mydirlist=os.listdir(startdir)
+ for x in mydirlist:
+ if x == "CVS" or x.startswith("."):
+ continue
+ if os.path.isdir(startdir+"/"+x):
+ scanlist.append(catdir+"/"+x)
+ repo_subdir = catdir + os.sep
+elif repolevel==1:
+ for x in repoman_settings.categories:
+ if not os.path.isdir(startdir+"/"+x):
+ continue
+ for y in os.listdir(startdir+"/"+x):
+ if y == "CVS" or y.startswith("."):
+ continue
+ if os.path.isdir(startdir+"/"+x+"/"+y):
+ scanlist.append(x+"/"+y)
+ repo_subdir = ""
+elif repolevel==3:
+ catdir = reposplit[-2]
+ if catdir not in repoman_settings.categories:
+ caterror(catdir)
+ scanlist.append(catdir+"/"+reposplit[-1])
+ repo_subdir = scanlist[-1] + os.sep
+else:
+ msg = 'Repoman is unable to determine PORTDIR or PORTDIR_OVERLAY' + \
+ ' from the current working directory'
+ logging.critical(msg)
+ sys.exit(1)
+
+repo_subdir_len = len(repo_subdir)
+scanlist.sort()
+
+logging.debug("Found the following packages to scan:\n%s" % '\n'.join(scanlist))
+
+def dev_keywords(profiles):
+ """
+ Create a set of KEYWORDS values that exist in 'dev'
+ profiles. These are used
+ to trigger a message notifying the user when they might
+ want to add the --include-dev option.
+ """
+ type_arch_map = {}
+ for arch, arch_profiles in profiles.items():
+ for prof in arch_profiles:
+ arch_set = type_arch_map.get(prof.status)
+ if arch_set is None:
+ arch_set = set()
+ type_arch_map[prof.status] = arch_set
+ arch_set.add(arch)
+
+ dev_keywords = type_arch_map.get('dev', set())
+ dev_keywords.update(['~' + arch for arch in dev_keywords])
+ return frozenset(dev_keywords)
+
+dev_keywords = dev_keywords(profiles)
+
+stats={}
+fails={}
+
+# provided by the desktop-file-utils package
+desktop_file_validate = find_binary("desktop-file-validate")
+desktop_pattern = re.compile(r'.*\.desktop$')
+
+for x in qacats:
+ stats[x]=0
+ fails[x]=[]
+
+xmllint_capable = False
+metadata_dtd = os.path.join(repoman_settings["DISTDIR"], 'metadata.dtd')
+
+def parsedate(s):
+ """Parse a RFC 822 date and time string.
+ This is required for python3 compatibility, since the
+ rfc822.parsedate() function is not available."""
+
+ s_split = []
+ for x in s.upper().split():
+ for y in x.split(','):
+ if y:
+ s_split.append(y)
+
+ if len(s_split) != 6:
+ return None
+
+ # %a, %d %b %Y %H:%M:%S %Z
+ a, d, b, Y, H_M_S, Z = s_split
+
+ # Convert month to integer, since strptime %w is locale-dependent.
+ month_map = {'JAN':1, 'FEB':2, 'MAR':3, 'APR':4, 'MAY':5, 'JUN':6,
+ 'JUL':7, 'AUG':8, 'SEP':9, 'OCT':10, 'NOV':11, 'DEC':12}
+ m = month_map.get(b)
+ if m is None:
+ return None
+ m = str(m).rjust(2, '0')
+
+ return time.strptime(':'.join((Y, m, d, H_M_S)), '%Y:%m:%d:%H:%M:%S')
+
+def fetch_metadata_dtd():
+ """
+ Fetch metadata.dtd if it doesn't exist or the ctime is older than
+ metadata_dtd_ctime_interval.
+ @rtype: bool
+ @returns: True if successful, otherwise False
+ """
+
+ must_fetch = True
+ metadata_dtd_st = None
+ current_time = int(time.time())
+ try:
+ metadata_dtd_st = os.stat(metadata_dtd)
+ except EnvironmentError as e:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
+ raise
+ del e
+ else:
+ # Trigger fetch if metadata.dtd mtime is old or clock is wrong.
+ if abs(current_time - metadata_dtd_st.st_ctime) \
+ < metadata_dtd_ctime_interval:
+ must_fetch = False
+
+ if must_fetch:
+ print()
+ print(green("***") + " the local copy of metadata.dtd " + \
+ "needs to be refetched, doing that now")
+ print()
+ try:
+ url_f = urllib_request_urlopen(metadata_dtd_uri)
+ msg_info = url_f.info()
+ last_modified = msg_info.get('last-modified')
+ if last_modified is not None:
+ last_modified = parsedate(last_modified)
+ if last_modified is not None:
+ last_modified = calendar.timegm(last_modified)
+
+ metadata_dtd_tmp = "%s.%s" % (metadata_dtd, os.getpid())
+ try:
+ local_f = open(metadata_dtd_tmp, mode='wb')
+ local_f.write(url_f.read())
+ local_f.close()
+ if last_modified is not None:
+ try:
+ os.utime(metadata_dtd_tmp,
+ (int(last_modified), int(last_modified)))
+ except OSError:
+ # This fails on some odd non-unix-like filesystems.
+ # We don't really need the mtime to be preserved
+ # anyway here (currently we use ctime to trigger
+ # fetch), so just ignore it.
+ pass
+ os.rename(metadata_dtd_tmp, metadata_dtd)
+ finally:
+ try:
+ os.unlink(metadata_dtd_tmp)
+ except OSError:
+ pass
+
+ url_f.close()
+
+ except EnvironmentError as e:
+ print()
+ print(red("!!!")+" attempting to fetch '%s', caught" % metadata_dtd_uri)
+ print(red("!!!")+" exception '%s' though." % (e,))
+ print(red("!!!")+" fetching new metadata.dtd failed, aborting")
+ return False
+
+ return True
+
+if options.mode == "manifest":
+ pass
+elif not find_binary('xmllint'):
+ print(red("!!! xmllint not found. Can't check metadata.xml.\n"))
+ if options.xml_parse or repolevel==3:
+ print(red("!!!")+" sorry, xmllint is needed. failing\n")
+ sys.exit(1)
+else:
+ if not fetch_metadata_dtd():
+ sys.exit(1)
+ #this can be problematic if xmllint changes their output
+ xmllint_capable=True
+
+if options.mode == 'commit' and vcs:
+ utilities.detect_vcs_conflicts(options, vcs)
+
+if options.mode == "manifest":
+ pass
+elif options.pretend:
+ print(green("\nRepoMan does a once-over of the neighborhood..."))
+else:
+ print(green("\nRepoMan scours the neighborhood..."))
+
+new_ebuilds = set()
+modified_ebuilds = set()
+modified_changelogs = set()
+mychanged = []
+mynew = []
+myremoved = []
+
+if vcs == "cvs":
+ mycvstree = cvstree.getentries("./", recursive=1)
+ mychanged = cvstree.findchanged(mycvstree, recursive=1, basedir="./")
+ mynew = cvstree.findnew(mycvstree, recursive=1, basedir="./")
+if vcs == "svn":
+ svnstatus = os.popen("svn status").readlines()
+ mychanged = [ "./" + elem.split()[-1:][0] for elem in svnstatus if elem and elem[:1] in "MR" ]
+ mynew = [ "./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("A") ]
+elif vcs == "git":
+ mychanged = os.popen("git diff-index --name-only --relative --diff-filter=M HEAD").readlines()
+ mychanged = ["./" + elem[:-1] for elem in mychanged]
+
+ mynew = os.popen("git diff-index --name-only --relative --diff-filter=A HEAD").readlines()
+ mynew = ["./" + elem[:-1] for elem in mynew]
+elif vcs == "bzr":
+ bzrstatus = os.popen("bzr status -S .").readlines()
+ mychanged = [ "./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and elem[1:2] == "M" ]
+ mynew = [ "./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and ( elem[1:2] == "NK" or elem[0:1] == "R" ) ]
+elif vcs == "hg":
+ mychanged = os.popen("hg status --no-status --modified .").readlines()
+ mychanged = ["./" + elem.rstrip() for elem in mychanged]
+ mynew = os.popen("hg status --no-status --added .").readlines()
+ mynew = ["./" + elem.rstrip() for elem in mynew]
+
+if vcs:
+ new_ebuilds.update(x for x in mynew if x.endswith(".ebuild"))
+ modified_ebuilds.update(x for x in mychanged if x.endswith(".ebuild"))
+ modified_changelogs.update(x for x in chain(mychanged, mynew) \
+ if os.path.basename(x) == "ChangeLog")
+
+have_pmasked = False
+have_dev_keywords = False
+dofail = 0
+arch_caches={}
+arch_xmatch_caches = {}
+shared_xmatch_caches = {"cp-list":{}}
+
+# Disable the "ebuild.notadded" check when not in commit mode and
+# running `svn status` in every package dir will be too expensive.
+
+check_ebuild_notadded = not \
+ (vcs == "svn" and repolevel < 3 and options.mode != "commit")
+
+# Build a regex from thirdpartymirrors for the SRC_URI.mirror check.
+thirdpartymirrors = []
+for v in repoman_settings.thirdpartymirrors().values():
+ thirdpartymirrors.extend(v)
+
+class _MetadataTreeBuilder(xml.etree.ElementTree.TreeBuilder):
+ """
+ Implements doctype() as required to avoid deprecation warnings with
+ >=python-2.7.
+ """
+ def doctype(self, name, pubid, system):
+ pass
+
+try:
+ herd_base = make_herd_base(os.path.join(repoman_settings["PORTDIR"], "metadata/herds.xml"))
+except (EnvironmentError, ParseError, PermissionDenied) as e:
+ err(str(e))
+except FileNotFound:
+ # TODO: Download as we do for metadata.dtd, but add a way to
+ # disable for non-gentoo repoman users who may not have herds.
+ herd_base = None
+
+for x in scanlist:
+ #ebuilds and digests added to cvs respectively.
+ logging.info("checking package %s" % x)
+ eadded=[]
+ catdir,pkgdir=x.split("/")
+ checkdir=repodir+"/"+x
+ checkdir_relative = ""
+ if repolevel < 3:
+ checkdir_relative = os.path.join(pkgdir, checkdir_relative)
+ if repolevel < 2:
+ checkdir_relative = os.path.join(catdir, checkdir_relative)
+ checkdir_relative = os.path.join(".", checkdir_relative)
+ generated_manifest = False
+
+ if options.mode == "manifest" or \
+ (options.mode != 'manifest-check' and \
+ 'digest' in repoman_settings.features) or \
+ options.mode in ('commit', 'fix') and not options.pretend:
+ auto_assumed = set()
+ fetchlist_dict = portage.FetchlistDict(checkdir,
+ repoman_settings, portdb)
+ if options.mode == 'manifest' and options.force:
+ portage._doebuild_manifest_exempt_depend += 1
+ try:
+ distdir = repoman_settings['DISTDIR']
+ mf = portage.manifest.Manifest(checkdir, distdir,
+ fetchlist_dict=fetchlist_dict)
+ mf.create(requiredDistfiles=None,
+ assumeDistHashesAlways=True)
+ for distfiles in fetchlist_dict.values():
+ for distfile in distfiles:
+ if os.path.isfile(os.path.join(distdir, distfile)):
+ mf.fhashdict['DIST'].pop(distfile, None)
+ else:
+ auto_assumed.add(distfile)
+ mf.write()
+ finally:
+ portage._doebuild_manifest_exempt_depend -= 1
+
+ repoman_settings["O"] = checkdir
+ try:
+ generated_manifest = digestgen(
+ mysettings=repoman_settings, myportdb=portdb)
+ except portage.exception.PermissionDenied as e:
+ generated_manifest = False
+ writemsg_level("!!! Permission denied: '%s'\n" % (e,),
+ level=logging.ERROR, noiselevel=-1)
+
+ if not generated_manifest:
+ print("Unable to generate manifest.")
+ dofail = 1
+
+ if options.mode == "manifest":
+ if not dofail and options.force and auto_assumed and \
+ 'assume-digests' in repoman_settings.features:
+ # Show which digests were assumed despite the --force option
+ # being given. This output will already have been shown by
+ # digestgen() if assume-digests is not enabled, so only show
+ # it here if assume-digests is enabled.
+ pkgs = list(fetchlist_dict)
+ pkgs.sort()
+ portage.writemsg_stdout(" digest.assumed" + \
+ portage.output.colorize("WARN",
+ str(len(auto_assumed)).rjust(18)) + "\n")
+ for cpv in pkgs:
+ fetchmap = fetchlist_dict[cpv]
+ pf = portage.catsplit(cpv)[1]
+ for distfile in sorted(fetchmap):
+ if distfile in auto_assumed:
+ portage.writemsg_stdout(
+ " %s::%s\n" % (pf, distfile))
+ continue
+ elif dofail:
+ sys.exit(1)
+
+ if not generated_manifest:
+ repoman_settings['O'] = checkdir
+ repoman_settings['PORTAGE_QUIET'] = '1'
+ if not portage.digestcheck([], repoman_settings, strict=1):
+ stats["manifest.bad"] += 1
+ fails["manifest.bad"].append(os.path.join(x, 'Manifest'))
+ repoman_settings.pop('PORTAGE_QUIET', None)
+
+ if options.mode == 'manifest-check':
+ continue
+
+ checkdirlist=os.listdir(checkdir)
+ ebuildlist=[]
+ pkgs = {}
+ allvalid = True
+ for y in checkdirlist:
+ if (y in no_exec or y.endswith(".ebuild")) and \
+ stat.S_IMODE(os.stat(os.path.join(checkdir, y)).st_mode) & 0o111:
+ stats["file.executable"] += 1
+ fails["file.executable"].append(os.path.join(checkdir, y))
+ if y.endswith(".ebuild"):
+ pf = y[:-7]
+ ebuildlist.append(pf)
+ cpv = "%s/%s" % (catdir, pf)
+ try:
+ myaux = dict(zip(allvars, portdb.aux_get(cpv, allvars)))
+ except KeyError:
+ allvalid = False
+ stats["ebuild.syntax"] += 1
+ fails["ebuild.syntax"].append(os.path.join(x, y))
+ continue
+ except IOError:
+ allvalid = False
+ stats["ebuild.output"] += 1
+ fails["ebuild.output"].append(os.path.join(x, y))
+ continue
+ if not portage.eapi_is_supported(myaux["EAPI"]):
+ allvalid = False
+ stats["EAPI.unsupported"] += 1
+ fails["EAPI.unsupported"].append(os.path.join(x, y))
+ continue
+ pkgs[pf] = Package(cpv=cpv, metadata=myaux,
+ root_config=root_config, type_name="ebuild")
+
+ # Sort ebuilds in ascending order for the KEYWORDS.dropped check.
+ pkgsplits = {}
+ for i in range(len(ebuildlist)):
+ ebuild_split = portage.pkgsplit(ebuildlist[i])
+ pkgsplits[ebuild_split] = ebuildlist[i]
+ ebuildlist[i] = ebuild_split
+ ebuildlist.sort(key=cmp_sort_key(portage.pkgcmp))
+ for i in range(len(ebuildlist)):
+ ebuildlist[i] = pkgsplits[ebuildlist[i]]
+ del pkgsplits
+
+ slot_keywords = {}
+
+ if len(pkgs) != len(ebuildlist):
+ # If we can't access all the metadata then it's totally unsafe to
+ # commit since there's no way to generate a correct Manifest.
+ # Do not try to do any more QA checks on this package since missing
+ # metadata leads to false positives for several checks, and false
+ # positives confuse users.
+ can_force = False
+ continue
+
+ for y in checkdirlist:
+ m = disallowed_filename_chars_re.search(y.strip(os.sep))
+ if m is not None:
+ stats["file.name"] += 1
+ fails["file.name"].append("%s/%s: char '%s'" % \
+ (checkdir, y, m.group(0)))
+
+ if not (y in ("ChangeLog", "metadata.xml") or y.endswith(".ebuild")):
+ continue
+ try:
+ line = 1
+ for l in io.open(_unicode_encode(os.path.join(checkdir, y),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content']):
+ line +=1
+ except UnicodeDecodeError as ue:
+ stats["file.UTF8"] += 1
+ s = ue.object[:ue.start]
+ l2 = s.count("\n")
+ line += l2
+ if l2 != 0:
+ s = s[s.rfind("\n") + 1:]
+ fails["file.UTF8"].append("%s/%s: line %i, just after: '%s'" % (checkdir, y, line, s))
+
+ if vcs in ("git", "hg") and check_ebuild_notadded:
+ if vcs == "git":
+ myf = os.popen("git ls-files --others %s" % \
+ (portage._shell_quote(checkdir_relative),))
+ if vcs == "hg":
+ myf = os.popen("hg status --no-status --unknown %s" % \
+ (portage._shell_quote(checkdir_relative),))
+ for l in myf:
+ if l[:-1][-7:] == ".ebuild":
+ stats["ebuild.notadded"] += 1
+ fails["ebuild.notadded"].append(
+ os.path.join(x, os.path.basename(l[:-1])))
+ myf.close()
+
+ if vcs in ("cvs", "svn", "bzr") and check_ebuild_notadded:
+ try:
+ if vcs == "cvs":
+ myf=open(checkdir+"/CVS/Entries","r")
+ if vcs == "svn":
+ myf = os.popen("svn status --depth=files --verbose " + checkdir)
+ if vcs == "bzr":
+ myf = os.popen("bzr ls -v --kind=file " + checkdir)
+ myl = myf.readlines()
+ myf.close()
+ for l in myl:
+ if vcs == "cvs":
+ if l[0]!="/":
+ continue
+ splitl=l[1:].split("/")
+ if not len(splitl):
+ continue
+ if splitl[0][-7:]==".ebuild":
+ eadded.append(splitl[0][:-7])
+ if vcs == "svn":
+ if l[:1] == "?":
+ continue
+ if l[:7] == ' >':
+ # tree conflict, new in subversion 1.6
+ continue
+ l = l.split()[-1]
+ if l[-7:] == ".ebuild":
+ eadded.append(os.path.basename(l[:-7]))
+ if vcs == "bzr":
+ if l[1:2] == "?":
+ continue
+ l = l.split()[-1]
+ if l[-7:] == ".ebuild":
+ eadded.append(os.path.basename(l[:-7]))
+ if vcs == "svn":
+ myf = os.popen("svn status " + checkdir)
+ myl=myf.readlines()
+ myf.close()
+ for l in myl:
+ if l[0] == "A":
+ l = l.rstrip().split(' ')[-1]
+ if l[-7:] == ".ebuild":
+ eadded.append(os.path.basename(l[:-7]))
+ except IOError:
+ if vcs == "cvs":
+ stats["CVS/Entries.IO_error"] += 1
+ fails["CVS/Entries.IO_error"].append(checkdir+"/CVS/Entries")
+ else:
+ raise
+ continue
+
+ mf = Manifest(checkdir, repoman_settings["DISTDIR"])
+ mydigests=mf.getTypeDigests("DIST")
+
+ fetchlist_dict = portage.FetchlistDict(checkdir, repoman_settings, portdb)
+ myfiles_all = []
+ src_uri_error = False
+ for mykey in fetchlist_dict:
+ try:
+ myfiles_all.extend(fetchlist_dict[mykey])
+ except portage.exception.InvalidDependString as e:
+ src_uri_error = True
+ try:
+ portdb.aux_get(mykey, ["SRC_URI"])
+ except KeyError:
+ # This will be reported as an "ebuild.syntax" error.
+ pass
+ else:
+ stats["SRC_URI.syntax"] = stats["SRC_URI.syntax"] + 1
+ fails["SRC_URI.syntax"].append(
+ "%s.ebuild SRC_URI: %s" % (mykey, e))
+ del fetchlist_dict
+ if not src_uri_error:
+ # This test can produce false positives if SRC_URI could not
+ # be parsed for one or more ebuilds. There's no point in
+ # producing a false error here since the root cause will
+ # produce a valid error elsewhere, such as "SRC_URI.syntax"
+ # or "ebuild.sytax".
+ myfiles_all = set(myfiles_all)
+ for entry in mydigests:
+ if entry not in myfiles_all:
+ stats["digest.unused"] += 1
+ fails["digest.unused"].append(checkdir+"::"+entry)
+ for entry in myfiles_all:
+ if entry not in mydigests:
+ stats["digest.missing"] += 1
+ fails["digest.missing"].append(checkdir+"::"+entry)
+ del myfiles_all
+
+ if os.path.exists(checkdir+"/files"):
+ filesdirlist=os.listdir(checkdir+"/files")
+
+ # recurse through files directory
+ # use filesdirlist as a stack, appending directories as needed so people can't hide > 20k files in a subdirectory.
+ while filesdirlist:
+ y = filesdirlist.pop(0)
+ relative_path = os.path.join(x, "files", y)
+ full_path = os.path.join(repodir, relative_path)
+ try:
+ mystat = os.stat(full_path)
+ except OSError as oe:
+ if oe.errno == 2:
+ # don't worry about it. it likely was removed via fix above.
+ continue
+ else:
+ raise oe
+ if S_ISDIR(mystat.st_mode):
+ # !!! VCS "portability" alert! Need some function isVcsDir() or alike !!!
+ if y == "CVS" or y == ".svn":
+ continue
+ for z in os.listdir(checkdir+"/files/"+y):
+ if z == "CVS" or z == ".svn":
+ continue
+ filesdirlist.append(y+"/"+z)
+ # Current policy is no files over 20 KiB, these are the checks. File size between
+ # 20 KiB and 60 KiB causes a warning, while file size over 60 KiB causes an error.
+ elif mystat.st_size > 61440:
+ stats["file.size.fatal"] += 1
+ fails["file.size.fatal"].append("("+ str(mystat.st_size//1024) + " KiB) "+x+"/files/"+y)
+ elif mystat.st_size > 20480:
+ stats["file.size"] += 1
+ fails["file.size"].append("("+ str(mystat.st_size//1024) + " KiB) "+x+"/files/"+y)
+
+ m = disallowed_filename_chars_re.search(
+ os.path.basename(y.rstrip(os.sep)))
+ if m is not None:
+ stats["file.name"] += 1
+ fails["file.name"].append("%s/files/%s: char '%s'" % \
+ (checkdir, y, m.group(0)))
+
+ if desktop_file_validate and desktop_pattern.match(y):
+ status, cmd_output = subprocess_getstatusoutput(
+ "'%s' '%s'" % (desktop_file_validate, full_path))
+ if os.WIFEXITED(status) and os.WEXITSTATUS(status) != os.EX_OK:
+ # Note: in the future we may want to grab the
+ # warnings in addition to the errors. We're
+ # just doing errors now since we don't want
+ # to generate too much noise at first.
+ error_re = re.compile(r'.*\s*error:\s*(.*)')
+ for line in cmd_output.splitlines():
+ error_match = error_re.match(line)
+ if error_match is None:
+ continue
+ stats["desktop.invalid"] += 1
+ fails["desktop.invalid"].append(
+ relative_path + ': %s' % error_match.group(1))
+
+ del mydigests
+
+ if check_changelog and "ChangeLog" not in checkdirlist:
+ stats["changelog.missing"]+=1
+ fails["changelog.missing"].append(x+"/ChangeLog")
+
+ musedict = {}
+ #metadata.xml file check
+ if "metadata.xml" not in checkdirlist:
+ stats["metadata.missing"]+=1
+ fails["metadata.missing"].append(x+"/metadata.xml")
+ #metadata.xml parse check
+ else:
+ metadata_bad = False
+
+ # read metadata.xml into memory
+ try:
+ _metadata_xml = xml.etree.ElementTree.parse(
+ os.path.join(checkdir, "metadata.xml"),
+ parser=xml.etree.ElementTree.XMLParser(
+ target=_MetadataTreeBuilder()))
+ except (ExpatError, SyntaxError, EnvironmentError) as e:
+ metadata_bad = True
+ stats["metadata.bad"] += 1
+ fails["metadata.bad"].append("%s/metadata.xml: %s" % (x, e))
+ del e
+ else:
+ # load USE flags from metadata.xml
+ try:
+ musedict = utilities.parse_metadata_use(_metadata_xml)
+ except portage.exception.ParseError as e:
+ metadata_bad = True
+ stats["metadata.bad"] += 1
+ fails["metadata.bad"].append("%s/metadata.xml: %s" % (x, e))
+
+ # Run other metadata.xml checkers
+ try:
+ utilities.check_metadata(_metadata_xml, herd_base)
+ except (utilities.UnknownHerdsError, ) as e:
+ metadata_bad = True
+ stats["metadata.bad"] += 1
+ fails["metadata.bad"].append("%s/metadata.xml: %s" % (x, e))
+ del e
+
+ #Only carry out if in package directory or check forced
+ if xmllint_capable and not metadata_bad:
+ # xmlint can produce garbage output even on success, so only dump
+ # the ouput when it fails.
+ st, out = subprocess_getstatusoutput(
+ "xmllint --nonet --noout --dtdvalid '%s' '%s'" % \
+ (metadata_dtd, os.path.join(checkdir, "metadata.xml")))
+ if st != os.EX_OK:
+ print(red("!!!") + " metadata.xml is invalid:")
+ for z in out.splitlines():
+ print(red("!!! ")+z)
+ stats["metadata.bad"]+=1
+ fails["metadata.bad"].append(x+"/metadata.xml")
+
+ del metadata_bad
+ muselist = frozenset(musedict)
+
+ changelog_path = os.path.join(checkdir_relative, "ChangeLog")
+ changelog_modified = changelog_path in modified_changelogs
+
+ allmasked = True
+ # detect unused local USE-descriptions
+ used_useflags = set()
+
+ for y in ebuildlist:
+ relative_path = os.path.join(x, y + ".ebuild")
+ full_path = os.path.join(repodir, relative_path)
+ ebuild_path = y + ".ebuild"
+ if repolevel < 3:
+ ebuild_path = os.path.join(pkgdir, ebuild_path)
+ if repolevel < 2:
+ ebuild_path = os.path.join(catdir, ebuild_path)
+ ebuild_path = os.path.join(".", ebuild_path)
+ if check_changelog and not changelog_modified \
+ and ebuild_path in new_ebuilds:
+ stats['changelog.ebuildadded'] += 1
+ fails['changelog.ebuildadded'].append(relative_path)
+
+ if vcs in ("cvs", "svn", "bzr") and check_ebuild_notadded and y not in eadded:
+ #ebuild not added to vcs
+ stats["ebuild.notadded"]=stats["ebuild.notadded"]+1
+ fails["ebuild.notadded"].append(x+"/"+y+".ebuild")
+ myesplit=portage.pkgsplit(y)
+ if myesplit is None or myesplit[0] != x.split("/")[-1] \
+ or pv_toolong_re.search(myesplit[1]) \
+ or pv_toolong_re.search(myesplit[2]):
+ stats["ebuild.invalidname"]=stats["ebuild.invalidname"]+1
+ fails["ebuild.invalidname"].append(x+"/"+y+".ebuild")
+ continue
+ elif myesplit[0]!=pkgdir:
+ print(pkgdir,myesplit[0])
+ stats["ebuild.namenomatch"]=stats["ebuild.namenomatch"]+1
+ fails["ebuild.namenomatch"].append(x+"/"+y+".ebuild")
+ continue
+
+ pkg = pkgs[y]
+
+ if pkg.invalid:
+ allvalid = False
+ for k, msgs in pkg.invalid.items():
+ for msg in msgs:
+ stats[k] = stats[k] + 1
+ fails[k].append("%s %s" % (relative_path, msg))
+ continue
+
+ myaux = pkg.metadata
+ eapi = myaux["EAPI"]
+ inherited = pkg.inherited
+ live_ebuild = live_eclasses.intersection(inherited)
+
+ for k, v in myaux.items():
+ if not isinstance(v, basestring):
+ continue
+ m = non_ascii_re.search(v)
+ if m is not None:
+ stats["variable.invalidchar"] += 1
+ fails["variable.invalidchar"].append(
+ ("%s: %s variable contains non-ASCII " + \
+ "character at position %s") % \
+ (relative_path, k, m.start() + 1))
+
+ if not src_uri_error:
+ # Check that URIs don't reference a server from thirdpartymirrors.
+ for uri in portage.dep.use_reduce( \
+ myaux["SRC_URI"], matchall=True, is_src_uri=True, eapi=eapi, flat=True):
+ contains_mirror = False
+ for mirror in thirdpartymirrors:
+ if uri.startswith(mirror):
+ contains_mirror = True
+ break
+ if not contains_mirror:
+ continue
+
+ stats["SRC_URI.mirror"] += 1
+ fails["SRC_URI.mirror"].append(
+ "%s: '%s' found in thirdpartymirrors" % \
+ (relative_path, mirror))
+
+ if myaux.get("PROVIDE"):
+ stats["virtual.oldstyle"]+=1
+ fails["virtual.oldstyle"].append(relative_path)
+
+ for pos, missing_var in enumerate(missingvars):
+ if not myaux.get(missing_var):
+ if catdir == "virtual" and \
+ missing_var in ("HOMEPAGE", "LICENSE"):
+ continue
+ if live_ebuild and missing_var == "KEYWORDS":
+ continue
+ myqakey=missingvars[pos]+".missing"
+ stats[myqakey]=stats[myqakey]+1
+ fails[myqakey].append(x+"/"+y+".ebuild")
+
+ if catdir == "virtual":
+ for var in ("HOMEPAGE", "LICENSE"):
+ if myaux.get(var):
+ myqakey = var + ".virtual"
+ stats[myqakey] = stats[myqakey] + 1
+ fails[myqakey].append(relative_path)
+
+ # 14 is the length of DESCRIPTION=""
+ if len(myaux['DESCRIPTION']) > max_desc_len:
+ stats['DESCRIPTION.toolong'] += 1
+ fails['DESCRIPTION.toolong'].append(
+ "%s: DESCRIPTION is %d characters (max %d)" % \
+ (relative_path, len(myaux['DESCRIPTION']), max_desc_len))
+
+ keywords = myaux["KEYWORDS"].split()
+ stable_keywords = []
+ for keyword in keywords:
+ if not keyword.startswith("~") and \
+ not keyword.startswith("-"):
+ stable_keywords.append(keyword)
+ if stable_keywords:
+ if ebuild_path in new_ebuilds:
+ stable_keywords.sort()
+ stats["KEYWORDS.stable"] += 1
+ fails["KEYWORDS.stable"].append(
+ x + "/" + y + ".ebuild added with stable keywords: %s" % \
+ " ".join(stable_keywords))
+
+ ebuild_archs = set(kw.lstrip("~") for kw in keywords \
+ if not kw.startswith("-"))
+
+ previous_keywords = slot_keywords.get(myaux["SLOT"])
+ if previous_keywords is None:
+ slot_keywords[myaux["SLOT"]] = set()
+ elif ebuild_archs and not live_ebuild:
+ dropped_keywords = previous_keywords.difference(ebuild_archs)
+ if dropped_keywords:
+ stats["KEYWORDS.dropped"] += 1
+ fails["KEYWORDS.dropped"].append(
+ relative_path + ": %s" % \
+ " ".join(sorted(dropped_keywords)))
+
+ slot_keywords[myaux["SLOT"]].update(ebuild_archs)
+
+ # KEYWORDS="-*" is a stupid replacement for package.mask and screws general KEYWORDS semantics
+ if "-*" in keywords:
+ haskeyword = False
+ for kw in keywords:
+ if kw[0] == "~":
+ kw = kw[1:]
+ if kw in kwlist:
+ haskeyword = True
+ if not haskeyword:
+ stats["KEYWORDS.stupid"] += 1
+ fails["KEYWORDS.stupid"].append(x+"/"+y+".ebuild")
+
+ """
+ Ebuilds that inherit a "Live" eclass (darcs,subversion,git,cvs,etc..) should
+ not be allowed to be marked stable
+ """
+ if live_ebuild:
+ bad_stable_keywords = []
+ for keyword in keywords:
+ if not keyword.startswith("~") and \
+ not keyword.startswith("-"):
+ bad_stable_keywords.append(keyword)
+ del keyword
+ if bad_stable_keywords:
+ stats["LIVEVCS.stable"] += 1
+ fails["LIVEVCS.stable"].append(
+ x + "/" + y + ".ebuild with stable keywords:%s " % \
+ bad_stable_keywords)
+ del bad_stable_keywords
+
+ if keywords and not has_global_mask(pkg):
+ stats["LIVEVCS.unmasked"] += 1
+ fails["LIVEVCS.unmasked"].append(relative_path)
+
+ if options.ignore_arches:
+ arches = [[repoman_settings["ARCH"], repoman_settings["ARCH"],
+ repoman_settings["ACCEPT_KEYWORDS"].split()]]
+ else:
+ arches=[]
+ for keyword in myaux["KEYWORDS"].split():
+ if (keyword[0]=="-"):
+ continue
+ elif (keyword[0]=="~"):
+ arches.append([keyword, keyword[1:], [keyword[1:], keyword]])
+ else:
+ arches.append([keyword, keyword, [keyword]])
+ allmasked = False
+ if not arches:
+ # Use an empty profile for checking dependencies of
+ # packages that have empty KEYWORDS.
+ arches.append(['**', '**', ['**']])
+
+ unknown_pkgs = {}
+ baddepsyntax = False
+ badlicsyntax = False
+ badprovsyntax = False
+ catpkg = catdir+"/"+y
+
+ inherited_java_eclass = "java-pkg-2" in inherited or \
+ "java-pkg-opt-2" in inherited
+ inherited_wxwidgets_eclass = "wxwidgets" in inherited
+ operator_tokens = set(["||", "(", ")"])
+ type_list, badsyntax = [], []
+ for mytype in ("DEPEND", "RDEPEND", "PDEPEND",
+ "LICENSE", "PROPERTIES", "PROVIDE"):
+ mydepstr = myaux[mytype]
+
+ token_class = None
+ if mytype in ("DEPEND", "RDEPEND", "PDEPEND"):
+ token_class=portage.dep.Atom
+
+ try:
+ atoms = portage.dep.use_reduce(mydepstr, matchall=1, flat=True, \
+ is_valid_flag=pkg.iuse.is_valid_flag, token_class=token_class)
+ except portage.exception.InvalidDependString as e:
+ atoms = None
+ badsyntax.append(str(e))
+
+ if atoms and mytype in ("DEPEND", "RDEPEND", "PDEPEND"):
+ if mytype in ("RDEPEND", "PDEPEND") and \
+ "test?" in mydepstr.split():
+ stats[mytype + '.suspect'] += 1
+ fails[mytype + '.suspect'].append(relative_path + \
+ ": 'test?' USE conditional in %s" % mytype)
+
+ for atom in atoms:
+ if atom == "||":
+ continue
+
+ if not atom.blocker and \
+ not portdb.cp_list(atom.cp) and \
+ not atom.cp.startswith("virtual/"):
+ unknown_pkgs.setdefault(atom.cp, set()).add(
+ (mytype, atom.unevaluated_atom))
+
+ is_blocker = atom.blocker
+
+ if mytype == "DEPEND" and \
+ not is_blocker and \
+ not inherited_java_eclass and \
+ atom.cp == "virtual/jdk":
+ stats['java.eclassesnotused'] += 1
+ fails['java.eclassesnotused'].append(relative_path)
+ elif mytype == "DEPEND" and \
+ not is_blocker and \
+ not inherited_wxwidgets_eclass and \
+ atom.cp == "x11-libs/wxGTK":
+ stats['wxwidgets.eclassnotused'] += 1
+ fails['wxwidgets.eclassnotused'].append(
+ relative_path + ": DEPENDs on x11-libs/wxGTK"
+ " without inheriting wxwidgets.eclass")
+ elif mytype in ("PDEPEND", "RDEPEND"):
+ if not is_blocker and \
+ atom.cp in suspect_rdepend:
+ stats[mytype + '.suspect'] += 1
+ fails[mytype + '.suspect'].append(
+ relative_path + ": '%s'" % atom)
+
+ if atom.operator == "~" and \
+ portage.versions.catpkgsplit(atom.cpv)[3] != "r0":
+ stats[mytype + '.badtilde'] += 1
+ fails[mytype + '.badtilde'].append(
+ (relative_path + ": %s uses the ~ operator"
+ " with a non-zero revision:" + \
+ " '%s'") % (mytype, atom))
+
+ type_list.extend([mytype] * (len(badsyntax) - len(type_list)))
+
+ for m,b in zip(type_list, badsyntax):
+ stats[m+".syntax"] += 1
+ fails[m+".syntax"].append(catpkg+".ebuild "+m+": "+b)
+
+ badlicsyntax = len([z for z in type_list if z == "LICENSE"])
+ badprovsyntax = len([z for z in type_list if z == "PROVIDE"])
+ baddepsyntax = len(type_list) != badlicsyntax + badprovsyntax
+ badlicsyntax = badlicsyntax > 0
+ badprovsyntax = badprovsyntax > 0
+
+ # uselist checks - global
+ myuse = []
+ default_use = []
+ for myflag in myaux["IUSE"].split():
+ flag_name = myflag.lstrip("+-")
+ used_useflags.add(flag_name)
+ if myflag != flag_name:
+ default_use.append(myflag)
+ if flag_name not in uselist:
+ myuse.append(flag_name)
+
+ # uselist checks - metadata
+ for mypos in range(len(myuse)-1,-1,-1):
+ if myuse[mypos] and (myuse[mypos] in muselist):
+ del myuse[mypos]
+
+ if default_use and not eapi_has_iuse_defaults(eapi):
+ for myflag in default_use:
+ stats['EAPI.incompatible'] += 1
+ fails['EAPI.incompatible'].append(
+ (relative_path + ": IUSE defaults" + \
+ " not supported with EAPI='%s':" + \
+ " '%s'") % (eapi, myflag))
+
+ for mypos in range(len(myuse)):
+ stats["IUSE.invalid"]=stats["IUSE.invalid"]+1
+ fails["IUSE.invalid"].append(x+"/"+y+".ebuild: %s" % myuse[mypos])
+
+ # license checks
+ if not badlicsyntax:
+ # Parse the LICENSE variable, remove USE conditions and
+ # flatten it.
+ licenses = portage.dep.use_reduce(myaux["LICENSE"], matchall=1, flat=True)
+ # Check each entry to ensure that it exists in PORTDIR's
+ # license directory.
+ for lic in licenses:
+ # Need to check for "||" manually as no portage
+ # function will remove it without removing values.
+ if lic not in liclist and lic != "||":
+ stats["LICENSE.invalid"]=stats["LICENSE.invalid"]+1
+ fails["LICENSE.invalid"].append(x+"/"+y+".ebuild: %s" % lic)
+
+ #keyword checks
+ myuse = myaux["KEYWORDS"].split()
+ for mykey in myuse:
+ myskey=mykey[:]
+ if myskey[0]=="-":
+ myskey=myskey[1:]
+ if myskey[0]=="~":
+ myskey=myskey[1:]
+ if mykey!="-*":
+ if myskey not in kwlist:
+ stats["KEYWORDS.invalid"] += 1
+ fails["KEYWORDS.invalid"].append(x+"/"+y+".ebuild: %s" % mykey)
+ elif myskey not in profiles:
+ stats["KEYWORDS.invalid"] += 1
+ fails["KEYWORDS.invalid"].append(x+"/"+y+".ebuild: %s (profile invalid)" % mykey)
+
+ #restrict checks
+ myrestrict = None
+ try:
+ myrestrict = portage.dep.use_reduce(myaux["RESTRICT"], matchall=1, flat=True)
+ except portage.exception.InvalidDependString as e:
+ stats["RESTRICT.syntax"] = stats["RESTRICT.syntax"] + 1
+ fails["RESTRICT.syntax"].append(
+ "%s: RESTRICT: %s" % (relative_path, e))
+ del e
+ if myrestrict:
+ myrestrict = set(myrestrict)
+ mybadrestrict = myrestrict.difference(valid_restrict)
+ if mybadrestrict:
+ stats["RESTRICT.invalid"] += len(mybadrestrict)
+ for mybad in mybadrestrict:
+ fails["RESTRICT.invalid"].append(x+"/"+y+".ebuild: %s" % mybad)
+ #REQUIRED_USE check
+ required_use = myaux["REQUIRED_USE"]
+ if required_use:
+ if not eapi_has_required_use(eapi):
+ stats['EAPI.incompatible'] += 1
+ fails['EAPI.incompatible'].append(
+ relative_path + ": REQUIRED_USE" + \
+ " not supported with EAPI='%s'" % (eapi,))
+ try:
+ portage.dep.check_required_use(required_use, (),
+ pkg.iuse.is_valid_flag)
+ except portage.exception.InvalidDependString as e:
+ stats["REQUIRED_USE.syntax"] = stats["REQUIRED_USE.syntax"] + 1
+ fails["REQUIRED_USE.syntax"].append(
+ "%s: REQUIRED_USE: %s" % (relative_path, e))
+ del e
+
+ # Syntax Checks
+ relative_path = os.path.join(x, y + ".ebuild")
+ full_path = os.path.join(repodir, relative_path)
+ if not vcs_preserves_mtime:
+ if ebuild_path not in new_ebuilds and \
+ ebuild_path not in modified_ebuilds:
+ pkg.mtime = None
+ try:
+ # All ebuilds should have utf_8 encoding.
+ f = io.open(_unicode_encode(full_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'])
+ try:
+ for check_name, e in run_checks(f, pkg):
+ stats[check_name] += 1
+ fails[check_name].append(relative_path + ': %s' % e)
+ finally:
+ f.close()
+ except UnicodeDecodeError:
+ # A file.UTF8 failure will have already been recorded above.
+ pass
+
+ if options.force:
+ # The dep_check() calls are the most expensive QA test. If --force
+ # is enabled, there's no point in wasting time on these since the
+ # user is intent on forcing the commit anyway.
+ continue
+
+ for keyword,arch,groups in arches:
+
+ if arch not in profiles:
+ # A missing profile will create an error further down
+ # during the KEYWORDS verification.
+ continue
+
+ for prof in profiles[arch]:
+
+ if prof.status not in ("stable", "dev") or \
+ prof.status == "dev" and not options.include_dev:
+ continue
+
+ dep_settings = arch_caches.get(prof.sub_path)
+ if dep_settings is None:
+ dep_settings = portage.config(
+ config_profile_path=prof.abs_path,
+ config_incrementals=repoman_incrementals,
+ local_config=False,
+ _unmatched_removal=options.unmatched_removal,
+ env=env)
+ if options.without_mask:
+ dep_settings._mask_manager = \
+ copy.deepcopy(dep_settings._mask_manager)
+ dep_settings._mask_manager._pmaskdict.clear()
+ arch_caches[prof.sub_path] = dep_settings
+
+ xmatch_cache_key = (prof.sub_path, tuple(groups))
+ xcache = arch_xmatch_caches.get(xmatch_cache_key)
+ if xcache is None:
+ portdb.melt()
+ portdb.freeze()
+ xcache = portdb.xcache
+ xcache.update(shared_xmatch_caches)
+ arch_xmatch_caches[xmatch_cache_key] = xcache
+
+ trees["/"]["porttree"].settings = dep_settings
+ portdb.settings = dep_settings
+ portdb.xcache = xcache
+ # for package.use.mask support inside dep_check
+ dep_settings.setcpv(pkg)
+ dep_settings["ACCEPT_KEYWORDS"] = " ".join(groups)
+ # just in case, prevent config.reset() from nuking these.
+ dep_settings.backup_changes("ACCEPT_KEYWORDS")
+
+ if not baddepsyntax:
+ ismasked = not ebuild_archs or \
+ pkg.cpv not in portdb.xmatch("list-visible", pkg.cp)
+ if ismasked:
+ if not have_pmasked:
+ have_pmasked = bool(dep_settings._getMaskAtom(
+ pkg.cpv, pkg.metadata))
+ if options.ignore_masked:
+ continue
+ #we are testing deps for a masked package; give it some lee-way
+ suffix="masked"
+ matchmode = "minimum-all"
+ else:
+ suffix=""
+ matchmode = "minimum-visible"
+
+ if not have_dev_keywords:
+ have_dev_keywords = \
+ bool(dev_keywords.intersection(keywords))
+
+ if prof.status == "dev":
+ suffix=suffix+"indev"
+
+ for mytype,mypos in [["DEPEND",len(missingvars)],["RDEPEND",len(missingvars)+1],["PDEPEND",len(missingvars)+2]]:
+
+ mykey=mytype+".bad"+suffix
+ myvalue = myaux[mytype]
+ if not myvalue:
+ continue
+
+ success, atoms = portage.dep_check(myvalue, portdb,
+ dep_settings, use="all", mode=matchmode,
+ trees=trees)
+
+ if success:
+ if atoms:
+ for atom in atoms:
+ if not atom.blocker:
+ # Don't bother with dependency.unknown
+ # for cases in which *DEPEND.bad is
+ # triggered.
+ unknown_pkgs.pop(atom.cp, None)
+
+ if not prof.sub_path:
+ # old-style virtuals currently aren't
+ # resolvable with empty profile, since
+ # 'virtuals' mappings are unavailable
+ # (it would be expensive to search
+ # for PROVIDE in all ebuilds)
+ atoms = [atom for atom in atoms if not \
+ (atom.cp.startswith('virtual/') and \
+ not portdb.cp_list(atom.cp))]
+
+ #we have some unsolvable deps
+ #remove ! deps, which always show up as unsatisfiable
+ atoms = [str(atom.unevaluated_atom) \
+ for atom in atoms if not atom.blocker]
+
+ #if we emptied out our list, continue:
+ if not atoms:
+ continue
+ stats[mykey]=stats[mykey]+1
+ fails[mykey].append("%s: %s(%s) %s" % \
+ (relative_path, keyword,
+ prof, repr(atoms)))
+ else:
+ stats[mykey]=stats[mykey]+1
+ fails[mykey].append("%s: %s(%s) %s" % \
+ (relative_path, keyword,
+ prof, repr(atoms)))
+
+ if not baddepsyntax and unknown_pkgs:
+ all_unknown = set()
+ all_unknown.update(*unknown_pkgs.values())
+ type_map = {}
+ for mytype, atom in all_unknown:
+ type_map.setdefault(mytype, set()).add(atom)
+ for mytype, atoms in type_map.items():
+ stats["dependency.unknown"] += 1
+ fails["dependency.unknown"].append("%s: %s: %s" %
+ (relative_path, mytype, ", ".join(sorted(atoms))))
+
+ # Check for 'all unstable' or 'all masked' -- ACCEPT_KEYWORDS is stripped
+ # XXX -- Needs to be implemented in dep code. Can't determine ~arch nicely.
+ #if not portage.portdb.xmatch("bestmatch-visible",x):
+ # stats["ebuild.nostable"]+=1
+ # fails["ebuild.nostable"].append(x)
+ if ebuildlist and allmasked and repolevel == 3:
+ stats["ebuild.allmasked"]+=1
+ fails["ebuild.allmasked"].append(x)
+
+ # check if there are unused local USE-descriptions in metadata.xml
+ # (unless there are any invalids, to avoid noise)
+ if allvalid:
+ for myflag in muselist.difference(used_useflags):
+ stats["metadata.warning"] += 1
+ fails["metadata.warning"].append(
+ "%s/metadata.xml: unused local USE-description: '%s'" % \
+ (x, myflag))
+
+if options.mode == "manifest":
+ sys.exit(dofail)
+
+#dofail will be set to 1 if we have failed in at least one non-warning category
+dofail=0
+#dowarn will be set to 1 if we tripped any warnings
+dowarn=0
+#dofull will be set if we should print a "repoman full" informational message
+dofull = options.mode != 'full'
+
+for x in qacats:
+ if not stats[x]:
+ continue
+ dowarn = 1
+ if x not in qawarnings:
+ dofail = 1
+
+if dofail or \
+ (dowarn and not (options.quiet or options.mode == "scan")):
+ dofull = 0
+
+# Save QA output so that it can be conveniently displayed
+# in $EDITOR while the user creates a commit message.
+# Otherwise, the user would not be able to see this output
+# once the editor has taken over the screen.
+qa_output = io.StringIO()
+style_file = ConsoleStyleFile(sys.stdout)
+if options.mode == 'commit' and \
+ (not commitmessage or not commitmessage.strip()):
+ style_file.write_listener = qa_output
+console_writer = StyleWriter(file=style_file, maxcol=9999)
+console_writer.style_listener = style_file.new_styles
+
+f = formatter.AbstractFormatter(console_writer)
+
+utilities.format_qa_output(f, stats, fails, dofull, dofail, options, qawarnings)
+
+style_file.flush()
+del console_writer, f, style_file
+qa_output = qa_output.getvalue()
+qa_output = qa_output.splitlines(True)
+
+def grouplist(mylist,seperator="/"):
+ """(list,seperator="/") -- Takes a list of elements; groups them into
+ same initial element categories. Returns a dict of {base:[sublist]}
+ From: ["blah/foo","spork/spatula","blah/weee/splat"]
+ To: {"blah":["foo","weee/splat"], "spork":["spatula"]}"""
+ mygroups={}
+ for x in mylist:
+ xs=x.split(seperator)
+ if xs[0]==".":
+ xs=xs[1:]
+ if xs[0] not in mygroups:
+ mygroups[xs[0]]=[seperator.join(xs[1:])]
+ else:
+ mygroups[xs[0]]+=[seperator.join(xs[1:])]
+ return mygroups
+
+suggest_ignore_masked = False
+suggest_include_dev = False
+
+if have_pmasked and not (options.without_mask or options.ignore_masked):
+ suggest_ignore_masked = True
+if have_dev_keywords and not options.include_dev:
+ suggest_include_dev = True
+
+if suggest_ignore_masked or suggest_include_dev:
+ print()
+ if suggest_ignore_masked:
+ print(bold("Note: use --without-mask to check " + \
+ "KEYWORDS on dependencies of masked packages"))
+
+ if suggest_include_dev:
+ print(bold("Note: use --include-dev (-d) to check " + \
+ "dependencies for 'dev' profiles"))
+ print()
+
+if options.mode != 'commit':
+ if dofull:
+ print(bold("Note: type \"repoman full\" for a complete listing."))
+ if dowarn and not dofail:
+ print(green("RepoMan sez:"),"\"You're only giving me a partial QA payment?\n I'll take it this time, but I'm not happy.\"")
+ elif not dofail:
+ print(green("RepoMan sez:"),"\"If everyone were like you, I'd be out of business!\"")
+ elif dofail:
+ print(bad("Please fix these important QA issues first."))
+ print(green("RepoMan sez:"),"\"Make your QA payment on time and you'll never see the likes of me.\"\n")
+ sys.exit(1)
+else:
+ if dofail and can_force and options.force and not options.pretend:
+ print(green("RepoMan sez:") + \
+ " \"You want to commit even with these QA issues?\n" + \
+ " I'll take it this time, but I'm not happy.\"\n")
+ elif dofail:
+ if options.force and not can_force:
+ print(bad("The --force option has been disabled due to extraordinary issues."))
+ print(bad("Please fix these important QA issues first."))
+ print(green("RepoMan sez:"),"\"Make your QA payment on time and you'll never see the likes of me.\"\n")
+ sys.exit(1)
+
+ if options.pretend:
+ print(green("RepoMan sez:"), "\"So, you want to play it safe. Good call.\"\n")
+
+ myunadded = []
+ if vcs == "cvs":
+ try:
+ myvcstree=portage.cvstree.getentries("./",recursive=1)
+ myunadded=portage.cvstree.findunadded(myvcstree,recursive=1,basedir="./")
+ except SystemExit as e:
+ raise # TODO propagate this
+ except:
+ err("Error retrieving CVS tree; exiting.")
+ if vcs == "svn":
+ try:
+ svnstatus=os.popen("svn status --no-ignore").readlines()
+ myunadded = [ "./"+elem.rstrip().split()[1] for elem in svnstatus if elem.startswith("?") or elem.startswith("I") ]
+ except SystemExit as e:
+ raise # TODO propagate this
+ except:
+ err("Error retrieving SVN info; exiting.")
+ if vcs == "git":
+ # get list of files not under version control or missing
+ myf = os.popen("git ls-files --others")
+ myunadded = [ "./" + elem[:-1] for elem in myf ]
+ myf.close()
+ if vcs == "bzr":
+ try:
+ bzrstatus=os.popen("bzr status -S .").readlines()
+ myunadded = [ "./"+elem.rstrip().split()[1].split('/')[-1:][0] for elem in bzrstatus if elem.startswith("?") or elem[0:2] == " D" ]
+ except SystemExit as e:
+ raise # TODO propagate this
+ except:
+ err("Error retrieving bzr info; exiting.")
+ if vcs == "hg":
+ myunadded = os.popen("hg status --no-status --unknown .").readlines()
+ myunadded = ["./" + elem.rstrip() for elem in myunadded]
+
+ # Mercurial doesn't handle manually deleted files as removed from
+ # the repository, so the user need to remove them before commit,
+ # using "hg remove [FILES]"
+ mydeleted = os.popen("hg status --no-status --deleted .").readlines()
+ mydeleted = ["./" + elem.rstrip() for elem in mydeleted]
+
+
+ myautoadd=[]
+ if myunadded:
+ for x in range(len(myunadded)-1,-1,-1):
+ xs=myunadded[x].split("/")
+ if xs[-1]=="files":
+ print("!!! files dir is not added! Please correct this.")
+ sys.exit(-1)
+ elif xs[-1]=="Manifest":
+ # It's a manifest... auto add
+ myautoadd+=[myunadded[x]]
+ del myunadded[x]
+
+ if myautoadd:
+ print(">>> Auto-Adding missing Manifest(s)...")
+ if options.pretend:
+ if vcs == "cvs":
+ print("(cvs add "+" ".join(myautoadd)+")")
+ elif vcs == "svn":
+ print("(svn add "+" ".join(myautoadd)+")")
+ elif vcs == "git":
+ print("(git add "+" ".join(myautoadd)+")")
+ elif vcs == "bzr":
+ print("(bzr add "+" ".join(myautoadd)+")")
+ elif vcs == "hg":
+ print("(hg add "+" ".join(myautoadd)+")")
+ retval=0
+ else:
+ if vcs == "cvs":
+ retval=os.system("cvs add "+" ".join(myautoadd))
+ elif vcs == "svn":
+ retval=os.system("svn add "+" ".join(myautoadd))
+ elif vcs == "git":
+ retval=os.system("git add "+" ".join(myautoadd))
+ elif vcs == "bzr":
+ retval=os.system("bzr add "+" ".join(myautoadd))
+ elif vcs == "hg":
+ retval=os.system("hg add "+" ".join(myautoadd))
+ if retval:
+ writemsg_level("!!! Exiting on %s (shell) error code: %s\n" % \
+ (vcs, retval), level=logging.ERROR, noiselevel=-1)
+ sys.exit(retval)
+
+ if myunadded:
+ print(red("!!! The following files are in your local tree but are not added to the master"))
+ print(red("!!! tree. Please remove them from the local tree or add them to the master tree."))
+ for x in myunadded:
+ print(" ",x)
+ print()
+ print()
+ sys.exit(1)
+
+ if vcs == "hg" and mydeleted:
+ print(red("!!! The following files are removed manually from your local tree but are not"))
+ print(red("!!! removed from the repository. Please remove them, using \"hg remove [FILES]\"."))
+ for x in mydeleted:
+ print(" ",x)
+ print()
+ print()
+ sys.exit(1)
+
+ if vcs == "cvs":
+ mycvstree = cvstree.getentries("./", recursive=1)
+ mychanged = cvstree.findchanged(mycvstree, recursive=1, basedir="./")
+ mynew = cvstree.findnew(mycvstree, recursive=1, basedir="./")
+ myremoved=portage.cvstree.findremoved(mycvstree,recursive=1,basedir="./")
+ bin_blob_pattern = re.compile("^-kb$")
+ no_expansion = set(portage.cvstree.findoption(mycvstree, bin_blob_pattern,
+ recursive=1, basedir="./"))
+
+
+ if vcs == "svn":
+ svnstatus = os.popen("svn status").readlines()
+ mychanged = [ "./" + elem.split()[-1:][0] for elem in svnstatus if (elem[:1] in "MR" or elem[1:2] in "M")]
+ mynew = [ "./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("A")]
+ myremoved = [ "./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("D")]
+
+ # Subversion expands keywords specified in svn:keywords properties.
+ props = os.popen("svn propget -R svn:keywords").readlines()
+ expansion = dict(("./" + prop.split(" - ")[0], prop.split(" - ")[1].split()) \
+ for prop in props if " - " in prop)
+
+ elif vcs == "git":
+ mychanged = os.popen("git diff-index --name-only --relative --diff-filter=M HEAD").readlines()
+ mychanged = ["./" + elem[:-1] for elem in mychanged]
+
+ mynew = os.popen("git diff-index --name-only --relative --diff-filter=A HEAD").readlines()
+ mynew = ["./" + elem[:-1] for elem in mynew]
+
+ myremoved = os.popen("git diff-index --name-only --relative --diff-filter=D HEAD").readlines()
+ myremoved = ["./" + elem[:-1] for elem in myremoved]
+
+ if vcs == "bzr":
+ bzrstatus = os.popen("bzr status -S .").readlines()
+ mychanged = [ "./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and elem[1:2] == "M" ]
+ mynew = [ "./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and ( elem[1:2] in "NK" or elem[0:1] == "R" ) ]
+ myremoved = [ "./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem.startswith("-") ]
+ myremoved = [ "./" + elem.split()[-3:-2][0].split('/')[-1:][0] for elem in bzrstatus if elem and ( elem[1:2] == "K" or elem[0:1] == "R" ) ]
+ # Bazaar expands nothing.
+
+ if vcs == "hg":
+ mychanged = os.popen("hg status --no-status --modified .").readlines()
+ mychanged = ["./" + elem.rstrip() for elem in mychanged]
+ mynew = os.popen("hg status --no-status --added .").readlines()
+ mynew = ["./" + elem.rstrip() for elem in mynew]
+ myremoved = os.popen("hg status --no-status --removed .").readlines()
+ myremoved = ["./" + elem.rstrip() for elem in myremoved]
+
+ if vcs:
+ if not (mychanged or mynew or myremoved or (vcs == "hg" and mydeleted)):
+ print(green("RepoMan sez:"), "\"Doing nothing is not always good for QA.\"")
+ print()
+ print("(Didn't find any changed files...)")
+ print()
+ sys.exit(1)
+
+ # Manifests need to be regenerated after all other commits, so don't commit
+ # them now even if they have changed.
+ mymanifests = set()
+ myupdates = set()
+ for f in mychanged + mynew:
+ if "Manifest" == os.path.basename(f):
+ mymanifests.add(f)
+ else:
+ myupdates.add(f)
+ if vcs in ('git', 'hg'):
+ myupdates.difference_update(myremoved)
+ myupdates = list(myupdates)
+ mymanifests = list(mymanifests)
+ myheaders = []
+ mydirty = []
+
+ print("* %s files being committed..." % green(str(len(myupdates))), end=' ')
+ if vcs not in ('cvs', 'svn'):
+ # With git, bzr and hg, there's never any keyword expansion, so
+ # there's no need to regenerate manifests and all files will be
+ # committed in one big commit at the end.
+ print()
+ else:
+ if vcs == 'cvs':
+ headerstring = "'\$(Header|Id).*\$'"
+ elif vcs == "svn":
+ svn_keywords = dict((k.lower(), k) for k in [
+ "Rev",
+ "Revision",
+ "LastChangedRevision",
+ "Date",
+ "LastChangedDate",
+ "Author",
+ "LastChangedBy",
+ "URL",
+ "HeadURL",
+ "Id",
+ "Header",
+ ])
+
+ for myfile in myupdates:
+
+ # for CVS, no_expansion contains files that are excluded from expansion
+ if vcs == "cvs":
+ if myfile in no_expansion:
+ continue
+
+ # for SVN, expansion contains files that are included in expansion
+ elif vcs == "svn":
+ if myfile not in expansion:
+ continue
+
+ # Subversion keywords are case-insensitive in svn:keywords properties, but case-sensitive in contents of files.
+ enabled_keywords = []
+ for k in expansion[myfile]:
+ keyword = svn_keywords.get(k.lower())
+ if keyword is not None:
+ enabled_keywords.append(keyword)
+
+ headerstring = "'\$(%s).*\$'" % "|".join(enabled_keywords)
+
+ myout = subprocess_getstatusoutput("egrep -q "+headerstring+" "+myfile)
+ if myout[0] == 0:
+ myheaders.append(myfile)
+
+ print("%s have headers that will change." % green(str(len(myheaders))))
+ print("* Files with headers will cause the manifests to be changed and committed separately.")
+
+ logging.info("myupdates: %s", myupdates)
+ logging.info("myheaders: %s", myheaders)
+
+ commitmessage = options.commitmsg
+ if options.commitmsgfile:
+ try:
+ f = io.open(_unicode_encode(options.commitmsgfile,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'], errors='replace')
+ commitmessage = f.read()
+ f.close()
+ del f
+ except (IOError, OSError) as e:
+ if e.errno == errno.ENOENT:
+ portage.writemsg("!!! File Not Found: --commitmsgfile='%s'\n" % options.commitmsgfile)
+ else:
+ raise
+ # We've read the content so the file is no longer needed.
+ commitmessagefile = None
+ if not commitmessage or not commitmessage.strip():
+ try:
+ editor = os.environ.get("EDITOR")
+ if editor and utilities.editor_is_executable(editor):
+ commitmessage = utilities.get_commit_message_with_editor(
+ editor, message=qa_output)
+ else:
+ commitmessage = utilities.get_commit_message_with_stdin()
+ except KeyboardInterrupt:
+ exithandler()
+ if not commitmessage or not commitmessage.strip():
+ print("* no commit message? aborting commit.")
+ sys.exit(1)
+ commitmessage = commitmessage.rstrip()
+ portage_version = getattr(portage, "VERSION", None)
+ if portage_version is None:
+ sys.stderr.write("Failed to insert portage version in message!\n")
+ sys.stderr.flush()
+ portage_version = "Unknown"
+ unameout = platform.system() + " "
+ if platform.system() in ["Darwin", "SunOS"]:
+ unameout += platform.processor()
+ else:
+ unameout += platform.machine()
+ commitmessage += "\n\n(Portage version: %s/%s/%s" % \
+ (portage_version, vcs, unameout)
+ if options.force:
+ commitmessage += ", RepoMan options: --force"
+ commitmessage += ")"
+
+ if options.ask and userquery('Commit changes?', True) != 'Yes':
+ print("* aborting commit.")
+ sys.exit(1)
+
+ if vcs in ('cvs', 'svn') and (myupdates or myremoved):
+ myfiles = myupdates + myremoved
+ if not myheaders and "sign" not in repoman_settings.features:
+ myfiles += mymanifests
+ fd, commitmessagefile = tempfile.mkstemp(".repoman.msg")
+ mymsg = os.fdopen(fd, "wb")
+ mymsg.write(_unicode_encode(commitmessage))
+ mymsg.close()
+
+ print()
+ print(green("Using commit message:"))
+ print(green("------------------------------------------------------------------------------"))
+ print(commitmessage)
+ print(green("------------------------------------------------------------------------------"))
+ print()
+
+ # Having a leading ./ prefix on file paths can trigger a bug in
+ # the cvs server when committing files to multiple directories,
+ # so strip the prefix.
+ myfiles = [f.lstrip("./") for f in myfiles]
+
+ commit_cmd = [vcs]
+ commit_cmd.extend(vcs_global_opts)
+ commit_cmd.append("commit")
+ commit_cmd.extend(vcs_local_opts)
+ commit_cmd.extend(["-F", commitmessagefile])
+ commit_cmd.extend(myfiles)
+
+ try:
+ if options.pretend:
+ print("(%s)" % (" ".join(commit_cmd),))
+ else:
+ retval = spawn(commit_cmd, env=os.environ)
+ if retval != os.EX_OK:
+ writemsg_level(("!!! Exiting on %s (shell) " + \
+ "error code: %s\n") % (vcs, retval),
+ level=logging.ERROR, noiselevel=-1)
+ sys.exit(retval)
+ finally:
+ try:
+ os.unlink(commitmessagefile)
+ except OSError:
+ pass
+
+ # Setup the GPG commands
+ def gpgsign(filename):
+ gpgcmd = repoman_settings.get("PORTAGE_GPG_SIGNING_COMMAND")
+ if gpgcmd is None:
+ raise MissingParameter("PORTAGE_GPG_SIGNING_COMMAND is unset!" + \
+ " Is make.globals missing?")
+ if "${PORTAGE_GPG_KEY}" in gpgcmd and \
+ "PORTAGE_GPG_KEY" not in repoman_settings:
+ raise MissingParameter("PORTAGE_GPG_KEY is unset!")
+ if "${PORTAGE_GPG_DIR}" in gpgcmd:
+ if "PORTAGE_GPG_DIR" not in repoman_settings:
+ repoman_settings["PORTAGE_GPG_DIR"] = \
+ os.path.expanduser("~/.gnupg")
+ logging.info("Automatically setting PORTAGE_GPG_DIR to '%s'" \
+ % repoman_settings["PORTAGE_GPG_DIR"])
+ else:
+ repoman_settings["PORTAGE_GPG_DIR"] = \
+ os.path.expanduser(repoman_settings["PORTAGE_GPG_DIR"])
+ if not os.access(repoman_settings["PORTAGE_GPG_DIR"], os.X_OK):
+ raise portage.exception.InvalidLocation(
+ "Unable to access directory: PORTAGE_GPG_DIR='%s'" % \
+ repoman_settings["PORTAGE_GPG_DIR"])
+ gpgvars = {"FILE": filename}
+ for k in ("PORTAGE_GPG_DIR", "PORTAGE_GPG_KEY"):
+ v = repoman_settings.get(k)
+ if v is not None:
+ gpgvars[k] = v
+ gpgcmd = portage.util.varexpand(gpgcmd, mydict=gpgvars)
+ if options.pretend:
+ print("("+gpgcmd+")")
+ else:
+ rValue = os.system(gpgcmd)
+ if rValue == os.EX_OK:
+ os.rename(filename+".asc", filename)
+ else:
+ raise portage.exception.PortageException("!!! gpg exited with '" + str(rValue) + "' status")
+
+ # When files are removed and re-added, the cvs server will put /Attic/
+ # inside the $Header path. This code detects the problem and corrects it
+ # so that the Manifest will generate correctly. See bug #169500.
+ # Use binary mode in order to avoid potential character encoding issues.
+ cvs_header_re = re.compile(br'^#\s*\$Header.*\$$')
+ attic_str = b'/Attic/'
+ attic_replace = b'/'
+ for x in myheaders:
+ f = open(_unicode_encode(x,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='rb')
+ mylines = f.readlines()
+ f.close()
+ modified = False
+ for i, line in enumerate(mylines):
+ if cvs_header_re.match(line) is not None and \
+ attic_str in line:
+ mylines[i] = line.replace(attic_str, attic_replace)
+ modified = True
+ if modified:
+ portage.util.write_atomic(x, b''.join(mylines),
+ mode='wb')
+
+ manifest_commit_required = True
+ if vcs in ('cvs', 'svn') and (myupdates or myremoved):
+ myfiles = myupdates + myremoved
+ for x in range(len(myfiles)-1, -1, -1):
+ if myfiles[x].count("/") < 4-repolevel:
+ del myfiles[x]
+ mydone=[]
+ if repolevel==3: # In a package dir
+ repoman_settings["O"] = startdir
+ digestgen(mysettings=repoman_settings, myportdb=portdb)
+ elif repolevel==2: # In a category dir
+ for x in myfiles:
+ xs=x.split("/")
+ if len(xs) < 4-repolevel:
+ continue
+ if xs[0]==".":
+ xs=xs[1:]
+ if xs[0] in mydone:
+ continue
+ mydone.append(xs[0])
+ repoman_settings["O"] = os.path.join(startdir, xs[0])
+ if not os.path.isdir(repoman_settings["O"]):
+ continue
+ digestgen(mysettings=repoman_settings, myportdb=portdb)
+ elif repolevel==1: # repo-cvsroot
+ print(green("RepoMan sez:"), "\"You're rather crazy... doing the entire repository.\"\n")
+ for x in myfiles:
+ xs=x.split("/")
+ if len(xs) < 4-repolevel:
+ continue
+ if xs[0]==".":
+ xs=xs[1:]
+ if "/".join(xs[:2]) in mydone:
+ continue
+ mydone.append("/".join(xs[:2]))
+ repoman_settings["O"] = os.path.join(startdir, xs[0], xs[1])
+ if not os.path.isdir(repoman_settings["O"]):
+ continue
+ digestgen(mysettings=repoman_settings, myportdb=portdb)
+ else:
+ print(red("I'm confused... I don't know where I am!"))
+ sys.exit(1)
+
+ # Force an unsigned commit when more than one Manifest needs to be signed.
+ if repolevel < 3 and "sign" in repoman_settings.features:
+
+ fd, commitmessagefile = tempfile.mkstemp(".repoman.msg")
+ mymsg = os.fdopen(fd, "wb")
+ mymsg.write(_unicode_encode(commitmessage))
+ mymsg.write(b"\n (Unsigned Manifest commit)")
+ mymsg.close()
+
+ commit_cmd = [vcs]
+ commit_cmd.extend(vcs_global_opts)
+ commit_cmd.append("commit")
+ commit_cmd.extend(vcs_local_opts)
+ commit_cmd.extend(["-F", commitmessagefile])
+ commit_cmd.extend(f.lstrip("./") for f in mymanifests)
+
+ try:
+ if options.pretend:
+ print("(%s)" % (" ".join(commit_cmd),))
+ else:
+ retval = spawn(commit_cmd, env=os.environ)
+ if retval:
+ writemsg_level(("!!! Exiting on %s (shell) " + \
+ "error code: %s\n") % (vcs, retval),
+ level=logging.ERROR, noiselevel=-1)
+ sys.exit(retval)
+ finally:
+ try:
+ os.unlink(commitmessagefile)
+ except OSError:
+ pass
+ manifest_commit_required = False
+
+ signed = False
+ if "sign" in repoman_settings.features:
+ signed = True
+ myfiles = myupdates + myremoved + mymanifests
+ try:
+ if repolevel==3: # In a package dir
+ repoman_settings["O"] = "."
+ gpgsign(os.path.join(repoman_settings["O"], "Manifest"))
+ elif repolevel==2: # In a category dir
+ mydone=[]
+ for x in myfiles:
+ xs=x.split("/")
+ if len(xs) < 4-repolevel:
+ continue
+ if xs[0]==".":
+ xs=xs[1:]
+ if xs[0] in mydone:
+ continue
+ mydone.append(xs[0])
+ repoman_settings["O"] = os.path.join(".", xs[0])
+ if not os.path.isdir(repoman_settings["O"]):
+ continue
+ gpgsign(os.path.join(repoman_settings["O"], "Manifest"))
+ elif repolevel==1: # repo-cvsroot
+ print(green("RepoMan sez:"), "\"You're rather crazy... doing the entire repository.\"\n")
+ mydone=[]
+ for x in myfiles:
+ xs=x.split("/")
+ if len(xs) < 4-repolevel:
+ continue
+ if xs[0]==".":
+ xs=xs[1:]
+ if "/".join(xs[:2]) in mydone:
+ continue
+ mydone.append("/".join(xs[:2]))
+ repoman_settings["O"] = os.path.join(".", xs[0], xs[1])
+ if not os.path.isdir(repoman_settings["O"]):
+ continue
+ gpgsign(os.path.join(repoman_settings["O"], "Manifest"))
+ except portage.exception.PortageException as e:
+ portage.writemsg("!!! %s\n" % str(e))
+ portage.writemsg("!!! Disabled FEATURES='sign'\n")
+ signed = False
+
+ if vcs == 'git':
+ # It's not safe to use the git commit -a option since there might
+ # be some modified files elsewhere in the working tree that the
+ # user doesn't want to commit. Therefore, call git update-index
+ # in order to ensure that the index is updated with the latest
+ # versions of all new and modified files in the relevant portion
+ # of the working tree.
+ myfiles = mymanifests + myupdates
+ myfiles.sort()
+ update_index_cmd = ["git", "update-index"]
+ update_index_cmd.extend(f.lstrip("./") for f in myfiles)
+ if options.pretend:
+ print("(%s)" % (" ".join(update_index_cmd),))
+ else:
+ retval = spawn(update_index_cmd, env=os.environ)
+ if retval != os.EX_OK:
+ writemsg_level(("!!! Exiting on %s (shell) " + \
+ "error code: %s\n") % (vcs, retval),
+ level=logging.ERROR, noiselevel=-1)
+ sys.exit(retval)
+
+ if vcs in ['git', 'bzr', 'hg'] or manifest_commit_required or signed:
+
+ myfiles = mymanifests[:]
+ if vcs in ['git', 'bzr', 'hg']:
+ myfiles += myupdates
+ myfiles += myremoved
+ myfiles.sort()
+
+ fd, commitmessagefile = tempfile.mkstemp(".repoman.msg")
+ mymsg = os.fdopen(fd, "wb")
+ # strip the closing parenthesis
+ mymsg.write(_unicode_encode(commitmessage[:-1]))
+ if signed:
+ mymsg.write(_unicode_encode(
+ ", signed Manifest commit with key %s)" % \
+ repoman_settings["PORTAGE_GPG_KEY"]))
+ else:
+ mymsg.write(b", unsigned Manifest commit)")
+ mymsg.close()
+
+ commit_cmd = []
+ if options.pretend and vcs is None:
+ # substitute a bogus value for pretend output
+ commit_cmd.append("cvs")
+ else:
+ commit_cmd.append(vcs)
+ commit_cmd.extend(vcs_global_opts)
+ commit_cmd.append("commit")
+ commit_cmd.extend(vcs_local_opts)
+ if vcs == "hg":
+ commit_cmd.extend(["--logfile", commitmessagefile])
+ commit_cmd.extend(myfiles)
+ else:
+ commit_cmd.extend(["-F", commitmessagefile])
+ commit_cmd.extend(f.lstrip("./") for f in myfiles)
+
+ try:
+ if options.pretend:
+ print("(%s)" % (" ".join(commit_cmd),))
+ else:
+ retval = spawn(commit_cmd, env=os.environ)
+ if retval != os.EX_OK:
+ writemsg_level(("!!! Exiting on %s (shell) " + \
+ "error code: %s\n") % (vcs, retval),
+ level=logging.ERROR, noiselevel=-1)
+ sys.exit(retval)
+ finally:
+ try:
+ os.unlink(commitmessagefile)
+ except OSError:
+ pass
+
+ print()
+ if vcs:
+ print("Commit complete.")
+ else:
+ print("repoman was too scared by not seeing any familiar version control file that he forgot to commit anything")
+ print(green("RepoMan sez:"), "\"If everyone were like you, I'd be out of business!\"\n")
+sys.exit(0)
+
diff --git a/portage_with_autodep/bin/xpak-helper.py b/portage_with_autodep/bin/xpak-helper.py
new file mode 100755
index 0000000..4766d99
--- /dev/null
+++ b/portage_with_autodep/bin/xpak-helper.py
@@ -0,0 +1,68 @@
+#!/usr/bin/python
+# Copyright 2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import optparse
+import sys
+import portage
+from portage import os
+
+def command_recompose(args):
+
+ usage = "usage: recompose <binpkg_path> <metadata_dir>\n"
+
+ if len(args) != 2:
+ sys.stderr.write(usage)
+ sys.stderr.write("2 arguments are required, got %s\n" % len(args))
+ return 1
+
+ binpkg_path, metadata_dir = args
+
+ if not os.path.isfile(binpkg_path):
+ sys.stderr.write(usage)
+ sys.stderr.write("Argument 1 is not a regular file: '%s'\n" % \
+ binpkg_path)
+ return 1
+
+ if not os.path.isdir(metadata_dir):
+ sys.stderr.write(usage)
+ sys.stderr.write("Argument 2 is not a directory: '%s'\n" % \
+ metadata_dir)
+ return 1
+
+ t = portage.xpak.tbz2(binpkg_path)
+ t.recompose(metadata_dir)
+ return os.EX_OK
+
+def main(argv):
+
+ if argv and sys.hexversion < 0x3000000 and not isinstance(argv[0], unicode):
+ for i, x in enumerate(argv):
+ argv[i] = portage._unicode_decode(x, errors='strict')
+
+ valid_commands = ('recompose',)
+ description = "Perform metadata operations on a binary package."
+ usage = "usage: %s COMMAND [args]" % \
+ os.path.basename(argv[0])
+
+ parser = optparse.OptionParser(description=description, usage=usage)
+ options, args = parser.parse_args(argv[1:])
+
+ if not args:
+ parser.error("missing command argument")
+
+ command = args[0]
+
+ if command not in valid_commands:
+ parser.error("invalid command: '%s'" % command)
+
+ if command == 'recompose':
+ rval = command_recompose(args[1:])
+ else:
+ raise AssertionError("invalid command: '%s'" % command)
+
+ return rval
+
+if __name__ == "__main__":
+ rval = main(sys.argv[:])
+ sys.exit(rval)
diff --git a/portage_with_autodep/pym/_emerge/AbstractDepPriority.py b/portage_with_autodep/pym/_emerge/AbstractDepPriority.py
new file mode 100644
index 0000000..94a9379
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/AbstractDepPriority.py
@@ -0,0 +1,29 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import copy
+from _emerge.SlotObject import SlotObject
+
+class AbstractDepPriority(SlotObject):
+ __slots__ = ("buildtime", "runtime", "runtime_post")
+
+ def __lt__(self, other):
+ return self.__int__() < other
+
+ def __le__(self, other):
+ return self.__int__() <= other
+
+ def __eq__(self, other):
+ return self.__int__() == other
+
+ def __ne__(self, other):
+ return self.__int__() != other
+
+ def __gt__(self, other):
+ return self.__int__() > other
+
+ def __ge__(self, other):
+ return self.__int__() >= other
+
+ def copy(self):
+ return copy.copy(self)
diff --git a/portage_with_autodep/pym/_emerge/AbstractEbuildProcess.py b/portage_with_autodep/pym/_emerge/AbstractEbuildProcess.py
new file mode 100644
index 0000000..4147ecb
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/AbstractEbuildProcess.py
@@ -0,0 +1,266 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import io
+import stat
+import textwrap
+from _emerge.SpawnProcess import SpawnProcess
+from _emerge.EbuildBuildDir import EbuildBuildDir
+from _emerge.EbuildIpcDaemon import EbuildIpcDaemon
+import portage
+from portage.elog import messages as elog_messages
+from portage.localization import _
+from portage.package.ebuild._ipc.ExitCommand import ExitCommand
+from portage.package.ebuild._ipc.QueryCommand import QueryCommand
+from portage import os
+from portage.util._pty import _create_pty_or_pipe
+from portage.util import apply_secpass_permissions
+
+class AbstractEbuildProcess(SpawnProcess):
+
+ __slots__ = ('phase', 'settings',) + \
+ ('_build_dir', '_ipc_daemon', '_exit_command',)
+ _phases_without_builddir = ('clean', 'cleanrm', 'depend', 'help',)
+
+ # Number of milliseconds to allow natural exit of the ebuild
+ # process after it has called the exit command via IPC. It
+ # doesn't hurt to be generous here since the scheduler
+ # continues to process events during this period, and it can
+ # return long before the timeout expires.
+ _exit_timeout = 10000 # 10 seconds
+
+ # The EbuildIpcDaemon support is well tested, but this variable
+ # is left so we can temporarily disable it if any issues arise.
+ _enable_ipc_daemon = True
+
+ def __init__(self, **kwargs):
+ SpawnProcess.__init__(self, **kwargs)
+ if self.phase is None:
+ phase = self.settings.get("EBUILD_PHASE")
+ if not phase:
+ phase = 'other'
+ self.phase = phase
+
+ def _start(self):
+
+ need_builddir = self.phase not in self._phases_without_builddir
+
+ # This can happen if the pre-clean phase triggers
+ # die_hooks for some reason, and PORTAGE_BUILDDIR
+ # doesn't exist yet.
+ if need_builddir and \
+ not os.path.isdir(self.settings['PORTAGE_BUILDDIR']):
+ msg = _("The ebuild phase '%s' has been aborted "
+ "since PORTAGE_BUILDIR does not exist: '%s'") % \
+ (self.phase, self.settings['PORTAGE_BUILDDIR'])
+ self._eerror(textwrap.wrap(msg, 72))
+ self._set_returncode((self.pid, 1 << 8))
+ self.wait()
+ return
+
+ if self.background:
+ # Automatically prevent color codes from showing up in logs,
+ # since we're not displaying to a terminal anyway.
+ self.settings['NOCOLOR'] = 'true'
+
+ if self._enable_ipc_daemon:
+ self.settings.pop('PORTAGE_EBUILD_EXIT_FILE', None)
+ if self.phase not in self._phases_without_builddir:
+ if 'PORTAGE_BUILDIR_LOCKED' not in self.settings:
+ self._build_dir = EbuildBuildDir(
+ scheduler=self.scheduler, settings=self.settings)
+ self._build_dir.lock()
+ self.settings['PORTAGE_IPC_DAEMON'] = "1"
+ self._start_ipc_daemon()
+ else:
+ self.settings.pop('PORTAGE_IPC_DAEMON', None)
+ else:
+ # Since the IPC daemon is disabled, use a simple tempfile based
+ # approach to detect unexpected exit like in bug #190128.
+ self.settings.pop('PORTAGE_IPC_DAEMON', None)
+ if self.phase not in self._phases_without_builddir:
+ exit_file = os.path.join(
+ self.settings['PORTAGE_BUILDDIR'],
+ '.exit_status')
+ self.settings['PORTAGE_EBUILD_EXIT_FILE'] = exit_file
+ try:
+ os.unlink(exit_file)
+ except OSError:
+ if os.path.exists(exit_file):
+ # make sure it doesn't exist
+ raise
+ else:
+ self.settings.pop('PORTAGE_EBUILD_EXIT_FILE', None)
+
+ SpawnProcess._start(self)
+
+ def _init_ipc_fifos(self):
+
+ input_fifo = os.path.join(
+ self.settings['PORTAGE_BUILDDIR'], '.ipc_in')
+ output_fifo = os.path.join(
+ self.settings['PORTAGE_BUILDDIR'], '.ipc_out')
+
+ for p in (input_fifo, output_fifo):
+
+ st = None
+ try:
+ st = os.lstat(p)
+ except OSError:
+ os.mkfifo(p)
+ else:
+ if not stat.S_ISFIFO(st.st_mode):
+ st = None
+ try:
+ os.unlink(p)
+ except OSError:
+ pass
+ os.mkfifo(p)
+
+ apply_secpass_permissions(p,
+ uid=os.getuid(),
+ gid=portage.data.portage_gid,
+ mode=0o770, stat_cached=st)
+
+ return (input_fifo, output_fifo)
+
+ def _start_ipc_daemon(self):
+ self._exit_command = ExitCommand()
+ self._exit_command.reply_hook = self._exit_command_callback
+ query_command = QueryCommand(self.settings, self.phase)
+ commands = {
+ 'best_version' : query_command,
+ 'exit' : self._exit_command,
+ 'has_version' : query_command,
+ }
+ input_fifo, output_fifo = self._init_ipc_fifos()
+ self._ipc_daemon = EbuildIpcDaemon(commands=commands,
+ input_fifo=input_fifo,
+ output_fifo=output_fifo,
+ scheduler=self.scheduler)
+ self._ipc_daemon.start()
+
+ def _exit_command_callback(self):
+ if self._registered:
+ # Let the process exit naturally, if possible.
+ self.scheduler.schedule(self._reg_id, timeout=self._exit_timeout)
+ if self._registered:
+ # If it doesn't exit naturally in a reasonable amount
+ # of time, kill it (solves bug #278895). We try to avoid
+ # this when possible since it makes sandbox complain about
+ # being killed by a signal.
+ self.cancel()
+
+ def _orphan_process_warn(self):
+ phase = self.phase
+
+ msg = _("The ebuild phase '%s' with pid %s appears "
+ "to have left an orphan process running in the "
+ "background.") % (phase, self.pid)
+
+ self._eerror(textwrap.wrap(msg, 72))
+
+ def _pipe(self, fd_pipes):
+ stdout_pipe = None
+ if not self.background:
+ stdout_pipe = fd_pipes.get(1)
+ got_pty, master_fd, slave_fd = \
+ _create_pty_or_pipe(copy_term_size=stdout_pipe)
+ return (master_fd, slave_fd)
+
+ def _can_log(self, slave_fd):
+ # With sesandbox, logging works through a pty but not through a
+ # normal pipe. So, disable logging if ptys are broken.
+ # See Bug #162404.
+ # TODO: Add support for logging via named pipe (fifo) with
+ # sesandbox, since EbuildIpcDaemon uses a fifo and it's known
+ # to be compatible with sesandbox.
+ return not ('sesandbox' in self.settings.features \
+ and self.settings.selinux_enabled()) or os.isatty(slave_fd)
+
+ def _killed_by_signal(self, signum):
+ msg = _("The ebuild phase '%s' has been "
+ "killed by signal %s.") % (self.phase, signum)
+ self._eerror(textwrap.wrap(msg, 72))
+
+ def _unexpected_exit(self):
+
+ phase = self.phase
+
+ msg = _("The ebuild phase '%s' has exited "
+ "unexpectedly. This type of behavior "
+ "is known to be triggered "
+ "by things such as failed variable "
+ "assignments (bug #190128) or bad substitution "
+ "errors (bug #200313). Normally, before exiting, bash should "
+ "have displayed an error message above. If bash did not "
+ "produce an error message above, it's possible "
+ "that the ebuild has called `exit` when it "
+ "should have called `die` instead. This behavior may also "
+ "be triggered by a corrupt bash binary or a hardware "
+ "problem such as memory or cpu malfunction. If the problem is not "
+ "reproducible or it appears to occur randomly, then it is likely "
+ "to be triggered by a hardware problem. "
+ "If you suspect a hardware problem then you should "
+ "try some basic hardware diagnostics such as memtest. "
+ "Please do not report this as a bug unless it is consistently "
+ "reproducible and you are sure that your bash binary and hardware "
+ "are functioning properly.") % phase
+
+ self._eerror(textwrap.wrap(msg, 72))
+
+ def _eerror(self, lines):
+ self._elog('eerror', lines)
+
+ def _elog(self, elog_funcname, lines):
+ out = io.StringIO()
+ phase = self.phase
+ elog_func = getattr(elog_messages, elog_funcname)
+ global_havecolor = portage.output.havecolor
+ try:
+ portage.output.havecolor = \
+ self.settings.get('NOCOLOR', 'false').lower() in ('no', 'false')
+ for line in lines:
+ elog_func(line, phase=phase, key=self.settings.mycpv, out=out)
+ finally:
+ portage.output.havecolor = global_havecolor
+ msg = out.getvalue()
+ if msg:
+ log_path = None
+ if self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
+ log_path = self.settings.get("PORTAGE_LOG_FILE")
+ self.scheduler.output(msg, log_path=log_path)
+
+ def _log_poll_exception(self, event):
+ self._elog("eerror",
+ ["%s received strange poll event: %s\n" % \
+ (self.__class__.__name__, event,)])
+
+ def _set_returncode(self, wait_retval):
+ SpawnProcess._set_returncode(self, wait_retval)
+
+ if self._ipc_daemon is not None:
+ self._ipc_daemon.cancel()
+ if self._exit_command.exitcode is not None:
+ self.returncode = self._exit_command.exitcode
+ else:
+ if self.returncode < 0:
+ if not self.cancelled:
+ self._killed_by_signal(-self.returncode)
+ else:
+ self.returncode = 1
+ if not self.cancelled:
+ self._unexpected_exit()
+ if self._build_dir is not None:
+ self._build_dir.unlock()
+ self._build_dir = None
+ elif not self.cancelled:
+ exit_file = self.settings.get('PORTAGE_EBUILD_EXIT_FILE')
+ if exit_file and not os.path.exists(exit_file):
+ if self.returncode < 0:
+ if not self.cancelled:
+ self._killed_by_signal(-self.returncode)
+ else:
+ self.returncode = 1
+ if not self.cancelled:
+ self._unexpected_exit()
diff --git a/portage_with_autodep/pym/_emerge/AbstractPollTask.py b/portage_with_autodep/pym/_emerge/AbstractPollTask.py
new file mode 100644
index 0000000..f7f3a95
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/AbstractPollTask.py
@@ -0,0 +1,62 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import array
+import logging
+
+from portage.util import writemsg_level
+from _emerge.AsynchronousTask import AsynchronousTask
+from _emerge.PollConstants import PollConstants
+class AbstractPollTask(AsynchronousTask):
+
+ __slots__ = ("scheduler",) + \
+ ("_registered",)
+
+ _bufsize = 4096
+ _exceptional_events = PollConstants.POLLERR | PollConstants.POLLNVAL
+ _registered_events = PollConstants.POLLIN | PollConstants.POLLHUP | \
+ _exceptional_events
+
+ def isAlive(self):
+ return bool(self._registered)
+
+ def _read_buf(self, f, event):
+ """
+ | POLLIN | RETURN
+ | BIT | VALUE
+ | ---------------------------------------------------
+ | 1 | Read self._bufsize into an instance of
+ | | array.array('B') and return it, ignoring
+ | | EOFError and IOError. An empty array
+ | | indicates EOF.
+ | ---------------------------------------------------
+ | 0 | None
+ """
+ buf = None
+ if event & PollConstants.POLLIN:
+ buf = array.array('B')
+ try:
+ buf.fromfile(f, self._bufsize)
+ except (EOFError, IOError):
+ pass
+ return buf
+
+ def _unregister(self):
+ raise NotImplementedError(self)
+
+ def _log_poll_exception(self, event):
+ writemsg_level(
+ "!!! %s received strange poll event: %s\n" % \
+ (self.__class__.__name__, event,),
+ level=logging.ERROR, noiselevel=-1)
+
+ def _unregister_if_appropriate(self, event):
+ if self._registered:
+ if event & self._exceptional_events:
+ self._log_poll_exception(event)
+ self._unregister()
+ self.cancel()
+ elif event & PollConstants.POLLHUP:
+ self._unregister()
+ self.wait()
+
diff --git a/portage_with_autodep/pym/_emerge/AsynchronousLock.py b/portage_with_autodep/pym/_emerge/AsynchronousLock.py
new file mode 100644
index 0000000..637ba73
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/AsynchronousLock.py
@@ -0,0 +1,288 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import dummy_threading
+import fcntl
+import logging
+import sys
+
+try:
+ import threading
+except ImportError:
+ import dummy_threading as threading
+
+import portage
+from portage import os
+from portage.exception import TryAgain
+from portage.localization import _
+from portage.locks import lockfile, unlockfile
+from portage.util import writemsg_level
+from _emerge.AbstractPollTask import AbstractPollTask
+from _emerge.AsynchronousTask import AsynchronousTask
+from _emerge.PollConstants import PollConstants
+from _emerge.SpawnProcess import SpawnProcess
+
+class AsynchronousLock(AsynchronousTask):
+ """
+ This uses the portage.locks module to acquire a lock asynchronously,
+ using either a thread (if available) or a subprocess.
+
+ The default behavior is to use a process instead of a thread, since
+ there is currently no way to interrupt a thread that is waiting for
+ a lock (notably, SIGINT doesn't work because python delivers all
+ signals to the main thread).
+ """
+
+ __slots__ = ('path', 'scheduler',) + \
+ ('_imp', '_force_async', '_force_dummy', '_force_process', \
+ '_force_thread', '_waiting')
+
+ _use_process_by_default = True
+
+ def _start(self):
+
+ if not self._force_async:
+ try:
+ self._imp = lockfile(self.path,
+ wantnewlockfile=True, flags=os.O_NONBLOCK)
+ except TryAgain:
+ pass
+ else:
+ self.returncode = os.EX_OK
+ self.wait()
+ return
+
+ if self._force_process or \
+ (not self._force_thread and \
+ (self._use_process_by_default or threading is dummy_threading)):
+ self._imp = _LockProcess(path=self.path, scheduler=self.scheduler)
+ else:
+ self._imp = _LockThread(path=self.path,
+ scheduler=self.scheduler,
+ _force_dummy=self._force_dummy)
+
+ self._imp.addExitListener(self._imp_exit)
+ self._imp.start()
+
+ def _imp_exit(self, imp):
+ # call exit listeners
+ if not self._waiting:
+ self.wait()
+
+ def _cancel(self):
+ if isinstance(self._imp, AsynchronousTask):
+ self._imp.cancel()
+
+ def _poll(self):
+ if isinstance(self._imp, AsynchronousTask):
+ self._imp.poll()
+ return self.returncode
+
+ def _wait(self):
+ if self.returncode is not None:
+ return self.returncode
+ self._waiting = True
+ self.returncode = self._imp.wait()
+ self._waiting = False
+ return self.returncode
+
+ def unlock(self):
+ if self._imp is None:
+ raise AssertionError('not locked')
+ if isinstance(self._imp, (_LockProcess, _LockThread)):
+ self._imp.unlock()
+ else:
+ unlockfile(self._imp)
+ self._imp = None
+
+class _LockThread(AbstractPollTask):
+ """
+ This uses the portage.locks module to acquire a lock asynchronously,
+ using a background thread. After the lock is acquired, the thread
+ writes to a pipe in order to notify a poll loop running in the main
+ thread.
+
+ If the threading module is unavailable then the dummy_threading
+ module will be used, and the lock will be acquired synchronously
+ (before the start() method returns).
+ """
+
+ __slots__ = ('path',) + \
+ ('_files', '_force_dummy', '_lock_obj',
+ '_thread', '_reg_id',)
+
+ def _start(self):
+ pr, pw = os.pipe()
+ self._files = {}
+ self._files['pipe_read'] = os.fdopen(pr, 'rb', 0)
+ self._files['pipe_write'] = os.fdopen(pw, 'wb', 0)
+ for k, f in self._files.items():
+ fcntl.fcntl(f.fileno(), fcntl.F_SETFL,
+ fcntl.fcntl(f.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK)
+ self._reg_id = self.scheduler.register(self._files['pipe_read'].fileno(),
+ PollConstants.POLLIN, self._output_handler)
+ self._registered = True
+ threading_mod = threading
+ if self._force_dummy:
+ threading_mod = dummy_threading
+ self._thread = threading_mod.Thread(target=self._run_lock)
+ self._thread.start()
+
+ def _run_lock(self):
+ self._lock_obj = lockfile(self.path, wantnewlockfile=True)
+ self._files['pipe_write'].write(b'\0')
+
+ def _output_handler(self, f, event):
+ buf = self._read_buf(self._files['pipe_read'], event)
+ if buf:
+ self._unregister()
+ self.returncode = os.EX_OK
+ self.wait()
+
+ def _cancel(self):
+ # There's currently no way to force thread termination.
+ pass
+
+ def _wait(self):
+ if self.returncode is not None:
+ return self.returncode
+ if self._registered:
+ self.scheduler.schedule(self._reg_id)
+ return self.returncode
+
+ def unlock(self):
+ if self._lock_obj is None:
+ raise AssertionError('not locked')
+ if self.returncode is None:
+ raise AssertionError('lock not acquired yet')
+ unlockfile(self._lock_obj)
+ self._lock_obj = None
+
+ def _unregister(self):
+ self._registered = False
+
+ if self._thread is not None:
+ self._thread.join()
+ self._thread = None
+
+ if self._reg_id is not None:
+ self.scheduler.unregister(self._reg_id)
+ self._reg_id = None
+
+ if self._files is not None:
+ for f in self._files.values():
+ f.close()
+ self._files = None
+
+class _LockProcess(AbstractPollTask):
+ """
+ This uses the portage.locks module to acquire a lock asynchronously,
+ using a subprocess. After the lock is acquired, the process
+ writes to a pipe in order to notify a poll loop running in the main
+ process. The unlock() method notifies the subprocess to release the
+ lock and exit.
+ """
+
+ __slots__ = ('path',) + \
+ ('_acquired', '_kill_test', '_proc', '_files', '_reg_id', '_unlocked')
+
+ def _start(self):
+ in_pr, in_pw = os.pipe()
+ out_pr, out_pw = os.pipe()
+ self._files = {}
+ self._files['pipe_in'] = os.fdopen(in_pr, 'rb', 0)
+ self._files['pipe_out'] = os.fdopen(out_pw, 'wb', 0)
+ fcntl.fcntl(in_pr, fcntl.F_SETFL,
+ fcntl.fcntl(in_pr, fcntl.F_GETFL) | os.O_NONBLOCK)
+ self._reg_id = self.scheduler.register(in_pr,
+ PollConstants.POLLIN, self._output_handler)
+ self._registered = True
+ self._proc = SpawnProcess(
+ args=[portage._python_interpreter,
+ os.path.join(portage._bin_path, 'lock-helper.py'), self.path],
+ env=dict(os.environ, PORTAGE_PYM_PATH=portage._pym_path),
+ fd_pipes={0:out_pr, 1:in_pw, 2:sys.stderr.fileno()},
+ scheduler=self.scheduler)
+ self._proc.addExitListener(self._proc_exit)
+ self._proc.start()
+ os.close(out_pr)
+ os.close(in_pw)
+
+ def _proc_exit(self, proc):
+ if proc.returncode != os.EX_OK:
+ # Typically, this will happen due to the
+ # process being killed by a signal.
+ if not self._acquired:
+ # If the lock hasn't been aquired yet, the
+ # caller can check the returncode and handle
+ # this failure appropriately.
+ if not (self.cancelled or self._kill_test):
+ writemsg_level("_LockProcess: %s\n" % \
+ _("failed to acquire lock on '%s'") % (self.path,),
+ level=logging.ERROR, noiselevel=-1)
+ self._unregister()
+ self.returncode = proc.returncode
+ self.wait()
+ return
+
+ if not self.cancelled and \
+ not self._unlocked:
+ # We don't want lost locks going unnoticed, so it's
+ # only safe to ignore if either the cancel() or
+ # unlock() methods have been previously called.
+ raise AssertionError("lock process failed with returncode %s" \
+ % (proc.returncode,))
+
+ def _cancel(self):
+ if self._proc is not None:
+ self._proc.cancel()
+
+ def _poll(self):
+ if self._proc is not None:
+ self._proc.poll()
+ return self.returncode
+
+ def _wait(self):
+ if self.returncode is not None:
+ return self.returncode
+ if self._registered:
+ self.scheduler.schedule(self._reg_id)
+ return self.returncode
+
+ def _output_handler(self, f, event):
+ buf = self._read_buf(self._files['pipe_in'], event)
+ if buf:
+ self._acquired = True
+ self._unregister()
+ self.returncode = os.EX_OK
+ self.wait()
+
+ def _unregister(self):
+ self._registered = False
+
+ if self._reg_id is not None:
+ self.scheduler.unregister(self._reg_id)
+ self._reg_id = None
+
+ if self._files is not None:
+ try:
+ pipe_in = self._files.pop('pipe_in')
+ except KeyError:
+ pass
+ else:
+ pipe_in.close()
+
+ def unlock(self):
+ if self._proc is None:
+ raise AssertionError('not locked')
+ if self.returncode is None:
+ raise AssertionError('lock not acquired yet')
+ if self.returncode != os.EX_OK:
+ raise AssertionError("lock process failed with returncode %s" \
+ % (self.returncode,))
+ self._unlocked = True
+ self._files['pipe_out'].write(b'\0')
+ self._files['pipe_out'].close()
+ self._files = None
+ self._proc.wait()
+ self._proc = None
diff --git a/portage_with_autodep/pym/_emerge/AsynchronousTask.py b/portage_with_autodep/pym/_emerge/AsynchronousTask.py
new file mode 100644
index 0000000..36522ca
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/AsynchronousTask.py
@@ -0,0 +1,129 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from _emerge.SlotObject import SlotObject
+class AsynchronousTask(SlotObject):
+ """
+ Subclasses override _wait() and _poll() so that calls
+ to public methods can be wrapped for implementing
+ hooks such as exit listener notification.
+
+ Sublasses should call self.wait() to notify exit listeners after
+ the task is complete and self.returncode has been set.
+ """
+
+ __slots__ = ("background", "cancelled", "returncode") + \
+ ("_exit_listeners", "_exit_listener_stack", "_start_listeners")
+
+ def start(self):
+ """
+ Start an asynchronous task and then return as soon as possible.
+ """
+ self._start_hook()
+ self._start()
+
+ def _start(self):
+ self.returncode = os.EX_OK
+ self.wait()
+
+ def isAlive(self):
+ return self.returncode is None
+
+ def poll(self):
+ if self.returncode is not None:
+ return self.returncode
+ self._poll()
+ self._wait_hook()
+ return self.returncode
+
+ def _poll(self):
+ return self.returncode
+
+ def wait(self):
+ if self.returncode is None:
+ self._wait()
+ self._wait_hook()
+ return self.returncode
+
+ def _wait(self):
+ return self.returncode
+
+ def cancel(self):
+ if not self.cancelled:
+ self.cancelled = True
+ self._cancel()
+ self.wait()
+
+ def _cancel(self):
+ """
+ Subclasses should implement this, as a template method
+ to be called by AsynchronousTask.cancel().
+ """
+ pass
+
+ def addStartListener(self, f):
+ """
+ The function will be called with one argument, a reference to self.
+ """
+ if self._start_listeners is None:
+ self._start_listeners = []
+ self._start_listeners.append(f)
+
+ def removeStartListener(self, f):
+ if self._start_listeners is None:
+ return
+ self._start_listeners.remove(f)
+
+ def _start_hook(self):
+ if self._start_listeners is not None:
+ start_listeners = self._start_listeners
+ self._start_listeners = None
+
+ for f in start_listeners:
+ f(self)
+
+ def addExitListener(self, f):
+ """
+ The function will be called with one argument, a reference to self.
+ """
+ if self._exit_listeners is None:
+ self._exit_listeners = []
+ self._exit_listeners.append(f)
+
+ def removeExitListener(self, f):
+ if self._exit_listeners is None:
+ if self._exit_listener_stack is not None:
+ self._exit_listener_stack.remove(f)
+ return
+ self._exit_listeners.remove(f)
+
+ def _wait_hook(self):
+ """
+ Call this method after the task completes, just before returning
+ the returncode from wait() or poll(). This hook is
+ used to trigger exit listeners when the returncode first
+ becomes available.
+ """
+ if self.returncode is not None and \
+ self._exit_listeners is not None:
+
+ # This prevents recursion, in case one of the
+ # exit handlers triggers this method again by
+ # calling wait(). Use a stack that gives
+ # removeExitListener() an opportunity to consume
+ # listeners from the stack, before they can get
+ # called below. This is necessary because a call
+ # to one exit listener may result in a call to
+ # removeExitListener() for another listener on
+ # the stack. That listener needs to be removed
+ # from the stack since it would be inconsistent
+ # to call it after it has been been passed into
+ # removeExitListener().
+ self._exit_listener_stack = self._exit_listeners
+ self._exit_listeners = None
+
+ self._exit_listener_stack.reverse()
+ while self._exit_listener_stack:
+ self._exit_listener_stack.pop()(self)
+
diff --git a/portage_with_autodep/pym/_emerge/AtomArg.py b/portage_with_autodep/pym/_emerge/AtomArg.py
new file mode 100644
index 0000000..a929b43
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/AtomArg.py
@@ -0,0 +1,11 @@
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage._sets.base import InternalPackageSet
+from _emerge.DependencyArg import DependencyArg
+
+class AtomArg(DependencyArg):
+ def __init__(self, atom=None, **kwargs):
+ DependencyArg.__init__(self, **kwargs)
+ self.atom = atom
+ self.pset = InternalPackageSet(initial_atoms=(self.atom,), allow_repo=True)
diff --git a/portage_with_autodep/pym/_emerge/Binpkg.py b/portage_with_autodep/pym/_emerge/Binpkg.py
new file mode 100644
index 0000000..bc6511e
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/Binpkg.py
@@ -0,0 +1,333 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.EbuildPhase import EbuildPhase
+from _emerge.BinpkgFetcher import BinpkgFetcher
+from _emerge.BinpkgEnvExtractor import BinpkgEnvExtractor
+from _emerge.BinpkgExtractorAsync import BinpkgExtractorAsync
+from _emerge.CompositeTask import CompositeTask
+from _emerge.BinpkgVerifier import BinpkgVerifier
+from _emerge.EbuildMerge import EbuildMerge
+from _emerge.EbuildBuildDir import EbuildBuildDir
+from portage.eapi import eapi_exports_replace_vars
+from portage.util import writemsg
+import portage
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+import io
+import logging
+from portage.output import colorize
+
+class Binpkg(CompositeTask):
+
+ __slots__ = ("find_blockers",
+ "ldpath_mtimes", "logger", "opts",
+ "pkg", "pkg_count", "prefetcher", "settings", "world_atom") + \
+ ("_bintree", "_build_dir", "_ebuild_path", "_fetched_pkg",
+ "_image_dir", "_infloc", "_pkg_path", "_tree", "_verify")
+
+ def _writemsg_level(self, msg, level=0, noiselevel=0):
+ self.scheduler.output(msg, level=level, noiselevel=noiselevel,
+ log_path=self.settings.get("PORTAGE_LOG_FILE"))
+
+ def _start(self):
+
+ pkg = self.pkg
+ settings = self.settings
+ settings.setcpv(pkg)
+ self._tree = "bintree"
+ self._bintree = self.pkg.root_config.trees[self._tree]
+ self._verify = not self.opts.pretend
+
+ # Use realpath like doebuild_environment() does, since we assert
+ # that this path is literally identical to PORTAGE_BUILDDIR.
+ dir_path = os.path.join(os.path.realpath(settings["PORTAGE_TMPDIR"]),
+ "portage", pkg.category, pkg.pf)
+ self._image_dir = os.path.join(dir_path, "image")
+ self._infloc = os.path.join(dir_path, "build-info")
+ self._ebuild_path = os.path.join(self._infloc, pkg.pf + ".ebuild")
+ settings["EBUILD"] = self._ebuild_path
+ portage.doebuild_environment(self._ebuild_path, 'setup',
+ settings=self.settings, db=self._bintree.dbapi)
+ if dir_path != self.settings['PORTAGE_BUILDDIR']:
+ raise AssertionError("'%s' != '%s'" % \
+ (dir_path, self.settings['PORTAGE_BUILDDIR']))
+ self._build_dir = EbuildBuildDir(
+ scheduler=self.scheduler, settings=settings)
+ settings.configdict["pkg"]["EMERGE_FROM"] = "binary"
+ settings.configdict["pkg"]["MERGE_TYPE"] = "binary"
+
+ if eapi_exports_replace_vars(settings["EAPI"]):
+ vardb = self.pkg.root_config.trees["vartree"].dbapi
+ settings["REPLACING_VERSIONS"] = " ".join(
+ set(portage.versions.cpv_getversion(x) \
+ for x in vardb.match(self.pkg.slot_atom) + \
+ vardb.match('='+self.pkg.cpv)))
+
+ # The prefetcher has already completed or it
+ # could be running now. If it's running now,
+ # wait for it to complete since it holds
+ # a lock on the file being fetched. The
+ # portage.locks functions are only designed
+ # to work between separate processes. Since
+ # the lock is held by the current process,
+ # use the scheduler and fetcher methods to
+ # synchronize with the fetcher.
+ prefetcher = self.prefetcher
+ if prefetcher is None:
+ pass
+ elif prefetcher.isAlive() and \
+ prefetcher.poll() is None:
+
+ waiting_msg = ("Fetching '%s' " + \
+ "in the background. " + \
+ "To view fetch progress, run `tail -f " + \
+ "/var/log/emerge-fetch.log` in another " + \
+ "terminal.") % prefetcher.pkg_path
+ msg_prefix = colorize("GOOD", " * ")
+ from textwrap import wrap
+ waiting_msg = "".join("%s%s\n" % (msg_prefix, line) \
+ for line in wrap(waiting_msg, 65))
+ if not self.background:
+ writemsg(waiting_msg, noiselevel=-1)
+
+ self._current_task = prefetcher
+ prefetcher.addExitListener(self._prefetch_exit)
+ return
+
+ self._prefetch_exit(prefetcher)
+
+ def _prefetch_exit(self, prefetcher):
+
+ pkg = self.pkg
+ pkg_count = self.pkg_count
+ if not (self.opts.pretend or self.opts.fetchonly):
+ self._build_dir.lock()
+ # Initialize PORTAGE_LOG_FILE (clean_log won't work without it).
+ portage.prepare_build_dirs(self.settings["ROOT"], self.settings, 1)
+ # If necessary, discard old log so that we don't
+ # append to it.
+ self._build_dir.clean_log()
+ fetcher = BinpkgFetcher(background=self.background,
+ logfile=self.settings.get("PORTAGE_LOG_FILE"), pkg=self.pkg,
+ pretend=self.opts.pretend, scheduler=self.scheduler)
+ pkg_path = fetcher.pkg_path
+ self._pkg_path = pkg_path
+ # This gives bashrc users an opportunity to do various things
+ # such as remove binary packages after they're installed.
+ self.settings["PORTAGE_BINPKG_FILE"] = pkg_path
+
+ if self.opts.getbinpkg and self._bintree.isremote(pkg.cpv):
+
+ msg = " --- (%s of %s) Fetching Binary (%s::%s)" %\
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg_path)
+ short_msg = "emerge: (%s of %s) %s Fetch" % \
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv)
+ self.logger.log(msg, short_msg=short_msg)
+
+ # Allow the Scheduler's fetch queue to control the
+ # number of concurrent fetchers.
+ fetcher.addExitListener(self._fetcher_exit)
+ self._task_queued(fetcher)
+ self.scheduler.fetch.schedule(fetcher)
+ return
+
+ self._fetcher_exit(fetcher)
+
+ def _fetcher_exit(self, fetcher):
+
+ # The fetcher only has a returncode when
+ # --getbinpkg is enabled.
+ if fetcher.returncode is not None:
+ self._fetched_pkg = True
+ if self._default_exit(fetcher) != os.EX_OK:
+ self._unlock_builddir()
+ self.wait()
+ return
+
+ if self.opts.pretend:
+ self._current_task = None
+ self.returncode = os.EX_OK
+ self.wait()
+ return
+
+ verifier = None
+ if self._verify:
+ logfile = self.settings.get("PORTAGE_LOG_FILE")
+ verifier = BinpkgVerifier(background=self.background,
+ logfile=logfile, pkg=self.pkg, scheduler=self.scheduler)
+ self._start_task(verifier, self._verifier_exit)
+ return
+
+ self._verifier_exit(verifier)
+
+ def _verifier_exit(self, verifier):
+ if verifier is not None and \
+ self._default_exit(verifier) != os.EX_OK:
+ self._unlock_builddir()
+ self.wait()
+ return
+
+ logger = self.logger
+ pkg = self.pkg
+ pkg_count = self.pkg_count
+ pkg_path = self._pkg_path
+
+ if self._fetched_pkg:
+ self._bintree.inject(pkg.cpv, filename=pkg_path)
+
+ logfile = self.settings.get("PORTAGE_LOG_FILE")
+ if logfile is not None and os.path.isfile(logfile):
+ # Remove fetch log after successful fetch.
+ try:
+ os.unlink(logfile)
+ except OSError:
+ pass
+
+ if self.opts.fetchonly:
+ self._current_task = None
+ self.returncode = os.EX_OK
+ self.wait()
+ return
+
+ msg = " === (%s of %s) Merging Binary (%s::%s)" % \
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg_path)
+ short_msg = "emerge: (%s of %s) %s Merge Binary" % \
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv)
+ logger.log(msg, short_msg=short_msg)
+
+ phase = "clean"
+ settings = self.settings
+ ebuild_phase = EbuildPhase(background=self.background,
+ phase=phase, scheduler=self.scheduler,
+ settings=settings)
+
+ self._start_task(ebuild_phase, self._clean_exit)
+
+ def _clean_exit(self, clean_phase):
+ if self._default_exit(clean_phase) != os.EX_OK:
+ self._unlock_builddir()
+ self.wait()
+ return
+
+ dir_path = self.settings['PORTAGE_BUILDDIR']
+
+ infloc = self._infloc
+ pkg = self.pkg
+ pkg_path = self._pkg_path
+
+ dir_mode = 0o755
+ for mydir in (dir_path, self._image_dir, infloc):
+ portage.util.ensure_dirs(mydir, uid=portage.data.portage_uid,
+ gid=portage.data.portage_gid, mode=dir_mode)
+
+ # This initializes PORTAGE_LOG_FILE.
+ portage.prepare_build_dirs(self.settings["ROOT"], self.settings, 1)
+ self._writemsg_level(">>> Extracting info\n")
+
+ pkg_xpak = portage.xpak.tbz2(self._pkg_path)
+ check_missing_metadata = ("CATEGORY", "PF")
+ missing_metadata = set()
+ for k in check_missing_metadata:
+ v = pkg_xpak.getfile(_unicode_encode(k,
+ encoding=_encodings['repo.content']))
+ if not v:
+ missing_metadata.add(k)
+
+ pkg_xpak.unpackinfo(infloc)
+ for k in missing_metadata:
+ if k == "CATEGORY":
+ v = pkg.category
+ elif k == "PF":
+ v = pkg.pf
+ else:
+ continue
+
+ f = io.open(_unicode_encode(os.path.join(infloc, k),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='w', encoding=_encodings['content'],
+ errors='backslashreplace')
+ try:
+ f.write(_unicode_decode(v + "\n"))
+ finally:
+ f.close()
+
+ # Store the md5sum in the vdb.
+ f = io.open(_unicode_encode(os.path.join(infloc, 'BINPKGMD5'),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='w', encoding=_encodings['content'], errors='strict')
+ try:
+ f.write(_unicode_decode(
+ str(portage.checksum.perform_md5(pkg_path)) + "\n"))
+ finally:
+ f.close()
+
+ env_extractor = BinpkgEnvExtractor(background=self.background,
+ scheduler=self.scheduler, settings=self.settings)
+
+ self._start_task(env_extractor, self._env_extractor_exit)
+
+ def _env_extractor_exit(self, env_extractor):
+ if self._default_exit(env_extractor) != os.EX_OK:
+ self._unlock_builddir()
+ self.wait()
+ return
+
+ setup_phase = EbuildPhase(background=self.background,
+ phase="setup", scheduler=self.scheduler,
+ settings=self.settings)
+
+ setup_phase.addExitListener(self._setup_exit)
+ self._task_queued(setup_phase)
+ self.scheduler.scheduleSetup(setup_phase)
+
+ def _setup_exit(self, setup_phase):
+ if self._default_exit(setup_phase) != os.EX_OK:
+ self._unlock_builddir()
+ self.wait()
+ return
+
+ extractor = BinpkgExtractorAsync(background=self.background,
+ env=self.settings.environ(),
+ image_dir=self._image_dir,
+ pkg=self.pkg, pkg_path=self._pkg_path,
+ logfile=self.settings.get("PORTAGE_LOG_FILE"),
+ scheduler=self.scheduler)
+ self._writemsg_level(">>> Extracting %s\n" % self.pkg.cpv)
+ self._start_task(extractor, self._extractor_exit)
+
+ def _extractor_exit(self, extractor):
+ if self._final_exit(extractor) != os.EX_OK:
+ self._unlock_builddir()
+ self._writemsg_level("!!! Error Extracting '%s'\n" % \
+ self._pkg_path, noiselevel=-1, level=logging.ERROR)
+ self.wait()
+
+ def _unlock_builddir(self):
+ if self.opts.pretend or self.opts.fetchonly:
+ return
+ portage.elog.elog_process(self.pkg.cpv, self.settings)
+ self._build_dir.unlock()
+
+ def create_install_task(self):
+ task = EbuildMerge(find_blockers=self.find_blockers,
+ ldpath_mtimes=self.ldpath_mtimes, logger=self.logger,
+ pkg=self.pkg, pkg_count=self.pkg_count,
+ pkg_path=self._pkg_path, scheduler=self.scheduler,
+ settings=self.settings, tree=self._tree,
+ world_atom=self.world_atom)
+ task.addExitListener(self._install_exit)
+ return task
+
+ def _install_exit(self, task):
+ self.settings.pop("PORTAGE_BINPKG_FILE", None)
+ self._unlock_builddir()
+ if task.returncode == os.EX_OK and \
+ 'binpkg-logs' not in self.settings.features and \
+ self.settings.get("PORTAGE_LOG_FILE"):
+ try:
+ os.unlink(self.settings["PORTAGE_LOG_FILE"])
+ except OSError:
+ pass
diff --git a/portage_with_autodep/pym/_emerge/BinpkgEnvExtractor.py b/portage_with_autodep/pym/_emerge/BinpkgEnvExtractor.py
new file mode 100644
index 0000000..f68971b
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/BinpkgEnvExtractor.py
@@ -0,0 +1,66 @@
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import errno
+
+from _emerge.CompositeTask import CompositeTask
+from _emerge.SpawnProcess import SpawnProcess
+from portage import os, _shell_quote, _unicode_encode
+from portage.const import BASH_BINARY
+
+class BinpkgEnvExtractor(CompositeTask):
+ """
+ Extract environment.bz2 for a binary or installed package.
+ """
+ __slots__ = ('settings',)
+
+ def saved_env_exists(self):
+ return os.path.exists(self._get_saved_env_path())
+
+ def dest_env_exists(self):
+ return os.path.exists(self._get_dest_env_path())
+
+ def _get_saved_env_path(self):
+ return os.path.join(os.path.dirname(self.settings['EBUILD']),
+ "environment.bz2")
+
+ def _get_dest_env_path(self):
+ return os.path.join(self.settings["T"], "environment")
+
+ def _start(self):
+ saved_env_path = self._get_saved_env_path()
+ dest_env_path = self._get_dest_env_path()
+ shell_cmd = "${PORTAGE_BUNZIP2_COMMAND:-${PORTAGE_BZIP2_COMMAND} -d} -c -- %s > %s" % \
+ (_shell_quote(saved_env_path),
+ _shell_quote(dest_env_path))
+ extractor_proc = SpawnProcess(
+ args=[BASH_BINARY, "-c", shell_cmd],
+ background=self.background,
+ env=self.settings.environ(),
+ scheduler=self.scheduler,
+ logfile=self.settings.get('PORTAGE_LOGFILE'))
+
+ self._start_task(extractor_proc, self._extractor_exit)
+
+ def _remove_dest_env(self):
+ try:
+ os.unlink(self._get_dest_env_path())
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+
+ def _extractor_exit(self, extractor_proc):
+
+ if self._default_exit(extractor_proc) != os.EX_OK:
+ self._remove_dest_env()
+ self.wait()
+ return
+
+ # This is a signal to ebuild.sh, so that it knows to filter
+ # out things like SANDBOX_{DENY,PREDICT,READ,WRITE} that
+ # would be preserved between normal phases.
+ open(_unicode_encode(self._get_dest_env_path() + '.raw'), 'w')
+
+ self._current_task = None
+ self.returncode = os.EX_OK
+ self.wait()
diff --git a/portage_with_autodep/pym/_emerge/BinpkgExtractorAsync.py b/portage_with_autodep/pym/_emerge/BinpkgExtractorAsync.py
new file mode 100644
index 0000000..d1630f2
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/BinpkgExtractorAsync.py
@@ -0,0 +1,31 @@
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.SpawnProcess import SpawnProcess
+import portage
+import os
+import signal
+
+class BinpkgExtractorAsync(SpawnProcess):
+
+ __slots__ = ("image_dir", "pkg", "pkg_path")
+
+ _shell_binary = portage.const.BASH_BINARY
+
+ def _start(self):
+ # Add -q to bzip2 opts, in order to avoid "trailing garbage after
+ # EOF ignored" warning messages due to xpak trailer.
+ # SIGPIPE handling (128 + SIGPIPE) should be compatible with
+ # assert_sigpipe_ok() that's used by the ebuild unpack() helper.
+ self.args = [self._shell_binary, "-c",
+ ("${PORTAGE_BUNZIP2_COMMAND:-${PORTAGE_BZIP2_COMMAND} -d} -cq -- %s | tar -xp -C %s -f - ; " + \
+ "p=(${PIPESTATUS[@]}) ; " + \
+ "if [[ ${p[0]} != 0 && ${p[0]} != %d ]] ; then " % (128 + signal.SIGPIPE) + \
+ "echo bzip2 failed with status ${p[0]} ; exit ${p[0]} ; fi ; " + \
+ "if [ ${p[1]} != 0 ] ; then " + \
+ "echo tar failed with status ${p[1]} ; exit ${p[1]} ; fi ; " + \
+ "exit 0 ;") % \
+ (portage._shell_quote(self.pkg_path),
+ portage._shell_quote(self.image_dir))]
+
+ SpawnProcess._start(self)
diff --git a/portage_with_autodep/pym/_emerge/BinpkgFetcher.py b/portage_with_autodep/pym/_emerge/BinpkgFetcher.py
new file mode 100644
index 0000000..baea4d6
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/BinpkgFetcher.py
@@ -0,0 +1,181 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.AsynchronousLock import AsynchronousLock
+from _emerge.SpawnProcess import SpawnProcess
+try:
+ from urllib.parse import urlparse as urllib_parse_urlparse
+except ImportError:
+ from urlparse import urlparse as urllib_parse_urlparse
+import stat
+import sys
+import portage
+from portage import os
+from portage.util._pty import _create_pty_or_pipe
+
+if sys.hexversion >= 0x3000000:
+ long = int
+
+class BinpkgFetcher(SpawnProcess):
+
+ __slots__ = ("pkg", "pretend",
+ "locked", "pkg_path", "_lock_obj")
+
+ def __init__(self, **kwargs):
+ SpawnProcess.__init__(self, **kwargs)
+ pkg = self.pkg
+ self.pkg_path = pkg.root_config.trees["bintree"].getname(pkg.cpv)
+
+ def _start(self):
+
+ if self.cancelled:
+ return
+
+ pkg = self.pkg
+ pretend = self.pretend
+ bintree = pkg.root_config.trees["bintree"]
+ settings = bintree.settings
+ use_locks = "distlocks" in settings.features
+ pkg_path = self.pkg_path
+
+ if not pretend:
+ portage.util.ensure_dirs(os.path.dirname(pkg_path))
+ if use_locks:
+ self.lock()
+ exists = os.path.exists(pkg_path)
+ resume = exists and os.path.basename(pkg_path) in bintree.invalids
+ if not (pretend or resume):
+ # Remove existing file or broken symlink.
+ try:
+ os.unlink(pkg_path)
+ except OSError:
+ pass
+
+ # urljoin doesn't work correctly with
+ # unrecognized protocols like sftp
+ if bintree._remote_has_index:
+ rel_uri = bintree._remotepkgs[pkg.cpv].get("PATH")
+ if not rel_uri:
+ rel_uri = pkg.cpv + ".tbz2"
+ remote_base_uri = bintree._remotepkgs[pkg.cpv]["BASE_URI"]
+ uri = remote_base_uri.rstrip("/") + "/" + rel_uri.lstrip("/")
+ else:
+ uri = settings["PORTAGE_BINHOST"].rstrip("/") + \
+ "/" + pkg.pf + ".tbz2"
+
+ if pretend:
+ portage.writemsg_stdout("\n%s\n" % uri, noiselevel=-1)
+ self._set_returncode((self.pid, os.EX_OK << 8))
+ self.wait()
+ return
+
+ protocol = urllib_parse_urlparse(uri)[0]
+ fcmd_prefix = "FETCHCOMMAND"
+ if resume:
+ fcmd_prefix = "RESUMECOMMAND"
+ fcmd = settings.get(fcmd_prefix + "_" + protocol.upper())
+ if not fcmd:
+ fcmd = settings.get(fcmd_prefix)
+
+ fcmd_vars = {
+ "DISTDIR" : os.path.dirname(pkg_path),
+ "URI" : uri,
+ "FILE" : os.path.basename(pkg_path)
+ }
+
+ fetch_env = dict(settings.items())
+ fetch_args = [portage.util.varexpand(x, mydict=fcmd_vars) \
+ for x in portage.util.shlex_split(fcmd)]
+
+ if self.fd_pipes is None:
+ self.fd_pipes = {}
+ fd_pipes = self.fd_pipes
+
+ # Redirect all output to stdout since some fetchers like
+ # wget pollute stderr (if portage detects a problem then it
+ # can send it's own message to stderr).
+ fd_pipes.setdefault(0, sys.stdin.fileno())
+ fd_pipes.setdefault(1, sys.stdout.fileno())
+ fd_pipes.setdefault(2, sys.stdout.fileno())
+
+ self.args = fetch_args
+ self.env = fetch_env
+ if settings.selinux_enabled():
+ self._selinux_type = settings["PORTAGE_FETCH_T"]
+ SpawnProcess._start(self)
+
+ def _pipe(self, fd_pipes):
+ """When appropriate, use a pty so that fetcher progress bars,
+ like wget has, will work properly."""
+ if self.background or not sys.stdout.isatty():
+ # When the output only goes to a log file,
+ # there's no point in creating a pty.
+ return os.pipe()
+ stdout_pipe = None
+ if not self.background:
+ stdout_pipe = fd_pipes.get(1)
+ got_pty, master_fd, slave_fd = \
+ _create_pty_or_pipe(copy_term_size=stdout_pipe)
+ return (master_fd, slave_fd)
+
+ def _set_returncode(self, wait_retval):
+ SpawnProcess._set_returncode(self, wait_retval)
+ if not self.pretend and self.returncode == os.EX_OK:
+ # If possible, update the mtime to match the remote package if
+ # the fetcher didn't already do it automatically.
+ bintree = self.pkg.root_config.trees["bintree"]
+ if bintree._remote_has_index:
+ remote_mtime = bintree._remotepkgs[self.pkg.cpv].get("MTIME")
+ if remote_mtime is not None:
+ try:
+ remote_mtime = long(remote_mtime)
+ except ValueError:
+ pass
+ else:
+ try:
+ local_mtime = os.stat(self.pkg_path)[stat.ST_MTIME]
+ except OSError:
+ pass
+ else:
+ if remote_mtime != local_mtime:
+ try:
+ os.utime(self.pkg_path,
+ (remote_mtime, remote_mtime))
+ except OSError:
+ pass
+
+ if self.locked:
+ self.unlock()
+
+ def lock(self):
+ """
+ This raises an AlreadyLocked exception if lock() is called
+ while a lock is already held. In order to avoid this, call
+ unlock() or check whether the "locked" attribute is True
+ or False before calling lock().
+ """
+ if self._lock_obj is not None:
+ raise self.AlreadyLocked((self._lock_obj,))
+
+ async_lock = AsynchronousLock(path=self.pkg_path,
+ scheduler=self.scheduler)
+ async_lock.start()
+
+ if async_lock.wait() != os.EX_OK:
+ # TODO: Use CompositeTask for better handling, like in EbuildPhase.
+ raise AssertionError("AsynchronousLock failed with returncode %s" \
+ % (async_lock.returncode,))
+
+ self._lock_obj = async_lock
+ self.locked = True
+
+ class AlreadyLocked(portage.exception.PortageException):
+ pass
+
+ def unlock(self):
+ if self._lock_obj is None:
+ return
+ self._lock_obj.unlock()
+ self._lock_obj = None
+ self.locked = False
+
diff --git a/portage_with_autodep/pym/_emerge/BinpkgPrefetcher.py b/portage_with_autodep/pym/_emerge/BinpkgPrefetcher.py
new file mode 100644
index 0000000..ffa4900
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/BinpkgPrefetcher.py
@@ -0,0 +1,43 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.BinpkgFetcher import BinpkgFetcher
+from _emerge.CompositeTask import CompositeTask
+from _emerge.BinpkgVerifier import BinpkgVerifier
+from portage import os
+
+class BinpkgPrefetcher(CompositeTask):
+
+ __slots__ = ("pkg",) + \
+ ("pkg_path", "_bintree",)
+
+ def _start(self):
+ self._bintree = self.pkg.root_config.trees["bintree"]
+ fetcher = BinpkgFetcher(background=self.background,
+ logfile=self.scheduler.fetch.log_file, pkg=self.pkg,
+ scheduler=self.scheduler)
+ self.pkg_path = fetcher.pkg_path
+ self._start_task(fetcher, self._fetcher_exit)
+
+ def _fetcher_exit(self, fetcher):
+
+ if self._default_exit(fetcher) != os.EX_OK:
+ self.wait()
+ return
+
+ verifier = BinpkgVerifier(background=self.background,
+ logfile=self.scheduler.fetch.log_file, pkg=self.pkg,
+ scheduler=self.scheduler)
+ self._start_task(verifier, self._verifier_exit)
+
+ def _verifier_exit(self, verifier):
+ if self._default_exit(verifier) != os.EX_OK:
+ self.wait()
+ return
+
+ self._bintree.inject(self.pkg.cpv, filename=self.pkg_path)
+
+ self._current_task = None
+ self.returncode = os.EX_OK
+ self.wait()
+
diff --git a/portage_with_autodep/pym/_emerge/BinpkgVerifier.py b/portage_with_autodep/pym/_emerge/BinpkgVerifier.py
new file mode 100644
index 0000000..0052967
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/BinpkgVerifier.py
@@ -0,0 +1,75 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.AsynchronousTask import AsynchronousTask
+from portage.util import writemsg
+import io
+import sys
+import portage
+from portage import os
+from portage.package.ebuild.fetch import _checksum_failure_temp_file
+
+class BinpkgVerifier(AsynchronousTask):
+ __slots__ = ("logfile", "pkg", "scheduler")
+
+ def _start(self):
+ """
+ Note: Unlike a normal AsynchronousTask.start() method,
+ this one does all work is synchronously. The returncode
+ attribute will be set before it returns.
+ """
+
+ pkg = self.pkg
+ root_config = pkg.root_config
+ bintree = root_config.trees["bintree"]
+ rval = os.EX_OK
+ stdout_orig = sys.stdout
+ stderr_orig = sys.stderr
+ global_havecolor = portage.output.havecolor
+ out = io.StringIO()
+ file_exists = True
+ try:
+ sys.stdout = out
+ sys.stderr = out
+ if portage.output.havecolor:
+ portage.output.havecolor = not self.background
+ try:
+ bintree.digestCheck(pkg)
+ except portage.exception.FileNotFound:
+ writemsg("!!! Fetching Binary failed " + \
+ "for '%s'\n" % pkg.cpv, noiselevel=-1)
+ rval = 1
+ file_exists = False
+ except portage.exception.DigestException as e:
+ writemsg("\n!!! Digest verification failed:\n",
+ noiselevel=-1)
+ writemsg("!!! %s\n" % e.value[0],
+ noiselevel=-1)
+ writemsg("!!! Reason: %s\n" % e.value[1],
+ noiselevel=-1)
+ writemsg("!!! Got: %s\n" % e.value[2],
+ noiselevel=-1)
+ writemsg("!!! Expected: %s\n" % e.value[3],
+ noiselevel=-1)
+ rval = 1
+ if rval == os.EX_OK:
+ pass
+ elif file_exists:
+ pkg_path = bintree.getname(pkg.cpv)
+ head, tail = os.path.split(pkg_path)
+ temp_filename = _checksum_failure_temp_file(head, tail)
+ writemsg("File renamed to '%s'\n" % (temp_filename,),
+ noiselevel=-1)
+ finally:
+ sys.stdout = stdout_orig
+ sys.stderr = stderr_orig
+ portage.output.havecolor = global_havecolor
+
+ msg = out.getvalue()
+ if msg:
+ self.scheduler.output(msg, log_path=self.logfile,
+ background=self.background)
+
+ self.returncode = rval
+ self.wait()
+
diff --git a/portage_with_autodep/pym/_emerge/Blocker.py b/portage_with_autodep/pym/_emerge/Blocker.py
new file mode 100644
index 0000000..9304606
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/Blocker.py
@@ -0,0 +1,15 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.Task import Task
+
+class Blocker(Task):
+
+ __hash__ = Task.__hash__
+ __slots__ = ("root", "atom", "cp", "eapi", "priority", "satisfied")
+
+ def __init__(self, **kwargs):
+ Task.__init__(self, **kwargs)
+ self.cp = self.atom.cp
+ self._hash_key = ("blocks", self.root, self.atom, self.eapi)
+ self._hash_value = hash(self._hash_key)
diff --git a/portage_with_autodep/pym/_emerge/BlockerCache.py b/portage_with_autodep/pym/_emerge/BlockerCache.py
new file mode 100644
index 0000000..5c4f43e
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/BlockerCache.py
@@ -0,0 +1,182 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+from portage.util import writemsg
+from portage.data import secpass
+import portage
+from portage import os
+
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+ long = int
+
+class BlockerCache(portage.cache.mappings.MutableMapping):
+ """This caches blockers of installed packages so that dep_check does not
+ have to be done for every single installed package on every invocation of
+ emerge. The cache is invalidated whenever it is detected that something
+ has changed that might alter the results of dep_check() calls:
+ 1) the set of installed packages (including COUNTER) has changed
+ """
+
+ # Number of uncached packages to trigger cache update, since
+ # it's wasteful to update it for every vdb change.
+ _cache_threshold = 5
+
+ class BlockerData(object):
+
+ __slots__ = ("__weakref__", "atoms", "counter")
+
+ def __init__(self, counter, atoms):
+ self.counter = counter
+ self.atoms = atoms
+
+ def __init__(self, myroot, vardb):
+ """ myroot is ignored in favour of EROOT """
+ self._vardb = vardb
+ self._cache_filename = os.path.join(vardb.settings['EROOT'],
+ portage.CACHE_PATH, "vdb_blockers.pickle")
+ self._cache_version = "1"
+ self._cache_data = None
+ self._modified = set()
+ self._load()
+
+ def _load(self):
+ try:
+ f = open(self._cache_filename, mode='rb')
+ mypickle = pickle.Unpickler(f)
+ try:
+ mypickle.find_global = None
+ except AttributeError:
+ # TODO: If py3k, override Unpickler.find_class().
+ pass
+ self._cache_data = mypickle.load()
+ f.close()
+ del f
+ except (IOError, OSError, EOFError, ValueError, pickle.UnpicklingError) as e:
+ if isinstance(e, pickle.UnpicklingError):
+ writemsg("!!! Error loading '%s': %s\n" % \
+ (self._cache_filename, str(e)), noiselevel=-1)
+ del e
+
+ cache_valid = self._cache_data and \
+ isinstance(self._cache_data, dict) and \
+ self._cache_data.get("version") == self._cache_version and \
+ isinstance(self._cache_data.get("blockers"), dict)
+ if cache_valid:
+ # Validate all the atoms and counters so that
+ # corruption is detected as soon as possible.
+ invalid_items = set()
+ for k, v in self._cache_data["blockers"].items():
+ if not isinstance(k, basestring):
+ invalid_items.add(k)
+ continue
+ try:
+ if portage.catpkgsplit(k) is None:
+ invalid_items.add(k)
+ continue
+ except portage.exception.InvalidData:
+ invalid_items.add(k)
+ continue
+ if not isinstance(v, tuple) or \
+ len(v) != 2:
+ invalid_items.add(k)
+ continue
+ counter, atoms = v
+ if not isinstance(counter, (int, long)):
+ invalid_items.add(k)
+ continue
+ if not isinstance(atoms, (list, tuple)):
+ invalid_items.add(k)
+ continue
+ invalid_atom = False
+ for atom in atoms:
+ if not isinstance(atom, basestring):
+ invalid_atom = True
+ break
+ if atom[:1] != "!" or \
+ not portage.isvalidatom(
+ atom, allow_blockers=True):
+ invalid_atom = True
+ break
+ if invalid_atom:
+ invalid_items.add(k)
+ continue
+
+ for k in invalid_items:
+ del self._cache_data["blockers"][k]
+ if not self._cache_data["blockers"]:
+ cache_valid = False
+
+ if not cache_valid:
+ self._cache_data = {"version":self._cache_version}
+ self._cache_data["blockers"] = {}
+ self._modified.clear()
+
+ def flush(self):
+ """If the current user has permission and the internal blocker cache
+ been updated, save it to disk and mark it unmodified. This is called
+ by emerge after it has proccessed blockers for all installed packages.
+ Currently, the cache is only written if the user has superuser
+ privileges (since that's required to obtain a lock), but all users
+ have read access and benefit from faster blocker lookups (as long as
+ the entire cache is still valid). The cache is stored as a pickled
+ dict object with the following format:
+
+ {
+ version : "1",
+ "blockers" : {cpv1:(counter,(atom1, atom2...)), cpv2...},
+ }
+ """
+ if len(self._modified) >= self._cache_threshold and \
+ secpass >= 2:
+ try:
+ f = portage.util.atomic_ofstream(self._cache_filename, mode='wb')
+ pickle.dump(self._cache_data, f, protocol=2)
+ f.close()
+ portage.util.apply_secpass_permissions(
+ self._cache_filename, gid=portage.portage_gid, mode=0o644)
+ except (IOError, OSError) as e:
+ pass
+ self._modified.clear()
+
+ def __setitem__(self, cpv, blocker_data):
+ """
+ Update the cache and mark it as modified for a future call to
+ self.flush().
+
+ @param cpv: Package for which to cache blockers.
+ @type cpv: String
+ @param blocker_data: An object with counter and atoms attributes.
+ @type blocker_data: BlockerData
+ """
+ self._cache_data["blockers"][cpv] = \
+ (blocker_data.counter, tuple(str(x) for x in blocker_data.atoms))
+ self._modified.add(cpv)
+
+ def __iter__(self):
+ if self._cache_data is None:
+ # triggered by python-trace
+ return iter([])
+ return iter(self._cache_data["blockers"])
+
+ def __len__(self):
+ """This needs to be implemented in order to avoid
+ infinite recursion in some cases."""
+ return len(self._cache_data["blockers"])
+
+ def __delitem__(self, cpv):
+ del self._cache_data["blockers"][cpv]
+
+ def __getitem__(self, cpv):
+ """
+ @rtype: BlockerData
+ @returns: An object with counter and atoms attributes.
+ """
+ return self.BlockerData(*self._cache_data["blockers"][cpv])
+
diff --git a/portage_with_autodep/pym/_emerge/BlockerDB.py b/portage_with_autodep/pym/_emerge/BlockerDB.py
new file mode 100644
index 0000000..4819749
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/BlockerDB.py
@@ -0,0 +1,124 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+
+import portage
+from portage import os
+from portage import digraph
+from portage._sets.base import InternalPackageSet
+
+from _emerge.BlockerCache import BlockerCache
+from _emerge.show_invalid_depstring_notice import show_invalid_depstring_notice
+
+if sys.hexversion >= 0x3000000:
+ long = int
+
+class BlockerDB(object):
+
+ def __init__(self, fake_vartree):
+ root_config = fake_vartree._root_config
+ self._root_config = root_config
+ self._vartree = root_config.trees["vartree"]
+ self._portdb = root_config.trees["porttree"].dbapi
+
+ self._dep_check_trees = None
+ self._fake_vartree = fake_vartree
+ self._dep_check_trees = {
+ self._vartree.root : {
+ "porttree" : fake_vartree,
+ "vartree" : fake_vartree,
+ }}
+
+ def findInstalledBlockers(self, new_pkg):
+ """
+ Search for installed run-time blockers in the root where
+ new_pkg is planned to be installed. This ignores build-time
+ blockers, since new_pkg is assumed to be built already.
+ """
+ blocker_cache = BlockerCache(self._vartree.root, self._vartree.dbapi)
+ dep_keys = ["RDEPEND", "PDEPEND"]
+ settings = self._vartree.settings
+ stale_cache = set(blocker_cache)
+ fake_vartree = self._fake_vartree
+ dep_check_trees = self._dep_check_trees
+ vardb = fake_vartree.dbapi
+ installed_pkgs = list(vardb)
+
+ for inst_pkg in installed_pkgs:
+ stale_cache.discard(inst_pkg.cpv)
+ cached_blockers = blocker_cache.get(inst_pkg.cpv)
+ if cached_blockers is not None and \
+ cached_blockers.counter != long(inst_pkg.metadata["COUNTER"]):
+ cached_blockers = None
+ if cached_blockers is not None:
+ blocker_atoms = cached_blockers.atoms
+ else:
+ # Use aux_get() to trigger FakeVartree global
+ # updates on *DEPEND when appropriate.
+ depstr = " ".join(vardb.aux_get(inst_pkg.cpv, dep_keys))
+ success, atoms = portage.dep_check(depstr,
+ vardb, settings, myuse=inst_pkg.use.enabled,
+ trees=dep_check_trees, myroot=inst_pkg.root)
+ if not success:
+ pkg_location = os.path.join(inst_pkg.root,
+ portage.VDB_PATH, inst_pkg.category, inst_pkg.pf)
+ portage.writemsg("!!! %s/*DEPEND: %s\n" % \
+ (pkg_location, atoms), noiselevel=-1)
+ continue
+
+ blocker_atoms = [atom for atom in atoms \
+ if atom.startswith("!")]
+ blocker_atoms.sort()
+ counter = long(inst_pkg.metadata["COUNTER"])
+ blocker_cache[inst_pkg.cpv] = \
+ blocker_cache.BlockerData(counter, blocker_atoms)
+ for cpv in stale_cache:
+ del blocker_cache[cpv]
+ blocker_cache.flush()
+
+ blocker_parents = digraph()
+ blocker_atoms = []
+ for pkg in installed_pkgs:
+ for blocker_atom in blocker_cache[pkg.cpv].atoms:
+ blocker_atom = blocker_atom.lstrip("!")
+ blocker_atoms.append(blocker_atom)
+ blocker_parents.add(blocker_atom, pkg)
+
+ blocker_atoms = InternalPackageSet(initial_atoms=blocker_atoms)
+ blocking_pkgs = set()
+ for atom in blocker_atoms.iterAtomsForPackage(new_pkg):
+ blocking_pkgs.update(blocker_parents.parent_nodes(atom))
+
+ # Check for blockers in the other direction.
+ depstr = " ".join(new_pkg.metadata[k] for k in dep_keys)
+ success, atoms = portage.dep_check(depstr,
+ vardb, settings, myuse=new_pkg.use.enabled,
+ trees=dep_check_trees, myroot=new_pkg.root)
+ if not success:
+ # We should never get this far with invalid deps.
+ show_invalid_depstring_notice(new_pkg, depstr, atoms)
+ assert False
+
+ blocker_atoms = [atom.lstrip("!") for atom in atoms \
+ if atom[:1] == "!"]
+ if blocker_atoms:
+ blocker_atoms = InternalPackageSet(initial_atoms=blocker_atoms)
+ for inst_pkg in installed_pkgs:
+ try:
+ next(blocker_atoms.iterAtomsForPackage(inst_pkg))
+ except (portage.exception.InvalidDependString, StopIteration):
+ continue
+ blocking_pkgs.add(inst_pkg)
+
+ return blocking_pkgs
+
+ def discardBlocker(self, pkg):
+ """Discard a package from the list of potential blockers.
+ This will match any package(s) with identical cpv or cp:slot."""
+ for cpv_match in self._fake_vartree.dbapi.match_pkgs("=%s" % (pkg.cpv,)):
+ if cpv_match.cp == pkg.cp:
+ self._fake_vartree.cpv_discard(cpv_match)
+ for slot_match in self._fake_vartree.dbapi.match_pkgs(pkg.slot_atom):
+ if slot_match.cp == pkg.cp:
+ self._fake_vartree.cpv_discard(slot_match)
diff --git a/portage_with_autodep/pym/_emerge/BlockerDepPriority.py b/portage_with_autodep/pym/_emerge/BlockerDepPriority.py
new file mode 100644
index 0000000..1004a37
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/BlockerDepPriority.py
@@ -0,0 +1,13 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.DepPriority import DepPriority
+class BlockerDepPriority(DepPriority):
+ __slots__ = ()
+ def __int__(self):
+ return 0
+
+ def __str__(self):
+ return 'blocker'
+
+BlockerDepPriority.instance = BlockerDepPriority()
diff --git a/portage_with_autodep/pym/_emerge/CompositeTask.py b/portage_with_autodep/pym/_emerge/CompositeTask.py
new file mode 100644
index 0000000..644a69b
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/CompositeTask.py
@@ -0,0 +1,157 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.AsynchronousTask import AsynchronousTask
+from portage import os
+
+class CompositeTask(AsynchronousTask):
+
+ __slots__ = ("scheduler",) + ("_current_task",)
+
+ _TASK_QUEUED = -1
+
+ def isAlive(self):
+ return self._current_task is not None
+
+ def _cancel(self):
+ if self._current_task is not None:
+ if self._current_task is self._TASK_QUEUED:
+ self.returncode = 1
+ self._current_task = None
+ else:
+ self._current_task.cancel()
+
+ def _poll(self):
+ """
+ This does a loop calling self._current_task.poll()
+ repeatedly as long as the value of self._current_task
+ keeps changing. It calls poll() a maximum of one time
+ for a given self._current_task instance. This is useful
+ since calling poll() on a task can trigger advance to
+ the next task could eventually lead to the returncode
+ being set in cases when polling only a single task would
+ not have the same effect.
+ """
+
+ prev = None
+ while True:
+ task = self._current_task
+ if task is None or \
+ task is self._TASK_QUEUED or \
+ task is prev:
+ # don't poll the same task more than once
+ break
+ task.poll()
+ prev = task
+
+ return self.returncode
+
+ def _wait(self):
+
+ prev = None
+ while True:
+ task = self._current_task
+ if task is None:
+ # don't wait for the same task more than once
+ break
+ if task is self._TASK_QUEUED:
+ if self.cancelled:
+ self.returncode = 1
+ self._current_task = None
+ break
+ else:
+ self.scheduler.schedule(condition=self._task_queued_wait)
+ if self.returncode is not None:
+ break
+ elif self.cancelled:
+ self.returncode = 1
+ self._current_task = None
+ break
+ else:
+ # try this again with new _current_task value
+ continue
+ if task is prev:
+ if self.returncode is not None:
+ # This is expected if we're being
+ # called from the task's exit listener
+ # after it's been cancelled.
+ break
+ # Before the task.wait() method returned, an exit
+ # listener should have set self._current_task to either
+ # a different task or None. Something is wrong.
+ raise AssertionError("self._current_task has not " + \
+ "changed since calling wait", self, task)
+ task.wait()
+ prev = task
+
+ return self.returncode
+
+ def _assert_current(self, task):
+ """
+ Raises an AssertionError if the given task is not the
+ same one as self._current_task. This can be useful
+ for detecting bugs.
+ """
+ if task is not self._current_task:
+ raise AssertionError("Unrecognized task: %s" % (task,))
+
+ def _default_exit(self, task):
+ """
+ Calls _assert_current() on the given task and then sets the
+ composite returncode attribute if task.returncode != os.EX_OK.
+ If the task failed then self._current_task will be set to None.
+ Subclasses can use this as a generic task exit callback.
+
+ @rtype: int
+ @returns: The task.returncode attribute.
+ """
+ self._assert_current(task)
+ if task.returncode != os.EX_OK:
+ self.returncode = task.returncode
+ self._current_task = None
+ return task.returncode
+
+ def _final_exit(self, task):
+ """
+ Assumes that task is the final task of this composite task.
+ Calls _default_exit() and sets self.returncode to the task's
+ returncode and sets self._current_task to None.
+ """
+ self._default_exit(task)
+ self._current_task = None
+ self.returncode = task.returncode
+ return self.returncode
+
+ def _default_final_exit(self, task):
+ """
+ This calls _final_exit() and then wait().
+
+ Subclasses can use this as a generic final task exit callback.
+
+ """
+ self._final_exit(task)
+ return self.wait()
+
+ def _start_task(self, task, exit_handler):
+ """
+ Register exit handler for the given task, set it
+ as self._current_task, and call task.start().
+
+ Subclasses can use this as a generic way to start
+ a task.
+
+ """
+ task.addExitListener(exit_handler)
+ self._current_task = task
+ task.start()
+
+ def _task_queued(self, task):
+ task.addStartListener(self._task_queued_start_handler)
+ self._current_task = self._TASK_QUEUED
+
+ def _task_queued_start_handler(self, task):
+ self._current_task = task
+
+ def _task_queued_wait(self):
+ return self._current_task is not self._TASK_QUEUED or \
+ self.cancelled or self.returncode is not None
diff --git a/portage_with_autodep/pym/_emerge/DepPriority.py b/portage_with_autodep/pym/_emerge/DepPriority.py
new file mode 100644
index 0000000..3c2256a
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/DepPriority.py
@@ -0,0 +1,49 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.AbstractDepPriority import AbstractDepPriority
+class DepPriority(AbstractDepPriority):
+
+ __slots__ = ("satisfied", "optional", "ignored")
+
+ def __int__(self):
+ """
+ Note: These priorities are only used for measuring hardness
+ in the circular dependency display via digraph.debug_print(),
+ and nothing more. For actual merge order calculations, the
+ measures defined by the DepPriorityNormalRange and
+ DepPrioritySatisfiedRange classes are used.
+
+ Attributes Hardness
+
+ buildtime 0
+ runtime -1
+ runtime_post -2
+ optional -3
+ (none of the above) -4
+
+ """
+
+ if self.optional:
+ return -3
+ if self.buildtime:
+ return 0
+ if self.runtime:
+ return -1
+ if self.runtime_post:
+ return -2
+ return -4
+
+ def __str__(self):
+ if self.ignored:
+ return "ignored"
+ if self.optional:
+ return "optional"
+ if self.buildtime:
+ return "buildtime"
+ if self.runtime:
+ return "runtime"
+ if self.runtime_post:
+ return "runtime_post"
+ return "soft"
+
diff --git a/portage_with_autodep/pym/_emerge/DepPriorityNormalRange.py b/portage_with_autodep/pym/_emerge/DepPriorityNormalRange.py
new file mode 100644
index 0000000..8639554
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/DepPriorityNormalRange.py
@@ -0,0 +1,47 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.DepPriority import DepPriority
+class DepPriorityNormalRange(object):
+ """
+ DepPriority properties Index Category
+
+ buildtime HARD
+ runtime 3 MEDIUM
+ runtime_post 2 MEDIUM_SOFT
+ optional 1 SOFT
+ (none of the above) 0 NONE
+ """
+ MEDIUM = 3
+ MEDIUM_SOFT = 2
+ SOFT = 1
+ NONE = 0
+
+ @classmethod
+ def _ignore_optional(cls, priority):
+ if priority.__class__ is not DepPriority:
+ return False
+ return bool(priority.optional)
+
+ @classmethod
+ def _ignore_runtime_post(cls, priority):
+ if priority.__class__ is not DepPriority:
+ return False
+ return bool(priority.optional or priority.runtime_post)
+
+ @classmethod
+ def _ignore_runtime(cls, priority):
+ if priority.__class__ is not DepPriority:
+ return False
+ return bool(priority.optional or not priority.buildtime)
+
+ ignore_medium = _ignore_runtime
+ ignore_medium_soft = _ignore_runtime_post
+ ignore_soft = _ignore_optional
+
+DepPriorityNormalRange.ignore_priority = (
+ None,
+ DepPriorityNormalRange._ignore_optional,
+ DepPriorityNormalRange._ignore_runtime_post,
+ DepPriorityNormalRange._ignore_runtime
+)
diff --git a/portage_with_autodep/pym/_emerge/DepPrioritySatisfiedRange.py b/portage_with_autodep/pym/_emerge/DepPrioritySatisfiedRange.py
new file mode 100644
index 0000000..edb29df
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/DepPrioritySatisfiedRange.py
@@ -0,0 +1,85 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.DepPriority import DepPriority
+class DepPrioritySatisfiedRange(object):
+ """
+ DepPriority Index Category
+
+ not satisfied and buildtime HARD
+ not satisfied and runtime 6 MEDIUM
+ not satisfied and runtime_post 5 MEDIUM_SOFT
+ satisfied and buildtime 4 SOFT
+ satisfied and runtime 3 SOFT
+ satisfied and runtime_post 2 SOFT
+ optional 1 SOFT
+ (none of the above) 0 NONE
+ """
+ MEDIUM = 6
+ MEDIUM_SOFT = 5
+ SOFT = 4
+ NONE = 0
+
+ @classmethod
+ def _ignore_optional(cls, priority):
+ if priority.__class__ is not DepPriority:
+ return False
+ return bool(priority.optional)
+
+ @classmethod
+ def _ignore_satisfied_runtime_post(cls, priority):
+ if priority.__class__ is not DepPriority:
+ return False
+ if priority.optional:
+ return True
+ if not priority.satisfied:
+ return False
+ return bool(priority.runtime_post)
+
+ @classmethod
+ def _ignore_satisfied_runtime(cls, priority):
+ if priority.__class__ is not DepPriority:
+ return False
+ if priority.optional:
+ return True
+ if not priority.satisfied:
+ return False
+ return not priority.buildtime
+
+ @classmethod
+ def _ignore_satisfied_buildtime(cls, priority):
+ if priority.__class__ is not DepPriority:
+ return False
+ return bool(priority.optional or \
+ priority.satisfied)
+
+ @classmethod
+ def _ignore_runtime_post(cls, priority):
+ if priority.__class__ is not DepPriority:
+ return False
+ return bool(priority.optional or \
+ priority.satisfied or \
+ priority.runtime_post)
+
+ @classmethod
+ def _ignore_runtime(cls, priority):
+ if priority.__class__ is not DepPriority:
+ return False
+ return bool(priority.satisfied or \
+ priority.optional or \
+ not priority.buildtime)
+
+ ignore_medium = _ignore_runtime
+ ignore_medium_soft = _ignore_runtime_post
+ ignore_soft = _ignore_satisfied_buildtime
+
+
+DepPrioritySatisfiedRange.ignore_priority = (
+ None,
+ DepPrioritySatisfiedRange._ignore_optional,
+ DepPrioritySatisfiedRange._ignore_satisfied_runtime_post,
+ DepPrioritySatisfiedRange._ignore_satisfied_runtime,
+ DepPrioritySatisfiedRange._ignore_satisfied_buildtime,
+ DepPrioritySatisfiedRange._ignore_runtime_post,
+ DepPrioritySatisfiedRange._ignore_runtime
+)
diff --git a/portage_with_autodep/pym/_emerge/Dependency.py b/portage_with_autodep/pym/_emerge/Dependency.py
new file mode 100644
index 0000000..0f746b6
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/Dependency.py
@@ -0,0 +1,20 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.DepPriority import DepPriority
+from _emerge.SlotObject import SlotObject
+class Dependency(SlotObject):
+ __slots__ = ("atom", "blocker", "child", "depth",
+ "parent", "onlydeps", "priority", "root",
+ "collapsed_parent", "collapsed_priority")
+ def __init__(self, **kwargs):
+ SlotObject.__init__(self, **kwargs)
+ if self.priority is None:
+ self.priority = DepPriority()
+ if self.depth is None:
+ self.depth = 0
+ if self.collapsed_parent is None:
+ self.collapsed_parent = self.parent
+ if self.collapsed_priority is None:
+ self.collapsed_priority = self.priority
+
diff --git a/portage_with_autodep/pym/_emerge/DependencyArg.py b/portage_with_autodep/pym/_emerge/DependencyArg.py
new file mode 100644
index 0000000..861d837
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/DependencyArg.py
@@ -0,0 +1,33 @@
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+
+from portage import _encodings, _unicode_encode, _unicode_decode
+
+class DependencyArg(object):
+ def __init__(self, arg=None, root_config=None):
+ self.arg = arg
+ self.root_config = root_config
+
+ def __eq__(self, other):
+ if self.__class__ is not other.__class__:
+ return False
+ return self.arg == other.arg and \
+ self.root_config.root == other.root_config.root
+
+ def __hash__(self):
+ return hash((self.arg, self.root_config.root))
+
+ def __str__(self):
+ # Force unicode format string for python-2.x safety,
+ # ensuring that self.arg.__unicode__() is used
+ # when necessary.
+ return _unicode_decode("%s") % (self.arg,)
+
+ if sys.hexversion < 0x3000000:
+
+ __unicode__ = __str__
+
+ def __str__(self):
+ return _unicode_encode(self.__unicode__(), encoding=_encodings['content'])
diff --git a/portage_with_autodep/pym/_emerge/EbuildBinpkg.py b/portage_with_autodep/pym/_emerge/EbuildBinpkg.py
new file mode 100644
index 0000000..b7d43ba
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/EbuildBinpkg.py
@@ -0,0 +1,46 @@
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.CompositeTask import CompositeTask
+from _emerge.EbuildPhase import EbuildPhase
+from portage import os
+
+class EbuildBinpkg(CompositeTask):
+ """
+ This assumes that src_install() has successfully completed.
+ """
+ __slots__ = ('pkg', 'settings') + \
+ ('_binpkg_tmpfile',)
+
+ def _start(self):
+ pkg = self.pkg
+ root_config = pkg.root_config
+ bintree = root_config.trees["bintree"]
+ bintree.prevent_collision(pkg.cpv)
+ binpkg_tmpfile = os.path.join(bintree.pkgdir,
+ pkg.cpv + ".tbz2." + str(os.getpid()))
+ bintree._ensure_dir(os.path.dirname(binpkg_tmpfile))
+
+ self._binpkg_tmpfile = binpkg_tmpfile
+ self.settings["PORTAGE_BINPKG_TMPFILE"] = self._binpkg_tmpfile
+
+ package_phase = EbuildPhase(background=self.background,
+ phase='package', scheduler=self.scheduler,
+ settings=self.settings)
+
+ self._start_task(package_phase, self._package_phase_exit)
+
+ def _package_phase_exit(self, package_phase):
+
+ self.settings.pop("PORTAGE_BINPKG_TMPFILE", None)
+ if self._default_exit(package_phase) != os.EX_OK:
+ self.wait()
+ return
+
+ pkg = self.pkg
+ bintree = pkg.root_config.trees["bintree"]
+ bintree.inject(pkg.cpv, filename=self._binpkg_tmpfile)
+
+ self._current_task = None
+ self.returncode = os.EX_OK
+ self.wait()
diff --git a/portage_with_autodep/pym/_emerge/EbuildBuild.py b/portage_with_autodep/pym/_emerge/EbuildBuild.py
new file mode 100644
index 0000000..1c423a3
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/EbuildBuild.py
@@ -0,0 +1,426 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.EbuildExecuter import EbuildExecuter
+from _emerge.EbuildPhase import EbuildPhase
+from _emerge.EbuildBinpkg import EbuildBinpkg
+from _emerge.EbuildFetcher import EbuildFetcher
+from _emerge.CompositeTask import CompositeTask
+from _emerge.EbuildMerge import EbuildMerge
+from _emerge.EbuildFetchonly import EbuildFetchonly
+from _emerge.EbuildBuildDir import EbuildBuildDir
+from _emerge.EventsAnalyser import EventsAnalyser, FilterProcGenerator
+from _emerge.EventsLogger import EventsLogger
+from _emerge.MiscFunctionsProcess import MiscFunctionsProcess
+from portage.util import writemsg
+import portage
+from portage import os
+from portage.output import colorize
+from portage.package.ebuild.digestcheck import digestcheck
+from portage.package.ebuild.doebuild import _check_temp_dir
+from portage.package.ebuild._spawn_nofetch import spawn_nofetch
+
+class EbuildBuild(CompositeTask):
+
+ __slots__ = ("args_set", "config_pool", "find_blockers",
+ "ldpath_mtimes", "logger", "logserver", "opts", "pkg", "pkg_count",
+ "prefetcher", "settings", "world_atom") + \
+ ("_build_dir", "_buildpkg", "_ebuild_path", "_issyspkg", "_tree")
+
+ def _start(self):
+
+ pkg = self.pkg
+ settings = self.settings
+
+ rval = _check_temp_dir(settings)
+ if rval != os.EX_OK:
+ self.returncode = rval
+ self._current_task = None
+ self.wait()
+ return
+
+ root_config = pkg.root_config
+ tree = "porttree"
+ self._tree = tree
+ portdb = root_config.trees[tree].dbapi
+ settings.setcpv(pkg)
+ settings.configdict["pkg"]["EMERGE_FROM"] = "ebuild"
+ if self.opts.buildpkgonly:
+ settings.configdict["pkg"]["MERGE_TYPE"] = "buildonly"
+ else:
+ settings.configdict["pkg"]["MERGE_TYPE"] = "source"
+ ebuild_path = portdb.findname(pkg.cpv, myrepo=pkg.repo)
+ if ebuild_path is None:
+ raise AssertionError("ebuild not found for '%s'" % pkg.cpv)
+ self._ebuild_path = ebuild_path
+ portage.doebuild_environment(ebuild_path, 'setup',
+ settings=self.settings, db=portdb)
+
+ # Check the manifest here since with --keep-going mode it's
+ # currently possible to get this far with a broken manifest.
+ if not self._check_manifest():
+ self.returncode = 1
+ self._current_task = None
+ self.wait()
+ return
+
+ prefetcher = self.prefetcher
+ if prefetcher is None:
+ pass
+ elif prefetcher.isAlive() and \
+ prefetcher.poll() is None:
+
+ waiting_msg = "Fetching files " + \
+ "in the background. " + \
+ "To view fetch progress, run `tail -f " + \
+ "/var/log/emerge-fetch.log` in another " + \
+ "terminal."
+ msg_prefix = colorize("GOOD", " * ")
+ from textwrap import wrap
+ waiting_msg = "".join("%s%s\n" % (msg_prefix, line) \
+ for line in wrap(waiting_msg, 65))
+ if not self.background:
+ writemsg(waiting_msg, noiselevel=-1)
+
+ self._current_task = prefetcher
+ prefetcher.addExitListener(self._prefetch_exit)
+ return
+
+ self._prefetch_exit(prefetcher)
+
+ def _check_manifest(self):
+ success = True
+
+ settings = self.settings
+ if 'strict' in settings.features:
+ settings['O'] = os.path.dirname(self._ebuild_path)
+ quiet_setting = settings.get('PORTAGE_QUIET')
+ settings['PORTAGE_QUIET'] = '1'
+ try:
+ success = digestcheck([], settings, strict=True)
+ finally:
+ if quiet_setting:
+ settings['PORTAGE_QUIET'] = quiet_setting
+ else:
+ del settings['PORTAGE_QUIET']
+
+ return success
+
+ def _prefetch_exit(self, prefetcher):
+
+ opts = self.opts
+ pkg = self.pkg
+ settings = self.settings
+
+ if opts.fetchonly:
+ if opts.pretend:
+ fetcher = EbuildFetchonly(
+ fetch_all=opts.fetch_all_uri,
+ pkg=pkg, pretend=opts.pretend,
+ settings=settings)
+ retval = fetcher.execute()
+ self.returncode = retval
+ self.wait()
+ return
+ else:
+ fetcher = EbuildFetcher(
+ config_pool=self.config_pool,
+ ebuild_path=self._ebuild_path,
+ fetchall=self.opts.fetch_all_uri,
+ fetchonly=self.opts.fetchonly,
+ background=False,
+ logfile=None,
+ pkg=self.pkg,
+ scheduler=self.scheduler)
+ self._start_task(fetcher, self._fetchonly_exit)
+ return
+
+ self._build_dir = EbuildBuildDir(
+ scheduler=self.scheduler, settings=settings)
+ self._build_dir.lock()
+
+ # Cleaning needs to happen before fetch, since the build dir
+ # is used for log handling.
+ msg = " === (%s of %s) Cleaning (%s::%s)" % \
+ (self.pkg_count.curval, self.pkg_count.maxval,
+ self.pkg.cpv, self._ebuild_path)
+ short_msg = "emerge: (%s of %s) %s Clean" % \
+ (self.pkg_count.curval, self.pkg_count.maxval, self.pkg.cpv)
+ self.logger.log(msg, short_msg=short_msg)
+
+ pre_clean_phase = EbuildPhase(background=self.background,
+ phase='clean', scheduler=self.scheduler, settings=self.settings)
+ self._start_task(pre_clean_phase, self._pre_clean_exit)
+
+ def _fetchonly_exit(self, fetcher):
+ self._final_exit(fetcher)
+ if self.returncode != os.EX_OK:
+ portdb = self.pkg.root_config.trees[self._tree].dbapi
+ spawn_nofetch(portdb, self._ebuild_path, settings=self.settings)
+ self.wait()
+
+ def _pre_clean_exit(self, pre_clean_phase):
+ if self._default_exit(pre_clean_phase) != os.EX_OK:
+ self._unlock_builddir()
+ self.wait()
+ return
+
+ # for log handling
+ portage.prepare_build_dirs(self.pkg.root, self.settings, 1)
+
+ fetcher = EbuildFetcher(config_pool=self.config_pool,
+ ebuild_path=self._ebuild_path,
+ fetchall=self.opts.fetch_all_uri,
+ fetchonly=self.opts.fetchonly,
+ background=self.background,
+ logfile=self.settings.get('PORTAGE_LOG_FILE'),
+ pkg=self.pkg, scheduler=self.scheduler)
+
+ try:
+ already_fetched = fetcher.already_fetched(self.settings)
+ except portage.exception.InvalidDependString as e:
+ msg_lines = []
+ msg = "Fetch failed for '%s' due to invalid SRC_URI: %s" % \
+ (self.pkg.cpv, e)
+ msg_lines.append(msg)
+ fetcher._eerror(msg_lines)
+ portage.elog.elog_process(self.pkg.cpv, self.settings)
+ self.returncode = 1
+ self._current_task = None
+ self._unlock_builddir()
+ self.wait()
+ return
+
+ if already_fetched:
+ # This case is optimized to skip the fetch queue.
+ fetcher = None
+ self._fetch_exit(fetcher)
+ return
+
+ # Allow the Scheduler's fetch queue to control the
+ # number of concurrent fetchers.
+ fetcher.addExitListener(self._fetch_exit)
+ self._task_queued(fetcher)
+ self.scheduler.fetch.schedule(fetcher)
+
+ def _fetch_exit(self, fetcher):
+
+ if fetcher is not None and \
+ self._default_exit(fetcher) != os.EX_OK:
+ self._fetch_failed()
+ return
+
+ # discard successful fetch log
+ self._build_dir.clean_log()
+ pkg = self.pkg
+ logger = self.logger
+ opts = self.opts
+ pkg_count = self.pkg_count
+ scheduler = self.scheduler
+ settings = self.settings
+ features = settings.features
+ ebuild_path = self._ebuild_path
+ system_set = pkg.root_config.sets["system"]
+
+ #buildsyspkg: Check if we need to _force_ binary package creation
+ self._issyspkg = "buildsyspkg" in features and \
+ system_set.findAtomForPackage(pkg) and \
+ not opts.buildpkg
+
+ if opts.buildpkg or self._issyspkg:
+
+ self._buildpkg = True
+
+ msg = " === (%s of %s) Compiling/Packaging (%s::%s)" % \
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
+ short_msg = "emerge: (%s of %s) %s Compile" % \
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv)
+ logger.log(msg, short_msg=short_msg)
+
+ else:
+ msg = " === (%s of %s) Compiling/Merging (%s::%s)" % \
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
+ short_msg = "emerge: (%s of %s) %s Compile" % \
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv)
+ logger.log(msg, short_msg=short_msg)
+
+ build = EbuildExecuter(background=self.background, pkg=pkg,
+ scheduler=scheduler, settings=settings)
+
+ build.addStartListener(self._build_start)
+ build.addExitListener(self._build_stop)
+
+ self._start_task(build, self._build_exit)
+
+ def _build_start(self,phase):
+ if "depcheck" in self.settings["FEATURES"] or \
+ "depcheckstrict" in self.settings["FEATURES"]:
+ # Lets start a log listening server
+ temp_path=self.settings.get("T",self.settings["PORTAGE_TMPDIR"])
+
+ if "depcheckstrict" not in self.settings["FEATURES"]:
+ # use default filter_proc
+ self.logserver=EventsLogger(socket_dir=temp_path)
+ else:
+ portage.util.writemsg("Getting list of allowed files..." + \
+ "This may take some time\n")
+ filter_gen=FilterProcGenerator(self.pkg.cpv, self.settings)
+ filter_proc=filter_gen.get_filter_proc()
+ self.logserver=EventsLogger(socket_dir=temp_path,
+ filter_proc=filter_proc)
+
+ self.logserver.start()
+
+ # Copy socket path to LOG_SOCKET environment variable
+ env=self.settings.configdict["pkg"]
+ env['LOG_SOCKET'] = self.logserver.socket_name
+
+ #import pdb; pdb.set_trace()
+
+ def _build_stop(self,phase):
+ if "depcheck" in self.settings["FEATURES"] or \
+ "depcheckstrict" in self.settings["FEATURES"]:
+ # Delete LOG_SOCKET from environment
+ env=self.settings.configdict["pkg"]
+ if 'LOG_SOCKET' in env:
+ del env['LOG_SOCKET']
+
+ events=self.logserver.stop()
+ self.logserver=None
+ analyser=EventsAnalyser(self.pkg.cpv, events, self.settings)
+ analyser.display() # show the analyse
+
+ #import pdb; pdb.set_trace()
+
+
+
+ def _fetch_failed(self):
+ # We only call the pkg_nofetch phase if either RESTRICT=fetch
+ # is set or the package has explicitly overridden the default
+ # pkg_nofetch implementation. This allows specialized messages
+ # to be displayed for problematic packages even though they do
+ # not set RESTRICT=fetch (bug #336499).
+
+ if 'fetch' not in self.pkg.metadata.restrict and \
+ 'nofetch' not in self.pkg.metadata.defined_phases:
+ self._unlock_builddir()
+ self.wait()
+ return
+
+ self.returncode = None
+ nofetch_phase = EbuildPhase(background=self.background,
+ phase='nofetch', scheduler=self.scheduler, settings=self.settings)
+ self._start_task(nofetch_phase, self._nofetch_exit)
+
+ def _nofetch_exit(self, nofetch_phase):
+ self._final_exit(nofetch_phase)
+ self._unlock_builddir()
+ self.returncode = 1
+ self.wait()
+
+ def _unlock_builddir(self):
+ portage.elog.elog_process(self.pkg.cpv, self.settings)
+ self._build_dir.unlock()
+
+ def _build_exit(self, build):
+ if self._default_exit(build) != os.EX_OK:
+ self._unlock_builddir()
+ self.wait()
+ return
+
+ buildpkg = self._buildpkg
+
+ if not buildpkg:
+ self._final_exit(build)
+ self.wait()
+ return
+
+ if self._issyspkg:
+ msg = ">>> This is a system package, " + \
+ "let's pack a rescue tarball.\n"
+ self.scheduler.output(msg,
+ log_path=self.settings.get("PORTAGE_LOG_FILE"))
+
+ packager = EbuildBinpkg(background=self.background, pkg=self.pkg,
+ scheduler=self.scheduler, settings=self.settings)
+
+ self._start_task(packager, self._buildpkg_exit)
+
+ def _buildpkg_exit(self, packager):
+ """
+ Released build dir lock when there is a failure or
+ when in buildpkgonly mode. Otherwise, the lock will
+ be released when merge() is called.
+ """
+
+ if self._default_exit(packager) != os.EX_OK:
+ self._unlock_builddir()
+ self.wait()
+ return
+
+ if self.opts.buildpkgonly:
+ phase = 'success_hooks'
+ success_hooks = MiscFunctionsProcess(
+ background=self.background,
+ commands=[phase], phase=phase,
+ scheduler=self.scheduler, settings=self.settings)
+ self._start_task(success_hooks,
+ self._buildpkgonly_success_hook_exit)
+ return
+
+ # Continue holding the builddir lock until
+ # after the package has been installed.
+ self._current_task = None
+ self.returncode = packager.returncode
+ self.wait()
+
+ def _buildpkgonly_success_hook_exit(self, success_hooks):
+ self._default_exit(success_hooks)
+ self.returncode = None
+ # Need to call "clean" phase for buildpkgonly mode
+ portage.elog.elog_process(self.pkg.cpv, self.settings)
+ phase = 'clean'
+ clean_phase = EbuildPhase(background=self.background,
+ phase=phase, scheduler=self.scheduler, settings=self.settings)
+ self._start_task(clean_phase, self._clean_exit)
+
+ def _clean_exit(self, clean_phase):
+ if self._final_exit(clean_phase) != os.EX_OK or \
+ self.opts.buildpkgonly:
+ self._unlock_builddir()
+ self.wait()
+
+ def create_install_task(self):
+ """
+ Install the package and then clean up and release locks.
+ Only call this after the build has completed successfully
+ and neither fetchonly nor buildpkgonly mode are enabled.
+ """
+
+ ldpath_mtimes = self.ldpath_mtimes
+ logger = self.logger
+ pkg = self.pkg
+ pkg_count = self.pkg_count
+ settings = self.settings
+ world_atom = self.world_atom
+ ebuild_path = self._ebuild_path
+ tree = self._tree
+
+ task = EbuildMerge(find_blockers=self.find_blockers,
+ ldpath_mtimes=ldpath_mtimes, logger=logger, pkg=pkg,
+ pkg_count=pkg_count, pkg_path=ebuild_path,
+ scheduler=self.scheduler,
+ settings=settings, tree=tree, world_atom=world_atom)
+
+ msg = " === (%s of %s) Merging (%s::%s)" % \
+ (pkg_count.curval, pkg_count.maxval,
+ pkg.cpv, ebuild_path)
+ short_msg = "emerge: (%s of %s) %s Merge" % \
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv)
+ logger.log(msg, short_msg=short_msg)
+
+ task.addExitListener(self._install_exit)
+ return task
+
+ def _install_exit(self, task):
+ self._unlock_builddir()
diff --git a/portage_with_autodep/pym/_emerge/EbuildBuildDir.py b/portage_with_autodep/pym/_emerge/EbuildBuildDir.py
new file mode 100644
index 0000000..ddc5fe0
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/EbuildBuildDir.py
@@ -0,0 +1,109 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.AsynchronousLock import AsynchronousLock
+from _emerge.SlotObject import SlotObject
+import portage
+from portage import os
+from portage.exception import PortageException
+import errno
+
+class EbuildBuildDir(SlotObject):
+
+ __slots__ = ("scheduler", "settings",
+ "locked", "_catdir", "_lock_obj")
+
+ def __init__(self, **kwargs):
+ SlotObject.__init__(self, **kwargs)
+ self.locked = False
+
+ def lock(self):
+ """
+ This raises an AlreadyLocked exception if lock() is called
+ while a lock is already held. In order to avoid this, call
+ unlock() or check whether the "locked" attribute is True
+ or False before calling lock().
+ """
+ if self._lock_obj is not None:
+ raise self.AlreadyLocked((self._lock_obj,))
+
+ dir_path = self.settings.get('PORTAGE_BUILDDIR')
+ if not dir_path:
+ raise AssertionError('PORTAGE_BUILDDIR is unset')
+ catdir = os.path.dirname(dir_path)
+ self._catdir = catdir
+
+ try:
+ portage.util.ensure_dirs(os.path.dirname(catdir),
+ gid=portage.portage_gid,
+ mode=0o70, mask=0)
+ except PortageException:
+ if not os.path.isdir(os.path.dirname(catdir)):
+ raise
+ catdir_lock = AsynchronousLock(path=catdir, scheduler=self.scheduler)
+ catdir_lock.start()
+ catdir_lock.wait()
+ self._assert_lock(catdir_lock)
+
+ try:
+ try:
+ portage.util.ensure_dirs(catdir,
+ gid=portage.portage_gid,
+ mode=0o70, mask=0)
+ except PortageException:
+ if not os.path.isdir(catdir):
+ raise
+ builddir_lock = AsynchronousLock(path=dir_path,
+ scheduler=self.scheduler)
+ builddir_lock.start()
+ builddir_lock.wait()
+ self._assert_lock(builddir_lock)
+ self._lock_obj = builddir_lock
+ self.settings['PORTAGE_BUILDIR_LOCKED'] = '1'
+ finally:
+ self.locked = self._lock_obj is not None
+ catdir_lock.unlock()
+
+ def _assert_lock(self, async_lock):
+ if async_lock.returncode != os.EX_OK:
+ # TODO: create a better way to propagate this error to the caller
+ raise AssertionError("AsynchronousLock failed with returncode %s" \
+ % (async_lock.returncode,))
+
+ def clean_log(self):
+ """Discard existing log. The log will not be be discarded
+ in cases when it would not make sense, like when FEATURES=keepwork
+ is enabled."""
+ settings = self.settings
+ if 'keepwork' in settings.features:
+ return
+ log_file = settings.get('PORTAGE_LOG_FILE')
+ if log_file is not None and os.path.isfile(log_file):
+ try:
+ os.unlink(log_file)
+ except OSError:
+ pass
+
+ def unlock(self):
+ if self._lock_obj is None:
+ return
+
+ self._lock_obj.unlock()
+ self._lock_obj = None
+ self.locked = False
+ self.settings.pop('PORTAGE_BUILDIR_LOCKED', None)
+ catdir_lock = AsynchronousLock(path=self._catdir, scheduler=self.scheduler)
+ catdir_lock.start()
+ if catdir_lock.wait() == os.EX_OK:
+ try:
+ os.rmdir(self._catdir)
+ except OSError as e:
+ if e.errno not in (errno.ENOENT,
+ errno.ENOTEMPTY, errno.EEXIST, errno.EPERM):
+ raise
+ finally:
+ catdir_lock.unlock()
+
+ class AlreadyLocked(portage.exception.PortageException):
+ pass
+
diff --git a/portage_with_autodep/pym/_emerge/EbuildExecuter.py b/portage_with_autodep/pym/_emerge/EbuildExecuter.py
new file mode 100644
index 0000000..f8febd4
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/EbuildExecuter.py
@@ -0,0 +1,99 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.EbuildPhase import EbuildPhase
+from _emerge.TaskSequence import TaskSequence
+from _emerge.CompositeTask import CompositeTask
+import portage
+from portage import os
+from portage.eapi import eapi_has_src_prepare_and_src_configure, \
+ eapi_exports_replace_vars
+from portage.package.ebuild.doebuild import _prepare_fake_distdir
+
+class EbuildExecuter(CompositeTask):
+
+ __slots__ = ("pkg", "scheduler", "settings")
+
+ _phases = ("prepare", "configure", "compile", "test", "install")
+
+ _live_eclasses = frozenset([
+ "bzr",
+ "cvs",
+ "darcs",
+ "git",
+ "git-2",
+ "mercurial",
+ "subversion",
+ "tla",
+ ])
+
+ def _start(self):
+ pkg = self.pkg
+ scheduler = self.scheduler
+ settings = self.settings
+ cleanup = 0
+ portage.prepare_build_dirs(pkg.root, settings, cleanup)
+
+ portdb = pkg.root_config.trees['porttree'].dbapi
+ ebuild_path = settings['EBUILD']
+ alist = settings.configdict["pkg"].get("A", "").split()
+ _prepare_fake_distdir(settings, alist)
+
+ if eapi_exports_replace_vars(settings['EAPI']):
+ vardb = pkg.root_config.trees['vartree'].dbapi
+ settings["REPLACING_VERSIONS"] = " ".join(
+ set(portage.versions.cpv_getversion(match) \
+ for match in vardb.match(pkg.slot_atom) + \
+ vardb.match('='+pkg.cpv)))
+
+ setup_phase = EbuildPhase(background=self.background,
+ phase="setup", scheduler=scheduler,
+ settings=settings)
+
+ setup_phase.addExitListener(self._setup_exit)
+ self._task_queued(setup_phase)
+ self.scheduler.scheduleSetup(setup_phase)
+
+ def _setup_exit(self, setup_phase):
+
+ if self._default_exit(setup_phase) != os.EX_OK:
+ self.wait()
+ return
+
+ unpack_phase = EbuildPhase(background=self.background,
+ phase="unpack", scheduler=self.scheduler,
+ settings=self.settings)
+
+ if self._live_eclasses.intersection(self.pkg.inherited):
+ # Serialize $DISTDIR access for live ebuilds since
+ # otherwise they can interfere with eachother.
+
+ unpack_phase.addExitListener(self._unpack_exit)
+ self._task_queued(unpack_phase)
+ self.scheduler.scheduleUnpack(unpack_phase)
+
+ else:
+ self._start_task(unpack_phase, self._unpack_exit)
+
+ def _unpack_exit(self, unpack_phase):
+
+ if self._default_exit(unpack_phase) != os.EX_OK:
+ self.wait()
+ return
+
+ ebuild_phases = TaskSequence(scheduler=self.scheduler)
+
+ pkg = self.pkg
+ phases = self._phases
+ eapi = pkg.metadata["EAPI"]
+ if not eapi_has_src_prepare_and_src_configure(eapi):
+ # skip src_prepare and src_configure
+ phases = phases[2:]
+
+ for phase in phases:
+ ebuild_phases.add(EbuildPhase(background=self.background,
+ phase=phase, scheduler=self.scheduler,
+ settings=self.settings))
+
+ self._start_task(ebuild_phases, self._default_final_exit)
+
diff --git a/portage_with_autodep/pym/_emerge/EbuildFetcher.py b/portage_with_autodep/pym/_emerge/EbuildFetcher.py
new file mode 100644
index 0000000..feb68d0
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/EbuildFetcher.py
@@ -0,0 +1,302 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import traceback
+
+from _emerge.SpawnProcess import SpawnProcess
+import copy
+import io
+import signal
+import sys
+import portage
+from portage import os
+from portage import _encodings
+from portage import _unicode_encode
+from portage import _unicode_decode
+from portage.elog.messages import eerror
+from portage.package.ebuild.fetch import _check_distfile, fetch
+from portage.util._pty import _create_pty_or_pipe
+
+class EbuildFetcher(SpawnProcess):
+
+ __slots__ = ("config_pool", "ebuild_path", "fetchonly", "fetchall",
+ "pkg", "prefetch") + \
+ ("_digests", "_settings", "_uri_map")
+
+ def already_fetched(self, settings):
+ """
+ Returns True if all files already exist locally and have correct
+ digests, otherwise return False. When returning True, appropriate
+ digest checking messages are produced for display and/or logging.
+ When returning False, no messages are produced, since we assume
+ that a fetcher process will later be executed in order to produce
+ such messages. This will raise InvalidDependString if SRC_URI is
+ invalid.
+ """
+
+ uri_map = self._get_uri_map()
+ if not uri_map:
+ return True
+
+ digests = self._get_digests()
+ distdir = settings["DISTDIR"]
+ allow_missing = "allow-missing-manifests" in settings.features
+
+ for filename in uri_map:
+ # Use stat rather than lstat since fetch() creates
+ # symlinks when PORTAGE_RO_DISTDIRS is used.
+ try:
+ st = os.stat(os.path.join(distdir, filename))
+ except OSError:
+ return False
+ if st.st_size == 0:
+ return False
+ expected_size = digests.get(filename, {}).get('size')
+ if expected_size is None:
+ continue
+ if st.st_size != expected_size:
+ return False
+
+ stdout_orig = sys.stdout
+ stderr_orig = sys.stderr
+ global_havecolor = portage.output.havecolor
+ out = io.StringIO()
+ eout = portage.output.EOutput()
+ eout.quiet = settings.get("PORTAGE_QUIET") == "1"
+ success = True
+ try:
+ sys.stdout = out
+ sys.stderr = out
+ if portage.output.havecolor:
+ portage.output.havecolor = not self.background
+
+ for filename in uri_map:
+ mydigests = digests.get(filename)
+ if mydigests is None:
+ if not allow_missing:
+ success = False
+ break
+ continue
+ ok, st = _check_distfile(os.path.join(distdir, filename),
+ mydigests, eout, show_errors=False)
+ if not ok:
+ success = False
+ break
+ except portage.exception.FileNotFound:
+ # A file disappeared unexpectedly.
+ return False
+ finally:
+ sys.stdout = stdout_orig
+ sys.stderr = stderr_orig
+ portage.output.havecolor = global_havecolor
+
+ if success:
+ # When returning unsuccessfully, no messages are produced, since
+ # we assume that a fetcher process will later be executed in order
+ # to produce such messages.
+ msg = out.getvalue()
+ if msg:
+ self.scheduler.output(msg, log_path=self.logfile)
+
+ return success
+
+ def _start(self):
+
+ root_config = self.pkg.root_config
+ portdb = root_config.trees["porttree"].dbapi
+ ebuild_path = self._get_ebuild_path()
+
+ try:
+ uri_map = self._get_uri_map()
+ except portage.exception.InvalidDependString as e:
+ msg_lines = []
+ msg = "Fetch failed for '%s' due to invalid SRC_URI: %s" % \
+ (self.pkg.cpv, e)
+ msg_lines.append(msg)
+ self._eerror(msg_lines)
+ self._set_returncode((self.pid, 1 << 8))
+ self.wait()
+ return
+
+ if not uri_map:
+ # Nothing to fetch.
+ self._set_returncode((self.pid, os.EX_OK << 8))
+ self.wait()
+ return
+
+ settings = self.config_pool.allocate()
+ settings.setcpv(self.pkg)
+ portage.doebuild_environment(ebuild_path, 'fetch',
+ settings=settings, db=portdb)
+
+ if self.prefetch and \
+ self._prefetch_size_ok(uri_map, settings, ebuild_path):
+ self.config_pool.deallocate(settings)
+ self._set_returncode((self.pid, os.EX_OK << 8))
+ self.wait()
+ return
+
+ nocolor = settings.get("NOCOLOR")
+
+ if self.prefetch:
+ settings["PORTAGE_PARALLEL_FETCHONLY"] = "1"
+
+ if self.background:
+ nocolor = "true"
+
+ if nocolor is not None:
+ settings["NOCOLOR"] = nocolor
+
+ self._settings = settings
+ SpawnProcess._start(self)
+
+ # Free settings now since it's no longer needed in
+ # this process (the subprocess has a private copy).
+ self.config_pool.deallocate(settings)
+ settings = None
+ self._settings = None
+
+ def _spawn(self, args, fd_pipes=None, **kwargs):
+ """
+ Fork a subprocess, apply local settings, and call fetch().
+ """
+
+ pid = os.fork()
+ if pid != 0:
+ portage.process.spawned_pids.append(pid)
+ return [pid]
+
+ portage.process._setup_pipes(fd_pipes)
+
+ # Use default signal handlers in order to avoid problems
+ # killing subprocesses as reported in bug #353239.
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+ signal.signal(signal.SIGTERM, signal.SIG_DFL)
+
+ # Force consistent color output, in case we are capturing fetch
+ # output through a normal pipe due to unavailability of ptys.
+ portage.output.havecolor = self._settings.get('NOCOLOR') \
+ not in ('yes', 'true')
+
+ rval = 1
+ allow_missing = 'allow-missing-manifests' in self._settings.features
+ try:
+ if fetch(self._uri_map, self._settings, fetchonly=self.fetchonly,
+ digests=copy.deepcopy(self._get_digests()),
+ allow_missing_digests=allow_missing):
+ rval = os.EX_OK
+ except SystemExit:
+ raise
+ except:
+ traceback.print_exc()
+ finally:
+ # Call os._exit() from finally block, in order to suppress any
+ # finally blocks from earlier in the call stack. See bug #345289.
+ os._exit(rval)
+
+ def _get_ebuild_path(self):
+ if self.ebuild_path is not None:
+ return self.ebuild_path
+ portdb = self.pkg.root_config.trees["porttree"].dbapi
+ self.ebuild_path = portdb.findname(self.pkg.cpv, myrepo=self.pkg.repo)
+ if self.ebuild_path is None:
+ raise AssertionError("ebuild not found for '%s'" % self.pkg.cpv)
+ return self.ebuild_path
+
+ def _get_digests(self):
+ if self._digests is not None:
+ return self._digests
+ self._digests = portage.Manifest(os.path.dirname(
+ self._get_ebuild_path()), None).getTypeDigests("DIST")
+ return self._digests
+
+ def _get_uri_map(self):
+ """
+ This can raise InvalidDependString from portdbapi.getFetchMap().
+ """
+ if self._uri_map is not None:
+ return self._uri_map
+ pkgdir = os.path.dirname(self._get_ebuild_path())
+ mytree = os.path.dirname(os.path.dirname(pkgdir))
+ use = None
+ if not self.fetchall:
+ use = self.pkg.use.enabled
+ portdb = self.pkg.root_config.trees["porttree"].dbapi
+ self._uri_map = portdb.getFetchMap(self.pkg.cpv,
+ useflags=use, mytree=mytree)
+ return self._uri_map
+
+ def _prefetch_size_ok(self, uri_map, settings, ebuild_path):
+ distdir = settings["DISTDIR"]
+
+ sizes = {}
+ for filename in uri_map:
+ # Use stat rather than lstat since portage.fetch() creates
+ # symlinks when PORTAGE_RO_DISTDIRS is used.
+ try:
+ st = os.stat(os.path.join(distdir, filename))
+ except OSError:
+ return False
+ if st.st_size == 0:
+ return False
+ sizes[filename] = st.st_size
+
+ digests = self._get_digests()
+ for filename, actual_size in sizes.items():
+ size = digests.get(filename, {}).get('size')
+ if size is None:
+ continue
+ if size != actual_size:
+ return False
+
+ # All files are present and sizes are ok. In this case the normal
+ # fetch code will be skipped, so we need to generate equivalent
+ # output here.
+ if self.logfile is not None:
+ f = io.open(_unicode_encode(self.logfile,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='a', encoding=_encodings['content'],
+ errors='backslashreplace')
+ for filename in uri_map:
+ f.write(_unicode_decode((' * %s size ;-) ...' % \
+ filename).ljust(73) + '[ ok ]\n'))
+ f.close()
+
+ return True
+
+ def _pipe(self, fd_pipes):
+ """When appropriate, use a pty so that fetcher progress bars,
+ like wget has, will work properly."""
+ if self.background or not sys.stdout.isatty():
+ # When the output only goes to a log file,
+ # there's no point in creating a pty.
+ return os.pipe()
+ stdout_pipe = None
+ if not self.background:
+ stdout_pipe = fd_pipes.get(1)
+ got_pty, master_fd, slave_fd = \
+ _create_pty_or_pipe(copy_term_size=stdout_pipe)
+ return (master_fd, slave_fd)
+
+ def _eerror(self, lines):
+ out = io.StringIO()
+ for line in lines:
+ eerror(line, phase="unpack", key=self.pkg.cpv, out=out)
+ msg = out.getvalue()
+ if msg:
+ self.scheduler.output(msg, log_path=self.logfile)
+
+ def _set_returncode(self, wait_retval):
+ SpawnProcess._set_returncode(self, wait_retval)
+ # Collect elog messages that might have been
+ # created by the pkg_nofetch phase.
+ # Skip elog messages for prefetch, in order to avoid duplicates.
+ if not self.prefetch and self.returncode != os.EX_OK:
+ msg_lines = []
+ msg = "Fetch failed for '%s'" % (self.pkg.cpv,)
+ if self.logfile is not None:
+ msg += ", Log file:"
+ msg_lines.append(msg)
+ if self.logfile is not None:
+ msg_lines.append(" '%s'" % (self.logfile,))
+ self._eerror(msg_lines)
diff --git a/portage_with_autodep/pym/_emerge/EbuildFetchonly.py b/portage_with_autodep/pym/_emerge/EbuildFetchonly.py
new file mode 100644
index 0000000..b898971
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/EbuildFetchonly.py
@@ -0,0 +1,32 @@
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.SlotObject import SlotObject
+import portage
+from portage import os
+from portage.elog.messages import eerror
+
+class EbuildFetchonly(SlotObject):
+
+ __slots__ = ("fetch_all", "pkg", "pretend", "settings")
+
+ def execute(self):
+ settings = self.settings
+ pkg = self.pkg
+ portdb = pkg.root_config.trees["porttree"].dbapi
+ ebuild_path = portdb.findname(pkg.cpv, myrepo=pkg.repo)
+ if ebuild_path is None:
+ raise AssertionError("ebuild not found for '%s'" % pkg.cpv)
+ settings.setcpv(pkg)
+ debug = settings.get("PORTAGE_DEBUG") == "1"
+
+ rval = portage.doebuild(ebuild_path, "fetch",
+ settings["ROOT"], settings, debug=debug,
+ listonly=self.pretend, fetchonly=1, fetchall=self.fetch_all,
+ mydbapi=portdb, tree="porttree")
+
+ if rval != os.EX_OK:
+ msg = "Fetch failed for '%s'" % (pkg.cpv,)
+ eerror(msg, phase="unpack", key=pkg.cpv)
+
+ return rval
diff --git a/portage_with_autodep/pym/_emerge/EbuildIpcDaemon.py b/portage_with_autodep/pym/_emerge/EbuildIpcDaemon.py
new file mode 100644
index 0000000..5dabe34
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/EbuildIpcDaemon.py
@@ -0,0 +1,108 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import errno
+import logging
+import pickle
+from portage import os
+from portage.localization import _
+from portage.util import writemsg_level
+from _emerge.FifoIpcDaemon import FifoIpcDaemon
+from _emerge.PollConstants import PollConstants
+
+class EbuildIpcDaemon(FifoIpcDaemon):
+ """
+ This class serves as an IPC daemon, which ebuild processes can use
+ to communicate with portage's main python process.
+
+ Here are a few possible uses:
+
+ 1) Robust subshell/subprocess die support. This allows the ebuild
+ environment to reliably die without having to rely on signal IPC.
+
+ 2) Delegation of portageq calls to the main python process, eliminating
+ performance and userpriv permission issues.
+
+ 3) Reliable ebuild termination in cases when the ebuild has accidentally
+ left orphan processes running in the background (as in bug #278895).
+
+ 4) Detect cases in which bash has exited unexpectedly (as in bug #190128).
+ """
+
+ __slots__ = ('commands',)
+
+ def _input_handler(self, fd, event):
+ # Read the whole pickle in a single atomic read() call.
+ data = None
+ if event & PollConstants.POLLIN:
+ # For maximum portability, use os.read() here since
+ # array.fromfile() and file.read() are both known to
+ # erroneously return an empty string from this
+ # non-blocking fifo stream on FreeBSD (bug #337465).
+ try:
+ data = os.read(fd, self._bufsize)
+ except OSError as e:
+ if e.errno != errno.EAGAIN:
+ raise
+ # Assume that another event will be generated
+ # if there's any relevant data.
+
+ if data:
+
+ try:
+ obj = pickle.loads(data)
+ except SystemExit:
+ raise
+ except Exception:
+ # The pickle module can raise practically
+ # any exception when given corrupt data.
+ pass
+ else:
+
+ self._reopen_input()
+
+ cmd_key = obj[0]
+ cmd_handler = self.commands[cmd_key]
+ reply = cmd_handler(obj)
+ try:
+ self._send_reply(reply)
+ except OSError as e:
+ if e.errno == errno.ENXIO:
+ # This happens if the client side has been killed.
+ pass
+ else:
+ raise
+
+ # Allow the command to execute hooks after its reply
+ # has been sent. This hook is used by the 'exit'
+ # command to kill the ebuild process. For some
+ # reason, the ebuild-ipc helper hangs up the
+ # ebuild process if it is waiting for a reply
+ # when we try to kill the ebuild process.
+ reply_hook = getattr(cmd_handler,
+ 'reply_hook', None)
+ if reply_hook is not None:
+ reply_hook()
+
+ def _send_reply(self, reply):
+ # File streams are in unbuffered mode since we do atomic
+ # read and write of whole pickles. Use non-blocking mode so
+ # we don't hang if the client is killed before we can send
+ # the reply. We rely on the client opening the other side
+ # of this fifo before it sends its request, since otherwise
+ # we'd have a race condition with this open call raising
+ # ENXIO if the client hasn't opened the fifo yet.
+ try:
+ output_fd = os.open(self.output_fifo,
+ os.O_WRONLY | os.O_NONBLOCK)
+ try:
+ os.write(output_fd, pickle.dumps(reply))
+ finally:
+ os.close(output_fd)
+ except OSError as e:
+ # This probably means that the client has been killed,
+ # which causes open to fail with ENXIO.
+ writemsg_level(
+ "!!! EbuildIpcDaemon %s: %s\n" % \
+ (_('failed to send reply'), e),
+ level=logging.ERROR, noiselevel=-1)
diff --git a/portage_with_autodep/pym/_emerge/EbuildMerge.py b/portage_with_autodep/pym/_emerge/EbuildMerge.py
new file mode 100644
index 0000000..9c35988
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/EbuildMerge.py
@@ -0,0 +1,56 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.CompositeTask import CompositeTask
+from portage import os
+from portage.dbapi._MergeProcess import MergeProcess
+
+class EbuildMerge(CompositeTask):
+
+ __slots__ = ("find_blockers", "logger", "ldpath_mtimes",
+ "pkg", "pkg_count", "pkg_path", "pretend",
+ "settings", "tree", "world_atom")
+
+ def _start(self):
+ root_config = self.pkg.root_config
+ settings = self.settings
+ mycat = settings["CATEGORY"]
+ mypkg = settings["PF"]
+ pkgloc = settings["D"]
+ infloc = os.path.join(settings["PORTAGE_BUILDDIR"], "build-info")
+ myebuild = settings["EBUILD"]
+ mydbapi = root_config.trees[self.tree].dbapi
+ vartree = root_config.trees["vartree"]
+ background = (settings.get('PORTAGE_BACKGROUND') == '1')
+ logfile = settings.get('PORTAGE_LOG_FILE')
+
+ merge_task = MergeProcess(
+ mycat=mycat, mypkg=mypkg, settings=settings,
+ treetype=self.tree, vartree=vartree, scheduler=self.scheduler,
+ background=background, blockers=self.find_blockers, pkgloc=pkgloc,
+ infloc=infloc, myebuild=myebuild, mydbapi=mydbapi,
+ prev_mtimes=self.ldpath_mtimes, logfile=logfile)
+
+ self._start_task(merge_task, self._merge_exit)
+
+ def _merge_exit(self, merge_task):
+ if self._final_exit(merge_task) != os.EX_OK:
+ self.wait()
+ return
+
+ pkg = self.pkg
+ self.world_atom(pkg)
+ pkg_count = self.pkg_count
+ pkg_path = self.pkg_path
+ logger = self.logger
+ if "noclean" not in self.settings.features:
+ short_msg = "emerge: (%s of %s) %s Clean Post" % \
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv)
+ logger.log((" === (%s of %s) " + \
+ "Post-Build Cleaning (%s::%s)") % \
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg_path),
+ short_msg=short_msg)
+ logger.log(" ::: completed emerge (%s of %s) %s to %s" % \
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg.root))
+
+ self.wait()
diff --git a/portage_with_autodep/pym/_emerge/EbuildMetadataPhase.py b/portage_with_autodep/pym/_emerge/EbuildMetadataPhase.py
new file mode 100644
index 0000000..e53298b
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/EbuildMetadataPhase.py
@@ -0,0 +1,133 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.SubProcess import SubProcess
+from _emerge.PollConstants import PollConstants
+import sys
+from portage.cache.mappings import slot_dict_class
+import portage
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+import fcntl
+import io
+
+class EbuildMetadataPhase(SubProcess):
+
+ """
+ Asynchronous interface for the ebuild "depend" phase which is
+ used to extract metadata from the ebuild.
+ """
+
+ __slots__ = ("cpv", "ebuild_path", "fd_pipes", "metadata_callback",
+ "ebuild_mtime", "metadata", "portdb", "repo_path", "settings") + \
+ ("_raw_metadata",)
+
+ _file_names = ("ebuild",)
+ _files_dict = slot_dict_class(_file_names, prefix="")
+ _metadata_fd = 9
+
+ def _start(self):
+ settings = self.settings
+ settings.setcpv(self.cpv)
+ ebuild_path = self.ebuild_path
+
+ eapi = None
+ if eapi is None and \
+ 'parse-eapi-ebuild-head' in settings.features:
+ eapi = portage._parse_eapi_ebuild_head(
+ io.open(_unicode_encode(ebuild_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'],
+ errors='replace'))
+
+ if eapi is not None:
+ if not portage.eapi_is_supported(eapi):
+ self.metadata_callback(self.cpv, self.ebuild_path,
+ self.repo_path, {'EAPI' : eapi}, self.ebuild_mtime)
+ self._set_returncode((self.pid, os.EX_OK << 8))
+ self.wait()
+ return
+
+ settings.configdict['pkg']['EAPI'] = eapi
+
+ debug = settings.get("PORTAGE_DEBUG") == "1"
+ master_fd = None
+ slave_fd = None
+ fd_pipes = None
+ if self.fd_pipes is not None:
+ fd_pipes = self.fd_pipes.copy()
+ else:
+ fd_pipes = {}
+
+ fd_pipes.setdefault(0, sys.stdin.fileno())
+ fd_pipes.setdefault(1, sys.stdout.fileno())
+ fd_pipes.setdefault(2, sys.stderr.fileno())
+
+ # flush any pending output
+ for fd in fd_pipes.values():
+ if fd == sys.stdout.fileno():
+ sys.stdout.flush()
+ if fd == sys.stderr.fileno():
+ sys.stderr.flush()
+
+ fd_pipes_orig = fd_pipes.copy()
+ self._files = self._files_dict()
+ files = self._files
+
+ master_fd, slave_fd = os.pipe()
+ fcntl.fcntl(master_fd, fcntl.F_SETFL,
+ fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
+
+ fd_pipes[self._metadata_fd] = slave_fd
+
+ self._raw_metadata = []
+ files.ebuild = os.fdopen(master_fd, 'rb', 0)
+ self._reg_id = self.scheduler.register(files.ebuild.fileno(),
+ self._registered_events, self._output_handler)
+ self._registered = True
+
+ retval = portage.doebuild(ebuild_path, "depend",
+ settings["ROOT"], settings, debug,
+ mydbapi=self.portdb, tree="porttree",
+ fd_pipes=fd_pipes, returnpid=True)
+
+ os.close(slave_fd)
+
+ if isinstance(retval, int):
+ # doebuild failed before spawning
+ self._unregister()
+ self._set_returncode((self.pid, retval << 8))
+ self.wait()
+ return
+
+ self.pid = retval[0]
+ portage.process.spawned_pids.remove(self.pid)
+
+ def _output_handler(self, fd, event):
+
+ if event & PollConstants.POLLIN:
+ self._raw_metadata.append(self._files.ebuild.read())
+ if not self._raw_metadata[-1]:
+ self._unregister()
+ self.wait()
+
+ self._unregister_if_appropriate(event)
+
+ def _set_returncode(self, wait_retval):
+ SubProcess._set_returncode(self, wait_retval)
+ if self.returncode == os.EX_OK:
+ metadata_lines = ''.join(_unicode_decode(chunk,
+ encoding=_encodings['repo.content'], errors='replace')
+ for chunk in self._raw_metadata).splitlines()
+ if len(portage.auxdbkeys) != len(metadata_lines):
+ # Don't trust bash's returncode if the
+ # number of lines is incorrect.
+ self.returncode = 1
+ else:
+ metadata = zip(portage.auxdbkeys, metadata_lines)
+ self.metadata = self.metadata_callback(self.cpv,
+ self.ebuild_path, self.repo_path, metadata,
+ self.ebuild_mtime)
+
diff --git a/portage_with_autodep/pym/_emerge/EbuildPhase.py b/portage_with_autodep/pym/_emerge/EbuildPhase.py
new file mode 100644
index 0000000..82c165d
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/EbuildPhase.py
@@ -0,0 +1,350 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import gzip
+import io
+import sys
+import tempfile
+
+from _emerge.AsynchronousLock import AsynchronousLock
+from _emerge.BinpkgEnvExtractor import BinpkgEnvExtractor
+from _emerge.MiscFunctionsProcess import MiscFunctionsProcess
+from _emerge.EbuildProcess import EbuildProcess
+from _emerge.CompositeTask import CompositeTask
+from portage.util import writemsg
+from portage.xml.metadata import MetaDataXML
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.elog:messages@elog_messages',
+ 'portage.package.ebuild.doebuild:_check_build_log,' + \
+ '_post_phase_cmds,_post_phase_userpriv_perms,' + \
+ '_post_src_install_chost_fix,' + \
+ '_post_src_install_soname_symlinks,' + \
+ '_post_src_install_uid_fix,_postinst_bsdflags,' + \
+ '_preinst_bsdflags'
+)
+from portage import os
+from portage import _encodings
+from portage import _unicode_encode
+
+class EbuildPhase(CompositeTask):
+
+ __slots__ = ("actionmap", "phase", "settings") + \
+ ("_ebuild_lock",)
+
+ # FEATURES displayed prior to setup phase
+ _features_display = ("ccache", "depcheck", "depcheckstrict" "distcc",
+ "distcc-pump", "fakeroot",
+ "installsources", "keeptemp", "keepwork", "nostrip",
+ "preserve-libs", "sandbox", "selinux", "sesandbox",
+ "splitdebug", "suidctl", "test", "userpriv",
+ "usersandbox")
+
+ # Locked phases
+ _locked_phases = ("setup", "preinst", "postinst", "prerm", "postrm")
+
+ def _start(self):
+
+ need_builddir = self.phase not in EbuildProcess._phases_without_builddir
+
+ if need_builddir:
+ phase_completed_file = os.path.join(
+ self.settings['PORTAGE_BUILDDIR'],
+ ".%sed" % self.phase.rstrip('e'))
+ if not os.path.exists(phase_completed_file):
+ # If the phase is really going to run then we want
+ # to eliminate any stale elog messages that may
+ # exist from a previous run.
+ try:
+ os.unlink(os.path.join(self.settings['T'],
+ 'logging', self.phase))
+ except OSError:
+ pass
+
+ if self.phase in ('nofetch', 'pretend', 'setup'):
+
+ use = self.settings.get('PORTAGE_BUILT_USE')
+ if use is None:
+ use = self.settings['PORTAGE_USE']
+
+ maint_str = ""
+ upstr_str = ""
+ metadata_xml_path = os.path.join(os.path.dirname(self.settings['EBUILD']), "metadata.xml")
+ if os.path.isfile(metadata_xml_path):
+ herds_path = os.path.join(self.settings['PORTDIR'],
+ 'metadata/herds.xml')
+ try:
+ metadata_xml = MetaDataXML(metadata_xml_path, herds_path)
+ maint_str = metadata_xml.format_maintainer_string()
+ upstr_str = metadata_xml.format_upstream_string()
+ except SyntaxError:
+ maint_str = "<invalid metadata.xml>"
+
+ msg = []
+ msg.append("Package: %s" % self.settings.mycpv)
+ if self.settings.get('PORTAGE_REPO_NAME'):
+ msg.append("Repository: %s" % self.settings['PORTAGE_REPO_NAME'])
+ if maint_str:
+ msg.append("Maintainer: %s" % maint_str)
+ if upstr_str:
+ msg.append("Upstream: %s" % upstr_str)
+
+ msg.append("USE: %s" % use)
+ relevant_features = []
+ enabled_features = self.settings.features
+ for x in self._features_display:
+ if x in enabled_features:
+ relevant_features.append(x)
+ if relevant_features:
+ msg.append("FEATURES: %s" % " ".join(relevant_features))
+
+ # Force background=True for this header since it's intended
+ # for the log and it doesn't necessarily need to be visible
+ # elsewhere.
+ self._elog('einfo', msg, background=True)
+
+ if self.phase == 'package':
+ if 'PORTAGE_BINPKG_TMPFILE' not in self.settings:
+ self.settings['PORTAGE_BINPKG_TMPFILE'] = \
+ os.path.join(self.settings['PKGDIR'],
+ self.settings['CATEGORY'], self.settings['PF']) + '.tbz2'
+
+ if self.phase in ("pretend", "prerm"):
+ env_extractor = BinpkgEnvExtractor(background=self.background,
+ scheduler=self.scheduler, settings=self.settings)
+ if env_extractor.saved_env_exists():
+ self._start_task(env_extractor, self._env_extractor_exit)
+ return
+ # If the environment.bz2 doesn't exist, then ebuild.sh will
+ # source the ebuild as a fallback.
+
+ self._start_lock()
+
+ def _env_extractor_exit(self, env_extractor):
+ if self._default_exit(env_extractor) != os.EX_OK:
+ self.wait()
+ return
+
+ self._start_lock()
+
+ def _start_lock(self):
+ if (self.phase in self._locked_phases and
+ "ebuild-locks" in self.settings.features):
+ eroot = self.settings["EROOT"]
+ lock_path = os.path.join(eroot, portage.VDB_PATH + "-ebuild")
+ if os.access(os.path.dirname(lock_path), os.W_OK):
+ self._ebuild_lock = AsynchronousLock(path=lock_path,
+ scheduler=self.scheduler)
+ self._start_task(self._ebuild_lock, self._lock_exit)
+ return
+
+ self._start_ebuild()
+
+ def _lock_exit(self, ebuild_lock):
+ if self._default_exit(ebuild_lock) != os.EX_OK:
+ self.wait()
+ return
+ self._start_ebuild()
+
+ def _start_ebuild(self):
+
+ # Don't open the log file during the clean phase since the
+ # open file can result in an nfs lock on $T/build.log which
+ # prevents the clean phase from removing $T.
+ logfile = None
+ if self.phase not in ("clean", "cleanrm") and \
+ self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
+ logfile = self.settings.get("PORTAGE_LOG_FILE")
+
+ fd_pipes = None
+ if not self.background and self.phase == 'nofetch':
+ # All the pkg_nofetch output goes to stderr since
+ # it's considered to be an error message.
+ fd_pipes = {1 : sys.stderr.fileno()}
+
+ ebuild_process = EbuildProcess(actionmap=self.actionmap,
+ background=self.background, fd_pipes=fd_pipes, logfile=logfile,
+ phase=self.phase, scheduler=self.scheduler,
+ settings=self.settings)
+
+ self._start_task(ebuild_process, self._ebuild_exit)
+
+ def _ebuild_exit(self, ebuild_process):
+
+ if self._ebuild_lock is not None:
+ self._ebuild_lock.unlock()
+ self._ebuild_lock = None
+
+ fail = False
+ if self._default_exit(ebuild_process) != os.EX_OK:
+ if self.phase == "test" and \
+ "test-fail-continue" in self.settings.features:
+ pass
+ else:
+ fail = True
+
+ if not fail:
+ self.returncode = None
+
+ logfile = None
+ if self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
+ logfile = self.settings.get("PORTAGE_LOG_FILE")
+
+ if self.phase == "install":
+ out = io.StringIO()
+ _check_build_log(self.settings, out=out)
+ msg = out.getvalue()
+ self.scheduler.output(msg, log_path=logfile)
+
+ if fail:
+ self._die_hooks()
+ return
+
+ settings = self.settings
+ _post_phase_userpriv_perms(settings)
+
+ if self.phase == "install":
+ out = io.StringIO()
+ _post_src_install_chost_fix(settings)
+ _post_src_install_uid_fix(settings, out)
+ msg = out.getvalue()
+ if msg:
+ self.scheduler.output(msg, log_path=logfile)
+ elif self.phase == "preinst":
+ _preinst_bsdflags(settings)
+ elif self.phase == "postinst":
+ _postinst_bsdflags(settings)
+
+ post_phase_cmds = _post_phase_cmds.get(self.phase)
+ if post_phase_cmds is not None:
+ if logfile is not None and self.phase in ("install",):
+ # Log to a temporary file, since the code we are running
+ # reads PORTAGE_LOG_FILE for QA checks, and we want to
+ # avoid annoying "gzip: unexpected end of file" messages
+ # when FEATURES=compress-build-logs is enabled.
+ fd, logfile = tempfile.mkstemp()
+ os.close(fd)
+ post_phase = MiscFunctionsProcess(background=self.background,
+ commands=post_phase_cmds, logfile=logfile, phase=self.phase,
+ scheduler=self.scheduler, settings=settings)
+ self._start_task(post_phase, self._post_phase_exit)
+ return
+
+ # this point is not reachable if there was a failure and
+ # we returned for die_hooks above, so returncode must
+ # indicate success (especially if ebuild_process.returncode
+ # is unsuccessful and test-fail-continue came into play)
+ self.returncode = os.EX_OK
+ self._current_task = None
+ self.wait()
+
+ def _post_phase_exit(self, post_phase):
+
+ self._assert_current(post_phase)
+
+ log_path = None
+ if self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
+ log_path = self.settings.get("PORTAGE_LOG_FILE")
+
+ if post_phase.logfile is not None and \
+ post_phase.logfile != log_path:
+ # We were logging to a temp file (see above), so append
+ # temp file to main log and remove temp file.
+ self._append_temp_log(post_phase.logfile, log_path)
+
+ if self._final_exit(post_phase) != os.EX_OK:
+ writemsg("!!! post %s failed; exiting.\n" % self.phase,
+ noiselevel=-1)
+ self._die_hooks()
+ return
+
+ if self.phase == "install":
+ out = io.StringIO()
+ _post_src_install_soname_symlinks(self.settings, out)
+ msg = out.getvalue()
+ if msg:
+ self.scheduler.output(msg, log_path=log_path)
+
+ self._current_task = None
+ self.wait()
+ return
+
+ def _append_temp_log(self, temp_log, log_path):
+
+ temp_file = open(_unicode_encode(temp_log,
+ encoding=_encodings['fs'], errors='strict'), 'rb')
+
+ log_file = self._open_log(log_path)
+
+ for line in temp_file:
+ log_file.write(line)
+
+ temp_file.close()
+ log_file.close()
+ os.unlink(temp_log)
+
+ def _open_log(self, log_path):
+
+ f = open(_unicode_encode(log_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='ab')
+
+ if log_path.endswith('.gz'):
+ f = gzip.GzipFile(filename='', mode='ab', fileobj=f)
+
+ return f
+
+ def _die_hooks(self):
+ self.returncode = None
+ phase = 'die_hooks'
+ die_hooks = MiscFunctionsProcess(background=self.background,
+ commands=[phase], phase=phase,
+ scheduler=self.scheduler, settings=self.settings)
+ self._start_task(die_hooks, self._die_hooks_exit)
+
+ def _die_hooks_exit(self, die_hooks):
+ if self.phase != 'clean' and \
+ 'noclean' not in self.settings.features and \
+ 'fail-clean' in self.settings.features:
+ self._default_exit(die_hooks)
+ self._fail_clean()
+ return
+ self._final_exit(die_hooks)
+ self.returncode = 1
+ self.wait()
+
+ def _fail_clean(self):
+ self.returncode = None
+ portage.elog.elog_process(self.settings.mycpv, self.settings)
+ phase = "clean"
+ clean_phase = EbuildPhase(background=self.background,
+ phase=phase, scheduler=self.scheduler, settings=self.settings)
+ self._start_task(clean_phase, self._fail_clean_exit)
+ return
+
+ def _fail_clean_exit(self, clean_phase):
+ self._final_exit(clean_phase)
+ self.returncode = 1
+ self.wait()
+
+ def _elog(self, elog_funcname, lines, background=None):
+ if background is None:
+ background = self.background
+ out = io.StringIO()
+ phase = self.phase
+ elog_func = getattr(elog_messages, elog_funcname)
+ global_havecolor = portage.output.havecolor
+ try:
+ portage.output.havecolor = \
+ self.settings.get('NOCOLOR', 'false').lower() in ('no', 'false')
+ for line in lines:
+ elog_func(line, phase=phase, key=self.settings.mycpv, out=out)
+ finally:
+ portage.output.havecolor = global_havecolor
+ msg = out.getvalue()
+ if msg:
+ log_path = None
+ if self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
+ log_path = self.settings.get("PORTAGE_LOG_FILE")
+ self.scheduler.output(msg, log_path=log_path,
+ background=background)
diff --git a/portage_with_autodep/pym/_emerge/EbuildProcess.py b/portage_with_autodep/pym/_emerge/EbuildProcess.py
new file mode 100644
index 0000000..ce97aff
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/EbuildProcess.py
@@ -0,0 +1,21 @@
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.AbstractEbuildProcess import AbstractEbuildProcess
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.package.ebuild.doebuild:_doebuild_spawn,_spawn_actionmap'
+)
+
+class EbuildProcess(AbstractEbuildProcess):
+
+ __slots__ = ('actionmap',)
+
+ def _spawn(self, args, **kwargs):
+
+ actionmap = self.actionmap
+ if actionmap is None:
+ actionmap = _spawn_actionmap(self.settings)
+
+ return _doebuild_spawn(self.phase, self.settings,
+ actionmap=actionmap, **kwargs)
diff --git a/portage_with_autodep/pym/_emerge/EbuildSpawnProcess.py b/portage_with_autodep/pym/_emerge/EbuildSpawnProcess.py
new file mode 100644
index 0000000..e1f682a
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/EbuildSpawnProcess.py
@@ -0,0 +1,16 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.AbstractEbuildProcess import AbstractEbuildProcess
+
+class EbuildSpawnProcess(AbstractEbuildProcess):
+ """
+ Used by doebuild.spawn() to manage the spawned process.
+ """
+ _spawn_kwarg_names = AbstractEbuildProcess._spawn_kwarg_names + \
+ ('fakeroot_state',)
+
+ __slots__ = ('fakeroot_state', 'spawn_func')
+
+ def _spawn(self, args, **kwargs):
+ return self.spawn_func(args, env=self.settings.environ(), **kwargs)
diff --git a/portage_with_autodep/pym/_emerge/EventsAnalyser.py b/portage_with_autodep/pym/_emerge/EventsAnalyser.py
new file mode 100644
index 0000000..65ece7b
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/EventsAnalyser.py
@@ -0,0 +1,511 @@
+# Distributed under the terms of the GNU General Public License v2
+
+import portage
+from portage.dbapi._expand_new_virt import expand_new_virt
+from portage import os
+
+import subprocess
+import re
+
+class PortageUtils:
+ """ class for accessing the portage api """
+ def __init__(self, settings):
+ """ test """
+ self.settings=settings
+ self.vartree=portage.vartree(settings=settings)
+ self.vardbapi=portage.vardbapi(settings=settings, vartree=self.vartree)
+ self.portdbapi=portage.portdbapi(mysettings=settings)
+ self.metadata_keys = [k for k in portage.auxdbkeys if not k.startswith("UNUSED_")]
+ self.use=self.settings["USE"]
+
+ def get_best_visible_pkg(self,pkg):
+ """
+ Gets best candidate on installing. Returns empty string if no found
+
+ :param pkg: package name
+
+ """
+ try:
+ return self.portdbapi.xmatch("bestmatch-visible", pkg)
+ except:
+ return ''
+
+ # non-recursive dependency getter
+ def get_dep(self,pkg,dep_type=["RDEPEND","DEPEND"]):
+ """
+ Gets current dependencies of a package. Looks in portage db
+
+ :param pkg: name of package
+ :param dep_type: type of dependencies to recurse. Can be ["DEPEND"] or
+ ["RDEPEND", "DEPEND"]
+ :returns: **set** of packages names
+ """
+ ret=set()
+
+ pkg = self.get_best_visible_pkg(pkg)
+ if not pkg:
+ return ret
+
+ # we found the best visible match in common tree
+
+
+ metadata = dict(zip(self.metadata_keys,
+ self.portdbapi.aux_get(pkg, self.metadata_keys)))
+ dep_str = " ".join(metadata[k] for k in dep_type)
+
+ # the IUSE default are very important for us
+ iuse_defaults=[
+ u[1:] for u in metadata.get("IUSE",'').split() if u.startswith("+")]
+
+ use=self.use.split()
+
+ for u in iuse_defaults:
+ if u not in use:
+ use.append(u)
+
+ success, atoms = portage.dep_check(dep_str, None, self.settings,
+ myuse=use, myroot=self.settings["ROOT"],
+ trees={self.settings["ROOT"]:{"vartree":self.vartree, "porttree": self.vartree}})
+ if not success:
+ return ret
+
+ for atom in atoms:
+ atomname = self.vartree.dep_bestmatch(atom)
+
+ if not atomname:
+ continue
+
+ for unvirt_pkg in expand_new_virt(self.vardbapi,'='+atomname):
+ for pkg in self.vartree.dep_match(unvirt_pkg):
+ ret.add(pkg)
+
+ return ret
+
+ # recursive dependency getter
+ def get_deps(self,pkg,dep_type=["RDEPEND","DEPEND"]):
+ """
+ Gets current dependencies of a package on any depth
+ All dependencies **must** be installed
+
+ :param pkg: name of package
+ :param dep_type: type of dependencies to recurse. Can be ["DEPEND"] or
+ ["RDEPEND", "DEPEND"]
+ :returns: **set** of packages names
+ """
+ ret=set()
+
+
+ # get porttree dependencies on the first package
+
+ pkg = self.portdbapi.xmatch("bestmatch-visible", pkg)
+ if not pkg:
+ return ret
+
+ known_packages=set()
+ unknown_packages=self.get_dep(pkg,dep_type)
+ ret=ret.union(unknown_packages)
+
+ while unknown_packages:
+ p=unknown_packages.pop()
+ if p in known_packages:
+ continue
+ known_packages.add(p)
+
+ metadata = dict(zip(self.metadata_keys, self.vardbapi.aux_get(p, self.metadata_keys)))
+
+ dep_str = " ".join(metadata[k] for k in dep_type)
+
+ # the IUSE default are very important for us
+ iuse_defaults=[
+ u[1:] for u in metadata.get("IUSE",'').split() if u.startswith("+")]
+
+ use=self.use.split()
+
+ for u in iuse_defaults:
+ if u not in use:
+ use.append(u)
+
+ success, atoms = portage.dep_check(dep_str, None, self.settings,
+ myuse=use, myroot=self.settings["ROOT"],
+ trees={self.settings["ROOT"]:{"vartree":self.vartree,"porttree": self.vartree}})
+
+ if not success:
+ continue
+
+ for atom in atoms:
+ atomname = self.vartree.dep_bestmatch(atom)
+ if not atomname:
+ continue
+
+ for unvirt_pkg in expand_new_virt(self.vardbapi,'='+atomname):
+ for pkg in self.vartree.dep_match(unvirt_pkg):
+ ret.add(pkg)
+ unknown_packages.add(pkg)
+ return ret
+
+ def get_deps_for_package_building(self, pkg):
+ """
+ returns buildtime dependencies of current package and
+ all runtime dependencies of that buildtime dependencies
+ """
+ buildtime_deps=self.get_dep(pkg, ["DEPEND"])
+ runtime_deps=set()
+ for dep in buildtime_deps:
+ runtime_deps=runtime_deps.union(self.get_deps(dep,["RDEPEND"]))
+
+ ret=buildtime_deps.union(runtime_deps)
+ return ret
+
+ def get_system_packages_list(self):
+ """
+ returns all packages from system set. They are always implicit dependencies
+
+ :returns: **list** of package names
+ """
+ ret=[]
+ for atom in self.settings.packages:
+ for pre_pkg in self.vartree.dep_match(atom):
+ for unvirt_pkg in expand_new_virt(self.vardbapi,'='+pre_pkg):
+ for pkg in self.vartree.dep_match(unvirt_pkg):
+ ret.append(pkg)
+ return ret
+
+
+class GentoolkitUtils:
+ """
+ Interface with qfile and qlist utils. They are much faster than
+ internals.
+ """
+
+ def getpackagesbyfiles(files):
+ """
+ :param files: list of filenames
+ :returns: **dictionary** file->package, if file doesn't belong to any
+ package it not returned as key of this dictionary
+ """
+ ret={}
+ listtocheck=[]
+ for f in files:
+ if os.path.isdir(f):
+ ret[f]="directory"
+ else:
+ listtocheck.append(f)
+
+ try:
+ proc=subprocess.Popen(['qfile']+['--nocolor','--exact','','--from','-'],
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,stderr=subprocess.PIPE,
+ bufsize=4096)
+
+ out,err=proc.communicate("\n".join(listtocheck).encode("utf8"))
+
+ lines=out.decode("utf8").split("\n")
+ #print lines
+ line_re=re.compile(r"^([^ ]+)\s+\(([^)]+)\)$")
+ for line in lines:
+ if len(line)==0:
+ continue
+ match=line_re.match(line)
+ if match:
+ ret[match.group(2)]=match.group(1)
+ else:
+ portage.util.writemsg("Util qfile returned unparsable string: %s\n" % line)
+
+ except OSError as e:
+ portage.util.writemsg("Error while launching qfile: %s\n" % e)
+
+
+ return ret
+
+ def getfilesbypackages(packagenames):
+ """
+
+ :param packagename: name of package
+ :returns: **list** of files in package with name *packagename*
+ """
+ ret=[]
+ try:
+ proc=subprocess.Popen(['qlist']+['--nocolor',"--obj"]+packagenames,
+ stdout=subprocess.PIPE,stderr=subprocess.PIPE,
+ bufsize=4096)
+
+ out,err=proc.communicate()
+
+ ret=out.decode("utf8").split("\n")
+ if ret==['']:
+ ret=[]
+ except OSError as e:
+ portage.util.writemsg("Error while launching qfile: %s\n" % e)
+
+ return ret
+
+ def get_all_packages_files():
+ """
+ Memory-hungry operation
+
+ :returns: **set** of all files that belongs to package
+ """
+ ret=[]
+ try:
+ proc=subprocess.Popen(['qlist']+['--all',"--obj"],
+ stdout=subprocess.PIPE,stderr=subprocess.PIPE,
+ bufsize=4096)
+
+ out,err=proc.communicate()
+
+ ret=out.decode("utf8").split("\n")
+ except OSError as e:
+ portage.util.writemsg("Error while launching qfile: %s\n" % e)
+
+ return set(ret)
+
+class FilterProcGenerator:
+ def __init__(self, pkgname, settings):
+ portageutils=PortageUtils(settings=settings)
+
+ deps_all=portageutils.get_deps_for_package_building(pkgname)
+ deps_portage=portageutils.get_dep('portage',["RDEPEND"])
+
+ system_packages=portageutils.get_system_packages_list()
+
+ allfiles=GentoolkitUtils.get_all_packages_files()
+ portage.util.writemsg("All files list recieved, waiting for " \
+ "a list of allowed files\n")
+
+
+ allowedpkgs=system_packages+list(deps_portage)+list(deps_all)
+
+ allowedfiles=GentoolkitUtils.getfilesbypackages(allowedpkgs)
+ #for pkg in allowedpkgs:
+ # allowedfiles+=GentoolkitUtils.getfilesbypackage(pkg)
+
+ #import pdb; pdb.set_trace()
+
+ # manually add all python interpreters to this list
+ allowedfiles+=GentoolkitUtils.getfilesbypackages(['python'])
+ allowedfiles=set(allowedfiles)
+
+ deniedfiles=allfiles-allowedfiles
+
+ def filter_proc(eventname,filename,stage):
+ if filename in deniedfiles:
+ return False
+ return True
+
+ self.filter_proc=filter_proc
+ def get_filter_proc(self):
+ return self.filter_proc
+
+class EventsAnalyser:
+ def __init__(self, pkgname, events, settings):
+ self.pkgname=pkgname
+ self.events=events
+ self.settings=settings
+ self.portageutils=PortageUtils(settings=settings)
+
+ self.deps_all=self.portageutils.get_deps_for_package_building(pkgname)
+ self.deps_direct=self.portageutils.get_dep(pkgname,["DEPEND"])
+ self.deps_portage=self.portageutils.get_dep('portage',["RDEPEND"])
+
+ self.system_packages=self.portageutils.get_system_packages_list()
+ # All analyse work is here
+
+ # get unique filenames
+ filenames=set()
+ for stage in events:
+ succ_events=set(events[stage][0])
+ fail_events=set(events[stage][1])
+ filenames=filenames.union(succ_events)
+ filenames=filenames.union(fail_events)
+ filenames=list(filenames)
+
+ file_to_package=GentoolkitUtils.getpackagesbyfiles(filenames)
+ # This part is completly unreadable.
+ # It converting one complex struct(returned by getfsevents) to another complex
+ # struct which good for generating output.
+ #
+ # Old struct is also used during output
+
+ packagesinfo={}
+
+ for stage in sorted(events):
+ succ_events=events[stage][0]
+ fail_events=events[stage][1]
+
+ for filename in succ_events:
+ if filename in file_to_package:
+ package=file_to_package[filename]
+ else:
+ package="unknown"
+
+ if not package in packagesinfo:
+ packagesinfo[package]={}
+ stageinfo=packagesinfo[package]
+ if not stage in stageinfo:
+ stageinfo[stage]={}
+
+ filesinfo=stageinfo[stage]
+ if not filename in filesinfo:
+ filesinfo[filename]={"found":[],"notfound":[]}
+ filesinfo[filename]["found"]=succ_events[filename]
+
+ for filename in fail_events:
+ if filename in file_to_package:
+ package=file_to_package[filename]
+ else:
+ package="unknown"
+ if not package in packagesinfo:
+ packagesinfo[package]={}
+ stageinfo=packagesinfo[package]
+ if not stage in stageinfo:
+ stageinfo[stage]={}
+
+ filesinfo=stageinfo[stage]
+ if not filename in filesinfo:
+ filesinfo[filename]={"found":[],"notfound":[]}
+ filesinfo[filename]["notfound"]=fail_events[filename]
+ self.packagesinfo=packagesinfo
+
+ def display(self):
+ portage.util.writemsg(
+ portage.output.colorize(
+ "WARN", "\nFile access report for %s:\n" % self.pkgname))
+
+ stagesorder={"clean":1,"setup":2,"unpack":3,"prepare":4,"configure":5,"compile":6,"test":7,
+ "install":8,"preinst":9,"postinst":10,"prerm":11,"postrm":12,"unknown":13}
+ packagesinfo=self.packagesinfo
+ # print information grouped by package
+ for package in sorted(packagesinfo):
+ # not showing special directory package
+ if package=="directory":
+ continue
+
+ if package=="unknown":
+ continue
+
+
+ is_pkg_in_dep=package in self.deps_all
+ is_pkg_in_portage_dep=package in self.deps_portage
+ is_pkg_in_system=package in self.system_packages
+ is_pkg_python="dev-lang/python" in package
+
+ stages=[]
+ for stage in sorted(packagesinfo[package].keys(), key=stagesorder.get):
+ if stage!="unknown":
+ stages.append(stage)
+
+ if len(stages)==0:
+ continue
+
+ filenames={}
+ for stage in stages:
+ for filename in packagesinfo[package][stage]:
+ if len(packagesinfo[package][stage][filename]["found"])!=0:
+ was_readed,was_writed=packagesinfo[package][stage][filename]["found"]
+ if not filename in filenames:
+ filenames[filename]=['ok',was_readed,was_writed]
+ else:
+ status, old_was_readed, old_was_writed=filenames[filename]
+ filenames[filename]=[
+ 'ok',old_was_readed | was_readed, old_was_writed | was_writed
+ ]
+ if len(packagesinfo[package][stage][filename]["notfound"])!=0:
+ was_notfound,was_blocked=packagesinfo[package][stage][filename]["notfound"]
+ if not filename in filenames:
+ filenames[filename]=['err',was_notfound,was_blocked]
+ else:
+ status, old_was_notfound, old_was_blocked=filenames[filename]
+ filenames[filename]=[
+ 'err',old_was_notfound | was_notfound, old_was_blocked | was_blocked
+ ]
+
+
+ if is_pkg_in_dep:
+ portage.util.writemsg("[OK]")
+ elif is_pkg_in_system:
+ portage.util.writemsg("[SYSTEM]")
+ elif is_pkg_in_portage_dep:
+ portage.util.writemsg("[PORTAGE DEP]")
+ elif is_pkg_python:
+ portage.util.writemsg("[INTERPRETER]")
+ elif not self.is_package_useful(package,stages,filenames.keys()):
+ portage.util.writemsg("[LIKELY OK]")
+ else:
+ portage.util.writemsg(portage.output.colorize("BAD", "[NOT IN DEPS]"))
+ # show information about accessed files
+
+ portage.util.writemsg(" %-40s: %s\n" % (package,stages))
+
+ # this is here for readability
+ action={
+ ('ok',False,False):"accessed",
+ ('ok',True,False):"readed",
+ ('ok',False,True):"writed",
+ ('ok',True,True):"readed and writed",
+ ('err',False,False):"other error",
+ ('err',True,False):"not found",
+ ('err',False,True):"blocked",
+ ('err',True,True):"not found and blocked"
+ }
+
+ filescounter=0
+
+ for filename in filenames:
+ event_info=tuple(filenames[filename])
+ portage.util.writemsg(" %-56s %-21s\n" % (filename,action[event_info]))
+ filescounter+=1
+ if filescounter>10:
+ portage.util.writemsg(" ... and %d more ...\n" % (len(filenames)-10))
+ break
+ # ... and one more check. Making sure that direct build time
+ # dependencies were accessed
+ #import pdb; pdb.set_trace()
+ not_accessed_deps=set(self.deps_direct)-set(self.packagesinfo.keys())
+ if not_accessed_deps:
+ portage.util.writemsg(portage.output.colorize("WARN", "!!! "))
+ portage.util.writemsg("Warning! Some build time dependencies " + \
+ "of packages were not accessed: " + \
+ " ".join(not_accessed_deps) + "\n")
+
+ def is_package_useful(self,pkg,stages,files):
+ """ some basic heuristics here to cut part of packages """
+
+ excluded_paths=set(
+ ['/etc/sandbox.d/']
+ )
+
+ excluded_packages=set(
+ # autodep shows these two packages every time
+ ['net-zope/zope-fixers', 'net-zope/zope-interface']
+ )
+
+
+ def is_pkg_excluded(p):
+ for pkg in excluded_packages:
+ if p.startswith(pkg): # if package is excluded
+ return True
+ return False
+
+
+ def is_file_excluded(f):
+ for path in excluded_paths:
+ if f.startswith(path): # if path is excluded
+ return True
+ return False
+
+
+ if is_pkg_excluded(pkg):
+ return False
+
+ for f in files:
+ if is_file_excluded(f):
+ continue
+
+ # test 1: package is not useful if all files are *.desktop or *.xml or *.m4
+ if not (f.endswith(".desktop") or f.endswith(".xml") or f.endswith(".m4") or f.endswith(".pc")):
+ break
+ else:
+ return False # we get here if cycle ends not with break
+
+ return True
+
+ \ No newline at end of file
diff --git a/portage_with_autodep/pym/_emerge/EventsLogger.py b/portage_with_autodep/pym/_emerge/EventsLogger.py
new file mode 100644
index 0000000..68b3c67
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/EventsLogger.py
@@ -0,0 +1,180 @@
+# Distributed under the terms of the GNU General Public License v2
+
+import io
+import sys
+import stat
+import socket
+import select
+import tempfile
+
+import threading
+
+from portage import os
+
+class EventsLogger(threading.Thread):
+ def default_filter(eventname, filename, stage):
+ return True
+
+ def __init__(self, socket_dir="/tmp/", filter_proc=default_filter):
+ threading.Thread.__init__(self) # init the Thread
+
+ self.alive=False
+
+ self.main_thread=threading.currentThread()
+
+ self.socket_dir=socket_dir
+ self.filter_proc=filter_proc
+
+ self.socket_name=None
+ self.socket_logger=None
+
+ self.events={}
+
+ try:
+ socket_dir_name = tempfile.mkdtemp(dir=self.socket_dir,
+ prefix="log_socket_")
+
+ socket_name = os.path.join(socket_dir_name, 'socket')
+
+ except OSError as e:
+ return
+
+ self.socket_name=socket_name
+
+ #print(self.socket_name)
+
+ try:
+ socket_logger=socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+ socket_logger.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+
+ socket_logger.bind(self.socket_name)
+ socket_logger.listen(64)
+
+ except socket.error as e:
+ return
+
+ self.socket_logger=socket_logger
+
+ try:
+ # Allow connecting to socket for anyone
+ os.chmod(socket_dir_name,
+ stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR|
+ stat.S_IROTH|stat.S_IWOTH|stat.S_IXOTH)
+ os.chmod(socket_name,
+ stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR|
+ stat.S_IROTH|stat.S_IWOTH|stat.S_IXOTH)
+ except OSError as e:
+ return
+
+ def run(self):
+ """ Starts the log server """
+
+ self.alive=True
+ self.listen_thread=threading.currentThread()
+ clients={}
+
+ epoll=select.epoll()
+ epoll.register(self.socket_logger.fileno(), select.EPOLLIN)
+
+ while self.alive:
+ try:
+ sock_events = epoll.poll(3)
+
+ for fileno, sock_event in sock_events:
+ if fileno == self.socket_logger.fileno():
+ ret = self.socket_logger.accept()
+ if ret is None:
+ pass
+ else:
+ (client,addr)=ret
+ epoll.register(client.fileno(), select.EPOLLIN)
+ clients[client.fileno()]=client
+ elif sock_event & select.EPOLLIN:
+ s=clients[fileno]
+ record=s.recv(8192)
+
+ if not record: # if connection was closed
+ epoll.unregister(fileno)
+ clients[fileno].close()
+ del clients[fileno]
+ continue
+
+ #import pdb; pdb.set_trace()
+ try:
+ message=record.decode("utf8").split("\0")
+ except UnicodeDecodeError:
+ print("Bad message %s" % record)
+ continue
+
+ # continue
+
+ #print(message)
+
+ try:
+ if message[4]=="ASKING":
+ if self.filter_proc(message[1],message[2],message[3]):
+ s.sendall(b"ALLOW\0")
+ else:
+ # TODO: log through portage infrastructure
+ #print("Blocking an access to %s" % message[2])
+ s.sendall(b"DENY\0")
+ else:
+ eventname,filename,stage,result=message[1:5]
+
+ if not stage in self.events:
+ self.events[stage]=[{},{}]
+
+ hashofsucesses=self.events[stage][0]
+ hashoffailures=self.events[stage][1]
+
+ if result=="DENIED":
+ print("Blocking an access to %s" % filename)
+
+ if result=="OK":
+ if not filename in hashofsucesses:
+ hashofsucesses[filename]=[False,False]
+
+ readed_or_writed=hashofsucesses[filename]
+
+ if eventname=="read":
+ readed_or_writed[0]=True
+ elif eventname=="write":
+ readed_or_writed[1]=True
+
+ elif result[0:3]=="ERR" or result=="DENIED":
+ if not filename in hashoffailures:
+ hashoffailures[filename]=[False,False]
+ notfound_or_blocked=hashoffailures[filename]
+
+ if result=="ERR/2":
+ notfound_or_blocked[0]=True
+ elif result=="DENIED":
+ notfound_or_blocked[1]=True
+
+ else:
+ print("Error in logger module<->analyser protocol")
+
+ except IndexError:
+ print("IndexError while parsing %s" % record)
+ except IOError as e:
+ if e.errno!=4: # handling "Interrupted system call" errors
+ raise
+
+ # if main thread doesnt exists then exit
+ if not self.main_thread.is_alive():
+ break
+ epoll.unregister(self.socket_logger.fileno())
+ epoll.close()
+ self.socket_logger.close()
+
+ def stop(self):
+ """ Stops the log server. Returns all events """
+
+ self.alive=False
+
+ # Block the main thread until listener exists
+ self.listen_thread.join()
+
+ # We assume portage clears tmp folder, so no deleting a socket file
+ # We assume that no new socket data will arrive after this moment
+ return self.events
diff --git a/portage_with_autodep/pym/_emerge/FakeVartree.py b/portage_with_autodep/pym/_emerge/FakeVartree.py
new file mode 100644
index 0000000..a11966f
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/FakeVartree.py
@@ -0,0 +1,265 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+
+import portage
+from portage import os
+from _emerge.Package import Package
+from _emerge.PackageVirtualDbapi import PackageVirtualDbapi
+from portage.const import VDB_PATH
+from portage.dbapi.vartree import vartree
+from portage.repository.config import _gen_valid_repo
+from portage.update import grab_updates, parse_updates, update_dbentries
+
+if sys.hexversion >= 0x3000000:
+ long = int
+
+class FakeVardbapi(PackageVirtualDbapi):
+ """
+ Implements the vardbapi.getpath() method which is used in error handling
+ code for the Package class and vartree.get_provide().
+ """
+ def getpath(self, cpv, filename=None):
+ path = os.path.join(self.settings['EROOT'], VDB_PATH, cpv)
+ if filename is not None:
+ path =os.path.join(path, filename)
+ return path
+
+class FakeVartree(vartree):
+ """This is implements an in-memory copy of a vartree instance that provides
+ all the interfaces required for use by the depgraph. The vardb is locked
+ during the constructor call just long enough to read a copy of the
+ installed package information. This allows the depgraph to do it's
+ dependency calculations without holding a lock on the vardb. It also
+ allows things like vardb global updates to be done in memory so that the
+ user doesn't necessarily need write access to the vardb in cases where
+ global updates are necessary (updates are performed when necessary if there
+ is not a matching ebuild in the tree). Instances of this class are not
+ populated until the sync() method is called."""
+ def __init__(self, root_config, pkg_cache=None, pkg_root_config=None):
+ self._root_config = root_config
+ if pkg_root_config is None:
+ pkg_root_config = self._root_config
+ self._pkg_root_config = pkg_root_config
+ if pkg_cache is None:
+ pkg_cache = {}
+ real_vartree = root_config.trees["vartree"]
+ self._real_vardb = real_vartree.dbapi
+ portdb = root_config.trees["porttree"].dbapi
+ self.root = real_vartree.root
+ self.settings = real_vartree.settings
+ mykeys = list(real_vartree.dbapi._aux_cache_keys)
+ if "_mtime_" not in mykeys:
+ mykeys.append("_mtime_")
+ self._db_keys = mykeys
+ self._pkg_cache = pkg_cache
+ self.dbapi = FakeVardbapi(real_vartree.settings)
+
+ # Initialize variables needed for lazy cache pulls of the live ebuild
+ # metadata. This ensures that the vardb lock is released ASAP, without
+ # being delayed in case cache generation is triggered.
+ self._aux_get = self.dbapi.aux_get
+ self.dbapi.aux_get = self._aux_get_wrapper
+ self._match = self.dbapi.match
+ self.dbapi.match = self._match_wrapper
+ self._aux_get_history = set()
+ self._portdb_keys = ["EAPI", "DEPEND", "RDEPEND", "PDEPEND"]
+ self._portdb = portdb
+ self._global_updates = None
+
+ def _match_wrapper(self, cpv, use_cache=1):
+ """
+ Make sure the metadata in Package instances gets updated for any
+ cpv that is returned from a match() call, since the metadata can
+ be accessed directly from the Package instance instead of via
+ aux_get().
+ """
+ matches = self._match(cpv, use_cache=use_cache)
+ for cpv in matches:
+ if cpv in self._aux_get_history:
+ continue
+ self._aux_get_wrapper(cpv, [])
+ return matches
+
+ def _aux_get_wrapper(self, pkg, wants, myrepo=None):
+ if pkg in self._aux_get_history:
+ return self._aux_get(pkg, wants)
+ self._aux_get_history.add(pkg)
+ # We need to check the EAPI, and this also raises
+ # a KeyError to the caller if appropriate.
+ installed_eapi, repo = self._aux_get(pkg, ["EAPI", "repository"])
+ try:
+ # Use the live ebuild metadata if possible.
+ repo = _gen_valid_repo(repo)
+ live_metadata = dict(zip(self._portdb_keys,
+ self._portdb.aux_get(pkg, self._portdb_keys, myrepo=repo)))
+ # Use the metadata from the installed instance if the EAPI
+ # of either instance is unsupported, since if the installed
+ # instance has an unsupported or corrupt EAPI then we don't
+ # want to attempt to do complex operations such as execute
+ # pkg_config, pkg_prerm or pkg_postrm phases. If both EAPIs
+ # are supported then go ahead and use the live_metadata, in
+ # order to respect dep updates without revision bump or EAPI
+ # bump, as in bug #368725.
+ if not (portage.eapi_is_supported(live_metadata["EAPI"]) and \
+ portage.eapi_is_supported(installed_eapi)):
+ raise KeyError(pkg)
+ self.dbapi.aux_update(pkg, live_metadata)
+ except (KeyError, portage.exception.PortageException):
+ if self._global_updates is None:
+ self._global_updates = \
+ grab_global_updates(self._portdb)
+ perform_global_updates(
+ pkg, self.dbapi, self._global_updates)
+ return self._aux_get(pkg, wants)
+
+ def cpv_discard(self, pkg):
+ """
+ Discard a package from the fake vardb if it exists.
+ """
+ old_pkg = self.dbapi.get(pkg)
+ if old_pkg is not None:
+ self.dbapi.cpv_remove(old_pkg)
+ self._pkg_cache.pop(old_pkg, None)
+ self._aux_get_history.discard(old_pkg.cpv)
+
+ def sync(self, acquire_lock=1):
+ """
+ Call this method to synchronize state with the real vardb
+ after one or more packages may have been installed or
+ uninstalled.
+ """
+ locked = False
+ try:
+ if acquire_lock and os.access(self._real_vardb._dbroot, os.W_OK):
+ self._real_vardb.lock()
+ locked = True
+ self._sync()
+ finally:
+ if locked:
+ self._real_vardb.unlock()
+
+ # Populate the old-style virtuals using the cached values.
+ # Skip the aux_get wrapper here, to avoid unwanted
+ # cache generation.
+ try:
+ self.dbapi.aux_get = self._aux_get
+ self.settings._populate_treeVirtuals_if_needed(self)
+ finally:
+ self.dbapi.aux_get = self._aux_get_wrapper
+
+ def _sync(self):
+
+ real_vardb = self._root_config.trees["vartree"].dbapi
+ current_cpv_set = frozenset(real_vardb.cpv_all())
+ pkg_vardb = self.dbapi
+ pkg_cache = self._pkg_cache
+ aux_get_history = self._aux_get_history
+
+ # Remove any packages that have been uninstalled.
+ for pkg in list(pkg_vardb):
+ if pkg.cpv not in current_cpv_set:
+ self.cpv_discard(pkg)
+
+ # Validate counters and timestamps.
+ slot_counters = {}
+ root_config = self._pkg_root_config
+ validation_keys = ["COUNTER", "_mtime_"]
+ for cpv in current_cpv_set:
+
+ pkg_hash_key = Package._gen_hash_key(cpv=cpv,
+ installed=True, root_config=root_config,
+ type_name="installed")
+ pkg = pkg_vardb.get(pkg_hash_key)
+ if pkg is not None:
+ counter, mtime = real_vardb.aux_get(cpv, validation_keys)
+ try:
+ counter = long(counter)
+ except ValueError:
+ counter = 0
+
+ if counter != pkg.counter or \
+ mtime != pkg.mtime:
+ self.cpv_discard(pkg)
+ pkg = None
+
+ if pkg is None:
+ pkg = self._pkg(cpv)
+
+ other_counter = slot_counters.get(pkg.slot_atom)
+ if other_counter is not None:
+ if other_counter > pkg.counter:
+ continue
+
+ slot_counters[pkg.slot_atom] = pkg.counter
+ pkg_vardb.cpv_inject(pkg)
+
+ real_vardb.flush_cache()
+
+ def _pkg(self, cpv):
+ """
+ The RootConfig instance that will become the Package.root_config
+ attribute can be overridden by the FakeVartree pkg_root_config
+ constructory argument, since we want to be consistent with the
+ depgraph._pkg() method which uses a specially optimized
+ RootConfig that has a FakeVartree instead of a real vartree.
+ """
+ pkg = Package(cpv=cpv, built=True, installed=True,
+ metadata=zip(self._db_keys,
+ self._real_vardb.aux_get(cpv, self._db_keys)),
+ root_config=self._pkg_root_config,
+ type_name="installed")
+
+ try:
+ mycounter = long(pkg.metadata["COUNTER"])
+ except ValueError:
+ mycounter = 0
+ pkg.metadata["COUNTER"] = str(mycounter)
+
+ self._pkg_cache[pkg] = pkg
+ return pkg
+
+def grab_global_updates(portdb):
+ retupdates = {}
+
+ for repo_name in portdb.getRepositories():
+ repo = portdb.getRepositoryPath(repo_name)
+ updpath = os.path.join(repo, "profiles", "updates")
+ if not os.path.isdir(updpath):
+ continue
+
+ try:
+ rawupdates = grab_updates(updpath)
+ except portage.exception.DirectoryNotFound:
+ rawupdates = []
+ upd_commands = []
+ for mykey, mystat, mycontent in rawupdates:
+ commands, errors = parse_updates(mycontent)
+ upd_commands.extend(commands)
+ retupdates[repo_name] = upd_commands
+
+ master_repo = portdb.getRepositoryName(portdb.porttree_root)
+ if master_repo in retupdates:
+ retupdates['DEFAULT'] = retupdates[master_repo]
+
+ return retupdates
+
+def perform_global_updates(mycpv, mydb, myupdates):
+ aux_keys = ["DEPEND", "RDEPEND", "PDEPEND", 'repository']
+ aux_dict = dict(zip(aux_keys, mydb.aux_get(mycpv, aux_keys)))
+ repository = aux_dict.pop('repository')
+ try:
+ mycommands = myupdates[repository]
+ except KeyError:
+ try:
+ mycommands = myupdates['DEFAULT']
+ except KeyError:
+ return
+
+ if not mycommands:
+ return
+
+ updates = update_dbentries(mycommands, aux_dict)
+ if updates:
+ mydb.aux_update(mycpv, updates)
diff --git a/portage_with_autodep/pym/_emerge/FifoIpcDaemon.py b/portage_with_autodep/pym/_emerge/FifoIpcDaemon.py
new file mode 100644
index 0000000..a716dac
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/FifoIpcDaemon.py
@@ -0,0 +1,81 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from _emerge.AbstractPollTask import AbstractPollTask
+from portage.cache.mappings import slot_dict_class
+
+class FifoIpcDaemon(AbstractPollTask):
+
+ __slots__ = ("input_fifo", "output_fifo",) + \
+ ("_files", "_reg_id",)
+
+ _file_names = ("pipe_in",)
+ _files_dict = slot_dict_class(_file_names, prefix="")
+
+ def _start(self):
+ self._files = self._files_dict()
+ input_fd = os.open(self.input_fifo, os.O_RDONLY|os.O_NONBLOCK)
+
+ # File streams are in unbuffered mode since we do atomic
+ # read and write of whole pickles.
+ self._files.pipe_in = os.fdopen(input_fd, 'rb', 0)
+
+ self._reg_id = self.scheduler.register(
+ self._files.pipe_in.fileno(),
+ self._registered_events, self._input_handler)
+
+ self._registered = True
+
+ def _reopen_input(self):
+ """
+ Re-open the input stream, in order to suppress
+ POLLHUP events (bug #339976).
+ """
+ self._files.pipe_in.close()
+ input_fd = os.open(self.input_fifo, os.O_RDONLY|os.O_NONBLOCK)
+ self._files.pipe_in = os.fdopen(input_fd, 'rb', 0)
+ self.scheduler.unregister(self._reg_id)
+ self._reg_id = self.scheduler.register(
+ self._files.pipe_in.fileno(),
+ self._registered_events, self._input_handler)
+
+ def isAlive(self):
+ return self._registered
+
+ def _cancel(self):
+ if self.returncode is None:
+ self.returncode = 1
+ self._unregister()
+
+ def _wait(self):
+ if self.returncode is not None:
+ return self.returncode
+
+ if self._registered:
+ self.scheduler.schedule(self._reg_id)
+ self._unregister()
+
+ if self.returncode is None:
+ self.returncode = os.EX_OK
+
+ return self.returncode
+
+ def _input_handler(self, fd, event):
+ raise NotImplementedError(self)
+
+ def _unregister(self):
+ """
+ Unregister from the scheduler and close open files.
+ """
+
+ self._registered = False
+
+ if self._reg_id is not None:
+ self.scheduler.unregister(self._reg_id)
+ self._reg_id = None
+
+ if self._files is not None:
+ for f in self._files.values():
+ f.close()
+ self._files = None
diff --git a/portage_with_autodep/pym/_emerge/JobStatusDisplay.py b/portage_with_autodep/pym/_emerge/JobStatusDisplay.py
new file mode 100644
index 0000000..1949232
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/JobStatusDisplay.py
@@ -0,0 +1,292 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import formatter
+import io
+import sys
+import time
+
+import portage
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+from portage.output import xtermTitle
+
+from _emerge.getloadavg import getloadavg
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+class JobStatusDisplay(object):
+
+ _bound_properties = ("curval", "failed", "running")
+
+ # Don't update the display unless at least this much
+ # time has passed, in units of seconds.
+ _min_display_latency = 2
+
+ _default_term_codes = {
+ 'cr' : '\r',
+ 'el' : '\x1b[K',
+ 'nel' : '\n',
+ }
+
+ _termcap_name_map = {
+ 'carriage_return' : 'cr',
+ 'clr_eol' : 'el',
+ 'newline' : 'nel',
+ }
+
+ def __init__(self, quiet=False, xterm_titles=True):
+ object.__setattr__(self, "quiet", quiet)
+ object.__setattr__(self, "xterm_titles", xterm_titles)
+ object.__setattr__(self, "maxval", 0)
+ object.__setattr__(self, "merges", 0)
+ object.__setattr__(self, "_changed", False)
+ object.__setattr__(self, "_displayed", False)
+ object.__setattr__(self, "_last_display_time", 0)
+
+ self.reset()
+
+ isatty = os.environ.get('TERM') != 'dumb' and \
+ hasattr(self.out, 'isatty') and \
+ self.out.isatty()
+ object.__setattr__(self, "_isatty", isatty)
+ if not isatty or not self._init_term():
+ term_codes = {}
+ for k, capname in self._termcap_name_map.items():
+ term_codes[k] = self._default_term_codes[capname]
+ object.__setattr__(self, "_term_codes", term_codes)
+ encoding = sys.getdefaultencoding()
+ for k, v in self._term_codes.items():
+ if not isinstance(v, basestring):
+ self._term_codes[k] = v.decode(encoding, 'replace')
+
+ if self._isatty:
+ width = portage.output.get_term_size()[1]
+ else:
+ width = 80
+ self._set_width(width)
+
+ def _set_width(self, width):
+ if width == getattr(self, 'width', None):
+ return
+ if width <= 0 or width > 80:
+ width = 80
+ object.__setattr__(self, "width", width)
+ object.__setattr__(self, "_jobs_column_width", width - 32)
+
+ @property
+ def out(self):
+ """Use a lazy reference to sys.stdout, in case the API consumer has
+ temporarily overridden stdout."""
+ return sys.stdout
+
+ def _write(self, s):
+ # avoid potential UnicodeEncodeError
+ s = _unicode_encode(s,
+ encoding=_encodings['stdio'], errors='backslashreplace')
+ out = self.out
+ if sys.hexversion >= 0x3000000:
+ out = out.buffer
+ out.write(s)
+ out.flush()
+
+ def _init_term(self):
+ """
+ Initialize term control codes.
+ @rtype: bool
+ @returns: True if term codes were successfully initialized,
+ False otherwise.
+ """
+
+ term_type = os.environ.get("TERM", "").strip()
+ if not term_type:
+ return False
+ tigetstr = None
+
+ try:
+ import curses
+ try:
+ curses.setupterm(term_type, self.out.fileno())
+ tigetstr = curses.tigetstr
+ except curses.error:
+ pass
+ except ImportError:
+ pass
+
+ if tigetstr is None:
+ return False
+
+ term_codes = {}
+ for k, capname in self._termcap_name_map.items():
+ code = tigetstr(capname)
+ if code is None:
+ code = self._default_term_codes[capname]
+ term_codes[k] = code
+ object.__setattr__(self, "_term_codes", term_codes)
+ return True
+
+ def _format_msg(self, msg):
+ return ">>> %s" % msg
+
+ def _erase(self):
+ self._write(
+ self._term_codes['carriage_return'] + \
+ self._term_codes['clr_eol'])
+ self._displayed = False
+
+ def _display(self, line):
+ self._write(line)
+ self._displayed = True
+
+ def _update(self, msg):
+
+ if not self._isatty:
+ self._write(self._format_msg(msg) + self._term_codes['newline'])
+ self._displayed = True
+ return
+
+ if self._displayed:
+ self._erase()
+
+ self._display(self._format_msg(msg))
+
+ def displayMessage(self, msg):
+
+ was_displayed = self._displayed
+
+ if self._isatty and self._displayed:
+ self._erase()
+
+ self._write(self._format_msg(msg) + self._term_codes['newline'])
+ self._displayed = False
+
+ if was_displayed:
+ self._changed = True
+ self.display()
+
+ def reset(self):
+ self.maxval = 0
+ self.merges = 0
+ for name in self._bound_properties:
+ object.__setattr__(self, name, 0)
+
+ if self._displayed:
+ self._write(self._term_codes['newline'])
+ self._displayed = False
+
+ def __setattr__(self, name, value):
+ old_value = getattr(self, name)
+ if value == old_value:
+ return
+ object.__setattr__(self, name, value)
+ if name in self._bound_properties:
+ self._property_change(name, old_value, value)
+
+ def _property_change(self, name, old_value, new_value):
+ self._changed = True
+ self.display()
+
+ def _load_avg_str(self):
+ try:
+ avg = getloadavg()
+ except OSError:
+ return 'unknown'
+
+ max_avg = max(avg)
+
+ if max_avg < 10:
+ digits = 2
+ elif max_avg < 100:
+ digits = 1
+ else:
+ digits = 0
+
+ return ", ".join(("%%.%df" % digits ) % x for x in avg)
+
+ def display(self):
+ """
+ Display status on stdout, but only if something has
+ changed since the last call.
+ """
+
+ if self.quiet:
+ return
+
+ current_time = time.time()
+ time_delta = current_time - self._last_display_time
+ if self._displayed and \
+ not self._changed:
+ if not self._isatty:
+ return
+ if time_delta < self._min_display_latency:
+ return
+
+ self._last_display_time = current_time
+ self._changed = False
+ self._display_status()
+
+ def _display_status(self):
+ # Don't use len(self._completed_tasks) here since that also
+ # can include uninstall tasks.
+ curval_str = str(self.curval)
+ maxval_str = str(self.maxval)
+ running_str = str(self.running)
+ failed_str = str(self.failed)
+ load_avg_str = self._load_avg_str()
+
+ color_output = io.StringIO()
+ plain_output = io.StringIO()
+ style_file = portage.output.ConsoleStyleFile(color_output)
+ style_file.write_listener = plain_output
+ style_writer = portage.output.StyleWriter(file=style_file, maxcol=9999)
+ style_writer.style_listener = style_file.new_styles
+ f = formatter.AbstractFormatter(style_writer)
+
+ number_style = "INFORM"
+ f.add_literal_data(_unicode_decode("Jobs: "))
+ f.push_style(number_style)
+ f.add_literal_data(_unicode_decode(curval_str))
+ f.pop_style()
+ f.add_literal_data(_unicode_decode(" of "))
+ f.push_style(number_style)
+ f.add_literal_data(_unicode_decode(maxval_str))
+ f.pop_style()
+ f.add_literal_data(_unicode_decode(" complete"))
+
+ if self.running:
+ f.add_literal_data(_unicode_decode(", "))
+ f.push_style(number_style)
+ f.add_literal_data(_unicode_decode(running_str))
+ f.pop_style()
+ f.add_literal_data(_unicode_decode(" running"))
+
+ if self.failed:
+ f.add_literal_data(_unicode_decode(", "))
+ f.push_style(number_style)
+ f.add_literal_data(_unicode_decode(failed_str))
+ f.pop_style()
+ f.add_literal_data(_unicode_decode(" failed"))
+
+ padding = self._jobs_column_width - len(plain_output.getvalue())
+ if padding > 0:
+ f.add_literal_data(padding * _unicode_decode(" "))
+
+ f.add_literal_data(_unicode_decode("Load avg: "))
+ f.add_literal_data(_unicode_decode(load_avg_str))
+
+ # Truncate to fit width, to avoid making the terminal scroll if the
+ # line overflows (happens when the load average is large).
+ plain_output = plain_output.getvalue()
+ if self._isatty and len(plain_output) > self.width:
+ # Use plain_output here since it's easier to truncate
+ # properly than the color output which contains console
+ # color codes.
+ self._update(plain_output[:self.width])
+ else:
+ self._update(color_output.getvalue())
+
+ if self.xterm_titles:
+ xtermTitle(" ".join(plain_output.split()))
diff --git a/portage_with_autodep/pym/_emerge/MergeListItem.py b/portage_with_autodep/pym/_emerge/MergeListItem.py
new file mode 100644
index 0000000..2176bf6
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/MergeListItem.py
@@ -0,0 +1,135 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from portage.output import colorize
+
+from _emerge.AsynchronousTask import AsynchronousTask
+from _emerge.Binpkg import Binpkg
+from _emerge.CompositeTask import CompositeTask
+from _emerge.EbuildBuild import EbuildBuild
+from _emerge.PackageUninstall import PackageUninstall
+
+class MergeListItem(CompositeTask):
+
+ """
+ TODO: For parallel scheduling, everything here needs asynchronous
+ execution support (start, poll, and wait methods).
+ """
+
+ __slots__ = ("args_set",
+ "binpkg_opts", "build_opts", "config_pool", "emerge_opts",
+ "find_blockers", "logger", "mtimedb", "pkg",
+ "pkg_count", "pkg_to_replace", "prefetcher",
+ "settings", "statusMessage", "world_atom") + \
+ ("_install_task",)
+
+ def _start(self):
+
+ pkg = self.pkg
+ build_opts = self.build_opts
+
+ if pkg.installed:
+ # uninstall, executed by self.merge()
+ self.returncode = os.EX_OK
+ self.wait()
+ return
+
+ args_set = self.args_set
+ find_blockers = self.find_blockers
+ logger = self.logger
+ mtimedb = self.mtimedb
+ pkg_count = self.pkg_count
+ scheduler = self.scheduler
+ settings = self.settings
+ world_atom = self.world_atom
+ ldpath_mtimes = mtimedb["ldpath"]
+
+ action_desc = "Emerging"
+ preposition = "for"
+ if pkg.type_name == "binary":
+ action_desc += " binary"
+
+ if build_opts.fetchonly:
+ action_desc = "Fetching"
+
+ msg = "%s (%s of %s) %s" % \
+ (action_desc,
+ colorize("MERGE_LIST_PROGRESS", str(pkg_count.curval)),
+ colorize("MERGE_LIST_PROGRESS", str(pkg_count.maxval)),
+ colorize("GOOD", pkg.cpv))
+
+ portdb = pkg.root_config.trees["porttree"].dbapi
+ portdir_repo_name = portdb.getRepositoryName(portdb.porttree_root)
+ if portdir_repo_name:
+ pkg_repo_name = pkg.repo
+ if pkg_repo_name != portdir_repo_name:
+ if pkg_repo_name == pkg.UNKNOWN_REPO:
+ pkg_repo_name = "unknown repo"
+ msg += " from %s" % pkg_repo_name
+
+ if pkg.root != "/":
+ msg += " %s %s" % (preposition, pkg.root)
+
+ if not build_opts.pretend:
+ self.statusMessage(msg)
+ logger.log(" >>> emerge (%s of %s) %s to %s" % \
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg.root))
+
+ if pkg.type_name == "ebuild":
+
+ build = EbuildBuild(args_set=args_set,
+ background=self.background,
+ config_pool=self.config_pool,
+ find_blockers=find_blockers,
+ ldpath_mtimes=ldpath_mtimes, logger=logger,
+ opts=build_opts, pkg=pkg, pkg_count=pkg_count,
+ prefetcher=self.prefetcher, scheduler=scheduler,
+ settings=settings, world_atom=world_atom)
+
+ self._install_task = build
+ self._start_task(build, self._default_final_exit)
+ return
+
+ elif pkg.type_name == "binary":
+
+ binpkg = Binpkg(background=self.background,
+ find_blockers=find_blockers,
+ ldpath_mtimes=ldpath_mtimes, logger=logger,
+ opts=self.binpkg_opts, pkg=pkg, pkg_count=pkg_count,
+ prefetcher=self.prefetcher, settings=settings,
+ scheduler=scheduler, world_atom=world_atom)
+
+ self._install_task = binpkg
+ self._start_task(binpkg, self._default_final_exit)
+ return
+
+ def create_install_task(self):
+
+ pkg = self.pkg
+ build_opts = self.build_opts
+ mtimedb = self.mtimedb
+ scheduler = self.scheduler
+ settings = self.settings
+ world_atom = self.world_atom
+ ldpath_mtimes = mtimedb["ldpath"]
+
+ if pkg.installed:
+ if not (build_opts.buildpkgonly or \
+ build_opts.fetchonly or build_opts.pretend):
+
+ task = PackageUninstall(background=self.background,
+ ldpath_mtimes=ldpath_mtimes, opts=self.emerge_opts,
+ pkg=pkg, scheduler=scheduler, settings=settings,
+ world_atom=world_atom)
+
+ else:
+ task = AsynchronousTask()
+
+ elif build_opts.fetchonly or \
+ build_opts.buildpkgonly:
+ task = AsynchronousTask()
+ else:
+ task = self._install_task.create_install_task()
+
+ return task
diff --git a/portage_with_autodep/pym/_emerge/MetadataRegen.py b/portage_with_autodep/pym/_emerge/MetadataRegen.py
new file mode 100644
index 0000000..8103175
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/MetadataRegen.py
@@ -0,0 +1,184 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import portage
+from portage import os
+from _emerge.EbuildMetadataPhase import EbuildMetadataPhase
+from _emerge.PollScheduler import PollScheduler
+
+class MetadataRegen(PollScheduler):
+
+ def __init__(self, portdb, cp_iter=None, consumer=None,
+ max_jobs=None, max_load=None):
+ PollScheduler.__init__(self)
+ self._portdb = portdb
+ self._global_cleanse = False
+ if cp_iter is None:
+ cp_iter = self._iter_every_cp()
+ # We can globally cleanse stale cache only if we
+ # iterate over every single cp.
+ self._global_cleanse = True
+ self._cp_iter = cp_iter
+ self._consumer = consumer
+
+ if max_jobs is None:
+ max_jobs = 1
+
+ self._max_jobs = max_jobs
+ self._max_load = max_load
+
+ self._valid_pkgs = set()
+ self._cp_set = set()
+ self._process_iter = self._iter_metadata_processes()
+ self.returncode = os.EX_OK
+ self._error_count = 0
+ self._running_tasks = set()
+
+ def _terminate_tasks(self):
+ while self._running_tasks:
+ self._running_tasks.pop().cancel()
+
+ def _iter_every_cp(self):
+ portage.writemsg_stdout("Listing available packages...\n")
+ every_cp = self._portdb.cp_all()
+ portage.writemsg_stdout("Regenerating cache entries...\n")
+ every_cp.sort(reverse=True)
+ try:
+ while not self._terminated_tasks:
+ yield every_cp.pop()
+ except IndexError:
+ pass
+
+ def _iter_metadata_processes(self):
+ portdb = self._portdb
+ valid_pkgs = self._valid_pkgs
+ cp_set = self._cp_set
+ consumer = self._consumer
+
+ for cp in self._cp_iter:
+ if self._terminated_tasks:
+ break
+ cp_set.add(cp)
+ portage.writemsg_stdout("Processing %s\n" % cp)
+ cpv_list = portdb.cp_list(cp)
+ for cpv in cpv_list:
+ if self._terminated_tasks:
+ break
+ valid_pkgs.add(cpv)
+ ebuild_path, repo_path = portdb.findname2(cpv)
+ if ebuild_path is None:
+ raise AssertionError("ebuild not found for '%s'" % cpv)
+ metadata, st, emtime = portdb._pull_valid_cache(
+ cpv, ebuild_path, repo_path)
+ if metadata is not None:
+ if consumer is not None:
+ consumer(cpv, ebuild_path,
+ repo_path, metadata)
+ continue
+
+ yield EbuildMetadataPhase(cpv=cpv, ebuild_path=ebuild_path,
+ ebuild_mtime=emtime,
+ metadata_callback=portdb._metadata_callback,
+ portdb=portdb, repo_path=repo_path,
+ settings=portdb.doebuild_settings)
+
+ def run(self):
+
+ portdb = self._portdb
+ from portage.cache.cache_errors import CacheError
+ dead_nodes = {}
+
+ while self._schedule():
+ self._poll_loop()
+
+ while self._jobs:
+ self._poll_loop()
+
+ if self._terminated_tasks:
+ self.returncode = 1
+ return
+
+ if self._global_cleanse:
+ for mytree in portdb.porttrees:
+ try:
+ dead_nodes[mytree] = set(portdb.auxdb[mytree])
+ except CacheError as e:
+ portage.writemsg("Error listing cache entries for " + \
+ "'%s': %s, continuing...\n" % (mytree, e),
+ noiselevel=-1)
+ del e
+ dead_nodes = None
+ break
+ else:
+ cp_set = self._cp_set
+ cpv_getkey = portage.cpv_getkey
+ for mytree in portdb.porttrees:
+ try:
+ dead_nodes[mytree] = set(cpv for cpv in \
+ portdb.auxdb[mytree] \
+ if cpv_getkey(cpv) in cp_set)
+ except CacheError as e:
+ portage.writemsg("Error listing cache entries for " + \
+ "'%s': %s, continuing...\n" % (mytree, e),
+ noiselevel=-1)
+ del e
+ dead_nodes = None
+ break
+
+ if dead_nodes:
+ for y in self._valid_pkgs:
+ for mytree in portdb.porttrees:
+ if portdb.findname2(y, mytree=mytree)[0]:
+ dead_nodes[mytree].discard(y)
+
+ for mytree, nodes in dead_nodes.items():
+ auxdb = portdb.auxdb[mytree]
+ for y in nodes:
+ try:
+ del auxdb[y]
+ except (KeyError, CacheError):
+ pass
+
+ def _schedule_tasks(self):
+ """
+ @rtype: bool
+ @returns: True if there may be remaining tasks to schedule,
+ False otherwise.
+ """
+ if self._terminated_tasks:
+ return False
+
+ while self._can_add_job():
+ try:
+ metadata_process = next(self._process_iter)
+ except StopIteration:
+ return False
+
+ self._jobs += 1
+ self._running_tasks.add(metadata_process)
+ metadata_process.scheduler = self.sched_iface
+ metadata_process.addExitListener(self._metadata_exit)
+ metadata_process.start()
+ return True
+
+ def _metadata_exit(self, metadata_process):
+ self._jobs -= 1
+ self._running_tasks.discard(metadata_process)
+ if metadata_process.returncode != os.EX_OK:
+ self.returncode = 1
+ self._error_count += 1
+ self._valid_pkgs.discard(metadata_process.cpv)
+ if not self._terminated_tasks:
+ portage.writemsg("Error processing %s, continuing...\n" % \
+ (metadata_process.cpv,), noiselevel=-1)
+
+ if self._consumer is not None:
+ # On failure, still notify the consumer (in this case the metadata
+ # argument is None).
+ self._consumer(metadata_process.cpv,
+ metadata_process.ebuild_path,
+ metadata_process.repo_path,
+ metadata_process.metadata)
+
+ self._schedule()
+
diff --git a/portage_with_autodep/pym/_emerge/MiscFunctionsProcess.py b/portage_with_autodep/pym/_emerge/MiscFunctionsProcess.py
new file mode 100644
index 0000000..ce0ab14
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/MiscFunctionsProcess.py
@@ -0,0 +1,33 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.AbstractEbuildProcess import AbstractEbuildProcess
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.package.ebuild.doebuild:spawn'
+)
+from portage import os
+
+class MiscFunctionsProcess(AbstractEbuildProcess):
+ """
+ Spawns misc-functions.sh with an existing ebuild environment.
+ """
+
+ __slots__ = ('commands',)
+
+ def _start(self):
+ settings = self.settings
+ portage_bin_path = settings["PORTAGE_BIN_PATH"]
+ misc_sh_binary = os.path.join(portage_bin_path,
+ os.path.basename(portage.const.MISC_SH_BINARY))
+
+ self.args = [portage._shell_quote(misc_sh_binary)] + self.commands
+ if self.logfile is None and \
+ self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
+ self.logfile = settings.get("PORTAGE_LOG_FILE")
+
+ AbstractEbuildProcess._start(self)
+
+ def _spawn(self, args, **kwargs):
+ self.settings.pop("EBUILD_PHASE", None)
+ return spawn(" ".join(args), self.settings, **kwargs)
diff --git a/portage_with_autodep/pym/_emerge/Package.py b/portage_with_autodep/pym/_emerge/Package.py
new file mode 100644
index 0000000..20c72b4
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/Package.py
@@ -0,0 +1,700 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+from itertools import chain
+import portage
+from portage import _encodings, _unicode_decode, _unicode_encode
+from portage.cache.mappings import slot_dict_class
+from portage.const import EBUILD_PHASES
+from portage.dep import Atom, check_required_use, use_reduce, \
+ paren_enclose, _slot_re, _slot_separator, _repo_separator
+from portage.eapi import eapi_has_iuse_defaults, eapi_has_required_use
+from portage.exception import InvalidDependString
+from portage.repository.config import _gen_valid_repo
+from _emerge.Task import Task
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+ long = int
+
+class Package(Task):
+
+ __hash__ = Task.__hash__
+ __slots__ = ("built", "cpv", "depth",
+ "installed", "metadata", "onlydeps", "operation",
+ "root_config", "type_name",
+ "category", "counter", "cp", "cpv_split",
+ "inherited", "invalid", "iuse", "masks", "mtime",
+ "pf", "pv_split", "root", "slot", "slot_atom", "visible",) + \
+ ("_raw_metadata", "_use",)
+
+ metadata_keys = [
+ "BUILD_TIME", "CHOST", "COUNTER", "DEPEND", "EAPI",
+ "INHERITED", "IUSE", "KEYWORDS",
+ "LICENSE", "PDEPEND", "PROVIDE", "RDEPEND",
+ "repository", "PROPERTIES", "RESTRICT", "SLOT", "USE",
+ "_mtime_", "DEFINED_PHASES", "REQUIRED_USE"]
+
+ _dep_keys = ('DEPEND', 'PDEPEND', 'RDEPEND',)
+ _use_conditional_misc_keys = ('LICENSE', 'PROPERTIES', 'RESTRICT')
+ UNKNOWN_REPO = "__unknown__"
+
+ def __init__(self, **kwargs):
+ Task.__init__(self, **kwargs)
+ # the SlotObject constructor assigns self.root_config from keyword args
+ # and is an instance of a '_emerge.RootConfig.RootConfig class
+ self.root = self.root_config.root
+ self._raw_metadata = _PackageMetadataWrapperBase(self.metadata)
+ self.metadata = _PackageMetadataWrapper(self, self._raw_metadata)
+ if not self.built:
+ self.metadata['CHOST'] = self.root_config.settings.get('CHOST', '')
+ self.cp = portage.cpv_getkey(self.cpv)
+ slot = self.slot
+ if _slot_re.match(slot) is None:
+ self._invalid_metadata('SLOT.invalid',
+ "SLOT: invalid value: '%s'" % slot)
+ # Avoid an InvalidAtom exception when creating slot_atom.
+ # This package instance will be masked due to empty SLOT.
+ slot = '0'
+ if (self.iuse.enabled or self.iuse.disabled) and \
+ not eapi_has_iuse_defaults(self.metadata["EAPI"]):
+ if not self.installed:
+ self._invalid_metadata('EAPI.incompatible',
+ "IUSE contains defaults, but EAPI doesn't allow them")
+ self.slot_atom = portage.dep.Atom("%s%s%s" % (self.cp, _slot_separator, slot))
+ self.category, self.pf = portage.catsplit(self.cpv)
+ self.cpv_split = portage.catpkgsplit(self.cpv)
+ self.pv_split = self.cpv_split[1:]
+ if self.inherited is None:
+ self.inherited = frozenset()
+ repo = _gen_valid_repo(self.metadata.get('repository', ''))
+ if not repo:
+ repo = self.UNKNOWN_REPO
+ self.metadata['repository'] = repo
+
+ self._validate_deps()
+ self.masks = self._masks()
+ self.visible = self._visible(self.masks)
+ if self.operation is None:
+ if self.onlydeps or self.installed:
+ self.operation = "nomerge"
+ else:
+ self.operation = "merge"
+
+ self._hash_key = Package._gen_hash_key(cpv=self.cpv,
+ installed=self.installed, onlydeps=self.onlydeps,
+ operation=self.operation, repo_name=repo,
+ root_config=self.root_config,
+ type_name=self.type_name)
+ self._hash_value = hash(self._hash_key)
+
+ @classmethod
+ def _gen_hash_key(cls, cpv=None, installed=None, onlydeps=None,
+ operation=None, repo_name=None, root_config=None,
+ type_name=None, **kwargs):
+
+ if operation is None:
+ if installed or onlydeps:
+ operation = "nomerge"
+ else:
+ operation = "merge"
+
+ root = None
+ if root_config is not None:
+ root = root_config.root
+ else:
+ raise TypeError("root_config argument is required")
+
+ # For installed (and binary) packages we don't care for the repo
+ # when it comes to hashing, because there can only be one cpv.
+ # So overwrite the repo_key with type_name.
+ if type_name is None:
+ raise TypeError("type_name argument is required")
+ elif type_name == "ebuild":
+ if repo_name is None:
+ raise AssertionError(
+ "Package._gen_hash_key() " + \
+ "called without 'repo_name' argument")
+ repo_key = repo_name
+ else:
+ # For installed (and binary) packages we don't care for the repo
+ # when it comes to hashing, because there can only be one cpv.
+ # So overwrite the repo_key with type_name.
+ repo_key = type_name
+
+ return (type_name, root, cpv, operation, repo_key)
+
+ def _validate_deps(self):
+ """
+ Validate deps. This does not trigger USE calculation since that
+ is expensive for ebuilds and therefore we want to avoid doing
+ in unnecessarily (like for masked packages).
+ """
+ eapi = self.metadata['EAPI']
+ dep_eapi = eapi
+ dep_valid_flag = self.iuse.is_valid_flag
+ if self.installed:
+ # Ignore EAPI.incompatible and conditionals missing
+ # from IUSE for installed packages since these issues
+ # aren't relevant now (re-evaluate when new EAPIs are
+ # deployed).
+ dep_eapi = None
+ dep_valid_flag = None
+
+ for k in self._dep_keys:
+ v = self.metadata.get(k)
+ if not v:
+ continue
+ try:
+ use_reduce(v, eapi=dep_eapi, matchall=True,
+ is_valid_flag=dep_valid_flag, token_class=Atom)
+ except InvalidDependString as e:
+ self._metadata_exception(k, e)
+
+ k = 'PROVIDE'
+ v = self.metadata.get(k)
+ if v:
+ try:
+ use_reduce(v, eapi=dep_eapi, matchall=True,
+ is_valid_flag=dep_valid_flag, token_class=Atom)
+ except InvalidDependString as e:
+ self._invalid_metadata("PROVIDE.syntax",
+ _unicode_decode("%s: %s") % (k, e))
+
+ for k in self._use_conditional_misc_keys:
+ v = self.metadata.get(k)
+ if not v:
+ continue
+ try:
+ use_reduce(v, eapi=dep_eapi, matchall=True,
+ is_valid_flag=dep_valid_flag)
+ except InvalidDependString as e:
+ self._metadata_exception(k, e)
+
+ k = 'REQUIRED_USE'
+ v = self.metadata.get(k)
+ if v:
+ if not eapi_has_required_use(eapi):
+ self._invalid_metadata('EAPI.incompatible',
+ "REQUIRED_USE set, but EAPI='%s' doesn't allow it" % eapi)
+ else:
+ try:
+ check_required_use(v, (),
+ self.iuse.is_valid_flag)
+ except InvalidDependString as e:
+ # Force unicode format string for python-2.x safety,
+ # ensuring that PortageException.__unicode__() is used
+ # when necessary.
+ self._invalid_metadata(k + ".syntax",
+ _unicode_decode("%s: %s") % (k, e))
+
+ k = 'SRC_URI'
+ v = self.metadata.get(k)
+ if v:
+ try:
+ use_reduce(v, is_src_uri=True, eapi=eapi, matchall=True,
+ is_valid_flag=self.iuse.is_valid_flag)
+ except InvalidDependString as e:
+ if not self.installed:
+ self._metadata_exception(k, e)
+
+ def copy(self):
+ return Package(built=self.built, cpv=self.cpv, depth=self.depth,
+ installed=self.installed, metadata=self._raw_metadata,
+ onlydeps=self.onlydeps, operation=self.operation,
+ root_config=self.root_config, type_name=self.type_name)
+
+ def _masks(self):
+ masks = {}
+ settings = self.root_config.settings
+
+ if self.invalid is not None:
+ masks['invalid'] = self.invalid
+
+ if not settings._accept_chost(self.cpv, self.metadata):
+ masks['CHOST'] = self.metadata['CHOST']
+
+ eapi = self.metadata["EAPI"]
+ if not portage.eapi_is_supported(eapi):
+ masks['EAPI.unsupported'] = eapi
+ if portage._eapi_is_deprecated(eapi):
+ masks['EAPI.deprecated'] = eapi
+
+ missing_keywords = settings._getMissingKeywords(
+ self.cpv, self.metadata)
+ if missing_keywords:
+ masks['KEYWORDS'] = missing_keywords
+
+ try:
+ missing_properties = settings._getMissingProperties(
+ self.cpv, self.metadata)
+ if missing_properties:
+ masks['PROPERTIES'] = missing_properties
+ except InvalidDependString:
+ # already recorded as 'invalid'
+ pass
+
+ mask_atom = settings._getMaskAtom(self.cpv, self.metadata)
+ if mask_atom is not None:
+ masks['package.mask'] = mask_atom
+
+ system_mask = settings._getProfileMaskAtom(
+ self.cpv, self.metadata)
+ if system_mask is not None:
+ masks['profile.system'] = system_mask
+
+ try:
+ missing_licenses = settings._getMissingLicenses(
+ self.cpv, self.metadata)
+ if missing_licenses:
+ masks['LICENSE'] = missing_licenses
+ except InvalidDependString:
+ # already recorded as 'invalid'
+ pass
+
+ if not masks:
+ masks = None
+
+ return masks
+
+ def _visible(self, masks):
+
+ if masks is not None:
+
+ if 'EAPI.unsupported' in masks:
+ return False
+
+ if 'invalid' in masks:
+ return False
+
+ if not self.installed and ( \
+ 'CHOST' in masks or \
+ 'EAPI.deprecated' in masks or \
+ 'KEYWORDS' in masks or \
+ 'PROPERTIES' in masks):
+ return False
+
+ if 'package.mask' in masks or \
+ 'profile.system' in masks or \
+ 'LICENSE' in masks:
+ return False
+
+ return True
+
+ def get_keyword_mask(self):
+ """returns None, 'missing', or 'unstable'."""
+
+ missing = self.root_config.settings._getRawMissingKeywords(
+ self.cpv, self.metadata)
+
+ if not missing:
+ return None
+
+ if '**' in missing:
+ return 'missing'
+
+ global_accept_keywords = frozenset(
+ self.root_config.settings.get("ACCEPT_KEYWORDS", "").split())
+
+ for keyword in missing:
+ if keyword.lstrip("~") in global_accept_keywords:
+ return 'unstable'
+
+ return 'missing'
+
+ def isHardMasked(self):
+ """returns a bool if the cpv is in the list of
+ expanded pmaskdict[cp] available ebuilds"""
+ pmask = self.root_config.settings._getRawMaskAtom(
+ self.cpv, self.metadata)
+ return pmask is not None
+
+ def _metadata_exception(self, k, e):
+
+ # For unicode safety with python-2.x we need to avoid
+ # using the string format operator with a non-unicode
+ # format string, since that will result in the
+ # PortageException.__str__() method being invoked,
+ # followed by unsafe decoding that may result in a
+ # UnicodeDecodeError. Therefore, use _unicode_decode()
+ # to ensure that format strings are unicode, so that
+ # PortageException.__unicode__() is used when necessary
+ # in python-2.x.
+ if not self.installed:
+ categorized_error = False
+ if e.errors:
+ for error in e.errors:
+ if getattr(error, 'category', None) is None:
+ continue
+ categorized_error = True
+ self._invalid_metadata(error.category,
+ _unicode_decode("%s: %s") % (k, error))
+
+ if not categorized_error:
+ self._invalid_metadata(k + ".syntax",
+ _unicode_decode("%s: %s") % (k, e))
+ else:
+ # For installed packages, show the path of the file
+ # containing the invalid metadata, since the user may
+ # want to fix the deps by hand.
+ vardb = self.root_config.trees['vartree'].dbapi
+ path = vardb.getpath(self.cpv, filename=k)
+ self._invalid_metadata(k + ".syntax",
+ _unicode_decode("%s: %s in '%s'") % (k, e, path))
+
+ def _invalid_metadata(self, msg_type, msg):
+ if self.invalid is None:
+ self.invalid = {}
+ msgs = self.invalid.get(msg_type)
+ if msgs is None:
+ msgs = []
+ self.invalid[msg_type] = msgs
+ msgs.append(msg)
+
+ def __str__(self):
+ if self.operation == "merge":
+ if self.type_name == "binary":
+ cpv_color = "PKG_BINARY_MERGE"
+ else:
+ cpv_color = "PKG_MERGE"
+ elif self.operation == "uninstall":
+ cpv_color = "PKG_UNINSTALL"
+ else:
+ cpv_color = "PKG_NOMERGE"
+
+ s = "(%s, %s" \
+ % (portage.output.colorize(cpv_color, self.cpv + _repo_separator + self.repo) , self.type_name)
+
+ if self.type_name == "installed":
+ if self.root != "/":
+ s += " in '%s'" % self.root
+ if self.operation == "uninstall":
+ s += " scheduled for uninstall"
+ else:
+ if self.operation == "merge":
+ s += " scheduled for merge"
+ if self.root != "/":
+ s += " to '%s'" % self.root
+ s += ")"
+ return s
+
+ if sys.hexversion < 0x3000000:
+
+ __unicode__ = __str__
+
+ def __str__(self):
+ return _unicode_encode(self.__unicode__(),
+ encoding=_encodings['content'])
+
+ class _use_class(object):
+
+ __slots__ = ("enabled", "_expand", "_expand_hidden",
+ "_force", "_pkg", "_mask")
+
+ # Share identical frozenset instances when available.
+ _frozensets = {}
+
+ def __init__(self, pkg, use_str):
+ self._pkg = pkg
+ self._expand = None
+ self._expand_hidden = None
+ self._force = None
+ self._mask = None
+ self.enabled = frozenset(use_str.split())
+ if pkg.built:
+ # Use IUSE to validate USE settings for built packages,
+ # in case the package manager that built this package
+ # failed to do that for some reason (or in case of
+ # data corruption).
+ missing_iuse = pkg.iuse.get_missing_iuse(self.enabled)
+ if missing_iuse:
+ self.enabled = self.enabled.difference(missing_iuse)
+
+ def _init_force_mask(self):
+ pkgsettings = self._pkg._get_pkgsettings()
+ frozensets = self._frozensets
+ s = frozenset(
+ pkgsettings.get("USE_EXPAND", "").lower().split())
+ self._expand = frozensets.setdefault(s, s)
+ s = frozenset(
+ pkgsettings.get("USE_EXPAND_HIDDEN", "").lower().split())
+ self._expand_hidden = frozensets.setdefault(s, s)
+ s = pkgsettings.useforce
+ self._force = frozensets.setdefault(s, s)
+ s = pkgsettings.usemask
+ self._mask = frozensets.setdefault(s, s)
+
+ @property
+ def expand(self):
+ if self._expand is None:
+ self._init_force_mask()
+ return self._expand
+
+ @property
+ def expand_hidden(self):
+ if self._expand_hidden is None:
+ self._init_force_mask()
+ return self._expand_hidden
+
+ @property
+ def force(self):
+ if self._force is None:
+ self._init_force_mask()
+ return self._force
+
+ @property
+ def mask(self):
+ if self._mask is None:
+ self._init_force_mask()
+ return self._mask
+
+ @property
+ def repo(self):
+ return self.metadata['repository']
+
+ @property
+ def repo_priority(self):
+ repo_info = self.root_config.settings.repositories.prepos.get(self.repo)
+ if repo_info is None:
+ return None
+ return repo_info.priority
+
+ @property
+ def use(self):
+ if self._use is None:
+ self.metadata._init_use()
+ return self._use
+
+ def _get_pkgsettings(self):
+ pkgsettings = self.root_config.trees[
+ 'porttree'].dbapi.doebuild_settings
+ pkgsettings.setcpv(self)
+ return pkgsettings
+
+ class _iuse(object):
+
+ __slots__ = ("__weakref__", "all", "enabled", "disabled",
+ "tokens") + ("_iuse_implicit_match",)
+
+ def __init__(self, tokens, iuse_implicit_match):
+ self.tokens = tuple(tokens)
+ self._iuse_implicit_match = iuse_implicit_match
+ enabled = []
+ disabled = []
+ other = []
+ for x in tokens:
+ prefix = x[:1]
+ if prefix == "+":
+ enabled.append(x[1:])
+ elif prefix == "-":
+ disabled.append(x[1:])
+ else:
+ other.append(x)
+ self.enabled = frozenset(enabled)
+ self.disabled = frozenset(disabled)
+ self.all = frozenset(chain(enabled, disabled, other))
+
+ def is_valid_flag(self, flags):
+ """
+ @returns: True if all flags are valid USE values which may
+ be specified in USE dependencies, False otherwise.
+ """
+ if isinstance(flags, basestring):
+ flags = [flags]
+
+ for flag in flags:
+ if not flag in self.all and \
+ not self._iuse_implicit_match(flag):
+ return False
+ return True
+
+ def get_missing_iuse(self, flags):
+ """
+ @returns: A list of flags missing from IUSE.
+ """
+ if isinstance(flags, basestring):
+ flags = [flags]
+ missing_iuse = []
+ for flag in flags:
+ if not flag in self.all and \
+ not self._iuse_implicit_match(flag):
+ missing_iuse.append(flag)
+ return missing_iuse
+
+ def __len__(self):
+ return 4
+
+ def __iter__(self):
+ """
+ This is used to generate mtimedb resume mergelist entries, so we
+ limit it to 4 items for backward compatibility.
+ """
+ return iter(self._hash_key[:4])
+
+ def __lt__(self, other):
+ if other.cp != self.cp:
+ return False
+ if portage.pkgcmp(self.pv_split, other.pv_split) < 0:
+ return True
+ return False
+
+ def __le__(self, other):
+ if other.cp != self.cp:
+ return False
+ if portage.pkgcmp(self.pv_split, other.pv_split) <= 0:
+ return True
+ return False
+
+ def __gt__(self, other):
+ if other.cp != self.cp:
+ return False
+ if portage.pkgcmp(self.pv_split, other.pv_split) > 0:
+ return True
+ return False
+
+ def __ge__(self, other):
+ if other.cp != self.cp:
+ return False
+ if portage.pkgcmp(self.pv_split, other.pv_split) >= 0:
+ return True
+ return False
+
+_all_metadata_keys = set(x for x in portage.auxdbkeys \
+ if not x.startswith("UNUSED_"))
+_all_metadata_keys.update(Package.metadata_keys)
+_all_metadata_keys = frozenset(_all_metadata_keys)
+
+_PackageMetadataWrapperBase = slot_dict_class(_all_metadata_keys)
+
+class _PackageMetadataWrapper(_PackageMetadataWrapperBase):
+ """
+ Detect metadata updates and synchronize Package attributes.
+ """
+
+ __slots__ = ("_pkg",)
+ _wrapped_keys = frozenset(
+ ["COUNTER", "INHERITED", "IUSE", "SLOT", "USE", "_mtime_"])
+ _use_conditional_keys = frozenset(
+ ['LICENSE', 'PROPERTIES', 'PROVIDE', 'RESTRICT',])
+
+ def __init__(self, pkg, metadata):
+ _PackageMetadataWrapperBase.__init__(self)
+ self._pkg = pkg
+ if not pkg.built:
+ # USE is lazy, but we want it to show up in self.keys().
+ _PackageMetadataWrapperBase.__setitem__(self, 'USE', '')
+
+ self.update(metadata)
+
+ def _init_use(self):
+ if self._pkg.built:
+ use_str = self['USE']
+ self._pkg._use = self._pkg._use_class(
+ self._pkg, use_str)
+ else:
+ try:
+ use_str = _PackageMetadataWrapperBase.__getitem__(self, 'USE')
+ except KeyError:
+ use_str = None
+ calculated_use = False
+ if not use_str:
+ use_str = self._pkg._get_pkgsettings()["PORTAGE_USE"]
+ calculated_use = True
+ _PackageMetadataWrapperBase.__setitem__(self, 'USE', use_str)
+ self._pkg._use = self._pkg._use_class(
+ self._pkg, use_str)
+ # Initialize these now, since USE access has just triggered
+ # setcpv, and we want to cache the result of the force/mask
+ # calculations that were done.
+ if calculated_use:
+ self._pkg._use._init_force_mask()
+
+ return use_str
+
+ def __getitem__(self, k):
+ v = _PackageMetadataWrapperBase.__getitem__(self, k)
+ if k in self._use_conditional_keys:
+ if self._pkg.root_config.settings.local_config and '?' in v:
+ try:
+ v = paren_enclose(use_reduce(v, uselist=self._pkg.use.enabled, \
+ is_valid_flag=self._pkg.iuse.is_valid_flag))
+ except InvalidDependString:
+ # This error should already have been registered via
+ # self._pkg._invalid_metadata().
+ pass
+ else:
+ self[k] = v
+
+ elif k == 'USE' and not self._pkg.built:
+ if not v:
+ # This is lazy because it's expensive.
+ v = self._init_use()
+
+ return v
+
+ def __setitem__(self, k, v):
+ _PackageMetadataWrapperBase.__setitem__(self, k, v)
+ if k in self._wrapped_keys:
+ getattr(self, "_set_" + k.lower())(k, v)
+
+ def _set_inherited(self, k, v):
+ if isinstance(v, basestring):
+ v = frozenset(v.split())
+ self._pkg.inherited = v
+
+ def _set_iuse(self, k, v):
+ self._pkg.iuse = self._pkg._iuse(
+ v.split(), self._pkg.root_config.settings._iuse_implicit_match)
+
+ def _set_slot(self, k, v):
+ self._pkg.slot = v
+
+ def _set_counter(self, k, v):
+ if isinstance(v, basestring):
+ try:
+ v = long(v.strip())
+ except ValueError:
+ v = 0
+ self._pkg.counter = v
+
+ def _set_use(self, k, v):
+ # Force regeneration of _use attribute
+ self._pkg._use = None
+ # Use raw metadata to restore USE conditional values
+ # to unevaluated state
+ raw_metadata = self._pkg._raw_metadata
+ for x in self._use_conditional_keys:
+ try:
+ self[x] = raw_metadata[x]
+ except KeyError:
+ pass
+
+ def _set__mtime_(self, k, v):
+ if isinstance(v, basestring):
+ try:
+ v = long(v.strip())
+ except ValueError:
+ v = 0
+ self._pkg.mtime = v
+
+ @property
+ def properties(self):
+ return self['PROPERTIES'].split()
+
+ @property
+ def restrict(self):
+ return self['RESTRICT'].split()
+
+ @property
+ def defined_phases(self):
+ """
+ Returns tokens from DEFINED_PHASES metadata if it is defined,
+ otherwise returns a tuple containing all possible phases. This
+ makes it easy to do containment checks to see if it's safe to
+ skip execution of a given phase.
+ """
+ s = self['DEFINED_PHASES']
+ if s:
+ return s.split()
+ return EBUILD_PHASES
diff --git a/portage_with_autodep/pym/_emerge/PackageArg.py b/portage_with_autodep/pym/_emerge/PackageArg.py
new file mode 100644
index 0000000..ebfe4b2
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/PackageArg.py
@@ -0,0 +1,19 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.DependencyArg import DependencyArg
+from _emerge.Package import Package
+import portage
+from portage._sets.base import InternalPackageSet
+from portage.dep import _repo_separator
+
+class PackageArg(DependencyArg):
+ def __init__(self, package=None, **kwargs):
+ DependencyArg.__init__(self, **kwargs)
+ self.package = package
+ atom = "=" + package.cpv
+ if package.repo != Package.UNKNOWN_REPO:
+ atom += _repo_separator + package.repo
+ self.atom = portage.dep.Atom(atom, allow_repo=True)
+ self.pset = InternalPackageSet(initial_atoms=(self.atom,),
+ allow_repo=True)
diff --git a/portage_with_autodep/pym/_emerge/PackageMerge.py b/portage_with_autodep/pym/_emerge/PackageMerge.py
new file mode 100644
index 0000000..f8fa04a
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/PackageMerge.py
@@ -0,0 +1,40 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.CompositeTask import CompositeTask
+from portage.output import colorize
+class PackageMerge(CompositeTask):
+ __slots__ = ("merge",)
+
+ def _start(self):
+
+ self.scheduler = self.merge.scheduler
+ pkg = self.merge.pkg
+ pkg_count = self.merge.pkg_count
+
+ if pkg.installed:
+ action_desc = "Uninstalling"
+ preposition = "from"
+ counter_str = ""
+ else:
+ action_desc = "Installing"
+ preposition = "to"
+ counter_str = "(%s of %s) " % \
+ (colorize("MERGE_LIST_PROGRESS", str(pkg_count.curval)),
+ colorize("MERGE_LIST_PROGRESS", str(pkg_count.maxval)))
+
+ msg = "%s %s%s" % \
+ (action_desc,
+ counter_str,
+ colorize("GOOD", pkg.cpv))
+
+ if pkg.root != "/":
+ msg += " %s %s" % (preposition, pkg.root)
+
+ if not self.merge.build_opts.fetchonly and \
+ not self.merge.build_opts.pretend and \
+ not self.merge.build_opts.buildpkgonly:
+ self.merge.statusMessage(msg)
+
+ task = self.merge.create_install_task()
+ self._start_task(task, self._default_final_exit)
diff --git a/portage_with_autodep/pym/_emerge/PackageUninstall.py b/portage_with_autodep/pym/_emerge/PackageUninstall.py
new file mode 100644
index 0000000..eb6a947
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/PackageUninstall.py
@@ -0,0 +1,110 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import logging
+import portage
+from portage import os
+from portage.dbapi._MergeProcess import MergeProcess
+from portage.exception import UnsupportedAPIException
+from _emerge.EbuildBuildDir import EbuildBuildDir
+from _emerge.emergelog import emergelog
+from _emerge.CompositeTask import CompositeTask
+from _emerge.unmerge import _unmerge_display
+
+class PackageUninstall(CompositeTask):
+ """
+ Uninstall a package asynchronously in a subprocess. When
+ both parallel-install and ebuild-locks FEATURES are enabled,
+ it is essential for the ebuild-locks code to execute in a
+ subprocess, since the portage.locks module does not behave
+ as desired if we try to lock the same file multiple times
+ concurrently from the same process for ebuild-locks phases
+ such as pkg_setup, pkg_prerm, and pkg_postrm.
+ """
+
+ __slots__ = ("world_atom", "ldpath_mtimes", "opts",
+ "pkg", "settings", "_builddir_lock")
+
+ def _start(self):
+
+ vardb = self.pkg.root_config.trees["vartree"].dbapi
+ dbdir = vardb.getpath(self.pkg.cpv)
+ if not os.path.exists(dbdir):
+ # Apparently the package got uninstalled
+ # already, so we can safely return early.
+ self.returncode = os.EX_OK
+ self.wait()
+ return
+
+ self.settings.setcpv(self.pkg)
+ cat, pf = portage.catsplit(self.pkg.cpv)
+ myebuildpath = os.path.join(dbdir, pf + ".ebuild")
+
+ try:
+ portage.doebuild_environment(myebuildpath, "prerm",
+ settings=self.settings, db=vardb)
+ except UnsupportedAPIException:
+ # This is safe to ignore since this function is
+ # guaranteed to set PORTAGE_BUILDDIR even though
+ # it raises UnsupportedAPIException. The error
+ # will be logged when it prevents the pkg_prerm
+ # and pkg_postrm phases from executing.
+ pass
+
+ self._builddir_lock = EbuildBuildDir(
+ scheduler=self.scheduler, settings=self.settings)
+ self._builddir_lock.lock()
+
+ portage.prepare_build_dirs(
+ settings=self.settings, cleanup=True)
+
+ # Output only gets logged if it comes after prepare_build_dirs()
+ # which initializes PORTAGE_LOG_FILE.
+ retval, pkgmap = _unmerge_display(self.pkg.root_config,
+ self.opts, "unmerge", [self.pkg.cpv], clean_delay=0,
+ writemsg_level=self._writemsg_level)
+
+ if retval != os.EX_OK:
+ self._builddir_lock.unlock()
+ self.returncode = retval
+ self.wait()
+ return
+
+ self._writemsg_level(">>> Unmerging %s...\n" % (self.pkg.cpv,),
+ noiselevel=-1)
+ self._emergelog("=== Unmerging... (%s)" % (self.pkg.cpv,))
+
+ unmerge_task = MergeProcess(
+ mycat=cat, mypkg=pf, settings=self.settings,
+ treetype="vartree", vartree=self.pkg.root_config.trees["vartree"],
+ scheduler=self.scheduler, background=self.background,
+ mydbapi=self.pkg.root_config.trees["vartree"].dbapi,
+ prev_mtimes=self.ldpath_mtimes,
+ logfile=self.settings.get("PORTAGE_LOG_FILE"), unmerge=True)
+
+ self._start_task(unmerge_task, self._unmerge_exit)
+
+ def _unmerge_exit(self, unmerge_task):
+ if self._final_exit(unmerge_task) != os.EX_OK:
+ self._emergelog(" !!! unmerge FAILURE: %s" % (self.pkg.cpv,))
+ else:
+ self._emergelog(" >>> unmerge success: %s" % (self.pkg.cpv,))
+ self.world_atom(self.pkg)
+ self._builddir_lock.unlock()
+ self.wait()
+
+ def _emergelog(self, msg):
+ emergelog("notitles" not in self.settings.features, msg)
+
+ def _writemsg_level(self, msg, level=0, noiselevel=0):
+
+ log_path = self.settings.get("PORTAGE_LOG_FILE")
+ background = self.background
+
+ if log_path is None:
+ if not (background and level < logging.WARNING):
+ portage.util.writemsg_level(msg,
+ level=level, noiselevel=noiselevel)
+ else:
+ self.scheduler.output(msg, log_path=log_path,
+ level=level, noiselevel=noiselevel)
diff --git a/portage_with_autodep/pym/_emerge/PackageVirtualDbapi.py b/portage_with_autodep/pym/_emerge/PackageVirtualDbapi.py
new file mode 100644
index 0000000..a692bb6
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/PackageVirtualDbapi.py
@@ -0,0 +1,145 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+from portage.dbapi import dbapi
+
+class PackageVirtualDbapi(dbapi):
+ """
+ A dbapi-like interface class that represents the state of the installed
+ package database as new packages are installed, replacing any packages
+ that previously existed in the same slot. The main difference between
+ this class and fakedbapi is that this one uses Package instances
+ internally (passed in via cpv_inject() and cpv_remove() calls).
+ """
+ def __init__(self, settings):
+ dbapi.__init__(self)
+ self.settings = settings
+ self._match_cache = {}
+ self._cp_map = {}
+ self._cpv_map = {}
+
+ def clear(self):
+ """
+ Remove all packages.
+ """
+ if self._cpv_map:
+ self._clear_cache()
+ self._cp_map.clear()
+ self._cpv_map.clear()
+
+ def copy(self):
+ obj = PackageVirtualDbapi(self.settings)
+ obj._match_cache = self._match_cache.copy()
+ obj._cp_map = self._cp_map.copy()
+ for k, v in obj._cp_map.items():
+ obj._cp_map[k] = v[:]
+ obj._cpv_map = self._cpv_map.copy()
+ return obj
+
+ def __bool__(self):
+ return bool(self._cpv_map)
+
+ if sys.hexversion < 0x3000000:
+ __nonzero__ = __bool__
+
+ def __iter__(self):
+ return iter(self._cpv_map.values())
+
+ def __contains__(self, item):
+ existing = self._cpv_map.get(item.cpv)
+ if existing is not None and \
+ existing == item:
+ return True
+ return False
+
+ def get(self, item, default=None):
+ cpv = getattr(item, "cpv", None)
+ if cpv is None:
+ if len(item) != 5:
+ return default
+ type_name, root, cpv, operation, repo_key = item
+
+ existing = self._cpv_map.get(cpv)
+ if existing is not None and \
+ existing == item:
+ return existing
+ return default
+
+ def match_pkgs(self, atom):
+ return [self._cpv_map[cpv] for cpv in self.match(atom)]
+
+ def _clear_cache(self):
+ if self._categories is not None:
+ self._categories = None
+ if self._match_cache:
+ self._match_cache = {}
+
+ def match(self, origdep, use_cache=1):
+ result = self._match_cache.get(origdep)
+ if result is not None:
+ return result[:]
+ result = dbapi.match(self, origdep, use_cache=use_cache)
+ self._match_cache[origdep] = result
+ return result[:]
+
+ def cpv_exists(self, cpv, myrepo=None):
+ return cpv in self._cpv_map
+
+ def cp_list(self, mycp, use_cache=1):
+ cachelist = self._match_cache.get(mycp)
+ # cp_list() doesn't expand old-style virtuals
+ if cachelist and cachelist[0].startswith(mycp):
+ return cachelist[:]
+ cpv_list = self._cp_map.get(mycp)
+ if cpv_list is None:
+ cpv_list = []
+ else:
+ cpv_list = [pkg.cpv for pkg in cpv_list]
+ self._cpv_sort_ascending(cpv_list)
+ if not (not cpv_list and mycp.startswith("virtual/")):
+ self._match_cache[mycp] = cpv_list
+ return cpv_list[:]
+
+ def cp_all(self):
+ return list(self._cp_map)
+
+ def cpv_all(self):
+ return list(self._cpv_map)
+
+ def cpv_inject(self, pkg):
+ cp_list = self._cp_map.get(pkg.cp)
+ if cp_list is None:
+ cp_list = []
+ self._cp_map[pkg.cp] = cp_list
+ e_pkg = self._cpv_map.get(pkg.cpv)
+ if e_pkg is not None:
+ if e_pkg == pkg:
+ return
+ self.cpv_remove(e_pkg)
+ for e_pkg in cp_list:
+ if e_pkg.slot_atom == pkg.slot_atom:
+ if e_pkg == pkg:
+ return
+ self.cpv_remove(e_pkg)
+ break
+ cp_list.append(pkg)
+ self._cpv_map[pkg.cpv] = pkg
+ self._clear_cache()
+
+ def cpv_remove(self, pkg):
+ old_pkg = self._cpv_map.get(pkg.cpv)
+ if old_pkg != pkg:
+ raise KeyError(pkg)
+ self._cp_map[pkg.cp].remove(pkg)
+ del self._cpv_map[pkg.cpv]
+ self._clear_cache()
+
+ def aux_get(self, cpv, wants, myrepo=None):
+ metadata = self._cpv_map[cpv].metadata
+ return [metadata.get(x, "") for x in wants]
+
+ def aux_update(self, cpv, values):
+ self._cpv_map[cpv].metadata.update(values)
+ self._clear_cache()
+
diff --git a/portage_with_autodep/pym/_emerge/PipeReader.py b/portage_with_autodep/pym/_emerge/PipeReader.py
new file mode 100644
index 0000000..375c98f
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/PipeReader.py
@@ -0,0 +1,96 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from _emerge.AbstractPollTask import AbstractPollTask
+from _emerge.PollConstants import PollConstants
+import fcntl
+import array
+
+class PipeReader(AbstractPollTask):
+
+ """
+ Reads output from one or more files and saves it in memory,
+ for retrieval via the getvalue() method. This is driven by
+ the scheduler's poll() loop, so it runs entirely within the
+ current process.
+ """
+
+ __slots__ = ("input_files",) + \
+ ("_read_data", "_reg_ids")
+
+ def _start(self):
+ self._reg_ids = set()
+ self._read_data = []
+ for k, f in self.input_files.items():
+ fcntl.fcntl(f.fileno(), fcntl.F_SETFL,
+ fcntl.fcntl(f.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK)
+ self._reg_ids.add(self.scheduler.register(f.fileno(),
+ self._registered_events, self._output_handler))
+ self._registered = True
+
+ def isAlive(self):
+ return self._registered
+
+ def _cancel(self):
+ if self.returncode is None:
+ self.returncode = 1
+
+ def _wait(self):
+ if self.returncode is not None:
+ return self.returncode
+
+ if self._registered:
+ self.scheduler.schedule(self._reg_ids)
+ self._unregister()
+
+ self.returncode = os.EX_OK
+ return self.returncode
+
+ def getvalue(self):
+ """Retrieve the entire contents"""
+ return b''.join(self._read_data)
+
+ def close(self):
+ """Free the memory buffer."""
+ self._read_data = None
+
+ def _output_handler(self, fd, event):
+
+ if event & PollConstants.POLLIN:
+
+ for f in self.input_files.values():
+ if fd == f.fileno():
+ break
+
+ buf = array.array('B')
+ try:
+ buf.fromfile(f, self._bufsize)
+ except (EOFError, IOError):
+ pass
+
+ if buf:
+ self._read_data.append(buf.tostring())
+ else:
+ self._unregister()
+ self.wait()
+
+ self._unregister_if_appropriate(event)
+
+ def _unregister(self):
+ """
+ Unregister from the scheduler and close open files.
+ """
+
+ self._registered = False
+
+ if self._reg_ids is not None:
+ for reg_id in self._reg_ids:
+ self.scheduler.unregister(reg_id)
+ self._reg_ids = None
+
+ if self.input_files is not None:
+ for f in self.input_files.values():
+ f.close()
+ self.input_files = None
+
diff --git a/portage_with_autodep/pym/_emerge/PollConstants.py b/portage_with_autodep/pym/_emerge/PollConstants.py
new file mode 100644
index 0000000..d0270a9
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/PollConstants.py
@@ -0,0 +1,18 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import select
+class PollConstants(object):
+
+ """
+ Provides POLL* constants that are equivalent to those from the
+ select module, for use by PollSelectAdapter.
+ """
+
+ names = ("POLLIN", "POLLPRI", "POLLOUT", "POLLERR", "POLLHUP", "POLLNVAL")
+ v = 1
+ for k in names:
+ locals()[k] = getattr(select, k, v)
+ v *= 2
+ del k, v
+
diff --git a/portage_with_autodep/pym/_emerge/PollScheduler.py b/portage_with_autodep/pym/_emerge/PollScheduler.py
new file mode 100644
index 0000000..a2b5c24
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/PollScheduler.py
@@ -0,0 +1,398 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import gzip
+import errno
+import logging
+import select
+import time
+
+try:
+ import threading
+except ImportError:
+ import dummy_threading as threading
+
+from portage import _encodings
+from portage import _unicode_encode
+from portage.util import writemsg_level
+
+from _emerge.SlotObject import SlotObject
+from _emerge.getloadavg import getloadavg
+from _emerge.PollConstants import PollConstants
+from _emerge.PollSelectAdapter import PollSelectAdapter
+
+class PollScheduler(object):
+
+ class _sched_iface_class(SlotObject):
+ __slots__ = ("output", "register", "schedule", "unregister")
+
+ def __init__(self):
+ self._terminated = threading.Event()
+ self._terminated_tasks = False
+ self._max_jobs = 1
+ self._max_load = None
+ self._jobs = 0
+ self._poll_event_queue = []
+ self._poll_event_handlers = {}
+ self._poll_event_handler_ids = {}
+ # Increment id for each new handler.
+ self._event_handler_id = 0
+ self._poll_obj = create_poll_instance()
+ self._scheduling = False
+ self._background = False
+ self.sched_iface = self._sched_iface_class(
+ output=self._task_output,
+ register=self._register,
+ schedule=self._schedule_wait,
+ unregister=self._unregister)
+
+ def terminate(self):
+ """
+ Schedules asynchronous, graceful termination of the scheduler
+ at the earliest opportunity.
+
+ This method is thread-safe (and safe for signal handlers).
+ """
+ self._terminated.set()
+
+ def _terminate_tasks(self):
+ """
+ Send signals to terminate all tasks. This is called once
+ from self._schedule() in the event dispatching thread. This
+ prevents it from being called while the _schedule_tasks()
+ implementation is running, in order to avoid potential
+ interference. All tasks should be cleaned up at the earliest
+ opportunity, but not necessarily before this method returns.
+ """
+ raise NotImplementedError()
+
+ def _schedule_tasks(self):
+ """
+ This is called from inside the _schedule() method, which
+ guarantees the following:
+
+ 1) It will not be called recursively.
+ 2) _terminate_tasks() will not be called while it is running.
+ 3) The state of the boolean _terminated_tasks variable will
+ not change while it is running.
+
+ Unless this method is used to perform user interface updates,
+ or something like that, the first thing it should do is check
+ the state of _terminated_tasks and if that is True then it
+ should return False immediately (since there's no need to
+ schedule anything after _terminate_tasks() has been called).
+ """
+ raise NotImplementedError()
+
+ def _schedule(self):
+ """
+ Calls _schedule_tasks() and automatically returns early from
+ any recursive calls to this method that the _schedule_tasks()
+ call might trigger. This makes _schedule() safe to call from
+ inside exit listeners.
+ """
+ if self._scheduling:
+ return False
+ self._scheduling = True
+ try:
+
+ if self._terminated.is_set() and \
+ not self._terminated_tasks:
+ self._terminated_tasks = True
+ self._terminate_tasks()
+
+ return self._schedule_tasks()
+ finally:
+ self._scheduling = False
+
+ def _running_job_count(self):
+ return self._jobs
+
+ def _can_add_job(self):
+ if self._terminated_tasks:
+ return False
+
+ max_jobs = self._max_jobs
+ max_load = self._max_load
+
+ if self._max_jobs is not True and \
+ self._running_job_count() >= self._max_jobs:
+ return False
+
+ if max_load is not None and \
+ (max_jobs is True or max_jobs > 1) and \
+ self._running_job_count() >= 1:
+ try:
+ avg1, avg5, avg15 = getloadavg()
+ except OSError:
+ return False
+
+ if avg1 >= max_load:
+ return False
+
+ return True
+
+ def _poll(self, timeout=None):
+ """
+ All poll() calls pass through here. The poll events
+ are added directly to self._poll_event_queue.
+ In order to avoid endless blocking, this raises
+ StopIteration if timeout is None and there are
+ no file descriptors to poll.
+ """
+ if not self._poll_event_handlers:
+ self._schedule()
+ if timeout is None and \
+ not self._poll_event_handlers:
+ raise StopIteration(
+ "timeout is None and there are no poll() event handlers")
+
+ # The following error is known to occur with Linux kernel versions
+ # less than 2.6.24:
+ #
+ # select.error: (4, 'Interrupted system call')
+ #
+ # This error has been observed after a SIGSTOP, followed by SIGCONT.
+ # Treat it similar to EAGAIN if timeout is None, otherwise just return
+ # without any events.
+ while True:
+ try:
+ self._poll_event_queue.extend(self._poll_obj.poll(timeout))
+ break
+ except select.error as e:
+ writemsg_level("\n!!! select error: %s\n" % (e,),
+ level=logging.ERROR, noiselevel=-1)
+ del e
+ if timeout is not None:
+ break
+
+ def _next_poll_event(self, timeout=None):
+ """
+ Since the _schedule_wait() loop is called by event
+ handlers from _poll_loop(), maintain a central event
+ queue for both of them to share events from a single
+ poll() call. In order to avoid endless blocking, this
+ raises StopIteration if timeout is None and there are
+ no file descriptors to poll.
+ """
+ if not self._poll_event_queue:
+ self._poll(timeout)
+ if not self._poll_event_queue:
+ raise StopIteration()
+ return self._poll_event_queue.pop()
+
+ def _poll_loop(self):
+
+ event_handlers = self._poll_event_handlers
+ event_handled = False
+
+ try:
+ while event_handlers:
+ f, event = self._next_poll_event()
+ handler, reg_id = event_handlers[f]
+ handler(f, event)
+ event_handled = True
+ except StopIteration:
+ event_handled = True
+
+ if not event_handled:
+ raise AssertionError("tight loop")
+
+ def _schedule_yield(self):
+ """
+ Schedule for a short period of time chosen by the scheduler based
+ on internal state. Synchronous tasks should call this periodically
+ in order to allow the scheduler to service pending poll events. The
+ scheduler will call poll() exactly once, without blocking, and any
+ resulting poll events will be serviced.
+ """
+ event_handlers = self._poll_event_handlers
+ events_handled = 0
+
+ if not event_handlers:
+ return bool(events_handled)
+
+ if not self._poll_event_queue:
+ self._poll(0)
+
+ try:
+ while event_handlers and self._poll_event_queue:
+ f, event = self._next_poll_event()
+ handler, reg_id = event_handlers[f]
+ handler(f, event)
+ events_handled += 1
+ except StopIteration:
+ events_handled += 1
+
+ return bool(events_handled)
+
+ def _register(self, f, eventmask, handler):
+ """
+ @rtype: Integer
+ @return: A unique registration id, for use in schedule() or
+ unregister() calls.
+ """
+ if f in self._poll_event_handlers:
+ raise AssertionError("fd %d is already registered" % f)
+ self._event_handler_id += 1
+ reg_id = self._event_handler_id
+ self._poll_event_handler_ids[reg_id] = f
+ self._poll_event_handlers[f] = (handler, reg_id)
+ self._poll_obj.register(f, eventmask)
+ return reg_id
+
+ def _unregister(self, reg_id):
+ f = self._poll_event_handler_ids[reg_id]
+ self._poll_obj.unregister(f)
+ if self._poll_event_queue:
+ # Discard any unhandled events that belong to this file,
+ # in order to prevent these events from being erroneously
+ # delivered to a future handler that is using a reallocated
+ # file descriptor of the same numeric value (causing
+ # extremely confusing bugs).
+ remaining_events = []
+ discarded_events = False
+ for event in self._poll_event_queue:
+ if event[0] == f:
+ discarded_events = True
+ else:
+ remaining_events.append(event)
+
+ if discarded_events:
+ self._poll_event_queue[:] = remaining_events
+
+ del self._poll_event_handlers[f]
+ del self._poll_event_handler_ids[reg_id]
+
+ def _schedule_wait(self, wait_ids=None, timeout=None, condition=None):
+ """
+ Schedule until wait_id is not longer registered
+ for poll() events.
+ @type wait_id: int
+ @param wait_id: a task id to wait for
+ """
+ event_handlers = self._poll_event_handlers
+ handler_ids = self._poll_event_handler_ids
+ event_handled = False
+
+ if isinstance(wait_ids, int):
+ wait_ids = frozenset([wait_ids])
+
+ start_time = None
+ remaining_timeout = timeout
+ timed_out = False
+ if timeout is not None:
+ start_time = time.time()
+ try:
+ while (wait_ids is None and event_handlers) or \
+ (wait_ids is not None and wait_ids.intersection(handler_ids)):
+ f, event = self._next_poll_event(timeout=remaining_timeout)
+ handler, reg_id = event_handlers[f]
+ handler(f, event)
+ event_handled = True
+ if condition is not None and condition():
+ break
+ if timeout is not None:
+ elapsed_time = time.time() - start_time
+ if elapsed_time < 0:
+ # The system clock has changed such that start_time
+ # is now in the future, so just assume that the
+ # timeout has already elapsed.
+ timed_out = True
+ break
+ remaining_timeout = timeout - 1000 * elapsed_time
+ if remaining_timeout <= 0:
+ timed_out = True
+ break
+ except StopIteration:
+ event_handled = True
+
+ return event_handled
+
+ def _task_output(self, msg, log_path=None, background=None,
+ level=0, noiselevel=-1):
+ """
+ Output msg to stdout if not self._background. If log_path
+ is not None then append msg to the log (appends with
+ compression if the filename extension of log_path
+ corresponds to a supported compression type).
+ """
+
+ if background is None:
+ # If the task does not have a local background value
+ # (like for parallel-fetch), then use the global value.
+ background = self._background
+
+ msg_shown = False
+ if not background:
+ writemsg_level(msg, level=level, noiselevel=noiselevel)
+ msg_shown = True
+
+ if log_path is not None:
+ try:
+ f = open(_unicode_encode(log_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='ab')
+ except IOError as e:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
+ raise
+ if not msg_shown:
+ writemsg_level(msg, level=level, noiselevel=noiselevel)
+ else:
+
+ if log_path.endswith('.gz'):
+ # NOTE: The empty filename argument prevents us from
+ # triggering a bug in python3 which causes GzipFile
+ # to raise AttributeError if fileobj.name is bytes
+ # instead of unicode.
+ f = gzip.GzipFile(filename='', mode='ab', fileobj=f)
+
+ f.write(_unicode_encode(msg))
+ f.close()
+
+_can_poll_device = None
+
+def can_poll_device():
+ """
+ Test if it's possible to use poll() on a device such as a pty. This
+ is known to fail on Darwin.
+ @rtype: bool
+ @returns: True if poll() on a device succeeds, False otherwise.
+ """
+
+ global _can_poll_device
+ if _can_poll_device is not None:
+ return _can_poll_device
+
+ if not hasattr(select, "poll"):
+ _can_poll_device = False
+ return _can_poll_device
+
+ try:
+ dev_null = open('/dev/null', 'rb')
+ except IOError:
+ _can_poll_device = False
+ return _can_poll_device
+
+ p = select.poll()
+ p.register(dev_null.fileno(), PollConstants.POLLIN)
+
+ invalid_request = False
+ for f, event in p.poll():
+ if event & PollConstants.POLLNVAL:
+ invalid_request = True
+ break
+ dev_null.close()
+
+ _can_poll_device = not invalid_request
+ return _can_poll_device
+
+def create_poll_instance():
+ """
+ Create an instance of select.poll, or an instance of
+ PollSelectAdapter there is no poll() implementation or
+ it is broken somehow.
+ """
+ if can_poll_device():
+ return select.poll()
+ return PollSelectAdapter()
diff --git a/portage_with_autodep/pym/_emerge/PollSelectAdapter.py b/portage_with_autodep/pym/_emerge/PollSelectAdapter.py
new file mode 100644
index 0000000..c11dab8
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/PollSelectAdapter.py
@@ -0,0 +1,73 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.PollConstants import PollConstants
+import select
+class PollSelectAdapter(PollConstants):
+
+ """
+ Use select to emulate a poll object, for
+ systems that don't support poll().
+ """
+
+ def __init__(self):
+ self._registered = {}
+ self._select_args = [[], [], []]
+
+ def register(self, fd, *args):
+ """
+ Only POLLIN is currently supported!
+ """
+ if len(args) > 1:
+ raise TypeError(
+ "register expected at most 2 arguments, got " + \
+ repr(1 + len(args)))
+
+ eventmask = PollConstants.POLLIN | \
+ PollConstants.POLLPRI | PollConstants.POLLOUT
+ if args:
+ eventmask = args[0]
+
+ self._registered[fd] = eventmask
+ self._select_args = None
+
+ def unregister(self, fd):
+ self._select_args = None
+ del self._registered[fd]
+
+ def poll(self, *args):
+ if len(args) > 1:
+ raise TypeError(
+ "poll expected at most 2 arguments, got " + \
+ repr(1 + len(args)))
+
+ timeout = None
+ if args:
+ timeout = args[0]
+
+ select_args = self._select_args
+ if select_args is None:
+ select_args = [list(self._registered), [], []]
+
+ if timeout is not None:
+ select_args = select_args[:]
+ # Translate poll() timeout args to select() timeout args:
+ #
+ # | units | value(s) for indefinite block
+ # ---------|--------------|------------------------------
+ # poll | milliseconds | omitted, negative, or None
+ # ---------|--------------|------------------------------
+ # select | seconds | omitted
+ # ---------|--------------|------------------------------
+
+ if timeout is not None and timeout < 0:
+ timeout = None
+ if timeout is not None:
+ select_args.append(timeout / 1000)
+
+ select_events = select.select(*select_args)
+ poll_events = []
+ for fd in select_events[0]:
+ poll_events.append((fd, PollConstants.POLLIN))
+ return poll_events
+
diff --git a/portage_with_autodep/pym/_emerge/ProgressHandler.py b/portage_with_autodep/pym/_emerge/ProgressHandler.py
new file mode 100644
index 0000000..f5afe6d
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/ProgressHandler.py
@@ -0,0 +1,22 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import time
+class ProgressHandler(object):
+ def __init__(self):
+ self.curval = 0
+ self.maxval = 0
+ self._last_update = 0
+ self.min_latency = 0.2
+
+ def onProgress(self, maxval, curval):
+ self.maxval = maxval
+ self.curval = curval
+ cur_time = time.time()
+ if cur_time - self._last_update >= self.min_latency:
+ self._last_update = cur_time
+ self.display()
+
+ def display(self):
+ raise NotImplementedError(self)
+
diff --git a/portage_with_autodep/pym/_emerge/QueueScheduler.py b/portage_with_autodep/pym/_emerge/QueueScheduler.py
new file mode 100644
index 0000000..a4ab328
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/QueueScheduler.py
@@ -0,0 +1,116 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import time
+
+from _emerge.PollScheduler import PollScheduler
+
+class QueueScheduler(PollScheduler):
+
+ """
+ Add instances of SequentialTaskQueue and then call run(). The
+ run() method returns when no tasks remain.
+ """
+
+ def __init__(self, max_jobs=None, max_load=None):
+ PollScheduler.__init__(self)
+
+ if max_jobs is None:
+ max_jobs = 1
+
+ self._max_jobs = max_jobs
+ self._max_load = max_load
+
+ self._queues = []
+ self._schedule_listeners = []
+
+ def add(self, q):
+ self._queues.append(q)
+
+ def remove(self, q):
+ self._queues.remove(q)
+
+ def clear(self):
+ for q in self._queues:
+ q.clear()
+
+ def run(self, timeout=None):
+
+ start_time = None
+ timed_out = False
+ remaining_timeout = timeout
+ if timeout is not None:
+ start_time = time.time()
+
+ while self._schedule():
+ self._schedule_wait(timeout=remaining_timeout)
+ if timeout is not None:
+ elapsed_time = time.time() - start_time
+ if elapsed_time < 0:
+ # The system clock has changed such that start_time
+ # is now in the future, so just assume that the
+ # timeout has already elapsed.
+ timed_out = True
+ break
+ remaining_timeout = timeout - 1000 * elapsed_time
+ if remaining_timeout <= 0:
+ timed_out = True
+ break
+
+ if timeout is None or not timed_out:
+ while self._running_job_count():
+ self._schedule_wait(timeout=remaining_timeout)
+ if timeout is not None:
+ elapsed_time = time.time() - start_time
+ if elapsed_time < 0:
+ # The system clock has changed such that start_time
+ # is now in the future, so just assume that the
+ # timeout has already elapsed.
+ timed_out = True
+ break
+ remaining_timeout = timeout - 1000 * elapsed_time
+ if remaining_timeout <= 0:
+ timed_out = True
+ break
+
+ def _schedule_tasks(self):
+ """
+ @rtype: bool
+ @returns: True if there may be remaining tasks to schedule,
+ False otherwise.
+ """
+ if self._terminated_tasks:
+ return False
+
+ while self._can_add_job():
+ n = self._max_jobs - self._running_job_count()
+ if n < 1:
+ break
+
+ if not self._start_next_job(n):
+ return False
+
+ for q in self._queues:
+ if q:
+ return True
+ return False
+
+ def _running_job_count(self):
+ job_count = 0
+ for q in self._queues:
+ job_count += len(q.running_tasks)
+ self._jobs = job_count
+ return job_count
+
+ def _start_next_job(self, n=1):
+ started_count = 0
+ for q in self._queues:
+ initial_job_count = len(q.running_tasks)
+ q.schedule()
+ final_job_count = len(q.running_tasks)
+ if final_job_count > initial_job_count:
+ started_count += (final_job_count - initial_job_count)
+ if started_count >= n:
+ break
+ return started_count
+
diff --git a/portage_with_autodep/pym/_emerge/RootConfig.py b/portage_with_autodep/pym/_emerge/RootConfig.py
new file mode 100644
index 0000000..d84f108
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/RootConfig.py
@@ -0,0 +1,34 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+class RootConfig(object):
+ """This is used internally by depgraph to track information about a
+ particular $ROOT."""
+ __slots__ = ("root", "setconfig", "sets", "settings", "trees")
+
+ pkg_tree_map = {
+ "ebuild" : "porttree",
+ "binary" : "bintree",
+ "installed" : "vartree"
+ }
+
+ tree_pkg_map = {}
+ for k, v in pkg_tree_map.items():
+ tree_pkg_map[v] = k
+
+ def __init__(self, settings, trees, setconfig):
+ self.trees = trees
+ self.settings = settings
+ self.root = self.settings["ROOT"]
+ self.setconfig = setconfig
+ if setconfig is None:
+ self.sets = {}
+ else:
+ self.sets = self.setconfig.getSets()
+
+ def update(self, other):
+ """
+ Shallow copy all attributes from another instance.
+ """
+ for k in self.__slots__:
+ setattr(self, k, getattr(other, k))
diff --git a/portage_with_autodep/pym/_emerge/Scheduler.py b/portage_with_autodep/pym/_emerge/Scheduler.py
new file mode 100644
index 0000000..6412d82
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/Scheduler.py
@@ -0,0 +1,1975 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+from collections import deque
+import gc
+import gzip
+import logging
+import shutil
+import signal
+import sys
+import tempfile
+import textwrap
+import time
+import warnings
+import weakref
+import zlib
+
+import portage
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode, _unicode_encode
+from portage.cache.mappings import slot_dict_class
+from portage.elog.messages import eerror
+from portage.localization import _
+from portage.output import colorize, create_color_func, red
+bad = create_color_func("BAD")
+from portage._sets import SETPREFIX
+from portage._sets.base import InternalPackageSet
+from portage.util import writemsg, writemsg_level
+from portage.package.ebuild.digestcheck import digestcheck
+from portage.package.ebuild.digestgen import digestgen
+from portage.package.ebuild.prepare_build_dirs import prepare_build_dirs
+
+import _emerge
+from _emerge.BinpkgFetcher import BinpkgFetcher
+from _emerge.BinpkgPrefetcher import BinpkgPrefetcher
+from _emerge.BinpkgVerifier import BinpkgVerifier
+from _emerge.Blocker import Blocker
+from _emerge.BlockerDB import BlockerDB
+from _emerge.clear_caches import clear_caches
+from _emerge.create_depgraph_params import create_depgraph_params
+from _emerge.create_world_atom import create_world_atom
+from _emerge.DepPriority import DepPriority
+from _emerge.depgraph import depgraph, resume_depgraph
+from _emerge.EbuildFetcher import EbuildFetcher
+from _emerge.EbuildPhase import EbuildPhase
+from _emerge.emergelog import emergelog
+from _emerge.FakeVartree import FakeVartree
+from _emerge._find_deep_system_runtime_deps import _find_deep_system_runtime_deps
+from _emerge._flush_elog_mod_echo import _flush_elog_mod_echo
+from _emerge.JobStatusDisplay import JobStatusDisplay
+from _emerge.MergeListItem import MergeListItem
+from _emerge.MiscFunctionsProcess import MiscFunctionsProcess
+from _emerge.Package import Package
+from _emerge.PackageMerge import PackageMerge
+from _emerge.PollScheduler import PollScheduler
+from _emerge.RootConfig import RootConfig
+from _emerge.SlotObject import SlotObject
+from _emerge.SequentialTaskQueue import SequentialTaskQueue
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+class Scheduler(PollScheduler):
+
+ # max time between display status updates (milliseconds)
+ _max_display_latency = 3000
+
+ _opts_ignore_blockers = \
+ frozenset(["--buildpkgonly",
+ "--fetchonly", "--fetch-all-uri",
+ "--nodeps", "--pretend"])
+
+ _opts_no_background = \
+ frozenset(["--pretend",
+ "--fetchonly", "--fetch-all-uri"])
+
+ _opts_no_restart = frozenset(["--buildpkgonly",
+ "--fetchonly", "--fetch-all-uri", "--pretend"])
+
+ _bad_resume_opts = set(["--ask", "--changelog",
+ "--resume", "--skipfirst"])
+
+ class _iface_class(SlotObject):
+ __slots__ = ("fetch",
+ "output", "register", "schedule",
+ "scheduleSetup", "scheduleUnpack", "scheduleYield",
+ "unregister")
+
+ class _fetch_iface_class(SlotObject):
+ __slots__ = ("log_file", "schedule")
+
+ _task_queues_class = slot_dict_class(
+ ("merge", "jobs", "ebuild_locks", "fetch", "unpack"), prefix="")
+
+ class _build_opts_class(SlotObject):
+ __slots__ = ("buildpkg", "buildpkgonly",
+ "fetch_all_uri", "fetchonly", "pretend")
+
+ class _binpkg_opts_class(SlotObject):
+ __slots__ = ("fetchonly", "getbinpkg", "pretend")
+
+ class _pkg_count_class(SlotObject):
+ __slots__ = ("curval", "maxval")
+
+ class _emerge_log_class(SlotObject):
+ __slots__ = ("xterm_titles",)
+
+ def log(self, *pargs, **kwargs):
+ if not self.xterm_titles:
+ # Avoid interference with the scheduler's status display.
+ kwargs.pop("short_msg", None)
+ emergelog(self.xterm_titles, *pargs, **kwargs)
+
+ class _failed_pkg(SlotObject):
+ __slots__ = ("build_dir", "build_log", "pkg", "returncode")
+
+ class _ConfigPool(object):
+ """Interface for a task to temporarily allocate a config
+ instance from a pool. This allows a task to be constructed
+ long before the config instance actually becomes needed, like
+ when prefetchers are constructed for the whole merge list."""
+ __slots__ = ("_root", "_allocate", "_deallocate")
+ def __init__(self, root, allocate, deallocate):
+ self._root = root
+ self._allocate = allocate
+ self._deallocate = deallocate
+ def allocate(self):
+ return self._allocate(self._root)
+ def deallocate(self, settings):
+ self._deallocate(settings)
+
+ class _unknown_internal_error(portage.exception.PortageException):
+ """
+ Used internally to terminate scheduling. The specific reason for
+ the failure should have been dumped to stderr.
+ """
+ def __init__(self, value=""):
+ portage.exception.PortageException.__init__(self, value)
+
+ def __init__(self, settings, trees, mtimedb, myopts,
+ spinner, mergelist=None, favorites=None, graph_config=None):
+ PollScheduler.__init__(self)
+
+ if mergelist is not None:
+ warnings.warn("The mergelist parameter of the " + \
+ "_emerge.Scheduler constructor is now unused. Use " + \
+ "the graph_config parameter instead.",
+ DeprecationWarning, stacklevel=2)
+
+ self.settings = settings
+ self.target_root = settings["ROOT"]
+ self.trees = trees
+ self.myopts = myopts
+ self._spinner = spinner
+ self._mtimedb = mtimedb
+ self._favorites = favorites
+ self._args_set = InternalPackageSet(favorites, allow_repo=True)
+ self._build_opts = self._build_opts_class()
+ for k in self._build_opts.__slots__:
+ setattr(self._build_opts, k, "--" + k.replace("_", "-") in myopts)
+ self._binpkg_opts = self._binpkg_opts_class()
+ for k in self._binpkg_opts.__slots__:
+ setattr(self._binpkg_opts, k, "--" + k.replace("_", "-") in myopts)
+
+ self.curval = 0
+ self._logger = self._emerge_log_class()
+ self._task_queues = self._task_queues_class()
+ for k in self._task_queues.allowed_keys:
+ setattr(self._task_queues, k,
+ SequentialTaskQueue())
+
+ # Holds merges that will wait to be executed when no builds are
+ # executing. This is useful for system packages since dependencies
+ # on system packages are frequently unspecified. For example, see
+ # bug #256616.
+ self._merge_wait_queue = deque()
+ # Holds merges that have been transfered from the merge_wait_queue to
+ # the actual merge queue. They are removed from this list upon
+ # completion. Other packages can start building only when this list is
+ # empty.
+ self._merge_wait_scheduled = []
+
+ # Holds system packages and their deep runtime dependencies. Before
+ # being merged, these packages go to merge_wait_queue, to be merged
+ # when no other packages are building.
+ self._deep_system_deps = set()
+
+ # Holds packages to merge which will satisfy currently unsatisfied
+ # deep runtime dependencies of system packages. If this is not empty
+ # then no parallel builds will be spawned until it is empty. This
+ # minimizes the possibility that a build will fail due to the system
+ # being in a fragile state. For example, see bug #259954.
+ self._unsatisfied_system_deps = set()
+
+ self._status_display = JobStatusDisplay(
+ xterm_titles=('notitles' not in settings.features))
+ self._max_load = myopts.get("--load-average")
+ max_jobs = myopts.get("--jobs")
+ if max_jobs is None:
+ max_jobs = 1
+ self._set_max_jobs(max_jobs)
+
+ # The root where the currently running
+ # portage instance is installed.
+ self._running_root = trees["/"]["root_config"]
+ self.edebug = 0
+ if settings.get("PORTAGE_DEBUG", "") == "1":
+ self.edebug = 1
+ self.pkgsettings = {}
+ self._config_pool = {}
+ for root in self.trees:
+ self._config_pool[root] = []
+
+ self._fetch_log = os.path.join(_emerge.emergelog._emerge_log_dir,
+ 'emerge-fetch.log')
+ fetch_iface = self._fetch_iface_class(log_file=self._fetch_log,
+ schedule=self._schedule_fetch)
+ self._sched_iface = self._iface_class(
+ fetch=fetch_iface, output=self._task_output,
+ register=self._register,
+ schedule=self._schedule_wait,
+ scheduleSetup=self._schedule_setup,
+ scheduleUnpack=self._schedule_unpack,
+ scheduleYield=self._schedule_yield,
+ unregister=self._unregister)
+
+ self._prefetchers = weakref.WeakValueDictionary()
+ self._pkg_queue = []
+ self._running_tasks = {}
+ self._completed_tasks = set()
+
+ self._failed_pkgs = []
+ self._failed_pkgs_all = []
+ self._failed_pkgs_die_msgs = []
+ self._post_mod_echo_msgs = []
+ self._parallel_fetch = False
+ self._init_graph(graph_config)
+ merge_count = len([x for x in self._mergelist \
+ if isinstance(x, Package) and x.operation == "merge"])
+ self._pkg_count = self._pkg_count_class(
+ curval=0, maxval=merge_count)
+ self._status_display.maxval = self._pkg_count.maxval
+
+ # The load average takes some time to respond when new
+ # jobs are added, so we need to limit the rate of adding
+ # new jobs.
+ self._job_delay_max = 10
+ self._job_delay_factor = 1.0
+ self._job_delay_exp = 1.5
+ self._previous_job_start_time = None
+
+ # This is used to memoize the _choose_pkg() result when
+ # no packages can be chosen until one of the existing
+ # jobs completes.
+ self._choose_pkg_return_early = False
+
+ features = self.settings.features
+ if "parallel-fetch" in features and \
+ not ("--pretend" in self.myopts or \
+ "--fetch-all-uri" in self.myopts or \
+ "--fetchonly" in self.myopts):
+ if "distlocks" not in features:
+ portage.writemsg(red("!!!")+"\n", noiselevel=-1)
+ portage.writemsg(red("!!!")+" parallel-fetching " + \
+ "requires the distlocks feature enabled"+"\n",
+ noiselevel=-1)
+ portage.writemsg(red("!!!")+" you have it disabled, " + \
+ "thus parallel-fetching is being disabled"+"\n",
+ noiselevel=-1)
+ portage.writemsg(red("!!!")+"\n", noiselevel=-1)
+ elif merge_count > 1:
+ self._parallel_fetch = True
+
+ if self._parallel_fetch:
+ # clear out existing fetch log if it exists
+ try:
+ open(self._fetch_log, 'w')
+ except EnvironmentError:
+ pass
+
+ self._running_portage = None
+ portage_match = self._running_root.trees["vartree"].dbapi.match(
+ portage.const.PORTAGE_PACKAGE_ATOM)
+ if portage_match:
+ cpv = portage_match.pop()
+ self._running_portage = self._pkg(cpv, "installed",
+ self._running_root, installed=True)
+
+ def _terminate_tasks(self):
+ self._status_display.quiet = True
+ while self._running_tasks:
+ task_id, task = self._running_tasks.popitem()
+ task.cancel()
+ for q in self._task_queues.values():
+ q.clear()
+
+ def _init_graph(self, graph_config):
+ """
+ Initialization structures used for dependency calculations
+ involving currently installed packages.
+ """
+ self._set_graph_config(graph_config)
+ self._blocker_db = {}
+ for root in self.trees:
+ if graph_config is None:
+ fake_vartree = FakeVartree(self.trees[root]["root_config"],
+ pkg_cache=self._pkg_cache)
+ fake_vartree.sync()
+ else:
+ fake_vartree = graph_config.trees[root]['vartree']
+ self._blocker_db[root] = BlockerDB(fake_vartree)
+
+ def _destroy_graph(self):
+ """
+ Use this to free memory at the beginning of _calc_resume_list().
+ After _calc_resume_list(), the _init_graph() method
+ must to be called in order to re-generate the structures that
+ this method destroys.
+ """
+ self._blocker_db = None
+ self._set_graph_config(None)
+ gc.collect()
+
+ def _poll(self, timeout=None):
+
+ self._schedule()
+
+ if timeout is None:
+ while True:
+ if not self._poll_event_handlers:
+ self._schedule()
+ if not self._poll_event_handlers:
+ raise StopIteration(
+ "timeout is None and there are no poll() event handlers")
+ previous_count = len(self._poll_event_queue)
+ PollScheduler._poll(self, timeout=self._max_display_latency)
+ self._status_display.display()
+ if previous_count != len(self._poll_event_queue):
+ break
+
+ elif timeout <= self._max_display_latency:
+ PollScheduler._poll(self, timeout=timeout)
+ if timeout == 0:
+ # The display is updated by _schedule() above, so it would be
+ # redundant to update it here when timeout is 0.
+ pass
+ else:
+ self._status_display.display()
+
+ else:
+ remaining_timeout = timeout
+ start_time = time.time()
+ while True:
+ previous_count = len(self._poll_event_queue)
+ PollScheduler._poll(self,
+ timeout=min(self._max_display_latency, remaining_timeout))
+ self._status_display.display()
+ if previous_count != len(self._poll_event_queue):
+ break
+ elapsed_time = time.time() - start_time
+ if elapsed_time < 0:
+ # The system clock has changed such that start_time
+ # is now in the future, so just assume that the
+ # timeout has already elapsed.
+ break
+ remaining_timeout = timeout - 1000 * elapsed_time
+ if remaining_timeout <= 0:
+ break
+
+ def _set_max_jobs(self, max_jobs):
+ self._max_jobs = max_jobs
+ self._task_queues.jobs.max_jobs = max_jobs
+ if "parallel-install" in self.settings.features:
+ self._task_queues.merge.max_jobs = max_jobs
+
+ def _background_mode(self):
+ """
+ Check if background mode is enabled and adjust states as necessary.
+
+ @rtype: bool
+ @returns: True if background mode is enabled, False otherwise.
+ """
+ background = (self._max_jobs is True or \
+ self._max_jobs > 1 or "--quiet" in self.myopts \
+ or "--quiet-build" in self.myopts) and \
+ not bool(self._opts_no_background.intersection(self.myopts))
+
+ if background:
+ interactive_tasks = self._get_interactive_tasks()
+ if interactive_tasks:
+ background = False
+ writemsg_level(">>> Sending package output to stdio due " + \
+ "to interactive package(s):\n",
+ level=logging.INFO, noiselevel=-1)
+ msg = [""]
+ for pkg in interactive_tasks:
+ pkg_str = " " + colorize("INFORM", str(pkg.cpv))
+ if pkg.root != "/":
+ pkg_str += " for " + pkg.root
+ msg.append(pkg_str)
+ msg.append("")
+ writemsg_level("".join("%s\n" % (l,) for l in msg),
+ level=logging.INFO, noiselevel=-1)
+ if self._max_jobs is True or self._max_jobs > 1:
+ self._set_max_jobs(1)
+ writemsg_level(">>> Setting --jobs=1 due " + \
+ "to the above interactive package(s)\n",
+ level=logging.INFO, noiselevel=-1)
+ writemsg_level(">>> In order to temporarily mask " + \
+ "interactive updates, you may\n" + \
+ ">>> specify --accept-properties=-interactive\n",
+ level=logging.INFO, noiselevel=-1)
+ self._status_display.quiet = \
+ not background or \
+ ("--quiet" in self.myopts and \
+ "--verbose" not in self.myopts)
+
+ self._logger.xterm_titles = \
+ "notitles" not in self.settings.features and \
+ self._status_display.quiet
+
+ return background
+
+ def _get_interactive_tasks(self):
+ interactive_tasks = []
+ for task in self._mergelist:
+ if not (isinstance(task, Package) and \
+ task.operation == "merge"):
+ continue
+ if 'interactive' in task.metadata.properties:
+ interactive_tasks.append(task)
+ return interactive_tasks
+
+ def _set_graph_config(self, graph_config):
+
+ if graph_config is None:
+ self._graph_config = None
+ self._pkg_cache = {}
+ self._digraph = None
+ self._mergelist = []
+ self._deep_system_deps.clear()
+ return
+
+ self._graph_config = graph_config
+ self._pkg_cache = graph_config.pkg_cache
+ self._digraph = graph_config.graph
+ self._mergelist = graph_config.mergelist
+
+ if "--nodeps" in self.myopts or \
+ (self._max_jobs is not True and self._max_jobs < 2):
+ # save some memory
+ self._digraph = None
+ graph_config.graph = None
+ graph_config.pkg_cache.clear()
+ self._deep_system_deps.clear()
+ for pkg in self._mergelist:
+ self._pkg_cache[pkg] = pkg
+ return
+
+ self._find_system_deps()
+ self._prune_digraph()
+ self._prevent_builddir_collisions()
+ if '--debug' in self.myopts:
+ writemsg("\nscheduler digraph:\n\n", noiselevel=-1)
+ self._digraph.debug_print()
+ writemsg("\n", noiselevel=-1)
+
+ def _find_system_deps(self):
+ """
+ Find system packages and their deep runtime dependencies. Before being
+ merged, these packages go to merge_wait_queue, to be merged when no
+ other packages are building.
+ NOTE: This can only find deep system deps if the system set has been
+ added to the graph and traversed deeply (the depgraph "complete"
+ parameter will do this, triggered by emerge --complete-graph option).
+ """
+ deep_system_deps = self._deep_system_deps
+ deep_system_deps.clear()
+ deep_system_deps.update(
+ _find_deep_system_runtime_deps(self._digraph))
+ deep_system_deps.difference_update([pkg for pkg in \
+ deep_system_deps if pkg.operation != "merge"])
+
+ def _prune_digraph(self):
+ """
+ Prune any root nodes that are irrelevant.
+ """
+
+ graph = self._digraph
+ completed_tasks = self._completed_tasks
+ removed_nodes = set()
+ while True:
+ for node in graph.root_nodes():
+ if not isinstance(node, Package) or \
+ (node.installed and node.operation == "nomerge") or \
+ node.onlydeps or \
+ node in completed_tasks:
+ removed_nodes.add(node)
+ if removed_nodes:
+ graph.difference_update(removed_nodes)
+ if not removed_nodes:
+ break
+ removed_nodes.clear()
+
+ def _prevent_builddir_collisions(self):
+ """
+ When building stages, sometimes the same exact cpv needs to be merged
+ to both $ROOTs. Add edges to the digraph in order to avoid collisions
+ in the builddir. Currently, normal file locks would be inappropriate
+ for this purpose since emerge holds all of it's build dir locks from
+ the main process.
+ """
+ cpv_map = {}
+ for pkg in self._mergelist:
+ if not isinstance(pkg, Package):
+ # a satisfied blocker
+ continue
+ if pkg.installed:
+ continue
+ if pkg.cpv not in cpv_map:
+ cpv_map[pkg.cpv] = [pkg]
+ continue
+ for earlier_pkg in cpv_map[pkg.cpv]:
+ self._digraph.add(earlier_pkg, pkg,
+ priority=DepPriority(buildtime=True))
+ cpv_map[pkg.cpv].append(pkg)
+
+ class _pkg_failure(portage.exception.PortageException):
+ """
+ An instance of this class is raised by unmerge() when
+ an uninstallation fails.
+ """
+ status = 1
+ def __init__(self, *pargs):
+ portage.exception.PortageException.__init__(self, pargs)
+ if pargs:
+ self.status = pargs[0]
+
+ def _schedule_fetch(self, fetcher):
+ """
+ Schedule a fetcher, in order to control the number of concurrent
+ fetchers. If self._max_jobs is greater than 1 then the fetch
+ queue is bypassed and the fetcher is started immediately,
+ otherwise it is added to the front of the parallel-fetch queue.
+ NOTE: The parallel-fetch queue is currently used to serialize
+ access to the parallel-fetch log, so changes in the log handling
+ would be required before it would be possible to enable
+ concurrent fetching within the parallel-fetch queue.
+ """
+ if self._max_jobs > 1:
+ fetcher.start()
+ else:
+ self._task_queues.fetch.addFront(fetcher)
+
+ def _schedule_setup(self, setup_phase):
+ """
+ Schedule a setup phase on the merge queue, in order to
+ serialize unsandboxed access to the live filesystem.
+ """
+ if self._task_queues.merge.max_jobs > 1 and \
+ "ebuild-locks" in self.settings.features:
+ # Use a separate queue for ebuild-locks when the merge
+ # queue allows more than 1 job (due to parallel-install),
+ # since the portage.locks module does not behave as desired
+ # if we try to lock the same file multiple times
+ # concurrently from the same process.
+ self._task_queues.ebuild_locks.add(setup_phase)
+ else:
+ self._task_queues.merge.add(setup_phase)
+ self._schedule()
+
+ def _schedule_unpack(self, unpack_phase):
+ """
+ Schedule an unpack phase on the unpack queue, in order
+ to serialize $DISTDIR access for live ebuilds.
+ """
+ self._task_queues.unpack.add(unpack_phase)
+
+ def _find_blockers(self, new_pkg):
+ """
+ Returns a callable.
+ """
+ def get_blockers():
+ return self._find_blockers_impl(new_pkg)
+ return get_blockers
+
+ def _find_blockers_impl(self, new_pkg):
+ if self._opts_ignore_blockers.intersection(self.myopts):
+ return None
+
+ blocker_db = self._blocker_db[new_pkg.root]
+
+ blocker_dblinks = []
+ for blocking_pkg in blocker_db.findInstalledBlockers(new_pkg):
+ if new_pkg.slot_atom == blocking_pkg.slot_atom:
+ continue
+ if new_pkg.cpv == blocking_pkg.cpv:
+ continue
+ blocker_dblinks.append(portage.dblink(
+ blocking_pkg.category, blocking_pkg.pf, blocking_pkg.root,
+ self.pkgsettings[blocking_pkg.root], treetype="vartree",
+ vartree=self.trees[blocking_pkg.root]["vartree"]))
+
+ return blocker_dblinks
+
+ def _generate_digests(self):
+ """
+ Generate digests if necessary for --digests or FEATURES=digest.
+ In order to avoid interference, this must done before parallel
+ tasks are started.
+ """
+
+ if '--fetchonly' in self.myopts:
+ return os.EX_OK
+
+ digest = '--digest' in self.myopts
+ if not digest:
+ for pkgsettings in self.pkgsettings.values():
+ if pkgsettings.mycpv is not None:
+ # ensure that we are using global features
+ # settings rather than those from package.env
+ pkgsettings.reset()
+ if 'digest' in pkgsettings.features:
+ digest = True
+ break
+
+ if not digest:
+ return os.EX_OK
+
+ for x in self._mergelist:
+ if not isinstance(x, Package) or \
+ x.type_name != 'ebuild' or \
+ x.operation != 'merge':
+ continue
+ pkgsettings = self.pkgsettings[x.root]
+ if pkgsettings.mycpv is not None:
+ # ensure that we are using global features
+ # settings rather than those from package.env
+ pkgsettings.reset()
+ if '--digest' not in self.myopts and \
+ 'digest' not in pkgsettings.features:
+ continue
+ portdb = x.root_config.trees['porttree'].dbapi
+ ebuild_path = portdb.findname(x.cpv, myrepo=x.repo)
+ if ebuild_path is None:
+ raise AssertionError("ebuild not found for '%s'" % x.cpv)
+ pkgsettings['O'] = os.path.dirname(ebuild_path)
+ if not digestgen(mysettings=pkgsettings, myportdb=portdb):
+ writemsg_level(
+ "!!! Unable to generate manifest for '%s'.\n" \
+ % x.cpv, level=logging.ERROR, noiselevel=-1)
+ return 1
+
+ return os.EX_OK
+
+ def _env_sanity_check(self):
+ """
+ Verify a sane environment before trying to build anything from source.
+ """
+ have_src_pkg = False
+ for x in self._mergelist:
+ if isinstance(x, Package) and not x.built:
+ have_src_pkg = True
+ break
+
+ if not have_src_pkg:
+ return os.EX_OK
+
+ for settings in self.pkgsettings.values():
+ for var in ("ARCH", ):
+ value = settings.get(var)
+ if value and value.strip():
+ continue
+ msg = _("%(var)s is not set... "
+ "Are you missing the '%(configroot)setc/make.profile' symlink? "
+ "Is the symlink correct? "
+ "Is your portage tree complete?") % \
+ {"var": var, "configroot": settings["PORTAGE_CONFIGROOT"]}
+
+ out = portage.output.EOutput()
+ for line in textwrap.wrap(msg, 70):
+ out.eerror(line)
+ return 1
+
+ return os.EX_OK
+
+ def _check_manifests(self):
+ # Verify all the manifests now so that the user is notified of failure
+ # as soon as possible.
+ if "strict" not in self.settings.features or \
+ "--fetchonly" in self.myopts or \
+ "--fetch-all-uri" in self.myopts:
+ return os.EX_OK
+
+ shown_verifying_msg = False
+ quiet_settings = {}
+ for myroot, pkgsettings in self.pkgsettings.items():
+ quiet_config = portage.config(clone=pkgsettings)
+ quiet_config["PORTAGE_QUIET"] = "1"
+ quiet_config.backup_changes("PORTAGE_QUIET")
+ quiet_settings[myroot] = quiet_config
+ del quiet_config
+
+ failures = 0
+
+ for x in self._mergelist:
+ if not isinstance(x, Package) or \
+ x.type_name != "ebuild":
+ continue
+
+ if x.operation == "uninstall":
+ continue
+
+ if not shown_verifying_msg:
+ shown_verifying_msg = True
+ self._status_msg("Verifying ebuild manifests")
+
+ root_config = x.root_config
+ portdb = root_config.trees["porttree"].dbapi
+ quiet_config = quiet_settings[root_config.root]
+ ebuild_path = portdb.findname(x.cpv, myrepo=x.repo)
+ if ebuild_path is None:
+ raise AssertionError("ebuild not found for '%s'" % x.cpv)
+ quiet_config["O"] = os.path.dirname(ebuild_path)
+ if not digestcheck([], quiet_config, strict=True):
+ failures |= 1
+
+ if failures:
+ return 1
+ return os.EX_OK
+
+ def _add_prefetchers(self):
+
+ if not self._parallel_fetch:
+ return
+
+ if self._parallel_fetch:
+ self._status_msg("Starting parallel fetch")
+
+ prefetchers = self._prefetchers
+ getbinpkg = "--getbinpkg" in self.myopts
+
+ for pkg in self._mergelist:
+ # mergelist can contain solved Blocker instances
+ if not isinstance(pkg, Package) or pkg.operation == "uninstall":
+ continue
+ prefetcher = self._create_prefetcher(pkg)
+ if prefetcher is not None:
+ self._task_queues.fetch.add(prefetcher)
+ prefetchers[pkg] = prefetcher
+
+ # Start the first prefetcher immediately so that self._task()
+ # won't discard it. This avoids a case where the first
+ # prefetcher is discarded, causing the second prefetcher to
+ # occupy the fetch queue before the first fetcher has an
+ # opportunity to execute.
+ self._task_queues.fetch.schedule()
+
+ def _create_prefetcher(self, pkg):
+ """
+ @return: a prefetcher, or None if not applicable
+ """
+ prefetcher = None
+
+ if not isinstance(pkg, Package):
+ pass
+
+ elif pkg.type_name == "ebuild":
+
+ prefetcher = EbuildFetcher(background=True,
+ config_pool=self._ConfigPool(pkg.root,
+ self._allocate_config, self._deallocate_config),
+ fetchonly=1, logfile=self._fetch_log,
+ pkg=pkg, prefetch=True, scheduler=self._sched_iface)
+
+ elif pkg.type_name == "binary" and \
+ "--getbinpkg" in self.myopts and \
+ pkg.root_config.trees["bintree"].isremote(pkg.cpv):
+
+ prefetcher = BinpkgPrefetcher(background=True,
+ pkg=pkg, scheduler=self._sched_iface)
+
+ return prefetcher
+
+ def _is_restart_scheduled(self):
+ """
+ Check if the merge list contains a replacement
+ for the current running instance, that will result
+ in restart after merge.
+ @rtype: bool
+ @returns: True if a restart is scheduled, False otherwise.
+ """
+ if self._opts_no_restart.intersection(self.myopts):
+ return False
+
+ mergelist = self._mergelist
+
+ for i, pkg in enumerate(mergelist):
+ if self._is_restart_necessary(pkg) and \
+ i != len(mergelist) - 1:
+ return True
+
+ return False
+
+ def _is_restart_necessary(self, pkg):
+ """
+ @return: True if merging the given package
+ requires restart, False otherwise.
+ """
+
+ # Figure out if we need a restart.
+ if pkg.root == self._running_root.root and \
+ portage.match_from_list(
+ portage.const.PORTAGE_PACKAGE_ATOM, [pkg]):
+ if self._running_portage is None:
+ return True
+ elif pkg.cpv != self._running_portage.cpv or \
+ '9999' in pkg.cpv or \
+ 'git' in pkg.inherited or \
+ 'git-2' in pkg.inherited:
+ return True
+ return False
+
+ def _restart_if_necessary(self, pkg):
+ """
+ Use execv() to restart emerge. This happens
+ if portage upgrades itself and there are
+ remaining packages in the list.
+ """
+
+ if self._opts_no_restart.intersection(self.myopts):
+ return
+
+ if not self._is_restart_necessary(pkg):
+ return
+
+ if pkg == self._mergelist[-1]:
+ return
+
+ self._main_loop_cleanup()
+
+ logger = self._logger
+ pkg_count = self._pkg_count
+ mtimedb = self._mtimedb
+ bad_resume_opts = self._bad_resume_opts
+
+ logger.log(" ::: completed emerge (%s of %s) %s to %s" % \
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg.root))
+
+ logger.log(" *** RESTARTING " + \
+ "emerge via exec() after change of " + \
+ "portage version.")
+
+ mtimedb["resume"]["mergelist"].remove(list(pkg))
+ mtimedb.commit()
+ portage.run_exitfuncs()
+ # Don't trust sys.argv[0] here because eselect-python may modify it.
+ emerge_binary = os.path.join(portage.const.PORTAGE_BIN_PATH, 'emerge')
+ mynewargv = [emerge_binary, "--resume"]
+ resume_opts = self.myopts.copy()
+ # For automatic resume, we need to prevent
+ # any of bad_resume_opts from leaking in
+ # via EMERGE_DEFAULT_OPTS.
+ resume_opts["--ignore-default-opts"] = True
+ for myopt, myarg in resume_opts.items():
+ if myopt not in bad_resume_opts:
+ if myarg is True:
+ mynewargv.append(myopt)
+ elif isinstance(myarg, list):
+ # arguments like --exclude that use 'append' action
+ for x in myarg:
+ mynewargv.append("%s=%s" % (myopt, x))
+ else:
+ mynewargv.append("%s=%s" % (myopt, myarg))
+ # priority only needs to be adjusted on the first run
+ os.environ["PORTAGE_NICENESS"] = "0"
+ os.execv(mynewargv[0], mynewargv)
+
+ def _run_pkg_pretend(self):
+ """
+ Since pkg_pretend output may be important, this method sends all
+ output directly to stdout (regardless of options like --quiet or
+ --jobs).
+ """
+
+ failures = 0
+
+ # Use a local PollScheduler instance here, since we don't
+ # want tasks here to trigger the usual Scheduler callbacks
+ # that handle job scheduling and status display.
+ sched_iface = PollScheduler().sched_iface
+
+ for x in self._mergelist:
+ if not isinstance(x, Package):
+ continue
+
+ if x.operation == "uninstall":
+ continue
+
+ if x.metadata["EAPI"] in ("0", "1", "2", "3"):
+ continue
+
+ if "pretend" not in x.metadata.defined_phases:
+ continue
+
+ out_str =">>> Running pre-merge checks for " + colorize("INFORM", x.cpv) + "\n"
+ portage.util.writemsg_stdout(out_str, noiselevel=-1)
+
+ root_config = x.root_config
+ settings = self.pkgsettings[root_config.root]
+ settings.setcpv(x)
+ tmpdir = tempfile.mkdtemp()
+ tmpdir_orig = settings["PORTAGE_TMPDIR"]
+ settings["PORTAGE_TMPDIR"] = tmpdir
+
+ try:
+ if x.built:
+ tree = "bintree"
+ bintree = root_config.trees["bintree"].dbapi.bintree
+ fetched = False
+
+ # Display fetch on stdout, so that it's always clear what
+ # is consuming time here.
+ if bintree.isremote(x.cpv):
+ fetcher = BinpkgFetcher(pkg=x,
+ scheduler=sched_iface)
+ fetcher.start()
+ if fetcher.wait() != os.EX_OK:
+ failures += 1
+ continue
+ fetched = fetcher.pkg_path
+
+ verifier = BinpkgVerifier(pkg=x,
+ scheduler=sched_iface)
+ verifier.start()
+ if verifier.wait() != os.EX_OK:
+ failures += 1
+ continue
+
+ if fetched:
+ bintree.inject(x.cpv, filename=fetched)
+ tbz2_file = bintree.getname(x.cpv)
+ infloc = os.path.join(tmpdir, x.category, x.pf, "build-info")
+ os.makedirs(infloc)
+ portage.xpak.tbz2(tbz2_file).unpackinfo(infloc)
+ ebuild_path = os.path.join(infloc, x.pf + ".ebuild")
+ settings.configdict["pkg"]["EMERGE_FROM"] = "binary"
+ settings.configdict["pkg"]["MERGE_TYPE"] = "binary"
+
+ else:
+ tree = "porttree"
+ portdb = root_config.trees["porttree"].dbapi
+ ebuild_path = portdb.findname(x.cpv, myrepo=x.repo)
+ if ebuild_path is None:
+ raise AssertionError("ebuild not found for '%s'" % x.cpv)
+ settings.configdict["pkg"]["EMERGE_FROM"] = "ebuild"
+ if self._build_opts.buildpkgonly:
+ settings.configdict["pkg"]["MERGE_TYPE"] = "buildonly"
+ else:
+ settings.configdict["pkg"]["MERGE_TYPE"] = "source"
+
+ portage.package.ebuild.doebuild.doebuild_environment(ebuild_path,
+ "pretend", settings=settings,
+ db=self.trees[settings["ROOT"]][tree].dbapi)
+ prepare_build_dirs(root_config.root, settings, cleanup=0)
+
+ vardb = root_config.trees['vartree'].dbapi
+ settings["REPLACING_VERSIONS"] = " ".join(
+ set(portage.versions.cpv_getversion(match) \
+ for match in vardb.match(x.slot_atom) + \
+ vardb.match('='+x.cpv)))
+ pretend_phase = EbuildPhase(
+ phase="pretend", scheduler=sched_iface,
+ settings=settings)
+
+ pretend_phase.start()
+ ret = pretend_phase.wait()
+ if ret != os.EX_OK:
+ failures += 1
+ portage.elog.elog_process(x.cpv, settings)
+ finally:
+ shutil.rmtree(tmpdir)
+ settings["PORTAGE_TMPDIR"] = tmpdir_orig
+
+ if failures:
+ return 1
+ return os.EX_OK
+
+ def merge(self):
+ if "--resume" in self.myopts:
+ # We're resuming.
+ portage.writemsg_stdout(
+ colorize("GOOD", "*** Resuming merge...\n"), noiselevel=-1)
+ self._logger.log(" *** Resuming merge...")
+
+ self._save_resume_list()
+
+ try:
+ self._background = self._background_mode()
+ except self._unknown_internal_error:
+ return 1
+
+ for root in self.trees:
+ root_config = self.trees[root]["root_config"]
+
+ # Even for --pretend --fetch mode, PORTAGE_TMPDIR is required
+ # since it might spawn pkg_nofetch which requires PORTAGE_BUILDDIR
+ # for ensuring sane $PWD (bug #239560) and storing elog messages.
+ tmpdir = root_config.settings.get("PORTAGE_TMPDIR", "")
+ if not tmpdir or not os.path.isdir(tmpdir):
+ msg = "The directory specified in your " + \
+ "PORTAGE_TMPDIR variable, '%s', " % tmpdir + \
+ "does not exist. Please create this " + \
+ "directory or correct your PORTAGE_TMPDIR setting."
+ msg = textwrap.wrap(msg, 70)
+ out = portage.output.EOutput()
+ for l in msg:
+ out.eerror(l)
+ return 1
+
+ if self._background:
+ root_config.settings.unlock()
+ root_config.settings["PORTAGE_BACKGROUND"] = "1"
+ root_config.settings.backup_changes("PORTAGE_BACKGROUND")
+ root_config.settings.lock()
+
+ self.pkgsettings[root] = portage.config(
+ clone=root_config.settings)
+
+ keep_going = "--keep-going" in self.myopts
+ fetchonly = self._build_opts.fetchonly
+ mtimedb = self._mtimedb
+ failed_pkgs = self._failed_pkgs
+
+ rval = self._generate_digests()
+ if rval != os.EX_OK:
+ return rval
+
+ rval = self._env_sanity_check()
+ if rval != os.EX_OK:
+ return rval
+
+ # TODO: Immediately recalculate deps here if --keep-going
+ # is enabled and corrupt manifests are detected.
+ rval = self._check_manifests()
+ if rval != os.EX_OK and not keep_going:
+ return rval
+
+ if not fetchonly:
+ rval = self._run_pkg_pretend()
+ if rval != os.EX_OK:
+ return rval
+
+ while True:
+
+ received_signal = []
+
+ def sighandler(signum, frame):
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
+ portage.util.writemsg("\n\nExiting on signal %(signal)s\n" % \
+ {"signal":signum})
+ self.terminate()
+ received_signal.append(128 + signum)
+
+ earlier_sigint_handler = signal.signal(signal.SIGINT, sighandler)
+ earlier_sigterm_handler = signal.signal(signal.SIGTERM, sighandler)
+
+ try:
+ rval = self._merge()
+ finally:
+ # Restore previous handlers
+ if earlier_sigint_handler is not None:
+ signal.signal(signal.SIGINT, earlier_sigint_handler)
+ else:
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+ if earlier_sigterm_handler is not None:
+ signal.signal(signal.SIGTERM, earlier_sigterm_handler)
+ else:
+ signal.signal(signal.SIGTERM, signal.SIG_DFL)
+
+ if received_signal:
+ sys.exit(received_signal[0])
+
+ if rval == os.EX_OK or fetchonly or not keep_going:
+ break
+ if "resume" not in mtimedb:
+ break
+ mergelist = self._mtimedb["resume"].get("mergelist")
+ if not mergelist:
+ break
+
+ if not failed_pkgs:
+ break
+
+ for failed_pkg in failed_pkgs:
+ mergelist.remove(list(failed_pkg.pkg))
+
+ self._failed_pkgs_all.extend(failed_pkgs)
+ del failed_pkgs[:]
+
+ if not mergelist:
+ break
+
+ if not self._calc_resume_list():
+ break
+
+ clear_caches(self.trees)
+ if not self._mergelist:
+ break
+
+ self._save_resume_list()
+ self._pkg_count.curval = 0
+ self._pkg_count.maxval = len([x for x in self._mergelist \
+ if isinstance(x, Package) and x.operation == "merge"])
+ self._status_display.maxval = self._pkg_count.maxval
+
+ self._logger.log(" *** Finished. Cleaning up...")
+
+ if failed_pkgs:
+ self._failed_pkgs_all.extend(failed_pkgs)
+ del failed_pkgs[:]
+
+ printer = portage.output.EOutput()
+ background = self._background
+ failure_log_shown = False
+ if background and len(self._failed_pkgs_all) == 1:
+ # If only one package failed then just show it's
+ # whole log for easy viewing.
+ failed_pkg = self._failed_pkgs_all[-1]
+ build_dir = failed_pkg.build_dir
+ log_file = None
+
+ log_paths = [failed_pkg.build_log]
+
+ log_path = self._locate_failure_log(failed_pkg)
+ if log_path is not None:
+ try:
+ log_file = open(_unicode_encode(log_path,
+ encoding=_encodings['fs'], errors='strict'), mode='rb')
+ except IOError:
+ pass
+ else:
+ if log_path.endswith('.gz'):
+ log_file = gzip.GzipFile(filename='',
+ mode='rb', fileobj=log_file)
+
+ if log_file is not None:
+ try:
+ for line in log_file:
+ writemsg_level(line, noiselevel=-1)
+ except zlib.error as e:
+ writemsg_level("%s\n" % (e,), level=logging.ERROR,
+ noiselevel=-1)
+ finally:
+ log_file.close()
+ failure_log_shown = True
+
+ # Dump mod_echo output now since it tends to flood the terminal.
+ # This allows us to avoid having more important output, generated
+ # later, from being swept away by the mod_echo output.
+ mod_echo_output = _flush_elog_mod_echo()
+
+ if background and not failure_log_shown and \
+ self._failed_pkgs_all and \
+ self._failed_pkgs_die_msgs and \
+ not mod_echo_output:
+
+ for mysettings, key, logentries in self._failed_pkgs_die_msgs:
+ root_msg = ""
+ if mysettings["ROOT"] != "/":
+ root_msg = " merged to %s" % mysettings["ROOT"]
+ print()
+ printer.einfo("Error messages for package %s%s:" % \
+ (colorize("INFORM", key), root_msg))
+ print()
+ for phase in portage.const.EBUILD_PHASES:
+ if phase not in logentries:
+ continue
+ for msgtype, msgcontent in logentries[phase]:
+ if isinstance(msgcontent, basestring):
+ msgcontent = [msgcontent]
+ for line in msgcontent:
+ printer.eerror(line.strip("\n"))
+
+ if self._post_mod_echo_msgs:
+ for msg in self._post_mod_echo_msgs:
+ msg()
+
+ if len(self._failed_pkgs_all) > 1 or \
+ (self._failed_pkgs_all and keep_going):
+ if len(self._failed_pkgs_all) > 1:
+ msg = "The following %d packages have " % \
+ len(self._failed_pkgs_all) + \
+ "failed to build or install:"
+ else:
+ msg = "The following package has " + \
+ "failed to build or install:"
+
+ printer.eerror("")
+ for line in textwrap.wrap(msg, 72):
+ printer.eerror(line)
+ printer.eerror("")
+ for failed_pkg in self._failed_pkgs_all:
+ # Use _unicode_decode() to force unicode format string so
+ # that Package.__unicode__() is called in python2.
+ msg = _unicode_decode(" %s") % (failed_pkg.pkg,)
+ log_path = self._locate_failure_log(failed_pkg)
+ if log_path is not None:
+ msg += ", Log file:"
+ printer.eerror(msg)
+ if log_path is not None:
+ printer.eerror(" '%s'" % colorize('INFORM', log_path))
+ printer.eerror("")
+
+ if self._failed_pkgs_all:
+ return 1
+ return os.EX_OK
+
+ def _elog_listener(self, mysettings, key, logentries, fulltext):
+ errors = portage.elog.filter_loglevels(logentries, ["ERROR"])
+ if errors:
+ self._failed_pkgs_die_msgs.append(
+ (mysettings, key, errors))
+
+ def _locate_failure_log(self, failed_pkg):
+
+ build_dir = failed_pkg.build_dir
+ log_file = None
+
+ log_paths = [failed_pkg.build_log]
+
+ for log_path in log_paths:
+ if not log_path:
+ continue
+
+ try:
+ log_size = os.stat(log_path).st_size
+ except OSError:
+ continue
+
+ if log_size == 0:
+ continue
+
+ return log_path
+
+ return None
+
+ def _add_packages(self):
+ pkg_queue = self._pkg_queue
+ for pkg in self._mergelist:
+ if isinstance(pkg, Package):
+ pkg_queue.append(pkg)
+ elif isinstance(pkg, Blocker):
+ pass
+
+ def _system_merge_started(self, merge):
+ """
+ Add any unsatisfied runtime deps to self._unsatisfied_system_deps.
+ In general, this keeps track of installed system packages with
+ unsatisfied RDEPEND or PDEPEND (circular dependencies). It can be
+ a fragile situation, so we don't execute any unrelated builds until
+ the circular dependencies are built and installed.
+ """
+ graph = self._digraph
+ if graph is None:
+ return
+ pkg = merge.merge.pkg
+
+ # Skip this if $ROOT != / since it shouldn't matter if there
+ # are unsatisfied system runtime deps in this case.
+ if pkg.root != '/':
+ return
+
+ completed_tasks = self._completed_tasks
+ unsatisfied = self._unsatisfied_system_deps
+
+ def ignore_non_runtime_or_satisfied(priority):
+ """
+ Ignore non-runtime and satisfied runtime priorities.
+ """
+ if isinstance(priority, DepPriority) and \
+ not priority.satisfied and \
+ (priority.runtime or priority.runtime_post):
+ return False
+ return True
+
+ # When checking for unsatisfied runtime deps, only check
+ # direct deps since indirect deps are checked when the
+ # corresponding parent is merged.
+ for child in graph.child_nodes(pkg,
+ ignore_priority=ignore_non_runtime_or_satisfied):
+ if not isinstance(child, Package) or \
+ child.operation == 'uninstall':
+ continue
+ if child is pkg:
+ continue
+ if child.operation == 'merge' and \
+ child not in completed_tasks:
+ unsatisfied.add(child)
+
+ def _merge_wait_exit_handler(self, task):
+ self._merge_wait_scheduled.remove(task)
+ self._merge_exit(task)
+
+ def _merge_exit(self, merge):
+ self._running_tasks.pop(id(merge), None)
+ self._do_merge_exit(merge)
+ self._deallocate_config(merge.merge.settings)
+ if merge.returncode == os.EX_OK and \
+ not merge.merge.pkg.installed:
+ self._status_display.curval += 1
+ self._status_display.merges = len(self._task_queues.merge)
+ self._schedule()
+
+ def _do_merge_exit(self, merge):
+ pkg = merge.merge.pkg
+ if merge.returncode != os.EX_OK:
+ settings = merge.merge.settings
+ build_dir = settings.get("PORTAGE_BUILDDIR")
+ build_log = settings.get("PORTAGE_LOG_FILE")
+
+ self._failed_pkgs.append(self._failed_pkg(
+ build_dir=build_dir, build_log=build_log,
+ pkg=pkg,
+ returncode=merge.returncode))
+ if not self._terminated_tasks:
+ self._failed_pkg_msg(self._failed_pkgs[-1], "install", "to")
+ self._status_display.failed = len(self._failed_pkgs)
+ return
+
+ self._task_complete(pkg)
+ pkg_to_replace = merge.merge.pkg_to_replace
+ if pkg_to_replace is not None:
+ # When a package is replaced, mark it's uninstall
+ # task complete (if any).
+ if self._digraph is not None and \
+ pkg_to_replace in self._digraph:
+ try:
+ self._pkg_queue.remove(pkg_to_replace)
+ except ValueError:
+ pass
+ self._task_complete(pkg_to_replace)
+ else:
+ self._pkg_cache.pop(pkg_to_replace, None)
+
+ if pkg.installed:
+ return
+
+ self._restart_if_necessary(pkg)
+
+ # Call mtimedb.commit() after each merge so that
+ # --resume still works after being interrupted
+ # by reboot, sigkill or similar.
+ mtimedb = self._mtimedb
+ mtimedb["resume"]["mergelist"].remove(list(pkg))
+ if not mtimedb["resume"]["mergelist"]:
+ del mtimedb["resume"]
+ mtimedb.commit()
+
+ def _build_exit(self, build):
+ self._running_tasks.pop(id(build), None)
+ if build.returncode == os.EX_OK and self._terminated_tasks:
+ # We've been interrupted, so we won't
+ # add this to the merge queue.
+ self.curval += 1
+ self._deallocate_config(build.settings)
+ elif build.returncode == os.EX_OK:
+ self.curval += 1
+ merge = PackageMerge(merge=build)
+ self._running_tasks[id(merge)] = merge
+ if not build.build_opts.buildpkgonly and \
+ build.pkg in self._deep_system_deps:
+ # Since dependencies on system packages are frequently
+ # unspecified, merge them only when no builds are executing.
+ self._merge_wait_queue.append(merge)
+ merge.addStartListener(self._system_merge_started)
+ else:
+ merge.addExitListener(self._merge_exit)
+ self._task_queues.merge.add(merge)
+ self._status_display.merges = len(self._task_queues.merge)
+ else:
+ settings = build.settings
+ build_dir = settings.get("PORTAGE_BUILDDIR")
+ build_log = settings.get("PORTAGE_LOG_FILE")
+
+ self._failed_pkgs.append(self._failed_pkg(
+ build_dir=build_dir, build_log=build_log,
+ pkg=build.pkg,
+ returncode=build.returncode))
+ if not self._terminated_tasks:
+ self._failed_pkg_msg(self._failed_pkgs[-1], "emerge", "for")
+ self._status_display.failed = len(self._failed_pkgs)
+ self._deallocate_config(build.settings)
+ self._jobs -= 1
+ self._status_display.running = self._jobs
+ self._schedule()
+
+ def _extract_exit(self, build):
+ self._build_exit(build)
+
+ def _task_complete(self, pkg):
+ self._completed_tasks.add(pkg)
+ self._unsatisfied_system_deps.discard(pkg)
+ self._choose_pkg_return_early = False
+ blocker_db = self._blocker_db[pkg.root]
+ blocker_db.discardBlocker(pkg)
+
+ def _merge(self):
+
+ self._add_prefetchers()
+ self._add_packages()
+ pkg_queue = self._pkg_queue
+ failed_pkgs = self._failed_pkgs
+ portage.locks._quiet = self._background
+ portage.elog.add_listener(self._elog_listener)
+ rval = os.EX_OK
+
+ try:
+ self._main_loop()
+ finally:
+ self._main_loop_cleanup()
+ portage.locks._quiet = False
+ portage.elog.remove_listener(self._elog_listener)
+ if failed_pkgs:
+ rval = failed_pkgs[-1].returncode
+
+ return rval
+
+ def _main_loop_cleanup(self):
+ del self._pkg_queue[:]
+ self._completed_tasks.clear()
+ self._deep_system_deps.clear()
+ self._unsatisfied_system_deps.clear()
+ self._choose_pkg_return_early = False
+ self._status_display.reset()
+ self._digraph = None
+ self._task_queues.fetch.clear()
+ self._prefetchers.clear()
+
+ def _choose_pkg(self):
+ """
+ Choose a task that has all its dependencies satisfied. This is used
+ for parallel build scheduling, and ensures that we don't build
+ anything with deep dependencies that have yet to be merged.
+ """
+
+ if self._choose_pkg_return_early:
+ return None
+
+ if self._digraph is None:
+ if self._is_work_scheduled() and \
+ not ("--nodeps" in self.myopts and \
+ (self._max_jobs is True or self._max_jobs > 1)):
+ self._choose_pkg_return_early = True
+ return None
+ return self._pkg_queue.pop(0)
+
+ if not self._is_work_scheduled():
+ return self._pkg_queue.pop(0)
+
+ self._prune_digraph()
+
+ chosen_pkg = None
+
+ # Prefer uninstall operations when available.
+ graph = self._digraph
+ for pkg in self._pkg_queue:
+ if pkg.operation == 'uninstall' and \
+ not graph.child_nodes(pkg):
+ chosen_pkg = pkg
+ break
+
+ if chosen_pkg is None:
+ later = set(self._pkg_queue)
+ for pkg in self._pkg_queue:
+ later.remove(pkg)
+ if not self._dependent_on_scheduled_merges(pkg, later):
+ chosen_pkg = pkg
+ break
+
+ if chosen_pkg is not None:
+ self._pkg_queue.remove(chosen_pkg)
+
+ if chosen_pkg is None:
+ # There's no point in searching for a package to
+ # choose until at least one of the existing jobs
+ # completes.
+ self._choose_pkg_return_early = True
+
+ return chosen_pkg
+
+ def _dependent_on_scheduled_merges(self, pkg, later):
+ """
+ Traverse the subgraph of the given packages deep dependencies
+ to see if it contains any scheduled merges.
+ @param pkg: a package to check dependencies for
+ @type pkg: Package
+ @param later: packages for which dependence should be ignored
+ since they will be merged later than pkg anyway and therefore
+ delaying the merge of pkg will not result in a more optimal
+ merge order
+ @type later: set
+ @rtype: bool
+ @returns: True if the package is dependent, False otherwise.
+ """
+
+ graph = self._digraph
+ completed_tasks = self._completed_tasks
+
+ dependent = False
+ traversed_nodes = set([pkg])
+ direct_deps = graph.child_nodes(pkg)
+ node_stack = direct_deps
+ direct_deps = frozenset(direct_deps)
+ while node_stack:
+ node = node_stack.pop()
+ if node in traversed_nodes:
+ continue
+ traversed_nodes.add(node)
+ if not ((node.installed and node.operation == "nomerge") or \
+ (node.operation == "uninstall" and \
+ node not in direct_deps) or \
+ node in completed_tasks or \
+ node in later):
+ dependent = True
+ break
+
+ # Don't traverse children of uninstall nodes since
+ # those aren't dependencies in the usual sense.
+ if node.operation != "uninstall":
+ node_stack.extend(graph.child_nodes(node))
+
+ return dependent
+
+ def _allocate_config(self, root):
+ """
+ Allocate a unique config instance for a task in order
+ to prevent interference between parallel tasks.
+ """
+ if self._config_pool[root]:
+ temp_settings = self._config_pool[root].pop()
+ else:
+ temp_settings = portage.config(clone=self.pkgsettings[root])
+ # Since config.setcpv() isn't guaranteed to call config.reset() due to
+ # performance reasons, call it here to make sure all settings from the
+ # previous package get flushed out (such as PORTAGE_LOG_FILE).
+ temp_settings.reload()
+ temp_settings.reset()
+ return temp_settings
+
+ def _deallocate_config(self, settings):
+ self._config_pool[settings["ROOT"]].append(settings)
+
+ def _main_loop(self):
+
+ # Only allow 1 job max if a restart is scheduled
+ # due to portage update.
+ if self._is_restart_scheduled() or \
+ self._opts_no_background.intersection(self.myopts):
+ self._set_max_jobs(1)
+
+ while self._schedule():
+ self._poll_loop()
+
+ while True:
+ self._schedule()
+ if not self._is_work_scheduled():
+ break
+ self._poll_loop()
+
+ def _keep_scheduling(self):
+ return bool(not self._terminated_tasks and self._pkg_queue and \
+ not (self._failed_pkgs and not self._build_opts.fetchonly))
+
+ def _is_work_scheduled(self):
+ return bool(self._running_tasks)
+
+ def _schedule_tasks(self):
+
+ while True:
+
+ # When the number of jobs and merges drops to zero,
+ # process a single merge from _merge_wait_queue if
+ # it's not empty. We only process one since these are
+ # special packages and we want to ensure that
+ # parallel-install does not cause more than one of
+ # them to install at the same time.
+ if (self._merge_wait_queue and not self._jobs and
+ not self._task_queues.merge):
+ task = self._merge_wait_queue.popleft()
+ task.addExitListener(self._merge_wait_exit_handler)
+ self._task_queues.merge.add(task)
+ self._status_display.merges = len(self._task_queues.merge)
+ self._merge_wait_scheduled.append(task)
+
+ self._schedule_tasks_imp()
+ self._status_display.display()
+
+ state_change = 0
+ for q in self._task_queues.values():
+ if q.schedule():
+ state_change += 1
+
+ # Cancel prefetchers if they're the only reason
+ # the main poll loop is still running.
+ if self._failed_pkgs and not self._build_opts.fetchonly and \
+ not self._is_work_scheduled() and \
+ self._task_queues.fetch:
+ self._task_queues.fetch.clear()
+ state_change += 1
+
+ if not (state_change or \
+ (self._merge_wait_queue and not self._jobs and
+ not self._task_queues.merge)):
+ break
+
+ return self._keep_scheduling()
+
+ def _job_delay(self):
+ """
+ @rtype: bool
+ @returns: True if job scheduling should be delayed, False otherwise.
+ """
+
+ if self._jobs and self._max_load is not None:
+
+ current_time = time.time()
+
+ delay = self._job_delay_factor * self._jobs ** self._job_delay_exp
+ if delay > self._job_delay_max:
+ delay = self._job_delay_max
+ if (current_time - self._previous_job_start_time) < delay:
+ return True
+
+ return False
+
+ def _schedule_tasks_imp(self):
+ """
+ @rtype: bool
+ @returns: True if state changed, False otherwise.
+ """
+
+ state_change = 0
+
+ while True:
+
+ if not self._keep_scheduling():
+ return bool(state_change)
+
+ if self._choose_pkg_return_early or \
+ self._merge_wait_scheduled or \
+ (self._jobs and self._unsatisfied_system_deps) or \
+ not self._can_add_job() or \
+ self._job_delay():
+ return bool(state_change)
+
+ pkg = self._choose_pkg()
+ if pkg is None:
+ return bool(state_change)
+
+ state_change += 1
+
+ if not pkg.installed:
+ self._pkg_count.curval += 1
+
+ task = self._task(pkg)
+
+ if pkg.installed:
+ merge = PackageMerge(merge=task)
+ self._running_tasks[id(merge)] = merge
+ merge.addExitListener(self._merge_exit)
+ self._task_queues.merge.addFront(merge)
+
+ elif pkg.built:
+ self._jobs += 1
+ self._previous_job_start_time = time.time()
+ self._status_display.running = self._jobs
+ self._running_tasks[id(task)] = task
+ task.addExitListener(self._extract_exit)
+ self._task_queues.jobs.add(task)
+
+ else:
+ self._jobs += 1
+ self._previous_job_start_time = time.time()
+ self._status_display.running = self._jobs
+ self._running_tasks[id(task)] = task
+ task.addExitListener(self._build_exit)
+ self._task_queues.jobs.add(task)
+
+ return bool(state_change)
+
+ def _task(self, pkg):
+
+ pkg_to_replace = None
+ if pkg.operation != "uninstall":
+ vardb = pkg.root_config.trees["vartree"].dbapi
+ previous_cpv = [x for x in vardb.match(pkg.slot_atom) \
+ if portage.cpv_getkey(x) == pkg.cp]
+ if not previous_cpv and vardb.cpv_exists(pkg.cpv):
+ # same cpv, different SLOT
+ previous_cpv = [pkg.cpv]
+ if previous_cpv:
+ previous_cpv = previous_cpv.pop()
+ pkg_to_replace = self._pkg(previous_cpv,
+ "installed", pkg.root_config, installed=True,
+ operation="uninstall")
+
+ prefetcher = self._prefetchers.pop(pkg, None)
+ if prefetcher is not None and not prefetcher.isAlive():
+ try:
+ self._task_queues.fetch._task_queue.remove(prefetcher)
+ except ValueError:
+ pass
+ prefetcher = None
+
+ task = MergeListItem(args_set=self._args_set,
+ background=self._background, binpkg_opts=self._binpkg_opts,
+ build_opts=self._build_opts,
+ config_pool=self._ConfigPool(pkg.root,
+ self._allocate_config, self._deallocate_config),
+ emerge_opts=self.myopts,
+ find_blockers=self._find_blockers(pkg), logger=self._logger,
+ mtimedb=self._mtimedb, pkg=pkg, pkg_count=self._pkg_count.copy(),
+ pkg_to_replace=pkg_to_replace,
+ prefetcher=prefetcher,
+ scheduler=self._sched_iface,
+ settings=self._allocate_config(pkg.root),
+ statusMessage=self._status_msg,
+ world_atom=self._world_atom)
+
+ return task
+
+ def _failed_pkg_msg(self, failed_pkg, action, preposition):
+ pkg = failed_pkg.pkg
+ msg = "%s to %s %s" % \
+ (bad("Failed"), action, colorize("INFORM", pkg.cpv))
+ if pkg.root != "/":
+ msg += " %s %s" % (preposition, pkg.root)
+
+ log_path = self._locate_failure_log(failed_pkg)
+ if log_path is not None:
+ msg += ", Log file:"
+ self._status_msg(msg)
+
+ if log_path is not None:
+ self._status_msg(" '%s'" % (colorize("INFORM", log_path),))
+
+ def _status_msg(self, msg):
+ """
+ Display a brief status message (no newlines) in the status display.
+ This is called by tasks to provide feedback to the user. This
+ delegates the resposibility of generating \r and \n control characters,
+ to guarantee that lines are created or erased when necessary and
+ appropriate.
+
+ @type msg: str
+ @param msg: a brief status message (no newlines allowed)
+ """
+ if not self._background:
+ writemsg_level("\n")
+ self._status_display.displayMessage(msg)
+
+ def _save_resume_list(self):
+ """
+ Do this before verifying the ebuild Manifests since it might
+ be possible for the user to use --resume --skipfirst get past
+ a non-essential package with a broken digest.
+ """
+ mtimedb = self._mtimedb
+
+ mtimedb["resume"] = {}
+ # Stored as a dict starting with portage-2.1.6_rc1, and supported
+ # by >=portage-2.1.3_rc8. Versions <portage-2.1.3_rc8 only support
+ # a list type for options.
+ mtimedb["resume"]["myopts"] = self.myopts.copy()
+
+ # Convert Atom instances to plain str.
+ mtimedb["resume"]["favorites"] = [str(x) for x in self._favorites]
+ mtimedb["resume"]["mergelist"] = [list(x) \
+ for x in self._mergelist \
+ if isinstance(x, Package) and x.operation == "merge"]
+
+ mtimedb.commit()
+
+ def _calc_resume_list(self):
+ """
+ Use the current resume list to calculate a new one,
+ dropping any packages with unsatisfied deps.
+ @rtype: bool
+ @returns: True if successful, False otherwise.
+ """
+ print(colorize("GOOD", "*** Resuming merge..."))
+
+ # free some memory before creating
+ # the resume depgraph
+ self._destroy_graph()
+
+ myparams = create_depgraph_params(self.myopts, None)
+ success = False
+ e = None
+ try:
+ success, mydepgraph, dropped_tasks = resume_depgraph(
+ self.settings, self.trees, self._mtimedb, self.myopts,
+ myparams, self._spinner)
+ except depgraph.UnsatisfiedResumeDep as exc:
+ # rename variable to avoid python-3.0 error:
+ # SyntaxError: can not delete variable 'e' referenced in nested
+ # scope
+ e = exc
+ mydepgraph = e.depgraph
+ dropped_tasks = set()
+
+ if e is not None:
+ def unsatisfied_resume_dep_msg():
+ mydepgraph.display_problems()
+ out = portage.output.EOutput()
+ out.eerror("One or more packages are either masked or " + \
+ "have missing dependencies:")
+ out.eerror("")
+ indent = " "
+ show_parents = set()
+ for dep in e.value:
+ if dep.parent in show_parents:
+ continue
+ show_parents.add(dep.parent)
+ if dep.atom is None:
+ out.eerror(indent + "Masked package:")
+ out.eerror(2 * indent + str(dep.parent))
+ out.eerror("")
+ else:
+ out.eerror(indent + str(dep.atom) + " pulled in by:")
+ out.eerror(2 * indent + str(dep.parent))
+ out.eerror("")
+ msg = "The resume list contains packages " + \
+ "that are either masked or have " + \
+ "unsatisfied dependencies. " + \
+ "Please restart/continue " + \
+ "the operation manually, or use --skipfirst " + \
+ "to skip the first package in the list and " + \
+ "any other packages that may be " + \
+ "masked or have missing dependencies."
+ for line in textwrap.wrap(msg, 72):
+ out.eerror(line)
+ self._post_mod_echo_msgs.append(unsatisfied_resume_dep_msg)
+ return False
+
+ if success and self._show_list():
+ mylist = mydepgraph.altlist()
+ if mylist:
+ if "--tree" in self.myopts:
+ mylist.reverse()
+ mydepgraph.display(mylist, favorites=self._favorites)
+
+ if not success:
+ self._post_mod_echo_msgs.append(mydepgraph.display_problems)
+ return False
+ mydepgraph.display_problems()
+ self._init_graph(mydepgraph.schedulerGraph())
+
+ msg_width = 75
+ for task in dropped_tasks:
+ if not (isinstance(task, Package) and task.operation == "merge"):
+ continue
+ pkg = task
+ msg = "emerge --keep-going:" + \
+ " %s" % (pkg.cpv,)
+ if pkg.root != "/":
+ msg += " for %s" % (pkg.root,)
+ msg += " dropped due to unsatisfied dependency."
+ for line in textwrap.wrap(msg, msg_width):
+ eerror(line, phase="other", key=pkg.cpv)
+ settings = self.pkgsettings[pkg.root]
+ # Ensure that log collection from $T is disabled inside
+ # elog_process(), since any logs that might exist are
+ # not valid here.
+ settings.pop("T", None)
+ portage.elog.elog_process(pkg.cpv, settings)
+ self._failed_pkgs_all.append(self._failed_pkg(pkg=pkg))
+
+ return True
+
+ def _show_list(self):
+ myopts = self.myopts
+ if "--quiet" not in myopts and \
+ ("--ask" in myopts or "--tree" in myopts or \
+ "--verbose" in myopts):
+ return True
+ return False
+
+ def _world_atom(self, pkg):
+ """
+ Add or remove the package to the world file, but only if
+ it's supposed to be added or removed. Otherwise, do nothing.
+ """
+
+ if set(("--buildpkgonly", "--fetchonly",
+ "--fetch-all-uri",
+ "--oneshot", "--onlydeps",
+ "--pretend")).intersection(self.myopts):
+ return
+
+ if pkg.root != self.target_root:
+ return
+
+ args_set = self._args_set
+ if not args_set.findAtomForPackage(pkg):
+ return
+
+ logger = self._logger
+ pkg_count = self._pkg_count
+ root_config = pkg.root_config
+ world_set = root_config.sets["selected"]
+ world_locked = False
+ if hasattr(world_set, "lock"):
+ world_set.lock()
+ world_locked = True
+
+ try:
+ if hasattr(world_set, "load"):
+ world_set.load() # maybe it's changed on disk
+
+ if pkg.operation == "uninstall":
+ if hasattr(world_set, "cleanPackage"):
+ world_set.cleanPackage(pkg.root_config.trees["vartree"].dbapi,
+ pkg.cpv)
+ if hasattr(world_set, "remove"):
+ for s in pkg.root_config.setconfig.active:
+ world_set.remove(SETPREFIX+s)
+ else:
+ atom = create_world_atom(pkg, args_set, root_config)
+ if atom:
+ if hasattr(world_set, "add"):
+ self._status_msg(('Recording %s in "world" ' + \
+ 'favorites file...') % atom)
+ logger.log(" === (%s of %s) Updating world file (%s)" % \
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv))
+ world_set.add(atom)
+ else:
+ writemsg_level('\n!!! Unable to record %s in "world"\n' % \
+ (atom,), level=logging.WARN, noiselevel=-1)
+ finally:
+ if world_locked:
+ world_set.unlock()
+
+ def _pkg(self, cpv, type_name, root_config, installed=False,
+ operation=None, myrepo=None):
+ """
+ Get a package instance from the cache, or create a new
+ one if necessary. Raises KeyError from aux_get if it
+ failures for some reason (package does not exist or is
+ corrupt).
+ """
+
+ # Reuse existing instance when available.
+ pkg = self._pkg_cache.get(Package._gen_hash_key(cpv=cpv,
+ type_name=type_name, repo_name=myrepo, root_config=root_config,
+ installed=installed, operation=operation))
+
+ if pkg is not None:
+ return pkg
+
+ tree_type = depgraph.pkg_tree_map[type_name]
+ db = root_config.trees[tree_type].dbapi
+ db_keys = list(self.trees[root_config.root][
+ tree_type].dbapi._aux_cache_keys)
+ metadata = zip(db_keys, db.aux_get(cpv, db_keys, myrepo=myrepo))
+ pkg = Package(built=(type_name != "ebuild"),
+ cpv=cpv, installed=installed, metadata=metadata,
+ root_config=root_config, type_name=type_name)
+ self._pkg_cache[pkg] = pkg
+ return pkg
diff --git a/portage_with_autodep/pym/_emerge/SequentialTaskQueue.py b/portage_with_autodep/pym/_emerge/SequentialTaskQueue.py
new file mode 100644
index 0000000..c1c98c4
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/SequentialTaskQueue.py
@@ -0,0 +1,89 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+from _emerge.SlotObject import SlotObject
+from collections import deque
+class SequentialTaskQueue(SlotObject):
+
+ __slots__ = ("max_jobs", "running_tasks") + \
+ ("_dirty", "_scheduling", "_task_queue")
+
+ def __init__(self, **kwargs):
+ SlotObject.__init__(self, **kwargs)
+ self._task_queue = deque()
+ self.running_tasks = set()
+ if self.max_jobs is None:
+ self.max_jobs = 1
+ self._dirty = True
+
+ def add(self, task):
+ self._task_queue.append(task)
+ self._dirty = True
+
+ def addFront(self, task):
+ self._task_queue.appendleft(task)
+ self._dirty = True
+
+ def schedule(self):
+
+ if not self._dirty:
+ return False
+
+ if not self:
+ return False
+
+ if self._scheduling:
+ # Ignore any recursive schedule() calls triggered via
+ # self._task_exit().
+ return False
+
+ self._scheduling = True
+
+ task_queue = self._task_queue
+ running_tasks = self.running_tasks
+ max_jobs = self.max_jobs
+ state_changed = False
+
+ while task_queue and \
+ (max_jobs is True or len(running_tasks) < max_jobs):
+ task = task_queue.popleft()
+ cancelled = getattr(task, "cancelled", None)
+ if not cancelled:
+ running_tasks.add(task)
+ task.addExitListener(self._task_exit)
+ task.start()
+ state_changed = True
+
+ self._dirty = False
+ self._scheduling = False
+
+ return state_changed
+
+ def _task_exit(self, task):
+ """
+ Since we can always rely on exit listeners being called, the set of
+ running tasks is always pruned automatically and there is never any need
+ to actively prune it.
+ """
+ self.running_tasks.remove(task)
+ if self._task_queue:
+ self._dirty = True
+
+ def clear(self):
+ self._task_queue.clear()
+ running_tasks = self.running_tasks
+ while running_tasks:
+ task = running_tasks.pop()
+ task.removeExitListener(self._task_exit)
+ task.cancel()
+ self._dirty = False
+
+ def __bool__(self):
+ return bool(self._task_queue or self.running_tasks)
+
+ if sys.hexversion < 0x3000000:
+ __nonzero__ = __bool__
+
+ def __len__(self):
+ return len(self._task_queue) + len(self.running_tasks)
diff --git a/portage_with_autodep/pym/_emerge/SetArg.py b/portage_with_autodep/pym/_emerge/SetArg.py
new file mode 100644
index 0000000..94cf0a6
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/SetArg.py
@@ -0,0 +1,11 @@
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.DependencyArg import DependencyArg
+from portage._sets import SETPREFIX
+class SetArg(DependencyArg):
+ def __init__(self, pset=None, **kwargs):
+ DependencyArg.__init__(self, **kwargs)
+ self.pset = pset
+ self.name = self.arg[len(SETPREFIX):]
+
diff --git a/portage_with_autodep/pym/_emerge/SlotObject.py b/portage_with_autodep/pym/_emerge/SlotObject.py
new file mode 100644
index 0000000..fdc6f35
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/SlotObject.py
@@ -0,0 +1,42 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+class SlotObject(object):
+ __slots__ = ("__weakref__",)
+
+ def __init__(self, **kwargs):
+ classes = [self.__class__]
+ while classes:
+ c = classes.pop()
+ if c is SlotObject:
+ continue
+ classes.extend(c.__bases__)
+ slots = getattr(c, "__slots__", None)
+ if not slots:
+ continue
+ for myattr in slots:
+ myvalue = kwargs.get(myattr, None)
+ setattr(self, myattr, myvalue)
+
+ def copy(self):
+ """
+ Create a new instance and copy all attributes
+ defined from __slots__ (including those from
+ inherited classes).
+ """
+ obj = self.__class__()
+
+ classes = [self.__class__]
+ while classes:
+ c = classes.pop()
+ if c is SlotObject:
+ continue
+ classes.extend(c.__bases__)
+ slots = getattr(c, "__slots__", None)
+ if not slots:
+ continue
+ for myattr in slots:
+ setattr(obj, myattr, getattr(self, myattr))
+
+ return obj
+
diff --git a/portage_with_autodep/pym/_emerge/SpawnProcess.py b/portage_with_autodep/pym/_emerge/SpawnProcess.py
new file mode 100644
index 0000000..b72971c
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/SpawnProcess.py
@@ -0,0 +1,235 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.SubProcess import SubProcess
+import sys
+from portage.cache.mappings import slot_dict_class
+import portage
+from portage import _encodings
+from portage import _unicode_encode
+from portage import os
+from portage.const import BASH_BINARY
+import fcntl
+import errno
+import gzip
+
+class SpawnProcess(SubProcess):
+
+ """
+ Constructor keyword args are passed into portage.process.spawn().
+ The required "args" keyword argument will be passed as the first
+ spawn() argument.
+ """
+
+ _spawn_kwarg_names = ("env", "opt_name", "fd_pipes",
+ "uid", "gid", "groups", "umask", "logfile",
+ "path_lookup", "pre_exec")
+
+ __slots__ = ("args",) + \
+ _spawn_kwarg_names + ("_selinux_type",)
+
+ _file_names = ("log", "process", "stdout")
+ _files_dict = slot_dict_class(_file_names, prefix="")
+
+ def _start(self):
+
+ if self.cancelled:
+ return
+
+ if self.fd_pipes is None:
+ self.fd_pipes = {}
+ fd_pipes = self.fd_pipes
+ fd_pipes.setdefault(0, sys.stdin.fileno())
+ fd_pipes.setdefault(1, sys.stdout.fileno())
+ fd_pipes.setdefault(2, sys.stderr.fileno())
+
+ # flush any pending output
+ for fd in fd_pipes.values():
+ if fd == sys.stdout.fileno():
+ sys.stdout.flush()
+ if fd == sys.stderr.fileno():
+ sys.stderr.flush()
+
+ self._files = self._files_dict()
+ files = self._files
+
+ master_fd, slave_fd = self._pipe(fd_pipes)
+ fcntl.fcntl(master_fd, fcntl.F_SETFL,
+ fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
+
+ logfile = None
+ if self._can_log(slave_fd):
+ logfile = self.logfile
+
+ null_input = None
+ fd_pipes_orig = fd_pipes.copy()
+ if self.background:
+ # TODO: Use job control functions like tcsetpgrp() to control
+ # access to stdin. Until then, use /dev/null so that any
+ # attempts to read from stdin will immediately return EOF
+ # instead of blocking indefinitely.
+ null_input = open('/dev/null', 'rb')
+ fd_pipes[0] = null_input.fileno()
+ else:
+ fd_pipes[0] = fd_pipes_orig[0]
+
+ # WARNING: It is very important to use unbuffered mode here,
+ # in order to avoid issue 5380 with python3.
+ files.process = os.fdopen(master_fd, 'rb', 0)
+ if logfile is not None:
+
+ fd_pipes[1] = slave_fd
+ fd_pipes[2] = slave_fd
+
+ files.log = open(_unicode_encode(logfile,
+ encoding=_encodings['fs'], errors='strict'), mode='ab')
+ if logfile.endswith('.gz'):
+ files.log = gzip.GzipFile(filename='', mode='ab',
+ fileobj=files.log)
+
+ portage.util.apply_secpass_permissions(logfile,
+ uid=portage.portage_uid, gid=portage.portage_gid,
+ mode=0o660)
+
+ if not self.background:
+ files.stdout = os.fdopen(os.dup(fd_pipes_orig[1]), 'wb')
+
+ output_handler = self._output_handler
+
+ else:
+
+ # Create a dummy pipe so the scheduler can monitor
+ # the process from inside a poll() loop.
+ fd_pipes[self._dummy_pipe_fd] = slave_fd
+ if self.background:
+ fd_pipes[1] = slave_fd
+ fd_pipes[2] = slave_fd
+ output_handler = self._dummy_handler
+
+ kwargs = {}
+ for k in self._spawn_kwarg_names:
+ v = getattr(self, k)
+ if v is not None:
+ kwargs[k] = v
+
+ kwargs["fd_pipes"] = fd_pipes
+ kwargs["returnpid"] = True
+ kwargs.pop("logfile", None)
+
+ self._reg_id = self.scheduler.register(files.process.fileno(),
+ self._registered_events, output_handler)
+ self._registered = True
+
+ retval = self._spawn(self.args, **kwargs)
+
+ os.close(slave_fd)
+ if null_input is not None:
+ null_input.close()
+
+ if isinstance(retval, int):
+ # spawn failed
+ self._unregister()
+ self._set_returncode((self.pid, retval))
+ self.wait()
+ return
+
+ self.pid = retval[0]
+ portage.process.spawned_pids.remove(self.pid)
+
+ def _can_log(self, slave_fd):
+ return True
+
+ def _pipe(self, fd_pipes):
+ """
+ @type fd_pipes: dict
+ @param fd_pipes: pipes from which to copy terminal size if desired.
+ """
+ return os.pipe()
+
+ def _spawn(self, args, **kwargs):
+ spawn_func = portage.process.spawn
+
+ if self._selinux_type is not None:
+ spawn_func = portage.selinux.spawn_wrapper(spawn_func,
+ self._selinux_type)
+ # bash is an allowed entrypoint, while most binaries are not
+ if args[0] != BASH_BINARY:
+ args = [BASH_BINARY, "-c", "exec \"$@\"", args[0]] + args
+
+ return spawn_func(args, **kwargs)
+
+ def _output_handler(self, fd, event):
+
+ files = self._files
+ buf = self._read_buf(files.process, event)
+
+ if buf is not None:
+
+ if buf:
+ if not self.background:
+ write_successful = False
+ failures = 0
+ while True:
+ try:
+ if not write_successful:
+ buf.tofile(files.stdout)
+ write_successful = True
+ files.stdout.flush()
+ break
+ except IOError as e:
+ if e.errno != errno.EAGAIN:
+ raise
+ del e
+ failures += 1
+ if failures > 50:
+ # Avoid a potentially infinite loop. In
+ # most cases, the failure count is zero
+ # and it's unlikely to exceed 1.
+ raise
+
+ # This means that a subprocess has put an inherited
+ # stdio file descriptor (typically stdin) into
+ # O_NONBLOCK mode. This is not acceptable (see bug
+ # #264435), so revert it. We need to use a loop
+ # here since there's a race condition due to
+ # parallel processes being able to change the
+ # flags on the inherited file descriptor.
+ # TODO: When possible, avoid having child processes
+ # inherit stdio file descriptors from portage
+ # (maybe it can't be avoided with
+ # PROPERTIES=interactive).
+ fcntl.fcntl(files.stdout.fileno(), fcntl.F_SETFL,
+ fcntl.fcntl(files.stdout.fileno(),
+ fcntl.F_GETFL) ^ os.O_NONBLOCK)
+
+ try:
+ buf.tofile(files.log)
+ except TypeError:
+ # array.tofile() doesn't work with GzipFile
+ files.log.write(buf.tostring())
+ files.log.flush()
+ else:
+ self._unregister()
+ self.wait()
+
+ self._unregister_if_appropriate(event)
+
+ def _dummy_handler(self, fd, event):
+ """
+ This method is mainly interested in detecting EOF, since
+ the only purpose of the pipe is to allow the scheduler to
+ monitor the process from inside a poll() loop.
+ """
+
+ buf = self._read_buf(self._files.process, event)
+
+ if buf is not None:
+
+ if buf:
+ pass
+ else:
+ self._unregister()
+ self.wait()
+
+ self._unregister_if_appropriate(event)
+
diff --git a/portage_with_autodep/pym/_emerge/SubProcess.py b/portage_with_autodep/pym/_emerge/SubProcess.py
new file mode 100644
index 0000000..b99cf0b
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/SubProcess.py
@@ -0,0 +1,141 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from _emerge.AbstractPollTask import AbstractPollTask
+import signal
+import errno
+
+class SubProcess(AbstractPollTask):
+
+ __slots__ = ("pid",) + \
+ ("_files", "_reg_id")
+
+ # A file descriptor is required for the scheduler to monitor changes from
+ # inside a poll() loop. When logging is not enabled, create a pipe just to
+ # serve this purpose alone.
+ _dummy_pipe_fd = 9
+
+ def _poll(self):
+ if self.returncode is not None:
+ return self.returncode
+ if self.pid is None:
+ return self.returncode
+ if self._registered:
+ return self.returncode
+
+ try:
+ # With waitpid and WNOHANG, only check the
+ # first element of the tuple since the second
+ # element may vary (bug #337465).
+ retval = os.waitpid(self.pid, os.WNOHANG)
+ except OSError as e:
+ if e.errno != errno.ECHILD:
+ raise
+ del e
+ retval = (self.pid, 1)
+
+ if retval[0] == 0:
+ return None
+ self._set_returncode(retval)
+ self.wait()
+ return self.returncode
+
+ def _cancel(self):
+ if self.isAlive():
+ try:
+ os.kill(self.pid, signal.SIGTERM)
+ except OSError as e:
+ if e.errno != errno.ESRCH:
+ raise
+
+ def isAlive(self):
+ return self.pid is not None and \
+ self.returncode is None
+
+ def _wait(self):
+
+ if self.returncode is not None:
+ return self.returncode
+
+ if self._registered:
+ if self.cancelled:
+ timeout = 1000
+ self.scheduler.schedule(self._reg_id, timeout=timeout)
+ if self._registered:
+ try:
+ os.kill(self.pid, signal.SIGKILL)
+ except OSError as e:
+ if e.errno != errno.ESRCH:
+ raise
+ del e
+ self.scheduler.schedule(self._reg_id, timeout=timeout)
+ if self._registered:
+ self._orphan_process_warn()
+ else:
+ self.scheduler.schedule(self._reg_id)
+ self._unregister()
+ if self.returncode is not None:
+ return self.returncode
+
+ try:
+ # With waitpid and WNOHANG, only check the
+ # first element of the tuple since the second
+ # element may vary (bug #337465).
+ wait_retval = os.waitpid(self.pid, os.WNOHANG)
+ except OSError as e:
+ if e.errno != errno.ECHILD:
+ raise
+ del e
+ self._set_returncode((self.pid, 1 << 8))
+ else:
+ if wait_retval[0] != 0:
+ self._set_returncode(wait_retval)
+ else:
+ try:
+ wait_retval = os.waitpid(self.pid, 0)
+ except OSError as e:
+ if e.errno != errno.ECHILD:
+ raise
+ del e
+ self._set_returncode((self.pid, 1 << 8))
+ else:
+ self._set_returncode(wait_retval)
+
+ return self.returncode
+
+ def _orphan_process_warn(self):
+ pass
+
+ def _unregister(self):
+ """
+ Unregister from the scheduler and close open files.
+ """
+
+ self._registered = False
+
+ if self._reg_id is not None:
+ self.scheduler.unregister(self._reg_id)
+ self._reg_id = None
+
+ if self._files is not None:
+ for f in self._files.values():
+ f.close()
+ self._files = None
+
+ def _set_returncode(self, wait_retval):
+ """
+ Set the returncode in a manner compatible with
+ subprocess.Popen.returncode: A negative value -N indicates
+ that the child was terminated by signal N (Unix only).
+ """
+
+ pid, status = wait_retval
+
+ if os.WIFSIGNALED(status):
+ retval = - os.WTERMSIG(status)
+ else:
+ retval = os.WEXITSTATUS(status)
+
+ self.returncode = retval
+
diff --git a/portage_with_autodep/pym/_emerge/Task.py b/portage_with_autodep/pym/_emerge/Task.py
new file mode 100644
index 0000000..efbe3a9
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/Task.py
@@ -0,0 +1,42 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.SlotObject import SlotObject
+class Task(SlotObject):
+ __slots__ = ("_hash_key", "_hash_value")
+
+ def __eq__(self, other):
+ try:
+ return self._hash_key == other._hash_key
+ except AttributeError:
+ # depgraph._pkg() generates _hash_key
+ # for lookups here, so handle that
+ return self._hash_key == other
+
+ def __ne__(self, other):
+ try:
+ return self._hash_key != other._hash_key
+ except AttributeError:
+ return True
+
+ def __hash__(self):
+ return self._hash_value
+
+ def __len__(self):
+ return len(self._hash_key)
+
+ def __getitem__(self, key):
+ return self._hash_key[key]
+
+ def __iter__(self):
+ return iter(self._hash_key)
+
+ def __contains__(self, key):
+ return key in self._hash_key
+
+ def __str__(self):
+ """
+ Emulate tuple.__repr__, but don't show 'foo' as u'foo' for unicode
+ strings.
+ """
+ return "(%s)" % ", ".join(("'%s'" % x for x in self._hash_key))
diff --git a/portage_with_autodep/pym/_emerge/TaskScheduler.py b/portage_with_autodep/pym/_emerge/TaskScheduler.py
new file mode 100644
index 0000000..83c0cbe
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/TaskScheduler.py
@@ -0,0 +1,25 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.QueueScheduler import QueueScheduler
+from _emerge.SequentialTaskQueue import SequentialTaskQueue
+
+class TaskScheduler(object):
+
+ """
+ A simple way to handle scheduling of AsynchrousTask instances. Simply
+ add tasks and call run(). The run() method returns when no tasks remain.
+ """
+
+ def __init__(self, max_jobs=None, max_load=None):
+ self._queue = SequentialTaskQueue(max_jobs=max_jobs)
+ self._scheduler = QueueScheduler(
+ max_jobs=max_jobs, max_load=max_load)
+ self.sched_iface = self._scheduler.sched_iface
+ self.run = self._scheduler.run
+ self.clear = self._scheduler.clear
+ self._scheduler.add(self._queue)
+
+ def add(self, task):
+ self._queue.add(task)
+
diff --git a/portage_with_autodep/pym/_emerge/TaskSequence.py b/portage_with_autodep/pym/_emerge/TaskSequence.py
new file mode 100644
index 0000000..1fecf63
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/TaskSequence.py
@@ -0,0 +1,44 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from _emerge.CompositeTask import CompositeTask
+from _emerge.AsynchronousTask import AsynchronousTask
+from collections import deque
+
+class TaskSequence(CompositeTask):
+ """
+ A collection of tasks that executes sequentially. Each task
+ must have a addExitListener() method that can be used as
+ a means to trigger movement from one task to the next.
+ """
+
+ __slots__ = ("_task_queue",)
+
+ def __init__(self, **kwargs):
+ AsynchronousTask.__init__(self, **kwargs)
+ self._task_queue = deque()
+
+ def add(self, task):
+ self._task_queue.append(task)
+
+ def _start(self):
+ self._start_next_task()
+
+ def _cancel(self):
+ self._task_queue.clear()
+ CompositeTask._cancel(self)
+
+ def _start_next_task(self):
+ self._start_task(self._task_queue.popleft(),
+ self._task_exit_handler)
+
+ def _task_exit_handler(self, task):
+ if self._default_exit(task) != os.EX_OK:
+ self.wait()
+ elif self._task_queue:
+ self._start_next_task()
+ else:
+ self._final_exit(task)
+ self.wait()
+
diff --git a/portage_with_autodep/pym/_emerge/UninstallFailure.py b/portage_with_autodep/pym/_emerge/UninstallFailure.py
new file mode 100644
index 0000000..e4f2834
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/UninstallFailure.py
@@ -0,0 +1,15 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import portage
+
+class UninstallFailure(portage.exception.PortageException):
+ """
+ An instance of this class is raised by unmerge() when
+ an uninstallation fails.
+ """
+ status = 1
+ def __init__(self, *pargs):
+ portage.exception.PortageException.__init__(self, pargs)
+ if pargs:
+ self.status = pargs[0]
diff --git a/portage_with_autodep/pym/_emerge/UnmergeDepPriority.py b/portage_with_autodep/pym/_emerge/UnmergeDepPriority.py
new file mode 100644
index 0000000..4316600
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/UnmergeDepPriority.py
@@ -0,0 +1,41 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.AbstractDepPriority import AbstractDepPriority
+class UnmergeDepPriority(AbstractDepPriority):
+ __slots__ = ("ignored", "optional", "satisfied",)
+ """
+ Combination of properties Priority Category
+
+ runtime 0 HARD
+ runtime_post -1 HARD
+ buildtime -2 SOFT
+ (none of the above) -2 SOFT
+ """
+
+ MAX = 0
+ SOFT = -2
+ MIN = -2
+
+ def __init__(self, **kwargs):
+ AbstractDepPriority.__init__(self, **kwargs)
+ if self.buildtime:
+ self.optional = True
+
+ def __int__(self):
+ if self.runtime:
+ return 0
+ if self.runtime_post:
+ return -1
+ if self.buildtime:
+ return -2
+ return -2
+
+ def __str__(self):
+ if self.ignored:
+ return "ignored"
+ myvalue = self.__int__()
+ if myvalue > self.SOFT:
+ return "hard"
+ return "soft"
+
diff --git a/portage_with_autodep/pym/_emerge/UseFlagDisplay.py b/portage_with_autodep/pym/_emerge/UseFlagDisplay.py
new file mode 100644
index 0000000..3daca19
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/UseFlagDisplay.py
@@ -0,0 +1,122 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from itertools import chain
+import sys
+
+from portage import _encodings, _unicode_decode, _unicode_encode
+from portage.output import red
+from portage.util import cmp_sort_key
+from portage.output import blue
+
+class UseFlagDisplay(object):
+
+ __slots__ = ('name', 'enabled', 'forced')
+
+ def __init__(self, name, enabled, forced):
+ self.name = name
+ self.enabled = enabled
+ self.forced = forced
+
+ def __str__(self):
+ s = self.name
+ if self.enabled:
+ s = red(s)
+ else:
+ s = '-' + s
+ s = blue(s)
+ if self.forced:
+ s = '(%s)' % s
+ return s
+
+ if sys.hexversion < 0x3000000:
+
+ __unicode__ = __str__
+
+ def __str__(self):
+ return _unicode_encode(self.__unicode__(),
+ encoding=_encodings['content'])
+
+ def _cmp_combined(a, b):
+ """
+ Sort by name, combining enabled and disabled flags.
+ """
+ return (a.name > b.name) - (a.name < b.name)
+
+ sort_combined = cmp_sort_key(_cmp_combined)
+ del _cmp_combined
+
+ def _cmp_separated(a, b):
+ """
+ Sort by name, separating enabled flags from disabled flags.
+ """
+ enabled_diff = b.enabled - a.enabled
+ if enabled_diff:
+ return enabled_diff
+ return (a.name > b.name) - (a.name < b.name)
+
+ sort_separated = cmp_sort_key(_cmp_separated)
+ del _cmp_separated
+
+def pkg_use_display(pkg, opts, modified_use=None):
+ settings = pkg.root_config.settings
+ use_expand = pkg.use.expand
+ use_expand_hidden = pkg.use.expand_hidden
+ alphabetical_use = '--alphabetical' in opts
+ forced_flags = set(chain(pkg.use.force,
+ pkg.use.mask))
+ if modified_use is None:
+ use = set(pkg.use.enabled)
+ else:
+ use = set(modified_use)
+ use.discard(settings.get('ARCH'))
+ use_expand_flags = set()
+ use_enabled = {}
+ use_disabled = {}
+ for varname in use_expand:
+ flag_prefix = varname.lower() + "_"
+ for f in use:
+ if f.startswith(flag_prefix):
+ use_expand_flags.add(f)
+ use_enabled.setdefault(
+ varname.upper(), []).append(f[len(flag_prefix):])
+
+ for f in pkg.iuse.all:
+ if f.startswith(flag_prefix):
+ use_expand_flags.add(f)
+ if f not in use:
+ use_disabled.setdefault(
+ varname.upper(), []).append(f[len(flag_prefix):])
+
+ var_order = set(use_enabled)
+ var_order.update(use_disabled)
+ var_order = sorted(var_order)
+ var_order.insert(0, 'USE')
+ use.difference_update(use_expand_flags)
+ use_enabled['USE'] = list(use)
+ use_disabled['USE'] = []
+
+ for f in pkg.iuse.all:
+ if f not in use and \
+ f not in use_expand_flags:
+ use_disabled['USE'].append(f)
+
+ flag_displays = []
+ for varname in var_order:
+ if varname.lower() in use_expand_hidden:
+ continue
+ flags = []
+ for f in use_enabled.get(varname, []):
+ flags.append(UseFlagDisplay(f, True, f in forced_flags))
+ for f in use_disabled.get(varname, []):
+ flags.append(UseFlagDisplay(f, False, f in forced_flags))
+ if alphabetical_use:
+ flags.sort(key=UseFlagDisplay.sort_combined)
+ else:
+ flags.sort(key=UseFlagDisplay.sort_separated)
+ # Use _unicode_decode() to force unicode format string so
+ # that UseFlagDisplay.__unicode__() is called in python2.
+ flag_displays.append('%s="%s"' % (varname,
+ ' '.join(_unicode_decode("%s") % (f,) for f in flags)))
+
+ return ' '.join(flag_displays)
diff --git a/portage_with_autodep/pym/_emerge/__init__.py b/portage_with_autodep/pym/_emerge/__init__.py
new file mode 100644
index 0000000..f98c564
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/_emerge/_find_deep_system_runtime_deps.py b/portage_with_autodep/pym/_emerge/_find_deep_system_runtime_deps.py
new file mode 100644
index 0000000..ca09d83
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/_find_deep_system_runtime_deps.py
@@ -0,0 +1,38 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from _emerge.DepPriority import DepPriority
+from _emerge.Package import Package
+
+def _find_deep_system_runtime_deps(graph):
+ deep_system_deps = set()
+ node_stack = []
+ for node in graph:
+ if not isinstance(node, Package) or \
+ node.operation == 'uninstall':
+ continue
+ if node.root_config.sets['system'].findAtomForPackage(node):
+ node_stack.append(node)
+
+ def ignore_priority(priority):
+ """
+ Ignore non-runtime priorities.
+ """
+ if isinstance(priority, DepPriority) and \
+ (priority.runtime or priority.runtime_post):
+ return False
+ return True
+
+ while node_stack:
+ node = node_stack.pop()
+ if node in deep_system_deps:
+ continue
+ deep_system_deps.add(node)
+ for child in graph.child_nodes(node, ignore_priority=ignore_priority):
+ if not isinstance(child, Package) or \
+ child.operation == 'uninstall':
+ continue
+ node_stack.append(child)
+
+ return deep_system_deps
+
diff --git a/portage_with_autodep/pym/_emerge/_flush_elog_mod_echo.py b/portage_with_autodep/pym/_emerge/_flush_elog_mod_echo.py
new file mode 100644
index 0000000..eab4168
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/_flush_elog_mod_echo.py
@@ -0,0 +1,15 @@
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.elog import mod_echo
+
+def _flush_elog_mod_echo():
+ """
+ Dump the mod_echo output now so that our other
+ notifications are shown last.
+ @rtype: bool
+ @returns: True if messages were shown, False otherwise.
+ """
+ messages_shown = bool(mod_echo._items)
+ mod_echo.finalize()
+ return messages_shown
diff --git a/portage_with_autodep/pym/_emerge/actions.py b/portage_with_autodep/pym/_emerge/actions.py
new file mode 100644
index 0000000..2166963
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/actions.py
@@ -0,0 +1,3123 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import errno
+import logging
+import platform
+import pwd
+import random
+import re
+import shutil
+import signal
+import socket
+import stat
+import sys
+import tempfile
+import textwrap
+import time
+from itertools import chain
+
+import portage
+from portage import os
+from portage import subprocess_getstatusoutput
+from portage import _unicode_decode
+from portage.cache.cache_errors import CacheError
+from portage.const import GLOBAL_CONFIG_PATH, NEWS_LIB_PATH
+from portage.const import _ENABLE_DYN_LINK_MAP, _ENABLE_SET_CONFIG
+from portage.dbapi.dep_expand import dep_expand
+from portage.dbapi._expand_new_virt import expand_new_virt
+from portage.dep import Atom, extended_cp_match
+from portage.exception import InvalidAtom
+from portage.output import blue, bold, colorize, create_color_func, darkgreen, \
+ red, yellow
+good = create_color_func("GOOD")
+bad = create_color_func("BAD")
+from portage.package.ebuild._ipc.QueryCommand import QueryCommand
+from portage.package.ebuild.doebuild import _check_temp_dir
+from portage._sets import load_default_config, SETPREFIX
+from portage._sets.base import InternalPackageSet
+from portage.util import cmp_sort_key, writemsg, \
+ writemsg_level, writemsg_stdout
+from portage.util.digraph import digraph
+from portage._global_updates import _global_updates
+
+from _emerge.clear_caches import clear_caches
+from _emerge.countdown import countdown
+from _emerge.create_depgraph_params import create_depgraph_params
+from _emerge.Dependency import Dependency
+from _emerge.depgraph import backtrack_depgraph, depgraph, resume_depgraph
+from _emerge.DepPrioritySatisfiedRange import DepPrioritySatisfiedRange
+from _emerge.emergelog import emergelog
+from _emerge.is_valid_package_atom import is_valid_package_atom
+from _emerge.MetadataRegen import MetadataRegen
+from _emerge.Package import Package
+from _emerge.ProgressHandler import ProgressHandler
+from _emerge.RootConfig import RootConfig
+from _emerge.Scheduler import Scheduler
+from _emerge.search import search
+from _emerge.SetArg import SetArg
+from _emerge.show_invalid_depstring_notice import show_invalid_depstring_notice
+from _emerge.sync.getaddrinfo_validate import getaddrinfo_validate
+from _emerge.sync.old_tree_timestamp import old_tree_timestamp_warn
+from _emerge.unmerge import unmerge
+from _emerge.UnmergeDepPriority import UnmergeDepPriority
+from _emerge.UseFlagDisplay import pkg_use_display
+from _emerge.userquery import userquery
+
+if sys.hexversion >= 0x3000000:
+ long = int
+
+def action_build(settings, trees, mtimedb,
+ myopts, myaction, myfiles, spinner):
+
+ if '--usepkgonly' not in myopts:
+ old_tree_timestamp_warn(settings['PORTDIR'], settings)
+
+ # It's best for config updates in /etc/portage to be processed
+ # before we get here, so warn if they're not (bug #267103).
+ chk_updated_cfg_files(settings['EROOT'], ['/etc/portage'])
+
+ # validate the state of the resume data
+ # so that we can make assumptions later.
+ for k in ("resume", "resume_backup"):
+ if k not in mtimedb:
+ continue
+ resume_data = mtimedb[k]
+ if not isinstance(resume_data, dict):
+ del mtimedb[k]
+ continue
+ mergelist = resume_data.get("mergelist")
+ if not isinstance(mergelist, list):
+ del mtimedb[k]
+ continue
+ for x in mergelist:
+ if not (isinstance(x, list) and len(x) == 4):
+ continue
+ pkg_type, pkg_root, pkg_key, pkg_action = x
+ if pkg_root not in trees:
+ # Current $ROOT setting differs,
+ # so the list must be stale.
+ mergelist = None
+ break
+ if not mergelist:
+ del mtimedb[k]
+ continue
+ resume_opts = resume_data.get("myopts")
+ if not isinstance(resume_opts, (dict, list)):
+ del mtimedb[k]
+ continue
+ favorites = resume_data.get("favorites")
+ if not isinstance(favorites, list):
+ del mtimedb[k]
+ continue
+
+ resume = False
+ if "--resume" in myopts and \
+ ("resume" in mtimedb or
+ "resume_backup" in mtimedb):
+ resume = True
+ if "resume" not in mtimedb:
+ mtimedb["resume"] = mtimedb["resume_backup"]
+ del mtimedb["resume_backup"]
+ mtimedb.commit()
+ # "myopts" is a list for backward compatibility.
+ resume_opts = mtimedb["resume"].get("myopts", [])
+ if isinstance(resume_opts, list):
+ resume_opts = dict((k,True) for k in resume_opts)
+ for opt in ("--ask", "--color", "--skipfirst", "--tree"):
+ resume_opts.pop(opt, None)
+
+ # Current options always override resume_opts.
+ resume_opts.update(myopts)
+ myopts.clear()
+ myopts.update(resume_opts)
+
+ if "--debug" in myopts:
+ writemsg_level("myopts %s\n" % (myopts,))
+
+ # Adjust config according to options of the command being resumed.
+ for myroot in trees:
+ mysettings = trees[myroot]["vartree"].settings
+ mysettings.unlock()
+ adjust_config(myopts, mysettings)
+ mysettings.lock()
+ del myroot, mysettings
+
+ ldpath_mtimes = mtimedb["ldpath"]
+ favorites=[]
+ buildpkgonly = "--buildpkgonly" in myopts
+ pretend = "--pretend" in myopts
+ fetchonly = "--fetchonly" in myopts or "--fetch-all-uri" in myopts
+ ask = "--ask" in myopts
+ enter_invalid = '--ask-enter-invalid' in myopts
+ nodeps = "--nodeps" in myopts
+ oneshot = "--oneshot" in myopts or "--onlydeps" in myopts
+ tree = "--tree" in myopts
+ if nodeps and tree:
+ tree = False
+ del myopts["--tree"]
+ portage.writemsg(colorize("WARN", " * ") + \
+ "--tree is broken with --nodeps. Disabling...\n")
+ debug = "--debug" in myopts
+ verbose = "--verbose" in myopts
+ quiet = "--quiet" in myopts
+ myparams = create_depgraph_params(myopts, myaction)
+
+ if pretend or fetchonly:
+ # make the mtimedb readonly
+ mtimedb.filename = None
+ if '--digest' in myopts or 'digest' in settings.features:
+ if '--digest' in myopts:
+ msg = "The --digest option"
+ else:
+ msg = "The FEATURES=digest setting"
+
+ msg += " can prevent corruption from being" + \
+ " noticed. The `repoman manifest` command is the preferred" + \
+ " way to generate manifests and it is capable of doing an" + \
+ " entire repository or category at once."
+ prefix = bad(" * ")
+ writemsg(prefix + "\n")
+ from textwrap import wrap
+ for line in wrap(msg, 72):
+ writemsg("%s%s\n" % (prefix, line))
+ writemsg(prefix + "\n")
+
+ if resume:
+ favorites = mtimedb["resume"].get("favorites")
+ if not isinstance(favorites, list):
+ favorites = []
+
+ resume_data = mtimedb["resume"]
+ mergelist = resume_data["mergelist"]
+ if mergelist and "--skipfirst" in myopts:
+ for i, task in enumerate(mergelist):
+ if isinstance(task, list) and \
+ task and task[-1] == "merge":
+ del mergelist[i]
+ break
+
+ success = False
+ mydepgraph = None
+ try:
+ success, mydepgraph, dropped_tasks = resume_depgraph(
+ settings, trees, mtimedb, myopts, myparams, spinner)
+ except (portage.exception.PackageNotFound,
+ depgraph.UnsatisfiedResumeDep) as e:
+ if isinstance(e, depgraph.UnsatisfiedResumeDep):
+ mydepgraph = e.depgraph
+
+ from textwrap import wrap
+ from portage.output import EOutput
+ out = EOutput()
+
+ resume_data = mtimedb["resume"]
+ mergelist = resume_data.get("mergelist")
+ if not isinstance(mergelist, list):
+ mergelist = []
+ if mergelist and debug or (verbose and not quiet):
+ out.eerror("Invalid resume list:")
+ out.eerror("")
+ indent = " "
+ for task in mergelist:
+ if isinstance(task, list):
+ out.eerror(indent + str(tuple(task)))
+ out.eerror("")
+
+ if isinstance(e, depgraph.UnsatisfiedResumeDep):
+ out.eerror("One or more packages are either masked or " + \
+ "have missing dependencies:")
+ out.eerror("")
+ indent = " "
+ for dep in e.value:
+ if dep.atom is None:
+ out.eerror(indent + "Masked package:")
+ out.eerror(2 * indent + str(dep.parent))
+ out.eerror("")
+ else:
+ out.eerror(indent + str(dep.atom) + " pulled in by:")
+ out.eerror(2 * indent + str(dep.parent))
+ out.eerror("")
+ msg = "The resume list contains packages " + \
+ "that are either masked or have " + \
+ "unsatisfied dependencies. " + \
+ "Please restart/continue " + \
+ "the operation manually, or use --skipfirst " + \
+ "to skip the first package in the list and " + \
+ "any other packages that may be " + \
+ "masked or have missing dependencies."
+ for line in wrap(msg, 72):
+ out.eerror(line)
+ elif isinstance(e, portage.exception.PackageNotFound):
+ out.eerror("An expected package is " + \
+ "not available: %s" % str(e))
+ out.eerror("")
+ msg = "The resume list contains one or more " + \
+ "packages that are no longer " + \
+ "available. Please restart/continue " + \
+ "the operation manually."
+ for line in wrap(msg, 72):
+ out.eerror(line)
+
+ if success:
+ if dropped_tasks:
+ portage.writemsg("!!! One or more packages have been " + \
+ "dropped due to\n" + \
+ "!!! masking or unsatisfied dependencies:\n\n",
+ noiselevel=-1)
+ for task in dropped_tasks:
+ portage.writemsg(" " + str(task) + "\n", noiselevel=-1)
+ portage.writemsg("\n", noiselevel=-1)
+ del dropped_tasks
+ else:
+ if mydepgraph is not None:
+ mydepgraph.display_problems()
+ if not (ask or pretend):
+ # delete the current list and also the backup
+ # since it's probably stale too.
+ for k in ("resume", "resume_backup"):
+ mtimedb.pop(k, None)
+ mtimedb.commit()
+
+ return 1
+ else:
+ if ("--resume" in myopts):
+ print(darkgreen("emerge: It seems we have nothing to resume..."))
+ return os.EX_OK
+
+ try:
+ success, mydepgraph, favorites = backtrack_depgraph(
+ settings, trees, myopts, myparams, myaction, myfiles, spinner)
+ except portage.exception.PackageSetNotFound as e:
+ root_config = trees[settings["ROOT"]]["root_config"]
+ display_missing_pkg_set(root_config, e.value)
+ return 1
+
+ if not success:
+ mydepgraph.display_problems()
+ return 1
+
+ if "--pretend" not in myopts and \
+ ("--ask" in myopts or "--tree" in myopts or \
+ "--verbose" in myopts) and \
+ not ("--quiet" in myopts and "--ask" not in myopts):
+ if "--resume" in myopts:
+ mymergelist = mydepgraph.altlist()
+ if len(mymergelist) == 0:
+ print(colorize("INFORM", "emerge: It seems we have nothing to resume..."))
+ return os.EX_OK
+ favorites = mtimedb["resume"]["favorites"]
+ retval = mydepgraph.display(
+ mydepgraph.altlist(reversed=tree),
+ favorites=favorites)
+ mydepgraph.display_problems()
+ if retval != os.EX_OK:
+ return retval
+ prompt="Would you like to resume merging these packages?"
+ else:
+ retval = mydepgraph.display(
+ mydepgraph.altlist(reversed=("--tree" in myopts)),
+ favorites=favorites)
+ mydepgraph.display_problems()
+ if retval != os.EX_OK:
+ return retval
+ mergecount=0
+ for x in mydepgraph.altlist():
+ if isinstance(x, Package) and x.operation == "merge":
+ mergecount += 1
+
+ if mergecount==0:
+ sets = trees[settings["ROOT"]]["root_config"].sets
+ world_candidates = None
+ if "selective" in myparams and \
+ not oneshot and favorites:
+ # Sets that are not world candidates are filtered
+ # out here since the favorites list needs to be
+ # complete for depgraph.loadResumeCommand() to
+ # operate correctly.
+ world_candidates = [x for x in favorites \
+ if not (x.startswith(SETPREFIX) and \
+ not sets[x[1:]].world_candidate)]
+ if "selective" in myparams and \
+ not oneshot and world_candidates:
+ print()
+ for x in world_candidates:
+ print(" %s %s" % (good("*"), x))
+ prompt="Would you like to add these packages to your world favorites?"
+ elif settings["AUTOCLEAN"] and "yes"==settings["AUTOCLEAN"]:
+ prompt="Nothing to merge; would you like to auto-clean packages?"
+ else:
+ print()
+ print("Nothing to merge; quitting.")
+ print()
+ return os.EX_OK
+ elif "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
+ prompt="Would you like to fetch the source files for these packages?"
+ else:
+ prompt="Would you like to merge these packages?"
+ print()
+ if "--ask" in myopts and userquery(prompt, enter_invalid) == "No":
+ print()
+ print("Quitting.")
+ print()
+ return os.EX_OK
+ # Don't ask again (e.g. when auto-cleaning packages after merge)
+ myopts.pop("--ask", None)
+
+ if ("--pretend" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts):
+ if ("--resume" in myopts):
+ mymergelist = mydepgraph.altlist()
+ if len(mymergelist) == 0:
+ print(colorize("INFORM", "emerge: It seems we have nothing to resume..."))
+ return os.EX_OK
+ favorites = mtimedb["resume"]["favorites"]
+ retval = mydepgraph.display(
+ mydepgraph.altlist(reversed=tree),
+ favorites=favorites)
+ mydepgraph.display_problems()
+ if retval != os.EX_OK:
+ return retval
+ else:
+ retval = mydepgraph.display(
+ mydepgraph.altlist(reversed=("--tree" in myopts)),
+ favorites=favorites)
+ mydepgraph.display_problems()
+ if retval != os.EX_OK:
+ return retval
+ if "--buildpkgonly" in myopts:
+ graph_copy = mydepgraph._dynamic_config.digraph.copy()
+ removed_nodes = set()
+ for node in graph_copy:
+ if not isinstance(node, Package) or \
+ node.operation == "nomerge":
+ removed_nodes.add(node)
+ graph_copy.difference_update(removed_nodes)
+ if not graph_copy.hasallzeros(ignore_priority = \
+ DepPrioritySatisfiedRange.ignore_medium):
+ print("\n!!! --buildpkgonly requires all dependencies to be merged.")
+ print("!!! You have to merge the dependencies before you can build this package.\n")
+ return 1
+ else:
+ if "--buildpkgonly" in myopts:
+ graph_copy = mydepgraph._dynamic_config.digraph.copy()
+ removed_nodes = set()
+ for node in graph_copy:
+ if not isinstance(node, Package) or \
+ node.operation == "nomerge":
+ removed_nodes.add(node)
+ graph_copy.difference_update(removed_nodes)
+ if not graph_copy.hasallzeros(ignore_priority = \
+ DepPrioritySatisfiedRange.ignore_medium):
+ print("\n!!! --buildpkgonly requires all dependencies to be merged.")
+ print("!!! Cannot merge requested packages. Merge deps and try again.\n")
+ return 1
+
+ if ("--resume" in myopts):
+ favorites=mtimedb["resume"]["favorites"]
+
+ else:
+ if "resume" in mtimedb and \
+ "mergelist" in mtimedb["resume"] and \
+ len(mtimedb["resume"]["mergelist"]) > 1:
+ mtimedb["resume_backup"] = mtimedb["resume"]
+ del mtimedb["resume"]
+ mtimedb.commit()
+
+ mydepgraph.saveNomergeFavorites()
+
+ mergetask = Scheduler(settings, trees, mtimedb, myopts,
+ spinner, favorites=favorites,
+ graph_config=mydepgraph.schedulerGraph())
+
+ del mydepgraph
+ clear_caches(trees)
+
+ retval = mergetask.merge()
+
+ if retval == os.EX_OK and not (buildpkgonly or fetchonly or pretend):
+ if "yes" == settings.get("AUTOCLEAN"):
+ portage.writemsg_stdout(">>> Auto-cleaning packages...\n")
+ unmerge(trees[settings["ROOT"]]["root_config"],
+ myopts, "clean", [],
+ ldpath_mtimes, autoclean=1)
+ else:
+ portage.writemsg_stdout(colorize("WARN", "WARNING:")
+ + " AUTOCLEAN is disabled. This can cause serious"
+ + " problems due to overlapping packages.\n")
+
+ return retval
+
+def action_config(settings, trees, myopts, myfiles):
+ enter_invalid = '--ask-enter-invalid' in myopts
+ if len(myfiles) != 1:
+ print(red("!!! config can only take a single package atom at this time\n"))
+ sys.exit(1)
+ if not is_valid_package_atom(myfiles[0]):
+ portage.writemsg("!!! '%s' is not a valid package atom.\n" % myfiles[0],
+ noiselevel=-1)
+ portage.writemsg("!!! Please check ebuild(5) for full details.\n")
+ portage.writemsg("!!! (Did you specify a version but forget to prefix with '='?)\n")
+ sys.exit(1)
+ print()
+ try:
+ pkgs = trees[settings["ROOT"]]["vartree"].dbapi.match(myfiles[0])
+ except portage.exception.AmbiguousPackageName as e:
+ # Multiple matches thrown from cpv_expand
+ pkgs = e.args[0]
+ if len(pkgs) == 0:
+ print("No packages found.\n")
+ sys.exit(0)
+ elif len(pkgs) > 1:
+ if "--ask" in myopts:
+ options = []
+ print("Please select a package to configure:")
+ idx = 0
+ for pkg in pkgs:
+ idx += 1
+ options.append(str(idx))
+ print(options[-1]+") "+pkg)
+ print("X) Cancel")
+ options.append("X")
+ idx = userquery("Selection?", enter_invalid, responses=options)
+ if idx == "X":
+ sys.exit(0)
+ pkg = pkgs[int(idx)-1]
+ else:
+ print("The following packages available:")
+ for pkg in pkgs:
+ print("* "+pkg)
+ print("\nPlease use a specific atom or the --ask option.")
+ sys.exit(1)
+ else:
+ pkg = pkgs[0]
+
+ print()
+ if "--ask" in myopts:
+ if userquery("Ready to configure %s?" % pkg, enter_invalid) == "No":
+ sys.exit(0)
+ else:
+ print("Configuring pkg...")
+ print()
+ ebuildpath = trees[settings["ROOT"]]["vartree"].dbapi.findname(pkg)
+ mysettings = portage.config(clone=settings)
+ vardb = trees[mysettings["ROOT"]]["vartree"].dbapi
+ debug = mysettings.get("PORTAGE_DEBUG") == "1"
+ retval = portage.doebuild(ebuildpath, "config", mysettings["ROOT"],
+ mysettings,
+ debug=(settings.get("PORTAGE_DEBUG", "") == 1), cleanup=True,
+ mydbapi=trees[settings["ROOT"]]["vartree"].dbapi, tree="vartree")
+ if retval == os.EX_OK:
+ portage.doebuild(ebuildpath, "clean", mysettings["ROOT"],
+ mysettings, debug=debug, mydbapi=vardb, tree="vartree")
+ print()
+
+def action_depclean(settings, trees, ldpath_mtimes,
+ myopts, action, myfiles, spinner, scheduler=None):
+ # Kill packages that aren't explicitly merged or are required as a
+ # dependency of another package. World file is explicit.
+
+ # Global depclean or prune operations are not very safe when there are
+ # missing dependencies since it's unknown how badly incomplete
+ # the dependency graph is, and we might accidentally remove packages
+ # that should have been pulled into the graph. On the other hand, it's
+ # relatively safe to ignore missing deps when only asked to remove
+ # specific packages.
+
+ msg = []
+ if not _ENABLE_DYN_LINK_MAP:
+ msg.append("Depclean may break link level dependencies. Thus, it is\n")
+ msg.append("recommended to use a tool such as " + good("`revdep-rebuild`") + " (from\n")
+ msg.append("app-portage/gentoolkit) in order to detect such breakage.\n")
+ msg.append("\n")
+ msg.append("Always study the list of packages to be cleaned for any obvious\n")
+ msg.append("mistakes. Packages that are part of the world set will always\n")
+ msg.append("be kept. They can be manually added to this set with\n")
+ msg.append(good("`emerge --noreplace <atom>`") + ". Packages that are listed in\n")
+ msg.append("package.provided (see portage(5)) will be removed by\n")
+ msg.append("depclean, even if they are part of the world set.\n")
+ msg.append("\n")
+ msg.append("As a safety measure, depclean will not remove any packages\n")
+ msg.append("unless *all* required dependencies have been resolved. As a\n")
+ msg.append("consequence, it is often necessary to run %s\n" % \
+ good("`emerge --update"))
+ msg.append(good("--newuse --deep @world`") + \
+ " prior to depclean.\n")
+
+ if action == "depclean" and "--quiet" not in myopts and not myfiles:
+ portage.writemsg_stdout("\n")
+ for x in msg:
+ portage.writemsg_stdout(colorize("WARN", " * ") + x)
+
+ root_config = trees[settings['ROOT']]['root_config']
+ vardb = root_config.trees['vartree'].dbapi
+
+ args_set = InternalPackageSet(allow_repo=True)
+ if myfiles:
+ args_set.update(myfiles)
+ matched_packages = False
+ for x in args_set:
+ if vardb.match(x):
+ matched_packages = True
+ else:
+ writemsg_level("--- Couldn't find '%s' to %s.\n" % \
+ (x.replace("null/", ""), action),
+ level=logging.WARN, noiselevel=-1)
+ if not matched_packages:
+ writemsg_level(">>> No packages selected for removal by %s\n" % \
+ action)
+ return 0
+
+ # The calculation is done in a separate function so that depgraph
+ # references go out of scope and the corresponding memory
+ # is freed before we call unmerge().
+ rval, cleanlist, ordered, req_pkg_count = \
+ calc_depclean(settings, trees, ldpath_mtimes,
+ myopts, action, args_set, spinner)
+
+ clear_caches(trees)
+
+ if rval != os.EX_OK:
+ return rval
+
+ if cleanlist:
+ unmerge(root_config, myopts, "unmerge",
+ cleanlist, ldpath_mtimes, ordered=ordered,
+ scheduler=scheduler)
+
+ if action == "prune":
+ return
+
+ if not cleanlist and "--quiet" in myopts:
+ return
+
+ print("Packages installed: " + str(len(vardb.cpv_all())))
+ print("Packages in world: " + \
+ str(len(root_config.sets["selected"].getAtoms())))
+ print("Packages in system: " + \
+ str(len(root_config.sets["system"].getAtoms())))
+ print("Required packages: "+str(req_pkg_count))
+ if "--pretend" in myopts:
+ print("Number to remove: "+str(len(cleanlist)))
+ else:
+ print("Number removed: "+str(len(cleanlist)))
+
+def calc_depclean(settings, trees, ldpath_mtimes,
+ myopts, action, args_set, spinner):
+ allow_missing_deps = bool(args_set)
+
+ debug = '--debug' in myopts
+ xterm_titles = "notitles" not in settings.features
+ myroot = settings["ROOT"]
+ root_config = trees[myroot]["root_config"]
+ psets = root_config.setconfig.psets
+ deselect = myopts.get('--deselect') != 'n'
+ required_sets = {}
+ required_sets['world'] = psets['world']
+
+ # When removing packages, a temporary version of the world 'selected'
+ # set may be used which excludes packages that are intended to be
+ # eligible for removal.
+ selected_set = psets['selected']
+ required_sets['selected'] = selected_set
+ protected_set = InternalPackageSet()
+ protected_set_name = '____depclean_protected_set____'
+ required_sets[protected_set_name] = protected_set
+ system_set = psets["system"]
+
+ if not system_set or not selected_set:
+
+ if not system_set:
+ writemsg_level("!!! You have no system list.\n",
+ level=logging.ERROR, noiselevel=-1)
+
+ if not selected_set:
+ writemsg_level("!!! You have no world file.\n",
+ level=logging.WARNING, noiselevel=-1)
+
+ writemsg_level("!!! Proceeding is likely to " + \
+ "break your installation.\n",
+ level=logging.WARNING, noiselevel=-1)
+ if "--pretend" not in myopts:
+ countdown(int(settings["EMERGE_WARNING_DELAY"]), ">>> Depclean")
+
+ if action == "depclean":
+ emergelog(xterm_titles, " >>> depclean")
+
+ writemsg_level("\nCalculating dependencies ")
+ resolver_params = create_depgraph_params(myopts, "remove")
+ resolver = depgraph(settings, trees, myopts, resolver_params, spinner)
+ resolver._load_vdb()
+ vardb = resolver._frozen_config.trees[myroot]["vartree"].dbapi
+ real_vardb = trees[myroot]["vartree"].dbapi
+
+ if action == "depclean":
+
+ if args_set:
+
+ if deselect:
+ # Start with an empty set.
+ selected_set = InternalPackageSet()
+ required_sets['selected'] = selected_set
+ # Pull in any sets nested within the selected set.
+ selected_set.update(psets['selected'].getNonAtoms())
+
+ # Pull in everything that's installed but not matched
+ # by an argument atom since we don't want to clean any
+ # package if something depends on it.
+ for pkg in vardb:
+ if spinner:
+ spinner.update()
+
+ try:
+ if args_set.findAtomForPackage(pkg) is None:
+ protected_set.add("=" + pkg.cpv)
+ continue
+ except portage.exception.InvalidDependString as e:
+ show_invalid_depstring_notice(pkg,
+ pkg.metadata["PROVIDE"], str(e))
+ del e
+ protected_set.add("=" + pkg.cpv)
+ continue
+
+ elif action == "prune":
+
+ if deselect:
+ # Start with an empty set.
+ selected_set = InternalPackageSet()
+ required_sets['selected'] = selected_set
+ # Pull in any sets nested within the selected set.
+ selected_set.update(psets['selected'].getNonAtoms())
+
+ # Pull in everything that's installed since we don't
+ # to prune a package if something depends on it.
+ protected_set.update(vardb.cp_all())
+
+ if not args_set:
+
+ # Try to prune everything that's slotted.
+ for cp in vardb.cp_all():
+ if len(vardb.cp_list(cp)) > 1:
+ args_set.add(cp)
+
+ # Remove atoms from world that match installed packages
+ # that are also matched by argument atoms, but do not remove
+ # them if they match the highest installed version.
+ for pkg in vardb:
+ spinner.update()
+ pkgs_for_cp = vardb.match_pkgs(pkg.cp)
+ if not pkgs_for_cp or pkg not in pkgs_for_cp:
+ raise AssertionError("package expected in matches: " + \
+ "cp = %s, cpv = %s matches = %s" % \
+ (pkg.cp, pkg.cpv, [str(x) for x in pkgs_for_cp]))
+
+ highest_version = pkgs_for_cp[-1]
+ if pkg == highest_version:
+ # pkg is the highest version
+ protected_set.add("=" + pkg.cpv)
+ continue
+
+ if len(pkgs_for_cp) <= 1:
+ raise AssertionError("more packages expected: " + \
+ "cp = %s, cpv = %s matches = %s" % \
+ (pkg.cp, pkg.cpv, [str(x) for x in pkgs_for_cp]))
+
+ try:
+ if args_set.findAtomForPackage(pkg) is None:
+ protected_set.add("=" + pkg.cpv)
+ continue
+ except portage.exception.InvalidDependString as e:
+ show_invalid_depstring_notice(pkg,
+ pkg.metadata["PROVIDE"], str(e))
+ del e
+ protected_set.add("=" + pkg.cpv)
+ continue
+
+ if resolver._frozen_config.excluded_pkgs:
+ excluded_set = resolver._frozen_config.excluded_pkgs
+ required_sets['__excluded__'] = InternalPackageSet()
+
+ for pkg in vardb:
+ if spinner:
+ spinner.update()
+
+ try:
+ if excluded_set.findAtomForPackage(pkg):
+ required_sets['__excluded__'].add("=" + pkg.cpv)
+ except portage.exception.InvalidDependString as e:
+ show_invalid_depstring_notice(pkg,
+ pkg.metadata["PROVIDE"], str(e))
+ del e
+ required_sets['__excluded__'].add("=" + pkg.cpv)
+
+ success = resolver._complete_graph(required_sets={myroot:required_sets})
+ writemsg_level("\b\b... done!\n")
+
+ resolver.display_problems()
+
+ if not success:
+ return 1, [], False, 0
+
+ def unresolved_deps():
+
+ unresolvable = set()
+ for dep in resolver._dynamic_config._initially_unsatisfied_deps:
+ if isinstance(dep.parent, Package) and \
+ (dep.priority > UnmergeDepPriority.SOFT):
+ unresolvable.add((dep.atom, dep.parent.cpv))
+
+ if not unresolvable:
+ return False
+
+ if unresolvable and not allow_missing_deps:
+
+ if "--debug" in myopts:
+ writemsg("\ndigraph:\n\n", noiselevel=-1)
+ resolver._dynamic_config.digraph.debug_print()
+ writemsg("\n", noiselevel=-1)
+
+ prefix = bad(" * ")
+ msg = []
+ msg.append("Dependencies could not be completely resolved due to")
+ msg.append("the following required packages not being installed:")
+ msg.append("")
+ for atom, parent in unresolvable:
+ msg.append(" %s pulled in by:" % (atom,))
+ msg.append(" %s" % (parent,))
+ msg.append("")
+ msg.extend(textwrap.wrap(
+ "Have you forgotten to do a complete update prior " + \
+ "to depclean? The most comprehensive command for this " + \
+ "purpose is as follows:", 65
+ ))
+ msg.append("")
+ msg.append(" " + \
+ good("emerge --update --newuse --deep --with-bdeps=y @world"))
+ msg.append("")
+ msg.extend(textwrap.wrap(
+ "Note that the --with-bdeps=y option is not required in " + \
+ "many situations. Refer to the emerge manual page " + \
+ "(run `man emerge`) for more information about " + \
+ "--with-bdeps.", 65
+ ))
+ msg.append("")
+ msg.extend(textwrap.wrap(
+ "Also, note that it may be necessary to manually uninstall " + \
+ "packages that no longer exist in the portage tree, since " + \
+ "it may not be possible to satisfy their dependencies.", 65
+ ))
+ if action == "prune":
+ msg.append("")
+ msg.append("If you would like to ignore " + \
+ "dependencies then use %s." % good("--nodeps"))
+ writemsg_level("".join("%s%s\n" % (prefix, line) for line in msg),
+ level=logging.ERROR, noiselevel=-1)
+ return True
+ return False
+
+ if unresolved_deps():
+ return 1, [], False, 0
+
+ graph = resolver._dynamic_config.digraph.copy()
+ required_pkgs_total = 0
+ for node in graph:
+ if isinstance(node, Package):
+ required_pkgs_total += 1
+
+ def show_parents(child_node):
+ parent_nodes = graph.parent_nodes(child_node)
+ if not parent_nodes:
+ # With --prune, the highest version can be pulled in without any
+ # real parent since all installed packages are pulled in. In that
+ # case there's nothing to show here.
+ return
+ parent_strs = []
+ for node in parent_nodes:
+ parent_strs.append(str(getattr(node, "cpv", node)))
+ parent_strs.sort()
+ msg = []
+ msg.append(" %s pulled in by:\n" % (child_node.cpv,))
+ for parent_str in parent_strs:
+ msg.append(" %s\n" % (parent_str,))
+ msg.append("\n")
+ portage.writemsg_stdout("".join(msg), noiselevel=-1)
+
+ def cmp_pkg_cpv(pkg1, pkg2):
+ """Sort Package instances by cpv."""
+ if pkg1.cpv > pkg2.cpv:
+ return 1
+ elif pkg1.cpv == pkg2.cpv:
+ return 0
+ else:
+ return -1
+
+ def create_cleanlist():
+
+ if "--debug" in myopts:
+ writemsg("\ndigraph:\n\n", noiselevel=-1)
+ graph.debug_print()
+ writemsg("\n", noiselevel=-1)
+
+ # Never display the special internal protected_set.
+ for node in graph:
+ if isinstance(node, SetArg) and node.name == protected_set_name:
+ graph.remove(node)
+ break
+
+ pkgs_to_remove = []
+
+ if action == "depclean":
+ if args_set:
+
+ for pkg in sorted(vardb, key=cmp_sort_key(cmp_pkg_cpv)):
+ arg_atom = None
+ try:
+ arg_atom = args_set.findAtomForPackage(pkg)
+ except portage.exception.InvalidDependString:
+ # this error has already been displayed by now
+ continue
+
+ if arg_atom:
+ if pkg not in graph:
+ pkgs_to_remove.append(pkg)
+ elif "--verbose" in myopts:
+ show_parents(pkg)
+
+ else:
+ for pkg in sorted(vardb, key=cmp_sort_key(cmp_pkg_cpv)):
+ if pkg not in graph:
+ pkgs_to_remove.append(pkg)
+ elif "--verbose" in myopts:
+ show_parents(pkg)
+
+ elif action == "prune":
+
+ for atom in args_set:
+ for pkg in vardb.match_pkgs(atom):
+ if pkg not in graph:
+ pkgs_to_remove.append(pkg)
+ elif "--verbose" in myopts:
+ show_parents(pkg)
+
+ if not pkgs_to_remove:
+ writemsg_level(
+ ">>> No packages selected for removal by %s\n" % action)
+ if "--verbose" not in myopts:
+ writemsg_level(
+ ">>> To see reverse dependencies, use %s\n" % \
+ good("--verbose"))
+ if action == "prune":
+ writemsg_level(
+ ">>> To ignore dependencies, use %s\n" % \
+ good("--nodeps"))
+
+ return pkgs_to_remove
+
+ cleanlist = create_cleanlist()
+ clean_set = set(cleanlist)
+
+ if cleanlist and \
+ real_vardb._linkmap is not None and \
+ myopts.get("--depclean-lib-check") != "n" and \
+ "preserve-libs" not in settings.features:
+
+ # Check if any of these packages are the sole providers of libraries
+ # with consumers that have not been selected for removal. If so, these
+ # packages and any dependencies need to be added to the graph.
+ linkmap = real_vardb._linkmap
+ consumer_cache = {}
+ provider_cache = {}
+ consumer_map = {}
+
+ writemsg_level(">>> Checking for lib consumers...\n")
+
+ for pkg in cleanlist:
+ pkg_dblink = real_vardb._dblink(pkg.cpv)
+ consumers = {}
+
+ for lib in pkg_dblink.getcontents():
+ lib = lib[len(myroot):]
+ lib_key = linkmap._obj_key(lib)
+ lib_consumers = consumer_cache.get(lib_key)
+ if lib_consumers is None:
+ try:
+ lib_consumers = linkmap.findConsumers(lib_key)
+ except KeyError:
+ continue
+ consumer_cache[lib_key] = lib_consumers
+ if lib_consumers:
+ consumers[lib_key] = lib_consumers
+
+ if not consumers:
+ continue
+
+ for lib, lib_consumers in list(consumers.items()):
+ for consumer_file in list(lib_consumers):
+ if pkg_dblink.isowner(consumer_file):
+ lib_consumers.remove(consumer_file)
+ if not lib_consumers:
+ del consumers[lib]
+
+ if not consumers:
+ continue
+
+ for lib, lib_consumers in consumers.items():
+
+ soname = linkmap.getSoname(lib)
+
+ consumer_providers = []
+ for lib_consumer in lib_consumers:
+ providers = provider_cache.get(lib)
+ if providers is None:
+ providers = linkmap.findProviders(lib_consumer)
+ provider_cache[lib_consumer] = providers
+ if soname not in providers:
+ # Why does this happen?
+ continue
+ consumer_providers.append(
+ (lib_consumer, providers[soname]))
+
+ consumers[lib] = consumer_providers
+
+ consumer_map[pkg] = consumers
+
+ if consumer_map:
+
+ search_files = set()
+ for consumers in consumer_map.values():
+ for lib, consumer_providers in consumers.items():
+ for lib_consumer, providers in consumer_providers:
+ search_files.add(lib_consumer)
+ search_files.update(providers)
+
+ writemsg_level(">>> Assigning files to packages...\n")
+ file_owners = {}
+ for f in search_files:
+ owner_set = set()
+ for owner in linkmap.getOwners(f):
+ owner_dblink = real_vardb._dblink(owner)
+ if owner_dblink.exists():
+ owner_set.add(owner_dblink)
+ if owner_set:
+ file_owners[f] = owner_set
+
+ for pkg, consumers in list(consumer_map.items()):
+ for lib, consumer_providers in list(consumers.items()):
+ lib_consumers = set()
+
+ for lib_consumer, providers in consumer_providers:
+ owner_set = file_owners.get(lib_consumer)
+ provider_dblinks = set()
+ provider_pkgs = set()
+
+ if len(providers) > 1:
+ for provider in providers:
+ provider_set = file_owners.get(provider)
+ if provider_set is not None:
+ provider_dblinks.update(provider_set)
+
+ if len(provider_dblinks) > 1:
+ for provider_dblink in provider_dblinks:
+ provider_pkg = resolver._pkg(
+ provider_dblink.mycpv, "installed",
+ root_config, installed=True)
+ if provider_pkg not in clean_set:
+ provider_pkgs.add(provider_pkg)
+
+ if provider_pkgs:
+ continue
+
+ if owner_set is not None:
+ lib_consumers.update(owner_set)
+
+ for consumer_dblink in list(lib_consumers):
+ if resolver._pkg(consumer_dblink.mycpv, "installed",
+ root_config, installed=True) in clean_set:
+ lib_consumers.remove(consumer_dblink)
+ continue
+
+ if lib_consumers:
+ consumers[lib] = lib_consumers
+ else:
+ del consumers[lib]
+ if not consumers:
+ del consumer_map[pkg]
+
+ if consumer_map:
+ # TODO: Implement a package set for rebuilding consumer packages.
+
+ msg = "In order to avoid breakage of link level " + \
+ "dependencies, one or more packages will not be removed. " + \
+ "This can be solved by rebuilding " + \
+ "the packages that pulled them in."
+
+ prefix = bad(" * ")
+ from textwrap import wrap
+ writemsg_level("".join(prefix + "%s\n" % line for \
+ line in wrap(msg, 70)), level=logging.WARNING, noiselevel=-1)
+
+ msg = []
+ for pkg in sorted(consumer_map, key=cmp_sort_key(cmp_pkg_cpv)):
+ consumers = consumer_map[pkg]
+ consumer_libs = {}
+ for lib, lib_consumers in consumers.items():
+ for consumer in lib_consumers:
+ consumer_libs.setdefault(
+ consumer.mycpv, set()).add(linkmap.getSoname(lib))
+ unique_consumers = set(chain(*consumers.values()))
+ unique_consumers = sorted(consumer.mycpv \
+ for consumer in unique_consumers)
+ msg.append("")
+ msg.append(" %s pulled in by:" % (pkg.cpv,))
+ for consumer in unique_consumers:
+ libs = consumer_libs[consumer]
+ msg.append(" %s needs %s" % \
+ (consumer, ', '.join(sorted(libs))))
+ msg.append("")
+ writemsg_level("".join(prefix + "%s\n" % line for line in msg),
+ level=logging.WARNING, noiselevel=-1)
+
+ # Add lib providers to the graph as children of lib consumers,
+ # and also add any dependencies pulled in by the provider.
+ writemsg_level(">>> Adding lib providers to graph...\n")
+
+ for pkg, consumers in consumer_map.items():
+ for consumer_dblink in set(chain(*consumers.values())):
+ consumer_pkg = resolver._pkg(consumer_dblink.mycpv,
+ "installed", root_config, installed=True)
+ if not resolver._add_pkg(pkg,
+ Dependency(parent=consumer_pkg,
+ priority=UnmergeDepPriority(runtime=True),
+ root=pkg.root)):
+ resolver.display_problems()
+ return 1, [], False, 0
+
+ writemsg_level("\nCalculating dependencies ")
+ success = resolver._complete_graph(
+ required_sets={myroot:required_sets})
+ writemsg_level("\b\b... done!\n")
+ resolver.display_problems()
+ if not success:
+ return 1, [], False, 0
+ if unresolved_deps():
+ return 1, [], False, 0
+
+ graph = resolver._dynamic_config.digraph.copy()
+ required_pkgs_total = 0
+ for node in graph:
+ if isinstance(node, Package):
+ required_pkgs_total += 1
+ cleanlist = create_cleanlist()
+ if not cleanlist:
+ return 0, [], False, required_pkgs_total
+ clean_set = set(cleanlist)
+
+ if clean_set:
+ writemsg_level(">>> Calculating removal order...\n")
+ # Use a topological sort to create an unmerge order such that
+ # each package is unmerged before it's dependencies. This is
+ # necessary to avoid breaking things that may need to run
+ # during pkg_prerm or pkg_postrm phases.
+
+ # Create a new graph to account for dependencies between the
+ # packages being unmerged.
+ graph = digraph()
+ del cleanlist[:]
+
+ dep_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
+ runtime = UnmergeDepPriority(runtime=True)
+ runtime_post = UnmergeDepPriority(runtime_post=True)
+ buildtime = UnmergeDepPriority(buildtime=True)
+ priority_map = {
+ "RDEPEND": runtime,
+ "PDEPEND": runtime_post,
+ "DEPEND": buildtime,
+ }
+
+ for node in clean_set:
+ graph.add(node, None)
+ mydeps = []
+ for dep_type in dep_keys:
+ depstr = node.metadata[dep_type]
+ if not depstr:
+ continue
+ priority = priority_map[dep_type]
+
+ if debug:
+ writemsg_level(_unicode_decode("\nParent: %s\n") \
+ % (node,), noiselevel=-1, level=logging.DEBUG)
+ writemsg_level(_unicode_decode( "Depstring: %s\n") \
+ % (depstr,), noiselevel=-1, level=logging.DEBUG)
+ writemsg_level(_unicode_decode( "Priority: %s\n") \
+ % (priority,), noiselevel=-1, level=logging.DEBUG)
+
+ try:
+ atoms = resolver._select_atoms(myroot, depstr,
+ myuse=node.use.enabled, parent=node,
+ priority=priority)[node]
+ except portage.exception.InvalidDependString:
+ # Ignore invalid deps of packages that will
+ # be uninstalled anyway.
+ continue
+
+ if debug:
+ writemsg_level("Candidates: [%s]\n" % \
+ ', '.join(_unicode_decode("'%s'") % (x,) for x in atoms),
+ noiselevel=-1, level=logging.DEBUG)
+
+ for atom in atoms:
+ if not isinstance(atom, portage.dep.Atom):
+ # Ignore invalid atoms returned from dep_check().
+ continue
+ if atom.blocker:
+ continue
+ matches = vardb.match_pkgs(atom)
+ if not matches:
+ continue
+ for child_node in matches:
+ if child_node in clean_set:
+ graph.add(child_node, node, priority=priority)
+
+ if debug:
+ writemsg_level("\nunmerge digraph:\n\n",
+ noiselevel=-1, level=logging.DEBUG)
+ graph.debug_print()
+ writemsg_level("\n", noiselevel=-1, level=logging.DEBUG)
+
+ ordered = True
+ if len(graph.order) == len(graph.root_nodes()):
+ # If there are no dependencies between packages
+ # let unmerge() group them by cat/pn.
+ ordered = False
+ cleanlist = [pkg.cpv for pkg in graph.order]
+ else:
+ # Order nodes from lowest to highest overall reference count for
+ # optimal root node selection (this can help minimize issues
+ # with unaccounted implicit dependencies).
+ node_refcounts = {}
+ for node in graph.order:
+ node_refcounts[node] = len(graph.parent_nodes(node))
+ def cmp_reference_count(node1, node2):
+ return node_refcounts[node1] - node_refcounts[node2]
+ graph.order.sort(key=cmp_sort_key(cmp_reference_count))
+
+ ignore_priority_range = [None]
+ ignore_priority_range.extend(
+ range(UnmergeDepPriority.MIN, UnmergeDepPriority.MAX + 1))
+ while graph:
+ for ignore_priority in ignore_priority_range:
+ nodes = graph.root_nodes(ignore_priority=ignore_priority)
+ if nodes:
+ break
+ if not nodes:
+ raise AssertionError("no root nodes")
+ if ignore_priority is not None:
+ # Some deps have been dropped due to circular dependencies,
+ # so only pop one node in order to minimize the number that
+ # are dropped.
+ del nodes[1:]
+ for node in nodes:
+ graph.remove(node)
+ cleanlist.append(node.cpv)
+
+ return 0, cleanlist, ordered, required_pkgs_total
+ return 0, [], False, required_pkgs_total
+
+def action_deselect(settings, trees, opts, atoms):
+ enter_invalid = '--ask-enter-invalid' in opts
+ root_config = trees[settings['ROOT']]['root_config']
+ world_set = root_config.sets['selected']
+ if not hasattr(world_set, 'update'):
+ writemsg_level("World @selected set does not appear to be mutable.\n",
+ level=logging.ERROR, noiselevel=-1)
+ return 1
+
+ pretend = '--pretend' in opts
+ locked = False
+ if not pretend and hasattr(world_set, 'lock'):
+ world_set.lock()
+ locked = True
+ try:
+ world_set.load()
+ world_atoms = world_set.getAtoms()
+ vardb = root_config.trees["vartree"].dbapi
+ expanded_atoms = set(atoms)
+
+ for atom in atoms:
+ if not atom.startswith(SETPREFIX):
+ if atom.cp.startswith("null/"):
+ # try to expand category from world set
+ null_cat, pn = portage.catsplit(atom.cp)
+ for world_atom in world_atoms:
+ cat, world_pn = portage.catsplit(world_atom.cp)
+ if pn == world_pn:
+ expanded_atoms.add(
+ Atom(atom.replace("null", cat, 1),
+ allow_repo=True, allow_wildcard=True))
+
+ for cpv in vardb.match(atom):
+ slot, = vardb.aux_get(cpv, ["SLOT"])
+ if not slot:
+ slot = "0"
+ expanded_atoms.add(Atom("%s:%s" % \
+ (portage.cpv_getkey(cpv), slot)))
+
+ discard_atoms = set()
+ for atom in world_set:
+ for arg_atom in expanded_atoms:
+ if arg_atom.startswith(SETPREFIX):
+ if atom.startswith(SETPREFIX) and \
+ arg_atom == atom:
+ discard_atoms.add(atom)
+ break
+ else:
+ if not atom.startswith(SETPREFIX) and \
+ arg_atom.intersects(atom) and \
+ not (arg_atom.slot and not atom.slot) and \
+ not (arg_atom.repo and not atom.repo):
+ discard_atoms.add(atom)
+ break
+ if discard_atoms:
+ for atom in sorted(discard_atoms):
+ if pretend:
+ print(">>> Would remove %s from \"world\" favorites file..." % \
+ colorize("INFORM", str(atom)))
+ else:
+ print(">>> Removing %s from \"world\" favorites file..." % \
+ colorize("INFORM", str(atom)))
+
+ if '--ask' in opts:
+ prompt = "Would you like to remove these " + \
+ "packages from your world favorites?"
+ if userquery(prompt, enter_invalid) == 'No':
+ return os.EX_OK
+
+ remaining = set(world_set)
+ remaining.difference_update(discard_atoms)
+ if not pretend:
+ world_set.replace(remaining)
+ else:
+ print(">>> No matching atoms found in \"world\" favorites file...")
+ finally:
+ if locked:
+ world_set.unlock()
+ return os.EX_OK
+
+class _info_pkgs_ver(object):
+ def __init__(self, ver, repo_suffix, provide_suffix):
+ self.ver = ver
+ self.repo_suffix = repo_suffix
+ self.provide_suffix = provide_suffix
+
+ def __lt__(self, other):
+ return portage.versions.vercmp(self.ver, other.ver) < 0
+
+ def toString(self):
+ """
+ This may return unicode if repo_name contains unicode.
+ Don't use __str__ and str() since unicode triggers compatibility
+ issues between python 2.x and 3.x.
+ """
+ return self.ver + self.repo_suffix + self.provide_suffix
+
+def action_info(settings, trees, myopts, myfiles):
+
+ output_buffer = []
+ append = output_buffer.append
+ root_config = trees[settings['ROOT']]['root_config']
+
+ append(getportageversion(settings["PORTDIR"], settings["ROOT"],
+ settings.profile_path, settings["CHOST"],
+ trees[settings["ROOT"]]["vartree"].dbapi))
+
+ header_width = 65
+ header_title = "System Settings"
+ if myfiles:
+ append(header_width * "=")
+ append(header_title.rjust(int(header_width/2 + len(header_title)/2)))
+ append(header_width * "=")
+ append("System uname: %s" % (platform.platform(aliased=1),))
+
+ lastSync = portage.grabfile(os.path.join(
+ settings["PORTDIR"], "metadata", "timestamp.chk"))
+ if lastSync:
+ lastSync = lastSync[0]
+ else:
+ lastSync = "Unknown"
+ append("Timestamp of tree: %s" % (lastSync,))
+
+ output=subprocess_getstatusoutput("distcc --version")
+ if output[0] == os.EX_OK:
+ distcc_str = output[1].split("\n", 1)[0]
+ if "distcc" in settings.features:
+ distcc_str += " [enabled]"
+ else:
+ distcc_str += " [disabled]"
+ append(distcc_str)
+
+ output=subprocess_getstatusoutput("ccache -V")
+ if output[0] == os.EX_OK:
+ ccache_str = output[1].split("\n", 1)[0]
+ if "ccache" in settings.features:
+ ccache_str += " [enabled]"
+ else:
+ ccache_str += " [disabled]"
+ append(ccache_str)
+
+ myvars = ["sys-devel/autoconf", "sys-devel/automake", "virtual/os-headers",
+ "sys-devel/binutils", "sys-devel/libtool", "dev-lang/python"]
+ myvars += portage.util.grabfile(settings["PORTDIR"]+"/profiles/info_pkgs")
+ atoms = []
+ vardb = trees["/"]["vartree"].dbapi
+ for x in myvars:
+ try:
+ x = Atom(x)
+ except InvalidAtom:
+ append("%-20s %s" % (x+":", "[NOT VALID]"))
+ else:
+ for atom in expand_new_virt(vardb, x):
+ if not atom.blocker:
+ atoms.append((x, atom))
+
+ myvars = sorted(set(atoms))
+
+ portdb = trees["/"]["porttree"].dbapi
+ main_repo = portdb.getRepositoryName(portdb.porttree_root)
+ cp_map = {}
+ cp_max_len = 0
+
+ for orig_atom, x in myvars:
+ pkg_matches = vardb.match(x)
+
+ versions = []
+ for cpv in pkg_matches:
+ matched_cp = portage.versions.cpv_getkey(cpv)
+ ver = portage.versions.cpv_getversion(cpv)
+ ver_map = cp_map.setdefault(matched_cp, {})
+ prev_match = ver_map.get(ver)
+ if prev_match is not None:
+ if prev_match.provide_suffix:
+ # prefer duplicate matches that include
+ # additional virtual provider info
+ continue
+
+ if len(matched_cp) > cp_max_len:
+ cp_max_len = len(matched_cp)
+ repo = vardb.aux_get(cpv, ["repository"])[0]
+ if repo == main_repo:
+ repo_suffix = ""
+ elif not repo:
+ repo_suffix = "::<unknown repository>"
+ else:
+ repo_suffix = "::" + repo
+
+ if matched_cp == orig_atom.cp:
+ provide_suffix = ""
+ else:
+ provide_suffix = " (%s)" % (orig_atom,)
+
+ ver_map[ver] = _info_pkgs_ver(ver, repo_suffix, provide_suffix)
+
+ for cp in sorted(cp_map):
+ versions = sorted(cp_map[cp].values())
+ versions = ", ".join(ver.toString() for ver in versions)
+ append("%s %s" % \
+ ((cp + ":").ljust(cp_max_len + 1), versions))
+
+ libtool_vers = ",".join(trees["/"]["vartree"].dbapi.match("sys-devel/libtool"))
+
+ repos = portdb.settings.repositories
+ if "--verbose" in myopts:
+ append("Repositories:\n")
+ for repo in repos:
+ append(repo.info_string())
+ else:
+ append("Repositories: %s" % \
+ " ".join(repo.name for repo in repos))
+
+ if _ENABLE_SET_CONFIG:
+ sets_line = "Installed sets: "
+ sets_line += ", ".join(s for s in \
+ sorted(root_config.sets['selected'].getNonAtoms()) \
+ if s.startswith(SETPREFIX))
+ append(sets_line)
+
+ if "--verbose" in myopts:
+ myvars = list(settings)
+ else:
+ myvars = ['GENTOO_MIRRORS', 'CONFIG_PROTECT', 'CONFIG_PROTECT_MASK',
+ 'PORTDIR', 'DISTDIR', 'PKGDIR', 'PORTAGE_TMPDIR',
+ 'PORTDIR_OVERLAY', 'PORTAGE_BUNZIP2_COMMAND',
+ 'PORTAGE_BZIP2_COMMAND',
+ 'USE', 'CHOST', 'CFLAGS', 'CXXFLAGS',
+ 'ACCEPT_KEYWORDS', 'ACCEPT_LICENSE', 'SYNC', 'FEATURES',
+ 'EMERGE_DEFAULT_OPTS']
+
+ myvars.extend(portage.util.grabfile(settings["PORTDIR"]+"/profiles/info_vars"))
+
+ myvars_ignore_defaults = {
+ 'PORTAGE_BZIP2_COMMAND' : 'bzip2',
+ }
+
+ myvars = portage.util.unique_array(myvars)
+ use_expand = settings.get('USE_EXPAND', '').split()
+ use_expand.sort()
+ use_expand_hidden = set(
+ settings.get('USE_EXPAND_HIDDEN', '').upper().split())
+ alphabetical_use = '--alphabetical' in myopts
+ unset_vars = []
+ myvars.sort()
+ for k in myvars:
+ v = settings.get(k)
+ if v is not None:
+ if k != "USE":
+ default = myvars_ignore_defaults.get(k)
+ if default is not None and \
+ default == v:
+ continue
+ append('%s="%s"' % (k, v))
+ else:
+ use = set(v.split())
+ for varname in use_expand:
+ flag_prefix = varname.lower() + "_"
+ for f in list(use):
+ if f.startswith(flag_prefix):
+ use.remove(f)
+ use = list(use)
+ use.sort()
+ use = ['USE="%s"' % " ".join(use)]
+ for varname in use_expand:
+ myval = settings.get(varname)
+ if myval:
+ use.append('%s="%s"' % (varname, myval))
+ append(" ".join(use))
+ else:
+ unset_vars.append(k)
+ if unset_vars:
+ append("Unset: "+", ".join(unset_vars))
+ append("")
+ append("")
+ writemsg_stdout("\n".join(output_buffer),
+ noiselevel=-1)
+
+ # See if we can find any packages installed matching the strings
+ # passed on the command line
+ mypkgs = []
+ vardb = trees[settings["ROOT"]]["vartree"].dbapi
+ portdb = trees[settings["ROOT"]]["porttree"].dbapi
+ bindb = trees[settings["ROOT"]]["bintree"].dbapi
+ for x in myfiles:
+ match_found = False
+ installed_match = vardb.match(x)
+ for installed in installed_match:
+ mypkgs.append((installed, "installed"))
+ match_found = True
+
+ if match_found:
+ continue
+
+ for db, pkg_type in ((portdb, "ebuild"), (bindb, "binary")):
+ if pkg_type == "binary" and "--usepkg" not in myopts:
+ continue
+
+ matches = db.match(x)
+ matches.reverse()
+ for match in matches:
+ if pkg_type == "binary":
+ if db.bintree.isremote(match):
+ continue
+ auxkeys = ["EAPI", "DEFINED_PHASES"]
+ metadata = dict(zip(auxkeys, db.aux_get(match, auxkeys)))
+ if metadata["EAPI"] not in ("0", "1", "2", "3") and \
+ "info" in metadata["DEFINED_PHASES"].split():
+ mypkgs.append((match, pkg_type))
+ break
+
+ # If some packages were found...
+ if mypkgs:
+ # Get our global settings (we only print stuff if it varies from
+ # the current config)
+ mydesiredvars = [ 'CHOST', 'CFLAGS', 'CXXFLAGS', 'LDFLAGS' ]
+ auxkeys = mydesiredvars + list(vardb._aux_cache_keys)
+ auxkeys.append('DEFINED_PHASES')
+ global_vals = {}
+ pkgsettings = portage.config(clone=settings)
+
+ # Loop through each package
+ # Only print settings if they differ from global settings
+ header_title = "Package Settings"
+ print(header_width * "=")
+ print(header_title.rjust(int(header_width/2 + len(header_title)/2)))
+ print(header_width * "=")
+ from portage.output import EOutput
+ out = EOutput()
+ for mypkg in mypkgs:
+ cpv = mypkg[0]
+ pkg_type = mypkg[1]
+ # Get all package specific variables
+ if pkg_type == "installed":
+ metadata = dict(zip(auxkeys, vardb.aux_get(cpv, auxkeys)))
+ elif pkg_type == "ebuild":
+ metadata = dict(zip(auxkeys, portdb.aux_get(cpv, auxkeys)))
+ elif pkg_type == "binary":
+ metadata = dict(zip(auxkeys, bindb.aux_get(cpv, auxkeys)))
+
+ pkg = Package(built=(pkg_type!="ebuild"), cpv=cpv,
+ installed=(pkg_type=="installed"), metadata=zip(Package.metadata_keys,
+ (metadata.get(x, '') for x in Package.metadata_keys)),
+ root_config=root_config, type_name=pkg_type)
+
+ if pkg_type == "installed":
+ print("\n%s was built with the following:" % \
+ colorize("INFORM", str(pkg.cpv)))
+ elif pkg_type == "ebuild":
+ print("\n%s would be build with the following:" % \
+ colorize("INFORM", str(pkg.cpv)))
+ elif pkg_type == "binary":
+ print("\n%s (non-installed binary) was built with the following:" % \
+ colorize("INFORM", str(pkg.cpv)))
+
+ writemsg_stdout('%s\n' % pkg_use_display(pkg, myopts),
+ noiselevel=-1)
+ if pkg_type == "installed":
+ for myvar in mydesiredvars:
+ if metadata[myvar].split() != settings.get(myvar, '').split():
+ print("%s=\"%s\"" % (myvar, metadata[myvar]))
+ print()
+
+ if metadata['DEFINED_PHASES']:
+ if 'info' not in metadata['DEFINED_PHASES'].split():
+ continue
+
+ print(">>> Attempting to run pkg_info() for '%s'" % pkg.cpv)
+
+ if pkg_type == "installed":
+ ebuildpath = vardb.findname(pkg.cpv)
+ elif pkg_type == "ebuild":
+ ebuildpath = portdb.findname(pkg.cpv, myrepo=pkg.repo)
+ elif pkg_type == "binary":
+ tbz2_file = bindb.bintree.getname(pkg.cpv)
+ ebuild_file_name = pkg.cpv.split("/")[1] + ".ebuild"
+ ebuild_file_contents = portage.xpak.tbz2(tbz2_file).getfile(ebuild_file_name)
+ tmpdir = tempfile.mkdtemp()
+ ebuildpath = os.path.join(tmpdir, ebuild_file_name)
+ file = open(ebuildpath, 'w')
+ file.write(ebuild_file_contents)
+ file.close()
+
+ if not ebuildpath or not os.path.exists(ebuildpath):
+ out.ewarn("No ebuild found for '%s'" % pkg.cpv)
+ continue
+
+ if pkg_type == "installed":
+ portage.doebuild(ebuildpath, "info", pkgsettings["ROOT"],
+ pkgsettings, debug=(settings.get("PORTAGE_DEBUG", "") == 1),
+ mydbapi=trees[settings["ROOT"]]["vartree"].dbapi,
+ tree="vartree")
+ elif pkg_type == "ebuild":
+ portage.doebuild(ebuildpath, "info", pkgsettings["ROOT"],
+ pkgsettings, debug=(settings.get("PORTAGE_DEBUG", "") == 1),
+ mydbapi=trees[settings["ROOT"]]["porttree"].dbapi,
+ tree="porttree")
+ elif pkg_type == "binary":
+ portage.doebuild(ebuildpath, "info", pkgsettings["ROOT"],
+ pkgsettings, debug=(settings.get("PORTAGE_DEBUG", "") == 1),
+ mydbapi=trees[settings["ROOT"]]["bintree"].dbapi,
+ tree="bintree")
+ shutil.rmtree(tmpdir)
+
+def action_metadata(settings, portdb, myopts, porttrees=None):
+ if porttrees is None:
+ porttrees = portdb.porttrees
+ portage.writemsg_stdout("\n>>> Updating Portage cache\n")
+ old_umask = os.umask(0o002)
+ cachedir = os.path.normpath(settings.depcachedir)
+ if cachedir in ["/", "/bin", "/dev", "/etc", "/home",
+ "/lib", "/opt", "/proc", "/root", "/sbin",
+ "/sys", "/tmp", "/usr", "/var"]:
+ print("!!! PORTAGE_DEPCACHEDIR IS SET TO A PRIMARY " + \
+ "ROOT DIRECTORY ON YOUR SYSTEM.", file=sys.stderr)
+ print("!!! This is ALMOST CERTAINLY NOT what you want: '%s'" % cachedir, file=sys.stderr)
+ sys.exit(73)
+ if not os.path.exists(cachedir):
+ os.makedirs(cachedir)
+
+ auxdbkeys = [x for x in portage.auxdbkeys if not x.startswith("UNUSED_0")]
+ auxdbkeys = tuple(auxdbkeys)
+
+ class TreeData(object):
+ __slots__ = ('dest_db', 'eclass_db', 'path', 'src_db', 'valid_nodes')
+ def __init__(self, dest_db, eclass_db, path, src_db):
+ self.dest_db = dest_db
+ self.eclass_db = eclass_db
+ self.path = path
+ self.src_db = src_db
+ self.valid_nodes = set()
+
+ porttrees_data = []
+ for path in porttrees:
+ src_db = portdb._pregen_auxdb.get(path)
+ if src_db is None and \
+ os.path.isdir(os.path.join(path, 'metadata', 'cache')):
+ src_db = portdb.metadbmodule(
+ path, 'metadata/cache', auxdbkeys, readonly=True)
+ try:
+ src_db.ec = portdb._repo_info[path].eclass_db
+ except AttributeError:
+ pass
+
+ if src_db is not None:
+ porttrees_data.append(TreeData(portdb.auxdb[path],
+ portdb._repo_info[path].eclass_db, path, src_db))
+
+ porttrees = [tree_data.path for tree_data in porttrees_data]
+
+ quiet = settings.get('TERM') == 'dumb' or \
+ '--quiet' in myopts or \
+ not sys.stdout.isatty()
+
+ onProgress = None
+ if not quiet:
+ progressBar = portage.output.TermProgressBar()
+ progressHandler = ProgressHandler()
+ onProgress = progressHandler.onProgress
+ def display():
+ progressBar.set(progressHandler.curval, progressHandler.maxval)
+ progressHandler.display = display
+ def sigwinch_handler(signum, frame):
+ lines, progressBar.term_columns = \
+ portage.output.get_term_size()
+ signal.signal(signal.SIGWINCH, sigwinch_handler)
+
+ # Temporarily override portdb.porttrees so portdb.cp_all()
+ # will only return the relevant subset.
+ portdb_porttrees = portdb.porttrees
+ portdb.porttrees = porttrees
+ try:
+ cp_all = portdb.cp_all()
+ finally:
+ portdb.porttrees = portdb_porttrees
+
+ curval = 0
+ maxval = len(cp_all)
+ if onProgress is not None:
+ onProgress(maxval, curval)
+
+ from portage.cache.util import quiet_mirroring
+ from portage import eapi_is_supported, \
+ _validate_cache_for_unsupported_eapis
+
+ # TODO: Display error messages, but do not interfere with the progress bar.
+ # Here's how:
+ # 1) erase the progress bar
+ # 2) show the error message
+ # 3) redraw the progress bar on a new line
+ noise = quiet_mirroring()
+
+ for cp in cp_all:
+ for tree_data in porttrees_data:
+ for cpv in portdb.cp_list(cp, mytree=tree_data.path):
+ tree_data.valid_nodes.add(cpv)
+ try:
+ src = tree_data.src_db[cpv]
+ except KeyError as e:
+ noise.missing_entry(cpv)
+ del e
+ continue
+ except CacheError as ce:
+ noise.exception(cpv, ce)
+ del ce
+ continue
+
+ eapi = src.get('EAPI')
+ if not eapi:
+ eapi = '0'
+ eapi = eapi.lstrip('-')
+ eapi_supported = eapi_is_supported(eapi)
+ if not eapi_supported:
+ if not _validate_cache_for_unsupported_eapis:
+ noise.misc(cpv, "unable to validate " + \
+ "cache for EAPI='%s'" % eapi)
+ continue
+
+ dest = None
+ try:
+ dest = tree_data.dest_db[cpv]
+ except (KeyError, CacheError):
+ pass
+
+ for d in (src, dest):
+ if d is not None and d.get('EAPI') in ('', '0'):
+ del d['EAPI']
+
+ if dest is not None:
+ if not (dest['_mtime_'] == src['_mtime_'] and \
+ tree_data.eclass_db.is_eclass_data_valid(
+ dest['_eclasses_']) and \
+ set(dest['_eclasses_']) == set(src['_eclasses_'])):
+ dest = None
+ else:
+ # We don't want to skip the write unless we're really
+ # sure that the existing cache is identical, so don't
+ # trust _mtime_ and _eclasses_ alone.
+ for k in set(chain(src, dest)).difference(
+ ('_mtime_', '_eclasses_')):
+ if dest.get(k, '') != src.get(k, ''):
+ dest = None
+ break
+
+ if dest is not None:
+ # The existing data is valid and identical,
+ # so there's no need to overwrite it.
+ continue
+
+ try:
+ inherited = src.get('INHERITED', '')
+ eclasses = src.get('_eclasses_')
+ except CacheError as ce:
+ noise.exception(cpv, ce)
+ del ce
+ continue
+
+ if eclasses is not None:
+ if not tree_data.eclass_db.is_eclass_data_valid(
+ src['_eclasses_']):
+ noise.eclass_stale(cpv)
+ continue
+ inherited = eclasses
+ else:
+ inherited = inherited.split()
+
+ if tree_data.src_db.complete_eclass_entries and \
+ eclasses is None:
+ noise.corruption(cpv, "missing _eclasses_ field")
+ continue
+
+ if inherited:
+ # Even if _eclasses_ already exists, replace it with data from
+ # eclass_cache, in order to insert local eclass paths.
+ try:
+ eclasses = tree_data.eclass_db.get_eclass_data(inherited)
+ except KeyError:
+ # INHERITED contains a non-existent eclass.
+ noise.eclass_stale(cpv)
+ continue
+
+ if eclasses is None:
+ noise.eclass_stale(cpv)
+ continue
+ src['_eclasses_'] = eclasses
+ else:
+ src['_eclasses_'] = {}
+
+ if not eapi_supported:
+ src = {
+ 'EAPI' : '-' + eapi,
+ '_mtime_' : src['_mtime_'],
+ '_eclasses_' : src['_eclasses_'],
+ }
+
+ try:
+ tree_data.dest_db[cpv] = src
+ except CacheError as ce:
+ noise.exception(cpv, ce)
+ del ce
+
+ curval += 1
+ if onProgress is not None:
+ onProgress(maxval, curval)
+
+ if onProgress is not None:
+ onProgress(maxval, curval)
+
+ for tree_data in porttrees_data:
+ try:
+ dead_nodes = set(tree_data.dest_db)
+ except CacheError as e:
+ writemsg_level("Error listing cache entries for " + \
+ "'%s': %s, continuing...\n" % (tree_data.path, e),
+ level=logging.ERROR, noiselevel=-1)
+ del e
+ else:
+ dead_nodes.difference_update(tree_data.valid_nodes)
+ for cpv in dead_nodes:
+ try:
+ del tree_data.dest_db[cpv]
+ except (KeyError, CacheError):
+ pass
+
+ if not quiet:
+ # make sure the final progress is displayed
+ progressHandler.display()
+ print()
+ signal.signal(signal.SIGWINCH, signal.SIG_DFL)
+
+ sys.stdout.flush()
+ os.umask(old_umask)
+
+def action_regen(settings, portdb, max_jobs, max_load):
+ xterm_titles = "notitles" not in settings.features
+ emergelog(xterm_titles, " === regen")
+ #regenerate cache entries
+ try:
+ os.close(sys.stdin.fileno())
+ except SystemExit as e:
+ raise # Needed else can't exit
+ except:
+ pass
+ sys.stdout.flush()
+
+ regen = MetadataRegen(portdb, max_jobs=max_jobs, max_load=max_load)
+ received_signal = []
+
+ def emergeexitsig(signum, frame):
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
+ portage.util.writemsg("\n\nExiting on signal %(signal)s\n" % \
+ {"signal":signum})
+ regen.terminate()
+ received_signal.append(128 + signum)
+
+ earlier_sigint_handler = signal.signal(signal.SIGINT, emergeexitsig)
+ earlier_sigterm_handler = signal.signal(signal.SIGTERM, emergeexitsig)
+
+ try:
+ regen.run()
+ finally:
+ # Restore previous handlers
+ if earlier_sigint_handler is not None:
+ signal.signal(signal.SIGINT, earlier_sigint_handler)
+ else:
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+ if earlier_sigterm_handler is not None:
+ signal.signal(signal.SIGTERM, earlier_sigterm_handler)
+ else:
+ signal.signal(signal.SIGTERM, signal.SIG_DFL)
+
+ if received_signal:
+ sys.exit(received_signal[0])
+
+ portage.writemsg_stdout("done!\n")
+ return regen.returncode
+
+def action_search(root_config, myopts, myfiles, spinner):
+ if not myfiles:
+ print("emerge: no search terms provided.")
+ else:
+ searchinstance = search(root_config,
+ spinner, "--searchdesc" in myopts,
+ "--quiet" not in myopts, "--usepkg" in myopts,
+ "--usepkgonly" in myopts)
+ for mysearch in myfiles:
+ try:
+ searchinstance.execute(mysearch)
+ except re.error as comment:
+ print("\n!!! Regular expression error in \"%s\": %s" % ( mysearch, comment ))
+ sys.exit(1)
+ searchinstance.output()
+
+def action_sync(settings, trees, mtimedb, myopts, myaction):
+ enter_invalid = '--ask-enter-invalid' in myopts
+ xterm_titles = "notitles" not in settings.features
+ emergelog(xterm_titles, " === sync")
+ portdb = trees[settings["ROOT"]]["porttree"].dbapi
+ myportdir = portdb.porttree_root
+ if not myportdir:
+ myportdir = settings.get('PORTDIR', '')
+ if myportdir and myportdir.strip():
+ myportdir = os.path.realpath(myportdir)
+ else:
+ myportdir = None
+ out = portage.output.EOutput()
+ global_config_path = GLOBAL_CONFIG_PATH
+ if settings['EPREFIX']:
+ global_config_path = os.path.join(settings['EPREFIX'],
+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
+ if not myportdir:
+ sys.stderr.write("!!! PORTDIR is undefined. " + \
+ "Is %s/make.globals missing?\n" % global_config_path)
+ sys.exit(1)
+ if myportdir[-1]=="/":
+ myportdir=myportdir[:-1]
+ try:
+ st = os.stat(myportdir)
+ except OSError:
+ st = None
+ if st is None:
+ print(">>>",myportdir,"not found, creating it.")
+ portage.util.ensure_dirs(myportdir, mode=0o755)
+ st = os.stat(myportdir)
+
+ usersync_uid = None
+ spawn_kwargs = {}
+ spawn_kwargs["env"] = settings.environ()
+ if 'usersync' in settings.features and \
+ portage.data.secpass >= 2 and \
+ (st.st_uid != os.getuid() and st.st_mode & 0o700 or \
+ st.st_gid != os.getgid() and st.st_mode & 0o070):
+ try:
+ homedir = pwd.getpwuid(st.st_uid).pw_dir
+ except KeyError:
+ pass
+ else:
+ # Drop privileges when syncing, in order to match
+ # existing uid/gid settings.
+ usersync_uid = st.st_uid
+ spawn_kwargs["uid"] = st.st_uid
+ spawn_kwargs["gid"] = st.st_gid
+ spawn_kwargs["groups"] = [st.st_gid]
+ spawn_kwargs["env"]["HOME"] = homedir
+ umask = 0o002
+ if not st.st_mode & 0o020:
+ umask = umask | 0o020
+ spawn_kwargs["umask"] = umask
+
+ if usersync_uid is not None:
+ # PORTAGE_TMPDIR is used below, so validate it and
+ # bail out if necessary.
+ rval = _check_temp_dir(settings)
+ if rval != os.EX_OK:
+ return rval
+
+ syncuri = settings.get("SYNC", "").strip()
+ if not syncuri:
+ writemsg_level("!!! SYNC is undefined. " + \
+ "Is %s/make.globals missing?\n" % global_config_path,
+ noiselevel=-1, level=logging.ERROR)
+ return 1
+
+ vcs_dirs = frozenset([".git", ".svn", "CVS", ".hg"])
+ vcs_dirs = vcs_dirs.intersection(os.listdir(myportdir))
+
+ os.umask(0o022)
+ dosyncuri = syncuri
+ updatecache_flg = False
+ if myaction == "metadata":
+ print("skipping sync")
+ updatecache_flg = True
+ elif ".git" in vcs_dirs:
+ # Update existing git repository, and ignore the syncuri. We are
+ # going to trust the user and assume that the user is in the branch
+ # that he/she wants updated. We'll let the user manage branches with
+ # git directly.
+ if portage.process.find_binary("git") is None:
+ msg = ["Command not found: git",
+ "Type \"emerge dev-util/git\" to enable git support."]
+ for l in msg:
+ writemsg_level("!!! %s\n" % l,
+ level=logging.ERROR, noiselevel=-1)
+ return 1
+ msg = ">>> Starting git pull in %s..." % myportdir
+ emergelog(xterm_titles, msg )
+ writemsg_level(msg + "\n")
+ exitcode = portage.process.spawn_bash("cd %s ; git pull" % \
+ (portage._shell_quote(myportdir),), **spawn_kwargs)
+ if exitcode != os.EX_OK:
+ msg = "!!! git pull error in %s." % myportdir
+ emergelog(xterm_titles, msg)
+ writemsg_level(msg + "\n", level=logging.ERROR, noiselevel=-1)
+ return exitcode
+ msg = ">>> Git pull in %s successful" % myportdir
+ emergelog(xterm_titles, msg)
+ writemsg_level(msg + "\n")
+ exitcode = git_sync_timestamps(settings, myportdir)
+ if exitcode == os.EX_OK:
+ updatecache_flg = True
+ elif syncuri[:8]=="rsync://" or syncuri[:6]=="ssh://":
+ for vcs_dir in vcs_dirs:
+ writemsg_level(("!!! %s appears to be under revision " + \
+ "control (contains %s).\n!!! Aborting rsync sync.\n") % \
+ (myportdir, vcs_dir), level=logging.ERROR, noiselevel=-1)
+ return 1
+ if not os.path.exists("/usr/bin/rsync"):
+ print("!!! /usr/bin/rsync does not exist, so rsync support is disabled.")
+ print("!!! Type \"emerge net-misc/rsync\" to enable rsync support.")
+ sys.exit(1)
+ mytimeout=180
+
+ rsync_opts = []
+ if settings["PORTAGE_RSYNC_OPTS"] == "":
+ portage.writemsg("PORTAGE_RSYNC_OPTS empty or unset, using hardcoded defaults\n")
+ rsync_opts.extend([
+ "--recursive", # Recurse directories
+ "--links", # Consider symlinks
+ "--safe-links", # Ignore links outside of tree
+ "--perms", # Preserve permissions
+ "--times", # Preserive mod times
+ "--compress", # Compress the data transmitted
+ "--force", # Force deletion on non-empty dirs
+ "--whole-file", # Don't do block transfers, only entire files
+ "--delete", # Delete files that aren't in the master tree
+ "--stats", # Show final statistics about what was transfered
+ "--timeout="+str(mytimeout), # IO timeout if not done in X seconds
+ "--exclude=/distfiles", # Exclude distfiles from consideration
+ "--exclude=/local", # Exclude local from consideration
+ "--exclude=/packages", # Exclude packages from consideration
+ ])
+
+ else:
+ # The below validation is not needed when using the above hardcoded
+ # defaults.
+
+ portage.writemsg("Using PORTAGE_RSYNC_OPTS instead of hardcoded defaults\n", 1)
+ rsync_opts.extend(portage.util.shlex_split(
+ settings.get("PORTAGE_RSYNC_OPTS", "")))
+ for opt in ("--recursive", "--times"):
+ if opt not in rsync_opts:
+ portage.writemsg(yellow("WARNING:") + " adding required option " + \
+ "%s not included in PORTAGE_RSYNC_OPTS\n" % opt)
+ rsync_opts.append(opt)
+
+ for exclude in ("distfiles", "local", "packages"):
+ opt = "--exclude=/%s" % exclude
+ if opt not in rsync_opts:
+ portage.writemsg(yellow("WARNING:") + \
+ " adding required option %s not included in " % opt + \
+ "PORTAGE_RSYNC_OPTS (can be overridden with --exclude='!')\n")
+ rsync_opts.append(opt)
+
+ if syncuri.rstrip("/").endswith(".gentoo.org/gentoo-portage"):
+ def rsync_opt_startswith(opt_prefix):
+ for x in rsync_opts:
+ if x.startswith(opt_prefix):
+ return True
+ return False
+
+ if not rsync_opt_startswith("--timeout="):
+ rsync_opts.append("--timeout=%d" % mytimeout)
+
+ for opt in ("--compress", "--whole-file"):
+ if opt not in rsync_opts:
+ portage.writemsg(yellow("WARNING:") + " adding required option " + \
+ "%s not included in PORTAGE_RSYNC_OPTS\n" % opt)
+ rsync_opts.append(opt)
+
+ if "--quiet" in myopts:
+ rsync_opts.append("--quiet") # Shut up a lot
+ else:
+ rsync_opts.append("--verbose") # Print filelist
+
+ if "--verbose" in myopts:
+ rsync_opts.append("--progress") # Progress meter for each file
+
+ if "--debug" in myopts:
+ rsync_opts.append("--checksum") # Force checksum on all files
+
+ # Real local timestamp file.
+ servertimestampfile = os.path.join(
+ myportdir, "metadata", "timestamp.chk")
+
+ content = portage.util.grabfile(servertimestampfile)
+ mytimestamp = 0
+ if content:
+ try:
+ mytimestamp = time.mktime(time.strptime(content[0],
+ "%a, %d %b %Y %H:%M:%S +0000"))
+ except (OverflowError, ValueError):
+ pass
+ del content
+
+ try:
+ rsync_initial_timeout = \
+ int(settings.get("PORTAGE_RSYNC_INITIAL_TIMEOUT", "15"))
+ except ValueError:
+ rsync_initial_timeout = 15
+
+ try:
+ maxretries=int(settings["PORTAGE_RSYNC_RETRIES"])
+ except SystemExit as e:
+ raise # Needed else can't exit
+ except:
+ maxretries = -1 #default number of retries
+
+ retries=0
+ try:
+ proto, user_name, hostname, port = re.split(
+ r"(rsync|ssh)://([^:/]+@)?(\[[:\da-fA-F]*\]|[^:/]*)(:[0-9]+)?",
+ syncuri, maxsplit=4)[1:5]
+ except ValueError:
+ writemsg_level("!!! SYNC is invalid: %s\n" % syncuri,
+ noiselevel=-1, level=logging.ERROR)
+ return 1
+ if port is None:
+ port=""
+ if user_name is None:
+ user_name=""
+ if re.match(r"^\[[:\da-fA-F]*\]$", hostname) is None:
+ getaddrinfo_host = hostname
+ else:
+ # getaddrinfo needs the brackets stripped
+ getaddrinfo_host = hostname[1:-1]
+ updatecache_flg=True
+ all_rsync_opts = set(rsync_opts)
+ extra_rsync_opts = portage.util.shlex_split(
+ settings.get("PORTAGE_RSYNC_EXTRA_OPTS",""))
+ all_rsync_opts.update(extra_rsync_opts)
+
+ family = socket.AF_UNSPEC
+ if "-4" in all_rsync_opts or "--ipv4" in all_rsync_opts:
+ family = socket.AF_INET
+ elif socket.has_ipv6 and \
+ ("-6" in all_rsync_opts or "--ipv6" in all_rsync_opts):
+ family = socket.AF_INET6
+
+ addrinfos = None
+ uris = []
+
+ try:
+ addrinfos = getaddrinfo_validate(
+ socket.getaddrinfo(getaddrinfo_host, None,
+ family, socket.SOCK_STREAM))
+ except socket.error as e:
+ writemsg_level(
+ "!!! getaddrinfo failed for '%s': %s\n" % (hostname, e),
+ noiselevel=-1, level=logging.ERROR)
+
+ if addrinfos:
+
+ AF_INET = socket.AF_INET
+ AF_INET6 = None
+ if socket.has_ipv6:
+ AF_INET6 = socket.AF_INET6
+
+ ips_v4 = []
+ ips_v6 = []
+
+ for addrinfo in addrinfos:
+ if addrinfo[0] == AF_INET:
+ ips_v4.append("%s" % addrinfo[4][0])
+ elif AF_INET6 is not None and addrinfo[0] == AF_INET6:
+ # IPv6 addresses need to be enclosed in square brackets
+ ips_v6.append("[%s]" % addrinfo[4][0])
+
+ random.shuffle(ips_v4)
+ random.shuffle(ips_v6)
+
+ # Give priority to the address family that
+ # getaddrinfo() returned first.
+ if AF_INET6 is not None and addrinfos and \
+ addrinfos[0][0] == AF_INET6:
+ ips = ips_v6 + ips_v4
+ else:
+ ips = ips_v4 + ips_v6
+
+ for ip in ips:
+ uris.append(syncuri.replace(
+ "//" + user_name + hostname + port + "/",
+ "//" + user_name + ip + port + "/", 1))
+
+ if not uris:
+ # With some configurations we need to use the plain hostname
+ # rather than try to resolve the ip addresses (bug #340817).
+ uris.append(syncuri)
+
+ # reverse, for use with pop()
+ uris.reverse()
+
+ effective_maxretries = maxretries
+ if effective_maxretries < 0:
+ effective_maxretries = len(uris) - 1
+
+ SERVER_OUT_OF_DATE = -1
+ EXCEEDED_MAX_RETRIES = -2
+ while (1):
+ if uris:
+ dosyncuri = uris.pop()
+ else:
+ writemsg("!!! Exhausted addresses for %s\n" % \
+ hostname, noiselevel=-1)
+ return 1
+
+ if (retries==0):
+ if "--ask" in myopts:
+ if userquery("Do you want to sync your Portage tree " + \
+ "with the mirror at\n" + blue(dosyncuri) + bold("?"),
+ enter_invalid) == "No":
+ print()
+ print("Quitting.")
+ print()
+ sys.exit(0)
+ emergelog(xterm_titles, ">>> Starting rsync with " + dosyncuri)
+ if "--quiet" not in myopts:
+ print(">>> Starting rsync with "+dosyncuri+"...")
+ else:
+ emergelog(xterm_titles,
+ ">>> Starting retry %d of %d with %s" % \
+ (retries, effective_maxretries, dosyncuri))
+ writemsg_stdout(
+ "\n\n>>> Starting retry %d of %d with %s\n" % \
+ (retries, effective_maxretries, dosyncuri), noiselevel=-1)
+
+ if dosyncuri.startswith('ssh://'):
+ dosyncuri = dosyncuri[6:].replace('/', ':/', 1)
+
+ if mytimestamp != 0 and "--quiet" not in myopts:
+ print(">>> Checking server timestamp ...")
+
+ rsynccommand = ["/usr/bin/rsync"] + rsync_opts + extra_rsync_opts
+
+ if "--debug" in myopts:
+ print(rsynccommand)
+
+ exitcode = os.EX_OK
+ servertimestamp = 0
+ # Even if there's no timestamp available locally, fetch the
+ # timestamp anyway as an initial probe to verify that the server is
+ # responsive. This protects us from hanging indefinitely on a
+ # connection attempt to an unresponsive server which rsync's
+ # --timeout option does not prevent.
+ if True:
+ # Temporary file for remote server timestamp comparison.
+ # NOTE: If FEATURES=usersync is enabled then the tempfile
+ # needs to be in a directory that's readable by the usersync
+ # user. We assume that PORTAGE_TMPDIR will satisfy this
+ # requirement, since that's not necessarily true for the
+ # default directory used by the tempfile module.
+ if usersync_uid is not None:
+ tmpdir = settings['PORTAGE_TMPDIR']
+ else:
+ # use default dir from tempfile module
+ tmpdir = None
+ fd, tmpservertimestampfile = \
+ tempfile.mkstemp(dir=tmpdir)
+ os.close(fd)
+ if usersync_uid is not None:
+ portage.util.apply_permissions(tmpservertimestampfile,
+ uid=usersync_uid)
+ mycommand = rsynccommand[:]
+ mycommand.append(dosyncuri.rstrip("/") + \
+ "/metadata/timestamp.chk")
+ mycommand.append(tmpservertimestampfile)
+ content = None
+ mypids = []
+ try:
+ # Timeout here in case the server is unresponsive. The
+ # --timeout rsync option doesn't apply to the initial
+ # connection attempt.
+ try:
+ if rsync_initial_timeout:
+ portage.exception.AlarmSignal.register(
+ rsync_initial_timeout)
+
+ mypids.extend(portage.process.spawn(
+ mycommand, returnpid=True, **spawn_kwargs))
+ exitcode = os.waitpid(mypids[0], 0)[1]
+ if usersync_uid is not None:
+ portage.util.apply_permissions(tmpservertimestampfile,
+ uid=os.getuid())
+ content = portage.grabfile(tmpservertimestampfile)
+ finally:
+ if rsync_initial_timeout:
+ portage.exception.AlarmSignal.unregister()
+ try:
+ os.unlink(tmpservertimestampfile)
+ except OSError:
+ pass
+ except portage.exception.AlarmSignal:
+ # timed out
+ print('timed out')
+ # With waitpid and WNOHANG, only check the
+ # first element of the tuple since the second
+ # element may vary (bug #337465).
+ if mypids and os.waitpid(mypids[0], os.WNOHANG)[0] == 0:
+ os.kill(mypids[0], signal.SIGTERM)
+ os.waitpid(mypids[0], 0)
+ # This is the same code rsync uses for timeout.
+ exitcode = 30
+ else:
+ if exitcode != os.EX_OK:
+ if exitcode & 0xff:
+ exitcode = (exitcode & 0xff) << 8
+ else:
+ exitcode = exitcode >> 8
+ if mypids:
+ portage.process.spawned_pids.remove(mypids[0])
+ if content:
+ try:
+ servertimestamp = time.mktime(time.strptime(
+ content[0], "%a, %d %b %Y %H:%M:%S +0000"))
+ except (OverflowError, ValueError):
+ pass
+ del mycommand, mypids, content
+ if exitcode == os.EX_OK:
+ if (servertimestamp != 0) and (servertimestamp == mytimestamp):
+ emergelog(xterm_titles,
+ ">>> Cancelling sync -- Already current.")
+ print()
+ print(">>>")
+ print(">>> Timestamps on the server and in the local repository are the same.")
+ print(">>> Cancelling all further sync action. You are already up to date.")
+ print(">>>")
+ print(">>> In order to force sync, remove '%s'." % servertimestampfile)
+ print(">>>")
+ print()
+ sys.exit(0)
+ elif (servertimestamp != 0) and (servertimestamp < mytimestamp):
+ emergelog(xterm_titles,
+ ">>> Server out of date: %s" % dosyncuri)
+ print()
+ print(">>>")
+ print(">>> SERVER OUT OF DATE: %s" % dosyncuri)
+ print(">>>")
+ print(">>> In order to force sync, remove '%s'." % servertimestampfile)
+ print(">>>")
+ print()
+ exitcode = SERVER_OUT_OF_DATE
+ elif (servertimestamp == 0) or (servertimestamp > mytimestamp):
+ # actual sync
+ mycommand = rsynccommand + [dosyncuri+"/", myportdir]
+ exitcode = portage.process.spawn(mycommand, **spawn_kwargs)
+ if exitcode in [0,1,3,4,11,14,20,21]:
+ break
+ elif exitcode in [1,3,4,11,14,20,21]:
+ break
+ else:
+ # Code 2 indicates protocol incompatibility, which is expected
+ # for servers with protocol < 29 that don't support
+ # --prune-empty-directories. Retry for a server that supports
+ # at least rsync protocol version 29 (>=rsync-2.6.4).
+ pass
+
+ retries=retries+1
+
+ if maxretries < 0 or retries <= maxretries:
+ print(">>> Retrying...")
+ else:
+ # over retries
+ # exit loop
+ updatecache_flg=False
+ exitcode = EXCEEDED_MAX_RETRIES
+ break
+
+ if (exitcode==0):
+ emergelog(xterm_titles, "=== Sync completed with %s" % dosyncuri)
+ elif exitcode == SERVER_OUT_OF_DATE:
+ sys.exit(1)
+ elif exitcode == EXCEEDED_MAX_RETRIES:
+ sys.stderr.write(
+ ">>> Exceeded PORTAGE_RSYNC_RETRIES: %s\n" % maxretries)
+ sys.exit(1)
+ elif (exitcode>0):
+ msg = []
+ if exitcode==1:
+ msg.append("Rsync has reported that there is a syntax error. Please ensure")
+ msg.append("that your SYNC statement is proper.")
+ msg.append("SYNC=" + settings["SYNC"])
+ elif exitcode==11:
+ msg.append("Rsync has reported that there is a File IO error. Normally")
+ msg.append("this means your disk is full, but can be caused by corruption")
+ msg.append("on the filesystem that contains PORTDIR. Please investigate")
+ msg.append("and try again after the problem has been fixed.")
+ msg.append("PORTDIR=" + settings["PORTDIR"])
+ elif exitcode==20:
+ msg.append("Rsync was killed before it finished.")
+ else:
+ msg.append("Rsync has not successfully finished. It is recommended that you keep")
+ msg.append("trying or that you use the 'emerge-webrsync' option if you are unable")
+ msg.append("to use rsync due to firewall or other restrictions. This should be a")
+ msg.append("temporary problem unless complications exist with your network")
+ msg.append("(and possibly your system's filesystem) configuration.")
+ for line in msg:
+ out.eerror(line)
+ sys.exit(exitcode)
+ elif syncuri[:6]=="cvs://":
+ if not os.path.exists("/usr/bin/cvs"):
+ print("!!! /usr/bin/cvs does not exist, so CVS support is disabled.")
+ print("!!! Type \"emerge dev-vcs/cvs\" to enable CVS support.")
+ sys.exit(1)
+ cvsroot=syncuri[6:]
+ cvsdir=os.path.dirname(myportdir)
+ if not os.path.exists(myportdir+"/CVS"):
+ #initial checkout
+ print(">>> Starting initial cvs checkout with "+syncuri+"...")
+ if os.path.exists(cvsdir+"/gentoo-x86"):
+ print("!!! existing",cvsdir+"/gentoo-x86 directory; exiting.")
+ sys.exit(1)
+ try:
+ os.rmdir(myportdir)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ sys.stderr.write(
+ "!!! existing '%s' directory; exiting.\n" % myportdir)
+ sys.exit(1)
+ del e
+ if portage.process.spawn_bash(
+ "cd %s; exec cvs -z0 -d %s co -P gentoo-x86" % \
+ (portage._shell_quote(cvsdir), portage._shell_quote(cvsroot)),
+ **spawn_kwargs) != os.EX_OK:
+ print("!!! cvs checkout error; exiting.")
+ sys.exit(1)
+ os.rename(os.path.join(cvsdir, "gentoo-x86"), myportdir)
+ else:
+ #cvs update
+ print(">>> Starting cvs update with "+syncuri+"...")
+ retval = portage.process.spawn_bash(
+ "cd %s; exec cvs -z0 -q update -dP" % \
+ (portage._shell_quote(myportdir),), **spawn_kwargs)
+ if retval != os.EX_OK:
+ writemsg_level("!!! cvs update error; exiting.\n",
+ noiselevel=-1, level=logging.ERROR)
+ sys.exit(retval)
+ dosyncuri = syncuri
+ else:
+ writemsg_level("!!! Unrecognized protocol: SYNC='%s'\n" % (syncuri,),
+ noiselevel=-1, level=logging.ERROR)
+ return 1
+
+ if updatecache_flg and \
+ myaction != "metadata" and \
+ "metadata-transfer" not in settings.features:
+ updatecache_flg = False
+
+ # Reload the whole config from scratch.
+ settings, trees, mtimedb = load_emerge_config(trees=trees)
+ adjust_configs(myopts, trees)
+ root_config = trees[settings["ROOT"]]["root_config"]
+ portdb = trees[settings["ROOT"]]["porttree"].dbapi
+
+ if updatecache_flg and \
+ os.path.exists(os.path.join(myportdir, 'metadata', 'cache')):
+
+ # Only update cache for myportdir since that's
+ # the only one that's been synced here.
+ action_metadata(settings, portdb, myopts, porttrees=[myportdir])
+
+ if myopts.get('--package-moves') != 'n' and \
+ _global_updates(trees, mtimedb["updates"], quiet=("--quiet" in myopts)):
+ mtimedb.commit()
+ # Reload the whole config from scratch.
+ settings, trees, mtimedb = load_emerge_config(trees=trees)
+ adjust_configs(myopts, trees)
+ portdb = trees[settings["ROOT"]]["porttree"].dbapi
+ root_config = trees[settings["ROOT"]]["root_config"]
+
+ mybestpv = portdb.xmatch("bestmatch-visible",
+ portage.const.PORTAGE_PACKAGE_ATOM)
+ mypvs = portage.best(
+ trees[settings["ROOT"]]["vartree"].dbapi.match(
+ portage.const.PORTAGE_PACKAGE_ATOM))
+
+ chk_updated_cfg_files(settings["EROOT"],
+ portage.util.shlex_split(settings.get("CONFIG_PROTECT", "")))
+
+ if myaction != "metadata":
+ postsync = os.path.join(settings["PORTAGE_CONFIGROOT"],
+ portage.USER_CONFIG_PATH, "bin", "post_sync")
+ if os.access(postsync, os.X_OK):
+ retval = portage.process.spawn(
+ [postsync, dosyncuri], env=settings.environ())
+ if retval != os.EX_OK:
+ writemsg_level(
+ " %s spawn failed of %s\n" % (bad("*"), postsync,),
+ level=logging.ERROR, noiselevel=-1)
+
+ if(mybestpv != mypvs) and not "--quiet" in myopts:
+ print()
+ print(red(" * ")+bold("An update to portage is available.")+" It is _highly_ recommended")
+ print(red(" * ")+"that you update portage now, before any other packages are updated.")
+ print()
+ print(red(" * ")+"To update portage, run 'emerge portage' now.")
+ print()
+
+ display_news_notification(root_config, myopts)
+ return os.EX_OK
+
+def action_uninstall(settings, trees, ldpath_mtimes,
+ opts, action, files, spinner):
+ # For backward compat, some actions do not require leading '='.
+ ignore_missing_eq = action in ('clean', 'unmerge')
+ root = settings['ROOT']
+ vardb = trees[root]['vartree'].dbapi
+ valid_atoms = []
+ lookup_owners = []
+
+ # Ensure atoms are valid before calling unmerge().
+ # For backward compat, leading '=' is not required.
+ for x in files:
+ if is_valid_package_atom(x, allow_repo=True) or \
+ (ignore_missing_eq and is_valid_package_atom('=' + x)):
+
+ try:
+ atom = dep_expand(x, mydb=vardb, settings=settings)
+ except portage.exception.AmbiguousPackageName as e:
+ msg = "The short ebuild name \"" + x + \
+ "\" is ambiguous. Please specify " + \
+ "one of the following " + \
+ "fully-qualified ebuild names instead:"
+ for line in textwrap.wrap(msg, 70):
+ writemsg_level("!!! %s\n" % (line,),
+ level=logging.ERROR, noiselevel=-1)
+ for i in e.args[0]:
+ writemsg_level(" %s\n" % colorize("INFORM", i),
+ level=logging.ERROR, noiselevel=-1)
+ writemsg_level("\n", level=logging.ERROR, noiselevel=-1)
+ return 1
+ else:
+ if atom.use and atom.use.conditional:
+ writemsg_level(
+ ("\n\n!!! '%s' contains a conditional " + \
+ "which is not allowed.\n") % (x,),
+ level=logging.ERROR, noiselevel=-1)
+ writemsg_level(
+ "!!! Please check ebuild(5) for full details.\n",
+ level=logging.ERROR)
+ return 1
+ valid_atoms.append(atom)
+
+ elif x.startswith(os.sep):
+ if not x.startswith(root):
+ writemsg_level(("!!! '%s' does not start with" + \
+ " $ROOT.\n") % x, level=logging.ERROR, noiselevel=-1)
+ return 1
+ # Queue these up since it's most efficient to handle
+ # multiple files in a single iter_owners() call.
+ lookup_owners.append(x)
+
+ elif x.startswith(SETPREFIX) and action == "deselect":
+ valid_atoms.append(x)
+
+ elif "*" in x:
+ try:
+ ext_atom = Atom(x, allow_repo=True, allow_wildcard=True)
+ except InvalidAtom:
+ msg = []
+ msg.append("'%s' is not a valid package atom." % (x,))
+ msg.append("Please check ebuild(5) for full details.")
+ writemsg_level("".join("!!! %s\n" % line for line in msg),
+ level=logging.ERROR, noiselevel=-1)
+ return 1
+
+ for cp in vardb.cp_all():
+ if extended_cp_match(ext_atom.cp, cp):
+ atom = cp
+ if ext_atom.slot:
+ atom += ":" + ext_atom.slot
+ if ext_atom.repo:
+ atom += "::" + ext_atom.repo
+
+ if vardb.match(atom):
+ valid_atoms.append(Atom(atom, allow_repo=True))
+
+ else:
+ msg = []
+ msg.append("'%s' is not a valid package atom." % (x,))
+ msg.append("Please check ebuild(5) for full details.")
+ writemsg_level("".join("!!! %s\n" % line for line in msg),
+ level=logging.ERROR, noiselevel=-1)
+ return 1
+
+ if lookup_owners:
+ relative_paths = []
+ search_for_multiple = False
+ if len(lookup_owners) > 1:
+ search_for_multiple = True
+
+ for x in lookup_owners:
+ if not search_for_multiple and os.path.isdir(x):
+ search_for_multiple = True
+ relative_paths.append(x[len(root)-1:])
+
+ owners = set()
+ for pkg, relative_path in \
+ vardb._owners.iter_owners(relative_paths):
+ owners.add(pkg.mycpv)
+ if not search_for_multiple:
+ break
+
+ if owners:
+ for cpv in owners:
+ slot = vardb.aux_get(cpv, ['SLOT'])[0]
+ if not slot:
+ # portage now masks packages with missing slot, but it's
+ # possible that one was installed by an older version
+ atom = portage.cpv_getkey(cpv)
+ else:
+ atom = '%s:%s' % (portage.cpv_getkey(cpv), slot)
+ valid_atoms.append(portage.dep.Atom(atom))
+ else:
+ writemsg_level(("!!! '%s' is not claimed " + \
+ "by any package.\n") % lookup_owners[0],
+ level=logging.WARNING, noiselevel=-1)
+
+ if files and not valid_atoms:
+ return 1
+
+ if action == 'unmerge' and \
+ '--quiet' not in opts and \
+ '--quiet-unmerge-warn' not in opts:
+ msg = "This action can remove important packages! " + \
+ "In order to be safer, use " + \
+ "`emerge -pv --depclean <atom>` to check for " + \
+ "reverse dependencies before removing packages."
+ out = portage.output.EOutput()
+ for line in textwrap.wrap(msg, 72):
+ out.ewarn(line)
+
+ if action == 'deselect':
+ return action_deselect(settings, trees, opts, valid_atoms)
+
+ # Create a Scheduler for calls to unmerge(), in order to cause
+ # redirection of ebuild phase output to logs as required for
+ # options such as --quiet.
+ sched = Scheduler(settings, trees, None, opts,
+ spinner)
+ sched._background = sched._background_mode()
+ sched._status_display.quiet = True
+
+ if sched._background:
+ sched.settings.unlock()
+ sched.settings["PORTAGE_BACKGROUND"] = "1"
+ sched.settings.backup_changes("PORTAGE_BACKGROUND")
+ sched.settings.lock()
+ sched.pkgsettings[root] = portage.config(clone=sched.settings)
+
+ if action in ('clean', 'unmerge') or \
+ (action == 'prune' and "--nodeps" in opts):
+ # When given a list of atoms, unmerge them in the order given.
+ ordered = action == 'unmerge'
+ unmerge(trees[settings["ROOT"]]['root_config'], opts, action,
+ valid_atoms, ldpath_mtimes, ordered=ordered,
+ scheduler=sched._sched_iface)
+ rval = os.EX_OK
+ else:
+ rval = action_depclean(settings, trees, ldpath_mtimes,
+ opts, action, valid_atoms, spinner, scheduler=sched._sched_iface)
+
+ return rval
+
+def adjust_configs(myopts, trees):
+ for myroot in trees:
+ mysettings = trees[myroot]["vartree"].settings
+ mysettings.unlock()
+ adjust_config(myopts, mysettings)
+ mysettings.lock()
+
+def adjust_config(myopts, settings):
+ """Make emerge specific adjustments to the config."""
+
+ # Kill noauto as it will break merges otherwise.
+ if "noauto" in settings.features:
+ settings.features.remove('noauto')
+
+ fail_clean = myopts.get('--fail-clean')
+ if fail_clean is not None:
+ if fail_clean is True and \
+ 'fail-clean' not in settings.features:
+ settings.features.add('fail-clean')
+ elif fail_clean == 'n' and \
+ 'fail-clean' in settings.features:
+ settings.features.remove('fail-clean')
+
+ CLEAN_DELAY = 5
+ try:
+ CLEAN_DELAY = int(settings.get("CLEAN_DELAY", str(CLEAN_DELAY)))
+ except ValueError as e:
+ portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
+ portage.writemsg("!!! Unable to parse integer: CLEAN_DELAY='%s'\n" % \
+ settings["CLEAN_DELAY"], noiselevel=-1)
+ settings["CLEAN_DELAY"] = str(CLEAN_DELAY)
+ settings.backup_changes("CLEAN_DELAY")
+
+ EMERGE_WARNING_DELAY = 10
+ try:
+ EMERGE_WARNING_DELAY = int(settings.get(
+ "EMERGE_WARNING_DELAY", str(EMERGE_WARNING_DELAY)))
+ except ValueError as e:
+ portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
+ portage.writemsg("!!! Unable to parse integer: EMERGE_WARNING_DELAY='%s'\n" % \
+ settings["EMERGE_WARNING_DELAY"], noiselevel=-1)
+ settings["EMERGE_WARNING_DELAY"] = str(EMERGE_WARNING_DELAY)
+ settings.backup_changes("EMERGE_WARNING_DELAY")
+
+ if "--quiet" in myopts or "--quiet-build" in myopts:
+ settings["PORTAGE_QUIET"]="1"
+ settings.backup_changes("PORTAGE_QUIET")
+
+ if "--verbose" in myopts:
+ settings["PORTAGE_VERBOSE"] = "1"
+ settings.backup_changes("PORTAGE_VERBOSE")
+
+ # Set so that configs will be merged regardless of remembered status
+ if ("--noconfmem" in myopts):
+ settings["NOCONFMEM"]="1"
+ settings.backup_changes("NOCONFMEM")
+
+ # Set various debug markers... They should be merged somehow.
+ PORTAGE_DEBUG = 0
+ try:
+ PORTAGE_DEBUG = int(settings.get("PORTAGE_DEBUG", str(PORTAGE_DEBUG)))
+ if PORTAGE_DEBUG not in (0, 1):
+ portage.writemsg("!!! Invalid value: PORTAGE_DEBUG='%i'\n" % \
+ PORTAGE_DEBUG, noiselevel=-1)
+ portage.writemsg("!!! PORTAGE_DEBUG must be either 0 or 1\n",
+ noiselevel=-1)
+ PORTAGE_DEBUG = 0
+ except ValueError as e:
+ portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
+ portage.writemsg("!!! Unable to parse integer: PORTAGE_DEBUG='%s'\n" %\
+ settings["PORTAGE_DEBUG"], noiselevel=-1)
+ del e
+ if "--debug" in myopts:
+ PORTAGE_DEBUG = 1
+ settings["PORTAGE_DEBUG"] = str(PORTAGE_DEBUG)
+ settings.backup_changes("PORTAGE_DEBUG")
+
+ if settings.get("NOCOLOR") not in ("yes","true"):
+ portage.output.havecolor = 1
+
+ """The explicit --color < y | n > option overrides the NOCOLOR environment
+ variable and stdout auto-detection."""
+ if "--color" in myopts:
+ if "y" == myopts["--color"]:
+ portage.output.havecolor = 1
+ settings["NOCOLOR"] = "false"
+ else:
+ portage.output.havecolor = 0
+ settings["NOCOLOR"] = "true"
+ settings.backup_changes("NOCOLOR")
+ elif settings.get('TERM') == 'dumb' or \
+ not sys.stdout.isatty():
+ portage.output.havecolor = 0
+ settings["NOCOLOR"] = "true"
+ settings.backup_changes("NOCOLOR")
+
+def display_missing_pkg_set(root_config, set_name):
+
+ msg = []
+ msg.append(("emerge: There are no sets to satisfy '%s'. " + \
+ "The following sets exist:") % \
+ colorize("INFORM", set_name))
+ msg.append("")
+
+ for s in sorted(root_config.sets):
+ msg.append(" %s" % s)
+ msg.append("")
+
+ writemsg_level("".join("%s\n" % l for l in msg),
+ level=logging.ERROR, noiselevel=-1)
+
+def relative_profile_path(portdir, abs_profile):
+ realpath = os.path.realpath(abs_profile)
+ basepath = os.path.realpath(os.path.join(portdir, "profiles"))
+ if realpath.startswith(basepath):
+ profilever = realpath[1 + len(basepath):]
+ else:
+ profilever = None
+ return profilever
+
+def getportageversion(portdir, target_root, profile, chost, vardb):
+ profilever = None
+ if profile:
+ profilever = relative_profile_path(portdir, profile)
+ if profilever is None:
+ try:
+ for parent in portage.grabfile(
+ os.path.join(profile, 'parent')):
+ profilever = relative_profile_path(portdir,
+ os.path.join(profile, parent))
+ if profilever is not None:
+ break
+ except portage.exception.PortageException:
+ pass
+
+ if profilever is None:
+ try:
+ profilever = "!" + os.readlink(profile)
+ except (OSError):
+ pass
+
+ if profilever is None:
+ profilever = "unavailable"
+
+ libcver = []
+ libclist = set()
+ for atom in expand_new_virt(vardb, portage.const.LIBC_PACKAGE_ATOM):
+ if not atom.blocker:
+ libclist.update(vardb.match(atom))
+ if libclist:
+ for cpv in sorted(libclist):
+ libc_split = portage.catpkgsplit(cpv)[1:]
+ if libc_split[-1] == "r0":
+ libc_split[:-1]
+ libcver.append("-".join(libc_split))
+ else:
+ libcver = ["unavailable"]
+
+ gccver = getgccversion(chost)
+ unameout=platform.release()+" "+platform.machine()
+
+ return "Portage %s (%s, %s, %s, %s)" % \
+ (portage.VERSION, profilever, gccver, ",".join(libcver), unameout)
+
+def git_sync_timestamps(settings, portdir):
+ """
+ Since git doesn't preserve timestamps, synchronize timestamps between
+ entries and ebuilds/eclasses. Assume the cache has the correct timestamp
+ for a given file as long as the file in the working tree is not modified
+ (relative to HEAD).
+ """
+ cache_dir = os.path.join(portdir, "metadata", "cache")
+ if not os.path.isdir(cache_dir):
+ return os.EX_OK
+ writemsg_level(">>> Synchronizing timestamps...\n")
+
+ from portage.cache.cache_errors import CacheError
+ try:
+ cache_db = settings.load_best_module("portdbapi.metadbmodule")(
+ portdir, "metadata/cache", portage.auxdbkeys[:], readonly=True)
+ except CacheError as e:
+ writemsg_level("!!! Unable to instantiate cache: %s\n" % (e,),
+ level=logging.ERROR, noiselevel=-1)
+ return 1
+
+ ec_dir = os.path.join(portdir, "eclass")
+ try:
+ ec_names = set(f[:-7] for f in os.listdir(ec_dir) \
+ if f.endswith(".eclass"))
+ except OSError as e:
+ writemsg_level("!!! Unable to list eclasses: %s\n" % (e,),
+ level=logging.ERROR, noiselevel=-1)
+ return 1
+
+ args = [portage.const.BASH_BINARY, "-c",
+ "cd %s && git diff-index --name-only --diff-filter=M HEAD" % \
+ portage._shell_quote(portdir)]
+ import subprocess
+ proc = subprocess.Popen(args, stdout=subprocess.PIPE)
+ modified_files = set(_unicode_decode(l).rstrip("\n") for l in proc.stdout)
+ rval = proc.wait()
+ if rval != os.EX_OK:
+ return rval
+
+ modified_eclasses = set(ec for ec in ec_names \
+ if os.path.join("eclass", ec + ".eclass") in modified_files)
+
+ updated_ec_mtimes = {}
+
+ for cpv in cache_db:
+ cpv_split = portage.catpkgsplit(cpv)
+ if cpv_split is None:
+ writemsg_level("!!! Invalid cache entry: %s\n" % (cpv,),
+ level=logging.ERROR, noiselevel=-1)
+ continue
+
+ cat, pn, ver, rev = cpv_split
+ cat, pf = portage.catsplit(cpv)
+ relative_eb_path = os.path.join(cat, pn, pf + ".ebuild")
+ if relative_eb_path in modified_files:
+ continue
+
+ try:
+ cache_entry = cache_db[cpv]
+ eb_mtime = cache_entry.get("_mtime_")
+ ec_mtimes = cache_entry.get("_eclasses_")
+ except KeyError:
+ writemsg_level("!!! Missing cache entry: %s\n" % (cpv,),
+ level=logging.ERROR, noiselevel=-1)
+ continue
+ except CacheError as e:
+ writemsg_level("!!! Unable to access cache entry: %s %s\n" % \
+ (cpv, e), level=logging.ERROR, noiselevel=-1)
+ continue
+
+ if eb_mtime is None:
+ writemsg_level("!!! Missing ebuild mtime: %s\n" % (cpv,),
+ level=logging.ERROR, noiselevel=-1)
+ continue
+
+ try:
+ eb_mtime = long(eb_mtime)
+ except ValueError:
+ writemsg_level("!!! Invalid ebuild mtime: %s %s\n" % \
+ (cpv, eb_mtime), level=logging.ERROR, noiselevel=-1)
+ continue
+
+ if ec_mtimes is None:
+ writemsg_level("!!! Missing eclass mtimes: %s\n" % (cpv,),
+ level=logging.ERROR, noiselevel=-1)
+ continue
+
+ if modified_eclasses.intersection(ec_mtimes):
+ continue
+
+ missing_eclasses = set(ec_mtimes).difference(ec_names)
+ if missing_eclasses:
+ writemsg_level("!!! Non-existent eclass(es): %s %s\n" % \
+ (cpv, sorted(missing_eclasses)), level=logging.ERROR,
+ noiselevel=-1)
+ continue
+
+ eb_path = os.path.join(portdir, relative_eb_path)
+ try:
+ current_eb_mtime = os.stat(eb_path)
+ except OSError:
+ writemsg_level("!!! Missing ebuild: %s\n" % \
+ (cpv,), level=logging.ERROR, noiselevel=-1)
+ continue
+
+ inconsistent = False
+ for ec, (ec_path, ec_mtime) in ec_mtimes.items():
+ updated_mtime = updated_ec_mtimes.get(ec)
+ if updated_mtime is not None and updated_mtime != ec_mtime:
+ writemsg_level("!!! Inconsistent eclass mtime: %s %s\n" % \
+ (cpv, ec), level=logging.ERROR, noiselevel=-1)
+ inconsistent = True
+ break
+
+ if inconsistent:
+ continue
+
+ if current_eb_mtime != eb_mtime:
+ os.utime(eb_path, (eb_mtime, eb_mtime))
+
+ for ec, (ec_path, ec_mtime) in ec_mtimes.items():
+ if ec in updated_ec_mtimes:
+ continue
+ ec_path = os.path.join(ec_dir, ec + ".eclass")
+ current_mtime = os.stat(ec_path)[stat.ST_MTIME]
+ if current_mtime != ec_mtime:
+ os.utime(ec_path, (ec_mtime, ec_mtime))
+ updated_ec_mtimes[ec] = ec_mtime
+
+ return os.EX_OK
+
+def load_emerge_config(trees=None):
+ kwargs = {}
+ for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT")):
+ v = os.environ.get(envvar, None)
+ if v and v.strip():
+ kwargs[k] = v
+ trees = portage.create_trees(trees=trees, **kwargs)
+
+ for root, root_trees in trees.items():
+ settings = root_trees["vartree"].settings
+ settings._init_dirs()
+ setconfig = load_default_config(settings, root_trees)
+ root_trees["root_config"] = RootConfig(settings, root_trees, setconfig)
+
+ settings = trees["/"]["vartree"].settings
+
+ for myroot in trees:
+ if myroot != "/":
+ settings = trees[myroot]["vartree"].settings
+ break
+
+ mtimedbfile = os.path.join(settings['EROOT'], portage.CACHE_PATH, "mtimedb")
+ mtimedb = portage.MtimeDB(mtimedbfile)
+ portage.output._init(config_root=settings['PORTAGE_CONFIGROOT'])
+ QueryCommand._db = trees
+ return settings, trees, mtimedb
+
+def chk_updated_cfg_files(eroot, config_protect):
+ target_root = eroot
+ result = list(
+ portage.util.find_updated_config_files(target_root, config_protect))
+
+ for x in result:
+ writemsg_level("\n %s " % (colorize("WARN", "* IMPORTANT:"),),
+ level=logging.INFO, noiselevel=-1)
+ if not x[1]: # it's a protected file
+ writemsg_level("config file '%s' needs updating.\n" % x[0],
+ level=logging.INFO, noiselevel=-1)
+ else: # it's a protected dir
+ if len(x[1]) == 1:
+ head, tail = os.path.split(x[1][0])
+ tail = tail[len("._cfg0000_"):]
+ fpath = os.path.join(head, tail)
+ writemsg_level("config file '%s' needs updating.\n" % fpath,
+ level=logging.INFO, noiselevel=-1)
+ else:
+ writemsg_level("%d config files in '%s' need updating.\n" % \
+ (len(x[1]), x[0]), level=logging.INFO, noiselevel=-1)
+
+ if result:
+ print(" "+yellow("*")+" See the "+colorize("INFORM","CONFIGURATION FILES")\
+ + " section of the " + bold("emerge"))
+ print(" "+yellow("*")+" man page to learn how to update config files.")
+
+def display_news_notification(root_config, myopts):
+ target_root = root_config.settings['EROOT']
+ trees = root_config.trees
+ settings = trees["vartree"].settings
+ portdb = trees["porttree"].dbapi
+ vardb = trees["vartree"].dbapi
+ NEWS_PATH = os.path.join("metadata", "news")
+ UNREAD_PATH = os.path.join(target_root, NEWS_LIB_PATH, "news")
+ newsReaderDisplay = False
+ update = "--pretend" not in myopts
+ if "news" not in settings.features:
+ return
+
+ for repo in portdb.getRepositories():
+ unreadItems = checkUpdatedNewsItems(
+ portdb, vardb, NEWS_PATH, UNREAD_PATH, repo, update=update)
+ if unreadItems:
+ if not newsReaderDisplay:
+ newsReaderDisplay = True
+ print()
+ print(colorize("WARN", " * IMPORTANT:"), end=' ')
+ print("%s news items need reading for repository '%s'." % (unreadItems, repo))
+
+
+ if newsReaderDisplay:
+ print(colorize("WARN", " *"), end=' ')
+ print("Use " + colorize("GOOD", "eselect news") + " to read news items.")
+ print()
+
+def getgccversion(chost):
+ """
+ rtype: C{str}
+ return: the current in-use gcc version
+ """
+
+ gcc_ver_command = 'gcc -dumpversion'
+ gcc_ver_prefix = 'gcc-'
+
+ gcc_not_found_error = red(
+ "!!! No gcc found. You probably need to 'source /etc/profile'\n" +
+ "!!! to update the environment of this terminal and possibly\n" +
+ "!!! other terminals also.\n"
+ )
+
+ mystatus, myoutput = subprocess_getstatusoutput("gcc-config -c")
+ if mystatus == os.EX_OK and myoutput.startswith(chost + "-"):
+ return myoutput.replace(chost + "-", gcc_ver_prefix, 1)
+
+ mystatus, myoutput = subprocess_getstatusoutput(
+ chost + "-" + gcc_ver_command)
+ if mystatus == os.EX_OK:
+ return gcc_ver_prefix + myoutput
+
+ mystatus, myoutput = subprocess_getstatusoutput(gcc_ver_command)
+ if mystatus == os.EX_OK:
+ return gcc_ver_prefix + myoutput
+
+ portage.writemsg(gcc_not_found_error, noiselevel=-1)
+ return "[unavailable]"
+
+def checkUpdatedNewsItems(portdb, vardb, NEWS_PATH, UNREAD_PATH, repo_id,
+ update=False):
+ """
+ Examines news items in repodir + '/' + NEWS_PATH and attempts to find unread items
+ Returns the number of unread (yet relevent) items.
+
+ @param portdb: a portage tree database
+ @type portdb: pordbapi
+ @param vardb: an installed package database
+ @type vardb: vardbapi
+ @param NEWS_PATH:
+ @type NEWS_PATH:
+ @param UNREAD_PATH:
+ @type UNREAD_PATH:
+ @param repo_id:
+ @type repo_id:
+ @rtype: Integer
+ @returns:
+ 1. The number of unread but relevant news items.
+
+ """
+ from portage.news import NewsManager
+ manager = NewsManager(portdb, vardb, NEWS_PATH, UNREAD_PATH)
+ return manager.getUnreadItems( repo_id, update=update )
+
diff --git a/portage_with_autodep/pym/_emerge/clear_caches.py b/portage_with_autodep/pym/_emerge/clear_caches.py
new file mode 100644
index 0000000..7b7c5ec
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/clear_caches.py
@@ -0,0 +1,19 @@
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import gc
+from portage.util.listdir import dircache
+
+def clear_caches(trees):
+ for d in trees.values():
+ d["porttree"].dbapi.melt()
+ d["porttree"].dbapi._aux_cache.clear()
+ d["bintree"].dbapi._aux_cache.clear()
+ d["bintree"].dbapi._clear_cache()
+ if d["vartree"].dbapi._linkmap is None:
+ # preserve-libs is entirely disabled
+ pass
+ else:
+ d["vartree"].dbapi._linkmap._clear_cache()
+ dircache.clear()
+ gc.collect()
diff --git a/portage_with_autodep/pym/_emerge/countdown.py b/portage_with_autodep/pym/_emerge/countdown.py
new file mode 100644
index 0000000..5abdc8a
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/countdown.py
@@ -0,0 +1,22 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import sys
+import time
+
+from portage.output import colorize
+
+def countdown(secs=5, doing="Starting"):
+ if secs:
+ print(">>> Waiting",secs,"seconds before starting...")
+ print(">>> (Control-C to abort)...\n"+doing+" in: ", end=' ')
+ ticks=list(range(secs))
+ ticks.reverse()
+ for sec in ticks:
+ sys.stdout.write(colorize("UNMERGE_WARN", str(sec+1)+" "))
+ sys.stdout.flush()
+ time.sleep(1)
+ print()
+
diff --git a/portage_with_autodep/pym/_emerge/create_depgraph_params.py b/portage_with_autodep/pym/_emerge/create_depgraph_params.py
new file mode 100644
index 0000000..44dceda
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/create_depgraph_params.py
@@ -0,0 +1,72 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import logging
+from portage.util import writemsg_level
+
+def create_depgraph_params(myopts, myaction):
+ #configure emerge engine parameters
+ #
+ # self: include _this_ package regardless of if it is merged.
+ # selective: exclude the package if it is merged
+ # recurse: go into the dependencies
+ # deep: go into the dependencies of already merged packages
+ # empty: pretend nothing is merged
+ # complete: completely account for all known dependencies
+ # remove: build graph for use in removing packages
+ # rebuilt_binaries: replace installed packages with rebuilt binaries
+ myparams = {"recurse" : True}
+
+ bdeps = myopts.get("--with-bdeps")
+ if bdeps is not None:
+ myparams["bdeps"] = bdeps
+
+ if myaction == "remove":
+ myparams["remove"] = True
+ myparams["complete"] = True
+ myparams["selective"] = True
+ return myparams
+
+ if "--update" in myopts or \
+ "--newuse" in myopts or \
+ "--reinstall" in myopts or \
+ "--noreplace" in myopts or \
+ myopts.get("--selective", "n") != "n":
+ myparams["selective"] = True
+
+ deep = myopts.get("--deep")
+ if deep is not None and deep != 0:
+ myparams["deep"] = deep
+ if ("--complete-graph" in myopts or "--rebuild-if-new-rev" in myopts or
+ "--rebuild-if-new-ver" in myopts or "--rebuild-if-unbuilt" in myopts):
+ myparams["complete"] = True
+ if "--emptytree" in myopts:
+ myparams["empty"] = True
+ myparams["deep"] = True
+ myparams.pop("selective", None)
+
+ if "--nodeps" in myopts:
+ myparams.pop("recurse", None)
+ myparams.pop("deep", None)
+ myparams.pop("complete", None)
+
+ rebuilt_binaries = myopts.get('--rebuilt-binaries')
+ if rebuilt_binaries is True or \
+ rebuilt_binaries != 'n' and \
+ '--usepkgonly' in myopts and \
+ myopts.get('--deep') is True and \
+ '--update' in myopts:
+ myparams['rebuilt_binaries'] = True
+
+ if myopts.get("--selective") == "n":
+ # --selective=n can be used to remove selective
+ # behavior that may have been implied by some
+ # other option like --update.
+ myparams.pop("selective", None)
+
+ if '--debug' in myopts:
+ writemsg_level('\n\nmyparams %s\n\n' % myparams,
+ noiselevel=-1, level=logging.DEBUG)
+
+ return myparams
+
diff --git a/portage_with_autodep/pym/_emerge/create_world_atom.py b/portage_with_autodep/pym/_emerge/create_world_atom.py
new file mode 100644
index 0000000..fa7cffc
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/create_world_atom.py
@@ -0,0 +1,92 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.dep import _repo_separator
+
+def create_world_atom(pkg, args_set, root_config):
+ """Create a new atom for the world file if one does not exist. If the
+ argument atom is precise enough to identify a specific slot then a slot
+ atom will be returned. Atoms that are in the system set may also be stored
+ in world since system atoms can only match one slot while world atoms can
+ be greedy with respect to slots. Unslotted system packages will not be
+ stored in world."""
+
+ arg_atom = args_set.findAtomForPackage(pkg)
+ if not arg_atom:
+ return None
+ cp = arg_atom.cp
+ new_world_atom = cp
+ if arg_atom.repo:
+ new_world_atom += _repo_separator + arg_atom.repo
+ sets = root_config.sets
+ portdb = root_config.trees["porttree"].dbapi
+ vardb = root_config.trees["vartree"].dbapi
+ available_slots = set(portdb.aux_get(cpv, ["SLOT"])[0] \
+ for cpv in portdb.match(cp))
+ slotted = len(available_slots) > 1 or \
+ (len(available_slots) == 1 and "0" not in available_slots)
+ if not slotted:
+ # check the vdb in case this is multislot
+ available_slots = set(vardb.aux_get(cpv, ["SLOT"])[0] \
+ for cpv in vardb.match(cp))
+ slotted = len(available_slots) > 1 or \
+ (len(available_slots) == 1 and "0" not in available_slots)
+ if slotted and arg_atom.without_repo != cp:
+ # If the user gave a specific atom, store it as a
+ # slot atom in the world file.
+ slot_atom = pkg.slot_atom
+
+ # For USE=multislot, there are a couple of cases to
+ # handle here:
+ #
+ # 1) SLOT="0", but the real SLOT spontaneously changed to some
+ # unknown value, so just record an unslotted atom.
+ #
+ # 2) SLOT comes from an installed package and there is no
+ # matching SLOT in the portage tree.
+ #
+ # Make sure that the slot atom is available in either the
+ # portdb or the vardb, since otherwise the user certainly
+ # doesn't want the SLOT atom recorded in the world file
+ # (case 1 above). If it's only available in the vardb,
+ # the user may be trying to prevent a USE=multislot
+ # package from being removed by --depclean (case 2 above).
+
+ mydb = portdb
+ if not portdb.match(slot_atom):
+ # SLOT seems to come from an installed multislot package
+ mydb = vardb
+ # If there is no installed package matching the SLOT atom,
+ # it probably changed SLOT spontaneously due to USE=multislot,
+ # so just record an unslotted atom.
+ if vardb.match(slot_atom):
+ # Now verify that the argument is precise
+ # enough to identify a specific slot.
+ matches = mydb.match(arg_atom)
+ matched_slots = set()
+ for cpv in matches:
+ matched_slots.add(mydb.aux_get(cpv, ["SLOT"])[0])
+ if len(matched_slots) == 1:
+ new_world_atom = slot_atom
+ if arg_atom.repo:
+ new_world_atom += _repo_separator + arg_atom.repo
+
+ if new_world_atom == sets["selected"].findAtomForPackage(pkg):
+ # Both atoms would be identical, so there's nothing to add.
+ return None
+ if not slotted and not arg_atom.repo:
+ # Unlike world atoms, system atoms are not greedy for slots, so they
+ # can't be safely excluded from world if they are slotted.
+ system_atom = sets["system"].findAtomForPackage(pkg)
+ if system_atom:
+ if not system_atom.cp.startswith("virtual/"):
+ return None
+ # System virtuals aren't safe to exclude from world since they can
+ # match multiple old-style virtuals but only one of them will be
+ # pulled in by update or depclean.
+ providers = portdb.settings.getvirtuals().get(system_atom.cp)
+ if providers and len(providers) == 1 and \
+ providers[0].cp == arg_atom.cp:
+ return None
+ return new_world_atom
+
diff --git a/portage_with_autodep/pym/_emerge/depgraph.py b/portage_with_autodep/pym/_emerge/depgraph.py
new file mode 100644
index 0000000..5b48aca
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/depgraph.py
@@ -0,0 +1,7029 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import difflib
+import errno
+import io
+import logging
+import stat
+import sys
+import textwrap
+from collections import deque
+from itertools import chain
+
+import portage
+from portage import os, OrderedDict
+from portage import _unicode_decode, _unicode_encode, _encodings
+from portage.const import PORTAGE_PACKAGE_ATOM, USER_CONFIG_PATH
+from portage.dbapi import dbapi
+from portage.dep import Atom, extract_affecting_use, check_required_use, human_readable_required_use, _repo_separator
+from portage.eapi import eapi_has_strong_blocks, eapi_has_required_use
+from portage.exception import InvalidAtom, InvalidDependString, PortageException
+from portage.output import colorize, create_color_func, \
+ darkgreen, green
+bad = create_color_func("BAD")
+from portage.package.ebuild.getmaskingstatus import \
+ _getmaskingstatus, _MaskReason
+from portage._sets import SETPREFIX
+from portage._sets.base import InternalPackageSet
+from portage.util import ConfigProtect, shlex_split, new_protect_filename
+from portage.util import cmp_sort_key, writemsg, writemsg_stdout
+from portage.util import ensure_dirs
+from portage.util import writemsg_level, write_atomic
+from portage.util.digraph import digraph
+from portage.util.listdir import _ignorecvs_dirs
+from portage.versions import catpkgsplit
+
+from _emerge.AtomArg import AtomArg
+from _emerge.Blocker import Blocker
+from _emerge.BlockerCache import BlockerCache
+from _emerge.BlockerDepPriority import BlockerDepPriority
+from _emerge.countdown import countdown
+from _emerge.create_world_atom import create_world_atom
+from _emerge.Dependency import Dependency
+from _emerge.DependencyArg import DependencyArg
+from _emerge.DepPriority import DepPriority
+from _emerge.DepPriorityNormalRange import DepPriorityNormalRange
+from _emerge.DepPrioritySatisfiedRange import DepPrioritySatisfiedRange
+from _emerge.FakeVartree import FakeVartree
+from _emerge._find_deep_system_runtime_deps import _find_deep_system_runtime_deps
+from _emerge.is_valid_package_atom import insert_category_into_atom, \
+ is_valid_package_atom
+from _emerge.Package import Package
+from _emerge.PackageArg import PackageArg
+from _emerge.PackageVirtualDbapi import PackageVirtualDbapi
+from _emerge.RootConfig import RootConfig
+from _emerge.search import search
+from _emerge.SetArg import SetArg
+from _emerge.show_invalid_depstring_notice import show_invalid_depstring_notice
+from _emerge.UnmergeDepPriority import UnmergeDepPriority
+from _emerge.UseFlagDisplay import pkg_use_display
+from _emerge.userquery import userquery
+
+from _emerge.resolver.backtracking import Backtracker, BacktrackParameter
+from _emerge.resolver.slot_collision import slot_conflict_handler
+from _emerge.resolver.circular_dependency import circular_dependency_handler
+from _emerge.resolver.output import Display
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+ long = int
+
+class _scheduler_graph_config(object):
+ def __init__(self, trees, pkg_cache, graph, mergelist):
+ self.trees = trees
+ self.pkg_cache = pkg_cache
+ self.graph = graph
+ self.mergelist = mergelist
+
+def _wildcard_set(atoms):
+ pkgs = InternalPackageSet(allow_wildcard=True)
+ for x in atoms:
+ try:
+ x = Atom(x, allow_wildcard=True)
+ except portage.exception.InvalidAtom:
+ x = Atom("*/" + x, allow_wildcard=True)
+ pkgs.add(x)
+ return pkgs
+
+class _frozen_depgraph_config(object):
+
+ def __init__(self, settings, trees, myopts, spinner):
+ self.settings = settings
+ self.target_root = settings["ROOT"]
+ self.myopts = myopts
+ self.edebug = 0
+ if settings.get("PORTAGE_DEBUG", "") == "1":
+ self.edebug = 1
+ self.spinner = spinner
+ self._running_root = trees["/"]["root_config"]
+ self._opts_no_restart = frozenset(["--buildpkgonly",
+ "--fetchonly", "--fetch-all-uri", "--pretend"])
+ self.pkgsettings = {}
+ self.trees = {}
+ self._trees_orig = trees
+ self.roots = {}
+ # All Package instances
+ self._pkg_cache = {}
+ self._highest_license_masked = {}
+ for myroot in trees:
+ self.trees[myroot] = {}
+ # Create a RootConfig instance that references
+ # the FakeVartree instead of the real one.
+ self.roots[myroot] = RootConfig(
+ trees[myroot]["vartree"].settings,
+ self.trees[myroot],
+ trees[myroot]["root_config"].setconfig)
+ for tree in ("porttree", "bintree"):
+ self.trees[myroot][tree] = trees[myroot][tree]
+ self.trees[myroot]["vartree"] = \
+ FakeVartree(trees[myroot]["root_config"],
+ pkg_cache=self._pkg_cache,
+ pkg_root_config=self.roots[myroot])
+ self.pkgsettings[myroot] = portage.config(
+ clone=self.trees[myroot]["vartree"].settings)
+
+ self._required_set_names = set(["world"])
+
+ atoms = ' '.join(myopts.get("--exclude", [])).split()
+ self.excluded_pkgs = _wildcard_set(atoms)
+ atoms = ' '.join(myopts.get("--reinstall-atoms", [])).split()
+ self.reinstall_atoms = _wildcard_set(atoms)
+ atoms = ' '.join(myopts.get("--usepkg-exclude", [])).split()
+ self.usepkg_exclude = _wildcard_set(atoms)
+ atoms = ' '.join(myopts.get("--useoldpkg-atoms", [])).split()
+ self.useoldpkg_atoms = _wildcard_set(atoms)
+ atoms = ' '.join(myopts.get("--rebuild-exclude", [])).split()
+ self.rebuild_exclude = _wildcard_set(atoms)
+ atoms = ' '.join(myopts.get("--rebuild-ignore", [])).split()
+ self.rebuild_ignore = _wildcard_set(atoms)
+
+ self.rebuild_if_new_rev = "--rebuild-if-new-rev" in myopts
+ self.rebuild_if_new_ver = "--rebuild-if-new-ver" in myopts
+ self.rebuild_if_unbuilt = "--rebuild-if-unbuilt" in myopts
+
+class _depgraph_sets(object):
+ def __init__(self):
+ # contains all sets added to the graph
+ self.sets = {}
+ # contains non-set atoms given as arguments
+ self.sets['__non_set_args__'] = InternalPackageSet(allow_repo=True)
+ # contains all atoms from all sets added to the graph, including
+ # atoms given as arguments
+ self.atoms = InternalPackageSet(allow_repo=True)
+ self.atom_arg_map = {}
+
+class _rebuild_config(object):
+ def __init__(self, frozen_config, backtrack_parameters):
+ self._graph = digraph()
+ self._frozen_config = frozen_config
+ self.rebuild_list = backtrack_parameters.rebuild_list.copy()
+ self.orig_rebuild_list = self.rebuild_list.copy()
+ self.reinstall_list = backtrack_parameters.reinstall_list.copy()
+ self.rebuild_if_new_rev = frozen_config.rebuild_if_new_rev
+ self.rebuild_if_new_ver = frozen_config.rebuild_if_new_ver
+ self.rebuild_if_unbuilt = frozen_config.rebuild_if_unbuilt
+ self.rebuild = (self.rebuild_if_new_rev or self.rebuild_if_new_ver or
+ self.rebuild_if_unbuilt)
+
+ def add(self, dep_pkg, dep):
+ parent = dep.collapsed_parent
+ priority = dep.collapsed_priority
+ rebuild_exclude = self._frozen_config.rebuild_exclude
+ rebuild_ignore = self._frozen_config.rebuild_ignore
+ if (self.rebuild and isinstance(parent, Package) and
+ parent.built and (priority.buildtime or priority.runtime) and
+ isinstance(dep_pkg, Package) and
+ not rebuild_exclude.findAtomForPackage(parent) and
+ not rebuild_ignore.findAtomForPackage(dep_pkg)):
+ self._graph.add(dep_pkg, parent, priority)
+
+ def _needs_rebuild(self, dep_pkg):
+ """Check whether packages that depend on dep_pkg need to be rebuilt."""
+ dep_root_slot = (dep_pkg.root, dep_pkg.slot_atom)
+ if dep_pkg.built or dep_root_slot in self.orig_rebuild_list:
+ return False
+
+ if self.rebuild_if_unbuilt:
+ # dep_pkg is being installed from source, so binary
+ # packages for parents are invalid. Force rebuild
+ return True
+
+ trees = self._frozen_config.trees
+ vardb = trees[dep_pkg.root]["vartree"].dbapi
+ if self.rebuild_if_new_rev:
+ # Parent packages are valid if a package with the same
+ # cpv is already installed.
+ return dep_pkg.cpv not in vardb.match(dep_pkg.slot_atom)
+
+ # Otherwise, parent packages are valid if a package with the same
+ # version (excluding revision) is already installed.
+ assert self.rebuild_if_new_ver
+ cpv_norev = catpkgsplit(dep_pkg.cpv)[:-1]
+ for inst_cpv in vardb.match(dep_pkg.slot_atom):
+ inst_cpv_norev = catpkgsplit(inst_cpv)[:-1]
+ if inst_cpv_norev == cpv_norev:
+ return False
+
+ return True
+
+ def _trigger_rebuild(self, parent, build_deps, runtime_deps):
+ root_slot = (parent.root, parent.slot_atom)
+ if root_slot in self.rebuild_list:
+ return False
+ trees = self._frozen_config.trees
+ children = set(build_deps).intersection(runtime_deps)
+ reinstall = False
+ for slot_atom in children:
+ kids = set([build_deps[slot_atom], runtime_deps[slot_atom]])
+ for dep_pkg in kids:
+ dep_root_slot = (dep_pkg.root, slot_atom)
+ if self._needs_rebuild(dep_pkg):
+ self.rebuild_list.add(root_slot)
+ return True
+ elif ("--usepkg" in self._frozen_config.myopts and
+ (dep_root_slot in self.reinstall_list or
+ dep_root_slot in self.rebuild_list or
+ not dep_pkg.installed)):
+
+ # A direct rebuild dependency is being installed. We
+ # should update the parent as well to the latest binary,
+ # if that binary is valid.
+ #
+ # To validate the binary, we check whether all of the
+ # rebuild dependencies are present on the same binhost.
+ #
+ # 1) If parent is present on the binhost, but one of its
+ # rebuild dependencies is not, then the parent should
+ # be rebuilt from source.
+ # 2) Otherwise, the parent binary is assumed to be valid,
+ # because all of its rebuild dependencies are
+ # consistent.
+ bintree = trees[parent.root]["bintree"]
+ uri = bintree.get_pkgindex_uri(parent.cpv)
+ dep_uri = bintree.get_pkgindex_uri(dep_pkg.cpv)
+ bindb = bintree.dbapi
+ if self.rebuild_if_new_ver and uri and uri != dep_uri:
+ cpv_norev = catpkgsplit(dep_pkg.cpv)[:-1]
+ for cpv in bindb.match(dep_pkg.slot_atom):
+ if cpv_norev == catpkgsplit(cpv)[:-1]:
+ dep_uri = bintree.get_pkgindex_uri(cpv)
+ if uri == dep_uri:
+ break
+ if uri and uri != dep_uri:
+ # 1) Remote binary package is invalid because it was
+ # built without dep_pkg. Force rebuild.
+ self.rebuild_list.add(root_slot)
+ return True
+ elif (parent.installed and
+ root_slot not in self.reinstall_list):
+ inst_build_time = parent.metadata.get("BUILD_TIME")
+ try:
+ bin_build_time, = bindb.aux_get(parent.cpv,
+ ["BUILD_TIME"])
+ except KeyError:
+ continue
+ if bin_build_time != inst_build_time:
+ # 2) Remote binary package is valid, and local package
+ # is not up to date. Force reinstall.
+ reinstall = True
+ if reinstall:
+ self.reinstall_list.add(root_slot)
+ return reinstall
+
+ def trigger_rebuilds(self):
+ """
+ Trigger rebuilds where necessary. If pkgA has been updated, and pkgB
+ depends on pkgA at both build-time and run-time, pkgB needs to be
+ rebuilt.
+ """
+ need_restart = False
+ graph = self._graph
+ build_deps = {}
+ runtime_deps = {}
+ leaf_nodes = deque(graph.leaf_nodes())
+
+ def ignore_non_runtime(priority):
+ return not priority.runtime
+
+ def ignore_non_buildtime(priority):
+ return not priority.buildtime
+
+ # Trigger rebuilds bottom-up (starting with the leaves) so that parents
+ # will always know which children are being rebuilt.
+ while graph:
+ if not leaf_nodes:
+ # We're interested in intersection of buildtime and runtime,
+ # so ignore edges that do not contain both.
+ leaf_nodes.extend(graph.leaf_nodes(
+ ignore_priority=ignore_non_runtime))
+ if not leaf_nodes:
+ leaf_nodes.extend(graph.leaf_nodes(
+ ignore_priority=ignore_non_buildtime))
+ if not leaf_nodes:
+ # We'll have to drop an edge that is both
+ # buildtime and runtime. This should be
+ # quite rare.
+ leaf_nodes.append(graph.order[-1])
+
+ node = leaf_nodes.popleft()
+ if node not in graph:
+ # This can be triggered by circular dependencies.
+ continue
+ slot_atom = node.slot_atom
+
+ # Remove our leaf node from the graph, keeping track of deps.
+ parents = graph.nodes[node][1].items()
+ graph.remove(node)
+ node_build_deps = build_deps.get(node, {})
+ node_runtime_deps = runtime_deps.get(node, {})
+ for parent, priorities in parents:
+ if parent == node:
+ # Ignore a direct cycle.
+ continue
+ parent_bdeps = build_deps.setdefault(parent, {})
+ parent_rdeps = runtime_deps.setdefault(parent, {})
+ for priority in priorities:
+ if priority.buildtime:
+ parent_bdeps[slot_atom] = node
+ if priority.runtime:
+ parent_rdeps[slot_atom] = node
+ if slot_atom in parent_bdeps and slot_atom in parent_rdeps:
+ parent_rdeps.update(node_runtime_deps)
+ if not graph.child_nodes(parent):
+ leaf_nodes.append(parent)
+
+ # Trigger rebuilds for our leaf node. Because all of our children
+ # have been processed, build_deps and runtime_deps will be
+ # completely filled in, and self.rebuild_list / self.reinstall_list
+ # will tell us whether any of our children need to be rebuilt or
+ # reinstalled.
+ if self._trigger_rebuild(node, node_build_deps, node_runtime_deps):
+ need_restart = True
+
+ return need_restart
+
+
+class _dynamic_depgraph_config(object):
+
+ def __init__(self, depgraph, myparams, allow_backtracking, backtrack_parameters):
+ self.myparams = myparams.copy()
+ self._vdb_loaded = False
+ self._allow_backtracking = allow_backtracking
+ # Maps slot atom to package for each Package added to the graph.
+ self._slot_pkg_map = {}
+ # Maps nodes to the reasons they were selected for reinstallation.
+ self._reinstall_nodes = {}
+ self.mydbapi = {}
+ # Contains a filtered view of preferred packages that are selected
+ # from available repositories.
+ self._filtered_trees = {}
+ # Contains installed packages and new packages that have been added
+ # to the graph.
+ self._graph_trees = {}
+ # Caches visible packages returned from _select_package, for use in
+ # depgraph._iter_atoms_for_pkg() SLOT logic.
+ self._visible_pkgs = {}
+ #contains the args created by select_files
+ self._initial_arg_list = []
+ self.digraph = portage.digraph()
+ # manages sets added to the graph
+ self.sets = {}
+ # contains all nodes pulled in by self.sets
+ self._set_nodes = set()
+ # Contains only Blocker -> Uninstall edges
+ self._blocker_uninstalls = digraph()
+ # Contains only Package -> Blocker edges
+ self._blocker_parents = digraph()
+ # Contains only irrelevant Package -> Blocker edges
+ self._irrelevant_blockers = digraph()
+ # Contains only unsolvable Package -> Blocker edges
+ self._unsolvable_blockers = digraph()
+ # Contains all Blocker -> Blocked Package edges
+ self._blocked_pkgs = digraph()
+ # Contains world packages that have been protected from
+ # uninstallation but may not have been added to the graph
+ # if the graph is not complete yet.
+ self._blocked_world_pkgs = {}
+ # Contains packages whose dependencies have been traversed.
+ # This use used to check if we have accounted for blockers
+ # relevant to a package.
+ self._traversed_pkg_deps = set()
+ self._slot_collision_info = {}
+ # Slot collision nodes are not allowed to block other packages since
+ # blocker validation is only able to account for one package per slot.
+ self._slot_collision_nodes = set()
+ self._parent_atoms = {}
+ self._slot_conflict_parent_atoms = set()
+ self._slot_conflict_handler = None
+ self._circular_dependency_handler = None
+ self._serialized_tasks_cache = None
+ self._scheduler_graph = None
+ self._displayed_list = None
+ self._pprovided_args = []
+ self._missing_args = []
+ self._masked_installed = set()
+ self._masked_license_updates = set()
+ self._unsatisfied_deps_for_display = []
+ self._unsatisfied_blockers_for_display = None
+ self._circular_deps_for_display = None
+ self._dep_stack = []
+ self._dep_disjunctive_stack = []
+ self._unsatisfied_deps = []
+ self._initially_unsatisfied_deps = []
+ self._ignored_deps = []
+ self._highest_pkg_cache = {}
+
+ self._needed_unstable_keywords = backtrack_parameters.needed_unstable_keywords
+ self._needed_p_mask_changes = backtrack_parameters.needed_p_mask_changes
+ self._needed_license_changes = backtrack_parameters.needed_license_changes
+ self._needed_use_config_changes = backtrack_parameters.needed_use_config_changes
+ self._runtime_pkg_mask = backtrack_parameters.runtime_pkg_mask
+ self._need_restart = False
+ # For conditions that always require user intervention, such as
+ # unsatisfied REQUIRED_USE (currently has no autounmask support).
+ self._skip_restart = False
+ self._backtrack_infos = {}
+
+ self._autounmask = depgraph._frozen_config.myopts.get('--autounmask') != 'n'
+ self._success_without_autounmask = False
+ self._traverse_ignored_deps = False
+
+ for myroot in depgraph._frozen_config.trees:
+ self.sets[myroot] = _depgraph_sets()
+ self._slot_pkg_map[myroot] = {}
+ vardb = depgraph._frozen_config.trees[myroot]["vartree"].dbapi
+ # This dbapi instance will model the state that the vdb will
+ # have after new packages have been installed.
+ fakedb = PackageVirtualDbapi(vardb.settings)
+
+ self.mydbapi[myroot] = fakedb
+ def graph_tree():
+ pass
+ graph_tree.dbapi = fakedb
+ self._graph_trees[myroot] = {}
+ self._filtered_trees[myroot] = {}
+ # Substitute the graph tree for the vartree in dep_check() since we
+ # want atom selections to be consistent with package selections
+ # have already been made.
+ self._graph_trees[myroot]["porttree"] = graph_tree
+ self._graph_trees[myroot]["vartree"] = graph_tree
+ self._graph_trees[myroot]["graph_db"] = graph_tree.dbapi
+ self._graph_trees[myroot]["graph"] = self.digraph
+ def filtered_tree():
+ pass
+ filtered_tree.dbapi = _dep_check_composite_db(depgraph, myroot)
+ self._filtered_trees[myroot]["porttree"] = filtered_tree
+ self._visible_pkgs[myroot] = PackageVirtualDbapi(vardb.settings)
+
+ # Passing in graph_tree as the vartree here could lead to better
+ # atom selections in some cases by causing atoms for packages that
+ # have been added to the graph to be preferred over other choices.
+ # However, it can trigger atom selections that result in
+ # unresolvable direct circular dependencies. For example, this
+ # happens with gwydion-dylan which depends on either itself or
+ # gwydion-dylan-bin. In case gwydion-dylan is not yet installed,
+ # gwydion-dylan-bin needs to be selected in order to avoid a
+ # an unresolvable direct circular dependency.
+ #
+ # To solve the problem described above, pass in "graph_db" so that
+ # packages that have been added to the graph are distinguishable
+ # from other available packages and installed packages. Also, pass
+ # the parent package into self._select_atoms() calls so that
+ # unresolvable direct circular dependencies can be detected and
+ # avoided when possible.
+ self._filtered_trees[myroot]["graph_db"] = graph_tree.dbapi
+ self._filtered_trees[myroot]["graph"] = self.digraph
+ self._filtered_trees[myroot]["vartree"] = \
+ depgraph._frozen_config.trees[myroot]["vartree"]
+
+ dbs = []
+ # (db, pkg_type, built, installed, db_keys)
+ if "remove" in self.myparams:
+ # For removal operations, use _dep_check_composite_db
+ # for availability and visibility checks. This provides
+ # consistency with install operations, so we don't
+ # get install/uninstall cycles like in bug #332719.
+ self._graph_trees[myroot]["porttree"] = filtered_tree
+ else:
+ if "--usepkgonly" not in depgraph._frozen_config.myopts:
+ portdb = depgraph._frozen_config.trees[myroot]["porttree"].dbapi
+ db_keys = list(portdb._aux_cache_keys)
+ dbs.append((portdb, "ebuild", False, False, db_keys))
+
+ if "--usepkg" in depgraph._frozen_config.myopts:
+ bindb = depgraph._frozen_config.trees[myroot]["bintree"].dbapi
+ db_keys = list(bindb._aux_cache_keys)
+ dbs.append((bindb, "binary", True, False, db_keys))
+
+ vardb = depgraph._frozen_config.trees[myroot]["vartree"].dbapi
+ db_keys = list(depgraph._frozen_config._trees_orig[myroot
+ ]["vartree"].dbapi._aux_cache_keys)
+ dbs.append((vardb, "installed", True, True, db_keys))
+ self._filtered_trees[myroot]["dbs"] = dbs
+
+class depgraph(object):
+
+ pkg_tree_map = RootConfig.pkg_tree_map
+
+ _dep_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
+
+ def __init__(self, settings, trees, myopts, myparams, spinner,
+ frozen_config=None, backtrack_parameters=BacktrackParameter(), allow_backtracking=False):
+ if frozen_config is None:
+ frozen_config = _frozen_depgraph_config(settings, trees,
+ myopts, spinner)
+ self._frozen_config = frozen_config
+ self._dynamic_config = _dynamic_depgraph_config(self, myparams,
+ allow_backtracking, backtrack_parameters)
+ self._rebuild = _rebuild_config(frozen_config, backtrack_parameters)
+
+ self._select_atoms = self._select_atoms_highest_available
+ self._select_package = self._select_pkg_highest_available
+
+ def _load_vdb(self):
+ """
+ Load installed package metadata if appropriate. This used to be called
+ from the constructor, but that wasn't very nice since this procedure
+ is slow and it generates spinner output. So, now it's called on-demand
+ by various methods when necessary.
+ """
+
+ if self._dynamic_config._vdb_loaded:
+ return
+
+ for myroot in self._frozen_config.trees:
+
+ preload_installed_pkgs = \
+ "--nodeps" not in self._frozen_config.myopts
+
+ fake_vartree = self._frozen_config.trees[myroot]["vartree"]
+ if not fake_vartree.dbapi:
+ # This needs to be called for the first depgraph, but not for
+ # backtracking depgraphs that share the same frozen_config.
+ fake_vartree.sync()
+
+ # FakeVartree.sync() populates virtuals, and we want
+ # self.pkgsettings to have them populated too.
+ self._frozen_config.pkgsettings[myroot] = \
+ portage.config(clone=fake_vartree.settings)
+
+ if preload_installed_pkgs:
+ vardb = fake_vartree.dbapi
+ fakedb = self._dynamic_config._graph_trees[
+ myroot]["vartree"].dbapi
+
+ for pkg in vardb:
+ self._spinner_update()
+ # This triggers metadata updates via FakeVartree.
+ vardb.aux_get(pkg.cpv, [])
+ fakedb.cpv_inject(pkg)
+
+ self._dynamic_config._vdb_loaded = True
+
+ def _spinner_update(self):
+ if self._frozen_config.spinner:
+ self._frozen_config.spinner.update()
+
+ def _show_missed_update(self):
+
+ # In order to minimize noise, show only the highest
+ # missed update from each SLOT.
+ missed_updates = {}
+ for pkg, mask_reasons in \
+ self._dynamic_config._runtime_pkg_mask.items():
+ if pkg.installed:
+ # Exclude installed here since we only
+ # want to show available updates.
+ continue
+ k = (pkg.root, pkg.slot_atom)
+ if k in missed_updates:
+ other_pkg, mask_type, parent_atoms = missed_updates[k]
+ if other_pkg > pkg:
+ continue
+ for mask_type, parent_atoms in mask_reasons.items():
+ if not parent_atoms:
+ continue
+ missed_updates[k] = (pkg, mask_type, parent_atoms)
+ break
+
+ if not missed_updates:
+ return
+
+ missed_update_types = {}
+ for pkg, mask_type, parent_atoms in missed_updates.values():
+ missed_update_types.setdefault(mask_type,
+ []).append((pkg, parent_atoms))
+
+ if '--quiet' in self._frozen_config.myopts and \
+ '--debug' not in self._frozen_config.myopts:
+ missed_update_types.pop("slot conflict", None)
+ missed_update_types.pop("missing dependency", None)
+
+ self._show_missed_update_slot_conflicts(
+ missed_update_types.get("slot conflict"))
+
+ self._show_missed_update_unsatisfied_dep(
+ missed_update_types.get("missing dependency"))
+
+ def _show_missed_update_unsatisfied_dep(self, missed_updates):
+
+ if not missed_updates:
+ return
+
+ backtrack_masked = []
+
+ for pkg, parent_atoms in missed_updates:
+
+ try:
+ for parent, root, atom in parent_atoms:
+ self._show_unsatisfied_dep(root, atom, myparent=parent,
+ check_backtrack=True)
+ except self._backtrack_mask:
+ # This is displayed below in abbreviated form.
+ backtrack_masked.append((pkg, parent_atoms))
+ continue
+
+ writemsg("\n!!! The following update has been skipped " + \
+ "due to unsatisfied dependencies:\n\n", noiselevel=-1)
+
+ writemsg(str(pkg.slot_atom), noiselevel=-1)
+ if pkg.root != '/':
+ writemsg(" for %s" % (pkg.root,), noiselevel=-1)
+ writemsg("\n", noiselevel=-1)
+
+ for parent, root, atom in parent_atoms:
+ self._show_unsatisfied_dep(root, atom, myparent=parent)
+ writemsg("\n", noiselevel=-1)
+
+ if backtrack_masked:
+ # These are shown in abbreviated form, in order to avoid terminal
+ # flooding from mask messages as reported in bug #285832.
+ writemsg("\n!!! The following update(s) have been skipped " + \
+ "due to unsatisfied dependencies\n" + \
+ "!!! triggered by backtracking:\n\n", noiselevel=-1)
+ for pkg, parent_atoms in backtrack_masked:
+ writemsg(str(pkg.slot_atom), noiselevel=-1)
+ if pkg.root != '/':
+ writemsg(" for %s" % (pkg.root,), noiselevel=-1)
+ writemsg("\n", noiselevel=-1)
+
+ def _show_missed_update_slot_conflicts(self, missed_updates):
+
+ if not missed_updates:
+ return
+
+ msg = []
+ msg.append("\nWARNING: One or more updates have been " + \
+ "skipped due to a dependency conflict:\n\n")
+
+ indent = " "
+ for pkg, parent_atoms in missed_updates:
+ msg.append(str(pkg.slot_atom))
+ if pkg.root != '/':
+ msg.append(" for %s" % (pkg.root,))
+ msg.append("\n\n")
+
+ for parent, atom in parent_atoms:
+ msg.append(indent)
+ msg.append(str(pkg))
+
+ msg.append(" conflicts with\n")
+ msg.append(2*indent)
+ if isinstance(parent,
+ (PackageArg, AtomArg)):
+ # For PackageArg and AtomArg types, it's
+ # redundant to display the atom attribute.
+ msg.append(str(parent))
+ else:
+ # Display the specific atom from SetArg or
+ # Package types.
+ msg.append("%s required by %s" % (atom, parent))
+ msg.append("\n")
+ msg.append("\n")
+
+ writemsg("".join(msg), noiselevel=-1)
+
+ def _show_slot_collision_notice(self):
+ """Show an informational message advising the user to mask one of the
+ the packages. In some cases it may be possible to resolve this
+ automatically, but support for backtracking (removal nodes that have
+ already been selected) will be required in order to handle all possible
+ cases.
+ """
+
+ if not self._dynamic_config._slot_collision_info:
+ return
+
+ self._show_merge_list()
+
+ self._dynamic_config._slot_conflict_handler = slot_conflict_handler(self)
+ handler = self._dynamic_config._slot_conflict_handler
+
+ conflict = handler.get_conflict()
+ writemsg(conflict, noiselevel=-1)
+
+ explanation = handler.get_explanation()
+ if explanation:
+ writemsg(explanation, noiselevel=-1)
+ return
+
+ if "--quiet" in self._frozen_config.myopts:
+ return
+
+ msg = []
+ msg.append("It may be possible to solve this problem ")
+ msg.append("by using package.mask to prevent one of ")
+ msg.append("those packages from being selected. ")
+ msg.append("However, it is also possible that conflicting ")
+ msg.append("dependencies exist such that they are impossible to ")
+ msg.append("satisfy simultaneously. If such a conflict exists in ")
+ msg.append("the dependencies of two different packages, then those ")
+ msg.append("packages can not be installed simultaneously.")
+ backtrack_opt = self._frozen_config.myopts.get('--backtrack')
+ if not self._dynamic_config._allow_backtracking and \
+ (backtrack_opt is None or \
+ (backtrack_opt > 0 and backtrack_opt < 30)):
+ msg.append(" You may want to try a larger value of the ")
+ msg.append("--backtrack option, such as --backtrack=30, ")
+ msg.append("in order to see if that will solve this conflict ")
+ msg.append("automatically.")
+
+ for line in textwrap.wrap(''.join(msg), 70):
+ writemsg(line + '\n', noiselevel=-1)
+ writemsg('\n', noiselevel=-1)
+
+ msg = []
+ msg.append("For more information, see MASKED PACKAGES ")
+ msg.append("section in the emerge man page or refer ")
+ msg.append("to the Gentoo Handbook.")
+ for line in textwrap.wrap(''.join(msg), 70):
+ writemsg(line + '\n', noiselevel=-1)
+ writemsg('\n', noiselevel=-1)
+
+ def _process_slot_conflicts(self):
+ """
+ Process slot conflict data to identify specific atoms which
+ lead to conflict. These atoms only match a subset of the
+ packages that have been pulled into a given slot.
+ """
+ for (slot_atom, root), slot_nodes \
+ in self._dynamic_config._slot_collision_info.items():
+
+ all_parent_atoms = set()
+ for pkg in slot_nodes:
+ parent_atoms = self._dynamic_config._parent_atoms.get(pkg)
+ if not parent_atoms:
+ continue
+ all_parent_atoms.update(parent_atoms)
+
+ for pkg in slot_nodes:
+ parent_atoms = self._dynamic_config._parent_atoms.get(pkg)
+ if parent_atoms is None:
+ parent_atoms = set()
+ self._dynamic_config._parent_atoms[pkg] = parent_atoms
+ for parent_atom in all_parent_atoms:
+ if parent_atom in parent_atoms:
+ continue
+ # Use package set for matching since it will match via
+ # PROVIDE when necessary, while match_from_list does not.
+ parent, atom = parent_atom
+ atom_set = InternalPackageSet(
+ initial_atoms=(atom,), allow_repo=True)
+ if atom_set.findAtomForPackage(pkg, modified_use=self._pkg_use_enabled(pkg)):
+ parent_atoms.add(parent_atom)
+ else:
+ self._dynamic_config._slot_conflict_parent_atoms.add(parent_atom)
+
+ def _reinstall_for_flags(self, forced_flags,
+ orig_use, orig_iuse, cur_use, cur_iuse):
+ """Return a set of flags that trigger reinstallation, or None if there
+ are no such flags."""
+ if "--newuse" in self._frozen_config.myopts or \
+ "--binpkg-respect-use" in self._frozen_config.myopts:
+ flags = set(orig_iuse.symmetric_difference(
+ cur_iuse).difference(forced_flags))
+ flags.update(orig_iuse.intersection(orig_use).symmetric_difference(
+ cur_iuse.intersection(cur_use)))
+ if flags:
+ return flags
+ elif "changed-use" == self._frozen_config.myopts.get("--reinstall"):
+ flags = orig_iuse.intersection(orig_use).symmetric_difference(
+ cur_iuse.intersection(cur_use))
+ if flags:
+ return flags
+ return None
+
+ def _create_graph(self, allow_unsatisfied=False):
+ dep_stack = self._dynamic_config._dep_stack
+ dep_disjunctive_stack = self._dynamic_config._dep_disjunctive_stack
+ while dep_stack or dep_disjunctive_stack:
+ self._spinner_update()
+ while dep_stack:
+ dep = dep_stack.pop()
+ if isinstance(dep, Package):
+ if not self._add_pkg_deps(dep,
+ allow_unsatisfied=allow_unsatisfied):
+ return 0
+ continue
+ if not self._add_dep(dep, allow_unsatisfied=allow_unsatisfied):
+ return 0
+ if dep_disjunctive_stack:
+ if not self._pop_disjunction(allow_unsatisfied):
+ return 0
+ return 1
+
+ def _expand_set_args(self, input_args, add_to_digraph=False):
+ """
+ Iterate over a list of DependencyArg instances and yield all
+ instances given in the input together with additional SetArg
+ instances that are generated from nested sets.
+ @param input_args: An iterable of DependencyArg instances
+ @type input_args: Iterable
+ @param add_to_digraph: If True then add SetArg instances
+ to the digraph, in order to record parent -> child
+ relationships from nested sets
+ @type add_to_digraph: Boolean
+ @rtype: Iterable
+ @returns: All args given in the input together with additional
+ SetArg instances that are generated from nested sets
+ """
+
+ traversed_set_args = set()
+
+ for arg in input_args:
+ if not isinstance(arg, SetArg):
+ yield arg
+ continue
+
+ root_config = arg.root_config
+ depgraph_sets = self._dynamic_config.sets[root_config.root]
+ arg_stack = [arg]
+ while arg_stack:
+ arg = arg_stack.pop()
+ if arg in traversed_set_args:
+ continue
+ traversed_set_args.add(arg)
+
+ if add_to_digraph:
+ self._dynamic_config.digraph.add(arg, None,
+ priority=BlockerDepPriority.instance)
+
+ yield arg
+
+ # Traverse nested sets and add them to the stack
+ # if they're not already in the graph. Also, graph
+ # edges between parent and nested sets.
+ for token in arg.pset.getNonAtoms():
+ if not token.startswith(SETPREFIX):
+ continue
+ s = token[len(SETPREFIX):]
+ nested_set = depgraph_sets.sets.get(s)
+ if nested_set is None:
+ nested_set = root_config.sets.get(s)
+ if nested_set is not None:
+ nested_arg = SetArg(arg=token, pset=nested_set,
+ root_config=root_config)
+ arg_stack.append(nested_arg)
+ if add_to_digraph:
+ self._dynamic_config.digraph.add(nested_arg, arg,
+ priority=BlockerDepPriority.instance)
+ depgraph_sets.sets[nested_arg.name] = nested_arg.pset
+
+ def _add_dep(self, dep, allow_unsatisfied=False):
+ debug = "--debug" in self._frozen_config.myopts
+ buildpkgonly = "--buildpkgonly" in self._frozen_config.myopts
+ nodeps = "--nodeps" in self._frozen_config.myopts
+ deep = self._dynamic_config.myparams.get("deep", 0)
+ recurse = deep is True or dep.depth <= deep
+ if dep.blocker:
+ if not buildpkgonly and \
+ not nodeps and \
+ not dep.collapsed_priority.ignored and \
+ not dep.collapsed_priority.optional and \
+ dep.parent not in self._dynamic_config._slot_collision_nodes:
+ if dep.parent.onlydeps:
+ # It's safe to ignore blockers if the
+ # parent is an --onlydeps node.
+ return 1
+ # The blocker applies to the root where
+ # the parent is or will be installed.
+ blocker = Blocker(atom=dep.atom,
+ eapi=dep.parent.metadata["EAPI"],
+ priority=dep.priority, root=dep.parent.root)
+ self._dynamic_config._blocker_parents.add(blocker, dep.parent)
+ return 1
+
+ if dep.child is None:
+ dep_pkg, existing_node = self._select_package(dep.root, dep.atom,
+ onlydeps=dep.onlydeps)
+ else:
+ # The caller has selected a specific package
+ # via self._minimize_packages().
+ dep_pkg = dep.child
+ existing_node = self._dynamic_config._slot_pkg_map[
+ dep.root].get(dep_pkg.slot_atom)
+
+ if not dep_pkg:
+ if (dep.collapsed_priority.optional or
+ dep.collapsed_priority.ignored):
+ # This is an unnecessary build-time dep.
+ return 1
+ if allow_unsatisfied:
+ self._dynamic_config._unsatisfied_deps.append(dep)
+ return 1
+ self._dynamic_config._unsatisfied_deps_for_display.append(
+ ((dep.root, dep.atom), {"myparent":dep.parent}))
+
+ # The parent node should not already be in
+ # runtime_pkg_mask, since that would trigger an
+ # infinite backtracking loop.
+ if self._dynamic_config._allow_backtracking:
+ if dep.parent in self._dynamic_config._runtime_pkg_mask:
+ if "--debug" in self._frozen_config.myopts:
+ writemsg(
+ "!!! backtracking loop detected: %s %s\n" % \
+ (dep.parent,
+ self._dynamic_config._runtime_pkg_mask[
+ dep.parent]), noiselevel=-1)
+ elif not self.need_restart():
+ # Do not backtrack if only USE have to be changed in
+ # order to satisfy the dependency.
+ dep_pkg, existing_node = \
+ self._select_package(dep.root, dep.atom.without_use,
+ onlydeps=dep.onlydeps)
+ if dep_pkg is None:
+ self._dynamic_config._backtrack_infos["missing dependency"] = dep
+ self._dynamic_config._need_restart = True
+ if "--debug" in self._frozen_config.myopts:
+ msg = []
+ msg.append("")
+ msg.append("")
+ msg.append("backtracking due to unsatisfied dep:")
+ msg.append(" parent: %s" % dep.parent)
+ msg.append(" priority: %s" % dep.priority)
+ msg.append(" root: %s" % dep.root)
+ msg.append(" atom: %s" % dep.atom)
+ msg.append("")
+ writemsg_level("".join("%s\n" % l for l in msg),
+ noiselevel=-1, level=logging.DEBUG)
+
+ return 0
+
+ self._rebuild.add(dep_pkg, dep)
+
+ ignore = dep.collapsed_priority.ignored and \
+ not self._dynamic_config._traverse_ignored_deps
+ if not ignore and not self._add_pkg(dep_pkg, dep):
+ return 0
+ return 1
+
+ def _check_slot_conflict(self, pkg, atom):
+ existing_node = self._dynamic_config._slot_pkg_map[pkg.root].get(pkg.slot_atom)
+ matches = None
+ if existing_node:
+ matches = pkg.cpv == existing_node.cpv
+ if pkg != existing_node and \
+ atom is not None:
+ # Use package set for matching since it will match via
+ # PROVIDE when necessary, while match_from_list does not.
+ matches = bool(InternalPackageSet(initial_atoms=(atom,),
+ allow_repo=True).findAtomForPackage(existing_node,
+ modified_use=self._pkg_use_enabled(existing_node)))
+
+ return (existing_node, matches)
+
+ def _add_pkg(self, pkg, dep):
+ """
+ Adds a package to the depgraph, queues dependencies, and handles
+ slot conflicts.
+ """
+ debug = "--debug" in self._frozen_config.myopts
+ myparent = None
+ priority = None
+ depth = 0
+ if dep is None:
+ dep = Dependency()
+ else:
+ myparent = dep.parent
+ priority = dep.priority
+ depth = dep.depth
+ if priority is None:
+ priority = DepPriority()
+
+ if debug:
+ writemsg_level(
+ "\n%s%s %s\n" % ("Child:".ljust(15), pkg,
+ pkg_use_display(pkg, self._frozen_config.myopts,
+ modified_use=self._pkg_use_enabled(pkg))),
+ level=logging.DEBUG, noiselevel=-1)
+ if isinstance(myparent,
+ (PackageArg, AtomArg)):
+ # For PackageArg and AtomArg types, it's
+ # redundant to display the atom attribute.
+ writemsg_level(
+ "%s%s\n" % ("Parent Dep:".ljust(15), myparent),
+ level=logging.DEBUG, noiselevel=-1)
+ else:
+ # Display the specific atom from SetArg or
+ # Package types.
+ writemsg_level(
+ "%s%s required by %s\n" %
+ ("Parent Dep:".ljust(15), dep.atom, myparent),
+ level=logging.DEBUG, noiselevel=-1)
+
+ # Ensure that the dependencies of the same package
+ # are never processed more than once.
+ previously_added = pkg in self._dynamic_config.digraph
+
+ # select the correct /var database that we'll be checking against
+ vardbapi = self._frozen_config.trees[pkg.root]["vartree"].dbapi
+ pkgsettings = self._frozen_config.pkgsettings[pkg.root]
+
+ arg_atoms = None
+ if True:
+ try:
+ arg_atoms = list(self._iter_atoms_for_pkg(pkg))
+ except portage.exception.InvalidDependString as e:
+ if not pkg.installed:
+ # should have been masked before it was selected
+ raise
+ del e
+
+ # NOTE: REQUIRED_USE checks are delayed until after
+ # package selection, since we want to prompt the user
+ # for USE adjustment rather than have REQUIRED_USE
+ # affect package selection and || dep choices.
+ if not pkg.built and pkg.metadata["REQUIRED_USE"] and \
+ eapi_has_required_use(pkg.metadata["EAPI"]):
+ required_use_is_sat = check_required_use(
+ pkg.metadata["REQUIRED_USE"],
+ self._pkg_use_enabled(pkg),
+ pkg.iuse.is_valid_flag)
+ if not required_use_is_sat:
+ if dep.atom is not None and dep.parent is not None:
+ self._add_parent_atom(pkg, (dep.parent, dep.atom))
+
+ if arg_atoms:
+ for parent_atom in arg_atoms:
+ parent, atom = parent_atom
+ self._add_parent_atom(pkg, parent_atom)
+
+ atom = dep.atom
+ if atom is None:
+ atom = Atom("=" + pkg.cpv)
+ self._dynamic_config._unsatisfied_deps_for_display.append(
+ ((pkg.root, atom), {"myparent":dep.parent}))
+ self._dynamic_config._skip_restart = True
+ return 0
+
+ if not pkg.onlydeps:
+
+ existing_node, existing_node_matches = \
+ self._check_slot_conflict(pkg, dep.atom)
+ slot_collision = False
+ if existing_node:
+ if existing_node_matches:
+ # The existing node can be reused.
+ if arg_atoms:
+ for parent_atom in arg_atoms:
+ parent, atom = parent_atom
+ self._dynamic_config.digraph.add(existing_node, parent,
+ priority=priority)
+ self._add_parent_atom(existing_node, parent_atom)
+ # If a direct circular dependency is not an unsatisfied
+ # buildtime dependency then drop it here since otherwise
+ # it can skew the merge order calculation in an unwanted
+ # way.
+ if existing_node != myparent or \
+ (priority.buildtime and not priority.satisfied):
+ self._dynamic_config.digraph.addnode(existing_node, myparent,
+ priority=priority)
+ if dep.atom is not None and dep.parent is not None:
+ self._add_parent_atom(existing_node,
+ (dep.parent, dep.atom))
+ return 1
+ else:
+ # A slot conflict has occurred.
+ # The existing node should not already be in
+ # runtime_pkg_mask, since that would trigger an
+ # infinite backtracking loop.
+ if self._dynamic_config._allow_backtracking and \
+ existing_node in \
+ self._dynamic_config._runtime_pkg_mask:
+ if "--debug" in self._frozen_config.myopts:
+ writemsg(
+ "!!! backtracking loop detected: %s %s\n" % \
+ (existing_node,
+ self._dynamic_config._runtime_pkg_mask[
+ existing_node]), noiselevel=-1)
+ elif self._dynamic_config._allow_backtracking and \
+ not self._accept_blocker_conflicts() and \
+ not self.need_restart():
+
+ self._add_slot_conflict(pkg)
+ if dep.atom is not None and dep.parent is not None:
+ self._add_parent_atom(pkg, (dep.parent, dep.atom))
+
+ if arg_atoms:
+ for parent_atom in arg_atoms:
+ parent, atom = parent_atom
+ self._add_parent_atom(pkg, parent_atom)
+ self._process_slot_conflicts()
+
+ backtrack_data = []
+ fallback_data = []
+ all_parents = set()
+ # The ordering of backtrack_data can make
+ # a difference here, because both mask actions may lead
+ # to valid, but different, solutions and the one with
+ # 'existing_node' masked is usually the better one. Because
+ # of that, we choose an order such that
+ # the backtracker will first explore the choice with
+ # existing_node masked. The backtracker reverses the
+ # order, so the order it uses is the reverse of the
+ # order shown here. See bug #339606.
+ for to_be_selected, to_be_masked in (existing_node, pkg), (pkg, existing_node):
+ # For missed update messages, find out which
+ # atoms matched to_be_selected that did not
+ # match to_be_masked.
+ parent_atoms = \
+ self._dynamic_config._parent_atoms.get(to_be_selected, set())
+ if parent_atoms:
+ conflict_atoms = self._dynamic_config._slot_conflict_parent_atoms.intersection(parent_atoms)
+ if conflict_atoms:
+ parent_atoms = conflict_atoms
+
+ all_parents.update(parent_atoms)
+
+ all_match = True
+ for parent, atom in parent_atoms:
+ i = InternalPackageSet(initial_atoms=(atom,),
+ allow_repo=True)
+ if not i.findAtomForPackage(to_be_masked):
+ all_match = False
+ break
+
+ if to_be_selected >= to_be_masked:
+ # We only care about the parent atoms
+ # when they trigger a downgrade.
+ parent_atoms = set()
+
+ fallback_data.append((to_be_masked, parent_atoms))
+
+ if all_match:
+ # 'to_be_masked' does not violate any parent atom, which means
+ # there is no point in masking it.
+ pass
+ else:
+ backtrack_data.append((to_be_masked, parent_atoms))
+
+ if not backtrack_data:
+ # This shouldn't happen, but fall back to the old
+ # behavior if this gets triggered somehow.
+ backtrack_data = fallback_data
+
+ if len(backtrack_data) > 1:
+ # NOTE: Generally, we prefer to mask the higher
+ # version since this solves common cases in which a
+ # lower version is needed so that all dependencies
+ # will be satisfied (bug #337178). However, if
+ # existing_node happens to be installed then we
+ # mask that since this is a common case that is
+ # triggered when --update is not enabled.
+ if existing_node.installed:
+ pass
+ elif pkg > existing_node:
+ backtrack_data.reverse()
+
+ to_be_masked = backtrack_data[-1][0]
+
+ self._dynamic_config._backtrack_infos["slot conflict"] = backtrack_data
+ self._dynamic_config._need_restart = True
+ if "--debug" in self._frozen_config.myopts:
+ msg = []
+ msg.append("")
+ msg.append("")
+ msg.append("backtracking due to slot conflict:")
+ if backtrack_data is fallback_data:
+ msg.append("!!! backtrack_data fallback")
+ msg.append(" first package: %s" % existing_node)
+ msg.append(" second package: %s" % pkg)
+ msg.append(" package to mask: %s" % to_be_masked)
+ msg.append(" slot: %s" % pkg.slot_atom)
+ msg.append(" parents: %s" % ", ".join( \
+ "(%s, '%s')" % (ppkg, atom) for ppkg, atom in all_parents))
+ msg.append("")
+ writemsg_level("".join("%s\n" % l for l in msg),
+ noiselevel=-1, level=logging.DEBUG)
+ return 0
+
+ # A slot collision has occurred. Sometimes this coincides
+ # with unresolvable blockers, so the slot collision will be
+ # shown later if there are no unresolvable blockers.
+ self._add_slot_conflict(pkg)
+ slot_collision = True
+
+ if debug:
+ writemsg_level(
+ "%s%s %s\n" % ("Slot Conflict:".ljust(15),
+ existing_node, pkg_use_display(existing_node,
+ self._frozen_config.myopts,
+ modified_use=self._pkg_use_enabled(existing_node))),
+ level=logging.DEBUG, noiselevel=-1)
+
+ if slot_collision:
+ # Now add this node to the graph so that self.display()
+ # can show use flags and --tree portage.output. This node is
+ # only being partially added to the graph. It must not be
+ # allowed to interfere with the other nodes that have been
+ # added. Do not overwrite data for existing nodes in
+ # self._dynamic_config.mydbapi since that data will be used for blocker
+ # validation.
+ # Even though the graph is now invalid, continue to process
+ # dependencies so that things like --fetchonly can still
+ # function despite collisions.
+ pass
+ elif not previously_added:
+ self._dynamic_config._slot_pkg_map[pkg.root][pkg.slot_atom] = pkg
+ self._dynamic_config.mydbapi[pkg.root].cpv_inject(pkg)
+ self._dynamic_config._filtered_trees[pkg.root]["porttree"].dbapi._clear_cache()
+ self._dynamic_config._highest_pkg_cache.clear()
+ self._check_masks(pkg)
+
+ if not pkg.installed:
+ # Allow this package to satisfy old-style virtuals in case it
+ # doesn't already. Any pre-existing providers will be preferred
+ # over this one.
+ try:
+ pkgsettings.setinst(pkg.cpv, pkg.metadata)
+ # For consistency, also update the global virtuals.
+ settings = self._frozen_config.roots[pkg.root].settings
+ settings.unlock()
+ settings.setinst(pkg.cpv, pkg.metadata)
+ settings.lock()
+ except portage.exception.InvalidDependString as e:
+ if not pkg.installed:
+ # should have been masked before it was selected
+ raise
+
+ if arg_atoms:
+ self._dynamic_config._set_nodes.add(pkg)
+
+ # Do this even when addme is False (--onlydeps) so that the
+ # parent/child relationship is always known in case
+ # self._show_slot_collision_notice() needs to be called later.
+ self._dynamic_config.digraph.add(pkg, myparent, priority=priority)
+ if dep.atom is not None and dep.parent is not None:
+ self._add_parent_atom(pkg, (dep.parent, dep.atom))
+
+ if arg_atoms:
+ for parent_atom in arg_atoms:
+ parent, atom = parent_atom
+ self._dynamic_config.digraph.add(pkg, parent, priority=priority)
+ self._add_parent_atom(pkg, parent_atom)
+
+ """ This section determines whether we go deeper into dependencies or not.
+ We want to go deeper on a few occasions:
+ Installing package A, we need to make sure package A's deps are met.
+ emerge --deep <pkgspec>; we need to recursively check dependencies of pkgspec
+ If we are in --nodeps (no recursion) mode, we obviously only check 1 level of dependencies.
+ """
+ if arg_atoms:
+ depth = 0
+ pkg.depth = depth
+ deep = self._dynamic_config.myparams.get("deep", 0)
+ recurse = deep is True or depth + 1 <= deep
+ dep_stack = self._dynamic_config._dep_stack
+ if "recurse" not in self._dynamic_config.myparams:
+ return 1
+ elif pkg.installed and not recurse:
+ dep_stack = self._dynamic_config._ignored_deps
+
+ self._spinner_update()
+
+ if not previously_added:
+ dep_stack.append(pkg)
+ return 1
+
+ def _check_masks(self, pkg):
+
+ slot_key = (pkg.root, pkg.slot_atom)
+
+ # Check for upgrades in the same slot that are
+ # masked due to a LICENSE change in a newer
+ # version that is not masked for any other reason.
+ other_pkg = self._frozen_config._highest_license_masked.get(slot_key)
+ if other_pkg is not None and pkg < other_pkg:
+ self._dynamic_config._masked_license_updates.add(other_pkg)
+
+ def _add_parent_atom(self, pkg, parent_atom):
+ parent_atoms = self._dynamic_config._parent_atoms.get(pkg)
+ if parent_atoms is None:
+ parent_atoms = set()
+ self._dynamic_config._parent_atoms[pkg] = parent_atoms
+ parent_atoms.add(parent_atom)
+
+ def _add_slot_conflict(self, pkg):
+ self._dynamic_config._slot_collision_nodes.add(pkg)
+ slot_key = (pkg.slot_atom, pkg.root)
+ slot_nodes = self._dynamic_config._slot_collision_info.get(slot_key)
+ if slot_nodes is None:
+ slot_nodes = set()
+ slot_nodes.add(self._dynamic_config._slot_pkg_map[pkg.root][pkg.slot_atom])
+ self._dynamic_config._slot_collision_info[slot_key] = slot_nodes
+ slot_nodes.add(pkg)
+
+ def _add_pkg_deps(self, pkg, allow_unsatisfied=False):
+
+ mytype = pkg.type_name
+ myroot = pkg.root
+ mykey = pkg.cpv
+ metadata = pkg.metadata
+ myuse = self._pkg_use_enabled(pkg)
+ jbigkey = pkg
+ depth = pkg.depth + 1
+ removal_action = "remove" in self._dynamic_config.myparams
+
+ edepend={}
+ depkeys = ["DEPEND","RDEPEND","PDEPEND"]
+ for k in depkeys:
+ edepend[k] = metadata[k]
+
+ if not pkg.built and \
+ "--buildpkgonly" in self._frozen_config.myopts and \
+ "deep" not in self._dynamic_config.myparams:
+ edepend["RDEPEND"] = ""
+ edepend["PDEPEND"] = ""
+
+ ignore_build_time_deps = False
+ if pkg.built and not removal_action:
+ if self._dynamic_config.myparams.get("bdeps", "n") == "y":
+ # Pull in build time deps as requested, but marked them as
+ # "optional" since they are not strictly required. This allows
+ # more freedom in the merge order calculation for solving
+ # circular dependencies. Don't convert to PDEPEND since that
+ # could make --with-bdeps=y less effective if it is used to
+ # adjust merge order to prevent built_with_use() calls from
+ # failing.
+ pass
+ else:
+ ignore_build_time_deps = True
+
+ if removal_action and self._dynamic_config.myparams.get("bdeps", "y") == "n":
+ # Removal actions never traverse ignored buildtime
+ # dependencies, so it's safe to discard them early.
+ edepend["DEPEND"] = ""
+ ignore_build_time_deps = True
+
+ if removal_action:
+ depend_root = myroot
+ else:
+ depend_root = "/"
+ root_deps = self._frozen_config.myopts.get("--root-deps")
+ if root_deps is not None:
+ if root_deps is True:
+ depend_root = myroot
+ elif root_deps == "rdeps":
+ ignore_build_time_deps = True
+
+ # If rebuild mode is not enabled, it's safe to discard ignored
+ # build-time dependencies. If you want these deps to be traversed
+ # in "complete" mode then you need to specify --with-bdeps=y.
+ if ignore_build_time_deps and \
+ not self._rebuild.rebuild:
+ edepend["DEPEND"] = ""
+
+ deps = (
+ (depend_root, edepend["DEPEND"],
+ self._priority(buildtime=True,
+ optional=(pkg.built or ignore_build_time_deps),
+ ignored=ignore_build_time_deps)),
+ (myroot, edepend["RDEPEND"],
+ self._priority(runtime=True)),
+ (myroot, edepend["PDEPEND"],
+ self._priority(runtime_post=True))
+ )
+
+ debug = "--debug" in self._frozen_config.myopts
+ strict = mytype != "installed"
+
+ for dep_root, dep_string, dep_priority in deps:
+ if not dep_string:
+ continue
+ if debug:
+ writemsg_level("\nParent: %s\n" % (pkg,),
+ noiselevel=-1, level=logging.DEBUG)
+ writemsg_level("Depstring: %s\n" % (dep_string,),
+ noiselevel=-1, level=logging.DEBUG)
+ writemsg_level("Priority: %s\n" % (dep_priority,),
+ noiselevel=-1, level=logging.DEBUG)
+
+ try:
+ dep_string = portage.dep.use_reduce(dep_string,
+ uselist=self._pkg_use_enabled(pkg), is_valid_flag=pkg.iuse.is_valid_flag)
+ except portage.exception.InvalidDependString as e:
+ if not pkg.installed:
+ # should have been masked before it was selected
+ raise
+ del e
+
+ # Try again, but omit the is_valid_flag argument, since
+ # invalid USE conditionals are a common problem and it's
+ # practical to ignore this issue for installed packages.
+ try:
+ dep_string = portage.dep.use_reduce(dep_string,
+ uselist=self._pkg_use_enabled(pkg))
+ except portage.exception.InvalidDependString as e:
+ self._dynamic_config._masked_installed.add(pkg)
+ del e
+ continue
+
+ try:
+ dep_string = list(self._queue_disjunctive_deps(
+ pkg, dep_root, dep_priority, dep_string))
+ except portage.exception.InvalidDependString as e:
+ if pkg.installed:
+ self._dynamic_config._masked_installed.add(pkg)
+ del e
+ continue
+
+ # should have been masked before it was selected
+ raise
+
+ if not dep_string:
+ continue
+
+ dep_string = portage.dep.paren_enclose(dep_string,
+ unevaluated_atom=True)
+
+ if not self._add_pkg_dep_string(
+ pkg, dep_root, dep_priority, dep_string,
+ allow_unsatisfied):
+ return 0
+
+ self._dynamic_config._traversed_pkg_deps.add(pkg)
+ return 1
+
+ def _add_pkg_dep_string(self, pkg, dep_root, dep_priority, dep_string,
+ allow_unsatisfied):
+ _autounmask_backup = self._dynamic_config._autounmask
+ if dep_priority.optional or dep_priority.ignored:
+ # Temporarily disable autounmask for deps that
+ # don't necessarily need to be satisfied.
+ self._dynamic_config._autounmask = False
+ try:
+ return self._wrapped_add_pkg_dep_string(
+ pkg, dep_root, dep_priority, dep_string,
+ allow_unsatisfied)
+ finally:
+ self._dynamic_config._autounmask = _autounmask_backup
+
+ def _wrapped_add_pkg_dep_string(self, pkg, dep_root, dep_priority,
+ dep_string, allow_unsatisfied):
+ depth = pkg.depth + 1
+ deep = self._dynamic_config.myparams.get("deep", 0)
+ recurse_satisfied = deep is True or depth <= deep
+ debug = "--debug" in self._frozen_config.myopts
+ strict = pkg.type_name != "installed"
+
+ if debug:
+ writemsg_level("\nParent: %s\n" % (pkg,),
+ noiselevel=-1, level=logging.DEBUG)
+ writemsg_level("Depstring: %s\n" % (dep_string,),
+ noiselevel=-1, level=logging.DEBUG)
+ writemsg_level("Priority: %s\n" % (dep_priority,),
+ noiselevel=-1, level=logging.DEBUG)
+
+ try:
+ selected_atoms = self._select_atoms(dep_root,
+ dep_string, myuse=self._pkg_use_enabled(pkg), parent=pkg,
+ strict=strict, priority=dep_priority)
+ except portage.exception.InvalidDependString as e:
+ if pkg.installed:
+ self._dynamic_config._masked_installed.add(pkg)
+ return 1
+
+ # should have been masked before it was selected
+ raise
+
+ if debug:
+ writemsg_level("Candidates: %s\n" % \
+ ([str(x) for x in selected_atoms[pkg]],),
+ noiselevel=-1, level=logging.DEBUG)
+
+ root_config = self._frozen_config.roots[dep_root]
+ vardb = root_config.trees["vartree"].dbapi
+ traversed_virt_pkgs = set()
+
+ reinstall_atoms = self._frozen_config.reinstall_atoms
+ for atom, child in self._minimize_children(
+ pkg, dep_priority, root_config, selected_atoms[pkg]):
+
+ # If this was a specially generated virtual atom
+ # from dep_check, map it back to the original, in
+ # order to avoid distortion in places like display
+ # or conflict resolution code.
+ is_virt = hasattr(atom, '_orig_atom')
+ atom = getattr(atom, '_orig_atom', atom)
+
+ if atom.blocker and \
+ (dep_priority.optional or dep_priority.ignored):
+ # For --with-bdeps, ignore build-time only blockers
+ # that originate from built packages.
+ continue
+
+ mypriority = dep_priority.copy()
+ if not atom.blocker:
+ inst_pkgs = [inst_pkg for inst_pkg in
+ reversed(vardb.match_pkgs(atom))
+ if not reinstall_atoms.findAtomForPackage(inst_pkg,
+ modified_use=self._pkg_use_enabled(inst_pkg))]
+ if inst_pkgs:
+ for inst_pkg in inst_pkgs:
+ if self._pkg_visibility_check(inst_pkg):
+ # highest visible
+ mypriority.satisfied = inst_pkg
+ break
+ if not mypriority.satisfied:
+ # none visible, so use highest
+ mypriority.satisfied = inst_pkgs[0]
+
+ dep = Dependency(atom=atom,
+ blocker=atom.blocker, child=child, depth=depth, parent=pkg,
+ priority=mypriority, root=dep_root)
+
+ # In some cases, dep_check will return deps that shouldn't
+ # be proccessed any further, so they are identified and
+ # discarded here. Try to discard as few as possible since
+ # discarded dependencies reduce the amount of information
+ # available for optimization of merge order.
+ ignored = False
+ if not atom.blocker and \
+ not recurse_satisfied and \
+ mypriority.satisfied and \
+ mypriority.satisfied.visible and \
+ dep.child is not None and \
+ not dep.child.installed and \
+ self._dynamic_config._slot_pkg_map[dep.child.root].get(
+ dep.child.slot_atom) is None:
+ myarg = None
+ if dep.root == self._frozen_config.target_root:
+ try:
+ myarg = next(self._iter_atoms_for_pkg(dep.child))
+ except StopIteration:
+ pass
+ except InvalidDependString:
+ if not dep.child.installed:
+ # This shouldn't happen since the package
+ # should have been masked.
+ raise
+
+ if myarg is None:
+ # Existing child selection may not be valid unless
+ # it's added to the graph immediately, since "complete"
+ # mode may select a different child later.
+ ignored = True
+ dep.child = None
+ self._dynamic_config._ignored_deps.append(dep)
+
+ if not ignored:
+ if dep_priority.ignored and \
+ not self._dynamic_config._traverse_ignored_deps:
+ if is_virt and dep.child is not None:
+ traversed_virt_pkgs.add(dep.child)
+ dep.child = None
+ self._dynamic_config._ignored_deps.append(dep)
+ else:
+ if not self._add_dep(dep,
+ allow_unsatisfied=allow_unsatisfied):
+ return 0
+ if is_virt and dep.child is not None:
+ traversed_virt_pkgs.add(dep.child)
+
+ selected_atoms.pop(pkg)
+
+ # Add selected indirect virtual deps to the graph. This
+ # takes advantage of circular dependency avoidance that's done
+ # by dep_zapdeps. We preserve actual parent/child relationships
+ # here in order to avoid distorting the dependency graph like
+ # <=portage-2.1.6.x did.
+ for virt_dep, atoms in selected_atoms.items():
+
+ virt_pkg = virt_dep.child
+ if virt_pkg not in traversed_virt_pkgs:
+ continue
+
+ if debug:
+ writemsg_level("\nCandidates: %s: %s\n" % \
+ (virt_pkg.cpv, [str(x) for x in atoms]),
+ noiselevel=-1, level=logging.DEBUG)
+
+ if not dep_priority.ignored or \
+ self._dynamic_config._traverse_ignored_deps:
+
+ inst_pkgs = [inst_pkg for inst_pkg in
+ reversed(vardb.match_pkgs(virt_dep.atom))
+ if not reinstall_atoms.findAtomForPackage(inst_pkg,
+ modified_use=self._pkg_use_enabled(inst_pkg))]
+ if inst_pkgs:
+ for inst_pkg in inst_pkgs:
+ if self._pkg_visibility_check(inst_pkg):
+ # highest visible
+ virt_dep.priority.satisfied = inst_pkg
+ break
+ if not virt_dep.priority.satisfied:
+ # none visible, so use highest
+ virt_dep.priority.satisfied = inst_pkgs[0]
+
+ if not self._add_pkg(virt_pkg, virt_dep):
+ return 0
+
+ for atom, child in self._minimize_children(
+ pkg, self._priority(runtime=True), root_config, atoms):
+
+ # If this was a specially generated virtual atom
+ # from dep_check, map it back to the original, in
+ # order to avoid distortion in places like display
+ # or conflict resolution code.
+ is_virt = hasattr(atom, '_orig_atom')
+ atom = getattr(atom, '_orig_atom', atom)
+
+ # This is a GLEP 37 virtual, so its deps are all runtime.
+ mypriority = self._priority(runtime=True)
+ if not atom.blocker:
+ inst_pkgs = [inst_pkg for inst_pkg in
+ reversed(vardb.match_pkgs(atom))
+ if not reinstall_atoms.findAtomForPackage(inst_pkg,
+ modified_use=self._pkg_use_enabled(inst_pkg))]
+ if inst_pkgs:
+ for inst_pkg in inst_pkgs:
+ if self._pkg_visibility_check(inst_pkg):
+ # highest visible
+ mypriority.satisfied = inst_pkg
+ break
+ if not mypriority.satisfied:
+ # none visible, so use highest
+ mypriority.satisfied = inst_pkgs[0]
+
+ # Dependencies of virtuals are considered to have the
+ # same depth as the virtual itself.
+ dep = Dependency(atom=atom,
+ blocker=atom.blocker, child=child, depth=virt_dep.depth,
+ parent=virt_pkg, priority=mypriority, root=dep_root,
+ collapsed_parent=pkg, collapsed_priority=dep_priority)
+
+ ignored = False
+ if not atom.blocker and \
+ not recurse_satisfied and \
+ mypriority.satisfied and \
+ mypriority.satisfied.visible and \
+ dep.child is not None and \
+ not dep.child.installed and \
+ self._dynamic_config._slot_pkg_map[dep.child.root].get(
+ dep.child.slot_atom) is None:
+ myarg = None
+ if dep.root == self._frozen_config.target_root:
+ try:
+ myarg = next(self._iter_atoms_for_pkg(dep.child))
+ except StopIteration:
+ pass
+ except InvalidDependString:
+ if not dep.child.installed:
+ raise
+
+ if myarg is None:
+ ignored = True
+ dep.child = None
+ self._dynamic_config._ignored_deps.append(dep)
+
+ if not ignored:
+ if dep_priority.ignored and \
+ not self._dynamic_config._traverse_ignored_deps:
+ if is_virt and dep.child is not None:
+ traversed_virt_pkgs.add(dep.child)
+ dep.child = None
+ self._dynamic_config._ignored_deps.append(dep)
+ else:
+ if not self._add_dep(dep,
+ allow_unsatisfied=allow_unsatisfied):
+ return 0
+ if is_virt and dep.child is not None:
+ traversed_virt_pkgs.add(dep.child)
+
+ if debug:
+ writemsg_level("\nExiting... %s\n" % (pkg,),
+ noiselevel=-1, level=logging.DEBUG)
+
+ return 1
+
+ def _minimize_children(self, parent, priority, root_config, atoms):
+ """
+ Selects packages to satisfy the given atoms, and minimizes the
+ number of selected packages. This serves to identify and eliminate
+ redundant package selections when multiple atoms happen to specify
+ a version range.
+ """
+
+ atom_pkg_map = {}
+
+ for atom in atoms:
+ if atom.blocker:
+ yield (atom, None)
+ continue
+ dep_pkg, existing_node = self._select_package(
+ root_config.root, atom)
+ if dep_pkg is None:
+ yield (atom, None)
+ continue
+ atom_pkg_map[atom] = dep_pkg
+
+ if len(atom_pkg_map) < 2:
+ for item in atom_pkg_map.items():
+ yield item
+ return
+
+ cp_pkg_map = {}
+ pkg_atom_map = {}
+ for atom, pkg in atom_pkg_map.items():
+ pkg_atom_map.setdefault(pkg, set()).add(atom)
+ cp_pkg_map.setdefault(pkg.cp, set()).add(pkg)
+
+ for cp, pkgs in cp_pkg_map.items():
+ if len(pkgs) < 2:
+ for pkg in pkgs:
+ for atom in pkg_atom_map[pkg]:
+ yield (atom, pkg)
+ continue
+
+ # Use a digraph to identify and eliminate any
+ # redundant package selections.
+ atom_pkg_graph = digraph()
+ cp_atoms = set()
+ for pkg1 in pkgs:
+ for atom in pkg_atom_map[pkg1]:
+ cp_atoms.add(atom)
+ atom_pkg_graph.add(pkg1, atom)
+ atom_set = InternalPackageSet(initial_atoms=(atom,),
+ allow_repo=True)
+ for pkg2 in pkgs:
+ if pkg2 is pkg1:
+ continue
+ if atom_set.findAtomForPackage(pkg2, modified_use=self._pkg_use_enabled(pkg2)):
+ atom_pkg_graph.add(pkg2, atom)
+
+ for pkg in pkgs:
+ eliminate_pkg = True
+ for atom in atom_pkg_graph.parent_nodes(pkg):
+ if len(atom_pkg_graph.child_nodes(atom)) < 2:
+ eliminate_pkg = False
+ break
+ if eliminate_pkg:
+ atom_pkg_graph.remove(pkg)
+
+ # Yield ~, =*, < and <= atoms first, since those are more likely to
+ # cause slot conflicts, and we want those atoms to be displayed
+ # in the resulting slot conflict message (see bug #291142).
+ conflict_atoms = []
+ normal_atoms = []
+ for atom in cp_atoms:
+ conflict = False
+ for child_pkg in atom_pkg_graph.child_nodes(atom):
+ existing_node, matches = \
+ self._check_slot_conflict(child_pkg, atom)
+ if existing_node and not matches:
+ conflict = True
+ break
+ if conflict:
+ conflict_atoms.append(atom)
+ else:
+ normal_atoms.append(atom)
+
+ for atom in chain(conflict_atoms, normal_atoms):
+ child_pkgs = atom_pkg_graph.child_nodes(atom)
+ # if more than one child, yield highest version
+ if len(child_pkgs) > 1:
+ child_pkgs.sort()
+ yield (atom, child_pkgs[-1])
+
+ def _queue_disjunctive_deps(self, pkg, dep_root, dep_priority, dep_struct):
+ """
+ Queue disjunctive (virtual and ||) deps in self._dynamic_config._dep_disjunctive_stack.
+ Yields non-disjunctive deps. Raises InvalidDependString when
+ necessary.
+ """
+ i = 0
+ while i < len(dep_struct):
+ x = dep_struct[i]
+ if isinstance(x, list):
+ for y in self._queue_disjunctive_deps(
+ pkg, dep_root, dep_priority, x):
+ yield y
+ elif x == "||":
+ self._queue_disjunction(pkg, dep_root, dep_priority,
+ [ x, dep_struct[ i + 1 ] ] )
+ i += 1
+ else:
+ try:
+ x = portage.dep.Atom(x)
+ except portage.exception.InvalidAtom:
+ if not pkg.installed:
+ raise portage.exception.InvalidDependString(
+ "invalid atom: '%s'" % x)
+ else:
+ # Note: Eventually this will check for PROPERTIES=virtual
+ # or whatever other metadata gets implemented for this
+ # purpose.
+ if x.cp.startswith('virtual/'):
+ self._queue_disjunction( pkg, dep_root,
+ dep_priority, [ str(x) ] )
+ else:
+ yield str(x)
+ i += 1
+
+ def _queue_disjunction(self, pkg, dep_root, dep_priority, dep_struct):
+ self._dynamic_config._dep_disjunctive_stack.append(
+ (pkg, dep_root, dep_priority, dep_struct))
+
+ def _pop_disjunction(self, allow_unsatisfied):
+ """
+ Pop one disjunctive dep from self._dynamic_config._dep_disjunctive_stack, and use it to
+ populate self._dynamic_config._dep_stack.
+ """
+ pkg, dep_root, dep_priority, dep_struct = \
+ self._dynamic_config._dep_disjunctive_stack.pop()
+ dep_string = portage.dep.paren_enclose(dep_struct,
+ unevaluated_atom=True)
+ if not self._add_pkg_dep_string(
+ pkg, dep_root, dep_priority, dep_string, allow_unsatisfied):
+ return 0
+ return 1
+
+ def _priority(self, **kwargs):
+ if "remove" in self._dynamic_config.myparams:
+ priority_constructor = UnmergeDepPriority
+ else:
+ priority_constructor = DepPriority
+ return priority_constructor(**kwargs)
+
+ def _dep_expand(self, root_config, atom_without_category):
+ """
+ @param root_config: a root config instance
+ @type root_config: RootConfig
+ @param atom_without_category: an atom without a category component
+ @type atom_without_category: String
+ @rtype: list
+ @returns: a list of atoms containing categories (possibly empty)
+ """
+ null_cp = portage.dep_getkey(insert_category_into_atom(
+ atom_without_category, "null"))
+ cat, atom_pn = portage.catsplit(null_cp)
+
+ dbs = self._dynamic_config._filtered_trees[root_config.root]["dbs"]
+ categories = set()
+ for db, pkg_type, built, installed, db_keys in dbs:
+ for cat in db.categories:
+ if db.cp_list("%s/%s" % (cat, atom_pn)):
+ categories.add(cat)
+
+ deps = []
+ for cat in categories:
+ deps.append(Atom(insert_category_into_atom(
+ atom_without_category, cat), allow_repo=True))
+ return deps
+
+ def _have_new_virt(self, root, atom_cp):
+ ret = False
+ for db, pkg_type, built, installed, db_keys in \
+ self._dynamic_config._filtered_trees[root]["dbs"]:
+ if db.cp_list(atom_cp):
+ ret = True
+ break
+ return ret
+
+ def _iter_atoms_for_pkg(self, pkg):
+ depgraph_sets = self._dynamic_config.sets[pkg.root]
+ atom_arg_map = depgraph_sets.atom_arg_map
+ root_config = self._frozen_config.roots[pkg.root]
+ for atom in depgraph_sets.atoms.iterAtomsForPackage(pkg):
+ if atom.cp != pkg.cp and \
+ self._have_new_virt(pkg.root, atom.cp):
+ continue
+ visible_pkgs = \
+ self._dynamic_config._visible_pkgs[pkg.root].match_pkgs(atom)
+ visible_pkgs.reverse() # descending order
+ higher_slot = None
+ for visible_pkg in visible_pkgs:
+ if visible_pkg.cp != atom.cp:
+ continue
+ if pkg >= visible_pkg:
+ # This is descending order, and we're not
+ # interested in any versions <= pkg given.
+ break
+ if pkg.slot_atom != visible_pkg.slot_atom:
+ higher_slot = visible_pkg
+ break
+ if higher_slot is not None:
+ continue
+ for arg in atom_arg_map[(atom, pkg.root)]:
+ if isinstance(arg, PackageArg) and \
+ arg.package != pkg:
+ continue
+ yield arg, atom
+
+ def select_files(self, myfiles):
+ """Given a list of .tbz2s, .ebuilds sets, and deps, populate
+ self._dynamic_config._initial_arg_list and call self._resolve to create the
+ appropriate depgraph and return a favorite list."""
+ self._load_vdb()
+ debug = "--debug" in self._frozen_config.myopts
+ root_config = self._frozen_config.roots[self._frozen_config.target_root]
+ sets = root_config.sets
+ depgraph_sets = self._dynamic_config.sets[root_config.root]
+ myfavorites=[]
+ myroot = self._frozen_config.target_root
+ dbs = self._dynamic_config._filtered_trees[myroot]["dbs"]
+ vardb = self._frozen_config.trees[myroot]["vartree"].dbapi
+ real_vardb = self._frozen_config._trees_orig[myroot]["vartree"].dbapi
+ portdb = self._frozen_config.trees[myroot]["porttree"].dbapi
+ bindb = self._frozen_config.trees[myroot]["bintree"].dbapi
+ pkgsettings = self._frozen_config.pkgsettings[myroot]
+ args = []
+ onlydeps = "--onlydeps" in self._frozen_config.myopts
+ lookup_owners = []
+ for x in myfiles:
+ ext = os.path.splitext(x)[1]
+ if ext==".tbz2":
+ if not os.path.exists(x):
+ if os.path.exists(
+ os.path.join(pkgsettings["PKGDIR"], "All", x)):
+ x = os.path.join(pkgsettings["PKGDIR"], "All", x)
+ elif os.path.exists(
+ os.path.join(pkgsettings["PKGDIR"], x)):
+ x = os.path.join(pkgsettings["PKGDIR"], x)
+ else:
+ writemsg("\n\n!!! Binary package '"+str(x)+"' does not exist.\n", noiselevel=-1)
+ writemsg("!!! Please ensure the tbz2 exists as specified.\n\n", noiselevel=-1)
+ return 0, myfavorites
+ mytbz2=portage.xpak.tbz2(x)
+ mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.splitext(os.path.basename(x))[0]
+ if os.path.realpath(x) != \
+ os.path.realpath(self._frozen_config.trees[myroot]["bintree"].getname(mykey)):
+ writemsg(colorize("BAD", "\n*** You need to adjust PKGDIR to emerge this package.\n\n"), noiselevel=-1)
+ self._dynamic_config._skip_restart = True
+ return 0, myfavorites
+
+ pkg = self._pkg(mykey, "binary", root_config,
+ onlydeps=onlydeps)
+ args.append(PackageArg(arg=x, package=pkg,
+ root_config=root_config))
+ elif ext==".ebuild":
+ ebuild_path = portage.util.normalize_path(os.path.abspath(x))
+ pkgdir = os.path.dirname(ebuild_path)
+ tree_root = os.path.dirname(os.path.dirname(pkgdir))
+ cp = pkgdir[len(tree_root)+1:]
+ e = portage.exception.PackageNotFound(
+ ("%s is not in a valid portage tree " + \
+ "hierarchy or does not exist") % x)
+ if not portage.isvalidatom(cp):
+ raise e
+ cat = portage.catsplit(cp)[0]
+ mykey = cat + "/" + os.path.basename(ebuild_path[:-7])
+ if not portage.isvalidatom("="+mykey):
+ raise e
+ ebuild_path = portdb.findname(mykey)
+ if ebuild_path:
+ if ebuild_path != os.path.join(os.path.realpath(tree_root),
+ cp, os.path.basename(ebuild_path)):
+ writemsg(colorize("BAD", "\n*** You need to adjust PORTDIR or PORTDIR_OVERLAY to emerge this package.\n\n"), noiselevel=-1)
+ self._dynamic_config._skip_restart = True
+ return 0, myfavorites
+ if mykey not in portdb.xmatch(
+ "match-visible", portage.cpv_getkey(mykey)):
+ writemsg(colorize("BAD", "\n*** You are emerging a masked package. It is MUCH better to use\n"), noiselevel=-1)
+ writemsg(colorize("BAD", "*** /etc/portage/package.* to accomplish this. See portage(5) man\n"), noiselevel=-1)
+ writemsg(colorize("BAD", "*** page for details.\n"), noiselevel=-1)
+ countdown(int(self._frozen_config.settings["EMERGE_WARNING_DELAY"]),
+ "Continuing...")
+ else:
+ raise portage.exception.PackageNotFound(
+ "%s is not in a valid portage tree hierarchy or does not exist" % x)
+ pkg = self._pkg(mykey, "ebuild", root_config,
+ onlydeps=onlydeps, myrepo=portdb.getRepositoryName(
+ os.path.dirname(os.path.dirname(os.path.dirname(ebuild_path)))))
+ args.append(PackageArg(arg=x, package=pkg,
+ root_config=root_config))
+ elif x.startswith(os.path.sep):
+ if not x.startswith(myroot):
+ portage.writemsg(("\n\n!!! '%s' does not start with" + \
+ " $ROOT.\n") % x, noiselevel=-1)
+ self._dynamic_config._skip_restart = True
+ return 0, []
+ # Queue these up since it's most efficient to handle
+ # multiple files in a single iter_owners() call.
+ lookup_owners.append(x)
+ elif x.startswith("." + os.sep) or \
+ x.startswith(".." + os.sep):
+ f = os.path.abspath(x)
+ if not f.startswith(myroot):
+ portage.writemsg(("\n\n!!! '%s' (resolved from '%s') does not start with" + \
+ " $ROOT.\n") % (f, x), noiselevel=-1)
+ self._dynamic_config._skip_restart = True
+ return 0, []
+ lookup_owners.append(f)
+ else:
+ if x in ("system", "world"):
+ x = SETPREFIX + x
+ if x.startswith(SETPREFIX):
+ s = x[len(SETPREFIX):]
+ if s not in sets:
+ raise portage.exception.PackageSetNotFound(s)
+ if s in depgraph_sets.sets:
+ continue
+ pset = sets[s]
+ depgraph_sets.sets[s] = pset
+ args.append(SetArg(arg=x, pset=pset,
+ root_config=root_config))
+ continue
+ if not is_valid_package_atom(x, allow_repo=True):
+ portage.writemsg("\n\n!!! '%s' is not a valid package atom.\n" % x,
+ noiselevel=-1)
+ portage.writemsg("!!! Please check ebuild(5) for full details.\n")
+ portage.writemsg("!!! (Did you specify a version but forget to prefix with '='?)\n")
+ self._dynamic_config._skip_restart = True
+ return (0,[])
+ # Don't expand categories or old-style virtuals here unless
+ # necessary. Expansion of old-style virtuals here causes at
+ # least the following problems:
+ # 1) It's more difficult to determine which set(s) an atom
+ # came from, if any.
+ # 2) It takes away freedom from the resolver to choose other
+ # possible expansions when necessary.
+ if "/" in x:
+ args.append(AtomArg(arg=x, atom=Atom(x, allow_repo=True),
+ root_config=root_config))
+ continue
+ expanded_atoms = self._dep_expand(root_config, x)
+ installed_cp_set = set()
+ for atom in expanded_atoms:
+ if vardb.cp_list(atom.cp):
+ installed_cp_set.add(atom.cp)
+
+ if len(installed_cp_set) > 1:
+ non_virtual_cps = set()
+ for atom_cp in installed_cp_set:
+ if not atom_cp.startswith("virtual/"):
+ non_virtual_cps.add(atom_cp)
+ if len(non_virtual_cps) == 1:
+ installed_cp_set = non_virtual_cps
+
+ if len(expanded_atoms) > 1 and len(installed_cp_set) == 1:
+ installed_cp = next(iter(installed_cp_set))
+ for atom in expanded_atoms:
+ if atom.cp == installed_cp:
+ available = False
+ for pkg in self._iter_match_pkgs_any(
+ root_config, atom.without_use,
+ onlydeps=onlydeps):
+ if not pkg.installed:
+ available = True
+ break
+ if available:
+ expanded_atoms = [atom]
+ break
+
+ # If a non-virtual package and one or more virtual packages
+ # are in expanded_atoms, use the non-virtual package.
+ if len(expanded_atoms) > 1:
+ number_of_virtuals = 0
+ for expanded_atom in expanded_atoms:
+ if expanded_atom.cp.startswith("virtual/"):
+ number_of_virtuals += 1
+ else:
+ candidate = expanded_atom
+ if len(expanded_atoms) - number_of_virtuals == 1:
+ expanded_atoms = [ candidate ]
+
+ if len(expanded_atoms) > 1:
+ writemsg("\n\n", noiselevel=-1)
+ ambiguous_package_name(x, expanded_atoms, root_config,
+ self._frozen_config.spinner, self._frozen_config.myopts)
+ self._dynamic_config._skip_restart = True
+ return False, myfavorites
+ if expanded_atoms:
+ atom = expanded_atoms[0]
+ else:
+ null_atom = Atom(insert_category_into_atom(x, "null"),
+ allow_repo=True)
+ cat, atom_pn = portage.catsplit(null_atom.cp)
+ virts_p = root_config.settings.get_virts_p().get(atom_pn)
+ if virts_p:
+ # Allow the depgraph to choose which virtual.
+ atom = Atom(null_atom.replace('null/', 'virtual/', 1),
+ allow_repo=True)
+ else:
+ atom = null_atom
+
+ if atom.use and atom.use.conditional:
+ writemsg(
+ ("\n\n!!! '%s' contains a conditional " + \
+ "which is not allowed.\n") % (x,), noiselevel=-1)
+ writemsg("!!! Please check ebuild(5) for full details.\n")
+ self._dynamic_config._skip_restart = True
+ return (0,[])
+
+ args.append(AtomArg(arg=x, atom=atom,
+ root_config=root_config))
+
+ if lookup_owners:
+ relative_paths = []
+ search_for_multiple = False
+ if len(lookup_owners) > 1:
+ search_for_multiple = True
+
+ for x in lookup_owners:
+ if not search_for_multiple and os.path.isdir(x):
+ search_for_multiple = True
+ relative_paths.append(x[len(myroot)-1:])
+
+ owners = set()
+ for pkg, relative_path in \
+ real_vardb._owners.iter_owners(relative_paths):
+ owners.add(pkg.mycpv)
+ if not search_for_multiple:
+ break
+
+ if not owners:
+ portage.writemsg(("\n\n!!! '%s' is not claimed " + \
+ "by any package.\n") % lookup_owners[0], noiselevel=-1)
+ self._dynamic_config._skip_restart = True
+ return 0, []
+
+ for cpv in owners:
+ slot = vardb.aux_get(cpv, ["SLOT"])[0]
+ if not slot:
+ # portage now masks packages with missing slot, but it's
+ # possible that one was installed by an older version
+ atom = Atom(portage.cpv_getkey(cpv))
+ else:
+ atom = Atom("%s:%s" % (portage.cpv_getkey(cpv), slot))
+ args.append(AtomArg(arg=atom, atom=atom,
+ root_config=root_config))
+
+ if "--update" in self._frozen_config.myopts:
+ # In some cases, the greedy slots behavior can pull in a slot that
+ # the user would want to uninstall due to it being blocked by a
+ # newer version in a different slot. Therefore, it's necessary to
+ # detect and discard any that should be uninstalled. Each time
+ # that arguments are updated, package selections are repeated in
+ # order to ensure consistency with the current arguments:
+ #
+ # 1) Initialize args
+ # 2) Select packages and generate initial greedy atoms
+ # 3) Update args with greedy atoms
+ # 4) Select packages and generate greedy atoms again, while
+ # accounting for any blockers between selected packages
+ # 5) Update args with revised greedy atoms
+
+ self._set_args(args)
+ greedy_args = []
+ for arg in args:
+ greedy_args.append(arg)
+ if not isinstance(arg, AtomArg):
+ continue
+ for atom in self._greedy_slots(arg.root_config, arg.atom):
+ greedy_args.append(
+ AtomArg(arg=arg.arg, atom=atom,
+ root_config=arg.root_config))
+
+ self._set_args(greedy_args)
+ del greedy_args
+
+ # Revise greedy atoms, accounting for any blockers
+ # between selected packages.
+ revised_greedy_args = []
+ for arg in args:
+ revised_greedy_args.append(arg)
+ if not isinstance(arg, AtomArg):
+ continue
+ for atom in self._greedy_slots(arg.root_config, arg.atom,
+ blocker_lookahead=True):
+ revised_greedy_args.append(
+ AtomArg(arg=arg.arg, atom=atom,
+ root_config=arg.root_config))
+ args = revised_greedy_args
+ del revised_greedy_args
+
+ self._set_args(args)
+
+ myfavorites = set(myfavorites)
+ for arg in args:
+ if isinstance(arg, (AtomArg, PackageArg)):
+ myfavorites.add(arg.atom)
+ elif isinstance(arg, SetArg):
+ myfavorites.add(arg.arg)
+ myfavorites = list(myfavorites)
+
+ if debug:
+ portage.writemsg("\n", noiselevel=-1)
+ # Order needs to be preserved since a feature of --nodeps
+ # is to allow the user to force a specific merge order.
+ self._dynamic_config._initial_arg_list = args[:]
+
+ return self._resolve(myfavorites)
+
+ def _resolve(self, myfavorites):
+ """Given self._dynamic_config._initial_arg_list, pull in the root nodes,
+ call self._creategraph to process theier deps and return
+ a favorite list."""
+ debug = "--debug" in self._frozen_config.myopts
+ onlydeps = "--onlydeps" in self._frozen_config.myopts
+ myroot = self._frozen_config.target_root
+ pkgsettings = self._frozen_config.pkgsettings[myroot]
+ pprovideddict = pkgsettings.pprovideddict
+ virtuals = pkgsettings.getvirtuals()
+ args = self._dynamic_config._initial_arg_list[:]
+ for root, atom in chain(self._rebuild.rebuild_list,
+ self._rebuild.reinstall_list):
+ args.append(AtomArg(arg=atom, atom=atom,
+ root_config=self._frozen_config.roots[root]))
+ for arg in self._expand_set_args(args, add_to_digraph=True):
+ for atom in arg.pset.getAtoms():
+ self._spinner_update()
+ dep = Dependency(atom=atom, onlydeps=onlydeps,
+ root=myroot, parent=arg)
+ try:
+ pprovided = pprovideddict.get(atom.cp)
+ if pprovided and portage.match_from_list(atom, pprovided):
+ # A provided package has been specified on the command line.
+ self._dynamic_config._pprovided_args.append((arg, atom))
+ continue
+ if isinstance(arg, PackageArg):
+ if not self._add_pkg(arg.package, dep) or \
+ not self._create_graph():
+ if not self.need_restart():
+ sys.stderr.write(("\n\n!!! Problem " + \
+ "resolving dependencies for %s\n") % \
+ arg.arg)
+ return 0, myfavorites
+ continue
+ if debug:
+ writemsg_level("\n Arg: %s\n Atom: %s\n" %
+ (arg, atom), noiselevel=-1, level=logging.DEBUG)
+ pkg, existing_node = self._select_package(
+ myroot, atom, onlydeps=onlydeps)
+ if not pkg:
+ pprovided_match = False
+ for virt_choice in virtuals.get(atom.cp, []):
+ expanded_atom = portage.dep.Atom(
+ atom.replace(atom.cp, virt_choice.cp, 1))
+ pprovided = pprovideddict.get(expanded_atom.cp)
+ if pprovided and \
+ portage.match_from_list(expanded_atom, pprovided):
+ # A provided package has been
+ # specified on the command line.
+ self._dynamic_config._pprovided_args.append((arg, atom))
+ pprovided_match = True
+ break
+ if pprovided_match:
+ continue
+
+ if not (isinstance(arg, SetArg) and \
+ arg.name in ("selected", "system", "world")):
+ self._dynamic_config._unsatisfied_deps_for_display.append(
+ ((myroot, atom), {"myparent" : arg}))
+ return 0, myfavorites
+
+ self._dynamic_config._missing_args.append((arg, atom))
+ continue
+ if atom.cp != pkg.cp:
+ # For old-style virtuals, we need to repeat the
+ # package.provided check against the selected package.
+ expanded_atom = atom.replace(atom.cp, pkg.cp)
+ pprovided = pprovideddict.get(pkg.cp)
+ if pprovided and \
+ portage.match_from_list(expanded_atom, pprovided):
+ # A provided package has been
+ # specified on the command line.
+ self._dynamic_config._pprovided_args.append((arg, atom))
+ continue
+ if pkg.installed and \
+ "selective" not in self._dynamic_config.myparams and \
+ not self._frozen_config.excluded_pkgs.findAtomForPackage(
+ pkg, modified_use=self._pkg_use_enabled(pkg)):
+ self._dynamic_config._unsatisfied_deps_for_display.append(
+ ((myroot, atom), {"myparent" : arg}))
+ # Previous behavior was to bail out in this case, but
+ # since the dep is satisfied by the installed package,
+ # it's more friendly to continue building the graph
+ # and just show a warning message. Therefore, only bail
+ # out here if the atom is not from either the system or
+ # world set.
+ if not (isinstance(arg, SetArg) and \
+ arg.name in ("selected", "system", "world")):
+ return 0, myfavorites
+
+ # Add the selected package to the graph as soon as possible
+ # so that later dep_check() calls can use it as feedback
+ # for making more consistent atom selections.
+ if not self._add_pkg(pkg, dep):
+ if self.need_restart():
+ pass
+ elif isinstance(arg, SetArg):
+ writemsg(("\n\n!!! Problem resolving " + \
+ "dependencies for %s from %s\n") % \
+ (atom, arg.arg), noiselevel=-1)
+ else:
+ writemsg(("\n\n!!! Problem resolving " + \
+ "dependencies for %s\n") % \
+ (atom,), noiselevel=-1)
+ return 0, myfavorites
+
+ except SystemExit as e:
+ raise # Needed else can't exit
+ except Exception as e:
+ writemsg("\n\n!!! Problem in '%s' dependencies.\n" % atom, noiselevel=-1)
+ writemsg("!!! %s %s\n" % (str(e), str(getattr(e, "__module__", None))))
+ raise
+
+ # Now that the root packages have been added to the graph,
+ # process the dependencies.
+ if not self._create_graph():
+ return 0, myfavorites
+
+ try:
+ self.altlist()
+ except self._unknown_internal_error:
+ return False, myfavorites
+
+ digraph_set = frozenset(self._dynamic_config.digraph)
+
+ if digraph_set.intersection(
+ self._dynamic_config._needed_unstable_keywords) or \
+ digraph_set.intersection(
+ self._dynamic_config._needed_p_mask_changes) or \
+ digraph_set.intersection(
+ self._dynamic_config._needed_use_config_changes) or \
+ digraph_set.intersection(
+ self._dynamic_config._needed_license_changes) :
+ #We failed if the user needs to change the configuration
+ self._dynamic_config._success_without_autounmask = True
+ return False, myfavorites
+
+ digraph_set = None
+
+ if self._rebuild.trigger_rebuilds():
+ backtrack_infos = self._dynamic_config._backtrack_infos
+ config = backtrack_infos.setdefault("config", {})
+ config["rebuild_list"] = self._rebuild.rebuild_list
+ config["reinstall_list"] = self._rebuild.reinstall_list
+ self._dynamic_config._need_restart = True
+ return False, myfavorites
+
+ # We're true here unless we are missing binaries.
+ return (True, myfavorites)
+
+ def _set_args(self, args):
+ """
+ Create the "__non_set_args__" package set from atoms and packages given as
+ arguments. This method can be called multiple times if necessary.
+ The package selection cache is automatically invalidated, since
+ arguments influence package selections.
+ """
+
+ set_atoms = {}
+ non_set_atoms = {}
+ for root in self._dynamic_config.sets:
+ depgraph_sets = self._dynamic_config.sets[root]
+ depgraph_sets.sets.setdefault('__non_set_args__',
+ InternalPackageSet(allow_repo=True)).clear()
+ depgraph_sets.atoms.clear()
+ depgraph_sets.atom_arg_map.clear()
+ set_atoms[root] = []
+ non_set_atoms[root] = []
+
+ # We don't add set args to the digraph here since that
+ # happens at a later stage and we don't want to make
+ # any state changes here that aren't reversed by a
+ # another call to this method.
+ for arg in self._expand_set_args(args, add_to_digraph=False):
+ atom_arg_map = self._dynamic_config.sets[
+ arg.root_config.root].atom_arg_map
+ if isinstance(arg, SetArg):
+ atom_group = set_atoms[arg.root_config.root]
+ else:
+ atom_group = non_set_atoms[arg.root_config.root]
+
+ for atom in arg.pset.getAtoms():
+ atom_group.append(atom)
+ atom_key = (atom, arg.root_config.root)
+ refs = atom_arg_map.get(atom_key)
+ if refs is None:
+ refs = []
+ atom_arg_map[atom_key] = refs
+ if arg not in refs:
+ refs.append(arg)
+
+ for root in self._dynamic_config.sets:
+ depgraph_sets = self._dynamic_config.sets[root]
+ depgraph_sets.atoms.update(chain(set_atoms.get(root, []),
+ non_set_atoms.get(root, [])))
+ depgraph_sets.sets['__non_set_args__'].update(
+ non_set_atoms.get(root, []))
+
+ # Invalidate the package selection cache, since
+ # arguments influence package selections.
+ self._dynamic_config._highest_pkg_cache.clear()
+ for trees in self._dynamic_config._filtered_trees.values():
+ trees["porttree"].dbapi._clear_cache()
+
+ def _greedy_slots(self, root_config, atom, blocker_lookahead=False):
+ """
+ Return a list of slot atoms corresponding to installed slots that
+ differ from the slot of the highest visible match. When
+ blocker_lookahead is True, slot atoms that would trigger a blocker
+ conflict are automatically discarded, potentially allowing automatic
+ uninstallation of older slots when appropriate.
+ """
+ highest_pkg, in_graph = self._select_package(root_config.root, atom)
+ if highest_pkg is None:
+ return []
+ vardb = root_config.trees["vartree"].dbapi
+ slots = set()
+ for cpv in vardb.match(atom):
+ # don't mix new virtuals with old virtuals
+ if portage.cpv_getkey(cpv) == highest_pkg.cp:
+ slots.add(vardb.aux_get(cpv, ["SLOT"])[0])
+
+ slots.add(highest_pkg.metadata["SLOT"])
+ if len(slots) == 1:
+ return []
+ greedy_pkgs = []
+ slots.remove(highest_pkg.metadata["SLOT"])
+ while slots:
+ slot = slots.pop()
+ slot_atom = portage.dep.Atom("%s:%s" % (highest_pkg.cp, slot))
+ pkg, in_graph = self._select_package(root_config.root, slot_atom)
+ if pkg is not None and \
+ pkg.cp == highest_pkg.cp and pkg < highest_pkg:
+ greedy_pkgs.append(pkg)
+ if not greedy_pkgs:
+ return []
+ if not blocker_lookahead:
+ return [pkg.slot_atom for pkg in greedy_pkgs]
+
+ blockers = {}
+ blocker_dep_keys = ["DEPEND", "PDEPEND", "RDEPEND"]
+ for pkg in greedy_pkgs + [highest_pkg]:
+ dep_str = " ".join(pkg.metadata[k] for k in blocker_dep_keys)
+ try:
+ selected_atoms = self._select_atoms(
+ pkg.root, dep_str, self._pkg_use_enabled(pkg),
+ parent=pkg, strict=True)
+ except portage.exception.InvalidDependString:
+ continue
+ blocker_atoms = []
+ for atoms in selected_atoms.values():
+ blocker_atoms.extend(x for x in atoms if x.blocker)
+ blockers[pkg] = InternalPackageSet(initial_atoms=blocker_atoms)
+
+ if highest_pkg not in blockers:
+ return []
+
+ # filter packages with invalid deps
+ greedy_pkgs = [pkg for pkg in greedy_pkgs if pkg in blockers]
+
+ # filter packages that conflict with highest_pkg
+ greedy_pkgs = [pkg for pkg in greedy_pkgs if not \
+ (blockers[highest_pkg].findAtomForPackage(pkg, modified_use=self._pkg_use_enabled(pkg)) or \
+ blockers[pkg].findAtomForPackage(highest_pkg, modified_use=self._pkg_use_enabled(highest_pkg)))]
+
+ if not greedy_pkgs:
+ return []
+
+ # If two packages conflict, discard the lower version.
+ discard_pkgs = set()
+ greedy_pkgs.sort(reverse=True)
+ for i in range(len(greedy_pkgs) - 1):
+ pkg1 = greedy_pkgs[i]
+ if pkg1 in discard_pkgs:
+ continue
+ for j in range(i + 1, len(greedy_pkgs)):
+ pkg2 = greedy_pkgs[j]
+ if pkg2 in discard_pkgs:
+ continue
+ if blockers[pkg1].findAtomForPackage(pkg2, modified_use=self._pkg_use_enabled(pkg2)) or \
+ blockers[pkg2].findAtomForPackage(pkg1, modified_use=self._pkg_use_enabled(pkg1)):
+ # pkg1 > pkg2
+ discard_pkgs.add(pkg2)
+
+ return [pkg.slot_atom for pkg in greedy_pkgs \
+ if pkg not in discard_pkgs]
+
+ def _select_atoms_from_graph(self, *pargs, **kwargs):
+ """
+ Prefer atoms matching packages that have already been
+ added to the graph or those that are installed and have
+ not been scheduled for replacement.
+ """
+ kwargs["trees"] = self._dynamic_config._graph_trees
+ return self._select_atoms_highest_available(*pargs, **kwargs)
+
+ def _select_atoms_highest_available(self, root, depstring,
+ myuse=None, parent=None, strict=True, trees=None, priority=None):
+ """This will raise InvalidDependString if necessary. If trees is
+ None then self._dynamic_config._filtered_trees is used."""
+
+ pkgsettings = self._frozen_config.pkgsettings[root]
+ if trees is None:
+ trees = self._dynamic_config._filtered_trees
+ mytrees = trees[root]
+ atom_graph = digraph()
+ if True:
+ # Temporarily disable autounmask so that || preferences
+ # account for masking and USE settings.
+ _autounmask_backup = self._dynamic_config._autounmask
+ self._dynamic_config._autounmask = False
+ mytrees["pkg_use_enabled"] = self._pkg_use_enabled
+ try:
+ if parent is not None:
+ trees[root]["parent"] = parent
+ trees[root]["atom_graph"] = atom_graph
+ if priority is not None:
+ trees[root]["priority"] = priority
+ mycheck = portage.dep_check(depstring, None,
+ pkgsettings, myuse=myuse,
+ myroot=root, trees=trees)
+ finally:
+ self._dynamic_config._autounmask = _autounmask_backup
+ del mytrees["pkg_use_enabled"]
+ if parent is not None:
+ trees[root].pop("parent")
+ trees[root].pop("atom_graph")
+ if priority is not None:
+ trees[root].pop("priority")
+ if not mycheck[0]:
+ raise portage.exception.InvalidDependString(mycheck[1])
+ if parent is None:
+ selected_atoms = mycheck[1]
+ elif parent not in atom_graph:
+ selected_atoms = {parent : mycheck[1]}
+ else:
+ # Recursively traversed virtual dependencies, and their
+ # direct dependencies, are considered to have the same
+ # depth as direct dependencies.
+ if parent.depth is None:
+ virt_depth = None
+ else:
+ virt_depth = parent.depth + 1
+ chosen_atom_ids = frozenset(id(atom) for atom in mycheck[1])
+ selected_atoms = OrderedDict()
+ node_stack = [(parent, None, None)]
+ traversed_nodes = set()
+ while node_stack:
+ node, node_parent, parent_atom = node_stack.pop()
+ traversed_nodes.add(node)
+ if node is parent:
+ k = parent
+ else:
+ if node_parent is parent:
+ if priority is None:
+ node_priority = None
+ else:
+ node_priority = priority.copy()
+ else:
+ # virtuals only have runtime deps
+ node_priority = self._priority(runtime=True)
+
+ k = Dependency(atom=parent_atom,
+ blocker=parent_atom.blocker, child=node,
+ depth=virt_depth, parent=node_parent,
+ priority=node_priority, root=node.root)
+
+ child_atoms = []
+ selected_atoms[k] = child_atoms
+ for atom_node in atom_graph.child_nodes(node):
+ child_atom = atom_node[0]
+ if id(child_atom) not in chosen_atom_ids:
+ continue
+ child_atoms.append(child_atom)
+ for child_node in atom_graph.child_nodes(atom_node):
+ if child_node in traversed_nodes:
+ continue
+ if not portage.match_from_list(
+ child_atom, [child_node]):
+ # Typically this means that the atom
+ # specifies USE deps that are unsatisfied
+ # by the selected package. The caller will
+ # record this as an unsatisfied dependency
+ # when necessary.
+ continue
+ node_stack.append((child_node, node, child_atom))
+
+ return selected_atoms
+
+ def _expand_virt_from_graph(self, root, atom):
+ if not isinstance(atom, Atom):
+ atom = Atom(atom)
+ graphdb = self._dynamic_config.mydbapi[root]
+ match = graphdb.match_pkgs(atom)
+ if not match:
+ yield atom
+ return
+ pkg = match[-1]
+ if not pkg.cpv.startswith("virtual/"):
+ yield atom
+ return
+ try:
+ rdepend = self._select_atoms_from_graph(
+ pkg.root, pkg.metadata.get("RDEPEND", ""),
+ myuse=self._pkg_use_enabled(pkg),
+ parent=pkg, strict=False)
+ except InvalidDependString as e:
+ writemsg_level("!!! Invalid RDEPEND in " + \
+ "'%svar/db/pkg/%s/RDEPEND': %s\n" % \
+ (pkg.root, pkg.cpv, e),
+ noiselevel=-1, level=logging.ERROR)
+ yield atom
+ return
+
+ for atoms in rdepend.values():
+ for atom in atoms:
+ if hasattr(atom, "_orig_atom"):
+ # Ignore virtual atoms since we're only
+ # interested in expanding the real atoms.
+ continue
+ yield atom
+
+ def _get_dep_chain(self, start_node, target_atom=None,
+ unsatisfied_dependency=False):
+ """
+ Returns a list of (atom, node_type) pairs that represent a dep chain.
+ If target_atom is None, the first package shown is pkg's parent.
+ If target_atom is not None the first package shown is pkg.
+ If unsatisfied_dependency is True, the first parent is select who's
+ dependency is not satisfied by 'pkg'. This is need for USE changes.
+ (Does not support target_atom.)
+ """
+ traversed_nodes = set()
+ dep_chain = []
+ node = start_node
+ child = None
+ all_parents = self._dynamic_config._parent_atoms
+
+ if target_atom is not None and isinstance(node, Package):
+ affecting_use = set()
+ for dep_str in "DEPEND", "RDEPEND", "PDEPEND":
+ try:
+ affecting_use.update(extract_affecting_use(
+ node.metadata[dep_str], target_atom,
+ eapi=node.metadata["EAPI"]))
+ except InvalidDependString:
+ if not node.installed:
+ raise
+ affecting_use.difference_update(node.use.mask, node.use.force)
+ pkg_name = _unicode_decode("%s") % (node.cpv,)
+ if affecting_use:
+ usedep = []
+ for flag in affecting_use:
+ if flag in self._pkg_use_enabled(node):
+ usedep.append(flag)
+ else:
+ usedep.append("-"+flag)
+ pkg_name += "[%s]" % ",".join(usedep)
+
+ dep_chain.append((pkg_name, node.type_name))
+
+ while node is not None:
+ traversed_nodes.add(node)
+
+ if isinstance(node, DependencyArg):
+ if self._dynamic_config.digraph.parent_nodes(node):
+ node_type = "set"
+ else:
+ node_type = "argument"
+ dep_chain.append((_unicode_decode("%s") % (node,), node_type))
+
+ elif node is not start_node:
+ for ppkg, patom in all_parents[child]:
+ if ppkg == node:
+ atom = patom.unevaluated_atom
+ break
+
+ dep_strings = set()
+ for priority in self._dynamic_config.digraph.nodes[node][0][child]:
+ if priority.buildtime:
+ dep_strings.add(node.metadata["DEPEND"])
+ if priority.runtime:
+ dep_strings.add(node.metadata["RDEPEND"])
+ if priority.runtime_post:
+ dep_strings.add(node.metadata["PDEPEND"])
+
+ affecting_use = set()
+ for dep_str in dep_strings:
+ try:
+ affecting_use.update(extract_affecting_use(
+ dep_str, atom, eapi=node.metadata["EAPI"]))
+ except InvalidDependString:
+ if not node.installed:
+ raise
+
+ #Don't show flags as 'affecting' if the user can't change them,
+ affecting_use.difference_update(node.use.mask, \
+ node.use.force)
+
+ pkg_name = _unicode_decode("%s") % (node.cpv,)
+ if affecting_use:
+ usedep = []
+ for flag in affecting_use:
+ if flag in self._pkg_use_enabled(node):
+ usedep.append(flag)
+ else:
+ usedep.append("-"+flag)
+ pkg_name += "[%s]" % ",".join(usedep)
+
+ dep_chain.append((pkg_name, node.type_name))
+
+ if node not in self._dynamic_config.digraph:
+ # The parent is not in the graph due to backtracking.
+ break
+
+ # When traversing to parents, prefer arguments over packages
+ # since arguments are root nodes. Never traverse the same
+ # package twice, in order to prevent an infinite loop.
+ child = node
+ selected_parent = None
+ parent_arg = None
+ parent_merge = None
+ parent_unsatisfied = None
+
+ for parent in self._dynamic_config.digraph.parent_nodes(node):
+ if parent in traversed_nodes:
+ continue
+ if isinstance(parent, DependencyArg):
+ parent_arg = parent
+ else:
+ if isinstance(parent, Package) and \
+ parent.operation == "merge":
+ parent_merge = parent
+ if unsatisfied_dependency and node is start_node:
+ # Make sure that pkg doesn't satisfy parent's dependency.
+ # This ensures that we select the correct parent for use
+ # flag changes.
+ for ppkg, atom in all_parents[start_node]:
+ if parent is ppkg:
+ atom_set = InternalPackageSet(initial_atoms=(atom,))
+ if not atom_set.findAtomForPackage(start_node):
+ parent_unsatisfied = parent
+ break
+ else:
+ selected_parent = parent
+
+ if parent_unsatisfied is not None:
+ selected_parent = parent_unsatisfied
+ elif parent_merge is not None:
+ # Prefer parent in the merge list (bug #354747).
+ selected_parent = parent_merge
+ elif parent_arg is not None:
+ if self._dynamic_config.digraph.parent_nodes(parent_arg):
+ selected_parent = parent_arg
+ else:
+ dep_chain.append(
+ (_unicode_decode("%s") % (parent_arg,), "argument"))
+ selected_parent = None
+
+ node = selected_parent
+ return dep_chain
+
+ def _get_dep_chain_as_comment(self, pkg, unsatisfied_dependency=False):
+ dep_chain = self._get_dep_chain(pkg, unsatisfied_dependency=unsatisfied_dependency)
+ display_list = []
+ for node, node_type in dep_chain:
+ if node_type == "argument":
+ display_list.append("required by %s (argument)" % node)
+ else:
+ display_list.append("required by %s" % node)
+
+ msg = "#" + ", ".join(display_list) + "\n"
+ return msg
+
+
+ def _show_unsatisfied_dep(self, root, atom, myparent=None, arg=None,
+ check_backtrack=False, check_autounmask_breakage=False):
+ """
+ When check_backtrack=True, no output is produced and
+ the method either returns or raises _backtrack_mask if
+ a matching package has been masked by backtracking.
+ """
+ backtrack_mask = False
+ autounmask_broke_use_dep = False
+ atom_set = InternalPackageSet(initial_atoms=(atom.without_use,),
+ allow_repo=True)
+ atom_set_with_use = InternalPackageSet(initial_atoms=(atom,),
+ allow_repo=True)
+ xinfo = '"%s"' % atom.unevaluated_atom
+ if arg:
+ xinfo='"%s"' % arg
+ if isinstance(myparent, AtomArg):
+ xinfo = _unicode_decode('"%s"') % (myparent,)
+ # Discard null/ from failed cpv_expand category expansion.
+ xinfo = xinfo.replace("null/", "")
+ if root != "/":
+ xinfo = "%s for %s" % (xinfo, root)
+ masked_packages = []
+ missing_use = []
+ missing_use_adjustable = set()
+ required_use_unsatisfied = []
+ masked_pkg_instances = set()
+ missing_licenses = []
+ have_eapi_mask = False
+ pkgsettings = self._frozen_config.pkgsettings[root]
+ root_config = self._frozen_config.roots[root]
+ portdb = self._frozen_config.roots[root].trees["porttree"].dbapi
+ vardb = self._frozen_config.roots[root].trees["vartree"].dbapi
+ bindb = self._frozen_config.roots[root].trees["bintree"].dbapi
+ dbs = self._dynamic_config._filtered_trees[root]["dbs"]
+ for db, pkg_type, built, installed, db_keys in dbs:
+ if installed:
+ continue
+ match = db.match
+ if hasattr(db, "xmatch"):
+ cpv_list = db.xmatch("match-all-cpv-only", atom.without_use)
+ else:
+ cpv_list = db.match(atom.without_use)
+
+ if atom.repo is None and hasattr(db, "getRepositories"):
+ repo_list = db.getRepositories()
+ else:
+ repo_list = [atom.repo]
+
+ # descending order
+ cpv_list.reverse()
+ for cpv in cpv_list:
+ for repo in repo_list:
+ if not db.cpv_exists(cpv, myrepo=repo):
+ continue
+
+ metadata, mreasons = get_mask_info(root_config, cpv, pkgsettings, db, pkg_type, \
+ built, installed, db_keys, myrepo=repo, _pkg_use_enabled=self._pkg_use_enabled)
+ if metadata is not None and \
+ portage.eapi_is_supported(metadata["EAPI"]):
+ if not repo:
+ repo = metadata.get('repository')
+ pkg = self._pkg(cpv, pkg_type, root_config,
+ installed=installed, myrepo=repo)
+ if not atom_set.findAtomForPackage(pkg,
+ modified_use=self._pkg_use_enabled(pkg)):
+ continue
+ # pkg.metadata contains calculated USE for ebuilds,
+ # required later for getMissingLicenses.
+ metadata = pkg.metadata
+ if pkg in self._dynamic_config._runtime_pkg_mask:
+ backtrack_reasons = \
+ self._dynamic_config._runtime_pkg_mask[pkg]
+ mreasons.append('backtracking: %s' % \
+ ', '.join(sorted(backtrack_reasons)))
+ backtrack_mask = True
+ if not mreasons and self._frozen_config.excluded_pkgs.findAtomForPackage(pkg, \
+ modified_use=self._pkg_use_enabled(pkg)):
+ mreasons = ["exclude option"]
+ if mreasons:
+ masked_pkg_instances.add(pkg)
+ if atom.unevaluated_atom.use:
+ try:
+ if not pkg.iuse.is_valid_flag(atom.unevaluated_atom.use.required) \
+ or atom.violated_conditionals(self._pkg_use_enabled(pkg), pkg.iuse.is_valid_flag).use:
+ missing_use.append(pkg)
+ if atom_set_with_use.findAtomForPackage(pkg):
+ autounmask_broke_use_dep = True
+ if not mreasons:
+ continue
+ except InvalidAtom:
+ writemsg("violated_conditionals raised " + \
+ "InvalidAtom: '%s' parent: %s" % \
+ (atom, myparent), noiselevel=-1)
+ raise
+ if not mreasons and \
+ not pkg.built and \
+ pkg.metadata["REQUIRED_USE"] and \
+ eapi_has_required_use(pkg.metadata["EAPI"]):
+ if not check_required_use(
+ pkg.metadata["REQUIRED_USE"],
+ self._pkg_use_enabled(pkg),
+ pkg.iuse.is_valid_flag):
+ required_use_unsatisfied.append(pkg)
+ continue
+ root_slot = (pkg.root, pkg.slot_atom)
+ if pkg.built and root_slot in self._rebuild.rebuild_list:
+ mreasons = ["need to rebuild from source"]
+ elif pkg.installed and root_slot in self._rebuild.reinstall_list:
+ mreasons = ["need to rebuild from source"]
+ elif pkg.built and not mreasons:
+ mreasons = ["use flag configuration mismatch"]
+ masked_packages.append(
+ (root_config, pkgsettings, cpv, repo, metadata, mreasons))
+
+ if check_backtrack:
+ if backtrack_mask:
+ raise self._backtrack_mask()
+ else:
+ return
+
+ if check_autounmask_breakage:
+ if autounmask_broke_use_dep:
+ raise self._autounmask_breakage()
+ else:
+ return
+
+ missing_use_reasons = []
+ missing_iuse_reasons = []
+ for pkg in missing_use:
+ use = self._pkg_use_enabled(pkg)
+ missing_iuse = []
+ #Use the unevaluated atom here, because some flags might have gone
+ #lost during evaluation.
+ required_flags = atom.unevaluated_atom.use.required
+ missing_iuse = pkg.iuse.get_missing_iuse(required_flags)
+
+ mreasons = []
+ if missing_iuse:
+ mreasons.append("Missing IUSE: %s" % " ".join(missing_iuse))
+ missing_iuse_reasons.append((pkg, mreasons))
+ else:
+ need_enable = sorted(atom.use.enabled.difference(use).intersection(pkg.iuse.all))
+ need_disable = sorted(atom.use.disabled.intersection(use).intersection(pkg.iuse.all))
+
+ untouchable_flags = \
+ frozenset(chain(pkg.use.mask, pkg.use.force))
+ if untouchable_flags.intersection(
+ chain(need_enable, need_disable)):
+ continue
+
+ missing_use_adjustable.add(pkg)
+ required_use = pkg.metadata["REQUIRED_USE"]
+ required_use_warning = ""
+ if required_use:
+ old_use = self._pkg_use_enabled(pkg)
+ new_use = set(self._pkg_use_enabled(pkg))
+ for flag in need_enable:
+ new_use.add(flag)
+ for flag in need_disable:
+ new_use.discard(flag)
+ if check_required_use(required_use, old_use, pkg.iuse.is_valid_flag) and \
+ not check_required_use(required_use, new_use, pkg.iuse.is_valid_flag):
+ required_use_warning = ", this change violates use flag constraints " + \
+ "defined by %s: '%s'" % (pkg.cpv, human_readable_required_use(required_use))
+
+ if need_enable or need_disable:
+ changes = []
+ changes.extend(colorize("red", "+" + x) \
+ for x in need_enable)
+ changes.extend(colorize("blue", "-" + x) \
+ for x in need_disable)
+ mreasons.append("Change USE: %s" % " ".join(changes) + required_use_warning)
+ missing_use_reasons.append((pkg, mreasons))
+
+ if not missing_iuse and myparent and atom.unevaluated_atom.use.conditional:
+ # Lets see if the violated use deps are conditional.
+ # If so, suggest to change them on the parent.
+
+ # If the child package is masked then a change to
+ # parent USE is not a valid solution (a normal mask
+ # message should be displayed instead).
+ if pkg in masked_pkg_instances:
+ continue
+
+ mreasons = []
+ violated_atom = atom.unevaluated_atom.violated_conditionals(self._pkg_use_enabled(pkg), \
+ pkg.iuse.is_valid_flag, self._pkg_use_enabled(myparent))
+ if not (violated_atom.use.enabled or violated_atom.use.disabled):
+ #all violated use deps are conditional
+ changes = []
+ conditional = violated_atom.use.conditional
+ involved_flags = set(chain(conditional.equal, conditional.not_equal, \
+ conditional.enabled, conditional.disabled))
+
+ untouchable_flags = \
+ frozenset(chain(myparent.use.mask, myparent.use.force))
+ if untouchable_flags.intersection(involved_flags):
+ continue
+
+ required_use = myparent.metadata["REQUIRED_USE"]
+ required_use_warning = ""
+ if required_use:
+ old_use = self._pkg_use_enabled(myparent)
+ new_use = set(self._pkg_use_enabled(myparent))
+ for flag in involved_flags:
+ if flag in old_use:
+ new_use.discard(flag)
+ else:
+ new_use.add(flag)
+ if check_required_use(required_use, old_use, myparent.iuse.is_valid_flag) and \
+ not check_required_use(required_use, new_use, myparent.iuse.is_valid_flag):
+ required_use_warning = ", this change violates use flag constraints " + \
+ "defined by %s: '%s'" % (myparent.cpv, \
+ human_readable_required_use(required_use))
+
+ for flag in involved_flags:
+ if flag in self._pkg_use_enabled(myparent):
+ changes.append(colorize("blue", "-" + flag))
+ else:
+ changes.append(colorize("red", "+" + flag))
+ mreasons.append("Change USE: %s" % " ".join(changes) + required_use_warning)
+ if (myparent, mreasons) not in missing_use_reasons:
+ missing_use_reasons.append((myparent, mreasons))
+
+ unmasked_use_reasons = [(pkg, mreasons) for (pkg, mreasons) \
+ in missing_use_reasons if pkg not in masked_pkg_instances]
+
+ unmasked_iuse_reasons = [(pkg, mreasons) for (pkg, mreasons) \
+ in missing_iuse_reasons if pkg not in masked_pkg_instances]
+
+ show_missing_use = False
+ if unmasked_use_reasons:
+ # Only show the latest version.
+ show_missing_use = []
+ pkg_reason = None
+ parent_reason = None
+ for pkg, mreasons in unmasked_use_reasons:
+ if pkg is myparent:
+ if parent_reason is None:
+ #This happens if a use change on the parent
+ #leads to a satisfied conditional use dep.
+ parent_reason = (pkg, mreasons)
+ elif pkg_reason is None:
+ #Don't rely on the first pkg in unmasked_use_reasons,
+ #being the highest version of the dependency.
+ pkg_reason = (pkg, mreasons)
+ if pkg_reason:
+ show_missing_use.append(pkg_reason)
+ if parent_reason:
+ show_missing_use.append(parent_reason)
+
+ elif unmasked_iuse_reasons:
+ masked_with_iuse = False
+ for pkg in masked_pkg_instances:
+ #Use atom.unevaluated here, because some flags might have gone
+ #lost during evaluation.
+ if not pkg.iuse.get_missing_iuse(atom.unevaluated_atom.use.required):
+ # Package(s) with required IUSE are masked,
+ # so display a normal masking message.
+ masked_with_iuse = True
+ break
+ if not masked_with_iuse:
+ show_missing_use = unmasked_iuse_reasons
+
+ if required_use_unsatisfied:
+ # If there's a higher unmasked version in missing_use_adjustable
+ # then we want to show that instead.
+ for pkg in missing_use_adjustable:
+ if pkg not in masked_pkg_instances and \
+ pkg > required_use_unsatisfied[0]:
+ required_use_unsatisfied = False
+ break
+
+ mask_docs = False
+
+ if required_use_unsatisfied:
+ # We have an unmasked package that only requires USE adjustment
+ # in order to satisfy REQUIRED_USE, and nothing more. We assume
+ # that the user wants the latest version, so only the first
+ # instance is displayed.
+ pkg = required_use_unsatisfied[0]
+ output_cpv = pkg.cpv + _repo_separator + pkg.repo
+ writemsg_stdout("\n!!! " + \
+ colorize("BAD", "The ebuild selected to satisfy ") + \
+ colorize("INFORM", xinfo) + \
+ colorize("BAD", " has unmet requirements.") + "\n",
+ noiselevel=-1)
+ use_display = pkg_use_display(pkg, self._frozen_config.myopts)
+ writemsg_stdout("- %s %s\n" % (output_cpv, use_display),
+ noiselevel=-1)
+ writemsg_stdout("\n The following REQUIRED_USE flag constraints " + \
+ "are unsatisfied:\n", noiselevel=-1)
+ reduced_noise = check_required_use(
+ pkg.metadata["REQUIRED_USE"],
+ self._pkg_use_enabled(pkg),
+ pkg.iuse.is_valid_flag).tounicode()
+ writemsg_stdout(" %s\n" % \
+ human_readable_required_use(reduced_noise),
+ noiselevel=-1)
+ normalized_required_use = \
+ " ".join(pkg.metadata["REQUIRED_USE"].split())
+ if reduced_noise != normalized_required_use:
+ writemsg_stdout("\n The above constraints " + \
+ "are a subset of the following complete expression:\n",
+ noiselevel=-1)
+ writemsg_stdout(" %s\n" % \
+ human_readable_required_use(normalized_required_use),
+ noiselevel=-1)
+ writemsg_stdout("\n", noiselevel=-1)
+
+ elif show_missing_use:
+ writemsg_stdout("\nemerge: there are no ebuilds built with USE flags to satisfy "+green(xinfo)+".\n", noiselevel=-1)
+ writemsg_stdout("!!! One of the following packages is required to complete your request:\n", noiselevel=-1)
+ for pkg, mreasons in show_missing_use:
+ writemsg_stdout("- "+pkg.cpv+_repo_separator+pkg.repo+" ("+", ".join(mreasons)+")\n", noiselevel=-1)
+
+ elif masked_packages:
+ writemsg_stdout("\n!!! " + \
+ colorize("BAD", "All ebuilds that could satisfy ") + \
+ colorize("INFORM", xinfo) + \
+ colorize("BAD", " have been masked.") + "\n", noiselevel=-1)
+ writemsg_stdout("!!! One of the following masked packages is required to complete your request:\n", noiselevel=-1)
+ have_eapi_mask = show_masked_packages(masked_packages)
+ if have_eapi_mask:
+ writemsg_stdout("\n", noiselevel=-1)
+ msg = ("The current version of portage supports " + \
+ "EAPI '%s'. You must upgrade to a newer version" + \
+ " of portage before EAPI masked packages can" + \
+ " be installed.") % portage.const.EAPI
+ writemsg_stdout("\n".join(textwrap.wrap(msg, 75)), noiselevel=-1)
+ writemsg_stdout("\n", noiselevel=-1)
+ mask_docs = True
+ else:
+ cp_exists = False
+ if not atom.cp.startswith("null/"):
+ for pkg in self._iter_match_pkgs_any(
+ root_config, Atom(atom.cp)):
+ cp_exists = True
+ break
+
+ writemsg_stdout("\nemerge: there are no ebuilds to satisfy "+green(xinfo)+".\n", noiselevel=-1)
+ if isinstance(myparent, AtomArg) and \
+ not cp_exists and \
+ self._frozen_config.myopts.get(
+ "--misspell-suggestions", "y") != "n":
+ cp = myparent.atom.cp.lower()
+ cat, pkg = portage.catsplit(cp)
+ if cat == "null":
+ cat = None
+
+ writemsg_stdout("\nemerge: searching for similar names..."
+ , noiselevel=-1)
+
+ all_cp = set()
+ all_cp.update(vardb.cp_all())
+ all_cp.update(portdb.cp_all())
+ if "--usepkg" in self._frozen_config.myopts:
+ all_cp.update(bindb.cp_all())
+ # discard dir containing no ebuilds
+ all_cp.discard(cp)
+
+ orig_cp_map = {}
+ for cp_orig in all_cp:
+ orig_cp_map.setdefault(cp_orig.lower(), []).append(cp_orig)
+ all_cp = set(orig_cp_map)
+
+ if cat:
+ matches = difflib.get_close_matches(cp, all_cp)
+ else:
+ pkg_to_cp = {}
+ for other_cp in list(all_cp):
+ other_pkg = portage.catsplit(other_cp)[1]
+ if other_pkg == pkg:
+ # discard dir containing no ebuilds
+ all_cp.discard(other_cp)
+ continue
+ pkg_to_cp.setdefault(other_pkg, set()).add(other_cp)
+ pkg_matches = difflib.get_close_matches(pkg, pkg_to_cp)
+ matches = []
+ for pkg_match in pkg_matches:
+ matches.extend(pkg_to_cp[pkg_match])
+
+ matches_orig_case = []
+ for cp in matches:
+ matches_orig_case.extend(orig_cp_map[cp])
+ matches = matches_orig_case
+
+ if len(matches) == 1:
+ writemsg_stdout("\nemerge: Maybe you meant " + matches[0] + "?\n"
+ , noiselevel=-1)
+ elif len(matches) > 1:
+ writemsg_stdout(
+ "\nemerge: Maybe you meant any of these: %s?\n" % \
+ (", ".join(matches),), noiselevel=-1)
+ else:
+ # Generally, this would only happen if
+ # all dbapis are empty.
+ writemsg_stdout(" nothing similar found.\n"
+ , noiselevel=-1)
+ msg = []
+ if not isinstance(myparent, AtomArg):
+ # It's redundant to show parent for AtomArg since
+ # it's the same as 'xinfo' displayed above.
+ dep_chain = self._get_dep_chain(myparent, atom)
+ for node, node_type in dep_chain:
+ msg.append('(dependency required by "%s" [%s])' % \
+ (colorize('INFORM', _unicode_decode("%s") % \
+ (node)), node_type))
+
+ if msg:
+ writemsg_stdout("\n".join(msg), noiselevel=-1)
+ writemsg_stdout("\n", noiselevel=-1)
+
+ if mask_docs:
+ show_mask_docs()
+ writemsg_stdout("\n", noiselevel=-1)
+
+ def _iter_match_pkgs_any(self, root_config, atom, onlydeps=False):
+ for db, pkg_type, built, installed, db_keys in \
+ self._dynamic_config._filtered_trees[root_config.root]["dbs"]:
+ for pkg in self._iter_match_pkgs(root_config,
+ pkg_type, atom, onlydeps=onlydeps):
+ yield pkg
+
+ def _iter_match_pkgs(self, root_config, pkg_type, atom, onlydeps=False):
+ """
+ Iterate over Package instances of pkg_type matching the given atom.
+ This does not check visibility and it also does not match USE for
+ unbuilt ebuilds since USE are lazily calculated after visibility
+ checks (to avoid the expense when possible).
+ """
+
+ db = root_config.trees[self.pkg_tree_map[pkg_type]].dbapi
+
+ if hasattr(db, "xmatch"):
+ # For portdbapi we match only against the cpv, in order
+ # to bypass unnecessary cache access for things like IUSE
+ # and SLOT. Later, we cache the metadata in a Package
+ # instance, and use that for further matching. This
+ # optimization is especially relevant since
+ # pordbapi.aux_get() does not cache calls that have
+ # myrepo or mytree arguments.
+ cpv_list = db.xmatch("match-all-cpv-only", atom)
+ else:
+ cpv_list = db.match(atom)
+
+ # USE=multislot can make an installed package appear as if
+ # it doesn't satisfy a slot dependency. Rebuilding the ebuild
+ # won't do any good as long as USE=multislot is enabled since
+ # the newly built package still won't have the expected slot.
+ # Therefore, assume that such SLOT dependencies are already
+ # satisfied rather than forcing a rebuild.
+ installed = pkg_type == 'installed'
+ if installed and not cpv_list and atom.slot:
+ for cpv in db.match(atom.cp):
+ slot_available = False
+ for other_db, other_type, other_built, \
+ other_installed, other_keys in \
+ self._dynamic_config._filtered_trees[root_config.root]["dbs"]:
+ try:
+ if atom.slot == \
+ other_db.aux_get(cpv, ["SLOT"])[0]:
+ slot_available = True
+ break
+ except KeyError:
+ pass
+ if not slot_available:
+ continue
+ inst_pkg = self._pkg(cpv, "installed",
+ root_config, installed=installed, myrepo = atom.repo)
+ # Remove the slot from the atom and verify that
+ # the package matches the resulting atom.
+ if portage.match_from_list(
+ atom.without_slot, [inst_pkg]):
+ yield inst_pkg
+ return
+
+ if cpv_list:
+ atom_set = InternalPackageSet(initial_atoms=(atom,),
+ allow_repo=True)
+ if atom.repo is None and hasattr(db, "getRepositories"):
+ repo_list = db.getRepositories()
+ else:
+ repo_list = [atom.repo]
+
+ # descending order
+ cpv_list.reverse()
+ for cpv in cpv_list:
+ for repo in repo_list:
+
+ try:
+ pkg = self._pkg(cpv, pkg_type, root_config,
+ installed=installed, onlydeps=onlydeps, myrepo=repo)
+ except portage.exception.PackageNotFound:
+ pass
+ else:
+ # A cpv can be returned from dbapi.match() as an
+ # old-style virtual match even in cases when the
+ # package does not actually PROVIDE the virtual.
+ # Filter out any such false matches here.
+
+ # Make sure that cpv from the current repo satisfies the atom.
+ # This might not be the case if there are several repos with
+ # the same cpv, but different metadata keys, like SLOT.
+ # Also, for portdbapi, parts of the match that require
+ # metadata access are deferred until we have cached the
+ # metadata in a Package instance.
+ if not atom_set.findAtomForPackage(pkg,
+ modified_use=self._pkg_use_enabled(pkg)):
+ continue
+ yield pkg
+
+ def _select_pkg_highest_available(self, root, atom, onlydeps=False):
+ cache_key = (root, atom, onlydeps)
+ ret = self._dynamic_config._highest_pkg_cache.get(cache_key)
+ if ret is not None:
+ pkg, existing = ret
+ if pkg and not existing:
+ existing = self._dynamic_config._slot_pkg_map[root].get(pkg.slot_atom)
+ if existing and existing == pkg:
+ # Update the cache to reflect that the
+ # package has been added to the graph.
+ ret = pkg, pkg
+ self._dynamic_config._highest_pkg_cache[cache_key] = ret
+ return ret
+ ret = self._select_pkg_highest_available_imp(root, atom, onlydeps=onlydeps)
+ self._dynamic_config._highest_pkg_cache[cache_key] = ret
+ pkg, existing = ret
+ if pkg is not None:
+ settings = pkg.root_config.settings
+ if self._pkg_visibility_check(pkg) and \
+ not (pkg.installed and pkg.masks):
+ self._dynamic_config._visible_pkgs[pkg.root].cpv_inject(pkg)
+ return ret
+
+ def _want_installed_pkg(self, pkg):
+ """
+ Given an installed package returned from select_pkg, return
+ True if the user has not explicitly requested for this package
+ to be replaced (typically via an atom on the command line).
+ """
+ if "selective" not in self._dynamic_config.myparams and \
+ pkg.root == self._frozen_config.target_root:
+ if self._frozen_config.excluded_pkgs.findAtomForPackage(pkg,
+ modified_use=self._pkg_use_enabled(pkg)):
+ return True
+ try:
+ next(self._iter_atoms_for_pkg(pkg))
+ except StopIteration:
+ pass
+ except portage.exception.InvalidDependString:
+ pass
+ else:
+ return False
+ return True
+
+ def _select_pkg_highest_available_imp(self, root, atom, onlydeps=False):
+ pkg, existing = self._wrapped_select_pkg_highest_available_imp(root, atom, onlydeps=onlydeps)
+
+ default_selection = (pkg, existing)
+
+ if self._dynamic_config._autounmask is True:
+ if pkg is not None and \
+ pkg.installed and \
+ not self._want_installed_pkg(pkg):
+ pkg = None
+
+ for only_use_changes in True, False:
+ if pkg is not None:
+ break
+
+ for allow_unmasks in (False, True):
+ if only_use_changes and allow_unmasks:
+ continue
+
+ if pkg is not None:
+ break
+
+ pkg, existing = \
+ self._wrapped_select_pkg_highest_available_imp(
+ root, atom, onlydeps=onlydeps,
+ allow_use_changes=True,
+ allow_unstable_keywords=(not only_use_changes),
+ allow_license_changes=(not only_use_changes),
+ allow_unmasks=allow_unmasks)
+
+ if pkg is not None and \
+ pkg.installed and \
+ not self._want_installed_pkg(pkg):
+ pkg = None
+
+ if self._dynamic_config._need_restart:
+ return None, None
+
+ if pkg is None:
+ # This ensures that we can fall back to an installed package
+ # that may have been rejected in the autounmask path above.
+ return default_selection
+
+ return pkg, existing
+
+ def _pkg_visibility_check(self, pkg, allow_unstable_keywords=False, allow_license_changes=False, allow_unmasks=False):
+
+ if pkg.visible:
+ return True
+
+ if pkg in self._dynamic_config.digraph:
+ # Sometimes we need to temporarily disable
+ # dynamic_config._autounmask, but for overall
+ # consistency in dependency resolution, in any
+ # case we want to respect autounmask visibity
+ # for packages that have already been added to
+ # the dependency graph.
+ return True
+
+ if not self._dynamic_config._autounmask:
+ return False
+
+ pkgsettings = self._frozen_config.pkgsettings[pkg.root]
+ root_config = self._frozen_config.roots[pkg.root]
+ mreasons = _get_masking_status(pkg, pkgsettings, root_config, use=self._pkg_use_enabled(pkg))
+
+ masked_by_unstable_keywords = False
+ masked_by_missing_keywords = False
+ missing_licenses = None
+ masked_by_something_else = False
+ masked_by_p_mask = False
+
+ for reason in mreasons:
+ hint = reason.unmask_hint
+
+ if hint is None:
+ masked_by_something_else = True
+ elif hint.key == "unstable keyword":
+ masked_by_unstable_keywords = True
+ if hint.value == "**":
+ masked_by_missing_keywords = True
+ elif hint.key == "p_mask":
+ masked_by_p_mask = True
+ elif hint.key == "license":
+ missing_licenses = hint.value
+ else:
+ masked_by_something_else = True
+
+ if masked_by_something_else:
+ return False
+
+ if pkg in self._dynamic_config._needed_unstable_keywords:
+ #If the package is already keyworded, remove the mask.
+ masked_by_unstable_keywords = False
+ masked_by_missing_keywords = False
+
+ if pkg in self._dynamic_config._needed_p_mask_changes:
+ #If the package is already keyworded, remove the mask.
+ masked_by_p_mask = False
+
+ if missing_licenses:
+ #If the needed licenses are already unmasked, remove the mask.
+ missing_licenses.difference_update(self._dynamic_config._needed_license_changes.get(pkg, set()))
+
+ if not (masked_by_unstable_keywords or masked_by_p_mask or missing_licenses):
+ #Package has already been unmasked.
+ return True
+
+ #We treat missing keywords in the same way as masks.
+ if (masked_by_unstable_keywords and not allow_unstable_keywords) or \
+ (masked_by_missing_keywords and not allow_unmasks) or \
+ (masked_by_p_mask and not allow_unmasks) or \
+ (missing_licenses and not allow_license_changes):
+ #We are not allowed to do the needed changes.
+ return False
+
+ if masked_by_unstable_keywords:
+ self._dynamic_config._needed_unstable_keywords.add(pkg)
+ backtrack_infos = self._dynamic_config._backtrack_infos
+ backtrack_infos.setdefault("config", {})
+ backtrack_infos["config"].setdefault("needed_unstable_keywords", set())
+ backtrack_infos["config"]["needed_unstable_keywords"].add(pkg)
+
+ if masked_by_p_mask:
+ self._dynamic_config._needed_p_mask_changes.add(pkg)
+ backtrack_infos = self._dynamic_config._backtrack_infos
+ backtrack_infos.setdefault("config", {})
+ backtrack_infos["config"].setdefault("needed_p_mask_changes", set())
+ backtrack_infos["config"]["needed_p_mask_changes"].add(pkg)
+
+ if missing_licenses:
+ self._dynamic_config._needed_license_changes.setdefault(pkg, set()).update(missing_licenses)
+ backtrack_infos = self._dynamic_config._backtrack_infos
+ backtrack_infos.setdefault("config", {})
+ backtrack_infos["config"].setdefault("needed_license_changes", set())
+ backtrack_infos["config"]["needed_license_changes"].add((pkg, frozenset(missing_licenses)))
+
+ return True
+
+ def _pkg_use_enabled(self, pkg, target_use=None):
+ """
+ If target_use is None, returns pkg.use.enabled + changes in _needed_use_config_changes.
+ If target_use is given, the need changes are computed to make the package useable.
+ Example: target_use = { "foo": True, "bar": False }
+ The flags target_use must be in the pkg's IUSE.
+ """
+ if pkg.built:
+ return pkg.use.enabled
+ needed_use_config_change = self._dynamic_config._needed_use_config_changes.get(pkg)
+
+ if target_use is None:
+ if needed_use_config_change is None:
+ return pkg.use.enabled
+ else:
+ return needed_use_config_change[0]
+
+ if needed_use_config_change is not None:
+ old_use = needed_use_config_change[0]
+ new_use = set()
+ old_changes = needed_use_config_change[1]
+ new_changes = old_changes.copy()
+ else:
+ old_use = pkg.use.enabled
+ new_use = set()
+ old_changes = {}
+ new_changes = {}
+
+ for flag, state in target_use.items():
+ if state:
+ if flag not in old_use:
+ if new_changes.get(flag) == False:
+ return old_use
+ new_changes[flag] = True
+ new_use.add(flag)
+ else:
+ if flag in old_use:
+ if new_changes.get(flag) == True:
+ return old_use
+ new_changes[flag] = False
+ new_use.update(old_use.difference(target_use))
+
+ def want_restart_for_use_change(pkg, new_use):
+ if pkg not in self._dynamic_config.digraph.nodes:
+ return False
+
+ for key in "DEPEND", "RDEPEND", "PDEPEND", "LICENSE":
+ dep = pkg.metadata[key]
+ old_val = set(portage.dep.use_reduce(dep, pkg.use.enabled, is_valid_flag=pkg.iuse.is_valid_flag, flat=True))
+ new_val = set(portage.dep.use_reduce(dep, new_use, is_valid_flag=pkg.iuse.is_valid_flag, flat=True))
+
+ if old_val != new_val:
+ return True
+
+ parent_atoms = self._dynamic_config._parent_atoms.get(pkg)
+ if not parent_atoms:
+ return False
+
+ new_use, changes = self._dynamic_config._needed_use_config_changes.get(pkg)
+ for ppkg, atom in parent_atoms:
+ if not atom.use or \
+ not atom.use.required.intersection(changes):
+ continue
+ else:
+ return True
+
+ return False
+
+ if new_changes != old_changes:
+ #Don't do the change if it violates REQUIRED_USE.
+ required_use = pkg.metadata["REQUIRED_USE"]
+ if required_use and check_required_use(required_use, old_use, pkg.iuse.is_valid_flag) and \
+ not check_required_use(required_use, new_use, pkg.iuse.is_valid_flag):
+ return old_use
+
+ if pkg.use.mask.intersection(new_changes) or \
+ pkg.use.force.intersection(new_changes):
+ return old_use
+
+ self._dynamic_config._needed_use_config_changes[pkg] = (new_use, new_changes)
+ backtrack_infos = self._dynamic_config._backtrack_infos
+ backtrack_infos.setdefault("config", {})
+ backtrack_infos["config"].setdefault("needed_use_config_changes", [])
+ backtrack_infos["config"]["needed_use_config_changes"].append((pkg, (new_use, new_changes)))
+ if want_restart_for_use_change(pkg, new_use):
+ self._dynamic_config._need_restart = True
+ return new_use
+
+ def _wrapped_select_pkg_highest_available_imp(self, root, atom, onlydeps=False, \
+ allow_use_changes=False, allow_unstable_keywords=False, allow_license_changes=False, allow_unmasks=False):
+ root_config = self._frozen_config.roots[root]
+ pkgsettings = self._frozen_config.pkgsettings[root]
+ dbs = self._dynamic_config._filtered_trees[root]["dbs"]
+ vardb = self._frozen_config.roots[root].trees["vartree"].dbapi
+ portdb = self._frozen_config.roots[root].trees["porttree"].dbapi
+ # List of acceptable packages, ordered by type preference.
+ matched_packages = []
+ matched_pkgs_ignore_use = []
+ highest_version = None
+ if not isinstance(atom, portage.dep.Atom):
+ atom = portage.dep.Atom(atom)
+ atom_cp = atom.cp
+ atom_set = InternalPackageSet(initial_atoms=(atom,), allow_repo=True)
+ existing_node = None
+ myeb = None
+ rebuilt_binaries = 'rebuilt_binaries' in self._dynamic_config.myparams
+ usepkg = "--usepkg" in self._frozen_config.myopts
+ usepkgonly = "--usepkgonly" in self._frozen_config.myopts
+ empty = "empty" in self._dynamic_config.myparams
+ selective = "selective" in self._dynamic_config.myparams
+ reinstall = False
+ avoid_update = "--update" not in self._frozen_config.myopts
+ dont_miss_updates = "--update" in self._frozen_config.myopts
+ use_ebuild_visibility = self._frozen_config.myopts.get(
+ '--use-ebuild-visibility', 'n') != 'n'
+ reinstall_atoms = self._frozen_config.reinstall_atoms
+ usepkg_exclude = self._frozen_config.usepkg_exclude
+ useoldpkg_atoms = self._frozen_config.useoldpkg_atoms
+ matched_oldpkg = []
+ # Behavior of the "selective" parameter depends on
+ # whether or not a package matches an argument atom.
+ # If an installed package provides an old-style
+ # virtual that is no longer provided by an available
+ # package, the installed package may match an argument
+ # atom even though none of the available packages do.
+ # Therefore, "selective" logic does not consider
+ # whether or not an installed package matches an
+ # argument atom. It only considers whether or not
+ # available packages match argument atoms, which is
+ # represented by the found_available_arg flag.
+ found_available_arg = False
+ packages_with_invalid_use_config = []
+ for find_existing_node in True, False:
+ if existing_node:
+ break
+ for db, pkg_type, built, installed, db_keys in dbs:
+ if existing_node:
+ break
+ if installed and not find_existing_node:
+ want_reinstall = reinstall or empty or \
+ (found_available_arg and not selective)
+ if want_reinstall and matched_packages:
+ continue
+
+ # Ignore USE deps for the initial match since we want to
+ # ensure that updates aren't missed solely due to the user's
+ # USE configuration.
+ for pkg in self._iter_match_pkgs(root_config, pkg_type, atom.without_use,
+ onlydeps=onlydeps):
+ if pkg in self._dynamic_config._runtime_pkg_mask:
+ # The package has been masked by the backtracking logic
+ continue
+ root_slot = (pkg.root, pkg.slot_atom)
+ if pkg.built and root_slot in self._rebuild.rebuild_list:
+ continue
+ if (pkg.installed and
+ root_slot in self._rebuild.reinstall_list):
+ continue
+
+ if not pkg.installed and \
+ self._frozen_config.excluded_pkgs.findAtomForPackage(pkg, \
+ modified_use=self._pkg_use_enabled(pkg)):
+ continue
+
+ if built and not installed and usepkg_exclude.findAtomForPackage(pkg, \
+ modified_use=self._pkg_use_enabled(pkg)):
+ break
+
+ useoldpkg = useoldpkg_atoms.findAtomForPackage(pkg, \
+ modified_use=self._pkg_use_enabled(pkg))
+
+ if packages_with_invalid_use_config and (not built or not useoldpkg) and \
+ (not pkg.installed or dont_miss_updates):
+ # Check if a higher version was rejected due to user
+ # USE configuration. The packages_with_invalid_use_config
+ # list only contains unbuilt ebuilds since USE can't
+ # be changed for built packages.
+ higher_version_rejected = False
+ repo_priority = pkg.repo_priority
+ for rejected in packages_with_invalid_use_config:
+ if rejected.cp != pkg.cp:
+ continue
+ if rejected > pkg:
+ higher_version_rejected = True
+ break
+ if portage.dep.cpvequal(rejected.cpv, pkg.cpv):
+ # If version is identical then compare
+ # repo priority (see bug #350254).
+ rej_repo_priority = rejected.repo_priority
+ if rej_repo_priority is not None and \
+ (repo_priority is None or
+ rej_repo_priority > repo_priority):
+ higher_version_rejected = True
+ break
+ if higher_version_rejected:
+ continue
+
+ cpv = pkg.cpv
+ reinstall_for_flags = None
+
+ if not pkg.installed or \
+ (matched_packages and not avoid_update):
+ # Only enforce visibility on installed packages
+ # if there is at least one other visible package
+ # available. By filtering installed masked packages
+ # here, packages that have been masked since they
+ # were installed can be automatically downgraded
+ # to an unmasked version. NOTE: This code needs to
+ # be consistent with masking behavior inside
+ # _dep_check_composite_db, in order to prevent
+ # incorrect choices in || deps like bug #351828.
+
+ if not self._pkg_visibility_check(pkg, \
+ allow_unstable_keywords=allow_unstable_keywords,
+ allow_license_changes=allow_license_changes,
+ allow_unmasks=allow_unmasks):
+ continue
+
+ # Enable upgrade or downgrade to a version
+ # with visible KEYWORDS when the installed
+ # version is masked by KEYWORDS, but never
+ # reinstall the same exact version only due
+ # to a KEYWORDS mask. See bug #252167.
+
+ if pkg.type_name != "ebuild" and matched_packages:
+ # Don't re-install a binary package that is
+ # identical to the currently installed package
+ # (see bug #354441).
+ identical_binary = False
+ if usepkg and pkg.installed:
+ for selected_pkg in matched_packages:
+ if selected_pkg.type_name == "binary" and \
+ selected_pkg.cpv == pkg.cpv and \
+ selected_pkg.metadata.get('BUILD_TIME') == \
+ pkg.metadata.get('BUILD_TIME'):
+ identical_binary = True
+ break
+
+ if not identical_binary:
+ # If the ebuild no longer exists or it's
+ # keywords have been dropped, reject built
+ # instances (installed or binary).
+ # If --usepkgonly is enabled, assume that
+ # the ebuild status should be ignored.
+ if not use_ebuild_visibility and (usepkgonly or useoldpkg):
+ if pkg.installed and pkg.masks:
+ continue
+ else:
+ try:
+ pkg_eb = self._pkg(
+ pkg.cpv, "ebuild", root_config, myrepo=pkg.repo)
+ except portage.exception.PackageNotFound:
+ pkg_eb_visible = False
+ for pkg_eb in self._iter_match_pkgs(pkg.root_config,
+ "ebuild", Atom("=%s" % (pkg.cpv,))):
+ if self._pkg_visibility_check(pkg_eb, \
+ allow_unstable_keywords=allow_unstable_keywords,
+ allow_license_changes=allow_license_changes,
+ allow_unmasks=allow_unmasks):
+ pkg_eb_visible = True
+ break
+ if not pkg_eb_visible:
+ continue
+ else:
+ if not self._pkg_visibility_check(pkg_eb, \
+ allow_unstable_keywords=allow_unstable_keywords,
+ allow_license_changes=allow_license_changes,
+ allow_unmasks=allow_unmasks):
+ continue
+
+ # Calculation of USE for unbuilt ebuilds is relatively
+ # expensive, so it is only performed lazily, after the
+ # above visibility checks are complete.
+
+ myarg = None
+ if root == self._frozen_config.target_root:
+ try:
+ myarg = next(self._iter_atoms_for_pkg(pkg))
+ except StopIteration:
+ pass
+ except portage.exception.InvalidDependString:
+ if not installed:
+ # masked by corruption
+ continue
+ if not installed and myarg:
+ found_available_arg = True
+
+ if atom.unevaluated_atom.use:
+ #Make sure we don't miss a 'missing IUSE'.
+ if pkg.iuse.get_missing_iuse(atom.unevaluated_atom.use.required):
+ # Don't add this to packages_with_invalid_use_config
+ # since IUSE cannot be adjusted by the user.
+ continue
+
+ if atom.use:
+
+ matched_pkgs_ignore_use.append(pkg)
+ if allow_use_changes and not pkg.built:
+ target_use = {}
+ for flag in atom.use.enabled:
+ target_use[flag] = True
+ for flag in atom.use.disabled:
+ target_use[flag] = False
+ use = self._pkg_use_enabled(pkg, target_use)
+ else:
+ use = self._pkg_use_enabled(pkg)
+
+ use_match = True
+ can_adjust_use = not pkg.built
+ missing_enabled = atom.use.missing_enabled.difference(pkg.iuse.all)
+ missing_disabled = atom.use.missing_disabled.difference(pkg.iuse.all)
+
+ if atom.use.enabled:
+ if atom.use.enabled.intersection(missing_disabled):
+ use_match = False
+ can_adjust_use = False
+ need_enabled = atom.use.enabled.difference(use)
+ if need_enabled:
+ need_enabled = need_enabled.difference(missing_enabled)
+ if need_enabled:
+ use_match = False
+ if can_adjust_use:
+ if pkg.use.mask.intersection(need_enabled):
+ can_adjust_use = False
+
+ if atom.use.disabled:
+ if atom.use.disabled.intersection(missing_enabled):
+ use_match = False
+ can_adjust_use = False
+ need_disabled = atom.use.disabled.intersection(use)
+ if need_disabled:
+ need_disabled = need_disabled.difference(missing_disabled)
+ if need_disabled:
+ use_match = False
+ if can_adjust_use:
+ if pkg.use.force.difference(
+ pkg.use.mask).intersection(need_disabled):
+ can_adjust_use = False
+
+ if not use_match:
+ if can_adjust_use:
+ # Above we must ensure that this package has
+ # absolutely no use.force, use.mask, or IUSE
+ # issues that the user typically can't make
+ # adjustments to solve (see bug #345979).
+ # FIXME: Conditional USE deps complicate
+ # issues. This code currently excludes cases
+ # in which the user can adjust the parent
+ # package's USE in order to satisfy the dep.
+ packages_with_invalid_use_config.append(pkg)
+ continue
+
+ if pkg.cp == atom_cp:
+ if highest_version is None:
+ highest_version = pkg
+ elif pkg > highest_version:
+ highest_version = pkg
+ # At this point, we've found the highest visible
+ # match from the current repo. Any lower versions
+ # from this repo are ignored, so this so the loop
+ # will always end with a break statement below
+ # this point.
+ if find_existing_node:
+ e_pkg = self._dynamic_config._slot_pkg_map[root].get(pkg.slot_atom)
+ if not e_pkg:
+ break
+ # Use PackageSet.findAtomForPackage()
+ # for PROVIDE support.
+ if atom_set.findAtomForPackage(e_pkg, modified_use=self._pkg_use_enabled(e_pkg)):
+ if highest_version and \
+ e_pkg.cp == atom_cp and \
+ e_pkg < highest_version and \
+ e_pkg.slot_atom != highest_version.slot_atom:
+ # There is a higher version available in a
+ # different slot, so this existing node is
+ # irrelevant.
+ pass
+ else:
+ matched_packages.append(e_pkg)
+ existing_node = e_pkg
+ break
+ # Compare built package to current config and
+ # reject the built package if necessary.
+ if built and not useoldpkg and (not installed or matched_pkgs_ignore_use) and \
+ ("--newuse" in self._frozen_config.myopts or \
+ "--reinstall" in self._frozen_config.myopts or \
+ "--binpkg-respect-use" in self._frozen_config.myopts):
+ iuses = pkg.iuse.all
+ old_use = self._pkg_use_enabled(pkg)
+ if myeb:
+ pkgsettings.setcpv(myeb)
+ else:
+ pkgsettings.setcpv(pkg)
+ now_use = pkgsettings["PORTAGE_USE"].split()
+ forced_flags = set()
+ forced_flags.update(pkgsettings.useforce)
+ forced_flags.update(pkgsettings.usemask)
+ cur_iuse = iuses
+ if myeb and not usepkgonly and not useoldpkg:
+ cur_iuse = myeb.iuse.all
+ if self._reinstall_for_flags(forced_flags,
+ old_use, iuses,
+ now_use, cur_iuse):
+ break
+ # Compare current config to installed package
+ # and do not reinstall if possible.
+ if not installed and not useoldpkg and \
+ ("--newuse" in self._frozen_config.myopts or \
+ "--reinstall" in self._frozen_config.myopts) and \
+ cpv in vardb.match(atom):
+ forced_flags = set()
+ forced_flags.update(pkg.use.force)
+ forced_flags.update(pkg.use.mask)
+ inst_pkg = vardb.match_pkgs('=' + pkg.cpv)[0]
+ old_use = inst_pkg.use.enabled
+ old_iuse = inst_pkg.iuse.all
+ cur_use = self._pkg_use_enabled(pkg)
+ cur_iuse = pkg.iuse.all
+ reinstall_for_flags = \
+ self._reinstall_for_flags(
+ forced_flags, old_use, old_iuse,
+ cur_use, cur_iuse)
+ if reinstall_for_flags:
+ reinstall = True
+ if reinstall_atoms.findAtomForPackage(pkg, \
+ modified_use=self._pkg_use_enabled(pkg)):
+ reinstall = True
+ if not built:
+ myeb = pkg
+ elif useoldpkg:
+ matched_oldpkg.append(pkg)
+ matched_packages.append(pkg)
+ if reinstall_for_flags:
+ self._dynamic_config._reinstall_nodes[pkg] = \
+ reinstall_for_flags
+ break
+
+ if not matched_packages:
+ return None, None
+
+ if "--debug" in self._frozen_config.myopts:
+ for pkg in matched_packages:
+ portage.writemsg("%s %s%s%s\n" % \
+ ((pkg.type_name + ":").rjust(10),
+ pkg.cpv, _repo_separator, pkg.repo), noiselevel=-1)
+
+ # Filter out any old-style virtual matches if they are
+ # mixed with new-style virtual matches.
+ cp = atom.cp
+ if len(matched_packages) > 1 and \
+ "virtual" == portage.catsplit(cp)[0]:
+ for pkg in matched_packages:
+ if pkg.cp != cp:
+ continue
+ # Got a new-style virtual, so filter
+ # out any old-style virtuals.
+ matched_packages = [pkg for pkg in matched_packages \
+ if pkg.cp == cp]
+ break
+
+ if existing_node is not None and \
+ existing_node in matched_packages:
+ return existing_node, existing_node
+
+ if len(matched_packages) > 1:
+ if rebuilt_binaries:
+ inst_pkg = None
+ built_pkg = None
+ unbuilt_pkg = None
+ for pkg in matched_packages:
+ if pkg.installed:
+ inst_pkg = pkg
+ elif pkg.built:
+ built_pkg = pkg
+ else:
+ if unbuilt_pkg is None or pkg > unbuilt_pkg:
+ unbuilt_pkg = pkg
+ if built_pkg is not None and inst_pkg is not None:
+ # Only reinstall if binary package BUILD_TIME is
+ # non-empty, in order to avoid cases like to
+ # bug #306659 where BUILD_TIME fields are missing
+ # in local and/or remote Packages file.
+ try:
+ built_timestamp = int(built_pkg.metadata['BUILD_TIME'])
+ except (KeyError, ValueError):
+ built_timestamp = 0
+
+ try:
+ installed_timestamp = int(inst_pkg.metadata['BUILD_TIME'])
+ except (KeyError, ValueError):
+ installed_timestamp = 0
+
+ if unbuilt_pkg is not None and unbuilt_pkg > built_pkg:
+ pass
+ elif "--rebuilt-binaries-timestamp" in self._frozen_config.myopts:
+ minimal_timestamp = self._frozen_config.myopts["--rebuilt-binaries-timestamp"]
+ if built_timestamp and \
+ built_timestamp > installed_timestamp and \
+ built_timestamp >= minimal_timestamp:
+ return built_pkg, existing_node
+ else:
+ #Don't care if the binary has an older BUILD_TIME than the installed
+ #package. This is for closely tracking a binhost.
+ #Use --rebuilt-binaries-timestamp 0 if you want only newer binaries
+ #pulled in here.
+ if built_timestamp and \
+ built_timestamp != installed_timestamp:
+ return built_pkg, existing_node
+
+ for pkg in matched_packages:
+ if pkg.installed and pkg.invalid:
+ matched_packages = [x for x in \
+ matched_packages if x is not pkg]
+
+ if avoid_update:
+ for pkg in matched_packages:
+ if pkg.installed and self._pkg_visibility_check(pkg, \
+ allow_unstable_keywords=allow_unstable_keywords,
+ allow_license_changes=allow_license_changes,
+ allow_unmasks=allow_unmasks):
+ return pkg, existing_node
+
+ visible_matches = []
+ if matched_oldpkg:
+ visible_matches = [pkg.cpv for pkg in matched_oldpkg \
+ if self._pkg_visibility_check(pkg, allow_unstable_keywords=allow_unstable_keywords,
+ allow_license_changes=allow_license_changes, allow_unmasks=allow_unmasks)]
+ if not visible_matches:
+ visible_matches = [pkg.cpv for pkg in matched_packages \
+ if self._pkg_visibility_check(pkg, allow_unstable_keywords=allow_unstable_keywords,
+ allow_license_changes=allow_license_changes, allow_unmasks=allow_unmasks)]
+ if visible_matches:
+ bestmatch = portage.best(visible_matches)
+ else:
+ # all are masked, so ignore visibility
+ bestmatch = portage.best([pkg.cpv for pkg in matched_packages])
+ matched_packages = [pkg for pkg in matched_packages \
+ if portage.dep.cpvequal(pkg.cpv, bestmatch)]
+
+ # ordered by type preference ("ebuild" type is the last resort)
+ return matched_packages[-1], existing_node
+
+ def _select_pkg_from_graph(self, root, atom, onlydeps=False):
+ """
+ Select packages that have already been added to the graph or
+ those that are installed and have not been scheduled for
+ replacement.
+ """
+ graph_db = self._dynamic_config._graph_trees[root]["porttree"].dbapi
+ matches = graph_db.match_pkgs(atom)
+ if not matches:
+ return None, None
+ pkg = matches[-1] # highest match
+ in_graph = self._dynamic_config._slot_pkg_map[root].get(pkg.slot_atom)
+ return pkg, in_graph
+
+ def _select_pkg_from_installed(self, root, atom, onlydeps=False):
+ """
+ Select packages that are installed.
+ """
+ vardb = self._dynamic_config._graph_trees[root]["vartree"].dbapi
+ matches = vardb.match_pkgs(atom)
+ if not matches:
+ return None, None
+ if len(matches) > 1:
+ unmasked = [pkg for pkg in matches if \
+ self._pkg_visibility_check(pkg)]
+ if unmasked:
+ if len(unmasked) == 1:
+ matches = unmasked
+ else:
+ # Account for packages with masks (like KEYWORDS masks)
+ # that are usually ignored in visibility checks for
+ # installed packages, in order to handle cases like
+ # bug #350285.
+ unmasked = [pkg for pkg in matches if not pkg.masks]
+ if unmasked:
+ matches = unmasked
+ pkg = matches[-1] # highest match
+ in_graph = self._dynamic_config._slot_pkg_map[root].get(pkg.slot_atom)
+ return pkg, in_graph
+
+ def _complete_graph(self, required_sets=None):
+ """
+ Add any deep dependencies of required sets (args, system, world) that
+ have not been pulled into the graph yet. This ensures that the graph
+ is consistent such that initially satisfied deep dependencies are not
+ broken in the new graph. Initially unsatisfied dependencies are
+ irrelevant since we only want to avoid breaking dependencies that are
+ initially satisfied.
+
+ Since this method can consume enough time to disturb users, it is
+ currently only enabled by the --complete-graph option.
+
+ @param required_sets: contains required sets (currently only used
+ for depclean and prune removal operations)
+ @type required_sets: dict
+ """
+ if "--buildpkgonly" in self._frozen_config.myopts or \
+ "recurse" not in self._dynamic_config.myparams:
+ return 1
+
+ if "complete" not in self._dynamic_config.myparams:
+ # Automatically enable complete mode if there are any
+ # downgrades, since they often break dependencies
+ # (like in bug #353613).
+ have_downgrade = False
+ for node in self._dynamic_config.digraph:
+ if not isinstance(node, Package) or \
+ node.operation != "merge":
+ continue
+ vardb = self._frozen_config.roots[
+ node.root].trees["vartree"].dbapi
+ inst_pkg = vardb.match_pkgs(node.slot_atom)
+ if inst_pkg and inst_pkg[0] > node:
+ have_downgrade = True
+ break
+
+ if have_downgrade:
+ self._dynamic_config.myparams["complete"] = True
+ else:
+ # Skip complete graph mode, in order to avoid consuming
+ # enough time to disturb users.
+ return 1
+
+ self._load_vdb()
+
+ # Put the depgraph into a mode that causes it to only
+ # select packages that have already been added to the
+ # graph or those that are installed and have not been
+ # scheduled for replacement. Also, toggle the "deep"
+ # parameter so that all dependencies are traversed and
+ # accounted for.
+ self._select_atoms = self._select_atoms_from_graph
+ if "remove" in self._dynamic_config.myparams:
+ self._select_package = self._select_pkg_from_installed
+ else:
+ self._select_package = self._select_pkg_from_graph
+ self._dynamic_config._traverse_ignored_deps = True
+ already_deep = self._dynamic_config.myparams.get("deep") is True
+ if not already_deep:
+ self._dynamic_config.myparams["deep"] = True
+
+ # Invalidate the package selection cache, since
+ # _select_package has just changed implementations.
+ for trees in self._dynamic_config._filtered_trees.values():
+ trees["porttree"].dbapi._clear_cache()
+
+ args = self._dynamic_config._initial_arg_list[:]
+ for root in self._frozen_config.roots:
+ if root != self._frozen_config.target_root and \
+ "remove" in self._dynamic_config.myparams:
+ # Only pull in deps for the relevant root.
+ continue
+ depgraph_sets = self._dynamic_config.sets[root]
+ required_set_names = self._frozen_config._required_set_names.copy()
+ remaining_args = required_set_names.copy()
+ if required_sets is None or root not in required_sets:
+ pass
+ else:
+ # Removal actions may override sets with temporary
+ # replacements that have had atoms removed in order
+ # to implement --deselect behavior.
+ required_set_names = set(required_sets[root])
+ depgraph_sets.sets.clear()
+ depgraph_sets.sets.update(required_sets[root])
+ if "remove" not in self._dynamic_config.myparams and \
+ root == self._frozen_config.target_root and \
+ already_deep:
+ remaining_args.difference_update(depgraph_sets.sets)
+ if not remaining_args and \
+ not self._dynamic_config._ignored_deps and \
+ not self._dynamic_config._dep_stack:
+ continue
+ root_config = self._frozen_config.roots[root]
+ for s in required_set_names:
+ pset = depgraph_sets.sets.get(s)
+ if pset is None:
+ pset = root_config.sets[s]
+ atom = SETPREFIX + s
+ args.append(SetArg(arg=atom, pset=pset,
+ root_config=root_config))
+
+ self._set_args(args)
+ for arg in self._expand_set_args(args, add_to_digraph=True):
+ for atom in arg.pset.getAtoms():
+ self._dynamic_config._dep_stack.append(
+ Dependency(atom=atom, root=arg.root_config.root,
+ parent=arg))
+
+ if True:
+ if self._dynamic_config._ignored_deps:
+ self._dynamic_config._dep_stack.extend(self._dynamic_config._ignored_deps)
+ self._dynamic_config._ignored_deps = []
+ if not self._create_graph(allow_unsatisfied=True):
+ return 0
+ # Check the unsatisfied deps to see if any initially satisfied deps
+ # will become unsatisfied due to an upgrade. Initially unsatisfied
+ # deps are irrelevant since we only want to avoid breaking deps
+ # that are initially satisfied.
+ while self._dynamic_config._unsatisfied_deps:
+ dep = self._dynamic_config._unsatisfied_deps.pop()
+ vardb = self._frozen_config.roots[
+ dep.root].trees["vartree"].dbapi
+ matches = vardb.match_pkgs(dep.atom)
+ if not matches:
+ self._dynamic_config._initially_unsatisfied_deps.append(dep)
+ continue
+ # An scheduled installation broke a deep dependency.
+ # Add the installed package to the graph so that it
+ # will be appropriately reported as a slot collision
+ # (possibly solvable via backtracking).
+ pkg = matches[-1] # highest match
+ if not self._add_pkg(pkg, dep):
+ return 0
+ if not self._create_graph(allow_unsatisfied=True):
+ return 0
+ return 1
+
+ def _pkg(self, cpv, type_name, root_config, installed=False,
+ onlydeps=False, myrepo = None):
+ """
+ Get a package instance from the cache, or create a new
+ one if necessary. Raises PackageNotFound from aux_get if it
+ failures for some reason (package does not exist or is
+ corrupt).
+ """
+
+ # Ensure that we use the specially optimized RootConfig instance
+ # that refers to FakeVartree instead of the real vartree.
+ root_config = self._frozen_config.roots[root_config.root]
+ pkg = self._frozen_config._pkg_cache.get(
+ Package._gen_hash_key(cpv=cpv, type_name=type_name,
+ repo_name=myrepo, root_config=root_config,
+ installed=installed, onlydeps=onlydeps))
+ if pkg is None and onlydeps and not installed:
+ # Maybe it already got pulled in as a "merge" node.
+ pkg = self._dynamic_config.mydbapi[root_config.root].get(
+ Package._gen_hash_key(cpv=cpv, type_name=type_name,
+ repo_name=myrepo, root_config=root_config,
+ installed=installed, onlydeps=False))
+
+ if pkg is None:
+ tree_type = self.pkg_tree_map[type_name]
+ db = root_config.trees[tree_type].dbapi
+ db_keys = list(self._frozen_config._trees_orig[root_config.root][
+ tree_type].dbapi._aux_cache_keys)
+
+ try:
+ metadata = zip(db_keys, db.aux_get(cpv, db_keys, myrepo=myrepo))
+ except KeyError:
+ raise portage.exception.PackageNotFound(cpv)
+
+ pkg = Package(built=(type_name != "ebuild"), cpv=cpv,
+ installed=installed, metadata=metadata, onlydeps=onlydeps,
+ root_config=root_config, type_name=type_name)
+
+ self._frozen_config._pkg_cache[pkg] = pkg
+
+ if not self._pkg_visibility_check(pkg) and \
+ 'LICENSE' in pkg.masks and len(pkg.masks) == 1:
+ slot_key = (pkg.root, pkg.slot_atom)
+ other_pkg = self._frozen_config._highest_license_masked.get(slot_key)
+ if other_pkg is None or pkg > other_pkg:
+ self._frozen_config._highest_license_masked[slot_key] = pkg
+
+ return pkg
+
+ def _validate_blockers(self):
+ """Remove any blockers from the digraph that do not match any of the
+ packages within the graph. If necessary, create hard deps to ensure
+ correct merge order such that mutually blocking packages are never
+ installed simultaneously. Also add runtime blockers from all installed
+ packages if any of them haven't been added already (bug 128809)."""
+
+ if "--buildpkgonly" in self._frozen_config.myopts or \
+ "--nodeps" in self._frozen_config.myopts:
+ return True
+
+ complete = "complete" in self._dynamic_config.myparams
+ deep = "deep" in self._dynamic_config.myparams
+
+ if True:
+ # Pull in blockers from all installed packages that haven't already
+ # been pulled into the depgraph, in order to ensure that they are
+ # respected (bug 128809). Due to the performance penalty that is
+ # incurred by all the additional dep_check calls that are required,
+ # blockers returned from dep_check are cached on disk by the
+ # BlockerCache class.
+
+ # For installed packages, always ignore blockers from DEPEND since
+ # only runtime dependencies should be relevant for packages that
+ # are already built.
+ dep_keys = ["RDEPEND", "PDEPEND"]
+ for myroot in self._frozen_config.trees:
+ vardb = self._frozen_config.trees[myroot]["vartree"].dbapi
+ portdb = self._frozen_config.trees[myroot]["porttree"].dbapi
+ pkgsettings = self._frozen_config.pkgsettings[myroot]
+ root_config = self._frozen_config.roots[myroot]
+ dbs = self._dynamic_config._filtered_trees[myroot]["dbs"]
+ final_db = self._dynamic_config.mydbapi[myroot]
+
+ blocker_cache = BlockerCache(myroot, vardb)
+ stale_cache = set(blocker_cache)
+ for pkg in vardb:
+ cpv = pkg.cpv
+ stale_cache.discard(cpv)
+ pkg_in_graph = self._dynamic_config.digraph.contains(pkg)
+ pkg_deps_added = \
+ pkg in self._dynamic_config._traversed_pkg_deps
+
+ # Check for masked installed packages. Only warn about
+ # packages that are in the graph in order to avoid warning
+ # about those that will be automatically uninstalled during
+ # the merge process or by --depclean. Always warn about
+ # packages masked by license, since the user likely wants
+ # to adjust ACCEPT_LICENSE.
+ if pkg in final_db:
+ if not self._pkg_visibility_check(pkg) and \
+ (pkg_in_graph or 'LICENSE' in pkg.masks):
+ self._dynamic_config._masked_installed.add(pkg)
+ else:
+ self._check_masks(pkg)
+
+ blocker_atoms = None
+ blockers = None
+ if pkg_deps_added:
+ blockers = []
+ try:
+ blockers.extend(
+ self._dynamic_config._blocker_parents.child_nodes(pkg))
+ except KeyError:
+ pass
+ try:
+ blockers.extend(
+ self._dynamic_config._irrelevant_blockers.child_nodes(pkg))
+ except KeyError:
+ pass
+ if blockers:
+ # Select just the runtime blockers.
+ blockers = [blocker for blocker in blockers \
+ if blocker.priority.runtime or \
+ blocker.priority.runtime_post]
+ if blockers is not None:
+ blockers = set(blocker.atom for blocker in blockers)
+
+ # If this node has any blockers, create a "nomerge"
+ # node for it so that they can be enforced.
+ self._spinner_update()
+ blocker_data = blocker_cache.get(cpv)
+ if blocker_data is not None and \
+ blocker_data.counter != long(pkg.metadata["COUNTER"]):
+ blocker_data = None
+
+ # If blocker data from the graph is available, use
+ # it to validate the cache and update the cache if
+ # it seems invalid.
+ if blocker_data is not None and \
+ blockers is not None:
+ if not blockers.symmetric_difference(
+ blocker_data.atoms):
+ continue
+ blocker_data = None
+
+ if blocker_data is None and \
+ blockers is not None:
+ # Re-use the blockers from the graph.
+ blocker_atoms = sorted(blockers)
+ counter = long(pkg.metadata["COUNTER"])
+ blocker_data = \
+ blocker_cache.BlockerData(counter, blocker_atoms)
+ blocker_cache[pkg.cpv] = blocker_data
+ continue
+
+ if blocker_data:
+ blocker_atoms = [Atom(atom) for atom in blocker_data.atoms]
+ else:
+ # Use aux_get() to trigger FakeVartree global
+ # updates on *DEPEND when appropriate.
+ depstr = " ".join(vardb.aux_get(pkg.cpv, dep_keys))
+ # It is crucial to pass in final_db here in order to
+ # optimize dep_check calls by eliminating atoms via
+ # dep_wordreduce and dep_eval calls.
+ try:
+ success, atoms = portage.dep_check(depstr,
+ final_db, pkgsettings, myuse=self._pkg_use_enabled(pkg),
+ trees=self._dynamic_config._graph_trees, myroot=myroot)
+ except SystemExit:
+ raise
+ except Exception as e:
+ # This is helpful, for example, if a ValueError
+ # is thrown from cpv_expand due to multiple
+ # matches (this can happen if an atom lacks a
+ # category).
+ show_invalid_depstring_notice(
+ pkg, depstr, str(e))
+ del e
+ raise
+ if not success:
+ replacement_pkg = final_db.match_pkgs(pkg.slot_atom)
+ if replacement_pkg and \
+ replacement_pkg[0].operation == "merge":
+ # This package is being replaced anyway, so
+ # ignore invalid dependencies so as not to
+ # annoy the user too much (otherwise they'd be
+ # forced to manually unmerge it first).
+ continue
+ show_invalid_depstring_notice(pkg, depstr, atoms)
+ return False
+ blocker_atoms = [myatom for myatom in atoms \
+ if myatom.blocker]
+ blocker_atoms.sort()
+ counter = long(pkg.metadata["COUNTER"])
+ blocker_cache[cpv] = \
+ blocker_cache.BlockerData(counter, blocker_atoms)
+ if blocker_atoms:
+ try:
+ for atom in blocker_atoms:
+ blocker = Blocker(atom=atom,
+ eapi=pkg.metadata["EAPI"],
+ priority=self._priority(runtime=True),
+ root=myroot)
+ self._dynamic_config._blocker_parents.add(blocker, pkg)
+ except portage.exception.InvalidAtom as e:
+ depstr = " ".join(vardb.aux_get(pkg.cpv, dep_keys))
+ show_invalid_depstring_notice(
+ pkg, depstr, "Invalid Atom: %s" % (e,))
+ return False
+ for cpv in stale_cache:
+ del blocker_cache[cpv]
+ blocker_cache.flush()
+ del blocker_cache
+
+ # Discard any "uninstall" tasks scheduled by previous calls
+ # to this method, since those tasks may not make sense given
+ # the current graph state.
+ previous_uninstall_tasks = self._dynamic_config._blocker_uninstalls.leaf_nodes()
+ if previous_uninstall_tasks:
+ self._dynamic_config._blocker_uninstalls = digraph()
+ self._dynamic_config.digraph.difference_update(previous_uninstall_tasks)
+
+ for blocker in self._dynamic_config._blocker_parents.leaf_nodes():
+ self._spinner_update()
+ root_config = self._frozen_config.roots[blocker.root]
+ virtuals = root_config.settings.getvirtuals()
+ myroot = blocker.root
+ initial_db = self._frozen_config.trees[myroot]["vartree"].dbapi
+ final_db = self._dynamic_config.mydbapi[myroot]
+
+ provider_virtual = False
+ if blocker.cp in virtuals and \
+ not self._have_new_virt(blocker.root, blocker.cp):
+ provider_virtual = True
+
+ # Use this to check PROVIDE for each matched package
+ # when necessary.
+ atom_set = InternalPackageSet(
+ initial_atoms=[blocker.atom])
+
+ if provider_virtual:
+ atoms = []
+ for provider_entry in virtuals[blocker.cp]:
+ atoms.append(Atom(blocker.atom.replace(
+ blocker.cp, provider_entry.cp, 1)))
+ else:
+ atoms = [blocker.atom]
+
+ blocked_initial = set()
+ for atom in atoms:
+ for pkg in initial_db.match_pkgs(atom):
+ if atom_set.findAtomForPackage(pkg, modified_use=self._pkg_use_enabled(pkg)):
+ blocked_initial.add(pkg)
+
+ blocked_final = set()
+ for atom in atoms:
+ for pkg in final_db.match_pkgs(atom):
+ if atom_set.findAtomForPackage(pkg, modified_use=self._pkg_use_enabled(pkg)):
+ blocked_final.add(pkg)
+
+ if not blocked_initial and not blocked_final:
+ parent_pkgs = self._dynamic_config._blocker_parents.parent_nodes(blocker)
+ self._dynamic_config._blocker_parents.remove(blocker)
+ # Discard any parents that don't have any more blockers.
+ for pkg in parent_pkgs:
+ self._dynamic_config._irrelevant_blockers.add(blocker, pkg)
+ if not self._dynamic_config._blocker_parents.child_nodes(pkg):
+ self._dynamic_config._blocker_parents.remove(pkg)
+ continue
+ for parent in self._dynamic_config._blocker_parents.parent_nodes(blocker):
+ unresolved_blocks = False
+ depends_on_order = set()
+ for pkg in blocked_initial:
+ if pkg.slot_atom == parent.slot_atom and \
+ not blocker.atom.blocker.overlap.forbid:
+ # New !!atom blockers do not allow temporary
+ # simulaneous installation, so unlike !atom
+ # blockers, !!atom blockers aren't ignored
+ # when they match other packages occupying
+ # the same slot.
+ continue
+ if parent.installed:
+ # Two currently installed packages conflict with
+ # eachother. Ignore this case since the damage
+ # is already done and this would be likely to
+ # confuse users if displayed like a normal blocker.
+ continue
+
+ self._dynamic_config._blocked_pkgs.add(pkg, blocker)
+
+ if parent.operation == "merge":
+ # Maybe the blocked package can be replaced or simply
+ # unmerged to resolve this block.
+ depends_on_order.add((pkg, parent))
+ continue
+ # None of the above blocker resolutions techniques apply,
+ # so apparently this one is unresolvable.
+ unresolved_blocks = True
+ for pkg in blocked_final:
+ if pkg.slot_atom == parent.slot_atom and \
+ not blocker.atom.blocker.overlap.forbid:
+ # New !!atom blockers do not allow temporary
+ # simulaneous installation, so unlike !atom
+ # blockers, !!atom blockers aren't ignored
+ # when they match other packages occupying
+ # the same slot.
+ continue
+ if parent.operation == "nomerge" and \
+ pkg.operation == "nomerge":
+ # This blocker will be handled the next time that a
+ # merge of either package is triggered.
+ continue
+
+ self._dynamic_config._blocked_pkgs.add(pkg, blocker)
+
+ # Maybe the blocking package can be
+ # unmerged to resolve this block.
+ if parent.operation == "merge" and pkg.installed:
+ depends_on_order.add((pkg, parent))
+ continue
+ elif parent.operation == "nomerge":
+ depends_on_order.add((parent, pkg))
+ continue
+ # None of the above blocker resolutions techniques apply,
+ # so apparently this one is unresolvable.
+ unresolved_blocks = True
+
+ # Make sure we don't unmerge any package that have been pulled
+ # into the graph.
+ if not unresolved_blocks and depends_on_order:
+ for inst_pkg, inst_task in depends_on_order:
+ if self._dynamic_config.digraph.contains(inst_pkg) and \
+ self._dynamic_config.digraph.parent_nodes(inst_pkg):
+ unresolved_blocks = True
+ break
+
+ if not unresolved_blocks and depends_on_order:
+ for inst_pkg, inst_task in depends_on_order:
+ uninst_task = Package(built=inst_pkg.built,
+ cpv=inst_pkg.cpv, installed=inst_pkg.installed,
+ metadata=inst_pkg.metadata,
+ operation="uninstall",
+ root_config=inst_pkg.root_config,
+ type_name=inst_pkg.type_name)
+ # Enforce correct merge order with a hard dep.
+ self._dynamic_config.digraph.addnode(uninst_task, inst_task,
+ priority=BlockerDepPriority.instance)
+ # Count references to this blocker so that it can be
+ # invalidated after nodes referencing it have been
+ # merged.
+ self._dynamic_config._blocker_uninstalls.addnode(uninst_task, blocker)
+ if not unresolved_blocks and not depends_on_order:
+ self._dynamic_config._irrelevant_blockers.add(blocker, parent)
+ self._dynamic_config._blocker_parents.remove_edge(blocker, parent)
+ if not self._dynamic_config._blocker_parents.parent_nodes(blocker):
+ self._dynamic_config._blocker_parents.remove(blocker)
+ if not self._dynamic_config._blocker_parents.child_nodes(parent):
+ self._dynamic_config._blocker_parents.remove(parent)
+ if unresolved_blocks:
+ self._dynamic_config._unsolvable_blockers.add(blocker, parent)
+
+ return True
+
+ def _accept_blocker_conflicts(self):
+ acceptable = False
+ for x in ("--buildpkgonly", "--fetchonly",
+ "--fetch-all-uri", "--nodeps"):
+ if x in self._frozen_config.myopts:
+ acceptable = True
+ break
+ return acceptable
+
+ def _merge_order_bias(self, mygraph):
+ """
+ For optimal leaf node selection, promote deep system runtime deps and
+ order nodes from highest to lowest overall reference count.
+ """
+
+ node_info = {}
+ for node in mygraph.order:
+ node_info[node] = len(mygraph.parent_nodes(node))
+ deep_system_deps = _find_deep_system_runtime_deps(mygraph)
+
+ def cmp_merge_preference(node1, node2):
+
+ if node1.operation == 'uninstall':
+ if node2.operation == 'uninstall':
+ return 0
+ return 1
+
+ if node2.operation == 'uninstall':
+ if node1.operation == 'uninstall':
+ return 0
+ return -1
+
+ node1_sys = node1 in deep_system_deps
+ node2_sys = node2 in deep_system_deps
+ if node1_sys != node2_sys:
+ if node1_sys:
+ return -1
+ return 1
+
+ return node_info[node2] - node_info[node1]
+
+ mygraph.order.sort(key=cmp_sort_key(cmp_merge_preference))
+
+ def altlist(self, reversed=False):
+
+ while self._dynamic_config._serialized_tasks_cache is None:
+ self._resolve_conflicts()
+ try:
+ self._dynamic_config._serialized_tasks_cache, self._dynamic_config._scheduler_graph = \
+ self._serialize_tasks()
+ except self._serialize_tasks_retry:
+ pass
+
+ retlist = self._dynamic_config._serialized_tasks_cache[:]
+ if reversed:
+ retlist.reverse()
+ return retlist
+
+ def _implicit_libc_deps(self, mergelist, graph):
+ """
+ Create implicit dependencies on libc, in order to ensure that libc
+ is installed as early as possible (see bug #303567).
+ """
+ libc_pkgs = {}
+ implicit_libc_roots = (self._frozen_config._running_root.root,)
+ for root in implicit_libc_roots:
+ graphdb = self._dynamic_config.mydbapi[root]
+ vardb = self._frozen_config.trees[root]["vartree"].dbapi
+ for atom in self._expand_virt_from_graph(root,
+ portage.const.LIBC_PACKAGE_ATOM):
+ if atom.blocker:
+ continue
+ match = graphdb.match_pkgs(atom)
+ if not match:
+ continue
+ pkg = match[-1]
+ if pkg.operation == "merge" and \
+ not vardb.cpv_exists(pkg.cpv):
+ libc_pkgs.setdefault(pkg.root, set()).add(pkg)
+
+ if not libc_pkgs:
+ return
+
+ earlier_libc_pkgs = set()
+
+ for pkg in mergelist:
+ if not isinstance(pkg, Package):
+ # a satisfied blocker
+ continue
+ root_libc_pkgs = libc_pkgs.get(pkg.root)
+ if root_libc_pkgs is not None and \
+ pkg.operation == "merge":
+ if pkg in root_libc_pkgs:
+ earlier_libc_pkgs.add(pkg)
+ else:
+ for libc_pkg in root_libc_pkgs:
+ if libc_pkg in earlier_libc_pkgs:
+ graph.add(libc_pkg, pkg,
+ priority=DepPriority(buildtime=True))
+
+ def schedulerGraph(self):
+ """
+ The scheduler graph is identical to the normal one except that
+ uninstall edges are reversed in specific cases that require
+ conflicting packages to be temporarily installed simultaneously.
+ This is intended for use by the Scheduler in it's parallelization
+ logic. It ensures that temporary simultaneous installation of
+ conflicting packages is avoided when appropriate (especially for
+ !!atom blockers), but allowed in specific cases that require it.
+
+ Note that this method calls break_refs() which alters the state of
+ internal Package instances such that this depgraph instance should
+ not be used to perform any more calculations.
+ """
+
+ # NOTE: altlist initializes self._dynamic_config._scheduler_graph
+ mergelist = self.altlist()
+ self._implicit_libc_deps(mergelist,
+ self._dynamic_config._scheduler_graph)
+
+ # Break DepPriority.satisfied attributes which reference
+ # installed Package instances.
+ for parents, children, node in \
+ self._dynamic_config._scheduler_graph.nodes.values():
+ for priorities in chain(parents.values(), children.values()):
+ for priority in priorities:
+ if priority.satisfied:
+ priority.satisfied = True
+
+ pkg_cache = self._frozen_config._pkg_cache
+ graph = self._dynamic_config._scheduler_graph
+ trees = self._frozen_config.trees
+ pruned_pkg_cache = {}
+ for key, pkg in pkg_cache.items():
+ if pkg in graph or \
+ (pkg.installed and pkg in trees[pkg.root]['vartree'].dbapi):
+ pruned_pkg_cache[key] = pkg
+
+ for root in trees:
+ trees[root]['vartree']._pkg_cache = pruned_pkg_cache
+
+ self.break_refs()
+ sched_config = \
+ _scheduler_graph_config(trees, pruned_pkg_cache, graph, mergelist)
+
+ return sched_config
+
+ def break_refs(self):
+ """
+ Break any references in Package instances that lead back to the depgraph.
+ This is useful if you want to hold references to packages without also
+ holding the depgraph on the heap. It should only be called after the
+ depgraph and _frozen_config will not be used for any more calculations.
+ """
+ for root_config in self._frozen_config.roots.values():
+ root_config.update(self._frozen_config._trees_orig[
+ root_config.root]["root_config"])
+ # Both instances are now identical, so discard the
+ # original which should have no other references.
+ self._frozen_config._trees_orig[
+ root_config.root]["root_config"] = root_config
+
+ def _resolve_conflicts(self):
+ if not self._complete_graph():
+ raise self._unknown_internal_error()
+
+ if not self._validate_blockers():
+ self._dynamic_config._skip_restart = True
+ raise self._unknown_internal_error()
+
+ if self._dynamic_config._slot_collision_info:
+ self._process_slot_conflicts()
+
+ def _serialize_tasks(self):
+
+ debug = "--debug" in self._frozen_config.myopts
+
+ if debug:
+ writemsg("\ndigraph:\n\n", noiselevel=-1)
+ self._dynamic_config.digraph.debug_print()
+ writemsg("\n", noiselevel=-1)
+
+ scheduler_graph = self._dynamic_config.digraph.copy()
+
+ if '--nodeps' in self._frozen_config.myopts:
+ # Preserve the package order given on the command line.
+ return ([node for node in scheduler_graph \
+ if isinstance(node, Package) \
+ and node.operation == 'merge'], scheduler_graph)
+
+ mygraph=self._dynamic_config.digraph.copy()
+
+ removed_nodes = set()
+
+ # Prune off all DependencyArg instances since they aren't
+ # needed, and because of nested sets this is faster than doing
+ # it with multiple digraph.root_nodes() calls below. This also
+ # takes care of nested sets that have circular references,
+ # which wouldn't be matched by digraph.root_nodes().
+ for node in mygraph:
+ if isinstance(node, DependencyArg):
+ removed_nodes.add(node)
+ if removed_nodes:
+ mygraph.difference_update(removed_nodes)
+ removed_nodes.clear()
+
+ # Prune "nomerge" root nodes if nothing depends on them, since
+ # otherwise they slow down merge order calculation. Don't remove
+ # non-root nodes since they help optimize merge order in some cases
+ # such as revdep-rebuild.
+
+ while True:
+ for node in mygraph.root_nodes():
+ if not isinstance(node, Package) or \
+ node.installed or node.onlydeps:
+ removed_nodes.add(node)
+ if removed_nodes:
+ self._spinner_update()
+ mygraph.difference_update(removed_nodes)
+ if not removed_nodes:
+ break
+ removed_nodes.clear()
+ self._merge_order_bias(mygraph)
+ def cmp_circular_bias(n1, n2):
+ """
+ RDEPEND is stronger than PDEPEND and this function
+ measures such a strength bias within a circular
+ dependency relationship.
+ """
+ n1_n2_medium = n2 in mygraph.child_nodes(n1,
+ ignore_priority=priority_range.ignore_medium_soft)
+ n2_n1_medium = n1 in mygraph.child_nodes(n2,
+ ignore_priority=priority_range.ignore_medium_soft)
+ if n1_n2_medium == n2_n1_medium:
+ return 0
+ elif n1_n2_medium:
+ return 1
+ return -1
+ myblocker_uninstalls = self._dynamic_config._blocker_uninstalls.copy()
+ retlist=[]
+ # Contains uninstall tasks that have been scheduled to
+ # occur after overlapping blockers have been installed.
+ scheduled_uninstalls = set()
+ # Contains any Uninstall tasks that have been ignored
+ # in order to avoid the circular deps code path. These
+ # correspond to blocker conflicts that could not be
+ # resolved.
+ ignored_uninstall_tasks = set()
+ have_uninstall_task = False
+ complete = "complete" in self._dynamic_config.myparams
+ asap_nodes = []
+
+ def get_nodes(**kwargs):
+ """
+ Returns leaf nodes excluding Uninstall instances
+ since those should be executed as late as possible.
+ """
+ return [node for node in mygraph.leaf_nodes(**kwargs) \
+ if isinstance(node, Package) and \
+ (node.operation != "uninstall" or \
+ node in scheduled_uninstalls)]
+
+ # sys-apps/portage needs special treatment if ROOT="/"
+ running_root = self._frozen_config._running_root.root
+ runtime_deps = InternalPackageSet(
+ initial_atoms=[PORTAGE_PACKAGE_ATOM])
+ running_portage = self._frozen_config.trees[running_root]["vartree"].dbapi.match_pkgs(
+ PORTAGE_PACKAGE_ATOM)
+ replacement_portage = self._dynamic_config.mydbapi[running_root].match_pkgs(
+ PORTAGE_PACKAGE_ATOM)
+
+ if running_portage:
+ running_portage = running_portage[0]
+ else:
+ running_portage = None
+
+ if replacement_portage:
+ replacement_portage = replacement_portage[0]
+ else:
+ replacement_portage = None
+
+ if replacement_portage == running_portage:
+ replacement_portage = None
+
+ if replacement_portage is not None and \
+ (running_portage is None or \
+ running_portage.cpv != replacement_portage.cpv or \
+ '9999' in replacement_portage.cpv or \
+ 'git' in replacement_portage.inherited or \
+ 'git-2' in replacement_portage.inherited):
+ # update from running_portage to replacement_portage asap
+ asap_nodes.append(replacement_portage)
+
+ if running_portage is not None:
+ try:
+ portage_rdepend = self._select_atoms_highest_available(
+ running_root, running_portage.metadata["RDEPEND"],
+ myuse=self._pkg_use_enabled(running_portage),
+ parent=running_portage, strict=False)
+ except portage.exception.InvalidDependString as e:
+ portage.writemsg("!!! Invalid RDEPEND in " + \
+ "'%svar/db/pkg/%s/RDEPEND': %s\n" % \
+ (running_root, running_portage.cpv, e), noiselevel=-1)
+ del e
+ portage_rdepend = {running_portage : []}
+ for atoms in portage_rdepend.values():
+ runtime_deps.update(atom for atom in atoms \
+ if not atom.blocker)
+
+ # Merge libc asap, in order to account for implicit
+ # dependencies. See bug #303567.
+ implicit_libc_roots = (running_root,)
+ for root in implicit_libc_roots:
+ libc_pkgs = set()
+ vardb = self._frozen_config.trees[root]["vartree"].dbapi
+ graphdb = self._dynamic_config.mydbapi[root]
+ for atom in self._expand_virt_from_graph(root,
+ portage.const.LIBC_PACKAGE_ATOM):
+ if atom.blocker:
+ continue
+ match = graphdb.match_pkgs(atom)
+ if not match:
+ continue
+ pkg = match[-1]
+ if pkg.operation == "merge" and \
+ not vardb.cpv_exists(pkg.cpv):
+ libc_pkgs.add(pkg)
+
+ if libc_pkgs:
+ # If there's also an os-headers upgrade, we need to
+ # pull that in first. See bug #328317.
+ for atom in self._expand_virt_from_graph(root,
+ portage.const.OS_HEADERS_PACKAGE_ATOM):
+ if atom.blocker:
+ continue
+ match = graphdb.match_pkgs(atom)
+ if not match:
+ continue
+ pkg = match[-1]
+ if pkg.operation == "merge" and \
+ not vardb.cpv_exists(pkg.cpv):
+ asap_nodes.append(pkg)
+
+ asap_nodes.extend(libc_pkgs)
+
+ def gather_deps(ignore_priority, mergeable_nodes,
+ selected_nodes, node):
+ """
+ Recursively gather a group of nodes that RDEPEND on
+ eachother. This ensures that they are merged as a group
+ and get their RDEPENDs satisfied as soon as possible.
+ """
+ if node in selected_nodes:
+ return True
+ if node not in mergeable_nodes:
+ return False
+ if node == replacement_portage and \
+ mygraph.child_nodes(node,
+ ignore_priority=priority_range.ignore_medium_soft):
+ # Make sure that portage always has all of it's
+ # RDEPENDs installed first.
+ return False
+ selected_nodes.add(node)
+ for child in mygraph.child_nodes(node,
+ ignore_priority=ignore_priority):
+ if not gather_deps(ignore_priority,
+ mergeable_nodes, selected_nodes, child):
+ return False
+ return True
+
+ def ignore_uninst_or_med(priority):
+ if priority is BlockerDepPriority.instance:
+ return True
+ return priority_range.ignore_medium(priority)
+
+ def ignore_uninst_or_med_soft(priority):
+ if priority is BlockerDepPriority.instance:
+ return True
+ return priority_range.ignore_medium_soft(priority)
+
+ tree_mode = "--tree" in self._frozen_config.myopts
+ # Tracks whether or not the current iteration should prefer asap_nodes
+ # if available. This is set to False when the previous iteration
+ # failed to select any nodes. It is reset whenever nodes are
+ # successfully selected.
+ prefer_asap = True
+
+ # Controls whether or not the current iteration should drop edges that
+ # are "satisfied" by installed packages, in order to solve circular
+ # dependencies. The deep runtime dependencies of installed packages are
+ # not checked in this case (bug #199856), so it must be avoided
+ # whenever possible.
+ drop_satisfied = False
+
+ # State of variables for successive iterations that loosen the
+ # criteria for node selection.
+ #
+ # iteration prefer_asap drop_satisfied
+ # 1 True False
+ # 2 False False
+ # 3 False True
+ #
+ # If no nodes are selected on the last iteration, it is due to
+ # unresolved blockers or circular dependencies.
+
+ while mygraph:
+ self._spinner_update()
+ selected_nodes = None
+ ignore_priority = None
+ if drop_satisfied or (prefer_asap and asap_nodes):
+ priority_range = DepPrioritySatisfiedRange
+ else:
+ priority_range = DepPriorityNormalRange
+ if prefer_asap and asap_nodes:
+ # ASAP nodes are merged before their soft deps. Go ahead and
+ # select root nodes here if necessary, since it's typical for
+ # the parent to have been removed from the graph already.
+ asap_nodes = [node for node in asap_nodes \
+ if mygraph.contains(node)]
+ for i in range(priority_range.SOFT,
+ priority_range.MEDIUM_SOFT + 1):
+ ignore_priority = priority_range.ignore_priority[i]
+ for node in asap_nodes:
+ if not mygraph.child_nodes(node,
+ ignore_priority=ignore_priority):
+ selected_nodes = [node]
+ asap_nodes.remove(node)
+ break
+ if selected_nodes:
+ break
+
+ if not selected_nodes and \
+ not (prefer_asap and asap_nodes):
+ for i in range(priority_range.NONE,
+ priority_range.MEDIUM_SOFT + 1):
+ ignore_priority = priority_range.ignore_priority[i]
+ nodes = get_nodes(ignore_priority=ignore_priority)
+ if nodes:
+ # If there is a mixture of merges and uninstalls,
+ # do the uninstalls first.
+ good_uninstalls = None
+ if len(nodes) > 1:
+ good_uninstalls = []
+ for node in nodes:
+ if node.operation == "uninstall":
+ good_uninstalls.append(node)
+
+ if good_uninstalls:
+ nodes = good_uninstalls
+ else:
+ nodes = nodes
+
+ if good_uninstalls or len(nodes) == 1 or \
+ (ignore_priority is None and \
+ not asap_nodes and not tree_mode):
+ # Greedily pop all of these nodes since no
+ # relationship has been ignored. This optimization
+ # destroys --tree output, so it's disabled in tree
+ # mode.
+ selected_nodes = nodes
+ else:
+ # For optimal merge order:
+ # * Only pop one node.
+ # * Removing a root node (node without a parent)
+ # will not produce a leaf node, so avoid it.
+ # * It's normal for a selected uninstall to be a
+ # root node, so don't check them for parents.
+ if asap_nodes:
+ prefer_asap_parents = (True, False)
+ else:
+ prefer_asap_parents = (False,)
+ for check_asap_parent in prefer_asap_parents:
+ if check_asap_parent:
+ for node in nodes:
+ parents = mygraph.parent_nodes(node,
+ ignore_priority=DepPrioritySatisfiedRange.ignore_soft)
+ if parents and set(parents).intersection(asap_nodes):
+ selected_nodes = [node]
+ break
+ else:
+ for node in nodes:
+ if mygraph.parent_nodes(node):
+ selected_nodes = [node]
+ break
+ if selected_nodes:
+ break
+ if selected_nodes:
+ break
+
+ if not selected_nodes:
+ nodes = get_nodes(ignore_priority=priority_range.ignore_medium)
+ if nodes:
+ mergeable_nodes = set(nodes)
+ if prefer_asap and asap_nodes:
+ nodes = asap_nodes
+ # When gathering the nodes belonging to a runtime cycle,
+ # we want to minimize the number of nodes gathered, since
+ # this tends to produce a more optimal merge order.
+ # Ignoring all medium_soft deps serves this purpose.
+ # In the case of multiple runtime cycles, where some cycles
+ # may depend on smaller independent cycles, it's optimal
+ # to merge smaller independent cycles before other cycles
+ # that depend on them. Therefore, we search for the
+ # smallest cycle in order to try and identify and prefer
+ # these smaller independent cycles.
+ ignore_priority = priority_range.ignore_medium_soft
+ smallest_cycle = None
+ for node in nodes:
+ if not mygraph.parent_nodes(node):
+ continue
+ selected_nodes = set()
+ if gather_deps(ignore_priority,
+ mergeable_nodes, selected_nodes, node):
+ # When selecting asap_nodes, we need to ensure
+ # that we haven't selected a large runtime cycle
+ # that is obviously sub-optimal. This will be
+ # obvious if any of the non-asap selected_nodes
+ # is a leaf node when medium_soft deps are
+ # ignored.
+ if prefer_asap and asap_nodes and \
+ len(selected_nodes) > 1:
+ for node in selected_nodes.difference(
+ asap_nodes):
+ if not mygraph.child_nodes(node,
+ ignore_priority =
+ DepPriorityNormalRange.ignore_medium_soft):
+ selected_nodes = None
+ break
+ if selected_nodes:
+ if smallest_cycle is None or \
+ len(selected_nodes) < len(smallest_cycle):
+ smallest_cycle = selected_nodes
+
+ selected_nodes = smallest_cycle
+
+ if selected_nodes and debug:
+ writemsg("\nruntime cycle digraph (%s nodes):\n\n" %
+ (len(selected_nodes),), noiselevel=-1)
+ cycle_digraph = mygraph.copy()
+ cycle_digraph.difference_update([x for x in
+ cycle_digraph if x not in selected_nodes])
+ cycle_digraph.debug_print()
+ writemsg("\n", noiselevel=-1)
+
+ if prefer_asap and asap_nodes and not selected_nodes:
+ # We failed to find any asap nodes to merge, so ignore
+ # them for the next iteration.
+ prefer_asap = False
+ continue
+
+ if selected_nodes and ignore_priority is not None:
+ # Try to merge ignored medium_soft deps as soon as possible
+ # if they're not satisfied by installed packages.
+ for node in selected_nodes:
+ children = set(mygraph.child_nodes(node))
+ soft = children.difference(
+ mygraph.child_nodes(node,
+ ignore_priority=DepPrioritySatisfiedRange.ignore_soft))
+ medium_soft = children.difference(
+ mygraph.child_nodes(node,
+ ignore_priority = \
+ DepPrioritySatisfiedRange.ignore_medium_soft))
+ medium_soft.difference_update(soft)
+ for child in medium_soft:
+ if child in selected_nodes:
+ continue
+ if child in asap_nodes:
+ continue
+ # Merge PDEPEND asap for bug #180045.
+ asap_nodes.append(child)
+
+ if selected_nodes and len(selected_nodes) > 1:
+ if not isinstance(selected_nodes, list):
+ selected_nodes = list(selected_nodes)
+ selected_nodes.sort(key=cmp_sort_key(cmp_circular_bias))
+
+ if not selected_nodes and myblocker_uninstalls:
+ # An Uninstall task needs to be executed in order to
+ # avoid conflict if possible.
+
+ if drop_satisfied:
+ priority_range = DepPrioritySatisfiedRange
+ else:
+ priority_range = DepPriorityNormalRange
+
+ mergeable_nodes = get_nodes(
+ ignore_priority=ignore_uninst_or_med)
+
+ min_parent_deps = None
+ uninst_task = None
+
+ for task in myblocker_uninstalls.leaf_nodes():
+ # Do some sanity checks so that system or world packages
+ # don't get uninstalled inappropriately here (only really
+ # necessary when --complete-graph has not been enabled).
+
+ if task in ignored_uninstall_tasks:
+ continue
+
+ if task in scheduled_uninstalls:
+ # It's been scheduled but it hasn't
+ # been executed yet due to dependence
+ # on installation of blocking packages.
+ continue
+
+ root_config = self._frozen_config.roots[task.root]
+ inst_pkg = self._pkg(task.cpv, "installed", root_config,
+ installed=True)
+
+ if self._dynamic_config.digraph.contains(inst_pkg):
+ continue
+
+ forbid_overlap = False
+ heuristic_overlap = False
+ for blocker in myblocker_uninstalls.parent_nodes(task):
+ if not eapi_has_strong_blocks(blocker.eapi):
+ heuristic_overlap = True
+ elif blocker.atom.blocker.overlap.forbid:
+ forbid_overlap = True
+ break
+ if forbid_overlap and running_root == task.root:
+ continue
+
+ if heuristic_overlap and running_root == task.root:
+ # Never uninstall sys-apps/portage or it's essential
+ # dependencies, except through replacement.
+ try:
+ runtime_dep_atoms = \
+ list(runtime_deps.iterAtomsForPackage(task))
+ except portage.exception.InvalidDependString as e:
+ portage.writemsg("!!! Invalid PROVIDE in " + \
+ "'%svar/db/pkg/%s/PROVIDE': %s\n" % \
+ (task.root, task.cpv, e), noiselevel=-1)
+ del e
+ continue
+
+ # Don't uninstall a runtime dep if it appears
+ # to be the only suitable one installed.
+ skip = False
+ vardb = root_config.trees["vartree"].dbapi
+ for atom in runtime_dep_atoms:
+ other_version = None
+ for pkg in vardb.match_pkgs(atom):
+ if pkg.cpv == task.cpv and \
+ pkg.metadata["COUNTER"] == \
+ task.metadata["COUNTER"]:
+ continue
+ other_version = pkg
+ break
+ if other_version is None:
+ skip = True
+ break
+ if skip:
+ continue
+
+ # For packages in the system set, don't take
+ # any chances. If the conflict can't be resolved
+ # by a normal replacement operation then abort.
+ skip = False
+ try:
+ for atom in root_config.sets[
+ "system"].iterAtomsForPackage(task):
+ skip = True
+ break
+ except portage.exception.InvalidDependString as e:
+ portage.writemsg("!!! Invalid PROVIDE in " + \
+ "'%svar/db/pkg/%s/PROVIDE': %s\n" % \
+ (task.root, task.cpv, e), noiselevel=-1)
+ del e
+ skip = True
+ if skip:
+ continue
+
+ # Note that the world check isn't always
+ # necessary since self._complete_graph() will
+ # add all packages from the system and world sets to the
+ # graph. This just allows unresolved conflicts to be
+ # detected as early as possible, which makes it possible
+ # to avoid calling self._complete_graph() when it is
+ # unnecessary due to blockers triggering an abortion.
+ if not complete:
+ # For packages in the world set, go ahead an uninstall
+ # when necessary, as long as the atom will be satisfied
+ # in the final state.
+ graph_db = self._dynamic_config.mydbapi[task.root]
+ skip = False
+ try:
+ for atom in root_config.sets[
+ "selected"].iterAtomsForPackage(task):
+ satisfied = False
+ for pkg in graph_db.match_pkgs(atom):
+ if pkg == inst_pkg:
+ continue
+ satisfied = True
+ break
+ if not satisfied:
+ skip = True
+ self._dynamic_config._blocked_world_pkgs[inst_pkg] = atom
+ break
+ except portage.exception.InvalidDependString as e:
+ portage.writemsg("!!! Invalid PROVIDE in " + \
+ "'%svar/db/pkg/%s/PROVIDE': %s\n" % \
+ (task.root, task.cpv, e), noiselevel=-1)
+ del e
+ skip = True
+ if skip:
+ continue
+
+ # Check the deps of parent nodes to ensure that
+ # the chosen task produces a leaf node. Maybe
+ # this can be optimized some more to make the
+ # best possible choice, but the current algorithm
+ # is simple and should be near optimal for most
+ # common cases.
+ self._spinner_update()
+ mergeable_parent = False
+ parent_deps = set()
+ parent_deps.add(task)
+ for parent in mygraph.parent_nodes(task):
+ parent_deps.update(mygraph.child_nodes(parent,
+ ignore_priority=priority_range.ignore_medium_soft))
+ if min_parent_deps is not None and \
+ len(parent_deps) >= min_parent_deps:
+ # This task is no better than a previously selected
+ # task, so abort search now in order to avoid wasting
+ # any more cpu time on this task. This increases
+ # performance dramatically in cases when there are
+ # hundreds of blockers to solve, like when
+ # upgrading to a new slot of kde-meta.
+ mergeable_parent = None
+ break
+ if parent in mergeable_nodes and \
+ gather_deps(ignore_uninst_or_med_soft,
+ mergeable_nodes, set(), parent):
+ mergeable_parent = True
+
+ if not mergeable_parent:
+ continue
+
+ if min_parent_deps is None or \
+ len(parent_deps) < min_parent_deps:
+ min_parent_deps = len(parent_deps)
+ uninst_task = task
+
+ if uninst_task is not None and min_parent_deps == 1:
+ # This is the best possible result, so so abort search
+ # now in order to avoid wasting any more cpu time.
+ break
+
+ if uninst_task is not None:
+ # The uninstall is performed only after blocking
+ # packages have been merged on top of it. File
+ # collisions between blocking packages are detected
+ # and removed from the list of files to be uninstalled.
+ scheduled_uninstalls.add(uninst_task)
+ parent_nodes = mygraph.parent_nodes(uninst_task)
+
+ # Reverse the parent -> uninstall edges since we want
+ # to do the uninstall after blocking packages have
+ # been merged on top of it.
+ mygraph.remove(uninst_task)
+ for blocked_pkg in parent_nodes:
+ mygraph.add(blocked_pkg, uninst_task,
+ priority=BlockerDepPriority.instance)
+ scheduler_graph.remove_edge(uninst_task, blocked_pkg)
+ scheduler_graph.add(blocked_pkg, uninst_task,
+ priority=BlockerDepPriority.instance)
+
+ # Sometimes a merge node will render an uninstall
+ # node unnecessary (due to occupying the same SLOT),
+ # and we want to avoid executing a separate uninstall
+ # task in that case.
+ slot_node = self._dynamic_config.mydbapi[uninst_task.root
+ ].match_pkgs(uninst_task.slot_atom)
+ if slot_node and \
+ slot_node[0].operation == "merge":
+ mygraph.add(slot_node[0], uninst_task,
+ priority=BlockerDepPriority.instance)
+
+ # Reset the state variables for leaf node selection and
+ # continue trying to select leaf nodes.
+ prefer_asap = True
+ drop_satisfied = False
+ continue
+
+ if not selected_nodes:
+ # Only select root nodes as a last resort. This case should
+ # only trigger when the graph is nearly empty and the only
+ # remaining nodes are isolated (no parents or children). Since
+ # the nodes must be isolated, ignore_priority is not needed.
+ selected_nodes = get_nodes()
+
+ if not selected_nodes and not drop_satisfied:
+ drop_satisfied = True
+ continue
+
+ if not selected_nodes and myblocker_uninstalls:
+ # If possible, drop an uninstall task here in order to avoid
+ # the circular deps code path. The corresponding blocker will
+ # still be counted as an unresolved conflict.
+ uninst_task = None
+ for node in myblocker_uninstalls.leaf_nodes():
+ try:
+ mygraph.remove(node)
+ except KeyError:
+ pass
+ else:
+ uninst_task = node
+ ignored_uninstall_tasks.add(node)
+ break
+
+ if uninst_task is not None:
+ # Reset the state variables for leaf node selection and
+ # continue trying to select leaf nodes.
+ prefer_asap = True
+ drop_satisfied = False
+ continue
+
+ if not selected_nodes:
+ self._dynamic_config._circular_deps_for_display = mygraph
+ self._dynamic_config._skip_restart = True
+ raise self._unknown_internal_error()
+
+ # At this point, we've succeeded in selecting one or more nodes, so
+ # reset state variables for leaf node selection.
+ prefer_asap = True
+ drop_satisfied = False
+
+ mygraph.difference_update(selected_nodes)
+
+ for node in selected_nodes:
+ if isinstance(node, Package) and \
+ node.operation == "nomerge":
+ continue
+
+ # Handle interactions between blockers
+ # and uninstallation tasks.
+ solved_blockers = set()
+ uninst_task = None
+ if isinstance(node, Package) and \
+ "uninstall" == node.operation:
+ have_uninstall_task = True
+ uninst_task = node
+ else:
+ vardb = self._frozen_config.trees[node.root]["vartree"].dbapi
+ inst_pkg = vardb.match_pkgs(node.slot_atom)
+ if inst_pkg:
+ # The package will be replaced by this one, so remove
+ # the corresponding Uninstall task if necessary.
+ inst_pkg = inst_pkg[0]
+ uninst_task = Package(built=inst_pkg.built,
+ cpv=inst_pkg.cpv, installed=inst_pkg.installed,
+ metadata=inst_pkg.metadata,
+ operation="uninstall",
+ root_config=inst_pkg.root_config,
+ type_name=inst_pkg.type_name)
+ try:
+ mygraph.remove(uninst_task)
+ except KeyError:
+ pass
+
+ if uninst_task is not None and \
+ uninst_task not in ignored_uninstall_tasks and \
+ myblocker_uninstalls.contains(uninst_task):
+ blocker_nodes = myblocker_uninstalls.parent_nodes(uninst_task)
+ myblocker_uninstalls.remove(uninst_task)
+ # Discard any blockers that this Uninstall solves.
+ for blocker in blocker_nodes:
+ if not myblocker_uninstalls.child_nodes(blocker):
+ myblocker_uninstalls.remove(blocker)
+ if blocker not in \
+ self._dynamic_config._unsolvable_blockers:
+ solved_blockers.add(blocker)
+
+ retlist.append(node)
+
+ if (isinstance(node, Package) and \
+ "uninstall" == node.operation) or \
+ (uninst_task is not None and \
+ uninst_task in scheduled_uninstalls):
+ # Include satisfied blockers in the merge list
+ # since the user might be interested and also
+ # it serves as an indicator that blocking packages
+ # will be temporarily installed simultaneously.
+ for blocker in solved_blockers:
+ retlist.append(blocker)
+
+ unsolvable_blockers = set(self._dynamic_config._unsolvable_blockers.leaf_nodes())
+ for node in myblocker_uninstalls.root_nodes():
+ unsolvable_blockers.add(node)
+
+ # If any Uninstall tasks need to be executed in order
+ # to avoid a conflict, complete the graph with any
+ # dependencies that may have been initially
+ # neglected (to ensure that unsafe Uninstall tasks
+ # are properly identified and blocked from execution).
+ if have_uninstall_task and \
+ not complete and \
+ not unsolvable_blockers:
+ self._dynamic_config.myparams["complete"] = True
+ if '--debug' in self._frozen_config.myopts:
+ msg = []
+ msg.append("enabling 'complete' depgraph mode " + \
+ "due to uninstall task(s):")
+ msg.append("")
+ for node in retlist:
+ if isinstance(node, Package) and \
+ node.operation == 'uninstall':
+ msg.append("\t%s" % (node,))
+ writemsg_level("\n%s\n" % \
+ "".join("%s\n" % line for line in msg),
+ level=logging.DEBUG, noiselevel=-1)
+ raise self._serialize_tasks_retry("")
+
+ # Set satisfied state on blockers, but not before the
+ # above retry path, since we don't want to modify the
+ # state in that case.
+ for node in retlist:
+ if isinstance(node, Blocker):
+ node.satisfied = True
+
+ for blocker in unsolvable_blockers:
+ retlist.append(blocker)
+
+ if unsolvable_blockers and \
+ not self._accept_blocker_conflicts():
+ self._dynamic_config._unsatisfied_blockers_for_display = unsolvable_blockers
+ self._dynamic_config._serialized_tasks_cache = retlist[:]
+ self._dynamic_config._scheduler_graph = scheduler_graph
+ self._dynamic_config._skip_restart = True
+ raise self._unknown_internal_error()
+
+ if self._dynamic_config._slot_collision_info and \
+ not self._accept_blocker_conflicts():
+ self._dynamic_config._serialized_tasks_cache = retlist[:]
+ self._dynamic_config._scheduler_graph = scheduler_graph
+ raise self._unknown_internal_error()
+
+ return retlist, scheduler_graph
+
+ def _show_circular_deps(self, mygraph):
+ self._dynamic_config._circular_dependency_handler = \
+ circular_dependency_handler(self, mygraph)
+ handler = self._dynamic_config._circular_dependency_handler
+
+ self._frozen_config.myopts.pop("--quiet", None)
+ self._frozen_config.myopts["--verbose"] = True
+ self._frozen_config.myopts["--tree"] = True
+ portage.writemsg("\n\n", noiselevel=-1)
+ self.display(handler.merge_list)
+ prefix = colorize("BAD", " * ")
+ portage.writemsg("\n", noiselevel=-1)
+ portage.writemsg(prefix + "Error: circular dependencies:\n",
+ noiselevel=-1)
+ portage.writemsg("\n", noiselevel=-1)
+
+ if handler.circular_dep_message is None:
+ handler.debug_print()
+ portage.writemsg("\n", noiselevel=-1)
+
+ if handler.circular_dep_message is not None:
+ portage.writemsg(handler.circular_dep_message, noiselevel=-1)
+
+ suggestions = handler.suggestions
+ if suggestions:
+ writemsg("\n\nIt might be possible to break this cycle\n", noiselevel=-1)
+ if len(suggestions) == 1:
+ writemsg("by applying the following change:\n", noiselevel=-1)
+ else:
+ writemsg("by applying " + colorize("bold", "any of") + \
+ " the following changes:\n", noiselevel=-1)
+ writemsg("".join(suggestions), noiselevel=-1)
+ writemsg("\nNote that this change can be reverted, once the package has" + \
+ " been installed.\n", noiselevel=-1)
+ if handler.large_cycle_count:
+ writemsg("\nNote that the dependency graph contains a lot of cycles.\n" + \
+ "Several changes might be required to resolve all cycles.\n" + \
+ "Temporarily changing some use flag for all packages might be the better option.\n", noiselevel=-1)
+ else:
+ writemsg("\n\n", noiselevel=-1)
+ writemsg(prefix + "Note that circular dependencies " + \
+ "can often be avoided by temporarily\n", noiselevel=-1)
+ writemsg(prefix + "disabling USE flags that trigger " + \
+ "optional dependencies.\n", noiselevel=-1)
+
+ def _show_merge_list(self):
+ if self._dynamic_config._serialized_tasks_cache is not None and \
+ not (self._dynamic_config._displayed_list is not None and \
+ (self._dynamic_config._displayed_list == self._dynamic_config._serialized_tasks_cache or \
+ self._dynamic_config._displayed_list == \
+ list(reversed(self._dynamic_config._serialized_tasks_cache)))):
+ display_list = self._dynamic_config._serialized_tasks_cache[:]
+ if "--tree" in self._frozen_config.myopts:
+ display_list.reverse()
+ self.display(display_list)
+
+ def _show_unsatisfied_blockers(self, blockers):
+ self._show_merge_list()
+ msg = "Error: The above package list contains " + \
+ "packages which cannot be installed " + \
+ "at the same time on the same system."
+ prefix = colorize("BAD", " * ")
+ portage.writemsg("\n", noiselevel=-1)
+ for line in textwrap.wrap(msg, 70):
+ portage.writemsg(prefix + line + "\n", noiselevel=-1)
+
+ # Display the conflicting packages along with the packages
+ # that pulled them in. This is helpful for troubleshooting
+ # cases in which blockers don't solve automatically and
+ # the reasons are not apparent from the normal merge list
+ # display.
+
+ conflict_pkgs = {}
+ for blocker in blockers:
+ for pkg in chain(self._dynamic_config._blocked_pkgs.child_nodes(blocker), \
+ self._dynamic_config._blocker_parents.parent_nodes(blocker)):
+ parent_atoms = self._dynamic_config._parent_atoms.get(pkg)
+ if not parent_atoms:
+ atom = self._dynamic_config._blocked_world_pkgs.get(pkg)
+ if atom is not None:
+ parent_atoms = set([("@selected", atom)])
+ if parent_atoms:
+ conflict_pkgs[pkg] = parent_atoms
+
+ if conflict_pkgs:
+ # Reduce noise by pruning packages that are only
+ # pulled in by other conflict packages.
+ pruned_pkgs = set()
+ for pkg, parent_atoms in conflict_pkgs.items():
+ relevant_parent = False
+ for parent, atom in parent_atoms:
+ if parent not in conflict_pkgs:
+ relevant_parent = True
+ break
+ if not relevant_parent:
+ pruned_pkgs.add(pkg)
+ for pkg in pruned_pkgs:
+ del conflict_pkgs[pkg]
+
+ if conflict_pkgs:
+ msg = []
+ msg.append("\n")
+ indent = " "
+ for pkg, parent_atoms in conflict_pkgs.items():
+
+ # Prefer packages that are not directly involved in a conflict.
+ # It can be essential to see all the packages here, so don't
+ # omit any. If the list is long, people can simply use a pager.
+ preferred_parents = set()
+ for parent_atom in parent_atoms:
+ parent, atom = parent_atom
+ if parent not in conflict_pkgs:
+ preferred_parents.add(parent_atom)
+
+ ordered_list = list(preferred_parents)
+ if len(parent_atoms) > len(ordered_list):
+ for parent_atom in parent_atoms:
+ if parent_atom not in preferred_parents:
+ ordered_list.append(parent_atom)
+
+ msg.append(indent + "%s pulled in by\n" % pkg)
+
+ for parent_atom in ordered_list:
+ parent, atom = parent_atom
+ msg.append(2*indent)
+ if isinstance(parent,
+ (PackageArg, AtomArg)):
+ # For PackageArg and AtomArg types, it's
+ # redundant to display the atom attribute.
+ msg.append(str(parent))
+ else:
+ # Display the specific atom from SetArg or
+ # Package types.
+ msg.append("%s required by %s" % (atom, parent))
+ msg.append("\n")
+
+ msg.append("\n")
+
+ writemsg("".join(msg), noiselevel=-1)
+
+ if "--quiet" not in self._frozen_config.myopts:
+ show_blocker_docs_link()
+
+ def display(self, mylist, favorites=[], verbosity=None):
+
+ # This is used to prevent display_problems() from
+ # redundantly displaying this exact same merge list
+ # again via _show_merge_list().
+ self._dynamic_config._displayed_list = mylist
+ display = Display()
+
+ return display(self, mylist, favorites, verbosity)
+
+ def _display_autounmask(self):
+ """
+ Display --autounmask message and optionally write it to config files
+ (using CONFIG_PROTECT). The message includes the comments and the changes.
+ """
+
+ autounmask_write = self._frozen_config.myopts.get("--autounmask-write", "n") == True
+ quiet = "--quiet" in self._frozen_config.myopts
+ pretend = "--pretend" in self._frozen_config.myopts
+ ask = "--ask" in self._frozen_config.myopts
+ enter_invalid = '--ask-enter-invalid' in self._frozen_config.myopts
+
+ def check_if_latest(pkg):
+ is_latest = True
+ is_latest_in_slot = True
+ dbs = self._dynamic_config._filtered_trees[pkg.root]["dbs"]
+ root_config = self._frozen_config.roots[pkg.root]
+
+ for db, pkg_type, built, installed, db_keys in dbs:
+ for other_pkg in self._iter_match_pkgs(root_config, pkg_type, Atom(pkg.cp)):
+ if other_pkg.cp != pkg.cp:
+ # old-style PROVIDE virtual means there are no
+ # normal matches for this pkg_type
+ break
+ if other_pkg > pkg:
+ is_latest = False
+ if other_pkg.slot_atom == pkg.slot_atom:
+ is_latest_in_slot = False
+ break
+ else:
+ # iter_match_pkgs yields highest version first, so
+ # there's no need to search this pkg_type any further
+ break
+
+ if not is_latest_in_slot:
+ break
+
+ return is_latest, is_latest_in_slot
+
+ #Set of roots we have autounmask changes for.
+ roots = set()
+
+ unstable_keyword_msg = {}
+ for pkg in self._dynamic_config._needed_unstable_keywords:
+ self._show_merge_list()
+ if pkg in self._dynamic_config.digraph:
+ root = pkg.root
+ roots.add(root)
+ unstable_keyword_msg.setdefault(root, [])
+ is_latest, is_latest_in_slot = check_if_latest(pkg)
+ pkgsettings = self._frozen_config.pkgsettings[pkg.root]
+ mreasons = _get_masking_status(pkg, pkgsettings, pkg.root_config,
+ use=self._pkg_use_enabled(pkg))
+ for reason in mreasons:
+ if reason.unmask_hint and \
+ reason.unmask_hint.key == 'unstable keyword':
+ keyword = reason.unmask_hint.value
+
+ unstable_keyword_msg[root].append(self._get_dep_chain_as_comment(pkg))
+ if is_latest:
+ unstable_keyword_msg[root].append(">=%s %s\n" % (pkg.cpv, keyword))
+ elif is_latest_in_slot:
+ unstable_keyword_msg[root].append(">=%s:%s %s\n" % (pkg.cpv, pkg.metadata["SLOT"], keyword))
+ else:
+ unstable_keyword_msg[root].append("=%s %s\n" % (pkg.cpv, keyword))
+
+ p_mask_change_msg = {}
+ for pkg in self._dynamic_config._needed_p_mask_changes:
+ self._show_merge_list()
+ if pkg in self._dynamic_config.digraph:
+ root = pkg.root
+ roots.add(root)
+ p_mask_change_msg.setdefault(root, [])
+ is_latest, is_latest_in_slot = check_if_latest(pkg)
+ pkgsettings = self._frozen_config.pkgsettings[pkg.root]
+ mreasons = _get_masking_status(pkg, pkgsettings, pkg.root_config,
+ use=self._pkg_use_enabled(pkg))
+ for reason in mreasons:
+ if reason.unmask_hint and \
+ reason.unmask_hint.key == 'p_mask':
+ keyword = reason.unmask_hint.value
+
+ comment, filename = portage.getmaskingreason(
+ pkg.cpv, metadata=pkg.metadata,
+ settings=pkgsettings,
+ portdb=pkg.root_config.trees["porttree"].dbapi,
+ return_location=True)
+
+ p_mask_change_msg[root].append(self._get_dep_chain_as_comment(pkg))
+ if filename:
+ p_mask_change_msg[root].append("# %s:\n" % filename)
+ if comment:
+ comment = [line for line in
+ comment.splitlines() if line]
+ for line in comment:
+ p_mask_change_msg[root].append("%s\n" % line)
+ if is_latest:
+ p_mask_change_msg[root].append(">=%s\n" % pkg.cpv)
+ elif is_latest_in_slot:
+ p_mask_change_msg[root].append(">=%s:%s\n" % (pkg.cpv, pkg.metadata["SLOT"]))
+ else:
+ p_mask_change_msg[root].append("=%s\n" % pkg.cpv)
+
+ use_changes_msg = {}
+ for pkg, needed_use_config_change in self._dynamic_config._needed_use_config_changes.items():
+ self._show_merge_list()
+ if pkg in self._dynamic_config.digraph:
+ root = pkg.root
+ roots.add(root)
+ use_changes_msg.setdefault(root, [])
+ is_latest, is_latest_in_slot = check_if_latest(pkg)
+ changes = needed_use_config_change[1]
+ adjustments = []
+ for flag, state in changes.items():
+ if state:
+ adjustments.append(flag)
+ else:
+ adjustments.append("-" + flag)
+ use_changes_msg[root].append(self._get_dep_chain_as_comment(pkg, unsatisfied_dependency=True))
+ if is_latest:
+ use_changes_msg[root].append(">=%s %s\n" % (pkg.cpv, " ".join(adjustments)))
+ elif is_latest_in_slot:
+ use_changes_msg[root].append(">=%s:%s %s\n" % (pkg.cpv, pkg.metadata["SLOT"], " ".join(adjustments)))
+ else:
+ use_changes_msg[root].append("=%s %s\n" % (pkg.cpv, " ".join(adjustments)))
+
+ license_msg = {}
+ for pkg, missing_licenses in self._dynamic_config._needed_license_changes.items():
+ self._show_merge_list()
+ if pkg in self._dynamic_config.digraph:
+ root = pkg.root
+ roots.add(root)
+ license_msg.setdefault(root, [])
+ is_latest, is_latest_in_slot = check_if_latest(pkg)
+
+ license_msg[root].append(self._get_dep_chain_as_comment(pkg))
+ if is_latest:
+ license_msg[root].append(">=%s %s\n" % (pkg.cpv, " ".join(sorted(missing_licenses))))
+ elif is_latest_in_slot:
+ license_msg[root].append(">=%s:%s %s\n" % (pkg.cpv, pkg.metadata["SLOT"], " ".join(sorted(missing_licenses))))
+ else:
+ license_msg[root].append("=%s %s\n" % (pkg.cpv, " ".join(sorted(missing_licenses))))
+
+ def find_config_file(abs_user_config, file_name):
+ """
+ Searches /etc/portage for an appropriate file to append changes to.
+ If the file_name is a file it is returned, if it is a directory, the
+ last file in it is returned. Order of traversal is the identical to
+ portage.util.grablines(recursive=True).
+
+ file_name - String containing a file name like "package.use"
+ return value - String. Absolute path of file to write to. None if
+ no suitable file exists.
+ """
+ file_path = os.path.join(abs_user_config, file_name)
+
+ try:
+ os.lstat(file_path)
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ # The file doesn't exist, so we'll
+ # simply create it.
+ return file_path
+
+ # Disk or file system trouble?
+ return None
+
+ last_file_path = None
+ stack = [file_path]
+ while stack:
+ p = stack.pop()
+ try:
+ st = os.stat(p)
+ except OSError:
+ pass
+ else:
+ if stat.S_ISREG(st.st_mode):
+ last_file_path = p
+ elif stat.S_ISDIR(st.st_mode):
+ if os.path.basename(p) in _ignorecvs_dirs:
+ continue
+ try:
+ contents = os.listdir(p)
+ except OSError:
+ pass
+ else:
+ contents.sort(reverse=True)
+ for child in contents:
+ if child.startswith(".") or \
+ child.endswith("~"):
+ continue
+ stack.append(os.path.join(p, child))
+
+ return last_file_path
+
+ write_to_file = autounmask_write and not pretend
+ #Make sure we have a file to write to before doing any write.
+ file_to_write_to = {}
+ problems = []
+ if write_to_file:
+ for root in roots:
+ settings = self._frozen_config.roots[root].settings
+ abs_user_config = os.path.join(
+ settings["PORTAGE_CONFIGROOT"], USER_CONFIG_PATH)
+
+ if root in unstable_keyword_msg:
+ if not os.path.exists(os.path.join(abs_user_config,
+ "package.keywords")):
+ filename = "package.accept_keywords"
+ else:
+ filename = "package.keywords"
+ file_to_write_to[(abs_user_config, "package.keywords")] = \
+ find_config_file(abs_user_config, filename)
+
+ if root in p_mask_change_msg:
+ file_to_write_to[(abs_user_config, "package.unmask")] = \
+ find_config_file(abs_user_config, "package.unmask")
+
+ if root in use_changes_msg:
+ file_to_write_to[(abs_user_config, "package.use")] = \
+ find_config_file(abs_user_config, "package.use")
+
+ if root in license_msg:
+ file_to_write_to[(abs_user_config, "package.license")] = \
+ find_config_file(abs_user_config, "package.license")
+
+ for (abs_user_config, f), path in file_to_write_to.items():
+ if path is None:
+ problems.append("!!! No file to write for '%s'\n" % os.path.join(abs_user_config, f))
+
+ write_to_file = not problems
+
+ for root in roots:
+ settings = self._frozen_config.roots[root].settings
+ abs_user_config = os.path.join(
+ settings["PORTAGE_CONFIGROOT"], USER_CONFIG_PATH)
+
+ if len(roots) > 1:
+ writemsg_stdout("\nFor %s:\n" % abs_user_config, noiselevel=-1)
+
+ if root in unstable_keyword_msg:
+ writemsg_stdout("\nThe following " + colorize("BAD", "keyword changes") + \
+ " are necessary to proceed:\n", noiselevel=-1)
+ writemsg_stdout("".join(unstable_keyword_msg[root]), noiselevel=-1)
+
+ if root in p_mask_change_msg:
+ writemsg_stdout("\nThe following " + colorize("BAD", "mask changes") + \
+ " are necessary to proceed:\n", noiselevel=-1)
+ writemsg_stdout("".join(p_mask_change_msg[root]), noiselevel=-1)
+
+ if root in use_changes_msg:
+ writemsg_stdout("\nThe following " + colorize("BAD", "USE changes") + \
+ " are necessary to proceed:\n", noiselevel=-1)
+ writemsg_stdout("".join(use_changes_msg[root]), noiselevel=-1)
+
+ if root in license_msg:
+ writemsg_stdout("\nThe following " + colorize("BAD", "license changes") + \
+ " are necessary to proceed:\n", noiselevel=-1)
+ writemsg_stdout("".join(license_msg[root]), noiselevel=-1)
+
+ protect_obj = {}
+ if write_to_file:
+ for root in roots:
+ settings = self._frozen_config.roots[root].settings
+ protect_obj[root] = ConfigProtect(settings["EROOT"], \
+ shlex_split(settings.get("CONFIG_PROTECT", "")),
+ shlex_split(settings.get("CONFIG_PROTECT_MASK", "")))
+
+ def write_changes(root, changes, file_to_write_to):
+ file_contents = None
+ try:
+ file_contents = io.open(
+ _unicode_encode(file_to_write_to,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'],
+ errors='replace').readlines()
+ except IOError as e:
+ if e.errno == errno.ENOENT:
+ file_contents = []
+ else:
+ problems.append("!!! Failed to read '%s': %s\n" % \
+ (file_to_write_to, e))
+ if file_contents is not None:
+ file_contents.extend(changes)
+ if protect_obj[root].isprotected(file_to_write_to):
+ # We want to force new_protect_filename to ensure
+ # that the user will see all our changes via
+ # etc-update, even if file_to_write_to doesn't
+ # exist yet, so we specify force=True.
+ file_to_write_to = new_protect_filename(file_to_write_to,
+ force=True)
+ try:
+ write_atomic(file_to_write_to, "".join(file_contents))
+ except PortageException:
+ problems.append("!!! Failed to write '%s'\n" % file_to_write_to)
+
+ if not quiet and \
+ (unstable_keyword_msg or \
+ p_mask_change_msg or \
+ use_changes_msg or \
+ license_msg):
+ msg = [
+ "",
+ "NOTE: This --autounmask behavior can be disabled by setting",
+ " EMERGE_DEFAULT_OPTS=\"--autounmask=n\" in make.conf."
+ ]
+ for line in msg:
+ if line:
+ line = colorize("INFORM", line)
+ writemsg_stdout(line + "\n", noiselevel=-1)
+
+ if ask and write_to_file and file_to_write_to:
+ prompt = "\nWould you like to add these " + \
+ "changes to your config files?"
+ if userquery(prompt, enter_invalid) == 'No':
+ write_to_file = False
+
+ if write_to_file and file_to_write_to:
+ for root in roots:
+ settings = self._frozen_config.roots[root].settings
+ abs_user_config = os.path.join(
+ settings["PORTAGE_CONFIGROOT"], USER_CONFIG_PATH)
+ ensure_dirs(abs_user_config)
+
+ if root in unstable_keyword_msg:
+ write_changes(root, unstable_keyword_msg[root],
+ file_to_write_to.get((abs_user_config, "package.keywords")))
+
+ if root in p_mask_change_msg:
+ write_changes(root, p_mask_change_msg[root],
+ file_to_write_to.get((abs_user_config, "package.unmask")))
+
+ if root in use_changes_msg:
+ write_changes(root, use_changes_msg[root],
+ file_to_write_to.get((abs_user_config, "package.use")))
+
+ if root in license_msg:
+ write_changes(root, license_msg[root],
+ file_to_write_to.get((abs_user_config, "package.license")))
+
+ if problems:
+ writemsg_stdout("\nThe following problems occurred while writing autounmask changes:\n", \
+ noiselevel=-1)
+ writemsg_stdout("".join(problems), noiselevel=-1)
+ elif write_to_file and roots:
+ writemsg_stdout("\nAutounmask changes successfully written. Remember to run etc-update.\n", \
+ noiselevel=-1)
+ elif not pretend and not autounmask_write and roots:
+ writemsg_stdout("\nUse --autounmask-write to write changes to config files (honoring CONFIG_PROTECT).\n", \
+ noiselevel=-1)
+
+
+ def display_problems(self):
+ """
+ Display problems with the dependency graph such as slot collisions.
+ This is called internally by display() to show the problems _after_
+ the merge list where it is most likely to be seen, but if display()
+ is not going to be called then this method should be called explicitly
+ to ensure that the user is notified of problems with the graph.
+
+ All output goes to stderr, except for unsatisfied dependencies which
+ go to stdout for parsing by programs such as autounmask.
+ """
+
+ # Note that show_masked_packages() sends its output to
+ # stdout, and some programs such as autounmask parse the
+ # output in cases when emerge bails out. However, when
+ # show_masked_packages() is called for installed packages
+ # here, the message is a warning that is more appropriate
+ # to send to stderr, so temporarily redirect stdout to
+ # stderr. TODO: Fix output code so there's a cleaner way
+ # to redirect everything to stderr.
+ sys.stdout.flush()
+ sys.stderr.flush()
+ stdout = sys.stdout
+ try:
+ sys.stdout = sys.stderr
+ self._display_problems()
+ finally:
+ sys.stdout = stdout
+ sys.stdout.flush()
+ sys.stderr.flush()
+
+ # This goes to stdout for parsing by programs like autounmask.
+ for pargs, kwargs in self._dynamic_config._unsatisfied_deps_for_display:
+ self._show_unsatisfied_dep(*pargs, **kwargs)
+
+ def _display_problems(self):
+ if self._dynamic_config._circular_deps_for_display is not None:
+ self._show_circular_deps(
+ self._dynamic_config._circular_deps_for_display)
+
+ # The user is only notified of a slot conflict if
+ # there are no unresolvable blocker conflicts.
+ if self._dynamic_config._unsatisfied_blockers_for_display is not None:
+ self._show_unsatisfied_blockers(
+ self._dynamic_config._unsatisfied_blockers_for_display)
+ elif self._dynamic_config._slot_collision_info:
+ self._show_slot_collision_notice()
+ else:
+ self._show_missed_update()
+
+ self._display_autounmask()
+
+ # TODO: Add generic support for "set problem" handlers so that
+ # the below warnings aren't special cases for world only.
+
+ if self._dynamic_config._missing_args:
+ world_problems = False
+ if "world" in self._dynamic_config.sets[
+ self._frozen_config.target_root].sets:
+ # Filter out indirect members of world (from nested sets)
+ # since only direct members of world are desired here.
+ world_set = self._frozen_config.roots[self._frozen_config.target_root].sets["selected"]
+ for arg, atom in self._dynamic_config._missing_args:
+ if arg.name in ("selected", "world") and atom in world_set:
+ world_problems = True
+ break
+
+ if world_problems:
+ sys.stderr.write("\n!!! Problems have been " + \
+ "detected with your world file\n")
+ sys.stderr.write("!!! Please run " + \
+ green("emaint --check world")+"\n\n")
+
+ if self._dynamic_config._missing_args:
+ sys.stderr.write("\n" + colorize("BAD", "!!!") + \
+ " Ebuilds for the following packages are either all\n")
+ sys.stderr.write(colorize("BAD", "!!!") + \
+ " masked or don't exist:\n")
+ sys.stderr.write(" ".join(str(atom) for arg, atom in \
+ self._dynamic_config._missing_args) + "\n")
+
+ if self._dynamic_config._pprovided_args:
+ arg_refs = {}
+ for arg, atom in self._dynamic_config._pprovided_args:
+ if isinstance(arg, SetArg):
+ parent = arg.name
+ arg_atom = (atom, atom)
+ else:
+ parent = "args"
+ arg_atom = (arg.arg, atom)
+ refs = arg_refs.setdefault(arg_atom, [])
+ if parent not in refs:
+ refs.append(parent)
+ msg = []
+ msg.append(bad("\nWARNING: "))
+ if len(self._dynamic_config._pprovided_args) > 1:
+ msg.append("Requested packages will not be " + \
+ "merged because they are listed in\n")
+ else:
+ msg.append("A requested package will not be " + \
+ "merged because it is listed in\n")
+ msg.append("package.provided:\n\n")
+ problems_sets = set()
+ for (arg, atom), refs in arg_refs.items():
+ ref_string = ""
+ if refs:
+ problems_sets.update(refs)
+ refs.sort()
+ ref_string = ", ".join(["'%s'" % name for name in refs])
+ ref_string = " pulled in by " + ref_string
+ msg.append(" %s%s\n" % (colorize("INFORM", str(arg)), ref_string))
+ msg.append("\n")
+ if "selected" in problems_sets or "world" in problems_sets:
+ msg.append("This problem can be solved in one of the following ways:\n\n")
+ msg.append(" A) Use emaint to clean offending packages from world (if not installed).\n")
+ msg.append(" B) Uninstall offending packages (cleans them from world).\n")
+ msg.append(" C) Remove offending entries from package.provided.\n\n")
+ msg.append("The best course of action depends on the reason that an offending\n")
+ msg.append("package.provided entry exists.\n\n")
+ sys.stderr.write("".join(msg))
+
+ masked_packages = []
+ for pkg in self._dynamic_config._masked_license_updates:
+ root_config = pkg.root_config
+ pkgsettings = self._frozen_config.pkgsettings[pkg.root]
+ mreasons = get_masking_status(pkg, pkgsettings, root_config, use=self._pkg_use_enabled(pkg))
+ masked_packages.append((root_config, pkgsettings,
+ pkg.cpv, pkg.repo, pkg.metadata, mreasons))
+ if masked_packages:
+ writemsg("\n" + colorize("BAD", "!!!") + \
+ " The following updates are masked by LICENSE changes:\n",
+ noiselevel=-1)
+ show_masked_packages(masked_packages)
+ show_mask_docs()
+ writemsg("\n", noiselevel=-1)
+
+ masked_packages = []
+ for pkg in self._dynamic_config._masked_installed:
+ root_config = pkg.root_config
+ pkgsettings = self._frozen_config.pkgsettings[pkg.root]
+ mreasons = get_masking_status(pkg, pkgsettings, root_config, use=self._pkg_use_enabled)
+ masked_packages.append((root_config, pkgsettings,
+ pkg.cpv, pkg.repo, pkg.metadata, mreasons))
+ if masked_packages:
+ writemsg("\n" + colorize("BAD", "!!!") + \
+ " The following installed packages are masked:\n",
+ noiselevel=-1)
+ show_masked_packages(masked_packages)
+ show_mask_docs()
+ writemsg("\n", noiselevel=-1)
+
+ def saveNomergeFavorites(self):
+ """Find atoms in favorites that are not in the mergelist and add them
+ to the world file if necessary."""
+ for x in ("--buildpkgonly", "--fetchonly", "--fetch-all-uri",
+ "--oneshot", "--onlydeps", "--pretend"):
+ if x in self._frozen_config.myopts:
+ return
+ root_config = self._frozen_config.roots[self._frozen_config.target_root]
+ world_set = root_config.sets["selected"]
+
+ world_locked = False
+ if hasattr(world_set, "lock"):
+ world_set.lock()
+ world_locked = True
+
+ if hasattr(world_set, "load"):
+ world_set.load() # maybe it's changed on disk
+
+ args_set = self._dynamic_config.sets[
+ self._frozen_config.target_root].sets['__non_set_args__']
+ portdb = self._frozen_config.trees[self._frozen_config.target_root]["porttree"].dbapi
+ added_favorites = set()
+ for x in self._dynamic_config._set_nodes:
+ if x.operation != "nomerge":
+ continue
+
+ if x.root != root_config.root:
+ continue
+
+ try:
+ myfavkey = create_world_atom(x, args_set, root_config)
+ if myfavkey:
+ if myfavkey in added_favorites:
+ continue
+ added_favorites.add(myfavkey)
+ except portage.exception.InvalidDependString as e:
+ writemsg("\n\n!!! '%s' has invalid PROVIDE: %s\n" % \
+ (x.cpv, e), noiselevel=-1)
+ writemsg("!!! see '%s'\n\n" % os.path.join(
+ x.root, portage.VDB_PATH, x.cpv, "PROVIDE"), noiselevel=-1)
+ del e
+ all_added = []
+ for arg in self._dynamic_config._initial_arg_list:
+ if not isinstance(arg, SetArg):
+ continue
+ if arg.root_config.root != root_config.root:
+ continue
+ k = arg.name
+ if k in ("selected", "world") or \
+ not root_config.sets[k].world_candidate:
+ continue
+ s = SETPREFIX + k
+ if s in world_set:
+ continue
+ all_added.append(SETPREFIX + k)
+ all_added.extend(added_favorites)
+ all_added.sort()
+ for a in all_added:
+ writemsg(">>> Recording %s in \"world\" favorites file...\n" % \
+ colorize("INFORM", str(a)), noiselevel=-1)
+ if all_added:
+ world_set.update(all_added)
+
+ if world_locked:
+ world_set.unlock()
+
+ def _loadResumeCommand(self, resume_data, skip_masked=True,
+ skip_missing=True):
+ """
+ Add a resume command to the graph and validate it in the process. This
+ will raise a PackageNotFound exception if a package is not available.
+ """
+
+ self._load_vdb()
+
+ if not isinstance(resume_data, dict):
+ return False
+
+ mergelist = resume_data.get("mergelist")
+ if not isinstance(mergelist, list):
+ mergelist = []
+
+ favorites = resume_data.get("favorites")
+ args_set = self._dynamic_config.sets[
+ self._frozen_config.target_root].sets['__non_set_args__']
+ if isinstance(favorites, list):
+ args = self._load_favorites(favorites)
+ else:
+ args = []
+
+ fakedb = self._dynamic_config.mydbapi
+ trees = self._frozen_config.trees
+ serialized_tasks = []
+ masked_tasks = []
+ for x in mergelist:
+ if not (isinstance(x, list) and len(x) == 4):
+ continue
+ pkg_type, myroot, pkg_key, action = x
+ if pkg_type not in self.pkg_tree_map:
+ continue
+ if action != "merge":
+ continue
+ root_config = self._frozen_config.roots[myroot]
+
+ # Use the resume "favorites" list to see if a repo was specified
+ # for this package.
+ depgraph_sets = self._dynamic_config.sets[root_config.root]
+ repo = None
+ for atom in depgraph_sets.atoms.getAtoms():
+ if atom.repo and portage.dep.match_from_list(atom, [pkg_key]):
+ repo = atom.repo
+ break
+
+ atom = "=" + pkg_key
+ if repo:
+ atom = atom + _repo_separator + repo
+
+ try:
+ atom = Atom(atom, allow_repo=True)
+ except InvalidAtom:
+ continue
+
+ pkg = None
+ for pkg in self._iter_match_pkgs(root_config, pkg_type, atom):
+ if not self._pkg_visibility_check(pkg) or \
+ self._frozen_config.excluded_pkgs.findAtomForPackage(pkg,
+ modified_use=self._pkg_use_enabled(pkg)):
+ continue
+ break
+
+ if pkg is None:
+ # It does no exist or it is corrupt.
+ if skip_missing:
+ # TODO: log these somewhere
+ continue
+ raise portage.exception.PackageNotFound(pkg_key)
+
+ if "merge" == pkg.operation and \
+ self._frozen_config.excluded_pkgs.findAtomForPackage(pkg, \
+ modified_use=self._pkg_use_enabled(pkg)):
+ continue
+
+ if "merge" == pkg.operation and not self._pkg_visibility_check(pkg):
+ if skip_masked:
+ masked_tasks.append(Dependency(root=pkg.root, parent=pkg))
+ else:
+ self._dynamic_config._unsatisfied_deps_for_display.append(
+ ((pkg.root, "="+pkg.cpv), {"myparent":None}))
+
+ fakedb[myroot].cpv_inject(pkg)
+ serialized_tasks.append(pkg)
+ self._spinner_update()
+
+ if self._dynamic_config._unsatisfied_deps_for_display:
+ return False
+
+ if not serialized_tasks or "--nodeps" in self._frozen_config.myopts:
+ self._dynamic_config._serialized_tasks_cache = serialized_tasks
+ self._dynamic_config._scheduler_graph = self._dynamic_config.digraph
+ else:
+ self._select_package = self._select_pkg_from_graph
+ self._dynamic_config.myparams["selective"] = True
+ # Always traverse deep dependencies in order to account for
+ # potentially unsatisfied dependencies of installed packages.
+ # This is necessary for correct --keep-going or --resume operation
+ # in case a package from a group of circularly dependent packages
+ # fails. In this case, a package which has recently been installed
+ # may have an unsatisfied circular dependency (pulled in by
+ # PDEPEND, for example). So, even though a package is already
+ # installed, it may not have all of it's dependencies satisfied, so
+ # it may not be usable. If such a package is in the subgraph of
+ # deep depenedencies of a scheduled build, that build needs to
+ # be cancelled. In order for this type of situation to be
+ # recognized, deep traversal of dependencies is required.
+ self._dynamic_config.myparams["deep"] = True
+
+ for task in serialized_tasks:
+ if isinstance(task, Package) and \
+ task.operation == "merge":
+ if not self._add_pkg(task, None):
+ return False
+
+ # Packages for argument atoms need to be explicitly
+ # added via _add_pkg() so that they are included in the
+ # digraph (needed at least for --tree display).
+ for arg in self._expand_set_args(args, add_to_digraph=True):
+ for atom in arg.pset.getAtoms():
+ pkg, existing_node = self._select_package(
+ arg.root_config.root, atom)
+ if existing_node is None and \
+ pkg is not None:
+ if not self._add_pkg(pkg, Dependency(atom=atom,
+ root=pkg.root, parent=arg)):
+ return False
+
+ # Allow unsatisfied deps here to avoid showing a masking
+ # message for an unsatisfied dep that isn't necessarily
+ # masked.
+ if not self._create_graph(allow_unsatisfied=True):
+ return False
+
+ unsatisfied_deps = []
+ for dep in self._dynamic_config._unsatisfied_deps:
+ if not isinstance(dep.parent, Package):
+ continue
+ if dep.parent.operation == "merge":
+ unsatisfied_deps.append(dep)
+ continue
+
+ # For unsatisfied deps of installed packages, only account for
+ # them if they are in the subgraph of dependencies of a package
+ # which is scheduled to be installed.
+ unsatisfied_install = False
+ traversed = set()
+ dep_stack = self._dynamic_config.digraph.parent_nodes(dep.parent)
+ while dep_stack:
+ node = dep_stack.pop()
+ if not isinstance(node, Package):
+ continue
+ if node.operation == "merge":
+ unsatisfied_install = True
+ break
+ if node in traversed:
+ continue
+ traversed.add(node)
+ dep_stack.extend(self._dynamic_config.digraph.parent_nodes(node))
+
+ if unsatisfied_install:
+ unsatisfied_deps.append(dep)
+
+ if masked_tasks or unsatisfied_deps:
+ # This probably means that a required package
+ # was dropped via --skipfirst. It makes the
+ # resume list invalid, so convert it to a
+ # UnsatisfiedResumeDep exception.
+ raise self.UnsatisfiedResumeDep(self,
+ masked_tasks + unsatisfied_deps)
+ self._dynamic_config._serialized_tasks_cache = None
+ try:
+ self.altlist()
+ except self._unknown_internal_error:
+ return False
+
+ return True
+
+ def _load_favorites(self, favorites):
+ """
+ Use a list of favorites to resume state from a
+ previous select_files() call. This creates similar
+ DependencyArg instances to those that would have
+ been created by the original select_files() call.
+ This allows Package instances to be matched with
+ DependencyArg instances during graph creation.
+ """
+ root_config = self._frozen_config.roots[self._frozen_config.target_root]
+ sets = root_config.sets
+ depgraph_sets = self._dynamic_config.sets[root_config.root]
+ args = []
+ for x in favorites:
+ if not isinstance(x, basestring):
+ continue
+ if x in ("system", "world"):
+ x = SETPREFIX + x
+ if x.startswith(SETPREFIX):
+ s = x[len(SETPREFIX):]
+ if s not in sets:
+ continue
+ if s in depgraph_sets.sets:
+ continue
+ pset = sets[s]
+ depgraph_sets.sets[s] = pset
+ args.append(SetArg(arg=x, pset=pset,
+ root_config=root_config))
+ else:
+ try:
+ x = Atom(x, allow_repo=True)
+ except portage.exception.InvalidAtom:
+ continue
+ args.append(AtomArg(arg=x, atom=x,
+ root_config=root_config))
+
+ self._set_args(args)
+ return args
+
+ class UnsatisfiedResumeDep(portage.exception.PortageException):
+ """
+ A dependency of a resume list is not installed. This
+ can occur when a required package is dropped from the
+ merge list via --skipfirst.
+ """
+ def __init__(self, depgraph, value):
+ portage.exception.PortageException.__init__(self, value)
+ self.depgraph = depgraph
+
+ class _internal_exception(portage.exception.PortageException):
+ def __init__(self, value=""):
+ portage.exception.PortageException.__init__(self, value)
+
+ class _unknown_internal_error(_internal_exception):
+ """
+ Used by the depgraph internally to terminate graph creation.
+ The specific reason for the failure should have been dumped
+ to stderr, unfortunately, the exact reason for the failure
+ may not be known.
+ """
+
+ class _serialize_tasks_retry(_internal_exception):
+ """
+ This is raised by the _serialize_tasks() method when it needs to
+ be called again for some reason. The only case that it's currently
+ used for is when neglected dependencies need to be added to the
+ graph in order to avoid making a potentially unsafe decision.
+ """
+
+ class _backtrack_mask(_internal_exception):
+ """
+ This is raised by _show_unsatisfied_dep() when it's called with
+ check_backtrack=True and a matching package has been masked by
+ backtracking.
+ """
+
+ class _autounmask_breakage(_internal_exception):
+ """
+ This is raised by _show_unsatisfied_dep() when it's called with
+ check_autounmask_breakage=True and a matching package has been
+ been disqualified due to autounmask changes.
+ """
+
+ def need_restart(self):
+ return self._dynamic_config._need_restart and \
+ not self._dynamic_config._skip_restart
+
+ def success_without_autounmask(self):
+ return self._dynamic_config._success_without_autounmask
+
+ def autounmask_breakage_detected(self):
+ try:
+ for pargs, kwargs in self._dynamic_config._unsatisfied_deps_for_display:
+ self._show_unsatisfied_dep(
+ *pargs, check_autounmask_breakage=True, **kwargs)
+ except self._autounmask_breakage:
+ return True
+ return False
+
+ def get_backtrack_infos(self):
+ return self._dynamic_config._backtrack_infos
+
+
+class _dep_check_composite_db(dbapi):
+ """
+ A dbapi-like interface that is optimized for use in dep_check() calls.
+ This is built on top of the existing depgraph package selection logic.
+ Some packages that have been added to the graph may be masked from this
+ view in order to influence the atom preference selection that occurs
+ via dep_check().
+ """
+ def __init__(self, depgraph, root):
+ dbapi.__init__(self)
+ self._depgraph = depgraph
+ self._root = root
+ self._match_cache = {}
+ self._cpv_pkg_map = {}
+
+ def _clear_cache(self):
+ self._match_cache.clear()
+ self._cpv_pkg_map.clear()
+
+ def cp_list(self, cp):
+ """
+ Emulate cp_list just so it can be used to check for existence
+ of new-style virtuals. Since it's a waste of time to return
+ more than one cpv for this use case, a maximum of one cpv will
+ be returned.
+ """
+ if isinstance(cp, Atom):
+ atom = cp
+ else:
+ atom = Atom(cp)
+ ret = []
+ for pkg in self._depgraph._iter_match_pkgs_any(
+ self._depgraph._frozen_config.roots[self._root], atom):
+ if pkg.cp == cp:
+ ret.append(pkg.cpv)
+ break
+
+ return ret
+
+ def match(self, atom):
+ ret = self._match_cache.get(atom)
+ if ret is not None:
+ return ret[:]
+ pkg, existing = self._depgraph._select_package(self._root, atom)
+ if not pkg:
+ ret = []
+ else:
+ # Return the highest available from select_package() as well as
+ # any matching slots in the graph db.
+ slots = set()
+ slots.add(pkg.metadata["SLOT"])
+ if pkg.cp.startswith("virtual/"):
+ # For new-style virtual lookahead that occurs inside
+ # dep_check(), examine all slots. This is needed
+ # so that newer slots will not unnecessarily be pulled in
+ # when a satisfying lower slot is already installed. For
+ # example, if virtual/jdk-1.4 is satisfied via kaffe then
+ # there's no need to pull in a newer slot to satisfy a
+ # virtual/jdk dependency.
+ for db, pkg_type, built, installed, db_keys in \
+ self._depgraph._dynamic_config._filtered_trees[self._root]["dbs"]:
+ for cpv in db.match(atom):
+ if portage.cpv_getkey(cpv) != pkg.cp:
+ continue
+ slots.add(db.aux_get(cpv, ["SLOT"])[0])
+ ret = []
+ if self._visible(pkg):
+ self._cpv_pkg_map[pkg.cpv] = pkg
+ ret.append(pkg.cpv)
+ slots.remove(pkg.metadata["SLOT"])
+ while slots:
+ slot_atom = Atom("%s:%s" % (atom.cp, slots.pop()))
+ pkg, existing = self._depgraph._select_package(
+ self._root, slot_atom)
+ if not pkg:
+ continue
+ if not self._visible(pkg):
+ continue
+ self._cpv_pkg_map[pkg.cpv] = pkg
+ ret.append(pkg.cpv)
+ if ret:
+ self._cpv_sort_ascending(ret)
+ self._match_cache[atom] = ret
+ return ret[:]
+
+ def _visible(self, pkg):
+ if pkg.installed and "selective" not in self._depgraph._dynamic_config.myparams:
+ try:
+ arg = next(self._depgraph._iter_atoms_for_pkg(pkg))
+ except (StopIteration, portage.exception.InvalidDependString):
+ arg = None
+ if arg:
+ return False
+ if pkg.installed and \
+ (pkg.masks or not self._depgraph._pkg_visibility_check(pkg)):
+ # Account for packages with masks (like KEYWORDS masks)
+ # that are usually ignored in visibility checks for
+ # installed packages, in order to handle cases like
+ # bug #350285.
+ myopts = self._depgraph._frozen_config.myopts
+ use_ebuild_visibility = myopts.get(
+ '--use-ebuild-visibility', 'n') != 'n'
+ avoid_update = "--update" not in myopts and \
+ "remove" not in self._depgraph._dynamic_config.myparams
+ usepkgonly = "--usepkgonly" in myopts
+ if not avoid_update:
+ if not use_ebuild_visibility and usepkgonly:
+ return False
+ else:
+ try:
+ pkg_eb = self._depgraph._pkg(
+ pkg.cpv, "ebuild", pkg.root_config,
+ myrepo=pkg.repo)
+ except portage.exception.PackageNotFound:
+ pkg_eb_visible = False
+ for pkg_eb in self._depgraph._iter_match_pkgs(
+ pkg.root_config, "ebuild",
+ Atom("=%s" % (pkg.cpv,))):
+ if self._depgraph._pkg_visibility_check(pkg_eb):
+ pkg_eb_visible = True
+ break
+ if not pkg_eb_visible:
+ return False
+ else:
+ if not self._depgraph._pkg_visibility_check(pkg_eb):
+ return False
+
+ in_graph = self._depgraph._dynamic_config._slot_pkg_map[
+ self._root].get(pkg.slot_atom)
+ if in_graph is None:
+ # Mask choices for packages which are not the highest visible
+ # version within their slot (since they usually trigger slot
+ # conflicts).
+ highest_visible, in_graph = self._depgraph._select_package(
+ self._root, pkg.slot_atom)
+ # Note: highest_visible is not necessarily the real highest
+ # visible, especially when --update is not enabled, so use
+ # < operator instead of !=.
+ if pkg < highest_visible:
+ return False
+ elif in_graph != pkg:
+ # Mask choices for packages that would trigger a slot
+ # conflict with a previously selected package.
+ return False
+ return True
+
+ def aux_get(self, cpv, wants):
+ metadata = self._cpv_pkg_map[cpv].metadata
+ return [metadata.get(x, "") for x in wants]
+
+ def match_pkgs(self, atom):
+ return [self._cpv_pkg_map[cpv] for cpv in self.match(atom)]
+
+def ambiguous_package_name(arg, atoms, root_config, spinner, myopts):
+
+ if "--quiet" in myopts:
+ writemsg("!!! The short ebuild name \"%s\" is ambiguous. Please specify\n" % arg, noiselevel=-1)
+ writemsg("!!! one of the following fully-qualified ebuild names instead:\n\n", noiselevel=-1)
+ for cp in sorted(set(portage.dep_getkey(atom) for atom in atoms)):
+ writemsg(" " + colorize("INFORM", cp) + "\n", noiselevel=-1)
+ return
+
+ s = search(root_config, spinner, "--searchdesc" in myopts,
+ "--quiet" not in myopts, "--usepkg" in myopts,
+ "--usepkgonly" in myopts)
+ null_cp = portage.dep_getkey(insert_category_into_atom(
+ arg, "null"))
+ cat, atom_pn = portage.catsplit(null_cp)
+ s.searchkey = atom_pn
+ for cp in sorted(set(portage.dep_getkey(atom) for atom in atoms)):
+ s.addCP(cp)
+ s.output()
+ writemsg("!!! The short ebuild name \"%s\" is ambiguous. Please specify\n" % arg, noiselevel=-1)
+ writemsg("!!! one of the above fully-qualified ebuild names instead.\n\n", noiselevel=-1)
+
+def _spinner_start(spinner, myopts):
+ if spinner is None:
+ return
+ if "--quiet" not in myopts and \
+ ("--pretend" in myopts or "--ask" in myopts or \
+ "--tree" in myopts or "--verbose" in myopts):
+ action = ""
+ if "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
+ action = "fetched"
+ elif "--buildpkgonly" in myopts:
+ action = "built"
+ else:
+ action = "merged"
+ if "--tree" in myopts and action != "fetched": # Tree doesn't work with fetching
+ if "--unordered-display" in myopts:
+ portage.writemsg_stdout("\n" + \
+ darkgreen("These are the packages that " + \
+ "would be %s:" % action) + "\n\n")
+ else:
+ portage.writemsg_stdout("\n" + \
+ darkgreen("These are the packages that " + \
+ "would be %s, in reverse order:" % action) + "\n\n")
+ else:
+ portage.writemsg_stdout("\n" + \
+ darkgreen("These are the packages that " + \
+ "would be %s, in order:" % action) + "\n\n")
+
+ show_spinner = "--quiet" not in myopts and "--nodeps" not in myopts
+ if not show_spinner:
+ spinner.update = spinner.update_quiet
+
+ if show_spinner:
+ portage.writemsg_stdout("Calculating dependencies ")
+
+def _spinner_stop(spinner):
+ if spinner is None or \
+ spinner.update == spinner.update_quiet:
+ return
+
+ if spinner.update != spinner.update_basic:
+ # update_basic is used for non-tty output,
+ # so don't output backspaces in that case.
+ portage.writemsg_stdout("\b\b")
+
+ portage.writemsg_stdout("... done!\n")
+
+def backtrack_depgraph(settings, trees, myopts, myparams,
+ myaction, myfiles, spinner):
+ """
+ Raises PackageSetNotFound if myfiles contains a missing package set.
+ """
+ _spinner_start(spinner, myopts)
+ try:
+ return _backtrack_depgraph(settings, trees, myopts, myparams,
+ myaction, myfiles, spinner)
+ finally:
+ _spinner_stop(spinner)
+
+
+def _backtrack_depgraph(settings, trees, myopts, myparams, myaction, myfiles, spinner):
+
+ debug = "--debug" in myopts
+ mydepgraph = None
+ max_retries = myopts.get('--backtrack', 10)
+ max_depth = max(1, (max_retries + 1) / 2)
+ allow_backtracking = max_retries > 0
+ backtracker = Backtracker(max_depth)
+ backtracked = 0
+
+ frozen_config = _frozen_depgraph_config(settings, trees,
+ myopts, spinner)
+
+ while backtracker:
+
+ if debug and mydepgraph is not None:
+ writemsg_level(
+ "\n\nbacktracking try %s \n\n" % \
+ backtracked, noiselevel=-1, level=logging.DEBUG)
+ mydepgraph.display_problems()
+
+ backtrack_parameters = backtracker.get()
+
+ mydepgraph = depgraph(settings, trees, myopts, myparams, spinner,
+ frozen_config=frozen_config,
+ allow_backtracking=allow_backtracking,
+ backtrack_parameters=backtrack_parameters)
+ success, favorites = mydepgraph.select_files(myfiles)
+
+ if success or mydepgraph.success_without_autounmask():
+ break
+ elif not allow_backtracking:
+ break
+ elif backtracked >= max_retries:
+ break
+ elif mydepgraph.need_restart():
+ backtracked += 1
+ backtracker.feedback(mydepgraph.get_backtrack_infos())
+ else:
+ break
+
+ if not (success or mydepgraph.success_without_autounmask()) and backtracked:
+
+ if debug:
+ writemsg_level(
+ "\n\nbacktracking aborted after %s tries\n\n" % \
+ backtracked, noiselevel=-1, level=logging.DEBUG)
+ mydepgraph.display_problems()
+
+ mydepgraph = depgraph(settings, trees, myopts, myparams, spinner,
+ frozen_config=frozen_config,
+ allow_backtracking=False,
+ backtrack_parameters=backtracker.get_best_run())
+ success, favorites = mydepgraph.select_files(myfiles)
+
+ if not success and mydepgraph.autounmask_breakage_detected():
+ if debug:
+ writemsg_level(
+ "\n\nautounmask breakage detected\n\n",
+ noiselevel=-1, level=logging.DEBUG)
+ mydepgraph.display_problems()
+ myopts["--autounmask"] = "n"
+ mydepgraph = depgraph(settings, trees, myopts, myparams, spinner,
+ frozen_config=frozen_config, allow_backtracking=False)
+ success, favorites = mydepgraph.select_files(myfiles)
+
+ return (success, mydepgraph, favorites)
+
+
+def resume_depgraph(settings, trees, mtimedb, myopts, myparams, spinner):
+ """
+ Raises PackageSetNotFound if myfiles contains a missing package set.
+ """
+ _spinner_start(spinner, myopts)
+ try:
+ return _resume_depgraph(settings, trees, mtimedb, myopts,
+ myparams, spinner)
+ finally:
+ _spinner_stop(spinner)
+
+def _resume_depgraph(settings, trees, mtimedb, myopts, myparams, spinner):
+ """
+ Construct a depgraph for the given resume list. This will raise
+ PackageNotFound or depgraph.UnsatisfiedResumeDep when necessary.
+ TODO: Return reasons for dropped_tasks, for display/logging.
+ @rtype: tuple
+ @returns: (success, depgraph, dropped_tasks)
+ """
+ skip_masked = True
+ skip_unsatisfied = True
+ mergelist = mtimedb["resume"]["mergelist"]
+ dropped_tasks = set()
+ frozen_config = _frozen_depgraph_config(settings, trees,
+ myopts, spinner)
+ while True:
+ mydepgraph = depgraph(settings, trees,
+ myopts, myparams, spinner, frozen_config=frozen_config)
+ try:
+ success = mydepgraph._loadResumeCommand(mtimedb["resume"],
+ skip_masked=skip_masked)
+ except depgraph.UnsatisfiedResumeDep as e:
+ if not skip_unsatisfied:
+ raise
+
+ graph = mydepgraph._dynamic_config.digraph
+ unsatisfied_parents = dict((dep.parent, dep.parent) \
+ for dep in e.value)
+ traversed_nodes = set()
+ unsatisfied_stack = list(unsatisfied_parents)
+ while unsatisfied_stack:
+ pkg = unsatisfied_stack.pop()
+ if pkg in traversed_nodes:
+ continue
+ traversed_nodes.add(pkg)
+
+ # If this package was pulled in by a parent
+ # package scheduled for merge, removing this
+ # package may cause the the parent package's
+ # dependency to become unsatisfied.
+ for parent_node in graph.parent_nodes(pkg):
+ if not isinstance(parent_node, Package) \
+ or parent_node.operation not in ("merge", "nomerge"):
+ continue
+ unsatisfied = \
+ graph.child_nodes(parent_node,
+ ignore_priority=DepPrioritySatisfiedRange.ignore_soft)
+ if pkg in unsatisfied:
+ unsatisfied_parents[parent_node] = parent_node
+ unsatisfied_stack.append(parent_node)
+
+ unsatisfied_tuples = frozenset(tuple(parent_node)
+ for parent_node in unsatisfied_parents
+ if isinstance(parent_node, Package))
+ pruned_mergelist = []
+ for x in mergelist:
+ if isinstance(x, list) and \
+ tuple(x) not in unsatisfied_tuples:
+ pruned_mergelist.append(x)
+
+ # If the mergelist doesn't shrink then this loop is infinite.
+ if len(pruned_mergelist) == len(mergelist):
+ # This happens if a package can't be dropped because
+ # it's already installed, but it has unsatisfied PDEPEND.
+ raise
+ mergelist[:] = pruned_mergelist
+
+ # Exclude installed packages that have been removed from the graph due
+ # to failure to build/install runtime dependencies after the dependent
+ # package has already been installed.
+ dropped_tasks.update(pkg for pkg in \
+ unsatisfied_parents if pkg.operation != "nomerge")
+
+ del e, graph, traversed_nodes, \
+ unsatisfied_parents, unsatisfied_stack
+ continue
+ else:
+ break
+ return (success, mydepgraph, dropped_tasks)
+
+def get_mask_info(root_config, cpv, pkgsettings,
+ db, pkg_type, built, installed, db_keys, myrepo = None, _pkg_use_enabled=None):
+ eapi_masked = False
+ try:
+ metadata = dict(zip(db_keys,
+ db.aux_get(cpv, db_keys, myrepo=myrepo)))
+ except KeyError:
+ metadata = None
+
+ if metadata is None:
+ mreasons = ["corruption"]
+ else:
+ eapi = metadata['EAPI']
+ if eapi[:1] == '-':
+ eapi = eapi[1:]
+ if not portage.eapi_is_supported(eapi):
+ mreasons = ['EAPI %s' % eapi]
+ else:
+ pkg = Package(type_name=pkg_type, root_config=root_config,
+ cpv=cpv, built=built, installed=installed, metadata=metadata)
+
+ modified_use = None
+ if _pkg_use_enabled is not None:
+ modified_use = _pkg_use_enabled(pkg)
+
+ mreasons = get_masking_status(pkg, pkgsettings, root_config, myrepo=myrepo, use=modified_use)
+
+ return metadata, mreasons
+
+def show_masked_packages(masked_packages):
+ shown_licenses = set()
+ shown_comments = set()
+ # Maybe there is both an ebuild and a binary. Only
+ # show one of them to avoid redundant appearance.
+ shown_cpvs = set()
+ have_eapi_mask = False
+ for (root_config, pkgsettings, cpv, repo,
+ metadata, mreasons) in masked_packages:
+ output_cpv = cpv
+ if repo:
+ output_cpv += _repo_separator + repo
+ if output_cpv in shown_cpvs:
+ continue
+ shown_cpvs.add(output_cpv)
+ eapi_masked = metadata is not None and \
+ not portage.eapi_is_supported(metadata["EAPI"])
+ if eapi_masked:
+ have_eapi_mask = True
+ # When masked by EAPI, metadata is mostly useless since
+ # it doesn't contain essential things like SLOT.
+ metadata = None
+ comment, filename = None, None
+ if not eapi_masked and \
+ "package.mask" in mreasons:
+ comment, filename = \
+ portage.getmaskingreason(
+ cpv, metadata=metadata,
+ settings=pkgsettings,
+ portdb=root_config.trees["porttree"].dbapi,
+ return_location=True)
+ missing_licenses = []
+ if not eapi_masked and metadata is not None:
+ try:
+ missing_licenses = \
+ pkgsettings._getMissingLicenses(
+ cpv, metadata)
+ except portage.exception.InvalidDependString:
+ # This will have already been reported
+ # above via mreasons.
+ pass
+
+ writemsg_stdout("- "+output_cpv+" (masked by: "+", ".join(mreasons)+")\n", noiselevel=-1)
+
+ if comment and comment not in shown_comments:
+ writemsg_stdout(filename + ":\n" + comment + "\n",
+ noiselevel=-1)
+ shown_comments.add(comment)
+ portdb = root_config.trees["porttree"].dbapi
+ for l in missing_licenses:
+ l_path = portdb.findLicensePath(l)
+ if l in shown_licenses:
+ continue
+ msg = ("A copy of the '%s' license" + \
+ " is located at '%s'.\n\n") % (l, l_path)
+ writemsg_stdout(msg, noiselevel=-1)
+ shown_licenses.add(l)
+ return have_eapi_mask
+
+def show_mask_docs():
+ writemsg_stdout("For more information, see the MASKED PACKAGES section in the emerge\n", noiselevel=-1)
+ writemsg_stdout("man page or refer to the Gentoo Handbook.\n", noiselevel=-1)
+
+def show_blocker_docs_link():
+ writemsg("\nFor more information about " + bad("Blocked Packages") + ", please refer to the following\n", noiselevel=-1)
+ writemsg("section of the Gentoo Linux x86 Handbook (architecture is irrelevant):\n\n", noiselevel=-1)
+ writemsg("http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?full=1#blocked\n\n", noiselevel=-1)
+
+def get_masking_status(pkg, pkgsettings, root_config, myrepo=None, use=None):
+ return [mreason.message for \
+ mreason in _get_masking_status(pkg, pkgsettings, root_config, myrepo=myrepo, use=use)]
+
+def _get_masking_status(pkg, pkgsettings, root_config, myrepo=None, use=None):
+ mreasons = _getmaskingstatus(
+ pkg, settings=pkgsettings,
+ portdb=root_config.trees["porttree"].dbapi, myrepo=myrepo)
+
+ if not pkg.installed:
+ if not pkgsettings._accept_chost(pkg.cpv, pkg.metadata):
+ mreasons.append(_MaskReason("CHOST", "CHOST: %s" % \
+ pkg.metadata["CHOST"]))
+
+ if pkg.invalid:
+ for msg_type, msgs in pkg.invalid.items():
+ for msg in msgs:
+ mreasons.append(
+ _MaskReason("invalid", "invalid: %s" % (msg,)))
+
+ if not pkg.metadata["SLOT"]:
+ mreasons.append(
+ _MaskReason("invalid", "SLOT: undefined"))
+
+ return mreasons
diff --git a/portage_with_autodep/pym/_emerge/emergelog.py b/portage_with_autodep/pym/_emerge/emergelog.py
new file mode 100644
index 0000000..d6ef1b4
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/emergelog.py
@@ -0,0 +1,63 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import io
+import sys
+import time
+import portage
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+from portage.data import secpass
+from portage.output import xtermTitle
+
+# We disable emergelog by default, since it's called from
+# dblink.merge() and we don't want that to trigger log writes
+# unless it's really called via emerge.
+_disable = True
+_emerge_log_dir = '/var/log'
+
+# Coerce to unicode, in order to prevent TypeError when writing
+# raw bytes to TextIOWrapper with python2.
+_log_fmt = _unicode_decode("%.0f: %s\n")
+
+def emergelog(xterm_titles, mystr, short_msg=None):
+
+ if _disable:
+ return
+
+ mystr = _unicode_decode(mystr)
+
+ if short_msg is not None:
+ short_msg = _unicode_decode(short_msg)
+
+ if xterm_titles and short_msg:
+ if "HOSTNAME" in os.environ:
+ short_msg = os.environ["HOSTNAME"]+": "+short_msg
+ xtermTitle(short_msg)
+ try:
+ file_path = os.path.join(_emerge_log_dir, 'emerge.log')
+ existing_log = os.path.isfile(file_path)
+ mylogfile = io.open(_unicode_encode(file_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='a', encoding=_encodings['content'],
+ errors='backslashreplace')
+ if not existing_log:
+ portage.util.apply_secpass_permissions(file_path,
+ uid=portage.portage_uid, gid=portage.portage_gid,
+ mode=0o660)
+ mylock = None
+ try:
+ mylock = portage.locks.lockfile(mylogfile)
+ mylogfile.write(_log_fmt % (time.time(), mystr))
+ mylogfile.flush()
+ finally:
+ if mylock:
+ portage.locks.unlockfile(mylock)
+ mylogfile.close()
+ except (IOError,OSError,portage.exception.PortageException) as e:
+ if secpass >= 1:
+ print("emergelog():",e, file=sys.stderr)
diff --git a/portage_with_autodep/pym/_emerge/getloadavg.py b/portage_with_autodep/pym/_emerge/getloadavg.py
new file mode 100644
index 0000000..e9babf1
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/getloadavg.py
@@ -0,0 +1,27 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+
+getloadavg = getattr(os, "getloadavg", None)
+if getloadavg is None:
+ def getloadavg():
+ """
+ Uses /proc/loadavg to emulate os.getloadavg().
+ Raises OSError if the load average was unobtainable.
+ """
+ try:
+ loadavg_str = open('/proc/loadavg').readline()
+ except IOError:
+ # getloadavg() is only supposed to raise OSError, so convert
+ raise OSError('unknown')
+ loadavg_split = loadavg_str.split()
+ if len(loadavg_split) < 3:
+ raise OSError('unknown')
+ loadavg_floats = []
+ for i in range(3):
+ try:
+ loadavg_floats.append(float(loadavg_split[i]))
+ except ValueError:
+ raise OSError('unknown')
+ return tuple(loadavg_floats)
diff --git a/portage_with_autodep/pym/_emerge/help.py b/portage_with_autodep/pym/_emerge/help.py
new file mode 100644
index 0000000..c978ce2
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/help.py
@@ -0,0 +1,815 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+from portage.const import _ENABLE_DYN_LINK_MAP
+from portage.output import bold, turquoise, green
+
+def shorthelp():
+ print(bold("emerge:")+" the other white meat (command-line interface to the Portage system)")
+ print(bold("Usage:"))
+ print(" "+turquoise("emerge")+" [ "+green("options")+" ] [ "+green("action")+" ] [ "+turquoise("ebuild")+" | "+turquoise("tbz2")+" | "+turquoise("file")+" | "+turquoise("@set")+" | "+turquoise("atom")+" ] [ ... ]")
+ print(" "+turquoise("emerge")+" [ "+green("options")+" ] [ "+green("action")+" ] < "+turquoise("system")+" | "+turquoise("world")+" >")
+ print(" "+turquoise("emerge")+" < "+turquoise("--sync")+" | "+turquoise("--metadata")+" | "+turquoise("--info")+" >")
+ print(" "+turquoise("emerge")+" "+turquoise("--resume")+" [ "+green("--pretend")+" | "+green("--ask")+" | "+green("--skipfirst")+" ]")
+ print(" "+turquoise("emerge")+" "+turquoise("--help")+" [ "+green("--verbose")+" ] ")
+ print(bold("Options:")+" "+green("-")+"["+green("abBcCdDefgGhjkKlnNoOpPqrsStuvV")+"]")
+ print(" [ " + green("--color")+" < " + turquoise("y") + " | "+ turquoise("n")+" > ] [ "+green("--columns")+" ]")
+ print(" [ "+green("--complete-graph")+" ] [ "+green("--deep")+" ]")
+ print(" [ "+green("--jobs") + " " + turquoise("JOBS")+" ] [ "+green("--keep-going")+" ] [ " + green("--load-average")+" " + turquoise("LOAD") + " ]")
+ print(" [ "+green("--newuse")+" ] [ "+green("--noconfmem")+" ] [ "+green("--nospinner")+" ]")
+ print(" [ "+green("--oneshot")+" ] [ "+green("--onlydeps")+" ]")
+ print(" [ "+green("--reinstall ")+turquoise("changed-use")+" ] [ " + green("--with-bdeps")+" < " + turquoise("y") + " | "+ turquoise("n")+" > ]")
+ print(bold("Actions:")+" [ "+green("--depclean")+" | "+green("--list-sets")+" | "+green("--search")+" | "+green("--sync")+" | "+green("--version")+" ]")
+
+def help(myopts, havecolor=1):
+ # TODO: Implement a wrap() that accounts for console color escape codes.
+ from textwrap import wrap
+ desc_left_margin = 14
+ desc_indent = desc_left_margin * " "
+ desc_width = 80 - desc_left_margin - 5
+ if "--verbose" not in myopts:
+ shorthelp()
+ print()
+ print(" For more help try 'emerge --help --verbose' or consult the man page.")
+ else:
+ shorthelp()
+ print()
+ print(turquoise("Help (this screen):"))
+ print(" "+green("--help")+" ("+green("-h")+" short option)")
+ print(" Displays this help; an additional argument (see above) will tell")
+ print(" emerge to display detailed help.")
+ print()
+ print(turquoise("Actions:"))
+ print(" "+green("--clean"))
+ print(" Cleans the system by removing outdated packages which will not")
+ print(" remove functionalities or prevent your system from working.")
+ print(" The arguments can be in several different formats :")
+ print(" * world ")
+ print(" * system or")
+ print(" * 'dependency specification' (in single quotes is best.)")
+ print(" Here are a few examples of the dependency specification format:")
+ print(" "+bold("binutils")+" matches")
+ print(" binutils-2.11.90.0.7 and binutils-2.11.92.0.12.3-r1")
+ print(" "+bold("sys-devel/binutils")+" matches")
+ print(" binutils-2.11.90.0.7 and binutils-2.11.92.0.12.3-r1")
+ print(" "+bold(">sys-devel/binutils-2.11.90.0.7")+" matches")
+ print(" binutils-2.11.92.0.12.3-r1")
+ print(" "+bold(">=sys-devel/binutils-2.11.90.0.7")+" matches")
+ print(" binutils-2.11.90.0.7 and binutils-2.11.92.0.12.3-r1")
+ print(" "+bold("<=sys-devel/binutils-2.11.92.0.12.3-r1")+" matches")
+ print(" binutils-2.11.90.0.7 and binutils-2.11.92.0.12.3-r1")
+ print()
+ print(" "+green("--config"))
+ print(" Runs package-specific operations that must be executed after an")
+ print(" emerge process has completed. This usually entails configuration")
+ print(" file setup or other similar setups that the user may wish to run.")
+ print()
+ print(" "+green("--depclean")+" ("+green("-c")+" short option)")
+
+ paragraph = "Cleans the system by removing packages that are " + \
+ "not associated with explicitly merged packages. Depclean works " + \
+ "by creating the full dependency tree from the " + \
+ "@world set, then comparing it to installed packages. Packages " + \
+ "installed, but not part of the dependency tree, will be " + \
+ "uninstalled by depclean. See --with-bdeps for behavior with " + \
+ "respect to build time dependencies that are not strictly " + \
+ "required. Packages that are part of the world set will " + \
+ "always be kept. They can be manually added to this set with " + \
+ "emerge --noreplace <atom>. As a safety measure, depclean " + \
+ "will not remove any packages unless *all* required dependencies " + \
+ "have been resolved. As a consequence, it is often necessary to " + \
+ "run emerge --update --newuse --deep @world " + \
+ "prior to depclean."
+
+ for line in wrap(paragraph, desc_width):
+ print(desc_indent + line)
+ print()
+
+ paragraph = "WARNING: Inexperienced users are advised to use " + \
+ "--pretend with this option in order to see a preview of which " + \
+ "packages will be uninstalled. Always study the list of packages " + \
+ "to be cleaned for any obvious mistakes. Note that packages " + \
+ "listed in package.provided (see portage(5)) may be removed by " + \
+ "depclean, even if they are part of the world set."
+
+ paragraph += " Also note that " + \
+ "depclean may break link level dependencies"
+
+ if _ENABLE_DYN_LINK_MAP:
+ paragraph += ", especially when the " + \
+ "--depclean-lib-check option is disabled"
+
+ paragraph += ". Thus, it is " + \
+ "recommended to use a tool such as revdep-rebuild(1) " + \
+ "in order to detect such breakage."
+
+ for line in wrap(paragraph, desc_width):
+ print(desc_indent + line)
+ print()
+
+ paragraph = "Depclean serves as a dependency aware version of " + \
+ "--unmerge. When given one or more atoms, it will unmerge " + \
+ "matched packages that have no reverse dependencies. Use " + \
+ "--depclean together with --verbose to show reverse dependencies."
+
+ for line in wrap(paragraph, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--deselect") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+
+ paragraph = \
+ "Remove atoms and/or sets from the world file. This action is implied " + \
+ "by uninstall actions, including --depclean, " + \
+ "--prune and --unmerge. Use --deselect=n " + \
+ "in order to prevent uninstall actions from removing " + \
+ "atoms from the world file."
+
+ for line in wrap(paragraph, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--ignore-default-opts"))
+
+ paragraph = \
+ "Causes EMERGE_DEFAULT_OPTS (see make.conf(5)) to be ignored."
+
+ for line in wrap(paragraph, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--info"))
+ print(" Displays important portage variables that will be exported to")
+ print(" ebuild.sh when performing merges. This information is useful")
+ print(" for bug reports and verification of settings. All settings in")
+ print(" make.{conf,globals,defaults} and the environment show up if")
+ print(" run with the '--verbose' flag.")
+ print()
+ print(" " + green("--list-sets"))
+ paragraph = "Displays a list of available package sets."
+
+ for line in wrap(paragraph, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--metadata"))
+ print(" Transfers metadata cache from ${PORTDIR}/metadata/cache/ to")
+ print(" /var/cache/edb/dep/ as is normally done on the tail end of an")
+ print(" rsync update using " + bold("emerge --sync") + ". This process populates the")
+ print(" cache database that portage uses for pre-parsed lookups of")
+ print(" package data. It does not populate cache for the overlays")
+ print(" listed in PORTDIR_OVERLAY. In order to generate cache for")
+ print(" overlays, use " + bold("--regen") + ".")
+ print()
+ print(" "+green("--prune")+" ("+green("-P")+" short option)")
+ print(" "+turquoise("WARNING: This action can remove important packages!"))
+ paragraph = "Removes all but the highest installed version of a " + \
+ "package from your system. Use --prune together with " + \
+ "--verbose to show reverse dependencies or with --nodeps " + \
+ "to ignore all dependencies. "
+
+ for line in wrap(paragraph, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--regen"))
+ print(" Causes portage to check and update the dependency cache of all")
+ print(" ebuilds in the portage tree. This is not recommended for rsync")
+ print(" users as rsync updates the cache using server-side caches.")
+ print(" Rsync users should simply 'emerge --sync' to regenerate.")
+ desc = "In order to specify parallel --regen behavior, use "+ \
+ "the ---jobs and --load-average options. If you would like to " + \
+ "generate and distribute cache for use by others, use egencache(1)."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--resume")+" ("+green("-r")+" short option)")
+ print(" Resumes the most recent merge list that has been aborted due to an")
+ print(" error. Please note that this operation will only return an error")
+ print(" on failure. If there is nothing for portage to do, then portage")
+ print(" will exit with a message and a success condition. A resume list")
+ print(" will persist until it has been completed in entirety or until")
+ print(" another aborted merge list replaces it. The resume history is")
+ print(" capable of storing two merge lists. After one resume list")
+ print(" completes, it is possible to invoke --resume once again in order")
+ print(" to resume an older list.")
+ print()
+ print(" "+green("--search")+" ("+green("-s")+" short option)")
+ print(" Searches for matches of the supplied string in the current local")
+ print(" portage tree. By default emerge uses a case-insensitive simple ")
+ print(" search, but you can enable a regular expression search by ")
+ print(" prefixing the search string with %.")
+ print(" Prepending the expression with a '@' will cause the category to")
+ print(" be included in the search.")
+ print(" A few examples:")
+ print(" "+bold("emerge --search libc"))
+ print(" list all packages that contain libc in their name")
+ print(" "+bold("emerge --search '%^kde'"))
+ print(" list all packages starting with kde")
+ print(" "+bold("emerge --search '%gcc$'"))
+ print(" list all packages ending with gcc")
+ print(" "+bold("emerge --search '%@^dev-java.*jdk'"))
+ print(" list all available Java JDKs")
+ print()
+ print(" "+green("--searchdesc")+" ("+green("-S")+" short option)")
+ print(" Matches the search string against the description field as well")
+ print(" the package's name. Take caution as the descriptions are also")
+ print(" matched as regular expressions.")
+ print(" emerge -S html")
+ print(" emerge -S applet")
+ print(" emerge -S 'perl.*module'")
+ print()
+ print(" "+green("--sync"))
+ desc = "This updates the portage tree that is located in the " + \
+ "directory that the PORTDIR variable refers to (default " + \
+ "location is /usr/portage). The SYNC variable specifies " + \
+ "the remote URI from which files will be synchronized. " + \
+ "The PORTAGE_SYNC_STALE variable configures " + \
+ "warnings that are shown when emerge --sync has not " + \
+ "been executed recently."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(desc_indent + turquoise("WARNING:"))
+ desc = "The emerge --sync action will modify and/or delete " + \
+ "files located inside the directory that the PORTDIR " + \
+ "variable refers to (default location is /usr/portage). " + \
+ "For more information, see the PORTDIR documentation in " + \
+ "the make.conf(5) man page."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(desc_indent + green("NOTE:"))
+ desc = "The emerge-webrsync program will download the entire " + \
+ "portage tree as a tarball, which is much faster than emerge " + \
+ "--sync for first time syncs."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--unmerge")+" ("+green("-C")+" short option)")
+ print(" "+turquoise("WARNING: This action can remove important packages!"))
+ print(" Removes all matching packages. This does no checking of")
+ print(" dependencies, so it may remove packages necessary for the proper")
+ print(" operation of your system. Its arguments can be atoms or")
+ print(" ebuilds. For a dependency aware version of --unmerge, use")
+ print(" --depclean or --prune.")
+ print()
+ print(" "+green("--version")+" ("+green("-V")+" short option)")
+ print(" Displays the currently installed version of portage along with")
+ print(" other information useful for quick reference on a system. See")
+ print(" "+bold("emerge info")+" for more advanced information.")
+ print()
+ print(turquoise("Options:"))
+ print(" "+green("--accept-properties=ACCEPT_PROPERTIES"))
+ desc = "This option temporarily overrides the ACCEPT_PROPERTIES " + \
+ "variable. The ACCEPT_PROPERTIES variable is incremental, " + \
+ "which means that the specified setting is appended to the " + \
+ "existing value from your configuration. The special -* " + \
+ "token can be used to discard the existing configuration " + \
+ "value and start fresh. See the MASKED PACKAGES section " + \
+ "and make.conf(5) for more information about " + \
+ "ACCEPT_PROPERTIES. A typical usage example for this option " + \
+ "would be to use --accept-properties=-interactive to " + \
+ "temporarily mask interactive packages. With default " + \
+ "configuration, this would result in an effective " + \
+ "ACCEPT_PROPERTIES value of \"* -interactive\"."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--alphabetical"))
+ print(" When displaying USE and other flag output, combines the enabled")
+ print(" and disabled flags into a single list and sorts it alphabetically.")
+ print(" With this option, output such as USE=\"dar -bar -foo\" will instead")
+ print(" be displayed as USE=\"-bar dar -foo\"")
+ print()
+ print(" " + green("--ask") + \
+ " [ %s | %s ] (%s short option)" % \
+ (turquoise("y"), turquoise("n"), green("-a")))
+ desc = "Before performing the action, display what will take place (server info for " + \
+ "--sync, --pretend output for merge, and so forth), then ask " + \
+ "whether to proceed with the action or abort. Using --ask is more " + \
+ "efficient than using --pretend and then executing the same command " + \
+ "without --pretend, as dependencies will only need to be calculated once. " + \
+ "WARNING: If the \"Enter\" key is pressed at the prompt (with no other input), " + \
+ "it is interpreted as acceptance of the first choice. Note that the input " + \
+ "buffer is not cleared prior to the prompt, so an accidental press of the " + \
+ "\"Enter\" key at any time prior to the prompt will be interpreted as a choice! " + \
+ "Use the --ask-enter-invalid option if you want a single \"Enter\" key " + \
+ "press to be interpreted as invalid input."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--ask-enter-invalid"))
+ desc = "When used together with the --ask option, " + \
+ "interpret a single \"Enter\" key press as " + \
+ "invalid input. This helps prevent accidental " + \
+ "acceptance of the first choice. This option is " + \
+ "intended to be set in the make.conf(5) " + \
+ "EMERGE_DEFAULT_OPTS variable."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--autounmask") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "Automatically unmask packages and generate package.use " + \
+ "settings as necessary to satisfy dependencies. This " + \
+ "option is enabled by default. If any configuration " + \
+ "changes are required, then they will be displayed " + \
+ "after the merge list and emerge will immediately " + \
+ "abort. If the displayed configuration changes are " + \
+ "satisfactory, you should copy and paste them into " + \
+ "the specified configuration file(s), or enable the " + \
+ "--autounmask-write option. The " + \
+ "EMERGE_DEFAULT_OPTS variable may be used to " + \
+ "disable this option by default in make.conf(5)."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--autounmask-write") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "If --autounmask is enabled, changes are written " + \
+ "to config files, respecting CONFIG_PROTECT and --ask."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--backtrack") + " " + turquoise("COUNT"))
+ desc = "Specifies an integer number of times to backtrack if " + \
+ "dependency calculation fails due to a conflict or an " + \
+ "unsatisfied dependency (default: '10')."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--binpkg-respect-use") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "Tells emerge to ignore binary packages if their use flags" + \
+ " don't match the current configuration. (default: 'n')"
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--buildpkg") + \
+ " [ %s | %s ] (%s short option)" % \
+ (turquoise("y"), turquoise("n"), green("-b")))
+ desc = "Tells emerge to build binary packages for all ebuilds processed in" + \
+ " addition to actually merging the packages. Useful for maintainers" + \
+ " or if you administrate multiple Gentoo Linux systems (build once," + \
+ " emerge tbz2s everywhere) as well as disaster recovery. The package" + \
+ " will be created in the" + \
+ " ${PKGDIR}/All directory. An alternative for already-merged" + \
+ " packages is to use quickpkg(1) which creates a tbz2 from the" + \
+ " live filesystem."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--buildpkgonly")+" ("+green("-B")+" short option)")
+ print(" Creates a binary package, but does not merge it to the")
+ print(" system. This has the restriction that unsatisfied dependencies")
+ print(" must not exist for the desired package as they cannot be used if")
+ print(" they do not exist on the system.")
+ print()
+ print(" " + green("--changed-use"))
+ desc = "This is an alias for --reinstall=changed-use."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--changelog")+" ("+green("-l")+" short option)")
+ print(" When pretending, also display the ChangeLog entries for packages")
+ print(" that will be upgraded.")
+ print()
+ print(" "+green("--color") + " < " + turquoise("y") + " | "+ turquoise("n")+" >")
+ print(" Enable or disable color output. This option will override NOCOLOR")
+ print(" (see make.conf(5)) and may also be used to force color output when")
+ print(" stdout is not a tty (by default, color is disabled unless stdout")
+ print(" is a tty).")
+ print()
+ print(" "+green("--columns"))
+ print(" Display the pretend output in a tabular form. Versions are")
+ print(" aligned vertically.")
+ print()
+ print(" "+green("--complete-graph") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "This causes emerge to consider the deep dependencies of all" + \
+ " packages from the world set. With this option enabled," + \
+ " emerge will bail out if it determines that the given operation will" + \
+ " break any dependencies of the packages that have been added to the" + \
+ " graph. Like the --deep option, the --complete-graph" + \
+ " option will significantly increase the time taken for dependency" + \
+ " calculations. Note that, unlike the --deep option, the" + \
+ " --complete-graph option does not cause any more packages to" + \
+ " be updated than would have otherwise " + \
+ "been updated with the option disabled. " + \
+ "Using --with-bdeps=y together with --complete-graph makes " + \
+ "the graph as complete as possible."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--config-root=DIR"))
+ desc = "Set the PORTAGE_CONFIGROOT environment variable " + \
+ "which is documented in the emerge(1) man page."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--debug")+" ("+green("-d")+" short option)")
+ print(" Tell emerge to run the ebuild command in --debug mode. In this")
+ print(" mode, the bash build environment will run with the -x option,")
+ print(" causing it to output verbose debug information print to stdout.")
+ print(" --debug is great for finding bash syntax errors as providing")
+ print(" very verbose information about the dependency and build process.")
+ print()
+ print(" "+green("--deep") + " " + turquoise("[DEPTH]") + \
+ " (" + green("-D") + " short option)")
+ print(" This flag forces emerge to consider the entire dependency tree of")
+ print(" packages, instead of checking only the immediate dependencies of")
+ print(" the packages. As an example, this catches updates in libraries")
+ print(" that are not directly listed in the dependencies of a package.")
+ print(" Also see --with-bdeps for behavior with respect to build time")
+ print(" dependencies that are not strictly required.")
+ print()
+
+ if _ENABLE_DYN_LINK_MAP:
+ print(" " + green("--depclean-lib-check") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "Account for library link-level dependencies during " + \
+ "--depclean and --prune actions. This " + \
+ "option is enabled by default. In some cases this can " + \
+ "be somewhat time-consuming. This option is ignored " + \
+ "when FEATURES=\"preserve-libs\" is enabled in " + \
+ "make.conf(5), since any libraries that have " + \
+ "consumers will simply be preserved."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+
+ print(" "+green("--emptytree")+" ("+green("-e")+" short option)")
+ desc = "Reinstalls target atoms and their entire deep " + \
+ "dependency tree, as though no packages are currently " + \
+ "installed. You should run this with --pretend " + \
+ "first to make sure the result is what you expect."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--exclude") + " " + turquoise("ATOMS"))
+ desc = "A space separated list of package names or slot atoms. " + \
+ "Emerge won't install any ebuild or binary package that " + \
+ "matches any of the given package atoms."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--fail-clean") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "Clean up temporary files after a build failure. This is " + \
+ "particularly useful if you have PORTAGE_TMPDIR on " + \
+ "tmpfs. If this option is enabled, you probably also want " + \
+ "to enable PORT_LOGDIR (see make.conf(5)) in " + \
+ "order to save the build log."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--fetchonly")+" ("+green("-f")+" short option)")
+ print(" Instead of doing any package building, just perform fetches for")
+ print(" all packages (main package as well as all dependencies.) When")
+ print(" used in combination with --pretend all the SRC_URIs will be")
+ print(" displayed multiple mirrors per line, one line per file.")
+ print()
+ print(" "+green("--fetch-all-uri")+" ("+green("-F")+" short option)")
+ print(" Same as --fetchonly except that all package files, including those")
+ print(" not required to build the package, will be processed.")
+ print()
+ print(" " + green("--getbinpkg") + \
+ " [ %s | %s ] (%s short option)" % \
+ (turquoise("y"), turquoise("n"), green("-g")))
+ print(" Using the server and location defined in PORTAGE_BINHOST, portage")
+ print(" will download the information from each binary file there and it")
+ print(" will use that information to help build the dependency list. This")
+ print(" option implies '-k'. (Use -gK for binary-only merging.)")
+ print()
+ print(" " + green("--getbinpkgonly") + \
+ " [ %s | %s ] (%s short option)" % \
+ (turquoise("y"), turquoise("n"), green("-G")))
+ print(" This option is identical to -g, as above, except it will not use")
+ print(" ANY information from the local machine. All binaries will be")
+ print(" downloaded from the remote server without consulting packages")
+ print(" existing in the packages directory.")
+ print()
+ print(" " + green("--jobs") + " " + turquoise("[JOBS]") + " ("+green("-j")+" short option)")
+ desc = "Specifies the number of packages " + \
+ "to build simultaneously. If this option is " + \
+ "given without an argument, emerge will not " + \
+ "limit the number of jobs that " + \
+ "can run simultaneously. Also see " + \
+ "the related --load-average option. " + \
+ "Note that interactive packages currently force a setting " + \
+ "of --jobs=1. This issue can be temporarily avoided " + \
+ "by specifying --accept-properties=-interactive."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--keep-going") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "Continue as much as possible after " + \
+ "an error. When an error occurs, " + \
+ "dependencies are recalculated for " + \
+ "remaining packages and any with " + \
+ "unsatisfied dependencies are " + \
+ "automatically dropped. Also see " + \
+ "the related --skipfirst option."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--load-average") + " " + turquoise("LOAD"))
+ desc = "Specifies that no new builds should " + \
+ "be started if there are other builds " + \
+ "running and the load average is at " + \
+ "least LOAD (a floating-point number). " + \
+ "This option is recommended for use " + \
+ "in combination with --jobs in " + \
+ "order to avoid excess load. See " + \
+ "make(1) for information about " + \
+ "analogous options that should be " + \
+ "configured via MAKEOPTS in " + \
+ "make.conf(5)."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--misspell-suggestions") + " < %s | %s >" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "Enable or disable misspell suggestions. By default, " + \
+ "emerge will show a list of packages with similar names " + \
+ "when a package doesn't exist. The EMERGE_DEFAULT_OPTS " + \
+ "variable may be used to disable this option by default"
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--newuse")+" ("+green("-N")+" short option)")
+ desc = "Tells emerge to include installed packages where USE " + \
+ "flags have changed since compilation. This option " + \
+ "also implies the --selective option. If you would " + \
+ "like to skip rebuilds for which disabled flags have " + \
+ "been added to or removed from IUSE, see the related " + \
+ "--reinstall=changed-use option."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--noconfmem"))
+ print(" Portage keeps track of files that have been placed into")
+ print(" CONFIG_PROTECT directories, and normally it will not merge the")
+ print(" same file more than once, as that would become annoying. This")
+ print(" can lead to problems when the user wants the file in the case")
+ print(" of accidental deletion. With this option, files will always be")
+ print(" merged to the live fs instead of silently dropped.")
+ print()
+ print(" "+green("--nodeps")+" ("+green("-O")+" short option)")
+ print(" Merge specified packages, but don't merge any dependencies.")
+ print(" Note that the build may fail if deps aren't satisfied.")
+ print()
+ print(" "+green("--noreplace")+" ("+green("-n")+" short option)")
+ print(" Skip the packages specified on the command-line that have")
+ print(" already been installed. Without this option, any packages,")
+ print(" ebuilds, or deps you specify on the command-line *will* cause")
+ print(" Portage to remerge the package, even if it is already installed.")
+ print(" Note that Portage won't remerge dependencies by default.")
+ print()
+ print(" "+green("--nospinner"))
+ print(" Disables the spinner regardless of terminal type.")
+ print()
+ print(" " + green("--usepkg-exclude") + " " + turquoise("ATOMS"))
+ desc = "A space separated list of package names or slot atoms." + \
+ " Emerge will ignore matching binary packages."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--rebuild-exclude") + " " + turquoise("ATOMS"))
+ desc = "A space separated list of package names or slot atoms." + \
+ " Emerge will not rebuild matching packages due to --rebuild."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--rebuild-ignore") + " " + turquoise("ATOMS"))
+ desc = "A space separated list of package names or slot atoms." + \
+ " Emerge will not rebuild packages that depend on matching " + \
+ " packages due to --rebuild."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--oneshot")+" ("+green("-1")+" short option)")
+ print(" Emerge as normal, but don't add packages to the world profile.")
+ print(" This package will only be updated if it is depended upon by")
+ print(" another package.")
+ print()
+ print(" "+green("--onlydeps")+" ("+green("-o")+" short option)")
+ print(" Only merge (or pretend to merge) the dependencies of the")
+ print(" specified packages, not the packages themselves.")
+ print()
+ print(" " + green("--package-moves") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "Perform package moves when necessary. This option " + \
+ "is enabled by default. WARNING: This option " + \
+ "should remain enabled under normal circumstances. " + \
+ "Do not disable it unless you know what you are " + \
+ "doing."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--pretend")+" ("+green("-p")+" short option)")
+ print(" Instead of actually performing the merge, simply display what")
+ print(" ebuilds and tbz2s *would* have been installed if --pretend")
+ print(" weren't used. Using --pretend is strongly recommended before")
+ print(" installing an unfamiliar package. In the printout, N = new,")
+ print(" U = updating, R = replacing, F = fetch restricted, B = blocked")
+ print(" by an already installed package, D = possible downgrading,")
+ print(" S = slotted install. --verbose causes affecting use flags to be")
+ print(" printed out accompanied by a '+' for enabled and a '-' for")
+ print(" disabled USE flags.")
+ print()
+ print(" " + green("--quiet") + \
+ " [ %s | %s ] (%s short option)" % \
+ (turquoise("y"), turquoise("n"), green("-q")))
+ print(" Effects vary, but the general outcome is a reduced or condensed")
+ print(" output from portage's displays.")
+ print()
+ print(" " + green("--quiet-build") + \
+ " [ %s | %s ]" % (turquoise("y"), turquoise("n")))
+ desc = "Redirect all build output to logs alone, and do not " + \
+ "display it on stdout."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--quiet-unmerge-warn"))
+ desc = "Disable the warning message that's shown prior to " + \
+ "--unmerge actions. This option is intended " + \
+ "to be set in the make.conf(5) " + \
+ "EMERGE_DEFAULT_OPTS variable."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--rebuild-if-new-rev") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "Rebuild packages when dependencies that are " + \
+ "used at both build-time and run-time are built, " + \
+ "if the dependency is not already installed with the " + \
+ "same version and revision."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--rebuild-if-new-ver") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "Rebuild packages when dependencies that are " + \
+ "used at both build-time and run-time are built, " + \
+ "if the dependency is not already installed with the " + \
+ "same version. Revision numbers are ignored."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--rebuild-if-unbuilt") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "Rebuild packages when dependencies that are " + \
+ "used at both build-time and run-time are built."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--rebuilt-binaries") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "Replace installed packages with binary packages that have " + \
+ "been rebuilt. Rebuilds are detected by comparison of " + \
+ "BUILD_TIME package metadata. This option is enabled " + \
+ "automatically when using binary packages " + \
+ "(--usepkgonly or --getbinpkgonly) together with " + \
+ "--update and --deep."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--rebuilt-binaries-timestamp") + "=%s" % turquoise("TIMESTAMP"))
+ desc = "This option modifies emerge's behaviour only if " + \
+ "--rebuilt-binaries is given. Only binaries that " + \
+ "have a BUILD_TIME that is larger than the given TIMESTAMP " + \
+ "and that is larger than that of the installed package will " + \
+ "be considered by the rebuilt-binaries logic."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--reinstall ") + turquoise("changed-use"))
+ print(" Tells emerge to include installed packages where USE flags have")
+ print(" changed since installation. Unlike --newuse, this option does")
+ print(" not trigger reinstallation when flags that the user has not")
+ print(" enabled are added or removed.")
+ print()
+ print(" " + green("--reinstall-atoms") + " " + turquoise("ATOMS"))
+ desc = "A space separated list of package names or slot atoms. " + \
+ "Emerge will treat matching packages as if they are not " + \
+ "installed, and reinstall them if necessary."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--root=DIR"))
+ desc = "Set the ROOT environment variable " + \
+ "which is documented in the emerge(1) man page."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--root-deps[=rdeps]"))
+ desc = "If no argument is given then build-time dependencies of packages for " + \
+ "ROOT are installed to " + \
+ "ROOT instead of /. If the rdeps argument is given then discard " + \
+ "all build-time dependencies of packages for ROOT. This option is " + \
+ "only meaningful when used together with ROOT and it should not " + \
+ "be enabled under normal circumstances. For currently supported " + \
+ "EAPI values, the build-time dependencies are specified in the " + \
+ "DEPEND variable. However, behavior may change for new " + \
+ "EAPIs when related extensions are added in the future."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--select") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "Add specified packages to the world set (inverse of " + \
+ "--oneshot). This is useful if you want to " + \
+ "use EMERGE_DEFAULT_OPTS to make " + \
+ "--oneshot behavior default."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--selective") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "This identical to the --noreplace option. " + \
+ "Some options, such as --update, imply --selective. " + \
+ "Use --selective=n if you want to forcefully disable " + \
+ "--selective, regardless of options like --update."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--skipfirst"))
+ desc = "This option is only valid when " + \
+ "used with --resume. It removes the " + \
+ "first package in the resume list. " + \
+ "Dependencies are recalculated for " + \
+ "remaining packages and any that " + \
+ "have unsatisfied dependencies or are " + \
+ "masked will be automatically dropped. " + \
+ "Also see the related " + \
+ "--keep-going option."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--tree")+" ("+green("-t")+" short option)")
+ print(" Shows the dependency tree using indentation for dependencies.")
+ print(" The packages are also listed in reverse merge order so that")
+ print(" a package's dependencies follow the package. Only really useful")
+ print(" in combination with --emptytree, --update or --deep.")
+ print()
+ print(" " + green("--unordered-display"))
+ desc = "By default the displayed merge list is sorted using the " + \
+ "order in which the packages will be merged. When " + \
+ "--tree is used together with this option, this " + \
+ "constraint is removed, hopefully leading to a more " + \
+ "readable dependency tree."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" "+green("--update")+" ("+green("-u")+" short option)")
+ desc = "Updates packages to the best version available, which may " + \
+ "not always be the highest version number due to masking " + \
+ "for testing and development. Package atoms specified on " + \
+ "the command line are greedy, meaning that unspecific " + \
+ "atoms may match multiple versions of slotted packages."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--use-ebuild-visibility") + " [ %s | %s ]" % \
+ (turquoise("y"), turquoise("n")))
+ desc = "Use unbuilt ebuild metadata for visibility " + \
+ "checks on built packages."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--useoldpkg-atoms") + " " + turquoise("ATOMS"))
+ desc = "A space separated list of package names or slot atoms." + \
+ " Emerge will prefer matching binary packages over newer" + \
+ " unbuilt packages."
+ for line in wrap(desc, desc_width):
+ print(desc_indent + line)
+ print()
+ print(" " + green("--usepkg") + \
+ " [ %s | %s ] (%s short option)" % \
+ (turquoise("y"), turquoise("n"), green("-k")))
+ print(" Tell emerge to use binary packages (from $PKGDIR) if they are")
+ print(" available, thus possibly avoiding some time-consuming compiles.")
+ print(" This option is useful for CD installs; you can export")
+ print(" PKGDIR=/mnt/cdrom/packages and then use this option to have")
+ print(" emerge \"pull\" binary packages from the CD in order to satisfy")
+ print(" dependencies.")
+ print()
+ print(" " + green("--usepkgonly") + \
+ " [ %s | %s ] (%s short option)" % \
+ (turquoise("y"), turquoise("n"), green("-K")))
+ print(" Like --usepkg above, except this only allows the use of binary")
+ print(" packages, and it will abort the emerge if the package is not")
+ print(" available at the time of dependency calculation.")
+ print()
+ print(" "+green("--verbose")+" ("+green("-v")+" short option)")
+ print(" Effects vary, but the general outcome is an increased or expanded")
+ print(" display of content in portage's displays.")
+ print()
+ print(" "+green("--with-bdeps")+" < " + turquoise("y") + " | "+ turquoise("n")+" >")
+ print(" In dependency calculations, pull in build time dependencies that")
+ print(" are not strictly required. This defaults to 'n' for installation")
+ print(" actions and 'y' for the --depclean action. This setting can be")
+ print(" added to EMERGE_DEFAULT_OPTS (see make.conf(5)) and later")
+ print(" overridden via the command line.")
+ print()
diff --git a/portage_with_autodep/pym/_emerge/is_valid_package_atom.py b/portage_with_autodep/pym/_emerge/is_valid_package_atom.py
new file mode 100644
index 0000000..7cb2a5b
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/is_valid_package_atom.py
@@ -0,0 +1,21 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import re
+from portage.dep import isvalidatom
+
+def insert_category_into_atom(atom, category):
+ alphanum = re.search(r'\w', atom)
+ if alphanum:
+ ret = atom[:alphanum.start()] + "%s/" % category + \
+ atom[alphanum.start():]
+ else:
+ ret = None
+ return ret
+
+def is_valid_package_atom(x, allow_repo=False):
+ if "/" not in x:
+ x2 = insert_category_into_atom(x, 'cat')
+ if x2 != None:
+ x = x2
+ return isvalidatom(x, allow_blockers=False, allow_repo=allow_repo)
diff --git a/portage_with_autodep/pym/_emerge/main.py b/portage_with_autodep/pym/_emerge/main.py
new file mode 100644
index 0000000..2830214
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/main.py
@@ -0,0 +1,1910 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import logging
+import signal
+import stat
+import sys
+import textwrap
+import platform
+import portage
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+import _emerge.help
+import portage.xpak, errno, re, time
+from portage.output import colorize, xtermTitle, xtermTitleReset
+from portage.output import create_color_func
+good = create_color_func("GOOD")
+bad = create_color_func("BAD")
+
+from portage.const import _ENABLE_DYN_LINK_MAP
+import portage.elog
+import portage.util
+import portage.locks
+import portage.exception
+from portage.data import secpass
+from portage.dbapi.dep_expand import dep_expand
+from portage.util import normalize_path as normpath
+from portage.util import shlex_split, writemsg_level, writemsg_stdout
+from portage._sets import SETPREFIX
+from portage._global_updates import _global_updates
+
+from _emerge.actions import action_config, action_sync, action_metadata, \
+ action_regen, action_search, action_uninstall, action_info, action_build, \
+ adjust_configs, chk_updated_cfg_files, display_missing_pkg_set, \
+ display_news_notification, getportageversion, load_emerge_config
+import _emerge
+from _emerge.emergelog import emergelog
+from _emerge._flush_elog_mod_echo import _flush_elog_mod_echo
+from _emerge.is_valid_package_atom import is_valid_package_atom
+from _emerge.stdout_spinner import stdout_spinner
+from _emerge.userquery import userquery
+
+if sys.hexversion >= 0x3000000:
+ long = int
+
+options=[
+"--alphabetical",
+"--ask-enter-invalid",
+"--buildpkgonly",
+"--changed-use",
+"--changelog", "--columns",
+"--debug",
+"--digest",
+"--emptytree",
+"--fetchonly", "--fetch-all-uri",
+"--ignore-default-opts",
+"--noconfmem",
+"--newuse",
+"--nodeps", "--noreplace",
+"--nospinner", "--oneshot",
+"--onlydeps", "--pretend",
+"--quiet-unmerge-warn",
+"--resume",
+"--searchdesc",
+"--skipfirst",
+"--tree",
+"--unordered-display",
+"--update",
+"--verbose",
+]
+
+shortmapping={
+"1":"--oneshot",
+"B":"--buildpkgonly",
+"c":"--depclean",
+"C":"--unmerge",
+"d":"--debug",
+"e":"--emptytree",
+"f":"--fetchonly", "F":"--fetch-all-uri",
+"h":"--help",
+"l":"--changelog",
+"n":"--noreplace", "N":"--newuse",
+"o":"--onlydeps", "O":"--nodeps",
+"p":"--pretend", "P":"--prune",
+"r":"--resume",
+"s":"--search", "S":"--searchdesc",
+"t":"--tree",
+"u":"--update",
+"v":"--verbose", "V":"--version"
+}
+
+def chk_updated_info_files(root, infodirs, prev_mtimes, retval):
+
+ if os.path.exists("/usr/bin/install-info"):
+ out = portage.output.EOutput()
+ regen_infodirs=[]
+ for z in infodirs:
+ if z=='':
+ continue
+ inforoot=normpath(root+z)
+ if os.path.isdir(inforoot) and \
+ not [x for x in os.listdir(inforoot) \
+ if x.startswith('.keepinfodir')]:
+ infomtime = os.stat(inforoot)[stat.ST_MTIME]
+ if inforoot not in prev_mtimes or \
+ prev_mtimes[inforoot] != infomtime:
+ regen_infodirs.append(inforoot)
+
+ if not regen_infodirs:
+ portage.writemsg_stdout("\n")
+ if portage.util.noiselimit >= 0:
+ out.einfo("GNU info directory index is up-to-date.")
+ else:
+ portage.writemsg_stdout("\n")
+ if portage.util.noiselimit >= 0:
+ out.einfo("Regenerating GNU info directory index...")
+
+ dir_extensions = ("", ".gz", ".bz2")
+ icount=0
+ badcount=0
+ errmsg = ""
+ for inforoot in regen_infodirs:
+ if inforoot=='':
+ continue
+
+ if not os.path.isdir(inforoot) or \
+ not os.access(inforoot, os.W_OK):
+ continue
+
+ file_list = os.listdir(inforoot)
+ file_list.sort()
+ dir_file = os.path.join(inforoot, "dir")
+ moved_old_dir = False
+ processed_count = 0
+ for x in file_list:
+ if x.startswith(".") or \
+ os.path.isdir(os.path.join(inforoot, x)):
+ continue
+ if x.startswith("dir"):
+ skip = False
+ for ext in dir_extensions:
+ if x == "dir" + ext or \
+ x == "dir" + ext + ".old":
+ skip = True
+ break
+ if skip:
+ continue
+ if processed_count == 0:
+ for ext in dir_extensions:
+ try:
+ os.rename(dir_file + ext, dir_file + ext + ".old")
+ moved_old_dir = True
+ except EnvironmentError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ processed_count += 1
+ myso = portage.subprocess_getstatusoutput(
+ "LANG=C LANGUAGE=C /usr/bin/install-info " +
+ "--dir-file=%s/dir %s/%s" % (inforoot, inforoot, x))[1]
+ existsstr="already exists, for file `"
+ if myso!="":
+ if re.search(existsstr,myso):
+ # Already exists... Don't increment the count for this.
+ pass
+ elif myso[:44]=="install-info: warning: no info dir entry in ":
+ # This info file doesn't contain a DIR-header: install-info produces this
+ # (harmless) warning (the --quiet switch doesn't seem to work).
+ # Don't increment the count for this.
+ pass
+ else:
+ badcount=badcount+1
+ errmsg += myso + "\n"
+ icount=icount+1
+
+ if moved_old_dir and not os.path.exists(dir_file):
+ # We didn't generate a new dir file, so put the old file
+ # back where it was originally found.
+ for ext in dir_extensions:
+ try:
+ os.rename(dir_file + ext + ".old", dir_file + ext)
+ except EnvironmentError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+
+ # Clean dir.old cruft so that they don't prevent
+ # unmerge of otherwise empty directories.
+ for ext in dir_extensions:
+ try:
+ os.unlink(dir_file + ext + ".old")
+ except EnvironmentError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+
+ #update mtime so we can potentially avoid regenerating.
+ prev_mtimes[inforoot] = os.stat(inforoot)[stat.ST_MTIME]
+
+ if badcount:
+ out.eerror("Processed %d info files; %d errors." % \
+ (icount, badcount))
+ writemsg_level(errmsg, level=logging.ERROR, noiselevel=-1)
+ else:
+ if icount > 0 and portage.util.noiselimit >= 0:
+ out.einfo("Processed %d info files." % (icount,))
+
+def display_preserved_libs(vardbapi, myopts):
+ MAX_DISPLAY = 3
+
+ if vardbapi._linkmap is None or \
+ vardbapi._plib_registry is None:
+ # preserve-libs is entirely disabled
+ return
+
+ # Explicitly load and prune the PreservedLibsRegistry in order
+ # to ensure that we do not display stale data.
+ vardbapi._plib_registry.load()
+
+ if vardbapi._plib_registry.hasEntries():
+ if "--quiet" in myopts:
+ print()
+ print(colorize("WARN", "!!!") + " existing preserved libs found")
+ return
+ else:
+ print()
+ print(colorize("WARN", "!!!") + " existing preserved libs:")
+
+ plibdata = vardbapi._plib_registry.getPreservedLibs()
+ linkmap = vardbapi._linkmap
+ consumer_map = {}
+ owners = {}
+ linkmap_broken = False
+
+ try:
+ linkmap.rebuild()
+ except portage.exception.CommandNotFound as e:
+ writemsg_level("!!! Command Not Found: %s\n" % (e,),
+ level=logging.ERROR, noiselevel=-1)
+ del e
+ linkmap_broken = True
+ else:
+ search_for_owners = set()
+ for cpv in plibdata:
+ internal_plib_keys = set(linkmap._obj_key(f) \
+ for f in plibdata[cpv])
+ for f in plibdata[cpv]:
+ if f in consumer_map:
+ continue
+ consumers = []
+ for c in linkmap.findConsumers(f):
+ # Filter out any consumers that are also preserved libs
+ # belonging to the same package as the provider.
+ if linkmap._obj_key(c) not in internal_plib_keys:
+ consumers.append(c)
+ consumers.sort()
+ consumer_map[f] = consumers
+ search_for_owners.update(consumers[:MAX_DISPLAY+1])
+
+ owners = {}
+ for f in search_for_owners:
+ owner_set = set()
+ for owner in linkmap.getOwners(f):
+ owner_dblink = vardbapi._dblink(owner)
+ if owner_dblink.exists():
+ owner_set.add(owner_dblink)
+ if owner_set:
+ owners[f] = owner_set
+
+ for cpv in plibdata:
+ print(colorize("WARN", ">>>") + " package: %s" % cpv)
+ samefile_map = {}
+ for f in plibdata[cpv]:
+ obj_key = linkmap._obj_key(f)
+ alt_paths = samefile_map.get(obj_key)
+ if alt_paths is None:
+ alt_paths = set()
+ samefile_map[obj_key] = alt_paths
+ alt_paths.add(f)
+
+ for alt_paths in samefile_map.values():
+ alt_paths = sorted(alt_paths)
+ for p in alt_paths:
+ print(colorize("WARN", " * ") + " - %s" % (p,))
+ f = alt_paths[0]
+ consumers = consumer_map.get(f, [])
+ for c in consumers[:MAX_DISPLAY]:
+ print(colorize("WARN", " * ") + " used by %s (%s)" % \
+ (c, ", ".join(x.mycpv for x in owners.get(c, []))))
+ if len(consumers) == MAX_DISPLAY + 1:
+ print(colorize("WARN", " * ") + " used by %s (%s)" % \
+ (consumers[MAX_DISPLAY], ", ".join(x.mycpv \
+ for x in owners.get(consumers[MAX_DISPLAY], []))))
+ elif len(consumers) > MAX_DISPLAY:
+ print(colorize("WARN", " * ") + " used by %d other files" % (len(consumers) - MAX_DISPLAY))
+ print("Use " + colorize("GOOD", "emerge @preserved-rebuild") + " to rebuild packages using these libraries")
+
+def post_emerge(myaction, myopts, myfiles,
+ target_root, trees, mtimedb, retval):
+ """
+ Misc. things to run at the end of a merge session.
+
+ Update Info Files
+ Update Config Files
+ Update News Items
+ Commit mtimeDB
+ Display preserved libs warnings
+
+ @param myaction: The action returned from parse_opts()
+ @type myaction: String
+ @param myopts: emerge options
+ @type myopts: dict
+ @param myfiles: emerge arguments
+ @type myfiles: list
+ @param target_root: The target ROOT for myaction
+ @type target_root: String
+ @param trees: A dictionary mapping each ROOT to it's package databases
+ @type trees: dict
+ @param mtimedb: The mtimeDB to store data needed across merge invocations
+ @type mtimedb: MtimeDB class instance
+ @param retval: Emerge's return value
+ @type retval: Int
+ """
+
+ root_config = trees[target_root]["root_config"]
+ vardbapi = trees[target_root]["vartree"].dbapi
+ settings = vardbapi.settings
+ info_mtimes = mtimedb["info"]
+
+ # Load the most current variables from ${ROOT}/etc/profile.env
+ settings.unlock()
+ settings.reload()
+ settings.regenerate()
+ settings.lock()
+
+ config_protect = shlex_split(settings.get("CONFIG_PROTECT", ""))
+ infodirs = settings.get("INFOPATH","").split(":") + \
+ settings.get("INFODIR","").split(":")
+
+ os.chdir("/")
+
+ if retval == os.EX_OK:
+ exit_msg = " *** exiting successfully."
+ else:
+ exit_msg = " *** exiting unsuccessfully with status '%s'." % retval
+ emergelog("notitles" not in settings.features, exit_msg)
+
+ _flush_elog_mod_echo()
+
+ if not vardbapi._pkgs_changed:
+ display_news_notification(root_config, myopts)
+ # If vdb state has not changed then there's nothing else to do.
+ return
+
+ vdb_path = os.path.join(root_config.settings['EROOT'], portage.VDB_PATH)
+ portage.util.ensure_dirs(vdb_path)
+ vdb_lock = None
+ if os.access(vdb_path, os.W_OK) and not "--pretend" in myopts:
+ vardbapi.lock()
+ vdb_lock = True
+
+ if vdb_lock:
+ try:
+ if "noinfo" not in settings.features:
+ chk_updated_info_files(target_root,
+ infodirs, info_mtimes, retval)
+ mtimedb.commit()
+ finally:
+ if vdb_lock:
+ vardbapi.unlock()
+
+ chk_updated_cfg_files(settings['EROOT'], config_protect)
+
+ display_news_notification(root_config, myopts)
+ if retval in (None, os.EX_OK) or (not "--pretend" in myopts):
+ display_preserved_libs(vardbapi, myopts)
+
+ postemerge = os.path.join(settings["PORTAGE_CONFIGROOT"],
+ portage.USER_CONFIG_PATH, "bin", "post_emerge")
+ if os.access(postemerge, os.X_OK):
+ hook_retval = portage.process.spawn(
+ [postemerge], env=settings.environ())
+ if hook_retval != os.EX_OK:
+ writemsg_level(
+ " %s spawn failed of %s\n" % (bad("*"), postemerge,),
+ level=logging.ERROR, noiselevel=-1)
+
+ if "--quiet" not in myopts and \
+ myaction is None and "@world" in myfiles:
+ show_depclean_suggestion()
+
+def show_depclean_suggestion():
+ out = portage.output.EOutput()
+ msg = "After world updates, it is important to remove " + \
+ "obsolete packages with emerge --depclean. Refer " + \
+ "to `man emerge` for more information."
+ for line in textwrap.wrap(msg, 72):
+ out.ewarn(line)
+
+def multiple_actions(action1, action2):
+ sys.stderr.write("\n!!! Multiple actions requested... Please choose one only.\n")
+ sys.stderr.write("!!! '%s' or '%s'\n\n" % (action1, action2))
+ sys.exit(1)
+
+def insert_optional_args(args):
+ """
+ Parse optional arguments and insert a value if one has
+ not been provided. This is done before feeding the args
+ to the optparse parser since that parser does not support
+ this feature natively.
+ """
+
+ class valid_integers(object):
+ def __contains__(self, s):
+ try:
+ return int(s) >= 0
+ except (ValueError, OverflowError):
+ return False
+
+ valid_integers = valid_integers()
+ y_or_n = ('y', 'n',)
+
+ new_args = []
+
+ default_arg_opts = {
+ '--ask' : y_or_n,
+ '--autounmask' : y_or_n,
+ '--autounmask-write' : y_or_n,
+ '--buildpkg' : y_or_n,
+ '--complete-graph' : y_or_n,
+ '--deep' : valid_integers,
+ '--deselect' : y_or_n,
+ '--binpkg-respect-use' : y_or_n,
+ '--fail-clean' : y_or_n,
+ '--getbinpkg' : y_or_n,
+ '--getbinpkgonly' : y_or_n,
+ '--jobs' : valid_integers,
+ '--keep-going' : y_or_n,
+ '--package-moves' : y_or_n,
+ '--quiet' : y_or_n,
+ '--quiet-build' : y_or_n,
+ '--rebuild-if-new-rev' : y_or_n,
+ '--rebuild-if-new-ver' : y_or_n,
+ '--rebuild-if-unbuilt' : y_or_n,
+ '--rebuilt-binaries' : y_or_n,
+ '--root-deps' : ('rdeps',),
+ '--select' : y_or_n,
+ '--selective' : y_or_n,
+ "--use-ebuild-visibility": y_or_n,
+ '--usepkg' : y_or_n,
+ '--usepkgonly' : y_or_n,
+ }
+
+ if _ENABLE_DYN_LINK_MAP:
+ default_arg_opts['--depclean-lib-check'] = y_or_n
+
+ short_arg_opts = {
+ 'D' : valid_integers,
+ 'j' : valid_integers,
+ }
+
+ # Don't make things like "-kn" expand to "-k n"
+ # since existence of -n makes it too ambiguous.
+ short_arg_opts_n = {
+ 'a' : y_or_n,
+ 'b' : y_or_n,
+ 'g' : y_or_n,
+ 'G' : y_or_n,
+ 'k' : y_or_n,
+ 'K' : y_or_n,
+ 'q' : y_or_n,
+ }
+
+ arg_stack = args[:]
+ arg_stack.reverse()
+ while arg_stack:
+ arg = arg_stack.pop()
+
+ default_arg_choices = default_arg_opts.get(arg)
+ if default_arg_choices is not None:
+ new_args.append(arg)
+ if arg_stack and arg_stack[-1] in default_arg_choices:
+ new_args.append(arg_stack.pop())
+ else:
+ # insert default argument
+ new_args.append('True')
+ continue
+
+ if arg[:1] != "-" or arg[:2] == "--":
+ new_args.append(arg)
+ continue
+
+ match = None
+ for k, arg_choices in short_arg_opts.items():
+ if k in arg:
+ match = k
+ break
+
+ if match is None:
+ for k, arg_choices in short_arg_opts_n.items():
+ if k in arg:
+ match = k
+ break
+
+ if match is None:
+ new_args.append(arg)
+ continue
+
+ if len(arg) == 2:
+ new_args.append(arg)
+ if arg_stack and arg_stack[-1] in arg_choices:
+ new_args.append(arg_stack.pop())
+ else:
+ # insert default argument
+ new_args.append('True')
+ continue
+
+ # Insert an empty placeholder in order to
+ # satisfy the requirements of optparse.
+
+ new_args.append("-" + match)
+ opt_arg = None
+ saved_opts = None
+
+ if arg[1:2] == match:
+ if match not in short_arg_opts_n and arg[2:] in arg_choices:
+ opt_arg = arg[2:]
+ else:
+ saved_opts = arg[2:]
+ opt_arg = "True"
+ else:
+ saved_opts = arg[1:].replace(match, "")
+ opt_arg = "True"
+
+ if opt_arg is None and arg_stack and \
+ arg_stack[-1] in arg_choices:
+ opt_arg = arg_stack.pop()
+
+ if opt_arg is None:
+ new_args.append("True")
+ else:
+ new_args.append(opt_arg)
+
+ if saved_opts is not None:
+ # Recycle these on arg_stack since they
+ # might contain another match.
+ arg_stack.append("-" + saved_opts)
+
+ return new_args
+
+def _find_bad_atoms(atoms):
+ bad_atoms = []
+ for x in ' '.join(atoms).split():
+ bad_atom = False
+ try:
+ atom = portage.dep.Atom(x, allow_wildcard=True)
+ except portage.exception.InvalidAtom:
+ try:
+ atom = portage.dep.Atom("*/"+x, allow_wildcard=True)
+ except portage.exception.InvalidAtom:
+ bad_atom = True
+
+ if bad_atom or atom.operator or atom.blocker or atom.use:
+ bad_atoms.append(x)
+ return bad_atoms
+
+
+def parse_opts(tmpcmdline, silent=False):
+ myaction=None
+ myopts = {}
+ myfiles=[]
+
+ global options, shortmapping
+
+ actions = frozenset([
+ "clean", "config", "depclean", "help",
+ "info", "list-sets", "metadata",
+ "prune", "regen", "search",
+ "sync", "unmerge", "version",
+ ])
+
+ longopt_aliases = {"--cols":"--columns", "--skip-first":"--skipfirst"}
+ true_y_or_n = ("True", "y", "n")
+ true_y = ("True", "y")
+ argument_options = {
+
+ "--ask": {
+ "shortopt" : "-a",
+ "help" : "prompt before performing any actions",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--autounmask": {
+ "help" : "automatically unmask packages",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--autounmask-write": {
+ "help" : "write changes made by --autounmask to disk",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--accept-properties": {
+ "help":"temporarily override ACCEPT_PROPERTIES",
+ "action":"store"
+ },
+
+ "--backtrack": {
+
+ "help" : "Specifies how many times to backtrack if dependency " + \
+ "calculation fails ",
+
+ "action" : "store"
+ },
+
+ "--buildpkg": {
+ "shortopt" : "-b",
+ "help" : "build binary packages",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--config-root": {
+ "help":"specify the location for portage configuration files",
+ "action":"store"
+ },
+ "--color": {
+ "help":"enable or disable color output",
+ "type":"choice",
+ "choices":("y", "n")
+ },
+
+ "--complete-graph": {
+ "help" : "completely account for all known dependencies",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--deep": {
+
+ "shortopt" : "-D",
+
+ "help" : "Specifies how deep to recurse into dependencies " + \
+ "of packages given as arguments. If no argument is given, " + \
+ "depth is unlimited. Default behavior is to skip " + \
+ "dependencies of installed packages.",
+
+ "action" : "store"
+ },
+
+ "--deselect": {
+ "help" : "remove atoms/sets from the world file",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--exclude": {
+ "help" :"A space separated list of package names or slot atoms. " + \
+ "Emerge won't install any ebuild or binary package that " + \
+ "matches any of the given package atoms.",
+
+ "action" : "append"
+ },
+
+ "--fail-clean": {
+ "help" : "clean temp files after build failure",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--jobs": {
+
+ "shortopt" : "-j",
+
+ "help" : "Specifies the number of packages to build " + \
+ "simultaneously.",
+
+ "action" : "store"
+ },
+
+ "--keep-going": {
+ "help" : "continue as much as possible after an error",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--load-average": {
+
+ "help" :"Specifies that no new builds should be started " + \
+ "if there are other builds running and the load average " + \
+ "is at least LOAD (a floating-point number).",
+
+ "action" : "store"
+ },
+
+ "--misspell-suggestions": {
+ "help" : "enable package name misspell suggestions",
+ "type" : "choice",
+ "choices" : ("y", "n")
+ },
+
+ "--with-bdeps": {
+ "help":"include unnecessary build time dependencies",
+ "type":"choice",
+ "choices":("y", "n")
+ },
+ "--reinstall": {
+ "help":"specify conditions to trigger package reinstallation",
+ "type":"choice",
+ "choices":["changed-use"]
+ },
+
+ "--reinstall-atoms": {
+ "help" :"A space separated list of package names or slot atoms. " + \
+ "Emerge will treat matching packages as if they are not " + \
+ "installed, and reinstall them if necessary. Implies --deep.",
+
+ "action" : "append",
+ },
+
+ "--binpkg-respect-use": {
+ "help" : "discard binary packages if their use flags \
+ don't match the current configuration",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--getbinpkg": {
+ "shortopt" : "-g",
+ "help" : "fetch binary packages",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--getbinpkgonly": {
+ "shortopt" : "-G",
+ "help" : "fetch binary packages only",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--usepkg-exclude": {
+ "help" :"A space separated list of package names or slot atoms. " + \
+ "Emerge will ignore matching binary packages. ",
+
+ "action" : "append",
+ },
+
+ "--rebuild-exclude": {
+ "help" :"A space separated list of package names or slot atoms. " + \
+ "Emerge will not rebuild these packages due to the " + \
+ "--rebuild flag. ",
+
+ "action" : "append",
+ },
+
+ "--rebuild-ignore": {
+ "help" :"A space separated list of package names or slot atoms. " + \
+ "Emerge will not rebuild packages that depend on matching " + \
+ "packages due to the --rebuild flag. ",
+
+ "action" : "append",
+ },
+
+ "--package-moves": {
+ "help" : "perform package moves when necessary",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--quiet": {
+ "shortopt" : "-q",
+ "help" : "reduced or condensed output",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--quiet-build": {
+ "help" : "redirect build output to logs",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--rebuild-if-new-rev": {
+ "help" : "Rebuild packages when dependencies that are " + \
+ "used at both build-time and run-time are built, " + \
+ "if the dependency is not already installed with the " + \
+ "same version and revision.",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--rebuild-if-new-ver": {
+ "help" : "Rebuild packages when dependencies that are " + \
+ "used at both build-time and run-time are built, " + \
+ "if the dependency is not already installed with the " + \
+ "same version. Revision numbers are ignored.",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--rebuild-if-unbuilt": {
+ "help" : "Rebuild packages when dependencies that are " + \
+ "used at both build-time and run-time are built.",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--rebuilt-binaries": {
+ "help" : "replace installed packages with binary " + \
+ "packages that have been rebuilt",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--rebuilt-binaries-timestamp": {
+ "help" : "use only binaries that are newer than this " + \
+ "timestamp for --rebuilt-binaries",
+ "action" : "store"
+ },
+
+ "--root": {
+ "help" : "specify the target root filesystem for merging packages",
+ "action" : "store"
+ },
+
+ "--root-deps": {
+ "help" : "modify interpretation of depedencies",
+ "type" : "choice",
+ "choices" :("True", "rdeps")
+ },
+
+ "--select": {
+ "help" : "add specified packages to the world set " + \
+ "(inverse of --oneshot)",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--selective": {
+ "help" : "identical to --noreplace",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--use-ebuild-visibility": {
+ "help" : "use unbuilt ebuild metadata for visibility checks on built packages",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--useoldpkg-atoms": {
+ "help" :"A space separated list of package names or slot atoms. " + \
+ "Emerge will prefer matching binary packages over newer unbuilt packages. ",
+
+ "action" : "append",
+ },
+
+ "--usepkg": {
+ "shortopt" : "-k",
+ "help" : "use binary packages",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ "--usepkgonly": {
+ "shortopt" : "-K",
+ "help" : "use only binary packages",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ },
+
+ }
+
+ if _ENABLE_DYN_LINK_MAP:
+ argument_options["--depclean-lib-check"] = {
+ "help" : "check for consumers of libraries before removing them",
+ "type" : "choice",
+ "choices" : true_y_or_n
+ }
+
+ from optparse import OptionParser
+ parser = OptionParser()
+ if parser.has_option("--help"):
+ parser.remove_option("--help")
+
+ for action_opt in actions:
+ parser.add_option("--" + action_opt, action="store_true",
+ dest=action_opt.replace("-", "_"), default=False)
+ for myopt in options:
+ parser.add_option(myopt, action="store_true",
+ dest=myopt.lstrip("--").replace("-", "_"), default=False)
+ for shortopt, longopt in shortmapping.items():
+ parser.add_option("-" + shortopt, action="store_true",
+ dest=longopt.lstrip("--").replace("-", "_"), default=False)
+ for myalias, myopt in longopt_aliases.items():
+ parser.add_option(myalias, action="store_true",
+ dest=myopt.lstrip("--").replace("-", "_"), default=False)
+
+ for myopt, kwargs in argument_options.items():
+ shortopt = kwargs.pop("shortopt", None)
+ args = [myopt]
+ if shortopt is not None:
+ args.append(shortopt)
+ parser.add_option(dest=myopt.lstrip("--").replace("-", "_"),
+ *args, **kwargs)
+
+ tmpcmdline = insert_optional_args(tmpcmdline)
+
+ myoptions, myargs = parser.parse_args(args=tmpcmdline)
+
+ if myoptions.ask in true_y:
+ myoptions.ask = True
+ else:
+ myoptions.ask = None
+
+ if myoptions.autounmask in true_y:
+ myoptions.autounmask = True
+
+ if myoptions.autounmask_write in true_y:
+ myoptions.autounmask_write = True
+
+ if myoptions.buildpkg in true_y:
+ myoptions.buildpkg = True
+ else:
+ myoptions.buildpkg = None
+
+ if myoptions.changed_use is not False:
+ myoptions.reinstall = "changed-use"
+ myoptions.changed_use = False
+
+ if myoptions.deselect in true_y:
+ myoptions.deselect = True
+
+ if myoptions.binpkg_respect_use in true_y:
+ myoptions.binpkg_respect_use = True
+ else:
+ myoptions.binpkg_respect_use = None
+
+ if myoptions.complete_graph in true_y:
+ myoptions.complete_graph = True
+ else:
+ myoptions.complete_graph = None
+
+ if _ENABLE_DYN_LINK_MAP:
+ if myoptions.depclean_lib_check in true_y:
+ myoptions.depclean_lib_check = True
+
+ if myoptions.exclude:
+ bad_atoms = _find_bad_atoms(myoptions.exclude)
+ if bad_atoms and not silent:
+ parser.error("Invalid Atom(s) in --exclude parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \
+ (",".join(bad_atoms),))
+
+ if myoptions.reinstall_atoms:
+ bad_atoms = _find_bad_atoms(myoptions.reinstall_atoms)
+ if bad_atoms and not silent:
+ parser.error("Invalid Atom(s) in --reinstall-atoms parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \
+ (",".join(bad_atoms),))
+
+ if myoptions.rebuild_exclude:
+ bad_atoms = _find_bad_atoms(myoptions.rebuild_exclude)
+ if bad_atoms and not silent:
+ parser.error("Invalid Atom(s) in --rebuild-exclude parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \
+ (",".join(bad_atoms),))
+
+ if myoptions.rebuild_ignore:
+ bad_atoms = _find_bad_atoms(myoptions.rebuild_ignore)
+ if bad_atoms and not silent:
+ parser.error("Invalid Atom(s) in --rebuild-ignore parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \
+ (",".join(bad_atoms),))
+
+ if myoptions.usepkg_exclude:
+ bad_atoms = _find_bad_atoms(myoptions.usepkg_exclude)
+ if bad_atoms and not silent:
+ parser.error("Invalid Atom(s) in --usepkg-exclude parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \
+ (",".join(bad_atoms),))
+
+ if myoptions.useoldpkg_atoms:
+ bad_atoms = _find_bad_atoms(myoptions.useoldpkg_atoms)
+ if bad_atoms and not silent:
+ parser.error("Invalid Atom(s) in --useoldpkg-atoms parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \
+ (",".join(bad_atoms),))
+
+ if myoptions.fail_clean in true_y:
+ myoptions.fail_clean = True
+
+ if myoptions.getbinpkg in true_y:
+ myoptions.getbinpkg = True
+ else:
+ myoptions.getbinpkg = None
+
+ if myoptions.getbinpkgonly in true_y:
+ myoptions.getbinpkgonly = True
+ else:
+ myoptions.getbinpkgonly = None
+
+ if myoptions.keep_going in true_y:
+ myoptions.keep_going = True
+ else:
+ myoptions.keep_going = None
+
+ if myoptions.package_moves in true_y:
+ myoptions.package_moves = True
+
+ if myoptions.quiet in true_y:
+ myoptions.quiet = True
+ else:
+ myoptions.quiet = None
+
+ if myoptions.quiet_build in true_y:
+ myoptions.quiet_build = True
+ else:
+ myoptions.quiet_build = None
+
+ if myoptions.rebuild_if_new_ver in true_y:
+ myoptions.rebuild_if_new_ver = True
+ else:
+ myoptions.rebuild_if_new_ver = None
+
+ if myoptions.rebuild_if_new_rev in true_y:
+ myoptions.rebuild_if_new_rev = True
+ myoptions.rebuild_if_new_ver = None
+ else:
+ myoptions.rebuild_if_new_rev = None
+
+ if myoptions.rebuild_if_unbuilt in true_y:
+ myoptions.rebuild_if_unbuilt = True
+ myoptions.rebuild_if_new_rev = None
+ myoptions.rebuild_if_new_ver = None
+ else:
+ myoptions.rebuild_if_unbuilt = None
+
+ if myoptions.rebuilt_binaries in true_y:
+ myoptions.rebuilt_binaries = True
+
+ if myoptions.root_deps in true_y:
+ myoptions.root_deps = True
+
+ if myoptions.select in true_y:
+ myoptions.select = True
+ myoptions.oneshot = False
+ elif myoptions.select == "n":
+ myoptions.oneshot = True
+
+ if myoptions.selective in true_y:
+ myoptions.selective = True
+
+ if myoptions.backtrack is not None:
+
+ try:
+ backtrack = int(myoptions.backtrack)
+ except (OverflowError, ValueError):
+ backtrack = -1
+
+ if backtrack < 0:
+ backtrack = None
+ if not silent:
+ parser.error("Invalid --backtrack parameter: '%s'\n" % \
+ (myoptions.backtrack,))
+
+ myoptions.backtrack = backtrack
+
+ if myoptions.deep is not None:
+ deep = None
+ if myoptions.deep == "True":
+ deep = True
+ else:
+ try:
+ deep = int(myoptions.deep)
+ except (OverflowError, ValueError):
+ deep = -1
+
+ if deep is not True and deep < 0:
+ deep = None
+ if not silent:
+ parser.error("Invalid --deep parameter: '%s'\n" % \
+ (myoptions.deep,))
+
+ myoptions.deep = deep
+
+ if myoptions.jobs:
+ jobs = None
+ if myoptions.jobs == "True":
+ jobs = True
+ else:
+ try:
+ jobs = int(myoptions.jobs)
+ except ValueError:
+ jobs = -1
+
+ if jobs is not True and \
+ jobs < 1:
+ jobs = None
+ if not silent:
+ parser.error("Invalid --jobs parameter: '%s'\n" % \
+ (myoptions.jobs,))
+
+ myoptions.jobs = jobs
+
+ if myoptions.load_average:
+ try:
+ load_average = float(myoptions.load_average)
+ except ValueError:
+ load_average = 0.0
+
+ if load_average <= 0.0:
+ load_average = None
+ if not silent:
+ parser.error("Invalid --load-average parameter: '%s'\n" % \
+ (myoptions.load_average,))
+
+ myoptions.load_average = load_average
+
+ if myoptions.rebuilt_binaries_timestamp:
+ try:
+ rebuilt_binaries_timestamp = int(myoptions.rebuilt_binaries_timestamp)
+ except ValueError:
+ rebuilt_binaries_timestamp = -1
+
+ if rebuilt_binaries_timestamp < 0:
+ rebuilt_binaries_timestamp = 0
+ if not silent:
+ parser.error("Invalid --rebuilt-binaries-timestamp parameter: '%s'\n" % \
+ (myoptions.rebuilt_binaries_timestamp,))
+
+ myoptions.rebuilt_binaries_timestamp = rebuilt_binaries_timestamp
+
+ if myoptions.use_ebuild_visibility in true_y:
+ myoptions.use_ebuild_visibility = True
+ else:
+ # None or "n"
+ pass
+
+ if myoptions.usepkg in true_y:
+ myoptions.usepkg = True
+ else:
+ myoptions.usepkg = None
+
+ if myoptions.usepkgonly in true_y:
+ myoptions.usepkgonly = True
+ else:
+ myoptions.usepkgonly = None
+
+ for myopt in options:
+ v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"))
+ if v:
+ myopts[myopt] = True
+
+ for myopt in argument_options:
+ v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"), None)
+ if v is not None:
+ myopts[myopt] = v
+
+ if myoptions.searchdesc:
+ myoptions.search = True
+
+ for action_opt in actions:
+ v = getattr(myoptions, action_opt.replace("-", "_"))
+ if v:
+ if myaction:
+ multiple_actions(myaction, action_opt)
+ sys.exit(1)
+ myaction = action_opt
+
+ if myaction is None and myoptions.deselect is True:
+ myaction = 'deselect'
+
+ if myargs and sys.hexversion < 0x3000000 and \
+ not isinstance(myargs[0], unicode):
+ for i in range(len(myargs)):
+ myargs[i] = portage._unicode_decode(myargs[i])
+
+ myfiles += myargs
+
+ return myaction, myopts, myfiles
+
+# Warn about features that may confuse users and
+# lead them to report invalid bugs.
+_emerge_features_warn = frozenset(['keeptemp', 'keepwork'])
+
+def validate_ebuild_environment(trees):
+ features_warn = set()
+ for myroot in trees:
+ settings = trees[myroot]["vartree"].settings
+ settings.validate()
+ features_warn.update(
+ _emerge_features_warn.intersection(settings.features))
+
+ if features_warn:
+ msg = "WARNING: The FEATURES variable contains one " + \
+ "or more values that should be disabled under " + \
+ "normal circumstances: %s" % " ".join(features_warn)
+ out = portage.output.EOutput()
+ for line in textwrap.wrap(msg, 65):
+ out.ewarn(line)
+
+def apply_priorities(settings):
+ ionice(settings)
+ nice(settings)
+
+def nice(settings):
+ try:
+ os.nice(int(settings.get("PORTAGE_NICENESS", "0")))
+ except (OSError, ValueError) as e:
+ out = portage.output.EOutput()
+ out.eerror("Failed to change nice value to '%s'" % \
+ settings["PORTAGE_NICENESS"])
+ out.eerror("%s\n" % str(e))
+
+def ionice(settings):
+
+ ionice_cmd = settings.get("PORTAGE_IONICE_COMMAND")
+ if ionice_cmd:
+ ionice_cmd = portage.util.shlex_split(ionice_cmd)
+ if not ionice_cmd:
+ return
+
+ from portage.util import varexpand
+ variables = {"PID" : str(os.getpid())}
+ cmd = [varexpand(x, mydict=variables) for x in ionice_cmd]
+
+ try:
+ rval = portage.process.spawn(cmd, env=os.environ)
+ except portage.exception.CommandNotFound:
+ # The OS kernel probably doesn't support ionice,
+ # so return silently.
+ return
+
+ if rval != os.EX_OK:
+ out = portage.output.EOutput()
+ out.eerror("PORTAGE_IONICE_COMMAND returned %d" % (rval,))
+ out.eerror("See the make.conf(5) man page for PORTAGE_IONICE_COMMAND usage instructions.")
+
+def setconfig_fallback(root_config):
+ from portage._sets.base import DummyPackageSet
+ from portage._sets.files import WorldSelectedSet
+ from portage._sets.profiles import PackagesSystemSet
+ setconfig = root_config.setconfig
+ setconfig.psets['world'] = DummyPackageSet(atoms=['@selected', '@system'])
+ setconfig.psets['selected'] = WorldSelectedSet(root_config.settings['EROOT'])
+ setconfig.psets['system'] = \
+ PackagesSystemSet(root_config.settings.profiles)
+ root_config.sets = setconfig.getSets()
+
+def get_missing_sets(root_config):
+ # emerge requires existence of "world", "selected", and "system"
+ missing_sets = []
+
+ for s in ("selected", "system", "world",):
+ if s not in root_config.sets:
+ missing_sets.append(s)
+
+ return missing_sets
+
+def missing_sets_warning(root_config, missing_sets):
+ if len(missing_sets) > 2:
+ missing_sets_str = ", ".join('"%s"' % s for s in missing_sets[:-1])
+ missing_sets_str += ', and "%s"' % missing_sets[-1]
+ elif len(missing_sets) == 2:
+ missing_sets_str = '"%s" and "%s"' % tuple(missing_sets)
+ else:
+ missing_sets_str = '"%s"' % missing_sets[-1]
+ msg = ["emerge: incomplete set configuration, " + \
+ "missing set(s): %s" % missing_sets_str]
+ if root_config.sets:
+ msg.append(" sets defined: %s" % ", ".join(root_config.sets))
+ global_config_path = portage.const.GLOBAL_CONFIG_PATH
+ if root_config.settings['EPREFIX']:
+ global_config_path = os.path.join(root_config.settings['EPREFIX'],
+ portage.const.GLOBAL_CONFIG_PATH.lstrip(os.sep))
+ msg.append(" This usually means that '%s'" % \
+ (os.path.join(global_config_path, "sets/portage.conf"),))
+ msg.append(" is missing or corrupt.")
+ msg.append(" Falling back to default world and system set configuration!!!")
+ for line in msg:
+ writemsg_level(line + "\n", level=logging.ERROR, noiselevel=-1)
+
+def ensure_required_sets(trees):
+ warning_shown = False
+ for root_trees in trees.values():
+ missing_sets = get_missing_sets(root_trees["root_config"])
+ if missing_sets and not warning_shown:
+ warning_shown = True
+ missing_sets_warning(root_trees["root_config"], missing_sets)
+ if missing_sets:
+ setconfig_fallback(root_trees["root_config"])
+
+def expand_set_arguments(myfiles, myaction, root_config):
+ retval = os.EX_OK
+ setconfig = root_config.setconfig
+
+ sets = setconfig.getSets()
+
+ # In order to know exactly which atoms/sets should be added to the
+ # world file, the depgraph performs set expansion later. It will get
+ # confused about where the atoms came from if it's not allowed to
+ # expand them itself.
+ do_not_expand = (None, )
+ newargs = []
+ for a in myfiles:
+ if a in ("system", "world"):
+ newargs.append(SETPREFIX+a)
+ else:
+ newargs.append(a)
+ myfiles = newargs
+ del newargs
+ newargs = []
+
+ # separators for set arguments
+ ARG_START = "{"
+ ARG_END = "}"
+
+ for i in range(0, len(myfiles)):
+ if myfiles[i].startswith(SETPREFIX):
+ start = 0
+ end = 0
+ x = myfiles[i][len(SETPREFIX):]
+ newset = ""
+ while x:
+ start = x.find(ARG_START)
+ end = x.find(ARG_END)
+ if start > 0 and start < end:
+ namepart = x[:start]
+ argpart = x[start+1:end]
+
+ # TODO: implement proper quoting
+ args = argpart.split(",")
+ options = {}
+ for a in args:
+ if "=" in a:
+ k, v = a.split("=", 1)
+ options[k] = v
+ else:
+ options[a] = "True"
+ setconfig.update(namepart, options)
+ newset += (x[:start-len(namepart)]+namepart)
+ x = x[end+len(ARG_END):]
+ else:
+ newset += x
+ x = ""
+ myfiles[i] = SETPREFIX+newset
+
+ sets = setconfig.getSets()
+
+ # display errors that occurred while loading the SetConfig instance
+ for e in setconfig.errors:
+ print(colorize("BAD", "Error during set creation: %s" % e))
+
+ unmerge_actions = ("unmerge", "prune", "clean", "depclean")
+
+ for a in myfiles:
+ if a.startswith(SETPREFIX):
+ s = a[len(SETPREFIX):]
+ if s not in sets:
+ display_missing_pkg_set(root_config, s)
+ return (None, 1)
+ setconfig.active.append(s)
+ try:
+ set_atoms = setconfig.getSetAtoms(s)
+ except portage.exception.PackageSetNotFound as e:
+ writemsg_level(("emerge: the given set '%s' " + \
+ "contains a non-existent set named '%s'.\n") % \
+ (s, e), level=logging.ERROR, noiselevel=-1)
+ return (None, 1)
+ if myaction in unmerge_actions and \
+ not sets[s].supportsOperation("unmerge"):
+ sys.stderr.write("emerge: the given set '%s' does " % s + \
+ "not support unmerge operations\n")
+ retval = 1
+ elif not set_atoms:
+ print("emerge: '%s' is an empty set" % s)
+ elif myaction not in do_not_expand:
+ newargs.extend(set_atoms)
+ else:
+ newargs.append(SETPREFIX+s)
+ for e in sets[s].errors:
+ print(e)
+ else:
+ newargs.append(a)
+ return (newargs, retval)
+
+def repo_name_check(trees):
+ missing_repo_names = set()
+ for root_trees in trees.values():
+ porttree = root_trees.get("porttree")
+ if porttree:
+ portdb = porttree.dbapi
+ missing_repo_names.update(portdb.getMissingRepoNames())
+ if portdb.porttree_root in missing_repo_names and \
+ not os.path.exists(os.path.join(
+ portdb.porttree_root, "profiles")):
+ # This is normal if $PORTDIR happens to be empty,
+ # so don't warn about it.
+ missing_repo_names.remove(portdb.porttree_root)
+
+ if missing_repo_names:
+ msg = []
+ msg.append("WARNING: One or more repositories " + \
+ "have missing repo_name entries:")
+ msg.append("")
+ for p in missing_repo_names:
+ msg.append("\t%s/profiles/repo_name" % (p,))
+ msg.append("")
+ msg.extend(textwrap.wrap("NOTE: Each repo_name entry " + \
+ "should be a plain text file containing a unique " + \
+ "name for the repository on the first line.", 70))
+ msg.append("\n")
+ writemsg_level("".join("%s\n" % l for l in msg),
+ level=logging.WARNING, noiselevel=-1)
+
+ return bool(missing_repo_names)
+
+def repo_name_duplicate_check(trees):
+ ignored_repos = {}
+ for root, root_trees in trees.items():
+ if 'porttree' in root_trees:
+ portdb = root_trees['porttree'].dbapi
+ if portdb.settings.get('PORTAGE_REPO_DUPLICATE_WARN') != '0':
+ for repo_name, paths in portdb.getIgnoredRepos():
+ k = (root, repo_name, portdb.getRepositoryPath(repo_name))
+ ignored_repos.setdefault(k, []).extend(paths)
+
+ if ignored_repos:
+ msg = []
+ msg.append('WARNING: One or more repositories ' + \
+ 'have been ignored due to duplicate')
+ msg.append(' profiles/repo_name entries:')
+ msg.append('')
+ for k in sorted(ignored_repos):
+ msg.append(' %s overrides' % ", ".join(k))
+ for path in ignored_repos[k]:
+ msg.append(' %s' % (path,))
+ msg.append('')
+ msg.extend(' ' + x for x in textwrap.wrap(
+ "All profiles/repo_name entries must be unique in order " + \
+ "to avoid having duplicates ignored. " + \
+ "Set PORTAGE_REPO_DUPLICATE_WARN=\"0\" in " + \
+ "/etc/make.conf if you would like to disable this warning."))
+ msg.append("\n")
+ writemsg_level(''.join('%s\n' % l for l in msg),
+ level=logging.WARNING, noiselevel=-1)
+
+ return bool(ignored_repos)
+
+def config_protect_check(trees):
+ for root, root_trees in trees.items():
+ if not root_trees["root_config"].settings.get("CONFIG_PROTECT"):
+ msg = "!!! CONFIG_PROTECT is empty"
+ if root != "/":
+ msg += " for '%s'" % root
+ msg += "\n"
+ writemsg_level(msg, level=logging.WARN, noiselevel=-1)
+
+def profile_check(trees, myaction):
+ if myaction in ("help", "info", "sync", "version"):
+ return os.EX_OK
+ for root, root_trees in trees.items():
+ if root_trees["root_config"].settings.profiles:
+ continue
+ # generate some profile related warning messages
+ validate_ebuild_environment(trees)
+ msg = "If you have just changed your profile configuration, you " + \
+ "should revert back to the previous configuration. Due to " + \
+ "your current profile being invalid, allowed actions are " + \
+ "limited to --help, --info, --sync, and --version."
+ writemsg_level("".join("!!! %s\n" % l for l in textwrap.wrap(msg, 70)),
+ level=logging.ERROR, noiselevel=-1)
+ return 1
+ return os.EX_OK
+
+def check_procfs():
+ procfs_path = '/proc'
+ if platform.system() not in ("Linux",) or \
+ os.path.ismount(procfs_path):
+ return os.EX_OK
+ msg = "It seems that %s is not mounted. You have been warned." % procfs_path
+ writemsg_level("".join("!!! %s\n" % l for l in textwrap.wrap(msg, 70)),
+ level=logging.ERROR, noiselevel=-1)
+ return 1
+
+def emerge_main(args=None):
+ """
+ @param args: command arguments (default: sys.argv[1:])
+ @type args: list
+ """
+ if args is None:
+ args = sys.argv[1:]
+
+ portage._disable_legacy_globals()
+ portage.dep._internal_warnings = True
+ # Disable color until we're sure that it should be enabled (after
+ # EMERGE_DEFAULT_OPTS has been parsed).
+ portage.output.havecolor = 0
+ # This first pass is just for options that need to be known as early as
+ # possible, such as --config-root. They will be parsed again later,
+ # together with EMERGE_DEFAULT_OPTS (which may vary depending on the
+ # the value of --config-root).
+ myaction, myopts, myfiles = parse_opts(args, silent=True)
+ if "--debug" in myopts:
+ os.environ["PORTAGE_DEBUG"] = "1"
+ if "--config-root" in myopts:
+ os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"]
+ if "--root" in myopts:
+ os.environ["ROOT"] = myopts["--root"]
+ if "--accept-properties" in myopts:
+ os.environ["ACCEPT_PROPERTIES"] = myopts["--accept-properties"]
+
+ # Portage needs to ensure a sane umask for the files it creates.
+ os.umask(0o22)
+ settings, trees, mtimedb = load_emerge_config()
+ portdb = trees[settings["ROOT"]]["porttree"].dbapi
+ rval = profile_check(trees, myaction)
+ if rval != os.EX_OK:
+ return rval
+
+ tmpcmdline = []
+ if "--ignore-default-opts" not in myopts:
+ tmpcmdline.extend(settings["EMERGE_DEFAULT_OPTS"].split())
+ tmpcmdline.extend(args)
+ myaction, myopts, myfiles = parse_opts(tmpcmdline)
+
+ if myaction not in ('help', 'info', 'version') and \
+ myopts.get('--package-moves') != 'n' and \
+ _global_updates(trees, mtimedb["updates"], quiet=("--quiet" in myopts)):
+ mtimedb.commit()
+ # Reload the whole config from scratch.
+ settings, trees, mtimedb = load_emerge_config(trees=trees)
+ portdb = trees[settings["ROOT"]]["porttree"].dbapi
+
+ xterm_titles = "notitles" not in settings.features
+ if xterm_titles:
+ xtermTitle("emerge")
+
+ if "--digest" in myopts:
+ os.environ["FEATURES"] = os.environ.get("FEATURES","") + " digest"
+ # Reload the whole config from scratch so that the portdbapi internal
+ # config is updated with new FEATURES.
+ settings, trees, mtimedb = load_emerge_config(trees=trees)
+ portdb = trees[settings["ROOT"]]["porttree"].dbapi
+
+ adjust_configs(myopts, trees)
+ apply_priorities(settings)
+
+ if myaction == 'version':
+ writemsg_stdout(getportageversion(
+ settings["PORTDIR"], settings["ROOT"],
+ settings.profile_path, settings["CHOST"],
+ trees[settings["ROOT"]]["vartree"].dbapi) + '\n', noiselevel=-1)
+ return 0
+ elif myaction == 'help':
+ _emerge.help.help(myopts, portage.output.havecolor)
+ return 0
+
+ spinner = stdout_spinner()
+ if "candy" in settings.features:
+ spinner.update = spinner.update_scroll
+
+ if "--quiet" not in myopts:
+ portage.deprecated_profile_check(settings=settings)
+ if portage.const._ENABLE_REPO_NAME_WARN:
+ # Bug #248603 - Disable warnings about missing
+ # repo_name entries for stable branch.
+ repo_name_check(trees)
+ repo_name_duplicate_check(trees)
+ config_protect_check(trees)
+ check_procfs()
+
+ if "getbinpkg" in settings.features:
+ myopts["--getbinpkg"] = True
+
+ if "--getbinpkgonly" in myopts:
+ myopts["--getbinpkg"] = True
+
+ if "--getbinpkgonly" in myopts:
+ myopts["--usepkgonly"] = True
+
+ if "--getbinpkg" in myopts:
+ myopts["--usepkg"] = True
+
+ if "--usepkgonly" in myopts:
+ myopts["--usepkg"] = True
+
+ if "buildpkg" in settings.features or "--buildpkgonly" in myopts:
+ myopts["--buildpkg"] = True
+
+ if "--buildpkgonly" in myopts:
+ # --buildpkgonly will not merge anything, so
+ # it cancels all binary package options.
+ for opt in ("--getbinpkg", "--getbinpkgonly",
+ "--usepkg", "--usepkgonly"):
+ myopts.pop(opt, None)
+
+ for mytrees in trees.values():
+ mydb = mytrees["porttree"].dbapi
+ # Freeze the portdbapi for performance (memoize all xmatch results).
+ mydb.freeze()
+
+ if myaction in ('search', None) and \
+ "--usepkg" in myopts:
+ # Populate the bintree with current --getbinpkg setting.
+ # This needs to happen before expand_set_arguments(), in case
+ # any sets use the bintree.
+ mytrees["bintree"].populate(
+ getbinpkgs="--getbinpkg" in myopts)
+
+ del mytrees, mydb
+
+ if "moo" in myfiles:
+ print("""
+
+ Larry loves Gentoo (""" + platform.system() + """)
+
+ _______________________
+< Have you mooed today? >
+ -----------------------
+ \ ^__^
+ \ (oo)\_______
+ (__)\ )\/\
+ ||----w |
+ || ||
+
+""")
+
+ for x in myfiles:
+ ext = os.path.splitext(x)[1]
+ if (ext == ".ebuild" or ext == ".tbz2") and os.path.exists(os.path.abspath(x)):
+ print(colorize("BAD", "\n*** emerging by path is broken and may not always work!!!\n"))
+ break
+
+ root_config = trees[settings["ROOT"]]["root_config"]
+ if myaction == "list-sets":
+ writemsg_stdout("".join("%s\n" % s for s in sorted(root_config.sets)))
+ return os.EX_OK
+
+ ensure_required_sets(trees)
+
+ # only expand sets for actions taking package arguments
+ oldargs = myfiles[:]
+ if myaction in ("clean", "config", "depclean", "info", "prune", "unmerge", None):
+ myfiles, retval = expand_set_arguments(myfiles, myaction, root_config)
+ if retval != os.EX_OK:
+ return retval
+
+ # Need to handle empty sets specially, otherwise emerge will react
+ # with the help message for empty argument lists
+ if oldargs and not myfiles:
+ print("emerge: no targets left after set expansion")
+ return 0
+
+ if ("--tree" in myopts) and ("--columns" in myopts):
+ print("emerge: can't specify both of \"--tree\" and \"--columns\".")
+ return 1
+
+ if '--emptytree' in myopts and '--noreplace' in myopts:
+ writemsg_level("emerge: can't specify both of " + \
+ "\"--emptytree\" and \"--noreplace\".\n",
+ level=logging.ERROR, noiselevel=-1)
+ return 1
+
+ if ("--quiet" in myopts):
+ spinner.update = spinner.update_quiet
+ portage.util.noiselimit = -1
+
+ if "--fetch-all-uri" in myopts:
+ myopts["--fetchonly"] = True
+
+ if "--skipfirst" in myopts and "--resume" not in myopts:
+ myopts["--resume"] = True
+
+ # Allow -p to remove --ask
+ if "--pretend" in myopts:
+ myopts.pop("--ask", None)
+
+ # forbid --ask when not in a terminal
+ # note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway.
+ if ("--ask" in myopts) and (not sys.stdin.isatty()):
+ portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n",
+ noiselevel=-1)
+ return 1
+
+ if settings.get("PORTAGE_DEBUG", "") == "1":
+ spinner.update = spinner.update_quiet
+ portage.util.noiselimit = 0
+ if "python-trace" in settings.features:
+ import portage.debug as portage_debug
+ portage_debug.set_trace(True)
+
+ if not ("--quiet" in myopts):
+ if '--nospinner' in myopts or \
+ settings.get('TERM') == 'dumb' or \
+ not sys.stdout.isatty():
+ spinner.update = spinner.update_basic
+
+ if "--debug" in myopts:
+ print("myaction", myaction)
+ print("myopts", myopts)
+
+ if not myaction and not myfiles and "--resume" not in myopts:
+ _emerge.help.help(myopts, portage.output.havecolor)
+ return 1
+
+ pretend = "--pretend" in myopts
+ fetchonly = "--fetchonly" in myopts or "--fetch-all-uri" in myopts
+ buildpkgonly = "--buildpkgonly" in myopts
+
+ # check if root user is the current user for the actions where emerge needs this
+ if portage.secpass < 2:
+ # We've already allowed "--version" and "--help" above.
+ if "--pretend" not in myopts and myaction not in ("search","info"):
+ need_superuser = myaction in ('clean', 'depclean', 'deselect',
+ 'prune', 'unmerge') or not \
+ (fetchonly or \
+ (buildpkgonly and secpass >= 1) or \
+ myaction in ("metadata", "regen", "sync"))
+ if portage.secpass < 1 or \
+ need_superuser:
+ if need_superuser:
+ access_desc = "superuser"
+ else:
+ access_desc = "portage group"
+ # Always show portage_group_warning() when only portage group
+ # access is required but the user is not in the portage group.
+ from portage.data import portage_group_warning
+ if "--ask" in myopts:
+ writemsg_stdout("This action requires %s access...\n" % \
+ (access_desc,), noiselevel=-1)
+ if portage.secpass < 1 and not need_superuser:
+ portage_group_warning()
+ if userquery("Would you like to add --pretend to options?",
+ "--ask-enter-invalid" in myopts) == "No":
+ return 1
+ myopts["--pretend"] = True
+ del myopts["--ask"]
+ else:
+ sys.stderr.write(("emerge: %s access is required\n") \
+ % access_desc)
+ if portage.secpass < 1 and not need_superuser:
+ portage_group_warning()
+ return 1
+
+ # Disable emergelog for everything except build or unmerge operations.
+ # This helps minimize parallel emerge.log entries that can confuse log
+ # parsers like genlop.
+ disable_emergelog = False
+ for x in ("--pretend", "--fetchonly", "--fetch-all-uri"):
+ if x in myopts:
+ disable_emergelog = True
+ break
+ if myaction in ("search", "info"):
+ disable_emergelog = True
+
+ _emerge.emergelog._disable = disable_emergelog
+
+ if not disable_emergelog:
+ if 'EMERGE_LOG_DIR' in settings:
+ try:
+ # At least the parent needs to exist for the lock file.
+ portage.util.ensure_dirs(settings['EMERGE_LOG_DIR'])
+ except portage.exception.PortageException as e:
+ writemsg_level("!!! Error creating directory for " + \
+ "EMERGE_LOG_DIR='%s':\n!!! %s\n" % \
+ (settings['EMERGE_LOG_DIR'], e),
+ noiselevel=-1, level=logging.ERROR)
+ else:
+ _emerge.emergelog._emerge_log_dir = settings["EMERGE_LOG_DIR"]
+
+ if not "--pretend" in myopts:
+ emergelog(xterm_titles, "Started emerge on: "+\
+ _unicode_decode(
+ time.strftime("%b %d, %Y %H:%M:%S", time.localtime()),
+ encoding=_encodings['content'], errors='replace'))
+ myelogstr=""
+ if myopts:
+ myelogstr=" ".join(myopts)
+ if myaction:
+ myelogstr+=" "+myaction
+ if myfiles:
+ myelogstr += " " + " ".join(oldargs)
+ emergelog(xterm_titles, " *** emerge " + myelogstr)
+ del oldargs
+
+ def emergeexitsig(signum, frame):
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
+ portage.util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum})
+ sys.exit(128 + signum)
+ signal.signal(signal.SIGINT, emergeexitsig)
+ signal.signal(signal.SIGTERM, emergeexitsig)
+
+ def emergeexit():
+ """This gets out final log message in before we quit."""
+ if "--pretend" not in myopts:
+ emergelog(xterm_titles, " *** terminating.")
+ if xterm_titles:
+ xtermTitleReset()
+ portage.atexit_register(emergeexit)
+
+ if myaction in ("config", "metadata", "regen", "sync"):
+ if "--pretend" in myopts:
+ sys.stderr.write(("emerge: The '%s' action does " + \
+ "not support '--pretend'.\n") % myaction)
+ return 1
+
+ if "sync" == myaction:
+ return action_sync(settings, trees, mtimedb, myopts, myaction)
+ elif "metadata" == myaction:
+ action_metadata(settings, portdb, myopts)
+ elif myaction=="regen":
+ validate_ebuild_environment(trees)
+ return action_regen(settings, portdb, myopts.get("--jobs"),
+ myopts.get("--load-average"))
+ # HELP action
+ elif "config"==myaction:
+ validate_ebuild_environment(trees)
+ action_config(settings, trees, myopts, myfiles)
+
+ # SEARCH action
+ elif "search"==myaction:
+ validate_ebuild_environment(trees)
+ action_search(trees[settings["ROOT"]]["root_config"],
+ myopts, myfiles, spinner)
+
+ elif myaction in ('clean', 'depclean', 'deselect', 'prune', 'unmerge'):
+ validate_ebuild_environment(trees)
+ rval = action_uninstall(settings, trees, mtimedb["ldpath"],
+ myopts, myaction, myfiles, spinner)
+ if not (myaction == 'deselect' or buildpkgonly or fetchonly or pretend):
+ post_emerge(myaction, myopts, myfiles, settings["ROOT"],
+ trees, mtimedb, rval)
+ return rval
+
+ elif myaction == 'info':
+
+ # Ensure atoms are valid before calling unmerge().
+ vardb = trees[settings["ROOT"]]["vartree"].dbapi
+ portdb = trees[settings["ROOT"]]["porttree"].dbapi
+ bindb = trees[settings["ROOT"]]["bintree"].dbapi
+ valid_atoms = []
+ for x in myfiles:
+ if is_valid_package_atom(x):
+ try:
+ #look at the installed files first, if there is no match
+ #look at the ebuilds, since EAPI 4 allows running pkg_info
+ #on non-installed packages
+ valid_atom = dep_expand(x, mydb=vardb, settings=settings)
+ if valid_atom.cp.split("/")[0] == "null":
+ valid_atom = dep_expand(x, mydb=portdb, settings=settings)
+ if valid_atom.cp.split("/")[0] == "null" and "--usepkg" in myopts:
+ valid_atom = dep_expand(x, mydb=bindb, settings=settings)
+ valid_atoms.append(valid_atom)
+ except portage.exception.AmbiguousPackageName as e:
+ msg = "The short ebuild name \"" + x + \
+ "\" is ambiguous. Please specify " + \
+ "one of the following " + \
+ "fully-qualified ebuild names instead:"
+ for line in textwrap.wrap(msg, 70):
+ writemsg_level("!!! %s\n" % (line,),
+ level=logging.ERROR, noiselevel=-1)
+ for i in e.args[0]:
+ writemsg_level(" %s\n" % colorize("INFORM", i),
+ level=logging.ERROR, noiselevel=-1)
+ writemsg_level("\n", level=logging.ERROR, noiselevel=-1)
+ return 1
+ continue
+ msg = []
+ msg.append("'%s' is not a valid package atom." % (x,))
+ msg.append("Please check ebuild(5) for full details.")
+ writemsg_level("".join("!!! %s\n" % line for line in msg),
+ level=logging.ERROR, noiselevel=-1)
+ return 1
+
+ return action_info(settings, trees, myopts, valid_atoms)
+
+ # "update", "system", or just process files:
+ else:
+ validate_ebuild_environment(trees)
+
+ for x in myfiles:
+ if x.startswith(SETPREFIX) or \
+ is_valid_package_atom(x, allow_repo=True):
+ continue
+ if x[:1] == os.sep:
+ continue
+ try:
+ os.lstat(x)
+ continue
+ except OSError:
+ pass
+ msg = []
+ msg.append("'%s' is not a valid package atom." % (x,))
+ msg.append("Please check ebuild(5) for full details.")
+ writemsg_level("".join("!!! %s\n" % line for line in msg),
+ level=logging.ERROR, noiselevel=-1)
+ return 1
+
+ if "--pretend" not in myopts:
+ display_news_notification(root_config, myopts)
+ retval = action_build(settings, trees, mtimedb,
+ myopts, myaction, myfiles, spinner)
+ post_emerge(myaction, myopts, myfiles, settings["ROOT"],
+ trees, mtimedb, retval)
+
+ return retval
diff --git a/portage_with_autodep/pym/_emerge/resolver/__init__.py b/portage_with_autodep/pym/_emerge/resolver/__init__.py
new file mode 100644
index 0000000..21a391a
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/resolver/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/_emerge/resolver/backtracking.py b/portage_with_autodep/pym/_emerge/resolver/backtracking.py
new file mode 100644
index 0000000..dcdaee0
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/resolver/backtracking.py
@@ -0,0 +1,197 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import copy
+
+class BacktrackParameter(object):
+
+ __slots__ = (
+ "needed_unstable_keywords", "runtime_pkg_mask", "needed_use_config_changes", "needed_license_changes",
+ "rebuild_list", "reinstall_list", "needed_p_mask_changes"
+ )
+
+ def __init__(self):
+ self.needed_unstable_keywords = set()
+ self.needed_p_mask_changes = set()
+ self.runtime_pkg_mask = {}
+ self.needed_use_config_changes = {}
+ self.needed_license_changes = {}
+ self.rebuild_list = set()
+ self.reinstall_list = set()
+
+ def __deepcopy__(self, memo=None):
+ if memo is None:
+ memo = {}
+ result = BacktrackParameter()
+ memo[id(self)] = result
+
+ #Shallow copies are enough here, as we only need to ensure that nobody adds stuff
+ #to our sets and dicts. The existing content is immutable.
+ result.needed_unstable_keywords = copy.copy(self.needed_unstable_keywords)
+ result.needed_p_mask_changes = copy.copy(self.needed_p_mask_changes)
+ result.runtime_pkg_mask = copy.copy(self.runtime_pkg_mask)
+ result.needed_use_config_changes = copy.copy(self.needed_use_config_changes)
+ result.needed_license_changes = copy.copy(self.needed_license_changes)
+ result.rebuild_list = copy.copy(self.rebuild_list)
+ result.reinstall_list = copy.copy(self.reinstall_list)
+
+ return result
+
+ def __eq__(self, other):
+ return self.needed_unstable_keywords == other.needed_unstable_keywords and \
+ self.needed_p_mask_changes == other.needed_p_mask_changes and \
+ self.runtime_pkg_mask == other.runtime_pkg_mask and \
+ self.needed_use_config_changes == other.needed_use_config_changes and \
+ self.needed_license_changes == other.needed_license_changes and \
+ self.rebuild_list == other.rebuild_list and \
+ self.reinstall_list == other.reinstall_list
+
+
+class _BacktrackNode:
+
+ __slots__ = (
+ "parameter", "depth", "mask_steps", "terminal",
+ )
+
+ def __init__(self, parameter=BacktrackParameter(), depth=0, mask_steps=0, terminal=True):
+ self.parameter = parameter
+ self.depth = depth
+ self.mask_steps = mask_steps
+ self.terminal = terminal
+
+ def __eq__(self, other):
+ return self.parameter == other.parameter
+
+
+class Backtracker(object):
+
+ __slots__ = (
+ "_max_depth", "_unexplored_nodes", "_current_node", "_nodes", "_root",
+ )
+
+ def __init__(self, max_depth):
+ self._max_depth = max_depth
+ self._unexplored_nodes = []
+ self._current_node = None
+ self._nodes = []
+
+ self._root = _BacktrackNode()
+ self._add(self._root)
+
+
+ def _add(self, node, explore=True):
+ """
+ Adds a newly computed backtrack parameter. Makes sure that it doesn't already exist and
+ that we don't backtrack deeper than we are allowed by --backtrack.
+ """
+ if node.mask_steps <= self._max_depth and node not in self._nodes:
+ if explore:
+ self._unexplored_nodes.append(node)
+ self._nodes.append(node)
+
+
+ def get(self):
+ """
+ Returns a backtrack parameter. The backtrack graph is explored with depth first.
+ """
+ if self._unexplored_nodes:
+ node = self._unexplored_nodes.pop()
+ self._current_node = node
+ return copy.deepcopy(node.parameter)
+ else:
+ return None
+
+
+ def __len__(self):
+ return len(self._unexplored_nodes)
+
+
+ def _feedback_slot_conflict(self, conflict_data):
+ for pkg, parent_atoms in conflict_data:
+ new_node = copy.deepcopy(self._current_node)
+ new_node.depth += 1
+ new_node.mask_steps += 1
+ new_node.terminal = False
+ new_node.parameter.runtime_pkg_mask.setdefault(
+ pkg, {})["slot conflict"] = parent_atoms
+ self._add(new_node)
+
+
+ def _feedback_missing_dep(self, dep):
+ new_node = copy.deepcopy(self._current_node)
+ new_node.depth += 1
+ new_node.mask_steps += 1
+ new_node.terminal = False
+
+ new_node.parameter.runtime_pkg_mask.setdefault(
+ dep.parent, {})["missing dependency"] = \
+ set([(dep.parent, dep.root, dep.atom)])
+
+ self._add(new_node)
+
+
+ def _feedback_config(self, changes, explore=True):
+ """
+ Handle config changes. Don't count config changes for the maximum backtrack depth.
+ """
+ new_node = copy.deepcopy(self._current_node)
+ new_node.depth += 1
+ para = new_node.parameter
+
+ for change, data in changes.items():
+ if change == "needed_unstable_keywords":
+ para.needed_unstable_keywords.update(data)
+ elif change == "needed_p_mask_changes":
+ para.needed_p_mask_changes.update(data)
+ elif change == "needed_license_changes":
+ for pkg, missing_licenses in data:
+ para.needed_license_changes.setdefault(pkg, set()).update(missing_licenses)
+ elif change == "needed_use_config_changes":
+ for pkg, (new_use, new_changes) in data:
+ para.needed_use_config_changes[pkg] = (new_use, new_changes)
+ elif change == "rebuild_list":
+ para.rebuild_list.update(data)
+ elif change == "reinstall_list":
+ para.reinstall_list.update(data)
+
+ self._add(new_node, explore=explore)
+ self._current_node = new_node
+
+
+ def feedback(self, infos):
+ """
+ Takes information from the depgraph and computes new backtrack parameters to try.
+ """
+ assert self._current_node is not None, "call feedback() only after get() was called"
+
+ #Not all config changes require a restart, that's why they can appear together
+ #with other conflicts.
+ if "config" in infos:
+ self._feedback_config(infos["config"], explore=(len(infos)==1))
+
+ #There is at most one of the following types of conflicts for a given restart.
+ if "slot conflict" in infos:
+ self._feedback_slot_conflict(infos["slot conflict"])
+ elif "missing dependency" in infos:
+ self._feedback_missing_dep(infos["missing dependency"])
+
+
+ def backtracked(self):
+ """
+ If we didn't backtrack, there is only the root.
+ """
+ return len(self._nodes) > 1
+
+
+ def get_best_run(self):
+ """
+ Like, get() but returns the backtrack parameter that has as many config changes as possible,
+ but has no masks. This makes --autounmask effective, but prevents confusing error messages
+ with "masked by backtracking".
+ """
+ best_node = self._root
+ for node in self._nodes:
+ if node.terminal and node.depth > best_node.depth:
+ best_node = node
+
+ return copy.deepcopy(best_node.parameter)
diff --git a/portage_with_autodep/pym/_emerge/resolver/circular_dependency.py b/portage_with_autodep/pym/_emerge/resolver/circular_dependency.py
new file mode 100644
index 0000000..d113c5e
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/resolver/circular_dependency.py
@@ -0,0 +1,267 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+from itertools import chain, product
+import logging
+
+from portage.dep import use_reduce, extract_affecting_use, check_required_use, get_required_use_flags
+from portage.exception import InvalidDependString
+from portage.output import colorize
+from portage.util import writemsg_level
+from _emerge.DepPrioritySatisfiedRange import DepPrioritySatisfiedRange
+
+class circular_dependency_handler(object):
+
+ def __init__(self, depgraph, graph):
+ self.depgraph = depgraph
+ self.graph = graph
+ self.all_parent_atoms = depgraph._dynamic_config._parent_atoms
+
+ if "--debug" in depgraph._frozen_config.myopts:
+ # Show this debug output before doing the calculations
+ # that follow, so at least we have this debug info
+ # if we happen to hit a bug later.
+ writemsg_level("\n\ncircular dependency graph:\n\n",
+ level=logging.DEBUG, noiselevel=-1)
+ self.debug_print()
+
+ self.cycles, self.shortest_cycle = self._find_cycles()
+ #Guess if it is a large cluster of cycles. This usually requires
+ #a global USE change.
+ self.large_cycle_count = len(self.cycles) > 3
+ self.merge_list = self._prepare_reduced_merge_list()
+ #The digraph dump
+ self.circular_dep_message = self._prepare_circular_dep_message()
+ #Suggestions, in machine and human readable form
+ self.solutions, self.suggestions = self._find_suggestions()
+
+ def _find_cycles(self):
+ shortest_cycle = None
+ cycles = self.graph.get_cycles(ignore_priority=DepPrioritySatisfiedRange.ignore_medium_soft)
+ for cycle in cycles:
+ if not shortest_cycle or len(cycle) < len(shortest_cycle):
+ shortest_cycle = cycle
+ return cycles, shortest_cycle
+
+ def _prepare_reduced_merge_list(self):
+ """
+ Create a merge to be displayed by depgraph.display().
+ This merge list contains only packages involved in
+ the circular deps.
+ """
+ display_order = []
+ tempgraph = self.graph.copy()
+ while tempgraph:
+ nodes = tempgraph.leaf_nodes()
+ if not nodes:
+ node = tempgraph.order[0]
+ else:
+ node = nodes[0]
+ display_order.append(node)
+ tempgraph.remove(node)
+ display_order.reverse()
+ return display_order
+
+ def _prepare_circular_dep_message(self):
+ """
+ Like digraph.debug_print(), but prints only the shortest cycle.
+ """
+ if not self.shortest_cycle:
+ return None
+
+ msg = []
+ indent = ""
+ for pos, pkg in enumerate(self.shortest_cycle):
+ parent = self.shortest_cycle[pos-1]
+ priorities = self.graph.nodes[parent][0][pkg]
+ if pos > 0:
+ msg.append(indent + "%s (%s)" % (pkg, priorities[-1],))
+ else:
+ msg.append(indent + "%s depends on" % pkg)
+ indent += " "
+
+ pkg = self.shortest_cycle[0]
+ parent = self.shortest_cycle[-1]
+ priorities = self.graph.nodes[parent][0][pkg]
+ msg.append(indent + "%s (%s)" % (pkg, priorities[-1],))
+
+ return "\n".join(msg)
+
+ def _get_use_mask_and_force(self, pkg):
+ return pkg.use.mask, pkg.use.force
+
+ def _get_autounmask_changes(self, pkg):
+ needed_use_config_change = self.depgraph._dynamic_config._needed_use_config_changes.get(pkg)
+ if needed_use_config_change is None:
+ return frozenset()
+
+ use, changes = needed_use_config_change
+ return frozenset(changes.keys())
+
+ def _find_suggestions(self):
+ if not self.shortest_cycle:
+ return None, None
+
+ suggestions = []
+ final_solutions = {}
+
+ for pos, pkg in enumerate(self.shortest_cycle):
+ parent = self.shortest_cycle[pos-1]
+ priorities = self.graph.nodes[parent][0][pkg]
+ parent_atoms = self.all_parent_atoms.get(pkg)
+
+ if priorities[-1].buildtime:
+ dep = parent.metadata["DEPEND"]
+ elif priorities[-1].runtime:
+ dep = parent.metadata["RDEPEND"]
+
+ for ppkg, atom in parent_atoms:
+ if ppkg == parent:
+ changed_parent = ppkg
+ parent_atom = atom.unevaluated_atom
+ break
+
+ try:
+ affecting_use = extract_affecting_use(dep, parent_atom,
+ eapi=parent.metadata["EAPI"])
+ except InvalidDependString:
+ if not parent.installed:
+ raise
+ affecting_use = set()
+
+ # Make sure we don't want to change a flag that is
+ # a) in use.mask or use.force
+ # b) changed by autounmask
+
+ usemask, useforce = self._get_use_mask_and_force(parent)
+ autounmask_changes = self._get_autounmask_changes(parent)
+ untouchable_flags = frozenset(chain(usemask, useforce, autounmask_changes))
+
+ affecting_use.difference_update(untouchable_flags)
+
+ #If any of the flags we're going to touch is in REQUIRED_USE, add all
+ #other flags in REQUIRED_USE to affecting_use, to not lose any solution.
+ required_use_flags = get_required_use_flags(parent.metadata["REQUIRED_USE"])
+
+ if affecting_use.intersection(required_use_flags):
+ # TODO: Find out exactly which REQUIRED_USE flags are
+ # entangled with affecting_use. We have to limit the
+ # number of flags since the number of loops is
+ # exponentially related (see bug #374397).
+ total_flags = set()
+ total_flags.update(affecting_use, required_use_flags)
+ total_flags.difference_update(untouchable_flags)
+ if len(total_flags) <= 10:
+ affecting_use = total_flags
+
+ affecting_use = tuple(affecting_use)
+
+ if not affecting_use:
+ continue
+
+ #We iterate over all possible settings of these use flags and gather
+ #a set of possible changes
+ #TODO: Use the information encoded in REQUIRED_USE
+ solutions = set()
+ for use_state in product(("disabled", "enabled"),
+ repeat=len(affecting_use)):
+ current_use = set(self.depgraph._pkg_use_enabled(parent))
+ for flag, state in zip(affecting_use, use_state):
+ if state == "enabled":
+ current_use.add(flag)
+ else:
+ current_use.discard(flag)
+ try:
+ reduced_dep = use_reduce(dep,
+ uselist=current_use, flat=True)
+ except InvalidDependString:
+ if not parent.installed:
+ raise
+ reduced_dep = None
+
+ if reduced_dep is not None and \
+ parent_atom not in reduced_dep:
+ #We found an assignment that removes the atom from 'dep'.
+ #Make sure it doesn't conflict with REQUIRED_USE.
+ required_use = parent.metadata["REQUIRED_USE"]
+
+ if check_required_use(required_use, current_use, parent.iuse.is_valid_flag):
+ use = self.depgraph._pkg_use_enabled(parent)
+ solution = set()
+ for flag, state in zip(affecting_use, use_state):
+ if state == "enabled" and \
+ flag not in use:
+ solution.add((flag, True))
+ elif state == "disabled" and \
+ flag in use:
+ solution.add((flag, False))
+ solutions.add(frozenset(solution))
+
+ for solution in solutions:
+ ignore_solution = False
+ for other_solution in solutions:
+ if solution is other_solution:
+ continue
+ if solution.issuperset(other_solution):
+ ignore_solution = True
+ if ignore_solution:
+ continue
+
+ #Check if a USE change conflicts with use requirements of the parents.
+ #If a requiremnet is hard, ignore the suggestion.
+ #If the requirment is conditional, warn the user that other changes might be needed.
+ followup_change = False
+ parent_parent_atoms = self.depgraph._dynamic_config._parent_atoms.get(changed_parent)
+ for ppkg, atom in parent_parent_atoms:
+
+ atom = atom.unevaluated_atom
+ if not atom.use:
+ continue
+
+ for flag, state in solution:
+ if flag in atom.use.enabled or flag in atom.use.disabled:
+ ignore_solution = True
+ break
+ elif atom.use.conditional:
+ for flags in atom.use.conditional.values():
+ if flag in flags:
+ followup_change = True
+ break
+
+ if ignore_solution:
+ break
+
+ if ignore_solution:
+ continue
+
+ changes = []
+ for flag, state in solution:
+ if state:
+ changes.append(colorize("red", "+"+flag))
+ else:
+ changes.append(colorize("blue", "-"+flag))
+ msg = "- %s (Change USE: %s)\n" \
+ % (parent.cpv, " ".join(changes))
+ if followup_change:
+ msg += " (This change might require USE changes on parent packages.)"
+ suggestions.append(msg)
+ final_solutions.setdefault(pkg, set()).add(solution)
+
+ return final_solutions, suggestions
+
+ def debug_print(self):
+ """
+ Create a copy of the digraph, prune all root nodes,
+ and call the debug_print() method.
+ """
+ graph = self.graph.copy()
+ while True:
+ root_nodes = graph.root_nodes(
+ ignore_priority=DepPrioritySatisfiedRange.ignore_medium_soft)
+ if not root_nodes:
+ break
+ graph.difference_update(root_nodes)
+
+ graph.debug_print()
diff --git a/portage_with_autodep/pym/_emerge/resolver/output.py b/portage_with_autodep/pym/_emerge/resolver/output.py
new file mode 100644
index 0000000..05e316a
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/resolver/output.py
@@ -0,0 +1,888 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+"""Resolver output display operation.
+"""
+
+__all__ = (
+ "Display",
+ )
+
+import sys
+
+from portage import os
+from portage import _unicode_decode
+from portage.dbapi.dep_expand import dep_expand
+from portage.const import PORTAGE_PACKAGE_ATOM
+from portage.dep import cpvequal, match_from_list
+from portage.exception import InvalidDependString
+from portage.output import ( blue, bold, colorize, create_color_func,
+ darkblue, darkgreen, green, nc_len, red, teal, turquoise, yellow )
+bad = create_color_func("BAD")
+from portage.util import writemsg_stdout, writemsg_level
+from portage.versions import best, catpkgsplit, cpv_getkey
+
+from _emerge.Blocker import Blocker
+from _emerge.create_world_atom import create_world_atom
+from _emerge.resolver.output_helpers import ( _DisplayConfig, _tree_display,
+ _PackageCounters, _create_use_string, _format_size, _calc_changelog, PkgInfo)
+from _emerge.show_invalid_depstring_notice import show_invalid_depstring_notice
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+
+class Display(object):
+ """Formats and outputs the depgrah supplied it for merge/re-merge, etc.
+
+ __call__()
+ @param depgraph: list
+ @param favorites: defaults to []
+ @param verbosity: integer, defaults to None
+ """
+
+ def __init__(self):
+ self.changelogs = []
+ self.print_msg = []
+ self.blockers = []
+ self.counters = _PackageCounters()
+ self.resolver = None
+ self.resolved = None
+ self.vardb = None
+ self.portdb = None
+ self.verboseadd = ''
+ self.oldlp = None
+ self.myfetchlist = None
+ self.indent = ''
+ self.is_new = True
+ self.cur_use = None
+ self.cur_iuse = None
+ self.old_use = ''
+ self.old_iuse = ''
+ self.use_expand = None
+ self.use_expand_hidden = None
+ self.pkgsettings = None
+ self.forced_flags = None
+ self.newlp = None
+ self.conf = None
+ self.blocker_style = None
+
+
+ def _blockers(self, pkg, fetch_symbol):
+ """Processes pkg for blockers and adds colorized strings to
+ self.print_msg and self.blockers
+
+ @param pkg: _emerge.Package instance
+ @param fetch_symbol: string
+ @rtype: bool
+ Modifies class globals: self.blocker_style, self.resolved,
+ self.print_msg
+ """
+ if pkg.satisfied:
+ self.blocker_style = "PKG_BLOCKER_SATISFIED"
+ addl = "%s %s " % (colorize(self.blocker_style, "b"),
+ fetch_symbol)
+ else:
+ self.blocker_style = "PKG_BLOCKER"
+ addl = "%s %s " % (colorize(self.blocker_style, "B"),
+ fetch_symbol)
+ addl += self.empty_space_in_brackets()
+ self.resolved = dep_expand(
+ str(pkg.atom).lstrip("!"), mydb=self.vardb,
+ settings=self.pkgsettings
+ )
+ if self.conf.columns and self.conf.quiet:
+ addl += " " + colorize(self.blocker_style, str(self.resolved))
+ else:
+ addl = "[%s %s] %s%s" % \
+ (colorize(self.blocker_style, "blocks"),
+ addl, self.indent,
+ colorize(self.blocker_style, str(self.resolved))
+ )
+ block_parents = self.conf.blocker_parents.parent_nodes(pkg)
+ block_parents = set([pnode[2] for pnode in block_parents])
+ block_parents = ", ".join(block_parents)
+ if self.resolved != pkg[2]:
+ addl += colorize(self.blocker_style,
+ " (\"%s\" is blocking %s)") % \
+ (str(pkg.atom).lstrip("!"), block_parents)
+ else:
+ addl += colorize(self.blocker_style,
+ " (is blocking %s)") % block_parents
+ if isinstance(pkg, Blocker) and pkg.satisfied:
+ if self.conf.columns:
+ return True
+ self.print_msg.append(addl)
+ else:
+ self.blockers.append(addl)
+ return False
+
+
+ def _display_use(self, pkg, myoldbest, myinslotlist):
+ """ USE flag display
+
+ @param pkg: _emerge.Package instance
+ @param myoldbest: list of installed versions
+ @param myinslotlist: list of installed slots
+ Modifies class globals: self.forced_flags, self.cur_iuse,
+ self.old_iuse, self.old_use, self.use_expand
+ """
+
+ self.forced_flags = set()
+ self.forced_flags.update(pkg.use.force)
+ self.forced_flags.update(pkg.use.mask)
+
+ self.cur_use = [flag for flag in self.conf.pkg_use_enabled(pkg) \
+ if flag in pkg.iuse.all]
+ self.cur_iuse = sorted(pkg.iuse.all)
+
+ if myoldbest and myinslotlist:
+ previous_cpv = myoldbest[0].cpv
+ else:
+ previous_cpv = pkg.cpv
+ if self.vardb.cpv_exists(previous_cpv):
+ previous_pkg = self.vardb.match_pkgs('=' + previous_cpv)[0]
+ self.old_iuse = sorted(previous_pkg.iuse.all)
+ self.old_use = previous_pkg.use.enabled
+ self.is_new = False
+ else:
+ self.old_iuse = []
+ self.old_use = []
+ self.is_new = True
+
+ self.old_use = [flag for flag in self.old_use if flag in self.old_iuse]
+
+ self.use_expand = pkg.use.expand
+ self.use_expand_hidden = pkg.use.expand_hidden
+ return
+
+ def include_mask_str(self):
+ return self.conf.verbosity > 1
+
+ def gen_mask_str(self, pkg):
+ """
+ @param pkg: _emerge.Package instance
+ """
+ hardmasked = pkg.isHardMasked()
+ mask_str = " "
+
+ if hardmasked:
+ mask_str = colorize("BAD", "#")
+ else:
+ keyword_mask = pkg.get_keyword_mask()
+
+ if keyword_mask is None:
+ pass
+ elif keyword_mask == "missing":
+ mask_str = colorize("BAD", "*")
+ else:
+ mask_str = colorize("WARN", "~")
+
+ return mask_str
+
+ def empty_space_in_brackets(self):
+ space = ""
+ if self.include_mask_str():
+ # add column for mask status
+ space += " "
+ return space
+
+ def map_to_use_expand(self, myvals, forced_flags=False,
+ remove_hidden=True):
+ """Map use expand variables
+
+ @param myvals: list
+ @param forced_flags: bool
+ @param remove_hidden: bool
+ @rtype ret dictionary
+ or ret dict, forced dict.
+ """
+ ret = {}
+ forced = {}
+ for exp in self.use_expand:
+ ret[exp] = []
+ forced[exp] = set()
+ for val in myvals[:]:
+ if val.startswith(exp.lower()+"_"):
+ if val in self.forced_flags:
+ forced[exp].add(val[len(exp)+1:])
+ ret[exp].append(val[len(exp)+1:])
+ myvals.remove(val)
+ ret["USE"] = myvals
+ forced["USE"] = [val for val in myvals \
+ if val in self.forced_flags]
+ if remove_hidden:
+ for exp in self.use_expand_hidden:
+ ret.pop(exp, None)
+ if forced_flags:
+ return ret, forced
+ return ret
+
+
+ def recheck_hidden(self, pkg):
+ """ Prevent USE_EXPAND_HIDDEN flags from being hidden if they
+ are the only thing that triggered reinstallation.
+
+ @param pkg: _emerge.Package instance
+ Modifies self.use_expand_hidden, self.use_expand, self.verboseadd
+ """
+ reinst_flags_map = {}
+ reinstall_for_flags = self.conf.reinstall_nodes.get(pkg)
+ reinst_expand_map = None
+ if reinstall_for_flags:
+ reinst_flags_map = self.map_to_use_expand(
+ list(reinstall_for_flags), remove_hidden=False)
+ for k in list(reinst_flags_map):
+ if not reinst_flags_map[k]:
+ del reinst_flags_map[k]
+ if not reinst_flags_map.get("USE"):
+ reinst_expand_map = reinst_flags_map.copy()
+ reinst_expand_map.pop("USE", None)
+ if reinst_expand_map and \
+ not set(reinst_expand_map).difference(
+ self.use_expand_hidden):
+ self.use_expand_hidden = \
+ set(self.use_expand_hidden).difference(
+ reinst_expand_map)
+
+ cur_iuse_map, iuse_forced = \
+ self.map_to_use_expand(self.cur_iuse, forced_flags=True)
+ cur_use_map = self.map_to_use_expand(self.cur_use)
+ old_iuse_map = self.map_to_use_expand(self.old_iuse)
+ old_use_map = self.map_to_use_expand(self.old_use)
+
+ use_expand = sorted(self.use_expand)
+ use_expand.insert(0, "USE")
+
+ for key in use_expand:
+ if key in self.use_expand_hidden:
+ continue
+ self.verboseadd += _create_use_string(self.conf, key.upper(),
+ cur_iuse_map[key], iuse_forced[key],
+ cur_use_map[key], old_iuse_map[key],
+ old_use_map[key], self.is_new,
+ reinst_flags_map.get(key))
+ return
+
+
+ @staticmethod
+ def pkgprint(pkg_str, pkg_info):
+ """Colorizes a string acording to pkg_info settings
+
+ @param pkg_str: string
+ @param pkg_info: dictionary
+ @rtype colorized string
+ """
+ if pkg_info.merge:
+ if pkg_info.built:
+ if pkg_info.system:
+ return colorize("PKG_BINARY_MERGE_SYSTEM", pkg_str)
+ elif pkg_info.world:
+ return colorize("PKG_BINARY_MERGE_WORLD", pkg_str)
+ else:
+ return colorize("PKG_BINARY_MERGE", pkg_str)
+ else:
+ if pkg_info.system:
+ return colorize("PKG_MERGE_SYSTEM", pkg_str)
+ elif pkg_info.world:
+ return colorize("PKG_MERGE_WORLD", pkg_str)
+ else:
+ return colorize("PKG_MERGE", pkg_str)
+ elif pkg_info.operation == "uninstall":
+ return colorize("PKG_UNINSTALL", pkg_str)
+ else:
+ if pkg_info.system:
+ return colorize("PKG_NOMERGE_SYSTEM", pkg_str)
+ elif pkg_info.world:
+ return colorize("PKG_NOMERGE_WORLD", pkg_str)
+ else:
+ return colorize("PKG_NOMERGE", pkg_str)
+
+
+ def verbose_size(self, pkg, repoadd_set, pkg_info):
+ """Determines the size of the downloads required
+
+ @param pkg: _emerge.Package instance
+ @param repoadd_set: set of repos to add
+ @param pkg_info: dictionary
+ Modifies class globals: self.myfetchlist, self.counters.totalsize,
+ self.verboseadd, repoadd_set.
+ """
+ mysize = 0
+ if pkg.type_name == "ebuild" and pkg_info.merge:
+ try:
+ myfilesdict = self.portdb.getfetchsizes(pkg.cpv,
+ useflags=pkg_info.use, myrepo=pkg.repo)
+ except InvalidDependString as e:
+ # FIXME: validate SRC_URI earlier
+ depstr, = self.portdb.aux_get(pkg.cpv,
+ ["SRC_URI"], myrepo=pkg.repo)
+ show_invalid_depstring_notice(
+ pkg, depstr, str(e))
+ raise
+ if myfilesdict is None:
+ myfilesdict = "[empty/missing/bad digest]"
+ else:
+ for myfetchfile in myfilesdict:
+ if myfetchfile not in self.myfetchlist:
+ mysize += myfilesdict[myfetchfile]
+ self.myfetchlist.append(myfetchfile)
+ if pkg_info.ordered:
+ self.counters.totalsize += mysize
+ self.verboseadd += _format_size(mysize)
+
+ # overlay verbose
+ # assign index for a previous version in the same slot
+ slot_matches = self.vardb.match(pkg.slot_atom)
+ if slot_matches:
+ repo_name_prev = self.vardb.aux_get(slot_matches[0],
+ ["repository"])[0]
+ else:
+ repo_name_prev = None
+
+ # now use the data to generate output
+ if pkg.installed or not slot_matches:
+ self.repoadd = self.conf.repo_display.repoStr(
+ pkg_info.repo_path_real)
+ else:
+ repo_path_prev = None
+ if repo_name_prev:
+ repo_path_prev = self.portdb.getRepositoryPath(
+ repo_name_prev)
+ if repo_path_prev == pkg_info.repo_path_real:
+ self.repoadd = self.conf.repo_display.repoStr(
+ pkg_info.repo_path_real)
+ else:
+ self.repoadd = "%s=>%s" % (
+ self.conf.repo_display.repoStr(repo_path_prev),
+ self.conf.repo_display.repoStr(pkg_info.repo_path_real))
+ if self.repoadd:
+ repoadd_set.add(self.repoadd)
+
+
+ @staticmethod
+ def convert_myoldbest(myoldbest):
+ """converts and colorizes a version list to a string
+
+ @param myoldbest: list
+ @rtype string.
+ """
+ # Convert myoldbest from a list to a string.
+ myoldbest_str = ""
+ if myoldbest:
+ versions = []
+ for pos, pkg in enumerate(myoldbest):
+ key = catpkgsplit(pkg.cpv)[2] + \
+ "-" + catpkgsplit(pkg.cpv)[3]
+ if key[-3:] == "-r0":
+ key = key[:-3]
+ versions.append(key)
+ myoldbest_str = blue("["+", ".join(versions)+"]")
+ return myoldbest_str
+
+
+ def set_interactive(self, pkg, ordered, addl):
+ """Increments counters.interactive if the pkg is to
+ be merged and it's metadata has interactive set True
+
+ @param pkg: _emerge.Package instance
+ @param ordered: boolean
+ @param addl: already defined string to add to
+ """
+ if 'interactive' in pkg.metadata.properties and \
+ pkg.operation == 'merge':
+ addl = colorize("WARN", "I") + addl[1:]
+ if ordered:
+ self.counters.interactive += 1
+ return addl
+
+ def _set_non_root_columns(self, addl, pkg_info, pkg):
+ """sets the indent level and formats the output
+
+ @param addl: already defined string to add to
+ @param pkg_info: dictionary
+ @param pkg: _emerge.Package instance
+ @rtype string
+ """
+ if self.conf.quiet:
+ myprint = addl + " " + self.indent + \
+ self.pkgprint(pkg_info.cp, pkg_info)
+ myprint = myprint+darkblue(" "+pkg_info.ver)+" "
+ myprint = myprint+pkg_info.oldbest
+ myprint = myprint+darkgreen("to "+pkg.root)
+ self.verboseadd = None
+ else:
+ if not pkg_info.merge:
+ myprint = "[%s] %s%s" % \
+ (self.pkgprint(pkg_info.operation.ljust(13), pkg_info),
+ self.indent, self.pkgprint(pkg.cp, pkg_info))
+ else:
+ myprint = "[%s %s] %s%s" % \
+ (self.pkgprint(pkg.type_name, pkg_info), addl,
+ self.indent, self.pkgprint(pkg.cp, pkg_info))
+ if (self.newlp-nc_len(myprint)) > 0:
+ myprint = myprint+(" "*(self.newlp-nc_len(myprint)))
+ myprint = myprint+"["+darkblue(pkg_info.ver)+"] "
+ if (self.oldlp-nc_len(myprint)) > 0:
+ myprint = myprint+" "*(self.oldlp-nc_len(myprint))
+ myprint = myprint+pkg_info.oldbest
+ myprint += darkgreen("to " + pkg.root)
+ return myprint
+
+
+ def _set_root_columns(self, addl, pkg_info, pkg):
+ """sets the indent level and formats the output
+
+ @param addl: already defined string to add to
+ @param pkg_info: dictionary
+ @param pkg: _emerge.Package instance
+ @rtype string
+ Modifies self.verboseadd
+ """
+ if self.conf.quiet:
+ myprint = addl + " " + self.indent + \
+ self.pkgprint(pkg_info.cp, pkg_info)
+ myprint = myprint+" "+green(pkg_info.ver)+" "
+ myprint = myprint+pkg_info.oldbest
+ self.verboseadd = None
+ else:
+ if not pkg_info.merge:
+ addl = self.empty_space_in_brackets()
+ myprint = "[%s%s] %s%s" % \
+ (self.pkgprint(pkg_info.operation.ljust(13), pkg_info),
+ addl, self.indent, self.pkgprint(pkg.cp, pkg_info))
+ else:
+ myprint = "[%s %s] %s%s" % \
+ (self.pkgprint(pkg.type_name, pkg_info), addl,
+ self.indent, self.pkgprint(pkg.cp, pkg_info))
+ if (self.newlp-nc_len(myprint)) > 0:
+ myprint = myprint+(" "*(self.newlp-nc_len(myprint)))
+ myprint = myprint+green(" ["+pkg_info.ver+"] ")
+ if (self.oldlp-nc_len(myprint)) > 0:
+ myprint = myprint+(" "*(self.oldlp-nc_len(myprint)))
+ myprint += pkg_info.oldbest
+ return myprint
+
+
+ def _set_no_columns(self, pkg, pkg_info, addl):
+ """prints pkg info without column indentation.
+
+ @param pkg: _emerge.Package instance
+ @param pkg_info: dictionary
+ @param addl: the current text to add for the next line to output
+ @rtype the updated addl
+ """
+ if not pkg_info.merge:
+ addl = self.empty_space_in_brackets()
+ myprint = "[%s%s] %s%s %s" % \
+ (self.pkgprint(pkg_info.operation.ljust(13),
+ pkg_info), addl,
+ self.indent, self.pkgprint(pkg.cpv, pkg_info),
+ pkg_info.oldbest)
+ else:
+ myprint = "[%s %s] %s%s %s" % \
+ (self.pkgprint(pkg.type_name, pkg_info),
+ addl, self.indent,
+ self.pkgprint(pkg.cpv, pkg_info), pkg_info.oldbest)
+ return myprint
+
+
+ def _insert_slot(self, pkg, pkg_info, myinslotlist):
+ """Adds slot info to the message
+
+ @returns addl: formatted slot info
+ @returns myoldbest: installed version list
+ Modifies self.counters.downgrades, self.counters.upgrades,
+ self.counters.binary
+ """
+ addl = " " + pkg_info.fetch_symbol
+ if not cpvequal(pkg.cpv,
+ best([pkg.cpv] + [x.cpv for x in myinslotlist])):
+ # Downgrade in slot
+ addl += turquoise("U")+blue("D")
+ if pkg_info.ordered:
+ self.counters.downgrades += 1
+ if pkg.type_name == "binary":
+ self.counters.binary += 1
+ else:
+ # Update in slot
+ addl += turquoise("U") + " "
+ if pkg_info.ordered:
+ self.counters.upgrades += 1
+ if pkg.type_name == "binary":
+ self.counters.binary += 1
+ return addl
+
+
+ def _new_slot(self, pkg, pkg_info):
+ """New slot, mark it new.
+
+ @returns addl: formatted slot info
+ @returns myoldbest: installed version list
+ Modifies self.counters.newslot, self.counters.binary
+ """
+ addl = " " + green("NS") + pkg_info.fetch_symbol + " "
+ if pkg_info.ordered:
+ self.counters.newslot += 1
+ if pkg.type_name == "binary":
+ self.counters.binary += 1
+ return addl
+
+
+ def print_messages(self, show_repos):
+ """Performs the actual output printing of the pre-formatted
+ messages
+
+ @param show_repos: bool.
+ """
+ for msg in self.print_msg:
+ if isinstance(msg, basestring):
+ writemsg_stdout("%s\n" % (msg,), noiselevel=-1)
+ continue
+ myprint, self.verboseadd, repoadd = msg
+ if self.verboseadd:
+ myprint += " " + self.verboseadd
+ if show_repos and repoadd:
+ myprint += " " + teal("[%s]" % repoadd)
+ writemsg_stdout("%s\n" % (myprint,), noiselevel=-1)
+ return
+
+
+ def print_blockers(self):
+ """Performs the actual output printing of the pre-formatted
+ blocker messages
+ """
+ for pkg in self.blockers:
+ writemsg_stdout("%s\n" % (pkg,), noiselevel=-1)
+ return
+
+
+ def print_verbose(self, show_repos):
+ """Prints the verbose output to std_out
+
+ @param show_repos: bool.
+ """
+ writemsg_stdout('\n%s\n' % (self.counters,), noiselevel=-1)
+ if show_repos:
+ # Use _unicode_decode() to force unicode format string so
+ # that RepoDisplay.__unicode__() is called in python2.
+ writemsg_stdout(_unicode_decode("%s") % (self.conf.repo_display,),
+ noiselevel=-1)
+ return
+
+
+ def print_changelog(self):
+ """Prints the changelog text to std_out
+ """
+ writemsg_stdout('\n', noiselevel=-1)
+ for revision, text in self.changelogs:
+ writemsg_stdout(bold('*'+revision) + '\n' + text,
+ noiselevel=-1)
+ return
+
+
+ def get_display_list(self, mylist):
+ """Determines the display list to process
+
+ @param mylist
+ @rtype list
+ Modifies self.counters.blocks, self.counters.blocks_satisfied,
+
+ """
+ unsatisfied_blockers = []
+ ordered_nodes = []
+ for pkg in mylist:
+ if isinstance(pkg, Blocker):
+ self.counters.blocks += 1
+ if pkg.satisfied:
+ ordered_nodes.append(pkg)
+ self.counters.blocks_satisfied += 1
+ else:
+ unsatisfied_blockers.append(pkg)
+ else:
+ ordered_nodes.append(pkg)
+ if self.conf.tree_display:
+ display_list = _tree_display(self.conf, ordered_nodes)
+ else:
+ display_list = [(pkg, 0, True) for pkg in ordered_nodes]
+ for pkg in unsatisfied_blockers:
+ display_list.append((pkg, 0, True))
+ return display_list
+
+
+ def set_pkg_info(self, pkg, ordered):
+ """Sets various pkg_info dictionary variables
+
+ @param pkg: _emerge.Package instance
+ @param ordered: bool
+ @rtype pkg_info dictionary
+ Modifies self.counters.restrict_fetch,
+ self.counters.restrict_fetch_satisfied
+ """
+ pkg_info = PkgInfo()
+ pkg_info.ordered = ordered
+ pkg_info.fetch_symbol = " "
+ pkg_info.operation = pkg.operation
+ pkg_info.merge = ordered and pkg_info.operation == "merge"
+ if not pkg_info.merge and pkg_info.operation == "merge":
+ pkg_info.operation = "nomerge"
+ pkg_info.built = pkg.type_name != "ebuild"
+ pkg_info.ebuild_path = None
+ pkg_info.repo_name = pkg.repo
+ if pkg.type_name == "ebuild":
+ pkg_info.ebuild_path = self.portdb.findname(
+ pkg.cpv, myrepo=pkg_info.repo_name)
+ if pkg_info.ebuild_path is None:
+ raise AssertionError(
+ "ebuild not found for '%s'" % pkg.cpv)
+ pkg_info.repo_path_real = os.path.dirname(os.path.dirname(
+ os.path.dirname(pkg_info.ebuild_path)))
+ else:
+ pkg_info.repo_path_real = \
+ self.portdb.getRepositoryPath(pkg.metadata["repository"])
+ pkg_info.use = list(self.conf.pkg_use_enabled(pkg))
+ if not pkg.built and pkg.operation == 'merge' and \
+ 'fetch' in pkg.metadata.restrict:
+ pkg_info.fetch_symbol = red("F")
+ if pkg_info.ordered:
+ self.counters.restrict_fetch += 1
+ if not self.portdb.getfetchsizes(pkg.cpv,
+ useflags=pkg_info.use, myrepo=pkg.repo):
+ pkg_info.fetch_symbol = green("f")
+ if pkg_info.ordered:
+ self.counters.restrict_fetch_satisfied += 1
+ return pkg_info
+
+
+ def do_changelog(self, pkg, pkg_info):
+ """Processes and adds the changelog text to the master text for output
+
+ @param pkg: _emerge.Package instance
+ @param pkg_info: dictionay
+ Modifies self.changelogs
+ """
+ inst_matches = self.vardb.match(pkg.slot_atom)
+ if inst_matches:
+ ebuild_path_cl = pkg_info.ebuild_path
+ if ebuild_path_cl is None:
+ # binary package
+ ebuild_path_cl = self.portdb.findname(pkg.cpv, myrepo=pkg.repo)
+ if ebuild_path_cl is not None:
+ self.changelogs.extend(_calc_changelog(
+ ebuild_path_cl, inst_matches[0], pkg.cpv))
+ return
+
+
+ def check_system_world(self, pkg):
+ """Checks for any occurances of the package in the system or world sets
+
+ @param pkg: _emerge.Package instance
+ @rtype system and world booleans
+ """
+ root_config = self.conf.roots[pkg.root]
+ system_set = root_config.sets["system"]
+ world_set = root_config.sets["selected"]
+ system = False
+ world = False
+ try:
+ system = system_set.findAtomForPackage(
+ pkg, modified_use=self.conf.pkg_use_enabled(pkg))
+ world = world_set.findAtomForPackage(
+ pkg, modified_use=self.conf.pkg_use_enabled(pkg))
+ if not (self.conf.oneshot or world) and \
+ pkg.root == self.conf.target_root and \
+ self.conf.favorites.findAtomForPackage(
+ pkg, modified_use=self.conf.pkg_use_enabled(pkg)
+ ):
+ # Maybe it will be added to world now.
+ if create_world_atom(pkg, self.conf.favorites, root_config):
+ world = True
+ except InvalidDependString:
+ # This is reported elsewhere if relevant.
+ pass
+ return system, world
+
+
+ @staticmethod
+ def get_ver_str(pkg):
+ """Obtains the version string
+ @param pkg: _emerge.Package instance
+ @rtype string
+ """
+ ver_str = list(catpkgsplit(pkg.cpv)[2:])
+ if ver_str[1] == "r0":
+ ver_str[1] = ""
+ else:
+ ver_str[1] = "-" + ver_str[1]
+ return ver_str[0]+ver_str[1]
+
+
+ def _get_installed_best(self, pkg, pkg_info):
+ """ we need to use "--emptrytree" testing here rather than
+ "empty" param testing because "empty"
+ param is used for -u, where you still *do* want to see when
+ something is being upgraded.
+
+ @param pkg: _emerge.Package instance
+ @param pkg_info: dictionay
+ @rtype addl, myoldbest: list, myinslotlist: list
+ Modifies self.counters.reinst, self.counters.binary, self.counters.new
+
+ """
+ myoldbest = []
+ myinslotlist = None
+ installed_versions = self.vardb.match_pkgs(pkg.cp)
+ if self.vardb.cpv_exists(pkg.cpv):
+ addl = " "+yellow("R")+pkg_info.fetch_symbol+" "
+ if pkg_info.ordered:
+ if pkg_info.merge:
+ self.counters.reinst += 1
+ if pkg.type_name == "binary":
+ self.counters.binary += 1
+ elif pkg_info.operation == "uninstall":
+ self.counters.uninst += 1
+ # filter out old-style virtual matches
+ elif installed_versions and \
+ installed_versions[0].cp == pkg.cp:
+ myinslotlist = self.vardb.match_pkgs(pkg.slot_atom)
+ # If this is the first install of a new-style virtual, we
+ # need to filter out old-style virtual matches.
+ if myinslotlist and \
+ myinslotlist[0].cp != pkg.cp:
+ myinslotlist = None
+ if myinslotlist:
+ myoldbest = myinslotlist[:]
+ addl = self._insert_slot(pkg, pkg_info, myinslotlist)
+ else:
+ myoldbest = installed_versions
+ addl = self._new_slot(pkg, pkg_info)
+ if self.conf.changelog:
+ self.do_changelog(pkg, pkg_info)
+ else:
+ addl = " " + green("N") + " " + pkg_info.fetch_symbol + " "
+ if pkg_info.ordered:
+ self.counters.new += 1
+ if pkg.type_name == "binary":
+ self.counters.binary += 1
+ return addl, myoldbest, myinslotlist
+
+
+ def __call__(self, depgraph, mylist, favorites=None, verbosity=None):
+ """The main operation to format and display the resolver output.
+
+ @param depgraph: dependency grah
+ @param mylist: list of packages being processed
+ @param favorites: list, defaults to []
+ @param verbosity: verbose level, defaults to None
+ Modifies self.conf, self.myfetchlist, self.portdb, self.vardb,
+ self.pkgsettings, self.verboseadd, self.oldlp, self.newlp,
+ self.print_msg,
+ """
+ if favorites is None:
+ favorites = []
+ self.conf = _DisplayConfig(depgraph, mylist, favorites, verbosity)
+ mylist = self.get_display_list(self.conf.mylist)
+ # files to fetch list - avoids counting a same file twice
+ # in size display (verbose mode)
+ self.myfetchlist = []
+ # Use this set to detect when all the "repoadd" strings are "[0]"
+ # and disable the entire repo display in this case.
+ repoadd_set = set()
+
+ for mylist_index in range(len(mylist)):
+ pkg, depth, ordered = mylist[mylist_index]
+ self.portdb = self.conf.trees[pkg.root]["porttree"].dbapi
+ self.vardb = self.conf.trees[pkg.root]["vartree"].dbapi
+ self.pkgsettings = self.conf.pkgsettings[pkg.root]
+ self.indent = " " * depth
+
+ if isinstance(pkg, Blocker):
+ if self._blockers(pkg, fetch_symbol=" "):
+ continue
+ else:
+ pkg_info = self.set_pkg_info(pkg, ordered)
+ addl, pkg_info.oldbest, myinslotlist = \
+ self._get_installed_best(pkg, pkg_info)
+ self.verboseadd = ""
+ self.repoadd = None
+ self._display_use(pkg, pkg_info.oldbest, myinslotlist)
+ self.recheck_hidden(pkg)
+ if self.conf.verbosity == 3:
+ self.verbose_size(pkg, repoadd_set, pkg_info)
+
+ pkg_info.cp = pkg.cp
+ pkg_info.ver = self.get_ver_str(pkg)
+
+ self.oldlp = self.conf.columnwidth - 30
+ self.newlp = self.oldlp - 30
+ pkg_info.oldbest = self.convert_myoldbest(pkg_info.oldbest)
+ pkg_info.system, pkg_info.world = \
+ self.check_system_world(pkg)
+ addl = self.set_interactive(pkg, pkg_info.ordered, addl)
+
+ if self.include_mask_str():
+ addl += self.gen_mask_str(pkg)
+
+ if pkg.root != "/":
+ if pkg_info.oldbest:
+ pkg_info.oldbest += " "
+ if self.conf.columns:
+ myprint = self._set_non_root_columns(
+ addl, pkg_info, pkg)
+ else:
+ if not pkg_info.merge:
+ addl = self.empty_space_in_brackets()
+ myprint = "[%s%s] " % (
+ self.pkgprint(pkg_info.operation.ljust(13),
+ pkg_info), addl,
+ )
+ else:
+ myprint = "[%s %s] " % (
+ self.pkgprint(pkg.type_name, pkg_info), addl)
+ myprint += self.indent + \
+ self.pkgprint(pkg.cpv, pkg_info) + " " + \
+ pkg_info.oldbest + darkgreen("to " + pkg.root)
+ else:
+ if self.conf.columns:
+ myprint = self._set_root_columns(
+ addl, pkg_info, pkg)
+ else:
+ myprint = self._set_no_columns(
+ pkg, pkg_info, addl)
+
+ if self.conf.columns and pkg.operation == "uninstall":
+ continue
+ self.print_msg.append((myprint, self.verboseadd, self.repoadd))
+
+ if not self.conf.tree_display \
+ and not self.conf.no_restart \
+ and pkg.root == self.conf.running_root.root \
+ and match_from_list(PORTAGE_PACKAGE_ATOM, [pkg]) \
+ and not self.conf.quiet:
+
+ if not self.vardb.cpv_exists(pkg.cpv) or \
+ '9999' in pkg.cpv or \
+ 'git' in pkg.inherited or \
+ 'git-2' in pkg.inherited:
+ if mylist_index < len(mylist) - 1:
+ self.print_msg.append(
+ colorize(
+ "WARN", "*** Portage will stop merging "
+ "at this point and reload itself,"
+ )
+ )
+ self.print_msg.append(
+ colorize("WARN", " then resume the merge.")
+ )
+
+ show_repos = repoadd_set and repoadd_set != set(["0"])
+
+ # now finally print out the messages
+ self.print_messages(show_repos)
+ self.print_blockers()
+ if self.conf.verbosity == 3:
+ self.print_verbose(show_repos)
+ if self.conf.changelog:
+ self.print_changelog()
+
+ return os.EX_OK
diff --git a/portage_with_autodep/pym/_emerge/resolver/output_helpers.py b/portage_with_autodep/pym/_emerge/resolver/output_helpers.py
new file mode 100644
index 0000000..b7e7376
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/resolver/output_helpers.py
@@ -0,0 +1,576 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+"""Contains private support functions for the Display class
+in output.py
+"""
+__all__ = (
+ )
+
+import io
+import re
+import sys
+
+from portage import os
+from portage import _encodings, _unicode_encode
+from portage._sets.base import InternalPackageSet
+from portage.output import blue, colorize, create_color_func, green, red, \
+ teal, yellow
+bad = create_color_func("BAD")
+from portage.util import writemsg
+from portage.versions import catpkgsplit
+
+from _emerge.Blocker import Blocker
+from _emerge.Package import Package
+
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+
+class _RepoDisplay(object):
+ def __init__(self, roots):
+ self._shown_repos = {}
+ self._unknown_repo = False
+ repo_paths = set()
+ for root_config in roots.values():
+ portdir = root_config.settings.get("PORTDIR")
+ if portdir:
+ repo_paths.add(portdir)
+ overlays = root_config.settings.get("PORTDIR_OVERLAY")
+ if overlays:
+ repo_paths.update(overlays.split())
+ repo_paths = list(repo_paths)
+ self._repo_paths = repo_paths
+ self._repo_paths_real = [ os.path.realpath(repo_path) \
+ for repo_path in repo_paths ]
+
+ # pre-allocate index for PORTDIR so that it always has index 0.
+ for root_config in roots.values():
+ portdb = root_config.trees["porttree"].dbapi
+ portdir = portdb.porttree_root
+ if portdir:
+ self.repoStr(portdir)
+
+ def repoStr(self, repo_path_real):
+ real_index = -1
+ if repo_path_real:
+ real_index = self._repo_paths_real.index(repo_path_real)
+ if real_index == -1:
+ s = "?"
+ self._unknown_repo = True
+ else:
+ shown_repos = self._shown_repos
+ repo_paths = self._repo_paths
+ repo_path = repo_paths[real_index]
+ index = shown_repos.get(repo_path)
+ if index is None:
+ index = len(shown_repos)
+ shown_repos[repo_path] = index
+ s = str(index)
+ return s
+
+ def __str__(self):
+ output = []
+ shown_repos = self._shown_repos
+ unknown_repo = self._unknown_repo
+ if shown_repos or self._unknown_repo:
+ output.append("Portage tree and overlays:\n")
+ show_repo_paths = list(shown_repos)
+ for repo_path, repo_index in shown_repos.items():
+ show_repo_paths[repo_index] = repo_path
+ if show_repo_paths:
+ for index, repo_path in enumerate(show_repo_paths):
+ output.append(" "+teal("["+str(index)+"]")+" %s\n" % repo_path)
+ if unknown_repo:
+ output.append(" "+teal("[?]") + \
+ " indicates that the source repository could not be determined\n")
+ return "".join(output)
+
+ if sys.hexversion < 0x3000000:
+
+ __unicode__ = __str__
+
+ def __str__(self):
+ return _unicode_encode(self.__unicode__(),
+ encoding=_encodings['content'])
+
+
+class _PackageCounters(object):
+
+ def __init__(self):
+ self.upgrades = 0
+ self.downgrades = 0
+ self.new = 0
+ self.newslot = 0
+ self.reinst = 0
+ self.uninst = 0
+ self.blocks = 0
+ self.blocks_satisfied = 0
+ self.totalsize = 0
+ self.restrict_fetch = 0
+ self.restrict_fetch_satisfied = 0
+ self.interactive = 0
+ self.binary = 0
+
+ def __str__(self):
+ total_installs = self.upgrades + self.downgrades + self.newslot + self.new + self.reinst
+ myoutput = []
+ details = []
+ myoutput.append("Total: %s package" % total_installs)
+ if total_installs != 1:
+ myoutput.append("s")
+ if total_installs != 0:
+ myoutput.append(" (")
+ if self.upgrades > 0:
+ details.append("%s upgrade" % self.upgrades)
+ if self.upgrades > 1:
+ details[-1] += "s"
+ if self.downgrades > 0:
+ details.append("%s downgrade" % self.downgrades)
+ if self.downgrades > 1:
+ details[-1] += "s"
+ if self.new > 0:
+ details.append("%s new" % self.new)
+ if self.newslot > 0:
+ details.append("%s in new slot" % self.newslot)
+ if self.newslot > 1:
+ details[-1] += "s"
+ if self.reinst > 0:
+ details.append("%s reinstall" % self.reinst)
+ if self.reinst > 1:
+ details[-1] += "s"
+ if self.binary > 0:
+ details.append("%s binary" % self.binary)
+ if self.binary > 1:
+ details[-1] = details[-1][:-1] + "ies"
+ if self.uninst > 0:
+ details.append("%s uninstall" % self.uninst)
+ if self.uninst > 1:
+ details[-1] += "s"
+ if self.interactive > 0:
+ details.append("%s %s" % (self.interactive,
+ colorize("WARN", "interactive")))
+ myoutput.append(", ".join(details))
+ if total_installs != 0:
+ myoutput.append(")")
+ myoutput.append(", Size of downloads: %s" % _format_size(self.totalsize))
+ if self.restrict_fetch:
+ myoutput.append("\nFetch Restriction: %s package" % \
+ self.restrict_fetch)
+ if self.restrict_fetch > 1:
+ myoutput.append("s")
+ if self.restrict_fetch_satisfied < self.restrict_fetch:
+ myoutput.append(bad(" (%s unsatisfied)") % \
+ (self.restrict_fetch - self.restrict_fetch_satisfied))
+ if self.blocks > 0:
+ myoutput.append("\nConflict: %s block" % \
+ self.blocks)
+ if self.blocks > 1:
+ myoutput.append("s")
+ if self.blocks_satisfied < self.blocks:
+ myoutput.append(bad(" (%s unsatisfied)") % \
+ (self.blocks - self.blocks_satisfied))
+ return "".join(myoutput)
+
+
+class _DisplayConfig(object):
+
+ def __init__(self, depgraph, mylist, favorites, verbosity):
+ frozen_config = depgraph._frozen_config
+ dynamic_config = depgraph._dynamic_config
+
+ self.mylist = mylist
+ self.favorites = InternalPackageSet(favorites, allow_repo=True)
+ self.verbosity = verbosity
+
+ if self.verbosity is None:
+ self.verbosity = ("--quiet" in frozen_config.myopts and 1 or \
+ "--verbose" in frozen_config.myopts and 3 or 2)
+
+ self.oneshot = "--oneshot" in frozen_config.myopts or \
+ "--onlydeps" in frozen_config.myopts
+ self.columns = "--columns" in frozen_config.myopts
+ self.tree_display = "--tree" in frozen_config.myopts
+ self.alphabetical = "--alphabetical" in frozen_config.myopts
+ self.quiet = "--quiet" in frozen_config.myopts
+ self.all_flags = self.verbosity == 3 or self.quiet
+ self.print_use_string = self.verbosity != 1 or "--verbose" in frozen_config.myopts
+ self.changelog = "--changelog" in frozen_config.myopts
+ self.edebug = frozen_config.edebug
+ self.no_restart = frozen_config._opts_no_restart.intersection(frozen_config.myopts)
+ self.unordered_display = "--unordered-display" in frozen_config.myopts
+
+ mywidth = 130
+ if "COLUMNWIDTH" in frozen_config.settings:
+ try:
+ mywidth = int(frozen_config.settings["COLUMNWIDTH"])
+ except ValueError as e:
+ writemsg("!!! %s\n" % str(e), noiselevel=-1)
+ writemsg("!!! Unable to parse COLUMNWIDTH='%s'\n" % \
+ frozen_config.settings["COLUMNWIDTH"], noiselevel=-1)
+ del e
+ self.columnwidth = mywidth
+
+ self.repo_display = _RepoDisplay(frozen_config.roots)
+ self.trees = frozen_config.trees
+ self.pkgsettings = frozen_config.pkgsettings
+ self.target_root = frozen_config.target_root
+ self.running_root = frozen_config._running_root
+ self.roots = frozen_config.roots
+
+ self.blocker_parents = dynamic_config._blocker_parents
+ self.reinstall_nodes = dynamic_config._reinstall_nodes
+ self.digraph = dynamic_config.digraph
+ self.blocker_uninstalls = dynamic_config._blocker_uninstalls
+ self.slot_pkg_map = dynamic_config._slot_pkg_map
+ self.set_nodes = dynamic_config._set_nodes
+
+ self.pkg_use_enabled = depgraph._pkg_use_enabled
+ self.pkg = depgraph._pkg
+
+
+# formats a size given in bytes nicely
+def _format_size(mysize):
+ if isinstance(mysize, basestring):
+ return mysize
+ if 0 != mysize % 1024:
+ # Always round up to the next kB so that it doesn't show 0 kB when
+ # some small file still needs to be fetched.
+ mysize += 1024 - mysize % 1024
+ mystr=str(mysize//1024)
+ mycount=len(mystr)
+ while (mycount > 3):
+ mycount-=3
+ mystr=mystr[:mycount]+","+mystr[mycount:]
+ return mystr+" kB"
+
+
+def _create_use_string(conf, name, cur_iuse, iuse_forced, cur_use,
+ old_iuse, old_use,
+ is_new, reinst_flags):
+
+ if not conf.print_use_string:
+ return ""
+
+ enabled = []
+ if conf.alphabetical:
+ disabled = enabled
+ removed = enabled
+ else:
+ disabled = []
+ removed = []
+ cur_iuse = set(cur_iuse)
+ enabled_flags = cur_iuse.intersection(cur_use)
+ removed_iuse = set(old_iuse).difference(cur_iuse)
+ any_iuse = cur_iuse.union(old_iuse)
+ any_iuse = list(any_iuse)
+ any_iuse.sort()
+ for flag in any_iuse:
+ flag_str = None
+ isEnabled = False
+ reinst_flag = reinst_flags and flag in reinst_flags
+ if flag in enabled_flags:
+ isEnabled = True
+ if is_new or flag in old_use and \
+ (conf.all_flags or reinst_flag):
+ flag_str = red(flag)
+ elif flag not in old_iuse:
+ flag_str = yellow(flag) + "%*"
+ elif flag not in old_use:
+ flag_str = green(flag) + "*"
+ elif flag in removed_iuse:
+ if conf.all_flags or reinst_flag:
+ flag_str = yellow("-" + flag) + "%"
+ if flag in old_use:
+ flag_str += "*"
+ flag_str = "(" + flag_str + ")"
+ removed.append(flag_str)
+ continue
+ else:
+ if is_new or flag in old_iuse and \
+ flag not in old_use and \
+ (conf.all_flags or reinst_flag):
+ flag_str = blue("-" + flag)
+ elif flag not in old_iuse:
+ flag_str = yellow("-" + flag)
+ if flag not in iuse_forced:
+ flag_str += "%"
+ elif flag in old_use:
+ flag_str = green("-" + flag) + "*"
+ if flag_str:
+ if flag in iuse_forced:
+ flag_str = "(" + flag_str + ")"
+ if isEnabled:
+ enabled.append(flag_str)
+ else:
+ disabled.append(flag_str)
+
+ if conf.alphabetical:
+ ret = " ".join(enabled)
+ else:
+ ret = " ".join(enabled + disabled + removed)
+ if ret:
+ ret = '%s="%s" ' % (name, ret)
+ return ret
+
+
+def _tree_display(conf, mylist):
+
+ # If there are any Uninstall instances, add the
+ # corresponding blockers to the digraph.
+ mygraph = conf.digraph.copy()
+
+ executed_uninstalls = set(node for node in mylist \
+ if isinstance(node, Package) and node.operation == "unmerge")
+
+ for uninstall in conf.blocker_uninstalls.leaf_nodes():
+ uninstall_parents = \
+ conf.blocker_uninstalls.parent_nodes(uninstall)
+ if not uninstall_parents:
+ continue
+
+ # Remove the corresponding "nomerge" node and substitute
+ # the Uninstall node.
+ inst_pkg = conf.pkg(uninstall.cpv, "installed",
+ uninstall.root_config, installed=True)
+
+ try:
+ mygraph.remove(inst_pkg)
+ except KeyError:
+ pass
+
+ try:
+ inst_pkg_blockers = conf.blocker_parents.child_nodes(inst_pkg)
+ except KeyError:
+ inst_pkg_blockers = []
+
+ # Break the Package -> Uninstall edges.
+ mygraph.remove(uninstall)
+
+ # Resolution of a package's blockers
+ # depend on it's own uninstallation.
+ for blocker in inst_pkg_blockers:
+ mygraph.add(uninstall, blocker)
+
+ # Expand Package -> Uninstall edges into
+ # Package -> Blocker -> Uninstall edges.
+ for blocker in uninstall_parents:
+ mygraph.add(uninstall, blocker)
+ for parent in conf.blocker_parents.parent_nodes(blocker):
+ if parent != inst_pkg:
+ mygraph.add(blocker, parent)
+
+ # If the uninstall task did not need to be executed because
+ # of an upgrade, display Blocker -> Upgrade edges since the
+ # corresponding Blocker -> Uninstall edges will not be shown.
+ upgrade_node = \
+ conf.slot_pkg_map[uninstall.root].get(uninstall.slot_atom)
+ if upgrade_node is not None and \
+ uninstall not in executed_uninstalls:
+ for blocker in uninstall_parents:
+ mygraph.add(upgrade_node, blocker)
+
+ if conf.unordered_display:
+ display_list = _unordered_tree_display(mygraph, mylist)
+ else:
+ display_list = _ordered_tree_display(conf, mygraph, mylist)
+
+ _prune_tree_display(display_list)
+
+ return display_list
+
+
+def _unordered_tree_display(mygraph, mylist):
+ display_list = []
+ seen_nodes = set()
+
+ def print_node(node, depth):
+
+ if node in seen_nodes:
+ pass
+ else:
+ seen_nodes.add(node)
+
+ if isinstance(node, (Blocker, Package)):
+ display_list.append((node, depth, True))
+ else:
+ depth = -1
+
+ for child_node in mygraph.child_nodes(node):
+ print_node(child_node, depth + 1)
+
+ for root_node in mygraph.root_nodes():
+ print_node(root_node, 0)
+
+ return display_list
+
+
+def _ordered_tree_display(conf, mygraph, mylist):
+ depth = 0
+ shown_edges = set()
+ tree_nodes = []
+ display_list = []
+
+ for x in mylist:
+ depth = len(tree_nodes)
+ while depth and x not in \
+ mygraph.child_nodes(tree_nodes[depth-1]):
+ depth -= 1
+ if depth:
+ tree_nodes = tree_nodes[:depth]
+ tree_nodes.append(x)
+ display_list.append((x, depth, True))
+ shown_edges.add((x, tree_nodes[depth-1]))
+ else:
+ traversed_nodes = set() # prevent endless circles
+ traversed_nodes.add(x)
+ def add_parents(current_node, ordered):
+ parent_nodes = None
+ # Do not traverse to parents if this node is an
+ # an argument or a direct member of a set that has
+ # been specified as an argument (system or world).
+ if current_node not in conf.set_nodes:
+ parent_nodes = mygraph.parent_nodes(current_node)
+ if parent_nodes:
+ child_nodes = set(mygraph.child_nodes(current_node))
+ selected_parent = None
+ # First, try to avoid a direct cycle.
+ for node in parent_nodes:
+ if not isinstance(node, (Blocker, Package)):
+ continue
+ if node not in traversed_nodes and \
+ node not in child_nodes:
+ edge = (current_node, node)
+ if edge in shown_edges:
+ continue
+ selected_parent = node
+ break
+ if not selected_parent:
+ # A direct cycle is unavoidable.
+ for node in parent_nodes:
+ if not isinstance(node, (Blocker, Package)):
+ continue
+ if node not in traversed_nodes:
+ edge = (current_node, node)
+ if edge in shown_edges:
+ continue
+ selected_parent = node
+ break
+ if selected_parent:
+ shown_edges.add((current_node, selected_parent))
+ traversed_nodes.add(selected_parent)
+ add_parents(selected_parent, False)
+ display_list.append((current_node,
+ len(tree_nodes), ordered))
+ tree_nodes.append(current_node)
+ tree_nodes = []
+ add_parents(x, True)
+
+ return display_list
+
+
+def _prune_tree_display(display_list):
+ last_merge_depth = 0
+ for i in range(len(display_list) - 1, -1, -1):
+ node, depth, ordered = display_list[i]
+ if not ordered and depth == 0 and i > 0 \
+ and node == display_list[i-1][0] and \
+ display_list[i-1][1] == 0:
+ # An ordered node got a consecutive duplicate
+ # when the tree was being filled in.
+ del display_list[i]
+ continue
+ if ordered and isinstance(node, Package) \
+ and node.operation in ('merge', 'uninstall'):
+ last_merge_depth = depth
+ continue
+ if depth >= last_merge_depth or \
+ i < len(display_list) - 1 and \
+ depth >= display_list[i+1][1]:
+ del display_list[i]
+
+
+def _calc_changelog(ebuildpath,current,next):
+ if ebuildpath == None or not os.path.exists(ebuildpath):
+ return []
+ current = '-'.join(catpkgsplit(current)[1:])
+ if current.endswith('-r0'):
+ current = current[:-3]
+ next = '-'.join(catpkgsplit(next)[1:])
+ if next.endswith('-r0'):
+ next = next[:-3]
+ changelogpath = os.path.join(os.path.split(ebuildpath)[0],'ChangeLog')
+ try:
+ changelog = io.open(_unicode_encode(changelogpath,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'], errors='replace'
+ ).read()
+ except SystemExit:
+ raise # Needed else can't exit
+ except:
+ return []
+ divisions = _find_changelog_tags(changelog)
+ #print 'XX from',current,'to',next
+ #for div,text in divisions: print 'XX',div
+ # skip entries for all revisions above the one we are about to emerge
+ for i in range(len(divisions)):
+ if divisions[i][0]==next:
+ divisions = divisions[i:]
+ break
+ # find out how many entries we are going to display
+ for i in range(len(divisions)):
+ if divisions[i][0]==current:
+ divisions = divisions[:i]
+ break
+ else:
+ # couldnt find the current revision in the list. display nothing
+ return []
+ return divisions
+
+
+def _find_changelog_tags(changelog):
+ divs = []
+ release = None
+ while 1:
+ match = re.search(r'^\*\ ?([-a-zA-Z0-9_.+]*)(?:\ .*)?\n',changelog,re.M)
+ if match is None:
+ if release is not None:
+ divs.append((release,changelog))
+ return divs
+ if release is not None:
+ divs.append((release,changelog[:match.start()]))
+ changelog = changelog[match.end():]
+ release = match.group(1)
+ if release.endswith('.ebuild'):
+ release = release[:-7]
+ if release.endswith('-r0'):
+ release = release[:-3]
+
+
+class PkgInfo(object):
+ """Simple class to hold instance attributes for current
+ information about the pkg being printed.
+ """
+
+ __slots__ = ("ordered", "fetch_symbol", "operation", "merge",
+ "built", "cp", "ebuild_path", "repo_name", "repo_path_real",
+ "world", "system", "use", "oldbest", "ver"
+ )
+
+
+ def __init__(self):
+ self.built = False
+ self.cp = ''
+ self.ebuild_path = ''
+ self.fetch_symbol = ''
+ self.merge = ''
+ self.oldbest = ''
+ self.operation = ''
+ self.ordered = False
+ self.repo_path_real = ''
+ self.repo_name = ''
+ self.system = False
+ self.use = ''
+ self.ver = ''
+ self.world = False
diff --git a/portage_with_autodep/pym/_emerge/resolver/slot_collision.py b/portage_with_autodep/pym/_emerge/resolver/slot_collision.py
new file mode 100644
index 0000000..0df8f20
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/resolver/slot_collision.py
@@ -0,0 +1,978 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import sys
+
+from _emerge.AtomArg import AtomArg
+from _emerge.Package import Package
+from _emerge.PackageArg import PackageArg
+from portage.dep import check_required_use
+from portage.output import colorize
+from portage._sets.base import InternalPackageSet
+from portage.util import writemsg
+from portage.versions import cpv_getversion, vercmp
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+class slot_conflict_handler(object):
+ """This class keeps track of all slot conflicts and provides
+ an interface to get possible solutions.
+
+ How it works:
+ If two packages have been pulled into a slot, one needs to
+ go away. This class focuses on cases where this can be achieved
+ with a change in USE settings.
+
+ 1) Find out if what causes a given slot conflict. There are
+ three possibilities:
+
+ a) One parent needs foo-1:0 and another one needs foo-2:0,
+ nothing we can do about this. This is called a 'version
+ based conflict'.
+
+ b) All parents of one of the conflict packages could use
+ another conflict package. This is called an 'unspecific
+ conflict'. This should be caught by the backtracking logic.
+ Ask the user to enable -uN (if not already enabled). If -uN is
+ enabled, this case is treated in the same way as c).
+
+ c) Neither a 'version based conflict' nor an 'unspecific
+ conflict'. Ignoring use deps would result result in an
+ 'unspecific conflict'. This is called a 'specific conflict'.
+ This is the only conflict we try to find suggestions for.
+
+ 2) Computing suggestions.
+
+ Def.: "configuration": A list of packages, containing exactly one
+ package from each slot conflict.
+
+ We try to find USE changes such that all parents of conflict packages
+ can work with a package in the configuration we're looking at. This
+ is done for all possible configurations, except if the 'all-ebuild'
+ configuration has a suggestion. In this case we immediately abort the
+ search.
+ For the current configuration, all use flags that are part of violated
+ use deps are computed. This is done for every slot conflict on its own.
+
+ Def.: "solution (candidate)": An assignment of "enabled" / "disabled"
+ values for the use flags that are part of violated use deps.
+
+ Now all involved use flags for the current configuration are known. For
+ now they have an undetermined value. Fix their value in the
+ following cases:
+ * The use dep in the parent atom is unconditional.
+ * The parent package is 'installed'.
+ * The conflict package is 'installed'.
+
+ USE of 'installed' packages can't be changed. This always requires an
+ non-installed package.
+
+ During this procedure, contradictions may occur. In this case the
+ configuration has no solution.
+
+ Now generate all possible solution candidates with fixed values. Check
+ if they don't introduce new conflicts.
+
+ We have found a valid assignment for all involved use flags. Compute
+ the needed USE changes and prepare the message for the user.
+ """
+
+ def __init__(self, depgraph):
+ self.depgraph = depgraph
+ self.myopts = depgraph._frozen_config.myopts
+ self.debug = "--debug" in self.myopts
+ if self.debug:
+ writemsg("Starting slot conflict handler\n", noiselevel=-1)
+ #slot_collision_info is a dict mapping (slot atom, root) to set
+ #of packages. The packages in the set all belong to the same
+ #slot.
+ self.slot_collision_info = depgraph._dynamic_config._slot_collision_info
+
+ #A dict mapping packages to pairs of parent package
+ #and parent atom
+ self.all_parents = depgraph._dynamic_config._parent_atoms
+
+ #set containing all nodes that are part of a slot conflict
+ conflict_nodes = set()
+
+ #a list containing list of packages that form a slot conflict
+ conflict_pkgs = []
+
+ #a list containing sets of (parent, atom) pairs that have pulled packages
+ #into the same slot
+ all_conflict_atoms_by_slotatom = []
+
+ #fill conflict_pkgs, all_conflict_atoms_by_slotatom
+ for (atom, root), pkgs \
+ in self.slot_collision_info.items():
+ conflict_pkgs.append(list(pkgs))
+ all_conflict_atoms_by_slotatom.append(set())
+
+ for pkg in pkgs:
+ conflict_nodes.add(pkg)
+ for ppkg, atom in self.all_parents.get(pkg):
+ all_conflict_atoms_by_slotatom[-1].add((ppkg, atom))
+
+ #Variable that holds the non-explanation part of the message.
+ self.conflict_msg = []
+ #If any conflict package was pulled in only by unspecific atoms, then
+ #the user forgot to enable --newuse and/or --update.
+ self.conflict_is_unspecific = False
+
+ #Indicate if the conflict is caused by incompatible version requirements
+ #cat/pkg-2 pulled in, but a parent requires <cat/pkg-2
+ self.is_a_version_conflict = False
+
+ self._prepare_conflict_msg_and_check_for_specificity()
+
+ #a list of dicts that hold the needed USE values to solve all conflicts
+ self.solutions = []
+
+ #a list of dicts that hold the needed USE changes to solve all conflicts
+ self.changes = []
+
+ #configuration = a list of packages with exactly one package from every
+ #single slot conflict
+ config_gen = _configuration_generator(conflict_pkgs)
+ first_config = True
+
+ #go through all configurations and collect solutions
+ while(True):
+ config = config_gen.get_configuration()
+ if not config:
+ break
+
+ if self.debug:
+ writemsg("\nNew configuration:\n", noiselevel=-1)
+ for pkg in config:
+ writemsg(" " + str(pkg) + "\n", noiselevel=-1)
+ writemsg("\n", noiselevel=-1)
+
+ new_solutions = self._check_configuration(config, all_conflict_atoms_by_slotatom, conflict_nodes)
+
+ if new_solutions:
+ self.solutions.extend(new_solutions)
+
+ if first_config:
+ #If the "all ebuild"-config gives a solution, use it.
+ #Otherwise enumerate all other solutions.
+ if self.debug:
+ writemsg("All-ebuild configuration has a solution. Aborting search.\n", noiselevel=-1)
+ break
+ first_config = False
+
+ if len(conflict_pkgs) > 4:
+ # The number of configurations to check grows exponentially in the number of conflict_pkgs.
+ # To prevent excessive running times, only check the "all-ebuild" configuration,
+ # if the number of conflict packages is too large.
+ if self.debug:
+ writemsg("\nAborting search due to excessive number of configurations.\n", noiselevel=-1)
+ break
+
+ for solution in self.solutions:
+ self._add_change(self._get_change(solution))
+
+
+ def get_conflict(self):
+ return "".join(self.conflict_msg)
+
+ def _is_subset(self, change1, change2):
+ """
+ Checks if a set of changes 'change1' is a subset of the changes 'change2'.
+ """
+ #All pkgs of change1 have to be in change2.
+ #For every package in change1, the changes have to be a subset of
+ #the corresponding changes in change2.
+ for pkg in change1:
+ if pkg not in change2:
+ return False
+
+ for flag in change1[pkg]:
+ if flag not in change2[pkg]:
+ return False
+ if change1[pkg][flag] != change2[pkg][flag]:
+ return False
+ return True
+
+ def _add_change(self, new_change):
+ """
+ Make sure to keep only minimal changes. If "+foo", does the job, discard "+foo -bar".
+ """
+ changes = self.changes
+ #Make sure there is no other solution that is a subset of the new solution.
+ ignore = False
+ to_be_removed = []
+ for change in changes:
+ if self._is_subset(change, new_change):
+ ignore = True
+ break
+ elif self._is_subset(new_change, change):
+ to_be_removed.append(change)
+
+ if not ignore:
+ #Discard all existing change that are a superset of the new change.
+ for obsolete_change in to_be_removed:
+ changes.remove(obsolete_change)
+ changes.append(new_change)
+
+ def _get_change(self, solution):
+ _pkg_use_enabled = self.depgraph._pkg_use_enabled
+ new_change = {}
+ for pkg in solution:
+ for flag, state in solution[pkg].items():
+ if state == "enabled" and flag not in _pkg_use_enabled(pkg):
+ new_change.setdefault(pkg, {})[flag] = True
+ elif state == "disabled" and flag in _pkg_use_enabled(pkg):
+ new_change.setdefault(pkg, {})[flag] = False
+ return new_change
+
+ def _prepare_conflict_msg_and_check_for_specificity(self):
+ """
+ Print all slot conflicts in a human readable way.
+ """
+ _pkg_use_enabled = self.depgraph._pkg_use_enabled
+ msg = self.conflict_msg
+ indent = " "
+ msg.append("\n!!! Multiple package instances within a single " + \
+ "package slot have been pulled\n")
+ msg.append("!!! into the dependency graph, resulting" + \
+ " in a slot conflict:\n\n")
+
+ for (slot_atom, root), pkgs \
+ in self.slot_collision_info.items():
+ msg.append(str(slot_atom))
+ if root != '/':
+ msg.append(" for %s" % (root,))
+ msg.append("\n\n")
+
+ for pkg in pkgs:
+ msg.append(indent)
+ msg.append(str(pkg))
+ parent_atoms = self.all_parents.get(pkg)
+ if parent_atoms:
+ #Create a list of collision reasons and map them to sets
+ #of atoms.
+ #Possible reasons:
+ # ("version", "ge") for operator >=, >
+ # ("version", "eq") for operator =, ~
+ # ("version", "le") for operator <=, <
+ # ("use", "<some use flag>") for unmet use conditionals
+ collision_reasons = {}
+ num_all_specific_atoms = 0
+
+ for ppkg, atom in parent_atoms:
+ atom_set = InternalPackageSet(initial_atoms=(atom,))
+ atom_without_use_set = InternalPackageSet(initial_atoms=(atom.without_use,))
+
+ for other_pkg in pkgs:
+ if other_pkg == pkg:
+ continue
+
+ if not atom_without_use_set.findAtomForPackage(other_pkg, \
+ modified_use=_pkg_use_enabled(other_pkg)):
+ #The version range does not match.
+ sub_type = None
+ if atom.operator in (">=", ">"):
+ sub_type = "ge"
+ elif atom.operator in ("=", "~"):
+ sub_type = "eq"
+ elif atom.operator in ("<=", "<"):
+ sub_type = "le"
+
+ atoms = collision_reasons.get(("version", sub_type), set())
+ atoms.add((ppkg, atom, other_pkg))
+ num_all_specific_atoms += 1
+ collision_reasons[("version", sub_type)] = atoms
+ elif not atom_set.findAtomForPackage(other_pkg, \
+ modified_use=_pkg_use_enabled(other_pkg)):
+ missing_iuse = other_pkg.iuse.get_missing_iuse(
+ atom.unevaluated_atom.use.required)
+ if missing_iuse:
+ for flag in missing_iuse:
+ atoms = collision_reasons.get(("use", flag), set())
+ atoms.add((ppkg, atom, other_pkg))
+ collision_reasons[("use", flag)] = atoms
+ num_all_specific_atoms += 1
+ else:
+ #Use conditionals not met.
+ violated_atom = atom.violated_conditionals(_pkg_use_enabled(other_pkg), \
+ other_pkg.iuse.is_valid_flag)
+ for flag in violated_atom.use.enabled.union(violated_atom.use.disabled):
+ atoms = collision_reasons.get(("use", flag), set())
+ atoms.add((ppkg, atom, other_pkg))
+ collision_reasons[("use", flag)] = atoms
+ num_all_specific_atoms += 1
+
+ msg.append(" pulled in by\n")
+
+ selected_for_display = set()
+ unconditional_use_deps = set()
+
+ for (type, sub_type), parents in collision_reasons.items():
+ #From each (type, sub_type) pair select at least one atom.
+ #Try to select as few atoms as possible
+
+ if type == "version":
+ #Find the atom with version that is as far away as possible.
+ best_matches = {}
+ for ppkg, atom, other_pkg in parents:
+ if atom.cp in best_matches:
+ cmp = vercmp( \
+ cpv_getversion(atom.cpv), \
+ cpv_getversion(best_matches[atom.cp][1].cpv))
+
+ if (sub_type == "ge" and cmp > 0) \
+ or (sub_type == "le" and cmp < 0) \
+ or (sub_type == "eq" and cmp > 0):
+ best_matches[atom.cp] = (ppkg, atom)
+ else:
+ best_matches[atom.cp] = (ppkg, atom)
+ selected_for_display.update(best_matches.values())
+ elif type == "use":
+ #Prefer atoms with unconditional use deps over, because it's
+ #not possible to change them on the parent, which means there
+ #are fewer possible solutions.
+ use = sub_type
+ for ppkg, atom, other_pkg in parents:
+ missing_iuse = other_pkg.iuse.get_missing_iuse(
+ atom.unevaluated_atom.use.required)
+ if missing_iuse:
+ unconditional_use_deps.add((ppkg, atom))
+ else:
+ parent_use = None
+ if isinstance(ppkg, Package):
+ parent_use = _pkg_use_enabled(ppkg)
+ violated_atom = atom.unevaluated_atom.violated_conditionals(
+ _pkg_use_enabled(other_pkg),
+ other_pkg.iuse.is_valid_flag,
+ parent_use=parent_use)
+ # It's possible for autounmask to change
+ # parent_use such that the unevaluated form
+ # of the atom now matches, even though the
+ # earlier evaluated form (from before
+ # autounmask changed parent_use) does not.
+ # In this case (see bug #374423), it's
+ # expected that violated_atom.use is None.
+ # Since the atom now matches, we don't want
+ # to display it in the slot conflict
+ # message, so we simply ignore it and rely
+ # on the autounmask display to communicate
+ # the necessary USE change to the user.
+ if violated_atom.use is None:
+ continue
+ if use in violated_atom.use.enabled or \
+ use in violated_atom.use.disabled:
+ unconditional_use_deps.add((ppkg, atom))
+ # When USE flags are removed, it can be
+ # essential to see all broken reverse
+ # dependencies here, so don't omit any.
+ # If the list is long, people can simply
+ # use a pager.
+ selected_for_display.add((ppkg, atom))
+
+ def highlight_violations(atom, version, use=[]):
+ """Colorize parts of an atom"""
+ atom_str = str(atom)
+ if version:
+ op = atom.operator
+ ver = None
+ if atom.cp != atom.cpv:
+ ver = cpv_getversion(atom.cpv)
+ slot = atom.slot
+
+ if op == "=*":
+ op = "="
+ ver += "*"
+
+ if op is not None:
+ atom_str = atom_str.replace(op, colorize("BAD", op), 1)
+
+ if ver is not None:
+ start = atom_str.rfind(ver)
+ end = start + len(ver)
+ atom_str = atom_str[:start] + \
+ colorize("BAD", ver) + \
+ atom_str[end:]
+ if slot:
+ atom_str = atom_str.replace(":" + slot, colorize("BAD", ":" + slot))
+
+ if use and atom.use.tokens:
+ use_part_start = atom_str.find("[")
+ use_part_end = atom_str.find("]")
+
+ new_tokens = []
+ for token in atom.use.tokens:
+ if token.lstrip("-!").rstrip("=?") in use:
+ new_tokens.append(colorize("BAD", token))
+ else:
+ new_tokens.append(token)
+
+ atom_str = atom_str[:use_part_start] \
+ + "[%s]" % (",".join(new_tokens),) + \
+ atom_str[use_part_end+1:]
+
+ return atom_str
+
+ # Show unconditional use deps first, since those
+ # are more problematic than the conditional kind.
+ ordered_list = list(unconditional_use_deps)
+ if len(selected_for_display) > len(unconditional_use_deps):
+ for parent_atom in selected_for_display:
+ if parent_atom not in unconditional_use_deps:
+ ordered_list.append(parent_atom)
+ for parent_atom in ordered_list:
+ parent, atom = parent_atom
+ msg.append(2*indent)
+ if isinstance(parent,
+ (PackageArg, AtomArg)):
+ # For PackageArg and AtomArg types, it's
+ # redundant to display the atom attribute.
+ msg.append(str(parent))
+ else:
+ # Display the specific atom from SetArg or
+ # Package types.
+ version_violated = False
+ use = []
+ for (type, sub_type), parents in collision_reasons.items():
+ for x in parents:
+ if parent == x[0] and atom == x[1]:
+ if type == "version":
+ version_violated = True
+ elif type == "use":
+ use.append(sub_type)
+ break
+
+ atom_str = highlight_violations(atom.unevaluated_atom, version_violated, use)
+
+ if version_violated:
+ self.is_a_version_conflict = True
+
+ msg.append("%s required by %s" % (atom_str, parent))
+ msg.append("\n")
+
+ if not selected_for_display:
+ msg.append(2*indent)
+ msg.append("(no parents that aren't satisfied by other packages in this slot)\n")
+ self.conflict_is_unspecific = True
+
+ omitted_parents = num_all_specific_atoms - len(selected_for_display)
+ if omitted_parents:
+ msg.append(2*indent)
+ if len(selected_for_display) > 1:
+ msg.append("(and %d more with the same problems)\n" % omitted_parents)
+ else:
+ msg.append("(and %d more with the same problem)\n" % omitted_parents)
+ else:
+ msg.append(" (no parents)\n")
+ msg.append("\n")
+ msg.append("\n")
+
+ def get_explanation(self):
+ msg = ""
+ _pkg_use_enabled = self.depgraph._pkg_use_enabled
+
+ if self.is_a_version_conflict:
+ return None
+
+ if self.conflict_is_unspecific and \
+ not ("--newuse" in self.myopts and "--update" in self.myopts):
+ msg += "!!! Enabling --newuse and --update might solve this conflict.\n"
+ msg += "!!! If not, it might help emerge to give a more specific suggestion.\n\n"
+ return msg
+
+ solutions = self.solutions
+ if not solutions:
+ return None
+
+ if len(solutions)==1:
+ if len(self.slot_collision_info)==1:
+ msg += "It might be possible to solve this slot collision\n"
+ else:
+ msg += "It might be possible to solve these slot collisions\n"
+ msg += "by applying all of the following changes:\n"
+ else:
+ if len(self.slot_collision_info)==1:
+ msg += "It might be possible to solve this slot collision\n"
+ else:
+ msg += "It might be possible to solve these slot collisions\n"
+ msg += "by applying one of the following solutions:\n"
+
+ def print_change(change, indent=""):
+ mymsg = ""
+ for pkg in change:
+ changes = []
+ for flag, state in change[pkg].items():
+ if state:
+ changes.append(colorize("red", "+" + flag))
+ else:
+ changes.append(colorize("blue", "-" + flag))
+ mymsg += indent + "- " + pkg.cpv + " (Change USE: %s" % " ".join(changes) + ")\n"
+ mymsg += "\n"
+ return mymsg
+
+
+ if len(self.changes) == 1:
+ msg += print_change(self.changes[0], " ")
+ else:
+ for change in self.changes:
+ msg += " Solution: Apply all of:\n"
+ msg += print_change(change, " ")
+
+ return msg
+
+ def _check_configuration(self, config, all_conflict_atoms_by_slotatom, conflict_nodes):
+ """
+ Given a configuartion, required use changes are computed and checked to
+ make sure that no new conflict is introduced. Returns a solution or None.
+ """
+ _pkg_use_enabled = self.depgraph._pkg_use_enabled
+ #An installed package can only be part of a valid configuration if it has no
+ #pending use changed. Otherwise the ebuild will be pulled in again.
+ for pkg in config:
+ if not pkg.installed:
+ continue
+
+ for (atom, root), pkgs \
+ in self.slot_collision_info.items():
+ if pkg not in pkgs:
+ continue
+ for other_pkg in pkgs:
+ if other_pkg == pkg:
+ continue
+ if pkg.iuse.all.symmetric_difference(other_pkg.iuse.all) \
+ or _pkg_use_enabled(pkg).symmetric_difference(_pkg_use_enabled(other_pkg)):
+ if self.debug:
+ writemsg(str(pkg) + " has pending USE changes. Rejecting configuration.\n", noiselevel=-1)
+ return False
+
+ #A list of dicts. Keeps one dict per slot conflict. [ { flag1: "enabled" }, { flag2: "disabled" } ]
+ all_involved_flags = []
+
+ #Go through all slot conflicts
+ for id, pkg in enumerate(config):
+ involved_flags = {}
+ for ppkg, atom in all_conflict_atoms_by_slotatom[id]:
+ if ppkg in conflict_nodes and not ppkg in config:
+ #The parent is part of a slot conflict itself and is
+ #not part of the current config.
+ continue
+
+ i = InternalPackageSet(initial_atoms=(atom,))
+ if i.findAtomForPackage(pkg, modified_use=_pkg_use_enabled(pkg)):
+ continue
+
+ i = InternalPackageSet(initial_atoms=(atom.without_use,))
+ if not i.findAtomForPackage(pkg, modified_use=_pkg_use_enabled(pkg)):
+ #Version range does not match.
+ if self.debug:
+ writemsg(str(pkg) + " does not satify all version requirements." + \
+ " Rejecting configuration.\n", noiselevel=-1)
+ return False
+
+ if not pkg.iuse.is_valid_flag(atom.unevaluated_atom.use.required):
+ #Missing IUSE.
+ #FIXME: This needs to support use dep defaults.
+ if self.debug:
+ writemsg(str(pkg) + " misses needed flags from IUSE." + \
+ " Rejecting configuration.\n", noiselevel=-1)
+ return False
+
+ if not isinstance(ppkg, Package) or ppkg.installed:
+ #We cannot assume that it's possible to reinstall the package. Do not
+ #check if some of its atom has use.conditional
+ violated_atom = atom.violated_conditionals(_pkg_use_enabled(pkg), \
+ pkg.iuse.is_valid_flag)
+ else:
+ violated_atom = atom.unevaluated_atom.violated_conditionals(_pkg_use_enabled(pkg), \
+ pkg.iuse.is_valid_flag, parent_use=_pkg_use_enabled(ppkg))
+ if violated_atom.use is None:
+ # It's possible for autounmask to change
+ # parent_use such that the unevaluated form
+ # of the atom now matches, even though the
+ # earlier evaluated form (from before
+ # autounmask changed parent_use) does not.
+ # In this case (see bug #374423), it's
+ # expected that violated_atom.use is None.
+ continue
+
+ if pkg.installed and (violated_atom.use.enabled or violated_atom.use.disabled):
+ #We can't change USE of an installed package (only of an ebuild, but that is already
+ #part of the conflict, isn't it?
+ if self.debug:
+ writemsg(str(pkg) + ": installed package would need USE changes." + \
+ " Rejecting configuration.\n", noiselevel=-1)
+ return False
+
+ #Compute the required USE changes. A flag can be forced to "enabled" or "disabled",
+ #it can be in the conditional state "cond" that allows both values or in the
+ #"contradiction" state, which means that some atoms insist on differnt values
+ #for this flag and those kill this configuration.
+ for flag in violated_atom.use.required:
+ state = involved_flags.get(flag, "")
+
+ if flag in violated_atom.use.enabled:
+ if state in ("", "cond", "enabled"):
+ state = "enabled"
+ else:
+ state = "contradiction"
+ elif flag in violated_atom.use.disabled:
+ if state in ("", "cond", "disabled"):
+ state = "disabled"
+ else:
+ state = "contradiction"
+ else:
+ if state == "":
+ state = "cond"
+
+ involved_flags[flag] = state
+
+ if pkg.installed:
+ #We don't change the installed pkg's USE. Force all involved flags
+ #to the same value as the installed package has it.
+ for flag in involved_flags:
+ if involved_flags[flag] == "enabled":
+ if not flag in _pkg_use_enabled(pkg):
+ involved_flags[flag] = "contradiction"
+ elif involved_flags[flag] == "disabled":
+ if flag in _pkg_use_enabled(pkg):
+ involved_flags[flag] = "contradiction"
+ elif involved_flags[flag] == "cond":
+ if flag in _pkg_use_enabled(pkg):
+ involved_flags[flag] = "enabled"
+ else:
+ involved_flags[flag] = "disabled"
+
+ for flag, state in involved_flags.items():
+ if state == "contradiction":
+ if self.debug:
+ writemsg("Contradicting requirements found for flag " + \
+ flag + ". Rejecting configuration.\n", noiselevel=-1)
+ return False
+
+ all_involved_flags.append(involved_flags)
+
+ if self.debug:
+ writemsg("All involved flags:\n", noiselevel=-1)
+ for id, involved_flags in enumerate(all_involved_flags):
+ writemsg(" " + str(config[id]) + "\n", noiselevel=-1)
+ for flag, state in involved_flags.items():
+ writemsg(" " + flag + ": " + state + "\n", noiselevel=-1)
+
+ solutions = []
+ sol_gen = _solution_candidate_generator(all_involved_flags)
+ while(True):
+ candidate = sol_gen.get_candidate()
+ if not candidate:
+ break
+ solution = self._check_solution(config, candidate, all_conflict_atoms_by_slotatom)
+ if solution:
+ solutions.append(solution)
+
+ if self.debug:
+ if not solutions:
+ writemsg("No viable solutions. Rejecting configuration.\n", noiselevel=-1)
+ return solutions
+
+
+ def _force_flag_for_package(self, required_changes, pkg, flag, state):
+ """
+ Adds an USE change to required_changes. Sets the target state to
+ "contradiction" if a flag is forced to conflicting values.
+ """
+ _pkg_use_enabled = self.depgraph._pkg_use_enabled
+
+ if state == "disabled":
+ changes = required_changes.get(pkg, {})
+ flag_change = changes.get(flag, "")
+ if flag_change == "enabled":
+ flag_change = "contradiction"
+ elif flag in _pkg_use_enabled(pkg):
+ flag_change = "disabled"
+
+ changes[flag] = flag_change
+ required_changes[pkg] = changes
+ elif state == "enabled":
+ changes = required_changes.get(pkg, {})
+ flag_change = changes.get(flag, "")
+ if flag_change == "disabled":
+ flag_change = "contradiction"
+ else:
+ flag_change = "enabled"
+
+ changes[flag] = flag_change
+ required_changes[pkg] = changes
+
+ def _check_solution(self, config, all_involved_flags, all_conflict_atoms_by_slotatom):
+ """
+ Given a configuartion and all involved flags, all possible settings for the involved
+ flags are checked if they solve the slot conflict.
+ """
+ _pkg_use_enabled = self.depgraph._pkg_use_enabled
+
+ if self.debug:
+ #The code is a bit verbose, because the states might not
+ #be a string, but a _value_helper.
+ msg = "Solution candidate: "
+ msg += "["
+ first = True
+ for involved_flags in all_involved_flags:
+ if first:
+ first = False
+ else:
+ msg += ", "
+ msg += "{"
+ inner_first = True
+ for flag, state in involved_flags.items():
+ if inner_first:
+ inner_first = False
+ else:
+ msg += ", "
+ msg += flag + ": " + str(state)
+ msg += "}"
+ msg += "]\n"
+ writemsg(msg, noiselevel=-1)
+
+ required_changes = {}
+ for id, pkg in enumerate(config):
+ if not pkg.installed:
+ #We can't change the USE of installed packages.
+ for flag in all_involved_flags[id]:
+ if not pkg.iuse.is_valid_flag(flag):
+ continue
+ state = all_involved_flags[id][flag]
+ self._force_flag_for_package(required_changes, pkg, flag, state)
+
+ #Go through all (parent, atom) pairs for the current slot conflict.
+ for ppkg, atom in all_conflict_atoms_by_slotatom[id]:
+ use = atom.unevaluated_atom.use
+ if not use:
+ #No need to force something for an atom without USE conditionals.
+ #These atoms are already satisfied.
+ continue
+ for flag in all_involved_flags[id]:
+ state = all_involved_flags[id][flag]
+
+ if flag not in use.required or not use.conditional:
+ continue
+ if flag in use.conditional.enabled:
+ #[flag?]
+ if state == "enabled":
+ #no need to change anything, the atom won't
+ #force -flag on pkg
+ pass
+ elif state == "disabled":
+ #if flag is enabled we get [flag] -> it must be disabled
+ self._force_flag_for_package(required_changes, ppkg, flag, "disabled")
+ elif flag in use.conditional.disabled:
+ #[!flag?]
+ if state == "enabled":
+ #if flag is enabled we get [-flag] -> it must be disabled
+ self._force_flag_for_package(required_changes, ppkg, flag, "disabled")
+ elif state == "disabled":
+ #no need to change anything, the atom won't
+ #force +flag on pkg
+ pass
+ elif flag in use.conditional.equal:
+ #[flag=]
+ if state == "enabled":
+ #if flag is disabled we get [-flag] -> it must be enabled
+ self._force_flag_for_package(required_changes, ppkg, flag, "enabled")
+ elif state == "disabled":
+ #if flag is enabled we get [flag] -> it must be disabled
+ self._force_flag_for_package(required_changes, ppkg, flag, "disabled")
+ elif flag in use.conditional.not_equal:
+ #[!flag=]
+ if state == "enabled":
+ #if flag is enabled we get [-flag] -> it must be disabled
+ self._force_flag_for_package(required_changes, ppkg, flag, "disabled")
+ elif state == "disabled":
+ #if flag is disabled we get [flag] -> it must be enabled
+ self._force_flag_for_package(required_changes, ppkg, flag, "enabled")
+
+ is_valid_solution = True
+ for pkg in required_changes:
+ for state in required_changes[pkg].values():
+ if not state in ("enabled", "disabled"):
+ is_valid_solution = False
+
+ if not is_valid_solution:
+ return None
+
+ #Check if all atoms are satisfied after the changes are applied.
+ for id, pkg in enumerate(config):
+ new_use = _pkg_use_enabled(pkg)
+ if pkg in required_changes:
+ old_use = pkg.use.enabled
+ new_use = set(new_use)
+ for flag, state in required_changes[pkg].items():
+ if state == "enabled":
+ new_use.add(flag)
+ elif state == "disabled":
+ new_use.discard(flag)
+ if not new_use.symmetric_difference(old_use):
+ #avoid copying the package in findAtomForPackage if possible
+ new_use = old_use
+
+ for ppkg, atom in all_conflict_atoms_by_slotatom[id]:
+ if not hasattr(ppkg, "use"):
+ #It's a SetArg or something like that.
+ continue
+ ppkg_new_use = set(_pkg_use_enabled(ppkg))
+ if ppkg in required_changes:
+ for flag, state in required_changes[ppkg].items():
+ if state == "enabled":
+ ppkg_new_use.add(flag)
+ elif state == "disabled":
+ ppkg_new_use.discard(flag)
+
+ new_atom = atom.unevaluated_atom.evaluate_conditionals(ppkg_new_use)
+ i = InternalPackageSet(initial_atoms=(new_atom,))
+ if not i.findAtomForPackage(pkg, new_use):
+ #We managed to create a new problem with our changes.
+ is_valid_solution = False
+ if self.debug:
+ writemsg("new conflict introduced: " + str(pkg) + \
+ " does not match " + new_atom + " from " + str(ppkg) + "\n", noiselevel=-1)
+ break
+
+ if not is_valid_solution:
+ break
+
+ #Make sure the changes don't violate REQUIRED_USE
+ for pkg in required_changes:
+ required_use = pkg.metadata["REQUIRED_USE"]
+ if not required_use:
+ continue
+
+ use = set(_pkg_use_enabled(pkg))
+ for flag, state in required_changes[pkg].items():
+ if state == "enabled":
+ use.add(flag)
+ else:
+ use.discard(flag)
+
+ if not check_required_use(required_use, use, pkg.iuse.is_valid_flag):
+ is_valid_solution = False
+ break
+
+ if is_valid_solution and required_changes:
+ return required_changes
+ else:
+ return None
+
+class _configuration_generator(object):
+ def __init__(self, conflict_pkgs):
+ #reorder packages such that installed packages come last
+ self.conflict_pkgs = []
+ for pkgs in conflict_pkgs:
+ new_pkgs = []
+ for pkg in pkgs:
+ if not pkg.installed:
+ new_pkgs.append(pkg)
+ for pkg in pkgs:
+ if pkg.installed:
+ new_pkgs.append(pkg)
+ self.conflict_pkgs.append(new_pkgs)
+
+ self.solution_ids = []
+ for pkgs in self.conflict_pkgs:
+ self.solution_ids.append(0)
+ self._is_first_solution = True
+
+ def get_configuration(self):
+ if self._is_first_solution:
+ self._is_first_solution = False
+ else:
+ if not self._next():
+ return None
+
+ solution = []
+ for id, pkgs in enumerate(self.conflict_pkgs):
+ solution.append(pkgs[self.solution_ids[id]])
+ return solution
+
+ def _next(self, id=None):
+ solution_ids = self.solution_ids
+ conflict_pkgs = self.conflict_pkgs
+
+ if id is None:
+ id = len(solution_ids)-1
+
+ if solution_ids[id] == len(conflict_pkgs[id])-1:
+ if id > 0:
+ return self._next(id=id-1)
+ else:
+ return False
+ else:
+ solution_ids[id] += 1
+ for other_id in range(id+1, len(solution_ids)):
+ solution_ids[other_id] = 0
+ return True
+
+class _solution_candidate_generator(object):
+ class _value_helper(object):
+ def __init__(self, value=None):
+ self.value = value
+ def __eq__(self, other):
+ if isinstance(other, basestring):
+ return self.value == other
+ else:
+ return self.value == other.value
+ def __str__(self):
+ return str(self.value)
+
+ def __init__(self, all_involved_flags):
+ #A copy of all_involved_flags with all "cond" values
+ #replaced by a _value_helper object.
+ self.all_involved_flags = []
+
+ #A list tracking references to all used _value_helper
+ #objects.
+ self.conditional_values = []
+
+ for involved_flags in all_involved_flags:
+ new_involved_flags = {}
+ for flag, state in involved_flags.items():
+ if state in ("enabled", "disabled"):
+ new_involved_flags[flag] = state
+ else:
+ v = self._value_helper("disabled")
+ new_involved_flags[flag] = v
+ self.conditional_values.append(v)
+ self.all_involved_flags.append(new_involved_flags)
+
+ self._is_first_solution = True
+
+ def get_candidate(self):
+ if self._is_first_solution:
+ self._is_first_solution = False
+ else:
+ if not self._next():
+ return None
+
+ return self.all_involved_flags
+
+ def _next(self, id=None):
+ values = self.conditional_values
+
+ if not values:
+ return False
+
+ if id is None:
+ id = len(values)-1
+
+ if values[id].value == "enabled":
+ if id > 0:
+ return self._next(id=id-1)
+ else:
+ return False
+ else:
+ values[id].value = "enabled"
+ for other_id in range(id+1, len(values)):
+ values[other_id].value = "disabled"
+ return True
+
+
diff --git a/portage_with_autodep/pym/_emerge/search.py b/portage_with_autodep/pym/_emerge/search.py
new file mode 100644
index 0000000..35f0412
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/search.py
@@ -0,0 +1,385 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import re
+import portage
+from portage import os
+from portage.output import bold, bold as white, darkgreen, green, red
+from portage.util import writemsg_stdout
+
+from _emerge.Package import Package
+
+class search(object):
+
+ #
+ # class constants
+ #
+ VERSION_SHORT=1
+ VERSION_RELEASE=2
+
+ #
+ # public interface
+ #
+ def __init__(self, root_config, spinner, searchdesc,
+ verbose, usepkg, usepkgonly):
+ """Searches the available and installed packages for the supplied search key.
+ The list of available and installed packages is created at object instantiation.
+ This makes successive searches faster."""
+ self.settings = root_config.settings
+ self.vartree = root_config.trees["vartree"]
+ self.spinner = spinner
+ self.verbose = verbose
+ self.searchdesc = searchdesc
+ self.root_config = root_config
+ self.setconfig = root_config.setconfig
+ self.matches = {"pkg" : []}
+ self.mlen = 0
+
+ self._dbs = []
+
+ portdb = root_config.trees["porttree"].dbapi
+ bindb = root_config.trees["bintree"].dbapi
+ vardb = root_config.trees["vartree"].dbapi
+
+ if not usepkgonly and portdb._have_root_eclass_dir:
+ self._dbs.append(portdb)
+
+ if (usepkg or usepkgonly) and bindb.cp_all():
+ self._dbs.append(bindb)
+
+ self._dbs.append(vardb)
+ self._portdb = portdb
+
+ def _spinner_update(self):
+ if self.spinner:
+ self.spinner.update()
+
+ def _cp_all(self):
+ cp_all = set()
+ for db in self._dbs:
+ cp_all.update(db.cp_all())
+ return list(sorted(cp_all))
+
+ def _aux_get(self, *args, **kwargs):
+ for db in self._dbs:
+ try:
+ return db.aux_get(*args, **kwargs)
+ except KeyError:
+ pass
+ raise
+
+ def _findname(self, *args, **kwargs):
+ for db in self._dbs:
+ if db is not self._portdb:
+ # We don't want findname to return anything
+ # unless it's an ebuild in a portage tree.
+ # Otherwise, it's already built and we don't
+ # care about it.
+ continue
+ func = getattr(db, "findname", None)
+ if func:
+ value = func(*args, **kwargs)
+ if value:
+ return value
+ return None
+
+ def _getFetchMap(self, *args, **kwargs):
+ for db in self._dbs:
+ func = getattr(db, "getFetchMap", None)
+ if func:
+ value = func(*args, **kwargs)
+ if value:
+ return value
+ return {}
+
+ def _visible(self, db, cpv, metadata):
+ installed = db is self.vartree.dbapi
+ built = installed or db is not self._portdb
+ pkg_type = "ebuild"
+ if installed:
+ pkg_type = "installed"
+ elif built:
+ pkg_type = "binary"
+ return Package(type_name=pkg_type,
+ root_config=self.root_config,
+ cpv=cpv, built=built, installed=installed,
+ metadata=metadata).visible
+
+ def _xmatch(self, level, atom):
+ """
+ This method does not expand old-style virtuals because it
+ is restricted to returning matches for a single ${CATEGORY}/${PN}
+ and old-style virual matches unreliable for that when querying
+ multiple package databases. If necessary, old-style virtuals
+ can be performed on atoms prior to calling this method.
+ """
+ cp = portage.dep_getkey(atom)
+ if level == "match-all":
+ matches = set()
+ for db in self._dbs:
+ if hasattr(db, "xmatch"):
+ matches.update(db.xmatch(level, atom))
+ else:
+ matches.update(db.match(atom))
+ result = list(x for x in matches if portage.cpv_getkey(x) == cp)
+ db._cpv_sort_ascending(result)
+ elif level == "match-visible":
+ matches = set()
+ for db in self._dbs:
+ if hasattr(db, "xmatch"):
+ matches.update(db.xmatch(level, atom))
+ else:
+ db_keys = list(db._aux_cache_keys)
+ for cpv in db.match(atom):
+ metadata = zip(db_keys,
+ db.aux_get(cpv, db_keys))
+ if not self._visible(db, cpv, metadata):
+ continue
+ matches.add(cpv)
+ result = list(x for x in matches if portage.cpv_getkey(x) == cp)
+ db._cpv_sort_ascending(result)
+ elif level == "bestmatch-visible":
+ result = None
+ for db in self._dbs:
+ if hasattr(db, "xmatch"):
+ cpv = db.xmatch("bestmatch-visible", atom)
+ if not cpv or portage.cpv_getkey(cpv) != cp:
+ continue
+ if not result or cpv == portage.best([cpv, result]):
+ result = cpv
+ else:
+ db_keys = Package.metadata_keys
+ # break out of this loop with highest visible
+ # match, checked in descending order
+ for cpv in reversed(db.match(atom)):
+ if portage.cpv_getkey(cpv) != cp:
+ continue
+ metadata = zip(db_keys,
+ db.aux_get(cpv, db_keys))
+ if not self._visible(db, cpv, metadata):
+ continue
+ if not result or cpv == portage.best([cpv, result]):
+ result = cpv
+ break
+ else:
+ raise NotImplementedError(level)
+ return result
+
+ def execute(self,searchkey):
+ """Performs the search for the supplied search key"""
+ match_category = 0
+ self.searchkey=searchkey
+ self.packagematches = []
+ if self.searchdesc:
+ self.searchdesc=1
+ self.matches = {"pkg":[], "desc":[], "set":[]}
+ else:
+ self.searchdesc=0
+ self.matches = {"pkg":[], "set":[]}
+ print("Searching... ", end=' ')
+
+ regexsearch = False
+ if self.searchkey.startswith('%'):
+ regexsearch = True
+ self.searchkey = self.searchkey[1:]
+ if self.searchkey.startswith('@'):
+ match_category = 1
+ self.searchkey = self.searchkey[1:]
+ if regexsearch:
+ self.searchre=re.compile(self.searchkey,re.I)
+ else:
+ self.searchre=re.compile(re.escape(self.searchkey), re.I)
+
+ for package in self._cp_all():
+ self._spinner_update()
+
+ if match_category:
+ match_string = package[:]
+ else:
+ match_string = package.split("/")[-1]
+
+ masked=0
+ if self.searchre.search(match_string):
+ if not self._xmatch("match-visible", package):
+ masked=1
+ self.matches["pkg"].append([package,masked])
+ elif self.searchdesc: # DESCRIPTION searching
+ full_package = self._xmatch("bestmatch-visible", package)
+ if not full_package:
+ #no match found; we don't want to query description
+ full_package = portage.best(
+ self._xmatch("match-all", package))
+ if not full_package:
+ continue
+ else:
+ masked=1
+ try:
+ full_desc = self._aux_get(
+ full_package, ["DESCRIPTION"])[0]
+ except KeyError:
+ print("emerge: search: aux_get() failed, skipping")
+ continue
+ if self.searchre.search(full_desc):
+ self.matches["desc"].append([full_package,masked])
+
+ self.sdict = self.setconfig.getSets()
+ for setname in self.sdict:
+ self._spinner_update()
+ if match_category:
+ match_string = setname
+ else:
+ match_string = setname.split("/")[-1]
+
+ if self.searchre.search(match_string):
+ self.matches["set"].append([setname, False])
+ elif self.searchdesc:
+ if self.searchre.search(
+ self.sdict[setname].getMetadata("DESCRIPTION")):
+ self.matches["set"].append([setname, False])
+
+ self.mlen=0
+ for mtype in self.matches:
+ self.matches[mtype].sort()
+ self.mlen += len(self.matches[mtype])
+
+ def addCP(self, cp):
+ if not self._xmatch("match-all", cp):
+ return
+ masked = 0
+ if not self._xmatch("bestmatch-visible", cp):
+ masked = 1
+ self.matches["pkg"].append([cp, masked])
+ self.mlen += 1
+
+ def output(self):
+ """Outputs the results of the search."""
+ msg = []
+ msg.append("\b\b \n[ Results for search key : " + \
+ bold(self.searchkey) + " ]\n")
+ msg.append("[ Applications found : " + \
+ bold(str(self.mlen)) + " ]\n\n")
+ vardb = self.vartree.dbapi
+ for mtype in self.matches:
+ for match,masked in self.matches[mtype]:
+ full_package = None
+ if mtype == "pkg":
+ catpack = match
+ full_package = self._xmatch(
+ "bestmatch-visible", match)
+ if not full_package:
+ #no match found; we don't want to query description
+ masked=1
+ full_package = portage.best(
+ self._xmatch("match-all",match))
+ elif mtype == "desc":
+ full_package = match
+ match = portage.cpv_getkey(match)
+ elif mtype == "set":
+ msg.append(green("*") + " " + bold(match) + "\n")
+ if self.verbose:
+ msg.append(" " + darkgreen("Description:") + \
+ " " + \
+ self.sdict[match].getMetadata("DESCRIPTION") \
+ + "\n\n")
+ if full_package:
+ try:
+ desc, homepage, license = self._aux_get(
+ full_package, ["DESCRIPTION","HOMEPAGE","LICENSE"])
+ except KeyError:
+ msg.append("emerge: search: aux_get() failed, skipping\n")
+ continue
+ if masked:
+ msg.append(green("*") + " " + \
+ white(match) + " " + red("[ Masked ]") + "\n")
+ else:
+ msg.append(green("*") + " " + bold(match) + "\n")
+ myversion = self.getVersion(full_package, search.VERSION_RELEASE)
+
+ mysum = [0,0]
+ file_size_str = None
+ mycat = match.split("/")[0]
+ mypkg = match.split("/")[1]
+ mycpv = match + "-" + myversion
+ myebuild = self._findname(mycpv)
+ if myebuild:
+ pkgdir = os.path.dirname(myebuild)
+ from portage import manifest
+ mf = manifest.Manifest(
+ pkgdir, self.settings["DISTDIR"])
+ try:
+ uri_map = self._getFetchMap(mycpv)
+ except portage.exception.InvalidDependString as e:
+ file_size_str = "Unknown (%s)" % (e,)
+ del e
+ else:
+ try:
+ mysum[0] = mf.getDistfilesSize(uri_map)
+ except KeyError as e:
+ file_size_str = "Unknown (missing " + \
+ "digest for %s)" % (e,)
+ del e
+
+ available = False
+ for db in self._dbs:
+ if db is not vardb and \
+ db.cpv_exists(mycpv):
+ available = True
+ if not myebuild and hasattr(db, "bintree"):
+ myebuild = db.bintree.getname(mycpv)
+ try:
+ mysum[0] = os.stat(myebuild).st_size
+ except OSError:
+ myebuild = None
+ break
+
+ if myebuild and file_size_str is None:
+ mystr = str(mysum[0] // 1024)
+ mycount = len(mystr)
+ while (mycount > 3):
+ mycount -= 3
+ mystr = mystr[:mycount] + "," + mystr[mycount:]
+ file_size_str = mystr + " kB"
+
+ if self.verbose:
+ if available:
+ msg.append(" %s %s\n" % \
+ (darkgreen("Latest version available:"),
+ myversion))
+ msg.append(" %s\n" % \
+ self.getInstallationStatus(mycat+'/'+mypkg))
+ if myebuild:
+ msg.append(" %s %s\n" % \
+ (darkgreen("Size of files:"), file_size_str))
+ msg.append(" " + darkgreen("Homepage:") + \
+ " " + homepage + "\n")
+ msg.append(" " + darkgreen("Description:") \
+ + " " + desc + "\n")
+ msg.append(" " + darkgreen("License:") + \
+ " " + license + "\n\n")
+ writemsg_stdout(''.join(msg), noiselevel=-1)
+ #
+ # private interface
+ #
+ def getInstallationStatus(self,package):
+ installed_package = self.vartree.dep_bestmatch(package)
+ result = ""
+ version = self.getVersion(installed_package,search.VERSION_RELEASE)
+ if len(version) > 0:
+ result = darkgreen("Latest version installed:")+" "+version
+ else:
+ result = darkgreen("Latest version installed:")+" [ Not Installed ]"
+ return result
+
+ def getVersion(self,full_package,detail):
+ if len(full_package) > 1:
+ package_parts = portage.catpkgsplit(full_package)
+ if detail == search.VERSION_RELEASE and package_parts[3] != 'r0':
+ result = package_parts[2]+ "-" + package_parts[3]
+ else:
+ result = package_parts[2]
+ else:
+ result = ""
+ return result
+
diff --git a/portage_with_autodep/pym/_emerge/show_invalid_depstring_notice.py b/portage_with_autodep/pym/_emerge/show_invalid_depstring_notice.py
new file mode 100644
index 0000000..a230b31
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/show_invalid_depstring_notice.py
@@ -0,0 +1,35 @@
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import logging
+import textwrap
+import portage
+from portage import os
+from portage.util import writemsg_level
+
+def show_invalid_depstring_notice(parent_node, depstring, error_msg):
+
+ msg1 = "\n\n!!! Invalid or corrupt dependency specification: " + \
+ "\n\n%s\n\n%s\n\n" % (error_msg, parent_node)
+ p_key = parent_node.cpv
+ p_status = parent_node.operation
+ msg = []
+ if p_status == "nomerge":
+ category, pf = portage.catsplit(p_key)
+ pkg_location = os.path.join(parent_node.root_config.settings['EROOT'], portage.VDB_PATH, category, pf)
+ msg.append("Portage is unable to process the dependencies of the ")
+ msg.append("'%s' package. " % p_key)
+ msg.append("In order to correct this problem, the package ")
+ msg.append("should be uninstalled, reinstalled, or upgraded. ")
+ msg.append("As a temporary workaround, the --nodeps option can ")
+ msg.append("be used to ignore all dependencies. For reference, ")
+ msg.append("the problematic dependencies can be found in the ")
+ msg.append("*DEPEND files located in '%s/'." % pkg_location)
+ else:
+ msg.append("This package can not be installed. ")
+ msg.append("Please notify the '%s' package maintainer " % p_key)
+ msg.append("about this problem.")
+
+ msg2 = "".join("%s\n" % line for line in textwrap.wrap("".join(msg), 72))
+ writemsg_level(msg1 + msg2, level=logging.ERROR, noiselevel=-1)
+
diff --git a/portage_with_autodep/pym/_emerge/stdout_spinner.py b/portage_with_autodep/pym/_emerge/stdout_spinner.py
new file mode 100644
index 0000000..5ad31f0
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/stdout_spinner.py
@@ -0,0 +1,83 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import platform
+import sys
+import time
+
+from portage.output import darkgreen, green
+
+class stdout_spinner(object):
+ scroll_msgs = [
+ "Gentoo Rocks ("+platform.system()+")",
+ "Thank you for using Gentoo. :)",
+ "Are you actually trying to read this?",
+ "How many times have you stared at this?",
+ "We are generating the cache right now",
+ "You are paying too much attention.",
+ "A theory is better than its explanation.",
+ "Phasers locked on target, Captain.",
+ "Thrashing is just virtual crashing.",
+ "To be is to program.",
+ "Real Users hate Real Programmers.",
+ "When all else fails, read the instructions.",
+ "Functionality breeds Contempt.",
+ "The future lies ahead.",
+ "3.1415926535897932384626433832795028841971694",
+ "Sometimes insanity is the only alternative.",
+ "Inaccuracy saves a world of explanation.",
+ ]
+
+ twirl_sequence = "/-\\|/-\\|/-\\|/-\\|\\-/|\\-/|\\-/|\\-/|"
+
+ def __init__(self):
+ self.spinpos = 0
+ self.update = self.update_twirl
+ self.scroll_sequence = self.scroll_msgs[
+ int(time.time() * 100) % len(self.scroll_msgs)]
+ self.last_update = 0
+ self.min_display_latency = 0.05
+
+ def _return_early(self):
+ """
+ Flushing ouput to the tty too frequently wastes cpu time. Therefore,
+ each update* method should return without doing any output when this
+ method returns True.
+ """
+ cur_time = time.time()
+ if cur_time - self.last_update < self.min_display_latency:
+ return True
+ self.last_update = cur_time
+ return False
+
+ def update_basic(self):
+ self.spinpos = (self.spinpos + 1) % 500
+ if self._return_early():
+ return
+ if (self.spinpos % 100) == 0:
+ if self.spinpos == 0:
+ sys.stdout.write(". ")
+ else:
+ sys.stdout.write(".")
+ sys.stdout.flush()
+
+ def update_scroll(self):
+ if self._return_early():
+ return
+ if(self.spinpos >= len(self.scroll_sequence)):
+ sys.stdout.write(darkgreen(" \b\b\b" + self.scroll_sequence[
+ len(self.scroll_sequence) - 1 - (self.spinpos % len(self.scroll_sequence))]))
+ else:
+ sys.stdout.write(green("\b " + self.scroll_sequence[self.spinpos]))
+ sys.stdout.flush()
+ self.spinpos = (self.spinpos + 1) % (2 * len(self.scroll_sequence))
+
+ def update_twirl(self):
+ self.spinpos = (self.spinpos + 1) % len(self.twirl_sequence)
+ if self._return_early():
+ return
+ sys.stdout.write("\b\b " + self.twirl_sequence[self.spinpos])
+ sys.stdout.flush()
+
+ def update_quiet(self):
+ return
diff --git a/portage_with_autodep/pym/_emerge/sync/__init__.py b/portage_with_autodep/pym/_emerge/sync/__init__.py
new file mode 100644
index 0000000..21a391a
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/sync/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/_emerge/sync/getaddrinfo_validate.py b/portage_with_autodep/pym/_emerge/sync/getaddrinfo_validate.py
new file mode 100644
index 0000000..5e6009c
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/sync/getaddrinfo_validate.py
@@ -0,0 +1,29 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+def getaddrinfo_validate(addrinfos):
+ """
+ Validate structures returned from getaddrinfo(),
+ since they may be corrupt, especially when python
+ has IPv6 support disabled (bug #340899).
+ """
+ valid_addrinfos = []
+ for addrinfo in addrinfos:
+ try:
+ if len(addrinfo) != 5:
+ continue
+ if len(addrinfo[4]) < 2:
+ continue
+ if not isinstance(addrinfo[4][0], basestring):
+ continue
+ except TypeError:
+ continue
+
+ valid_addrinfos.append(addrinfo)
+
+ return valid_addrinfos
diff --git a/portage_with_autodep/pym/_emerge/sync/old_tree_timestamp.py b/portage_with_autodep/pym/_emerge/sync/old_tree_timestamp.py
new file mode 100644
index 0000000..9b35aed
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/sync/old_tree_timestamp.py
@@ -0,0 +1,98 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import locale
+import logging
+import time
+
+from portage import os
+from portage.exception import PortageException
+from portage.localization import _
+from portage.output import EOutput
+from portage.util import grabfile, writemsg_level
+
+def have_english_locale():
+ lang, enc = locale.getdefaultlocale()
+ if lang is not None:
+ lang = lang.lower()
+ lang = lang.split('_', 1)[0]
+ return lang is None or lang in ('c', 'en')
+
+def whenago(seconds):
+ sec = int(seconds)
+ mins = 0
+ days = 0
+ hrs = 0
+ years = 0
+ out = []
+
+ if sec > 60:
+ mins = sec / 60
+ sec = sec % 60
+ if mins > 60:
+ hrs = mins / 60
+ mins = mins % 60
+ if hrs > 24:
+ days = hrs / 24
+ hrs = hrs % 24
+ if days > 365:
+ years = days / 365
+ days = days % 365
+
+ if years:
+ out.append("%dy " % years)
+ if days:
+ out.append("%dd " % days)
+ if hrs:
+ out.append("%dh " % hrs)
+ if mins:
+ out.append("%dm " % mins)
+ if sec:
+ out.append("%ds " % sec)
+
+ return "".join(out).strip()
+
+def old_tree_timestamp_warn(portdir, settings):
+ unixtime = time.time()
+ default_warnsync = 30
+
+ timestamp_file = os.path.join(portdir, "metadata/timestamp.x")
+ try:
+ lastsync = grabfile(timestamp_file)
+ except PortageException:
+ return False
+
+ if not lastsync:
+ return False
+
+ lastsync = lastsync[0].split()
+ if not lastsync:
+ return False
+
+ try:
+ lastsync = int(lastsync[0])
+ except ValueError:
+ return False
+
+ var_name = 'PORTAGE_SYNC_STALE'
+ try:
+ warnsync = float(settings.get(var_name, default_warnsync))
+ except ValueError:
+ writemsg_level("!!! %s contains non-numeric value: %s\n" % \
+ (var_name, settings[var_name]),
+ level=logging.ERROR, noiselevel=-1)
+ return False
+
+ if warnsync <= 0:
+ return False
+
+ if (unixtime - 86400 * warnsync) > lastsync:
+ out = EOutput()
+ if have_english_locale():
+ out.ewarn("Last emerge --sync was %s ago." % \
+ whenago(unixtime - lastsync))
+ else:
+ out.ewarn(_("Last emerge --sync was %s.") % \
+ time.strftime('%c', time.localtime(lastsync)))
+ return True
+ return False
diff --git a/portage_with_autodep/pym/_emerge/unmerge.py b/portage_with_autodep/pym/_emerge/unmerge.py
new file mode 100644
index 0000000..3db3a8b
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/unmerge.py
@@ -0,0 +1,578 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import logging
+import sys
+import textwrap
+import portage
+from portage import os
+from portage.dbapi._expand_new_virt import expand_new_virt
+from portage.output import bold, colorize, darkgreen, green
+from portage._sets import SETPREFIX
+from portage._sets.base import EditablePackageSet
+from portage.util import cmp_sort_key
+
+from _emerge.emergelog import emergelog
+from _emerge.Package import Package
+from _emerge.UninstallFailure import UninstallFailure
+from _emerge.userquery import userquery
+from _emerge.countdown import countdown
+
+def _unmerge_display(root_config, myopts, unmerge_action,
+ unmerge_files, clean_delay=1, ordered=0,
+ writemsg_level=portage.util.writemsg_level):
+ """
+ Returns a tuple of (returncode, pkgmap) where returncode is
+ os.EX_OK if no errors occur, and 1 otherwise.
+ """
+
+ quiet = "--quiet" in myopts
+ settings = root_config.settings
+ sets = root_config.sets
+ vartree = root_config.trees["vartree"]
+ candidate_catpkgs=[]
+ global_unmerge=0
+ out = portage.output.EOutput()
+ pkg_cache = {}
+ db_keys = list(vartree.dbapi._aux_cache_keys)
+
+ def _pkg(cpv):
+ pkg = pkg_cache.get(cpv)
+ if pkg is None:
+ pkg = Package(built=True, cpv=cpv, installed=True,
+ metadata=zip(db_keys, vartree.dbapi.aux_get(cpv, db_keys)),
+ operation="uninstall", root_config=root_config,
+ type_name="installed")
+ pkg_cache[cpv] = pkg
+ return pkg
+
+ vdb_path = os.path.join(settings["EROOT"], portage.VDB_PATH)
+ try:
+ # At least the parent needs to exist for the lock file.
+ portage.util.ensure_dirs(vdb_path)
+ except portage.exception.PortageException:
+ pass
+ vdb_lock = None
+ try:
+ if os.access(vdb_path, os.W_OK):
+ vartree.dbapi.lock()
+ vdb_lock = True
+
+ realsyslist = []
+ sys_virt_map = {}
+ for x in sets["system"].getAtoms():
+ for atom in expand_new_virt(vartree.dbapi, x):
+ if not atom.blocker:
+ realsyslist.append(atom)
+ if atom.cp != x.cp:
+ sys_virt_map[atom.cp] = x.cp
+
+ syslist = []
+ for x in realsyslist:
+ mycp = x.cp
+ # Since Gentoo stopped using old-style virtuals in
+ # 2011, typically it's possible to avoid getvirtuals()
+ # calls entirely. It will not be triggered here by
+ # new-style virtuals since those are expanded to
+ # non-virtual atoms above by expand_new_virt().
+ if mycp.startswith("virtual/") and \
+ mycp in settings.getvirtuals():
+ providers = []
+ for provider in settings.getvirtuals()[mycp]:
+ if vartree.dbapi.match(provider):
+ providers.append(provider)
+ if len(providers) == 1:
+ syslist.extend(providers)
+ else:
+ syslist.append(mycp)
+ syslist = frozenset(syslist)
+
+ if not unmerge_files:
+ if unmerge_action == "unmerge":
+ print()
+ print(bold("emerge unmerge") + " can only be used with specific package names")
+ print()
+ return 1, {}
+ else:
+ global_unmerge = 1
+
+ localtree = vartree
+ # process all arguments and add all
+ # valid db entries to candidate_catpkgs
+ if global_unmerge:
+ if not unmerge_files:
+ candidate_catpkgs.extend(vartree.dbapi.cp_all())
+ else:
+ #we've got command-line arguments
+ if not unmerge_files:
+ print("\nNo packages to unmerge have been provided.\n")
+ return 1, {}
+ for x in unmerge_files:
+ arg_parts = x.split('/')
+ if x[0] not in [".","/"] and \
+ arg_parts[-1][-7:] != ".ebuild":
+ #possible cat/pkg or dep; treat as such
+ candidate_catpkgs.append(x)
+ elif unmerge_action in ["prune","clean"]:
+ print("\n!!! Prune and clean do not accept individual" + \
+ " ebuilds as arguments;\n skipping.\n")
+ continue
+ else:
+ # it appears that the user is specifying an installed
+ # ebuild and we're in "unmerge" mode, so it's ok.
+ if not os.path.exists(x):
+ print("\n!!! The path '"+x+"' doesn't exist.\n")
+ return 1, {}
+
+ absx = os.path.abspath(x)
+ sp_absx = absx.split("/")
+ if sp_absx[-1][-7:] == ".ebuild":
+ del sp_absx[-1]
+ absx = "/".join(sp_absx)
+
+ sp_absx_len = len(sp_absx)
+
+ vdb_path = os.path.join(settings["EROOT"], portage.VDB_PATH)
+
+ sp_vdb = vdb_path.split("/")
+ sp_vdb_len = len(sp_vdb)
+
+ if not os.path.exists(absx+"/CONTENTS"):
+ print("!!! Not a valid db dir: "+str(absx))
+ return 1, {}
+
+ if sp_absx_len <= sp_vdb_len:
+ # The Path is shorter... so it can't be inside the vdb.
+ print(sp_absx)
+ print(absx)
+ print("\n!!!",x,"cannot be inside "+ \
+ vdb_path+"; aborting.\n")
+ return 1, {}
+
+ for idx in range(0,sp_vdb_len):
+ if idx >= sp_absx_len or sp_vdb[idx] != sp_absx[idx]:
+ print(sp_absx)
+ print(absx)
+ print("\n!!!", x, "is not inside "+\
+ vdb_path+"; aborting.\n")
+ return 1, {}
+
+ print("="+"/".join(sp_absx[sp_vdb_len:]))
+ candidate_catpkgs.append(
+ "="+"/".join(sp_absx[sp_vdb_len:]))
+
+ newline=""
+ if (not "--quiet" in myopts):
+ newline="\n"
+ if settings["ROOT"] != "/":
+ writemsg_level(darkgreen(newline+ \
+ ">>> Using system located in ROOT tree %s\n" % \
+ settings["ROOT"]))
+
+ if (("--pretend" in myopts) or ("--ask" in myopts)) and \
+ not ("--quiet" in myopts):
+ writemsg_level(darkgreen(newline+\
+ ">>> These are the packages that would be unmerged:\n"))
+
+ # Preservation of order is required for --depclean and --prune so
+ # that dependencies are respected. Use all_selected to eliminate
+ # duplicate packages since the same package may be selected by
+ # multiple atoms.
+ pkgmap = []
+ all_selected = set()
+ for x in candidate_catpkgs:
+ # cycle through all our candidate deps and determine
+ # what will and will not get unmerged
+ try:
+ mymatch = vartree.dbapi.match(x)
+ except portage.exception.AmbiguousPackageName as errpkgs:
+ print("\n\n!!! The short ebuild name \"" + \
+ x + "\" is ambiguous. Please specify")
+ print("!!! one of the following fully-qualified " + \
+ "ebuild names instead:\n")
+ for i in errpkgs[0]:
+ print(" " + green(i))
+ print()
+ sys.exit(1)
+
+ if not mymatch and x[0] not in "<>=~":
+ mymatch = localtree.dep_match(x)
+ if not mymatch:
+ portage.writemsg("\n--- Couldn't find '%s' to %s.\n" % \
+ (x.replace("null/", ""), unmerge_action), noiselevel=-1)
+ continue
+
+ pkgmap.append(
+ {"protected": set(), "selected": set(), "omitted": set()})
+ mykey = len(pkgmap) - 1
+ if unmerge_action=="unmerge":
+ for y in mymatch:
+ if y not in all_selected:
+ pkgmap[mykey]["selected"].add(y)
+ all_selected.add(y)
+ elif unmerge_action == "prune":
+ if len(mymatch) == 1:
+ continue
+ best_version = mymatch[0]
+ best_slot = vartree.getslot(best_version)
+ best_counter = vartree.dbapi.cpv_counter(best_version)
+ for mypkg in mymatch[1:]:
+ myslot = vartree.getslot(mypkg)
+ mycounter = vartree.dbapi.cpv_counter(mypkg)
+ if (myslot == best_slot and mycounter > best_counter) or \
+ mypkg == portage.best([mypkg, best_version]):
+ if myslot == best_slot:
+ if mycounter < best_counter:
+ # On slot collision, keep the one with the
+ # highest counter since it is the most
+ # recently installed.
+ continue
+ best_version = mypkg
+ best_slot = myslot
+ best_counter = mycounter
+ pkgmap[mykey]["protected"].add(best_version)
+ pkgmap[mykey]["selected"].update(mypkg for mypkg in mymatch \
+ if mypkg != best_version and mypkg not in all_selected)
+ all_selected.update(pkgmap[mykey]["selected"])
+ else:
+ # unmerge_action == "clean"
+ slotmap={}
+ for mypkg in mymatch:
+ if unmerge_action == "clean":
+ myslot = localtree.getslot(mypkg)
+ else:
+ # since we're pruning, we don't care about slots
+ # and put all the pkgs in together
+ myslot = 0
+ if myslot not in slotmap:
+ slotmap[myslot] = {}
+ slotmap[myslot][localtree.dbapi.cpv_counter(mypkg)] = mypkg
+
+ for mypkg in vartree.dbapi.cp_list(
+ portage.cpv_getkey(mymatch[0])):
+ myslot = vartree.getslot(mypkg)
+ if myslot not in slotmap:
+ slotmap[myslot] = {}
+ slotmap[myslot][vartree.dbapi.cpv_counter(mypkg)] = mypkg
+
+ for myslot in slotmap:
+ counterkeys = list(slotmap[myslot])
+ if not counterkeys:
+ continue
+ counterkeys.sort()
+ pkgmap[mykey]["protected"].add(
+ slotmap[myslot][counterkeys[-1]])
+ del counterkeys[-1]
+
+ for counter in counterkeys[:]:
+ mypkg = slotmap[myslot][counter]
+ if mypkg not in mymatch:
+ counterkeys.remove(counter)
+ pkgmap[mykey]["protected"].add(
+ slotmap[myslot][counter])
+
+ #be pretty and get them in order of merge:
+ for ckey in counterkeys:
+ mypkg = slotmap[myslot][ckey]
+ if mypkg not in all_selected:
+ pkgmap[mykey]["selected"].add(mypkg)
+ all_selected.add(mypkg)
+ # ok, now the last-merged package
+ # is protected, and the rest are selected
+ numselected = len(all_selected)
+ if global_unmerge and not numselected:
+ portage.writemsg_stdout("\n>>> No outdated packages were found on your system.\n")
+ return 1, {}
+
+ if not numselected:
+ portage.writemsg_stdout(
+ "\n>>> No packages selected for removal by " + \
+ unmerge_action + "\n")
+ return 1, {}
+ finally:
+ if vdb_lock:
+ vartree.dbapi.flush_cache()
+ vartree.dbapi.unlock()
+
+ # generate a list of package sets that are directly or indirectly listed in "selected",
+ # as there is no persistent list of "installed" sets
+ installed_sets = ["selected"]
+ stop = False
+ pos = 0
+ while not stop:
+ stop = True
+ pos = len(installed_sets)
+ for s in installed_sets[pos - 1:]:
+ if s not in sets:
+ continue
+ candidates = [x[len(SETPREFIX):] for x in sets[s].getNonAtoms() if x.startswith(SETPREFIX)]
+ if candidates:
+ stop = False
+ installed_sets += candidates
+ installed_sets = [x for x in installed_sets if x not in root_config.setconfig.active]
+ del stop, pos
+
+ # we don't want to unmerge packages that are still listed in user-editable package sets
+ # listed in "world" as they would be remerged on the next update of "world" or the
+ # relevant package sets.
+ unknown_sets = set()
+ for cp in range(len(pkgmap)):
+ for cpv in pkgmap[cp]["selected"].copy():
+ try:
+ pkg = _pkg(cpv)
+ except KeyError:
+ # It could have been uninstalled
+ # by a concurrent process.
+ continue
+
+ if unmerge_action != "clean" and root_config.root == "/":
+ skip_pkg = False
+ if portage.match_from_list(portage.const.PORTAGE_PACKAGE_ATOM, [pkg]):
+ msg = ("Not unmerging package %s since there is no valid reason "
+ "for Portage to unmerge itself.") % (pkg.cpv,)
+ skip_pkg = True
+ elif vartree.dbapi._dblink(cpv).isowner(portage._python_interpreter):
+ msg = ("Not unmerging package %s since there is no valid reason "
+ "for Portage to unmerge currently used Python interpreter.") % (pkg.cpv,)
+ skip_pkg = True
+ if skip_pkg:
+ for line in textwrap.wrap(msg, 75):
+ out.eerror(line)
+ # adjust pkgmap so the display output is correct
+ pkgmap[cp]["selected"].remove(cpv)
+ all_selected.remove(cpv)
+ pkgmap[cp]["protected"].add(cpv)
+ continue
+
+ parents = []
+ for s in installed_sets:
+ # skip sets that the user requested to unmerge, and skip world
+ # user-selected set, since the package will be removed from
+ # that set later on.
+ if s in root_config.setconfig.active or s == "selected":
+ continue
+
+ if s not in sets:
+ if s in unknown_sets:
+ continue
+ unknown_sets.add(s)
+ out = portage.output.EOutput()
+ out.eerror(("Unknown set '@%s' in %s%s") % \
+ (s, root_config.settings['EROOT'], portage.const.WORLD_SETS_FILE))
+ continue
+
+ # only check instances of EditablePackageSet as other classes are generally used for
+ # special purposes and can be ignored here (and are usually generated dynamically, so the
+ # user can't do much about them anyway)
+ if isinstance(sets[s], EditablePackageSet):
+
+ # This is derived from a snippet of code in the
+ # depgraph._iter_atoms_for_pkg() method.
+ for atom in sets[s].iterAtomsForPackage(pkg):
+ inst_matches = vartree.dbapi.match(atom)
+ inst_matches.reverse() # descending order
+ higher_slot = None
+ for inst_cpv in inst_matches:
+ try:
+ inst_pkg = _pkg(inst_cpv)
+ except KeyError:
+ # It could have been uninstalled
+ # by a concurrent process.
+ continue
+
+ if inst_pkg.cp != atom.cp:
+ continue
+ if pkg >= inst_pkg:
+ # This is descending order, and we're not
+ # interested in any versions <= pkg given.
+ break
+ if pkg.slot_atom != inst_pkg.slot_atom:
+ higher_slot = inst_pkg
+ break
+ if higher_slot is None:
+ parents.append(s)
+ break
+ if parents:
+ print(colorize("WARN", "Package %s is going to be unmerged," % cpv))
+ print(colorize("WARN", "but still listed in the following package sets:"))
+ print(" %s\n" % ", ".join(parents))
+
+ del installed_sets
+
+ numselected = len(all_selected)
+ if not numselected:
+ writemsg_level(
+ "\n>>> No packages selected for removal by " + \
+ unmerge_action + "\n")
+ return 1, {}
+
+ # Unmerge order only matters in some cases
+ if not ordered:
+ unordered = {}
+ for d in pkgmap:
+ selected = d["selected"]
+ if not selected:
+ continue
+ cp = portage.cpv_getkey(next(iter(selected)))
+ cp_dict = unordered.get(cp)
+ if cp_dict is None:
+ cp_dict = {}
+ unordered[cp] = cp_dict
+ for k in d:
+ cp_dict[k] = set()
+ for k, v in d.items():
+ cp_dict[k].update(v)
+ pkgmap = [unordered[cp] for cp in sorted(unordered)]
+
+ for x in range(len(pkgmap)):
+ selected = pkgmap[x]["selected"]
+ if not selected:
+ continue
+ for mytype, mylist in pkgmap[x].items():
+ if mytype == "selected":
+ continue
+ mylist.difference_update(all_selected)
+ cp = portage.cpv_getkey(next(iter(selected)))
+ for y in localtree.dep_match(cp):
+ if y not in pkgmap[x]["omitted"] and \
+ y not in pkgmap[x]["selected"] and \
+ y not in pkgmap[x]["protected"] and \
+ y not in all_selected:
+ pkgmap[x]["omitted"].add(y)
+ if global_unmerge and not pkgmap[x]["selected"]:
+ #avoid cluttering the preview printout with stuff that isn't getting unmerged
+ continue
+ if not (pkgmap[x]["protected"] or pkgmap[x]["omitted"]) and cp in syslist:
+ virt_cp = sys_virt_map.get(cp)
+ if virt_cp is None:
+ cp_info = "'%s'" % (cp,)
+ else:
+ cp_info = "'%s' (%s)" % (cp, virt_cp)
+ writemsg_level(colorize("BAD","\n\n!!! " + \
+ "%s is part of your system profile.\n" % (cp_info,)),
+ level=logging.WARNING, noiselevel=-1)
+ writemsg_level(colorize("WARN","!!! Unmerging it may " + \
+ "be damaging to your system.\n\n"),
+ level=logging.WARNING, noiselevel=-1)
+ if clean_delay and "--pretend" not in myopts and "--ask" not in myopts:
+ countdown(int(settings["EMERGE_WARNING_DELAY"]),
+ colorize("UNMERGE_WARN", "Press Ctrl-C to Stop"))
+ if not quiet:
+ writemsg_level("\n %s\n" % (bold(cp),), noiselevel=-1)
+ else:
+ writemsg_level(bold(cp) + ": ", noiselevel=-1)
+ for mytype in ["selected","protected","omitted"]:
+ if not quiet:
+ writemsg_level((mytype + ": ").rjust(14), noiselevel=-1)
+ if pkgmap[x][mytype]:
+ sorted_pkgs = [portage.catpkgsplit(mypkg)[1:] for mypkg in pkgmap[x][mytype]]
+ sorted_pkgs.sort(key=cmp_sort_key(portage.pkgcmp))
+ for pn, ver, rev in sorted_pkgs:
+ if rev == "r0":
+ myversion = ver
+ else:
+ myversion = ver + "-" + rev
+ if mytype == "selected":
+ writemsg_level(
+ colorize("UNMERGE_WARN", myversion + " "),
+ noiselevel=-1)
+ else:
+ writemsg_level(
+ colorize("GOOD", myversion + " "), noiselevel=-1)
+ else:
+ writemsg_level("none ", noiselevel=-1)
+ if not quiet:
+ writemsg_level("\n", noiselevel=-1)
+ if quiet:
+ writemsg_level("\n", noiselevel=-1)
+
+ writemsg_level("\nAll selected packages: %s\n" % " ".join(all_selected), noiselevel=-1)
+
+ writemsg_level("\n>>> " + colorize("UNMERGE_WARN", "'Selected'") + \
+ " packages are slated for removal.\n")
+ writemsg_level(">>> " + colorize("GOOD", "'Protected'") + \
+ " and " + colorize("GOOD", "'omitted'") + \
+ " packages will not be removed.\n\n")
+
+ return os.EX_OK, pkgmap
+
+def unmerge(root_config, myopts, unmerge_action,
+ unmerge_files, ldpath_mtimes, autoclean=0,
+ clean_world=1, clean_delay=1, ordered=0, raise_on_error=0,
+ scheduler=None, writemsg_level=portage.util.writemsg_level):
+ """
+ Returns 1 if successful, otherwise 0.
+ """
+
+ if clean_world:
+ clean_world = myopts.get('--deselect') != 'n'
+
+ rval, pkgmap = _unmerge_display(root_config, myopts,
+ unmerge_action, unmerge_files,
+ clean_delay=clean_delay, ordered=ordered,
+ writemsg_level=writemsg_level)
+
+ if rval != os.EX_OK:
+ return 0
+
+ enter_invalid = '--ask-enter-invalid' in myopts
+ vartree = root_config.trees["vartree"]
+ sets = root_config.sets
+ settings = root_config.settings
+ mysettings = portage.config(clone=settings)
+ xterm_titles = "notitles" not in settings.features
+
+ if "--pretend" in myopts:
+ #we're done... return
+ return 0
+ if "--ask" in myopts:
+ if userquery("Would you like to unmerge these packages?",
+ enter_invalid) == "No":
+ # enter pretend mode for correct formatting of results
+ myopts["--pretend"] = True
+ print()
+ print("Quitting.")
+ print()
+ return 0
+ #the real unmerging begins, after a short delay....
+ if clean_delay and not autoclean:
+ countdown(int(settings["CLEAN_DELAY"]), ">>> Unmerging")
+
+ for x in range(len(pkgmap)):
+ for y in pkgmap[x]["selected"]:
+ writemsg_level(">>> Unmerging "+y+"...\n", noiselevel=-1)
+ emergelog(xterm_titles, "=== Unmerging... ("+y+")")
+ mysplit = y.split("/")
+ #unmerge...
+ retval = portage.unmerge(mysplit[0], mysplit[1], settings["ROOT"],
+ mysettings, unmerge_action not in ["clean","prune"],
+ vartree=vartree, ldpath_mtimes=ldpath_mtimes,
+ scheduler=scheduler)
+
+ if retval != os.EX_OK:
+ emergelog(xterm_titles, " !!! unmerge FAILURE: "+y)
+ if raise_on_error:
+ raise UninstallFailure(retval)
+ sys.exit(retval)
+ else:
+ if clean_world and hasattr(sets["selected"], "cleanPackage")\
+ and hasattr(sets["selected"], "lock"):
+ sets["selected"].lock()
+ if hasattr(sets["selected"], "load"):
+ sets["selected"].load()
+ sets["selected"].cleanPackage(vartree.dbapi, y)
+ sets["selected"].unlock()
+ emergelog(xterm_titles, " >>> unmerge success: "+y)
+
+ if clean_world and hasattr(sets["selected"], "remove")\
+ and hasattr(sets["selected"], "lock"):
+ sets["selected"].lock()
+ # load is called inside remove()
+ for s in root_config.setconfig.active:
+ sets["selected"].remove(SETPREFIX + s)
+ sets["selected"].unlock()
+
+ return 1
+
diff --git a/portage_with_autodep/pym/_emerge/userquery.py b/portage_with_autodep/pym/_emerge/userquery.py
new file mode 100644
index 0000000..e7ed400
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/userquery.py
@@ -0,0 +1,55 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import sys
+
+from portage.output import bold, create_color_func
+
+def userquery(prompt, enter_invalid, responses=None, colours=None):
+ """Displays a prompt and a set of responses, then waits for a response
+ which is checked against the responses and the first to match is
+ returned. An empty response will match the first value in responses,
+ unless enter_invalid is True. The input buffer is *not* cleared prior
+ to the prompt!
+
+ prompt: a String.
+ responses: a List of Strings.
+ colours: a List of Functions taking and returning a String, used to
+ process the responses for display. Typically these will be functions
+ like red() but could be e.g. lambda x: "DisplayString".
+ If responses is omitted, defaults to ["Yes", "No"], [green, red].
+ If only colours is omitted, defaults to [bold, ...].
+
+ Returns a member of the List responses. (If called without optional
+ arguments, returns "Yes" or "No".)
+ KeyboardInterrupt is converted to SystemExit to avoid tracebacks being
+ printed."""
+ if responses is None:
+ responses = ["Yes", "No"]
+ colours = [
+ create_color_func("PROMPT_CHOICE_DEFAULT"),
+ create_color_func("PROMPT_CHOICE_OTHER")
+ ]
+ elif colours is None:
+ colours=[bold]
+ colours=(colours*len(responses))[:len(responses)]
+ print(bold(prompt), end=' ')
+ try:
+ while True:
+ if sys.hexversion >= 0x3000000:
+ response=input("["+"/".join([colours[i](responses[i]) for i in range(len(responses))])+"] ")
+ else:
+ response=raw_input("["+"/".join([colours[i](responses[i]) for i in range(len(responses))])+"] ")
+ if response or not enter_invalid:
+ for key in responses:
+ # An empty response will match the
+ # first value in responses.
+ if response.upper()==key[:len(response)].upper():
+ return key
+ print("Sorry, response '%s' not understood." % response, end=' ')
+ except (EOFError, KeyboardInterrupt):
+ print("Interrupted.")
+ sys.exit(1)
+
diff --git a/portage_with_autodep/pym/portage/__init__.py b/portage_with_autodep/pym/portage/__init__.py
new file mode 100644
index 0000000..2a2eb99
--- /dev/null
+++ b/portage_with_autodep/pym/portage/__init__.py
@@ -0,0 +1,610 @@
+# portage.py -- core Portage functionality
+# Copyright 1998-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+VERSION="HEAD"
+
+# ===========================================================================
+# START OF IMPORTS -- START OF IMPORTS -- START OF IMPORTS -- START OF IMPORT
+# ===========================================================================
+
+try:
+ import sys
+ import errno
+ if not hasattr(errno, 'ESTALE'):
+ # ESTALE may not be defined on some systems, such as interix.
+ errno.ESTALE = -1
+ import re
+ import types
+
+ # Try the commands module first, since this allows us to eliminate
+ # the subprocess module from the baseline imports under python2.
+ try:
+ from commands import getstatusoutput as subprocess_getstatusoutput
+ except ImportError:
+ from subprocess import getstatusoutput as subprocess_getstatusoutput
+
+ import platform
+
+ # Temporarily delete these imports, to ensure that only the
+ # wrapped versions are imported by portage internals.
+ import os
+ del os
+ import shutil
+ del shutil
+
+except ImportError as e:
+ sys.stderr.write("\n\n")
+ sys.stderr.write("!!! Failed to complete python imports. These are internal modules for\n")
+ sys.stderr.write("!!! python and failure here indicates that you have a problem with python\n")
+ sys.stderr.write("!!! itself and thus portage is not able to continue processing.\n\n")
+
+ sys.stderr.write("!!! You might consider starting python with verbose flags to see what has\n")
+ sys.stderr.write("!!! gone wrong. Here is the information we got for this exception:\n")
+ sys.stderr.write(" "+str(e)+"\n\n");
+ raise
+
+try:
+
+ import portage.proxy.lazyimport
+ import portage.proxy as proxy
+ proxy.lazyimport.lazyimport(globals(),
+ 'portage.cache.cache_errors:CacheError',
+ 'portage.checksum',
+ 'portage.checksum:perform_checksum,perform_md5,prelink_capable',
+ 'portage.cvstree',
+ 'portage.data',
+ 'portage.data:lchown,ostype,portage_gid,portage_uid,secpass,' + \
+ 'uid,userland,userpriv_groups,wheelgid',
+ 'portage.dbapi',
+ 'portage.dbapi.bintree:bindbapi,binarytree',
+ 'portage.dbapi.cpv_expand:cpv_expand',
+ 'portage.dbapi.dep_expand:dep_expand',
+ 'portage.dbapi.porttree:close_portdbapi_caches,FetchlistDict,' + \
+ 'portagetree,portdbapi',
+ 'portage.dbapi.vartree:dblink,merge,unmerge,vardbapi,vartree',
+ 'portage.dbapi.virtual:fakedbapi',
+ 'portage.dep',
+ 'portage.dep:best_match_to_list,dep_getcpv,dep_getkey,' + \
+ 'flatten,get_operator,isjustname,isspecific,isvalidatom,' + \
+ 'match_from_list,match_to_list',
+ 'portage.dep.dep_check:dep_check,dep_eval,dep_wordreduce,dep_zapdeps',
+ 'portage.eclass_cache',
+ 'portage.exception',
+ 'portage.getbinpkg',
+ 'portage.locks',
+ 'portage.locks:lockdir,lockfile,unlockdir,unlockfile',
+ 'portage.mail',
+ 'portage.manifest:Manifest',
+ 'portage.output',
+ 'portage.output:bold,colorize',
+ 'portage.package.ebuild.doebuild:doebuild,' + \
+ 'doebuild_environment,spawn,spawnebuild',
+ 'portage.package.ebuild.config:autouse,best_from_dict,' + \
+ 'check_config_instance,config',
+ 'portage.package.ebuild.deprecated_profile_check:' + \
+ 'deprecated_profile_check',
+ 'portage.package.ebuild.digestcheck:digestcheck',
+ 'portage.package.ebuild.digestgen:digestgen',
+ 'portage.package.ebuild.fetch:fetch',
+ 'portage.package.ebuild.getmaskingreason:getmaskingreason',
+ 'portage.package.ebuild.getmaskingstatus:getmaskingstatus',
+ 'portage.package.ebuild.prepare_build_dirs:prepare_build_dirs',
+ 'portage.process',
+ 'portage.process:atexit_register,run_exitfuncs',
+ 'portage.update:dep_transform,fixdbentries,grab_updates,' + \
+ 'parse_updates,update_config_files,update_dbentries,' + \
+ 'update_dbentry',
+ 'portage.util',
+ 'portage.util:atomic_ofstream,apply_secpass_permissions,' + \
+ 'apply_recursive_permissions,dump_traceback,getconfig,' + \
+ 'grabdict,grabdict_package,grabfile,grabfile_package,' + \
+ 'map_dictlist_vals,new_protect_filename,normalize_path,' + \
+ 'pickle_read,pickle_write,stack_dictlist,stack_dicts,' + \
+ 'stack_lists,unique_array,varexpand,writedict,writemsg,' + \
+ 'writemsg_stdout,write_atomic',
+ 'portage.util.digraph:digraph',
+ 'portage.util.env_update:env_update',
+ 'portage.util.ExtractKernelVersion:ExtractKernelVersion',
+ 'portage.util.listdir:cacheddir,listdir',
+ 'portage.util.movefile:movefile',
+ 'portage.util.mtimedb:MtimeDB',
+ 'portage.versions',
+ 'portage.versions:best,catpkgsplit,catsplit,cpv_getkey,' + \
+ 'cpv_getkey@getCPFromCPV,endversion_keys,' + \
+ 'suffix_value@endversion,pkgcmp,pkgsplit,vercmp,ververify',
+ 'portage.xpak',
+ 'time',
+ )
+
+ try:
+ from collections import OrderedDict
+ except ImportError:
+ proxy.lazyimport.lazyimport(globals(),
+ 'portage.cache.mappings:OrderedDict')
+
+ import portage.const
+ from portage.const import VDB_PATH, PRIVATE_PATH, CACHE_PATH, DEPCACHE_PATH, \
+ USER_CONFIG_PATH, MODULES_FILE_PATH, CUSTOM_PROFILE_PATH, PORTAGE_BASE_PATH, \
+ PORTAGE_BIN_PATH, PORTAGE_PYM_PATH, PROFILE_PATH, LOCALE_DATA_PATH, \
+ EBUILD_SH_BINARY, SANDBOX_BINARY, BASH_BINARY, \
+ MOVE_BINARY, PRELINK_BINARY, WORLD_FILE, MAKE_CONF_FILE, MAKE_DEFAULTS_FILE, \
+ DEPRECATED_PROFILE_FILE, USER_VIRTUALS_FILE, EBUILD_SH_ENV_FILE, \
+ INVALID_ENV_FILE, CUSTOM_MIRRORS_FILE, CONFIG_MEMORY_FILE,\
+ INCREMENTALS, EAPI, MISC_SH_BINARY, REPO_NAME_LOC, REPO_NAME_FILE
+
+except ImportError as e:
+ sys.stderr.write("\n\n")
+ sys.stderr.write("!!! Failed to complete portage imports. There are internal modules for\n")
+ sys.stderr.write("!!! portage and failure here indicates that you have a problem with your\n")
+ sys.stderr.write("!!! installation of portage. Please try a rescue portage located in the\n")
+ sys.stderr.write("!!! portage tree under '/usr/portage/sys-apps/portage/files/' (default).\n")
+ sys.stderr.write("!!! There is a README.RESCUE file that details the steps required to perform\n")
+ sys.stderr.write("!!! a recovery of portage.\n")
+ sys.stderr.write(" "+str(e)+"\n\n")
+ raise
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+ long = int
+
+# Assume utf_8 fs encoding everywhere except in merge code, where the
+# user's locale is respected.
+_encodings = {
+ 'content' : 'utf_8',
+ 'fs' : 'utf_8',
+ 'merge' : sys.getfilesystemencoding(),
+ 'repo.content' : 'utf_8',
+ 'stdio' : 'utf_8',
+}
+
+# This can happen if python is built with USE=build (stage 1).
+if _encodings['merge'] is None:
+ _encodings['merge'] = 'ascii'
+
+if sys.hexversion >= 0x3000000:
+ def _unicode_encode(s, encoding=_encodings['content'], errors='backslashreplace'):
+ if isinstance(s, str):
+ s = s.encode(encoding, errors)
+ return s
+
+ def _unicode_decode(s, encoding=_encodings['content'], errors='replace'):
+ if isinstance(s, bytes):
+ s = str(s, encoding=encoding, errors=errors)
+ return s
+else:
+ def _unicode_encode(s, encoding=_encodings['content'], errors='backslashreplace'):
+ if isinstance(s, unicode):
+ s = s.encode(encoding, errors)
+ return s
+
+ def _unicode_decode(s, encoding=_encodings['content'], errors='replace'):
+ if isinstance(s, bytes):
+ s = unicode(s, encoding=encoding, errors=errors)
+ return s
+
+class _unicode_func_wrapper(object):
+ """
+ Wraps a function, converts arguments from unicode to bytes,
+ and return values to unicode from bytes. Function calls
+ will raise UnicodeEncodeError if an argument fails to be
+ encoded with the required encoding. Return values that
+ are single strings are decoded with errors='replace'. Return
+ values that are lists of strings are decoded with errors='strict'
+ and elements that fail to be decoded are omitted from the returned
+ list.
+ """
+ __slots__ = ('_func', '_encoding')
+
+ def __init__(self, func, encoding=_encodings['fs']):
+ self._func = func
+ self._encoding = encoding
+
+ def __call__(self, *args, **kwargs):
+
+ encoding = self._encoding
+ wrapped_args = [_unicode_encode(x, encoding=encoding, errors='strict')
+ for x in args]
+ if kwargs:
+ wrapped_kwargs = dict(
+ (k, _unicode_encode(v, encoding=encoding, errors='strict'))
+ for k, v in kwargs.items())
+ else:
+ wrapped_kwargs = {}
+
+ rval = self._func(*wrapped_args, **wrapped_kwargs)
+
+ # Don't use isinstance() since we don't want to convert subclasses
+ # of tuple such as posix.stat_result in python-3.2.
+ if rval.__class__ in (list, tuple):
+ decoded_rval = []
+ for x in rval:
+ try:
+ x = _unicode_decode(x, encoding=encoding, errors='strict')
+ except UnicodeDecodeError:
+ pass
+ else:
+ decoded_rval.append(x)
+
+ if isinstance(rval, tuple):
+ rval = tuple(decoded_rval)
+ else:
+ rval = decoded_rval
+ else:
+ rval = _unicode_decode(rval, encoding=encoding, errors='replace')
+
+ return rval
+
+class _unicode_module_wrapper(object):
+ """
+ Wraps a module and wraps all functions with _unicode_func_wrapper.
+ """
+ __slots__ = ('_mod', '_encoding', '_overrides', '_cache')
+
+ def __init__(self, mod, encoding=_encodings['fs'], overrides=None, cache=True):
+ object.__setattr__(self, '_mod', mod)
+ object.__setattr__(self, '_encoding', encoding)
+ object.__setattr__(self, '_overrides', overrides)
+ if cache:
+ cache = {}
+ else:
+ cache = None
+ object.__setattr__(self, '_cache', cache)
+
+ def __getattribute__(self, attr):
+ cache = object.__getattribute__(self, '_cache')
+ if cache is not None:
+ result = cache.get(attr)
+ if result is not None:
+ return result
+ result = getattr(object.__getattribute__(self, '_mod'), attr)
+ encoding = object.__getattribute__(self, '_encoding')
+ overrides = object.__getattribute__(self, '_overrides')
+ override = None
+ if overrides is not None:
+ override = overrides.get(id(result))
+ if override is not None:
+ result = override
+ elif isinstance(result, type):
+ pass
+ elif type(result) is types.ModuleType:
+ result = _unicode_module_wrapper(result,
+ encoding=encoding, overrides=overrides)
+ elif hasattr(result, '__call__'):
+ result = _unicode_func_wrapper(result, encoding=encoding)
+ if cache is not None:
+ cache[attr] = result
+ return result
+
+import os as _os
+_os_overrides = {
+ id(_os.fdopen) : _os.fdopen,
+ id(_os.mkfifo) : _os.mkfifo,
+ id(_os.popen) : _os.popen,
+ id(_os.read) : _os.read,
+ id(_os.system) : _os.system,
+}
+
+if hasattr(_os, 'statvfs'):
+ _os_overrides[id(_os.statvfs)] = _os.statvfs
+
+os = _unicode_module_wrapper(_os, overrides=_os_overrides,
+ encoding=_encodings['fs'])
+_os_merge = _unicode_module_wrapper(_os,
+ encoding=_encodings['merge'], overrides=_os_overrides)
+
+import shutil as _shutil
+shutil = _unicode_module_wrapper(_shutil, encoding=_encodings['fs'])
+
+# Imports below this point rely on the above unicode wrapper definitions.
+try:
+ __import__('selinux')
+ import portage._selinux
+ selinux = _unicode_module_wrapper(_selinux,
+ encoding=_encodings['fs'])
+ _selinux_merge = _unicode_module_wrapper(_selinux,
+ encoding=_encodings['merge'])
+except (ImportError, OSError) as e:
+ if isinstance(e, OSError):
+ sys.stderr.write("!!! SELinux not loaded: %s\n" % str(e))
+ del e
+ _selinux = None
+ selinux = None
+ _selinux_merge = None
+
+# ===========================================================================
+# END OF IMPORTS -- END OF IMPORTS -- END OF IMPORTS -- END OF IMPORTS -- END
+# ===========================================================================
+
+_python_interpreter = os.path.realpath(sys.executable)
+_bin_path = PORTAGE_BIN_PATH
+_pym_path = PORTAGE_PYM_PATH
+
+def _shell_quote(s):
+ """
+ Quote a string in double-quotes and use backslashes to
+ escape any backslashes, double-quotes, dollar signs, or
+ backquotes in the string.
+ """
+ for letter in "\\\"$`":
+ if letter in s:
+ s = s.replace(letter, "\\" + letter)
+ return "\"%s\"" % s
+
+bsd_chflags = None
+
+if platform.system() in ('FreeBSD',):
+
+ class bsd_chflags(object):
+
+ @classmethod
+ def chflags(cls, path, flags, opts=""):
+ cmd = 'chflags %s %o %s' % (opts, flags, _shell_quote(path))
+ status, output = subprocess_getstatusoutput(cmd)
+ if os.WIFEXITED(status) and os.WEXITSTATUS(status) == os.EX_OK:
+ return
+ # Try to generate an ENOENT error if appropriate.
+ if 'h' in opts:
+ _os_merge.lstat(path)
+ else:
+ _os_merge.stat(path)
+ # Make sure the binary exists.
+ if not portage.process.find_binary('chflags'):
+ raise portage.exception.CommandNotFound('chflags')
+ # Now we're not sure exactly why it failed or what
+ # the real errno was, so just report EPERM.
+ e = OSError(errno.EPERM, output)
+ e.errno = errno.EPERM
+ e.filename = path
+ e.message = output
+ raise e
+
+ @classmethod
+ def lchflags(cls, path, flags):
+ return cls.chflags(path, flags, opts='-h')
+
+def load_mod(name):
+ modname = ".".join(name.split(".")[:-1])
+ mod = __import__(modname)
+ components = name.split('.')
+ for comp in components[1:]:
+ mod = getattr(mod, comp)
+ return mod
+
+def getcwd():
+ "this fixes situations where the current directory doesn't exist"
+ try:
+ return os.getcwd()
+ except OSError: #dir doesn't exist
+ os.chdir("/")
+ return "/"
+getcwd()
+
+def abssymlink(symlink):
+ "This reads symlinks, resolving the relative symlinks, and returning the absolute."
+ mylink=os.readlink(symlink)
+ if mylink[0] != '/':
+ mydir=os.path.dirname(symlink)
+ mylink=mydir+"/"+mylink
+ return os.path.normpath(mylink)
+
+_doebuild_manifest_exempt_depend = 0
+
+_testing_eapis = frozenset(["4-python"])
+_deprecated_eapis = frozenset(["4_pre1", "3_pre2", "3_pre1"])
+
+def _eapi_is_deprecated(eapi):
+ return eapi in _deprecated_eapis
+
+def eapi_is_supported(eapi):
+ if not isinstance(eapi, basestring):
+ # Only call str() when necessary since with python2 it
+ # can trigger UnicodeEncodeError if EAPI is corrupt.
+ eapi = str(eapi)
+ eapi = eapi.strip()
+
+ if _eapi_is_deprecated(eapi):
+ return True
+
+ if eapi in _testing_eapis:
+ return True
+
+ try:
+ eapi = int(eapi)
+ except ValueError:
+ eapi = -1
+ if eapi < 0:
+ return False
+ return eapi <= portage.const.EAPI
+
+# Generally, it's best not to assume that cache entries for unsupported EAPIs
+# can be validated. However, the current package manager specification does not
+# guarantee that the EAPI can be parsed without sourcing the ebuild, so
+# it's too costly to discard existing cache entries for unsupported EAPIs.
+# Therefore, by default, assume that cache entries for unsupported EAPIs can be
+# validated. If FEATURES=parse-eapi-* is enabled, this assumption is discarded
+# since the EAPI can be determined without the incurring the cost of sourcing
+# the ebuild.
+_validate_cache_for_unsupported_eapis = True
+
+_parse_eapi_ebuild_head_re = re.compile(r'^EAPI=[\'"]?([^\'"#]*)')
+_parse_eapi_ebuild_head_max_lines = 30
+
+def _parse_eapi_ebuild_head(f):
+ count = 0
+ for line in f:
+ m = _parse_eapi_ebuild_head_re.match(line)
+ if m is not None:
+ return m.group(1).strip()
+ count += 1
+ if count >= _parse_eapi_ebuild_head_max_lines:
+ break
+ return '0'
+
+def _movefile(src, dest, **kwargs):
+ """Calls movefile and raises a PortageException if an error occurs."""
+ if movefile(src, dest, **kwargs) is None:
+ raise portage.exception.PortageException(
+ "mv '%s' '%s'" % (src, dest))
+
+auxdbkeys = (
+ 'DEPEND', 'RDEPEND', 'SLOT', 'SRC_URI',
+ 'RESTRICT', 'HOMEPAGE', 'LICENSE', 'DESCRIPTION',
+ 'KEYWORDS', 'INHERITED', 'IUSE', 'REQUIRED_USE',
+ 'PDEPEND', 'PROVIDE', 'EAPI',
+ 'PROPERTIES', 'DEFINED_PHASES', 'UNUSED_05', 'UNUSED_04',
+ 'UNUSED_03', 'UNUSED_02', 'UNUSED_01',
+)
+auxdbkeylen=len(auxdbkeys)
+
+def portageexit():
+ if data.secpass > 1 and os.environ.get("SANDBOX_ON") != "1":
+ close_portdbapi_caches()
+
+def create_trees(config_root=None, target_root=None, trees=None):
+ if trees is None:
+ trees = {}
+ else:
+ # clean up any existing portdbapi instances
+ for myroot in trees:
+ portdb = trees[myroot]["porttree"].dbapi
+ portdb.close_caches()
+ portdbapi.portdbapi_instances.remove(portdb)
+ del trees[myroot]["porttree"], myroot, portdb
+
+ settings = config(config_root=config_root, target_root=target_root,
+ config_incrementals=portage.const.INCREMENTALS)
+ settings.lock()
+
+ myroots = [(settings["ROOT"], settings)]
+ if settings["ROOT"] != "/":
+
+ # When ROOT != "/" we only want overrides from the calling
+ # environment to apply to the config that's associated
+ # with ROOT != "/", so pass a nearly empty dict for the env parameter.
+ clean_env = {}
+ for k in ('PATH', 'PORTAGE_GRPNAME', 'PORTAGE_USERNAME',
+ 'SSH_AGENT_PID', 'SSH_AUTH_SOCK', 'TERM',
+ 'ftp_proxy', 'http_proxy', 'no_proxy'):
+ v = settings.get(k)
+ if v is not None:
+ clean_env[k] = v
+ settings = config(config_root=None, target_root="/", env=clean_env)
+ settings.lock()
+ myroots.append((settings["ROOT"], settings))
+
+ for myroot, mysettings in myroots:
+ trees[myroot] = portage.util.LazyItemsDict(trees.get(myroot, {}))
+ trees[myroot].addLazySingleton("virtuals", mysettings.getvirtuals)
+ trees[myroot].addLazySingleton(
+ "vartree", vartree, myroot, categories=mysettings.categories,
+ settings=mysettings)
+ trees[myroot].addLazySingleton("porttree",
+ portagetree, myroot, settings=mysettings)
+ trees[myroot].addLazySingleton("bintree",
+ binarytree, myroot, mysettings["PKGDIR"], settings=mysettings)
+ return trees
+
+if VERSION == 'HEAD':
+ class _LazyVersion(proxy.objectproxy.ObjectProxy):
+ def _get_target(self):
+ global VERSION
+ if VERSION is not self:
+ return VERSION
+ if os.path.isdir(os.path.join(PORTAGE_BASE_PATH, '.git')):
+ status, output = subprocess_getstatusoutput((
+ "cd %s ; git describe --tags || exit $? ; " + \
+ "if [ -n \"`git diff-index --name-only --diff-filter=M HEAD`\" ] ; " + \
+ "then echo modified ; git rev-list --format=%%ct -n 1 HEAD ; fi ; " + \
+ "exit 0") % _shell_quote(PORTAGE_BASE_PATH))
+ if os.WIFEXITED(status) and os.WEXITSTATUS(status) == os.EX_OK:
+ output_lines = output.splitlines()
+ if output_lines:
+ version_split = output_lines[0].split('-')
+ if version_split:
+ VERSION = version_split[0].lstrip('v')
+ patchlevel = False
+ if len(version_split) > 1:
+ patchlevel = True
+ VERSION = "%s_p%s" %(VERSION, version_split[1])
+ if len(output_lines) > 1 and output_lines[1] == 'modified':
+ head_timestamp = None
+ if len(output_lines) > 3:
+ try:
+ head_timestamp = long(output_lines[3])
+ except ValueError:
+ pass
+ timestamp = long(time.time())
+ if head_timestamp is not None and timestamp > head_timestamp:
+ timestamp = timestamp - head_timestamp
+ if not patchlevel:
+ VERSION = "%s_p0" % (VERSION,)
+ VERSION = "%s_p%d" % (VERSION, timestamp)
+ return VERSION
+ VERSION = 'HEAD'
+ return VERSION
+ VERSION = _LazyVersion()
+
+if "_legacy_globals_constructed" in globals():
+ # The module has been reloaded, so perform any relevant cleanup
+ # and prevent memory leaks.
+ if "db" in _legacy_globals_constructed:
+ try:
+ db
+ except NameError:
+ pass
+ else:
+ if isinstance(db, dict) and db:
+ for _x in db.values():
+ try:
+ if "porttree" in _x.lazy_items:
+ continue
+ except (AttributeError, TypeError):
+ continue
+ try:
+ _x = _x["porttree"].dbapi
+ except (AttributeError, KeyError):
+ continue
+ if not isinstance(_x, portdbapi):
+ continue
+ _x.close_caches()
+ try:
+ portdbapi.portdbapi_instances.remove(_x)
+ except ValueError:
+ pass
+ del _x
+
+class _LegacyGlobalProxy(proxy.objectproxy.ObjectProxy):
+
+ __slots__ = ('_name',)
+
+ def __init__(self, name):
+ proxy.objectproxy.ObjectProxy.__init__(self)
+ object.__setattr__(self, '_name', name)
+
+ def _get_target(self):
+ name = object.__getattribute__(self, '_name')
+ from portage._legacy_globals import _get_legacy_global
+ return _get_legacy_global(name)
+
+_legacy_global_var_names = ("archlist", "db", "features",
+ "groups", "mtimedb", "mtimedbfile", "pkglines",
+ "portdb", "profiledir", "root", "selinux_enabled",
+ "settings", "thirdpartymirrors")
+
+for k in _legacy_global_var_names:
+ globals()[k] = _LegacyGlobalProxy(k)
+del k
+
+_legacy_globals_constructed = set()
+
+def _disable_legacy_globals():
+ """
+ This deletes the ObjectProxy instances that are used
+ for lazy initialization of legacy global variables.
+ The purpose of deleting them is to prevent new code
+ from referencing these deprecated variables.
+ """
+ global _legacy_global_var_names
+ for k in _legacy_global_var_names:
+ globals().pop(k, None)
diff --git a/portage_with_autodep/pym/portage/_global_updates.py b/portage_with_autodep/pym/portage/_global_updates.py
new file mode 100644
index 0000000..868d1ee
--- /dev/null
+++ b/portage_with_autodep/pym/portage/_global_updates.py
@@ -0,0 +1,250 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import stat
+
+from portage import best, os
+from portage.const import WORLD_FILE
+from portage.data import secpass
+from portage.exception import DirectoryNotFound
+from portage.localization import _
+from portage.output import bold, colorize
+from portage.update import grab_updates, parse_updates, update_config_files, update_dbentry
+from portage.util import grabfile, shlex_split, \
+ writemsg, writemsg_stdout, write_atomic
+
+def _global_updates(trees, prev_mtimes, quiet=False):
+ """
+ Perform new global updates if they exist in 'profiles/updates/'
+ subdirectories of all active repositories (PORTDIR + PORTDIR_OVERLAY).
+ This simply returns if ROOT != "/" (when len(trees) != 1). If ROOT != "/"
+ then the user should instead use emaint --fix movebin and/or moveinst.
+
+ @param trees: A dictionary containing portage trees.
+ @type trees: dict
+ @param prev_mtimes: A dictionary containing mtimes of files located in
+ $PORTDIR/profiles/updates/.
+ @type prev_mtimes: dict
+ @rtype: bool
+ @return: True if update commands have been performed, otherwise False
+ """
+ # only do this if we're root and not running repoman/ebuild digest
+
+ retupd = False
+ if secpass < 2 or \
+ "SANDBOX_ACTIVE" in os.environ or \
+ len(trees) != 1:
+ return retupd
+ root = "/"
+ mysettings = trees[root]["vartree"].settings
+ portdb = trees[root]["porttree"].dbapi
+ vardb = trees[root]["vartree"].dbapi
+ bindb = trees[root]["bintree"].dbapi
+ if not os.access(bindb.bintree.pkgdir, os.W_OK):
+ bindb = None
+ else:
+ # Call binarytree.populate(), since we want to make sure it's
+ # only populated with local packages here (getbinpkgs=0).
+ bindb.bintree.populate()
+
+ world_file = os.path.join(mysettings['EROOT'], WORLD_FILE)
+ world_list = grabfile(world_file)
+ world_modified = False
+ world_warnings = set()
+ updpath_map = {}
+ # Maps repo_name to list of updates. If a given repo has no updates
+ # directory, it will be omitted. If a repo has an updates directory
+ # but none need to be applied (according to timestamp logic), the
+ # value in the dict will be an empty list.
+ repo_map = {}
+ timestamps = {}
+
+ update_notice_printed = False
+ for repo_name in portdb.getRepositories():
+ repo = portdb.getRepositoryPath(repo_name)
+ updpath = os.path.join(repo, "profiles", "updates")
+ if not os.path.isdir(updpath):
+ continue
+
+ if updpath in updpath_map:
+ repo_map[repo_name] = updpath_map[updpath]
+ continue
+
+ try:
+ if mysettings.get("PORTAGE_CALLER") == "fixpackages":
+ update_data = grab_updates(updpath)
+ else:
+ update_data = grab_updates(updpath, prev_mtimes)
+ except DirectoryNotFound:
+ continue
+ myupd = []
+ updpath_map[updpath] = myupd
+ repo_map[repo_name] = myupd
+ if len(update_data) > 0:
+ for mykey, mystat, mycontent in update_data:
+ if not update_notice_printed:
+ update_notice_printed = True
+ writemsg_stdout("\n")
+ if quiet:
+ writemsg_stdout(colorize("GOOD",
+ _("Performing Global Updates\n")))
+ writemsg_stdout(_("(Could take a couple of minutes if you have a lot of binary packages.)\n"))
+ else:
+ writemsg_stdout(colorize("GOOD",
+ _("Performing Global Updates:\n")))
+ writemsg_stdout(_("(Could take a couple of minutes if you have a lot of binary packages.)\n"))
+ writemsg_stdout(_(" %s='update pass' %s='binary update' "
+ "%s='/var/db update' %s='/var/db move'\n"
+ " %s='/var/db SLOT move' %s='binary move' "
+ "%s='binary SLOT move'\n %s='update /etc/portage/package.*'\n") % \
+ (bold("."), bold("*"), bold("#"), bold("@"), bold("s"), bold("%"), bold("S"), bold("p")))
+ valid_updates, errors = parse_updates(mycontent)
+ myupd.extend(valid_updates)
+ if not quiet:
+ writemsg_stdout(bold(mykey))
+ writemsg_stdout(len(valid_updates) * "." + "\n")
+ if len(errors) == 0:
+ # Update our internal mtime since we
+ # processed all of our directives.
+ timestamps[mykey] = mystat[stat.ST_MTIME]
+ else:
+ for msg in errors:
+ writemsg("%s\n" % msg, noiselevel=-1)
+ if myupd:
+ retupd = True
+
+ master_repo = portdb.getRepositoryName(portdb.porttree_root)
+ if master_repo in repo_map:
+ repo_map['DEFAULT'] = repo_map[master_repo]
+
+ for repo_name, myupd in repo_map.items():
+ if repo_name == 'DEFAULT':
+ continue
+ if not myupd:
+ continue
+
+ def repo_match(repository):
+ return repository == repo_name or \
+ (repo_name == master_repo and repository not in repo_map)
+
+ def _world_repo_match(atoma, atomb):
+ """
+ Check whether to perform a world change from atoma to atomb.
+ If best vardb match for atoma comes from the same repository
+ as the update file, allow that. Additionally, if portdb still
+ can find a match for old atom name, warn about that.
+ """
+ matches = vardb.match(atoma)
+ if not matches:
+ matches = vardb.match(atomb)
+ if matches and \
+ repo_match(vardb.aux_get(best(matches), ['repository'])[0]):
+ if portdb.match(atoma):
+ world_warnings.add((atoma, atomb))
+ return True
+ else:
+ return False
+
+ for update_cmd in myupd:
+ for pos, atom in enumerate(world_list):
+ new_atom = update_dbentry(update_cmd, atom)
+ if atom != new_atom:
+ if _world_repo_match(atom, new_atom):
+ world_list[pos] = new_atom
+ world_modified = True
+
+ for update_cmd in myupd:
+ if update_cmd[0] == "move":
+ moves = vardb.move_ent(update_cmd, repo_match=repo_match)
+ if moves:
+ writemsg_stdout(moves * "@")
+ if bindb:
+ moves = bindb.move_ent(update_cmd, repo_match=repo_match)
+ if moves:
+ writemsg_stdout(moves * "%")
+ elif update_cmd[0] == "slotmove":
+ moves = vardb.move_slot_ent(update_cmd, repo_match=repo_match)
+ if moves:
+ writemsg_stdout(moves * "s")
+ if bindb:
+ moves = bindb.move_slot_ent(update_cmd, repo_match=repo_match)
+ if moves:
+ writemsg_stdout(moves * "S")
+
+ if world_modified:
+ world_list.sort()
+ write_atomic(world_file,
+ "".join("%s\n" % (x,) for x in world_list))
+ if world_warnings:
+ # XXX: print warning that we've updated world entries
+ # and the old name still matches something (from an overlay)?
+ pass
+
+ if retupd:
+
+ def _config_repo_match(repo_name, atoma, atomb):
+ """
+ Check whether to perform a world change from atoma to atomb.
+ If best vardb match for atoma comes from the same repository
+ as the update file, allow that. Additionally, if portdb still
+ can find a match for old atom name, warn about that.
+ """
+ matches = vardb.match(atoma)
+ if not matches:
+ matches = vardb.match(atomb)
+ if not matches:
+ return False
+ repository = vardb.aux_get(best(matches), ['repository'])[0]
+ return repository == repo_name or \
+ (repo_name == master_repo and repository not in repo_map)
+
+ update_config_files(root,
+ shlex_split(mysettings.get("CONFIG_PROTECT", "")),
+ shlex_split(mysettings.get("CONFIG_PROTECT_MASK", "")),
+ repo_map, match_callback=_config_repo_match)
+
+ # The above global updates proceed quickly, so they
+ # are considered a single mtimedb transaction.
+ if timestamps:
+ # We do not update the mtime in the mtimedb
+ # until after _all_ of the above updates have
+ # been processed because the mtimedb will
+ # automatically commit when killed by ctrl C.
+ for mykey, mtime in timestamps.items():
+ prev_mtimes[mykey] = mtime
+
+ do_upgrade_packagesmessage = False
+ # We gotta do the brute force updates for these now.
+ if mysettings.get("PORTAGE_CALLER") == "fixpackages" or \
+ "fixpackages" in mysettings.features:
+ def onUpdate(maxval, curval):
+ if curval > 0:
+ writemsg_stdout("#")
+ if quiet:
+ onUpdate = None
+ vardb.update_ents(repo_map, onUpdate=onUpdate)
+ if bindb:
+ def onUpdate(maxval, curval):
+ if curval > 0:
+ writemsg_stdout("*")
+ if quiet:
+ onUpdate = None
+ bindb.update_ents(repo_map, onUpdate=onUpdate)
+ else:
+ do_upgrade_packagesmessage = 1
+
+ # Update progress above is indicated by characters written to stdout so
+ # we print a couple new lines here to separate the progress output from
+ # what follows.
+ print()
+ print()
+
+ if do_upgrade_packagesmessage and bindb and \
+ bindb.cpv_all():
+ writemsg_stdout(_(" ** Skipping packages. Run 'fixpackages' or set it in FEATURES to fix the tbz2's in the packages directory.\n"))
+ writemsg_stdout(bold(_("Note: This can take a very long time.")))
+ writemsg_stdout("\n")
+
+ return retupd
diff --git a/portage_with_autodep/pym/portage/_legacy_globals.py b/portage_with_autodep/pym/portage/_legacy_globals.py
new file mode 100644
index 0000000..615591a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/_legacy_globals.py
@@ -0,0 +1,81 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import portage
+from portage import os
+from portage.const import CACHE_PATH, PROFILE_PATH
+
+def _get_legacy_global(name):
+ constructed = portage._legacy_globals_constructed
+ if name in constructed:
+ return getattr(portage, name)
+
+ if name == 'portdb':
+ portage.portdb = portage.db[portage.root]["porttree"].dbapi
+ constructed.add(name)
+ return getattr(portage, name)
+
+ elif name in ('mtimedb', 'mtimedbfile'):
+ portage.mtimedbfile = os.path.join(portage.settings['EROOT'],
+ CACHE_PATH, "mtimedb")
+ constructed.add('mtimedbfile')
+ portage.mtimedb = portage.MtimeDB(portage.mtimedbfile)
+ constructed.add('mtimedb')
+ return getattr(portage, name)
+
+ # Portage needs to ensure a sane umask for the files it creates.
+ os.umask(0o22)
+
+ kwargs = {}
+ for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT")):
+ kwargs[k] = os.environ.get(envvar)
+
+ portage._initializing_globals = True
+ portage.db = portage.create_trees(**kwargs)
+ constructed.add('db')
+ del portage._initializing_globals
+
+ settings = portage.db["/"]["vartree"].settings
+
+ for root in portage.db:
+ if root != "/":
+ settings = portage.db[root]["vartree"].settings
+ break
+
+ portage.output._init(config_root=settings['PORTAGE_CONFIGROOT'])
+
+ portage.settings = settings
+ constructed.add('settings')
+
+ portage.root = root
+ constructed.add('root')
+
+ # COMPATIBILITY
+ # These attributes should not be used within
+ # Portage under any circumstances.
+
+ portage.archlist = settings.archlist()
+ constructed.add('archlist')
+
+ portage.features = settings.features
+ constructed.add('features')
+
+ portage.groups = settings["ACCEPT_KEYWORDS"].split()
+ constructed.add('groups')
+
+ portage.pkglines = settings.packages
+ constructed.add('pkglines')
+
+ portage.selinux_enabled = settings.selinux_enabled()
+ constructed.add('selinux_enabled')
+
+ portage.thirdpartymirrors = settings.thirdpartymirrors()
+ constructed.add('thirdpartymirrors')
+
+ profiledir = os.path.join(settings["PORTAGE_CONFIGROOT"], PROFILE_PATH)
+ if not os.path.isdir(profiledir):
+ profiledir = None
+ portage.profiledir = profiledir
+ constructed.add('profiledir')
+
+ return getattr(portage, name)
diff --git a/portage_with_autodep/pym/portage/_selinux.py b/portage_with_autodep/pym/portage/_selinux.py
new file mode 100644
index 0000000..9470978
--- /dev/null
+++ b/portage_with_autodep/pym/portage/_selinux.py
@@ -0,0 +1,129 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Don't use the unicode-wrapped os and shutil modules here since
+# the whole _selinux module itself will be wrapped.
+import os
+import shutil
+
+import portage
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+from portage.localization import _
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'selinux')
+
+def copyfile(src, dest):
+ src = _unicode_encode(src, encoding=_encodings['fs'], errors='strict')
+ dest = _unicode_encode(dest, encoding=_encodings['fs'], errors='strict')
+ (rc, ctx) = selinux.lgetfilecon(src)
+ if rc < 0:
+ src = _unicode_decode(src, encoding=_encodings['fs'], errors='replace')
+ raise OSError(_("copyfile: Failed getting context of \"%s\".") % src)
+
+ setfscreate(ctx)
+ try:
+ shutil.copyfile(src, dest)
+ finally:
+ setfscreate()
+
+def getcontext():
+ (rc, ctx) = selinux.getcon()
+ if rc < 0:
+ raise OSError(_("getcontext: Failed getting current process context."))
+
+ return ctx
+
+def is_selinux_enabled():
+ return selinux.is_selinux_enabled()
+
+def mkdir(target, refdir):
+ target = _unicode_encode(target, encoding=_encodings['fs'], errors='strict')
+ refdir = _unicode_encode(refdir, encoding=_encodings['fs'], errors='strict')
+ (rc, ctx) = selinux.getfilecon(refdir)
+ if rc < 0:
+ refdir = _unicode_decode(refdir, encoding=_encodings['fs'],
+ errors='replace')
+ raise OSError(
+ _("mkdir: Failed getting context of reference directory \"%s\".") \
+ % refdir)
+
+ setfscreate(ctx)
+ try:
+ os.mkdir(target)
+ finally:
+ setfscreate()
+
+def rename(src, dest):
+ src = _unicode_encode(src, encoding=_encodings['fs'], errors='strict')
+ dest = _unicode_encode(dest, encoding=_encodings['fs'], errors='strict')
+ (rc, ctx) = selinux.lgetfilecon(src)
+ if rc < 0:
+ src = _unicode_decode(src, encoding=_encodings['fs'], errors='replace')
+ raise OSError(_("rename: Failed getting context of \"%s\".") % src)
+
+ setfscreate(ctx)
+ try:
+ os.rename(src,dest)
+ finally:
+ setfscreate()
+
+def settype(newtype):
+ ret = getcontext().split(":")
+ ret[2] = newtype
+ return ":".join(ret)
+
+def setexec(ctx="\n"):
+ ctx = _unicode_encode(ctx, encoding=_encodings['content'], errors='strict')
+ if selinux.setexeccon(ctx) < 0:
+ ctx = _unicode_decode(ctx, encoding=_encodings['content'],
+ errors='replace')
+ if selinux.security_getenforce() == 1:
+ raise OSError(_("Failed setting exec() context \"%s\".") % ctx)
+ else:
+ portage.writemsg("!!! " + \
+ _("Failed setting exec() context \"%s\".") % ctx, \
+ noiselevel=-1)
+
+def setfscreate(ctx="\n"):
+ ctx = _unicode_encode(ctx,
+ encoding=_encodings['content'], errors='strict')
+ if selinux.setfscreatecon(ctx) < 0:
+ ctx = _unicode_decode(ctx,
+ encoding=_encodings['content'], errors='replace')
+ raise OSError(
+ _("setfscreate: Failed setting fs create context \"%s\".") % ctx)
+
+def spawn_wrapper(spawn_func, selinux_type):
+
+ selinux_type = _unicode_encode(selinux_type,
+ encoding=_encodings['content'], errors='strict')
+
+ def wrapper_func(*args, **kwargs):
+ con = settype(selinux_type)
+ setexec(con)
+ try:
+ return spawn_func(*args, **kwargs)
+ finally:
+ setexec()
+
+ return wrapper_func
+
+def symlink(target, link, reflnk):
+ target = _unicode_encode(target, encoding=_encodings['fs'], errors='strict')
+ link = _unicode_encode(link, encoding=_encodings['fs'], errors='strict')
+ reflnk = _unicode_encode(reflnk, encoding=_encodings['fs'], errors='strict')
+ (rc, ctx) = selinux.lgetfilecon(reflnk)
+ if rc < 0:
+ reflnk = _unicode_decode(reflnk, encoding=_encodings['fs'],
+ errors='replace')
+ raise OSError(
+ _("symlink: Failed getting context of reference symlink \"%s\".") \
+ % reflnk)
+
+ setfscreate(ctx)
+ try:
+ os.symlink(target, link)
+ finally:
+ setfscreate()
diff --git a/portage_with_autodep/pym/portage/_sets/__init__.py b/portage_with_autodep/pym/portage/_sets/__init__.py
new file mode 100644
index 0000000..1b3484e
--- /dev/null
+++ b/portage_with_autodep/pym/portage/_sets/__init__.py
@@ -0,0 +1,245 @@
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+__all__ = ["SETPREFIX", "get_boolean", "SetConfigError",
+ "SetConfig", "load_default_config"]
+
+try:
+ from configparser import SafeConfigParser, NoOptionError
+except ImportError:
+ from ConfigParser import SafeConfigParser, NoOptionError
+from portage import os
+from portage import load_mod
+from portage.const import USER_CONFIG_PATH, GLOBAL_CONFIG_PATH
+from portage.const import _ENABLE_SET_CONFIG
+from portage.exception import PackageSetNotFound
+from portage.localization import _
+
+SETPREFIX = "@"
+
+def get_boolean(options, name, default):
+ if not name in options:
+ return default
+ elif options[name].lower() in ("1", "yes", "on", "true"):
+ return True
+ elif options[name].lower() in ("0", "no", "off", "false"):
+ return False
+ else:
+ raise SetConfigError(_("invalid value '%(value)s' for option '%(option)s'") % {"value": options[name], "option": name})
+
+class SetConfigError(Exception):
+ pass
+
+class SetConfig(object):
+ def __init__(self, paths, settings, trees):
+ self._parser = SafeConfigParser(
+ defaults={
+ "EPREFIX" : settings["EPREFIX"],
+ "EROOT" : settings["EROOT"],
+ "PORTAGE_CONFIGROOT" : settings["PORTAGE_CONFIGROOT"],
+ "ROOT" : settings["ROOT"],
+ })
+
+ if _ENABLE_SET_CONFIG:
+ self._parser.read(paths)
+ else:
+ self._create_default_config()
+
+ self.errors = []
+ self.psets = {}
+ self.trees = trees
+ self.settings = settings
+ self._parsed = False
+ self.active = []
+
+ def _create_default_config(self):
+ """
+ Create a default hardcoded set configuration for a portage version
+ that does not support set configuration files. This is only used
+ in the current branch of portage if _ENABLE_SET_CONFIG is False.
+ Even if it's not used in this branch, keep it here in order to
+ minimize the diff between branches.
+
+ [world]
+ class = portage.sets.base.DummyPackageSet
+ packages = @selected @system
+
+ [selected]
+ class = portage.sets.files.WorldSelectedSet
+
+ [system]
+ class = portage.sets.profiles.PackagesSystemSet
+
+ """
+ parser = self._parser
+
+ parser.add_section("world")
+ parser.set("world", "class", "portage.sets.base.DummyPackageSet")
+ parser.set("world", "packages", "@selected @system")
+
+ parser.add_section("selected")
+ parser.set("selected", "class", "portage.sets.files.WorldSelectedSet")
+
+ parser.add_section("system")
+ parser.set("system", "class", "portage.sets.profiles.PackagesSystemSet")
+
+ def update(self, setname, options):
+ parser = self._parser
+ self.errors = []
+ if not setname in self.psets:
+ options["name"] = setname
+ options["world-candidate"] = "False"
+
+ # for the unlikely case that there is already a section with the requested setname
+ import random
+ while setname in parser.sections():
+ setname = "%08d" % random.randint(0, 10**10)
+
+ parser.add_section(setname)
+ for k, v in options.items():
+ parser.set(setname, k, v)
+ else:
+ section = self.psets[setname].creator
+ if parser.has_option(section, "multiset") and \
+ parser.getboolean(section, "multiset"):
+ self.errors.append(_("Invalid request to reconfigure set '%(set)s' generated "
+ "by multiset section '%(section)s'") % {"set": setname, "section": section})
+ return
+ for k, v in options.items():
+ parser.set(section, k, v)
+ self._parse(update=True)
+
+ def _parse(self, update=False):
+ if self._parsed and not update:
+ return
+ parser = self._parser
+ for sname in parser.sections():
+ # find classname for current section, default to file based sets
+ if not parser.has_option(sname, "class"):
+ classname = "portage._sets.files.StaticFileSet"
+ else:
+ classname = parser.get(sname, "class")
+
+ if classname.startswith('portage.sets.'):
+ # The module has been made private, but we still support
+ # the previous namespace for sets.conf entries.
+ classname = classname.replace('sets', '_sets', 1)
+
+ # try to import the specified class
+ try:
+ setclass = load_mod(classname)
+ except (ImportError, AttributeError):
+ try:
+ setclass = load_mod("portage._sets." + classname)
+ except (ImportError, AttributeError):
+ self.errors.append(_("Could not import '%(class)s' for section "
+ "'%(section)s'") % {"class": classname, "section": sname})
+ continue
+ # prepare option dict for the current section
+ optdict = {}
+ for oname in parser.options(sname):
+ optdict[oname] = parser.get(sname, oname)
+
+ # create single or multiple instances of the given class depending on configuration
+ if parser.has_option(sname, "multiset") and \
+ parser.getboolean(sname, "multiset"):
+ if hasattr(setclass, "multiBuilder"):
+ newsets = {}
+ try:
+ newsets = setclass.multiBuilder(optdict, self.settings, self.trees)
+ except SetConfigError as e:
+ self.errors.append(_("Configuration error in section '%s': %s") % (sname, str(e)))
+ continue
+ for x in newsets:
+ if x in self.psets and not update:
+ self.errors.append(_("Redefinition of set '%s' (sections: '%s', '%s')") % (x, self.psets[x].creator, sname))
+ newsets[x].creator = sname
+ if parser.has_option(sname, "world-candidate") and \
+ parser.getboolean(sname, "world-candidate"):
+ newsets[x].world_candidate = True
+ self.psets.update(newsets)
+ else:
+ self.errors.append(_("Section '%(section)s' is configured as multiset, but '%(class)s' "
+ "doesn't support that configuration") % {"section": sname, "class": classname})
+ continue
+ else:
+ try:
+ setname = parser.get(sname, "name")
+ except NoOptionError:
+ setname = sname
+ if setname in self.psets and not update:
+ self.errors.append(_("Redefinition of set '%s' (sections: '%s', '%s')") % (setname, self.psets[setname].creator, sname))
+ if hasattr(setclass, "singleBuilder"):
+ try:
+ self.psets[setname] = setclass.singleBuilder(optdict, self.settings, self.trees)
+ self.psets[setname].creator = sname
+ if parser.has_option(sname, "world-candidate") and \
+ parser.getboolean(sname, "world-candidate"):
+ self.psets[setname].world_candidate = True
+ except SetConfigError as e:
+ self.errors.append(_("Configuration error in section '%s': %s") % (sname, str(e)))
+ continue
+ else:
+ self.errors.append(_("'%(class)s' does not support individual set creation, section '%(section)s' "
+ "must be configured as multiset") % {"class": classname, "section": sname})
+ continue
+ self._parsed = True
+
+ def getSets(self):
+ self._parse()
+ return self.psets.copy()
+
+ def getSetAtoms(self, setname, ignorelist=None):
+ """
+ This raises PackageSetNotFound if the give setname does not exist.
+ """
+ self._parse()
+ try:
+ myset = self.psets[setname]
+ except KeyError:
+ raise PackageSetNotFound(setname)
+ myatoms = myset.getAtoms()
+ parser = self._parser
+
+ if ignorelist is None:
+ ignorelist = set()
+
+ ignorelist.add(setname)
+ for n in myset.getNonAtoms():
+ if n.startswith(SETPREFIX):
+ s = n[len(SETPREFIX):]
+ if s in self.psets:
+ if s not in ignorelist:
+ myatoms.update(self.getSetAtoms(s,
+ ignorelist=ignorelist))
+ else:
+ raise PackageSetNotFound(s)
+
+ return myatoms
+
+def load_default_config(settings, trees):
+
+ if not _ENABLE_SET_CONFIG:
+ return SetConfig(None, settings, trees)
+
+ global_config_path = GLOBAL_CONFIG_PATH
+ if settings['EPREFIX']:
+ global_config_path = os.path.join(settings['EPREFIX'],
+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
+ def _getfiles():
+ for path, dirs, files in os.walk(os.path.join(global_config_path, "sets")):
+ for f in files:
+ if not f.startswith(b'.'):
+ yield os.path.join(path, f)
+
+ dbapi = trees["porttree"].dbapi
+ for repo in dbapi.getRepositories():
+ path = dbapi.getRepositoryPath(repo)
+ yield os.path.join(path, "sets.conf")
+
+ yield os.path.join(settings["PORTAGE_CONFIGROOT"],
+ USER_CONFIG_PATH, "sets.conf")
+
+ return SetConfig(_getfiles(), settings, trees)
diff --git a/portage_with_autodep/pym/portage/_sets/base.py b/portage_with_autodep/pym/portage/_sets/base.py
new file mode 100644
index 0000000..c8d3ae4
--- /dev/null
+++ b/portage_with_autodep/pym/portage/_sets/base.py
@@ -0,0 +1,264 @@
+# Copyright 2007-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+from portage.dep import Atom, ExtendedAtomDict, best_match_to_list, match_from_list
+from portage.exception import InvalidAtom
+from portage.versions import cpv_getkey
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+OPERATIONS = ["merge", "unmerge"]
+
+class PackageSet(object):
+ # Set this to operations that are supported by your subclass. While
+ # technically there is no difference between "merge" and "unmerge" regarding
+ # package sets, the latter doesn't make sense for some sets like "system"
+ # or "security" and therefore isn't supported by them.
+ _operations = ["merge"]
+ description = "generic package set"
+
+ def __init__(self, allow_wildcard=False, allow_repo=False):
+ self._atoms = set()
+ self._atommap = ExtendedAtomDict(set)
+ self._loaded = False
+ self._loading = False
+ self.errors = []
+ self._nonatoms = set()
+ self.world_candidate = False
+ self._allow_wildcard = allow_wildcard
+ self._allow_repo = allow_repo
+
+ def __contains__(self, atom):
+ self._load()
+ return atom in self._atoms or atom in self._nonatoms
+
+ def __iter__(self):
+ self._load()
+ for x in self._atoms:
+ yield x
+ for x in self._nonatoms:
+ yield x
+
+ def __bool__(self):
+ self._load()
+ return bool(self._atoms or self._nonatoms)
+
+ if sys.hexversion < 0x3000000:
+ __nonzero__ = __bool__
+
+ def supportsOperation(self, op):
+ if not op in OPERATIONS:
+ raise ValueError(op)
+ return op in self._operations
+
+ def _load(self):
+ if not (self._loaded or self._loading):
+ self._loading = True
+ self.load()
+ self._loaded = True
+ self._loading = False
+
+ def getAtoms(self):
+ self._load()
+ return self._atoms.copy()
+
+ def getNonAtoms(self):
+ self._load()
+ return self._nonatoms.copy()
+
+ def _setAtoms(self, atoms):
+ self._atoms.clear()
+ self._nonatoms.clear()
+ for a in atoms:
+ if not isinstance(a, Atom):
+ if isinstance(a, basestring):
+ a = a.strip()
+ if not a:
+ continue
+ try:
+ a = Atom(a, allow_wildcard=True, allow_repo=True)
+ except InvalidAtom:
+ self._nonatoms.add(a)
+ continue
+ if not self._allow_wildcard and a.extended_syntax:
+ raise InvalidAtom("extended atom syntax not allowed here")
+ if not self._allow_repo and a.repo:
+ raise InvalidAtom("repository specification not allowed here")
+ self._atoms.add(a)
+
+ self._updateAtomMap()
+
+ def load(self):
+ # This method must be overwritten by subclasses
+ # Editable sets should use the value of self._mtime to determine if they
+ # need to reload themselves
+ raise NotImplementedError()
+
+ def containsCPV(self, cpv):
+ self._load()
+ for a in self._atoms:
+ if match_from_list(a, [cpv]):
+ return True
+ return False
+
+ def getMetadata(self, key):
+ if hasattr(self, key.lower()):
+ return getattr(self, key.lower())
+ else:
+ return ""
+
+ def _updateAtomMap(self, atoms=None):
+ """Update self._atommap for specific atoms or all atoms."""
+ if not atoms:
+ self._atommap.clear()
+ atoms = self._atoms
+ for a in atoms:
+ self._atommap.setdefault(a.cp, set()).add(a)
+
+ # Not sure if this one should really be in PackageSet
+ def findAtomForPackage(self, pkg, modified_use=None):
+ """Return the best match for a given package from the arguments, or
+ None if there are no matches. This matches virtual arguments against
+ the PROVIDE metadata. This can raise an InvalidDependString exception
+ if an error occurs while parsing PROVIDE."""
+
+ if modified_use is not None and modified_use is not pkg.use.enabled:
+ pkg = pkg.copy()
+ pkg.metadata["USE"] = " ".join(modified_use)
+
+ # Atoms matched via PROVIDE must be temporarily transformed since
+ # match_from_list() only works correctly when atom.cp == pkg.cp.
+ rev_transform = {}
+ for atom in self.iterAtomsForPackage(pkg):
+ if atom.cp == pkg.cp:
+ rev_transform[atom] = atom
+ else:
+ rev_transform[Atom(atom.replace(atom.cp, pkg.cp, 1), allow_wildcard=True, allow_repo=True)] = atom
+ best_match = best_match_to_list(pkg, iter(rev_transform))
+ if best_match:
+ return rev_transform[best_match]
+ return None
+
+ def iterAtomsForPackage(self, pkg):
+ """
+ Find all matching atoms for a given package. This matches virtual
+ arguments against the PROVIDE metadata. This will raise an
+ InvalidDependString exception if PROVIDE is invalid.
+ """
+ cpv_slot_list = [pkg]
+ cp = cpv_getkey(pkg.cpv)
+ self._load() # make sure the atoms are loaded
+
+ atoms = self._atommap.get(cp)
+ if atoms:
+ for atom in atoms:
+ if match_from_list(atom, cpv_slot_list):
+ yield atom
+ provides = pkg.metadata['PROVIDE']
+ if not provides:
+ return
+ provides = provides.split()
+ for provide in provides:
+ try:
+ provided_cp = Atom(provide).cp
+ except InvalidAtom:
+ continue
+ atoms = self._atommap.get(provided_cp)
+ if atoms:
+ for atom in atoms:
+ if match_from_list(atom.replace(provided_cp, cp),
+ cpv_slot_list):
+ yield atom
+
+class EditablePackageSet(PackageSet):
+
+ def __init__(self, allow_wildcard=False, allow_repo=False):
+ super(EditablePackageSet, self).__init__(allow_wildcard=allow_wildcard, allow_repo=allow_repo)
+
+ def update(self, atoms):
+ self._load()
+ modified = False
+ normal_atoms = []
+ for a in atoms:
+ if not isinstance(a, Atom):
+ try:
+ a = Atom(a, allow_wildcard=True, allow_repo=True)
+ except InvalidAtom:
+ modified = True
+ self._nonatoms.add(a)
+ continue
+ if not self._allow_wildcard and a.extended_syntax:
+ raise InvalidAtom("extended atom syntax not allowed here")
+ if not self._allow_repo and a.repo:
+ raise InvalidAtom("repository specification not allowed here")
+ normal_atoms.append(a)
+
+ if normal_atoms:
+ modified = True
+ self._atoms.update(normal_atoms)
+ self._updateAtomMap(atoms=normal_atoms)
+ if modified:
+ self.write()
+
+ def add(self, atom):
+ self.update([atom])
+
+ def replace(self, atoms):
+ self._setAtoms(atoms)
+ self.write()
+
+ def remove(self, atom):
+ self._load()
+ self._atoms.discard(atom)
+ self._nonatoms.discard(atom)
+ self._updateAtomMap()
+ self.write()
+
+ def removePackageAtoms(self, cp):
+ self._load()
+ for a in list(self._atoms):
+ if a.cp == cp:
+ self.remove(a)
+ self.write()
+
+ def write(self):
+ # This method must be overwritten in subclasses that should be editable
+ raise NotImplementedError()
+
+class InternalPackageSet(EditablePackageSet):
+ def __init__(self, initial_atoms=None, allow_wildcard=False, allow_repo=True):
+ """
+ Repo atoms are allowed more often than not, so it makes sense for this
+ class to allow them by default. The Atom constructor and isvalidatom()
+ functions default to allow_repo=False, which is sufficient to ensure
+ that repo atoms are prohibited when necessary.
+ """
+ super(InternalPackageSet, self).__init__(allow_wildcard=allow_wildcard, allow_repo=allow_repo)
+ if initial_atoms != None:
+ self.update(initial_atoms)
+
+ def clear(self):
+ self._atoms.clear()
+ self._updateAtomMap()
+
+ def load(self):
+ pass
+
+ def write(self):
+ pass
+
+class DummyPackageSet(PackageSet):
+ def __init__(self, atoms=None):
+ super(DummyPackageSet, self).__init__()
+ if atoms:
+ self._setAtoms(atoms)
+
+ def load(self):
+ pass
+
+ def singleBuilder(cls, options, settings, trees):
+ atoms = options.get("packages", "").split()
+ return DummyPackageSet(atoms=atoms)
+ singleBuilder = classmethod(singleBuilder)
diff --git a/portage_with_autodep/pym/portage/_sets/dbapi.py b/portage_with_autodep/pym/portage/_sets/dbapi.py
new file mode 100644
index 0000000..0f238f0
--- /dev/null
+++ b/portage_with_autodep/pym/portage/_sets/dbapi.py
@@ -0,0 +1,383 @@
+# Copyright 2007-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import time
+
+from portage import os
+from portage.versions import catpkgsplit, catsplit, pkgcmp, best
+from portage.dep import Atom
+from portage.localization import _
+from portage._sets.base import PackageSet
+from portage._sets import SetConfigError, get_boolean
+import portage
+
+__all__ = ["CategorySet", "DowngradeSet",
+ "EverythingSet", "OwnerSet", "VariableSet"]
+
+class EverythingSet(PackageSet):
+ _operations = ["merge"]
+ description = "Package set which contains SLOT " + \
+ "atoms to match all installed packages"
+ _filter = None
+
+ def __init__(self, vdbapi, **kwargs):
+ super(EverythingSet, self).__init__()
+ self._db = vdbapi
+
+ def load(self):
+ myatoms = []
+ db_keys = ["SLOT"]
+ aux_get = self._db.aux_get
+ cp_list = self._db.cp_list
+
+ for cp in self._db.cp_all():
+ for cpv in cp_list(cp):
+ # NOTE: Create SLOT atoms even when there is only one
+ # SLOT installed, in order to avoid the possibility
+ # of unwanted upgrades as reported in bug #338959.
+ slot, = aux_get(cpv, db_keys)
+ atom = Atom("%s:%s" % (cp, slot))
+ if self._filter:
+ if self._filter(atom):
+ myatoms.append(atom)
+ else:
+ myatoms.append(atom)
+
+ self._setAtoms(myatoms)
+
+ def singleBuilder(self, options, settings, trees):
+ return EverythingSet(trees["vartree"].dbapi)
+ singleBuilder = classmethod(singleBuilder)
+
+class OwnerSet(PackageSet):
+
+ _operations = ["merge", "unmerge"]
+
+ description = "Package set which contains all packages " + \
+ "that own one or more files."
+
+ def __init__(self, vardb=None, exclude_files=None, files=None):
+ super(OwnerSet, self).__init__()
+ self._db = vardb
+ self._exclude_files = exclude_files
+ self._files = files
+
+ def mapPathsToAtoms(self, paths, exclude_paths=None):
+ """
+ All paths must have $EROOT stripped from the left side.
+ """
+ rValue = set()
+ vardb = self._db
+ aux_get = vardb.aux_get
+ aux_keys = ["SLOT"]
+ if exclude_paths is None:
+ for link, p in vardb._owners.iter_owners(paths):
+ cat, pn = catpkgsplit(link.mycpv)[:2]
+ slot, = aux_get(link.mycpv, aux_keys)
+ rValue.add("%s/%s:%s" % (cat, pn, slot))
+ else:
+ all_paths = set()
+ all_paths.update(paths)
+ all_paths.update(exclude_paths)
+ exclude_atoms = set()
+ for link, p in vardb._owners.iter_owners(all_paths):
+ cat, pn = catpkgsplit(link.mycpv)[:2]
+ slot, = aux_get(link.mycpv, aux_keys)
+ atom = "%s/%s:%s" % (cat, pn, slot)
+ rValue.add(atom)
+ if p in exclude_paths:
+ exclude_atoms.add(atom)
+ rValue.difference_update(exclude_atoms)
+
+ return rValue
+
+ def load(self):
+ self._setAtoms(self.mapPathsToAtoms(self._files,
+ exclude_paths=self._exclude_files))
+
+ def singleBuilder(cls, options, settings, trees):
+ if not "files" in options:
+ raise SetConfigError(_("no files given"))
+
+ exclude_files = options.get("exclude-files")
+ if exclude_files is not None:
+ exclude_files = frozenset(portage.util.shlex_split(exclude_files))
+ return cls(vardb=trees["vartree"].dbapi, exclude_files=exclude_files,
+ files=frozenset(portage.util.shlex_split(options["files"])))
+
+ singleBuilder = classmethod(singleBuilder)
+
+class VariableSet(EverythingSet):
+
+ _operations = ["merge", "unmerge"]
+
+ description = "Package set which contains all packages " + \
+ "that match specified values of a specified variable."
+
+ def __init__(self, vardb, metadatadb=None, variable=None, includes=None, excludes=None):
+ super(VariableSet, self).__init__(vardb)
+ self._metadatadb = metadatadb
+ self._variable = variable
+ self._includes = includes
+ self._excludes = excludes
+
+ def _filter(self, atom):
+ ebuild = best(self._metadatadb.match(atom))
+ if not ebuild:
+ return False
+ values, = self._metadatadb.aux_get(ebuild, [self._variable])
+ values = values.split()
+ if self._includes and not self._includes.intersection(values):
+ return False
+ if self._excludes and self._excludes.intersection(values):
+ return False
+ return True
+
+ def singleBuilder(cls, options, settings, trees):
+
+ variable = options.get("variable")
+ if variable is None:
+ raise SetConfigError(_("missing required attribute: 'variable'"))
+
+ includes = options.get("includes", "")
+ excludes = options.get("excludes", "")
+
+ if not (includes or excludes):
+ raise SetConfigError(_("no includes or excludes given"))
+
+ metadatadb = options.get("metadata-source", "vartree")
+ if not metadatadb in trees:
+ raise SetConfigError(_("invalid value '%s' for option metadata-source") % metadatadb)
+
+ return cls(trees["vartree"].dbapi,
+ metadatadb=trees[metadatadb].dbapi,
+ excludes=frozenset(excludes.split()),
+ includes=frozenset(includes.split()),
+ variable=variable)
+
+ singleBuilder = classmethod(singleBuilder)
+
+class DowngradeSet(PackageSet):
+
+ _operations = ["merge", "unmerge"]
+
+ description = "Package set which contains all packages " + \
+ "for which the highest visible ebuild version is lower than " + \
+ "the currently installed version."
+
+ def __init__(self, portdb=None, vardb=None):
+ super(DowngradeSet, self).__init__()
+ self._portdb = portdb
+ self._vardb = vardb
+
+ def load(self):
+ atoms = []
+ xmatch = self._portdb.xmatch
+ xmatch_level = "bestmatch-visible"
+ cp_list = self._vardb.cp_list
+ aux_get = self._vardb.aux_get
+ aux_keys = ["SLOT"]
+ for cp in self._vardb.cp_all():
+ for cpv in cp_list(cp):
+ slot, = aux_get(cpv, aux_keys)
+ slot_atom = "%s:%s" % (cp, slot)
+ ebuild = xmatch(xmatch_level, slot_atom)
+ if not ebuild:
+ continue
+ ebuild_split = catpkgsplit(ebuild)[1:]
+ installed_split = catpkgsplit(cpv)[1:]
+ if pkgcmp(installed_split, ebuild_split) > 0:
+ atoms.append(slot_atom)
+
+ self._setAtoms(atoms)
+
+ def singleBuilder(cls, options, settings, trees):
+ return cls(portdb=trees["porttree"].dbapi,
+ vardb=trees["vartree"].dbapi)
+
+ singleBuilder = classmethod(singleBuilder)
+
+class UnavailableSet(EverythingSet):
+
+ _operations = ["unmerge"]
+
+ description = "Package set which contains all installed " + \
+ "packages for which there are no visible ebuilds " + \
+ "corresponding to the same $CATEGORY/$PN:$SLOT."
+
+ def __init__(self, vardb, metadatadb=None):
+ super(UnavailableSet, self).__init__(vardb)
+ self._metadatadb = metadatadb
+
+ def _filter(self, atom):
+ return not self._metadatadb.match(atom)
+
+ def singleBuilder(cls, options, settings, trees):
+
+ metadatadb = options.get("metadata-source", "porttree")
+ if not metadatadb in trees:
+ raise SetConfigError(_("invalid value '%s' for option "
+ "metadata-source") % (metadatadb,))
+
+ return cls(trees["vartree"].dbapi,
+ metadatadb=trees[metadatadb].dbapi)
+
+ singleBuilder = classmethod(singleBuilder)
+
+class UnavailableBinaries(EverythingSet):
+
+ _operations = ('merge', 'unmerge',)
+
+ description = "Package set which contains all installed " + \
+ "packages for which corresponding binary packages " + \
+ "are not available."
+
+ def __init__(self, vardb, metadatadb=None):
+ super(UnavailableBinaries, self).__init__(vardb)
+ self._metadatadb = metadatadb
+
+ def _filter(self, atom):
+ inst_pkg = self._db.match(atom)
+ if not inst_pkg:
+ return False
+ inst_cpv = inst_pkg[0]
+ return not self._metadatadb.cpv_exists(inst_cpv)
+
+ def singleBuilder(cls, options, settings, trees):
+
+ metadatadb = options.get("metadata-source", "bintree")
+ if not metadatadb in trees:
+ raise SetConfigError(_("invalid value '%s' for option "
+ "metadata-source") % (metadatadb,))
+
+ return cls(trees["vartree"].dbapi,
+ metadatadb=trees[metadatadb].dbapi)
+
+ singleBuilder = classmethod(singleBuilder)
+
+class CategorySet(PackageSet):
+ _operations = ["merge", "unmerge"]
+
+ def __init__(self, category, dbapi, only_visible=True):
+ super(CategorySet, self).__init__()
+ self._db = dbapi
+ self._category = category
+ self._check = only_visible
+ if only_visible:
+ s="visible"
+ else:
+ s="all"
+ self.description = "Package set containing %s packages of category %s" % (s, self._category)
+
+ def load(self):
+ myatoms = []
+ for cp in self._db.cp_all():
+ if catsplit(cp)[0] == self._category:
+ if (not self._check) or len(self._db.match(cp)) > 0:
+ myatoms.append(cp)
+ self._setAtoms(myatoms)
+
+ def _builderGetRepository(cls, options, repositories):
+ repository = options.get("repository", "porttree")
+ if not repository in repositories:
+ raise SetConfigError(_("invalid repository class '%s'") % repository)
+ return repository
+ _builderGetRepository = classmethod(_builderGetRepository)
+
+ def _builderGetVisible(cls, options):
+ return get_boolean(options, "only_visible", True)
+ _builderGetVisible = classmethod(_builderGetVisible)
+
+ def singleBuilder(cls, options, settings, trees):
+ if not "category" in options:
+ raise SetConfigError(_("no category given"))
+
+ category = options["category"]
+ if not category in settings.categories:
+ raise SetConfigError(_("invalid category name '%s'") % category)
+
+ repository = cls._builderGetRepository(options, trees.keys())
+ visible = cls._builderGetVisible(options)
+
+ return CategorySet(category, dbapi=trees[repository].dbapi, only_visible=visible)
+ singleBuilder = classmethod(singleBuilder)
+
+ def multiBuilder(cls, options, settings, trees):
+ rValue = {}
+
+ if "categories" in options:
+ categories = options["categories"].split()
+ invalid = set(categories).difference(settings.categories)
+ if invalid:
+ raise SetConfigError(_("invalid categories: %s") % ", ".join(list(invalid)))
+ else:
+ categories = settings.categories
+
+ repository = cls._builderGetRepository(options, trees.keys())
+ visible = cls._builderGetVisible(options)
+ name_pattern = options.get("name_pattern", "$category/*")
+
+ if not "$category" in name_pattern and not "${category}" in name_pattern:
+ raise SetConfigError(_("name_pattern doesn't include $category placeholder"))
+
+ for cat in categories:
+ myset = CategorySet(cat, trees[repository].dbapi, only_visible=visible)
+ myname = name_pattern.replace("$category", cat)
+ myname = myname.replace("${category}", cat)
+ rValue[myname] = myset
+ return rValue
+ multiBuilder = classmethod(multiBuilder)
+
+class AgeSet(EverythingSet):
+ _operations = ["merge", "unmerge"]
+
+ def __init__(self, vardb, mode="older", age=7):
+ super(AgeSet, self).__init__(vardb)
+ self._mode = mode
+ self._age = age
+
+ def _filter(self, atom):
+
+ cpv = self._db.match(atom)[0]
+ path = self._db.getpath(cpv, filename="COUNTER")
+ age = (time.time() - os.stat(path).st_mtime) / (3600 * 24)
+ if ((self._mode == "older" and age <= self._age) \
+ or (self._mode == "newer" and age >= self._age)):
+ return False
+ else:
+ return True
+
+ def singleBuilder(cls, options, settings, trees):
+ mode = options.get("mode", "older")
+ if str(mode).lower() not in ["newer", "older"]:
+ raise SetConfigError(_("invalid 'mode' value %s (use either 'newer' or 'older')") % mode)
+ try:
+ age = int(options.get("age", "7"))
+ except ValueError as e:
+ raise SetConfigError(_("value of option 'age' is not an integer"))
+ return AgeSet(vardb=trees["vartree"].dbapi, mode=mode, age=age)
+
+ singleBuilder = classmethod(singleBuilder)
+
+class RebuiltBinaries(EverythingSet):
+ _operations = ('merge',)
+ _aux_keys = ('BUILD_TIME',)
+
+ def __init__(self, vardb, bindb=None):
+ super(RebuiltBinaries, self).__init__(vardb, bindb=bindb)
+ self._bindb = bindb
+
+ def _filter(self, atom):
+ cpv = self._db.match(atom)[0]
+ inst_build_time, = self._db.aux_get(cpv, self._aux_keys)
+ try:
+ bin_build_time, = self._bindb.aux_get(cpv, self._aux_keys)
+ except KeyError:
+ return False
+ return bool(bin_build_time and (inst_build_time != bin_build_time))
+
+ def singleBuilder(cls, options, settings, trees):
+ return RebuiltBinaries(trees["vartree"].dbapi,
+ bindb=trees["bintree"].dbapi)
+
+ singleBuilder = classmethod(singleBuilder)
diff --git a/portage_with_autodep/pym/portage/_sets/files.py b/portage_with_autodep/pym/portage/_sets/files.py
new file mode 100644
index 0000000..f19ecf6
--- /dev/null
+++ b/portage_with_autodep/pym/portage/_sets/files.py
@@ -0,0 +1,341 @@
+# Copyright 2007-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import errno
+import re
+from itertools import chain
+
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+from portage.util import grabfile, write_atomic, ensure_dirs, normalize_path
+from portage.const import USER_CONFIG_PATH, WORLD_FILE, WORLD_SETS_FILE
+from portage.const import _ENABLE_SET_CONFIG
+from portage.localization import _
+from portage.locks import lockfile, unlockfile
+from portage import portage_gid
+from portage._sets.base import PackageSet, EditablePackageSet
+from portage._sets import SetConfigError, SETPREFIX, get_boolean
+from portage.env.loaders import ItemFileLoader, KeyListFileLoader
+from portage.env.validators import ValidAtomValidator
+from portage import cpv_getkey
+
+__all__ = ["StaticFileSet", "ConfigFileSet", "WorldSelectedSet"]
+
+class StaticFileSet(EditablePackageSet):
+ _operations = ["merge", "unmerge"]
+ _repopath_match = re.compile(r'.*\$\{repository:(?P<reponame>.+)\}.*')
+ _repopath_sub = re.compile(r'\$\{repository:(?P<reponame>.+)\}')
+
+ def __init__(self, filename, greedy=False, dbapi=None):
+ super(StaticFileSet, self).__init__(allow_repo=True)
+ self._filename = filename
+ self._mtime = None
+ self.description = "Package set loaded from file %s" % self._filename
+ self.loader = ItemFileLoader(self._filename, self._validate)
+ if greedy and not dbapi:
+ self.errors.append(_("%s configured as greedy set, but no dbapi instance passed in constructor") % self._filename)
+ greedy = False
+ self.greedy = greedy
+ self.dbapi = dbapi
+
+ metadata = grabfile(self._filename + ".metadata")
+ key = None
+ value = []
+ for line in metadata:
+ line = line.strip()
+ if len(line) == 0 and key != None:
+ setattr(self, key, " ".join(value))
+ key = None
+ elif line[-1] == ":" and key == None:
+ key = line[:-1].lower()
+ value = []
+ elif key != None:
+ value.append(line)
+ else:
+ pass
+ else:
+ if key != None:
+ setattr(self, key, " ".join(value))
+
+ def _validate(self, atom):
+ return bool(atom[:1] == SETPREFIX or ValidAtomValidator(atom, allow_repo=True))
+
+ def write(self):
+ write_atomic(self._filename, "".join("%s\n" % (atom,) \
+ for atom in sorted(chain(self._atoms, self._nonatoms))))
+
+ def load(self):
+ try:
+ mtime = os.stat(self._filename).st_mtime
+ except (OSError, IOError):
+ mtime = None
+ if (not self._loaded or self._mtime != mtime):
+ try:
+ data, errors = self.loader.load()
+ for fname in errors:
+ for e in errors[fname]:
+ self.errors.append(fname+": "+e)
+ except EnvironmentError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ data = {}
+ if self.greedy:
+ atoms = []
+ for a in data:
+ matches = self.dbapi.match(a)
+ for cpv in matches:
+ atoms.append("%s:%s" % (cpv_getkey(cpv),
+ self.dbapi.aux_get(cpv, ["SLOT"])[0]))
+ # In addition to any installed slots, also try to pull
+ # in the latest new slot that may be available.
+ atoms.append(a)
+ else:
+ atoms = iter(data)
+ self._setAtoms(atoms)
+ self._mtime = mtime
+
+ def singleBuilder(self, options, settings, trees):
+ if not "filename" in options:
+ raise SetConfigError(_("no filename specified"))
+ greedy = get_boolean(options, "greedy", False)
+ filename = options["filename"]
+ # look for repository path variables
+ match = self._repopath_match.match(filename)
+ if match:
+ try:
+ filename = self._repopath_sub.sub(trees["porttree"].dbapi.treemap[match.groupdict()["reponame"]], filename)
+ except KeyError:
+ raise SetConfigError(_("Could not find repository '%s'") % match.groupdict()["reponame"])
+ return StaticFileSet(filename, greedy=greedy, dbapi=trees["vartree"].dbapi)
+ singleBuilder = classmethod(singleBuilder)
+
+ def multiBuilder(self, options, settings, trees):
+ rValue = {}
+ directory = options.get("directory",
+ os.path.join(settings["PORTAGE_CONFIGROOT"],
+ USER_CONFIG_PATH, "sets"))
+ name_pattern = options.get("name_pattern", "${name}")
+ if not "$name" in name_pattern and not "${name}" in name_pattern:
+ raise SetConfigError(_("name_pattern doesn't include ${name} placeholder"))
+ greedy = get_boolean(options, "greedy", False)
+ # look for repository path variables
+ match = self._repopath_match.match(directory)
+ if match:
+ try:
+ directory = self._repopath_sub.sub(trees["porttree"].dbapi.treemap[match.groupdict()["reponame"]], directory)
+ except KeyError:
+ raise SetConfigError(_("Could not find repository '%s'") % match.groupdict()["reponame"])
+
+ try:
+ directory = _unicode_decode(directory,
+ encoding=_encodings['fs'], errors='strict')
+ # Now verify that we can also encode it.
+ _unicode_encode(directory,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeError:
+ directory = _unicode_decode(directory,
+ encoding=_encodings['fs'], errors='replace')
+ raise SetConfigError(
+ _("Directory path contains invalid character(s) for encoding '%s': '%s'") \
+ % (_encodings['fs'], directory))
+
+ if os.path.isdir(directory):
+ directory = normalize_path(directory)
+
+ for parent, dirs, files in os.walk(directory):
+ try:
+ parent = _unicode_decode(parent,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ continue
+ for d in dirs[:]:
+ if d[:1] == '.':
+ dirs.remove(d)
+ for filename in files:
+ try:
+ filename = _unicode_decode(filename,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ continue
+ if filename[:1] == '.':
+ continue
+ if filename.endswith(".metadata"):
+ continue
+ filename = os.path.join(parent,
+ filename)[1 + len(directory):]
+ myname = name_pattern.replace("$name", filename)
+ myname = myname.replace("${name}", filename)
+ rValue[myname] = StaticFileSet(
+ os.path.join(directory, filename),
+ greedy=greedy, dbapi=trees["vartree"].dbapi)
+ return rValue
+ multiBuilder = classmethod(multiBuilder)
+
+class ConfigFileSet(PackageSet):
+ def __init__(self, filename):
+ super(ConfigFileSet, self).__init__()
+ self._filename = filename
+ self.description = "Package set generated from %s" % self._filename
+ self.loader = KeyListFileLoader(self._filename, ValidAtomValidator)
+
+ def load(self):
+ data, errors = self.loader.load()
+ self._setAtoms(iter(data))
+
+ def singleBuilder(self, options, settings, trees):
+ if not "filename" in options:
+ raise SetConfigError(_("no filename specified"))
+ return ConfigFileSet(options["filename"])
+ singleBuilder = classmethod(singleBuilder)
+
+ def multiBuilder(self, options, settings, trees):
+ rValue = {}
+ directory = options.get("directory",
+ os.path.join(settings["PORTAGE_CONFIGROOT"], USER_CONFIG_PATH))
+ name_pattern = options.get("name_pattern", "sets/package_$suffix")
+ if not "$suffix" in name_pattern and not "${suffix}" in name_pattern:
+ raise SetConfigError(_("name_pattern doesn't include $suffix placeholder"))
+ for suffix in ["keywords", "use", "mask", "unmask"]:
+ myname = name_pattern.replace("$suffix", suffix)
+ myname = myname.replace("${suffix}", suffix)
+ rValue[myname] = ConfigFileSet(os.path.join(directory, "package."+suffix))
+ return rValue
+ multiBuilder = classmethod(multiBuilder)
+
+class WorldSelectedSet(EditablePackageSet):
+ description = "Set of packages that were directly installed by the user"
+
+ def __init__(self, eroot):
+ super(WorldSelectedSet, self).__init__(allow_repo=True)
+ # most attributes exist twice as atoms and non-atoms are stored in
+ # separate files
+ self._lock = None
+ self._filename = os.path.join(eroot, WORLD_FILE)
+ self.loader = ItemFileLoader(self._filename, self._validate)
+ self._mtime = None
+
+ self._filename2 = os.path.join(eroot, WORLD_SETS_FILE)
+ self.loader2 = ItemFileLoader(self._filename2, self._validate2)
+ self._mtime2 = None
+
+ def _validate(self, atom):
+ return ValidAtomValidator(atom, allow_repo=True)
+
+ def _validate2(self, setname):
+ return setname.startswith(SETPREFIX)
+
+ def write(self):
+ write_atomic(self._filename,
+ "".join(sorted("%s\n" % x for x in self._atoms)))
+
+ if _ENABLE_SET_CONFIG:
+ write_atomic(self._filename2,
+ "".join(sorted("%s\n" % x for x in self._nonatoms)))
+
+ def load(self):
+ atoms = []
+ nonatoms = []
+ atoms_changed = False
+ # load atoms and non-atoms from different files so the worldfile is
+ # backwards-compatible with older versions and other PMs, even though
+ # it's supposed to be private state data :/
+ try:
+ mtime = os.stat(self._filename).st_mtime
+ except (OSError, IOError):
+ mtime = None
+ if (not self._loaded or self._mtime != mtime):
+ try:
+ data, errors = self.loader.load()
+ for fname in errors:
+ for e in errors[fname]:
+ self.errors.append(fname+": "+e)
+ except EnvironmentError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ data = {}
+ atoms = list(data)
+ self._mtime = mtime
+ atoms_changed = True
+ else:
+ atoms.extend(self._atoms)
+
+ if _ENABLE_SET_CONFIG:
+ changed2, nonatoms = self._load2()
+ atoms_changed |= changed2
+
+ if atoms_changed:
+ self._setAtoms(atoms+nonatoms)
+
+ def _load2(self):
+ changed = False
+ try:
+ mtime = os.stat(self._filename2).st_mtime
+ except (OSError, IOError):
+ mtime = None
+ if (not self._loaded or self._mtime2 != mtime):
+ try:
+ data, errors = self.loader2.load()
+ for fname in errors:
+ for e in errors[fname]:
+ self.errors.append(fname+": "+e)
+ except EnvironmentError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ data = {}
+ nonatoms = list(data)
+ self._mtime2 = mtime
+ changed = True
+ else:
+ nonatoms = list(self._nonatoms)
+
+ return changed, nonatoms
+
+ def _ensure_dirs(self):
+ ensure_dirs(os.path.dirname(self._filename), gid=portage_gid, mode=0o2750, mask=0o2)
+
+ def lock(self):
+ self._ensure_dirs()
+ self._lock = lockfile(self._filename, wantnewlockfile=1)
+
+ def unlock(self):
+ unlockfile(self._lock)
+ self._lock = None
+
+ def cleanPackage(self, vardb, cpv):
+ '''
+ Before calling this function you should call lock and load.
+ After calling this function you should call unlock.
+ '''
+ if not self._lock:
+ raise AssertionError('cleanPackage needs the set to be locked')
+
+ worldlist = list(self._atoms)
+ mykey = cpv_getkey(cpv)
+ newworldlist = []
+ for x in worldlist:
+ if x.cp == mykey:
+ matches = vardb.match(x, use_cache=0)
+ if not matches:
+ #zap our world entry
+ pass
+ elif len(matches) == 1 and matches[0] == cpv:
+ #zap our world entry
+ pass
+ else:
+ #others are around; keep it.
+ newworldlist.append(x)
+ else:
+ #this doesn't match the package we're unmerging; keep it.
+ newworldlist.append(x)
+
+ newworldlist.extend(self._nonatoms)
+ self.replace(newworldlist)
+
+ def singleBuilder(self, options, settings, trees):
+ return WorldSelectedSet(settings["EROOT"])
+ singleBuilder = classmethod(singleBuilder)
diff --git a/portage_with_autodep/pym/portage/_sets/libs.py b/portage_with_autodep/pym/portage/_sets/libs.py
new file mode 100644
index 0000000..6c5babc
--- /dev/null
+++ b/portage_with_autodep/pym/portage/_sets/libs.py
@@ -0,0 +1,98 @@
+# Copyright 2007-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+from portage.localization import _
+from portage._sets.base import PackageSet
+from portage._sets import get_boolean, SetConfigError
+from portage.versions import cpv_getkey
+import portage
+
+class LibraryConsumerSet(PackageSet):
+ _operations = ["merge", "unmerge"]
+
+ def __init__(self, vardbapi, debug=False):
+ super(LibraryConsumerSet, self).__init__()
+ self.dbapi = vardbapi
+ self.debug = debug
+
+ def mapPathsToAtoms(self, paths):
+ rValue = set()
+ for p in paths:
+ for cpv in self.dbapi._linkmap.getOwners(p):
+ try:
+ slot, = self.dbapi.aux_get(cpv, ["SLOT"])
+ except KeyError:
+ # This is expected for preserved libraries
+ # of packages that have been uninstalled
+ # without replacement.
+ pass
+ else:
+ rValue.add("%s:%s" % (cpv_getkey(cpv), slot))
+ return rValue
+
+class LibraryFileConsumerSet(LibraryConsumerSet):
+
+ """
+ Note: This does not detect libtool archive (*.la) files that consume the
+ specified files (revdep-rebuild is able to detect them).
+ """
+
+ description = "Package set which contains all packages " + \
+ "that consume the specified library file(s)."
+
+ def __init__(self, vardbapi, files, **kargs):
+ super(LibraryFileConsumerSet, self).__init__(vardbapi, **kargs)
+ self.files = files
+
+ def load(self):
+ consumers = set()
+ for lib in self.files:
+ consumers.update(self.dbapi._linkmap.findConsumers(lib))
+
+ if not consumers:
+ return
+ self._setAtoms(self.mapPathsToAtoms(consumers))
+
+ def singleBuilder(cls, options, settings, trees):
+ files = tuple(portage.util.shlex_split(options.get("files", "")))
+ if not files:
+ raise SetConfigError(_("no files given"))
+ debug = get_boolean(options, "debug", False)
+ return LibraryFileConsumerSet(trees["vartree"].dbapi,
+ files, debug=debug)
+ singleBuilder = classmethod(singleBuilder)
+
+class PreservedLibraryConsumerSet(LibraryConsumerSet):
+ def load(self):
+ reg = self.dbapi._plib_registry
+ if reg is None:
+ # preserve-libs is entirely disabled
+ return
+ consumers = set()
+ if reg:
+ plib_dict = reg.getPreservedLibs()
+ for libs in plib_dict.values():
+ for lib in libs:
+ if self.debug:
+ print(lib)
+ for x in sorted(self.dbapi._linkmap.findConsumers(lib)):
+ print(" ", x)
+ print("-"*40)
+ consumers.update(self.dbapi._linkmap.findConsumers(lib))
+ # Don't rebuild packages just because they contain preserved
+ # libs that happen to be consumers of other preserved libs.
+ for libs in plib_dict.values():
+ consumers.difference_update(libs)
+ else:
+ return
+ if not consumers:
+ return
+ self._setAtoms(self.mapPathsToAtoms(consumers))
+
+ def singleBuilder(cls, options, settings, trees):
+ debug = get_boolean(options, "debug", False)
+ return PreservedLibraryConsumerSet(trees["vartree"].dbapi,
+ debug=debug)
+ singleBuilder = classmethod(singleBuilder)
diff --git a/portage_with_autodep/pym/portage/_sets/profiles.py b/portage_with_autodep/pym/portage/_sets/profiles.py
new file mode 100644
index 0000000..39a2968
--- /dev/null
+++ b/portage_with_autodep/pym/portage/_sets/profiles.py
@@ -0,0 +1,53 @@
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import logging
+
+from portage import os
+from portage.util import grabfile_package, stack_lists
+from portage._sets.base import PackageSet
+from portage._sets import get_boolean
+from portage.util import writemsg_level
+
+__all__ = ["PackagesSystemSet"]
+
+class PackagesSystemSet(PackageSet):
+ _operations = ["merge"]
+
+ def __init__(self, profile_paths, debug=False):
+ super(PackagesSystemSet, self).__init__()
+ self._profile_paths = profile_paths
+ self._debug = debug
+ if profile_paths:
+ description = self._profile_paths[-1]
+ if description == "/etc/portage/profile" and \
+ len(self._profile_paths) > 1:
+ description = self._profile_paths[-2]
+ else:
+ description = None
+ self.description = "System packages for profile %s" % description
+
+ def load(self):
+ debug = self._debug
+ if debug:
+ writemsg_level("\nPackagesSystemSet: profile paths: %s\n" % \
+ (self._profile_paths,), level=logging.DEBUG, noiselevel=-1)
+
+ mylist = [grabfile_package(os.path.join(x, "packages"), verify_eapi=True) for x in self._profile_paths]
+
+ if debug:
+ writemsg_level("\nPackagesSystemSet: raw packages: %s\n" % \
+ (mylist,), level=logging.DEBUG, noiselevel=-1)
+
+ mylist = stack_lists(mylist, incremental=1)
+
+ if debug:
+ writemsg_level("\nPackagesSystemSet: stacked packages: %s\n" % \
+ (mylist,), level=logging.DEBUG, noiselevel=-1)
+
+ self._setAtoms([x[1:] for x in mylist if x[0] == "*"])
+
+ def singleBuilder(self, options, settings, trees):
+ debug = get_boolean(options, "debug", False)
+ return PackagesSystemSet(settings.profiles, debug=debug)
+ singleBuilder = classmethod(singleBuilder)
diff --git a/portage_with_autodep/pym/portage/_sets/security.py b/portage_with_autodep/pym/portage/_sets/security.py
new file mode 100644
index 0000000..2d8fcf6
--- /dev/null
+++ b/portage_with_autodep/pym/portage/_sets/security.py
@@ -0,0 +1,86 @@
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import portage.glsa as glsa
+from portage._sets.base import PackageSet
+from portage.versions import catpkgsplit, pkgcmp
+from portage._sets import get_boolean
+
+__all__ = ["SecuritySet", "NewGlsaSet", "NewAffectedSet", "AffectedSet"]
+
+class SecuritySet(PackageSet):
+ _operations = ["merge"]
+ _skip_applied = False
+
+ description = "package set that includes all packages possibly affected by a GLSA"
+
+ def __init__(self, settings, vardbapi, portdbapi, least_change=True):
+ super(SecuritySet, self).__init__()
+ self._settings = settings
+ self._vardbapi = vardbapi
+ self._portdbapi = portdbapi
+ self._least_change = least_change
+
+ def getGlsaList(self, skip_applied):
+ glsaindexlist = glsa.get_glsa_list(self._settings)
+ if skip_applied:
+ applied_list = glsa.get_applied_glsas(self._settings)
+ glsaindexlist = set(glsaindexlist).difference(applied_list)
+ glsaindexlist = list(glsaindexlist)
+ glsaindexlist.sort()
+ return glsaindexlist
+
+ def load(self):
+ glsaindexlist = self.getGlsaList(self._skip_applied)
+ atomlist = []
+ for glsaid in glsaindexlist:
+ myglsa = glsa.Glsa(glsaid, self._settings, self._vardbapi, self._portdbapi)
+ #print glsaid, myglsa.isVulnerable(), myglsa.isApplied(), myglsa.getMergeList()
+ if self.useGlsa(myglsa):
+ atomlist += ["="+x for x in myglsa.getMergeList(least_change=self._least_change)]
+ self._setAtoms(self._reduce(atomlist))
+
+ def _reduce(self, atomlist):
+ mydict = {}
+ for atom in atomlist[:]:
+ cpv = self._portdbapi.xmatch("match-all", atom)[0]
+ slot = self._portdbapi.aux_get(cpv, ["SLOT"])[0]
+ cps = "/".join(catpkgsplit(cpv)[0:2]) + ":" + slot
+ if not cps in mydict:
+ mydict[cps] = (atom, cpv)
+ else:
+ other_cpv = mydict[cps][1]
+ if pkgcmp(catpkgsplit(cpv)[1:], catpkgsplit(other_cpv)[1:]) > 0:
+ atomlist.remove(mydict[cps][0])
+ mydict[cps] = (atom, cpv)
+ return atomlist
+
+ def useGlsa(self, myglsa):
+ return True
+
+ def updateAppliedList(self):
+ glsaindexlist = self.getGlsaList(True)
+ applied_list = glsa.get_applied_glsas(self._settings)
+ for glsaid in glsaindexlist:
+ myglsa = glsa.Glsa(glsaid, self._settings, self._vardbapi, self._portdbapi)
+ if not myglsa.isVulnerable() and not myglsa.nr in applied_list:
+ myglsa.inject()
+
+ def singleBuilder(cls, options, settings, trees):
+ least_change = not get_boolean(options, "use_emerge_resolver", False)
+ return cls(settings, trees["vartree"].dbapi, trees["porttree"].dbapi, least_change=least_change)
+ singleBuilder = classmethod(singleBuilder)
+
+class NewGlsaSet(SecuritySet):
+ _skip_applied = True
+ description = "Package set that includes all packages possibly affected by an unapplied GLSA"
+
+class AffectedSet(SecuritySet):
+ description = "Package set that includes all packages affected by an unapplied GLSA"
+
+ def useGlsa(self, myglsa):
+ return myglsa.isVulnerable()
+
+class NewAffectedSet(AffectedSet):
+ _skip_applied = True
+ description = "Package set that includes all packages affected by an unapplied GLSA"
diff --git a/portage_with_autodep/pym/portage/_sets/shell.py b/portage_with_autodep/pym/portage/_sets/shell.py
new file mode 100644
index 0000000..2c95845
--- /dev/null
+++ b/portage_with_autodep/pym/portage/_sets/shell.py
@@ -0,0 +1,44 @@
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import subprocess
+
+from portage import os
+from portage import _unicode_decode
+from portage._sets.base import PackageSet
+from portage._sets import SetConfigError
+
+__all__ = ["CommandOutputSet"]
+
+class CommandOutputSet(PackageSet):
+ """This class creates a PackageSet from the output of a shell command.
+ The shell command should produce one atom per line, that is:
+
+ >>> atom1
+ atom2
+ ...
+ atomN
+
+ Args:
+ name: A string that identifies the set.
+ command: A string or sequence identifying the command to run
+ (see the subprocess.Popen documentaion for the format)
+ """
+ _operations = ["merge", "unmerge"]
+
+ def __init__(self, command):
+ super(CommandOutputSet, self).__init__()
+ self._command = command
+ self.description = "Package set generated from output of '%s'" % self._command
+
+ def load(self):
+ pipe = subprocess.Popen(self._command, stdout=subprocess.PIPE, shell=True)
+ stdout, stderr = pipe.communicate()
+ if pipe.wait() == os.EX_OK:
+ self._setAtoms(_unicode_decode(stdout).splitlines())
+
+ def singleBuilder(self, options, settings, trees):
+ if not "command" in options:
+ raise SetConfigError("no command specified")
+ return CommandOutputSet(options["command"])
+ singleBuilder = classmethod(singleBuilder)
diff --git a/portage_with_autodep/pym/portage/cache/__init__.py b/portage_with_autodep/pym/portage/cache/__init__.py
new file mode 100644
index 0000000..e7fe599
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cache/__init__.py
@@ -0,0 +1,4 @@
+# Copyright: 2005 Gentoo Foundation
+# Author(s): Brian Harring (ferringb@gentoo.org)
+# License: GPL2
+
diff --git a/portage_with_autodep/pym/portage/cache/anydbm.py b/portage_with_autodep/pym/portage/cache/anydbm.py
new file mode 100644
index 0000000..1d56b14
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cache/anydbm.py
@@ -0,0 +1,113 @@
+# Copyright 2005-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# Author(s): Brian Harring (ferringb@gentoo.org)
+
+from __future__ import absolute_import
+
+try:
+ import anydbm as anydbm_module
+except ImportError:
+ # python 3.x
+ import dbm as anydbm_module
+
+try:
+ import dbm.gnu as gdbm
+except ImportError:
+ try:
+ import gdbm
+ except ImportError:
+ gdbm = None
+
+try:
+ from dbm import whichdb
+except ImportError:
+ from whichdb import whichdb
+
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+from portage import _unicode_encode
+from portage import os
+import sys
+from portage.cache import fs_template
+from portage.cache import cache_errors
+
+
+class database(fs_template.FsBased):
+
+ autocommits = True
+ cleanse_keys = True
+ serialize_eclasses = False
+
+ def __init__(self, *args, **config):
+ super(database,self).__init__(*args, **config)
+
+ default_db = config.get("dbtype","anydbm")
+ if not default_db.startswith("."):
+ default_db = '.' + default_db
+
+ self._db_path = os.path.join(self.location, fs_template.gen_label(self.location, self.label)+default_db)
+ self.__db = None
+ mode = "w"
+ if whichdb(self._db_path) in ("dbm.gnu", "gdbm"):
+ # Allow multiple concurrent writers (see bug #53607).
+ mode += "u"
+ try:
+ # dbm.open() will not work with bytes in python-3.1:
+ # TypeError: can't concat bytes to str
+ self.__db = anydbm_module.open(self._db_path,
+ mode, self._perms)
+ except anydbm_module.error:
+ # XXX handle this at some point
+ try:
+ self._ensure_dirs()
+ self._ensure_dirs(self._db_path)
+ except (OSError, IOError) as e:
+ raise cache_errors.InitializationError(self.__class__, e)
+
+ # try again if failed
+ try:
+ if self.__db == None:
+ # dbm.open() will not work with bytes in python-3.1:
+ # TypeError: can't concat bytes to str
+ if gdbm is None:
+ self.__db = anydbm_module.open(self._db_path,
+ "c", self._perms)
+ else:
+ # Prefer gdbm type if available, since it allows
+ # multiple concurrent writers (see bug #53607).
+ self.__db = gdbm.open(self._db_path,
+ "cu", self._perms)
+ except anydbm_module.error as e:
+ raise cache_errors.InitializationError(self.__class__, e)
+ self._ensure_access(self._db_path)
+
+ def iteritems(self):
+ # dbm doesn't implement items()
+ for k in self.__db.keys():
+ yield (k, self[k])
+
+ def _getitem(self, cpv):
+ # we override getitem because it's just a cpickling of the data handed in.
+ return pickle.loads(self.__db[_unicode_encode(cpv)])
+
+ def _setitem(self, cpv, values):
+ self.__db[_unicode_encode(cpv)] = pickle.dumps(values,pickle.HIGHEST_PROTOCOL)
+
+ def _delitem(self, cpv):
+ del self.__db[cpv]
+
+ def __iter__(self):
+ return iter(list(self.__db.keys()))
+
+ def __contains__(self, cpv):
+ return cpv in self.__db
+
+ def __del__(self):
+ if "__db" in self.__dict__ and self.__db != None:
+ self.__db.sync()
+ self.__db.close()
+
+ if sys.hexversion >= 0x3000000:
+ items = iteritems
diff --git a/portage_with_autodep/pym/portage/cache/cache_errors.py b/portage_with_autodep/pym/portage/cache/cache_errors.py
new file mode 100644
index 0000000..3c1f239
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cache/cache_errors.py
@@ -0,0 +1,62 @@
+# Copyright: 2005 Gentoo Foundation
+# Author(s): Brian Harring (ferringb@gentoo.org)
+# License: GPL2
+
+class CacheError(Exception): pass
+
+class InitializationError(CacheError):
+ def __init__(self, class_name, error):
+ self.error, self.class_name = error, class_name
+ def __str__(self):
+ return "Creation of instance %s failed due to %s" % \
+ (self.class_name, str(self.error))
+
+
+class CacheCorruption(CacheError):
+ def __init__(self, key, ex):
+ self.key, self.ex = key, ex
+ def __str__(self):
+ return "%s is corrupt: %s" % (self.key, str(self.ex))
+
+
+class GeneralCacheCorruption(CacheError):
+ def __init__(self,ex): self.ex = ex
+ def __str__(self): return "corruption detected: %s" % str(self.ex)
+
+
+class InvalidRestriction(CacheError):
+ def __init__(self, key, restriction, exception=None):
+ if exception == None: exception = ''
+ self.key, self.restriction, self.ex = key, restriction, ex
+ def __str__(self):
+ return "%s:%s is not valid: %s" % \
+ (self.key, self.restriction, str(self.ex))
+
+
+class ReadOnlyRestriction(CacheError):
+ def __init__(self, info=''):
+ self.info = info
+ def __str__(self):
+ return "cache is non-modifiable"+str(self.info)
+
+class StatCollision(CacheError):
+ """
+ If the content of a cache entry changes and neither the file mtime nor
+ size changes, it will prevent rsync from detecting changes. Cache backends
+ may raise this exception from _setitem() if they detect this type of stat
+ collision. See bug #139134.
+ """
+ def __init__(self, key, filename, mtime, size):
+ self.key = key
+ self.filename = filename
+ self.mtime = mtime
+ self.size = size
+
+ def __str__(self):
+ return "%s has stat collision with size %s and mtime %s" % \
+ (self.key, self.size, self.mtime)
+
+ def __repr__(self):
+ return "portage.cache.cache_errors.StatCollision(%s)" % \
+ (', '.join((repr(self.key), repr(self.filename),
+ repr(self.mtime), repr(self.size))),)
diff --git a/portage_with_autodep/pym/portage/cache/ebuild_xattr.py b/portage_with_autodep/pym/portage/cache/ebuild_xattr.py
new file mode 100644
index 0000000..6b388fa
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cache/ebuild_xattr.py
@@ -0,0 +1,171 @@
+# Copyright: 2009-2011 Gentoo Foundation
+# Author(s): Petteri R&#228;ty (betelgeuse@gentoo.org)
+# License: GPL2
+
+__all__ = ['database']
+
+import errno
+
+import portage
+from portage.cache import fs_template
+from portage.versions import catsplit
+from portage import cpv_getkey
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'xattr')
+
+class NoValueException(Exception):
+ pass
+
+class database(fs_template.FsBased):
+
+ autocommits = True
+
+ def __init__(self, *args, **config):
+ super(database,self).__init__(*args, **config)
+ self.portdir = self.label
+ self.ns = xattr.NS_USER + '.gentoo.cache'
+ self.keys = set(self._known_keys)
+ self.keys.add('_mtime_')
+ self.keys.add('_eclasses_')
+ # xattrs have an upper length
+ self.max_len = self.__get_max()
+
+ def __get_max(self):
+ path = os.path.join(self.portdir,'profiles/repo_name')
+ try:
+ return int(self.__get(path,'value_max_len'))
+ except NoValueException as e:
+ max = self.__calc_max(path)
+ self.__set(path,'value_max_len',str(max))
+ return max
+
+ def __calc_max(self,path):
+ """ Find out max attribute length supported by the file system """
+
+ hundred = ''
+ for i in range(100):
+ hundred+='a'
+
+ s=hundred
+
+ # Could use finally but needs python 2.5 then
+ try:
+ while True:
+ self.__set(path,'test_max',s)
+ s+=hundred
+ except IOError as e:
+ # ext based give wrong errno
+ # http://bugzilla.kernel.org/show_bug.cgi?id=12793
+ if e.errno in (errno.E2BIG, errno.ENOSPC):
+ result = len(s)-100
+ else:
+ raise
+
+ try:
+ self.__remove(path,'test_max')
+ except IOError as e:
+ if e.errno != errno.ENODATA:
+ raise
+
+ return result
+
+ def __get_path(self,cpv):
+ cat,pn = catsplit(cpv_getkey(cpv))
+ return os.path.join(self.portdir,cat,pn,os.path.basename(cpv) + ".ebuild")
+
+ def __has_cache(self,path):
+ try:
+ self.__get(path,'_mtime_')
+ except NoValueException as e:
+ return False
+
+ return True
+
+ def __get(self,path,key,default=None):
+ try:
+ return xattr.get(path,key,namespace=self.ns)
+ except IOError as e:
+ if not default is None and errno.ENODATA == e.errno:
+ return default
+ else:
+ raise NoValueException()
+
+ def __remove(self,path,key):
+ xattr.remove(path,key,namespace=self.ns)
+
+ def __set(self,path,key,value):
+ xattr.set(path,key,value,namespace=self.ns)
+
+ def _getitem(self, cpv):
+ values = {}
+ path = self.__get_path(cpv)
+ all = {}
+ for tuple in xattr.get_all(path,namespace=self.ns):
+ key,value = tuple
+ all[key] = value
+
+ if not '_mtime_' in all:
+ raise KeyError(cpv)
+
+ # We default to '' like other caches
+ for key in self.keys:
+ attr_value = all.get(key,'1:')
+ parts,sep,value = attr_value.partition(':')
+ parts = int(parts)
+ if parts > 1:
+ for i in range(1,parts):
+ value += all.get(key+str(i))
+ values[key] = value
+
+ return values
+
+ def _setitem(self, cpv, values):
+ path = self.__get_path(cpv)
+ max = self.max_len
+ for key,value in values.items():
+ # mtime comes in as long so need to convert to strings
+ s = str(value)
+ # We need to split long values
+ value_len = len(s)
+ parts = 0
+ if value_len > max:
+ # Find out how many parts we need
+ parts = value_len/max
+ if value_len % max > 0:
+ parts += 1
+
+ # Only the first entry carries the number of parts
+ self.__set(path,key,'%s:%s'%(parts,s[0:max]))
+
+ # Write out the rest
+ for i in range(1,parts):
+ start = i * max
+ val = s[start:start+max]
+ self.__set(path,key+str(i),val)
+ else:
+ self.__set(path,key,"%s:%s"%(1,s))
+
+ def _delitem(self, cpv):
+ pass # Will be gone with the ebuild
+
+ def __contains__(self, cpv):
+ return os.path.exists(self.__get_path(cpv))
+
+ def __iter__(self):
+
+ for root, dirs, files in os.walk(self.portdir):
+ for file in files:
+ try:
+ file = _unicode_decode(file,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ continue
+ if file[-7:] == '.ebuild':
+ cat = os.path.basename(os.path.dirname(root))
+ pn_pv = file[:-7]
+ path = os.path.join(root,file)
+ if self.__has_cache(path):
+ yield "%s/%s/%s" % (cat,os.path.basename(root),file[:-7])
diff --git a/portage_with_autodep/pym/portage/cache/flat_hash.py b/portage_with_autodep/pym/portage/cache/flat_hash.py
new file mode 100644
index 0000000..b6bc074
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cache/flat_hash.py
@@ -0,0 +1,155 @@
+# Copyright: 2005-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# Author(s): Brian Harring (ferringb@gentoo.org)
+
+from portage.cache import fs_template
+from portage.cache import cache_errors
+import errno
+import io
+import stat
+import sys
+import os as _os
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+
+if sys.hexversion >= 0x3000000:
+ long = int
+
+# Coerce to unicode, in order to prevent TypeError when writing
+# raw bytes to TextIOWrapper with python2.
+_setitem_fmt = _unicode_decode("%s=%s\n")
+
+class database(fs_template.FsBased):
+
+ autocommits = True
+
+ def __init__(self, *args, **config):
+ super(database,self).__init__(*args, **config)
+ self.location = os.path.join(self.location,
+ self.label.lstrip(os.path.sep).rstrip(os.path.sep))
+ write_keys = set(self._known_keys)
+ write_keys.add("_eclasses_")
+ write_keys.add("_mtime_")
+ self._write_keys = sorted(write_keys)
+ if not self.readonly and not os.path.exists(self.location):
+ self._ensure_dirs()
+
+ def _getitem(self, cpv):
+ # Don't use os.path.join, for better performance.
+ fp = self.location + _os.sep + cpv
+ try:
+ myf = io.open(_unicode_encode(fp,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'],
+ errors='replace')
+ try:
+ lines = myf.read().split("\n")
+ if not lines[-1]:
+ lines.pop()
+ d = self._parse_data(lines, cpv)
+ if '_mtime_' not in d:
+ # Backward compatibility with old cache
+ # that uses mtime mangling.
+ d['_mtime_'] = _os.fstat(myf.fileno())[stat.ST_MTIME]
+ return d
+ finally:
+ myf.close()
+ except (IOError, OSError) as e:
+ if e.errno != errno.ENOENT:
+ raise cache_errors.CacheCorruption(cpv, e)
+ raise KeyError(cpv, e)
+
+ def _parse_data(self, data, cpv):
+ try:
+ return dict( x.split("=", 1) for x in data )
+ except ValueError as e:
+ # If a line is missing an "=", the split length is 1 instead of 2.
+ raise cache_errors.CacheCorruption(cpv, e)
+
+ def _setitem(self, cpv, values):
+# import pdb;pdb.set_trace()
+ s = cpv.rfind("/")
+ fp = os.path.join(self.location,cpv[:s],".update.%i.%s" % (os.getpid(), cpv[s+1:]))
+ try:
+ myf = io.open(_unicode_encode(fp,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='w', encoding=_encodings['repo.content'],
+ errors='backslashreplace')
+ except (IOError, OSError) as e:
+ if errno.ENOENT == e.errno:
+ try:
+ self._ensure_dirs(cpv)
+ myf = io.open(_unicode_encode(fp,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='w', encoding=_encodings['repo.content'],
+ errors='backslashreplace')
+ except (OSError, IOError) as e:
+ raise cache_errors.CacheCorruption(cpv, e)
+ else:
+ raise cache_errors.CacheCorruption(cpv, e)
+
+ try:
+ for k in self._write_keys:
+ v = values.get(k)
+ if not v:
+ continue
+ myf.write(_setitem_fmt % (k, v))
+ finally:
+ myf.close()
+ self._ensure_access(fp)
+
+ #update written. now we move it.
+
+ new_fp = os.path.join(self.location,cpv)
+ try:
+ os.rename(fp, new_fp)
+ except (OSError, IOError) as e:
+ os.remove(fp)
+ raise cache_errors.CacheCorruption(cpv, e)
+
+ def _delitem(self, cpv):
+# import pdb;pdb.set_trace()
+ try:
+ os.remove(os.path.join(self.location,cpv))
+ except OSError as e:
+ if errno.ENOENT == e.errno:
+ raise KeyError(cpv)
+ else:
+ raise cache_errors.CacheCorruption(cpv, e)
+
+ def __contains__(self, cpv):
+ return os.path.exists(os.path.join(self.location, cpv))
+
+ def __iter__(self):
+ """generator for walking the dir struct"""
+ dirs = [(0, self.location)]
+ len_base = len(self.location)
+ while dirs:
+ depth, dir_path = dirs.pop()
+ try:
+ dir_list = os.listdir(dir_path)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ continue
+ for l in dir_list:
+ if l.endswith(".cpickle"):
+ continue
+ p = os.path.join(dir_path, l)
+ try:
+ st = os.lstat(p)
+ except OSError:
+ # Cache entry disappeared.
+ continue
+ if stat.S_ISDIR(st.st_mode):
+ # Only recurse 1 deep, in order to avoid iteration over
+ # entries from another nested cache instance. This can
+ # happen if the user nests an overlay inside
+ # /usr/portage/local as in bug #302764.
+ if depth < 1:
+ dirs.append((depth+1, p))
+ continue
+ yield p[len_base+1:]
diff --git a/portage_with_autodep/pym/portage/cache/flat_list.py b/portage_with_autodep/pym/portage/cache/flat_list.py
new file mode 100644
index 0000000..7288307
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cache/flat_list.py
@@ -0,0 +1,134 @@
+# Copyright 2005-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.cache import fs_template
+from portage.cache import cache_errors
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+import errno
+import io
+import stat
+import sys
+
+if sys.hexversion >= 0x3000000:
+ long = int
+
+# Coerce to unicode, in order to prevent TypeError when writing
+# raw bytes to TextIOWrapper with python2.
+_setitem_fmt = _unicode_decode("%s\n")
+
+# store the current key order *here*.
+class database(fs_template.FsBased):
+
+ autocommits = True
+
+ # do not screw with this ordering. _eclasses_ needs to be last
+ auxdbkey_order=('DEPEND', 'RDEPEND', 'SLOT', 'SRC_URI',
+ 'RESTRICT', 'HOMEPAGE', 'LICENSE', 'DESCRIPTION',
+ 'KEYWORDS', 'IUSE', 'REQUIRED_USE',
+ 'PDEPEND', 'PROVIDE', 'EAPI', 'PROPERTIES', 'DEFINED_PHASES')
+
+ def __init__(self, *args, **config):
+ super(database,self).__init__(*args, **config)
+ self.location = os.path.join(self.location,
+ self.label.lstrip(os.path.sep).rstrip(os.path.sep))
+
+ if len(self._known_keys) > len(self.auxdbkey_order) + 2:
+ raise Exception("less ordered keys then auxdbkeys")
+ if not os.path.exists(self.location):
+ self._ensure_dirs()
+
+
+ def _getitem(self, cpv):
+ d = {}
+ try:
+ myf = io.open(_unicode_encode(os.path.join(self.location, cpv),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'],
+ errors='replace')
+ for k,v in zip(self.auxdbkey_order, myf):
+ d[k] = v.rstrip("\n")
+ except (OSError, IOError) as e:
+ if errno.ENOENT == e.errno:
+ raise KeyError(cpv)
+ raise cache_errors.CacheCorruption(cpv, e)
+
+ try:
+ d["_mtime_"] = os.fstat(myf.fileno())[stat.ST_MTIME]
+ except OSError as e:
+ myf.close()
+ raise cache_errors.CacheCorruption(cpv, e)
+ myf.close()
+ return d
+
+
+ def _setitem(self, cpv, values):
+ s = cpv.rfind("/")
+ fp=os.path.join(self.location,cpv[:s],".update.%i.%s" % (os.getpid(), cpv[s+1:]))
+ try:
+ myf = io.open(_unicode_encode(fp,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='w', encoding=_encodings['repo.content'],
+ errors='backslashreplace')
+ except (OSError, IOError) as e:
+ if errno.ENOENT == e.errno:
+ try:
+ self._ensure_dirs(cpv)
+ myf = io.open(_unicode_encode(fp,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='w', encoding=_encodings['repo.content'],
+ errors='backslashreplace')
+ except (OSError, IOError) as e:
+ raise cache_errors.CacheCorruption(cpv, e)
+ else:
+ raise cache_errors.CacheCorruption(cpv, e)
+
+
+ for x in self.auxdbkey_order:
+ myf.write(_setitem_fmt % (values.get(x, ""),))
+
+ myf.close()
+ self._ensure_access(fp, mtime=values["_mtime_"])
+ #update written. now we move it.
+ new_fp = os.path.join(self.location,cpv)
+ try:
+ os.rename(fp, new_fp)
+ except (OSError, IOError) as e:
+ os.remove(fp)
+ raise cache_errors.CacheCorruption(cpv, e)
+
+
+ def _delitem(self, cpv):
+ try:
+ os.remove(os.path.join(self.location,cpv))
+ except OSError as e:
+ if errno.ENOENT == e.errno:
+ raise KeyError(cpv)
+ else:
+ raise cache_errors.CacheCorruption(cpv, e)
+
+
+ def __contains__(self, cpv):
+ return os.path.exists(os.path.join(self.location, cpv))
+
+
+ def __iter__(self):
+ """generator for walking the dir struct"""
+ dirs = [self.location]
+ len_base = len(self.location)
+ while len(dirs):
+ for l in os.listdir(dirs[0]):
+ if l.endswith(".cpickle"):
+ continue
+ p = os.path.join(dirs[0],l)
+ st = os.lstat(p)
+ if stat.S_ISDIR(st.st_mode):
+ dirs.append(p)
+ continue
+ yield p[len_base+1:]
+ dirs.pop(0)
+
+
+ def commit(self): pass
diff --git a/portage_with_autodep/pym/portage/cache/fs_template.py b/portage_with_autodep/pym/portage/cache/fs_template.py
new file mode 100644
index 0000000..a82e862
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cache/fs_template.py
@@ -0,0 +1,90 @@
+# Copyright: 2005 Gentoo Foundation
+# Author(s): Brian Harring (ferringb@gentoo.org)
+# License: GPL2
+
+import sys
+from portage.cache import template
+from portage import os
+
+from portage.proxy.lazyimport import lazyimport
+lazyimport(globals(),
+ 'portage.data:portage_gid',
+ 'portage.exception:PortageException',
+ 'portage.util:apply_permissions',
+)
+del lazyimport
+
+if sys.hexversion >= 0x3000000:
+ long = int
+
+class FsBased(template.database):
+ """template wrapping fs needed options, and providing _ensure_access as a way to
+ attempt to ensure files have the specified owners/perms"""
+
+ def __init__(self, *args, **config):
+ """throws InitializationError if needs args aren't specified
+ gid and perms aren't listed do to an oddity python currying mechanism
+ gid=portage_gid
+ perms=0665"""
+
+ for x, y in (("gid", -1), ("perms", -1)):
+ if x in config:
+ setattr(self, "_"+x, config[x])
+ del config[x]
+ else:
+ setattr(self, "_"+x, y)
+ super(FsBased, self).__init__(*args, **config)
+
+ if self.label.startswith(os.path.sep):
+ # normpath.
+ self.label = os.path.sep + os.path.normpath(self.label).lstrip(os.path.sep)
+
+
+ def _ensure_access(self, path, mtime=-1):
+ """returns true or false if it's able to ensure that path is properly chmod'd and chowned.
+ if mtime is specified, attempts to ensure that's correct also"""
+ try:
+ apply_permissions(path, gid=self._gid, mode=self._perms)
+ if mtime != -1:
+ mtime=long(mtime)
+ os.utime(path, (mtime, mtime))
+ except (PortageException, EnvironmentError):
+ return False
+ return True
+
+ def _ensure_dirs(self, path=None):
+ """with path!=None, ensure beyond self.location. otherwise, ensure self.location"""
+ if path:
+ path = os.path.dirname(path)
+ base = self.location
+ else:
+ path = self.location
+ base='/'
+
+ for dir in path.lstrip(os.path.sep).rstrip(os.path.sep).split(os.path.sep):
+ base = os.path.join(base,dir)
+ if not os.path.exists(base):
+ if self._perms != -1:
+ um = os.umask(0)
+ try:
+ perms = self._perms
+ if perms == -1:
+ perms = 0
+ perms |= 0o755
+ os.mkdir(base, perms)
+ if self._gid != -1:
+ os.chown(base, -1, self._gid)
+ finally:
+ if self._perms != -1:
+ os.umask(um)
+
+
+def gen_label(base, label):
+ """if supplied label is a path, generate a unique label based upon label, and supplied base path"""
+ if label.find(os.path.sep) == -1:
+ return label
+ label = label.strip("\"").strip("'")
+ label = os.path.join(*(label.rstrip(os.path.sep).split(os.path.sep)))
+ tail = os.path.split(label)[1]
+ return "%s-%X" % (tail, abs(label.__hash__()))
+
diff --git a/portage_with_autodep/pym/portage/cache/mappings.py b/portage_with_autodep/pym/portage/cache/mappings.py
new file mode 100644
index 0000000..60a918e
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cache/mappings.py
@@ -0,0 +1,485 @@
+# Copyright: 2005-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# Author(s): Brian Harring (ferringb@gentoo.org)
+
+__all__ = ["Mapping", "MutableMapping", "UserDict", "ProtectedDict",
+ "LazyLoad", "slot_dict_class"]
+
+import sys
+import weakref
+
+class Mapping(object):
+ """
+ In python-3.0, the UserDict.DictMixin class has been replaced by
+ Mapping and MutableMapping from the collections module, but 2to3
+ doesn't currently account for this change:
+
+ http://bugs.python.org/issue2876
+
+ As a workaround for the above issue, use this class as a substitute
+ for UserDict.DictMixin so that code converted via 2to3 will run.
+ """
+
+ __slots__ = ()
+
+ def __iter__(self):
+ return iter(self.keys())
+
+ def keys(self):
+ return list(self.__iter__())
+
+ def __contains__(self, key):
+ try:
+ value = self[key]
+ except KeyError:
+ return False
+ return True
+
+ def iteritems(self):
+ for k in self:
+ yield (k, self[k])
+
+ def iterkeys(self):
+ return self.__iter__()
+
+ def itervalues(self):
+ for _, v in self.items():
+ yield v
+
+ def values(self):
+ return [v for _, v in self.iteritems()]
+
+ def items(self):
+ return list(self.iteritems())
+
+ def get(self, key, default=None):
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
+ def __repr__(self):
+ return repr(dict(self.items()))
+
+ def __len__(self):
+ return len(list(self))
+
+ if sys.hexversion >= 0x3000000:
+ items = iteritems
+ keys = __iter__
+ values = itervalues
+
+class MutableMapping(Mapping):
+ """
+ A mutable vesion of the Mapping class.
+ """
+
+ __slots__ = ()
+
+ def clear(self):
+ for key in list(self):
+ del self[key]
+
+ def setdefault(self, key, default=None):
+ try:
+ return self[key]
+ except KeyError:
+ self[key] = default
+ return default
+
+ def pop(self, key, *args):
+ if len(args) > 1:
+ raise TypeError("pop expected at most 2 arguments, got " + \
+ repr(1 + len(args)))
+ try:
+ value = self[key]
+ except KeyError:
+ if args:
+ return args[0]
+ raise
+ del self[key]
+ return value
+
+ def popitem(self):
+ try:
+ k, v = next(iter(self.items()))
+ except StopIteration:
+ raise KeyError('container is empty')
+ del self[k]
+ return (k, v)
+
+ def update(self, *args, **kwargs):
+ if len(args) > 1:
+ raise TypeError(
+ "expected at most 1 positional argument, got " + \
+ repr(len(args)))
+ other = None
+ if args:
+ other = args[0]
+ if other is None:
+ pass
+ elif hasattr(other, 'iteritems'):
+ # Use getattr to avoid interference from 2to3.
+ for k, v in getattr(other, 'iteritems')():
+ self[k] = v
+ elif hasattr(other, 'items'):
+ # Use getattr to avoid interference from 2to3.
+ for k, v in getattr(other, 'items')():
+ self[k] = v
+ elif hasattr(other, 'keys'):
+ for k in other.keys():
+ self[k] = other[k]
+ else:
+ for k, v in other:
+ self[k] = v
+ if kwargs:
+ self.update(kwargs)
+
+class UserDict(MutableMapping):
+ """
+ Use this class as a substitute for UserDict.UserDict so that
+ code converted via 2to3 will run:
+
+ http://bugs.python.org/issue2876
+ """
+
+ __slots__ = ('data',)
+
+ def __init__(self, *args, **kwargs):
+
+ self.data = {}
+
+ if len(args) > 1:
+ raise TypeError(
+ "expected at most 1 positional argument, got " + \
+ repr(len(args)))
+
+ if args:
+ self.update(args[0])
+
+ if kwargs:
+ self.update(kwargs)
+
+ def __repr__(self):
+ return repr(self.data)
+
+ def __contains__(self, key):
+ return key in self.data
+
+ def __iter__(self):
+ return iter(self.data)
+
+ def __len__(self):
+ return len(self.data)
+
+ def __getitem__(self, key):
+ return self.data[key]
+
+ def __setitem__(self, key, item):
+ self.data[key] = item
+
+ def __delitem__(self, key):
+ del self.data[key]
+
+ def clear(self):
+ self.data.clear()
+
+ if sys.hexversion >= 0x3000000:
+ keys = __iter__
+
+class OrderedDict(UserDict):
+
+ __slots__ = ('_order',)
+
+ def __init__(self, *args, **kwargs):
+ self._order = []
+ UserDict.__init__(self, *args, **kwargs)
+
+ def __iter__(self):
+ return iter(self._order)
+
+ def __setitem__(self, key, item):
+ if key in self:
+ self._order.remove(key)
+ UserDict.__setitem__(self, key, item)
+ self._order.append(key)
+
+ def __delitem__(self, key):
+ UserDict.__delitem__(self, key)
+ self._order.remove(key)
+
+ def clear(self):
+ UserDict.clear(self)
+ del self._order[:]
+
+ if sys.hexversion >= 0x3000000:
+ keys = __iter__
+
+class ProtectedDict(MutableMapping):
+ """
+ given an initial dict, this wraps that dict storing changes in a secondary dict, protecting
+ the underlying dict from changes
+ """
+ __slots__=("orig","new","blacklist")
+
+ def __init__(self, orig):
+ self.orig = orig
+ self.new = {}
+ self.blacklist = {}
+
+
+ def __setitem__(self, key, val):
+ self.new[key] = val
+ if key in self.blacklist:
+ del self.blacklist[key]
+
+
+ def __getitem__(self, key):
+ if key in self.new:
+ return self.new[key]
+ if key in self.blacklist:
+ raise KeyError(key)
+ return self.orig[key]
+
+
+ def __delitem__(self, key):
+ if key in self.new:
+ del self.new[key]
+ elif key in self.orig:
+ if key not in self.blacklist:
+ self.blacklist[key] = True
+ return
+ raise KeyError(key)
+
+
+ def __iter__(self):
+ for k in self.new:
+ yield k
+ for k in self.orig:
+ if k not in self.blacklist and k not in self.new:
+ yield k
+
+ def __contains__(self, key):
+ return key in self.new or (key not in self.blacklist and key in self.orig)
+
+ if sys.hexversion >= 0x3000000:
+ keys = __iter__
+
+class LazyLoad(Mapping):
+ """
+ Lazy loading of values for a dict
+ """
+ __slots__=("pull", "d")
+
+ def __init__(self, pull_items_func, initial_items=[]):
+ self.d = {}
+ for k, v in initial_items:
+ self.d[k] = v
+ self.pull = pull_items_func
+
+ def __getitem__(self, key):
+ if key in self.d:
+ return self.d[key]
+ elif self.pull != None:
+ self.d.update(self.pull())
+ self.pull = None
+ return self.d[key]
+
+ def __iter__(self):
+ if self.pull is not None:
+ self.d.update(self.pull())
+ self.pull = None
+ return iter(self.d)
+
+ def __contains__(self, key):
+ if key in self.d:
+ return True
+ elif self.pull != None:
+ self.d.update(self.pull())
+ self.pull = None
+ return key in self.d
+
+ if sys.hexversion >= 0x3000000:
+ keys = __iter__
+
+_slot_dict_classes = weakref.WeakValueDictionary()
+
+def slot_dict_class(keys, prefix="_val_"):
+ """
+ Generates mapping classes that behave similar to a dict but store values
+ as object attributes that are allocated via __slots__. Instances of these
+ objects have a smaller memory footprint than a normal dict object.
+
+ @param keys: Fixed set of allowed keys
+ @type keys: Iterable
+ @param prefix: a prefix to use when mapping
+ attribute names from keys
+ @type prefix: String
+ @rtype: SlotDict
+ @returns: A class that constructs SlotDict instances
+ having the specified keys.
+ """
+ if isinstance(keys, frozenset):
+ keys_set = keys
+ else:
+ keys_set = frozenset(keys)
+ v = _slot_dict_classes.get((keys_set, prefix))
+ if v is None:
+
+ class SlotDict(object):
+
+ allowed_keys = keys_set
+ _prefix = prefix
+ __slots__ = ("__weakref__",) + \
+ tuple(prefix + k for k in allowed_keys)
+
+ def __init__(self, *args, **kwargs):
+
+ if len(args) > 1:
+ raise TypeError(
+ "expected at most 1 positional argument, got " + \
+ repr(len(args)))
+
+ if args:
+ self.update(args[0])
+
+ if kwargs:
+ self.update(kwargs)
+
+ def __iter__(self):
+ for k, v in self.iteritems():
+ yield k
+
+ def __len__(self):
+ l = 0
+ for i in self.iteritems():
+ l += 1
+ return l
+
+ def keys(self):
+ return list(self)
+
+ def iteritems(self):
+ prefix = self._prefix
+ for k in self.allowed_keys:
+ try:
+ yield (k, getattr(self, prefix + k))
+ except AttributeError:
+ pass
+
+ def items(self):
+ return list(self.iteritems())
+
+ def itervalues(self):
+ for k, v in self.iteritems():
+ yield v
+
+ def values(self):
+ return list(self.itervalues())
+
+ def __delitem__(self, k):
+ try:
+ delattr(self, self._prefix + k)
+ except AttributeError:
+ raise KeyError(k)
+
+ def __setitem__(self, k, v):
+ setattr(self, self._prefix + k, v)
+
+ def setdefault(self, key, default=None):
+ try:
+ return self[key]
+ except KeyError:
+ self[key] = default
+ return default
+
+ def update(self, *args, **kwargs):
+ if len(args) > 1:
+ raise TypeError(
+ "expected at most 1 positional argument, got " + \
+ repr(len(args)))
+ other = None
+ if args:
+ other = args[0]
+ if other is None:
+ pass
+ elif hasattr(other, 'iteritems'):
+ # Use getattr to avoid interference from 2to3.
+ for k, v in getattr(other, 'iteritems')():
+ self[k] = v
+ elif hasattr(other, 'items'):
+ # Use getattr to avoid interference from 2to3.
+ for k, v in getattr(other, 'items')():
+ self[k] = v
+ elif hasattr(other, 'keys'):
+ for k in other.keys():
+ self[k] = other[k]
+ else:
+ for k, v in other:
+ self[k] = v
+ if kwargs:
+ self.update(kwargs)
+
+ def __getitem__(self, k):
+ try:
+ return getattr(self, self._prefix + k)
+ except AttributeError:
+ raise KeyError(k)
+
+ def get(self, key, default=None):
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
+ def __contains__(self, k):
+ return hasattr(self, self._prefix + k)
+
+ def pop(self, key, *args):
+ if len(args) > 1:
+ raise TypeError(
+ "pop expected at most 2 arguments, got " + \
+ repr(1 + len(args)))
+ try:
+ value = self[key]
+ except KeyError:
+ if args:
+ return args[0]
+ raise
+ del self[key]
+ return value
+
+ def popitem(self):
+ try:
+ k, v = self.iteritems().next()
+ except StopIteration:
+ raise KeyError('container is empty')
+ del self[k]
+ return (k, v)
+
+ def copy(self):
+ c = self.__class__()
+ c.update(self)
+ return c
+
+ def clear(self):
+ for k in self.allowed_keys:
+ try:
+ delattr(self, self._prefix + k)
+ except AttributeError:
+ pass
+
+ def __str__(self):
+ return str(dict(self.iteritems()))
+
+ def __repr__(self):
+ return repr(dict(self.iteritems()))
+
+ if sys.hexversion >= 0x3000000:
+ items = iteritems
+ keys = __iter__
+ values = itervalues
+
+ v = SlotDict
+ _slot_dict_classes[v.allowed_keys] = v
+ return v
diff --git a/portage_with_autodep/pym/portage/cache/metadata.py b/portage_with_autodep/pym/portage/cache/metadata.py
new file mode 100644
index 0000000..4c735d7
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cache/metadata.py
@@ -0,0 +1,154 @@
+# Copyright: 2005 Gentoo Foundation
+# Author(s): Brian Harring (ferringb@gentoo.org)
+# License: GPL2
+
+import errno
+import re
+import stat
+import sys
+from portage import os
+from portage import _encodings
+from portage import _unicode_encode
+from portage.cache import cache_errors, flat_hash
+import portage.eclass_cache
+from portage.cache.template import reconstruct_eclasses
+from portage.cache.mappings import ProtectedDict
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+ long = int
+
+# this is the old cache format, flat_list. count maintained here.
+magic_line_count = 22
+
+# store the current key order *here*.
+class database(flat_hash.database):
+ complete_eclass_entries = False
+ auxdbkey_order=('DEPEND', 'RDEPEND', 'SLOT', 'SRC_URI',
+ 'RESTRICT', 'HOMEPAGE', 'LICENSE', 'DESCRIPTION',
+ 'KEYWORDS', 'INHERITED', 'IUSE', 'REQUIRED_USE',
+ 'PDEPEND', 'PROVIDE', 'EAPI', 'PROPERTIES', 'DEFINED_PHASES')
+
+ autocommits = True
+ serialize_eclasses = False
+
+ _hashed_re = re.compile('^(\\w+)=([^\n]*)')
+
+ def __init__(self, location, *args, **config):
+ loc = location
+ super(database, self).__init__(location, *args, **config)
+ self.location = os.path.join(loc, "metadata","cache")
+ self.ec = None
+ self.raise_stat_collision = False
+
+ def _parse_data(self, data, cpv):
+ _hashed_re_match = self._hashed_re.match
+ d = {}
+
+ for line in data:
+ hashed = False
+ hashed_match = _hashed_re_match(line)
+ if hashed_match is None:
+ d.clear()
+ try:
+ for i, key in enumerate(self.auxdbkey_order):
+ d[key] = data[i]
+ except IndexError:
+ pass
+ break
+ else:
+ d[hashed_match.group(1)] = hashed_match.group(2)
+
+ if "_eclasses_" not in d:
+ if "INHERITED" in d:
+ if self.ec is None:
+ self.ec = portage.eclass_cache.cache(self.location[:-15])
+ try:
+ d["_eclasses_"] = self.ec.get_eclass_data(
+ d["INHERITED"].split())
+ except KeyError as e:
+ # INHERITED contains a non-existent eclass.
+ raise cache_errors.CacheCorruption(cpv, e)
+ del d["INHERITED"]
+ else:
+ d["_eclasses_"] = {}
+ elif isinstance(d["_eclasses_"], basestring):
+ # We skip this if flat_hash.database._parse_data() was called above
+ # because it calls reconstruct_eclasses() internally.
+ d["_eclasses_"] = reconstruct_eclasses(None, d["_eclasses_"])
+
+ return d
+
+ def _setitem(self, cpv, values):
+ if "_eclasses_" in values:
+ values = ProtectedDict(values)
+ values["INHERITED"] = ' '.join(sorted(values["_eclasses_"]))
+
+ new_content = []
+ for k in self.auxdbkey_order:
+ new_content.append(values.get(k, ''))
+ new_content.append('\n')
+ for i in range(magic_line_count - len(self.auxdbkey_order)):
+ new_content.append('\n')
+ new_content = ''.join(new_content)
+ new_content = _unicode_encode(new_content,
+ _encodings['repo.content'], errors='backslashreplace')
+
+ new_fp = os.path.join(self.location, cpv)
+ try:
+ f = open(_unicode_encode(new_fp,
+ encoding=_encodings['fs'], errors='strict'), 'rb')
+ except EnvironmentError:
+ pass
+ else:
+ try:
+ try:
+ existing_st = os.fstat(f.fileno())
+ existing_content = f.read()
+ finally:
+ f.close()
+ except EnvironmentError:
+ pass
+ else:
+ existing_mtime = existing_st[stat.ST_MTIME]
+ if values['_mtime_'] == existing_mtime and \
+ existing_content == new_content:
+ return
+
+ if self.raise_stat_collision and \
+ values['_mtime_'] == existing_mtime and \
+ len(new_content) == existing_st.st_size:
+ raise cache_errors.StatCollision(cpv, new_fp,
+ existing_mtime, existing_st.st_size)
+
+ s = cpv.rfind("/")
+ fp = os.path.join(self.location,cpv[:s],
+ ".update.%i.%s" % (os.getpid(), cpv[s+1:]))
+ try:
+ myf = open(_unicode_encode(fp,
+ encoding=_encodings['fs'], errors='strict'), 'wb')
+ except EnvironmentError as e:
+ if errno.ENOENT == e.errno:
+ try:
+ self._ensure_dirs(cpv)
+ myf = open(_unicode_encode(fp,
+ encoding=_encodings['fs'], errors='strict'), 'wb')
+ except EnvironmentError as e:
+ raise cache_errors.CacheCorruption(cpv, e)
+ else:
+ raise cache_errors.CacheCorruption(cpv, e)
+
+ try:
+ myf.write(new_content)
+ finally:
+ myf.close()
+ self._ensure_access(fp, mtime=values["_mtime_"])
+
+ try:
+ os.rename(fp, new_fp)
+ except EnvironmentError as e:
+ try:
+ os.unlink(fp)
+ except EnvironmentError:
+ pass
+ raise cache_errors.CacheCorruption(cpv, e)
diff --git a/portage_with_autodep/pym/portage/cache/metadata_overlay.py b/portage_with_autodep/pym/portage/cache/metadata_overlay.py
new file mode 100644
index 0000000..cfa0051
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cache/metadata_overlay.py
@@ -0,0 +1,105 @@
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.cache import template
+from portage.cache.cache_errors import CacheCorruption
+from portage.cache.flat_hash import database as db_rw
+from portage.cache.metadata import database as db_ro
+
+class database(template.database):
+
+ serialize_eclasses = False
+
+ def __init__(self, location, label, auxdbkeys, db_rw=db_rw, db_ro=db_ro,
+ *args, **config):
+ super_config = config.copy()
+ super_config.pop("gid", None)
+ super_config.pop("perms", None)
+ super(database, self).__init__(location, label, auxdbkeys,
+ *args, **super_config)
+ self.db_rw = db_rw(location, label, auxdbkeys, **config)
+ self.commit = self.db_rw.commit
+ self.autocommits = self.db_rw.autocommits
+ if isinstance(db_ro, type):
+ ro_config = config.copy()
+ ro_config["readonly"] = True
+ self.db_ro = db_ro(label, "metadata/cache", auxdbkeys, **ro_config)
+ else:
+ self.db_ro = db_ro
+
+ def __getitem__(self, cpv):
+ """funnel whiteout validation through here, since value needs to be fetched"""
+ try:
+ value = self.db_rw[cpv]
+ except KeyError:
+ return self.db_ro[cpv] # raises a KeyError when necessary
+ except CacheCorruption:
+ del self.db_rw[cpv]
+ return self.db_ro[cpv] # raises a KeyError when necessary
+ if self._is_whiteout(value):
+ if self._is_whiteout_valid(cpv, value):
+ raise KeyError(cpv)
+ else:
+ del self.db_rw[cpv]
+ return self.db_ro[cpv] # raises a KeyError when necessary
+ else:
+ return value
+
+ def _setitem(self, name, values):
+ try:
+ value_ro = self.db_ro.get(name)
+ except CacheCorruption:
+ value_ro = None
+ if value_ro is not None and \
+ self._are_values_identical(value_ro, values):
+ # we have matching values in the underlying db_ro
+ # so it is unnecessary to store data in db_rw
+ try:
+ del self.db_rw[name] # delete unwanted whiteout when necessary
+ except KeyError:
+ pass
+ return
+ self.db_rw[name] = values
+
+ def _delitem(self, cpv):
+ value = self[cpv] # validates whiteout and/or raises a KeyError when necessary
+ if cpv in self.db_ro:
+ self.db_rw[cpv] = self._create_whiteout(value)
+ else:
+ del self.db_rw[cpv]
+
+ def __contains__(self, cpv):
+ try:
+ self[cpv] # validates whiteout when necessary
+ except KeyError:
+ return False
+ return True
+
+ def __iter__(self):
+ s = set()
+ for cpv in self.db_rw:
+ if cpv in self: # validates whiteout when necessary
+ yield cpv
+ # set includes whiteouts so they won't be yielded later
+ s.add(cpv)
+ for cpv in self.db_ro:
+ if cpv not in s:
+ yield cpv
+
+ def _is_whiteout(self, value):
+ return value["EAPI"] == "whiteout"
+
+ def _create_whiteout(self, value):
+ return {"EAPI":"whiteout","_eclasses_":value["_eclasses_"],"_mtime_":value["_mtime_"]}
+
+ def _is_whiteout_valid(self, name, value_rw):
+ try:
+ value_ro = self.db_ro[name]
+ return self._are_values_identical(value_rw,value_ro)
+ except KeyError:
+ return False
+
+ def _are_values_identical(self, value1, value2):
+ if value1['_mtime_'] != value2['_mtime_']:
+ return False
+ return value1["_eclasses_"] == value2["_eclasses_"]
diff --git a/portage_with_autodep/pym/portage/cache/sql_template.py b/portage_with_autodep/pym/portage/cache/sql_template.py
new file mode 100644
index 0000000..d023b1b
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cache/sql_template.py
@@ -0,0 +1,301 @@
+# Copyright: 2005 Gentoo Foundation
+# Author(s): Brian Harring (ferringb@gentoo.org)
+# License: GPL2
+
+import sys
+from portage.cache import template, cache_errors
+from portage.cache.template import reconstruct_eclasses
+
+class SQLDatabase(template.database):
+ """template class for RDBM based caches
+
+ This class is designed such that derivatives don't have to change much code, mostly constant strings.
+ _BaseError must be an exception class that all Exceptions thrown from the derived RDBMS are derived
+ from.
+
+ SCHEMA_INSERT_CPV_INTO_PACKAGE should be modified dependant on the RDBMS, as should SCHEMA_PACKAGE_CREATE-
+ basically you need to deal with creation of a unique pkgid. If the dbapi2 rdbms class has a method of
+ recovering that id, then modify _insert_cpv to remove the extra select.
+
+ Creation of a derived class involves supplying _initdb_con, and table_exists.
+ Additionally, the default schemas may have to be modified.
+ """
+
+ SCHEMA_PACKAGE_NAME = "package_cache"
+ SCHEMA_PACKAGE_CREATE = "CREATE TABLE %s (\
+ pkgid INTEGER PRIMARY KEY, label VARCHAR(255), cpv VARCHAR(255), UNIQUE(label, cpv))" % SCHEMA_PACKAGE_NAME
+ SCHEMA_PACKAGE_DROP = "DROP TABLE %s" % SCHEMA_PACKAGE_NAME
+
+ SCHEMA_VALUES_NAME = "values_cache"
+ SCHEMA_VALUES_CREATE = "CREATE TABLE %s ( pkgid integer references %s (pkgid) on delete cascade, \
+ key varchar(255), value text, UNIQUE(pkgid, key))" % (SCHEMA_VALUES_NAME, SCHEMA_PACKAGE_NAME)
+ SCHEMA_VALUES_DROP = "DROP TABLE %s" % SCHEMA_VALUES_NAME
+ SCHEMA_INSERT_CPV_INTO_PACKAGE = "INSERT INTO %s (label, cpv) VALUES(%%s, %%s)" % SCHEMA_PACKAGE_NAME
+
+ _BaseError = ()
+ _dbClass = None
+
+ autocommits = False
+# cleanse_keys = True
+
+ # boolean indicating if the derived RDBMS class supports replace syntax
+ _supports_replace = False
+
+ def __init__(self, location, label, auxdbkeys, *args, **config):
+ """initialize the instance.
+ derived classes shouldn't need to override this"""
+
+ super(SQLDatabase, self).__init__(location, label, auxdbkeys, *args, **config)
+
+ config.setdefault("host","127.0.0.1")
+ config.setdefault("autocommit", self.autocommits)
+ self._initdb_con(config)
+
+ self.label = self._sfilter(self.label)
+
+
+ def _dbconnect(self, config):
+ """should be overridden if the derived class needs special parameters for initializing
+ the db connection, or cursor"""
+ self.db = self._dbClass(**config)
+ self.con = self.db.cursor()
+
+
+ def _initdb_con(self,config):
+ """ensure needed tables are in place.
+ If the derived class needs a different set of table creation commands, overload the approriate
+ SCHEMA_ attributes. If it needs additional execution beyond, override"""
+
+ self._dbconnect(config)
+ if not self._table_exists(self.SCHEMA_PACKAGE_NAME):
+ if self.readonly:
+ raise cache_errors.ReadOnlyRestriction("table %s doesn't exist" % \
+ self.SCHEMA_PACKAGE_NAME)
+ try:
+ self.con.execute(self.SCHEMA_PACKAGE_CREATE)
+ except self._BaseError as e:
+ raise cache_errors.InitializationError(self.__class__, e)
+
+ if not self._table_exists(self.SCHEMA_VALUES_NAME):
+ if self.readonly:
+ raise cache_errors.ReadOnlyRestriction("table %s doesn't exist" % \
+ self.SCHEMA_VALUES_NAME)
+ try:
+ self.con.execute(self.SCHEMA_VALUES_CREATE)
+ except self._BaseError as e:
+ raise cache_errors.InitializationError(self.__class__, e)
+
+
+ def _table_exists(self, tbl):
+ """return true if a table exists
+ derived classes must override this"""
+ raise NotImplementedError
+
+
+ def _sfilter(self, s):
+ """meta escaping, returns quoted string for use in sql statements"""
+ return "\"%s\"" % s.replace("\\","\\\\").replace("\"","\\\"")
+
+
+ def _getitem(self, cpv):
+ try:
+ self.con.execute("SELECT key, value FROM %s NATURAL JOIN %s "
+ "WHERE label=%s AND cpv=%s" % (self.SCHEMA_PACKAGE_NAME, self.SCHEMA_VALUES_NAME,
+ self.label, self._sfilter(cpv)))
+ except self._BaseError as e:
+ raise cache_errors.CacheCorruption(self, cpv, e)
+
+ rows = self.con.fetchall()
+
+ if len(rows) == 0:
+ raise KeyError(cpv)
+
+ vals = dict([(k,"") for k in self._known_keys])
+ vals.update(dict(rows))
+ return vals
+
+
+ def _delitem(self, cpv):
+ """delete a cpv cache entry
+ derived RDBM classes for this *must* either support cascaded deletes, or
+ override this method"""
+ try:
+ try:
+ self.con.execute("DELETE FROM %s WHERE label=%s AND cpv=%s" % \
+ (self.SCHEMA_PACKAGE_NAME, self.label, self._sfilter(cpv)))
+ if self.autocommits:
+ self.commit()
+ except self._BaseError as e:
+ raise cache_errors.CacheCorruption(self, cpv, e)
+ if self.con.rowcount <= 0:
+ raise KeyError(cpv)
+ except SystemExit:
+ raise
+ except Exception:
+ if not self.autocommits:
+ self.db.rollback()
+ # yes, this can roll back a lot more then just the delete. deal.
+ raise
+
+ def __del__(self):
+ # just to be safe.
+ if "db" in self.__dict__ and self.db != None:
+ self.commit()
+ self.db.close()
+
+ def _setitem(self, cpv, values):
+
+ try:
+ # insert.
+ try:
+ pkgid = self._insert_cpv(cpv)
+ except self._BaseError as e:
+ raise cache_errors.CacheCorruption(cpv, e)
+
+ # __getitem__ fills out missing values,
+ # so we store only what's handed to us and is a known key
+ db_values = []
+ for key in self._known_keys:
+ if key in values and values[key]:
+ db_values.append({"key":key, "value":values[key]})
+
+ if len(db_values) > 0:
+ try:
+ self.con.executemany("INSERT INTO %s (pkgid, key, value) VALUES(\"%s\", %%(key)s, %%(value)s)" % \
+ (self.SCHEMA_VALUES_NAME, str(pkgid)), db_values)
+ except self._BaseError as e:
+ raise cache_errors.CacheCorruption(cpv, e)
+ if self.autocommits:
+ self.commit()
+
+ except SystemExit:
+ raise
+ except Exception:
+ if not self.autocommits:
+ try:
+ self.db.rollback()
+ except self._BaseError:
+ pass
+ raise
+
+
+ def _insert_cpv(self, cpv):
+ """uses SCHEMA_INSERT_CPV_INTO_PACKAGE, which must be overloaded if the table definition
+ doesn't support auto-increment columns for pkgid.
+ returns the cpvs new pkgid
+ note this doesn't commit the transaction. The caller is expected to."""
+
+ cpv = self._sfilter(cpv)
+ if self._supports_replace:
+ query_str = self.SCHEMA_INSERT_CPV_INTO_PACKAGE.replace("INSERT","REPLACE",1)
+ else:
+ # just delete it.
+ try:
+ del self[cpv]
+ except (cache_errors.CacheCorruption, KeyError):
+ pass
+ query_str = self.SCHEMA_INSERT_CPV_INTO_PACKAGE
+ try:
+ self.con.execute(query_str % (self.label, cpv))
+ except self._BaseError:
+ self.db.rollback()
+ raise
+ self.con.execute("SELECT pkgid FROM %s WHERE label=%s AND cpv=%s" % \
+ (self.SCHEMA_PACKAGE_NAME, self.label, cpv))
+
+ if self.con.rowcount != 1:
+ raise cache_error.CacheCorruption(cpv, "Tried to insert the cpv, but found "
+ " %i matches upon the following select!" % len(rows))
+ return self.con.fetchone()[0]
+
+
+ def __contains__(self, cpv):
+ if not self.autocommits:
+ try:
+ self.commit()
+ except self._BaseError as e:
+ raise cache_errors.GeneralCacheCorruption(e)
+
+ try:
+ self.con.execute("SELECT cpv FROM %s WHERE label=%s AND cpv=%s" % \
+ (self.SCHEMA_PACKAGE_NAME, self.label, self._sfilter(cpv)))
+ except self._BaseError as e:
+ raise cache_errors.GeneralCacheCorruption(e)
+ return self.con.rowcount > 0
+
+
+ def __iter__(self):
+ if not self.autocommits:
+ try:
+ self.commit()
+ except self._BaseError as e:
+ raise cache_errors.GeneralCacheCorruption(e)
+
+ try:
+ self.con.execute("SELECT cpv FROM %s WHERE label=%s" %
+ (self.SCHEMA_PACKAGE_NAME, self.label))
+ except self._BaseError as e:
+ raise cache_errors.GeneralCacheCorruption(e)
+# return [ row[0] for row in self.con.fetchall() ]
+ for x in self.con.fetchall():
+ yield x[0]
+
+ def iteritems(self):
+ try:
+ self.con.execute("SELECT cpv, key, value FROM %s NATURAL JOIN %s "
+ "WHERE label=%s" % (self.SCHEMA_PACKAGE_NAME, self.SCHEMA_VALUES_NAME,
+ self.label))
+ except self._BaseError as e:
+ raise cache_errors.CacheCorruption(self, cpv, e)
+
+ oldcpv = None
+ l = []
+ for x, y, v in self.con.fetchall():
+ if oldcpv != x:
+ if oldcpv != None:
+ d = dict(l)
+ if "_eclasses_" in d:
+ d["_eclasses_"] = reconstruct_eclasses(oldcpv, d["_eclasses_"])
+ else:
+ d["_eclasses_"] = {}
+ yield cpv, d
+ l.clear()
+ oldcpv = x
+ l.append((y,v))
+ if oldcpv != None:
+ d = dict(l)
+ if "_eclasses_" in d:
+ d["_eclasses_"] = reconstruct_eclasses(oldcpv, d["_eclasses_"])
+ else:
+ d["_eclasses_"] = {}
+ yield cpv, d
+
+ def commit(self):
+ self.db.commit()
+
+ def get_matches(self,match_dict):
+ query_list = []
+ for k,v in match_dict.items():
+ if k not in self._known_keys:
+ raise cache_errors.InvalidRestriction(k, v, "key isn't known to this cache instance")
+ v = v.replace("%","\\%")
+ v = v.replace(".*","%")
+ query_list.append("(key=%s AND value LIKE %s)" % (self._sfilter(k), self._sfilter(v)))
+
+ if len(query_list):
+ query = " AND "+" AND ".join(query_list)
+ else:
+ query = ''
+
+ print("query = SELECT cpv from package_cache natural join values_cache WHERE label=%s %s" % (self.label, query))
+ try:
+ self.con.execute("SELECT cpv from package_cache natural join values_cache WHERE label=%s %s" % \
+ (self.label, query))
+ except self._BaseError as e:
+ raise cache_errors.GeneralCacheCorruption(e)
+
+ return [ row[0] for row in self.con.fetchall() ]
+
+ if sys.hexversion >= 0x3000000:
+ items = iteritems
+ keys = __iter__
diff --git a/portage_with_autodep/pym/portage/cache/sqlite.py b/portage_with_autodep/pym/portage/cache/sqlite.py
new file mode 100644
index 0000000..fcc62ff
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cache/sqlite.py
@@ -0,0 +1,245 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+from portage.cache import fs_template
+from portage.cache import cache_errors
+from portage import os
+from portage import _unicode_decode
+from portage.util import writemsg
+from portage.localization import _
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+class database(fs_template.FsBased):
+
+ autocommits = False
+ synchronous = False
+ # cache_bytes is used together with page_size (set at sqlite build time)
+ # to calculate the number of pages requested, according to the following
+ # equation: cache_bytes = page_bytes * page_count
+ cache_bytes = 1024 * 1024 * 10
+ _db_table = None
+
+ def __init__(self, *args, **config):
+ super(database, self).__init__(*args, **config)
+ self._import_sqlite()
+ self._allowed_keys = ["_mtime_", "_eclasses_"]
+ self._allowed_keys.extend(self._known_keys)
+ self._allowed_keys.sort()
+ self.location = os.path.join(self.location,
+ self.label.lstrip(os.path.sep).rstrip(os.path.sep))
+
+ if not self.readonly and not os.path.exists(self.location):
+ self._ensure_dirs()
+
+ config.setdefault("autocommit", self.autocommits)
+ config.setdefault("cache_bytes", self.cache_bytes)
+ config.setdefault("synchronous", self.synchronous)
+ # Timeout for throwing a "database is locked" exception (pysqlite
+ # default is 5.0 seconds).
+ config.setdefault("timeout", 15)
+ self._db_init_connection(config)
+ self._db_init_structures()
+
+ def _import_sqlite(self):
+ # sqlite3 is optional with >=python-2.5
+ try:
+ import sqlite3 as db_module
+ except ImportError:
+ try:
+ from pysqlite2 import dbapi2 as db_module
+ except ImportError as e:
+ raise cache_errors.InitializationError(self.__class__, e)
+
+ self._db_module = db_module
+ self._db_error = db_module.Error
+
+ def _db_escape_string(self, s):
+ """meta escaping, returns quoted string for use in sql statements"""
+ if not isinstance(s, basestring):
+ # Avoid potential UnicodeEncodeError in python-2.x by
+ # only calling str() when it's absolutely necessary.
+ s = str(s)
+ # This is equivalent to the _quote function from pysqlite 1.1.
+ return "'%s'" % s.replace("'", "''")
+
+ def _db_init_connection(self, config):
+ self._dbpath = self.location + ".sqlite"
+ #if os.path.exists(self._dbpath):
+ # os.unlink(self._dbpath)
+ connection_kwargs = {}
+ connection_kwargs["timeout"] = config["timeout"]
+ try:
+ if not self.readonly:
+ self._ensure_dirs()
+ self._db_connection = self._db_module.connect(
+ database=_unicode_decode(self._dbpath), **connection_kwargs)
+ self._db_cursor = self._db_connection.cursor()
+ self._db_cursor.execute("PRAGMA encoding = %s" % self._db_escape_string("UTF-8"))
+ if not self.readonly and not self._ensure_access(self._dbpath):
+ raise cache_errors.InitializationError(self.__class__, "can't ensure perms on %s" % self._dbpath)
+ self._db_init_cache_size(config["cache_bytes"])
+ self._db_init_synchronous(config["synchronous"])
+ except self._db_error as e:
+ raise cache_errors.InitializationError(self.__class__, e)
+
+ def _db_init_structures(self):
+ self._db_table = {}
+ self._db_table["packages"] = {}
+ mytable = "portage_packages"
+ self._db_table["packages"]["table_name"] = mytable
+ self._db_table["packages"]["package_id"] = "internal_db_package_id"
+ self._db_table["packages"]["package_key"] = "portage_package_key"
+ self._db_table["packages"]["internal_columns"] = \
+ [self._db_table["packages"]["package_id"],
+ self._db_table["packages"]["package_key"]]
+ create_statement = []
+ create_statement.append("CREATE TABLE")
+ create_statement.append(mytable)
+ create_statement.append("(")
+ table_parameters = []
+ table_parameters.append("%s INTEGER PRIMARY KEY AUTOINCREMENT" % self._db_table["packages"]["package_id"])
+ table_parameters.append("%s TEXT" % self._db_table["packages"]["package_key"])
+ for k in self._allowed_keys:
+ table_parameters.append("%s TEXT" % k)
+ table_parameters.append("UNIQUE(%s)" % self._db_table["packages"]["package_key"])
+ create_statement.append(",".join(table_parameters))
+ create_statement.append(")")
+
+ self._db_table["packages"]["create"] = " ".join(create_statement)
+ self._db_table["packages"]["columns"] = \
+ self._db_table["packages"]["internal_columns"] + \
+ self._allowed_keys
+
+ cursor = self._db_cursor
+ for k, v in self._db_table.items():
+ if self._db_table_exists(v["table_name"]):
+ create_statement = self._db_table_get_create(v["table_name"])
+ if create_statement != v["create"]:
+ writemsg(_("sqlite: dropping old table: %s\n") % v["table_name"])
+ cursor.execute("DROP TABLE %s" % v["table_name"])
+ cursor.execute(v["create"])
+ else:
+ cursor.execute(v["create"])
+
+ def _db_table_exists(self, table_name):
+ """return true/false dependant on a tbl existing"""
+ cursor = self._db_cursor
+ cursor.execute("SELECT name FROM sqlite_master WHERE type=\"table\" AND name=%s" % \
+ self._db_escape_string(table_name))
+ return len(cursor.fetchall()) == 1
+
+ def _db_table_get_create(self, table_name):
+ """return true/false dependant on a tbl existing"""
+ cursor = self._db_cursor
+ cursor.execute("SELECT sql FROM sqlite_master WHERE name=%s" % \
+ self._db_escape_string(table_name))
+ return cursor.fetchall()[0][0]
+
+ def _db_init_cache_size(self, cache_bytes):
+ cursor = self._db_cursor
+ cursor.execute("PRAGMA page_size")
+ page_size=int(cursor.fetchone()[0])
+ # number of pages, sqlite default is 2000
+ cache_size = cache_bytes / page_size
+ cursor.execute("PRAGMA cache_size = %d" % cache_size)
+ cursor.execute("PRAGMA cache_size")
+ actual_cache_size = int(cursor.fetchone()[0])
+ del cursor
+ if actual_cache_size != cache_size:
+ raise cache_errors.InitializationError(self.__class__,"actual cache_size = "+actual_cache_size+" does does not match requested size of "+cache_size)
+
+ def _db_init_synchronous(self, synchronous):
+ cursor = self._db_cursor
+ cursor.execute("PRAGMA synchronous = %d" % synchronous)
+ cursor.execute("PRAGMA synchronous")
+ actual_synchronous=int(cursor.fetchone()[0])
+ del cursor
+ if actual_synchronous!=synchronous:
+ raise cache_errors.InitializationError(self.__class__,"actual synchronous = "+actual_synchronous+" does does not match requested value of "+synchronous)
+
+ def _getitem(self, cpv):
+ cursor = self._db_cursor
+ cursor.execute("select * from %s where %s=%s" % \
+ (self._db_table["packages"]["table_name"],
+ self._db_table["packages"]["package_key"],
+ self._db_escape_string(cpv)))
+ result = cursor.fetchall()
+ if len(result) == 1:
+ pass
+ elif len(result) == 0:
+ raise KeyError(cpv)
+ else:
+ raise cache_errors.CacheCorruption(cpv, "key is not unique")
+ d = {}
+ internal_columns = self._db_table["packages"]["internal_columns"]
+ column_index = -1
+ for k in self._db_table["packages"]["columns"]:
+ column_index +=1
+ if k not in internal_columns:
+ d[k] = result[0][column_index]
+
+ return d
+
+ def _setitem(self, cpv, values):
+ update_statement = []
+ update_statement.append("REPLACE INTO %s" % self._db_table["packages"]["table_name"])
+ update_statement.append("(")
+ update_statement.append(','.join([self._db_table["packages"]["package_key"]] + self._allowed_keys))
+ update_statement.append(")")
+ update_statement.append("VALUES")
+ update_statement.append("(")
+ values_parameters = []
+ values_parameters.append(self._db_escape_string(cpv))
+ for k in self._allowed_keys:
+ values_parameters.append(self._db_escape_string(values.get(k, '')))
+ update_statement.append(",".join(values_parameters))
+ update_statement.append(")")
+ cursor = self._db_cursor
+ try:
+ s = " ".join(update_statement)
+ cursor.execute(s)
+ except self._db_error as e:
+ writemsg("%s: %s\n" % (cpv, str(e)))
+ raise
+
+ def commit(self):
+ self._db_connection.commit()
+
+ def _delitem(self, cpv):
+ cursor = self._db_cursor
+ cursor.execute("DELETE FROM %s WHERE %s=%s" % \
+ (self._db_table["packages"]["table_name"],
+ self._db_table["packages"]["package_key"],
+ self._db_escape_string(cpv)))
+
+ def __contains__(self, cpv):
+ cursor = self._db_cursor
+ cursor.execute(" ".join(
+ ["SELECT %s FROM %s" %
+ (self._db_table["packages"]["package_id"],
+ self._db_table["packages"]["table_name"]),
+ "WHERE %s=%s" % (
+ self._db_table["packages"]["package_key"],
+ self._db_escape_string(cpv))]))
+ result = cursor.fetchall()
+ if len(result) == 0:
+ return False
+ elif len(result) == 1:
+ return True
+ else:
+ raise cache_errors.CacheCorruption(cpv, "key is not unique")
+
+ def __iter__(self):
+ """generator for walking the dir struct"""
+ cursor = self._db_cursor
+ cursor.execute("SELECT %s FROM %s" % \
+ (self._db_table["packages"]["package_key"],
+ self._db_table["packages"]["table_name"]))
+ result = cursor.fetchall()
+ key_list = [x[0] for x in result]
+ del result
+ while key_list:
+ yield key_list.pop()
diff --git a/portage_with_autodep/pym/portage/cache/template.py b/portage_with_autodep/pym/portage/cache/template.py
new file mode 100644
index 0000000..f84d8f4
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cache/template.py
@@ -0,0 +1,236 @@
+# Copyright: 2005 Gentoo Foundation
+# Author(s): Brian Harring (ferringb@gentoo.org)
+# License: GPL2
+
+from portage.cache import cache_errors
+from portage.cache.cache_errors import InvalidRestriction
+from portage.cache.mappings import ProtectedDict
+import sys
+import warnings
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+ long = int
+
+class database(object):
+ # this is for metadata/cache transfer.
+ # basically flags the cache needs be updated when transfered cache to cache.
+ # leave this.
+
+ complete_eclass_entries = True
+ autocommits = False
+ cleanse_keys = False
+ serialize_eclasses = True
+
+ def __init__(self, location, label, auxdbkeys, readonly=False):
+ """ initialize the derived class; specifically, store label/keys"""
+ self._known_keys = auxdbkeys
+ self.location = location
+ self.label = label
+ self.readonly = readonly
+ self.sync_rate = 0
+ self.updates = 0
+
+ def __getitem__(self, cpv):
+ """set a cpv to values
+ This shouldn't be overriden in derived classes since it handles the __eclasses__ conversion.
+ that said, if the class handles it, they can override it."""
+ if self.updates > self.sync_rate:
+ self.commit()
+ self.updates = 0
+ d=self._getitem(cpv)
+ if self.serialize_eclasses and "_eclasses_" in d:
+ d["_eclasses_"] = reconstruct_eclasses(cpv, d["_eclasses_"])
+ elif "_eclasses_" not in d:
+ d["_eclasses_"] = {}
+ mtime = d.get('_mtime_')
+ if mtime is None:
+ raise cache_errors.CacheCorruption(cpv,
+ '_mtime_ field is missing')
+ try:
+ mtime = long(mtime)
+ except ValueError:
+ raise cache_errors.CacheCorruption(cpv,
+ '_mtime_ conversion to long failed: %s' % (mtime,))
+ d['_mtime_'] = mtime
+ return d
+
+ def _getitem(self, cpv):
+ """get cpv's values.
+ override this in derived classess"""
+ raise NotImplementedError
+
+ def __setitem__(self, cpv, values):
+ """set a cpv to values
+ This shouldn't be overriden in derived classes since it handles the readonly checks"""
+ if self.readonly:
+ raise cache_errors.ReadOnlyRestriction()
+ if self.cleanse_keys:
+ d=ProtectedDict(values)
+ for k, v in list(d.items()):
+ if not v:
+ del d[k]
+ if self.serialize_eclasses and "_eclasses_" in values:
+ d["_eclasses_"] = serialize_eclasses(d["_eclasses_"])
+ elif self.serialize_eclasses and "_eclasses_" in values:
+ d = ProtectedDict(values)
+ d["_eclasses_"] = serialize_eclasses(d["_eclasses_"])
+ else:
+ d = values
+ self._setitem(cpv, d)
+ if not self.autocommits:
+ self.updates += 1
+ if self.updates > self.sync_rate:
+ self.commit()
+ self.updates = 0
+
+ def _setitem(self, name, values):
+ """__setitem__ calls this after readonly checks. override it in derived classes
+ note _eclassees_ key *must* be handled"""
+ raise NotImplementedError
+
+ def __delitem__(self, cpv):
+ """delete a key from the cache.
+ This shouldn't be overriden in derived classes since it handles the readonly checks"""
+ if self.readonly:
+ raise cache_errors.ReadOnlyRestriction()
+ if not self.autocommits:
+ self.updates += 1
+ self._delitem(cpv)
+ if self.updates > self.sync_rate:
+ self.commit()
+ self.updates = 0
+
+ def _delitem(self,cpv):
+ """__delitem__ calls this after readonly checks. override it in derived classes"""
+ raise NotImplementedError
+
+ def has_key(self, cpv):
+ return cpv in self
+
+ def keys(self):
+ return list(self)
+
+ def iterkeys(self):
+ return iter(self)
+
+ def iteritems(self):
+ for x in self:
+ yield (x, self[x])
+
+ def items(self):
+ return list(self.iteritems())
+
+ def sync(self, rate=0):
+ self.sync_rate = rate
+ if(rate == 0):
+ self.commit()
+
+ def commit(self):
+ if not self.autocommits:
+ raise NotImplementedError
+
+ def __contains__(self, cpv):
+ """This method should always be overridden. It is provided only for
+ backward compatibility with modules that override has_key instead. It
+ will automatically raise a NotImplementedError if has_key has not been
+ overridden."""
+ if self.has_key is database.has_key:
+ # prevent a possible recursive loop
+ raise NotImplementedError
+ warnings.warn("portage.cache.template.database.has_key() is "
+ "deprecated, override __contains__ instead",
+ DeprecationWarning)
+ return self.has_key(cpv)
+
+ def __iter__(self):
+ """This method should always be overridden. It is provided only for
+ backward compatibility with modules that override iterkeys instead. It
+ will automatically raise a NotImplementedError if iterkeys has not been
+ overridden."""
+ if self.iterkeys is database.iterkeys:
+ # prevent a possible recursive loop
+ raise NotImplementedError(self)
+ return iter(self.keys())
+
+ def get(self, k, x=None):
+ try:
+ return self[k]
+ except KeyError:
+ return x
+
+ def get_matches(self, match_dict):
+ """generic function for walking the entire cache db, matching restrictions to
+ filter what cpv's are returned. Derived classes should override this if they
+ can implement a faster method then pulling each cpv:values, and checking it.
+
+ For example, RDBMS derived classes should push the matching logic down to the
+ actual RDBM."""
+
+ import re
+ restricts = {}
+ for key,match in match_dict.items():
+ # XXX this sucks.
+ try:
+ if isinstance(match, basestring):
+ restricts[key] = re.compile(match).match
+ else:
+ restricts[key] = re.compile(match[0],match[1]).match
+ except re.error as e:
+ raise InvalidRestriction(key, match, e)
+ if key not in self.__known_keys:
+ raise InvalidRestriction(key, match, "Key isn't valid")
+
+ for cpv in self:
+ cont = True
+ vals = self[cpv]
+ for key, match in restricts.items():
+ if not match(vals[key]):
+ cont = False
+ break
+ if cont:
+ yield cpv
+
+ if sys.hexversion >= 0x3000000:
+ keys = __iter__
+ items = iteritems
+
+def serialize_eclasses(eclass_dict):
+ """takes a dict, returns a string representing said dict"""
+ """The "new format", which causes older versions of <portage-2.1.2 to
+ traceback with a ValueError due to failed long() conversion. This format
+ isn't currently written, but the the capability to read it is already built
+ in.
+ return "\t".join(["%s\t%s" % (k, str(v)) \
+ for k, v in eclass_dict.iteritems()])
+ """
+ if not eclass_dict:
+ return ""
+ return "\t".join(k + "\t%s\t%s" % eclass_dict[k] \
+ for k in sorted(eclass_dict))
+
+def reconstruct_eclasses(cpv, eclass_string):
+ """returns a dict when handed a string generated by serialize_eclasses"""
+ eclasses = eclass_string.rstrip().lstrip().split("\t")
+ if eclasses == [""]:
+ # occasionally this occurs in the fs backends. they suck.
+ return {}
+
+ if len(eclasses) % 2 != 0 and len(eclasses) % 3 != 0:
+ raise cache_errors.CacheCorruption(cpv, "_eclasses_ was of invalid len %i" % len(eclasses))
+ d={}
+ try:
+ if eclasses[1].isdigit():
+ for x in range(0, len(eclasses), 2):
+ d[eclasses[x]] = ("", long(eclasses[x + 1]))
+ else:
+ # The old format contains paths that will be discarded.
+ for x in range(0, len(eclasses), 3):
+ d[eclasses[x]] = (eclasses[x + 1], long(eclasses[x + 2]))
+ except IndexError:
+ raise cache_errors.CacheCorruption(cpv,
+ "_eclasses_ was of invalid len %i" % len(eclasses))
+ except ValueError:
+ raise cache_errors.CacheCorruption(cpv, "_eclasses_ mtime conversion to long failed")
+ del eclasses
+ return d
diff --git a/portage_with_autodep/pym/portage/cache/util.py b/portage_with_autodep/pym/portage/cache/util.py
new file mode 100644
index 0000000..b824689
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cache/util.py
@@ -0,0 +1,170 @@
+# Copyright: 2005 Gentoo Foundation
+# Author(s): Brian Harring (ferringb@gentoo.org)
+# License: GPL2
+
+from __future__ import print_function
+
+__all__ = ["mirror_cache", "non_quiet_mirroring", "quiet_mirroring"]
+
+from itertools import chain
+from portage.cache import cache_errors
+from portage.localization import _
+
+def mirror_cache(valid_nodes_iterable, src_cache, trg_cache, eclass_cache=None, verbose_instance=None):
+
+ from portage import eapi_is_supported, \
+ _validate_cache_for_unsupported_eapis
+ if not src_cache.complete_eclass_entries and not eclass_cache:
+ raise Exception("eclass_cache required for cache's of class %s!" % src_cache.__class__)
+
+ if verbose_instance == None:
+ noise=quiet_mirroring()
+ else:
+ noise=verbose_instance
+
+ dead_nodes = set(trg_cache)
+ count=0
+
+ if not trg_cache.autocommits:
+ trg_cache.sync(100)
+
+ for x in valid_nodes_iterable:
+# print "processing x=",x
+ count+=1
+ dead_nodes.discard(x)
+ try:
+ entry = src_cache[x]
+ except KeyError as e:
+ noise.missing_entry(x)
+ del e
+ continue
+ except cache_errors.CacheError as ce:
+ noise.exception(x, ce)
+ del ce
+ continue
+
+ eapi = entry.get('EAPI')
+ if not eapi:
+ eapi = '0'
+ eapi = eapi.lstrip('-')
+ eapi_supported = eapi_is_supported(eapi)
+ if not eapi_supported:
+ if not _validate_cache_for_unsupported_eapis:
+ noise.misc(x, _("unable to validate cache for EAPI='%s'") % eapi)
+ continue
+
+ write_it = True
+ trg = None
+ try:
+ trg = trg_cache[x]
+ except (KeyError, cache_errors.CacheError):
+ pass
+ else:
+ if trg['_mtime_'] == entry['_mtime_'] and \
+ eclass_cache.is_eclass_data_valid(trg['_eclasses_']) and \
+ set(trg['_eclasses_']) == set(entry['_eclasses_']):
+ write_it = False
+
+ for d in (entry, trg):
+ if d is not None and d.get('EAPI') in ('', '0'):
+ del d['EAPI']
+
+ if trg and not write_it:
+ """ We don't want to skip the write unless we're really sure that
+ the existing cache is identical, so don't trust _mtime_ and
+ _eclasses_ alone."""
+ for k in set(chain(entry, trg)).difference(
+ ("_mtime_", "_eclasses_")):
+ if trg.get(k, "") != entry.get(k, ""):
+ write_it = True
+ break
+
+ if write_it:
+ try:
+ inherited = entry.get("INHERITED", "")
+ eclasses = entry.get("_eclasses_")
+ except cache_errors.CacheError as ce:
+ noise.exception(x, ce)
+ del ce
+ continue
+
+ if eclasses is not None:
+ if not eclass_cache.is_eclass_data_valid(entry["_eclasses_"]):
+ noise.eclass_stale(x)
+ continue
+ inherited = eclasses
+ else:
+ inherited = inherited.split()
+
+ if inherited:
+ if src_cache.complete_eclass_entries and eclasses is None:
+ noise.corruption(x, "missing _eclasses_ field")
+ continue
+
+ # Even if _eclasses_ already exists, replace it with data from
+ # eclass_cache, in order to insert local eclass paths.
+ try:
+ eclasses = eclass_cache.get_eclass_data(inherited)
+ except KeyError:
+ # INHERITED contains a non-existent eclass.
+ noise.eclass_stale(x)
+ continue
+
+ if eclasses is None:
+ noise.eclass_stale(x)
+ continue
+ entry["_eclasses_"] = eclasses
+
+ if not eapi_supported:
+ for k in set(entry).difference(("_mtime_", "_eclasses_")):
+ entry[k] = ""
+ entry["EAPI"] = "-" + eapi
+
+ # by this time, if it reaches here, the eclass has been validated, and the entry has
+ # been updated/translated (if needs be, for metadata/cache mainly)
+ try:
+ trg_cache[x] = entry
+ except cache_errors.CacheError as ce:
+ noise.exception(x, ce)
+ del ce
+ continue
+ if count >= noise.call_update_min:
+ noise.update(x)
+ count = 0
+
+ if not trg_cache.autocommits:
+ trg_cache.commit()
+
+ # ok. by this time, the trg_cache is up to date, and we have a dict
+ # with a crapload of cpv's. we now walk the target db, removing stuff if it's in the list.
+ for key in dead_nodes:
+ try:
+ del trg_cache[key]
+ except KeyError:
+ pass
+ except cache_errors.CacheError as ce:
+ noise.exception(ce)
+ del ce
+ noise.finish()
+
+
+class quiet_mirroring(object):
+ # call_update_every is used by mirror_cache to determine how often to call in.
+ # quiet defaults to 2^24 -1. Don't call update, 'cept once every 16 million or so :)
+ call_update_min = 0xffffff
+ def update(self,key,*arg): pass
+ def exception(self,key,*arg): pass
+ def eclass_stale(self,*arg): pass
+ def missing_entry(self, key): pass
+ def misc(self,key,*arg): pass
+ def corruption(self, key, s): pass
+ def finish(self, *arg): pass
+
+class non_quiet_mirroring(quiet_mirroring):
+ call_update_min=1
+ def update(self,key,*arg): print("processed",key)
+ def exception(self, key, *arg): print("exec",key,arg)
+ def missing(self,key): print("key %s is missing", key)
+ def corruption(self,key,*arg): print("corrupt %s:" % key,arg)
+ def eclass_stale(self,key,*arg):print("stale %s:"%key,arg)
+
diff --git a/portage_with_autodep/pym/portage/cache/volatile.py b/portage_with_autodep/pym/portage/cache/volatile.py
new file mode 100644
index 0000000..0bf6bab
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cache/volatile.py
@@ -0,0 +1,25 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import copy
+from portage.cache import template
+
+class database(template.database):
+
+ autocommits = True
+ serialize_eclasses = False
+
+ def __init__(self, *args, **config):
+ config.pop("gid", None)
+ config.pop("perms", None)
+ super(database, self).__init__(*args, **config)
+ self._data = {}
+ self.__iter__ = self._data.__iter__
+ self._delitem = self._data.__delitem__
+ self.__contains__ = self._data.__contains__
+
+ def _setitem(self, name, values):
+ self._data[name] = copy.deepcopy(values)
+
+ def _getitem(self, cpv):
+ return copy.deepcopy(self._data[cpv])
diff --git a/portage_with_autodep/pym/portage/checksum.py b/portage_with_autodep/pym/portage/checksum.py
new file mode 100644
index 0000000..9e7e455
--- /dev/null
+++ b/portage_with_autodep/pym/portage/checksum.py
@@ -0,0 +1,291 @@
+# checksum.py -- core Portage functionality
+# Copyright 1998-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import portage
+from portage.const import PRELINK_BINARY,HASHING_BLOCKSIZE
+from portage.localization import _
+from portage import os
+from portage import _encodings
+from portage import _unicode_encode
+import errno
+import stat
+import tempfile
+
+#dict of all available hash functions
+hashfunc_map = {}
+hashorigin_map = {}
+
+def _generate_hash_function(hashtype, hashobject, origin="unknown"):
+ def pyhash(filename):
+ """
+ Run a checksum against a file.
+
+ @param filename: File to run the checksum against
+ @type filename: String
+ @return: The hash and size of the data
+ """
+ try:
+ f = open(_unicode_encode(filename,
+ encoding=_encodings['fs'], errors='strict'), 'rb')
+ except IOError as e:
+ func_call = "open('%s')" % filename
+ if e.errno == errno.EPERM:
+ raise portage.exception.OperationNotPermitted(func_call)
+ elif e.errno == errno.EACCES:
+ raise portage.exception.PermissionDenied(func_call)
+ elif e.errno == errno.ENOENT:
+ raise portage.exception.FileNotFound(filename)
+ else:
+ raise
+ blocksize = HASHING_BLOCKSIZE
+ data = f.read(blocksize)
+ size = 0
+ checksum = hashobject()
+ while data:
+ checksum.update(data)
+ size = size + len(data)
+ data = f.read(blocksize)
+ f.close()
+
+ return (checksum.hexdigest(), size)
+ hashfunc_map[hashtype] = pyhash
+ hashorigin_map[hashtype] = origin
+ return pyhash
+
+# Define hash functions, try to use the best module available. Later definitions
+# override earlier ones
+
+# Use the internal modules as last fallback
+try:
+ from hashlib import md5 as _new_md5
+except ImportError:
+ from md5 import new as _new_md5
+
+md5hash = _generate_hash_function("MD5", _new_md5, origin="internal")
+
+try:
+ from hashlib import sha1 as _new_sha1
+except ImportError:
+ from sha import new as _new_sha1
+
+sha1hash = _generate_hash_function("SHA1", _new_sha1, origin="internal")
+
+# Use pycrypto when available, prefer it over the internal fallbacks
+try:
+ from Crypto.Hash import SHA256, RIPEMD
+ sha256hash = _generate_hash_function("SHA256", SHA256.new, origin="pycrypto")
+ rmd160hash = _generate_hash_function("RMD160", RIPEMD.new, origin="pycrypto")
+except ImportError as e:
+ pass
+
+# Use hashlib from python-2.5 if available and prefer it over pycrypto and internal fallbacks.
+# Need special handling for RMD160 as it may not always be provided by hashlib.
+try:
+ import hashlib
+
+ md5hash = _generate_hash_function("MD5", hashlib.md5, origin="hashlib")
+ sha1hash = _generate_hash_function("SHA1", hashlib.sha1, origin="hashlib")
+ sha256hash = _generate_hash_function("SHA256", hashlib.sha256, origin="hashlib")
+ try:
+ hashlib.new('ripemd160')
+ except ValueError:
+ pass
+ else:
+ def rmd160():
+ return hashlib.new('ripemd160')
+ rmd160hash = _generate_hash_function("RMD160", rmd160, origin="hashlib")
+except ImportError as e:
+ pass
+
+
+# Use python-fchksum if available, prefer it over all other MD5 implementations
+try:
+ import fchksum
+
+ def md5hash(filename):
+ return fchksum.fmd5t(filename)
+ hashfunc_map["MD5"] = md5hash
+ hashorigin_map["MD5"] = "python-fchksum"
+
+except ImportError:
+ pass
+
+# There is only one implementation for size
+def getsize(filename):
+ size = os.stat(filename).st_size
+ return (size, size)
+hashfunc_map["size"] = getsize
+
+# end actual hash functions
+
+prelink_capable = False
+if os.path.exists(PRELINK_BINARY):
+ results = portage.subprocess_getstatusoutput(
+ "%s --version > /dev/null 2>&1" % (PRELINK_BINARY,))
+ if (results[0] >> 8) == 0:
+ prelink_capable=1
+ del results
+
+def perform_md5(x, calc_prelink=0):
+ return perform_checksum(x, "MD5", calc_prelink)[0]
+
+def _perform_md5_merge(x, **kwargs):
+ return perform_md5(_unicode_encode(x,
+ encoding=_encodings['merge'], errors='strict'), **kwargs)
+
+def perform_all(x, calc_prelink=0):
+ mydict = {}
+ for k in hashfunc_map:
+ mydict[k] = perform_checksum(x, hashfunc_map[k], calc_prelink)[0]
+ return mydict
+
+def get_valid_checksum_keys():
+ return list(hashfunc_map)
+
+def get_hash_origin(hashtype):
+ if hashtype not in hashfunc_map:
+ raise KeyError(hashtype)
+ return hashorigin_map.get(hashtype, "unknown")
+
+def verify_all(filename, mydict, calc_prelink=0, strict=0):
+ """
+ Verify all checksums against a file.
+
+ @param filename: File to run the checksums against
+ @type filename: String
+ @param calc_prelink: Whether or not to reverse prelink before running the checksum
+ @type calc_prelink: Integer
+ @param strict: Enable/Disable strict checking (which stops exactly at a checksum failure and throws an exception)
+ @type strict: Integer
+ @rtype: Tuple
+ @return: Result of the checks and possible message:
+ 1) If size fails, False, and a tuple containing a message, the given size, and the actual size
+ 2) If there is an os error, False, and a tuple containing the system error followed by 2 nulls
+ 3) If a checksum fails, False and a tuple containing a message, the given hash, and the actual hash
+ 4) If all checks succeed, return True and a fake reason
+ """
+ # Dict relates to single file only.
+ # returns: (passed,reason)
+ file_is_ok = True
+ reason = "Reason unknown"
+ try:
+ mysize = os.stat(filename)[stat.ST_SIZE]
+ if mydict["size"] != mysize:
+ return False,(_("Filesize does not match recorded size"), mysize, mydict["size"])
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ raise portage.exception.FileNotFound(filename)
+ return False, (str(e), None, None)
+
+ verifiable_hash_types = set(mydict).intersection(hashfunc_map)
+ verifiable_hash_types.discard("size")
+ if not verifiable_hash_types:
+ expected = set(hashfunc_map)
+ expected.discard("size")
+ expected = list(expected)
+ expected.sort()
+ expected = " ".join(expected)
+ got = set(mydict)
+ got.discard("size")
+ got = list(got)
+ got.sort()
+ got = " ".join(got)
+ return False, (_("Insufficient data for checksum verification"), got, expected)
+
+ for x in sorted(mydict):
+ if x == "size":
+ continue
+ elif x in hashfunc_map:
+ myhash = perform_checksum(filename, x, calc_prelink=calc_prelink)[0]
+ if mydict[x] != myhash:
+ if strict:
+ raise portage.exception.DigestException(
+ ("Failed to verify '$(file)s' on " + \
+ "checksum type '%(type)s'") % \
+ {"file" : filename, "type" : x})
+ else:
+ file_is_ok = False
+ reason = (("Failed on %s verification" % x), myhash,mydict[x])
+ break
+ return file_is_ok,reason
+
+def perform_checksum(filename, hashname="MD5", calc_prelink=0):
+ """
+ Run a specific checksum against a file. The filename can
+ be either unicode or an encoded byte string. If filename
+ is unicode then a UnicodeDecodeError will be raised if
+ necessary.
+
+ @param filename: File to run the checksum against
+ @type filename: String
+ @param hashname: The type of hash function to run
+ @type hashname: String
+ @param calc_prelink: Whether or not to reverse prelink before running the checksum
+ @type calc_prelink: Integer
+ @rtype: Tuple
+ @return: The hash and size of the data
+ """
+ global prelink_capable
+ # Make sure filename is encoded with the correct encoding before
+ # it is passed to spawn (for prelink) and/or the hash function.
+ filename = _unicode_encode(filename,
+ encoding=_encodings['fs'], errors='strict')
+ myfilename = filename
+ prelink_tmpfile = None
+ try:
+ if calc_prelink and prelink_capable:
+ # Create non-prelinked temporary file to checksum.
+ # Files rejected by prelink are summed in place.
+ try:
+ tmpfile_fd, prelink_tmpfile = tempfile.mkstemp()
+ try:
+ retval = portage.process.spawn([PRELINK_BINARY,
+ "--verify", filename], fd_pipes={1:tmpfile_fd})
+ finally:
+ os.close(tmpfile_fd)
+ if retval == os.EX_OK:
+ myfilename = prelink_tmpfile
+ except portage.exception.CommandNotFound:
+ # This happens during uninstallation of prelink.
+ prelink_capable = False
+ try:
+ if hashname not in hashfunc_map:
+ raise portage.exception.DigestException(hashname + \
+ " hash function not available (needs dev-python/pycrypto)")
+ myhash, mysize = hashfunc_map[hashname](myfilename)
+ except (OSError, IOError) as e:
+ if e.errno == errno.ENOENT:
+ raise portage.exception.FileNotFound(myfilename)
+ raise
+ return myhash, mysize
+ finally:
+ if prelink_tmpfile:
+ try:
+ os.unlink(prelink_tmpfile)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+
+def perform_multiple_checksums(filename, hashes=["MD5"], calc_prelink=0):
+ """
+ Run a group of checksums against a file.
+
+ @param filename: File to run the checksums against
+ @type filename: String
+ @param hashes: A list of checksum functions to run against the file
+ @type hashname: List
+ @param calc_prelink: Whether or not to reverse prelink before running the checksum
+ @type calc_prelink: Integer
+ @rtype: Tuple
+ @return: A dictionary in the form:
+ return_value[hash_name] = (hash_result,size)
+ for each given checksum
+ """
+ rVal = {}
+ for x in hashes:
+ if x not in hashfunc_map:
+ raise portage.exception.DigestException(x+" hash function not available (needs dev-python/pycrypto or >=dev-lang/python-2.5)")
+ rVal[x] = perform_checksum(filename, x, calc_prelink)[0]
+ return rVal
diff --git a/portage_with_autodep/pym/portage/const.py b/portage_with_autodep/pym/portage/const.py
new file mode 100644
index 0000000..f34398d
--- /dev/null
+++ b/portage_with_autodep/pym/portage/const.py
@@ -0,0 +1,143 @@
+# portage: Constants
+# Copyright 1998-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import os
+
+# ===========================================================================
+# START OF CONSTANTS -- START OF CONSTANTS -- START OF CONSTANTS -- START OF
+# ===========================================================================
+
+# There are two types of variables here which can easily be confused,
+# resulting in arbitrary bugs, mainly exposed with an offset
+# installation (Prefix). The two types relate to the usage of
+# config_root or target_root.
+# The first, config_root (PORTAGE_CONFIGROOT), can be a path somewhere,
+# from which all derived paths need to be relative (e.g.
+# USER_CONFIG_PATH) without EPREFIX prepended in Prefix. This means
+# config_root can for instance be set to "$HOME/my/config". Obviously,
+# in such case it is not appropriate to prepend EPREFIX to derived
+# constants. The default value of config_root is EPREFIX (in non-Prefix
+# the empty string) -- overriding the value loses the EPREFIX as one
+# would expect.
+# Second there is target_root (ROOT) which is used to install somewhere
+# completely else, in Prefix of limited use. Because this is an offset
+# always given, the EPREFIX should always be applied in it, hence the
+# code always prefixes them with EROOT.
+# The variables in this file are grouped by config_root, target_root.
+
+# variables used with config_root (these need to be relative)
+MAKE_CONF_FILE = "etc/make.conf"
+USER_CONFIG_PATH = "etc/portage"
+MODULES_FILE_PATH = USER_CONFIG_PATH + "/modules"
+CUSTOM_PROFILE_PATH = USER_CONFIG_PATH + "/profile"
+USER_VIRTUALS_FILE = USER_CONFIG_PATH + "/virtuals"
+EBUILD_SH_ENV_FILE = USER_CONFIG_PATH + "/bashrc"
+EBUILD_SH_ENV_DIR = USER_CONFIG_PATH + "/env"
+CUSTOM_MIRRORS_FILE = USER_CONFIG_PATH + "/mirrors"
+COLOR_MAP_FILE = USER_CONFIG_PATH + "/color.map"
+PROFILE_PATH = "etc/make.profile"
+MAKE_DEFAULTS_FILE = PROFILE_PATH + "/make.defaults" # FIXME: not used
+DEPRECATED_PROFILE_FILE = PROFILE_PATH + "/deprecated"
+
+# variables used with targetroot (these need to be absolute, but not
+# have a leading '/' since they are used directly with os.path.join on EROOT)
+VDB_PATH = "var/db/pkg"
+CACHE_PATH = "var/cache/edb"
+PRIVATE_PATH = "var/lib/portage"
+WORLD_FILE = PRIVATE_PATH + "/world"
+WORLD_SETS_FILE = PRIVATE_PATH + "/world_sets"
+CONFIG_MEMORY_FILE = PRIVATE_PATH + "/config"
+NEWS_LIB_PATH = "var/lib/gentoo"
+
+# these variables get EPREFIX prepended automagically when they are
+# translated into their lowercase variants
+DEPCACHE_PATH = "/var/cache/edb/dep"
+GLOBAL_CONFIG_PATH = "/usr/share/portage/config"
+
+# these variables are not used with target_root or config_root
+PORTAGE_BASE_PATH = os.path.join(os.sep, os.sep.join(__file__.split(os.sep)[:-3]))
+PORTAGE_BIN_PATH = PORTAGE_BASE_PATH + "/bin"
+PORTAGE_PYM_PATH = PORTAGE_BASE_PATH + "/pym"
+LOCALE_DATA_PATH = PORTAGE_BASE_PATH + "/locale" # FIXME: not used
+EBUILD_SH_BINARY = PORTAGE_BIN_PATH + "/ebuild.sh"
+MISC_SH_BINARY = PORTAGE_BIN_PATH + "/misc-functions.sh"
+SANDBOX_BINARY = "/usr/bin/sandbox"
+FAKEROOT_BINARY = "/usr/bin/fakeroot"
+BASH_BINARY = "/bin/bash"
+MOVE_BINARY = "/bin/mv"
+PRELINK_BINARY = "/usr/sbin/prelink"
+AUTODEP_LIBRARY = "/usr/lib/file_hook.so"
+
+
+INVALID_ENV_FILE = "/etc/spork/is/not/valid/profile.env"
+REPO_NAME_FILE = "repo_name"
+REPO_NAME_LOC = "profiles" + "/" + REPO_NAME_FILE
+
+PORTAGE_PACKAGE_ATOM = "sys-apps/portage"
+LIBC_PACKAGE_ATOM = "virtual/libc"
+OS_HEADERS_PACKAGE_ATOM = "virtual/os-headers"
+
+INCREMENTALS = ("USE", "USE_EXPAND", "USE_EXPAND_HIDDEN",
+ "FEATURES", "ACCEPT_KEYWORDS",
+ "CONFIG_PROTECT_MASK", "CONFIG_PROTECT",
+ "PRELINK_PATH", "PRELINK_PATH_MASK",
+ "PROFILE_ONLY_VARIABLES")
+EBUILD_PHASES = ("pretend", "setup", "unpack", "prepare", "configure",
+ "compile", "test", "install",
+ "package", "preinst", "postinst","prerm", "postrm",
+ "nofetch", "config", "info", "other")
+SUPPORTED_FEATURES = frozenset([
+ "allow-missing-manifests",
+ "assume-digests", "binpkg-logs", "buildpkg", "buildsyspkg", "candy",
+ "ccache", "chflags", "collision-protect", "compress-build-logs",
+ "depcheck", "depcheckstrict",
+ "digest", "distcc", "distcc-pump", "distlocks", "ebuild-locks", "fakeroot",
+ "fail-clean", "fixpackages", "force-mirror", "getbinpkg",
+ "installsources", "keeptemp", "keepwork", "fixlafiles", "lmirror",
+ "metadata-transfer", "mirror", "multilib-strict", "news",
+ "noauto", "noclean", "nodoc", "noinfo", "noman",
+ "nostrip", "notitles", "parallel-fetch", "parallel-install",
+ "parse-eapi-ebuild-head",
+ "prelink-checksums", "preserve-libs",
+ "protect-owned", "python-trace", "sandbox",
+ "selinux", "sesandbox", "sfperms",
+ "sign", "skiprocheck", "split-elog", "split-log", "splitdebug",
+ "strict", "stricter", "suidctl", "test", "test-fail-continue",
+ "unknown-features-filter", "unknown-features-warn",
+ "unmerge-logs", "unmerge-orphans", "userfetch", "userpriv",
+ "usersandbox", "usersync", "webrsync-gpg"])
+
+EAPI = 4
+
+HASHING_BLOCKSIZE = 32768
+MANIFEST1_HASH_FUNCTIONS = ("MD5", "SHA256", "RMD160")
+MANIFEST2_HASH_FUNCTIONS = ("SHA1", "SHA256", "RMD160")
+
+MANIFEST1_REQUIRED_HASH = "MD5"
+MANIFEST2_REQUIRED_HASH = "SHA1"
+
+MANIFEST2_IDENTIFIERS = ("AUX", "MISC", "DIST", "EBUILD")
+# ===========================================================================
+# END OF CONSTANTS -- END OF CONSTANTS -- END OF CONSTANTS -- END OF CONSTANT
+# ===========================================================================
+
+# Private constants for use in conditional code in order to minimize the diff
+# between branches.
+_ENABLE_DYN_LINK_MAP = True
+_ENABLE_PRESERVE_LIBS = True
+_ENABLE_REPO_NAME_WARN = True
+_ENABLE_SET_CONFIG = True
+_SANDBOX_COMPAT_LEVEL = "22"
+
+
+# The definitions above will differ between branches, so it's useful to have
+# common lines of diff context here in order to avoid merge conflicts.
+
+if not _ENABLE_PRESERVE_LIBS:
+ SUPPORTED_FEATURES = set(SUPPORTED_FEATURES)
+ SUPPORTED_FEATURES.remove("preserve-libs")
+ SUPPORTED_FEATURES = frozenset(SUPPORTED_FEATURES)
+
+if not _ENABLE_SET_CONFIG:
+ WORLD_SETS_FILE = '/dev/null'
diff --git a/portage_with_autodep/pym/portage/cvstree.py b/portage_with_autodep/pym/portage/cvstree.py
new file mode 100644
index 0000000..9ba22f3
--- /dev/null
+++ b/portage_with_autodep/pym/portage/cvstree.py
@@ -0,0 +1,293 @@
+# cvstree.py -- cvs tree utilities
+# Copyright 1998-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import io
+import re
+import stat
+import sys
+import time
+
+from portage import os
+from portage import _encodings
+from portage import _unicode_encode
+
+if sys.hexversion >= 0x3000000:
+ long = int
+
+# [D]/Name/Version/Date/Flags/Tags
+
+def pathdata(entries, path):
+ """(entries,path)
+ Returns the data(dict) for a specific file/dir at the path specified."""
+ mysplit=path.split("/")
+ myentries=entries
+ mytarget=mysplit[-1]
+ mysplit=mysplit[:-1]
+ for mys in mysplit:
+ if mys in myentries["dirs"]:
+ myentries=myentries["dirs"][mys]
+ else:
+ return None
+ if mytarget in myentries["dirs"]:
+ return myentries["dirs"][mytarget]
+ elif mytarget in myentries["files"]:
+ return myentries["files"][mytarget]
+ else:
+ return None
+
+def fileat(entries, path):
+ return pathdata(entries,path)
+
+def isadded(entries, path):
+ """(entries,path)
+ Returns true if the path exists and is added to the cvs tree."""
+ mytarget=pathdata(entries, path)
+ if mytarget:
+ if "cvs" in mytarget["status"]:
+ return 1
+
+ basedir=os.path.dirname(path)
+ filename=os.path.basename(path)
+
+ try:
+ myfile = io.open(
+ _unicode_encode(os.path.join(basedir, 'CVS', 'Entries'),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'], errors='strict')
+ except IOError:
+ return 0
+ mylines=myfile.readlines()
+ myfile.close()
+
+ rep=re.compile("^\/"+re.escape(filename)+"\/");
+ for x in mylines:
+ if rep.search(x):
+ return 1
+
+ return 0
+
+def findnew(entries,recursive=0,basedir=""):
+ """(entries,recursive=0,basedir="")
+ Recurses the entries tree to find all elements that have been added but
+ have not yet been committed. Returns a list of paths, optionally prepended
+ with a basedir."""
+ if basedir and basedir[-1]!="/":
+ basedir=basedir+"/"
+ mylist=[]
+ for myfile in entries["files"]:
+ if "cvs" in entries["files"][myfile]["status"]:
+ if "0" == entries["files"][myfile]["revision"]:
+ mylist.append(basedir+myfile)
+ if recursive:
+ for mydir in entries["dirs"]:
+ mylist+=findnew(entries["dirs"][mydir],recursive,basedir+mydir)
+ return mylist
+
+def findoption(entries, pattern, recursive=0, basedir=""):
+ """(entries, pattern, recursive=0, basedir="")
+ Iterate over paths of cvs entries for which the pattern.search() method
+ finds a match. Returns a list of paths, optionally prepended with a
+ basedir."""
+ if not basedir.endswith("/"):
+ basedir += "/"
+ for myfile, mydata in entries["files"].items():
+ if "cvs" in mydata["status"]:
+ if pattern.search(mydata["flags"]):
+ yield basedir+myfile
+ if recursive:
+ for mydir, mydata in entries["dirs"].items():
+ for x in findoption(mydata, pattern,
+ recursive, basedir+mydir):
+ yield x
+
+def findchanged(entries,recursive=0,basedir=""):
+ """(entries,recursive=0,basedir="")
+ Recurses the entries tree to find all elements that exist in the cvs tree
+ and differ from the committed version. Returns a list of paths, optionally
+ prepended with a basedir."""
+ if basedir and basedir[-1]!="/":
+ basedir=basedir+"/"
+ mylist=[]
+ for myfile in entries["files"]:
+ if "cvs" in entries["files"][myfile]["status"]:
+ if "current" not in entries["files"][myfile]["status"]:
+ if "exists" in entries["files"][myfile]["status"]:
+ if entries["files"][myfile]["revision"]!="0":
+ mylist.append(basedir+myfile)
+ if recursive:
+ for mydir in entries["dirs"]:
+ mylist+=findchanged(entries["dirs"][mydir],recursive,basedir+mydir)
+ return mylist
+
+def findmissing(entries,recursive=0,basedir=""):
+ """(entries,recursive=0,basedir="")
+ Recurses the entries tree to find all elements that are listed in the cvs
+ tree but do not exist on the filesystem. Returns a list of paths,
+ optionally prepended with a basedir."""
+ if basedir and basedir[-1]!="/":
+ basedir=basedir+"/"
+ mylist=[]
+ for myfile in entries["files"]:
+ if "cvs" in entries["files"][myfile]["status"]:
+ if "exists" not in entries["files"][myfile]["status"]:
+ if "removed" not in entries["files"][myfile]["status"]:
+ mylist.append(basedir+myfile)
+ if recursive:
+ for mydir in entries["dirs"]:
+ mylist+=findmissing(entries["dirs"][mydir],recursive,basedir+mydir)
+ return mylist
+
+def findunadded(entries,recursive=0,basedir=""):
+ """(entries,recursive=0,basedir="")
+ Recurses the entries tree to find all elements that are in valid cvs
+ directories but are not part of the cvs tree. Returns a list of paths,
+ optionally prepended with a basedir."""
+ if basedir and basedir[-1]!="/":
+ basedir=basedir+"/"
+ mylist=[]
+
+ #ignore what cvs ignores.
+ for myfile in entries["files"]:
+ if "cvs" not in entries["files"][myfile]["status"]:
+ mylist.append(basedir+myfile)
+ if recursive:
+ for mydir in entries["dirs"]:
+ mylist+=findunadded(entries["dirs"][mydir],recursive,basedir+mydir)
+ return mylist
+
+def findremoved(entries,recursive=0,basedir=""):
+ """(entries,recursive=0,basedir="")
+ Recurses the entries tree to find all elements that are in flagged for cvs
+ deletions. Returns a list of paths, optionally prepended with a basedir."""
+ if basedir and basedir[-1]!="/":
+ basedir=basedir+"/"
+ mylist=[]
+ for myfile in entries["files"]:
+ if "removed" in entries["files"][myfile]["status"]:
+ mylist.append(basedir+myfile)
+ if recursive:
+ for mydir in entries["dirs"]:
+ mylist+=findremoved(entries["dirs"][mydir],recursive,basedir+mydir)
+ return mylist
+
+def findall(entries, recursive=0, basedir=""):
+ """(entries,recursive=0,basedir="")
+ Recurses the entries tree to find all new, changed, missing, and unadded
+ entities. Returns a 4 element list of lists as returned from each find*()."""
+
+ if basedir and basedir[-1]!="/":
+ basedir=basedir+"/"
+ mynew = findnew(entries,recursive,basedir)
+ mychanged = findchanged(entries,recursive,basedir)
+ mymissing = findmissing(entries,recursive,basedir)
+ myunadded = findunadded(entries,recursive,basedir)
+ myremoved = findremoved(entries,recursive,basedir)
+ return [mynew, mychanged, mymissing, myunadded, myremoved]
+
+ignore_list = re.compile("(^|/)(RCS(|LOG)|SCCS|CVS(|\.adm)|cvslog\..*|tags|TAGS|\.(make\.state|nse_depinfo)|.*~|(\.|)#.*|,.*|_$.*|.*\$|\.del-.*|.*\.(old|BAK|bak|orig|rej|a|olb|o|obj|so|exe|Z|elc|ln)|core)$")
+def apply_cvsignore_filter(list):
+ x=0
+ while x < len(list):
+ if ignore_list.match(list[x].split("/")[-1]):
+ list.pop(x)
+ else:
+ x+=1
+ return list
+
+def getentries(mydir,recursive=0):
+ """(basedir,recursive=0)
+ Scans the given directory and returns a datadict of all the entries in
+ the directory separated as a dirs dict and a files dict."""
+ myfn=mydir+"/CVS/Entries"
+ # entries=[dirs, files]
+ entries={"dirs":{},"files":{}}
+ if not os.path.exists(mydir):
+ return entries
+ try:
+ myfile = io.open(_unicode_encode(myfn,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'], errors='strict')
+ mylines=myfile.readlines()
+ myfile.close()
+ except SystemExit as e:
+ raise
+ except:
+ mylines=[]
+ for line in mylines:
+ if line and line[-1]=="\n":
+ line=line[:-1]
+ if not line:
+ continue
+ if line=="D": # End of entries file
+ break
+ mysplit=line.split("/")
+ if len(mysplit)!=6:
+ print("Confused:",mysplit)
+ continue
+ if mysplit[0]=="D":
+ entries["dirs"][mysplit[1]]={"dirs":{},"files":{},"status":[]}
+ entries["dirs"][mysplit[1]]["status"]=["cvs"]
+ if os.path.isdir(mydir+"/"+mysplit[1]):
+ entries["dirs"][mysplit[1]]["status"]+=["exists"]
+ entries["dirs"][mysplit[1]]["flags"]=mysplit[2:]
+ if recursive:
+ rentries=getentries(mydir+"/"+mysplit[1],recursive)
+ entries["dirs"][mysplit[1]]["dirs"]=rentries["dirs"]
+ entries["dirs"][mysplit[1]]["files"]=rentries["files"]
+ else:
+ # [D]/Name/revision/Date/Flags/Tags
+ entries["files"][mysplit[1]]={}
+ entries["files"][mysplit[1]]["revision"]=mysplit[2]
+ entries["files"][mysplit[1]]["date"]=mysplit[3]
+ entries["files"][mysplit[1]]["flags"]=mysplit[4]
+ entries["files"][mysplit[1]]["tags"]=mysplit[5]
+ entries["files"][mysplit[1]]["status"]=["cvs"]
+ if entries["files"][mysplit[1]]["revision"][0]=="-":
+ entries["files"][mysplit[1]]["status"]+=["removed"]
+
+ for file in apply_cvsignore_filter(os.listdir(mydir)):
+ if file=="CVS":
+ continue
+ if os.path.isdir(mydir+"/"+file):
+ if file not in entries["dirs"]:
+ entries["dirs"][file]={"dirs":{},"files":{}}
+ # It's normal for a directory to be unlisted in Entries
+ # when checked out without -P (see bug #257660).
+ rentries=getentries(mydir+"/"+file,recursive)
+ entries["dirs"][file]["dirs"]=rentries["dirs"]
+ entries["dirs"][file]["files"]=rentries["files"]
+ if "status" in entries["dirs"][file]:
+ if "exists" not in entries["dirs"][file]["status"]:
+ entries["dirs"][file]["status"]+=["exists"]
+ else:
+ entries["dirs"][file]["status"]=["exists"]
+ elif os.path.isfile(mydir+"/"+file):
+ if file not in entries["files"]:
+ entries["files"][file]={"revision":"","date":"","flags":"","tags":""}
+ if "status" in entries["files"][file]:
+ if "exists" not in entries["files"][file]["status"]:
+ entries["files"][file]["status"]+=["exists"]
+ else:
+ entries["files"][file]["status"]=["exists"]
+ try:
+ mystat=os.stat(mydir+"/"+file)
+ mytime = time.asctime(time.gmtime(mystat[stat.ST_MTIME]))
+ if "status" not in entries["files"][file]:
+ entries["files"][file]["status"]=[]
+ if mytime==entries["files"][file]["date"]:
+ entries["files"][file]["status"]+=["current"]
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ print("failed to stat",file)
+ print(e)
+ return
+
+ else:
+ print()
+ print("File of unknown type:",mydir+"/"+file)
+ print()
+ return entries
diff --git a/portage_with_autodep/pym/portage/data.py b/portage_with_autodep/pym/portage/data.py
new file mode 100644
index 0000000..c38fa17
--- /dev/null
+++ b/portage_with_autodep/pym/portage/data.py
@@ -0,0 +1,122 @@
+# data.py -- Calculated/Discovered Data Values
+# Copyright 1998-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import os, pwd, grp, platform
+
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.output:colorize',
+ 'portage.util:writemsg',
+)
+from portage.localization import _
+
+ostype=platform.system()
+userland = None
+if ostype == "DragonFly" or ostype.endswith("BSD"):
+ userland = "BSD"
+else:
+ userland = "GNU"
+
+lchown = getattr(os, "lchown", None)
+
+if not lchown:
+ if ostype == "Darwin":
+ def lchown(*pos_args, **key_args):
+ pass
+ else:
+ def lchown(*pargs, **kwargs):
+ writemsg(colorize("BAD", "!!!") + _(
+ " It seems that os.lchown does not"
+ " exist. Please rebuild python.\n"), noiselevel=-1)
+ lchown()
+
+lchown = portage._unicode_func_wrapper(lchown)
+
+def portage_group_warning():
+ warn_prefix = colorize("BAD", "*** WARNING *** ")
+ mylines = [
+ "For security reasons, only system administrators should be",
+ "allowed in the portage group. Untrusted users or processes",
+ "can potentially exploit the portage group for attacks such as",
+ "local privilege escalation."
+ ]
+ for x in mylines:
+ writemsg(warn_prefix, noiselevel=-1)
+ writemsg(x, noiselevel=-1)
+ writemsg("\n", noiselevel=-1)
+ writemsg("\n", noiselevel=-1)
+
+# Portage has 3 security levels that depend on the uid and gid of the main
+# process and are assigned according to the following table:
+#
+# Privileges secpass uid gid
+# normal 0 any any
+# group 1 any portage_gid
+# super 2 0 any
+#
+# If the "wheel" group does not exist then wheelgid falls back to 0.
+# If the "portage" group does not exist then portage_uid falls back to wheelgid.
+
+secpass=0
+
+uid=os.getuid()
+wheelgid=0
+
+if uid==0:
+ secpass=2
+try:
+ wheelgid=grp.getgrnam("wheel")[2]
+except KeyError:
+ pass
+
+# Allow the overriding of the user used for 'userpriv' and 'userfetch'
+_portage_uname = os.environ.get('PORTAGE_USERNAME', 'portage')
+_portage_grpname = os.environ.get('PORTAGE_GRPNAME', 'portage')
+
+#Discover the uid and gid of the portage user/group
+try:
+ portage_uid = pwd.getpwnam(_portage_uname)[2]
+ portage_gid = grp.getgrnam(_portage_grpname)[2]
+ if secpass < 1 and portage_gid in os.getgroups():
+ secpass=1
+except KeyError:
+ portage_uid=0
+ portage_gid=0
+ userpriv_groups = [portage_gid]
+ writemsg(colorize("BAD",
+ _("portage: 'portage' user or group missing.")) + "\n", noiselevel=-1)
+ writemsg(_(
+ " For the defaults, line 1 goes into passwd, "
+ "and 2 into group.\n"), noiselevel=-1)
+ writemsg(colorize("GOOD",
+ " portage:x:250:250:portage:/var/tmp/portage:/bin/false") \
+ + "\n", noiselevel=-1)
+ writemsg(colorize("GOOD", " portage::250:portage") + "\n",
+ noiselevel=-1)
+ portage_group_warning()
+else:
+ userpriv_groups = [portage_gid]
+ if secpass >= 2:
+ class _LazyUserprivGroups(portage.proxy.objectproxy.ObjectProxy):
+ def _get_target(self):
+ global userpriv_groups
+ if userpriv_groups is not self:
+ return userpriv_groups
+ userpriv_groups = _userpriv_groups
+ # Get a list of group IDs for the portage user. Do not use
+ # grp.getgrall() since it is known to trigger spurious
+ # SIGPIPE problems with nss_ldap.
+ mystatus, myoutput = \
+ portage.subprocess_getstatusoutput("id -G %s" % _portage_uname)
+ if mystatus == os.EX_OK:
+ for x in myoutput.split():
+ try:
+ userpriv_groups.append(int(x))
+ except ValueError:
+ pass
+ userpriv_groups[:] = sorted(set(userpriv_groups))
+ return userpriv_groups
+
+ _userpriv_groups = userpriv_groups
+ userpriv_groups = _LazyUserprivGroups()
diff --git a/portage_with_autodep/pym/portage/dbapi/_MergeProcess.py b/portage_with_autodep/pym/portage/dbapi/_MergeProcess.py
new file mode 100644
index 0000000..34ed031
--- /dev/null
+++ b/portage_with_autodep/pym/portage/dbapi/_MergeProcess.py
@@ -0,0 +1,282 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import io
+import shutil
+import signal
+import tempfile
+import traceback
+
+import errno
+import fcntl
+import portage
+from portage import os, _unicode_decode
+from portage.const import PORTAGE_PACKAGE_ATOM
+from portage.dep import match_from_list
+import portage.elog.messages
+from portage.elog import _preload_elog_modules
+from portage.util import ensure_dirs
+from _emerge.PollConstants import PollConstants
+from _emerge.SpawnProcess import SpawnProcess
+
+class MergeProcess(SpawnProcess):
+ """
+ Merge packages in a subprocess, so the Scheduler can run in the main
+ thread while files are moved or copied asynchronously.
+ """
+
+ __slots__ = ('mycat', 'mypkg', 'settings', 'treetype',
+ 'vartree', 'scheduler', 'blockers', 'pkgloc', 'infloc', 'myebuild',
+ 'mydbapi', 'prev_mtimes', 'unmerge', '_elog_reader_fd', '_elog_reg_id',
+ '_buf', '_elog_keys', '_locked_vdb')
+
+ def _start(self):
+ # Portage should always call setcpv prior to this
+ # point, but here we have a fallback as a convenience
+ # for external API consumers. It's important that
+ # this metadata access happens in the parent process,
+ # since closing of file descriptors in the subprocess
+ # can prevent access to open database connections such
+ # as that used by the sqlite metadata cache module.
+ cpv = "%s/%s" % (self.mycat, self.mypkg)
+ settings = self.settings
+ if cpv != settings.mycpv or \
+ "EAPI" not in settings.configdict["pkg"]:
+ settings.reload()
+ settings.reset()
+ settings.setcpv(cpv, mydb=self.mydbapi)
+
+ if not self.unmerge:
+ self._handle_self_reinstall()
+ super(MergeProcess, self)._start()
+
+ def _lock_vdb(self):
+ """
+ Lock the vdb if FEATURES=parallel-install is NOT enabled,
+ otherwise do nothing. This is implemented with
+ vardbapi.lock(), which supports reentrance by the
+ subprocess that we spawn.
+ """
+ if "parallel-install" not in self.settings.features:
+ self.vartree.dbapi.lock()
+ self._locked_vdb = True
+
+ def _unlock_vdb(self):
+ """
+ Unlock the vdb if we hold a lock, otherwise do nothing.
+ """
+ if self._locked_vdb:
+ self.vartree.dbapi.unlock()
+ self._locked_vdb = False
+
+ def _handle_self_reinstall(self):
+ """
+ If portage is reinstalling itself, create temporary
+ copies of PORTAGE_BIN_PATH and PORTAGE_PYM_PATH in order
+ to avoid relying on the new versions which may be
+ incompatible. Register an atexit hook to clean up the
+ temporary directories. Pre-load elog modules here since
+ we won't be able to later if they get unmerged (happens
+ when namespace changes).
+ """
+
+ settings = self.settings
+ cpv = settings.mycpv
+ reinstall_self = False
+ if self.settings["ROOT"] == "/" and \
+ match_from_list(PORTAGE_PACKAGE_ATOM, [cpv]):
+ inherited = frozenset(self.settings.get('INHERITED', '').split())
+ if not self.vartree.dbapi.cpv_exists(cpv) or \
+ '9999' in cpv or \
+ 'git' in inherited or \
+ 'git-2' in inherited:
+ reinstall_self = True
+
+ if reinstall_self:
+ # Load lazily referenced portage submodules into memory,
+ # so imports won't fail during portage upgrade/downgrade.
+ _preload_elog_modules(self.settings)
+ portage.proxy.lazyimport._preload_portage_submodules()
+
+ # Make the temp directory inside $PORTAGE_TMPDIR/portage, since
+ # it's common for /tmp and /var/tmp to be mounted with the
+ # "noexec" option (see bug #346899).
+ build_prefix = os.path.join(settings["PORTAGE_TMPDIR"], "portage")
+ ensure_dirs(build_prefix)
+ base_path_tmp = tempfile.mkdtemp(
+ "", "._portage_reinstall_.", build_prefix)
+ portage.process.atexit_register(shutil.rmtree, base_path_tmp)
+ dir_perms = 0o755
+ for subdir in "bin", "pym":
+ var_name = "PORTAGE_%s_PATH" % subdir.upper()
+ var_orig = settings[var_name]
+ var_new = os.path.join(base_path_tmp, subdir)
+ settings[var_name] = var_new
+ settings.backup_changes(var_name)
+ shutil.copytree(var_orig, var_new, symlinks=True)
+ os.chmod(var_new, dir_perms)
+ portage._bin_path = settings['PORTAGE_BIN_PATH']
+ portage._pym_path = settings['PORTAGE_PYM_PATH']
+ os.chmod(base_path_tmp, dir_perms)
+
+ def _elog_output_handler(self, fd, event):
+ output = None
+ if event & PollConstants.POLLIN:
+ try:
+ output = os.read(fd, self._bufsize)
+ except OSError as e:
+ if e.errno not in (errno.EAGAIN, errno.EINTR):
+ raise
+ if output:
+ lines = _unicode_decode(output).split('\n')
+ if len(lines) == 1:
+ self._buf += lines[0]
+ else:
+ lines[0] = self._buf + lines[0]
+ self._buf = lines.pop()
+ out = io.StringIO()
+ for line in lines:
+ funcname, phase, key, msg = line.split(' ', 3)
+ self._elog_keys.add(key)
+ reporter = getattr(portage.elog.messages, funcname)
+ reporter(msg, phase=phase, key=key, out=out)
+
+ def _spawn(self, args, fd_pipes, **kwargs):
+ """
+ Fork a subprocess, apply local settings, and call
+ dblink.merge().
+ """
+
+ elog_reader_fd, elog_writer_fd = os.pipe()
+ fcntl.fcntl(elog_reader_fd, fcntl.F_SETFL,
+ fcntl.fcntl(elog_reader_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
+ blockers = None
+ if self.blockers is not None:
+ # Query blockers in the main process, since closing
+ # of file descriptors in the subprocess can prevent
+ # access to open database connections such as that
+ # used by the sqlite metadata cache module.
+ blockers = self.blockers()
+ mylink = portage.dblink(self.mycat, self.mypkg, settings=self.settings,
+ treetype=self.treetype, vartree=self.vartree,
+ blockers=blockers, scheduler=self.scheduler,
+ pipe=elog_writer_fd)
+ fd_pipes[elog_writer_fd] = elog_writer_fd
+ self._elog_reg_id = self.scheduler.register(elog_reader_fd,
+ self._registered_events, self._elog_output_handler)
+
+ # If a concurrent emerge process tries to install a package
+ # in the same SLOT as this one at the same time, there is an
+ # extremely unlikely chance that the COUNTER values will not be
+ # ordered correctly unless we lock the vdb here.
+ # FEATURES=parallel-install skips this lock in order to
+ # improve performance, and the risk is practically negligible.
+ self._lock_vdb()
+ counter = None
+ if not self.unmerge:
+ counter = self.vartree.dbapi.counter_tick()
+
+ pid = os.fork()
+ if pid != 0:
+ os.close(elog_writer_fd)
+ self._elog_reader_fd = elog_reader_fd
+ self._buf = ""
+ self._elog_keys = set()
+
+ # invalidate relevant vardbapi caches
+ if self.vartree.dbapi._categories is not None:
+ self.vartree.dbapi._categories = None
+ self.vartree.dbapi._pkgs_changed = True
+ self.vartree.dbapi._clear_pkg_cache(mylink)
+
+ portage.process.spawned_pids.append(pid)
+ return [pid]
+
+ os.close(elog_reader_fd)
+ portage.process._setup_pipes(fd_pipes)
+
+ # Use default signal handlers since the ones inherited
+ # from the parent process are irrelevant here.
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+ signal.signal(signal.SIGTERM, signal.SIG_DFL)
+
+ portage.output.havecolor = self.settings.get('NOCOLOR') \
+ not in ('yes', 'true')
+
+ # In this subprocess we want mylink._display_merge() to use
+ # stdout/stderr directly since they are pipes. This behavior
+ # is triggered when mylink._scheduler is None.
+ mylink._scheduler = None
+
+ # Avoid wastful updates of the vdb cache.
+ self.vartree.dbapi._flush_cache_enabled = False
+
+ # In this subprocess we don't want PORTAGE_BACKGROUND to
+ # suppress stdout/stderr output since they are pipes. We
+ # also don't want to open PORTAGE_LOG_FILE, since it will
+ # already be opened by the parent process, so we set the
+ # "subprocess" value for use in conditional logging code
+ # involving PORTAGE_LOG_FILE.
+ if not self.unmerge:
+ # unmerge phases have separate logs
+ if self.settings.get("PORTAGE_BACKGROUND") == "1":
+ self.settings["PORTAGE_BACKGROUND_UNMERGE"] = "1"
+ else:
+ self.settings["PORTAGE_BACKGROUND_UNMERGE"] = "0"
+ self.settings.backup_changes("PORTAGE_BACKGROUND_UNMERGE")
+ self.settings["PORTAGE_BACKGROUND"] = "subprocess"
+ self.settings.backup_changes("PORTAGE_BACKGROUND")
+
+ rval = 1
+ try:
+ if self.unmerge:
+ if not mylink.exists():
+ rval = os.EX_OK
+ elif mylink.unmerge(
+ ldpath_mtimes=self.prev_mtimes) == os.EX_OK:
+ mylink.lockdb()
+ try:
+ mylink.delete()
+ finally:
+ mylink.unlockdb()
+ rval = os.EX_OK
+ else:
+ rval = mylink.merge(self.pkgloc, self.infloc,
+ myebuild=self.myebuild, mydbapi=self.mydbapi,
+ prev_mtimes=self.prev_mtimes, counter=counter)
+ except SystemExit:
+ raise
+ except:
+ traceback.print_exc()
+ finally:
+ # Call os._exit() from finally block, in order to suppress any
+ # finally blocks from earlier in the call stack. See bug #345289.
+ os._exit(rval)
+
+ def _unregister(self):
+ """
+ Unregister from the scheduler and close open files.
+ """
+
+ if not self.unmerge:
+ # Populate the vardbapi cache for the new package
+ # while its inodes are still hot.
+ try:
+ self.vartree.dbapi.aux_get(self.settings.mycpv, ["EAPI"])
+ except KeyError:
+ pass
+
+ self._unlock_vdb()
+ if self._elog_reg_id is not None:
+ self.scheduler.unregister(self._elog_reg_id)
+ self._elog_reg_id = None
+ if self._elog_reader_fd:
+ os.close(self._elog_reader_fd)
+ self._elog_reader_fd = None
+ if self._elog_keys is not None:
+ for key in self._elog_keys:
+ portage.elog.elog_process(key, self.settings,
+ phasefilter=("prerm", "postrm"))
+ self._elog_keys = None
+
+ super(MergeProcess, self)._unregister()
diff --git a/portage_with_autodep/pym/portage/dbapi/__init__.py b/portage_with_autodep/pym/portage/dbapi/__init__.py
new file mode 100644
index 0000000..e386faa
--- /dev/null
+++ b/portage_with_autodep/pym/portage/dbapi/__init__.py
@@ -0,0 +1,302 @@
+# Copyright 1998-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ["dbapi"]
+
+import re
+
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.dbapi.dep_expand:dep_expand@_dep_expand',
+ 'portage.dep:match_from_list',
+ 'portage.output:colorize',
+ 'portage.util:cmp_sort_key,writemsg',
+ 'portage.versions:catsplit,catpkgsplit,vercmp',
+)
+
+from portage import os
+from portage import auxdbkeys
+from portage.localization import _
+
+class dbapi(object):
+ _category_re = re.compile(r'^\w[-.+\w]*$')
+ _categories = None
+ _use_mutable = False
+ _known_keys = frozenset(x for x in auxdbkeys
+ if not x.startswith("UNUSED_0"))
+ def __init__(self):
+ pass
+
+ @property
+ def categories(self):
+ """
+ Use self.cp_all() to generate a category list. Mutable instances
+ can delete the self._categories attribute in cases when the cached
+ categories become invalid and need to be regenerated.
+ """
+ if self._categories is not None:
+ return self._categories
+ self._categories = tuple(sorted(set(catsplit(x)[0] \
+ for x in self.cp_all())))
+ return self._categories
+
+ def close_caches(self):
+ pass
+
+ def cp_list(self, cp, use_cache=1):
+ raise NotImplementedError(self)
+
+ def _cpv_sort_ascending(self, cpv_list):
+ """
+ Use this to sort self.cp_list() results in ascending
+ order. It sorts in place and returns None.
+ """
+ if len(cpv_list) > 1:
+ # If the cpv includes explicit -r0, it has to be preserved
+ # for consistency in findname and aux_get calls, so use a
+ # dict to map strings back to their original values.
+ ver_map = {}
+ for cpv in cpv_list:
+ ver_map[cpv] = '-'.join(catpkgsplit(cpv)[2:])
+ def cmp_cpv(cpv1, cpv2):
+ return vercmp(ver_map[cpv1], ver_map[cpv2])
+ cpv_list.sort(key=cmp_sort_key(cmp_cpv))
+
+ def cpv_all(self):
+ """Return all CPVs in the db
+ Args:
+ None
+ Returns:
+ A list of Strings, 1 per CPV
+
+ This function relies on a subclass implementing cp_all, this is why the hasattr is there
+ """
+
+ if not hasattr(self, "cp_all"):
+ raise NotImplementedError
+ cpv_list = []
+ for cp in self.cp_all():
+ cpv_list.extend(self.cp_list(cp))
+ return cpv_list
+
+ def cp_all(self):
+ """ Implement this in a child class
+ Args
+ None
+ Returns:
+ A list of strings 1 per CP in the datastore
+ """
+ return NotImplementedError
+
+ def aux_get(self, mycpv, mylist, myrepo=None):
+ """Return the metadata keys in mylist for mycpv
+ Args:
+ mycpv - "sys-apps/foo-1.0"
+ mylist - ["SLOT","DEPEND","HOMEPAGE"]
+ myrepo - The repository name.
+ Returns:
+ a list of results, in order of keys in mylist, such as:
+ ["0",">=sys-libs/bar-1.0","http://www.foo.com"] or [] if mycpv not found'
+ """
+ raise NotImplementedError
+
+ def aux_update(self, cpv, metadata_updates):
+ """
+ Args:
+ cpv - "sys-apps/foo-1.0"
+ metadata_updates = { key : newvalue }
+ Returns:
+ None
+ """
+ raise NotImplementedError
+
+ def match(self, origdep, use_cache=1):
+ """Given a dependency, try to find packages that match
+ Args:
+ origdep - Depend atom
+ use_cache - Boolean indicating if we should use the cache or not
+ NOTE: Do we ever not want the cache?
+ Returns:
+ a list of packages that match origdep
+ """
+ mydep = _dep_expand(origdep, mydb=self, settings=self.settings)
+ return list(self._iter_match(mydep,
+ self.cp_list(mydep.cp, use_cache=use_cache)))
+
+ def _iter_match(self, atom, cpv_iter):
+ cpv_iter = iter(match_from_list(atom, cpv_iter))
+ if atom.slot:
+ cpv_iter = self._iter_match_slot(atom, cpv_iter)
+ if atom.unevaluated_atom.use:
+ cpv_iter = self._iter_match_use(atom, cpv_iter)
+ if atom.repo:
+ cpv_iter = self._iter_match_repo(atom, cpv_iter)
+ return cpv_iter
+
+ def _iter_match_repo(self, atom, cpv_iter):
+ for cpv in cpv_iter:
+ try:
+ if self.aux_get(cpv, ["repository"], myrepo=atom.repo)[0] == atom.repo:
+ yield cpv
+ except KeyError:
+ continue
+
+ def _iter_match_slot(self, atom, cpv_iter):
+ for cpv in cpv_iter:
+ try:
+ if self.aux_get(cpv, ["SLOT"], myrepo=atom.repo)[0] == atom.slot:
+ yield cpv
+ except KeyError:
+ continue
+
+ def _iter_match_use(self, atom, cpv_iter):
+ """
+ 1) Check for required IUSE intersection (need implicit IUSE here).
+ 2) Check enabled/disabled flag states.
+ """
+
+ iuse_implicit_match = self.settings._iuse_implicit_match
+ for cpv in cpv_iter:
+ try:
+ iuse, slot, use = self.aux_get(cpv, ["IUSE", "SLOT", "USE"], myrepo=atom.repo)
+ except KeyError:
+ continue
+ iuse = frozenset(x.lstrip('+-') for x in iuse.split())
+ missing_iuse = False
+ for x in atom.unevaluated_atom.use.required:
+ if x not in iuse and not iuse_implicit_match(x):
+ missing_iuse = True
+ break
+ if missing_iuse:
+ continue
+ if not atom.use:
+ pass
+ elif not self._use_mutable:
+ # Use IUSE to validate USE settings for built packages,
+ # in case the package manager that built this package
+ # failed to do that for some reason (or in case of
+ # data corruption).
+ use = frozenset(x for x in use.split() if x in iuse or \
+ iuse_implicit_match(x))
+ missing_enabled = atom.use.missing_enabled.difference(iuse)
+ missing_disabled = atom.use.missing_disabled.difference(iuse)
+
+ if atom.use.enabled:
+ if atom.use.enabled.intersection(missing_disabled):
+ continue
+ need_enabled = atom.use.enabled.difference(use)
+ if need_enabled:
+ need_enabled = need_enabled.difference(missing_enabled)
+ if need_enabled:
+ continue
+
+ if atom.use.disabled:
+ if atom.use.disabled.intersection(missing_enabled):
+ continue
+ need_disabled = atom.use.disabled.intersection(use)
+ if need_disabled:
+ need_disabled = need_disabled.difference(missing_disabled)
+ if need_disabled:
+ continue
+ else:
+ # Check masked and forced flags for repoman.
+ mysettings = getattr(self, 'settings', None)
+ if mysettings is not None and not mysettings.local_config:
+
+ pkg = "%s:%s" % (cpv, slot)
+ usemask = mysettings._getUseMask(pkg)
+ if usemask.intersection(atom.use.enabled):
+ continue
+
+ useforce = mysettings._getUseForce(pkg).difference(usemask)
+ if useforce.intersection(atom.use.disabled):
+ continue
+
+ yield cpv
+
+ def invalidentry(self, mypath):
+ if '/-MERGING-' in mypath:
+ if os.path.exists(mypath):
+ writemsg(colorize("BAD", _("INCOMPLETE MERGE:"))+" %s\n" % mypath,
+ noiselevel=-1)
+ else:
+ writemsg("!!! Invalid db entry: %s\n" % mypath, noiselevel=-1)
+
+ def update_ents(self, updates, onProgress=None, onUpdate=None):
+ """
+ Update metadata of all packages for package moves.
+ @param updates: A list of move commands, or dict of {repo_name: list}
+ @type updates: list or dict
+ @param onProgress: A progress callback function
+ @type onProgress: a callable that takes 2 integer arguments: maxval and curval
+ @param onUpdate: A progress callback function called only
+ for packages that are modified by updates.
+ @type onUpdate: a callable that takes 2 integer arguments:
+ maxval and curval
+ """
+ cpv_all = self.cpv_all()
+ cpv_all.sort()
+ maxval = len(cpv_all)
+ aux_get = self.aux_get
+ aux_update = self.aux_update
+ meta_keys = ["DEPEND", "RDEPEND", "PDEPEND", "PROVIDE", 'repository']
+ repo_dict = None
+ if isinstance(updates, dict):
+ repo_dict = updates
+ from portage.update import update_dbentries
+ if onUpdate:
+ onUpdate(maxval, 0)
+ if onProgress:
+ onProgress(maxval, 0)
+ for i, cpv in enumerate(cpv_all):
+ metadata = dict(zip(meta_keys, aux_get(cpv, meta_keys)))
+ repo = metadata.pop('repository')
+ if repo_dict is None:
+ updates_list = updates
+ else:
+ try:
+ updates_list = repo_dict[repo]
+ except KeyError:
+ try:
+ updates_list = repo_dict['DEFAULT']
+ except KeyError:
+ continue
+
+ if not updates_list:
+ continue
+
+ metadata_updates = update_dbentries(updates_list, metadata)
+ if metadata_updates:
+ aux_update(cpv, metadata_updates)
+ if onUpdate:
+ onUpdate(maxval, i+1)
+ if onProgress:
+ onProgress(maxval, i+1)
+
+ def move_slot_ent(self, mylist, repo_match=None):
+ """This function takes a sequence:
+ Args:
+ mylist: a sequence of (package, originalslot, newslot)
+ repo_match: callable that takes single repo_name argument
+ and returns True if the update should be applied
+ Returns:
+ The number of slotmoves this function did
+ """
+ pkg = mylist[1]
+ origslot = mylist[2]
+ newslot = mylist[3]
+ origmatches = self.match(pkg)
+ moves = 0
+ if not origmatches:
+ return moves
+ for mycpv in origmatches:
+ slot = self.aux_get(mycpv, ["SLOT"])[0]
+ if slot != origslot:
+ continue
+ if repo_match is not None \
+ and not repo_match(self.aux_get(mycpv, ['repository'])[0]):
+ continue
+ moves += 1
+ mydata = {"SLOT": newslot+"\n"}
+ self.aux_update(mycpv, mydata)
+ return moves
diff --git a/portage_with_autodep/pym/portage/dbapi/_expand_new_virt.py b/portage_with_autodep/pym/portage/dbapi/_expand_new_virt.py
new file mode 100644
index 0000000..6d6a27d
--- /dev/null
+++ b/portage_with_autodep/pym/portage/dbapi/_expand_new_virt.py
@@ -0,0 +1,72 @@
+# Copyright 2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import portage
+from portage.dep import Atom, _get_useflag_re
+
+def expand_new_virt(vardb, atom):
+ """
+ Iterate over the recursively expanded RDEPEND atoms of
+ a new-style virtual. If atom is not a new-style virtual
+ or it does not match an installed package then it is
+ yielded without any expansion.
+ """
+ if not isinstance(atom, Atom):
+ atom = Atom(atom)
+
+ if not atom.cp.startswith("virtual/"):
+ yield atom
+ return
+
+ traversed = set()
+ stack = [atom]
+
+ while stack:
+ atom = stack.pop()
+ if atom.blocker or \
+ not atom.cp.startswith("virtual/"):
+ yield atom
+ continue
+
+ matches = vardb.match(atom)
+ if not (matches and matches[-1].startswith("virtual/")):
+ yield atom
+ continue
+
+ virt_cpv = matches[-1]
+ if virt_cpv in traversed:
+ continue
+
+ traversed.add(virt_cpv)
+ eapi, iuse, rdepend, use = vardb.aux_get(virt_cpv,
+ ["EAPI", "IUSE", "RDEPEND", "USE"])
+ if not portage.eapi_is_supported(eapi):
+ yield atom
+ continue
+
+ # Validate IUSE and IUSE, for early detection of vardb corruption.
+ useflag_re = _get_useflag_re(eapi)
+ valid_iuse = []
+ for x in iuse.split():
+ if x[:1] in ("+", "-"):
+ x = x[1:]
+ if useflag_re.match(x) is not None:
+ valid_iuse.append(x)
+ valid_iuse = frozenset(valid_iuse)
+
+ iuse_implicit_match = vardb.settings._iuse_implicit_match
+ valid_use = []
+ for x in use.split():
+ if x in valid_iuse or iuse_implicit_match(x):
+ valid_use.append(x)
+ valid_use = frozenset(valid_use)
+
+ success, atoms = portage.dep_check(rdepend,
+ None, vardb.settings, myuse=valid_use,
+ myroot=vardb.root, trees={vardb.root:{"porttree":vardb.vartree,
+ "vartree":vardb.vartree}})
+
+ if success:
+ stack.extend(atoms)
+ else:
+ yield atom
diff --git a/portage_with_autodep/pym/portage/dbapi/bintree.py b/portage_with_autodep/pym/portage/dbapi/bintree.py
new file mode 100644
index 0000000..62fc623
--- /dev/null
+++ b/portage_with_autodep/pym/portage/dbapi/bintree.py
@@ -0,0 +1,1366 @@
+# Copyright 1998-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ["bindbapi", "binarytree"]
+
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.checksum:hashfunc_map,perform_multiple_checksums,verify_all',
+ 'portage.dbapi.dep_expand:dep_expand',
+ 'portage.dep:dep_getkey,isjustname,match_from_list',
+ 'portage.output:EOutput,colorize',
+ 'portage.locks:lockfile,unlockfile',
+ 'portage.package.ebuild.doebuild:_vdb_use_conditional_atoms',
+ 'portage.package.ebuild.fetch:_check_distfile',
+ 'portage.update:update_dbentries',
+ 'portage.util:atomic_ofstream,ensure_dirs,normalize_path,' + \
+ 'writemsg,writemsg_stdout',
+ 'portage.util.listdir:listdir',
+ 'portage.versions:best,catpkgsplit,catsplit',
+)
+
+from portage.cache.mappings import slot_dict_class
+from portage.const import CACHE_PATH
+from portage.dbapi.virtual import fakedbapi
+from portage.dep import Atom, use_reduce, paren_enclose
+from portage.exception import AlarmSignal, InvalidPackageName, \
+ PermissionDenied, PortageException
+from portage.localization import _
+from portage import _movefile
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+
+import codecs
+import errno
+import io
+import re
+import stat
+import subprocess
+import sys
+import tempfile
+import textwrap
+from itertools import chain
+try:
+ from urllib.parse import urlparse
+ from urllib.request import urlopen as urllib_request_urlopen
+except ImportError:
+ from urlparse import urlparse
+ from urllib import urlopen as urllib_request_urlopen
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+ long = int
+
+class bindbapi(fakedbapi):
+ _known_keys = frozenset(list(fakedbapi._known_keys) + \
+ ["CHOST", "repository", "USE"])
+ def __init__(self, mybintree=None, **kwargs):
+ fakedbapi.__init__(self, **kwargs)
+ self.bintree = mybintree
+ self.move_ent = mybintree.move_ent
+ self.cpvdict={}
+ self.cpdict={}
+ # Selectively cache metadata in order to optimize dep matching.
+ self._aux_cache_keys = set(
+ ["BUILD_TIME", "CHOST", "DEPEND", "EAPI", "IUSE", "KEYWORDS",
+ "LICENSE", "PDEPEND", "PROPERTIES", "PROVIDE",
+ "RDEPEND", "repository", "RESTRICT", "SLOT", "USE", "DEFINED_PHASES",
+ "REQUIRED_USE"])
+ self._aux_cache_slot_dict = slot_dict_class(self._aux_cache_keys)
+ self._aux_cache = {}
+
+ def match(self, *pargs, **kwargs):
+ if self.bintree and not self.bintree.populated:
+ self.bintree.populate()
+ return fakedbapi.match(self, *pargs, **kwargs)
+
+ def cpv_exists(self, cpv, myrepo=None):
+ if self.bintree and not self.bintree.populated:
+ self.bintree.populate()
+ return fakedbapi.cpv_exists(self, cpv)
+
+ def cpv_inject(self, cpv, **kwargs):
+ self._aux_cache.pop(cpv, None)
+ fakedbapi.cpv_inject(self, cpv, **kwargs)
+
+ def cpv_remove(self, cpv):
+ self._aux_cache.pop(cpv, None)
+ fakedbapi.cpv_remove(self, cpv)
+
+ def aux_get(self, mycpv, wants, myrepo=None):
+ if self.bintree and not self.bintree.populated:
+ self.bintree.populate()
+ cache_me = False
+ if not self._known_keys.intersection(
+ wants).difference(self._aux_cache_keys):
+ aux_cache = self._aux_cache.get(mycpv)
+ if aux_cache is not None:
+ return [aux_cache.get(x, "") for x in wants]
+ cache_me = True
+ mysplit = mycpv.split("/")
+ mylist = []
+ tbz2name = mysplit[1]+".tbz2"
+ if not self.bintree._remotepkgs or \
+ not self.bintree.isremote(mycpv):
+ tbz2_path = self.bintree.getname(mycpv)
+ if not os.path.exists(tbz2_path):
+ raise KeyError(mycpv)
+ metadata_bytes = portage.xpak.tbz2(tbz2_path).get_data()
+ def getitem(k):
+ v = metadata_bytes.get(_unicode_encode(k,
+ encoding=_encodings['repo.content'],
+ errors='backslashreplace'))
+ if v is not None:
+ v = _unicode_decode(v,
+ encoding=_encodings['repo.content'], errors='replace')
+ return v
+ else:
+ getitem = self.bintree._remotepkgs[mycpv].get
+ mydata = {}
+ mykeys = wants
+ if cache_me:
+ mykeys = self._aux_cache_keys.union(wants)
+ for x in mykeys:
+ myval = getitem(x)
+ # myval is None if the key doesn't exist
+ # or the tbz2 is corrupt.
+ if myval:
+ mydata[x] = " ".join(myval.split())
+
+ if not mydata.setdefault('EAPI', _unicode_decode('0')):
+ mydata['EAPI'] = _unicode_decode('0')
+
+ if cache_me:
+ aux_cache = self._aux_cache_slot_dict()
+ for x in self._aux_cache_keys:
+ aux_cache[x] = mydata.get(x, _unicode_decode(''))
+ self._aux_cache[mycpv] = aux_cache
+ return [mydata.get(x, _unicode_decode('')) for x in wants]
+
+ def aux_update(self, cpv, values):
+ if not self.bintree.populated:
+ self.bintree.populate()
+ tbz2path = self.bintree.getname(cpv)
+ if not os.path.exists(tbz2path):
+ raise KeyError(cpv)
+ mytbz2 = portage.xpak.tbz2(tbz2path)
+ mydata = mytbz2.get_data()
+
+ for k, v in values.items():
+ k = _unicode_encode(k,
+ encoding=_encodings['repo.content'], errors='backslashreplace')
+ v = _unicode_encode(v,
+ encoding=_encodings['repo.content'], errors='backslashreplace')
+ mydata[k] = v
+
+ for k, v in list(mydata.items()):
+ if not v:
+ del mydata[k]
+ mytbz2.recompose_mem(portage.xpak.xpak_mem(mydata))
+ # inject will clear stale caches via cpv_inject.
+ self.bintree.inject(cpv)
+
+ def cp_list(self, *pargs, **kwargs):
+ if not self.bintree.populated:
+ self.bintree.populate()
+ return fakedbapi.cp_list(self, *pargs, **kwargs)
+
+ def cp_all(self):
+ if not self.bintree.populated:
+ self.bintree.populate()
+ return fakedbapi.cp_all(self)
+
+ def cpv_all(self):
+ if not self.bintree.populated:
+ self.bintree.populate()
+ return fakedbapi.cpv_all(self)
+
+def _pkgindex_cpv_map_latest_build(pkgindex):
+ """
+ Given a PackageIndex instance, create a dict of cpv -> metadata map.
+ If multiple packages have identical CPV values, prefer the package
+ with latest BUILD_TIME value.
+ @param pkgindex: A PackageIndex instance.
+ @type pkgindex: PackageIndex
+ @rtype: dict
+ @returns: a dict containing entry for the give cpv.
+ """
+ cpv_map = {}
+
+ for d in pkgindex.packages:
+ cpv = d["CPV"]
+
+ btime = d.get('BUILD_TIME', '')
+ try:
+ btime = int(btime)
+ except ValueError:
+ btime = None
+
+ other_d = cpv_map.get(cpv)
+ if other_d is not None:
+ other_btime = other_d.get('BUILD_TIME', '')
+ try:
+ other_btime = int(other_btime)
+ except ValueError:
+ other_btime = None
+ if other_btime and (not btime or other_btime > btime):
+ continue
+
+ cpv_map[cpv] = d
+
+ return cpv_map
+
+class binarytree(object):
+ "this tree scans for a list of all packages available in PKGDIR"
+ def __init__(self, root, pkgdir, virtual=None, settings=None):
+ if True:
+ self.root = root
+ #self.pkgdir=settings["PKGDIR"]
+ self.pkgdir = normalize_path(pkgdir)
+ self.dbapi = bindbapi(self, settings=settings)
+ self.update_ents = self.dbapi.update_ents
+ self.move_slot_ent = self.dbapi.move_slot_ent
+ self.populated = 0
+ self.tree = {}
+ self._remote_has_index = False
+ self._remotepkgs = None # remote metadata indexed by cpv
+ self.invalids = []
+ self.settings = settings
+ self._pkg_paths = {}
+ self._pkgindex_uri = {}
+ self._populating = False
+ self._all_directory = os.path.isdir(
+ os.path.join(self.pkgdir, "All"))
+ self._pkgindex_version = 0
+ self._pkgindex_hashes = ["MD5","SHA1"]
+ self._pkgindex_file = os.path.join(self.pkgdir, "Packages")
+ self._pkgindex_keys = self.dbapi._aux_cache_keys.copy()
+ self._pkgindex_keys.update(["CPV", "MTIME", "SIZE"])
+ self._pkgindex_aux_keys = \
+ ["BUILD_TIME", "CHOST", "DEPEND", "DESCRIPTION", "EAPI",
+ "IUSE", "KEYWORDS", "LICENSE", "PDEPEND", "PROPERTIES",
+ "PROVIDE", "RDEPEND", "repository", "SLOT", "USE", "DEFINED_PHASES",
+ "REQUIRED_USE", "BASE_URI"]
+ self._pkgindex_aux_keys = list(self._pkgindex_aux_keys)
+ self._pkgindex_use_evaluated_keys = \
+ ("LICENSE", "RDEPEND", "DEPEND",
+ "PDEPEND", "PROPERTIES", "PROVIDE")
+ self._pkgindex_header_keys = set([
+ "ACCEPT_KEYWORDS", "ACCEPT_LICENSE",
+ "ACCEPT_PROPERTIES", "CBUILD",
+ "CONFIG_PROTECT", "CONFIG_PROTECT_MASK", "FEATURES",
+ "GENTOO_MIRRORS", "INSTALL_MASK", "SYNC", "USE"])
+ self._pkgindex_default_pkg_data = {
+ "BUILD_TIME" : "",
+ "DEPEND" : "",
+ "EAPI" : "0",
+ "IUSE" : "",
+ "KEYWORDS": "",
+ "LICENSE" : "",
+ "PATH" : "",
+ "PDEPEND" : "",
+ "PROPERTIES" : "",
+ "PROVIDE" : "",
+ "RDEPEND" : "",
+ "RESTRICT": "",
+ "SLOT" : "0",
+ "USE" : "",
+ "DEFINED_PHASES" : "",
+ "REQUIRED_USE" : ""
+ }
+ self._pkgindex_inherited_keys = ["CHOST", "repository"]
+
+ # Populate the header with appropriate defaults.
+ self._pkgindex_default_header_data = {
+ "CHOST" : self.settings.get("CHOST", ""),
+ "repository" : "",
+ }
+
+ # It is especially important to populate keys like
+ # "repository" that save space when entries can
+ # inherit them from the header. If an existing
+ # pkgindex header already defines these keys, then
+ # they will appropriately override our defaults.
+ main_repo = self.settings.repositories.mainRepo()
+ if main_repo is not None and not main_repo.missing_repo_name:
+ self._pkgindex_default_header_data["repository"] = \
+ main_repo.name
+
+ self._pkgindex_translated_keys = (
+ ("DESCRIPTION" , "DESC"),
+ ("repository" , "REPO"),
+ )
+
+ self._pkgindex_allowed_pkg_keys = set(chain(
+ self._pkgindex_keys,
+ self._pkgindex_aux_keys,
+ self._pkgindex_hashes,
+ self._pkgindex_default_pkg_data,
+ self._pkgindex_inherited_keys,
+ chain(*self._pkgindex_translated_keys)
+ ))
+
+ def move_ent(self, mylist, repo_match=None):
+ if not self.populated:
+ self.populate()
+ origcp = mylist[1]
+ newcp = mylist[2]
+ # sanity check
+ for atom in (origcp, newcp):
+ if not isjustname(atom):
+ raise InvalidPackageName(str(atom))
+ mynewcat = catsplit(newcp)[0]
+ origmatches=self.dbapi.cp_list(origcp)
+ moves = 0
+ if not origmatches:
+ return moves
+ for mycpv in origmatches:
+ mycpv_cp = portage.cpv_getkey(mycpv)
+ if mycpv_cp != origcp:
+ # Ignore PROVIDE virtual match.
+ continue
+ if repo_match is not None \
+ and not repo_match(self.dbapi.aux_get(mycpv,
+ ['repository'])[0]):
+ continue
+ mynewcpv = mycpv.replace(mycpv_cp, str(newcp), 1)
+ myoldpkg = catsplit(mycpv)[1]
+ mynewpkg = catsplit(mynewcpv)[1]
+
+ if (mynewpkg != myoldpkg) and os.path.exists(self.getname(mynewcpv)):
+ writemsg(_("!!! Cannot update binary: Destination exists.\n"),
+ noiselevel=-1)
+ writemsg("!!! "+mycpv+" -> "+mynewcpv+"\n", noiselevel=-1)
+ continue
+
+ tbz2path = self.getname(mycpv)
+ if os.path.exists(tbz2path) and not os.access(tbz2path,os.W_OK):
+ writemsg(_("!!! Cannot update readonly binary: %s\n") % mycpv,
+ noiselevel=-1)
+ continue
+
+ moves += 1
+ mytbz2 = portage.xpak.tbz2(tbz2path)
+ mydata = mytbz2.get_data()
+ updated_items = update_dbentries([mylist], mydata)
+ mydata.update(updated_items)
+ mydata[b'PF'] = \
+ _unicode_encode(mynewpkg + "\n",
+ encoding=_encodings['repo.content'])
+ mydata[b'CATEGORY'] = \
+ _unicode_encode(mynewcat + "\n",
+ encoding=_encodings['repo.content'])
+ if mynewpkg != myoldpkg:
+ ebuild_data = mydata.pop(_unicode_encode(myoldpkg + '.ebuild',
+ encoding=_encodings['repo.content']), None)
+ if ebuild_data is not None:
+ mydata[_unicode_encode(mynewpkg + '.ebuild',
+ encoding=_encodings['repo.content'])] = ebuild_data
+
+ mytbz2.recompose_mem(portage.xpak.xpak_mem(mydata))
+
+ self.dbapi.cpv_remove(mycpv)
+ del self._pkg_paths[mycpv]
+ new_path = self.getname(mynewcpv)
+ self._pkg_paths[mynewcpv] = os.path.join(
+ *new_path.split(os.path.sep)[-2:])
+ if new_path != mytbz2:
+ self._ensure_dir(os.path.dirname(new_path))
+ _movefile(tbz2path, new_path, mysettings=self.settings)
+ self._remove_symlink(mycpv)
+ if new_path.split(os.path.sep)[-2] == "All":
+ self._create_symlink(mynewcpv)
+ self.inject(mynewcpv)
+
+ return moves
+
+ def _remove_symlink(self, cpv):
+ """Remove a ${PKGDIR}/${CATEGORY}/${PF}.tbz2 symlink and also remove
+ the ${PKGDIR}/${CATEGORY} directory if empty. The file will not be
+ removed if os.path.islink() returns False."""
+ mycat, mypkg = catsplit(cpv)
+ mylink = os.path.join(self.pkgdir, mycat, mypkg + ".tbz2")
+ if os.path.islink(mylink):
+ """Only remove it if it's really a link so that this method never
+ removes a real package that was placed here to avoid a collision."""
+ os.unlink(mylink)
+ try:
+ os.rmdir(os.path.join(self.pkgdir, mycat))
+ except OSError as e:
+ if e.errno not in (errno.ENOENT,
+ errno.ENOTEMPTY, errno.EEXIST):
+ raise
+ del e
+
+ def _create_symlink(self, cpv):
+ """Create a ${PKGDIR}/${CATEGORY}/${PF}.tbz2 symlink (and
+ ${PKGDIR}/${CATEGORY} directory, if necessary). Any file that may
+ exist in the location of the symlink will first be removed."""
+ mycat, mypkg = catsplit(cpv)
+ full_path = os.path.join(self.pkgdir, mycat, mypkg + ".tbz2")
+ self._ensure_dir(os.path.dirname(full_path))
+ try:
+ os.unlink(full_path)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ os.symlink(os.path.join("..", "All", mypkg + ".tbz2"), full_path)
+
+ def prevent_collision(self, cpv):
+ """Make sure that the file location ${PKGDIR}/All/${PF}.tbz2 is safe to
+ use for a given cpv. If a collision will occur with an existing
+ package from another category, the existing package will be bumped to
+ ${PKGDIR}/${CATEGORY}/${PF}.tbz2 so that both can coexist."""
+ if not self._all_directory:
+ return
+
+ # Copy group permissions for new directories that
+ # may have been created.
+ for path in ("All", catsplit(cpv)[0]):
+ path = os.path.join(self.pkgdir, path)
+ self._ensure_dir(path)
+ if not os.access(path, os.W_OK):
+ raise PermissionDenied("access('%s', W_OK)" % path)
+
+ full_path = self.getname(cpv)
+ if "All" == full_path.split(os.path.sep)[-2]:
+ return
+ """Move a colliding package if it exists. Code below this point only
+ executes in rare cases."""
+ mycat, mypkg = catsplit(cpv)
+ myfile = mypkg + ".tbz2"
+ mypath = os.path.join("All", myfile)
+ dest_path = os.path.join(self.pkgdir, mypath)
+
+ try:
+ st = os.lstat(dest_path)
+ except OSError:
+ st = None
+ else:
+ if stat.S_ISLNK(st.st_mode):
+ st = None
+ try:
+ os.unlink(dest_path)
+ except OSError:
+ if os.path.exists(dest_path):
+ raise
+
+ if st is not None:
+ # For invalid packages, other_cat could be None.
+ other_cat = portage.xpak.tbz2(dest_path).getfile(b"CATEGORY")
+ if other_cat:
+ other_cat = _unicode_decode(other_cat,
+ encoding=_encodings['repo.content'], errors='replace')
+ other_cat = other_cat.strip()
+ other_cpv = other_cat + "/" + mypkg
+ self._move_from_all(other_cpv)
+ self.inject(other_cpv)
+ self._move_to_all(cpv)
+
+ def _ensure_dir(self, path):
+ """
+ Create the specified directory. Also, copy gid and group mode
+ bits from self.pkgdir if possible.
+ @param cat_dir: Absolute path of the directory to be created.
+ @type cat_dir: String
+ """
+ try:
+ pkgdir_st = os.stat(self.pkgdir)
+ except OSError:
+ ensure_dirs(path)
+ return
+ pkgdir_gid = pkgdir_st.st_gid
+ pkgdir_grp_mode = 0o2070 & pkgdir_st.st_mode
+ try:
+ ensure_dirs(path, gid=pkgdir_gid, mode=pkgdir_grp_mode, mask=0)
+ except PortageException:
+ if not os.path.isdir(path):
+ raise
+
+ def _move_to_all(self, cpv):
+ """If the file exists, move it. Whether or not it exists, update state
+ for future getname() calls."""
+ mycat, mypkg = catsplit(cpv)
+ myfile = mypkg + ".tbz2"
+ self._pkg_paths[cpv] = os.path.join("All", myfile)
+ src_path = os.path.join(self.pkgdir, mycat, myfile)
+ try:
+ mystat = os.lstat(src_path)
+ except OSError as e:
+ mystat = None
+ if mystat and stat.S_ISREG(mystat.st_mode):
+ self._ensure_dir(os.path.join(self.pkgdir, "All"))
+ dest_path = os.path.join(self.pkgdir, "All", myfile)
+ _movefile(src_path, dest_path, mysettings=self.settings)
+ self._create_symlink(cpv)
+ self.inject(cpv)
+
+ def _move_from_all(self, cpv):
+ """Move a package from ${PKGDIR}/All/${PF}.tbz2 to
+ ${PKGDIR}/${CATEGORY}/${PF}.tbz2 and update state from getname calls."""
+ self._remove_symlink(cpv)
+ mycat, mypkg = catsplit(cpv)
+ myfile = mypkg + ".tbz2"
+ mypath = os.path.join(mycat, myfile)
+ dest_path = os.path.join(self.pkgdir, mypath)
+ self._ensure_dir(os.path.dirname(dest_path))
+ src_path = os.path.join(self.pkgdir, "All", myfile)
+ _movefile(src_path, dest_path, mysettings=self.settings)
+ self._pkg_paths[cpv] = mypath
+
+ def populate(self, getbinpkgs=0):
+ "populates the binarytree"
+
+ if self._populating:
+ return
+
+ pkgindex_lock = None
+ try:
+ if os.access(self.pkgdir, os.W_OK):
+ pkgindex_lock = lockfile(self._pkgindex_file,
+ wantnewlockfile=1)
+ self._populating = True
+ self._populate(getbinpkgs)
+ finally:
+ if pkgindex_lock:
+ unlockfile(pkgindex_lock)
+ self._populating = False
+
+ def _populate(self, getbinpkgs=0):
+ if (not os.path.isdir(self.pkgdir) and not getbinpkgs):
+ return 0
+
+ # Clear all caches in case populate is called multiple times
+ # as may be the case when _global_updates calls populate()
+ # prior to performing package moves since it only wants to
+ # operate on local packages (getbinpkgs=0).
+ self._remotepkgs = None
+ self.dbapi._clear_cache()
+ self.dbapi._aux_cache.clear()
+ if True:
+ pkg_paths = {}
+ self._pkg_paths = pkg_paths
+ dirs = listdir(self.pkgdir, dirsonly=True, EmptyOnError=True)
+ if "All" in dirs:
+ dirs.remove("All")
+ dirs.sort()
+ dirs.insert(0, "All")
+ pkgindex = self._load_pkgindex()
+ pf_index = None
+ if not self._pkgindex_version_supported(pkgindex):
+ pkgindex = self._new_pkgindex()
+ header = pkgindex.header
+ metadata = {}
+ for d in pkgindex.packages:
+ metadata[d["CPV"]] = d
+ update_pkgindex = False
+ for mydir in dirs:
+ for myfile in listdir(os.path.join(self.pkgdir, mydir)):
+ if not myfile.endswith(".tbz2"):
+ continue
+ mypath = os.path.join(mydir, myfile)
+ full_path = os.path.join(self.pkgdir, mypath)
+ s = os.lstat(full_path)
+ if stat.S_ISLNK(s.st_mode):
+ continue
+
+ # Validate data from the package index and try to avoid
+ # reading the xpak if possible.
+ if mydir != "All":
+ possibilities = None
+ d = metadata.get(mydir+"/"+myfile[:-5])
+ if d:
+ possibilities = [d]
+ else:
+ if pf_index is None:
+ pf_index = {}
+ for mycpv in metadata:
+ mycat, mypf = catsplit(mycpv)
+ pf_index.setdefault(
+ mypf, []).append(metadata[mycpv])
+ possibilities = pf_index.get(myfile[:-5])
+ if possibilities:
+ match = None
+ for d in possibilities:
+ try:
+ if long(d["MTIME"]) != s[stat.ST_MTIME]:
+ continue
+ except (KeyError, ValueError):
+ continue
+ try:
+ if long(d["SIZE"]) != long(s.st_size):
+ continue
+ except (KeyError, ValueError):
+ continue
+ if not self._pkgindex_keys.difference(d):
+ match = d
+ break
+ if match:
+ mycpv = match["CPV"]
+ if mycpv in pkg_paths:
+ # discard duplicates (All/ is preferred)
+ continue
+ pkg_paths[mycpv] = mypath
+ # update the path if the package has been moved
+ oldpath = d.get("PATH")
+ if oldpath and oldpath != mypath:
+ update_pkgindex = True
+ if mypath != mycpv + ".tbz2":
+ d["PATH"] = mypath
+ if not oldpath:
+ update_pkgindex = True
+ else:
+ d.pop("PATH", None)
+ if oldpath:
+ update_pkgindex = True
+ self.dbapi.cpv_inject(mycpv)
+ if not self.dbapi._aux_cache_keys.difference(d):
+ aux_cache = self.dbapi._aux_cache_slot_dict()
+ for k in self.dbapi._aux_cache_keys:
+ aux_cache[k] = d[k]
+ self.dbapi._aux_cache[mycpv] = aux_cache
+ continue
+ if not os.access(full_path, os.R_OK):
+ writemsg(_("!!! Permission denied to read " \
+ "binary package: '%s'\n") % full_path,
+ noiselevel=-1)
+ self.invalids.append(myfile[:-5])
+ continue
+ metadata_bytes = portage.xpak.tbz2(full_path).get_data()
+ mycat = _unicode_decode(metadata_bytes.get(b"CATEGORY", ""),
+ encoding=_encodings['repo.content'], errors='replace')
+ mypf = _unicode_decode(metadata_bytes.get(b"PF", ""),
+ encoding=_encodings['repo.content'], errors='replace')
+ slot = _unicode_decode(metadata_bytes.get(b"SLOT", ""),
+ encoding=_encodings['repo.content'], errors='replace')
+ mypkg = myfile[:-5]
+ if not mycat or not mypf or not slot:
+ #old-style or corrupt package
+ writemsg(_("\n!!! Invalid binary package: '%s'\n") % full_path,
+ noiselevel=-1)
+ missing_keys = []
+ if not mycat:
+ missing_keys.append("CATEGORY")
+ if not mypf:
+ missing_keys.append("PF")
+ if not slot:
+ missing_keys.append("SLOT")
+ msg = []
+ if missing_keys:
+ missing_keys.sort()
+ msg.append(_("Missing metadata key(s): %s.") % \
+ ", ".join(missing_keys))
+ msg.append(_(" This binary package is not " \
+ "recoverable and should be deleted."))
+ for line in textwrap.wrap("".join(msg), 72):
+ writemsg("!!! %s\n" % line, noiselevel=-1)
+ self.invalids.append(mypkg)
+ continue
+ mycat = mycat.strip()
+ slot = slot.strip()
+ if mycat != mydir and mydir != "All":
+ continue
+ if mypkg != mypf.strip():
+ continue
+ mycpv = mycat + "/" + mypkg
+ if mycpv in pkg_paths:
+ # All is first, so it's preferred.
+ continue
+ if not self.dbapi._category_re.match(mycat):
+ writemsg(_("!!! Binary package has an " \
+ "unrecognized category: '%s'\n") % full_path,
+ noiselevel=-1)
+ writemsg(_("!!! '%s' has a category that is not" \
+ " listed in %setc/portage/categories\n") % \
+ (mycpv, self.settings["PORTAGE_CONFIGROOT"]),
+ noiselevel=-1)
+ continue
+ pkg_paths[mycpv] = mypath
+ self.dbapi.cpv_inject(mycpv)
+ update_pkgindex = True
+ d = metadata.get(mycpv, {})
+ if d:
+ try:
+ if long(d["MTIME"]) != s[stat.ST_MTIME]:
+ d.clear()
+ except (KeyError, ValueError):
+ d.clear()
+ if d:
+ try:
+ if long(d["SIZE"]) != long(s.st_size):
+ d.clear()
+ except (KeyError, ValueError):
+ d.clear()
+
+ d["CPV"] = mycpv
+ d["SLOT"] = slot
+ d["MTIME"] = str(s[stat.ST_MTIME])
+ d["SIZE"] = str(s.st_size)
+
+ d.update(zip(self._pkgindex_aux_keys,
+ self.dbapi.aux_get(mycpv, self._pkgindex_aux_keys)))
+ try:
+ self._eval_use_flags(mycpv, d)
+ except portage.exception.InvalidDependString:
+ writemsg(_("!!! Invalid binary package: '%s'\n") % \
+ self.getname(mycpv), noiselevel=-1)
+ self.dbapi.cpv_remove(mycpv)
+ del pkg_paths[mycpv]
+
+ # record location if it's non-default
+ if mypath != mycpv + ".tbz2":
+ d["PATH"] = mypath
+ else:
+ d.pop("PATH", None)
+ metadata[mycpv] = d
+ if not self.dbapi._aux_cache_keys.difference(d):
+ aux_cache = self.dbapi._aux_cache_slot_dict()
+ for k in self.dbapi._aux_cache_keys:
+ aux_cache[k] = d[k]
+ self.dbapi._aux_cache[mycpv] = aux_cache
+
+ for cpv in list(metadata):
+ if cpv not in pkg_paths:
+ del metadata[cpv]
+
+ # Do not bother to write the Packages index if $PKGDIR/All/ exists
+ # since it will provide no benefit due to the need to read CATEGORY
+ # from xpak.
+ if update_pkgindex and os.access(self.pkgdir, os.W_OK):
+ del pkgindex.packages[:]
+ pkgindex.packages.extend(iter(metadata.values()))
+ self._update_pkgindex_header(pkgindex.header)
+ f = atomic_ofstream(self._pkgindex_file)
+ pkgindex.write(f)
+ f.close()
+
+ if getbinpkgs and not self.settings["PORTAGE_BINHOST"]:
+ writemsg(_("!!! PORTAGE_BINHOST unset, but use is requested.\n"),
+ noiselevel=-1)
+
+ if not getbinpkgs or 'PORTAGE_BINHOST' not in self.settings:
+ self.populated=1
+ return
+ self._remotepkgs = {}
+ for base_url in self.settings["PORTAGE_BINHOST"].split():
+ parsed_url = urlparse(base_url)
+ host = parsed_url.netloc
+ port = parsed_url.port
+ user = None
+ passwd = None
+ user_passwd = ""
+ if "@" in host:
+ user, host = host.split("@", 1)
+ user_passwd = user + "@"
+ if ":" in user:
+ user, passwd = user.split(":", 1)
+ port_args = []
+ if port is not None:
+ port_str = ":%s" % (port,)
+ if host.endswith(port_str):
+ host = host[:-len(port_str)]
+ pkgindex_file = os.path.join(self.settings["EROOT"], CACHE_PATH, "binhost",
+ host, parsed_url.path.lstrip("/"), "Packages")
+ pkgindex = self._new_pkgindex()
+ try:
+ f = io.open(_unicode_encode(pkgindex_file,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'],
+ errors='replace')
+ try:
+ pkgindex.read(f)
+ finally:
+ f.close()
+ except EnvironmentError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ local_timestamp = pkgindex.header.get("TIMESTAMP", None)
+ rmt_idx = self._new_pkgindex()
+ proc = None
+ tmp_filename = None
+ try:
+ # urlparse.urljoin() only works correctly with recognized
+ # protocols and requires the base url to have a trailing
+ # slash, so join manually...
+ url = base_url.rstrip("/") + "/Packages"
+ try:
+ f = urllib_request_urlopen(url)
+ except IOError:
+ path = parsed_url.path.rstrip("/") + "/Packages"
+
+ if parsed_url.scheme == 'sftp':
+ # The sftp command complains about 'Illegal seek' if
+ # we try to make it write to /dev/stdout, so use a
+ # temp file instead.
+ fd, tmp_filename = tempfile.mkstemp()
+ os.close(fd)
+ if port is not None:
+ port_args = ['-P', "%s" % (port,)]
+ proc = subprocess.Popen(['sftp'] + port_args + \
+ [user_passwd + host + ":" + path, tmp_filename])
+ if proc.wait() != os.EX_OK:
+ raise
+ f = open(tmp_filename, 'rb')
+ elif parsed_url.scheme == 'ssh':
+ if port is not None:
+ port_args = ['-p', "%s" % (port,)]
+ proc = subprocess.Popen(['ssh'] + port_args + \
+ [user_passwd + host, '--', 'cat', path],
+ stdout=subprocess.PIPE)
+ f = proc.stdout
+ else:
+ setting = 'FETCHCOMMAND_' + parsed_url.scheme.upper()
+ fcmd = self.settings.get(setting)
+ if not fcmd:
+ raise
+ fd, tmp_filename = tempfile.mkstemp()
+ tmp_dirname, tmp_basename = os.path.split(tmp_filename)
+ os.close(fd)
+ success = portage.getbinpkg.file_get(url,
+ tmp_dirname, fcmd=fcmd, filename=tmp_basename)
+ if not success:
+ raise EnvironmentError("%s failed" % (setting,))
+ f = open(tmp_filename, 'rb')
+
+ f_dec = codecs.iterdecode(f,
+ _encodings['repo.content'], errors='replace')
+ try:
+ rmt_idx.readHeader(f_dec)
+ remote_timestamp = rmt_idx.header.get("TIMESTAMP", None)
+ if not remote_timestamp:
+ # no timestamp in the header, something's wrong
+ pkgindex = None
+ writemsg(_("\n\n!!! Binhost package index " \
+ " has no TIMESTAMP field.\n"), noiselevel=-1)
+ else:
+ if not self._pkgindex_version_supported(rmt_idx):
+ writemsg(_("\n\n!!! Binhost package index version" \
+ " is not supported: '%s'\n") % \
+ rmt_idx.header.get("VERSION"), noiselevel=-1)
+ pkgindex = None
+ elif local_timestamp != remote_timestamp:
+ rmt_idx.readBody(f_dec)
+ pkgindex = rmt_idx
+ finally:
+ # Timeout after 5 seconds, in case close() blocks
+ # indefinitely (see bug #350139).
+ try:
+ try:
+ AlarmSignal.register(5)
+ f.close()
+ finally:
+ AlarmSignal.unregister()
+ except AlarmSignal:
+ writemsg("\n\n!!! %s\n" % \
+ _("Timed out while closing connection to binhost"),
+ noiselevel=-1)
+ except EnvironmentError as e:
+ writemsg(_("\n\n!!! Error fetching binhost package" \
+ " info from '%s'\n") % base_url)
+ writemsg("!!! %s\n\n" % str(e))
+ del e
+ pkgindex = None
+ if proc is not None:
+ if proc.poll() is None:
+ proc.kill()
+ proc.wait()
+ proc = None
+ if tmp_filename is not None:
+ try:
+ os.unlink(tmp_filename)
+ except OSError:
+ pass
+ if pkgindex is rmt_idx:
+ pkgindex.modified = False # don't update the header
+ try:
+ ensure_dirs(os.path.dirname(pkgindex_file))
+ f = atomic_ofstream(pkgindex_file)
+ pkgindex.write(f)
+ f.close()
+ except (IOError, PortageException):
+ if os.access(os.path.dirname(pkgindex_file), os.W_OK):
+ raise
+ # The current user doesn't have permission to cache the
+ # file, but that's alright.
+ if pkgindex:
+ # Organize remote package list as a cpv -> metadata map.
+ remotepkgs = _pkgindex_cpv_map_latest_build(pkgindex)
+ remote_base_uri = pkgindex.header.get("URI", base_url)
+ for cpv, remote_metadata in remotepkgs.items():
+ remote_metadata["BASE_URI"] = remote_base_uri
+ self._pkgindex_uri[cpv] = url
+ self._remotepkgs.update(remotepkgs)
+ self._remote_has_index = True
+ for cpv in remotepkgs:
+ self.dbapi.cpv_inject(cpv)
+ if True:
+ # Remote package instances override local package
+ # if they are not identical.
+ hash_names = ["SIZE"] + self._pkgindex_hashes
+ for cpv, local_metadata in metadata.items():
+ remote_metadata = self._remotepkgs.get(cpv)
+ if remote_metadata is None:
+ continue
+ # Use digests to compare identity.
+ identical = True
+ for hash_name in hash_names:
+ local_value = local_metadata.get(hash_name)
+ if local_value is None:
+ continue
+ remote_value = remote_metadata.get(hash_name)
+ if remote_value is None:
+ continue
+ if local_value != remote_value:
+ identical = False
+ break
+ if identical:
+ del self._remotepkgs[cpv]
+ else:
+ # Override the local package in the aux_get cache.
+ self.dbapi._aux_cache[cpv] = remote_metadata
+ else:
+ # Local package instances override remote instances.
+ for cpv in metadata:
+ self._remotepkgs.pop(cpv, None)
+ continue
+ try:
+ chunk_size = long(self.settings["PORTAGE_BINHOST_CHUNKSIZE"])
+ if chunk_size < 8:
+ chunk_size = 8
+ except (ValueError, KeyError):
+ chunk_size = 3000
+ writemsg_stdout("\n")
+ writemsg_stdout(
+ colorize("GOOD", _("Fetching bininfo from ")) + \
+ re.sub(r'//(.+):.+@(.+)/', r'//\1:*password*@\2/', base_url) + "\n")
+ remotepkgs = portage.getbinpkg.dir_get_metadata(
+ base_url, chunk_size=chunk_size)
+
+ for mypkg, remote_metadata in remotepkgs.items():
+ mycat = remote_metadata.get("CATEGORY")
+ if mycat is None:
+ #old-style or corrupt package
+ writemsg(_("!!! Invalid remote binary package: %s\n") % mypkg,
+ noiselevel=-1)
+ continue
+ mycat = mycat.strip()
+ fullpkg = mycat+"/"+mypkg[:-5]
+
+ if fullpkg in metadata:
+ # When using this old protocol, comparison with the remote
+ # package isn't supported, so the local package is always
+ # preferred even if getbinpkgsonly is enabled.
+ continue
+
+ if not self.dbapi._category_re.match(mycat):
+ writemsg(_("!!! Remote binary package has an " \
+ "unrecognized category: '%s'\n") % fullpkg,
+ noiselevel=-1)
+ writemsg(_("!!! '%s' has a category that is not" \
+ " listed in %setc/portage/categories\n") % \
+ (fullpkg, self.settings["PORTAGE_CONFIGROOT"]),
+ noiselevel=-1)
+ continue
+ mykey = portage.cpv_getkey(fullpkg)
+ try:
+ # invalid tbz2's can hurt things.
+ self.dbapi.cpv_inject(fullpkg)
+ for k, v in remote_metadata.items():
+ remote_metadata[k] = v.strip()
+ remote_metadata["BASE_URI"] = base_url
+
+ # Eliminate metadata values with names that digestCheck
+ # uses, since they are not valid when using the old
+ # protocol. Typically this is needed for SIZE metadata
+ # which corresponds to the size of the unpacked files
+ # rather than the binpkg file size, triggering digest
+ # verification failures as reported in bug #303211.
+ remote_metadata.pop('SIZE', None)
+ for k in portage.checksum.hashfunc_map:
+ remote_metadata.pop(k, None)
+
+ self._remotepkgs[fullpkg] = remote_metadata
+ except SystemExit as e:
+ raise
+ except:
+ writemsg(_("!!! Failed to inject remote binary package: %s\n") % fullpkg,
+ noiselevel=-1)
+ continue
+ self.populated=1
+
+ def inject(self, cpv, filename=None):
+ """Add a freshly built package to the database. This updates
+ $PKGDIR/Packages with the new package metadata (including MD5).
+ @param cpv: The cpv of the new package to inject
+ @type cpv: string
+ @param filename: File path of the package to inject, or None if it's
+ already in the location returned by getname()
+ @type filename: string
+ @rtype: None
+ """
+ mycat, mypkg = catsplit(cpv)
+ if not self.populated:
+ self.populate()
+ if filename is None:
+ full_path = self.getname(cpv)
+ else:
+ full_path = filename
+ try:
+ s = os.stat(full_path)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ writemsg(_("!!! Binary package does not exist: '%s'\n") % full_path,
+ noiselevel=-1)
+ return
+ mytbz2 = portage.xpak.tbz2(full_path)
+ slot = mytbz2.getfile("SLOT")
+ if slot is None:
+ writemsg(_("!!! Invalid binary package: '%s'\n") % full_path,
+ noiselevel=-1)
+ return
+ slot = slot.strip()
+ self.dbapi.cpv_inject(cpv)
+
+ # Reread the Packages index (in case it's been changed by another
+ # process) and then updated it, all while holding a lock.
+ pkgindex_lock = None
+ created_symlink = False
+ try:
+ pkgindex_lock = lockfile(self._pkgindex_file,
+ wantnewlockfile=1)
+ if filename is not None:
+ new_filename = self.getname(cpv)
+ try:
+ samefile = os.path.samefile(filename, new_filename)
+ except OSError:
+ samefile = False
+ if not samefile:
+ self._ensure_dir(os.path.dirname(new_filename))
+ _movefile(filename, new_filename, mysettings=self.settings)
+ if self._all_directory and \
+ self.getname(cpv).split(os.path.sep)[-2] == "All":
+ self._create_symlink(cpv)
+ created_symlink = True
+ pkgindex = self._load_pkgindex()
+
+ if not self._pkgindex_version_supported(pkgindex):
+ pkgindex = self._new_pkgindex()
+
+ # Discard remote metadata to ensure that _pkgindex_entry
+ # gets the local metadata. This also updates state for future
+ # isremote calls.
+ if self._remotepkgs is not None:
+ self._remotepkgs.pop(cpv, None)
+
+ # Discard cached metadata to ensure that _pkgindex_entry
+ # doesn't return stale metadata.
+ self.dbapi._aux_cache.pop(cpv, None)
+
+ try:
+ d = self._pkgindex_entry(cpv)
+ except portage.exception.InvalidDependString:
+ writemsg(_("!!! Invalid binary package: '%s'\n") % \
+ self.getname(cpv), noiselevel=-1)
+ self.dbapi.cpv_remove(cpv)
+ del self._pkg_paths[cpv]
+ return
+
+ # If found, remove package(s) with duplicate path.
+ path = d.get("PATH", "")
+ for i in range(len(pkgindex.packages) - 1, -1, -1):
+ d2 = pkgindex.packages[i]
+ if path and path == d2.get("PATH"):
+ # Handle path collisions in $PKGDIR/All
+ # when CPV is not identical.
+ del pkgindex.packages[i]
+ elif cpv == d2.get("CPV"):
+ if path == d2.get("PATH", ""):
+ del pkgindex.packages[i]
+ elif created_symlink and not d2.get("PATH", ""):
+ # Delete entry for the package that was just
+ # overwritten by a symlink to this package.
+ del pkgindex.packages[i]
+
+ pkgindex.packages.append(d)
+
+ self._update_pkgindex_header(pkgindex.header)
+ f = atomic_ofstream(os.path.join(self.pkgdir, "Packages"))
+ pkgindex.write(f)
+ f.close()
+ finally:
+ if pkgindex_lock:
+ unlockfile(pkgindex_lock)
+
+ def _pkgindex_entry(self, cpv):
+ """
+ Performs checksums and evaluates USE flag conditionals.
+ Raises InvalidDependString if necessary.
+ @rtype: dict
+ @returns: a dict containing entry for the give cpv.
+ """
+
+ pkg_path = self.getname(cpv)
+
+ d = dict(zip(self._pkgindex_aux_keys,
+ self.dbapi.aux_get(cpv, self._pkgindex_aux_keys)))
+
+ d.update(perform_multiple_checksums(
+ pkg_path, hashes=self._pkgindex_hashes))
+
+ d["CPV"] = cpv
+ st = os.stat(pkg_path)
+ d["MTIME"] = str(st[stat.ST_MTIME])
+ d["SIZE"] = str(st.st_size)
+
+ rel_path = self._pkg_paths[cpv]
+ # record location if it's non-default
+ if rel_path != cpv + ".tbz2":
+ d["PATH"] = rel_path
+
+ self._eval_use_flags(cpv, d)
+ return d
+
+ def _new_pkgindex(self):
+ return portage.getbinpkg.PackageIndex(
+ allowed_pkg_keys=self._pkgindex_allowed_pkg_keys,
+ default_header_data=self._pkgindex_default_header_data,
+ default_pkg_data=self._pkgindex_default_pkg_data,
+ inherited_keys=self._pkgindex_inherited_keys,
+ translated_keys=self._pkgindex_translated_keys)
+
+ def _update_pkgindex_header(self, header):
+ portdir = normalize_path(os.path.realpath(self.settings["PORTDIR"]))
+ profiles_base = os.path.join(portdir, "profiles") + os.path.sep
+ if self.settings.profile_path:
+ profile_path = normalize_path(
+ os.path.realpath(self.settings.profile_path))
+ if profile_path.startswith(profiles_base):
+ profile_path = profile_path[len(profiles_base):]
+ header["PROFILE"] = profile_path
+ header["VERSION"] = str(self._pkgindex_version)
+ base_uri = self.settings.get("PORTAGE_BINHOST_HEADER_URI")
+ if base_uri:
+ header["URI"] = base_uri
+ else:
+ header.pop("URI", None)
+ for k in self._pkgindex_header_keys:
+ v = self.settings.get(k, None)
+ if v:
+ header[k] = v
+ else:
+ header.pop(k, None)
+
+ def _pkgindex_version_supported(self, pkgindex):
+ version = pkgindex.header.get("VERSION")
+ if version:
+ try:
+ if int(version) <= self._pkgindex_version:
+ return True
+ except ValueError:
+ pass
+ return False
+
+ def _eval_use_flags(self, cpv, metadata):
+ use = frozenset(metadata["USE"].split())
+ raw_use = use
+ iuse = set(f.lstrip("-+") for f in metadata["IUSE"].split())
+ use = [f for f in use if f in iuse]
+ use.sort()
+ metadata["USE"] = " ".join(use)
+ for k in self._pkgindex_use_evaluated_keys:
+ if k.endswith('DEPEND'):
+ token_class = Atom
+ else:
+ token_class = None
+
+ try:
+ deps = metadata[k]
+ deps = use_reduce(deps, uselist=raw_use, token_class=token_class)
+ deps = paren_enclose(deps)
+ except portage.exception.InvalidDependString as e:
+ writemsg("%s: %s\n" % (k, str(e)),
+ noiselevel=-1)
+ raise
+ metadata[k] = deps
+
+ def exists_specific(self, cpv):
+ if not self.populated:
+ self.populate()
+ return self.dbapi.match(
+ dep_expand("="+cpv, mydb=self.dbapi, settings=self.settings))
+
+ def dep_bestmatch(self, mydep):
+ "compatibility method -- all matches, not just visible ones"
+ if not self.populated:
+ self.populate()
+ writemsg("\n\n", 1)
+ writemsg("mydep: %s\n" % mydep, 1)
+ mydep = dep_expand(mydep, mydb=self.dbapi, settings=self.settings)
+ writemsg("mydep: %s\n" % mydep, 1)
+ mykey = dep_getkey(mydep)
+ writemsg("mykey: %s\n" % mykey, 1)
+ mymatch = best(match_from_list(mydep,self.dbapi.cp_list(mykey)))
+ writemsg("mymatch: %s\n" % mymatch, 1)
+ if mymatch is None:
+ return ""
+ return mymatch
+
+ def getname(self, pkgname):
+ """Returns a file location for this package. The default location is
+ ${PKGDIR}/All/${PF}.tbz2, but will be ${PKGDIR}/${CATEGORY}/${PF}.tbz2
+ in the rare event of a collision. The prevent_collision() method can
+ be called to ensure that ${PKGDIR}/All/${PF}.tbz2 is available for a
+ specific cpv."""
+ if not self.populated:
+ self.populate()
+ mycpv = pkgname
+ mypath = self._pkg_paths.get(mycpv, None)
+ if mypath:
+ return os.path.join(self.pkgdir, mypath)
+ mycat, mypkg = catsplit(mycpv)
+ if self._all_directory:
+ mypath = os.path.join("All", mypkg + ".tbz2")
+ if mypath in self._pkg_paths.values():
+ mypath = os.path.join(mycat, mypkg + ".tbz2")
+ else:
+ mypath = os.path.join(mycat, mypkg + ".tbz2")
+ self._pkg_paths[mycpv] = mypath # cache for future lookups
+ return os.path.join(self.pkgdir, mypath)
+
+ def isremote(self, pkgname):
+ """Returns true if the package is kept remotely and it has not been
+ downloaded (or it is only partially downloaded)."""
+ if self._remotepkgs is None or pkgname not in self._remotepkgs:
+ return False
+ # Presence in self._remotepkgs implies that it's remote. When a
+ # package is downloaded, state is updated by self.inject().
+ return True
+
+ def get_pkgindex_uri(self, pkgname):
+ """Returns the URI to the Packages file for a given package."""
+ return self._pkgindex_uri.get(pkgname)
+
+ def gettbz2(self, pkgname):
+ """Fetches the package from a remote site, if necessary. Attempts to
+ resume if the file appears to be partially downloaded."""
+ tbz2_path = self.getname(pkgname)
+ tbz2name = os.path.basename(tbz2_path)
+ resume = False
+ if os.path.exists(tbz2_path):
+ if (tbz2name not in self.invalids):
+ return
+ else:
+ resume = True
+ writemsg(_("Resuming download of this tbz2, but it is possible that it is corrupt.\n"),
+ noiselevel=-1)
+
+ mydest = os.path.dirname(self.getname(pkgname))
+ self._ensure_dir(mydest)
+ # urljoin doesn't work correctly with unrecognized protocols like sftp
+ if self._remote_has_index:
+ rel_url = self._remotepkgs[pkgname].get("PATH")
+ if not rel_url:
+ rel_url = pkgname+".tbz2"
+ remote_base_uri = self._remotepkgs[pkgname]["BASE_URI"]
+ url = remote_base_uri.rstrip("/") + "/" + rel_url.lstrip("/")
+ else:
+ url = self.settings["PORTAGE_BINHOST"].rstrip("/") + "/" + tbz2name
+ protocol = urlparse(url)[0]
+ fcmd_prefix = "FETCHCOMMAND"
+ if resume:
+ fcmd_prefix = "RESUMECOMMAND"
+ fcmd = self.settings.get(fcmd_prefix + "_" + protocol.upper())
+ if not fcmd:
+ fcmd = self.settings.get(fcmd_prefix)
+ success = portage.getbinpkg.file_get(url, mydest, fcmd=fcmd)
+ if not success:
+ try:
+ os.unlink(self.getname(pkgname))
+ except OSError:
+ pass
+ raise portage.exception.FileNotFound(mydest)
+ self.inject(pkgname)
+
+ def _load_pkgindex(self):
+ pkgindex = self._new_pkgindex()
+ try:
+ f = io.open(_unicode_encode(self._pkgindex_file,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'],
+ errors='replace')
+ except EnvironmentError:
+ pass
+ else:
+ try:
+ pkgindex.read(f)
+ finally:
+ f.close()
+ return pkgindex
+
+ def digestCheck(self, pkg):
+ """
+ Verify digests for the given package and raise DigestException
+ if verification fails.
+ @rtype: bool
+ @returns: True if digests could be located, False otherwise.
+ """
+ cpv = pkg
+ if not isinstance(cpv, basestring):
+ cpv = pkg.cpv
+ pkg = None
+
+ pkg_path = self.getname(cpv)
+ metadata = None
+ if self._remotepkgs is None or cpv not in self._remotepkgs:
+ for d in self._load_pkgindex().packages:
+ if d["CPV"] == cpv:
+ metadata = d
+ break
+ else:
+ metadata = self._remotepkgs[cpv]
+ if metadata is None:
+ return False
+
+ digests = {}
+ for k in hashfunc_map:
+ v = metadata.get(k)
+ if not v:
+ continue
+ digests[k] = v
+
+ if "SIZE" in metadata:
+ try:
+ digests["size"] = int(metadata["SIZE"])
+ except ValueError:
+ writemsg(_("!!! Malformed SIZE attribute in remote " \
+ "metadata for '%s'\n") % cpv)
+
+ if not digests:
+ return False
+
+ eout = EOutput()
+ eout.quiet = self.settings.get("PORTAGE_QUIET") == "1"
+ ok, st = _check_distfile(pkg_path, digests, eout, show_errors=0)
+ if not ok:
+ ok, reason = verify_all(pkg_path, digests)
+ if not ok:
+ raise portage.exception.DigestException(
+ (pkg_path,) + tuple(reason))
+
+ return True
+
+ def getslot(self, mycatpkg):
+ "Get a slot for a catpkg; assume it exists."
+ myslot = ""
+ try:
+ myslot = self.dbapi.aux_get(mycatpkg,["SLOT"])[0]
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ pass
+ return myslot
diff --git a/portage_with_autodep/pym/portage/dbapi/cpv_expand.py b/portage_with_autodep/pym/portage/dbapi/cpv_expand.py
new file mode 100644
index 0000000..947194c
--- /dev/null
+++ b/portage_with_autodep/pym/portage/dbapi/cpv_expand.py
@@ -0,0 +1,106 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ["cpv_expand"]
+
+import portage
+from portage.exception import AmbiguousPackageName
+from portage.localization import _
+from portage.util import writemsg
+from portage.versions import _pkgsplit
+
+def cpv_expand(mycpv, mydb=None, use_cache=1, settings=None):
+ """Given a string (packagename or virtual) expand it into a valid
+ cat/package string. Virtuals use the mydb to determine which provided
+ virtual is a valid choice and defaults to the first element when there
+ are no installed/available candidates."""
+ myslash=mycpv.split("/")
+ mysplit = _pkgsplit(myslash[-1])
+ if settings is None:
+ try:
+ settings = mydb.settings
+ except AttributeError:
+ settings = portage.settings
+ if len(myslash)>2:
+ # this is illegal case.
+ mysplit=[]
+ mykey=mycpv
+ elif len(myslash)==2:
+ if mysplit:
+ mykey=myslash[0]+"/"+mysplit[0]
+ else:
+ mykey=mycpv
+
+ # Since Gentoo stopped using old-style virtuals in
+ # 2011, typically it's possible to avoid getvirtuals()
+ # calls entirely. Therefore, only call getvirtuals()
+ # if the atom category is "virtual" and cp_list()
+ # returns nothing.
+ if mykey.startswith("virtual/") and \
+ hasattr(mydb, "cp_list") and \
+ not mydb.cp_list(mykey, use_cache=use_cache):
+ if hasattr(mydb, "vartree"):
+ settings._populate_treeVirtuals_if_needed(mydb.vartree)
+ virts = settings.getvirtuals().get(mykey)
+ if virts:
+ mykey_orig = mykey
+ for vkey in virts:
+ # The virtuals file can contain a versioned atom, so
+ # it may be necessary to remove the operator and
+ # version from the atom before it is passed into
+ # dbapi.cp_list().
+ if mydb.cp_list(vkey.cp):
+ mykey = str(vkey)
+ break
+ if mykey == mykey_orig:
+ mykey = str(virts[0])
+ #we only perform virtual expansion if we are passed a dbapi
+ else:
+ #specific cpv, no category, ie. "foo-1.0"
+ if mysplit:
+ myp=mysplit[0]
+ else:
+ # "foo" ?
+ myp=mycpv
+ mykey=None
+ matches=[]
+ if mydb and hasattr(mydb, "categories"):
+ for x in mydb.categories:
+ if mydb.cp_list(x+"/"+myp,use_cache=use_cache):
+ matches.append(x+"/"+myp)
+ if len(matches) > 1:
+ virtual_name_collision = False
+ if len(matches) == 2:
+ for x in matches:
+ if not x.startswith("virtual/"):
+ # Assume that the non-virtual is desired. This helps
+ # avoid the ValueError for invalid deps that come from
+ # installed packages (during reverse blocker detection,
+ # for example).
+ mykey = x
+ else:
+ virtual_name_collision = True
+ if not virtual_name_collision:
+ # AmbiguousPackageName inherits from ValueError,
+ # for backward compatibility with calling code
+ # that already handles ValueError.
+ raise AmbiguousPackageName(matches)
+ elif matches:
+ mykey=matches[0]
+
+ if not mykey and not isinstance(mydb, list):
+ if hasattr(mydb, "vartree"):
+ settings._populate_treeVirtuals_if_needed(mydb.vartree)
+ virts_p = settings.get_virts_p().get(myp)
+ if virts_p:
+ mykey = virts_p[0]
+ #again, we only perform virtual expansion if we have a dbapi (not a list)
+ if not mykey:
+ mykey="null/"+myp
+ if mysplit:
+ if mysplit[2]=="r0":
+ return mykey+"-"+mysplit[1]
+ else:
+ return mykey+"-"+mysplit[1]+"-"+mysplit[2]
+ else:
+ return mykey
diff --git a/portage_with_autodep/pym/portage/dbapi/dep_expand.py b/portage_with_autodep/pym/portage/dbapi/dep_expand.py
new file mode 100644
index 0000000..ac8ccf4
--- /dev/null
+++ b/portage_with_autodep/pym/portage/dbapi/dep_expand.py
@@ -0,0 +1,56 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ["dep_expand"]
+
+import re
+
+from portage.dbapi.cpv_expand import cpv_expand
+from portage.dep import Atom, isvalidatom
+from portage.exception import InvalidAtom
+from portage.versions import catsplit
+
+def dep_expand(mydep, mydb=None, use_cache=1, settings=None):
+ '''
+ @rtype: Atom
+ '''
+ orig_dep = mydep
+ if isinstance(orig_dep, Atom):
+ has_cat = True
+ else:
+ if not mydep:
+ return mydep
+ if mydep[0] == "*":
+ mydep = mydep[1:]
+ orig_dep = mydep
+ has_cat = '/' in orig_dep
+ if not has_cat:
+ alphanum = re.search(r'\w', orig_dep)
+ if alphanum:
+ mydep = orig_dep[:alphanum.start()] + "null/" + \
+ orig_dep[alphanum.start():]
+ try:
+ mydep = Atom(mydep, allow_repo=True)
+ except InvalidAtom:
+ # Missing '=' prefix is allowed for backward compatibility.
+ if not isvalidatom("=" + mydep, allow_repo=True):
+ raise
+ mydep = Atom('=' + mydep, allow_repo=True)
+ orig_dep = '=' + orig_dep
+ if not has_cat:
+ null_cat, pn = catsplit(mydep.cp)
+ mydep = pn
+
+ if has_cat:
+ # Optimize most common cases to avoid calling cpv_expand.
+ if not mydep.cp.startswith("virtual/"):
+ return mydep
+ if not hasattr(mydb, "cp_list") or \
+ mydb.cp_list(mydep.cp):
+ return mydep
+ # Fallback to legacy cpv_expand for old-style PROVIDE virtuals.
+ mydep = mydep.cp
+
+ expanded = cpv_expand(mydep, mydb=mydb,
+ use_cache=use_cache, settings=settings)
+ return Atom(orig_dep.replace(mydep, expanded, 1), allow_repo=True)
diff --git a/portage_with_autodep/pym/portage/dbapi/porttree.py b/portage_with_autodep/pym/portage/dbapi/porttree.py
new file mode 100644
index 0000000..ecf275c
--- /dev/null
+++ b/portage_with_autodep/pym/portage/dbapi/porttree.py
@@ -0,0 +1,1168 @@
+# Copyright 1998-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = [
+ "close_portdbapi_caches", "FetchlistDict", "portagetree", "portdbapi"
+]
+
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.checksum',
+ 'portage.data:portage_gid,secpass',
+ 'portage.dbapi.dep_expand:dep_expand',
+ 'portage.dep:Atom,dep_getkey,match_from_list,use_reduce',
+ 'portage.package.ebuild.doebuild:doebuild',
+ 'portage.util:ensure_dirs,shlex_split,writemsg,writemsg_level',
+ 'portage.util.listdir:listdir',
+ 'portage.versions:best,catpkgsplit,_pkgsplit@pkgsplit,ver_regexp',
+)
+
+from portage.cache import metadata_overlay, volatile
+from portage.cache.cache_errors import CacheError
+from portage.cache.mappings import Mapping
+from portage.dbapi import dbapi
+from portage.exception import PortageException, \
+ FileNotFound, InvalidAtom, InvalidDependString, InvalidPackageName
+from portage.localization import _
+from portage.manifest import Manifest
+
+from portage import eclass_cache, auxdbkeys, \
+ eapi_is_supported, dep_check, \
+ _eapi_is_deprecated
+from portage import os
+from portage import _encodings
+from portage import _unicode_encode
+from portage import OrderedDict
+from _emerge.EbuildMetadataPhase import EbuildMetadataPhase
+from _emerge.PollScheduler import PollScheduler
+
+import os as _os
+import io
+import stat
+import sys
+import traceback
+import warnings
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+ long = int
+
+class _repo_info(object):
+ __slots__ = ('name', 'path', 'eclass_db', 'portdir', 'portdir_overlay')
+ def __init__(self, name, path, eclass_db):
+ self.name = name
+ self.path = path
+ self.eclass_db = eclass_db
+ self.portdir = eclass_db.porttrees[0]
+ self.portdir_overlay = ' '.join(eclass_db.porttrees[1:])
+
+class portdbapi(dbapi):
+ """this tree will scan a portage directory located at root (passed to init)"""
+ portdbapi_instances = []
+ _use_mutable = True
+
+ @property
+ def _categories(self):
+ return self.settings.categories
+
+ @property
+ def porttree_root(self):
+ return self.settings.repositories.mainRepoLocation()
+
+ def __init__(self, _unused_param=None, mysettings=None):
+ """
+ @param _unused_param: deprecated, use mysettings['PORTDIR'] instead
+ @type _unused_param: None
+ @param mysettings: an immutable config instance
+ @type mysettings: portage.config
+ """
+ portdbapi.portdbapi_instances.append(self)
+
+ from portage import config
+ if mysettings:
+ self.settings = mysettings
+ else:
+ from portage import settings
+ self.settings = config(clone=settings)
+
+ if _unused_param is not None:
+ warnings.warn("The first parameter of the " + \
+ "portage.dbapi.porttree.portdbapi" + \
+ " constructor is unused since portage-2.1.8. " + \
+ "mysettings['PORTDIR'] is used instead.",
+ DeprecationWarning, stacklevel=2)
+
+ self.repositories = self.settings.repositories
+ self.treemap = self.repositories.treemap
+
+ # This is strictly for use in aux_get() doebuild calls when metadata
+ # is generated by the depend phase. It's safest to use a clone for
+ # this purpose because doebuild makes many changes to the config
+ # instance that is passed in.
+ self.doebuild_settings = config(clone=self.settings)
+ self.depcachedir = os.path.realpath(self.settings.depcachedir)
+
+ if os.environ.get("SANDBOX_ON") == "1":
+ # Make api consumers exempt from sandbox violations
+ # when doing metadata cache updates.
+ sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
+ if self.depcachedir not in sandbox_write:
+ sandbox_write.append(self.depcachedir)
+ os.environ["SANDBOX_WRITE"] = \
+ ":".join(filter(None, sandbox_write))
+
+ self.porttrees = list(self.settings.repositories.repoLocationList())
+ self.eclassdb = eclass_cache.cache(self.settings.repositories.mainRepoLocation())
+
+ # This is used as sanity check for aux_get(). If there is no
+ # root eclass dir, we assume that PORTDIR is invalid or
+ # missing. This check allows aux_get() to detect a missing
+ # portage tree and return early by raising a KeyError.
+ self._have_root_eclass_dir = os.path.isdir(
+ os.path.join(self.settings.repositories.mainRepoLocation(), "eclass"))
+
+ self.metadbmodule = self.settings.load_best_module("portdbapi.metadbmodule")
+
+ #if the portdbapi is "frozen", then we assume that we can cache everything (that no updates to it are happening)
+ self.xcache = {}
+ self.frozen = 0
+
+ #Create eclass dbs
+ self._repo_info = {}
+ eclass_dbs = {self.settings.repositories.mainRepoLocation() : self.eclassdb}
+ for repo in self.repositories:
+ if repo.location in self._repo_info:
+ continue
+
+ eclass_db = None
+ for eclass_location in repo.eclass_locations:
+ tree_db = eclass_dbs.get(eclass_location)
+ if tree_db is None:
+ tree_db = eclass_cache.cache(eclass_location)
+ eclass_dbs[eclass_location] = tree_db
+ if eclass_db is None:
+ eclass_db = tree_db.copy()
+ else:
+ eclass_db.append(tree_db)
+
+ self._repo_info[repo.location] = _repo_info(repo.name, repo.location, eclass_db)
+
+ #Keep a list of repo names, sorted by priority (highest priority first).
+ self._ordered_repo_name_list = tuple(reversed(self.repositories.prepos_order))
+
+ self.auxdbmodule = self.settings.load_best_module("portdbapi.auxdbmodule")
+ self.auxdb = {}
+ self._pregen_auxdb = {}
+ self._init_cache_dirs()
+ depcachedir_w_ok = os.access(self.depcachedir, os.W_OK)
+ cache_kwargs = {
+ 'gid' : portage_gid,
+ 'perms' : 0o664
+ }
+
+ # XXX: REMOVE THIS ONCE UNUSED_0 IS YANKED FROM auxdbkeys
+ # ~harring
+ filtered_auxdbkeys = [x for x in auxdbkeys if not x.startswith("UNUSED_0")]
+ filtered_auxdbkeys.sort()
+ # If secpass < 1, we don't want to write to the cache
+ # since then we won't be able to apply group permissions
+ # to the cache entries/directories.
+ if secpass < 1 or not depcachedir_w_ok:
+ for x in self.porttrees:
+ try:
+ db_ro = self.auxdbmodule(self.depcachedir, x,
+ filtered_auxdbkeys, readonly=True, **cache_kwargs)
+ except CacheError:
+ self.auxdb[x] = volatile.database(
+ self.depcachedir, x, filtered_auxdbkeys,
+ **cache_kwargs)
+ else:
+ self.auxdb[x] = metadata_overlay.database(
+ self.depcachedir, x, filtered_auxdbkeys,
+ db_rw=volatile.database, db_ro=db_ro,
+ **cache_kwargs)
+ else:
+ for x in self.porttrees:
+ if x in self.auxdb:
+ continue
+ # location, label, auxdbkeys
+ self.auxdb[x] = self.auxdbmodule(
+ self.depcachedir, x, filtered_auxdbkeys, **cache_kwargs)
+ if self.auxdbmodule is metadata_overlay.database:
+ self.auxdb[x].db_ro.ec = self._repo_info[x].eclass_db
+ if "metadata-transfer" not in self.settings.features:
+ for x in self.porttrees:
+ if x in self._pregen_auxdb:
+ continue
+ if os.path.isdir(os.path.join(x, "metadata", "cache")):
+ self._pregen_auxdb[x] = self.metadbmodule(
+ x, "metadata/cache", filtered_auxdbkeys, readonly=True)
+ try:
+ self._pregen_auxdb[x].ec = self._repo_info[x].eclass_db
+ except AttributeError:
+ pass
+ # Selectively cache metadata in order to optimize dep matching.
+ self._aux_cache_keys = set(
+ ["DEPEND", "EAPI", "INHERITED", "IUSE", "KEYWORDS", "LICENSE",
+ "PDEPEND", "PROPERTIES", "PROVIDE", "RDEPEND", "repository",
+ "RESTRICT", "SLOT", "DEFINED_PHASES", "REQUIRED_USE"])
+
+ self._aux_cache = {}
+ self._broken_ebuilds = set()
+
+ def _init_cache_dirs(self):
+ """Create /var/cache/edb/dep and adjust permissions for the portage
+ group."""
+
+ dirmode = 0o2070
+ filemode = 0o60
+ modemask = 0o2
+
+ try:
+ ensure_dirs(self.depcachedir, gid=portage_gid,
+ mode=dirmode, mask=modemask)
+ except PortageException as e:
+ pass
+
+ def close_caches(self):
+ if not hasattr(self, "auxdb"):
+ # unhandled exception thrown from constructor
+ return
+ for x in self.auxdb:
+ self.auxdb[x].sync()
+ self.auxdb.clear()
+
+ def flush_cache(self):
+ for x in self.auxdb.values():
+ x.sync()
+
+ def findLicensePath(self, license_name):
+ for x in reversed(self.porttrees):
+ license_path = os.path.join(x, "licenses", license_name)
+ if os.access(license_path, os.R_OK):
+ return license_path
+ return None
+
+ def findname(self,mycpv, mytree = None, myrepo = None):
+ return self.findname2(mycpv, mytree, myrepo)[0]
+
+ def getRepositoryPath(self, repository_id):
+ """
+ This function is required for GLEP 42 compliance; given a valid repository ID
+ it must return a path to the repository
+ TreeMap = { id:path }
+ """
+ return self.treemap.get(repository_id)
+
+ def getRepositoryName(self, canonical_repo_path):
+ """
+ This is the inverse of getRepositoryPath().
+ @param canonical_repo_path: the canonical path of a repository, as
+ resolved by os.path.realpath()
+ @type canonical_repo_path: String
+ @returns: The repo_name for the corresponding repository, or None
+ if the path does not correspond a known repository
+ @rtype: String or None
+ """
+ try:
+ return self.repositories.get_name_for_location(canonical_repo_path)
+ except KeyError:
+ return None
+
+ def getRepositories(self):
+ """
+ This function is required for GLEP 42 compliance; it will return a list of
+ repository IDs
+ TreeMap = {id: path}
+ """
+ return self._ordered_repo_name_list
+
+ def getMissingRepoNames(self):
+ """
+ Returns a list of repository paths that lack profiles/repo_name.
+ """
+ return self.settings.repositories.missing_repo_names
+
+ def getIgnoredRepos(self):
+ """
+ Returns a list of repository paths that have been ignored, because
+ another repo with the same name exists.
+ """
+ return self.settings.repositories.ignored_repos
+
+ def findname2(self, mycpv, mytree=None, myrepo = None):
+ """
+ Returns the location of the CPV, and what overlay it was in.
+ Searches overlays first, then PORTDIR; this allows us to return the first
+ matching file. As opposed to starting in portdir and then doing overlays
+ second, we would have to exhaustively search the overlays until we found
+ the file we wanted.
+ If myrepo is not None it will find packages from this repository(overlay)
+ """
+ if not mycpv:
+ return (None, 0)
+
+ if myrepo is not None:
+ mytree = self.treemap.get(myrepo)
+ if mytree is None:
+ return (None, 0)
+
+ mysplit = mycpv.split("/")
+ psplit = pkgsplit(mysplit[1])
+ if psplit is None or len(mysplit) != 2:
+ raise InvalidPackageName(mycpv)
+
+ # For optimal performace in this hot spot, we do manual unicode
+ # handling here instead of using the wrapped os module.
+ encoding = _encodings['fs']
+ errors = 'strict'
+
+ if mytree:
+ mytrees = [mytree]
+ else:
+ mytrees = reversed(self.porttrees)
+
+ relative_path = mysplit[0] + _os.sep + psplit[0] + _os.sep + \
+ mysplit[1] + ".ebuild"
+
+ for x in mytrees:
+ filename = x + _os.sep + relative_path
+ if _os.access(_unicode_encode(filename,
+ encoding=encoding, errors=errors), _os.R_OK):
+ return (filename, x)
+ return (None, 0)
+
+ def _metadata_process(self, cpv, ebuild_path, repo_path):
+ """
+ Create an EbuildMetadataPhase instance to generate metadata for the
+ give ebuild.
+ @rtype: EbuildMetadataPhase
+ @returns: A new EbuildMetadataPhase instance, or None if the
+ metadata cache is already valid.
+ """
+ metadata, st, emtime = self._pull_valid_cache(cpv, ebuild_path, repo_path)
+ if metadata is not None:
+ return None
+
+ process = EbuildMetadataPhase(cpv=cpv, ebuild_path=ebuild_path,
+ ebuild_mtime=emtime, metadata_callback=self._metadata_callback,
+ portdb=self, repo_path=repo_path, settings=self.doebuild_settings)
+ return process
+
+ def _metadata_callback(self, cpv, ebuild_path, repo_path, metadata, mtime):
+
+ i = metadata
+ if hasattr(metadata, "items"):
+ i = iter(metadata.items())
+ metadata = dict(i)
+
+ if metadata.get("INHERITED", False):
+ metadata["_eclasses_"] = self._repo_info[repo_path
+ ].eclass_db.get_eclass_data(metadata["INHERITED"].split())
+ else:
+ metadata["_eclasses_"] = {}
+
+ metadata.pop("INHERITED", None)
+ metadata["_mtime_"] = mtime
+
+ eapi = metadata.get("EAPI")
+ if not eapi or not eapi.strip():
+ eapi = "0"
+ metadata["EAPI"] = eapi
+ if not eapi_is_supported(eapi):
+ for k in set(metadata).difference(("_mtime_", "_eclasses_")):
+ metadata[k] = ""
+ metadata["EAPI"] = "-" + eapi.lstrip("-")
+
+ try:
+ self.auxdb[repo_path][cpv] = metadata
+ except CacheError:
+ # Normally this shouldn't happen, so we'll show
+ # a traceback for debugging purposes.
+ traceback.print_exc()
+ return metadata
+
+ def _pull_valid_cache(self, cpv, ebuild_path, repo_path):
+ try:
+ # Don't use unicode-wrapped os module, for better performance.
+ st = _os.stat(_unicode_encode(ebuild_path,
+ encoding=_encodings['fs'], errors='strict'))
+ emtime = st[stat.ST_MTIME]
+ except OSError:
+ writemsg(_("!!! aux_get(): ebuild for " \
+ "'%s' does not exist at:\n") % (cpv,), noiselevel=-1)
+ writemsg("!!! %s\n" % ebuild_path, noiselevel=-1)
+ raise KeyError(cpv)
+
+ # Pull pre-generated metadata from the metadata/cache/
+ # directory if it exists and is valid, otherwise fall
+ # back to the normal writable cache.
+ auxdbs = []
+ pregen_auxdb = self._pregen_auxdb.get(repo_path)
+ if pregen_auxdb is not None:
+ auxdbs.append(pregen_auxdb)
+ auxdbs.append(self.auxdb[repo_path])
+ eclass_db = self._repo_info[repo_path].eclass_db
+
+ doregen = True
+ for auxdb in auxdbs:
+ try:
+ metadata = auxdb[cpv]
+ except KeyError:
+ pass
+ except CacheError:
+ if auxdb is not pregen_auxdb:
+ try:
+ del auxdb[cpv]
+ except KeyError:
+ pass
+ except CacheError:
+ pass
+ else:
+ eapi = metadata.get('EAPI', '').strip()
+ if not eapi:
+ eapi = '0'
+ if not (eapi[:1] == '-' and eapi_is_supported(eapi[1:])) and \
+ emtime == metadata['_mtime_'] and \
+ eclass_db.is_eclass_data_valid(metadata['_eclasses_']):
+ doregen = False
+
+ if not doregen:
+ break
+
+ if doregen:
+ metadata = None
+
+ return (metadata, st, emtime)
+
+ def aux_get(self, mycpv, mylist, mytree=None, myrepo=None):
+ "stub code for returning auxilliary db information, such as SLOT, DEPEND, etc."
+ 'input: "sys-apps/foo-1.0",["SLOT","DEPEND","HOMEPAGE"]'
+ 'return: ["0",">=sys-libs/bar-1.0","http://www.foo.com"] or raise KeyError if error'
+ cache_me = False
+ if myrepo is not None:
+ mytree = self.treemap.get(myrepo)
+ if mytree is None:
+ raise KeyError(myrepo)
+
+ if not mytree:
+ cache_me = True
+ if not mytree and not self._known_keys.intersection(
+ mylist).difference(self._aux_cache_keys):
+ aux_cache = self._aux_cache.get(mycpv)
+ if aux_cache is not None:
+ return [aux_cache.get(x, "") for x in mylist]
+ cache_me = True
+ global auxdbkeys, auxdbkeylen
+ try:
+ cat, pkg = mycpv.split("/", 1)
+ except ValueError:
+ # Missing slash. Can't find ebuild so raise KeyError.
+ raise KeyError(mycpv)
+
+ myebuild, mylocation = self.findname2(mycpv, mytree)
+
+ if not myebuild:
+ writemsg("!!! aux_get(): %s\n" % \
+ _("ebuild not found for '%s'") % mycpv, noiselevel=1)
+ raise KeyError(mycpv)
+
+ mydata, st, emtime = self._pull_valid_cache(mycpv, myebuild, mylocation)
+ doregen = mydata is None
+
+ if doregen:
+ if myebuild in self._broken_ebuilds:
+ raise KeyError(mycpv)
+
+ self.doebuild_settings.setcpv(mycpv)
+ eapi = None
+
+ if eapi is None and \
+ 'parse-eapi-ebuild-head' in self.doebuild_settings.features:
+ eapi = portage._parse_eapi_ebuild_head(io.open(
+ _unicode_encode(myebuild,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'],
+ errors='replace'))
+
+ if eapi is not None:
+ self.doebuild_settings.configdict['pkg']['EAPI'] = eapi
+
+ if eapi is not None and not portage.eapi_is_supported(eapi):
+ mydata = self._metadata_callback(
+ mycpv, myebuild, mylocation, {'EAPI':eapi}, emtime)
+ else:
+ proc = EbuildMetadataPhase(cpv=mycpv, ebuild_path=myebuild,
+ ebuild_mtime=emtime,
+ metadata_callback=self._metadata_callback, portdb=self,
+ repo_path=mylocation,
+ scheduler=PollScheduler().sched_iface,
+ settings=self.doebuild_settings)
+
+ proc.start()
+ proc.wait()
+
+ if proc.returncode != os.EX_OK:
+ self._broken_ebuilds.add(myebuild)
+ raise KeyError(mycpv)
+
+ mydata = proc.metadata
+
+ # do we have a origin repository name for the current package
+ mydata["repository"] = self.repositories.get_name_for_location(mylocation)
+ mydata["INHERITED"] = ' '.join(mydata.get("_eclasses_", []))
+ mydata["_mtime_"] = st[stat.ST_MTIME]
+
+ eapi = mydata.get("EAPI")
+ if not eapi:
+ eapi = "0"
+ mydata["EAPI"] = eapi
+ if not eapi_is_supported(eapi):
+ for k in set(mydata).difference(("_mtime_", "_eclasses_")):
+ mydata[k] = ""
+ mydata["EAPI"] = "-" + eapi.lstrip("-")
+
+ #finally, we look at our internal cache entry and return the requested data.
+ returnme = [mydata.get(x, "") for x in mylist]
+
+ if cache_me:
+ aux_cache = {}
+ for x in self._aux_cache_keys:
+ aux_cache[x] = mydata.get(x, "")
+ self._aux_cache[mycpv] = aux_cache
+
+ return returnme
+
+ def getFetchMap(self, mypkg, useflags=None, mytree=None):
+ """
+ Get the SRC_URI metadata as a dict which maps each file name to a
+ set of alternative URIs.
+
+ @param mypkg: cpv for an ebuild
+ @type mypkg: String
+ @param useflags: a collection of enabled USE flags, for evaluation of
+ conditionals
+ @type useflags: set, or None to enable all conditionals
+ @param mytree: The canonical path of the tree in which the ebuild
+ is located, or None for automatic lookup
+ @type mypkg: String
+ @returns: A dict which maps each file name to a set of alternative
+ URIs.
+ @rtype: dict
+ """
+
+ try:
+ eapi, myuris = self.aux_get(mypkg,
+ ["EAPI", "SRC_URI"], mytree=mytree)
+ except KeyError:
+ # Convert this to an InvalidDependString exception since callers
+ # already handle it.
+ raise portage.exception.InvalidDependString(
+ "getFetchMap(): aux_get() error reading "+mypkg+"; aborting.")
+
+ if not eapi_is_supported(eapi):
+ # Convert this to an InvalidDependString exception
+ # since callers already handle it.
+ raise portage.exception.InvalidDependString(
+ "getFetchMap(): '%s' has unsupported EAPI: '%s'" % \
+ (mypkg, eapi.lstrip("-")))
+
+ return _parse_uri_map(mypkg, {'EAPI':eapi,'SRC_URI':myuris},
+ use=useflags)
+
+ def getfetchsizes(self, mypkg, useflags=None, debug=0, myrepo=None):
+ # returns a filename:size dictionnary of remaining downloads
+ myebuild, mytree = self.findname2(mypkg, myrepo=myrepo)
+ if myebuild is None:
+ raise AssertionError(_("ebuild not found for '%s'") % mypkg)
+ pkgdir = os.path.dirname(myebuild)
+ mf = Manifest(pkgdir, self.settings["DISTDIR"])
+ checksums = mf.getDigests()
+ if not checksums:
+ if debug:
+ writemsg(_("[empty/missing/bad digest]: %s\n") % (mypkg,))
+ return {}
+ filesdict={}
+ myfiles = self.getFetchMap(mypkg, useflags=useflags, mytree=mytree)
+ #XXX: maybe this should be improved: take partial downloads
+ # into account? check checksums?
+ for myfile in myfiles:
+ try:
+ fetch_size = int(checksums[myfile]["size"])
+ except (KeyError, ValueError):
+ if debug:
+ writemsg(_("[bad digest]: missing %(file)s for %(pkg)s\n") % {"file":myfile, "pkg":mypkg})
+ continue
+ file_path = os.path.join(self.settings["DISTDIR"], myfile)
+ mystat = None
+ try:
+ mystat = os.stat(file_path)
+ except OSError as e:
+ pass
+ if mystat is None:
+ existing_size = 0
+ ro_distdirs = self.settings.get("PORTAGE_RO_DISTDIRS")
+ if ro_distdirs is not None:
+ for x in shlex_split(ro_distdirs):
+ try:
+ mystat = os.stat(os.path.join(x, myfile))
+ except OSError:
+ pass
+ else:
+ if mystat.st_size == fetch_size:
+ existing_size = fetch_size
+ break
+ else:
+ existing_size = mystat.st_size
+ remaining_size = fetch_size - existing_size
+ if remaining_size > 0:
+ # Assume the download is resumable.
+ filesdict[myfile] = remaining_size
+ elif remaining_size < 0:
+ # The existing file is too large and therefore corrupt.
+ filesdict[myfile] = int(checksums[myfile]["size"])
+ return filesdict
+
+ def fetch_check(self, mypkg, useflags=None, mysettings=None, all=False, myrepo=None):
+ """
+ TODO: account for PORTAGE_RO_DISTDIRS
+ """
+ if all:
+ useflags = None
+ elif useflags is None:
+ if mysettings:
+ useflags = mysettings["USE"].split()
+ if myrepo is not None:
+ mytree = self.treemap.get(myrepo)
+ if mytree is None:
+ return False
+ else:
+ mytree = None
+
+ myfiles = self.getFetchMap(mypkg, useflags=useflags, mytree=mytree)
+ myebuild = self.findname(mypkg, myrepo=myrepo)
+ if myebuild is None:
+ raise AssertionError(_("ebuild not found for '%s'") % mypkg)
+ pkgdir = os.path.dirname(myebuild)
+ mf = Manifest(pkgdir, self.settings["DISTDIR"])
+ mysums = mf.getDigests()
+
+ failures = {}
+ for x in myfiles:
+ if not mysums or x not in mysums:
+ ok = False
+ reason = _("digest missing")
+ else:
+ try:
+ ok, reason = portage.checksum.verify_all(
+ os.path.join(self.settings["DISTDIR"], x), mysums[x])
+ except FileNotFound as e:
+ ok = False
+ reason = _("File Not Found: '%s'") % (e,)
+ if not ok:
+ failures[x] = reason
+ if failures:
+ return False
+ return True
+
+ def cpv_exists(self, mykey, myrepo=None):
+ "Tells us whether an actual ebuild exists on disk (no masking)"
+ cps2 = mykey.split("/")
+ cps = catpkgsplit(mykey, silent=0)
+ if not cps:
+ #invalid cat/pkg-v
+ return 0
+ if self.findname(cps[0] + "/" + cps2[1], myrepo=myrepo):
+ return 1
+ else:
+ return 0
+
+ def cp_all(self, categories=None, trees=None):
+ """
+ This returns a list of all keys in our tree or trees
+ @param categories: optional list of categories to search or
+ defaults to self.settings.categories
+ @param trees: optional list of trees to search the categories in or
+ defaults to self.porttrees
+ @rtype list of [cat/pkg,...]
+ """
+ d = {}
+ if categories is None:
+ categories = self.settings.categories
+ if trees is None:
+ trees = self.porttrees
+ for x in categories:
+ for oroot in trees:
+ for y in listdir(oroot+"/"+x, EmptyOnError=1, ignorecvs=1, dirsonly=1):
+ try:
+ atom = Atom("%s/%s" % (x, y))
+ except InvalidAtom:
+ continue
+ if atom != atom.cp:
+ continue
+ d[atom.cp] = None
+ l = list(d)
+ l.sort()
+ return l
+
+ def cp_list(self, mycp, use_cache=1, mytree=None):
+ if self.frozen and mytree is None:
+ cachelist = self.xcache["cp-list"].get(mycp)
+ if cachelist is not None:
+ # Try to propagate this to the match-all cache here for
+ # repoman since he uses separate match-all caches for each
+ # profile (due to old-style virtuals). Do not propagate
+ # old-style virtuals since cp_list() doesn't expand them.
+ if not (not cachelist and mycp.startswith("virtual/")):
+ self.xcache["match-all"][mycp] = cachelist
+ return cachelist[:]
+ mysplit = mycp.split("/")
+ invalid_category = mysplit[0] not in self._categories
+ d={}
+ if mytree is not None:
+ if isinstance(mytree, basestring):
+ mytrees = [mytree]
+ else:
+ # assume it's iterable
+ mytrees = mytree
+ else:
+ mytrees = self.porttrees
+ for oroot in mytrees:
+ try:
+ file_list = os.listdir(os.path.join(oroot, mycp))
+ except OSError:
+ continue
+ for x in file_list:
+ pf = None
+ if x[-7:] == '.ebuild':
+ pf = x[:-7]
+
+ if pf is not None:
+ ps = pkgsplit(pf)
+ if not ps:
+ writemsg(_("\nInvalid ebuild name: %s\n") % \
+ os.path.join(oroot, mycp, x), noiselevel=-1)
+ continue
+ if ps[0] != mysplit[1]:
+ writemsg(_("\nInvalid ebuild name: %s\n") % \
+ os.path.join(oroot, mycp, x), noiselevel=-1)
+ continue
+ ver_match = ver_regexp.match("-".join(ps[1:]))
+ if ver_match is None or not ver_match.groups():
+ writemsg(_("\nInvalid ebuild version: %s\n") % \
+ os.path.join(oroot, mycp, x), noiselevel=-1)
+ continue
+ d[mysplit[0]+"/"+pf] = None
+ if invalid_category and d:
+ writemsg(_("\n!!! '%s' has a category that is not listed in " \
+ "%setc/portage/categories\n") % \
+ (mycp, self.settings["PORTAGE_CONFIGROOT"]), noiselevel=-1)
+ mylist = []
+ else:
+ mylist = list(d)
+ # Always sort in ascending order here since it's handy
+ # and the result can be easily cached and reused.
+ self._cpv_sort_ascending(mylist)
+ if self.frozen and mytree is None:
+ cachelist = mylist[:]
+ self.xcache["cp-list"][mycp] = cachelist
+ # Do not propagate old-style virtuals since
+ # cp_list() doesn't expand them.
+ if not (not cachelist and mycp.startswith("virtual/")):
+ self.xcache["match-all"][mycp] = cachelist
+ return mylist
+
+ def freeze(self):
+ for x in "bestmatch-visible", "cp-list", "list-visible", "match-all", \
+ "match-all-cpv-only", "match-visible", "minimum-all", \
+ "minimum-visible":
+ self.xcache[x]={}
+ self.frozen=1
+
+ def melt(self):
+ self.xcache = {}
+ self.frozen = 0
+
+ def xmatch(self,level,origdep,mydep=None,mykey=None,mylist=None):
+ "caching match function; very trick stuff"
+ #if no updates are being made to the tree, we can consult our xcache...
+ if self.frozen:
+ try:
+ return self.xcache[level][origdep][:]
+ except KeyError:
+ pass
+
+ if mydep is None:
+ #this stuff only runs on first call of xmatch()
+ #create mydep, mykey from origdep
+ mydep = dep_expand(origdep, mydb=self, settings=self.settings)
+ mykey = mydep.cp
+
+ myval = None
+ mytree = None
+ if mydep.repo is not None:
+ mytree = self.treemap.get(mydep.repo)
+ if mytree is None:
+ myval = []
+
+ if myval is not None:
+ # Unknown repo, empty result.
+ pass
+ elif level == "match-all-cpv-only":
+ # match *all* packages, only against the cpv, in order
+ # to bypass unnecessary cache access for things like IUSE
+ # and SLOT.
+ if mydep == mykey:
+ # Share cache with match-all/cp_list when the result is the
+ # same. Note that this requires that mydep.repo is None and
+ # thus mytree is also None.
+ level = "match-all"
+ myval = self.cp_list(mykey, mytree=mytree)
+ else:
+ myval = match_from_list(mydep,
+ self.cp_list(mykey, mytree=mytree))
+
+ elif level == "list-visible":
+ #a list of all visible packages, not called directly (just by xmatch())
+ #myval = self.visible(self.cp_list(mykey))
+
+ myval = self.gvisible(self.visible(
+ self.cp_list(mykey, mytree=mytree)))
+ elif level == "minimum-all":
+ # Find the minimum matching version. This is optimized to
+ # minimize the number of metadata accesses (improves performance
+ # especially in cases where metadata needs to be generated).
+ if mydep == mykey:
+ cpv_iter = iter(self.cp_list(mykey, mytree=mytree))
+ else:
+ cpv_iter = self._iter_match(mydep,
+ self.cp_list(mykey, mytree=mytree))
+ try:
+ myval = next(cpv_iter)
+ except StopIteration:
+ myval = ""
+
+ elif level in ("minimum-visible", "bestmatch-visible"):
+ # Find the minimum matching visible version. This is optimized to
+ # minimize the number of metadata accesses (improves performance
+ # especially in cases where metadata needs to be generated).
+ if mydep == mykey:
+ mylist = self.cp_list(mykey, mytree=mytree)
+ else:
+ mylist = match_from_list(mydep,
+ self.cp_list(mykey, mytree=mytree))
+ myval = ""
+ settings = self.settings
+ local_config = settings.local_config
+ aux_keys = list(self._aux_cache_keys)
+ if level == "minimum-visible":
+ iterfunc = iter
+ else:
+ iterfunc = reversed
+ for cpv in iterfunc(mylist):
+ try:
+ metadata = dict(zip(aux_keys,
+ self.aux_get(cpv, aux_keys)))
+ except KeyError:
+ # ebuild masked by corruption
+ continue
+ if not eapi_is_supported(metadata["EAPI"]):
+ continue
+ if mydep.slot and mydep.slot != metadata["SLOT"]:
+ continue
+ if settings._getMissingKeywords(cpv, metadata):
+ continue
+ if settings._getMaskAtom(cpv, metadata):
+ continue
+ if settings._getProfileMaskAtom(cpv, metadata):
+ continue
+ if local_config:
+ metadata["USE"] = ""
+ if "?" in metadata["LICENSE"] or "?" in metadata["PROPERTIES"]:
+ self.doebuild_settings.setcpv(cpv, mydb=metadata)
+ metadata["USE"] = self.doebuild_settings.get("USE", "")
+ try:
+ if settings._getMissingLicenses(cpv, metadata):
+ continue
+ if settings._getMissingProperties(cpv, metadata):
+ continue
+ except InvalidDependString:
+ continue
+ if mydep.use:
+ has_iuse = False
+ for has_iuse in self._iter_match_use(mydep, [cpv]):
+ break
+ if not has_iuse:
+ continue
+ myval = cpv
+ break
+ elif level == "bestmatch-list":
+ #dep match -- find best match but restrict search to sublist
+ #no point in calling xmatch again since we're not caching list deps
+
+ myval = best(list(self._iter_match(mydep, mylist)))
+ elif level == "match-list":
+ #dep match -- find all matches but restrict search to sublist (used in 2nd half of visible())
+
+ myval = list(self._iter_match(mydep, mylist))
+ elif level == "match-visible":
+ #dep match -- find all visible matches
+ #get all visible packages, then get the matching ones
+ myval = list(self._iter_match(mydep,
+ self.xmatch("list-visible", mykey, mydep=Atom(mykey), mykey=mykey)))
+ elif level == "match-all":
+ #match *all* visible *and* masked packages
+ if mydep == mykey:
+ myval = self.cp_list(mykey, mytree=mytree)
+ else:
+ myval = list(self._iter_match(mydep,
+ self.cp_list(mykey, mytree=mytree)))
+ else:
+ raise AssertionError(
+ "Invalid level argument: '%s'" % level)
+
+ if self.frozen and (level not in ["match-list", "bestmatch-list"]):
+ self.xcache[level][mydep] = myval
+ if origdep and origdep != mydep:
+ self.xcache[level][origdep] = myval
+ return myval[:]
+
+ def match(self, mydep, use_cache=1):
+ return self.xmatch("match-visible", mydep)
+
+ def visible(self, mylist):
+ """two functions in one. Accepts a list of cpv values and uses the package.mask *and*
+ packages file to remove invisible entries, returning remaining items. This function assumes
+ that all entries in mylist have the same category and package name."""
+ if not mylist:
+ return []
+
+ db_keys = ["SLOT"]
+ visible = []
+ getMaskAtom = self.settings._getMaskAtom
+ getProfileMaskAtom = self.settings._getProfileMaskAtom
+ for cpv in mylist:
+ try:
+ metadata = dict(zip(db_keys, self.aux_get(cpv, db_keys)))
+ except KeyError:
+ # masked by corruption
+ continue
+ if not metadata["SLOT"]:
+ continue
+ if getMaskAtom(cpv, metadata):
+ continue
+ if getProfileMaskAtom(cpv, metadata):
+ continue
+ visible.append(cpv)
+ return visible
+
+ def gvisible(self,mylist):
+ "strip out group-masked (not in current group) entries"
+
+ if mylist is None:
+ return []
+ newlist=[]
+ aux_keys = list(self._aux_cache_keys)
+ metadata = {}
+ local_config = self.settings.local_config
+ chost = self.settings.get('CHOST', '')
+ accept_chost = self.settings._accept_chost
+ for mycpv in mylist:
+ metadata.clear()
+ try:
+ metadata.update(zip(aux_keys, self.aux_get(mycpv, aux_keys)))
+ except KeyError:
+ continue
+ except PortageException as e:
+ writemsg("!!! Error: aux_get('%s', %s)\n" % (mycpv, aux_keys),
+ noiselevel=-1)
+ writemsg("!!! %s\n" % (e,), noiselevel=-1)
+ del e
+ continue
+ eapi = metadata["EAPI"]
+ if not eapi_is_supported(eapi):
+ continue
+ if _eapi_is_deprecated(eapi):
+ continue
+ if self.settings._getMissingKeywords(mycpv, metadata):
+ continue
+ if local_config:
+ metadata['CHOST'] = chost
+ if not accept_chost(mycpv, metadata):
+ continue
+ metadata["USE"] = ""
+ if "?" in metadata["LICENSE"] or "?" in metadata["PROPERTIES"]:
+ self.doebuild_settings.setcpv(mycpv, mydb=metadata)
+ metadata['USE'] = self.doebuild_settings['PORTAGE_USE']
+ try:
+ if self.settings._getMissingLicenses(mycpv, metadata):
+ continue
+ if self.settings._getMissingProperties(mycpv, metadata):
+ continue
+ except InvalidDependString:
+ continue
+ newlist.append(mycpv)
+ return newlist
+
+def close_portdbapi_caches():
+ for i in portdbapi.portdbapi_instances:
+ i.close_caches()
+
+portage.process.atexit_register(portage.portageexit)
+
+class portagetree(object):
+ def __init__(self, root=None, virtual=None, settings=None):
+ """
+ Constructor for a PortageTree
+
+ @param root: deprecated, defaults to settings['ROOT']
+ @type root: String/Path
+ @param virtual: UNUSED
+ @type virtual: No Idea
+ @param settings: Portage Configuration object (portage.settings)
+ @type settings: Instance of portage.config
+ """
+
+ if settings is None:
+ settings = portage.settings
+ self.settings = settings
+
+ if root is not None and root != settings['ROOT']:
+ warnings.warn("The root parameter of the " + \
+ "portage.dbapi.porttree.portagetree" + \
+ " constructor is now unused. Use " + \
+ "settings['ROOT'] instead.",
+ DeprecationWarning, stacklevel=2)
+
+ self.portroot = settings["PORTDIR"]
+ self.virtual = virtual
+ self.dbapi = portdbapi(mysettings=settings)
+
+ @property
+ def root(self):
+ warnings.warn("The root attribute of " + \
+ "portage.dbapi.porttree.portagetree" + \
+ " is deprecated. Use " + \
+ "settings['ROOT'] instead.",
+ DeprecationWarning, stacklevel=2)
+ return self.settings['ROOT']
+
+ def dep_bestmatch(self,mydep):
+ "compatibility method"
+ mymatch = self.dbapi.xmatch("bestmatch-visible",mydep)
+ if mymatch is None:
+ return ""
+ return mymatch
+
+ def dep_match(self,mydep):
+ "compatibility method"
+ mymatch = self.dbapi.xmatch("match-visible",mydep)
+ if mymatch is None:
+ return []
+ return mymatch
+
+ def exists_specific(self,cpv):
+ return self.dbapi.cpv_exists(cpv)
+
+ def getallnodes(self):
+ """new behavior: these are all *unmasked* nodes. There may or may not be available
+ masked package for nodes in this nodes list."""
+ return self.dbapi.cp_all()
+
+ def getname(self, pkgname):
+ "returns file location for this particular package (DEPRECATED)"
+ if not pkgname:
+ return ""
+ mysplit = pkgname.split("/")
+ psplit = pkgsplit(mysplit[1])
+ return "/".join([self.portroot, mysplit[0], psplit[0], mysplit[1]])+".ebuild"
+
+ def depcheck(self, mycheck, use="yes", myusesplit=None):
+ return dep_check(mycheck, self.dbapi, use=use, myuse=myusesplit)
+
+ def getslot(self,mycatpkg):
+ "Get a slot for a catpkg; assume it exists."
+ myslot = ""
+ try:
+ myslot = self.dbapi.aux_get(mycatpkg, ["SLOT"])[0]
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ pass
+ return myslot
+
+class FetchlistDict(Mapping):
+ """
+ This provide a mapping interface to retrieve fetch lists. It's used
+ to allow portage.manifest.Manifest to access fetch lists via a standard
+ mapping interface rather than use the dbapi directly.
+ """
+ def __init__(self, pkgdir, settings, mydbapi):
+ """pkgdir is a directory containing ebuilds and settings is passed into
+ portdbapi.getfetchlist for __getitem__ calls."""
+ self.pkgdir = pkgdir
+ self.cp = os.sep.join(pkgdir.split(os.sep)[-2:])
+ self.settings = settings
+ self.mytree = os.path.realpath(os.path.dirname(os.path.dirname(pkgdir)))
+ self.portdb = mydbapi
+
+ def __getitem__(self, pkg_key):
+ """Returns the complete fetch list for a given package."""
+ return list(self.portdb.getFetchMap(pkg_key, mytree=self.mytree))
+
+ def __contains__(self, cpv):
+ return cpv in self.__iter__()
+
+ def has_key(self, pkg_key):
+ """Returns true if the given package exists within pkgdir."""
+ warnings.warn("portage.dbapi.porttree.FetchlistDict.has_key() is "
+ "deprecated, use the 'in' operator instead",
+ DeprecationWarning, stacklevel=2)
+ return pkg_key in self
+
+ def __iter__(self):
+ return iter(self.portdb.cp_list(self.cp, mytree=self.mytree))
+
+ def __len__(self):
+ """This needs to be implemented in order to avoid
+ infinite recursion in some cases."""
+ return len(self.portdb.cp_list(self.cp, mytree=self.mytree))
+
+ def keys(self):
+ """Returns keys for all packages within pkgdir"""
+ return self.portdb.cp_list(self.cp, mytree=self.mytree)
+
+ if sys.hexversion >= 0x3000000:
+ keys = __iter__
+
+def _parse_uri_map(cpv, metadata, use=None):
+
+ myuris = use_reduce(metadata.get('SRC_URI', ''),
+ uselist=use, matchall=(use is None),
+ is_src_uri=True,
+ eapi=metadata['EAPI'])
+
+ uri_map = OrderedDict()
+
+ myuris.reverse()
+ while myuris:
+ uri = myuris.pop()
+ if myuris and myuris[-1] == "->":
+ operator = myuris.pop()
+ distfile = myuris.pop()
+ else:
+ distfile = os.path.basename(uri)
+ if not distfile:
+ raise portage.exception.InvalidDependString(
+ ("getFetchMap(): '%s' SRC_URI has no file " + \
+ "name: '%s'") % (cpv, uri))
+
+ uri_set = uri_map.get(distfile)
+ if uri_set is None:
+ uri_set = set()
+ uri_map[distfile] = uri_set
+ uri_set.add(uri)
+ uri = None
+ operator = None
+
+ return uri_map
diff --git a/portage_with_autodep/pym/portage/dbapi/vartree.py b/portage_with_autodep/pym/portage/dbapi/vartree.py
new file mode 100644
index 0000000..7f7873b
--- /dev/null
+++ b/portage_with_autodep/pym/portage/dbapi/vartree.py
@@ -0,0 +1,4527 @@
+# Copyright 1998-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = [
+ "vardbapi", "vartree", "dblink"] + \
+ ["write_contents", "tar_contents"]
+
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.checksum:_perform_md5_merge@perform_md5',
+ 'portage.data:portage_gid,portage_uid,secpass',
+ 'portage.dbapi.dep_expand:dep_expand',
+ 'portage.dbapi._MergeProcess:MergeProcess',
+ 'portage.dep:dep_getkey,isjustname,match_from_list,' + \
+ 'use_reduce,_slot_re',
+ 'portage.elog:collect_ebuild_messages,collect_messages,' + \
+ 'elog_process,_merge_logentries',
+ 'portage.locks:lockdir,unlockdir,lockfile,unlockfile',
+ 'portage.output:bold,colorize',
+ 'portage.package.ebuild.doebuild:doebuild_environment,' + \
+ '_spawn_phase',
+ 'portage.package.ebuild.prepare_build_dirs:prepare_build_dirs',
+ 'portage.update:fixdbentries',
+ 'portage.util:apply_secpass_permissions,ConfigProtect,ensure_dirs,' + \
+ 'writemsg,writemsg_level,write_atomic,atomic_ofstream,writedict,' + \
+ 'grabdict,normalize_path,new_protect_filename',
+ 'portage.util.digraph:digraph',
+ 'portage.util.env_update:env_update',
+ 'portage.util.listdir:dircache,listdir',
+ 'portage.util._dyn_libs.PreservedLibsRegistry:PreservedLibsRegistry',
+ 'portage.util._dyn_libs.LinkageMapELF:LinkageMapELF@LinkageMap',
+ 'portage.versions:best,catpkgsplit,catsplit,cpv_getkey,pkgcmp,' + \
+ '_pkgsplit@pkgsplit',
+)
+
+from portage.const import CACHE_PATH, CONFIG_MEMORY_FILE, \
+ PORTAGE_PACKAGE_ATOM, PRIVATE_PATH, VDB_PATH
+from portage.const import _ENABLE_DYN_LINK_MAP, _ENABLE_PRESERVE_LIBS
+from portage.dbapi import dbapi
+from portage.exception import CommandNotFound, \
+ InvalidData, InvalidLocation, InvalidPackageName, \
+ FileNotFound, PermissionDenied, UnsupportedAPIException
+from portage.localization import _
+from portage.util.movefile import movefile
+
+from portage import abssymlink, _movefile, bsd_chflags
+
+# This is a special version of the os module, wrapped for unicode support.
+from portage import os
+from portage import _encodings
+from portage import _os_merge
+from portage import _selinux_merge
+from portage import _unicode_decode
+from portage import _unicode_encode
+
+from _emerge.EbuildBuildDir import EbuildBuildDir
+from _emerge.EbuildPhase import EbuildPhase
+from _emerge.emergelog import emergelog
+from _emerge.PollScheduler import PollScheduler
+from _emerge.MiscFunctionsProcess import MiscFunctionsProcess
+
+import errno
+import gc
+import io
+from itertools import chain
+import logging
+import os as _os
+import re
+import shutil
+import stat
+import sys
+import tempfile
+import textwrap
+import time
+import warnings
+
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+ long = int
+
+class vardbapi(dbapi):
+
+ _excluded_dirs = ["CVS", "lost+found"]
+ _excluded_dirs = [re.escape(x) for x in _excluded_dirs]
+ _excluded_dirs = re.compile(r'^(\..*|-MERGING-.*|' + \
+ "|".join(_excluded_dirs) + r')$')
+
+ _aux_cache_version = "1"
+ _owners_cache_version = "1"
+
+ # Number of uncached packages to trigger cache update, since
+ # it's wasteful to update it for every vdb change.
+ _aux_cache_threshold = 5
+
+ _aux_cache_keys_re = re.compile(r'^NEEDED\..*$')
+ _aux_multi_line_re = re.compile(r'^(CONTENTS|NEEDED\..*)$')
+
+ def __init__(self, _unused_param=None, categories=None, settings=None, vartree=None):
+ """
+ The categories parameter is unused since the dbapi class
+ now has a categories property that is generated from the
+ available packages.
+ """
+
+ # Used by emerge to check whether any packages
+ # have been added or removed.
+ self._pkgs_changed = False
+
+ # The _aux_cache_threshold doesn't work as designed
+ # if the cache is flushed from a subprocess, so we
+ # use this to avoid waste vdb cache updates.
+ self._flush_cache_enabled = True
+
+ #cache for category directory mtimes
+ self.mtdircache = {}
+
+ #cache for dependency checks
+ self.matchcache = {}
+
+ #cache for cp_list results
+ self.cpcache = {}
+
+ self.blockers = None
+ if settings is None:
+ settings = portage.settings
+ self.settings = settings
+ self.root = settings['ROOT']
+
+ if _unused_param is not None and _unused_param != self.root:
+ warnings.warn("The first parameter of the " + \
+ "portage.dbapi.vartree.vardbapi" + \
+ " constructor is now unused. Use " + \
+ "settings['ROOT'] instead.",
+ DeprecationWarning, stacklevel=2)
+
+ self._eroot = settings['EROOT']
+ self._dbroot = self._eroot + VDB_PATH
+ self._lock = None
+ self._lock_count = 0
+
+ self._conf_mem_file = self._eroot + CONFIG_MEMORY_FILE
+ self._fs_lock_obj = None
+ self._fs_lock_count = 0
+
+ if vartree is None:
+ vartree = portage.db[self.root]["vartree"]
+ self.vartree = vartree
+ self._aux_cache_keys = set(
+ ["BUILD_TIME", "CHOST", "COUNTER", "DEPEND", "DESCRIPTION",
+ "EAPI", "HOMEPAGE", "IUSE", "KEYWORDS",
+ "LICENSE", "PDEPEND", "PROPERTIES", "PROVIDE", "RDEPEND",
+ "repository", "RESTRICT" , "SLOT", "USE", "DEFINED_PHASES",
+ "REQUIRED_USE"])
+ self._aux_cache_obj = None
+ self._aux_cache_filename = os.path.join(self._eroot,
+ CACHE_PATH, "vdb_metadata.pickle")
+ self._counter_path = os.path.join(self._eroot,
+ CACHE_PATH, "counter")
+
+ self._plib_registry = None
+ if _ENABLE_PRESERVE_LIBS:
+ self._plib_registry = PreservedLibsRegistry(self.root,
+ os.path.join(self._eroot, PRIVATE_PATH,
+ "preserved_libs_registry"))
+
+ self._linkmap = None
+ if _ENABLE_DYN_LINK_MAP:
+ self._linkmap = LinkageMap(self)
+ self._owners = self._owners_db(self)
+
+ self._cached_counter = None
+
+ def getpath(self, mykey, filename=None):
+ # This is an optimized hotspot, so don't use unicode-wrapped
+ # os module and don't use os.path.join().
+ rValue = self._eroot + VDB_PATH + _os.sep + mykey
+ if filename is not None:
+ # If filename is always relative, we can do just
+ # rValue += _os.sep + filename
+ rValue = _os.path.join(rValue, filename)
+ return rValue
+
+ def lock(self):
+ """
+ Acquire a reentrant lock, blocking, for cooperation with concurrent
+ processes. State is inherited by subprocesses, allowing subprocesses
+ to reenter a lock that was acquired by a parent process. However,
+ a lock can be released only by the same process that acquired it.
+ """
+ if self._lock_count:
+ self._lock_count += 1
+ else:
+ if self._lock is not None:
+ raise AssertionError("already locked")
+ # At least the parent needs to exist for the lock file.
+ ensure_dirs(self._dbroot)
+ self._lock = lockdir(self._dbroot)
+ self._lock_count += 1
+
+ def unlock(self):
+ """
+ Release a lock, decrementing the recursion level. Each unlock() call
+ must be matched with a prior lock() call, or else an AssertionError
+ will be raised if unlock() is called while not locked.
+ """
+ if self._lock_count > 1:
+ self._lock_count -= 1
+ else:
+ if self._lock is None:
+ raise AssertionError("not locked")
+ self._lock_count = 0
+ unlockdir(self._lock)
+ self._lock = None
+
+ def _fs_lock(self):
+ """
+ Acquire a reentrant lock, blocking, for cooperation with concurrent
+ processes.
+ """
+ if self._fs_lock_count < 1:
+ if self._fs_lock_obj is not None:
+ raise AssertionError("already locked")
+ try:
+ self._fs_lock_obj = lockfile(self._conf_mem_file)
+ except InvalidLocation:
+ self.settings._init_dirs()
+ self._fs_lock_obj = lockfile(self._conf_mem_file)
+ self._fs_lock_count += 1
+
+ def _fs_unlock(self):
+ """
+ Release a lock, decrementing the recursion level.
+ """
+ if self._fs_lock_count <= 1:
+ if self._fs_lock_obj is None:
+ raise AssertionError("not locked")
+ unlockfile(self._fs_lock_obj)
+ self._fs_lock_obj = None
+ self._fs_lock_count -= 1
+
+ def _bump_mtime(self, cpv):
+ """
+ This is called before an after any modifications, so that consumers
+ can use directory mtimes to validate caches. See bug #290428.
+ """
+ base = self._eroot + VDB_PATH
+ cat = catsplit(cpv)[0]
+ catdir = base + _os.sep + cat
+ t = time.time()
+ t = (t, t)
+ try:
+ for x in (catdir, base):
+ os.utime(x, t)
+ except OSError:
+ ensure_dirs(catdir)
+
+ def cpv_exists(self, mykey, myrepo=None):
+ "Tells us whether an actual ebuild exists on disk (no masking)"
+ return os.path.exists(self.getpath(mykey))
+
+ def cpv_counter(self, mycpv):
+ "This method will grab the COUNTER. Returns a counter value."
+ try:
+ return long(self.aux_get(mycpv, ["COUNTER"])[0])
+ except (KeyError, ValueError):
+ pass
+ writemsg_level(_("portage: COUNTER for %s was corrupted; " \
+ "resetting to value of 0\n") % (mycpv,),
+ level=logging.ERROR, noiselevel=-1)
+ return 0
+
+ def cpv_inject(self, mycpv):
+ "injects a real package into our on-disk database; assumes mycpv is valid and doesn't already exist"
+ ensure_dirs(self.getpath(mycpv))
+ counter = self.counter_tick(mycpv=mycpv)
+ # write local package counter so that emerge clean does the right thing
+ write_atomic(self.getpath(mycpv, filename="COUNTER"), str(counter))
+
+ def isInjected(self, mycpv):
+ if self.cpv_exists(mycpv):
+ if os.path.exists(self.getpath(mycpv, filename="INJECTED")):
+ return True
+ if not os.path.exists(self.getpath(mycpv, filename="CONTENTS")):
+ return True
+ return False
+
+ def move_ent(self, mylist, repo_match=None):
+ origcp = mylist[1]
+ newcp = mylist[2]
+
+ # sanity check
+ for atom in (origcp, newcp):
+ if not isjustname(atom):
+ raise InvalidPackageName(str(atom))
+ origmatches = self.match(origcp, use_cache=0)
+ moves = 0
+ if not origmatches:
+ return moves
+ for mycpv in origmatches:
+ mycpv_cp = cpv_getkey(mycpv)
+ if mycpv_cp != origcp:
+ # Ignore PROVIDE virtual match.
+ continue
+ if repo_match is not None \
+ and not repo_match(self.aux_get(mycpv, ['repository'])[0]):
+ continue
+ mynewcpv = mycpv.replace(mycpv_cp, str(newcp), 1)
+ mynewcat = catsplit(newcp)[0]
+ origpath = self.getpath(mycpv)
+ if not os.path.exists(origpath):
+ continue
+ moves += 1
+ if not os.path.exists(self.getpath(mynewcat)):
+ #create the directory
+ ensure_dirs(self.getpath(mynewcat))
+ newpath = self.getpath(mynewcpv)
+ if os.path.exists(newpath):
+ #dest already exists; keep this puppy where it is.
+ continue
+ _movefile(origpath, newpath, mysettings=self.settings)
+ self._clear_pkg_cache(self._dblink(mycpv))
+ self._clear_pkg_cache(self._dblink(mynewcpv))
+
+ # We need to rename the ebuild now.
+ old_pf = catsplit(mycpv)[1]
+ new_pf = catsplit(mynewcpv)[1]
+ if new_pf != old_pf:
+ try:
+ os.rename(os.path.join(newpath, old_pf + ".ebuild"),
+ os.path.join(newpath, new_pf + ".ebuild"))
+ except EnvironmentError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ write_atomic(os.path.join(newpath, "PF"), new_pf+"\n")
+ write_atomic(os.path.join(newpath, "CATEGORY"), mynewcat+"\n")
+ fixdbentries([mylist], newpath)
+ return moves
+
+ def cp_list(self, mycp, use_cache=1):
+ mysplit=catsplit(mycp)
+ if mysplit[0] == '*':
+ mysplit[0] = mysplit[0][1:]
+ try:
+ mystat = os.stat(self.getpath(mysplit[0])).st_mtime
+ except OSError:
+ mystat = 0
+ if use_cache and mycp in self.cpcache:
+ cpc = self.cpcache[mycp]
+ if cpc[0] == mystat:
+ return cpc[1][:]
+ cat_dir = self.getpath(mysplit[0])
+ try:
+ dir_list = os.listdir(cat_dir)
+ except EnvironmentError as e:
+ if e.errno == PermissionDenied.errno:
+ raise PermissionDenied(cat_dir)
+ del e
+ dir_list = []
+
+ returnme = []
+ for x in dir_list:
+ if self._excluded_dirs.match(x) is not None:
+ continue
+ ps = pkgsplit(x)
+ if not ps:
+ self.invalidentry(os.path.join(self.getpath(mysplit[0]), x))
+ continue
+ if len(mysplit) > 1:
+ if ps[0] == mysplit[1]:
+ returnme.append(mysplit[0]+"/"+x)
+ self._cpv_sort_ascending(returnme)
+ if use_cache:
+ self.cpcache[mycp] = [mystat, returnme[:]]
+ elif mycp in self.cpcache:
+ del self.cpcache[mycp]
+ return returnme
+
+ def cpv_all(self, use_cache=1):
+ """
+ Set use_cache=0 to bypass the portage.cachedir() cache in cases
+ when the accuracy of mtime staleness checks should not be trusted
+ (generally this is only necessary in critical sections that
+ involve merge or unmerge of packages).
+ """
+ returnme = []
+ basepath = os.path.join(self._eroot, VDB_PATH) + os.path.sep
+
+ if use_cache:
+ from portage import listdir
+ else:
+ def listdir(p, **kwargs):
+ try:
+ return [x for x in os.listdir(p) \
+ if os.path.isdir(os.path.join(p, x))]
+ except EnvironmentError as e:
+ if e.errno == PermissionDenied.errno:
+ raise PermissionDenied(p)
+ del e
+ return []
+
+ for x in listdir(basepath, EmptyOnError=1, ignorecvs=1, dirsonly=1):
+ if self._excluded_dirs.match(x) is not None:
+ continue
+ if not self._category_re.match(x):
+ continue
+ for y in listdir(basepath + x, EmptyOnError=1, dirsonly=1):
+ if self._excluded_dirs.match(y) is not None:
+ continue
+ subpath = x + "/" + y
+ # -MERGING- should never be a cpv, nor should files.
+ try:
+ if catpkgsplit(subpath) is None:
+ self.invalidentry(self.getpath(subpath))
+ continue
+ except InvalidData:
+ self.invalidentry(self.getpath(subpath))
+ continue
+ returnme.append(subpath)
+
+ return returnme
+
+ def cp_all(self, use_cache=1):
+ mylist = self.cpv_all(use_cache=use_cache)
+ d={}
+ for y in mylist:
+ if y[0] == '*':
+ y = y[1:]
+ try:
+ mysplit = catpkgsplit(y)
+ except InvalidData:
+ self.invalidentry(self.getpath(y))
+ continue
+ if not mysplit:
+ self.invalidentry(self.getpath(y))
+ continue
+ d[mysplit[0]+"/"+mysplit[1]] = None
+ return list(d)
+
+ def checkblockers(self, origdep):
+ pass
+
+ def _clear_cache(self):
+ self.mtdircache.clear()
+ self.matchcache.clear()
+ self.cpcache.clear()
+ self._aux_cache_obj = None
+
+ def _add(self, pkg_dblink):
+ self._pkgs_changed = True
+ self._clear_pkg_cache(pkg_dblink)
+
+ def _remove(self, pkg_dblink):
+ self._pkgs_changed = True
+ self._clear_pkg_cache(pkg_dblink)
+
+ def _clear_pkg_cache(self, pkg_dblink):
+ # Due to 1 second mtime granularity in <python-2.5, mtime checks
+ # are not always sufficient to invalidate vardbapi caches. Therefore,
+ # the caches need to be actively invalidated here.
+ self.mtdircache.pop(pkg_dblink.cat, None)
+ self.matchcache.pop(pkg_dblink.cat, None)
+ self.cpcache.pop(pkg_dblink.mysplit[0], None)
+ dircache.pop(pkg_dblink.dbcatdir, None)
+
+ def match(self, origdep, use_cache=1):
+ "caching match function"
+ mydep = dep_expand(
+ origdep, mydb=self, use_cache=use_cache, settings=self.settings)
+ mykey = dep_getkey(mydep)
+ mycat = catsplit(mykey)[0]
+ if not use_cache:
+ if mycat in self.matchcache:
+ del self.mtdircache[mycat]
+ del self.matchcache[mycat]
+ return list(self._iter_match(mydep,
+ self.cp_list(mydep.cp, use_cache=use_cache)))
+ try:
+ curmtime = os.stat(os.path.join(self._eroot, VDB_PATH, mycat)).st_mtime
+ except (IOError, OSError):
+ curmtime=0
+
+ if mycat not in self.matchcache or \
+ self.mtdircache[mycat] != curmtime:
+ # clear cache entry
+ self.mtdircache[mycat] = curmtime
+ self.matchcache[mycat] = {}
+ if mydep not in self.matchcache[mycat]:
+ mymatch = list(self._iter_match(mydep,
+ self.cp_list(mydep.cp, use_cache=use_cache)))
+ self.matchcache[mycat][mydep] = mymatch
+ return self.matchcache[mycat][mydep][:]
+
+ def findname(self, mycpv, myrepo=None):
+ return self.getpath(str(mycpv), filename=catsplit(mycpv)[1]+".ebuild")
+
+ def flush_cache(self):
+ """If the current user has permission and the internal aux_get cache has
+ been updated, save it to disk and mark it unmodified. This is called
+ by emerge after it has loaded the full vdb for use in dependency
+ calculations. Currently, the cache is only written if the user has
+ superuser privileges (since that's required to obtain a lock), but all
+ users have read access and benefit from faster metadata lookups (as
+ long as at least part of the cache is still valid)."""
+ if self._flush_cache_enabled and \
+ self._aux_cache is not None and \
+ len(self._aux_cache["modified"]) >= self._aux_cache_threshold and \
+ secpass >= 2:
+ self._owners.populate() # index any unindexed contents
+ valid_nodes = set(self.cpv_all())
+ for cpv in list(self._aux_cache["packages"]):
+ if cpv not in valid_nodes:
+ del self._aux_cache["packages"][cpv]
+ del self._aux_cache["modified"]
+ try:
+ f = atomic_ofstream(self._aux_cache_filename, 'wb')
+ pickle.dump(self._aux_cache, f, protocol=2)
+ f.close()
+ apply_secpass_permissions(
+ self._aux_cache_filename, gid=portage_gid, mode=0o644)
+ except (IOError, OSError) as e:
+ pass
+ self._aux_cache["modified"] = set()
+
+ @property
+ def _aux_cache(self):
+ if self._aux_cache_obj is None:
+ self._aux_cache_init()
+ return self._aux_cache_obj
+
+ def _aux_cache_init(self):
+ aux_cache = None
+ open_kwargs = {}
+ if sys.hexversion >= 0x3000000:
+ # Buffered io triggers extreme performance issues in
+ # Unpickler.load() (problem observed with python-3.0.1).
+ # Unfortunately, performance is still poor relative to
+ # python-2.x, but buffering makes it much worse.
+ open_kwargs["buffering"] = 0
+ try:
+ f = open(_unicode_encode(self._aux_cache_filename,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='rb', **open_kwargs)
+ mypickle = pickle.Unpickler(f)
+ try:
+ mypickle.find_global = None
+ except AttributeError:
+ # TODO: If py3k, override Unpickler.find_class().
+ pass
+ aux_cache = mypickle.load()
+ f.close()
+ del f
+ except (IOError, OSError, EOFError, ValueError, pickle.UnpicklingError) as e:
+ if isinstance(e, pickle.UnpicklingError):
+ writemsg(_unicode_decode(_("!!! Error loading '%s': %s\n")) % \
+ (self._aux_cache_filename, e), noiselevel=-1)
+ del e
+
+ if not aux_cache or \
+ not isinstance(aux_cache, dict) or \
+ aux_cache.get("version") != self._aux_cache_version or \
+ not aux_cache.get("packages"):
+ aux_cache = {"version": self._aux_cache_version}
+ aux_cache["packages"] = {}
+
+ owners = aux_cache.get("owners")
+ if owners is not None:
+ if not isinstance(owners, dict):
+ owners = None
+ elif "version" not in owners:
+ owners = None
+ elif owners["version"] != self._owners_cache_version:
+ owners = None
+ elif "base_names" not in owners:
+ owners = None
+ elif not isinstance(owners["base_names"], dict):
+ owners = None
+
+ if owners is None:
+ owners = {
+ "base_names" : {},
+ "version" : self._owners_cache_version
+ }
+ aux_cache["owners"] = owners
+
+ aux_cache["modified"] = set()
+ self._aux_cache_obj = aux_cache
+
+ def aux_get(self, mycpv, wants, myrepo = None):
+ """This automatically caches selected keys that are frequently needed
+ by emerge for dependency calculations. The cached metadata is
+ considered valid if the mtime of the package directory has not changed
+ since the data was cached. The cache is stored in a pickled dict
+ object with the following format:
+
+ {version:"1", "packages":{cpv1:(mtime,{k1,v1, k2,v2, ...}), cpv2...}}
+
+ If an error occurs while loading the cache pickle or the version is
+ unrecognized, the cache will simple be recreated from scratch (it is
+ completely disposable).
+ """
+ cache_these_wants = self._aux_cache_keys.intersection(wants)
+ for x in wants:
+ if self._aux_cache_keys_re.match(x) is not None:
+ cache_these_wants.add(x)
+
+ if not cache_these_wants:
+ return self._aux_get(mycpv, wants)
+
+ cache_these = set(self._aux_cache_keys)
+ cache_these.update(cache_these_wants)
+
+ mydir = self.getpath(mycpv)
+ mydir_stat = None
+ try:
+ mydir_stat = os.stat(mydir)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ raise KeyError(mycpv)
+ mydir_mtime = mydir_stat[stat.ST_MTIME]
+ pkg_data = self._aux_cache["packages"].get(mycpv)
+ pull_me = cache_these.union(wants)
+ mydata = {"_mtime_" : mydir_mtime}
+ cache_valid = False
+ cache_incomplete = False
+ cache_mtime = None
+ metadata = None
+ if pkg_data is not None:
+ if not isinstance(pkg_data, tuple) or len(pkg_data) != 2:
+ pkg_data = None
+ else:
+ cache_mtime, metadata = pkg_data
+ if not isinstance(cache_mtime, (long, int)) or \
+ not isinstance(metadata, dict):
+ pkg_data = None
+
+ if pkg_data:
+ cache_mtime, metadata = pkg_data
+ cache_valid = cache_mtime == mydir_mtime
+ if cache_valid:
+ # Migrate old metadata to unicode.
+ for k, v in metadata.items():
+ metadata[k] = _unicode_decode(v,
+ encoding=_encodings['repo.content'], errors='replace')
+
+ mydata.update(metadata)
+ pull_me.difference_update(mydata)
+
+ if pull_me:
+ # pull any needed data and cache it
+ aux_keys = list(pull_me)
+ for k, v in zip(aux_keys,
+ self._aux_get(mycpv, aux_keys, st=mydir_stat)):
+ mydata[k] = v
+ if not cache_valid or cache_these.difference(metadata):
+ cache_data = {}
+ if cache_valid and metadata:
+ cache_data.update(metadata)
+ for aux_key in cache_these:
+ cache_data[aux_key] = mydata[aux_key]
+ self._aux_cache["packages"][mycpv] = (mydir_mtime, cache_data)
+ self._aux_cache["modified"].add(mycpv)
+
+ if _slot_re.match(mydata['SLOT']) is None:
+ # Empty or invalid slot triggers InvalidAtom exceptions when
+ # generating slot atoms for packages, so translate it to '0' here.
+ mydata['SLOT'] = _unicode_decode('0')
+
+ return [mydata[x] for x in wants]
+
+ def _aux_get(self, mycpv, wants, st=None):
+ mydir = self.getpath(mycpv)
+ if st is None:
+ try:
+ st = os.stat(mydir)
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ raise KeyError(mycpv)
+ elif e.errno == PermissionDenied.errno:
+ raise PermissionDenied(mydir)
+ else:
+ raise
+ if not stat.S_ISDIR(st.st_mode):
+ raise KeyError(mycpv)
+ results = []
+ for x in wants:
+ if x == "_mtime_":
+ results.append(st[stat.ST_MTIME])
+ continue
+ try:
+ myf = io.open(
+ _unicode_encode(os.path.join(mydir, x),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'],
+ errors='replace')
+ try:
+ myd = myf.read()
+ finally:
+ myf.close()
+ # Preserve \n for metadata that is known to
+ # contain multiple lines.
+ if self._aux_multi_line_re.match(x) is None:
+ myd = " ".join(myd.split())
+ except IOError:
+ myd = _unicode_decode('')
+ if x == "EAPI" and not myd:
+ results.append(_unicode_decode('0'))
+ else:
+ results.append(myd)
+ return results
+
+ def aux_update(self, cpv, values):
+ mylink = self._dblink(cpv)
+ if not mylink.exists():
+ raise KeyError(cpv)
+ self._bump_mtime(cpv)
+ self._clear_pkg_cache(mylink)
+ for k, v in values.items():
+ if v:
+ mylink.setfile(k, v)
+ else:
+ try:
+ os.unlink(os.path.join(self.getpath(cpv), k))
+ except EnvironmentError:
+ pass
+ self._bump_mtime(cpv)
+
+ def counter_tick(self, myroot=None, mycpv=None):
+ """
+ @param myroot: ignored, self._eroot is used instead
+ """
+ return self.counter_tick_core(incrementing=1, mycpv=mycpv)
+
+ def get_counter_tick_core(self, myroot=None, mycpv=None):
+ """
+ Use this method to retrieve the counter instead
+ of having to trust the value of a global counter
+ file that can lead to invalid COUNTER
+ generation. When cache is valid, the package COUNTER
+ files are not read and we rely on the timestamp of
+ the package directory to validate cache. The stat
+ calls should only take a short time, so performance
+ is sufficient without having to rely on a potentially
+ corrupt global counter file.
+
+ The global counter file located at
+ $CACHE_PATH/counter serves to record the
+ counter of the last installed package and
+ it also corresponds to the total number of
+ installation actions that have occurred in
+ the history of this package database.
+
+ @param myroot: ignored, self._eroot is used instead
+ """
+ myroot = None
+ new_vdb = False
+ counter = -1
+ try:
+ cfile = io.open(
+ _unicode_encode(self._counter_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'],
+ errors='replace')
+ except EnvironmentError as e:
+ new_vdb = not bool(self.cpv_all())
+ if not new_vdb:
+ writemsg(_("!!! Unable to read COUNTER file: '%s'\n") % \
+ self._counter_path, noiselevel=-1)
+ writemsg("!!! %s\n" % str(e), noiselevel=-1)
+ del e
+ else:
+ try:
+ try:
+ counter = long(cfile.readline().strip())
+ finally:
+ cfile.close()
+ except (OverflowError, ValueError) as e:
+ writemsg(_("!!! COUNTER file is corrupt: '%s'\n") % \
+ self._counter_path, noiselevel=-1)
+ writemsg("!!! %s\n" % str(e), noiselevel=-1)
+ del e
+
+ if self._cached_counter == counter:
+ max_counter = counter
+ else:
+ # We must ensure that we return a counter
+ # value that is at least as large as the
+ # highest one from the installed packages,
+ # since having a corrupt value that is too low
+ # can trigger incorrect AUTOCLEAN behavior due
+ # to newly installed packages having lower
+ # COUNTERs than the previous version in the
+ # same slot.
+ max_counter = counter
+ for cpv in self.cpv_all():
+ try:
+ pkg_counter = int(self.aux_get(cpv, ["COUNTER"])[0])
+ except (KeyError, OverflowError, ValueError):
+ continue
+ if pkg_counter > max_counter:
+ max_counter = pkg_counter
+
+ if counter < 0 and not new_vdb:
+ writemsg(_("!!! Initializing COUNTER to " \
+ "value of %d\n") % max_counter, noiselevel=-1)
+
+ return max_counter + 1
+
+ def counter_tick_core(self, myroot=None, incrementing=1, mycpv=None):
+ """
+ This method will grab the next COUNTER value and record it back
+ to the global file. Note that every package install must have
+ a unique counter, since a slotmove update can move two packages
+ into the same SLOT and in that case it's important that both
+ packages have different COUNTER metadata.
+
+ @param myroot: ignored, self._eroot is used instead
+ @param mycpv: ignored
+ @rtype: int
+ @returns: new counter value
+ """
+ myroot = None
+ mycpv = None
+ self.lock()
+ try:
+ counter = self.get_counter_tick_core() - 1
+ if incrementing:
+ #increment counter
+ counter += 1
+ # update new global counter file
+ try:
+ write_atomic(self._counter_path, str(counter))
+ except InvalidLocation:
+ self.settings._init_dirs()
+ write_atomic(self._counter_path, str(counter))
+ self._cached_counter = counter
+
+ # Since we hold a lock, this is a good opportunity
+ # to flush the cache. Note that this will only
+ # flush the cache periodically in the main process
+ # when _aux_cache_threshold is exceeded.
+ self.flush_cache()
+ finally:
+ self.unlock()
+
+ return counter
+
+ def _dblink(self, cpv):
+ category, pf = catsplit(cpv)
+ return dblink(category, pf, settings=self.settings,
+ vartree=self.vartree, treetype="vartree")
+
+ def removeFromContents(self, pkg, paths, relative_paths=True):
+ """
+ @param pkg: cpv for an installed package
+ @type pkg: string
+ @param paths: paths of files to remove from contents
+ @type paths: iterable
+ """
+ if not hasattr(pkg, "getcontents"):
+ pkg = self._dblink(pkg)
+ root = self.settings['ROOT']
+ root_len = len(root) - 1
+ new_contents = pkg.getcontents().copy()
+ removed = 0
+
+ for filename in paths:
+ filename = _unicode_decode(filename,
+ encoding=_encodings['content'], errors='strict')
+ filename = normalize_path(filename)
+ if relative_paths:
+ relative_filename = filename
+ else:
+ relative_filename = filename[root_len:]
+ contents_key = pkg._match_contents(relative_filename)
+ if contents_key:
+ del new_contents[contents_key]
+ removed += 1
+
+ if removed:
+ self._bump_mtime(pkg.mycpv)
+ f = atomic_ofstream(os.path.join(pkg.dbdir, "CONTENTS"))
+ write_contents(new_contents, root, f)
+ f.close()
+ self._bump_mtime(pkg.mycpv)
+ pkg._clear_contents_cache()
+
+ class _owners_cache(object):
+ """
+ This class maintains an hash table that serves to index package
+ contents by mapping the basename of file to a list of possible
+ packages that own it. This is used to optimize owner lookups
+ by narrowing the search down to a smaller number of packages.
+ """
+ try:
+ from hashlib import md5 as _new_hash
+ except ImportError:
+ from md5 import new as _new_hash
+
+ _hash_bits = 16
+ _hex_chars = int(_hash_bits / 4)
+
+ def __init__(self, vardb):
+ self._vardb = vardb
+
+ def add(self, cpv):
+ eroot_len = len(self._vardb._eroot)
+ contents = self._vardb._dblink(cpv).getcontents()
+ pkg_hash = self._hash_pkg(cpv)
+ if not contents:
+ # Empty path is a code used to represent empty contents.
+ self._add_path("", pkg_hash)
+
+ for x in contents:
+ self._add_path(x[eroot_len:], pkg_hash)
+
+ self._vardb._aux_cache["modified"].add(cpv)
+
+ def _add_path(self, path, pkg_hash):
+ """
+ Empty path is a code that represents empty contents.
+ """
+ if path:
+ name = os.path.basename(path.rstrip(os.path.sep))
+ if not name:
+ return
+ else:
+ name = path
+ name_hash = self._hash_str(name)
+ base_names = self._vardb._aux_cache["owners"]["base_names"]
+ pkgs = base_names.get(name_hash)
+ if pkgs is None:
+ pkgs = {}
+ base_names[name_hash] = pkgs
+ pkgs[pkg_hash] = None
+
+ def _hash_str(self, s):
+ h = self._new_hash()
+ # Always use a constant utf_8 encoding here, since
+ # the "default" encoding can change.
+ h.update(_unicode_encode(s,
+ encoding=_encodings['repo.content'],
+ errors='backslashreplace'))
+ h = h.hexdigest()
+ h = h[-self._hex_chars:]
+ h = int(h, 16)
+ return h
+
+ def _hash_pkg(self, cpv):
+ counter, mtime = self._vardb.aux_get(
+ cpv, ["COUNTER", "_mtime_"])
+ try:
+ counter = int(counter)
+ except ValueError:
+ counter = 0
+ return (cpv, counter, mtime)
+
+ class _owners_db(object):
+
+ def __init__(self, vardb):
+ self._vardb = vardb
+
+ def populate(self):
+ self._populate()
+
+ def _populate(self):
+ owners_cache = vardbapi._owners_cache(self._vardb)
+ cached_hashes = set()
+ base_names = self._vardb._aux_cache["owners"]["base_names"]
+
+ # Take inventory of all cached package hashes.
+ for name, hash_values in list(base_names.items()):
+ if not isinstance(hash_values, dict):
+ del base_names[name]
+ continue
+ cached_hashes.update(hash_values)
+
+ # Create sets of valid package hashes and uncached packages.
+ uncached_pkgs = set()
+ hash_pkg = owners_cache._hash_pkg
+ valid_pkg_hashes = set()
+ for cpv in self._vardb.cpv_all():
+ hash_value = hash_pkg(cpv)
+ valid_pkg_hashes.add(hash_value)
+ if hash_value not in cached_hashes:
+ uncached_pkgs.add(cpv)
+
+ # Cache any missing packages.
+ for cpv in uncached_pkgs:
+ owners_cache.add(cpv)
+
+ # Delete any stale cache.
+ stale_hashes = cached_hashes.difference(valid_pkg_hashes)
+ if stale_hashes:
+ for base_name_hash, bucket in list(base_names.items()):
+ for hash_value in stale_hashes.intersection(bucket):
+ del bucket[hash_value]
+ if not bucket:
+ del base_names[base_name_hash]
+
+ return owners_cache
+
+ def get_owners(self, path_iter):
+ """
+ @return the owners as a dblink -> set(files) mapping.
+ """
+ owners = {}
+ for owner, f in self.iter_owners(path_iter):
+ owned_files = owners.get(owner)
+ if owned_files is None:
+ owned_files = set()
+ owners[owner] = owned_files
+ owned_files.add(f)
+ return owners
+
+ def getFileOwnerMap(self, path_iter):
+ owners = self.get_owners(path_iter)
+ file_owners = {}
+ for pkg_dblink, files in owners.items():
+ for f in files:
+ owner_set = file_owners.get(f)
+ if owner_set is None:
+ owner_set = set()
+ file_owners[f] = owner_set
+ owner_set.add(pkg_dblink)
+ return file_owners
+
+ def iter_owners(self, path_iter):
+ """
+ Iterate over tuples of (dblink, path). In order to avoid
+ consuming too many resources for too much time, resources
+ are only allocated for the duration of a given iter_owners()
+ call. Therefore, to maximize reuse of resources when searching
+ for multiple files, it's best to search for them all in a single
+ call.
+ """
+
+ if not isinstance(path_iter, list):
+ path_iter = list(path_iter)
+ owners_cache = self._populate()
+ vardb = self._vardb
+ root = vardb._eroot
+ hash_pkg = owners_cache._hash_pkg
+ hash_str = owners_cache._hash_str
+ base_names = self._vardb._aux_cache["owners"]["base_names"]
+
+ dblink_cache = {}
+
+ def dblink(cpv):
+ x = dblink_cache.get(cpv)
+ if x is None:
+ if len(dblink_cache) > 20:
+ # Ensure that we don't run out of memory.
+ raise StopIteration()
+ x = self._vardb._dblink(cpv)
+ dblink_cache[cpv] = x
+ return x
+
+ while path_iter:
+
+ path = path_iter.pop()
+ is_basename = os.sep != path[:1]
+ if is_basename:
+ name = path
+ else:
+ name = os.path.basename(path.rstrip(os.path.sep))
+
+ if not name:
+ continue
+
+ name_hash = hash_str(name)
+ pkgs = base_names.get(name_hash)
+ owners = []
+ if pkgs is not None:
+ try:
+ for hash_value in pkgs:
+ if not isinstance(hash_value, tuple) or \
+ len(hash_value) != 3:
+ continue
+ cpv, counter, mtime = hash_value
+ if not isinstance(cpv, basestring):
+ continue
+ try:
+ current_hash = hash_pkg(cpv)
+ except KeyError:
+ continue
+
+ if current_hash != hash_value:
+ continue
+
+ if is_basename:
+ for p in dblink(cpv).getcontents():
+ if os.path.basename(p) == name:
+ owners.append((cpv, p[len(root):]))
+ else:
+ if dblink(cpv).isowner(path):
+ owners.append((cpv, path))
+
+ except StopIteration:
+ path_iter.append(path)
+ del owners[:]
+ dblink_cache.clear()
+ gc.collect()
+ for x in self._iter_owners_low_mem(path_iter):
+ yield x
+ return
+ else:
+ for cpv, p in owners:
+ yield (dblink(cpv), p)
+
+ def _iter_owners_low_mem(self, path_list):
+ """
+ This implemention will make a short-lived dblink instance (and
+ parse CONTENTS) for every single installed package. This is
+ slower and but uses less memory than the method which uses the
+ basename cache.
+ """
+
+ if not path_list:
+ return
+
+ path_info_list = []
+ for path in path_list:
+ is_basename = os.sep != path[:1]
+ if is_basename:
+ name = path
+ else:
+ name = os.path.basename(path.rstrip(os.path.sep))
+ path_info_list.append((path, name, is_basename))
+
+ root = self._vardb._eroot
+ for cpv in self._vardb.cpv_all():
+ dblnk = self._vardb._dblink(cpv)
+
+ for path, name, is_basename in path_info_list:
+ if is_basename:
+ for p in dblnk.getcontents():
+ if os.path.basename(p) == name:
+ yield dblnk, p[len(root):]
+ else:
+ if dblnk.isowner(path):
+ yield dblnk, path
+
+class vartree(object):
+ "this tree will scan a var/db/pkg database located at root (passed to init)"
+ def __init__(self, root=None, virtual=None, categories=None,
+ settings=None):
+
+ if settings is None:
+ settings = portage.settings
+ self.root = settings['ROOT']
+
+ if root is not None and root != self.root:
+ warnings.warn("The 'root' parameter of the " + \
+ "portage.dbapi.vartree.vartree" + \
+ " constructor is now unused. Use " + \
+ "settings['ROOT'] instead.",
+ DeprecationWarning, stacklevel=2)
+
+ self.settings = settings
+ self.dbapi = vardbapi(settings=settings, vartree=self)
+ self.populated = 1
+
+ def getpath(self, mykey, filename=None):
+ return self.dbapi.getpath(mykey, filename=filename)
+
+ def zap(self, mycpv):
+ return
+
+ def inject(self, mycpv):
+ return
+
+ def get_provide(self, mycpv):
+ myprovides = []
+ mylines = None
+ try:
+ mylines, myuse = self.dbapi.aux_get(mycpv, ["PROVIDE", "USE"])
+ if mylines:
+ myuse = myuse.split()
+ mylines = use_reduce(mylines, uselist=myuse, flat=True)
+ for myprovide in mylines:
+ mys = catpkgsplit(myprovide)
+ if not mys:
+ mys = myprovide.split("/")
+ myprovides += [mys[0] + "/" + mys[1]]
+ return myprovides
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ mydir = self.dbapi.getpath(mycpv)
+ writemsg(_("\nParse Error reading PROVIDE and USE in '%s'\n") % mydir,
+ noiselevel=-1)
+ if mylines:
+ writemsg(_("Possibly Invalid: '%s'\n") % str(mylines),
+ noiselevel=-1)
+ writemsg(_("Exception: %s\n\n") % str(e), noiselevel=-1)
+ return []
+
+ def get_all_provides(self):
+ myprovides = {}
+ for node in self.getallcpv():
+ for mykey in self.get_provide(node):
+ if mykey in myprovides:
+ myprovides[mykey] += [node]
+ else:
+ myprovides[mykey] = [node]
+ return myprovides
+
+ def dep_bestmatch(self, mydep, use_cache=1):
+ "compatibility method -- all matches, not just visible ones"
+ #mymatch=best(match(dep_expand(mydep,self.dbapi),self.dbapi))
+ mymatch = best(self.dbapi.match(
+ dep_expand(mydep, mydb=self.dbapi, settings=self.settings),
+ use_cache=use_cache))
+ if mymatch is None:
+ return ""
+ else:
+ return mymatch
+
+ def dep_match(self, mydep, use_cache=1):
+ "compatibility method -- we want to see all matches, not just visible ones"
+ #mymatch = match(mydep,self.dbapi)
+ mymatch = self.dbapi.match(mydep, use_cache=use_cache)
+ if mymatch is None:
+ return []
+ else:
+ return mymatch
+
+ def exists_specific(self, cpv):
+ return self.dbapi.cpv_exists(cpv)
+
+ def getallcpv(self):
+ """temporary function, probably to be renamed --- Gets a list of all
+ category/package-versions installed on the system."""
+ return self.dbapi.cpv_all()
+
+ def getallnodes(self):
+ """new behavior: these are all *unmasked* nodes. There may or may not be available
+ masked package for nodes in this nodes list."""
+ return self.dbapi.cp_all()
+
+ def getebuildpath(self, fullpackage):
+ cat, package = catsplit(fullpackage)
+ return self.getpath(fullpackage, filename=package+".ebuild")
+
+ def getslot(self, mycatpkg):
+ "Get a slot for a catpkg; assume it exists."
+ try:
+ return self.dbapi.aux_get(mycatpkg, ["SLOT"])[0]
+ except KeyError:
+ return ""
+
+ def populate(self):
+ self.populated=1
+
+class dblink(object):
+ """
+ This class provides an interface to the installed package database
+ At present this is implemented as a text backend in /var/db/pkg.
+ """
+
+ import re
+ _normalize_needed = re.compile(r'//|^[^/]|./$|(^|/)\.\.?(/|$)')
+
+ _contents_re = re.compile(r'^(' + \
+ r'(?P<dir>(dev|dir|fif) (.+))|' + \
+ r'(?P<obj>(obj) (.+) (\S+) (\d+))|' + \
+ r'(?P<sym>(sym) (.+) -> (.+) ((\d+)|(?P<oldsym>(' + \
+ r'\(\d+, \d+L, \d+L, \d+, \d+, \d+, \d+L, \d+, (\d+), \d+\)))))' + \
+ r')$'
+ )
+
+ def __init__(self, cat, pkg, myroot=None, settings=None, treetype=None,
+ vartree=None, blockers=None, scheduler=None, pipe=None):
+ """
+ Creates a DBlink object for a given CPV.
+ The given CPV may not be present in the database already.
+
+ @param cat: Category
+ @type cat: String
+ @param pkg: Package (PV)
+ @type pkg: String
+ @param myroot: ignored, settings['ROOT'] is used instead
+ @type myroot: String (Path)
+ @param settings: Typically portage.settings
+ @type settings: portage.config
+ @param treetype: one of ['porttree','bintree','vartree']
+ @type treetype: String
+ @param vartree: an instance of vartree corresponding to myroot.
+ @type vartree: vartree
+ """
+
+ if settings is None:
+ raise TypeError("settings argument is required")
+
+ mysettings = settings
+ myroot = settings['ROOT']
+ self.cat = cat
+ self.pkg = pkg
+ self.mycpv = self.cat + "/" + self.pkg
+ self.mysplit = list(catpkgsplit(self.mycpv)[1:])
+ self.mysplit[0] = "%s/%s" % (self.cat, self.mysplit[0])
+ self.treetype = treetype
+ if vartree is None:
+ vartree = portage.db[myroot]["vartree"]
+ self.vartree = vartree
+ self._blockers = blockers
+ self._scheduler = scheduler
+
+ # WARNING: EROOT support is experimental and may be incomplete
+ # for cases in which EPREFIX is non-empty.
+ self._eroot = mysettings['EROOT']
+ self.dbroot = normalize_path(os.path.join(self._eroot, VDB_PATH))
+ self.dbcatdir = self.dbroot+"/"+cat
+ self.dbpkgdir = self.dbcatdir+"/"+pkg
+ self.dbtmpdir = self.dbcatdir+"/-MERGING-"+pkg
+ self.dbdir = self.dbpkgdir
+ self.settings = mysettings
+ self._verbose = self.settings.get("PORTAGE_VERBOSE") == "1"
+
+ self.myroot=myroot
+ self._installed_instance = None
+ self.contentscache = None
+ self._contents_inodes = None
+ self._contents_basenames = None
+ self._linkmap_broken = False
+ self._md5_merge_map = {}
+ self._hash_key = (self.myroot, self.mycpv)
+ self._protect_obj = None
+ self._pipe = pipe
+
+ def __hash__(self):
+ return hash(self._hash_key)
+
+ def __eq__(self, other):
+ return isinstance(other, dblink) and \
+ self._hash_key == other._hash_key
+
+ def _get_protect_obj(self):
+
+ if self._protect_obj is None:
+ self._protect_obj = ConfigProtect(self._eroot,
+ portage.util.shlex_split(
+ self.settings.get("CONFIG_PROTECT", "")),
+ portage.util.shlex_split(
+ self.settings.get("CONFIG_PROTECT_MASK", "")))
+
+ return self._protect_obj
+
+ def isprotected(self, obj):
+ return self._get_protect_obj().isprotected(obj)
+
+ def updateprotect(self):
+ self._get_protect_obj().updateprotect()
+
+ def lockdb(self):
+ self.vartree.dbapi.lock()
+
+ def unlockdb(self):
+ self.vartree.dbapi.unlock()
+
+ def getpath(self):
+ "return path to location of db information (for >>> informational display)"
+ return self.dbdir
+
+ def exists(self):
+ "does the db entry exist? boolean."
+ return os.path.exists(self.dbdir)
+
+ def delete(self):
+ """
+ Remove this entry from the database
+ """
+ if not os.path.exists(self.dbdir):
+ return
+
+ # Check validity of self.dbdir before attempting to remove it.
+ if not self.dbdir.startswith(self.dbroot):
+ writemsg(_("portage.dblink.delete(): invalid dbdir: %s\n") % \
+ self.dbdir, noiselevel=-1)
+ return
+
+ shutil.rmtree(self.dbdir)
+ # If empty, remove parent category directory.
+ try:
+ os.rmdir(os.path.dirname(self.dbdir))
+ except OSError:
+ pass
+ self.vartree.dbapi._remove(self)
+
+ def clearcontents(self):
+ """
+ For a given db entry (self), erase the CONTENTS values.
+ """
+ self.lockdb()
+ try:
+ if os.path.exists(self.dbdir+"/CONTENTS"):
+ os.unlink(self.dbdir+"/CONTENTS")
+ finally:
+ self.unlockdb()
+
+ def _clear_contents_cache(self):
+ self.contentscache = None
+ self._contents_inodes = None
+ self._contents_basenames = None
+
+ def getcontents(self):
+ """
+ Get the installed files of a given package (aka what that package installed)
+ """
+ contents_file = os.path.join(self.dbdir, "CONTENTS")
+ if self.contentscache is not None:
+ return self.contentscache
+ pkgfiles = {}
+ try:
+ myc = io.open(_unicode_encode(contents_file,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'],
+ errors='replace')
+ except EnvironmentError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ self.contentscache = pkgfiles
+ return pkgfiles
+ mylines = myc.readlines()
+ myc.close()
+ null_byte = "\0"
+ normalize_needed = self._normalize_needed
+ contents_re = self._contents_re
+ obj_index = contents_re.groupindex['obj']
+ dir_index = contents_re.groupindex['dir']
+ sym_index = contents_re.groupindex['sym']
+ # The old symlink format may exist on systems that have packages
+ # which were installed many years ago (see bug #351814).
+ oldsym_index = contents_re.groupindex['oldsym']
+ # CONTENTS files already contain EPREFIX
+ myroot = self.settings['ROOT']
+ if myroot == os.path.sep:
+ myroot = None
+ # used to generate parent dir entries
+ dir_entry = (_unicode_decode("dir"),)
+ eroot_split_len = len(self.settings["EROOT"].split(os.sep)) - 1
+ pos = 0
+ errors = []
+ for pos, line in enumerate(mylines):
+ if null_byte in line:
+ # Null bytes are a common indication of corruption.
+ errors.append((pos + 1, _("Null byte found in CONTENTS entry")))
+ continue
+ line = line.rstrip("\n")
+ m = contents_re.match(line)
+ if m is None:
+ errors.append((pos + 1, _("Unrecognized CONTENTS entry")))
+ continue
+
+ if m.group(obj_index) is not None:
+ base = obj_index
+ #format: type, mtime, md5sum
+ data = (m.group(base+1), m.group(base+4), m.group(base+3))
+ elif m.group(dir_index) is not None:
+ base = dir_index
+ #format: type
+ data = (m.group(base+1),)
+ elif m.group(sym_index) is not None:
+ base = sym_index
+ if m.group(oldsym_index) is None:
+ mtime = m.group(base+5)
+ else:
+ mtime = m.group(base+8)
+ #format: type, mtime, dest
+ data = (m.group(base+1), mtime, m.group(base+3))
+ else:
+ # This won't happen as long the regular expression
+ # is written to only match valid entries.
+ raise AssertionError(_("required group not found " + \
+ "in CONTENTS entry: '%s'") % line)
+
+ path = m.group(base+2)
+ if normalize_needed.search(path) is not None:
+ path = normalize_path(path)
+ if not path.startswith(os.path.sep):
+ path = os.path.sep + path
+
+ if myroot is not None:
+ path = os.path.join(myroot, path.lstrip(os.path.sep))
+
+ # Implicitly add parent directories, since we can't necessarily
+ # assume that they are explicitly listed in CONTENTS, and it's
+ # useful for callers if they can rely on parent directory entries
+ # being generated here (crucial for things like dblink.isowner()).
+ path_split = path.split(os.sep)
+ path_split.pop()
+ while len(path_split) > eroot_split_len:
+ parent = os.sep.join(path_split)
+ if parent in pkgfiles:
+ break
+ pkgfiles[parent] = dir_entry
+ path_split.pop()
+
+ pkgfiles[path] = data
+
+ if errors:
+ writemsg(_("!!! Parse error in '%s'\n") % contents_file, noiselevel=-1)
+ for pos, e in errors:
+ writemsg(_("!!! line %d: %s\n") % (pos, e), noiselevel=-1)
+ self.contentscache = pkgfiles
+ return pkgfiles
+
+ def _prune_plib_registry(self, unmerge=False,
+ needed=None, preserve_paths=None):
+ # remove preserved libraries that don't have any consumers left
+ if not (self._linkmap_broken or
+ self.vartree.dbapi._linkmap is None or
+ self.vartree.dbapi._plib_registry is None):
+ self.vartree.dbapi._fs_lock()
+ plib_registry = self.vartree.dbapi._plib_registry
+ plib_registry.lock()
+ try:
+ plib_registry.load()
+
+ unmerge_with_replacement = \
+ unmerge and preserve_paths is not None
+ if unmerge_with_replacement:
+ # If self.mycpv is about to be unmerged and we
+ # have a replacement package, we want to exclude
+ # the irrelevant NEEDED data that belongs to
+ # files which are being unmerged now.
+ exclude_pkgs = (self.mycpv,)
+ else:
+ exclude_pkgs = None
+
+ self._linkmap_rebuild(exclude_pkgs=exclude_pkgs,
+ include_file=needed, preserve_paths=preserve_paths)
+
+ if unmerge:
+ unmerge_preserve = None
+ if not unmerge_with_replacement:
+ unmerge_preserve = \
+ self._find_libs_to_preserve(unmerge=True)
+ counter = self.vartree.dbapi.cpv_counter(self.mycpv)
+ plib_registry.unregister(self.mycpv,
+ self.settings["SLOT"], counter)
+ if unmerge_preserve:
+ for path in sorted(unmerge_preserve):
+ contents_key = self._match_contents(path)
+ if not contents_key:
+ continue
+ obj_type = self.getcontents()[contents_key][0]
+ self._display_merge(_(">>> needed %s %s\n") % \
+ (obj_type, contents_key), noiselevel=-1)
+ plib_registry.register(self.mycpv,
+ self.settings["SLOT"], counter, unmerge_preserve)
+ # Remove the preserved files from our contents
+ # so that they won't be unmerged.
+ self.vartree.dbapi.removeFromContents(self,
+ unmerge_preserve)
+
+ unmerge_no_replacement = \
+ unmerge and not unmerge_with_replacement
+ cpv_lib_map = self._find_unused_preserved_libs(
+ unmerge_no_replacement)
+ if cpv_lib_map:
+ self._remove_preserved_libs(cpv_lib_map)
+ self.vartree.dbapi.lock()
+ try:
+ for cpv, removed in cpv_lib_map.items():
+ if not self.vartree.dbapi.cpv_exists(cpv):
+ continue
+ self.vartree.dbapi.removeFromContents(cpv, removed)
+ finally:
+ self.vartree.dbapi.unlock()
+
+ plib_registry.store()
+ finally:
+ plib_registry.unlock()
+ self.vartree.dbapi._fs_unlock()
+
+ def unmerge(self, pkgfiles=None, trimworld=None, cleanup=True,
+ ldpath_mtimes=None, others_in_slot=None, needed=None,
+ preserve_paths=None):
+ """
+ Calls prerm
+ Unmerges a given package (CPV)
+ calls postrm
+ calls cleanrm
+ calls env_update
+
+ @param pkgfiles: files to unmerge (generally self.getcontents() )
+ @type pkgfiles: Dictionary
+ @param trimworld: Unused
+ @type trimworld: Boolean
+ @param cleanup: cleanup to pass to doebuild (see doebuild)
+ @type cleanup: Boolean
+ @param ldpath_mtimes: mtimes to pass to env_update (see env_update)
+ @type ldpath_mtimes: Dictionary
+ @param others_in_slot: all dblink instances in this slot, excluding self
+ @type others_in_slot: list
+ @param needed: Filename containing libraries needed after unmerge.
+ @type needed: String
+ @param preserve_paths: Libraries preserved by a package instance that
+ is currently being merged. They need to be explicitly passed to the
+ LinkageMap, since they are not registered in the
+ PreservedLibsRegistry yet.
+ @type preserve_paths: set
+ @rtype: Integer
+ @returns:
+ 1. os.EX_OK if everything went well.
+ 2. return code of the failed phase (for prerm, postrm, cleanrm)
+ """
+
+ if trimworld is not None:
+ warnings.warn("The trimworld parameter of the " + \
+ "portage.dbapi.vartree.dblink.unmerge()" + \
+ " method is now unused.",
+ DeprecationWarning, stacklevel=2)
+
+ background = False
+ log_path = self.settings.get("PORTAGE_LOG_FILE")
+ if self._scheduler is None:
+ # We create a scheduler instance and use it to
+ # log unmerge output separately from merge output.
+ self._scheduler = PollScheduler().sched_iface
+ if self.settings.get("PORTAGE_BACKGROUND") == "subprocess":
+ if self.settings.get("PORTAGE_BACKGROUND_UNMERGE") == "1":
+ self.settings["PORTAGE_BACKGROUND"] = "1"
+ self.settings.backup_changes("PORTAGE_BACKGROUND")
+ background = True
+ elif self.settings.get("PORTAGE_BACKGROUND_UNMERGE") == "0":
+ self.settings["PORTAGE_BACKGROUND"] = "0"
+ self.settings.backup_changes("PORTAGE_BACKGROUND")
+ elif self.settings.get("PORTAGE_BACKGROUND") == "1":
+ background = True
+
+ self.vartree.dbapi._bump_mtime(self.mycpv)
+ showMessage = self._display_merge
+ if self.vartree.dbapi._categories is not None:
+ self.vartree.dbapi._categories = None
+ # When others_in_slot is supplied, the security check has already been
+ # done for this slot, so it shouldn't be repeated until the next
+ # replacement or unmerge operation.
+ if others_in_slot is None:
+ slot = self.vartree.dbapi.aux_get(self.mycpv, ["SLOT"])[0]
+ slot_matches = self.vartree.dbapi.match(
+ "%s:%s" % (portage.cpv_getkey(self.mycpv), slot))
+ others_in_slot = []
+ for cur_cpv in slot_matches:
+ if cur_cpv == self.mycpv:
+ continue
+ others_in_slot.append(dblink(self.cat, catsplit(cur_cpv)[1],
+ settings=self.settings, vartree=self.vartree,
+ treetype="vartree", pipe=self._pipe))
+
+ retval = self._security_check([self] + others_in_slot)
+ if retval:
+ return retval
+
+ contents = self.getcontents()
+ # Now, don't assume that the name of the ebuild is the same as the
+ # name of the dir; the package may have been moved.
+ myebuildpath = os.path.join(self.dbdir, self.pkg + ".ebuild")
+ failures = 0
+ ebuild_phase = "prerm"
+ mystuff = os.listdir(self.dbdir)
+ for x in mystuff:
+ if x.endswith(".ebuild"):
+ if x[:-7] != self.pkg:
+ # Clean up after vardbapi.move_ent() breakage in
+ # portage versions before 2.1.2
+ os.rename(os.path.join(self.dbdir, x), myebuildpath)
+ write_atomic(os.path.join(self.dbdir, "PF"), self.pkg+"\n")
+ break
+
+ if self.mycpv != self.settings.mycpv or \
+ "EAPI" not in self.settings.configdict["pkg"]:
+ # We avoid a redundant setcpv call here when
+ # the caller has already taken care of it.
+ self.settings.setcpv(self.mycpv, mydb=self.vartree.dbapi)
+
+ eapi_unsupported = False
+ try:
+ doebuild_environment(myebuildpath, "prerm",
+ settings=self.settings, db=self.vartree.dbapi)
+ except UnsupportedAPIException as e:
+ eapi_unsupported = e
+
+ self._prune_plib_registry(unmerge=True, needed=needed,
+ preserve_paths=preserve_paths)
+
+ builddir_lock = None
+ scheduler = self._scheduler
+ retval = os.EX_OK
+ try:
+ # Only create builddir_lock if the caller
+ # has not already acquired the lock.
+ if "PORTAGE_BUILDIR_LOCKED" not in self.settings:
+ builddir_lock = EbuildBuildDir(
+ scheduler=scheduler,
+ settings=self.settings)
+ builddir_lock.lock()
+ prepare_build_dirs(settings=self.settings, cleanup=True)
+ log_path = self.settings.get("PORTAGE_LOG_FILE")
+
+ # Log the error after PORTAGE_LOG_FILE is initialized
+ # by prepare_build_dirs above.
+ if eapi_unsupported:
+ # Sometimes this happens due to corruption of the EAPI file.
+ failures += 1
+ showMessage(_("!!! FAILED prerm: %s\n") % \
+ os.path.join(self.dbdir, "EAPI"),
+ level=logging.ERROR, noiselevel=-1)
+ showMessage(_unicode_decode("%s\n") % (eapi_unsupported,),
+ level=logging.ERROR, noiselevel=-1)
+ elif os.path.isfile(myebuildpath):
+ phase = EbuildPhase(background=background,
+ phase=ebuild_phase, scheduler=scheduler,
+ settings=self.settings)
+ phase.start()
+ retval = phase.wait()
+
+ # XXX: Decide how to handle failures here.
+ if retval != os.EX_OK:
+ failures += 1
+ showMessage(_("!!! FAILED prerm: %s\n") % retval,
+ level=logging.ERROR, noiselevel=-1)
+
+ self.vartree.dbapi._fs_lock()
+ try:
+ self._unmerge_pkgfiles(pkgfiles, others_in_slot)
+ finally:
+ self.vartree.dbapi._fs_unlock()
+ self._clear_contents_cache()
+
+ if not eapi_unsupported and os.path.isfile(myebuildpath):
+ ebuild_phase = "postrm"
+ phase = EbuildPhase(background=background,
+ phase=ebuild_phase, scheduler=scheduler,
+ settings=self.settings)
+ phase.start()
+ retval = phase.wait()
+
+ # XXX: Decide how to handle failures here.
+ if retval != os.EX_OK:
+ failures += 1
+ showMessage(_("!!! FAILED postrm: %s\n") % retval,
+ level=logging.ERROR, noiselevel=-1)
+
+ finally:
+ self.vartree.dbapi._bump_mtime(self.mycpv)
+ try:
+ if not eapi_unsupported and os.path.isfile(myebuildpath):
+ if retval != os.EX_OK:
+ msg_lines = []
+ msg = _("The '%(ebuild_phase)s' "
+ "phase of the '%(cpv)s' package "
+ "has failed with exit value %(retval)s.") % \
+ {"ebuild_phase":ebuild_phase, "cpv":self.mycpv,
+ "retval":retval}
+ from textwrap import wrap
+ msg_lines.extend(wrap(msg, 72))
+ msg_lines.append("")
+
+ ebuild_name = os.path.basename(myebuildpath)
+ ebuild_dir = os.path.dirname(myebuildpath)
+ msg = _("The problem occurred while executing "
+ "the ebuild file named '%(ebuild_name)s' "
+ "located in the '%(ebuild_dir)s' directory. "
+ "If necessary, manually remove "
+ "the environment.bz2 file and/or the "
+ "ebuild file located in that directory.") % \
+ {"ebuild_name":ebuild_name, "ebuild_dir":ebuild_dir}
+ msg_lines.extend(wrap(msg, 72))
+ msg_lines.append("")
+
+ msg = _("Removal "
+ "of the environment.bz2 file is "
+ "preferred since it may allow the "
+ "removal phases to execute successfully. "
+ "The ebuild will be "
+ "sourced and the eclasses "
+ "from the current portage tree will be used "
+ "when necessary. Removal of "
+ "the ebuild file will cause the "
+ "pkg_prerm() and pkg_postrm() removal "
+ "phases to be skipped entirely.")
+ msg_lines.extend(wrap(msg, 72))
+
+ self._eerror(ebuild_phase, msg_lines)
+
+ self._elog_process(phasefilter=("prerm", "postrm"))
+
+ if retval == os.EX_OK:
+ try:
+ doebuild_environment(myebuildpath, "cleanrm",
+ settings=self.settings, db=self.vartree.dbapi)
+ except UnsupportedAPIException:
+ pass
+ phase = EbuildPhase(background=background,
+ phase="cleanrm", scheduler=scheduler,
+ settings=self.settings)
+ phase.start()
+ retval = phase.wait()
+ finally:
+ if builddir_lock is not None:
+ builddir_lock.unlock()
+
+ if log_path is not None:
+
+ if not failures and 'unmerge-logs' not in self.settings.features:
+ try:
+ os.unlink(log_path)
+ except OSError:
+ pass
+
+ try:
+ st = os.stat(log_path)
+ except OSError:
+ pass
+ else:
+ if st.st_size == 0:
+ try:
+ os.unlink(log_path)
+ except OSError:
+ pass
+
+ if log_path is not None and os.path.exists(log_path):
+ # Restore this since it gets lost somewhere above and it
+ # needs to be set for _display_merge() to be able to log.
+ # Note that the log isn't necessarily supposed to exist
+ # since if PORT_LOGDIR is unset then it's a temp file
+ # so it gets cleaned above.
+ self.settings["PORTAGE_LOG_FILE"] = log_path
+ else:
+ self.settings.pop("PORTAGE_LOG_FILE", None)
+
+ # Lock the config memory file to prevent symlink creation
+ # in merge_contents from overlapping with env-update.
+ self.vartree.dbapi._fs_lock()
+ try:
+ env_update(target_root=self.settings['ROOT'],
+ prev_mtimes=ldpath_mtimes,
+ contents=contents, env=self.settings.environ(),
+ writemsg_level=self._display_merge)
+ finally:
+ self.vartree.dbapi._fs_unlock()
+
+ return os.EX_OK
+
+ def _display_merge(self, msg, level=0, noiselevel=0):
+ if not self._verbose and noiselevel >= 0 and level < logging.WARN:
+ return
+ if self._scheduler is None:
+ writemsg_level(msg, level=level, noiselevel=noiselevel)
+ else:
+ log_path = None
+ if self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
+ log_path = self.settings.get("PORTAGE_LOG_FILE")
+ background = self.settings.get("PORTAGE_BACKGROUND") == "1"
+
+ if background and log_path is None:
+ if level >= logging.WARN:
+ writemsg_level(msg, level=level, noiselevel=noiselevel)
+ else:
+ self._scheduler.output(msg,
+ log_path=log_path, background=background,
+ level=level, noiselevel=noiselevel)
+
+ def _unmerge_pkgfiles(self, pkgfiles, others_in_slot):
+ """
+
+ Unmerges the contents of a package from the liveFS
+ Removes the VDB entry for self
+
+ @param pkgfiles: typically self.getcontents()
+ @type pkgfiles: Dictionary { filename: [ 'type', '?', 'md5sum' ] }
+ @param others_in_slot: all dblink instances in this slot, excluding self
+ @type others_in_slot: list
+ @rtype: None
+ """
+
+ os = _os_merge
+ perf_md5 = perform_md5
+ showMessage = self._display_merge
+
+ if not pkgfiles:
+ showMessage(_("No package files given... Grabbing a set.\n"))
+ pkgfiles = self.getcontents()
+
+ if others_in_slot is None:
+ others_in_slot = []
+ slot = self.vartree.dbapi.aux_get(self.mycpv, ["SLOT"])[0]
+ slot_matches = self.vartree.dbapi.match(
+ "%s:%s" % (portage.cpv_getkey(self.mycpv), slot))
+ for cur_cpv in slot_matches:
+ if cur_cpv == self.mycpv:
+ continue
+ others_in_slot.append(dblink(self.cat, catsplit(cur_cpv)[1],
+ settings=self.settings,
+ vartree=self.vartree, treetype="vartree", pipe=self._pipe))
+
+ dest_root = self._eroot
+ dest_root_len = len(dest_root) - 1
+
+ cfgfiledict = grabdict(self.vartree.dbapi._conf_mem_file)
+ stale_confmem = []
+ protected_symlinks = {}
+
+ unmerge_orphans = "unmerge-orphans" in self.settings.features
+ calc_prelink = "prelink-checksums" in self.settings.features
+
+ if pkgfiles:
+ self.updateprotect()
+ mykeys = list(pkgfiles)
+ mykeys.sort()
+ mykeys.reverse()
+
+ #process symlinks second-to-last, directories last.
+ mydirs = set()
+ ignored_unlink_errnos = (
+ errno.EBUSY, errno.ENOENT,
+ errno.ENOTDIR, errno.EISDIR)
+ ignored_rmdir_errnos = (
+ errno.EEXIST, errno.ENOTEMPTY,
+ errno.EBUSY, errno.ENOENT,
+ errno.ENOTDIR, errno.EISDIR,
+ errno.EPERM)
+ modprotect = os.path.join(self._eroot, "lib/modules/")
+
+ def unlink(file_name, lstatobj):
+ if bsd_chflags:
+ if lstatobj.st_flags != 0:
+ bsd_chflags.lchflags(file_name, 0)
+ parent_name = os.path.dirname(file_name)
+ # Use normal stat/chflags for the parent since we want to
+ # follow any symlinks to the real parent directory.
+ pflags = os.stat(parent_name).st_flags
+ if pflags != 0:
+ bsd_chflags.chflags(parent_name, 0)
+ try:
+ if not stat.S_ISLNK(lstatobj.st_mode):
+ # Remove permissions to ensure that any hardlinks to
+ # suid/sgid files are rendered harmless.
+ os.chmod(file_name, 0)
+ os.unlink(file_name)
+ except OSError as ose:
+ # If the chmod or unlink fails, you are in trouble.
+ # With Prefix this can be because the file is owned
+ # by someone else (a screwup by root?), on a normal
+ # system maybe filesystem corruption. In any case,
+ # if we backtrace and die here, we leave the system
+ # in a totally undefined state, hence we just bleed
+ # like hell and continue to hopefully finish all our
+ # administrative and pkg_postinst stuff.
+ self._eerror("postrm",
+ ["Could not chmod or unlink '%s': %s" % \
+ (file_name, ose)])
+ finally:
+ if bsd_chflags and pflags != 0:
+ # Restore the parent flags we saved before unlinking
+ bsd_chflags.chflags(parent_name, pflags)
+
+ def show_unmerge(zing, desc, file_type, file_name):
+ showMessage("%s %s %s %s\n" % \
+ (zing, desc.ljust(8), file_type, file_name))
+
+ unmerge_desc = {}
+ unmerge_desc["cfgpro"] = _("cfgpro")
+ unmerge_desc["replaced"] = _("replaced")
+ unmerge_desc["!dir"] = _("!dir")
+ unmerge_desc["!empty"] = _("!empty")
+ unmerge_desc["!fif"] = _("!fif")
+ unmerge_desc["!found"] = _("!found")
+ unmerge_desc["!md5"] = _("!md5")
+ unmerge_desc["!mtime"] = _("!mtime")
+ unmerge_desc["!obj"] = _("!obj")
+ unmerge_desc["!sym"] = _("!sym")
+
+ real_root = self.settings['ROOT']
+ real_root_len = len(real_root) - 1
+ eroot_split_len = len(self.settings["EROOT"].split(os.sep)) - 1
+
+ # These files are generated by emerge, so we need to remove
+ # them when they are the only thing left in a directory.
+ infodir_cleanup = frozenset(["dir", "dir.old"])
+ infodirs = frozenset(infodir for infodir in chain(
+ self.settings.get("INFOPATH", "").split(":"),
+ self.settings.get("INFODIR", "").split(":")) if infodir)
+ infodirs_inodes = set()
+ for infodir in infodirs:
+ infodir = os.path.join(real_root, infodir.lstrip(os.sep))
+ try:
+ statobj = os.stat(infodir)
+ except OSError:
+ pass
+ else:
+ infodirs_inodes.add((statobj.st_dev, statobj.st_ino))
+
+ for i, objkey in enumerate(mykeys):
+
+ obj = normalize_path(objkey)
+ if os is _os_merge:
+ try:
+ _unicode_encode(obj,
+ encoding=_encodings['merge'], errors='strict')
+ except UnicodeEncodeError:
+ # The package appears to have been merged with a
+ # different value of sys.getfilesystemencoding(),
+ # so fall back to utf_8 if appropriate.
+ try:
+ _unicode_encode(obj,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeEncodeError:
+ pass
+ else:
+ os = portage.os
+ perf_md5 = portage.checksum.perform_md5
+
+ file_data = pkgfiles[objkey]
+ file_type = file_data[0]
+ statobj = None
+ try:
+ statobj = os.stat(obj)
+ except OSError:
+ pass
+ lstatobj = None
+ try:
+ lstatobj = os.lstat(obj)
+ except (OSError, AttributeError):
+ pass
+ islink = lstatobj is not None and stat.S_ISLNK(lstatobj.st_mode)
+ if lstatobj is None:
+ show_unmerge("---", unmerge_desc["!found"], file_type, obj)
+ continue
+ # don't use EROOT, CONTENTS entries already contain EPREFIX
+ if obj.startswith(real_root):
+ relative_path = obj[real_root_len:]
+ is_owned = False
+ for dblnk in others_in_slot:
+ if dblnk.isowner(relative_path):
+ is_owned = True
+ break
+
+ if file_type == "sym" and is_owned and \
+ (islink and statobj and stat.S_ISDIR(statobj.st_mode)):
+ # A new instance of this package claims the file, so
+ # don't unmerge it. If the file is symlink to a
+ # directory and the unmerging package installed it as
+ # a symlink, but the new owner has it listed as a
+ # directory, then we'll produce a warning since the
+ # symlink is a sort of orphan in this case (see
+ # bug #326685).
+ symlink_orphan = False
+ for dblnk in others_in_slot:
+ parent_contents_key = \
+ dblnk._match_contents(relative_path)
+ if not parent_contents_key:
+ continue
+ if not parent_contents_key.startswith(
+ real_root):
+ continue
+ if dblnk.getcontents()[
+ parent_contents_key][0] == "dir":
+ symlink_orphan = True
+ break
+
+ if symlink_orphan:
+ protected_symlinks.setdefault(
+ (statobj.st_dev, statobj.st_ino),
+ []).append(relative_path)
+
+ if is_owned:
+ show_unmerge("---", unmerge_desc["replaced"], file_type, obj)
+ continue
+ elif relative_path in cfgfiledict:
+ stale_confmem.append(relative_path)
+ # next line includes a tweak to protect modules from being unmerged,
+ # but we don't protect modules from being overwritten if they are
+ # upgraded. We effectively only want one half of the config protection
+ # functionality for /lib/modules. For portage-ng both capabilities
+ # should be able to be independently specified.
+ # TODO: For rebuilds, re-parent previous modules to the new
+ # installed instance (so they are not orphans). For normal
+ # uninstall (not rebuild/reinstall), remove the modules along
+ # with all other files (leave no orphans).
+ if obj.startswith(modprotect):
+ show_unmerge("---", unmerge_desc["cfgpro"], file_type, obj)
+ continue
+
+ # Don't unlink symlinks to directories here since that can
+ # remove /lib and /usr/lib symlinks.
+ if unmerge_orphans and \
+ lstatobj and not stat.S_ISDIR(lstatobj.st_mode) and \
+ not (islink and statobj and stat.S_ISDIR(statobj.st_mode)) and \
+ not self.isprotected(obj):
+ try:
+ unlink(obj, lstatobj)
+ except EnvironmentError as e:
+ if e.errno not in ignored_unlink_errnos:
+ raise
+ del e
+ show_unmerge("<<<", "", file_type, obj)
+ continue
+
+ lmtime = str(lstatobj[stat.ST_MTIME])
+ if (pkgfiles[objkey][0] not in ("dir", "fif", "dev")) and (lmtime != pkgfiles[objkey][1]):
+ show_unmerge("---", unmerge_desc["!mtime"], file_type, obj)
+ continue
+
+ if pkgfiles[objkey][0] == "dir":
+ if lstatobj is None or not stat.S_ISDIR(lstatobj.st_mode):
+ show_unmerge("---", unmerge_desc["!dir"], file_type, obj)
+ continue
+ mydirs.add((obj, (lstatobj.st_dev, lstatobj.st_ino)))
+ elif pkgfiles[objkey][0] == "sym":
+ if not islink:
+ show_unmerge("---", unmerge_desc["!sym"], file_type, obj)
+ continue
+
+ # If this symlink points to a directory then we don't want
+ # to unmerge it if there are any other packages that
+ # installed files into the directory via this symlink
+ # (see bug #326685).
+ # TODO: Resolving a symlink to a directory will require
+ # simulation if $ROOT != / and the link is not relative.
+ if islink and statobj and stat.S_ISDIR(statobj.st_mode) \
+ and obj.startswith(real_root):
+
+ relative_path = obj[real_root_len:]
+ try:
+ target_dir_contents = os.listdir(obj)
+ except OSError:
+ pass
+ else:
+ if target_dir_contents:
+ # If all the children are regular files owned
+ # by this package, then the symlink should be
+ # safe to unmerge.
+ all_owned = True
+ for child in target_dir_contents:
+ child = os.path.join(relative_path, child)
+ if not self.isowner(child):
+ all_owned = False
+ break
+ try:
+ child_lstat = os.lstat(os.path.join(
+ real_root, child.lstrip(os.sep)))
+ except OSError:
+ continue
+
+ if not stat.S_ISREG(child_lstat.st_mode):
+ # Nested symlinks or directories make
+ # the issue very complex, so just
+ # preserve the symlink in order to be
+ # on the safe side.
+ all_owned = False
+ break
+
+ if not all_owned:
+ protected_symlinks.setdefault(
+ (statobj.st_dev, statobj.st_ino),
+ []).append(relative_path)
+ show_unmerge("---", unmerge_desc["!empty"],
+ file_type, obj)
+ continue
+
+ # Go ahead and unlink symlinks to directories here when
+ # they're actually recorded as symlinks in the contents.
+ # Normally, symlinks such as /lib -> lib64 are not recorded
+ # as symlinks in the contents of a package. If a package
+ # installs something into ${D}/lib/, it is recorded in the
+ # contents as a directory even if it happens to correspond
+ # to a symlink when it's merged to the live filesystem.
+ try:
+ unlink(obj, lstatobj)
+ show_unmerge("<<<", "", file_type, obj)
+ except (OSError, IOError) as e:
+ if e.errno not in ignored_unlink_errnos:
+ raise
+ del e
+ show_unmerge("!!!", "", file_type, obj)
+ elif pkgfiles[objkey][0] == "obj":
+ if statobj is None or not stat.S_ISREG(statobj.st_mode):
+ show_unmerge("---", unmerge_desc["!obj"], file_type, obj)
+ continue
+ mymd5 = None
+ try:
+ mymd5 = perf_md5(obj, calc_prelink=calc_prelink)
+ except FileNotFound as e:
+ # the file has disappeared between now and our stat call
+ show_unmerge("---", unmerge_desc["!obj"], file_type, obj)
+ continue
+
+ # string.lower is needed because db entries used to be in upper-case. The
+ # string.lower allows for backwards compatibility.
+ if mymd5 != pkgfiles[objkey][2].lower():
+ show_unmerge("---", unmerge_desc["!md5"], file_type, obj)
+ continue
+ try:
+ unlink(obj, lstatobj)
+ except (OSError, IOError) as e:
+ if e.errno not in ignored_unlink_errnos:
+ raise
+ del e
+ show_unmerge("<<<", "", file_type, obj)
+ elif pkgfiles[objkey][0] == "fif":
+ if not stat.S_ISFIFO(lstatobj[stat.ST_MODE]):
+ show_unmerge("---", unmerge_desc["!fif"], file_type, obj)
+ continue
+ show_unmerge("---", "", file_type, obj)
+ elif pkgfiles[objkey][0] == "dev":
+ show_unmerge("---", "", file_type, obj)
+
+ mydirs = sorted(mydirs)
+ mydirs.reverse()
+
+ for obj, inode_key in mydirs:
+ # Treat any directory named "info" as a candidate here,
+ # since it might have been in INFOPATH previously even
+ # though it may not be there now.
+ if inode_key in infodirs_inodes or \
+ os.path.basename(obj) == "info":
+ try:
+ remaining = os.listdir(obj)
+ except OSError:
+ pass
+ else:
+ cleanup_info_dir = ()
+ if remaining and \
+ len(remaining) <= len(infodir_cleanup):
+ if not set(remaining).difference(infodir_cleanup):
+ cleanup_info_dir = remaining
+
+ for child in cleanup_info_dir:
+ child = os.path.join(obj, child)
+ try:
+ lstatobj = os.lstat(child)
+ if stat.S_ISREG(lstatobj.st_mode):
+ unlink(child, lstatobj)
+ show_unmerge("<<<", "", "obj", child)
+ except EnvironmentError as e:
+ if e.errno not in ignored_unlink_errnos:
+ raise
+ del e
+ show_unmerge("!!!", "", "obj", child)
+ try:
+ if bsd_chflags:
+ lstatobj = os.lstat(obj)
+ if lstatobj.st_flags != 0:
+ bsd_chflags.lchflags(obj, 0)
+ parent_name = os.path.dirname(obj)
+ # Use normal stat/chflags for the parent since we want to
+ # follow any symlinks to the real parent directory.
+ pflags = os.stat(parent_name).st_flags
+ if pflags != 0:
+ bsd_chflags.chflags(parent_name, 0)
+ try:
+ os.rmdir(obj)
+ finally:
+ if bsd_chflags and pflags != 0:
+ # Restore the parent flags we saved before unlinking
+ bsd_chflags.chflags(parent_name, pflags)
+ show_unmerge("<<<", "", "dir", obj)
+ except EnvironmentError as e:
+ if e.errno not in ignored_rmdir_errnos:
+ raise
+ if e.errno != errno.ENOENT:
+ show_unmerge("---", unmerge_desc["!empty"], "dir", obj)
+ del e
+ else:
+ # When a directory is successfully removed, there's
+ # no need to protect symlinks that point to it.
+ unmerge_syms = protected_symlinks.pop(inode_key, None)
+ if unmerge_syms is not None:
+ for relative_path in unmerge_syms:
+ obj = os.path.join(real_root,
+ relative_path.lstrip(os.sep))
+ try:
+ unlink(obj, os.lstat(obj))
+ show_unmerge("<<<", "", "sym", obj)
+ except (OSError, IOError) as e:
+ if e.errno not in ignored_unlink_errnos:
+ raise
+ del e
+ show_unmerge("!!!", "", "sym", obj)
+
+ if protected_symlinks:
+ msg = "One or more symlinks to directories have been " + \
+ "preserved in order to ensure that files installed " + \
+ "via these symlinks remain accessible:"
+ lines = textwrap.wrap(msg, 72)
+ lines.append("")
+ flat_list = set()
+ flat_list.update(*protected_symlinks.values())
+ flat_list = sorted(flat_list)
+ for f in flat_list:
+ lines.append("\t%s" % (os.path.join(real_root,
+ f.lstrip(os.sep))))
+ lines.append("")
+ self._elog("eerror", "postrm", lines)
+
+ # Remove stale entries from config memory.
+ if stale_confmem:
+ for filename in stale_confmem:
+ del cfgfiledict[filename]
+ writedict(cfgfiledict, self.vartree.dbapi._conf_mem_file)
+
+ #remove self from vartree database so that our own virtual gets zapped if we're the last node
+ self.vartree.zap(self.mycpv)
+
+ def isowner(self, filename, destroot=None):
+ """
+ Check if a file belongs to this package. This may
+ result in a stat call for the parent directory of
+ every installed file, since the inode numbers are
+ used to work around the problem of ambiguous paths
+ caused by symlinked directories. The results of
+ stat calls are cached to optimize multiple calls
+ to this method.
+
+ @param filename:
+ @type filename:
+ @param destroot:
+ @type destroot:
+ @rtype: Boolean
+ @returns:
+ 1. True if this package owns the file.
+ 2. False if this package does not own the file.
+ """
+
+ if destroot is not None and destroot != self._eroot:
+ warnings.warn("The second parameter of the " + \
+ "portage.dbapi.vartree.dblink.isowner()" + \
+ " is now unused. Instead " + \
+ "self.settings['EROOT'] will be used.",
+ DeprecationWarning, stacklevel=2)
+
+ return bool(self._match_contents(filename))
+
+ def _match_contents(self, filename, destroot=None):
+ """
+ The matching contents entry is returned, which is useful
+ since the path may differ from the one given by the caller,
+ due to symlinks.
+
+ @rtype: String
+ @return: the contents entry corresponding to the given path, or False
+ if the file is not owned by this package.
+ """
+
+ filename = _unicode_decode(filename,
+ encoding=_encodings['content'], errors='strict')
+
+ if destroot is not None and destroot != self._eroot:
+ warnings.warn("The second parameter of the " + \
+ "portage.dbapi.vartree.dblink._match_contents()" + \
+ " is now unused. Instead " + \
+ "self.settings['ROOT'] will be used.",
+ DeprecationWarning, stacklevel=2)
+
+ # don't use EROOT here, image already contains EPREFIX
+ destroot = self.settings['ROOT']
+
+ # The given filename argument might have a different encoding than the
+ # the filenames contained in the contents, so use separate wrapped os
+ # modules for each. The basename is more likely to contain non-ascii
+ # characters than the directory path, so use os_filename_arg for all
+ # operations involving the basename of the filename arg.
+ os_filename_arg = _os_merge
+ os = _os_merge
+
+ try:
+ _unicode_encode(filename,
+ encoding=_encodings['merge'], errors='strict')
+ except UnicodeEncodeError:
+ # The package appears to have been merged with a
+ # different value of sys.getfilesystemencoding(),
+ # so fall back to utf_8 if appropriate.
+ try:
+ _unicode_encode(filename,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeEncodeError:
+ pass
+ else:
+ os_filename_arg = portage.os
+
+ destfile = normalize_path(
+ os_filename_arg.path.join(destroot,
+ filename.lstrip(os_filename_arg.path.sep)))
+
+ pkgfiles = self.getcontents()
+ if pkgfiles and destfile in pkgfiles:
+ return destfile
+ if pkgfiles:
+ basename = os_filename_arg.path.basename(destfile)
+ if self._contents_basenames is None:
+
+ try:
+ for x in pkgfiles:
+ _unicode_encode(x,
+ encoding=_encodings['merge'],
+ errors='strict')
+ except UnicodeEncodeError:
+ # The package appears to have been merged with a
+ # different value of sys.getfilesystemencoding(),
+ # so fall back to utf_8 if appropriate.
+ try:
+ for x in pkgfiles:
+ _unicode_encode(x,
+ encoding=_encodings['fs'],
+ errors='strict')
+ except UnicodeEncodeError:
+ pass
+ else:
+ os = portage.os
+
+ self._contents_basenames = set(
+ os.path.basename(x) for x in pkgfiles)
+ if basename not in self._contents_basenames:
+ # This is a shortcut that, in most cases, allows us to
+ # eliminate this package as an owner without the need
+ # to examine inode numbers of parent directories.
+ return False
+
+ # Use stat rather than lstat since we want to follow
+ # any symlinks to the real parent directory.
+ parent_path = os_filename_arg.path.dirname(destfile)
+ try:
+ parent_stat = os_filename_arg.stat(parent_path)
+ except EnvironmentError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ return False
+ if self._contents_inodes is None:
+
+ if os is _os_merge:
+ try:
+ for x in pkgfiles:
+ _unicode_encode(x,
+ encoding=_encodings['merge'],
+ errors='strict')
+ except UnicodeEncodeError:
+ # The package appears to have been merged with a
+ # different value of sys.getfilesystemencoding(),
+ # so fall back to utf_8 if appropriate.
+ try:
+ for x in pkgfiles:
+ _unicode_encode(x,
+ encoding=_encodings['fs'],
+ errors='strict')
+ except UnicodeEncodeError:
+ pass
+ else:
+ os = portage.os
+
+ self._contents_inodes = {}
+ parent_paths = set()
+ for x in pkgfiles:
+ p_path = os.path.dirname(x)
+ if p_path in parent_paths:
+ continue
+ parent_paths.add(p_path)
+ try:
+ s = os.stat(p_path)
+ except OSError:
+ pass
+ else:
+ inode_key = (s.st_dev, s.st_ino)
+ # Use lists of paths in case multiple
+ # paths reference the same inode.
+ p_path_list = self._contents_inodes.get(inode_key)
+ if p_path_list is None:
+ p_path_list = []
+ self._contents_inodes[inode_key] = p_path_list
+ if p_path not in p_path_list:
+ p_path_list.append(p_path)
+
+ p_path_list = self._contents_inodes.get(
+ (parent_stat.st_dev, parent_stat.st_ino))
+ if p_path_list:
+ for p_path in p_path_list:
+ x = os_filename_arg.path.join(p_path, basename)
+ if x in pkgfiles:
+ return x
+
+ return False
+
+ def _linkmap_rebuild(self, **kwargs):
+ """
+ Rebuild the self._linkmap if it's not broken due to missing
+ scanelf binary. Also, return early if preserve-libs is disabled
+ and the preserve-libs registry is empty.
+ """
+ if self._linkmap_broken or \
+ self.vartree.dbapi._linkmap is None or \
+ self.vartree.dbapi._plib_registry is None or \
+ ("preserve-libs" not in self.settings.features and \
+ not self.vartree.dbapi._plib_registry.hasEntries()):
+ return
+ try:
+ self.vartree.dbapi._linkmap.rebuild(**kwargs)
+ except CommandNotFound as e:
+ self._linkmap_broken = True
+ self._display_merge(_("!!! Disabling preserve-libs " \
+ "due to error: Command Not Found: %s\n") % (e,),
+ level=logging.ERROR, noiselevel=-1)
+
+ def _find_libs_to_preserve(self, unmerge=False):
+ """
+ Get set of relative paths for libraries to be preserved. When
+ unmerge is False, file paths to preserve are selected from
+ self._installed_instance. Otherwise, paths are selected from
+ self.
+ """
+ if self._linkmap_broken or \
+ self.vartree.dbapi._linkmap is None or \
+ self.vartree.dbapi._plib_registry is None or \
+ (not unmerge and self._installed_instance is None) or \
+ "preserve-libs" not in self.settings.features:
+ return set()
+
+ os = _os_merge
+ linkmap = self.vartree.dbapi._linkmap
+ if unmerge:
+ installed_instance = self
+ else:
+ installed_instance = self._installed_instance
+ old_contents = installed_instance.getcontents()
+ root = self.settings['ROOT']
+ root_len = len(root) - 1
+ lib_graph = digraph()
+ path_node_map = {}
+
+ def path_to_node(path):
+ node = path_node_map.get(path)
+ if node is None:
+ node = LinkageMap._LibGraphNode(linkmap._obj_key(path))
+ alt_path_node = lib_graph.get(node)
+ if alt_path_node is not None:
+ node = alt_path_node
+ node.alt_paths.add(path)
+ path_node_map[path] = node
+ return node
+
+ consumer_map = {}
+ provider_nodes = set()
+ # Create provider nodes and add them to the graph.
+ for f_abs in old_contents:
+
+ if os is _os_merge:
+ try:
+ _unicode_encode(f_abs,
+ encoding=_encodings['merge'], errors='strict')
+ except UnicodeEncodeError:
+ # The package appears to have been merged with a
+ # different value of sys.getfilesystemencoding(),
+ # so fall back to utf_8 if appropriate.
+ try:
+ _unicode_encode(f_abs,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeEncodeError:
+ pass
+ else:
+ os = portage.os
+
+ f = f_abs[root_len:]
+ if not unmerge and self.isowner(f):
+ # We have an indentically named replacement file,
+ # so we don't try to preserve the old copy.
+ continue
+ try:
+ consumers = linkmap.findConsumers(f,
+ exclude_providers=(installed_instance.isowner,))
+ except KeyError:
+ continue
+ if not consumers:
+ continue
+ provider_node = path_to_node(f)
+ lib_graph.add(provider_node, None)
+ provider_nodes.add(provider_node)
+ consumer_map[provider_node] = consumers
+
+ # Create consumer nodes and add them to the graph.
+ # Note that consumers can also be providers.
+ for provider_node, consumers in consumer_map.items():
+ for c in consumers:
+ consumer_node = path_to_node(c)
+ if installed_instance.isowner(c) and \
+ consumer_node not in provider_nodes:
+ # This is not a provider, so it will be uninstalled.
+ continue
+ lib_graph.add(provider_node, consumer_node)
+
+ # Locate nodes which should be preserved. They consist of all
+ # providers that are reachable from consumers that are not
+ # providers themselves.
+ preserve_nodes = set()
+ for consumer_node in lib_graph.root_nodes():
+ if consumer_node in provider_nodes:
+ continue
+ # Preserve all providers that are reachable from this consumer.
+ node_stack = lib_graph.child_nodes(consumer_node)
+ while node_stack:
+ provider_node = node_stack.pop()
+ if provider_node in preserve_nodes:
+ continue
+ preserve_nodes.add(provider_node)
+ node_stack.extend(lib_graph.child_nodes(provider_node))
+
+ preserve_paths = set()
+ for preserve_node in preserve_nodes:
+ # Preserve the library itself, and also preserve the
+ # soname symlink which is the only symlink that is
+ # strictly required.
+ hardlinks = set()
+ soname_symlinks = set()
+ soname = linkmap.getSoname(next(iter(preserve_node.alt_paths)))
+ for f in preserve_node.alt_paths:
+ f_abs = os.path.join(root, f.lstrip(os.sep))
+ try:
+ if stat.S_ISREG(os.lstat(f_abs).st_mode):
+ hardlinks.add(f)
+ elif os.path.basename(f) == soname:
+ soname_symlinks.add(f)
+ except OSError:
+ pass
+
+ if hardlinks:
+ preserve_paths.update(hardlinks)
+ preserve_paths.update(soname_symlinks)
+
+ return preserve_paths
+
+ def _add_preserve_libs_to_contents(self, preserve_paths):
+ """
+ Preserve libs returned from _find_libs_to_preserve().
+ """
+
+ if not preserve_paths:
+ return
+
+ os = _os_merge
+ showMessage = self._display_merge
+ root = self.settings['ROOT']
+
+ # Copy contents entries from the old package to the new one.
+ new_contents = self.getcontents().copy()
+ old_contents = self._installed_instance.getcontents()
+ for f in sorted(preserve_paths):
+ f = _unicode_decode(f,
+ encoding=_encodings['content'], errors='strict')
+ f_abs = os.path.join(root, f.lstrip(os.sep))
+ contents_entry = old_contents.get(f_abs)
+ if contents_entry is None:
+ # This will probably never happen, but it might if one of the
+ # paths returned from findConsumers() refers to one of the libs
+ # that should be preserved yet the path is not listed in the
+ # contents. Such a path might belong to some other package, so
+ # it shouldn't be preserved here.
+ showMessage(_("!!! File '%s' will not be preserved "
+ "due to missing contents entry\n") % (f_abs,),
+ level=logging.ERROR, noiselevel=-1)
+ preserve_paths.remove(f)
+ continue
+ new_contents[f_abs] = contents_entry
+ obj_type = contents_entry[0]
+ showMessage(_(">>> needed %s %s\n") % (obj_type, f_abs),
+ noiselevel=-1)
+ # Add parent directories to contents if necessary.
+ parent_dir = os.path.dirname(f_abs)
+ while len(parent_dir) > len(root):
+ new_contents[parent_dir] = ["dir"]
+ prev = parent_dir
+ parent_dir = os.path.dirname(parent_dir)
+ if prev == parent_dir:
+ break
+ outfile = atomic_ofstream(os.path.join(self.dbtmpdir, "CONTENTS"))
+ write_contents(new_contents, root, outfile)
+ outfile.close()
+ self._clear_contents_cache()
+
+ def _find_unused_preserved_libs(self, unmerge_no_replacement):
+ """
+ Find preserved libraries that don't have any consumers left.
+ """
+
+ if self._linkmap_broken or \
+ self.vartree.dbapi._linkmap is None or \
+ self.vartree.dbapi._plib_registry is None or \
+ not self.vartree.dbapi._plib_registry.hasEntries():
+ return {}
+
+ # Since preserved libraries can be consumers of other preserved
+ # libraries, use a graph to track consumer relationships.
+ plib_dict = self.vartree.dbapi._plib_registry.getPreservedLibs()
+ linkmap = self.vartree.dbapi._linkmap
+ lib_graph = digraph()
+ preserved_nodes = set()
+ preserved_paths = set()
+ path_cpv_map = {}
+ path_node_map = {}
+ root = self.settings['ROOT']
+
+ def path_to_node(path):
+ node = path_node_map.get(path)
+ if node is None:
+ node = LinkageMap._LibGraphNode(linkmap._obj_key(path))
+ alt_path_node = lib_graph.get(node)
+ if alt_path_node is not None:
+ node = alt_path_node
+ node.alt_paths.add(path)
+ path_node_map[path] = node
+ return node
+
+ for cpv, plibs in plib_dict.items():
+ for f in plibs:
+ path_cpv_map[f] = cpv
+ preserved_node = path_to_node(f)
+ if not preserved_node.file_exists():
+ continue
+ lib_graph.add(preserved_node, None)
+ preserved_paths.add(f)
+ preserved_nodes.add(preserved_node)
+ for c in self.vartree.dbapi._linkmap.findConsumers(f):
+ consumer_node = path_to_node(c)
+ if not consumer_node.file_exists():
+ continue
+ # Note that consumers may also be providers.
+ lib_graph.add(preserved_node, consumer_node)
+
+ # Eliminate consumers having providers with the same soname as an
+ # installed library that is not preserved. This eliminates
+ # libraries that are erroneously preserved due to a move from one
+ # directory to another.
+ # Also eliminate consumers that are going to be unmerged if
+ # unmerge_no_replacement is True.
+ provider_cache = {}
+ for preserved_node in preserved_nodes:
+ soname = linkmap.getSoname(preserved_node)
+ for consumer_node in lib_graph.parent_nodes(preserved_node):
+ if consumer_node in preserved_nodes:
+ continue
+ if unmerge_no_replacement:
+ will_be_unmerged = True
+ for path in consumer_node.alt_paths:
+ if not self.isowner(path):
+ will_be_unmerged = False
+ break
+ if will_be_unmerged:
+ # This consumer is not preserved and it is
+ # being unmerged, so drop this edge.
+ lib_graph.remove_edge(preserved_node, consumer_node)
+ continue
+
+ providers = provider_cache.get(consumer_node)
+ if providers is None:
+ providers = linkmap.findProviders(consumer_node)
+ provider_cache[consumer_node] = providers
+ providers = providers.get(soname)
+ if providers is None:
+ continue
+ for provider in providers:
+ if provider in preserved_paths:
+ continue
+ provider_node = path_to_node(provider)
+ if not provider_node.file_exists():
+ continue
+ if provider_node in preserved_nodes:
+ continue
+ # An alternative provider seems to be
+ # installed, so drop this edge.
+ lib_graph.remove_edge(preserved_node, consumer_node)
+ break
+
+ cpv_lib_map = {}
+ while lib_graph:
+ root_nodes = preserved_nodes.intersection(lib_graph.root_nodes())
+ if not root_nodes:
+ break
+ lib_graph.difference_update(root_nodes)
+ unlink_list = set()
+ for node in root_nodes:
+ unlink_list.update(node.alt_paths)
+ unlink_list = sorted(unlink_list)
+ for obj in unlink_list:
+ cpv = path_cpv_map.get(obj)
+ if cpv is None:
+ # This means that a symlink is in the preserved libs
+ # registry, but the actual lib it points to is not.
+ self._display_merge(_("!!! symlink to lib is preserved, "
+ "but not the lib itself:\n!!! '%s'\n") % (obj,),
+ level=logging.ERROR, noiselevel=-1)
+ continue
+ removed = cpv_lib_map.get(cpv)
+ if removed is None:
+ removed = set()
+ cpv_lib_map[cpv] = removed
+ removed.add(obj)
+
+ return cpv_lib_map
+
+ def _remove_preserved_libs(self, cpv_lib_map):
+ """
+ Remove files returned from _find_unused_preserved_libs().
+ """
+
+ os = _os_merge
+
+ files_to_remove = set()
+ for files in cpv_lib_map.values():
+ files_to_remove.update(files)
+ files_to_remove = sorted(files_to_remove)
+ showMessage = self._display_merge
+ root = self.settings['ROOT']
+
+ parent_dirs = set()
+ for obj in files_to_remove:
+ obj = os.path.join(root, obj.lstrip(os.sep))
+ parent_dirs.add(os.path.dirname(obj))
+ if os.path.islink(obj):
+ obj_type = _("sym")
+ else:
+ obj_type = _("obj")
+ try:
+ os.unlink(obj)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ else:
+ showMessage(_("<<< !needed %s %s\n") % (obj_type, obj),
+ noiselevel=-1)
+
+ # Remove empty parent directories if possible.
+ while parent_dirs:
+ x = parent_dirs.pop()
+ while True:
+ try:
+ os.rmdir(x)
+ except OSError:
+ break
+ prev = x
+ x = os.path.dirname(x)
+ if x == prev:
+ break
+
+ self.vartree.dbapi._plib_registry.pruneNonExisting()
+
+ def _collision_protect(self, srcroot, destroot, mypkglist,
+ file_list, symlink_list):
+
+ os = _os_merge
+
+ collision_ignore = set([normalize_path(myignore) for myignore in \
+ portage.util.shlex_split(
+ self.settings.get("COLLISION_IGNORE", ""))])
+
+ # For collisions with preserved libraries, the current package
+ # will assume ownership and the libraries will be unregistered.
+ if self.vartree.dbapi._plib_registry is None:
+ # preserve-libs is entirely disabled
+ plib_cpv_map = None
+ plib_paths = None
+ plib_inodes = {}
+ else:
+ plib_dict = self.vartree.dbapi._plib_registry.getPreservedLibs()
+ plib_cpv_map = {}
+ plib_paths = set()
+ for cpv, paths in plib_dict.items():
+ plib_paths.update(paths)
+ for f in paths:
+ plib_cpv_map[f] = cpv
+ plib_inodes = self._lstat_inode_map(plib_paths)
+
+ plib_collisions = {}
+
+ showMessage = self._display_merge
+ stopmerge = False
+ collisions = []
+ symlink_collisions = []
+ destroot = self.settings['ROOT']
+ showMessage(_(" %s checking %d files for package collisions\n") % \
+ (colorize("GOOD", "*"), len(file_list) + len(symlink_list)))
+ for i, (f, f_type) in enumerate(chain(
+ ((f, "reg") for f in file_list),
+ ((f, "sym") for f in symlink_list))):
+ if i % 1000 == 0 and i != 0:
+ showMessage(_("%d files checked ...\n") % i)
+
+ dest_path = normalize_path(
+ os.path.join(destroot, f.lstrip(os.path.sep)))
+ try:
+ dest_lstat = os.lstat(dest_path)
+ except EnvironmentError as e:
+ if e.errno == errno.ENOENT:
+ del e
+ continue
+ elif e.errno == errno.ENOTDIR:
+ del e
+ # A non-directory is in a location where this package
+ # expects to have a directory.
+ dest_lstat = None
+ parent_path = dest_path
+ while len(parent_path) > len(destroot):
+ parent_path = os.path.dirname(parent_path)
+ try:
+ dest_lstat = os.lstat(parent_path)
+ break
+ except EnvironmentError as e:
+ if e.errno != errno.ENOTDIR:
+ raise
+ del e
+ if not dest_lstat:
+ raise AssertionError(
+ "unable to find non-directory " + \
+ "parent for '%s'" % dest_path)
+ dest_path = parent_path
+ f = os.path.sep + dest_path[len(destroot):]
+ if f in collisions:
+ continue
+ else:
+ raise
+ if f[0] != "/":
+ f="/"+f
+
+ if stat.S_ISDIR(dest_lstat.st_mode):
+ if f_type == "sym":
+ # This case is explicitly banned
+ # by PMS (see bug #326685).
+ symlink_collisions.append(f)
+ collisions.append(f)
+ continue
+
+ plibs = plib_inodes.get((dest_lstat.st_dev, dest_lstat.st_ino))
+ if plibs:
+ for path in plibs:
+ cpv = plib_cpv_map[path]
+ paths = plib_collisions.get(cpv)
+ if paths is None:
+ paths = set()
+ plib_collisions[cpv] = paths
+ paths.add(path)
+ # The current package will assume ownership and the
+ # libraries will be unregistered, so exclude this
+ # path from the normal collisions.
+ continue
+
+ isowned = False
+ full_path = os.path.join(destroot, f.lstrip(os.path.sep))
+ for ver in mypkglist:
+ if ver.isowner(f):
+ isowned = True
+ break
+ if not isowned and self.isprotected(full_path):
+ isowned = True
+ if not isowned:
+ stopmerge = True
+ if collision_ignore:
+ if f in collision_ignore:
+ stopmerge = False
+ else:
+ for myignore in collision_ignore:
+ if f.startswith(myignore + os.path.sep):
+ stopmerge = False
+ break
+ if stopmerge:
+ collisions.append(f)
+ return collisions, symlink_collisions, plib_collisions
+
+ def _lstat_inode_map(self, path_iter):
+ """
+ Use lstat to create a map of the form:
+ {(st_dev, st_ino) : set([path1, path2, ...])}
+ Multiple paths may reference the same inode due to hardlinks.
+ All lstat() calls are relative to self.myroot.
+ """
+
+ os = _os_merge
+
+ root = self.settings['ROOT']
+ inode_map = {}
+ for f in path_iter:
+ path = os.path.join(root, f.lstrip(os.sep))
+ try:
+ st = os.lstat(path)
+ except OSError as e:
+ if e.errno not in (errno.ENOENT, errno.ENOTDIR):
+ raise
+ del e
+ continue
+ key = (st.st_dev, st.st_ino)
+ paths = inode_map.get(key)
+ if paths is None:
+ paths = set()
+ inode_map[key] = paths
+ paths.add(f)
+ return inode_map
+
+ def _security_check(self, installed_instances):
+ if not installed_instances:
+ return 0
+
+ os = _os_merge
+
+ showMessage = self._display_merge
+
+ file_paths = set()
+ for dblnk in installed_instances:
+ file_paths.update(dblnk.getcontents())
+ inode_map = {}
+ real_paths = set()
+ for i, path in enumerate(file_paths):
+
+ if os is _os_merge:
+ try:
+ _unicode_encode(path,
+ encoding=_encodings['merge'], errors='strict')
+ except UnicodeEncodeError:
+ # The package appears to have been merged with a
+ # different value of sys.getfilesystemencoding(),
+ # so fall back to utf_8 if appropriate.
+ try:
+ _unicode_encode(path,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeEncodeError:
+ pass
+ else:
+ os = portage.os
+
+ try:
+ s = os.lstat(path)
+ except OSError as e:
+ if e.errno not in (errno.ENOENT, errno.ENOTDIR):
+ raise
+ del e
+ continue
+ if not stat.S_ISREG(s.st_mode):
+ continue
+ path = os.path.realpath(path)
+ if path in real_paths:
+ continue
+ real_paths.add(path)
+ if s.st_nlink > 1 and \
+ s.st_mode & (stat.S_ISUID | stat.S_ISGID):
+ k = (s.st_dev, s.st_ino)
+ inode_map.setdefault(k, []).append((path, s))
+ suspicious_hardlinks = []
+ for path_list in inode_map.values():
+ path, s = path_list[0]
+ if len(path_list) == s.st_nlink:
+ # All hardlinks seem to be owned by this package.
+ continue
+ suspicious_hardlinks.append(path_list)
+ if not suspicious_hardlinks:
+ return 0
+
+ msg = []
+ msg.append(_("suid/sgid file(s) "
+ "with suspicious hardlink(s):"))
+ msg.append("")
+ for path_list in suspicious_hardlinks:
+ for path, s in path_list:
+ msg.append("\t%s" % path)
+ msg.append("")
+ msg.append(_("See the Gentoo Security Handbook "
+ "guide for advice on how to proceed."))
+
+ self._eerror("preinst", msg)
+
+ return 1
+
+ def _eqawarn(self, phase, lines):
+ self._elog("eqawarn", phase, lines)
+
+ def _eerror(self, phase, lines):
+ self._elog("eerror", phase, lines)
+
+ def _elog(self, funcname, phase, lines):
+ func = getattr(portage.elog.messages, funcname)
+ if self._scheduler is None:
+ for l in lines:
+ func(l, phase=phase, key=self.mycpv)
+ else:
+ background = self.settings.get("PORTAGE_BACKGROUND") == "1"
+ log_path = None
+ if self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
+ log_path = self.settings.get("PORTAGE_LOG_FILE")
+ out = io.StringIO()
+ for line in lines:
+ func(line, phase=phase, key=self.mycpv, out=out)
+ msg = out.getvalue()
+ self._scheduler.output(msg,
+ background=background, log_path=log_path)
+
+ def _elog_process(self, phasefilter=None):
+ cpv = self.mycpv
+ if self._pipe is None:
+ elog_process(cpv, self.settings, phasefilter=phasefilter)
+ else:
+ logdir = os.path.join(self.settings["T"], "logging")
+ ebuild_logentries = collect_ebuild_messages(logdir)
+ py_logentries = collect_messages(key=cpv).get(cpv, {})
+ logentries = _merge_logentries(py_logentries, ebuild_logentries)
+ funcnames = {
+ "INFO": "einfo",
+ "LOG": "elog",
+ "WARN": "ewarn",
+ "QA": "eqawarn",
+ "ERROR": "eerror"
+ }
+ str_buffer = []
+ for phase, messages in logentries.items():
+ for key, lines in messages:
+ funcname = funcnames[key]
+ if isinstance(lines, basestring):
+ lines = [lines]
+ for line in lines:
+ fields = (funcname, phase, cpv, line.rstrip('\n'))
+ str_buffer.append(' '.join(fields))
+ str_buffer.append('\n')
+ if str_buffer:
+ os.write(self._pipe, _unicode_encode(''.join(str_buffer)))
+
+ def _emerge_log(self, msg):
+ emergelog(False, msg)
+
+ def treewalk(self, srcroot, destroot, inforoot, myebuild, cleanup=0,
+ mydbapi=None, prev_mtimes=None, counter=None):
+ """
+
+ This function does the following:
+
+ calls self._preserve_libs if FEATURES=preserve-libs
+ calls self._collision_protect if FEATURES=collision-protect
+ calls doebuild(mydo=pkg_preinst)
+ Merges the package to the livefs
+ unmerges old version (if required)
+ calls doebuild(mydo=pkg_postinst)
+ calls env_update
+
+ @param srcroot: Typically this is ${D}
+ @type srcroot: String (Path)
+ @param destroot: ignored, self.settings['ROOT'] is used instead
+ @type destroot: String (Path)
+ @param inforoot: root of the vardb entry ?
+ @type inforoot: String (Path)
+ @param myebuild: path to the ebuild that we are processing
+ @type myebuild: String (Path)
+ @param mydbapi: dbapi which is handed to doebuild.
+ @type mydbapi: portdbapi instance
+ @param prev_mtimes: { Filename:mtime } mapping for env_update
+ @type prev_mtimes: Dictionary
+ @rtype: Boolean
+ @returns:
+ 1. 0 on success
+ 2. 1 on failure
+
+ secondhand is a list of symlinks that have been skipped due to their target
+ not existing; we will merge these symlinks at a later time.
+ """
+
+ os = _os_merge
+
+ srcroot = _unicode_decode(srcroot,
+ encoding=_encodings['content'], errors='strict')
+ destroot = self.settings['ROOT']
+ inforoot = _unicode_decode(inforoot,
+ encoding=_encodings['content'], errors='strict')
+ myebuild = _unicode_decode(myebuild,
+ encoding=_encodings['content'], errors='strict')
+
+ showMessage = self._display_merge
+ srcroot = normalize_path(srcroot).rstrip(os.path.sep) + os.path.sep
+
+ if not os.path.isdir(srcroot):
+ showMessage(_("!!! Directory Not Found: D='%s'\n") % srcroot,
+ level=logging.ERROR, noiselevel=-1)
+ return 1
+
+ slot = ''
+ for var_name in ('CHOST', 'SLOT'):
+ if var_name == 'CHOST' and self.cat == 'virtual':
+ try:
+ os.unlink(os.path.join(inforoot, var_name))
+ except OSError:
+ pass
+ continue
+
+ try:
+ val = io.open(_unicode_encode(
+ os.path.join(inforoot, var_name),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'],
+ errors='replace').readline().strip()
+ except EnvironmentError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ val = ''
+
+ if var_name == 'SLOT':
+ slot = val
+
+ if not slot.strip():
+ slot = self.settings.get(var_name, '')
+ if not slot.strip():
+ showMessage(_("!!! SLOT is undefined\n"),
+ level=logging.ERROR, noiselevel=-1)
+ return 1
+ write_atomic(os.path.join(inforoot, var_name), slot + '\n')
+
+ if val != self.settings.get(var_name, ''):
+ self._eqawarn('preinst',
+ [_("QA Notice: Expected %(var_name)s='%(expected_value)s', got '%(actual_value)s'\n") % \
+ {"var_name":var_name, "expected_value":self.settings.get(var_name, ''), "actual_value":val}])
+
+ def eerror(lines):
+ self._eerror("preinst", lines)
+
+ if not os.path.exists(self.dbcatdir):
+ ensure_dirs(self.dbcatdir)
+
+ otherversions = []
+ for v in self.vartree.dbapi.cp_list(self.mysplit[0]):
+ otherversions.append(v.split("/")[1])
+
+ cp = self.mysplit[0]
+ slot_atom = "%s:%s" % (cp, slot)
+
+ # filter any old-style virtual matches
+ slot_matches = [cpv for cpv in self.vartree.dbapi.match(slot_atom) \
+ if cpv_getkey(cpv) == cp]
+
+ if self.mycpv not in slot_matches and \
+ self.vartree.dbapi.cpv_exists(self.mycpv):
+ # handle multislot or unapplied slotmove
+ slot_matches.append(self.mycpv)
+
+ others_in_slot = []
+ from portage import config
+ for cur_cpv in slot_matches:
+ # Clone the config in case one of these has to be unmerged since
+ # we need it to have private ${T} etc... for things like elog.
+ settings_clone = config(clone=self.settings)
+ settings_clone.pop("PORTAGE_BUILDIR_LOCKED", None)
+ settings_clone.reset()
+ others_in_slot.append(dblink(self.cat, catsplit(cur_cpv)[1],
+ settings=settings_clone,
+ vartree=self.vartree, treetype="vartree",
+ scheduler=self._scheduler, pipe=self._pipe))
+
+ retval = self._security_check(others_in_slot)
+ if retval:
+ return retval
+
+ if slot_matches:
+ # Used by self.isprotected().
+ max_dblnk = None
+ max_counter = -1
+ for dblnk in others_in_slot:
+ cur_counter = self.vartree.dbapi.cpv_counter(dblnk.mycpv)
+ if cur_counter > max_counter:
+ max_counter = cur_counter
+ max_dblnk = dblnk
+ self._installed_instance = max_dblnk
+
+ # We check for unicode encoding issues after src_install. However,
+ # the check must be repeated here for binary packages (it's
+ # inexpensive since we call os.walk() here anyway).
+ unicode_errors = []
+
+ while True:
+
+ unicode_error = False
+
+ myfilelist = []
+ mylinklist = []
+ paths_with_newlines = []
+ srcroot_len = len(srcroot)
+ def onerror(e):
+ raise
+ for parent, dirs, files in os.walk(srcroot, onerror=onerror):
+ try:
+ parent = _unicode_decode(parent,
+ encoding=_encodings['merge'], errors='strict')
+ except UnicodeDecodeError:
+ new_parent = _unicode_decode(parent,
+ encoding=_encodings['merge'], errors='replace')
+ new_parent = _unicode_encode(new_parent,
+ encoding=_encodings['merge'], errors='backslashreplace')
+ new_parent = _unicode_decode(new_parent,
+ encoding=_encodings['merge'], errors='replace')
+ os.rename(parent, new_parent)
+ unicode_error = True
+ unicode_errors.append(new_parent[srcroot_len:])
+ break
+
+ for fname in files:
+ try:
+ fname = _unicode_decode(fname,
+ encoding=_encodings['merge'], errors='strict')
+ except UnicodeDecodeError:
+ fpath = portage._os.path.join(
+ parent.encode(_encodings['merge']), fname)
+ new_fname = _unicode_decode(fname,
+ encoding=_encodings['merge'], errors='replace')
+ new_fname = _unicode_encode(new_fname,
+ encoding=_encodings['merge'], errors='backslashreplace')
+ new_fname = _unicode_decode(new_fname,
+ encoding=_encodings['merge'], errors='replace')
+ new_fpath = os.path.join(parent, new_fname)
+ os.rename(fpath, new_fpath)
+ unicode_error = True
+ unicode_errors.append(new_fpath[srcroot_len:])
+ fname = new_fname
+ fpath = new_fpath
+ else:
+ fpath = os.path.join(parent, fname)
+
+ relative_path = fpath[srcroot_len:]
+
+ if "\n" in relative_path:
+ paths_with_newlines.append(relative_path)
+
+ file_mode = os.lstat(fpath).st_mode
+ if stat.S_ISREG(file_mode):
+ myfilelist.append(relative_path)
+ elif stat.S_ISLNK(file_mode):
+ # Note: os.walk puts symlinks to directories in the "dirs"
+ # list and it does not traverse them since that could lead
+ # to an infinite recursion loop.
+ mylinklist.append(relative_path)
+
+ if unicode_error:
+ break
+
+ if not unicode_error:
+ break
+
+ if unicode_errors:
+ eerror(portage._merge_unicode_error(unicode_errors))
+
+ if paths_with_newlines:
+ msg = []
+ msg.append(_("This package installs one or more files containing a newline (\\n) character:"))
+ msg.append("")
+ paths_with_newlines.sort()
+ for f in paths_with_newlines:
+ msg.append("\t/%s" % (f.replace("\n", "\\n")))
+ msg.append("")
+ msg.append(_("package %s NOT merged") % self.mycpv)
+ msg.append("")
+ eerror(msg)
+ return 1
+
+ # If there are no files to merge, and an installed package in the same
+ # slot has files, it probably means that something went wrong.
+ if self.settings.get("PORTAGE_PACKAGE_EMPTY_ABORT") == "1" and \
+ not myfilelist and not mylinklist and others_in_slot:
+ installed_files = None
+ for other_dblink in others_in_slot:
+ installed_files = other_dblink.getcontents()
+ if not installed_files:
+ continue
+ from textwrap import wrap
+ wrap_width = 72
+ msg = []
+ d = {
+ "new_cpv":self.mycpv,
+ "old_cpv":other_dblink.mycpv
+ }
+ msg.extend(wrap(_("The '%(new_cpv)s' package will not install "
+ "any files, but the currently installed '%(old_cpv)s'"
+ " package has the following files: ") % d, wrap_width))
+ msg.append("")
+ msg.extend(sorted(installed_files))
+ msg.append("")
+ msg.append(_("package %s NOT merged") % self.mycpv)
+ msg.append("")
+ msg.extend(wrap(
+ _("Manually run `emerge --unmerge =%s` if you "
+ "really want to remove the above files. Set "
+ "PORTAGE_PACKAGE_EMPTY_ABORT=\"0\" in "
+ "/etc/make.conf if you do not want to "
+ "abort in cases like this.") % other_dblink.mycpv,
+ wrap_width))
+ eerror(msg)
+ if installed_files:
+ return 1
+
+ # check for package collisions
+ blockers = self._blockers
+ if blockers is None:
+ blockers = []
+ collisions, symlink_collisions, plib_collisions = \
+ self._collision_protect(srcroot, destroot,
+ others_in_slot + blockers, myfilelist, mylinklist)
+
+ # Make sure the ebuild environment is initialized and that ${T}/elog
+ # exists for logging of collision-protect eerror messages.
+ if myebuild is None:
+ myebuild = os.path.join(inforoot, self.pkg + ".ebuild")
+ doebuild_environment(myebuild, "preinst",
+ settings=self.settings, db=mydbapi)
+ self.settings["REPLACING_VERSIONS"] = " ".join(
+ [portage.versions.cpv_getversion(other.mycpv)
+ for other in others_in_slot])
+ prepare_build_dirs(settings=self.settings, cleanup=cleanup)
+
+ if collisions:
+ collision_protect = "collision-protect" in self.settings.features
+ protect_owned = "protect-owned" in self.settings.features
+ msg = _("This package will overwrite one or more files that"
+ " may belong to other packages (see list below).")
+ if not (collision_protect or protect_owned):
+ msg += _(" Add either \"collision-protect\" or"
+ " \"protect-owned\" to FEATURES in"
+ " make.conf if you would like the merge to abort"
+ " in cases like this. See the make.conf man page for"
+ " more information about these features.")
+ if self.settings.get("PORTAGE_QUIET") != "1":
+ msg += _(" You can use a command such as"
+ " `portageq owners / <filename>` to identify the"
+ " installed package that owns a file. If portageq"
+ " reports that only one package owns a file then do NOT"
+ " file a bug report. A bug report is only useful if it"
+ " identifies at least two or more packages that are known"
+ " to install the same file(s)."
+ " If a collision occurs and you"
+ " can not explain where the file came from then you"
+ " should simply ignore the collision since there is not"
+ " enough information to determine if a real problem"
+ " exists. Please do NOT file a bug report at"
+ " http://bugs.gentoo.org unless you report exactly which"
+ " two packages install the same file(s). Once again,"
+ " please do NOT file a bug report unless you have"
+ " completely understood the above message.")
+
+ self.settings["EBUILD_PHASE"] = "preinst"
+ from textwrap import wrap
+ msg = wrap(msg, 70)
+ if collision_protect:
+ msg.append("")
+ msg.append(_("package %s NOT merged") % self.settings.mycpv)
+ msg.append("")
+ msg.append(_("Detected file collision(s):"))
+ msg.append("")
+
+ for f in collisions:
+ msg.append("\t%s" % \
+ os.path.join(destroot, f.lstrip(os.path.sep)))
+
+ eerror(msg)
+
+ owners = None
+ if collision_protect or protect_owned or symlink_collisions:
+ msg = []
+ msg.append("")
+ msg.append(_("Searching all installed"
+ " packages for file collisions..."))
+ msg.append("")
+ msg.append(_("Press Ctrl-C to Stop"))
+ msg.append("")
+ eerror(msg)
+
+ if len(collisions) > 20:
+ # get_owners is slow for large numbers of files, so
+ # don't look them all up.
+ collisions = collisions[:20]
+ self.lockdb()
+ try:
+ owners = self.vartree.dbapi._owners.get_owners(collisions)
+ self.vartree.dbapi.flush_cache()
+ finally:
+ self.unlockdb()
+
+ for pkg, owned_files in owners.items():
+ cpv = pkg.mycpv
+ msg = []
+ msg.append("%s" % cpv)
+ for f in sorted(owned_files):
+ msg.append("\t%s" % os.path.join(destroot,
+ f.lstrip(os.path.sep)))
+ msg.append("")
+ eerror(msg)
+
+ if not owners:
+ eerror([_("None of the installed"
+ " packages claim the file(s)."), ""])
+
+ # The explanation about the collision and how to solve
+ # it may not be visible via a scrollback buffer, especially
+ # if the number of file collisions is large. Therefore,
+ # show a summary at the end.
+ abort = False
+ if collision_protect:
+ abort = True
+ msg = _("Package '%s' NOT merged due to file collisions.") % \
+ self.settings.mycpv
+ elif protect_owned and owners:
+ abort = True
+ msg = _("Package '%s' NOT merged due to file collisions.") % \
+ self.settings.mycpv
+ elif symlink_collisions:
+ abort = True
+ msg = _("Package '%s' NOT merged due to collision " + \
+ "between a symlink and a directory which is explicitly " + \
+ "forbidden by PMS (see bug #326685).") % \
+ (self.settings.mycpv,)
+ else:
+ msg = _("Package '%s' merged despite file collisions.") % \
+ self.settings.mycpv
+ msg += _(" If necessary, refer to your elog "
+ "messages for the whole content of the above message.")
+ eerror(wrap(msg, 70))
+
+ if abort:
+ return 1
+
+ # The merge process may move files out of the image directory,
+ # which causes invalidation of the .installed flag.
+ try:
+ os.unlink(os.path.join(
+ os.path.dirname(normalize_path(srcroot)), ".installed"))
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+
+ self.dbdir = self.dbtmpdir
+ self.delete()
+ ensure_dirs(self.dbtmpdir)
+
+ # run preinst script
+ showMessage(_(">>> Merging %(cpv)s to %(destroot)s\n") % \
+ {"cpv":self.mycpv, "destroot":destroot})
+ phase = EbuildPhase(background=False, phase="preinst",
+ scheduler=self._scheduler, settings=self.settings)
+ phase.start()
+ a = phase.wait()
+
+ # XXX: Decide how to handle failures here.
+ if a != os.EX_OK:
+ showMessage(_("!!! FAILED preinst: ")+str(a)+"\n",
+ level=logging.ERROR, noiselevel=-1)
+ return a
+
+ # copy "info" files (like SLOT, CFLAGS, etc.) into the database
+ for x in os.listdir(inforoot):
+ self.copyfile(inforoot+"/"+x)
+
+ # write local package counter for recording
+ if counter is None:
+ counter = self.vartree.dbapi.counter_tick(mycpv=self.mycpv)
+ io.open(_unicode_encode(os.path.join(self.dbtmpdir, 'COUNTER'),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='w', encoding=_encodings['repo.content'],
+ errors='backslashreplace').write(_unicode_decode(str(counter)))
+
+ self.updateprotect()
+
+ #if we have a file containing previously-merged config file md5sums, grab it.
+ self.vartree.dbapi._fs_lock()
+ try:
+ cfgfiledict = grabdict(self.vartree.dbapi._conf_mem_file)
+ if "NOCONFMEM" in self.settings:
+ cfgfiledict["IGNORE"]=1
+ else:
+ cfgfiledict["IGNORE"]=0
+
+ # Always behave like --noconfmem is enabled for downgrades
+ # so that people who don't know about this option are less
+ # likely to get confused when doing upgrade/downgrade cycles.
+ pv_split = catpkgsplit(self.mycpv)[1:]
+ for other in others_in_slot:
+ if pkgcmp(pv_split, catpkgsplit(other.mycpv)[1:]) < 0:
+ cfgfiledict["IGNORE"] = 1
+ break
+
+ rval = self._merge_contents(srcroot, destroot, cfgfiledict)
+ if rval != os.EX_OK:
+ return rval
+ finally:
+ self.vartree.dbapi._fs_unlock()
+
+ # These caches are populated during collision-protect and the data
+ # they contain is now invalid. It's very important to invalidate
+ # the contents_inodes cache so that FEATURES=unmerge-orphans
+ # doesn't unmerge anything that belongs to this package that has
+ # just been merged.
+ for dblnk in others_in_slot:
+ dblnk._clear_contents_cache()
+ self._clear_contents_cache()
+
+ linkmap = self.vartree.dbapi._linkmap
+ plib_registry = self.vartree.dbapi._plib_registry
+ # We initialize preserve_paths to an empty set rather
+ # than None here because it plays an important role
+ # in prune_plib_registry logic by serving to indicate
+ # that we have a replacement for a package that's
+ # being unmerged.
+
+ preserve_paths = set()
+ needed = None
+ if not (self._linkmap_broken or linkmap is None or
+ plib_registry is None):
+ self.vartree.dbapi._fs_lock()
+ plib_registry.lock()
+ try:
+ plib_registry.load()
+ needed = os.path.join(inforoot, linkmap._needed_aux_key)
+ self._linkmap_rebuild(include_file=needed)
+
+ # Preserve old libs if they are still in use
+ # TODO: Handle cases where the previous instance
+ # has already been uninstalled but it still has some
+ # preserved libraries in the registry that we may
+ # want to preserve here.
+ preserve_paths = self._find_libs_to_preserve()
+ finally:
+ plib_registry.unlock()
+ self.vartree.dbapi._fs_unlock()
+
+ if preserve_paths:
+ self._add_preserve_libs_to_contents(preserve_paths)
+
+ # If portage is reinstalling itself, remove the old
+ # version now since we want to use the temporary
+ # PORTAGE_BIN_PATH that will be removed when we return.
+ reinstall_self = False
+ if self.myroot == "/" and \
+ match_from_list(PORTAGE_PACKAGE_ATOM, [self.mycpv]):
+ reinstall_self = True
+
+ emerge_log = self._emerge_log
+
+ # If we have any preserved libraries then autoclean
+ # is forced so that preserve-libs logic doesn't have
+ # to account for the additional complexity of the
+ # AUTOCLEAN=no mode.
+ autoclean = self.settings.get("AUTOCLEAN", "yes") == "yes" \
+ or preserve_paths
+
+ if autoclean:
+ emerge_log(_(" >>> AUTOCLEAN: %s") % (slot_atom,))
+
+ others_in_slot.append(self) # self has just been merged
+ for dblnk in list(others_in_slot):
+ if dblnk is self:
+ continue
+ if not (autoclean or dblnk.mycpv == self.mycpv or reinstall_self):
+ continue
+ showMessage(_(">>> Safely unmerging already-installed instance...\n"))
+ emerge_log(_(" === Unmerging... (%s)") % (dblnk.mycpv,))
+ others_in_slot.remove(dblnk) # dblnk will unmerge itself now
+ dblnk._linkmap_broken = self._linkmap_broken
+ dblnk.settings["REPLACED_BY_VERSION"] = portage.versions.cpv_getversion(self.mycpv)
+ dblnk.settings.backup_changes("REPLACED_BY_VERSION")
+ unmerge_rval = dblnk.unmerge(ldpath_mtimes=prev_mtimes,
+ others_in_slot=others_in_slot, needed=needed,
+ preserve_paths=preserve_paths)
+ dblnk.settings.pop("REPLACED_BY_VERSION", None)
+
+ if unmerge_rval == os.EX_OK:
+ emerge_log(_(" >>> unmerge success: %s") % (dblnk.mycpv,))
+ else:
+ emerge_log(_(" !!! unmerge FAILURE: %s") % (dblnk.mycpv,))
+
+ self.lockdb()
+ try:
+ # TODO: Check status and abort if necessary.
+ dblnk.delete()
+ finally:
+ self.unlockdb()
+ showMessage(_(">>> Original instance of package unmerged safely.\n"))
+
+ if len(others_in_slot) > 1:
+ showMessage(colorize("WARN", _("WARNING:"))
+ + _(" AUTOCLEAN is disabled. This can cause serious"
+ " problems due to overlapping packages.\n"),
+ level=logging.WARN, noiselevel=-1)
+
+ # We hold both directory locks.
+ self.dbdir = self.dbpkgdir
+ self.lockdb()
+ try:
+ self.delete()
+ _movefile(self.dbtmpdir, self.dbpkgdir, mysettings=self.settings)
+ finally:
+ self.unlockdb()
+
+ # Check for file collisions with blocking packages
+ # and remove any colliding files from their CONTENTS
+ # since they now belong to this package.
+ self._clear_contents_cache()
+ contents = self.getcontents()
+ destroot_len = len(destroot) - 1
+ self.lockdb()
+ try:
+ for blocker in blockers:
+ self.vartree.dbapi.removeFromContents(blocker, iter(contents),
+ relative_paths=False)
+ finally:
+ self.unlockdb()
+
+ plib_registry = self.vartree.dbapi._plib_registry
+ if plib_registry:
+ self.vartree.dbapi._fs_lock()
+ plib_registry.lock()
+ try:
+ plib_registry.load()
+
+ if preserve_paths:
+ # keep track of the libs we preserved
+ plib_registry.register(self.mycpv, slot, counter,
+ sorted(preserve_paths))
+
+ # Unregister any preserved libs that this package has overwritten
+ # and update the contents of the packages that owned them.
+ plib_dict = plib_registry.getPreservedLibs()
+ for cpv, paths in plib_collisions.items():
+ if cpv not in plib_dict:
+ continue
+ has_vdb_entry = False
+ if cpv != self.mycpv:
+ # If we've replaced another instance with the
+ # same cpv then the vdb entry no longer belongs
+ # to it, so we'll have to get the slot and counter
+ # from plib_registry._data instead.
+ self.vartree.dbapi.lock()
+ try:
+ try:
+ slot, counter = self.vartree.dbapi.aux_get(
+ cpv, ["SLOT", "COUNTER"])
+ except KeyError:
+ pass
+ else:
+ has_vdb_entry = True
+ self.vartree.dbapi.removeFromContents(
+ cpv, paths)
+ finally:
+ self.vartree.dbapi.unlock()
+
+ if not has_vdb_entry:
+ # It's possible for previously unmerged packages
+ # to have preserved libs in the registry, so try
+ # to retrieve the slot and counter from there.
+ has_registry_entry = False
+ for plib_cps, (plib_cpv, plib_counter, plib_paths) in \
+ plib_registry._data.items():
+ if plib_cpv != cpv:
+ continue
+ try:
+ cp, slot = plib_cps.split(":", 1)
+ except ValueError:
+ continue
+ counter = plib_counter
+ has_registry_entry = True
+ break
+
+ if not has_registry_entry:
+ continue
+
+ remaining = [f for f in plib_dict[cpv] if f not in paths]
+ plib_registry.register(cpv, slot, counter, remaining)
+
+ plib_registry.store()
+ finally:
+ plib_registry.unlock()
+ self.vartree.dbapi._fs_unlock()
+
+ self.vartree.dbapi._add(self)
+ contents = self.getcontents()
+
+ #do postinst script
+ self.settings["PORTAGE_UPDATE_ENV"] = \
+ os.path.join(self.dbpkgdir, "environment.bz2")
+ self.settings.backup_changes("PORTAGE_UPDATE_ENV")
+ try:
+ phase = EbuildPhase(background=False, phase="postinst",
+ scheduler=self._scheduler, settings=self.settings)
+ phase.start()
+ a = phase.wait()
+ if a == os.EX_OK:
+ showMessage(_(">>> %s merged.\n") % self.mycpv)
+ finally:
+ self.settings.pop("PORTAGE_UPDATE_ENV", None)
+
+ if a != os.EX_OK:
+ # It's stupid to bail out here, so keep going regardless of
+ # phase return code.
+ showMessage(_("!!! FAILED postinst: ")+str(a)+"\n",
+ level=logging.ERROR, noiselevel=-1)
+
+ downgrade = False
+ for v in otherversions:
+ if pkgcmp(catpkgsplit(self.pkg)[1:], catpkgsplit(v)[1:]) < 0:
+ downgrade = True
+
+ # Lock the config memory file to prevent symlink creation
+ # in merge_contents from overlapping with env-update.
+ self.vartree.dbapi._fs_lock()
+ try:
+ #update environment settings, library paths. DO NOT change symlinks.
+ env_update(makelinks=(not downgrade),
+ target_root=self.settings['ROOT'], prev_mtimes=prev_mtimes,
+ contents=contents, env=self.settings.environ(),
+ writemsg_level=self._display_merge)
+ finally:
+ self.vartree.dbapi._fs_unlock()
+
+ # For gcc upgrades, preserved libs have to be removed after the
+ # the library path has been updated.
+ self._prune_plib_registry()
+
+ return os.EX_OK
+
+ def _new_backup_path(self, p):
+ """
+ The works for any type path, such as a regular file, symlink,
+ or directory. The parent directory is assumed to exist.
+ The returned filename is of the form p + '.backup.' + x, where
+ x guarantees that the returned path does not exist yet.
+ """
+ os = _os_merge
+
+ x = -1
+ while True:
+ x += 1
+ backup_p = p + '.backup.' + str(x).rjust(4, '0')
+ try:
+ os.lstat(backup_p)
+ except OSError:
+ break
+
+ return backup_p
+
+ def _merge_contents(self, srcroot, destroot, cfgfiledict):
+
+ cfgfiledict_orig = cfgfiledict.copy()
+
+ # open CONTENTS file (possibly overwriting old one) for recording
+ # Use atomic_ofstream for automatic coercion of raw bytes to
+ # unicode, in order to prevent TypeError when writing raw bytes
+ # to TextIOWrapper with python2.
+ outfile = atomic_ofstream(_unicode_encode(
+ os.path.join(self.dbtmpdir, 'CONTENTS'),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='w', encoding=_encodings['repo.content'],
+ errors='backslashreplace')
+
+ # Don't bump mtimes on merge since some application require
+ # preservation of timestamps. This means that the unmerge phase must
+ # check to see if file belongs to an installed instance in the same
+ # slot.
+ mymtime = None
+
+ # set umask to 0 for merging; back up umask, save old one in prevmask (since this is a global change)
+ prevmask = os.umask(0)
+ secondhand = []
+
+ # we do a first merge; this will recurse through all files in our srcroot but also build up a
+ # "second hand" of symlinks to merge later
+ if self.mergeme(srcroot, destroot, outfile, secondhand, "", cfgfiledict, mymtime):
+ return 1
+
+ # now, it's time for dealing our second hand; we'll loop until we can't merge anymore. The rest are
+ # broken symlinks. We'll merge them too.
+ lastlen = 0
+ while len(secondhand) and len(secondhand)!=lastlen:
+ # clear the thirdhand. Anything from our second hand that
+ # couldn't get merged will be added to thirdhand.
+
+ thirdhand = []
+ if self.mergeme(srcroot, destroot, outfile, thirdhand,
+ secondhand, cfgfiledict, mymtime):
+ return 1
+
+ #swap hands
+ lastlen = len(secondhand)
+
+ # our thirdhand now becomes our secondhand. It's ok to throw
+ # away secondhand since thirdhand contains all the stuff that
+ # couldn't be merged.
+ secondhand = thirdhand
+
+ if len(secondhand):
+ # force merge of remaining symlinks (broken or circular; oh well)
+ if self.mergeme(srcroot, destroot, outfile, None,
+ secondhand, cfgfiledict, mymtime):
+ return 1
+
+ #restore umask
+ os.umask(prevmask)
+
+ #if we opened it, close it
+ outfile.flush()
+ outfile.close()
+
+ # write out our collection of md5sums
+ if cfgfiledict != cfgfiledict_orig:
+ cfgfiledict.pop("IGNORE", None)
+ try:
+ writedict(cfgfiledict, self.vartree.dbapi._conf_mem_file)
+ except InvalidLocation:
+ self.settings._init_dirs()
+ writedict(cfgfiledict, self.vartree.dbapi._conf_mem_file)
+
+ return os.EX_OK
+
+ def mergeme(self, srcroot, destroot, outfile, secondhand, stufftomerge, cfgfiledict, thismtime):
+ """
+
+ This function handles actual merging of the package contents to the livefs.
+ It also handles config protection.
+
+ @param srcroot: Where are we copying files from (usually ${D})
+ @type srcroot: String (Path)
+ @param destroot: Typically ${ROOT}
+ @type destroot: String (Path)
+ @param outfile: File to log operations to
+ @type outfile: File Object
+ @param secondhand: A set of items to merge in pass two (usually
+ or symlinks that point to non-existing files that may get merged later)
+ @type secondhand: List
+ @param stufftomerge: Either a diretory to merge, or a list of items.
+ @type stufftomerge: String or List
+ @param cfgfiledict: { File:mtime } mapping for config_protected files
+ @type cfgfiledict: Dictionary
+ @param thismtime: The current time (typically long(time.time())
+ @type thismtime: Long
+ @rtype: None or Boolean
+ @returns:
+ 1. True on failure
+ 2. None otherwise
+
+ """
+
+ showMessage = self._display_merge
+ writemsg = self._display_merge
+
+ os = _os_merge
+ sep = os.sep
+ join = os.path.join
+ srcroot = normalize_path(srcroot).rstrip(sep) + sep
+ destroot = normalize_path(destroot).rstrip(sep) + sep
+ calc_prelink = "prelink-checksums" in self.settings.features
+
+ # this is supposed to merge a list of files. There will be 2 forms of argument passing.
+ if isinstance(stufftomerge, basestring):
+ #A directory is specified. Figure out protection paths, listdir() it and process it.
+ mergelist = os.listdir(join(srcroot, stufftomerge))
+ offset = stufftomerge
+ else:
+ mergelist = stufftomerge
+ offset = ""
+
+ for i, x in enumerate(mergelist):
+
+ mysrc = join(srcroot, offset, x)
+ mydest = join(destroot, offset, x)
+ # myrealdest is mydest without the $ROOT prefix (makes a difference if ROOT!="/")
+ myrealdest = join(sep, offset, x)
+ # stat file once, test using S_* macros many times (faster that way)
+ mystat = os.lstat(mysrc)
+ mymode = mystat[stat.ST_MODE]
+ # handy variables; mydest is the target object on the live filesystems;
+ # mysrc is the source object in the temporary install dir
+ try:
+ mydstat = os.lstat(mydest)
+ mydmode = mydstat.st_mode
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ #dest file doesn't exist
+ mydstat = None
+ mydmode = None
+
+ if stat.S_ISLNK(mymode):
+ # we are merging a symbolic link
+ myabsto = abssymlink(mysrc)
+ if myabsto.startswith(srcroot):
+ myabsto = myabsto[len(srcroot):]
+ myabsto = myabsto.lstrip(sep)
+ myto = os.readlink(mysrc)
+ if self.settings and self.settings["D"]:
+ if myto.startswith(self.settings["D"]):
+ myto = myto[len(self.settings["D"]):]
+ # myrealto contains the path of the real file to which this symlink points.
+ # we can simply test for existence of this file to see if the target has been merged yet
+ myrealto = normalize_path(os.path.join(destroot, myabsto))
+ if mydmode!=None:
+ #destination exists
+ if stat.S_ISDIR(mydmode):
+ # we can't merge a symlink over a directory
+ newdest = self._new_backup_path(mydest)
+ msg = []
+ msg.append("")
+ msg.append(_("Installation of a symlink is blocked by a directory:"))
+ msg.append(" '%s'" % mydest)
+ msg.append(_("This symlink will be merged with a different name:"))
+ msg.append(" '%s'" % newdest)
+ msg.append("")
+ self._eerror("preinst", msg)
+ mydest = newdest
+
+ elif not stat.S_ISLNK(mydmode):
+ if os.path.exists(mysrc) and stat.S_ISDIR(os.stat(mysrc)[stat.ST_MODE]):
+ # Kill file blocking installation of symlink to dir #71787
+ pass
+ elif self.isprotected(mydest):
+ # Use md5 of the target in ${D} if it exists...
+ try:
+ newmd5 = perform_md5(join(srcroot, myabsto))
+ except FileNotFound:
+ # Maybe the target is merged already.
+ try:
+ newmd5 = perform_md5(myrealto)
+ except FileNotFound:
+ newmd5 = None
+ mydest = new_protect_filename(mydest, newmd5=newmd5)
+
+ # if secondhand is None it means we're operating in "force" mode and should not create a second hand.
+ if (secondhand != None) and (not os.path.exists(myrealto)):
+ # either the target directory doesn't exist yet or the target file doesn't exist -- or
+ # the target is a broken symlink. We will add this file to our "second hand" and merge
+ # it later.
+ secondhand.append(mysrc[len(srcroot):])
+ continue
+ # unlinking no longer necessary; "movefile" will overwrite symlinks atomically and correctly
+ mymtime = movefile(mysrc, mydest, newmtime=thismtime,
+ sstat=mystat, mysettings=self.settings,
+ encoding=_encodings['merge'])
+ if mymtime != None:
+ showMessage(">>> %s -> %s\n" % (mydest, myto))
+ outfile.write("sym "+myrealdest+" -> "+myto+" "+str(mymtime)+"\n")
+ else:
+ showMessage(_("!!! Failed to move file.\n"),
+ level=logging.ERROR, noiselevel=-1)
+ showMessage("!!! %s -> %s\n" % (mydest, myto),
+ level=logging.ERROR, noiselevel=-1)
+ return 1
+ elif stat.S_ISDIR(mymode):
+ # we are merging a directory
+ if mydmode != None:
+ # destination exists
+
+ if bsd_chflags:
+ # Save then clear flags on dest.
+ dflags = mydstat.st_flags
+ if dflags != 0:
+ bsd_chflags.lchflags(mydest, 0)
+
+ if not os.access(mydest, os.W_OK):
+ pkgstuff = pkgsplit(self.pkg)
+ writemsg(_("\n!!! Cannot write to '%s'.\n") % mydest, noiselevel=-1)
+ writemsg(_("!!! Please check permissions and directories for broken symlinks.\n"))
+ writemsg(_("!!! You may start the merge process again by using ebuild:\n"))
+ writemsg("!!! ebuild "+self.settings["PORTDIR"]+"/"+self.cat+"/"+pkgstuff[0]+"/"+self.pkg+".ebuild merge\n")
+ writemsg(_("!!! And finish by running this: env-update\n\n"))
+ return 1
+
+ if stat.S_ISDIR(mydmode) or \
+ (stat.S_ISLNK(mydmode) and os.path.isdir(mydest)):
+ # a symlink to an existing directory will work for us; keep it:
+ showMessage("--- %s/\n" % mydest)
+ if bsd_chflags:
+ bsd_chflags.lchflags(mydest, dflags)
+ else:
+ # a non-directory and non-symlink-to-directory. Won't work for us. Move out of the way.
+ backup_dest = self._new_backup_path(mydest)
+ msg = []
+ msg.append("")
+ msg.append(_("Installation of a directory is blocked by a file:"))
+ msg.append(" '%s'" % mydest)
+ msg.append(_("This file will be renamed to a different name:"))
+ msg.append(" '%s'" % backup_dest)
+ msg.append("")
+ self._eerror("preinst", msg)
+ if movefile(mydest, backup_dest,
+ mysettings=self.settings,
+ encoding=_encodings['merge']) is None:
+ return 1
+ showMessage(_("bak %s %s.backup\n") % (mydest, mydest),
+ level=logging.ERROR, noiselevel=-1)
+ #now create our directory
+ try:
+ if self.settings.selinux_enabled():
+ _selinux_merge.mkdir(mydest, mysrc)
+ else:
+ os.mkdir(mydest)
+ except OSError as e:
+ # Error handling should be equivalent to
+ # portage.util.ensure_dirs() for cases
+ # like bug #187518.
+ if e.errno in (errno.EEXIST,):
+ pass
+ elif os.path.isdir(mydest):
+ pass
+ else:
+ raise
+ del e
+
+ if bsd_chflags:
+ bsd_chflags.lchflags(mydest, dflags)
+ os.chmod(mydest, mystat[0])
+ os.chown(mydest, mystat[4], mystat[5])
+ showMessage(">>> %s/\n" % mydest)
+ else:
+ try:
+ #destination doesn't exist
+ if self.settings.selinux_enabled():
+ _selinux_merge.mkdir(mydest, mysrc)
+ else:
+ os.mkdir(mydest)
+ except OSError as e:
+ # Error handling should be equivalent to
+ # portage.util.ensure_dirs() for cases
+ # like bug #187518.
+ if e.errno in (errno.EEXIST,):
+ pass
+ elif os.path.isdir(mydest):
+ pass
+ else:
+ raise
+ del e
+ os.chmod(mydest, mystat[0])
+ os.chown(mydest, mystat[4], mystat[5])
+ showMessage(">>> %s/\n" % mydest)
+ outfile.write("dir "+myrealdest+"\n")
+ # recurse and merge this directory
+ if self.mergeme(srcroot, destroot, outfile, secondhand,
+ join(offset, x), cfgfiledict, thismtime):
+ return 1
+ elif stat.S_ISREG(mymode):
+ # we are merging a regular file
+ mymd5 = perform_md5(mysrc, calc_prelink=calc_prelink)
+ # calculate config file protection stuff
+ mydestdir = os.path.dirname(mydest)
+ moveme = 1
+ zing = "!!!"
+ mymtime = None
+ protected = self.isprotected(mydest)
+ if mydmode != None:
+ # destination file exists
+
+ if stat.S_ISDIR(mydmode):
+ # install of destination is blocked by an existing directory with the same name
+ newdest = self._new_backup_path(mydest)
+ msg = []
+ msg.append("")
+ msg.append(_("Installation of a regular file is blocked by a directory:"))
+ msg.append(" '%s'" % mydest)
+ msg.append(_("This file will be merged with a different name:"))
+ msg.append(" '%s'" % newdest)
+ msg.append("")
+ self._eerror("preinst", msg)
+ mydest = newdest
+
+ elif stat.S_ISREG(mydmode) or (stat.S_ISLNK(mydmode) and os.path.exists(mydest) and stat.S_ISREG(os.stat(mydest)[stat.ST_MODE])):
+ # install of destination is blocked by an existing regular file,
+ # or by a symlink to an existing regular file;
+ # now, config file management may come into play.
+ # we only need to tweak mydest if cfg file management is in play.
+ if protected:
+ # we have a protection path; enable config file management.
+ cfgprot = 0
+ destmd5 = perform_md5(mydest, calc_prelink=calc_prelink)
+ if mymd5 == destmd5:
+ #file already in place; simply update mtimes of destination
+ moveme = 1
+ else:
+ if mymd5 == cfgfiledict.get(myrealdest, [None])[0]:
+ """ An identical update has previously been
+ merged. Skip it unless the user has chosen
+ --noconfmem."""
+ moveme = cfgfiledict["IGNORE"]
+ cfgprot = cfgfiledict["IGNORE"]
+ if not moveme:
+ zing = "---"
+ mymtime = mystat[stat.ST_MTIME]
+ else:
+ moveme = 1
+ cfgprot = 1
+ if moveme:
+ # Merging a new file, so update confmem.
+ cfgfiledict[myrealdest] = [mymd5]
+ elif destmd5 == cfgfiledict.get(myrealdest, [None])[0]:
+ """A previously remembered update has been
+ accepted, so it is removed from confmem."""
+ del cfgfiledict[myrealdest]
+
+ if cfgprot:
+ mydest = new_protect_filename(mydest, newmd5=mymd5)
+
+ # whether config protection or not, we merge the new file the
+ # same way. Unless moveme=0 (blocking directory)
+ if moveme:
+ # Create hardlinks only for source files that already exist
+ # as hardlinks (having identical st_dev and st_ino).
+ hardlink_key = (mystat.st_dev, mystat.st_ino)
+
+ hardlink_candidates = self._md5_merge_map.get(hardlink_key)
+ if hardlink_candidates is None:
+ hardlink_candidates = []
+ self._md5_merge_map[hardlink_key] = hardlink_candidates
+
+ mymtime = movefile(mysrc, mydest, newmtime=thismtime,
+ sstat=mystat, mysettings=self.settings,
+ hardlink_candidates=hardlink_candidates,
+ encoding=_encodings['merge'])
+ if mymtime is None:
+ return 1
+ if hardlink_candidates is not None:
+ hardlink_candidates.append(mydest)
+ zing = ">>>"
+
+ if mymtime != None:
+ outfile.write("obj "+myrealdest+" "+mymd5+" "+str(mymtime)+"\n")
+ showMessage("%s %s\n" % (zing,mydest))
+ else:
+ # we are merging a fifo or device node
+ zing = "!!!"
+ if mydmode is None:
+ # destination doesn't exist
+ if movefile(mysrc, mydest, newmtime=thismtime,
+ sstat=mystat, mysettings=self.settings,
+ encoding=_encodings['merge']) is not None:
+ zing = ">>>"
+ else:
+ return 1
+ if stat.S_ISFIFO(mymode):
+ outfile.write("fif %s\n" % myrealdest)
+ else:
+ outfile.write("dev %s\n" % myrealdest)
+ showMessage(zing + " " + mydest + "\n")
+
+ def merge(self, mergeroot, inforoot, myroot=None, myebuild=None, cleanup=0,
+ mydbapi=None, prev_mtimes=None, counter=None):
+ """
+ @param myroot: ignored, self._eroot is used instead
+ """
+ myroot = None
+ retval = -1
+ parallel_install = "parallel-install" in self.settings.features
+ if not parallel_install:
+ self.lockdb()
+ self.vartree.dbapi._bump_mtime(self.mycpv)
+ if self._scheduler is None:
+ self._scheduler = PollScheduler().sched_iface
+ try:
+ retval = self.treewalk(mergeroot, myroot, inforoot, myebuild,
+ cleanup=cleanup, mydbapi=mydbapi, prev_mtimes=prev_mtimes,
+ counter=counter)
+
+ # If PORTAGE_BUILDDIR doesn't exist, then it probably means
+ # fail-clean is enabled, and the success/die hooks have
+ # already been called by EbuildPhase.
+ if os.path.isdir(self.settings['PORTAGE_BUILDDIR']):
+
+ if retval == os.EX_OK:
+ phase = 'success_hooks'
+ else:
+ phase = 'die_hooks'
+
+ ebuild_phase = MiscFunctionsProcess(
+ background=False, commands=[phase],
+ scheduler=self._scheduler, settings=self.settings)
+ ebuild_phase.start()
+ ebuild_phase.wait()
+ self._elog_process()
+
+ if 'noclean' not in self.settings.features and \
+ (retval == os.EX_OK or \
+ 'fail-clean' in self.settings.features):
+ if myebuild is None:
+ myebuild = os.path.join(inforoot, self.pkg + ".ebuild")
+
+ doebuild_environment(myebuild, "clean",
+ settings=self.settings, db=mydbapi)
+ phase = EbuildPhase(background=False, phase="clean",
+ scheduler=self._scheduler, settings=self.settings)
+ phase.start()
+ phase.wait()
+ finally:
+ self.settings.pop('REPLACING_VERSIONS', None)
+ if self.vartree.dbapi._linkmap is None:
+ # preserve-libs is entirely disabled
+ pass
+ else:
+ self.vartree.dbapi._linkmap._clear_cache()
+ self.vartree.dbapi._bump_mtime(self.mycpv)
+ if not parallel_install:
+ self.unlockdb()
+ return retval
+
+ def getstring(self,name):
+ "returns contents of a file with whitespace converted to spaces"
+ if not os.path.exists(self.dbdir+"/"+name):
+ return ""
+ mydata = io.open(
+ _unicode_encode(os.path.join(self.dbdir, name),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'], errors='replace'
+ ).read().split()
+ return " ".join(mydata)
+
+ def copyfile(self,fname):
+ shutil.copyfile(fname,self.dbdir+"/"+os.path.basename(fname))
+
+ def getfile(self,fname):
+ if not os.path.exists(self.dbdir+"/"+fname):
+ return ""
+ return io.open(_unicode_encode(os.path.join(self.dbdir, fname),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'], errors='replace'
+ ).read()
+
+ def setfile(self,fname,data):
+ kwargs = {}
+ if fname == 'environment.bz2' or not isinstance(data, basestring):
+ kwargs['mode'] = 'wb'
+ else:
+ kwargs['mode'] = 'w'
+ kwargs['encoding'] = _encodings['repo.content']
+ write_atomic(os.path.join(self.dbdir, fname), data, **kwargs)
+
+ def getelements(self,ename):
+ if not os.path.exists(self.dbdir+"/"+ename):
+ return []
+ mylines = io.open(_unicode_encode(
+ os.path.join(self.dbdir, ename),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'], errors='replace'
+ ).readlines()
+ myreturn = []
+ for x in mylines:
+ for y in x[:-1].split():
+ myreturn.append(y)
+ return myreturn
+
+ def setelements(self,mylist,ename):
+ myelement = io.open(_unicode_encode(
+ os.path.join(self.dbdir, ename),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='w', encoding=_encodings['repo.content'],
+ errors='backslashreplace')
+ for x in mylist:
+ myelement.write(_unicode_decode(x+"\n"))
+ myelement.close()
+
+ def isregular(self):
+ "Is this a regular package (does it have a CATEGORY file? A dblink can be virtual *and* regular)"
+ return os.path.exists(os.path.join(self.dbdir, "CATEGORY"))
+
+def merge(mycat, mypkg, pkgloc, infloc,
+ myroot=None, settings=None, myebuild=None,
+ mytree=None, mydbapi=None, vartree=None, prev_mtimes=None, blockers=None,
+ scheduler=None):
+ """
+ @param myroot: ignored, settings['EROOT'] is used instead
+ """
+ myroot = None
+ if settings is None:
+ raise TypeError("settings argument is required")
+ if not os.access(settings['EROOT'], os.W_OK):
+ writemsg(_("Permission denied: access('%s', W_OK)\n") % settings['EROOT'],
+ noiselevel=-1)
+ return errno.EACCES
+ background = (settings.get('PORTAGE_BACKGROUND') == '1')
+ merge_task = MergeProcess(
+ mycat=mycat, mypkg=mypkg, settings=settings,
+ treetype=mytree, vartree=vartree,
+ scheduler=(scheduler or PollScheduler().sched_iface),
+ background=background, blockers=blockers, pkgloc=pkgloc,
+ infloc=infloc, myebuild=myebuild, mydbapi=mydbapi,
+ prev_mtimes=prev_mtimes, logfile=settings.get('PORTAGE_LOG_FILE'))
+ merge_task.start()
+ retcode = merge_task.wait()
+ return retcode
+
+def unmerge(cat, pkg, myroot=None, settings=None,
+ mytrimworld=None, vartree=None,
+ ldpath_mtimes=None, scheduler=None):
+ """
+ @param myroot: ignored, settings['EROOT'] is used instead
+ @param mytrimworld: ignored
+ """
+ myroot = None
+ if settings is None:
+ raise TypeError("settings argument is required")
+ mylink = dblink(cat, pkg, settings=settings, treetype="vartree",
+ vartree=vartree, scheduler=scheduler)
+ vartree = mylink.vartree
+ parallel_install = "parallel-install" in settings.features
+ if not parallel_install:
+ mylink.lockdb()
+ try:
+ if mylink.exists():
+ retval = mylink.unmerge(ldpath_mtimes=ldpath_mtimes)
+ if retval == os.EX_OK:
+ mylink.lockdb()
+ try:
+ mylink.delete()
+ finally:
+ mylink.unlockdb()
+ return retval
+ return os.EX_OK
+ finally:
+ if vartree.dbapi._linkmap is None:
+ # preserve-libs is entirely disabled
+ pass
+ else:
+ vartree.dbapi._linkmap._clear_cache()
+ if not parallel_install:
+ mylink.unlockdb()
+
+def write_contents(contents, root, f):
+ """
+ Write contents to any file like object. The file will be left open.
+ """
+ root_len = len(root) - 1
+ for filename in sorted(contents):
+ entry_data = contents[filename]
+ entry_type = entry_data[0]
+ relative_filename = filename[root_len:]
+ if entry_type == "obj":
+ entry_type, mtime, md5sum = entry_data
+ line = "%s %s %s %s\n" % \
+ (entry_type, relative_filename, md5sum, mtime)
+ elif entry_type == "sym":
+ entry_type, mtime, link = entry_data
+ line = "%s %s -> %s %s\n" % \
+ (entry_type, relative_filename, link, mtime)
+ else: # dir, dev, fif
+ line = "%s %s\n" % (entry_type, relative_filename)
+ f.write(line)
+
+def tar_contents(contents, root, tar, protect=None, onProgress=None):
+ os = _os_merge
+
+ try:
+ for x in contents:
+ _unicode_encode(x,
+ encoding=_encodings['merge'],
+ errors='strict')
+ except UnicodeEncodeError:
+ # The package appears to have been merged with a
+ # different value of sys.getfilesystemencoding(),
+ # so fall back to utf_8 if appropriate.
+ try:
+ for x in contents:
+ _unicode_encode(x,
+ encoding=_encodings['fs'],
+ errors='strict')
+ except UnicodeEncodeError:
+ pass
+ else:
+ os = portage.os
+
+ root = normalize_path(root).rstrip(os.path.sep) + os.path.sep
+ id_strings = {}
+ maxval = len(contents)
+ curval = 0
+ if onProgress:
+ onProgress(maxval, 0)
+ paths = list(contents)
+ paths.sort()
+ for path in paths:
+ curval += 1
+ try:
+ lst = os.lstat(path)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ if onProgress:
+ onProgress(maxval, curval)
+ continue
+ contents_type = contents[path][0]
+ if path.startswith(root):
+ arcname = path[len(root):]
+ else:
+ raise ValueError("invalid root argument: '%s'" % root)
+ live_path = path
+ if 'dir' == contents_type and \
+ not stat.S_ISDIR(lst.st_mode) and \
+ os.path.isdir(live_path):
+ # Even though this was a directory in the original ${D}, it exists
+ # as a symlink to a directory in the live filesystem. It must be
+ # recorded as a real directory in the tar file to ensure that tar
+ # can properly extract it's children.
+ live_path = os.path.realpath(live_path)
+ tarinfo = tar.gettarinfo(live_path, arcname)
+
+ if stat.S_ISREG(lst.st_mode):
+ if protect and protect(path):
+ # Create an empty file as a place holder in order to avoid
+ # potential collision-protect issues.
+ f = tempfile.TemporaryFile()
+ f.write(_unicode_encode(
+ "# empty file because --include-config=n " + \
+ "when `quickpkg` was used\n"))
+ f.flush()
+ f.seek(0)
+ tarinfo.size = os.fstat(f.fileno()).st_size
+ tar.addfile(tarinfo, f)
+ f.close()
+ else:
+ f = open(_unicode_encode(path,
+ encoding=object.__getattribute__(os, '_encoding'),
+ errors='strict'), 'rb')
+ try:
+ tar.addfile(tarinfo, f)
+ finally:
+ f.close()
+ else:
+ tar.addfile(tarinfo)
+ if onProgress:
+ onProgress(maxval, curval)
diff --git a/portage_with_autodep/pym/portage/dbapi/virtual.py b/portage_with_autodep/pym/portage/dbapi/virtual.py
new file mode 100644
index 0000000..ec97ffe
--- /dev/null
+++ b/portage_with_autodep/pym/portage/dbapi/virtual.py
@@ -0,0 +1,131 @@
+# Copyright 1998-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+
+from portage.dbapi import dbapi
+from portage import cpv_getkey
+
+class fakedbapi(dbapi):
+ """A fake dbapi that allows consumers to inject/remove packages to/from it
+ portage.settings is required to maintain the dbAPI.
+ """
+ def __init__(self, settings=None, exclusive_slots=True):
+ """
+ @param exclusive_slots: When True, injecting a package with SLOT
+ metadata causes an existing package in the same slot to be
+ automatically removed (default is True).
+ @type exclusive_slots: Boolean
+ """
+ self._exclusive_slots = exclusive_slots
+ self.cpvdict = {}
+ self.cpdict = {}
+ if settings is None:
+ from portage import settings
+ self.settings = settings
+ self._match_cache = {}
+
+ def _clear_cache(self):
+ if self._categories is not None:
+ self._categories = None
+ if self._match_cache:
+ self._match_cache = {}
+
+ def match(self, origdep, use_cache=1):
+ result = self._match_cache.get(origdep, None)
+ if result is not None:
+ return result[:]
+ result = dbapi.match(self, origdep, use_cache=use_cache)
+ self._match_cache[origdep] = result
+ return result[:]
+
+ def cpv_exists(self, mycpv, myrepo=None):
+ return mycpv in self.cpvdict
+
+ def cp_list(self, mycp, use_cache=1, myrepo=None):
+ cachelist = self._match_cache.get(mycp)
+ # cp_list() doesn't expand old-style virtuals
+ if cachelist and cachelist[0].startswith(mycp):
+ return cachelist[:]
+ cpv_list = self.cpdict.get(mycp)
+ if cpv_list is None:
+ cpv_list = []
+ self._cpv_sort_ascending(cpv_list)
+ if not (not cpv_list and mycp.startswith("virtual/")):
+ self._match_cache[mycp] = cpv_list
+ return cpv_list[:]
+
+ def cp_all(self):
+ return list(self.cpdict)
+
+ def cpv_all(self):
+ return list(self.cpvdict)
+
+ def cpv_inject(self, mycpv, metadata=None):
+ """Adds a cpv to the list of available packages. See the
+ exclusive_slots constructor parameter for behavior with
+ respect to SLOT metadata.
+ @param mycpv: cpv for the package to inject
+ @type mycpv: str
+ @param metadata: dictionary of raw metadata for aux_get() calls
+ @param metadata: dict
+ """
+ self._clear_cache()
+ mycp = cpv_getkey(mycpv)
+ self.cpvdict[mycpv] = metadata
+ myslot = None
+ if self._exclusive_slots and metadata:
+ myslot = metadata.get("SLOT", None)
+ if myslot and mycp in self.cpdict:
+ # If necessary, remove another package in the same SLOT.
+ for cpv in self.cpdict[mycp]:
+ if mycpv != cpv:
+ other_metadata = self.cpvdict[cpv]
+ if other_metadata:
+ if myslot == other_metadata.get("SLOT", None):
+ self.cpv_remove(cpv)
+ break
+ if mycp not in self.cpdict:
+ self.cpdict[mycp] = []
+ if not mycpv in self.cpdict[mycp]:
+ self.cpdict[mycp].append(mycpv)
+
+ def cpv_remove(self,mycpv):
+ """Removes a cpv from the list of available packages."""
+ self._clear_cache()
+ mycp = cpv_getkey(mycpv)
+ if mycpv in self.cpvdict:
+ del self.cpvdict[mycpv]
+ if mycp not in self.cpdict:
+ return
+ while mycpv in self.cpdict[mycp]:
+ del self.cpdict[mycp][self.cpdict[mycp].index(mycpv)]
+ if not len(self.cpdict[mycp]):
+ del self.cpdict[mycp]
+
+ def aux_get(self, mycpv, wants, myrepo=None):
+ if not self.cpv_exists(mycpv):
+ raise KeyError(mycpv)
+ metadata = self.cpvdict[mycpv]
+ if not metadata:
+ return ["" for x in wants]
+ return [metadata.get(x, "") for x in wants]
+
+ def aux_update(self, cpv, values):
+ self._clear_cache()
+ self.cpvdict[cpv].update(values)
+
+class testdbapi(object):
+ """A dbapi instance with completely fake functions to get by hitting disk
+ TODO(antarus):
+ This class really needs to be rewritten to have better stubs; but these work for now.
+ The dbapi classes themselves need unit tests...and that will be a lot of work.
+ """
+
+ def __init__(self):
+ self.cpvs = {}
+ def f(*args, **kwargs):
+ return True
+ fake_api = dir(dbapi)
+ for call in fake_api:
+ if not hasattr(self, call):
+ setattr(self, call, f)
diff --git a/portage_with_autodep/pym/portage/debug.py b/portage_with_autodep/pym/portage/debug.py
new file mode 100644
index 0000000..ce642fe
--- /dev/null
+++ b/portage_with_autodep/pym/portage/debug.py
@@ -0,0 +1,120 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import os
+import sys
+
+try:
+ import threading
+except ImportError:
+ import dummy_threading as threading
+
+import portage.const
+from portage.util import writemsg
+
+def set_trace(on=True):
+ if on:
+ t = trace_handler()
+ threading.settrace(t.event_handler)
+ sys.settrace(t.event_handler)
+ else:
+ sys.settrace(None)
+ threading.settrace(None)
+
+class trace_handler(object):
+
+ def __init__(self):
+ python_system_paths = []
+ for x in sys.path:
+ if os.path.basename(x).startswith("python2."):
+ python_system_paths.append(x)
+
+ self.ignore_prefixes = []
+ for x in python_system_paths:
+ self.ignore_prefixes.append(x + os.sep)
+
+ self.trim_filename = prefix_trimmer(os.path.join(portage.const.PORTAGE_BASE_PATH, "pym") + os.sep).trim
+ self.show_local_lines = False
+ self.max_repr_length = 200
+
+ def event_handler(self, *args):
+ frame, event, arg = args
+ if "line" == event:
+ if self.show_local_lines:
+ self.trace_line(*args)
+ else:
+ if not self.ignore_filename(frame.f_code.co_filename):
+ self.trace_event(*args)
+ return self.event_handler
+
+ def trace_event(self, frame, event, arg):
+ writemsg("%s line=%d name=%s event=%s %slocals=%s\n" % \
+ (self.trim_filename(frame.f_code.co_filename),
+ frame.f_lineno,
+ frame.f_code.co_name,
+ event,
+ self.arg_repr(frame, event, arg),
+ self.locals_repr(frame, event, arg)))
+
+ def arg_repr(self, frame, event, arg):
+ my_repr = None
+ if "return" == event:
+ my_repr = repr(arg)
+ if len(my_repr) > self.max_repr_length:
+ my_repr = "'omitted'"
+ return "value=%s " % my_repr
+ elif "exception" == event:
+ my_repr = repr(arg[1])
+ if len(my_repr) > self.max_repr_length:
+ my_repr = "'omitted'"
+ return "type=%s value=%s " % (arg[0], my_repr)
+
+ return ""
+
+ def trace_line(self, frame, event, arg):
+ writemsg("%s line=%d\n" % (self.trim_filename(frame.f_code.co_filename), frame.f_lineno))
+
+ def ignore_filename(self, filename):
+ if filename:
+ for x in self.ignore_prefixes:
+ if filename.startswith(x):
+ return True
+ return False
+
+ def locals_repr(self, frame, event, arg):
+ """Create a representation of the locals dict that is suitable for
+ tracing output."""
+
+ my_locals = frame.f_locals.copy()
+
+ # prevent unsafe __repr__ call on self when __init__ is called
+ # (method calls aren't safe until after __init__ has completed).
+ if frame.f_code.co_name == "__init__" and "self" in my_locals:
+ my_locals["self"] = "omitted"
+
+ # We omit items that will lead to unreasonable bloat of the trace
+ # output (and resulting log file).
+ for k, v in my_locals.items():
+ my_repr = repr(v)
+ if len(my_repr) > self.max_repr_length:
+ my_locals[k] = "omitted"
+ return my_locals
+
+class prefix_trimmer(object):
+ def __init__(self, prefix):
+ self.prefix = prefix
+ self.cut_index = len(prefix)
+ self.previous = None
+ self.previous_trimmed = None
+
+ def trim(self, s):
+ """Remove a prefix from the string and return the result.
+ The previous result is automatically cached."""
+ if s == self.previous:
+ return self.previous_trimmed
+ else:
+ if s.startswith(self.prefix):
+ self.previous_trimmed = s[self.cut_index:]
+ else:
+ self.previous_trimmed = s
+ return self.previous_trimmed
diff --git a/portage_with_autodep/pym/portage/dep/__init__.py b/portage_with_autodep/pym/portage/dep/__init__.py
new file mode 100644
index 0000000..fd5ad30
--- /dev/null
+++ b/portage_with_autodep/pym/portage/dep/__init__.py
@@ -0,0 +1,2432 @@
+# deps.py -- Portage dependency resolution functions
+# Copyright 2003-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = [
+ 'Atom', 'best_match_to_list', 'cpvequal',
+ 'dep_getcpv', 'dep_getkey', 'dep_getslot',
+ 'dep_getusedeps', 'dep_opconvert', 'flatten',
+ 'get_operator', 'isjustname', 'isspecific',
+ 'isvalidatom', 'match_from_list', 'match_to_list',
+ 'paren_enclose', 'paren_normalize', 'paren_reduce',
+ 'remove_slot', 'strip_empty', 'use_reduce',
+ '_repo_separator', '_slot_separator',
+]
+
+# DEPEND SYNTAX:
+#
+# 'use?' only affects the immediately following word!
+# Nesting is the only legal way to form multiple '[!]use?' requirements.
+#
+# Where: 'a' and 'b' are use flags, and 'z' is a depend atom.
+#
+# "a? z" -- If 'a' in [use], then b is valid.
+# "a? ( z )" -- Syntax with parenthesis.
+# "a? b? z" -- Deprecated.
+# "a? ( b? z )" -- Valid
+# "a? ( b? ( z ) ) -- Valid
+#
+
+import re, sys
+import warnings
+from itertools import chain
+from portage import _unicode_decode
+from portage.eapi import eapi_has_slot_deps, eapi_has_src_uri_arrows, \
+ eapi_has_use_deps, eapi_has_strong_blocks, eapi_has_use_dep_defaults
+from portage.exception import InvalidAtom, InvalidData, InvalidDependString
+from portage.localization import _
+from portage.versions import catpkgsplit, catsplit, \
+ pkgcmp, ververify, _cp, _cpv
+import portage.cache.mappings
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+# Api consumers included in portage should set this to True.
+# Once the relevant api changes are in a portage release with
+# stable keywords, make these warnings unconditional.
+_internal_warnings = False
+
+def cpvequal(cpv1, cpv2):
+ """
+
+ @param cpv1: CategoryPackageVersion (no operators) Example: "sys-apps/portage-2.1"
+ @type cpv1: String
+ @param cpv2: CategoryPackageVersion (no operators) Example: "sys-apps/portage-2.1"
+ @type cpv2: String
+ @rtype: Boolean
+ @returns:
+ 1. True if cpv1 = cpv2
+ 2. False Otherwise
+ 3. Throws PortageException if cpv1 or cpv2 is not a CPV
+
+ Example Usage:
+ >>> from portage.dep import cpvequal
+ >>> cpvequal("sys-apps/portage-2.1","sys-apps/portage-2.1")
+ >>> True
+
+ """
+
+ split1 = catpkgsplit(cpv1)
+ split2 = catpkgsplit(cpv2)
+
+ if not split1 or not split2:
+ raise portage.exception.PortageException(_("Invalid data '%s, %s', parameter was not a CPV") % (cpv1, cpv2))
+
+ if split1[0] != split2[0]:
+ return False
+
+ return (pkgcmp(split1[1:], split2[1:]) == 0)
+
+def strip_empty(myarr):
+ """
+ Strip all empty elements from an array
+
+ @param myarr: The list of elements
+ @type myarr: List
+ @rtype: Array
+ @return: The array with empty elements removed
+ """
+ warnings.warn(_("%s is deprecated and will be removed without replacement.") % \
+ ('portage.dep.strip_empty',), DeprecationWarning, stacklevel=2)
+ return [x for x in myarr if x]
+
+def paren_reduce(mystr):
+ """
+ Take a string and convert all paren enclosed entities into sublists and
+ split the list elements by spaces. All redundant brackets are removed.
+
+ Example usage:
+ >>> paren_reduce('foobar foo? ( bar baz )')
+ ['foobar', 'foo?', ['bar', 'baz']]
+
+ @param mystr: The string to reduce
+ @type mystr: String
+ @rtype: Array
+ @return: The reduced string in an array
+ """
+ if _internal_warnings:
+ warnings.warn(_("%s is deprecated and will be removed without replacement.") % \
+ ('portage.dep.paren_reduce',), DeprecationWarning, stacklevel=2)
+ mysplit = mystr.split()
+ level = 0
+ stack = [[]]
+ need_bracket = False
+
+ for token in mysplit:
+ if token == "(":
+ need_bracket = False
+ stack.append([])
+ level += 1
+ elif token == ")":
+ if need_bracket:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % mystr)
+ if level > 0:
+ level -= 1
+ l = stack.pop()
+ is_single = (len(l) == 1 or (len(l)==2 and (l[0] == "||" or l[0][-1] == "?")))
+
+ def ends_in_any_of_dep(k):
+ return k>=0 and stack[k] and stack[k][-1] == "||"
+
+ def ends_in_operator(k):
+ return k>=0 and stack[k] and (stack[k][-1] == "||" or stack[k][-1][-1] == "?")
+
+ def special_append():
+ """
+ Use extend instead of append if possible. This kills all redundant brackets.
+ """
+ if is_single and (not stack[level] or not stack[level][-1][-1] == "?"):
+ if len(l) == 1 and isinstance(l[0], list):
+ # l = [[...]]
+ stack[level].extend(l[0])
+ else:
+ stack[level].extend(l)
+ else:
+ stack[level].append(l)
+
+ if l:
+ if not ends_in_any_of_dep(level-1) and not ends_in_operator(level):
+ #Optimize: ( ( ... ) ) -> ( ... ). Make sure there is no '||' hanging around.
+ stack[level].extend(l)
+ elif not stack[level]:
+ #An '||' in the level above forces us to keep to brackets.
+ special_append()
+ elif len(l) == 1 and ends_in_any_of_dep(level):
+ #Optimize: || ( A ) -> A
+ stack[level].pop()
+ special_append()
+ elif len(l) == 2 and (l[0] == "||" or l[0][-1] == "?") and stack[level][-1] in (l[0], "||"):
+ #Optimize: || ( || ( ... ) ) -> || ( ... )
+ # foo? ( foo? ( ... ) ) -> foo? ( ... )
+ # || ( foo? ( ... ) ) -> foo? ( ... )
+ stack[level].pop()
+ special_append()
+ else:
+ special_append()
+ else:
+ if stack[level] and (stack[level][-1] == "||" or stack[level][-1][-1] == "?"):
+ stack[level].pop()
+ else:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % mystr)
+ elif token == "||":
+ if need_bracket:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % mystr)
+ need_bracket = True
+ stack[level].append(token)
+ else:
+ if need_bracket:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % mystr)
+
+ if token[-1] == "?":
+ need_bracket = True
+
+ stack[level].append(token)
+
+ if level != 0 or need_bracket:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % mystr)
+
+ return stack[0]
+
+class paren_normalize(list):
+ """Take a dependency structure as returned by paren_reduce or use_reduce
+ and generate an equivalent structure that has no redundant lists."""
+ def __init__(self, src):
+ if _internal_warnings:
+ warnings.warn(_("%s is deprecated and will be removed without replacement.") % \
+ ('portage.dep.paren_normalize',), DeprecationWarning, stacklevel=2)
+ list.__init__(self)
+ self._zap_parens(src, self)
+
+ def _zap_parens(self, src, dest, disjunction=False):
+ if not src:
+ return dest
+ i = iter(src)
+ for x in i:
+ if isinstance(x, basestring):
+ if x in ('||', '^^'):
+ y = self._zap_parens(next(i), [], disjunction=True)
+ if len(y) == 1:
+ dest.append(y[0])
+ else:
+ dest.append(x)
+ dest.append(y)
+ elif x.endswith("?"):
+ dest.append(x)
+ dest.append(self._zap_parens(next(i), []))
+ else:
+ dest.append(x)
+ else:
+ if disjunction:
+ x = self._zap_parens(x, [])
+ if len(x) == 1:
+ dest.append(x[0])
+ else:
+ dest.append(x)
+ else:
+ self._zap_parens(x, dest)
+ return dest
+
+def paren_enclose(mylist, unevaluated_atom=False):
+ """
+ Convert a list to a string with sublists enclosed with parens.
+
+ Example usage:
+ >>> test = ['foobar','foo',['bar','baz']]
+ >>> paren_enclose(test)
+ 'foobar foo ( bar baz )'
+
+ @param mylist: The list
+ @type mylist: List
+ @rtype: String
+ @return: The paren enclosed string
+ """
+ mystrparts = []
+ for x in mylist:
+ if isinstance(x, list):
+ mystrparts.append("( "+paren_enclose(x)+" )")
+ else:
+ if unevaluated_atom:
+ x = getattr(x, 'unevaluated_atom', x)
+ mystrparts.append(x)
+ return " ".join(mystrparts)
+
+def use_reduce(depstr, uselist=[], masklist=[], matchall=False, excludeall=[], is_src_uri=False, \
+ eapi=None, opconvert=False, flat=False, is_valid_flag=None, token_class=None, matchnone=False):
+ """
+ Takes a dep string and reduces the use? conditionals out, leaving an array
+ with subarrays. All redundant brackets are removed.
+
+ @param deparray: depstring
+ @type deparray: String
+ @param uselist: List of use enabled flags
+ @type uselist: List
+ @param masklist: List of masked flags (always treated as disabled)
+ @type masklist: List
+ @param matchall: Treat all conditionals as active. Used by repoman.
+ @type matchall: Bool
+ @param excludeall: List of flags for which negated conditionals are always treated as inactive.
+ @type excludeall: List
+ @param is_src_uri: Indicates if depstr represents a SRC_URI
+ @type is_src_uri: Bool
+ @param eapi: Indicates the EAPI the dep string has to comply to
+ @type eapi: String
+ @param opconvert: Put every operator as first element into it's argument list
+ @type opconvert: Bool
+ @param flat: Create a flat list of all tokens
+ @type flat: Bool
+ @param is_valid_flag: Function that decides if a given use flag might be used in use conditionals
+ @type is_valid_flag: Function
+ @param token_class: Convert all non operator tokens into this class
+ @type token_class: Class
+ @param matchnone: Treat all conditionals as inactive. Used by digestgen().
+ @type matchnone: Bool
+ @rtype: List
+ @return: The use reduced depend array
+ """
+ if isinstance(depstr, list):
+ if _internal_warnings:
+ warnings.warn(_("Passing paren_reduced dep arrays to %s is deprecated. " + \
+ "Pass the original dep string instead.") % \
+ ('portage.dep.use_reduce',), DeprecationWarning, stacklevel=2)
+ depstr = paren_enclose(depstr)
+
+ if opconvert and flat:
+ raise ValueError("portage.dep.use_reduce: 'opconvert' and 'flat' are mutually exclusive")
+
+ if matchall and matchnone:
+ raise ValueError("portage.dep.use_reduce: 'matchall' and 'matchnone' are mutually exclusive")
+
+ useflag_re = _get_useflag_re(eapi)
+
+ def is_active(conditional):
+ """
+ Decides if a given use conditional is active.
+ """
+ if conditional.startswith("!"):
+ flag = conditional[1:-1]
+ is_negated = True
+ else:
+ flag = conditional[:-1]
+ is_negated = False
+
+ if is_valid_flag:
+ if not is_valid_flag(flag):
+ msg = _("USE flag '%s' referenced in " + \
+ "conditional '%s' is not in IUSE") \
+ % (flag, conditional)
+ e = InvalidData(msg, category='IUSE.missing')
+ raise InvalidDependString(msg, errors=(e,))
+ else:
+ if useflag_re.match(flag) is None:
+ raise InvalidDependString(
+ _("invalid use flag '%s' in conditional '%s'") % (flag, conditional))
+
+ if is_negated and flag in excludeall:
+ return False
+
+ if flag in masklist:
+ return is_negated
+
+ if matchall:
+ return True
+
+ if matchnone:
+ return False
+
+ return (flag in uselist and not is_negated) or \
+ (flag not in uselist and is_negated)
+
+ def missing_white_space_check(token, pos):
+ """
+ Used to generate good error messages for invalid tokens.
+ """
+ for x in (")", "(", "||"):
+ if token.startswith(x) or token.endswith(x):
+ raise InvalidDependString(
+ _("missing whitespace around '%s' at '%s', token %s") % (x, token, pos+1))
+
+ mysplit = depstr.split()
+ #Count the bracket level.
+ level = 0
+ #We parse into a stack. Every time we hit a '(', a new empty list is appended to the stack.
+ #When we hit a ')', the last list in the stack is merged with list one level up.
+ stack = [[]]
+ #Set need_bracket to True after use conditionals or ||. Other tokens need to ensure
+ #that need_bracket is not True.
+ need_bracket = False
+ #Set need_simple_token to True after a SRC_URI arrow. Other tokens need to ensure
+ #that need_simple_token is not True.
+ need_simple_token = False
+
+ for pos, token in enumerate(mysplit):
+ if token == "(":
+ if need_simple_token:
+ raise InvalidDependString(
+ _("expected: file name, got: '%s', token %s") % (token, pos+1))
+ if len(mysplit) >= pos+2 and mysplit[pos+1] == ")":
+ raise InvalidDependString(
+ _("expected: dependency string, got: ')', token %s") % (pos+1,))
+ need_bracket = False
+ stack.append([])
+ level += 1
+ elif token == ")":
+ if need_bracket:
+ raise InvalidDependString(
+ _("expected: '(', got: '%s', token %s") % (token, pos+1))
+ if need_simple_token:
+ raise InvalidDependString(
+ _("expected: file name, got: '%s', token %s") % (token, pos+1))
+ if level > 0:
+ level -= 1
+ l = stack.pop()
+
+ is_single = len(l) == 1 or \
+ (opconvert and l and l[0] == "||") or \
+ (not opconvert and len(l)==2 and l[0] == "||")
+ ignore = False
+
+ if flat:
+ #In 'flat' mode, we simply merge all lists into a single large one.
+ if stack[level] and stack[level][-1][-1] == "?":
+ #The last token before the '(' that matches the current ')'
+ #was a use conditional. The conditional is removed in any case.
+ #Merge the current list if needed.
+ if is_active(stack[level][-1]):
+ stack[level].pop()
+ stack[level].extend(l)
+ else:
+ stack[level].pop()
+ else:
+ stack[level].extend(l)
+ continue
+
+ if stack[level]:
+ if stack[level][-1] == "||" and not l:
+ #Optimize: || ( ) -> .
+ stack[level].pop()
+ elif stack[level][-1][-1] == "?":
+ #The last token before the '(' that matches the current ')'
+ #was a use conditional, remove it and decide if we
+ #have to keep the current list.
+ if not is_active(stack[level][-1]):
+ ignore = True
+ stack[level].pop()
+
+ def ends_in_any_of_dep(k):
+ return k>=0 and stack[k] and stack[k][-1] == "||"
+
+ def starts_with_any_of_dep(k):
+ #'ends_in_any_of_dep' for opconvert
+ return k>=0 and stack[k] and stack[k][0] == "||"
+
+ def last_any_of_operator_level(k):
+ #Returns the level of the last || operator if it is in effect for
+ #the current level. It is not in effect, if there is a level, that
+ #ends in a non-operator. This is almost equivalent to stack[level][-1]=="||",
+ #expect that it skips empty levels.
+ while k>=0:
+ if stack[k]:
+ if stack[k][-1] == "||":
+ return k
+ elif stack[k][-1][-1] != "?":
+ return -1
+ k -= 1
+ return -1
+
+ def special_append():
+ """
+ Use extend instead of append if possible. This kills all redundant brackets.
+ """
+ if is_single:
+ #Either [A], [[...]] or [|| [...]]
+ if l[0] == "||" and ends_in_any_of_dep(level-1):
+ if opconvert:
+ stack[level].extend(l[1:])
+ else:
+ stack[level].extend(l[1])
+ elif len(l) == 1 and isinstance(l[0], list):
+ # l = [[...]]
+ last = last_any_of_operator_level(level-1)
+ if last == -1:
+ if opconvert and isinstance(l[0], list) \
+ and l[0] and l[0][0] == '||':
+ stack[level].append(l[0])
+ else:
+ stack[level].extend(l[0])
+ else:
+ if opconvert and l[0] and l[0][0] == "||":
+ stack[level].extend(l[0][1:])
+ else:
+ stack[level].append(l[0])
+ else:
+ stack[level].extend(l)
+ else:
+ if opconvert and stack[level] and stack[level][-1] == '||':
+ stack[level][-1] = ['||'] + l
+ else:
+ stack[level].append(l)
+
+ if l and not ignore:
+ #The current list is not empty and we don't want to ignore it because
+ #of an inactive use conditional.
+ if not ends_in_any_of_dep(level-1) and not ends_in_any_of_dep(level):
+ #Optimize: ( ( ... ) ) -> ( ... ). Make sure there is no '||' hanging around.
+ stack[level].extend(l)
+ elif not stack[level]:
+ #An '||' in the level above forces us to keep to brackets.
+ special_append()
+ elif is_single and ends_in_any_of_dep(level):
+ #Optimize: || ( A ) -> A, || ( || ( ... ) ) -> || ( ... )
+ stack[level].pop()
+ special_append()
+ elif ends_in_any_of_dep(level) and ends_in_any_of_dep(level-1):
+ #Optimize: || ( A || ( B C ) ) -> || ( A B C )
+ stack[level].pop()
+ stack[level].extend(l)
+ else:
+ if opconvert and ends_in_any_of_dep(level):
+ #In opconvert mode, we have to move the operator from the level
+ #above into the current list.
+ stack[level].pop()
+ stack[level].append(["||"] + l)
+ else:
+ special_append()
+
+ else:
+ raise InvalidDependString(
+ _("no matching '%s' for '%s', token %s") % ("(", ")", pos+1))
+ elif token == "||":
+ if is_src_uri:
+ raise InvalidDependString(
+ _("any-of dependencies are not allowed in SRC_URI: token %s") % (pos+1,))
+ if need_bracket:
+ raise InvalidDependString(
+ _("expected: '(', got: '%s', token %s") % (token, pos+1))
+ need_bracket = True
+ stack[level].append(token)
+ elif token == "->":
+ if need_simple_token:
+ raise InvalidDependString(
+ _("expected: file name, got: '%s', token %s") % (token, pos+1))
+ if not is_src_uri:
+ raise InvalidDependString(
+ _("SRC_URI arrow are only allowed in SRC_URI: token %s") % (pos+1,))
+ if eapi is None or not eapi_has_src_uri_arrows(eapi):
+ raise InvalidDependString(
+ _("SRC_URI arrow not allowed in EAPI %s: token %s") % (eapi, pos+1))
+ need_simple_token = True
+ stack[level].append(token)
+ else:
+ missing_white_space_check(token, pos)
+
+ if need_bracket:
+ raise InvalidDependString(
+ _("expected: '(', got: '%s', token %s") % (token, pos+1))
+
+ if need_simple_token and "/" in token:
+ #The last token was a SRC_URI arrow, make sure we have a simple file name.
+ raise InvalidDependString(
+ _("expected: file name, got: '%s', token %s") % (token, pos+1))
+
+ if token[-1] == "?":
+ need_bracket = True
+ else:
+ need_simple_token = False
+ if token_class and not is_src_uri:
+ #Add a hack for SRC_URI here, to avoid conditional code at the consumer level
+ try:
+ token = token_class(token, eapi=eapi,
+ is_valid_flag=is_valid_flag)
+ except InvalidAtom as e:
+ raise InvalidDependString(
+ _("Invalid atom (%s), token %s") \
+ % (e, pos+1), errors=(e,))
+ except SystemExit:
+ raise
+ except Exception as e:
+ raise InvalidDependString(
+ _("Invalid token '%s', token %s") % (token, pos+1))
+
+ if not matchall and \
+ hasattr(token, 'evaluate_conditionals'):
+ token = token.evaluate_conditionals(uselist)
+
+ stack[level].append(token)
+
+ if level != 0:
+ raise InvalidDependString(
+ _("Missing '%s' at end of string") % (")",))
+
+ if need_bracket:
+ raise InvalidDependString(
+ _("Missing '%s' at end of string") % ("(",))
+
+ if need_simple_token:
+ raise InvalidDependString(
+ _("Missing file name at end of string"))
+
+ return stack[0]
+
+def dep_opconvert(deplist):
+ """
+ Iterate recursively through a list of deps, if the
+ dep is a '||' or '&&' operator, combine it with the
+ list of deps that follows..
+
+ Example usage:
+ >>> test = ["blah", "||", ["foo", "bar", "baz"]]
+ >>> dep_opconvert(test)
+ ['blah', ['||', 'foo', 'bar', 'baz']]
+
+ @param deplist: A list of deps to format
+ @type mydep: List
+ @rtype: List
+ @return:
+ The new list with the new ordering
+ """
+ if _internal_warnings:
+ warnings.warn(_("%s is deprecated. Use %s with the opconvert parameter set to True instead.") % \
+ ('portage.dep.dep_opconvert', 'portage.dep.use_reduce'), DeprecationWarning, stacklevel=2)
+
+ retlist = []
+ x = 0
+ while x != len(deplist):
+ if isinstance(deplist[x], list):
+ retlist.append(dep_opconvert(deplist[x]))
+ elif deplist[x] == "||":
+ retlist.append([deplist[x]] + dep_opconvert(deplist[x+1]))
+ x += 1
+ else:
+ retlist.append(deplist[x])
+ x += 1
+ return retlist
+
+def flatten(mylist):
+ """
+ Recursively traverse nested lists and return a single list containing
+ all non-list elements that are found.
+
+ Example usage:
+ >>> flatten([1, [2, 3, [4]]])
+ [1, 2, 3, 4]
+
+ @param mylist: A list containing nested lists and non-list elements.
+ @type mylist: List
+ @rtype: List
+ @return: A single list containing only non-list elements.
+ """
+ if _internal_warnings:
+ warnings.warn(_("%s is deprecated and will be removed without replacement.") % \
+ ('portage.dep.flatten',), DeprecationWarning, stacklevel=2)
+
+ newlist = []
+ for x in mylist:
+ if isinstance(x, list):
+ newlist.extend(flatten(x))
+ else:
+ newlist.append(x)
+ return newlist
+
+
+_usedep_re = {
+ "0": re.compile("^(?P<prefix>[!-]?)(?P<flag>[A-Za-z0-9][A-Za-z0-9+_@-]*)(?P<default>(\(\+\)|\(\-\))?)(?P<suffix>[?=]?)$"),
+ "4-python": re.compile("^(?P<prefix>[!-]?)(?P<flag>[A-Za-z0-9][A-Za-z0-9+_@.-]*)(?P<default>(\(\+\)|\(\-\))?)(?P<suffix>[?=]?)$"),
+}
+
+def _get_usedep_re(eapi):
+ """
+ When eapi is None then validation is not as strict, since we want the
+ same to work for multiple EAPIs that may have slightly different rules.
+ @param eapi: The EAPI
+ @type eapi: String or None
+ @rtype: regular expression object
+ @return: A regular expression object that matches valid USE deps for the
+ given eapi.
+ """
+ if eapi in (None, "4-python",):
+ return _usedep_re["4-python"]
+ else:
+ return _usedep_re["0"]
+
+class _use_dep(object):
+
+ __slots__ = ("__weakref__", "eapi", "conditional", "missing_enabled", "missing_disabled",
+ "disabled", "enabled", "tokens", "required")
+
+ class _conditionals_class(object):
+ __slots__ = ("enabled", "disabled", "equal", "not_equal")
+
+ def items(self):
+ for k in self.__slots__:
+ v = getattr(self, k, None)
+ if v:
+ yield (k, v)
+
+ def values(self):
+ for k in self.__slots__:
+ v = getattr(self, k, None)
+ if v:
+ yield v
+
+ # used in InvalidAtom messages
+ _conditional_strings = {
+ 'enabled' : '%s?',
+ 'disabled': '!%s?',
+ 'equal': '%s=',
+ 'not_equal': '!%s=',
+ }
+
+ def __init__(self, use, eapi, enabled_flags=None, disabled_flags=None, missing_enabled=None, \
+ missing_disabled=None, conditional=None, required=None):
+
+ self.eapi = eapi
+
+ if enabled_flags is not None:
+ #A shortcut for the classe's own methods.
+ self.tokens = use
+ if not isinstance(self.tokens, tuple):
+ self.tokens = tuple(self.tokens)
+
+ self.required = frozenset(required)
+ self.enabled = frozenset(enabled_flags)
+ self.disabled = frozenset(disabled_flags)
+ self.missing_enabled = frozenset(missing_enabled)
+ self.missing_disabled = frozenset(missing_disabled)
+ self.conditional = None
+
+ if conditional:
+ self.conditional = self._conditionals_class()
+ for k in "enabled", "disabled", "equal", "not_equal":
+ setattr(self.conditional, k, frozenset(conditional.get(k, [])))
+
+ return
+
+ enabled_flags = set()
+ disabled_flags = set()
+ missing_enabled = set()
+ missing_disabled = set()
+ no_default = set()
+
+ conditional = {}
+ usedep_re = _get_usedep_re(self.eapi)
+
+ for x in use:
+ m = usedep_re.match(x)
+ if m is None:
+ raise InvalidAtom(_("Invalid use dep: '%s'") % (x,))
+
+ operator = m.group("prefix") + m.group("suffix")
+ flag = m.group("flag")
+ default = m.group("default")
+
+ if not operator:
+ enabled_flags.add(flag)
+ elif operator == "-":
+ disabled_flags.add(flag)
+ elif operator == "?":
+ conditional.setdefault("enabled", set()).add(flag)
+ elif operator == "=":
+ conditional.setdefault("equal", set()).add(flag)
+ elif operator == "!=":
+ conditional.setdefault("not_equal", set()).add(flag)
+ elif operator == "!?":
+ conditional.setdefault("disabled", set()).add(flag)
+ else:
+ raise InvalidAtom(_("Invalid use dep: '%s'") % (x,))
+
+ if default:
+ if default == "(+)":
+ if flag in missing_disabled or flag in no_default:
+ raise InvalidAtom(_("Invalid use dep: '%s'") % (x,))
+ missing_enabled.add(flag)
+ else:
+ if flag in missing_enabled or flag in no_default:
+ raise InvalidAtom(_("Invalid use dep: '%s'") % (x,))
+ missing_disabled.add(flag)
+ else:
+ if flag in missing_enabled or flag in missing_disabled:
+ raise InvalidAtom(_("Invalid use dep: '%s'") % (x,))
+ no_default.add(flag)
+
+ self.tokens = use
+ if not isinstance(self.tokens, tuple):
+ self.tokens = tuple(self.tokens)
+
+ self.required = frozenset(no_default)
+
+ self.enabled = frozenset(enabled_flags)
+ self.disabled = frozenset(disabled_flags)
+ self.missing_enabled = frozenset(missing_enabled)
+ self.missing_disabled = frozenset(missing_disabled)
+ self.conditional = None
+
+ if conditional:
+ self.conditional = self._conditionals_class()
+ for k in "enabled", "disabled", "equal", "not_equal":
+ setattr(self.conditional, k, frozenset(conditional.get(k, [])))
+
+ def __bool__(self):
+ return bool(self.tokens)
+
+ if sys.hexversion < 0x3000000:
+ __nonzero__ = __bool__
+
+ def __str__(self):
+ if not self.tokens:
+ return ""
+ return "[%s]" % (",".join(self.tokens),)
+
+ def __repr__(self):
+ return "portage.dep._use_dep(%s)" % repr(self.tokens)
+
+ def evaluate_conditionals(self, use):
+ """
+ Create a new instance with conditionals evaluated.
+
+ Conditional evaluation behavior:
+
+ parent state conditional result
+
+ x x? x
+ -x x?
+ x !x?
+ -x !x? -x
+
+ x x= x
+ -x x= -x
+ x !x= -x
+ -x !x= x
+
+ Conditional syntax examples:
+
+ Compact Form Equivalent Expanded Form
+
+ foo[bar?] bar? ( foo[bar] ) !bar? ( foo )
+ foo[!bar?] bar? ( foo ) !bar? ( foo[-bar] )
+ foo[bar=] bar? ( foo[bar] ) !bar? ( foo[-bar] )
+ foo[!bar=] bar? ( foo[-bar] ) !bar? ( foo[bar] )
+
+ """
+ enabled_flags = set(self.enabled)
+ disabled_flags = set(self.disabled)
+
+ tokens = []
+ usedep_re = _get_usedep_re(self.eapi)
+
+ for x in self.tokens:
+ m = usedep_re.match(x)
+
+ operator = m.group("prefix") + m.group("suffix")
+ flag = m.group("flag")
+ default = m.group("default")
+ if default is None:
+ default = ""
+
+ if operator == "?":
+ if flag in use:
+ enabled_flags.add(flag)
+ tokens.append(flag+default)
+ elif operator == "=":
+ if flag in use:
+ enabled_flags.add(flag)
+ tokens.append(flag+default)
+ else:
+ disabled_flags.add(flag)
+ tokens.append("-"+flag+default)
+ elif operator == "!=":
+ if flag in use:
+ disabled_flags.add(flag)
+ tokens.append("-"+flag+default)
+ else:
+ enabled_flags.add(flag)
+ tokens.append(flag+default)
+ elif operator == "!?":
+ if flag not in use:
+ disabled_flags.add(flag)
+ tokens.append("-"+flag+default)
+ else:
+ tokens.append(x)
+
+ return _use_dep(tokens, self.eapi, enabled_flags=enabled_flags, disabled_flags=disabled_flags, \
+ missing_enabled=self.missing_enabled, missing_disabled=self.missing_disabled, required=self.required)
+
+ def violated_conditionals(self, other_use, is_valid_flag, parent_use=None):
+ """
+ Create a new instance with satisfied use deps removed.
+ """
+ if parent_use is None and self.conditional:
+ raise InvalidAtom("violated_conditionals needs 'parent_use'" + \
+ " parameter for conditional flags.")
+
+ enabled_flags = set()
+ disabled_flags = set()
+
+ conditional = {}
+ tokens = []
+
+ all_defaults = frozenset(chain(self.missing_enabled, self.missing_disabled))
+
+ def validate_flag(flag):
+ return is_valid_flag(flag) or flag in all_defaults
+
+ usedep_re = _get_usedep_re(self.eapi)
+
+ for x in self.tokens:
+ m = usedep_re.match(x)
+
+ operator = m.group("prefix") + m.group("suffix")
+ flag = m.group("flag")
+
+ if not validate_flag(flag):
+ tokens.append(x)
+ if not operator:
+ enabled_flags.add(flag)
+ elif operator == "-":
+ disabled_flags.add(flag)
+ elif operator == "?":
+ conditional.setdefault("enabled", set()).add(flag)
+ elif operator == "=":
+ conditional.setdefault("equal", set()).add(flag)
+ elif operator == "!=":
+ conditional.setdefault("not_equal", set()).add(flag)
+ elif operator == "!?":
+ conditional.setdefault("disabled", set()).add(flag)
+
+ continue
+
+ if not operator:
+ if flag not in other_use:
+ if is_valid_flag(flag) or flag in self.missing_disabled:
+ tokens.append(x)
+ enabled_flags.add(flag)
+ elif operator == "-":
+ if flag not in other_use:
+ if not is_valid_flag(flag):
+ if flag in self.missing_enabled:
+ tokens.append(x)
+ disabled_flags.add(flag)
+ else:
+ tokens.append(x)
+ disabled_flags.add(flag)
+ elif operator == "?":
+ if flag not in parent_use or flag in other_use:
+ continue
+
+ if is_valid_flag(flag) or flag in self.missing_disabled:
+ tokens.append(x)
+ conditional.setdefault("enabled", set()).add(flag)
+ elif operator == "=":
+ if flag in parent_use and flag not in other_use:
+ if is_valid_flag(flag):
+ tokens.append(x)
+ conditional.setdefault("equal", set()).add(flag)
+ else:
+ if flag in self.missing_disabled:
+ tokens.append(x)
+ conditional.setdefault("equal", set()).add(flag)
+ elif flag not in parent_use:
+ if flag not in other_use:
+ if not is_valid_flag(flag):
+ if flag in self.missing_enabled:
+ tokens.append(x)
+ conditional.setdefault("equal", set()).add(flag)
+ else:
+ tokens.append(x)
+ conditional.setdefault("equal", set()).add(flag)
+ elif operator == "!=":
+ if flag not in parent_use and flag not in other_use:
+ if is_valid_flag(flag):
+ tokens.append(x)
+ conditional.setdefault("not_equal", set()).add(flag)
+ else:
+ if flag in self.missing_disabled:
+ tokens.append(x)
+ conditional.setdefault("not_equal", set()).add(flag)
+ elif flag in parent_use:
+ if flag not in other_use:
+ if not is_valid_flag(flag):
+ if flag in self.missing_enabled:
+ tokens.append(x)
+ conditional.setdefault("not_equal", set()).add(flag)
+ else:
+ tokens.append(x)
+ conditional.setdefault("not_equal", set()).add(flag)
+ elif operator == "!?":
+ if flag not in parent_use:
+ if flag not in other_use:
+ if not is_valid_flag(flag) and flag in self.missing_enabled:
+ tokens.append(x)
+ conditional.setdefault("disabled", set()).add(flag)
+ else:
+ tokens.append(x)
+ conditional.setdefault("disabled", set()).add(flag)
+
+ return _use_dep(tokens, self.eapi, enabled_flags=enabled_flags, disabled_flags=disabled_flags, \
+ missing_enabled=self.missing_enabled, missing_disabled=self.missing_disabled, \
+ conditional=conditional, required=self.required)
+
+ def _eval_qa_conditionals(self, use_mask, use_force):
+ """
+ For repoman, evaluate all possible combinations within the constraints
+ of the given use.force and use.mask settings. The result may seem
+ ambiguous in the sense that the same flag can be in both the enabled
+ and disabled sets, but this is useful within the context of how its
+ intended to be used by repoman. It is assumed that the caller has
+ already ensured that there is no intersection between the given
+ use_mask and use_force sets when necessary.
+ """
+ enabled_flags = set(self.enabled)
+ disabled_flags = set(self.disabled)
+ missing_enabled = self.missing_enabled
+ missing_disabled = self.missing_disabled
+
+ tokens = []
+ usedep_re = _get_usedep_re(self.eapi)
+
+ for x in self.tokens:
+ m = usedep_re.match(x)
+
+ operator = m.group("prefix") + m.group("suffix")
+ flag = m.group("flag")
+ default = m.group("default")
+ if default is None:
+ default = ""
+
+ if operator == "?":
+ if flag not in use_mask:
+ enabled_flags.add(flag)
+ tokens.append(flag+default)
+ elif operator == "=":
+ if flag not in use_mask:
+ enabled_flags.add(flag)
+ tokens.append(flag+default)
+ if flag not in use_force:
+ disabled_flags.add(flag)
+ tokens.append("-"+flag+default)
+ elif operator == "!=":
+ if flag not in use_force:
+ enabled_flags.add(flag)
+ tokens.append(flag+default)
+ if flag not in use_mask:
+ disabled_flags.add(flag)
+ tokens.append("-"+flag+default)
+ elif operator == "!?":
+ if flag not in use_force:
+ disabled_flags.add(flag)
+ tokens.append("-"+flag+default)
+ else:
+ tokens.append(x)
+
+ return _use_dep(tokens, self.eapi, enabled_flags=enabled_flags, disabled_flags=disabled_flags, \
+ missing_enabled=missing_enabled, missing_disabled=missing_disabled, required=self.required)
+
+if sys.hexversion < 0x3000000:
+ _atom_base = unicode
+else:
+ _atom_base = str
+
+class Atom(_atom_base):
+
+ """
+ For compatibility with existing atom string manipulation code, this
+ class emulates most of the str methods that are useful with atoms.
+ """
+
+ class _blocker(object):
+ __slots__ = ("overlap",)
+
+ class _overlap(object):
+ __slots__ = ("forbid",)
+
+ def __init__(self, forbid=False):
+ self.forbid = forbid
+
+ def __init__(self, forbid_overlap=False):
+ self.overlap = self._overlap(forbid=forbid_overlap)
+
+ def __new__(cls, s, unevaluated_atom=None, allow_wildcard=False, allow_repo=False,
+ _use=None, eapi=None, is_valid_flag=None):
+ return _atom_base.__new__(cls, s)
+
+ def __init__(self, s, unevaluated_atom=None, allow_wildcard=False, allow_repo=False,
+ _use=None, eapi=None, is_valid_flag=None):
+ if isinstance(s, Atom):
+ # This is an efficiency assertion, to ensure that the Atom
+ # constructor is not called redundantly.
+ raise TypeError(_("Expected %s, got %s") % \
+ (_atom_base, type(s)))
+
+ if not isinstance(s, _atom_base):
+ # Avoid TypeError from _atom_base.__init__ with PyPy.
+ s = _unicode_decode(s)
+
+ _atom_base.__init__(s)
+
+ if "!" == s[:1]:
+ blocker = self._blocker(forbid_overlap=("!" == s[1:2]))
+ if blocker.overlap.forbid:
+ s = s[2:]
+ else:
+ s = s[1:]
+ else:
+ blocker = False
+ self.__dict__['blocker'] = blocker
+ m = _atom_re.match(s)
+ extended_syntax = False
+ if m is None:
+ if allow_wildcard:
+ m = _atom_wildcard_re.match(s)
+ if m is None:
+ raise InvalidAtom(self)
+ op = None
+ gdict = m.groupdict()
+ cpv = cp = gdict['simple']
+ if cpv.find("**") != -1:
+ raise InvalidAtom(self)
+ slot = gdict['slot']
+ repo = gdict['repo']
+ use_str = None
+ extended_syntax = True
+ else:
+ raise InvalidAtom(self)
+ elif m.group('op') is not None:
+ base = _atom_re.groupindex['op']
+ op = m.group(base + 1)
+ cpv = m.group(base + 2)
+ cp = m.group(base + 3)
+ slot = m.group(_atom_re.groups - 2)
+ repo = m.group(_atom_re.groups - 1)
+ use_str = m.group(_atom_re.groups)
+ if m.group(base + 4) is not None:
+ raise InvalidAtom(self)
+ elif m.group('star') is not None:
+ base = _atom_re.groupindex['star']
+ op = '=*'
+ cpv = m.group(base + 1)
+ cp = m.group(base + 2)
+ slot = m.group(_atom_re.groups - 2)
+ repo = m.group(_atom_re.groups - 1)
+ use_str = m.group(_atom_re.groups)
+ if m.group(base + 3) is not None:
+ raise InvalidAtom(self)
+ elif m.group('simple') is not None:
+ op = None
+ cpv = cp = m.group(_atom_re.groupindex['simple'] + 1)
+ slot = m.group(_atom_re.groups - 2)
+ repo = m.group(_atom_re.groups - 1)
+ use_str = m.group(_atom_re.groups)
+ if m.group(_atom_re.groupindex['simple'] + 2) is not None:
+ raise InvalidAtom(self)
+
+ else:
+ raise AssertionError(_("required group not found in atom: '%s'") % self)
+ self.__dict__['cp'] = cp
+ self.__dict__['cpv'] = cpv
+ self.__dict__['repo'] = repo
+ self.__dict__['slot'] = slot
+ self.__dict__['operator'] = op
+ self.__dict__['extended_syntax'] = extended_syntax
+
+ if not (repo is None or allow_repo):
+ raise InvalidAtom(self)
+
+ if use_str is not None:
+ if _use is not None:
+ use = _use
+ else:
+ use = _use_dep(use_str[1:-1].split(","), eapi)
+ without_use = Atom(m.group('without_use'), allow_repo=allow_repo)
+ else:
+ use = None
+ if unevaluated_atom is not None and \
+ unevaluated_atom.use is not None:
+ # unevaluated_atom.use is used for IUSE checks when matching
+ # packages, so it must not propagate to without_use
+ without_use = Atom(s, allow_wildcard=allow_wildcard,
+ allow_repo=allow_repo)
+ else:
+ without_use = self
+
+ self.__dict__['use'] = use
+ self.__dict__['without_use'] = without_use
+
+ if unevaluated_atom:
+ self.__dict__['unevaluated_atom'] = unevaluated_atom
+ else:
+ self.__dict__['unevaluated_atom'] = self
+
+ if eapi is not None:
+ if not isinstance(eapi, basestring):
+ raise TypeError('expected eapi argument of ' + \
+ '%s, got %s: %s' % (basestring, type(eapi), eapi,))
+ if self.slot and not eapi_has_slot_deps(eapi):
+ raise InvalidAtom(
+ _("Slot deps are not allowed in EAPI %s: '%s'") \
+ % (eapi, self), category='EAPI.incompatible')
+ if self.use:
+ if not eapi_has_use_deps(eapi):
+ raise InvalidAtom(
+ _("Use deps are not allowed in EAPI %s: '%s'") \
+ % (eapi, self), category='EAPI.incompatible')
+ elif not eapi_has_use_dep_defaults(eapi) and \
+ (self.use.missing_enabled or self.use.missing_disabled):
+ raise InvalidAtom(
+ _("Use dep defaults are not allowed in EAPI %s: '%s'") \
+ % (eapi, self), category='EAPI.incompatible')
+ if is_valid_flag is not None and self.use.conditional:
+ invalid_flag = None
+ try:
+ for conditional_type, flags in \
+ self.use.conditional.items():
+ for flag in flags:
+ if not is_valid_flag(flag):
+ invalid_flag = (conditional_type, flag)
+ raise StopIteration()
+ except StopIteration:
+ pass
+ if invalid_flag is not None:
+ conditional_type, flag = invalid_flag
+ conditional_str = _use_dep._conditional_strings[conditional_type]
+ msg = _("USE flag '%s' referenced in " + \
+ "conditional '%s' in atom '%s' is not in IUSE") \
+ % (flag, conditional_str % flag, self)
+ raise InvalidAtom(msg, category='IUSE.missing')
+ if self.blocker and self.blocker.overlap.forbid and not eapi_has_strong_blocks(eapi):
+ raise InvalidAtom(
+ _("Strong blocks are not allowed in EAPI %s: '%s'") \
+ % (eapi, self), category='EAPI.incompatible')
+
+ @property
+ def without_repo(self):
+ if self.repo is None:
+ return self
+ return Atom(self.replace(_repo_separator + self.repo, '', 1),
+ allow_wildcard=True)
+
+ @property
+ def without_slot(self):
+ if self.slot is None:
+ return self
+ return Atom(self.replace(_slot_separator + self.slot, '', 1),
+ allow_repo=True, allow_wildcard=True)
+
+ def __setattr__(self, name, value):
+ raise AttributeError("Atom instances are immutable",
+ self.__class__, name, value)
+
+ def intersects(self, other):
+ """
+ Atoms with different cpv, operator or use attributes cause this method
+ to return False even though there may actually be some intersection.
+ TODO: Detect more forms of intersection.
+ @param other: The package atom to match
+ @type other: Atom
+ @rtype: Boolean
+ @return: True if this atom and the other atom intersect,
+ False otherwise.
+ """
+ if not isinstance(other, Atom):
+ raise TypeError("expected %s, got %s" % \
+ (Atom, type(other)))
+
+ if self == other:
+ return True
+
+ if self.cp != other.cp or \
+ self.use != other.use or \
+ self.operator != other.operator or \
+ self.cpv != other.cpv:
+ return False
+
+ if self.slot is None or \
+ other.slot is None or \
+ self.slot == other.slot:
+ return True
+
+ return False
+
+ def evaluate_conditionals(self, use):
+ """
+ Create an atom instance with any USE conditionals evaluated.
+ @param use: The set of enabled USE flags
+ @type use: set
+ @rtype: Atom
+ @return: an atom instance with any USE conditionals evaluated
+ """
+ if not (self.use and self.use.conditional):
+ return self
+ atom = remove_slot(self)
+ if self.slot:
+ atom += ":%s" % self.slot
+ use_dep = self.use.evaluate_conditionals(use)
+ atom += str(use_dep)
+ return Atom(atom, unevaluated_atom=self, allow_repo=(self.repo is not None), _use=use_dep)
+
+ def violated_conditionals(self, other_use, is_valid_flag, parent_use=None):
+ """
+ Create an atom instance with any USE conditional removed, that is
+ satisfied by other_use.
+ @param other_use: The set of enabled USE flags
+ @type other_use: set
+ @param is_valid_flag: Function that decides if a use flag is referenceable in use deps
+ @type is_valid_flag: function
+ @param parent_use: Set of enabled use flags of the package requiring this atom
+ @type parent_use: set
+ @rtype: Atom
+ @return: an atom instance with any satisfied USE conditionals removed
+ """
+ if not self.use:
+ return self
+ atom = remove_slot(self)
+ if self.slot:
+ atom += ":%s" % self.slot
+ use_dep = self.use.violated_conditionals(other_use, is_valid_flag, parent_use)
+ atom += str(use_dep)
+ return Atom(atom, unevaluated_atom=self, allow_repo=(self.repo is not None), _use=use_dep)
+
+ def _eval_qa_conditionals(self, use_mask, use_force):
+ if not (self.use and self.use.conditional):
+ return self
+ atom = remove_slot(self)
+ if self.slot:
+ atom += ":%s" % self.slot
+ use_dep = self.use._eval_qa_conditionals(use_mask, use_force)
+ atom += str(use_dep)
+ return Atom(atom, unevaluated_atom=self, allow_repo=(self.repo is not None), _use=use_dep)
+
+ def __copy__(self):
+ """Immutable, so returns self."""
+ return self
+
+ def __deepcopy__(self, memo=None):
+ """Immutable, so returns self."""
+ memo[id(self)] = self
+ return self
+
+_extended_cp_re_cache = {}
+
+def extended_cp_match(extended_cp, other_cp):
+ """
+ Checks if an extended syntax cp matches a non extended cp
+ """
+ # Escape special '+' and '.' characters which are allowed in atoms,
+ # and convert '*' to regex equivalent.
+ global _extended_cp_re_cache
+ extended_cp_re = _extended_cp_re_cache.get(extended_cp)
+ if extended_cp_re is None:
+ extended_cp_re = re.compile("^" + re.escape(extended_cp).replace(
+ r'\*', '[^/]*') + "$")
+ _extended_cp_re_cache[extended_cp] = extended_cp_re
+ return extended_cp_re.match(other_cp) is not None
+
+class ExtendedAtomDict(portage.cache.mappings.MutableMapping):
+ """
+ dict() wrapper that supports extended atoms as keys and allows lookup
+ of a normal cp against other normal cp and extended cp.
+ The value type has to be given to __init__ and is assumed to be the same
+ for all values.
+ """
+
+ __slots__ = ('_extended', '_normal', '_value_class')
+
+ def __init__(self, value_class):
+ self._extended = {}
+ self._normal = {}
+ self._value_class = value_class
+
+ def copy(self):
+ result = self.__class__(self._value_class)
+ result._extended.update(self._extended)
+ result._normal.update(self._normal)
+ return result
+
+ def __iter__(self):
+ for k in self._normal:
+ yield k
+ for k in self._extended:
+ yield k
+
+ def iteritems(self):
+ for item in self._normal.items():
+ yield item
+ for item in self._extended.items():
+ yield item
+
+ def __delitem__(self, cp):
+ if "*" in cp:
+ return self._extended.__delitem__(cp)
+ else:
+ return self._normal.__delitem__(cp)
+
+ if sys.hexversion >= 0x3000000:
+ keys = __iter__
+ items = iteritems
+
+ def __len__(self):
+ return len(self._normal) + len(self._extended)
+
+ def setdefault(self, cp, default=None):
+ if "*" in cp:
+ return self._extended.setdefault(cp, default)
+ else:
+ return self._normal.setdefault(cp, default)
+
+ def __getitem__(self, cp):
+
+ if not isinstance(cp, basestring):
+ raise KeyError(cp)
+
+ if '*' in cp:
+ return self._extended[cp]
+
+ ret = self._value_class()
+ normal_match = self._normal.get(cp)
+ match = False
+
+ if normal_match is not None:
+ match = True
+ if hasattr(ret, "update"):
+ ret.update(normal_match)
+ elif hasattr(ret, "extend"):
+ ret.extend(normal_match)
+ else:
+ raise NotImplementedError()
+
+ for extended_cp in self._extended:
+ if extended_cp_match(extended_cp, cp):
+ match = True
+ if hasattr(ret, "update"):
+ ret.update(self._extended[extended_cp])
+ elif hasattr(ret, "extend"):
+ ret.extend(self._extended[extended_cp])
+ else:
+ raise NotImplementedError()
+
+ if not match:
+ raise KeyError(cp)
+
+ return ret
+
+ def __setitem__(self, cp, val):
+ if "*" in cp:
+ self._extended[cp] = val
+ else:
+ self._normal[cp] = val
+
+ def __eq__(self, other):
+ return self._value_class == other._value_class and \
+ self._extended == other._extended and \
+ self._normal == other._normal
+
+ def clear(self):
+ self._extended.clear()
+ self._normal.clear()
+
+
+def get_operator(mydep):
+ """
+ Return the operator used in a depstring.
+
+ Example usage:
+ >>> from portage.dep import *
+ >>> get_operator(">=test-1.0")
+ '>='
+
+ @param mydep: The dep string to check
+ @type mydep: String
+ @rtype: String
+ @return: The operator. One of:
+ '~', '=', '>', '<', '=*', '>=', or '<='
+ """
+ if not isinstance(mydep, Atom):
+ mydep = Atom(mydep)
+
+ return mydep.operator
+
+def dep_getcpv(mydep):
+ """
+ Return the category-package-version with any operators/slot specifications stripped off
+
+ Example usage:
+ >>> dep_getcpv('>=media-libs/test-3.0')
+ 'media-libs/test-3.0'
+
+ @param mydep: The depstring
+ @type mydep: String
+ @rtype: String
+ @return: The depstring with the operator removed
+ """
+ if not isinstance(mydep, Atom):
+ mydep = Atom(mydep)
+
+ return mydep.cpv
+
+def dep_getslot(mydep):
+ """
+ Retrieve the slot on a depend.
+
+ Example usage:
+ >>> dep_getslot('app-misc/test:3')
+ '3'
+
+ @param mydep: The depstring to retrieve the slot of
+ @type mydep: String
+ @rtype: String
+ @return: The slot
+ """
+ slot = getattr(mydep, "slot", False)
+ if slot is not False:
+ return slot
+
+ #remove repo_name if present
+ mydep = mydep.split(_repo_separator)[0]
+
+ colon = mydep.find(_slot_separator)
+ if colon != -1:
+ bracket = mydep.find("[", colon)
+ if bracket == -1:
+ return mydep[colon+1:]
+ else:
+ return mydep[colon+1:bracket]
+ return None
+
+def dep_getrepo(mydep):
+ """
+ Retrieve the repo on a depend.
+
+ Example usage:
+ >>> dep_getrepo('app-misc/test::repository')
+ 'repository'
+
+ @param mydep: The depstring to retrieve the repository of
+ @type mydep: String
+ @rtype: String
+ @return: The repository name
+ """
+ repo = getattr(mydep, "repo", False)
+ if repo is not False:
+ return repo
+
+ metadata = getattr(mydep, "metadata", False)
+ if metadata:
+ repo = metadata.get('repository', False)
+ if repo is not False:
+ return repo
+
+ colon = mydep.find(_repo_separator)
+ if colon != -1:
+ bracket = mydep.find("[", colon)
+ if bracket == -1:
+ return mydep[colon+2:]
+ else:
+ return mydep[colon+2:bracket]
+ return None
+def remove_slot(mydep):
+ """
+ Removes dep components from the right side of an atom:
+ * slot
+ * use
+ * repo
+ And repo_name from the left side.
+ """
+ colon = mydep.find(_slot_separator)
+ if colon != -1:
+ mydep = mydep[:colon]
+ else:
+ bracket = mydep.find("[")
+ if bracket != -1:
+ mydep = mydep[:bracket]
+ return mydep
+
+def dep_getusedeps( depend ):
+ """
+ Pull a listing of USE Dependencies out of a dep atom.
+
+ Example usage:
+ >>> dep_getusedeps('app-misc/test:3[foo,-bar]')
+ ('foo', '-bar')
+
+ @param depend: The depstring to process
+ @type depend: String
+ @rtype: List
+ @return: List of use flags ( or [] if no flags exist )
+ """
+ use_list = []
+ open_bracket = depend.find('[')
+ # -1 = failure (think c++ string::npos)
+ comma_separated = False
+ bracket_count = 0
+ while( open_bracket != -1 ):
+ bracket_count += 1
+ if bracket_count > 1:
+ raise InvalidAtom(_("USE Dependency with more "
+ "than one set of brackets: %s") % (depend,))
+ close_bracket = depend.find(']', open_bracket )
+ if close_bracket == -1:
+ raise InvalidAtom(_("USE Dependency with no closing bracket: %s") % depend )
+ use = depend[open_bracket + 1: close_bracket]
+ # foo[1:1] may return '' instead of None, we don't want '' in the result
+ if not use:
+ raise InvalidAtom(_("USE Dependency with "
+ "no use flag ([]): %s") % depend )
+ if not comma_separated:
+ comma_separated = "," in use
+
+ if comma_separated and bracket_count > 1:
+ raise InvalidAtom(_("USE Dependency contains a mixture of "
+ "comma and bracket separators: %s") % depend )
+
+ if comma_separated:
+ for x in use.split(","):
+ if x:
+ use_list.append(x)
+ else:
+ raise InvalidAtom(_("USE Dependency with no use "
+ "flag next to comma: %s") % depend )
+ else:
+ use_list.append(use)
+
+ # Find next use flag
+ open_bracket = depend.find( '[', open_bracket+1 )
+ return tuple(use_list)
+
+# \w is [a-zA-Z0-9_]
+
+# 2.1.3 A slot name may contain any of the characters [A-Za-z0-9+_.-].
+# It must not begin with a hyphen or a dot.
+_slot_separator = ":"
+_slot = r'([\w+][\w+.-]*)'
+_slot_re = re.compile('^' + _slot + '$', re.VERBOSE)
+
+_use = r'\[.*\]'
+_op = r'([=~]|[><]=?)'
+_repo_separator = "::"
+_repo_name = r'[\w][\w-]*'
+_repo = r'(?:' + _repo_separator + '(' + _repo_name + ')' + ')?'
+
+_atom_re = re.compile('^(?P<without_use>(?:' +
+ '(?P<op>' + _op + _cpv + ')|' +
+ '(?P<star>=' + _cpv + r'\*)|' +
+ '(?P<simple>' + _cp + '))' +
+ '(' + _slot_separator + _slot + ')?' + _repo + ')(' + _use + ')?$', re.VERBOSE)
+
+_extended_cat = r'[\w+*][\w+.*-]*'
+_extended_pkg = r'[\w+*][\w+*-]*?'
+
+_atom_wildcard_re = re.compile('(?P<simple>(' + _extended_cat + ')/(' + _extended_pkg + '))(:(?P<slot>' + _slot + '))?(' + _repo_separator + '(?P<repo>' + _repo_name + '))?$')
+
+_useflag_re = {
+ "0": re.compile(r'^[A-Za-z0-9][A-Za-z0-9+_@-]*$'),
+ "4-python": re.compile(r'^[A-Za-z0-9][A-Za-z0-9+_@.-]*$'),
+}
+
+def _get_useflag_re(eapi):
+ """
+ When eapi is None then validation is not as strict, since we want the
+ same to work for multiple EAPIs that may have slightly different rules.
+ @param eapi: The EAPI
+ @type eapi: String or None
+ @rtype: regular expression object
+ @return: A regular expression object that matches valid USE flags for the
+ given eapi.
+ """
+ if eapi in (None, "4-python",):
+ return _useflag_re["4-python"]
+ else:
+ return _useflag_re["0"]
+
+def isvalidatom(atom, allow_blockers=False, allow_wildcard=False, allow_repo=False):
+ """
+ Check to see if a depend atom is valid
+
+ Example usage:
+ >>> isvalidatom('media-libs/test-3.0')
+ False
+ >>> isvalidatom('>=media-libs/test-3.0')
+ True
+
+ @param atom: The depend atom to check against
+ @type atom: String or Atom
+ @rtype: Boolean
+ @return: One of the following:
+ 1) False if the atom is invalid
+ 2) True if the atom is valid
+ """
+ try:
+ if not isinstance(atom, Atom):
+ atom = Atom(atom, allow_wildcard=allow_wildcard, allow_repo=allow_repo)
+ if not allow_blockers and atom.blocker:
+ return False
+ return True
+ except InvalidAtom:
+ return False
+
+def isjustname(mypkg):
+ """
+ Checks to see if the atom is only the package name (no version parts).
+
+ Example usage:
+ >>> isjustname('=media-libs/test-3.0')
+ False
+ >>> isjustname('media-libs/test')
+ True
+
+ @param mypkg: The package atom to check
+ @param mypkg: String or Atom
+ @rtype: Integer
+ @return: One of the following:
+ 1) False if the package string is not just the package name
+ 2) True if it is
+ """
+ try:
+ if not isinstance(mypkg, Atom):
+ mypkg = Atom(mypkg)
+ return mypkg == mypkg.cp
+ except InvalidAtom:
+ pass
+
+ for x in mypkg.split('-')[-2:]:
+ if ververify(x):
+ return False
+ return True
+
+def isspecific(mypkg):
+ """
+ Checks to see if a package is in =category/package-version or
+ package-version format.
+
+ Example usage:
+ >>> isspecific('media-libs/test')
+ False
+ >>> isspecific('=media-libs/test-3.0')
+ True
+
+ @param mypkg: The package depstring to check against
+ @type mypkg: String
+ @rtype: Boolean
+ @return: One of the following:
+ 1) False if the package string is not specific
+ 2) True if it is
+ """
+ try:
+ if not isinstance(mypkg, Atom):
+ mypkg = Atom(mypkg)
+ return mypkg != mypkg.cp
+ except InvalidAtom:
+ pass
+
+ # Fall back to legacy code for backward compatibility.
+ return not isjustname(mypkg)
+
+def dep_getkey(mydep):
+ """
+ Return the category/package-name of a depstring.
+
+ Example usage:
+ >>> dep_getkey('=media-libs/test-3.0')
+ 'media-libs/test'
+
+ @param mydep: The depstring to retrieve the category/package-name of
+ @type mydep: String
+ @rtype: String
+ @return: The package category/package-name
+ """
+ if not isinstance(mydep, Atom):
+ mydep = Atom(mydep, allow_wildcard=True, allow_repo=True)
+
+ return mydep.cp
+
+def match_to_list(mypkg, mylist):
+ """
+ Searches list for entries that matches the package.
+
+ @param mypkg: The package atom to match
+ @type mypkg: String
+ @param mylist: The list of package atoms to compare against
+ @param mylist: List
+ @rtype: List
+ @return: A unique list of package atoms that match the given package atom
+ """
+ return [ x for x in set(mylist) if match_from_list(x, [mypkg]) ]
+
+def best_match_to_list(mypkg, mylist):
+ """
+ Returns the most specific entry that matches the package given.
+
+ @param mypkg: The package atom to check
+ @type mypkg: String
+ @param mylist: The list of package atoms to check against
+ @type mylist: List
+ @rtype: String
+ @return: The package atom which best matches given the following ordering:
+ - =cpv 6
+ - ~cpv 5
+ - =cpv* 4
+ - cp:slot 3
+ - >cpv 2
+ - <cpv 2
+ - >=cpv 2
+ - <=cpv 2
+ - cp 1
+ - cp:slot with extended syntax 0
+ - cp with extended syntax -1
+ """
+ operator_values = {'=':6, '~':5, '=*':4,
+ '>':2, '<':2, '>=':2, '<=':2, None:1}
+ maxvalue = -2
+ bestm = None
+ for x in match_to_list(mypkg, mylist):
+ if x.extended_syntax:
+ if dep_getslot(x) is not None:
+ if maxvalue < 0:
+ maxvalue = 0
+ bestm = x
+ else:
+ if maxvalue < -1:
+ maxvalue = -1
+ bestm = x
+ continue
+ if dep_getslot(x) is not None:
+ if maxvalue < 3:
+ maxvalue = 3
+ bestm = x
+ op_val = operator_values[x.operator]
+ if op_val > maxvalue:
+ maxvalue = op_val
+ bestm = x
+ return bestm
+
+def match_from_list(mydep, candidate_list):
+ """
+ Searches list for entries that matches the package.
+
+ @param mydep: The package atom to match
+ @type mydep: String
+ @param candidate_list: The list of package atoms to compare against
+ @param candidate_list: List
+ @rtype: List
+ @return: A list of package atoms that match the given package atom
+ """
+
+ if not candidate_list:
+ return []
+
+ from portage.util import writemsg
+ if "!" == mydep[:1]:
+ if "!" == mydep[1:2]:
+ mydep = mydep[2:]
+ else:
+ mydep = mydep[1:]
+ if not isinstance(mydep, Atom):
+ mydep = Atom(mydep, allow_wildcard=True, allow_repo=True)
+
+ mycpv = mydep.cpv
+ mycpv_cps = catpkgsplit(mycpv) # Can be None if not specific
+ slot = mydep.slot
+
+ if not mycpv_cps:
+ cat, pkg = catsplit(mycpv)
+ ver = None
+ rev = None
+ else:
+ cat, pkg, ver, rev = mycpv_cps
+ if mydep == mycpv:
+ raise KeyError(_("Specific key requires an operator"
+ " (%s) (try adding an '=')") % (mydep))
+
+ if ver and rev:
+ operator = mydep.operator
+ if not operator:
+ writemsg(_("!!! Invalid atom: %s\n") % mydep, noiselevel=-1)
+ return []
+ else:
+ operator = None
+
+ mylist = []
+
+ if operator is None:
+ for x in candidate_list:
+ cp = getattr(x, "cp", None)
+ if cp is None:
+ mysplit = catpkgsplit(remove_slot(x))
+ if mysplit is not None:
+ cp = mysplit[0] + '/' + mysplit[1]
+
+ if cp is None:
+ continue
+
+ if cp == mycpv or (mydep.extended_syntax and \
+ extended_cp_match(mydep.cp, cp)):
+ mylist.append(x)
+
+ elif operator == "=": # Exact match
+ for x in candidate_list:
+ xcpv = getattr(x, "cpv", None)
+ if xcpv is None:
+ xcpv = remove_slot(x)
+ if not cpvequal(xcpv, mycpv):
+ continue
+ mylist.append(x)
+
+ elif operator == "=*": # glob match
+ # XXX: Nasty special casing for leading zeros
+ # Required as =* is a literal prefix match, so can't
+ # use vercmp
+ mysplit = catpkgsplit(mycpv)
+ myver = mysplit[2].lstrip("0")
+ if not myver or not myver[0].isdigit():
+ myver = "0"+myver
+ mycpv = mysplit[0]+"/"+mysplit[1]+"-"+myver
+ for x in candidate_list:
+ xs = getattr(x, "cpv_split", None)
+ if xs is None:
+ xs = catpkgsplit(remove_slot(x))
+ myver = xs[2].lstrip("0")
+ if not myver or not myver[0].isdigit():
+ myver = "0"+myver
+ xcpv = xs[0]+"/"+xs[1]+"-"+myver
+ if xcpv.startswith(mycpv):
+ mylist.append(x)
+
+ elif operator == "~": # version, any revision, match
+ for x in candidate_list:
+ xs = getattr(x, "cpv_split", None)
+ if xs is None:
+ xs = catpkgsplit(remove_slot(x))
+ if xs is None:
+ raise InvalidData(x)
+ if not cpvequal(xs[0]+"/"+xs[1]+"-"+xs[2], mycpv_cps[0]+"/"+mycpv_cps[1]+"-"+mycpv_cps[2]):
+ continue
+ if xs[2] != ver:
+ continue
+ mylist.append(x)
+
+ elif operator in [">", ">=", "<", "<="]:
+ mysplit = ["%s/%s" % (cat, pkg), ver, rev]
+ for x in candidate_list:
+ xs = getattr(x, "cpv_split", None)
+ if xs is None:
+ xs = catpkgsplit(remove_slot(x))
+ xcat, xpkg, xver, xrev = xs
+ xs = ["%s/%s" % (xcat, xpkg), xver, xrev]
+ try:
+ result = pkgcmp(xs, mysplit)
+ except ValueError: # pkgcmp may return ValueError during int() conversion
+ writemsg(_("\nInvalid package name: %s\n") % x, noiselevel=-1)
+ raise
+ if result is None:
+ continue
+ elif operator == ">":
+ if result > 0:
+ mylist.append(x)
+ elif operator == ">=":
+ if result >= 0:
+ mylist.append(x)
+ elif operator == "<":
+ if result < 0:
+ mylist.append(x)
+ elif operator == "<=":
+ if result <= 0:
+ mylist.append(x)
+ else:
+ raise KeyError(_("Unknown operator: %s") % mydep)
+ else:
+ raise KeyError(_("Unknown operator: %s") % mydep)
+
+ if slot is not None and not mydep.extended_syntax:
+ candidate_list = mylist
+ mylist = []
+ for x in candidate_list:
+ xslot = getattr(x, "slot", False)
+ if xslot is False:
+ xslot = dep_getslot(x)
+ if xslot is not None and xslot != slot:
+ continue
+ mylist.append(x)
+
+ if mydep.unevaluated_atom.use:
+ candidate_list = mylist
+ mylist = []
+ for x in candidate_list:
+ use = getattr(x, "use", None)
+ if use is not None:
+ if mydep.unevaluated_atom.use and \
+ not x.iuse.is_valid_flag(
+ mydep.unevaluated_atom.use.required):
+ continue
+
+ if mydep.use:
+
+ missing_enabled = mydep.use.missing_enabled.difference(x.iuse.all)
+ missing_disabled = mydep.use.missing_disabled.difference(x.iuse.all)
+
+ if mydep.use.enabled:
+ if mydep.use.enabled.intersection(missing_disabled):
+ continue
+ need_enabled = mydep.use.enabled.difference(use.enabled)
+ if need_enabled:
+ need_enabled = need_enabled.difference(missing_enabled)
+ if need_enabled:
+ continue
+
+ if mydep.use.disabled:
+ if mydep.use.disabled.intersection(missing_enabled):
+ continue
+ need_disabled = mydep.use.disabled.intersection(use.enabled)
+ if need_disabled:
+ need_disabled = need_disabled.difference(missing_disabled)
+ if need_disabled:
+ continue
+
+ mylist.append(x)
+
+ if mydep.repo:
+ candidate_list = mylist
+ mylist = []
+ for x in candidate_list:
+ repo = getattr(x, "repo", False)
+ if repo is False:
+ repo = dep_getrepo(x)
+ if repo is not None and repo != mydep.repo:
+ continue
+ mylist.append(x)
+
+ return mylist
+
+def human_readable_required_use(required_use):
+ return required_use.replace("^^", "exactly-one-of").replace("||", "any-of")
+
+def get_required_use_flags(required_use):
+ """
+ Returns a set of use flags that are used in the given REQUIRED_USE string
+
+ @param required_use: REQUIRED_USE string
+ @type required_use: String
+ @rtype: Set
+ @return: Set of use flags that are used in the given REQUIRED_USE string
+ """
+
+ mysplit = required_use.split()
+ level = 0
+ stack = [[]]
+ need_bracket = False
+
+ used_flags = set()
+
+ def register_token(token):
+ if token.endswith("?"):
+ token = token[:-1]
+ if token.startswith("!"):
+ token = token[1:]
+ used_flags.add(token)
+
+ for token in mysplit:
+ if token == "(":
+ need_bracket = False
+ stack.append([])
+ level += 1
+ elif token == ")":
+ if need_bracket:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % required_use)
+ if level > 0:
+ level -= 1
+ l = stack.pop()
+ ignore = False
+ if stack[level]:
+ if stack[level][-1] in ("||", "^^") or \
+ (not isinstance(stack[level][-1], bool) and \
+ stack[level][-1][-1] == "?"):
+ ignore = True
+ stack[level].pop()
+ stack[level].append(True)
+
+ if l and not ignore:
+ stack[level].append(all(x for x in l))
+ else:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % required_use)
+ elif token in ("||", "^^"):
+ if need_bracket:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % required_use)
+ need_bracket = True
+ stack[level].append(token)
+ else:
+ if need_bracket or "(" in token or ")" in token or \
+ "|" in token or "^" in token:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % required_use)
+
+ if token[-1] == "?":
+ need_bracket = True
+ stack[level].append(token)
+ else:
+ stack[level].append(True)
+
+ register_token(token)
+
+ if level != 0 or need_bracket:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % required_use)
+
+ return frozenset(used_flags)
+
+class _RequiredUseLeaf(object):
+
+ __slots__ = ('_satisfied', '_token')
+
+ def __init__(self, token, satisfied):
+ self._token = token
+ self._satisfied = satisfied
+
+ def tounicode(self):
+ return self._token
+
+class _RequiredUseBranch(object):
+
+ __slots__ = ('_children', '_operator', '_parent', '_satisfied')
+
+ def __init__(self, operator=None, parent=None):
+ self._children = []
+ self._operator = operator
+ self._parent = parent
+ self._satisfied = False
+
+ def __bool__(self):
+ return self._satisfied
+
+ def tounicode(self):
+
+ include_parens = self._parent is not None
+ tokens = []
+ if self._operator is not None:
+ tokens.append(self._operator)
+
+ if include_parens:
+ tokens.append("(")
+
+ complex_nesting = False
+ node = self
+ while node != None and not complex_nesting:
+ if node._operator in ("||", "^^"):
+ complex_nesting = True
+ else:
+ node = node._parent
+
+ if complex_nesting:
+ for child in self._children:
+ tokens.append(child.tounicode())
+ else:
+ for child in self._children:
+ if not child._satisfied:
+ tokens.append(child.tounicode())
+
+ if include_parens:
+ tokens.append(")")
+
+ return " ".join(tokens)
+
+ if sys.hexversion < 0x3000000:
+ __nonzero__ = __bool__
+
+def check_required_use(required_use, use, iuse_match):
+ """
+ Checks if the use flags listed in 'use' satisfy all
+ constraints specified in 'constraints'.
+
+ @param required_use: REQUIRED_USE string
+ @type required_use: String
+ @param use: Enabled use flags
+ @param use: List
+ @param iuse_match: Callable that takes a single flag argument and returns
+ True if the flag is matched, false otherwise,
+ @param iuse_match: Callable
+ @rtype: Bool
+ @return: Indicates if REQUIRED_USE constraints are satisfied
+ """
+
+ def is_active(token):
+ if token.startswith("!"):
+ flag = token[1:]
+ is_negated = True
+ else:
+ flag = token
+ is_negated = False
+
+ if not flag or not iuse_match(flag):
+ msg = _("USE flag '%s' is not in IUSE") \
+ % (flag,)
+ e = InvalidData(msg, category='IUSE.missing')
+ raise InvalidDependString(msg, errors=(e,))
+
+ return (flag in use and not is_negated) or \
+ (flag not in use and is_negated)
+
+ def is_satisfied(operator, argument):
+ if not argument:
+ #|| ( ) -> True
+ return True
+
+ if operator == "||":
+ return (True in argument)
+ elif operator == "^^":
+ return (argument.count(True) == 1)
+ elif operator[-1] == "?":
+ return (False not in argument)
+
+ mysplit = required_use.split()
+ level = 0
+ stack = [[]]
+ tree = _RequiredUseBranch()
+ node = tree
+ need_bracket = False
+
+ for token in mysplit:
+ if token == "(":
+ if not need_bracket:
+ child = _RequiredUseBranch(parent=node)
+ node._children.append(child)
+ node = child
+
+ need_bracket = False
+ stack.append([])
+ level += 1
+ elif token == ")":
+ if need_bracket:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % required_use)
+ if level > 0:
+ level -= 1
+ l = stack.pop()
+ op = None
+ if stack[level]:
+ if stack[level][-1] in ("||", "^^"):
+ op = stack[level].pop()
+ satisfied = is_satisfied(op, l)
+ stack[level].append(satisfied)
+ node._satisfied = satisfied
+
+ elif not isinstance(stack[level][-1], bool) and \
+ stack[level][-1][-1] == "?":
+ op = stack[level].pop()
+ if is_active(op[:-1]):
+ satisfied = is_satisfied(op, l)
+ stack[level].append(satisfied)
+ node._satisfied = satisfied
+ else:
+ node._satisfied = True
+ last_node = node._parent._children.pop()
+ if last_node is not node:
+ raise AssertionError(
+ "node is not last child of parent")
+ node = node._parent
+ continue
+
+ if op is None:
+ satisfied = False not in l
+ node._satisfied = satisfied
+ if l:
+ stack[level].append(satisfied)
+
+ if len(node._children) <= 1 or \
+ node._parent._operator not in ("||", "^^"):
+ last_node = node._parent._children.pop()
+ if last_node is not node:
+ raise AssertionError(
+ "node is not last child of parent")
+ for child in node._children:
+ node._parent._children.append(child)
+ if isinstance(child, _RequiredUseBranch):
+ child._parent = node._parent
+
+ elif not node._children:
+ last_node = node._parent._children.pop()
+ if last_node is not node:
+ raise AssertionError(
+ "node is not last child of parent")
+
+ elif len(node._children) == 1 and op in ("||", "^^"):
+ last_node = node._parent._children.pop()
+ if last_node is not node:
+ raise AssertionError(
+ "node is not last child of parent")
+ node._parent._children.append(node._children[0])
+ if isinstance(node._children[0], _RequiredUseBranch):
+ node._children[0]._parent = node._parent
+ node = node._children[0]
+ if node._operator is None and \
+ node._parent._operator not in ("||", "^^"):
+ last_node = node._parent._children.pop()
+ if last_node is not node:
+ raise AssertionError(
+ "node is not last child of parent")
+ for child in node._children:
+ node._parent._children.append(child)
+ if isinstance(child, _RequiredUseBranch):
+ child._parent = node._parent
+
+ node = node._parent
+ else:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % required_use)
+ elif token in ("||", "^^"):
+ if need_bracket:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % required_use)
+ need_bracket = True
+ stack[level].append(token)
+ child = _RequiredUseBranch(operator=token, parent=node)
+ node._children.append(child)
+ node = child
+ else:
+ if need_bracket or "(" in token or ")" in token or \
+ "|" in token or "^" in token:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % required_use)
+
+ if token[-1] == "?":
+ need_bracket = True
+ stack[level].append(token)
+ child = _RequiredUseBranch(operator=token, parent=node)
+ node._children.append(child)
+ node = child
+ else:
+ satisfied = is_active(token)
+ stack[level].append(satisfied)
+ node._children.append(_RequiredUseLeaf(token, satisfied))
+
+ if level != 0 or need_bracket:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % required_use)
+
+ tree._satisfied = False not in stack[0]
+ return tree
+
+def extract_affecting_use(mystr, atom, eapi=None):
+ """
+ Take a dep string and an atom and return the use flags
+ that decide if the given atom is in effect.
+
+ Example usage:
+ >>> extract_use_cond('sasl? ( dev-libs/cyrus-sasl ) \
+ !minimal? ( cxx? ( dev-libs/cyrus-sasl ) )', 'dev-libs/cyrus-sasl')
+ (['sasl', 'minimal', 'cxx'])
+
+ @param dep: The dependency string
+ @type mystr: String
+ @param atom: The atom to get into effect
+ @type atom: String
+ @rtype: Tuple of two lists of strings
+ @return: List of use flags that need to be enabled, List of use flag that need to be disabled
+ """
+ useflag_re = _get_useflag_re(eapi)
+ mysplit = mystr.split()
+ level = 0
+ stack = [[]]
+ need_bracket = False
+ affecting_use = set()
+
+ def flag(conditional):
+ if conditional[0] == "!":
+ flag = conditional[1:-1]
+ else:
+ flag = conditional[:-1]
+
+ if useflag_re.match(flag) is None:
+ raise InvalidDependString(
+ _("invalid use flag '%s' in conditional '%s'") % \
+ (flag, conditional))
+
+ return flag
+
+ for token in mysplit:
+ if token == "(":
+ need_bracket = False
+ stack.append([])
+ level += 1
+ elif token == ")":
+ if need_bracket:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % mystr)
+ if level > 0:
+ level -= 1
+ l = stack.pop()
+ is_single = (len(l) == 1 or (len(l)==2 and (l[0] == "||" or l[0][-1] == "?")))
+
+ def ends_in_any_of_dep(k):
+ return k>=0 and stack[k] and stack[k][-1] == "||"
+
+ def ends_in_operator(k):
+ return k>=0 and stack[k] and (stack[k][-1] == "||" or stack[k][-1][-1] == "?")
+
+ def special_append():
+ """
+ Use extend instead of append if possible. This kills all redundant brackets.
+ """
+ if is_single and (not stack[level] or not stack[level][-1][-1] == "?"):
+ if len(l) == 1 and isinstance(l[0], list):
+ # l = [[...]]
+ stack[level].extend(l[0])
+ else:
+ stack[level].extend(l)
+ else:
+ stack[level].append(l)
+
+ if l:
+ if not ends_in_any_of_dep(level-1) and not ends_in_operator(level):
+ #Optimize: ( ( ... ) ) -> ( ... ). Make sure there is no '||' hanging around.
+ stack[level].extend(l)
+ elif not stack[level]:
+ #An '||' in the level above forces us to keep to brackets.
+ special_append()
+ elif len(l) == 1 and ends_in_any_of_dep(level):
+ #Optimize: || ( A ) -> A
+ stack[level].pop()
+ special_append()
+ elif len(l) == 2 and (l[0] == "||" or l[0][-1] == "?") and stack[level][-1] in (l[0], "||"):
+ #Optimize: || ( || ( ... ) ) -> || ( ... )
+ # foo? ( foo? ( ... ) ) -> foo? ( ... )
+ # || ( foo? ( ... ) ) -> foo? ( ... )
+ stack[level].pop()
+ special_append()
+ if l[0][-1] == "?":
+ affecting_use.add(flag(l[0]))
+ else:
+ if stack[level] and stack[level][-1][-1] == "?":
+ affecting_use.add(flag(stack[level][-1]))
+ special_append()
+ else:
+ if stack[level] and (stack[level][-1] == "||" or stack[level][-1][-1] == "?"):
+ stack[level].pop()
+ else:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % mystr)
+ elif token == "||":
+ if need_bracket:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % mystr)
+ need_bracket = True
+ stack[level].append(token)
+ else:
+ if need_bracket:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % mystr)
+
+ if token[-1] == "?":
+ need_bracket = True
+ stack[level].append(token)
+ elif token == atom:
+ stack[level].append(token)
+
+ if level != 0 or need_bracket:
+ raise InvalidDependString(
+ _("malformed syntax: '%s'") % mystr)
+
+ return affecting_use
diff --git a/portage_with_autodep/pym/portage/dep/dep_check.py b/portage_with_autodep/pym/portage/dep/dep_check.py
new file mode 100644
index 0000000..01d5021
--- /dev/null
+++ b/portage_with_autodep/pym/portage/dep/dep_check.py
@@ -0,0 +1,679 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['dep_check', 'dep_eval', 'dep_wordreduce', 'dep_zapdeps']
+
+import logging
+
+import portage
+from portage import _unicode_decode
+from portage.dep import Atom, match_from_list, use_reduce
+from portage.exception import InvalidDependString, ParseError
+from portage.localization import _
+from portage.util import writemsg, writemsg_level
+from portage.versions import catpkgsplit, cpv_getkey, pkgcmp
+
+def _expand_new_virtuals(mysplit, edebug, mydbapi, mysettings, myroot="/",
+ trees=None, use_mask=None, use_force=None, **kwargs):
+ """
+ In order to solve bug #141118, recursively expand new-style virtuals so
+ as to collapse one or more levels of indirection, generating an expanded
+ search space. In dep_zapdeps, new-style virtuals will be assigned
+ zero cost regardless of whether or not they are currently installed. Virtual
+ blockers are supported but only when the virtual expands to a single
+ atom because it wouldn't necessarily make sense to block all the components
+ of a compound virtual. When more than one new-style virtual is matched,
+ the matches are sorted from highest to lowest versions and the atom is
+ expanded to || ( highest match ... lowest match )."""
+ newsplit = []
+ mytrees = trees[myroot]
+ portdb = mytrees["porttree"].dbapi
+ pkg_use_enabled = mytrees.get("pkg_use_enabled")
+ # Atoms are stored in the graph as (atom, id(atom)) tuples
+ # since each atom is considered to be a unique entity. For
+ # example, atoms that appear identical may behave differently
+ # in USE matching, depending on their unevaluated form. Also,
+ # specially generated virtual atoms may appear identical while
+ # having different _orig_atom attributes.
+ atom_graph = mytrees.get("atom_graph")
+ parent = mytrees.get("parent")
+ virt_parent = mytrees.get("virt_parent")
+ graph_parent = None
+ eapi = None
+ if parent is not None:
+ if virt_parent is not None:
+ graph_parent = virt_parent
+ parent = virt_parent
+ else:
+ graph_parent = parent
+ eapi = parent.metadata["EAPI"]
+ repoman = not mysettings.local_config
+ if kwargs["use_binaries"]:
+ portdb = trees[myroot]["bintree"].dbapi
+ pprovideddict = mysettings.pprovideddict
+ myuse = kwargs["myuse"]
+ for x in mysplit:
+ if x == "||":
+ newsplit.append(x)
+ continue
+ elif isinstance(x, list):
+ newsplit.append(_expand_new_virtuals(x, edebug, mydbapi,
+ mysettings, myroot=myroot, trees=trees, use_mask=use_mask,
+ use_force=use_force, **kwargs))
+ continue
+
+ if not isinstance(x, Atom):
+ raise ParseError(
+ _("invalid token: '%s'") % x)
+
+ if repoman:
+ x = x._eval_qa_conditionals(use_mask, use_force)
+
+ mykey = x.cp
+ if not mykey.startswith("virtual/"):
+ newsplit.append(x)
+ if atom_graph is not None:
+ atom_graph.add((x, id(x)), graph_parent)
+ continue
+
+ if x.blocker:
+ # Virtual blockers are no longer expanded here since
+ # the un-expanded virtual atom is more useful for
+ # maintaining a cache of blocker atoms.
+ newsplit.append(x)
+ if atom_graph is not None:
+ atom_graph.add((x, id(x)), graph_parent)
+ continue
+
+ if repoman or not hasattr(portdb, 'match_pkgs') or \
+ pkg_use_enabled is None:
+ if portdb.cp_list(x.cp):
+ newsplit.append(x)
+ else:
+ # TODO: Add PROVIDE check for repoman.
+ a = []
+ myvartree = mytrees.get("vartree")
+ if myvartree is not None:
+ mysettings._populate_treeVirtuals_if_needed(myvartree)
+ mychoices = mysettings.getvirtuals().get(mykey, [])
+ for y in mychoices:
+ a.append(Atom(x.replace(x.cp, y.cp, 1)))
+ if not a:
+ newsplit.append(x)
+ elif len(a) == 1:
+ newsplit.append(a[0])
+ else:
+ newsplit.append(['||'] + a)
+ continue
+
+ pkgs = []
+ # Ignore USE deps here, since otherwise we might not
+ # get any matches. Choices with correct USE settings
+ # will be preferred in dep_zapdeps().
+ matches = portdb.match_pkgs(x.without_use)
+ # Use descending order to prefer higher versions.
+ matches.reverse()
+ for pkg in matches:
+ # only use new-style matches
+ if pkg.cp.startswith("virtual/"):
+ pkgs.append(pkg)
+
+ mychoices = []
+ if not pkgs and not portdb.cp_list(x.cp):
+ myvartree = mytrees.get("vartree")
+ if myvartree is not None:
+ mysettings._populate_treeVirtuals_if_needed(myvartree)
+ mychoices = mysettings.getvirtuals().get(mykey, [])
+
+ if not (pkgs or mychoices):
+ # This one couldn't be expanded as a new-style virtual. Old-style
+ # virtuals have already been expanded by dep_virtual, so this one
+ # is unavailable and dep_zapdeps will identify it as such. The
+ # atom is not eliminated here since it may still represent a
+ # dependency that needs to be satisfied.
+ newsplit.append(x)
+ if atom_graph is not None:
+ atom_graph.add((x, id(x)), graph_parent)
+ continue
+
+ a = []
+ for pkg in pkgs:
+ virt_atom = '=' + pkg.cpv
+ if x.unevaluated_atom.use:
+ virt_atom += str(x.unevaluated_atom.use)
+ virt_atom = Atom(virt_atom)
+ if parent is None:
+ if myuse is None:
+ virt_atom = virt_atom.evaluate_conditionals(
+ mysettings.get("PORTAGE_USE", "").split())
+ else:
+ virt_atom = virt_atom.evaluate_conditionals(myuse)
+ else:
+ virt_atom = virt_atom.evaluate_conditionals(
+ pkg_use_enabled(parent))
+ else:
+ virt_atom = Atom(virt_atom)
+
+ # Allow the depgraph to map this atom back to the
+ # original, in order to avoid distortion in places
+ # like display or conflict resolution code.
+ virt_atom.__dict__['_orig_atom'] = x
+
+ # According to GLEP 37, RDEPEND is the only dependency
+ # type that is valid for new-style virtuals. Repoman
+ # should enforce this.
+ depstring = pkg.metadata['RDEPEND']
+ pkg_kwargs = kwargs.copy()
+ pkg_kwargs["myuse"] = pkg_use_enabled(pkg)
+ if edebug:
+ writemsg_level(_("Virtual Parent: %s\n") \
+ % (pkg,), noiselevel=-1, level=logging.DEBUG)
+ writemsg_level(_("Virtual Depstring: %s\n") \
+ % (depstring,), noiselevel=-1, level=logging.DEBUG)
+
+ # Set EAPI used for validation in dep_check() recursion.
+ mytrees["virt_parent"] = pkg
+
+ try:
+ mycheck = dep_check(depstring, mydbapi, mysettings,
+ myroot=myroot, trees=trees, **pkg_kwargs)
+ finally:
+ # Restore previous EAPI after recursion.
+ if virt_parent is not None:
+ mytrees["virt_parent"] = virt_parent
+ else:
+ del mytrees["virt_parent"]
+
+ if not mycheck[0]:
+ raise ParseError(_unicode_decode("%s: %s '%s'") % \
+ (pkg, mycheck[1], depstring))
+
+ # pull in the new-style virtual
+ mycheck[1].append(virt_atom)
+ a.append(mycheck[1])
+ if atom_graph is not None:
+ virt_atom_node = (virt_atom, id(virt_atom))
+ atom_graph.add(virt_atom_node, graph_parent)
+ atom_graph.add(pkg, virt_atom_node)
+ # Plain old-style virtuals. New-style virtuals are preferred.
+ if not pkgs:
+ for y in mychoices:
+ new_atom = Atom(x.replace(x.cp, y.cp, 1))
+ matches = portdb.match(new_atom)
+ # portdb is an instance of depgraph._dep_check_composite_db, so
+ # USE conditionals are already evaluated.
+ if matches and mykey in \
+ portdb.aux_get(matches[-1], ['PROVIDE'])[0].split():
+ a.append(new_atom)
+ if atom_graph is not None:
+ atom_graph.add((new_atom, id(new_atom)),
+ graph_parent)
+
+ if not a and mychoices:
+ # Check for a virtual package.provided match.
+ for y in mychoices:
+ new_atom = Atom(x.replace(x.cp, y.cp, 1))
+ if match_from_list(new_atom,
+ pprovideddict.get(new_atom.cp, [])):
+ a.append(new_atom)
+ if atom_graph is not None:
+ atom_graph.add((new_atom, id(new_atom)), graph_parent)
+
+ if not a:
+ newsplit.append(x)
+ if atom_graph is not None:
+ atom_graph.add((x, id(x)), graph_parent)
+ elif len(a) == 1:
+ newsplit.append(a[0])
+ else:
+ newsplit.append(['||'] + a)
+
+ return newsplit
+
+def dep_eval(deplist):
+ if not deplist:
+ return 1
+ if deplist[0]=="||":
+ #or list; we just need one "1"
+ for x in deplist[1:]:
+ if isinstance(x, list):
+ if dep_eval(x)==1:
+ return 1
+ elif x==1:
+ return 1
+ #XXX: unless there's no available atoms in the list
+ #in which case we need to assume that everything is
+ #okay as some ebuilds are relying on an old bug.
+ if len(deplist) == 1:
+ return 1
+ return 0
+ else:
+ for x in deplist:
+ if isinstance(x, list):
+ if dep_eval(x)==0:
+ return 0
+ elif x==0 or x==2:
+ return 0
+ return 1
+
+def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None):
+ """
+ Takes an unreduced and reduced deplist and removes satisfied dependencies.
+ Returned deplist contains steps that must be taken to satisfy dependencies.
+ """
+ if trees is None:
+ trees = portage.db
+ writemsg("ZapDeps -- %s\n" % (use_binaries), 2)
+ if not reduced or unreduced == ["||"] or dep_eval(reduced):
+ return []
+
+ if unreduced[0] != "||":
+ unresolved = []
+ for x, satisfied in zip(unreduced, reduced):
+ if isinstance(x, list):
+ unresolved += dep_zapdeps(x, satisfied, myroot,
+ use_binaries=use_binaries, trees=trees)
+ elif not satisfied:
+ unresolved.append(x)
+ return unresolved
+
+ # We're at a ( || atom ... ) type level and need to make a choice
+ deps = unreduced[1:]
+ satisfieds = reduced[1:]
+
+ # Our preference order is for an the first item that:
+ # a) contains all unmasked packages with the same key as installed packages
+ # b) contains all unmasked packages
+ # c) contains masked installed packages
+ # d) is the first item
+
+ preferred_installed = []
+ preferred_in_graph = []
+ preferred_any_slot = []
+ preferred_non_installed = []
+ unsat_use_in_graph = []
+ unsat_use_installed = []
+ unsat_use_non_installed = []
+ other_installed = []
+ other_installed_some = []
+ other = []
+
+ # unsat_use_* must come after preferred_non_installed
+ # for correct ordering in cases like || ( foo[a] foo[b] ).
+ choice_bins = (
+ preferred_in_graph,
+ preferred_installed,
+ preferred_any_slot,
+ preferred_non_installed,
+ unsat_use_in_graph,
+ unsat_use_installed,
+ unsat_use_non_installed,
+ other_installed,
+ other_installed_some,
+ other,
+ )
+
+ # Alias the trees we'll be checking availability against
+ parent = trees[myroot].get("parent")
+ priority = trees[myroot].get("priority")
+ graph_db = trees[myroot].get("graph_db")
+ graph = trees[myroot].get("graph")
+ vardb = None
+ if "vartree" in trees[myroot]:
+ vardb = trees[myroot]["vartree"].dbapi
+ if use_binaries:
+ mydbapi = trees[myroot]["bintree"].dbapi
+ else:
+ mydbapi = trees[myroot]["porttree"].dbapi
+
+ # Sort the deps into installed, not installed but already
+ # in the graph and other, not installed and not in the graph
+ # and other, with values of [[required_atom], availablility]
+ for x, satisfied in zip(deps, satisfieds):
+ if isinstance(x, list):
+ atoms = dep_zapdeps(x, satisfied, myroot,
+ use_binaries=use_binaries, trees=trees)
+ else:
+ atoms = [x]
+ if vardb is None:
+ # When called by repoman, we can simply return the first choice
+ # because dep_eval() handles preference selection.
+ return atoms
+
+ all_available = True
+ all_use_satisfied = True
+ slot_map = {}
+ cp_map = {}
+ for atom in atoms:
+ if atom.blocker:
+ continue
+ # Ignore USE dependencies here since we don't want USE
+ # settings to adversely affect || preference evaluation.
+ avail_pkg = mydbapi.match(atom.without_use)
+ if avail_pkg:
+ avail_pkg = avail_pkg[-1] # highest (ascending order)
+ avail_slot = Atom("%s:%s" % (atom.cp,
+ mydbapi.aux_get(avail_pkg, ["SLOT"])[0]))
+ if not avail_pkg:
+ all_available = False
+ all_use_satisfied = False
+ break
+
+ if atom.use:
+ avail_pkg_use = mydbapi.match(atom)
+ if not avail_pkg_use:
+ all_use_satisfied = False
+ else:
+ # highest (ascending order)
+ avail_pkg_use = avail_pkg_use[-1]
+ if avail_pkg_use != avail_pkg:
+ avail_pkg = avail_pkg_use
+ avail_slot = Atom("%s:%s" % (atom.cp,
+ mydbapi.aux_get(avail_pkg, ["SLOT"])[0]))
+
+ slot_map[avail_slot] = avail_pkg
+ pkg_cp = cpv_getkey(avail_pkg)
+ highest_cpv = cp_map.get(pkg_cp)
+ if highest_cpv is None or \
+ pkgcmp(catpkgsplit(avail_pkg)[1:],
+ catpkgsplit(highest_cpv)[1:]) > 0:
+ cp_map[pkg_cp] = avail_pkg
+
+ this_choice = (atoms, slot_map, cp_map, all_available)
+ if all_available:
+ # The "all installed" criterion is not version or slot specific.
+ # If any version of a package is already in the graph then we
+ # assume that it is preferred over other possible packages choices.
+ all_installed = True
+ for atom in set(Atom(atom.cp) for atom in atoms \
+ if not atom.blocker):
+ # New-style virtuals have zero cost to install.
+ if not vardb.match(atom) and not atom.startswith("virtual/"):
+ all_installed = False
+ break
+ all_installed_slots = False
+ if all_installed:
+ all_installed_slots = True
+ for slot_atom in slot_map:
+ # New-style virtuals have zero cost to install.
+ if not vardb.match(slot_atom) and \
+ not slot_atom.startswith("virtual/"):
+ all_installed_slots = False
+ break
+ if graph_db is None:
+ if all_use_satisfied:
+ if all_installed:
+ if all_installed_slots:
+ preferred_installed.append(this_choice)
+ else:
+ preferred_any_slot.append(this_choice)
+ else:
+ preferred_non_installed.append(this_choice)
+ else:
+ if all_installed_slots:
+ unsat_use_installed.append(this_choice)
+ else:
+ unsat_use_non_installed.append(this_choice)
+ else:
+ all_in_graph = True
+ for slot_atom in slot_map:
+ # New-style virtuals have zero cost to install.
+ if slot_atom.startswith("virtual/"):
+ continue
+ # We check if the matched package has actually been
+ # added to the digraph, in order to distinguish between
+ # those packages and installed packages that may need
+ # to be uninstalled in order to resolve blockers.
+ graph_matches = graph_db.match_pkgs(slot_atom)
+ if not graph_matches or graph_matches[-1] not in graph:
+ all_in_graph = False
+ break
+ circular_atom = None
+ if all_in_graph:
+ if parent is None or priority is None:
+ pass
+ elif priority.buildtime and \
+ not (priority.satisfied or priority.optional):
+ # Check if the atom would result in a direct circular
+ # dependency and try to avoid that if it seems likely
+ # to be unresolvable. This is only relevant for
+ # buildtime deps that aren't already satisfied by an
+ # installed package.
+ cpv_slot_list = [parent]
+ for atom in atoms:
+ if atom.blocker:
+ continue
+ if vardb.match(atom):
+ # If the atom is satisfied by an installed
+ # version then it's not a circular dep.
+ continue
+ if atom.cp != parent.cp:
+ continue
+ if match_from_list(atom, cpv_slot_list):
+ circular_atom = atom
+ break
+ if circular_atom is not None:
+ other.append(this_choice)
+ else:
+ if all_use_satisfied:
+ if all_in_graph:
+ preferred_in_graph.append(this_choice)
+ elif all_installed:
+ if all_installed_slots:
+ preferred_installed.append(this_choice)
+ else:
+ preferred_any_slot.append(this_choice)
+ else:
+ preferred_non_installed.append(this_choice)
+ else:
+ if all_in_graph:
+ unsat_use_in_graph.append(this_choice)
+ elif all_installed_slots:
+ unsat_use_installed.append(this_choice)
+ else:
+ unsat_use_non_installed.append(this_choice)
+ else:
+ all_installed = True
+ some_installed = False
+ for atom in atoms:
+ if not atom.blocker:
+ if vardb.match(atom):
+ some_installed = True
+ else:
+ all_installed = False
+
+ if all_installed:
+ other_installed.append(this_choice)
+ elif some_installed:
+ other_installed_some.append(this_choice)
+ else:
+ other.append(this_choice)
+
+ # Prefer choices which contain upgrades to higher slots. This helps
+ # for deps such as || ( foo:1 foo:2 ), where we want to prefer the
+ # atom which matches the higher version rather than the atom furthest
+ # to the left. Sorting is done separately for each of choice_bins, so
+ # as not to interfere with the ordering of the bins. Because of the
+ # bin separation, the main function of this code is to allow
+ # --depclean to remove old slots (rather than to pull in new slots).
+ for choices in choice_bins:
+ if len(choices) < 2:
+ continue
+ for choice_1 in choices[1:]:
+ atoms_1, slot_map_1, cp_map_1, all_available_1 = choice_1
+ cps = set(cp_map_1)
+ for choice_2 in choices:
+ if choice_1 is choice_2:
+ # choice_1 will not be promoted, so move on
+ break
+ atoms_2, slot_map_2, cp_map_2, all_available_2 = choice_2
+ intersecting_cps = cps.intersection(cp_map_2)
+ if not intersecting_cps:
+ continue
+ has_upgrade = False
+ has_downgrade = False
+ for cp in intersecting_cps:
+ version_1 = cp_map_1[cp]
+ version_2 = cp_map_2[cp]
+ difference = pkgcmp(catpkgsplit(version_1)[1:],
+ catpkgsplit(version_2)[1:])
+ if difference != 0:
+ if difference > 0:
+ has_upgrade = True
+ else:
+ has_downgrade = True
+ break
+ if has_upgrade and not has_downgrade:
+ # promote choice_1 in front of choice_2
+ choices.remove(choice_1)
+ index_2 = choices.index(choice_2)
+ choices.insert(index_2, choice_1)
+ break
+
+ for allow_masked in (False, True):
+ for choices in choice_bins:
+ for atoms, slot_map, cp_map, all_available in choices:
+ if all_available or allow_masked:
+ return atoms
+
+ assert(False) # This point should not be reachable
+
+def dep_check(depstring, mydbapi, mysettings, use="yes", mode=None, myuse=None,
+ use_cache=1, use_binaries=0, myroot="/", trees=None):
+ """Takes a depend string and parses the condition."""
+ edebug = mysettings.get("PORTAGE_DEBUG", None) == "1"
+ #check_config_instance(mysettings)
+ if trees is None:
+ trees = globals()["db"]
+ if use=="yes":
+ if myuse is None:
+ #default behavior
+ myusesplit = mysettings["PORTAGE_USE"].split()
+ else:
+ myusesplit = myuse
+ # We've been given useflags to use.
+ #print "USE FLAGS PASSED IN."
+ #print myuse
+ #if "bindist" in myusesplit:
+ # print "BINDIST is set!"
+ #else:
+ # print "BINDIST NOT set."
+ else:
+ #we are being run by autouse(), don't consult USE vars yet.
+ # WE ALSO CANNOT USE SETTINGS
+ myusesplit=[]
+
+ mymasks = set()
+ useforce = set()
+ useforce.add(mysettings["ARCH"])
+ if use == "all":
+ # This masking/forcing is only for repoman. In other cases, relevant
+ # masking/forcing should have already been applied via
+ # config.regenerate(). Also, binary or installed packages may have
+ # been built with flags that are now masked, and it would be
+ # inconsistent to mask them now. Additionally, myuse may consist of
+ # flags from a parent package that is being merged to a $ROOT that is
+ # different from the one that mysettings represents.
+ mymasks.update(mysettings.usemask)
+ mymasks.update(mysettings.archlist())
+ mymasks.discard(mysettings["ARCH"])
+ useforce.update(mysettings.useforce)
+ useforce.difference_update(mymasks)
+
+ # eapi code borrowed from _expand_new_virtuals()
+ mytrees = trees[myroot]
+ parent = mytrees.get("parent")
+ virt_parent = mytrees.get("virt_parent")
+ current_parent = None
+ eapi = None
+ if parent is not None:
+ if virt_parent is not None:
+ current_parent = virt_parent
+ else:
+ current_parent = parent
+
+ if current_parent is not None:
+ # Don't pass the eapi argument to use_reduce() for installed packages
+ # since previous validation will have already marked them as invalid
+ # when necessary and now we're more interested in evaluating
+ # dependencies so that things like --depclean work as well as possible
+ # in spite of partial invalidity.
+ if not current_parent.installed:
+ eapi = current_parent.metadata['EAPI']
+
+ try:
+ mysplit = use_reduce(depstring, uselist=myusesplit, masklist=mymasks, \
+ matchall=(use=="all"), excludeall=useforce, opconvert=True, \
+ token_class=Atom, eapi=eapi)
+ except InvalidDependString as e:
+ return [0, _unicode_decode("%s") % (e,)]
+
+ if mysplit == []:
+ #dependencies were reduced to nothing
+ return [1,[]]
+
+ # Recursively expand new-style virtuals so as to
+ # collapse one or more levels of indirection.
+ try:
+ mysplit = _expand_new_virtuals(mysplit, edebug, mydbapi, mysettings,
+ use=use, mode=mode, myuse=myuse,
+ use_force=useforce, use_mask=mymasks, use_cache=use_cache,
+ use_binaries=use_binaries, myroot=myroot, trees=trees)
+ except ParseError as e:
+ return [0, _unicode_decode("%s") % (e,)]
+
+ mysplit2=mysplit[:]
+ mysplit2=dep_wordreduce(mysplit2,mysettings,mydbapi,mode,use_cache=use_cache)
+ if mysplit2 is None:
+ return [0, _("Invalid token")]
+
+ writemsg("\n\n\n", 1)
+ writemsg("mysplit: %s\n" % (mysplit), 1)
+ writemsg("mysplit2: %s\n" % (mysplit2), 1)
+
+ selected_atoms = dep_zapdeps(mysplit, mysplit2, myroot,
+ use_binaries=use_binaries, trees=trees)
+
+ return [1, selected_atoms]
+
+def dep_wordreduce(mydeplist,mysettings,mydbapi,mode,use_cache=1):
+ "Reduces the deplist to ones and zeros"
+ deplist=mydeplist[:]
+ for mypos, token in enumerate(deplist):
+ if isinstance(deplist[mypos], list):
+ #recurse
+ deplist[mypos]=dep_wordreduce(deplist[mypos],mysettings,mydbapi,mode,use_cache=use_cache)
+ elif deplist[mypos]=="||":
+ pass
+ elif token[:1] == "!":
+ deplist[mypos] = False
+ else:
+ mykey = deplist[mypos].cp
+ if mysettings and mykey in mysettings.pprovideddict and \
+ match_from_list(deplist[mypos], mysettings.pprovideddict[mykey]):
+ deplist[mypos]=True
+ elif mydbapi is None:
+ # Assume nothing is satisfied. This forces dep_zapdeps to
+ # return all of deps the deps that have been selected
+ # (excluding those satisfied by package.provided).
+ deplist[mypos] = False
+ else:
+ if mode:
+ x = mydbapi.xmatch(mode, deplist[mypos])
+ if mode.startswith("minimum-"):
+ mydep = []
+ if x:
+ mydep.append(x)
+ else:
+ mydep = x
+ else:
+ mydep=mydbapi.match(deplist[mypos],use_cache=use_cache)
+ if mydep!=None:
+ tmp=(len(mydep)>=1)
+ if deplist[mypos][0]=="!":
+ tmp=False
+ deplist[mypos]=tmp
+ else:
+ #encountered invalid string
+ return None
+ return deplist
diff --git a/portage_with_autodep/pym/portage/dispatch_conf.py b/portage_with_autodep/pym/portage/dispatch_conf.py
new file mode 100644
index 0000000..4991020
--- /dev/null
+++ b/portage_with_autodep/pym/portage/dispatch_conf.py
@@ -0,0 +1,188 @@
+# archive_conf.py -- functionality common to archive-conf and dispatch-conf
+# Copyright 2003-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+
+# Library by Wayne Davison <gentoo@blorf.net>, derived from code
+# written by Jeremy Wohl (http://igmus.org)
+
+from __future__ import print_function
+
+import os, sys, shutil
+
+import portage
+from portage.env.loaders import KeyValuePairFileLoader
+from portage.localization import _
+
+RCS_BRANCH = '1.1.1'
+RCS_LOCK = 'rcs -ko -M -l'
+RCS_PUT = 'ci -t-"Archived config file." -m"dispatch-conf update."'
+RCS_GET = 'co'
+RCS_MERGE = "rcsmerge -p -r" + RCS_BRANCH + " '%s' > '%s'"
+
+DIFF3_MERGE = "diff3 -mE '%s' '%s' '%s' > '%s'"
+
+def diffstatusoutput_len(cmd):
+ """
+ Execute the string cmd in a shell with getstatusoutput() and return a
+ 2-tuple (status, output_length). If getstatusoutput() raises
+ UnicodeDecodeError (known to happen with python3.1), return a
+ 2-tuple (1, 1). This provides a simple way to check for non-zero
+ output length of diff commands, while providing simple handling of
+ UnicodeDecodeError when necessary.
+ """
+ try:
+ status, output = portage.subprocess_getstatusoutput(cmd)
+ return (status, len(output))
+ except UnicodeDecodeError:
+ return (1, 1)
+
+def read_config(mandatory_opts):
+ loader = KeyValuePairFileLoader(
+ '/etc/dispatch-conf.conf', None)
+ opts, errors = loader.load()
+ if not opts:
+ print(_('dispatch-conf: Error reading /etc/dispatch-conf.conf; fatal'), file=sys.stderr)
+ sys.exit(1)
+
+ # Handle quote removal here, since KeyValuePairFileLoader doesn't do that.
+ quotes = "\"'"
+ for k, v in opts.items():
+ if v[:1] in quotes and v[:1] == v[-1:]:
+ opts[k] = v[1:-1]
+
+ for key in mandatory_opts:
+ if key not in opts:
+ if key == "merge":
+ opts["merge"] = "sdiff --suppress-common-lines --output='%s' '%s' '%s'"
+ else:
+ print(_('dispatch-conf: Missing option "%s" in /etc/dispatch-conf.conf; fatal') % (key,), file=sys.stderr)
+
+ if not os.path.exists(opts['archive-dir']):
+ os.mkdir(opts['archive-dir'])
+ # Use restrictive permissions by default, in order to protect
+ # against vulnerabilities (like bug #315603 involving rcs).
+ os.chmod(opts['archive-dir'], 0o700)
+ elif not os.path.isdir(opts['archive-dir']):
+ print(_('dispatch-conf: Config archive dir [%s] must exist; fatal') % (opts['archive-dir'],), file=sys.stderr)
+ sys.exit(1)
+
+ return opts
+
+
+def rcs_archive(archive, curconf, newconf, mrgconf):
+ """Archive existing config in rcs (on trunk). Then, if mrgconf is
+ specified and an old branch version exists, merge the user's changes
+ and the distributed changes and put the result into mrgconf. Lastly,
+ if newconf was specified, leave it in the archive dir with a .dist.new
+ suffix along with the last 1.1.1 branch version with a .dist suffix."""
+
+ try:
+ os.makedirs(os.path.dirname(archive))
+ except OSError:
+ pass
+
+ if os.path.isfile(curconf):
+ try:
+ shutil.copy2(curconf, archive)
+ except(IOError, os.error) as why:
+ print(_('dispatch-conf: Error copying %(curconf)s to %(archive)s: %(reason)s; fatal') % \
+ {"curconf": curconf, "archive": archive, "reason": str(why)}, file=sys.stderr)
+
+ if os.path.exists(archive + ',v'):
+ os.system(RCS_LOCK + ' ' + archive)
+ os.system(RCS_PUT + ' ' + archive)
+
+ ret = 0
+ if newconf != '':
+ os.system(RCS_GET + ' -r' + RCS_BRANCH + ' ' + archive)
+ has_branch = os.path.exists(archive)
+ if has_branch:
+ os.rename(archive, archive + '.dist')
+
+ try:
+ shutil.copy2(newconf, archive)
+ except(IOError, os.error) as why:
+ print(_('dispatch-conf: Error copying %(newconf)s to %(archive)s: %(reason)s; fatal') % \
+ {"newconf": newconf, "archive": archive, "reason": str(why)}, file=sys.stderr)
+
+ if has_branch:
+ if mrgconf != '':
+ # This puts the results of the merge into mrgconf.
+ ret = os.system(RCS_MERGE % (archive, mrgconf))
+ mystat = os.lstat(newconf)
+ os.chmod(mrgconf, mystat.st_mode)
+ os.chown(mrgconf, mystat.st_uid, mystat.st_gid)
+ os.rename(archive, archive + '.dist.new')
+ return ret
+
+
+def file_archive(archive, curconf, newconf, mrgconf):
+ """Archive existing config to the archive-dir, bumping old versions
+ out of the way into .# versions (log-rotate style). Then, if mrgconf
+ was specified and there is a .dist version, merge the user's changes
+ and the distributed changes and put the result into mrgconf. Lastly,
+ if newconf was specified, archive it as a .dist.new version (which
+ gets moved to the .dist version at the end of the processing)."""
+
+ try:
+ os.makedirs(os.path.dirname(archive))
+ except OSError:
+ pass
+
+ # Archive the current config file if it isn't already saved
+ if os.path.exists(archive) \
+ and diffstatusoutput_len("diff -aq '%s' '%s'" % (curconf,archive))[1] != 0:
+ suf = 1
+ while suf < 9 and os.path.exists(archive + '.' + str(suf)):
+ suf += 1
+
+ while suf > 1:
+ os.rename(archive + '.' + str(suf-1), archive + '.' + str(suf))
+ suf -= 1
+
+ os.rename(archive, archive + '.1')
+
+ if os.path.isfile(curconf):
+ try:
+ shutil.copy2(curconf, archive)
+ except(IOError, os.error) as why:
+ print(_('dispatch-conf: Error copying %(curconf)s to %(archive)s: %(reason)s; fatal') % \
+ {"curconf": curconf, "archive": archive, "reason": str(why)}, file=sys.stderr)
+
+ if newconf != '':
+ # Save off new config file in the archive dir with .dist.new suffix
+ try:
+ shutil.copy2(newconf, archive + '.dist.new')
+ except(IOError, os.error) as why:
+ print(_('dispatch-conf: Error copying %(newconf)s to %(archive)s: %(reason)s; fatal') % \
+ {"newconf": newconf, "archive": archive + '.dist.new', "reason": str(why)}, file=sys.stderr)
+
+ ret = 0
+ if mrgconf != '' and os.path.exists(archive + '.dist'):
+ # This puts the results of the merge into mrgconf.
+ ret = os.system(DIFF3_MERGE % (curconf, archive + '.dist', newconf, mrgconf))
+ mystat = os.lstat(newconf)
+ os.chmod(mrgconf, mystat.st_mode)
+ os.chown(mrgconf, mystat.st_uid, mystat.st_gid)
+
+ return ret
+
+
+def rcs_archive_post_process(archive):
+ """Check in the archive file with the .dist.new suffix on the branch
+ and remove the one with the .dist suffix."""
+ os.rename(archive + '.dist.new', archive)
+ if os.path.exists(archive + '.dist'):
+ # Commit the last-distributed version onto the branch.
+ os.system(RCS_LOCK + RCS_BRANCH + ' ' + archive)
+ os.system(RCS_PUT + ' -r' + RCS_BRANCH + ' ' + archive)
+ os.unlink(archive + '.dist')
+ else:
+ # Forcefully commit the last-distributed version onto the branch.
+ os.system(RCS_PUT + ' -f -r' + RCS_BRANCH + ' ' + archive)
+
+
+def file_archive_post_process(archive):
+ """Rename the archive file with the .dist.new suffix to a .dist suffix"""
+ os.rename(archive + '.dist.new', archive + '.dist')
diff --git a/portage_with_autodep/pym/portage/eapi.py b/portage_with_autodep/pym/portage/eapi.py
new file mode 100644
index 0000000..da5fd8c
--- /dev/null
+++ b/portage_with_autodep/pym/portage/eapi.py
@@ -0,0 +1,50 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+def eapi_has_iuse_defaults(eapi):
+ return eapi != "0"
+
+def eapi_has_slot_deps(eapi):
+ return eapi != "0"
+
+def eapi_has_src_uri_arrows(eapi):
+ return eapi not in ("0", "1")
+
+def eapi_has_use_deps(eapi):
+ return eapi not in ("0", "1")
+
+def eapi_has_strong_blocks(eapi):
+ return eapi not in ("0", "1")
+
+def eapi_has_src_prepare_and_src_configure(eapi):
+ return eapi not in ("0", "1")
+
+def eapi_supports_prefix(eapi):
+ return eapi not in ("0", "1", "2")
+
+def eapi_exports_AA(eapi):
+ return eapi in ("0", "1", "2", "3")
+
+def eapi_exports_KV(eapi):
+ return eapi in ("0", "1", "2", "3")
+
+def eapi_exports_merge_type(eapi):
+ return eapi not in ("0", "1", "2", "3")
+
+def eapi_exports_replace_vars(eapi):
+ return eapi not in ("0", "1", "2", "3")
+
+def eapi_has_pkg_pretend(eapi):
+ return eapi not in ("0", "1", "2", "3")
+
+def eapi_has_implicit_rdepend(eapi):
+ return eapi in ("0", "1", "2", "3")
+
+def eapi_has_dosed_dohard(eapi):
+ return eapi in ("0", "1", "2", "3")
+
+def eapi_has_required_use(eapi):
+ return eapi not in ("0", "1", "2", "3")
+
+def eapi_has_use_dep_defaults(eapi):
+ return eapi not in ("0", "1", "2", "3")
diff --git a/portage_with_autodep/pym/portage/eclass_cache.py b/portage_with_autodep/pym/portage/eclass_cache.py
new file mode 100644
index 0000000..1374f1d
--- /dev/null
+++ b/portage_with_autodep/pym/portage/eclass_cache.py
@@ -0,0 +1,123 @@
+# Copyright 2005-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# Author(s): Nicholas Carpaski (carpaski@gentoo.org), Brian Harring (ferringb@gentoo.org)
+
+__all__ = ["cache"]
+
+import stat
+import sys
+from portage.util import normalize_path
+import errno
+from portage.exception import PermissionDenied
+from portage import os
+
+if sys.hexversion >= 0x3000000:
+ long = int
+
+class cache(object):
+ """
+ Maintains the cache information about eclasses used in ebuild.
+ """
+ def __init__(self, porttree_root, overlays=[]):
+
+ self.eclasses = {} # {"Name": ("location","_mtime_")}
+ self._eclass_locations = {}
+
+ # screw with the porttree ordering, w/out having bash inherit match it, and I'll hurt you.
+ # ~harring
+ if porttree_root:
+ self.porttree_root = porttree_root
+ self.porttrees = [self.porttree_root] + overlays
+ self.porttrees = tuple(map(normalize_path, self.porttrees))
+ self._master_eclass_root = os.path.join(self.porttrees[0], "eclass")
+ self.update_eclasses()
+ else:
+ self.porttree_root = None
+ self.porttrees = ()
+ self._master_eclass_root = None
+
+ def copy(self):
+ return self.__copy__()
+
+ def __copy__(self):
+ result = self.__class__(None)
+ result.eclasses = self.eclasses.copy()
+ result._eclass_locations = self._eclass_locations.copy()
+ result.porttree_root = self.porttree_root
+ result.porttrees = self.porttrees
+ result._master_eclass_root = self._master_eclass_root
+ return result
+
+ def append(self, other):
+ """
+ Append another instance to this instance. This will cause eclasses
+ from the other instance to override any eclasses from this instance
+ that have the same name.
+ """
+ if not isinstance(other, self.__class__):
+ raise TypeError(
+ "expected type %s, got %s" % (self.__class__, type(other)))
+ self.porttrees = self.porttrees + other.porttrees
+ self.eclasses.update(other.eclasses)
+ self._eclass_locations.update(other._eclass_locations)
+
+ def update_eclasses(self):
+ self.eclasses = {}
+ self._eclass_locations = {}
+ master_eclasses = {}
+ eclass_len = len(".eclass")
+ ignored_listdir_errnos = (errno.ENOENT, errno.ENOTDIR)
+ for x in [normalize_path(os.path.join(y,"eclass")) for y in self.porttrees]:
+ try:
+ eclass_filenames = os.listdir(x)
+ except OSError as e:
+ if e.errno in ignored_listdir_errnos:
+ del e
+ continue
+ elif e.errno == PermissionDenied.errno:
+ raise PermissionDenied(x)
+ raise
+ for y in eclass_filenames:
+ if not y.endswith(".eclass"):
+ continue
+ try:
+ mtime = os.stat(os.path.join(x, y))[stat.ST_MTIME]
+ except OSError:
+ continue
+ ys=y[:-eclass_len]
+ if x == self._master_eclass_root:
+ master_eclasses[ys] = mtime
+ self.eclasses[ys] = (x, mtime)
+ self._eclass_locations[ys] = x
+ continue
+
+ master_mtime = master_eclasses.get(ys)
+ if master_mtime is not None:
+ if master_mtime == mtime:
+ # It appears to be identical to the master,
+ # so prefer the master entry.
+ continue
+
+ self.eclasses[ys] = (x, mtime)
+ self._eclass_locations[ys] = x
+
+ def is_eclass_data_valid(self, ec_dict):
+ if not isinstance(ec_dict, dict):
+ return False
+ for eclass, tup in ec_dict.items():
+ cached_data = self.eclasses.get(eclass, None)
+ """ Only use the mtime for validation since the probability of a
+ collision is small and, depending on the cache implementation, the
+ path may not be specified (cache from rsync mirrors, for example).
+ """
+ if cached_data is None or tup[1] != cached_data[1]:
+ return False
+
+ return True
+
+ def get_eclass_data(self, inherits):
+ ec_dict = {}
+ for x in inherits:
+ ec_dict[x] = self.eclasses[x]
+
+ return ec_dict
diff --git a/portage_with_autodep/pym/portage/elog/__init__.py b/portage_with_autodep/pym/portage/elog/__init__.py
new file mode 100644
index 0000000..1a8309d
--- /dev/null
+++ b/portage_with_autodep/pym/portage/elog/__init__.py
@@ -0,0 +1,182 @@
+# elog/__init__.py - elog core functions
+# Copyright 2006-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.util:writemsg',
+)
+
+from portage.const import EBUILD_PHASES
+from portage.exception import AlarmSignal, PortageException
+from portage.process import atexit_register
+from portage.elog.messages import collect_ebuild_messages, collect_messages
+from portage.elog.filtering import filter_loglevels
+from portage.localization import _
+from portage import os
+
+def _preload_elog_modules(settings):
+ logsystems = settings.get("PORTAGE_ELOG_SYSTEM", "").split()
+ for s in logsystems:
+ # allow per module overrides of PORTAGE_ELOG_CLASSES
+ if ":" in s:
+ s, levels = s.split(":", 1)
+ levels = levels.split(",")
+ # - is nicer than _ for module names, so allow people to use it.
+ s = s.replace("-", "_")
+ try:
+ _load_mod("portage.elog.mod_" + s)
+ except ImportError:
+ pass
+
+def _merge_logentries(a, b):
+ rValue = {}
+ phases = set(a)
+ phases.update(b)
+ for p in phases:
+ merged_msgs = []
+ rValue[p] = merged_msgs
+ for d in a, b:
+ msgs = d.get(p)
+ if msgs:
+ merged_msgs.extend(msgs)
+ return rValue
+
+def _combine_logentries(logentries):
+ # generate a single string with all log messages
+ rValue = []
+ for phase in EBUILD_PHASES:
+ if not phase in logentries:
+ continue
+ previous_type = None
+ for msgtype, msgcontent in logentries[phase]:
+ if previous_type != msgtype:
+ previous_type = msgtype
+ rValue.append("%s: %s\n" % (msgtype, phase))
+ for line in msgcontent:
+ rValue.append(line)
+ rValue.append("\n")
+ return "".join(rValue)
+
+_elog_mod_imports = {}
+def _load_mod(name):
+ global _elog_mod_imports
+ m = _elog_mod_imports.get(name)
+ if m is None:
+ m = __import__(name)
+ for comp in name.split(".")[1:]:
+ m = getattr(m, comp)
+ _elog_mod_imports[name] = m
+ return m
+
+_elog_listeners = []
+def add_listener(listener):
+ '''
+ Listeners should accept four arguments: settings, key, logentries and logtext
+ '''
+ _elog_listeners.append(listener)
+
+def remove_listener(listener):
+ '''
+ Remove previously added listener
+ '''
+ _elog_listeners.remove(listener)
+
+_elog_atexit_handlers = []
+
+def elog_process(cpv, mysettings, phasefilter=None):
+ global _elog_atexit_handlers
+
+ logsystems = mysettings.get("PORTAGE_ELOG_SYSTEM","").split()
+ for s in logsystems:
+ # allow per module overrides of PORTAGE_ELOG_CLASSES
+ if ":" in s:
+ s, levels = s.split(":", 1)
+ levels = levels.split(",")
+ # - is nicer than _ for module names, so allow people to use it.
+ s = s.replace("-", "_")
+ try:
+ _load_mod("portage.elog.mod_" + s)
+ except ImportError:
+ pass
+
+ if "T" in mysettings:
+ ebuild_logentries = collect_ebuild_messages(
+ os.path.join(mysettings["T"], "logging"))
+ else:
+ # A build dir isn't necessarily required since the messages.e*
+ # functions allow messages to be generated in-memory.
+ ebuild_logentries = {}
+ all_logentries = collect_messages(key=cpv, phasefilter=phasefilter)
+ if cpv in all_logentries:
+ # Messages generated by the python elog implementation are assumed
+ # to come first. For example, this ensures correct order for einfo
+ # messages that are generated prior to the setup phase.
+ all_logentries[cpv] = \
+ _merge_logentries(all_logentries[cpv], ebuild_logentries)
+ else:
+ all_logentries[cpv] = ebuild_logentries
+
+ my_elog_classes = set(mysettings.get("PORTAGE_ELOG_CLASSES", "").split())
+ logsystems = {}
+ for token in mysettings.get("PORTAGE_ELOG_SYSTEM", "").split():
+ if ":" in token:
+ s, levels = token.split(":", 1)
+ levels = levels.split(",")
+ else:
+ s = token
+ levels = ()
+ levels_set = logsystems.get(s)
+ if levels_set is None:
+ levels_set = set()
+ logsystems[s] = levels_set
+ levels_set.update(levels)
+
+ for key in all_logentries:
+ default_logentries = filter_loglevels(all_logentries[key], my_elog_classes)
+
+ # in case the filters matched all messages and no module overrides exist
+ if len(default_logentries) == 0 and (not ":" in mysettings.get("PORTAGE_ELOG_SYSTEM", "")):
+ continue
+
+ default_fulllog = _combine_logentries(default_logentries)
+
+ # call listeners
+ for listener in _elog_listeners:
+ listener(mysettings, str(key), default_logentries, default_fulllog)
+
+ # pass the processing to the individual modules
+ for s, levels in logsystems.items():
+ # allow per module overrides of PORTAGE_ELOG_CLASSES
+ if levels:
+ mod_logentries = filter_loglevels(all_logentries[key], levels)
+ mod_fulllog = _combine_logentries(mod_logentries)
+ else:
+ mod_logentries = default_logentries
+ mod_fulllog = default_fulllog
+ if len(mod_logentries) == 0:
+ continue
+ # - is nicer than _ for module names, so allow people to use it.
+ s = s.replace("-", "_")
+ try:
+ m = _load_mod("portage.elog.mod_" + s)
+ # Timeout after one minute (in case something like the mail
+ # module gets hung).
+ try:
+ AlarmSignal.register(60)
+ m.process(mysettings, str(key), mod_logentries, mod_fulllog)
+ finally:
+ AlarmSignal.unregister()
+ if hasattr(m, "finalize") and not m.finalize in _elog_atexit_handlers:
+ _elog_atexit_handlers.append(m.finalize)
+ atexit_register(m.finalize)
+ except (ImportError, AttributeError) as e:
+ writemsg(_("!!! Error while importing logging modules "
+ "while loading \"mod_%s\":\n") % str(s))
+ writemsg("%s\n" % str(e), noiselevel=-1)
+ except AlarmSignal:
+ writemsg("Timeout in elog_process for system '%s'\n" % s,
+ noiselevel=-1)
+ except PortageException as e:
+ writemsg("%s\n" % str(e), noiselevel=-1)
+
diff --git a/portage_with_autodep/pym/portage/elog/filtering.py b/portage_with_autodep/pym/portage/elog/filtering.py
new file mode 100644
index 0000000..82181a4
--- /dev/null
+++ b/portage_with_autodep/pym/portage/elog/filtering.py
@@ -0,0 +1,15 @@
+# elog/messages.py - elog core functions
+# Copyright 2006-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+def filter_loglevels(logentries, loglevels):
+ # remove unwanted entries from all logentries
+ rValue = {}
+ loglevels = [x.upper() for x in loglevels]
+ for phase in logentries:
+ for msgtype, msgcontent in logentries[phase]:
+ if msgtype.upper() in loglevels or "*" in loglevels:
+ if phase not in rValue:
+ rValue[phase] = []
+ rValue[phase].append((msgtype, msgcontent))
+ return rValue
diff --git a/portage_with_autodep/pym/portage/elog/messages.py b/portage_with_autodep/pym/portage/elog/messages.py
new file mode 100644
index 0000000..6c1580a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/elog/messages.py
@@ -0,0 +1,172 @@
+# elog/messages.py - elog core functions
+# Copyright 2006-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.output:colorize',
+ 'portage.util:writemsg',
+)
+
+from portage.const import EBUILD_PHASES
+from portage.localization import _
+from portage import os
+from portage import _encodings
+from portage import _unicode_encode
+from portage import _unicode_decode
+
+import io
+import sys
+
+def collect_ebuild_messages(path):
+ """ Collect elog messages generated by the bash logging function stored
+ at 'path'.
+ """
+ mylogfiles = None
+ try:
+ mylogfiles = os.listdir(path)
+ except OSError:
+ pass
+ # shortcut for packages without any messages
+ if not mylogfiles:
+ return {}
+ # exploit listdir() file order so we process log entries in chronological order
+ mylogfiles.reverse()
+ logentries = {}
+ for msgfunction in mylogfiles:
+ filename = os.path.join(path, msgfunction)
+ if msgfunction not in EBUILD_PHASES:
+ writemsg(_("!!! can't process invalid log file: %s\n") % filename,
+ noiselevel=-1)
+ continue
+ if not msgfunction in logentries:
+ logentries[msgfunction] = []
+ lastmsgtype = None
+ msgcontent = []
+ for l in io.open(_unicode_encode(filename,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'], errors='replace'):
+ if not l:
+ continue
+ try:
+ msgtype, msg = l.split(" ", 1)
+ except ValueError:
+ writemsg(_("!!! malformed entry in "
+ "log file: '%s'\n") % filename, noiselevel=-1)
+ continue
+
+ if lastmsgtype is None:
+ lastmsgtype = msgtype
+
+ if msgtype == lastmsgtype:
+ msgcontent.append(msg)
+ else:
+ if msgcontent:
+ logentries[msgfunction].append((lastmsgtype, msgcontent))
+ msgcontent = [msg]
+ lastmsgtype = msgtype
+ if msgcontent:
+ logentries[msgfunction].append((lastmsgtype, msgcontent))
+
+ # clean logfiles to avoid repetitions
+ for f in mylogfiles:
+ try:
+ os.unlink(os.path.join(path, f))
+ except OSError:
+ pass
+ return logentries
+
+_msgbuffer = {}
+def _elog_base(level, msg, phase="other", key=None, color=None, out=None):
+ """ Backend for the other messaging functions, should not be called
+ directly.
+ """
+
+ # TODO: Have callers pass in a more unique 'key' parameter than a plain
+ # cpv, in order to ensure that messages are properly grouped together
+ # for a given package instance, and also to ensure that each elog module's
+ # process() function is only called once for each unique package. This is
+ # needed not only when building packages in parallel, but also to preserve
+ # continuity in messages when a package is simply updated, since we don't
+ # want the elog_process() call from the uninstall of the old version to
+ # cause discontinuity in the elog messages of the new one being installed.
+
+ global _msgbuffer
+
+ if out is None:
+ out = sys.stdout
+
+ if color is None:
+ color = "GOOD"
+
+ msg = _unicode_decode(msg,
+ encoding=_encodings['content'], errors='replace')
+
+ formatted_msg = colorize(color, " * ") + msg + "\n"
+
+ # avoid potential UnicodeEncodeError
+ if out in (sys.stdout, sys.stderr):
+ formatted_msg = _unicode_encode(formatted_msg,
+ encoding=_encodings['stdio'], errors='backslashreplace')
+ if sys.hexversion >= 0x3000000:
+ out = out.buffer
+
+ out.write(formatted_msg)
+
+ if key not in _msgbuffer:
+ _msgbuffer[key] = {}
+ if phase not in _msgbuffer[key]:
+ _msgbuffer[key][phase] = []
+ _msgbuffer[key][phase].append((level, msg))
+
+ #raise NotImplementedError()
+
+def collect_messages(key=None, phasefilter=None):
+ global _msgbuffer
+
+ if key is None:
+ rValue = _msgbuffer
+ _reset_buffer()
+ else:
+ rValue = {}
+ if key in _msgbuffer:
+ if phasefilter is None:
+ rValue[key] = _msgbuffer.pop(key)
+ else:
+ rValue[key] = {}
+ for phase in phasefilter:
+ try:
+ rValue[key][phase] = _msgbuffer[key].pop(phase)
+ except KeyError:
+ pass
+ if not _msgbuffer[key]:
+ del _msgbuffer[key]
+ return rValue
+
+def _reset_buffer():
+ """ Reset the internal message buffer when it has been processed,
+ should not be called directly.
+ """
+ global _msgbuffer
+
+ _msgbuffer = {}
+
+# creating and exporting the actual messaging functions
+_functions = { "einfo": ("INFO", "GOOD"),
+ "elog": ("LOG", "GOOD"),
+ "ewarn": ("WARN", "WARN"),
+ "eqawarn": ("QA", "WARN"),
+ "eerror": ("ERROR", "BAD"),
+}
+
+def _make_msgfunction(level, color):
+ def _elog(msg, phase="other", key=None, out=None):
+ """ Display and log a message assigned to the given key/cpv
+ (or unassigned if no key is given).
+ """
+ _elog_base(level, msg, phase=phase, key=key, color=color, out=out)
+ return _elog
+
+for f in _functions:
+ setattr(sys.modules[__name__], f, _make_msgfunction(_functions[f][0], _functions[f][1]))
+del f, _functions
diff --git a/portage_with_autodep/pym/portage/elog/mod_custom.py b/portage_with_autodep/pym/portage/elog/mod_custom.py
new file mode 100644
index 0000000..e1a5223
--- /dev/null
+++ b/portage_with_autodep/pym/portage/elog/mod_custom.py
@@ -0,0 +1,19 @@
+# elog/mod_custom.py - elog dispatch module
+# Copyright 2006-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import portage.elog.mod_save, portage.process, portage.exception
+
+def process(mysettings, key, logentries, fulltext):
+ elogfilename = portage.elog.mod_save.process(mysettings, key, logentries, fulltext)
+
+ if not mysettings.get("PORTAGE_ELOG_COMMAND"):
+ raise portage.exception.MissingParameter("!!! Custom logging requested but PORTAGE_ELOG_COMMAND is not defined")
+ else:
+ mylogcmd = mysettings["PORTAGE_ELOG_COMMAND"]
+ mylogcmd = mylogcmd.replace("${LOGFILE}", elogfilename)
+ mylogcmd = mylogcmd.replace("${PACKAGE}", key)
+ retval = portage.process.spawn_bash(mylogcmd)
+ if retval != 0:
+ raise portage.exception.PortageException("!!! PORTAGE_ELOG_COMMAND failed with exitcode %d" % retval)
+ return
diff --git a/portage_with_autodep/pym/portage/elog/mod_echo.py b/portage_with_autodep/pym/portage/elog/mod_echo.py
new file mode 100644
index 0000000..5de25bf
--- /dev/null
+++ b/portage_with_autodep/pym/portage/elog/mod_echo.py
@@ -0,0 +1,46 @@
+# elog/mod_echo.py - elog dispatch module
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import sys
+from portage.output import EOutput, colorize
+from portage.const import EBUILD_PHASES
+from portage.localization import _
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+_items = []
+def process(mysettings, key, logentries, fulltext):
+ global _items
+ _items.append((mysettings["ROOT"], key, logentries))
+
+def finalize():
+ global _items
+ printer = EOutput()
+ for root, key, logentries in _items:
+ print()
+ if root == "/":
+ printer.einfo(_("Messages for package %s:") %
+ colorize("INFORM", key))
+ else:
+ printer.einfo(_("Messages for package %(pkg)s merged to %(root)s:") %
+ {"pkg": colorize("INFORM", key), "root": root})
+ print()
+ for phase in EBUILD_PHASES:
+ if phase not in logentries:
+ continue
+ for msgtype, msgcontent in logentries[phase]:
+ fmap = {"INFO": printer.einfo,
+ "WARN": printer.ewarn,
+ "ERROR": printer.eerror,
+ "LOG": printer.einfo,
+ "QA": printer.ewarn}
+ if isinstance(msgcontent, basestring):
+ msgcontent = [msgcontent]
+ for line in msgcontent:
+ fmap[msgtype](line.strip("\n"))
+ _items = []
+ return
diff --git a/portage_with_autodep/pym/portage/elog/mod_mail.py b/portage_with_autodep/pym/portage/elog/mod_mail.py
new file mode 100644
index 0000000..086c683
--- /dev/null
+++ b/portage_with_autodep/pym/portage/elog/mod_mail.py
@@ -0,0 +1,43 @@
+# elog/mod_mail.py - elog dispatch module
+# Copyright 2006-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import portage.mail, socket
+from portage.exception import PortageException
+from portage.localization import _
+from portage.util import writemsg
+
+def process(mysettings, key, logentries, fulltext):
+ if "PORTAGE_ELOG_MAILURI" in mysettings:
+ myrecipient = mysettings["PORTAGE_ELOG_MAILURI"].split()[0]
+ else:
+ myrecipient = "root@localhost"
+
+ myfrom = mysettings["PORTAGE_ELOG_MAILFROM"]
+ myfrom = myfrom.replace("${HOST}", socket.getfqdn())
+ mysubject = mysettings["PORTAGE_ELOG_MAILSUBJECT"]
+ mysubject = mysubject.replace("${PACKAGE}", key)
+ mysubject = mysubject.replace("${HOST}", socket.getfqdn())
+
+ # look at the phases listed in our logentries to figure out what action was performed
+ action = _("merged")
+ for phase in logentries:
+ # if we found a *rm phase assume that the package was unmerged
+ if phase in ["postrm", "prerm"]:
+ action = _("unmerged")
+ # if we think that the package was unmerged, make sure there was no unexpected
+ # phase recorded to avoid misinformation
+ if action == _("unmerged"):
+ for phase in logentries:
+ if phase not in ["postrm", "prerm", "other"]:
+ action = _("unknown")
+
+ mysubject = mysubject.replace("${ACTION}", action)
+
+ mymessage = portage.mail.create_message(myfrom, myrecipient, mysubject, fulltext)
+ try:
+ portage.mail.send_mail(mysettings, mymessage)
+ except PortageException as e:
+ writemsg("%s\n" % str(e), noiselevel=-1)
+
+ return
diff --git a/portage_with_autodep/pym/portage/elog/mod_mail_summary.py b/portage_with_autodep/pym/portage/elog/mod_mail_summary.py
new file mode 100644
index 0000000..0bd67f2
--- /dev/null
+++ b/portage_with_autodep/pym/portage/elog/mod_mail_summary.py
@@ -0,0 +1,89 @@
+# elog/mod_mail_summary.py - elog dispatch module
+# Copyright 2006-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import portage
+from portage.exception import AlarmSignal, PortageException
+from portage.localization import _
+from portage.util import writemsg
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+
+import socket
+import time
+
+_config_keys = ('PORTAGE_ELOG_MAILURI', 'PORTAGE_ELOG_MAILFROM',
+ 'PORTAGE_ELOG_MAILSUBJECT',)
+_items = {}
+def process(mysettings, key, logentries, fulltext):
+ global _items
+ time_str = _unicode_decode(
+ time.strftime("%Y%m%d-%H%M%S %Z", time.localtime(time.time())),
+ encoding=_encodings['content'], errors='replace')
+ header = _(">>> Messages generated for package %(pkg)s by process %(pid)d on %(time)s:\n\n") % \
+ {"pkg": key, "pid": os.getpid(), "time": time_str}
+ config_root = mysettings["PORTAGE_CONFIGROOT"]
+
+ # Copy needed variables from the config instance,
+ # since we don't need to hold a reference for the
+ # whole thing. This also makes it possible to
+ # rely on per-package variable settings that may
+ # have come from /etc/portage/package.env, since
+ # we'll be isolated from any future mutations of
+ # mysettings.
+ config_dict = {}
+ for k in _config_keys:
+ v = mysettings.get(k)
+ if v is not None:
+ config_dict[k] = v
+
+ config_dict, items = _items.setdefault(config_root, (config_dict, {}))
+ items[key] = header + fulltext
+
+def finalize():
+ global _items
+ for mysettings, items in _items.values():
+ _finalize(mysettings, items)
+ _items.clear()
+
+def _finalize(mysettings, items):
+ if len(items) == 0:
+ return
+ elif len(items) == 1:
+ count = _("one package")
+ else:
+ count = _("multiple packages")
+ if "PORTAGE_ELOG_MAILURI" in mysettings:
+ myrecipient = mysettings["PORTAGE_ELOG_MAILURI"].split()[0]
+ else:
+ myrecipient = "root@localhost"
+
+ myfrom = mysettings.get("PORTAGE_ELOG_MAILFROM", "")
+ myfrom = myfrom.replace("${HOST}", socket.getfqdn())
+ mysubject = mysettings.get("PORTAGE_ELOG_MAILSUBJECT", "")
+ mysubject = mysubject.replace("${PACKAGE}", count)
+ mysubject = mysubject.replace("${HOST}", socket.getfqdn())
+
+ mybody = _("elog messages for the following packages generated by "
+ "process %(pid)d on host %(host)s:\n") % {"pid": os.getpid(), "host": socket.getfqdn()}
+ for key in items:
+ mybody += "- %s\n" % key
+
+ mymessage = portage.mail.create_message(myfrom, myrecipient, mysubject,
+ mybody, attachments=list(items.values()))
+
+ # Timeout after one minute in case send_mail() blocks indefinitely.
+ try:
+ try:
+ AlarmSignal.register(60)
+ portage.mail.send_mail(mysettings, mymessage)
+ finally:
+ AlarmSignal.unregister()
+ except AlarmSignal:
+ writemsg("Timeout in finalize() for elog system 'mail_summary'\n",
+ noiselevel=-1)
+ except PortageException as e:
+ writemsg("%s\n" % (e,), noiselevel=-1)
+
+ return
diff --git a/portage_with_autodep/pym/portage/elog/mod_save.py b/portage_with_autodep/pym/portage/elog/mod_save.py
new file mode 100644
index 0000000..9350a6e
--- /dev/null
+++ b/portage_with_autodep/pym/portage/elog/mod_save.py
@@ -0,0 +1,51 @@
+# elog/mod_save.py - elog dispatch module
+# Copyright 2006-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import io
+import time
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+from portage.data import portage_gid, portage_uid
+from portage.package.ebuild.prepare_build_dirs import _ensure_log_subdirs
+from portage.util import ensure_dirs, normalize_path
+
+def process(mysettings, key, logentries, fulltext):
+
+ if mysettings.get("PORT_LOGDIR"):
+ logdir = normalize_path(mysettings["PORT_LOGDIR"])
+ else:
+ logdir = os.path.join(os.sep, "var", "log", "portage")
+
+ if not os.path.isdir(logdir):
+ # Only initialize group/mode if the directory doesn't
+ # exist, so that we don't override permissions if they
+ # were previously set by the administrator.
+ # NOTE: These permissions should be compatible with our
+ # default logrotate config as discussed in bug 374287.
+ ensure_dirs(logdir, uid=portage_uid, gid=portage_gid, mode=0o2770)
+
+ cat = mysettings['CATEGORY']
+ pf = mysettings['PF']
+
+ elogfilename = pf + ":" + _unicode_decode(
+ time.strftime("%Y%m%d-%H%M%S", time.gmtime(time.time())),
+ encoding=_encodings['content'], errors='replace') + ".log"
+
+ if "split-elog" in mysettings.features:
+ log_subdir = os.path.join(logdir, "elog", cat)
+ elogfilename = os.path.join(log_subdir, elogfilename)
+ else:
+ log_subdir = os.path.join(logdir, "elog")
+ elogfilename = os.path.join(log_subdir, cat + ':' + elogfilename)
+ _ensure_log_subdirs(logdir, log_subdir)
+
+ elogfile = io.open(_unicode_encode(elogfilename,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='w', encoding=_encodings['content'], errors='backslashreplace')
+ elogfile.write(_unicode_decode(fulltext))
+ elogfile.close()
+
+ return elogfilename
diff --git a/portage_with_autodep/pym/portage/elog/mod_save_summary.py b/portage_with_autodep/pym/portage/elog/mod_save_summary.py
new file mode 100644
index 0000000..4adc6f3
--- /dev/null
+++ b/portage_with_autodep/pym/portage/elog/mod_save_summary.py
@@ -0,0 +1,59 @@
+# elog/mod_save_summary.py - elog dispatch module
+# Copyright 2006-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import io
+import time
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+from portage.data import portage_gid, portage_uid
+from portage.localization import _
+from portage.package.ebuild.prepare_build_dirs import _ensure_log_subdirs
+from portage.util import apply_permissions, ensure_dirs, normalize_path
+
+def process(mysettings, key, logentries, fulltext):
+ if mysettings.get("PORT_LOGDIR"):
+ logdir = normalize_path(mysettings["PORT_LOGDIR"])
+ else:
+ logdir = os.path.join(os.sep, "var", "log", "portage")
+
+ if not os.path.isdir(logdir):
+ # Only initialize group/mode if the directory doesn't
+ # exist, so that we don't override permissions if they
+ # were previously set by the administrator.
+ # NOTE: These permissions should be compatible with our
+ # default logrotate config as discussed in bug 374287.
+ ensure_dirs(logdir, uid=portage_uid, gid=portage_gid, mode=0o2770)
+
+ elogdir = os.path.join(logdir, "elog")
+ _ensure_log_subdirs(logdir, elogdir)
+
+ # TODO: Locking
+ elogfilename = elogdir+"/summary.log"
+ elogfile = io.open(_unicode_encode(elogfilename,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='a', encoding=_encodings['content'], errors='backslashreplace')
+
+ # Copy group permission bits from parent directory.
+ elogdir_st = os.stat(elogdir)
+ elogdir_gid = elogdir_st.st_gid
+ elogdir_grp_mode = 0o060 & elogdir_st.st_mode
+ apply_permissions(elogfilename, gid=elogdir_gid,
+ mode=elogdir_grp_mode, mask=0)
+
+ time_str = time.strftime("%Y-%m-%d %H:%M:%S %Z",
+ time.localtime(time.time()))
+ # Avoid potential UnicodeDecodeError later.
+ time_str = _unicode_decode(time_str,
+ encoding=_encodings['content'], errors='replace')
+ elogfile.write(_unicode_decode(
+ _(">>> Messages generated by process " +
+ "%(pid)d on %(time)s for package %(pkg)s:\n\n") %
+ {"pid": os.getpid(), "time": time_str, "pkg": key}))
+ elogfile.write(_unicode_decode(fulltext))
+ elogfile.write(_unicode_decode("\n"))
+ elogfile.close()
+
+ return elogfilename
diff --git a/portage_with_autodep/pym/portage/elog/mod_syslog.py b/portage_with_autodep/pym/portage/elog/mod_syslog.py
new file mode 100644
index 0000000..d71dab4
--- /dev/null
+++ b/portage_with_autodep/pym/portage/elog/mod_syslog.py
@@ -0,0 +1,32 @@
+# elog/mod_syslog.py - elog dispatch module
+# Copyright 2006-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+import syslog
+from portage.const import EBUILD_PHASES
+from portage import _encodings
+
+_pri = {
+ "INFO" : syslog.LOG_INFO,
+ "WARN" : syslog.LOG_WARNING,
+ "ERROR" : syslog.LOG_ERR,
+ "LOG" : syslog.LOG_NOTICE,
+ "QA" : syslog.LOG_WARNING
+}
+
+def process(mysettings, key, logentries, fulltext):
+ syslog.openlog("portage", syslog.LOG_ERR | syslog.LOG_WARNING | syslog.LOG_INFO | syslog.LOG_NOTICE, syslog.LOG_LOCAL5)
+ for phase in EBUILD_PHASES:
+ if not phase in logentries:
+ continue
+ for msgtype,msgcontent in logentries[phase]:
+ msgtext = "".join(msgcontent)
+ for line in msgtext.splitlines():
+ line = "%s: %s: %s" % (key, phase, line)
+ if sys.hexversion < 0x3000000 and isinstance(msgtext, unicode):
+ # Avoid TypeError from syslog.syslog()
+ line = line.encode(_encodings['content'],
+ 'backslashreplace')
+ syslog.syslog(_pri[msgtype], line)
+ syslog.closelog()
diff --git a/portage_with_autodep/pym/portage/env/__init__.py b/portage_with_autodep/pym/portage/env/__init__.py
new file mode 100644
index 0000000..17b66d1
--- /dev/null
+++ b/portage_with_autodep/pym/portage/env/__init__.py
@@ -0,0 +1,3 @@
+# Copyright: 2007 Gentoo Foundation
+# License: GPL2
+
diff --git a/portage_with_autodep/pym/portage/env/config.py b/portage_with_autodep/pym/portage/env/config.py
new file mode 100644
index 0000000..865d835
--- /dev/null
+++ b/portage_with_autodep/pym/portage/env/config.py
@@ -0,0 +1,105 @@
+# config.py -- Portage Config
+# Copyright 2007-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ["ConfigLoaderKlass", "GenericFile", "PackageKeywordsFile",
+ "PackageUseFile", "PackageMaskFile", "PortageModulesFile"]
+
+from portage.cache.mappings import UserDict
+from portage.env.loaders import KeyListFileLoader, KeyValuePairFileLoader, ItemFileLoader
+
+class ConfigLoaderKlass(UserDict):
+ """
+ A base class stub for things to inherit from.
+ Users may want a non-file backend.
+ """
+
+ def __init__(self, loader):
+ """
+ @param loader: A class that has a load() that returns two dicts
+ the first being a data dict, the second being a dict of errors.
+ """
+ UserDict.__init__(self)
+ self._loader = loader
+
+ def load(self):
+ """
+ Load the data from the loader.
+
+ @throws LoaderError:
+ """
+
+ self.data, self.errors = self._loader.load()
+
+class GenericFile(UserDict):
+ """
+ Inherits from ConfigLoaderKlass, attempts to use all known loaders
+ until it gets <something> in data. This is probably really slow but is
+ helpful when you really have no idea what you are loading (hint hint the file
+ should perhaps declare what type it is? ;)
+ """
+
+ loaders = [KeyListFileLoader, KeyValuePairFileLoader, ItemFileLoader]
+
+ def __init__(self, filename):
+ UserDict.__init__(self)
+ self.filename = filename
+
+ def load(self):
+ for loader in self.loaders:
+ l = loader(self.filename, None)
+ data, errors = l.load()
+ if len(data) and not len(errors):
+ (self.data, self.errors) = (data, errors)
+ return
+
+
+class PackageKeywordsFile(ConfigLoaderKlass):
+ """
+ Inherits from ConfigLoaderKlass; implements a file-based backend.
+ """
+
+ default_loader = KeyListFileLoader
+
+ def __init__(self, filename):
+ super(PackageKeywordsFile, self).__init__(
+ self.default_loader(filename, validator=None))
+
+class PackageUseFile(ConfigLoaderKlass):
+ """
+ Inherits from PackageUse; implements a file-based backend. Doesn't handle recursion yet.
+ """
+
+ default_loader = KeyListFileLoader
+ def __init__(self, filename):
+ super(PackageUseFile, self).__init__(
+ self.default_loader(filename, validator=None))
+
+class PackageMaskFile(ConfigLoaderKlass):
+ """
+ A class that implements a file-based package.mask
+
+ Entires in package.mask are of the form:
+ atom1
+ atom2
+ or optionally
+ -atom3
+ to revert a previous mask; this only works when masking files are stacked
+ """
+
+ default_loader = ItemFileLoader
+
+ def __init__(self, filename):
+ super(PackageMaskFile, self).__init__(
+ self.default_loader(filename, validator=None))
+
+class PortageModulesFile(ConfigLoaderKlass):
+ """
+ File Class for /etc/portage/modules
+ """
+
+ default_loader = KeyValuePairFileLoader
+
+ def __init__(self, filename):
+ super(PortageModulesFile, self).__init__(
+ self.default_loader(filename, validator=None))
diff --git a/portage_with_autodep/pym/portage/env/loaders.py b/portage_with_autodep/pym/portage/env/loaders.py
new file mode 100644
index 0000000..b540fbb
--- /dev/null
+++ b/portage_with_autodep/pym/portage/env/loaders.py
@@ -0,0 +1,319 @@
+# config.py -- Portage Config
+# Copyright 2007-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import errno
+import io
+import stat
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+from portage.localization import _
+
+class LoaderError(Exception):
+
+ def __init__(self, resource, error_msg):
+ """
+ @param resource: Resource that failed to load (file/sql/etc)
+ @type resource: String
+ @param error_msg: Error from underlying Loader system
+ @type error_msg: String
+ """
+
+ self.resource = resource
+ self.error_msg = error_msg
+
+ def __str__(self):
+ return "Failed while loading resource: %s, error was: %s" % (
+ self.resource, self.error_msg)
+
+
+def RecursiveFileLoader(filename):
+ """
+ If filename is of type file, return a generate that yields filename
+ else if filename is of type directory, return a generator that fields
+ files in that directory.
+
+ Ignore files beginning with . or ending in ~.
+ Prune CVS directories.
+
+ @param filename: name of a file/directory to traverse
+ @rtype: list
+ @returns: List of files to process
+ """
+
+ try:
+ st = os.stat(filename)
+ except OSError:
+ return
+ if stat.S_ISDIR(st.st_mode):
+ for root, dirs, files in os.walk(filename):
+ for d in list(dirs):
+ if d[:1] == '.' or d == 'CVS':
+ dirs.remove(d)
+ for f in files:
+ try:
+ f = _unicode_decode(f,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ continue
+ if f[:1] == '.' or f[-1:] == '~':
+ continue
+ yield os.path.join(root, f)
+ else:
+ yield filename
+
+
+class DataLoader(object):
+
+ def __init__(self, validator):
+ f = validator
+ if f is None:
+ # if they pass in no validator, just make a fake one
+ # that always returns true
+ def validate(key):
+ return True
+ f = validate
+ self._validate = f
+
+ def load(self):
+ """
+ Function to do the actual work of a Loader
+ """
+ raise NotImplementedError("Please override in a subclass")
+
+class EnvLoader(DataLoader):
+ """ Class to access data in the environment """
+ def __init__(self, validator):
+ DataLoader.__init__(self, validator)
+
+ def load(self):
+ return os.environ
+
+class TestTextLoader(DataLoader):
+ """ You give it some data, it 'loads' it for you, no filesystem access
+ """
+ def __init__(self, validator):
+ DataLoader.__init__(self, validator)
+ self.data = {}
+ self.errors = {}
+
+ def setData(self, text):
+ """Explicitly set the data field
+ Args:
+ text - a dict of data typical of Loaders
+ Returns:
+ None
+ """
+ if isinstance(text, dict):
+ self.data = text
+ else:
+ raise ValueError("setData requires a dict argument")
+
+ def setErrors(self, errors):
+ self.errors = errors
+
+ def load(self):
+ return (self.data, self.errors)
+
+
+class FileLoader(DataLoader):
+ """ Class to access data in files """
+
+ def __init__(self, filename, validator):
+ """
+ Args:
+ filename : Name of file or directory to open
+ validator : class with validate() method to validate data.
+ """
+ DataLoader.__init__(self, validator)
+ self.fname = filename
+
+ def load(self):
+ """
+ Return the {source: {key: value}} pairs from a file
+ Return the {source: [list of errors] from a load
+
+ @param recursive: If set and self.fname is a directory;
+ load all files in self.fname
+ @type: Boolean
+ @rtype: tuple
+ @returns:
+ Returns (data,errors), both may be empty dicts or populated.
+ """
+ data = {}
+ errors = {}
+ # I tried to save a nasty lookup on lineparser by doing the lookup
+ # once, which may be expensive due to digging in child classes.
+ func = self.lineParser
+ for fn in RecursiveFileLoader(self.fname):
+ try:
+ f = io.open(_unicode_encode(fn,
+ encoding=_encodings['fs'], errors='strict'), mode='r',
+ encoding=_encodings['content'], errors='replace')
+ except EnvironmentError as e:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
+ raise
+ del e
+ continue
+ for line_num, line in enumerate(f):
+ func(line, line_num, data, errors)
+ f.close()
+ return (data, errors)
+
+ def lineParser(self, line, line_num, data, errors):
+ """ This function parses 1 line at a time
+ Args:
+ line: a string representing 1 line of a file
+ line_num: an integer representing what line we are processing
+ data: a dict that contains the data we have extracted from the file
+ already
+ errors: a dict representing parse errors.
+ Returns:
+ Nothing (None). Writes to data and errors
+ """
+ raise NotImplementedError("Please over-ride this in a child class")
+
+class ItemFileLoader(FileLoader):
+ """
+ Class to load data from a file full of items one per line
+
+ >>> item1
+ >>> item2
+ >>> item3
+ >>> item1
+
+ becomes { 'item1':None, 'item2':None, 'item3':None }
+ Note that due to the data store being a dict, duplicates
+ are removed.
+ """
+
+ def __init__(self, filename, validator):
+ FileLoader.__init__(self, filename, validator)
+
+ def lineParser(self, line, line_num, data, errors):
+ line = line.strip()
+ if line.startswith('#'): # Skip commented lines
+ return
+ if not len(line): # skip empty lines
+ return
+ split = line.split()
+ if not len(split):
+ errors.setdefault(self.fname, []).append(
+ _("Malformed data at line: %s, data: %s")
+ % (line_num + 1, line))
+ return
+ key = split[0]
+ if not self._validate(key):
+ errors.setdefault(self.fname, []).append(
+ _("Validation failed at line: %s, data %s")
+ % (line_num + 1, key))
+ return
+ data[key] = None
+
+class KeyListFileLoader(FileLoader):
+ """
+ Class to load data from a file full of key [list] tuples
+
+ >>>>key foo1 foo2 foo3
+ becomes
+ {'key':['foo1','foo2','foo3']}
+ """
+
+ def __init__(self, filename, validator=None, valuevalidator=None):
+ FileLoader.__init__(self, filename, validator)
+
+ f = valuevalidator
+ if f is None:
+ # if they pass in no validator, just make a fake one
+ # that always returns true
+ def validate(key):
+ return True
+ f = validate
+ self._valueValidate = f
+
+ def lineParser(self, line, line_num, data, errors):
+ line = line.strip()
+ if line.startswith('#'): # Skip commented lines
+ return
+ if not len(line): # skip empty lines
+ return
+ split = line.split()
+ if len(split) < 1:
+ errors.setdefault(self.fname, []).append(
+ _("Malformed data at line: %s, data: %s")
+ % (line_num + 1, line))
+ return
+ key = split[0]
+ value = split[1:]
+ if not self._validate(key):
+ errors.setdefault(self.fname, []).append(
+ _("Key validation failed at line: %s, data %s")
+ % (line_num + 1, key))
+ return
+ if not self._valueValidate(value):
+ errors.setdefault(self.fname, []).append(
+ _("Value validation failed at line: %s, data %s")
+ % (line_num + 1, value))
+ return
+ if key in data:
+ data[key].append(value)
+ else:
+ data[key] = value
+
+
+class KeyValuePairFileLoader(FileLoader):
+ """
+ Class to load data from a file full of key=value pairs
+
+ >>>>key=value
+ >>>>foo=bar
+ becomes:
+ {'key':'value',
+ 'foo':'bar'}
+ """
+
+ def __init__(self, filename, validator, valuevalidator=None):
+ FileLoader.__init__(self, filename, validator)
+
+ f = valuevalidator
+ if f is None:
+ # if they pass in no validator, just make a fake one
+ # that always returns true
+ def validate(key):
+ return True
+ f = validate
+ self._valueValidate = f
+
+
+ def lineParser(self, line, line_num, data, errors):
+ line = line.strip()
+ if line.startswith('#'): # skip commented lines
+ return
+ if not len(line): # skip empty lines
+ return
+ split = line.split('=', 1)
+ if len(split) < 2:
+ errors.setdefault(self.fname, []).append(
+ _("Malformed data at line: %s, data %s")
+ % (line_num + 1, line))
+ return
+ key = split[0].strip()
+ value = split[1].strip()
+ if not key:
+ errors.setdefault(self.fname, []).append(
+ _("Malformed key at line: %s, key %s")
+ % (line_num + 1, key))
+ return
+ if not self._validate(key):
+ errors.setdefault(self.fname, []).append(
+ _("Key validation failed at line: %s, data %s")
+ % (line_num + 1, key))
+ return
+ if not self._valueValidate(value):
+ errors.setdefault(self.fname, []).append(
+ _("Value validation failed at line: %s, data %s")
+ % (line_num + 1, value))
+ return
+ data[key] = value
diff --git a/portage_with_autodep/pym/portage/env/validators.py b/portage_with_autodep/pym/portage/env/validators.py
new file mode 100644
index 0000000..4d11d69
--- /dev/null
+++ b/portage_with_autodep/pym/portage/env/validators.py
@@ -0,0 +1,20 @@
+# validators.py Portage File Loader Code
+# Copyright 2007 Gentoo Foundation
+
+from portage.dep import isvalidatom
+
+ValidAtomValidator = isvalidatom
+
+def PackagesFileValidator(atom):
+ """ This function mutates atoms that begin with - or *
+ It then checks to see if that atom is valid, and if
+ so returns True, else it returns False.
+
+ Args:
+ atom: a string representing an atom such as sys-apps/portage-2.1
+ """
+ if atom.startswith("*") or atom.startswith("-"):
+ atom = atom[1:]
+ if not isvalidatom(atom):
+ return False
+ return True
diff --git a/portage_with_autodep/pym/portage/exception.py b/portage_with_autodep/pym/portage/exception.py
new file mode 100644
index 0000000..7891120
--- /dev/null
+++ b/portage_with_autodep/pym/portage/exception.py
@@ -0,0 +1,186 @@
+# Copyright 1998-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import signal
+import sys
+from portage import _encodings, _unicode_encode, _unicode_decode
+from portage.localization import _
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+class PortageException(Exception):
+ """General superclass for portage exceptions"""
+ def __init__(self,value):
+ self.value = value[:]
+ if isinstance(self.value, basestring):
+ self.value = _unicode_decode(self.value,
+ encoding=_encodings['content'], errors='replace')
+
+ def __str__(self):
+ if isinstance(self.value, basestring):
+ return self.value
+ else:
+ return _unicode_decode(repr(self.value),
+ encoding=_encodings['content'], errors='replace')
+
+ if sys.hexversion < 0x3000000:
+
+ __unicode__ = __str__
+
+ def __str__(self):
+ return _unicode_encode(self.__unicode__(),
+ encoding=_encodings['content'], errors='backslashreplace')
+
+class CorruptionError(PortageException):
+ """Corruption indication"""
+
+class InvalidDependString(PortageException):
+ """An invalid depend string has been encountered"""
+ def __init__(self, value, errors=None):
+ PortageException.__init__(self, value)
+ self.errors = errors
+
+class InvalidVersionString(PortageException):
+ """An invalid version string has been encountered"""
+
+class SecurityViolation(PortageException):
+ """An incorrect formatting was passed instead of the expected one"""
+
+class IncorrectParameter(PortageException):
+ """A parameter of the wrong type was passed"""
+
+class MissingParameter(PortageException):
+ """A parameter is required for the action requested but was not passed"""
+
+class ParseError(PortageException):
+ """An error was generated while attempting to parse the request"""
+
+class InvalidData(PortageException):
+ """An incorrect formatting was passed instead of the expected one"""
+ def __init__(self, value, category=None):
+ PortageException.__init__(self, value)
+ self.category = category
+
+class InvalidDataType(PortageException):
+ """An incorrect type was passed instead of the expected one"""
+
+class InvalidLocation(PortageException):
+ """Data was not found when it was expected to exist or was specified incorrectly"""
+
+class FileNotFound(InvalidLocation):
+ """A file was not found when it was expected to exist"""
+
+class DirectoryNotFound(InvalidLocation):
+ """A directory was not found when it was expected to exist"""
+
+class OperationNotPermitted(PortageException):
+ from errno import EPERM as errno
+ """An operation was not permitted operating system"""
+
+class PermissionDenied(PortageException):
+ from errno import EACCES as errno
+ """Permission denied"""
+
+class TryAgain(PortageException):
+ from errno import EAGAIN as errno
+ """Try again"""
+
+class TimeoutException(PortageException):
+ """Operation timed out"""
+ # NOTE: ETIME is undefined on FreeBSD (bug #336875)
+ #from errno import ETIME as errno
+
+class AlarmSignal(TimeoutException):
+ def __init__(self, value, signum=None, frame=None):
+ TimeoutException.__init__(self, value)
+ self.signum = signum
+ self.frame = frame
+
+ @classmethod
+ def register(cls, time):
+ signal.signal(signal.SIGALRM, cls._signal_handler)
+ signal.alarm(time)
+
+ @classmethod
+ def unregister(cls):
+ signal.alarm(0)
+ signal.signal(signal.SIGALRM, signal.SIG_DFL)
+
+ @classmethod
+ def _signal_handler(cls, signum, frame):
+ signal.signal(signal.SIGALRM, signal.SIG_DFL)
+ raise AlarmSignal("alarm signal",
+ signum=signum, frame=frame)
+
+class ReadOnlyFileSystem(PortageException):
+ """Read-only file system"""
+
+class CommandNotFound(PortageException):
+ """A required binary was not available or executable"""
+
+class AmbiguousPackageName(ValueError, PortageException):
+ """Raised by portage.cpv_expand() when the package name is ambiguous due
+ to the existence of multiple matches in different categories. This inherits
+ from ValueError, for backward compatibility with calling code that already
+ handles ValueError."""
+ def __str__(self):
+ return ValueError.__str__(self)
+
+class PortagePackageException(PortageException):
+ """Malformed or missing package data"""
+
+class PackageNotFound(PortagePackageException):
+ """Missing Ebuild or Binary"""
+
+class PackageSetNotFound(PortagePackageException):
+ """Missing package set"""
+
+class InvalidPackageName(PortagePackageException):
+ """Malformed package name"""
+
+class InvalidAtom(PortagePackageException):
+ """Malformed atom spec"""
+ def __init__(self, value, category=None):
+ PortagePackageException.__init__(self, value)
+ self.category = category
+
+class UnsupportedAPIException(PortagePackageException):
+ """Unsupported API"""
+ def __init__(self, cpv, eapi):
+ self.cpv, self.eapi = cpv, eapi
+ def __str__(self):
+ eapi = self.eapi
+ if not isinstance(eapi, basestring):
+ eapi = str(eapi)
+ eapi = eapi.lstrip("-")
+ msg = _("Unable to do any operations on '%(cpv)s', since "
+ "its EAPI is higher than this portage version's. Please upgrade"
+ " to a portage version that supports EAPI '%(eapi)s'.") % \
+ {"cpv": self.cpv, "eapi": eapi}
+ return _unicode_decode(msg,
+ encoding=_encodings['content'], errors='replace')
+
+ if sys.hexversion < 0x3000000:
+
+ __unicode__ = __str__
+
+ def __str__(self):
+ return _unicode_encode(self.__unicode__(),
+ encoding=_encodings['content'], errors='backslashreplace')
+
+class SignatureException(PortageException):
+ """Signature was not present in the checked file"""
+
+class DigestException(SignatureException):
+ """A problem exists in the digest"""
+
+class MissingSignature(SignatureException):
+ """Signature was not present in the checked file"""
+
+class InvalidSignature(SignatureException):
+ """Signature was checked and was not a valid, current, nor trusted signature"""
+
+class UntrustedSignature(SignatureException):
+ """Signature was not certified to the desired security level"""
+
diff --git a/portage_with_autodep/pym/portage/getbinpkg.py b/portage_with_autodep/pym/portage/getbinpkg.py
new file mode 100644
index 0000000..a511f51
--- /dev/null
+++ b/portage_with_autodep/pym/portage/getbinpkg.py
@@ -0,0 +1,861 @@
+# getbinpkg.py -- Portage binary-package helper functions
+# Copyright 2003-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.output import colorize
+from portage.cache.mappings import slot_dict_class
+from portage.localization import _
+import portage
+from portage import os
+from portage import _encodings
+from portage import _unicode_encode
+
+import sys
+import socket
+import time
+import tempfile
+import base64
+
+_all_errors = [NotImplementedError, ValueError, socket.error]
+
+try:
+ from html.parser import HTMLParser as html_parser_HTMLParser
+except ImportError:
+ from HTMLParser import HTMLParser as html_parser_HTMLParser
+
+try:
+ from urllib.parse import unquote as urllib_parse_unquote
+except ImportError:
+ from urllib2 import unquote as urllib_parse_unquote
+
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+
+try:
+ import ftplib
+except ImportError as e:
+ sys.stderr.write(colorize("BAD","!!! CANNOT IMPORT FTPLIB: ")+str(e)+"\n")
+else:
+ _all_errors.extend(ftplib.all_errors)
+
+try:
+ try:
+ from http.client import HTTPConnection as http_client_HTTPConnection
+ from http.client import BadStatusLine as http_client_BadStatusLine
+ from http.client import ResponseNotReady as http_client_ResponseNotReady
+ from http.client import error as http_client_error
+ except ImportError:
+ from httplib import HTTPConnection as http_client_HTTPConnection
+ from httplib import BadStatusLine as http_client_BadStatusLine
+ from httplib import ResponseNotReady as http_client_ResponseNotReady
+ from httplib import error as http_client_error
+except ImportError as e:
+ sys.stderr.write(colorize("BAD","!!! CANNOT IMPORT HTTP.CLIENT: ")+str(e)+"\n")
+else:
+ _all_errors.append(http_client_error)
+
+_all_errors = tuple(_all_errors)
+
+if sys.hexversion >= 0x3000000:
+ long = int
+
+def make_metadata_dict(data):
+ myid,myglob = data
+
+ mydict = {}
+ for x in portage.xpak.getindex_mem(myid):
+ mydict[x] = portage.xpak.getitem(data,x)
+
+ return mydict
+
+class ParseLinks(html_parser_HTMLParser):
+ """Parser class that overrides HTMLParser to grab all anchors from an html
+ page and provide suffix and prefix limitors"""
+ def __init__(self):
+ self.PL_anchors = []
+ html_parser_HTMLParser.__init__(self)
+
+ def get_anchors(self):
+ return self.PL_anchors
+
+ def get_anchors_by_prefix(self,prefix):
+ newlist = []
+ for x in self.PL_anchors:
+ if x.startswith(prefix):
+ if x not in newlist:
+ newlist.append(x[:])
+ return newlist
+
+ def get_anchors_by_suffix(self,suffix):
+ newlist = []
+ for x in self.PL_anchors:
+ if x.endswith(suffix):
+ if x not in newlist:
+ newlist.append(x[:])
+ return newlist
+
+ def handle_endtag(self,tag):
+ pass
+
+ def handle_starttag(self,tag,attrs):
+ if tag == "a":
+ for x in attrs:
+ if x[0] == 'href':
+ if x[1] not in self.PL_anchors:
+ self.PL_anchors.append(urllib_parse_unquote(x[1]))
+
+
+def create_conn(baseurl,conn=None):
+ """(baseurl,conn) --- Takes a protocol://site:port/address url, and an
+ optional connection. If connection is already active, it is passed on.
+ baseurl is reduced to address and is returned in tuple (conn,address)"""
+
+ parts = baseurl.split("://",1)
+ if len(parts) != 2:
+ raise ValueError(_("Provided URI does not "
+ "contain protocol identifier. '%s'") % baseurl)
+ protocol,url_parts = parts
+ del parts
+
+ url_parts = url_parts.split("/")
+ host = url_parts[0]
+ if len(url_parts) < 2:
+ address = "/"
+ else:
+ address = "/"+"/".join(url_parts[1:])
+ del url_parts
+
+ userpass_host = host.split("@",1)
+ if len(userpass_host) == 1:
+ host = userpass_host[0]
+ userpass = ["anonymous"]
+ else:
+ host = userpass_host[1]
+ userpass = userpass_host[0].split(":")
+ del userpass_host
+
+ if len(userpass) > 2:
+ raise ValueError(_("Unable to interpret username/password provided."))
+ elif len(userpass) == 2:
+ username = userpass[0]
+ password = userpass[1]
+ elif len(userpass) == 1:
+ username = userpass[0]
+ password = None
+ del userpass
+
+ http_headers = {}
+ http_params = {}
+ if username and password:
+ http_headers = {
+ "Authorization": "Basic %s" %
+ base64.encodestring("%s:%s" % (username, password)).replace(
+ "\012",
+ ""
+ ),
+ }
+
+ if not conn:
+ if protocol == "https":
+ # Use local import since https typically isn't needed, and
+ # this way we can usually avoid triggering the global scope
+ # http.client ImportError handler (like during stage1 -> stage2
+ # builds where USE=ssl is disabled for python).
+ try:
+ try:
+ from http.client import HTTPSConnection as http_client_HTTPSConnection
+ except ImportError:
+ from httplib import HTTPSConnection as http_client_HTTPSConnection
+ except ImportError:
+ raise NotImplementedError(
+ _("python must have ssl enabled for https support"))
+ conn = http_client_HTTPSConnection(host)
+ elif protocol == "http":
+ conn = http_client_HTTPConnection(host)
+ elif protocol == "ftp":
+ passive = 1
+ if(host[-1] == "*"):
+ passive = 0
+ host = host[:-1]
+ conn = ftplib.FTP(host)
+ if password:
+ conn.login(username,password)
+ else:
+ sys.stderr.write(colorize("WARN",
+ _(" * No password provided for username"))+" '%s'" % \
+ (username,) + "\n\n")
+ conn.login(username)
+ conn.set_pasv(passive)
+ conn.set_debuglevel(0)
+ elif protocol == "sftp":
+ try:
+ import paramiko
+ except ImportError:
+ raise NotImplementedError(
+ _("paramiko must be installed for sftp support"))
+ t = paramiko.Transport(host)
+ t.connect(username=username, password=password)
+ conn = paramiko.SFTPClient.from_transport(t)
+ else:
+ raise NotImplementedError(_("%s is not a supported protocol.") % protocol)
+
+ return (conn,protocol,address, http_params, http_headers)
+
+def make_ftp_request(conn, address, rest=None, dest=None):
+ """(conn,address,rest) --- uses the conn object to request the data
+ from address and issuing a rest if it is passed."""
+ try:
+
+ if dest:
+ fstart_pos = dest.tell()
+
+ conn.voidcmd("TYPE I")
+ fsize = conn.size(address)
+
+ if (rest != None) and (rest < 0):
+ rest = fsize+int(rest)
+ if rest < 0:
+ rest = 0
+
+ if rest != None:
+ mysocket = conn.transfercmd("RETR "+str(address), rest)
+ else:
+ mysocket = conn.transfercmd("RETR "+str(address))
+
+ mydata = ""
+ while 1:
+ somedata = mysocket.recv(8192)
+ if somedata:
+ if dest:
+ dest.write(somedata)
+ else:
+ mydata = mydata + somedata
+ else:
+ break
+
+ if dest:
+ data_size = fstart_pos - dest.tell()
+ else:
+ data_size = len(mydata)
+
+ mysocket.close()
+ conn.voidresp()
+ conn.voidcmd("TYPE A")
+
+ return mydata,not (fsize==data_size),""
+
+ except ValueError as e:
+ return None,int(str(e)[:4]),str(e)
+
+
+def make_http_request(conn, address, params={}, headers={}, dest=None):
+ """(conn,address,params,headers) --- uses the conn object to request
+ the data from address, performing Location forwarding and using the
+ optional params and headers."""
+
+ rc = 0
+ response = None
+ while (rc == 0) or (rc == 301) or (rc == 302):
+ try:
+ if (rc != 0):
+ conn,ignore,ignore,ignore,ignore = create_conn(address)
+ conn.request("GET", address, body=None, headers=headers)
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ return None,None,"Server request failed: "+str(e)
+ response = conn.getresponse()
+ rc = response.status
+
+ # 301 means that the page address is wrong.
+ if ((rc == 301) or (rc == 302)):
+ ignored_data = response.read()
+ del ignored_data
+ for x in str(response.msg).split("\n"):
+ parts = x.split(": ",1)
+ if parts[0] == "Location":
+ if (rc == 301):
+ sys.stderr.write(colorize("BAD",
+ _("Location has moved: ")) + str(parts[1]) + "\n")
+ if (rc == 302):
+ sys.stderr.write(colorize("BAD",
+ _("Location has temporarily moved: ")) + \
+ str(parts[1]) + "\n")
+ address = parts[1]
+ break
+
+ if (rc != 200) and (rc != 206):
+ return None,rc,"Server did not respond successfully ("+str(response.status)+": "+str(response.reason)+")"
+
+ if dest:
+ dest.write(response.read())
+ return "",0,""
+
+ return response.read(),0,""
+
+
+def match_in_array(array, prefix="", suffix="", match_both=1, allow_overlap=0):
+ myarray = []
+
+ if not (prefix and suffix):
+ match_both = 0
+
+ for x in array:
+ add_p = 0
+ if prefix and (len(x) >= len(prefix)) and (x[:len(prefix)] == prefix):
+ add_p = 1
+
+ if match_both:
+ if prefix and not add_p: # Require both, but don't have first one.
+ continue
+ else:
+ if add_p: # Only need one, and we have it.
+ myarray.append(x[:])
+ continue
+
+ if not allow_overlap: # Not allow to overlap prefix and suffix
+ if len(x) >= (len(prefix)+len(suffix)):
+ pass
+ else:
+ continue # Too short to match.
+ else:
+ pass # Do whatever... We're overlapping.
+
+ if suffix and (len(x) >= len(suffix)) and (x[-len(suffix):] == suffix):
+ myarray.append(x) # It matches
+ else:
+ continue # Doesn't match.
+
+ return myarray
+
+
+
+def dir_get_list(baseurl,conn=None):
+ """(baseurl[,connection]) -- Takes a base url to connect to and read from.
+ URI should be in the form <proto>://<site>[:port]<path>
+ Connection is used for persistent connection instances."""
+
+ if not conn:
+ keepconnection = 0
+ else:
+ keepconnection = 1
+
+ conn,protocol,address,params,headers = create_conn(baseurl, conn)
+
+ listing = None
+ if protocol in ["http","https"]:
+ if not address.endswith("/"):
+ # http servers can return a 400 error here
+ # if the address doesn't end with a slash.
+ address += "/"
+ page,rc,msg = make_http_request(conn,address,params,headers)
+
+ if page:
+ parser = ParseLinks()
+ parser.feed(page)
+ del page
+ listing = parser.get_anchors()
+ else:
+ import portage.exception
+ raise portage.exception.PortageException(
+ _("Unable to get listing: %s %s") % (rc,msg))
+ elif protocol in ["ftp"]:
+ if address[-1] == '/':
+ olddir = conn.pwd()
+ conn.cwd(address)
+ listing = conn.nlst()
+ conn.cwd(olddir)
+ del olddir
+ else:
+ listing = conn.nlst(address)
+ elif protocol == "sftp":
+ listing = conn.listdir(address)
+ else:
+ raise TypeError(_("Unknown protocol. '%s'") % protocol)
+
+ if not keepconnection:
+ conn.close()
+
+ return listing
+
+def file_get_metadata(baseurl,conn=None, chunk_size=3000):
+ """(baseurl[,connection]) -- Takes a base url to connect to and read from.
+ URI should be in the form <proto>://<site>[:port]<path>
+ Connection is used for persistent connection instances."""
+
+ if not conn:
+ keepconnection = 0
+ else:
+ keepconnection = 1
+
+ conn,protocol,address,params,headers = create_conn(baseurl, conn)
+
+ if protocol in ["http","https"]:
+ headers["Range"] = "bytes=-"+str(chunk_size)
+ data,rc,msg = make_http_request(conn, address, params, headers)
+ elif protocol in ["ftp"]:
+ data,rc,msg = make_ftp_request(conn, address, -chunk_size)
+ elif protocol == "sftp":
+ f = conn.open(address)
+ try:
+ f.seek(-chunk_size, 2)
+ data = f.read()
+ finally:
+ f.close()
+ else:
+ raise TypeError(_("Unknown protocol. '%s'") % protocol)
+
+ if data:
+ xpaksize = portage.xpak.decodeint(data[-8:-4])
+ if (xpaksize+8) > chunk_size:
+ myid = file_get_metadata(baseurl, conn, (xpaksize+8))
+ if not keepconnection:
+ conn.close()
+ return myid
+ else:
+ xpak_data = data[len(data)-(xpaksize+8):-8]
+ del data
+
+ myid = portage.xpak.xsplit_mem(xpak_data)
+ if not myid:
+ myid = None,None
+ del xpak_data
+ else:
+ myid = None,None
+
+ if not keepconnection:
+ conn.close()
+
+ return myid
+
+
+def file_get(baseurl,dest,conn=None,fcmd=None,filename=None):
+ """(baseurl,dest,fcmd=) -- Takes a base url to connect to and read from.
+ URI should be in the form <proto>://[user[:pass]@]<site>[:port]<path>"""
+
+ if not fcmd:
+ return file_get_lib(baseurl,dest,conn)
+ if not filename:
+ filename = os.path.basename(baseurl)
+
+ variables = {
+ "DISTDIR": dest,
+ "URI": baseurl,
+ "FILE": filename
+ }
+
+ from portage.util import varexpand
+ from portage.process import spawn
+ myfetch = portage.util.shlex_split(fcmd)
+ myfetch = [varexpand(x, mydict=variables) for x in myfetch]
+ fd_pipes= {
+ 0:sys.stdin.fileno(),
+ 1:sys.stdout.fileno(),
+ 2:sys.stdout.fileno()
+ }
+ retval = spawn(myfetch, env=os.environ.copy(), fd_pipes=fd_pipes)
+ if retval != os.EX_OK:
+ sys.stderr.write(_("Fetcher exited with a failure condition.\n"))
+ return 0
+ return 1
+
+def file_get_lib(baseurl,dest,conn=None):
+ """(baseurl[,connection]) -- Takes a base url to connect to and read from.
+ URI should be in the form <proto>://<site>[:port]<path>
+ Connection is used for persistent connection instances."""
+
+ if not conn:
+ keepconnection = 0
+ else:
+ keepconnection = 1
+
+ conn,protocol,address,params,headers = create_conn(baseurl, conn)
+
+ sys.stderr.write("Fetching '"+str(os.path.basename(address)+"'\n"))
+ if protocol in ["http","https"]:
+ data,rc,msg = make_http_request(conn, address, params, headers, dest=dest)
+ elif protocol in ["ftp"]:
+ data,rc,msg = make_ftp_request(conn, address, dest=dest)
+ elif protocol == "sftp":
+ rc = 0
+ try:
+ f = conn.open(address)
+ except SystemExit:
+ raise
+ except Exception:
+ rc = 1
+ else:
+ try:
+ if dest:
+ bufsize = 8192
+ while True:
+ data = f.read(bufsize)
+ if not data:
+ break
+ dest.write(data)
+ finally:
+ f.close()
+ else:
+ raise TypeError(_("Unknown protocol. '%s'") % protocol)
+
+ if not keepconnection:
+ conn.close()
+
+ return rc
+
+
+def dir_get_metadata(baseurl, conn=None, chunk_size=3000, verbose=1, usingcache=1, makepickle=None):
+ """(baseurl,conn,chunk_size,verbose) --
+ """
+ if not conn:
+ keepconnection = 0
+ else:
+ keepconnection = 1
+
+ cache_path = "/var/cache/edb"
+ metadatafilename = os.path.join(cache_path, 'remote_metadata.pickle')
+
+ if makepickle is None:
+ makepickle = "/var/cache/edb/metadata.idx.most_recent"
+
+ try:
+ conn, protocol, address, params, headers = create_conn(baseurl, conn)
+ except _all_errors as e:
+ # ftplib.FTP(host) can raise errors like this:
+ # socket.error: (111, 'Connection refused')
+ sys.stderr.write("!!! %s\n" % (e,))
+ return {}
+
+ out = sys.stdout
+ try:
+ metadatafile = open(_unicode_encode(metadatafilename,
+ encoding=_encodings['fs'], errors='strict'), 'rb')
+ mypickle = pickle.Unpickler(metadatafile)
+ try:
+ mypickle.find_global = None
+ except AttributeError:
+ # TODO: If py3k, override Unpickler.find_class().
+ pass
+ metadata = mypickle.load()
+ out.write(_("Loaded metadata pickle.\n"))
+ out.flush()
+ metadatafile.close()
+ except (IOError, OSError, EOFError, ValueError, pickle.UnpicklingError):
+ metadata = {}
+ if baseurl not in metadata:
+ metadata[baseurl]={}
+ if "indexname" not in metadata[baseurl]:
+ metadata[baseurl]["indexname"]=""
+ if "timestamp" not in metadata[baseurl]:
+ metadata[baseurl]["timestamp"]=0
+ if "unmodified" not in metadata[baseurl]:
+ metadata[baseurl]["unmodified"]=0
+ if "data" not in metadata[baseurl]:
+ metadata[baseurl]["data"]={}
+
+ if not os.access(cache_path, os.W_OK):
+ sys.stderr.write(_("!!! Unable to write binary metadata to disk!\n"))
+ sys.stderr.write(_("!!! Permission denied: '%s'\n") % cache_path)
+ return metadata[baseurl]["data"]
+
+ import portage.exception
+ try:
+ filelist = dir_get_list(baseurl, conn)
+ except portage.exception.PortageException as e:
+ sys.stderr.write(_("!!! Error connecting to '%s'.\n") % baseurl)
+ sys.stderr.write("!!! %s\n" % str(e))
+ del e
+ return metadata[baseurl]["data"]
+ tbz2list = match_in_array(filelist, suffix=".tbz2")
+ metalist = match_in_array(filelist, prefix="metadata.idx")
+ del filelist
+
+ # Determine if our metadata file is current.
+ metalist.sort()
+ metalist.reverse() # makes the order new-to-old.
+ for mfile in metalist:
+ if usingcache and \
+ ((metadata[baseurl]["indexname"] != mfile) or \
+ (metadata[baseurl]["timestamp"] < int(time.time()-(60*60*24)))):
+ # Try to download new cache until we succeed on one.
+ data=""
+ for trynum in [1,2,3]:
+ mytempfile = tempfile.TemporaryFile()
+ try:
+ file_get(baseurl+"/"+mfile, mytempfile, conn)
+ if mytempfile.tell() > len(data):
+ mytempfile.seek(0)
+ data = mytempfile.read()
+ except ValueError as e:
+ sys.stderr.write("--- "+str(e)+"\n")
+ if trynum < 3:
+ sys.stderr.write(_("Retrying...\n"))
+ sys.stderr.flush()
+ mytempfile.close()
+ continue
+ if match_in_array([mfile],suffix=".gz"):
+ out.write("gzip'd\n")
+ out.flush()
+ try:
+ import gzip
+ mytempfile.seek(0)
+ gzindex = gzip.GzipFile(mfile[:-3],'rb',9,mytempfile)
+ data = gzindex.read()
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ mytempfile.close()
+ sys.stderr.write(_("!!! Failed to use gzip: ")+str(e)+"\n")
+ sys.stderr.flush()
+ mytempfile.close()
+ try:
+ metadata[baseurl]["data"] = pickle.loads(data)
+ del data
+ metadata[baseurl]["indexname"] = mfile
+ metadata[baseurl]["timestamp"] = int(time.time())
+ metadata[baseurl]["modified"] = 0 # It's not, right after download.
+ out.write(_("Pickle loaded.\n"))
+ out.flush()
+ break
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ sys.stderr.write(_("!!! Failed to read data from index: ")+str(mfile)+"\n")
+ sys.stderr.write("!!! "+str(e)+"\n")
+ sys.stderr.flush()
+ try:
+ metadatafile = open(_unicode_encode(metadatafilename,
+ encoding=_encodings['fs'], errors='strict'), 'wb')
+ pickle.dump(metadata, metadatafile, protocol=2)
+ metadatafile.close()
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ sys.stderr.write(_("!!! Failed to write binary metadata to disk!\n"))
+ sys.stderr.write("!!! "+str(e)+"\n")
+ sys.stderr.flush()
+ break
+ # We may have metadata... now we run through the tbz2 list and check.
+
+ class CacheStats(object):
+ from time import time
+ def __init__(self, out):
+ self.misses = 0
+ self.hits = 0
+ self.last_update = 0
+ self.out = out
+ self.min_display_latency = 0.2
+ def update(self):
+ cur_time = self.time()
+ if cur_time - self.last_update >= self.min_display_latency:
+ self.last_update = cur_time
+ self.display()
+ def display(self):
+ self.out.write("\r"+colorize("WARN",
+ _("cache miss: '")+str(self.misses)+"'") + \
+ " --- "+colorize("GOOD", _("cache hit: '")+str(self.hits)+"'"))
+ self.out.flush()
+
+ cache_stats = CacheStats(out)
+ have_tty = os.environ.get('TERM') != 'dumb' and out.isatty()
+ if have_tty:
+ cache_stats.display()
+ binpkg_filenames = set()
+ for x in tbz2list:
+ x = os.path.basename(x)
+ binpkg_filenames.add(x)
+ if x not in metadata[baseurl]["data"]:
+ cache_stats.misses += 1
+ if have_tty:
+ cache_stats.update()
+ metadata[baseurl]["modified"] = 1
+ myid = None
+ for retry in range(3):
+ try:
+ myid = file_get_metadata(
+ "/".join((baseurl.rstrip("/"), x.lstrip("/"))),
+ conn, chunk_size)
+ break
+ except http_client_BadStatusLine:
+ # Sometimes this error is thrown from conn.getresponse() in
+ # make_http_request(). The docstring for this error in
+ # httplib.py says "Presumably, the server closed the
+ # connection before sending a valid response".
+ conn, protocol, address, params, headers = create_conn(
+ baseurl)
+ except http_client_ResponseNotReady:
+ # With some http servers this error is known to be thrown
+ # from conn.getresponse() in make_http_request() when the
+ # remote file does not have appropriate read permissions.
+ # Maybe it's possible to recover from this exception in
+ # cases though, so retry.
+ conn, protocol, address, params, headers = create_conn(
+ baseurl)
+
+ if myid and myid[0]:
+ metadata[baseurl]["data"][x] = make_metadata_dict(myid)
+ elif verbose:
+ sys.stderr.write(colorize("BAD",
+ _("!!! Failed to retrieve metadata on: "))+str(x)+"\n")
+ sys.stderr.flush()
+ else:
+ cache_stats.hits += 1
+ if have_tty:
+ cache_stats.update()
+ cache_stats.display()
+ # Cleanse stale cache for files that don't exist on the server anymore.
+ stale_cache = set(metadata[baseurl]["data"]).difference(binpkg_filenames)
+ if stale_cache:
+ for x in stale_cache:
+ del metadata[baseurl]["data"][x]
+ metadata[baseurl]["modified"] = 1
+ del stale_cache
+ del binpkg_filenames
+ out.write("\n")
+ out.flush()
+
+ try:
+ if "modified" in metadata[baseurl] and metadata[baseurl]["modified"]:
+ metadata[baseurl]["timestamp"] = int(time.time())
+ metadatafile = open(_unicode_encode(metadatafilename,
+ encoding=_encodings['fs'], errors='strict'), 'wb')
+ pickle.dump(metadata, metadatafile, protocol=2)
+ metadatafile.close()
+ if makepickle:
+ metadatafile = open(_unicode_encode(makepickle,
+ encoding=_encodings['fs'], errors='strict'), 'wb')
+ pickle.dump(metadata[baseurl]["data"], metadatafile, protocol=2)
+ metadatafile.close()
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ sys.stderr.write(_("!!! Failed to write binary metadata to disk!\n"))
+ sys.stderr.write("!!! "+str(e)+"\n")
+ sys.stderr.flush()
+
+ if not keepconnection:
+ conn.close()
+
+ return metadata[baseurl]["data"]
+
+def _cmp_cpv(d1, d2):
+ cpv1 = d1["CPV"]
+ cpv2 = d2["CPV"]
+ if cpv1 > cpv2:
+ return 1
+ elif cpv1 == cpv2:
+ return 0
+ else:
+ return -1
+
+class PackageIndex(object):
+
+ def __init__(self,
+ allowed_pkg_keys=None,
+ default_header_data=None,
+ default_pkg_data=None,
+ inherited_keys=None,
+ translated_keys=None):
+
+ self._pkg_slot_dict = None
+ if allowed_pkg_keys is not None:
+ self._pkg_slot_dict = slot_dict_class(allowed_pkg_keys)
+
+ self._default_header_data = default_header_data
+ self._default_pkg_data = default_pkg_data
+ self._inherited_keys = inherited_keys
+ self._write_translation_map = {}
+ self._read_translation_map = {}
+ if translated_keys:
+ self._write_translation_map.update(translated_keys)
+ self._read_translation_map.update(((y, x) for (x, y) in translated_keys))
+ self.header = {}
+ if self._default_header_data:
+ self.header.update(self._default_header_data)
+ self.packages = []
+ self.modified = True
+
+ def _readpkgindex(self, pkgfile, pkg_entry=True):
+
+ allowed_keys = None
+ if self._pkg_slot_dict is None or not pkg_entry:
+ d = {}
+ else:
+ d = self._pkg_slot_dict()
+ allowed_keys = d.allowed_keys
+
+ for line in pkgfile:
+ line = line.rstrip("\n")
+ if not line:
+ break
+ line = line.split(":", 1)
+ if not len(line) == 2:
+ continue
+ k, v = line
+ if v:
+ v = v[1:]
+ k = self._read_translation_map.get(k, k)
+ if allowed_keys is not None and \
+ k not in allowed_keys:
+ continue
+ d[k] = v
+ return d
+
+ def _writepkgindex(self, pkgfile, items):
+ for k, v in items:
+ pkgfile.write("%s: %s\n" % \
+ (self._write_translation_map.get(k, k), v))
+ pkgfile.write("\n")
+
+ def read(self, pkgfile):
+ self.readHeader(pkgfile)
+ self.readBody(pkgfile)
+
+ def readHeader(self, pkgfile):
+ self.header.update(self._readpkgindex(pkgfile, pkg_entry=False))
+
+ def readBody(self, pkgfile):
+ while True:
+ d = self._readpkgindex(pkgfile)
+ if not d:
+ break
+ mycpv = d.get("CPV")
+ if not mycpv:
+ continue
+ if self._default_pkg_data:
+ for k, v in self._default_pkg_data.items():
+ d.setdefault(k, v)
+ if self._inherited_keys:
+ for k in self._inherited_keys:
+ v = self.header.get(k)
+ if v is not None:
+ d.setdefault(k, v)
+ self.packages.append(d)
+
+ def write(self, pkgfile):
+ if self.modified:
+ self.header["TIMESTAMP"] = str(long(time.time()))
+ self.header["PACKAGES"] = str(len(self.packages))
+ keys = list(self.header)
+ keys.sort()
+ self._writepkgindex(pkgfile, [(k, self.header[k]) \
+ for k in keys if self.header[k]])
+ for metadata in sorted(self.packages,
+ key=portage.util.cmp_sort_key(_cmp_cpv)):
+ metadata = metadata.copy()
+ cpv = metadata["CPV"]
+ if self._inherited_keys:
+ for k in self._inherited_keys:
+ v = self.header.get(k)
+ if v is not None and v == metadata.get(k):
+ del metadata[k]
+ if self._default_pkg_data:
+ for k, v in self._default_pkg_data.items():
+ if metadata.get(k) == v:
+ metadata.pop(k, None)
+ keys = list(metadata)
+ keys.sort()
+ self._writepkgindex(pkgfile,
+ [(k, metadata[k]) for k in keys if metadata[k]])
diff --git a/portage_with_autodep/pym/portage/glsa.py b/portage_with_autodep/pym/portage/glsa.py
new file mode 100644
index 0000000..a784d14
--- /dev/null
+++ b/portage_with_autodep/pym/portage/glsa.py
@@ -0,0 +1,699 @@
+# Copyright 2003-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import absolute_import
+
+import io
+import sys
+try:
+ from urllib.request import urlopen as urllib_request_urlopen
+except ImportError:
+ from urllib import urlopen as urllib_request_urlopen
+import re
+import xml.dom.minidom
+
+import portage
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+from portage.versions import pkgsplit, catpkgsplit, pkgcmp, best
+from portage.util import grabfile
+from portage.const import CACHE_PATH
+from portage.localization import _
+from portage.dep import _slot_separator
+
+# Note: the space for rgt and rlt is important !!
+# FIXME: use slot deps instead, requires GLSA format versioning
+opMapping = {"le": "<=", "lt": "<", "eq": "=", "gt": ">", "ge": ">=",
+ "rge": ">=~", "rle": "<=~", "rgt": " >~", "rlt": " <~"}
+NEWLINE_ESCAPE = "!;\\n" # some random string to mark newlines that should be preserved
+SPACE_ESCAPE = "!;_" # some random string to mark spaces that should be preserved
+
+def get_applied_glsas(settings):
+ """
+ Return a list of applied or injected GLSA IDs
+
+ @type settings: portage.config
+ @param settings: portage config instance
+ @rtype: list
+ @return: list of glsa IDs
+ """
+ return grabfile(os.path.join(settings["EROOT"], CACHE_PATH, "glsa"))
+
+
+# TODO: use the textwrap module instead
+def wrap(text, width, caption=""):
+ """
+ Wraps the given text at column I{width}, optionally indenting
+ it so that no text is under I{caption}. It's possible to encode
+ hard linebreaks in I{text} with L{NEWLINE_ESCAPE}.
+
+ @type text: String
+ @param text: the text to be wrapped
+ @type width: Integer
+ @param width: the column at which the text should be wrapped
+ @type caption: String
+ @param caption: this string is inserted at the beginning of the
+ return value and the paragraph is indented up to
+ C{len(caption)}.
+ @rtype: String
+ @return: the wrapped and indented paragraph
+ """
+ rValue = ""
+ line = caption
+ text = text.replace(2*NEWLINE_ESCAPE, NEWLINE_ESCAPE+" "+NEWLINE_ESCAPE)
+ words = text.split()
+ indentLevel = len(caption)+1
+
+ for w in words:
+ if line != "" and line[-1] == "\n":
+ rValue += line
+ line = " "*indentLevel
+ if len(line)+len(w.replace(NEWLINE_ESCAPE, ""))+1 > width:
+ rValue += line+"\n"
+ line = " "*indentLevel+w.replace(NEWLINE_ESCAPE, "\n")
+ elif w.find(NEWLINE_ESCAPE) >= 0:
+ if len(line.strip()) > 0:
+ rValue += line+" "+w.replace(NEWLINE_ESCAPE, "\n")
+ else:
+ rValue += line+w.replace(NEWLINE_ESCAPE, "\n")
+ line = " "*indentLevel
+ else:
+ if len(line.strip()) > 0:
+ line += " "+w
+ else:
+ line += w
+ if len(line) > 0:
+ rValue += line.replace(NEWLINE_ESCAPE, "\n")
+ rValue = rValue.replace(SPACE_ESCAPE, " ")
+ return rValue
+
+def get_glsa_list(myconfig):
+ """
+ Returns a list of all available GLSAs in the given repository
+ by comparing the filelist there with the pattern described in
+ the config.
+
+ @type myconfig: portage.config
+ @param myconfig: Portage settings instance
+
+ @rtype: List of Strings
+ @return: a list of GLSA IDs in this repository
+ """
+ rValue = []
+
+ if "GLSA_DIR" in myconfig:
+ repository = myconfig["GLSA_DIR"]
+ else:
+ repository = os.path.join(myconfig["PORTDIR"], "metadata", "glsa")
+
+ if not os.access(repository, os.R_OK):
+ return []
+ dirlist = os.listdir(repository)
+ prefix = "glsa-"
+ suffix = ".xml"
+
+ for f in dirlist:
+ try:
+ if f[:len(prefix)] == prefix:
+ rValue.append(f[len(prefix):-1*len(suffix)])
+ except IndexError:
+ pass
+ return rValue
+
+def getListElements(listnode):
+ """
+ Get all <li> elements for a given <ol> or <ul> node.
+
+ @type listnode: xml.dom.Node
+ @param listnode: <ul> or <ol> list to get the elements for
+ @rtype: List of Strings
+ @return: a list that contains the value of the <li> elements
+ """
+ rValue = []
+ if not listnode.nodeName in ["ul", "ol"]:
+ raise GlsaFormatException("Invalid function call: listnode is not <ul> or <ol>")
+ for li in listnode.childNodes:
+ if li.nodeType != xml.dom.Node.ELEMENT_NODE:
+ continue
+ rValue.append(getText(li, format="strip"))
+ return rValue
+
+def getText(node, format):
+ """
+ This is the main parser function. It takes a node and traverses
+ recursive over the subnodes, getting the text of each (and the
+ I{link} attribute for <uri> and <mail>). Depending on the I{format}
+ parameter the text might be formatted by adding/removing newlines,
+ tabs and spaces. This function is only useful for the GLSA DTD,
+ it's not applicable for other DTDs.
+
+ @type node: xml.dom.Node
+ @param node: the root node to start with the parsing
+ @type format: String
+ @param format: this should be either I{strip}, I{keep} or I{xml}
+ I{keep} just gets the text and does no formatting.
+ I{strip} replaces newlines and tabs with spaces and
+ replaces multiple spaces with one space.
+ I{xml} does some more formatting, depending on the
+ type of the encountered nodes.
+ @rtype: String
+ @return: the (formatted) content of the node and its subnodes
+ """
+ rValue = ""
+ if format in ["strip", "keep"]:
+ if node.nodeName in ["uri", "mail"]:
+ rValue += node.childNodes[0].data+": "+node.getAttribute("link")
+ else:
+ for subnode in node.childNodes:
+ if subnode.nodeName == "#text":
+ rValue += subnode.data
+ else:
+ rValue += getText(subnode, format)
+ else:
+ for subnode in node.childNodes:
+ if subnode.nodeName == "p":
+ for p_subnode in subnode.childNodes:
+ if p_subnode.nodeName == "#text":
+ rValue += p_subnode.data.strip()
+ elif p_subnode.nodeName in ["uri", "mail"]:
+ rValue += p_subnode.childNodes[0].data
+ rValue += " ( "+p_subnode.getAttribute("link")+" )"
+ rValue += NEWLINE_ESCAPE
+ elif subnode.nodeName == "ul":
+ for li in getListElements(subnode):
+ rValue += "-"+SPACE_ESCAPE+li+NEWLINE_ESCAPE+" "
+ elif subnode.nodeName == "ol":
+ i = 0
+ for li in getListElements(subnode):
+ i = i+1
+ rValue += str(i)+"."+SPACE_ESCAPE+li+NEWLINE_ESCAPE+" "
+ elif subnode.nodeName == "code":
+ rValue += getText(subnode, format="keep").replace("\n", NEWLINE_ESCAPE)
+ if rValue[-1*len(NEWLINE_ESCAPE):] != NEWLINE_ESCAPE:
+ rValue += NEWLINE_ESCAPE
+ elif subnode.nodeName == "#text":
+ rValue += subnode.data
+ else:
+ raise GlsaFormatException(_("Invalid Tag found: "), subnode.nodeName)
+ if format == "strip":
+ rValue = rValue.strip(" \n\t")
+ rValue = re.sub("[\s]{2,}", " ", rValue)
+ return rValue
+
+def getMultiTagsText(rootnode, tagname, format):
+ """
+ Returns a list with the text of all subnodes of type I{tagname}
+ under I{rootnode} (which itself is not parsed) using the given I{format}.
+
+ @type rootnode: xml.dom.Node
+ @param rootnode: the node to search for I{tagname}
+ @type tagname: String
+ @param tagname: the name of the tags to search for
+ @type format: String
+ @param format: see L{getText}
+ @rtype: List of Strings
+ @return: a list containing the text of all I{tagname} childnodes
+ """
+ rValue = []
+ for e in rootnode.getElementsByTagName(tagname):
+ rValue.append(getText(e, format))
+ return rValue
+
+def makeAtom(pkgname, versionNode):
+ """
+ creates from the given package name and information in the
+ I{versionNode} a (syntactical) valid portage atom.
+
+ @type pkgname: String
+ @param pkgname: the name of the package for this atom
+ @type versionNode: xml.dom.Node
+ @param versionNode: a <vulnerable> or <unaffected> Node that
+ contains the version information for this atom
+ @rtype: String
+ @return: the portage atom
+ """
+ rValue = opMapping[versionNode.getAttribute("range")] \
+ + pkgname \
+ + "-" + getText(versionNode, format="strip")
+ try:
+ slot = versionNode.getAttribute("slot").strip()
+ except KeyError:
+ pass
+ else:
+ if slot and slot != "*":
+ rValue += _slot_separator + slot
+ return str(rValue)
+
+def makeVersion(versionNode):
+ """
+ creates from the information in the I{versionNode} a
+ version string (format <op><version>).
+
+ @type versionNode: xml.dom.Node
+ @param versionNode: a <vulnerable> or <unaffected> Node that
+ contains the version information for this atom
+ @rtype: String
+ @return: the version string
+ """
+ rValue = opMapping[versionNode.getAttribute("range")] \
+ + getText(versionNode, format="strip")
+ try:
+ slot = versionNode.getAttribute("slot").strip()
+ except KeyError:
+ pass
+ else:
+ if slot and slot != "*":
+ rValue += _slot_separator + slot
+ return rValue
+
+def match(atom, dbapi, match_type="default"):
+ """
+ wrapper that calls revisionMatch() or portage.dbapi.dbapi.match() depending on
+ the given atom.
+
+ @type atom: string
+ @param atom: a <~ or >~ atom or a normal portage atom that contains the atom to match against
+ @type dbapi: portage.dbapi.dbapi
+ @param dbapi: one of the portage databases to use as information source
+ @type match_type: string
+ @param match_type: if != "default" passed as first argument to dbapi.xmatch
+ to apply the wanted visibility filters
+
+ @rtype: list of strings
+ @return: a list with the matching versions
+ """
+ if atom[2] == "~":
+ return revisionMatch(atom, dbapi, match_type=match_type)
+ elif match_type == "default" or not hasattr(dbapi, "xmatch"):
+ return dbapi.match(atom)
+ else:
+ return dbapi.xmatch(match_type, atom)
+
+def revisionMatch(revisionAtom, dbapi, match_type="default"):
+ """
+ handler for the special >~, >=~, <=~ and <~ atoms that are supposed to behave
+ as > and < except that they are limited to the same version, the range only
+ applies to the revision part.
+
+ @type revisionAtom: string
+ @param revisionAtom: a <~ or >~ atom that contains the atom to match against
+ @type dbapi: portage.dbapi.dbapi
+ @param dbapi: one of the portage databases to use as information source
+ @type match_type: string
+ @param match_type: if != "default" passed as first argument to portdb.xmatch
+ to apply the wanted visibility filters
+
+ @rtype: list of strings
+ @return: a list with the matching versions
+ """
+ if match_type == "default" or not hasattr(dbapi, "xmatch"):
+ if ":" in revisionAtom:
+ mylist = dbapi.match(re.sub(r'-r[0-9]+(:[^ ]+)?$', r'\1', revisionAtom[2:]))
+ else:
+ mylist = dbapi.match(re.sub("-r[0-9]+$", "", revisionAtom[2:]))
+ else:
+ if ":" in revisionAtom:
+ mylist = dbapi.xmatch(match_type, re.sub(r'-r[0-9]+(:[^ ]+)?$', r'\1', revisionAtom[2:]))
+ else:
+ mylist = dbapi.xmatch(match_type, re.sub("-r[0-9]+$", "", revisionAtom[2:]))
+ rValue = []
+ for v in mylist:
+ r1 = pkgsplit(v)[-1][1:]
+ r2 = pkgsplit(revisionAtom[3:])[-1][1:]
+ if eval(r1+" "+revisionAtom[0:2]+" "+r2):
+ rValue.append(v)
+ return rValue
+
+
+def getMinUpgrade(vulnerableList, unaffectedList, portdbapi, vardbapi, minimize=True):
+ """
+ Checks if the systemstate is matching an atom in
+ I{vulnerableList} and returns string describing
+ the lowest version for the package that matches an atom in
+ I{unaffectedList} and is greater than the currently installed
+ version or None if the system is not affected. Both
+ I{vulnerableList} and I{unaffectedList} should have the
+ same base package.
+
+ @type vulnerableList: List of Strings
+ @param vulnerableList: atoms matching vulnerable package versions
+ @type unaffectedList: List of Strings
+ @param unaffectedList: atoms matching unaffected package versions
+ @type portdbapi: portage.dbapi.porttree.portdbapi
+ @param portdbapi: Ebuild repository
+ @type vardbapi: portage.dbapi.vartree.vardbapi
+ @param vardbapi: Installed package repository
+ @type minimize: Boolean
+ @param minimize: True for a least-change upgrade, False for emerge-like algorithm
+
+ @rtype: String | None
+ @return: the lowest unaffected version that is greater than
+ the installed version.
+ """
+ rValue = None
+ v_installed = []
+ u_installed = []
+ for v in vulnerableList:
+ v_installed += match(v, vardbapi)
+
+ for u in unaffectedList:
+ u_installed += match(u, vardbapi)
+
+ install_unaffected = True
+ for i in v_installed:
+ if i not in u_installed:
+ install_unaffected = False
+
+ if install_unaffected:
+ return rValue
+
+ for u in unaffectedList:
+ mylist = match(u, portdbapi, match_type="match-all")
+ for c in mylist:
+ c_pv = catpkgsplit(c)
+ i_pv = catpkgsplit(best(v_installed))
+ if pkgcmp(c_pv[1:], i_pv[1:]) > 0 \
+ and (rValue == None \
+ or not match("="+rValue, portdbapi) \
+ or (minimize ^ (pkgcmp(c_pv[1:], catpkgsplit(rValue)[1:]) > 0)) \
+ and match("="+c, portdbapi)) \
+ and portdbapi.aux_get(c, ["SLOT"]) == vardbapi.aux_get(best(v_installed), ["SLOT"]):
+ rValue = c_pv[0]+"/"+c_pv[1]+"-"+c_pv[2]
+ if c_pv[3] != "r0": # we don't like -r0 for display
+ rValue += "-"+c_pv[3]
+ return rValue
+
+def format_date(datestr):
+ """
+ Takes a date (announced, revised) date from a GLSA and formats
+ it as readable text (i.e. "January 1, 2008").
+
+ @type date: String
+ @param date: the date string to reformat
+ @rtype: String
+ @return: a reformatted string, or the original string
+ if it cannot be reformatted.
+ """
+ splitdate = datestr.split("-", 2)
+ if len(splitdate) != 3:
+ return datestr
+
+ # This cannot raise an error as we use () instead of []
+ splitdate = (int(x) for x in splitdate)
+
+ from datetime import date
+ try:
+ d = date(*splitdate)
+ except ValueError:
+ return datestr
+
+ # TODO We could format to local date format '%x' here?
+ return _unicode_decode(d.strftime("%B %d, %Y"),
+ encoding=_encodings['content'], errors='replace')
+
+# simple Exception classes to catch specific errors
+class GlsaTypeException(Exception):
+ def __init__(self, doctype):
+ Exception.__init__(self, "wrong DOCTYPE: %s" % doctype)
+
+class GlsaFormatException(Exception):
+ pass
+
+class GlsaArgumentException(Exception):
+ pass
+
+# GLSA xml data wrapper class
+class Glsa:
+ """
+ This class is a wrapper for the XML data and provides methods to access
+ and display the contained data.
+ """
+ def __init__(self, myid, myconfig, vardbapi, portdbapi):
+ """
+ Simple constructor to set the ID, store the config and gets the
+ XML data by calling C{self.read()}.
+
+ @type myid: String
+ @param myid: String describing the id for the GLSA object (standard
+ GLSAs have an ID of the form YYYYMM-nn) or an existing
+ filename containing a GLSA.
+ @type myconfig: portage.config
+ @param myconfig: the config that should be used for this object.
+ @type vardbapi: portage.dbapi.vartree.vardbapi
+ @param vardbapi: installed package repository
+ @type portdbapi: portage.dbapi.porttree.portdbapi
+ @param portdbapi: ebuild repository
+ """
+ myid = _unicode_decode(myid,
+ encoding=_encodings['content'], errors='strict')
+ if re.match(r'\d{6}-\d{2}', myid):
+ self.type = "id"
+ elif os.path.exists(myid):
+ self.type = "file"
+ else:
+ raise GlsaArgumentException(_("Given ID %s isn't a valid GLSA ID or filename.") % myid)
+ self.nr = myid
+ self.config = myconfig
+ self.vardbapi = vardbapi
+ self.portdbapi = portdbapi
+ self.read()
+
+ def read(self):
+ """
+ Here we build the filename from the config and the ID and pass
+ it to urllib to fetch it from the filesystem or a remote server.
+
+ @rtype: None
+ @return: None
+ """
+ if "GLSA_DIR" in self.config:
+ repository = "file://" + self.config["GLSA_DIR"]+"/"
+ else:
+ repository = "file://" + self.config["PORTDIR"] + "/metadata/glsa/"
+ if self.type == "file":
+ myurl = "file://"+self.nr
+ else:
+ myurl = repository + "glsa-%s.xml" % str(self.nr)
+ self.parse(urllib_request_urlopen(myurl))
+ return None
+
+ def parse(self, myfile):
+ """
+ This method parses the XML file and sets up the internal data
+ structures by calling the different helper functions in this
+ module.
+
+ @type myfile: String
+ @param myfile: Filename to grab the XML data from
+ @rtype: None
+ @returns: None
+ """
+ self.DOM = xml.dom.minidom.parse(myfile)
+ if not self.DOM.doctype:
+ raise GlsaTypeException(None)
+ elif self.DOM.doctype.systemId == "http://www.gentoo.org/dtd/glsa.dtd":
+ self.dtdversion = 0
+ elif self.DOM.doctype.systemId == "http://www.gentoo.org/dtd/glsa-2.dtd":
+ self.dtdversion = 2
+ else:
+ raise GlsaTypeException(self.DOM.doctype.systemId)
+ myroot = self.DOM.getElementsByTagName("glsa")[0]
+ if self.type == "id" and myroot.getAttribute("id") != self.nr:
+ raise GlsaFormatException(_("filename and internal id don't match:") + myroot.getAttribute("id") + " != " + self.nr)
+
+ # the simple (single, required, top-level, #PCDATA) tags first
+ self.title = getText(myroot.getElementsByTagName("title")[0], format="strip")
+ self.synopsis = getText(myroot.getElementsByTagName("synopsis")[0], format="strip")
+ self.announced = format_date(getText(myroot.getElementsByTagName("announced")[0], format="strip"))
+
+ count = 1
+ # Support both formats of revised:
+ # <revised>December 30, 2007: 02</revised>
+ # <revised count="2">2007-12-30</revised>
+ revisedEl = myroot.getElementsByTagName("revised")[0]
+ self.revised = getText(revisedEl, format="strip")
+ if ((sys.hexversion >= 0x3000000 and "count" in revisedEl.attributes) or
+ (sys.hexversion < 0x3000000 and revisedEl.attributes.has_key("count"))):
+ count = revisedEl.getAttribute("count")
+ elif (self.revised.find(":") >= 0):
+ (self.revised, count) = self.revised.split(":")
+
+ self.revised = format_date(self.revised)
+
+ try:
+ self.count = int(count)
+ except ValueError:
+ # TODO should this raise a GlsaFormatException?
+ self.count = 1
+
+ # now the optional and 0-n toplevel, #PCDATA tags and references
+ try:
+ self.access = getText(myroot.getElementsByTagName("access")[0], format="strip")
+ except IndexError:
+ self.access = ""
+ self.bugs = getMultiTagsText(myroot, "bug", format="strip")
+ self.references = getMultiTagsText(myroot.getElementsByTagName("references")[0], "uri", format="keep")
+
+ # and now the formatted text elements
+ self.description = getText(myroot.getElementsByTagName("description")[0], format="xml")
+ self.workaround = getText(myroot.getElementsByTagName("workaround")[0], format="xml")
+ self.resolution = getText(myroot.getElementsByTagName("resolution")[0], format="xml")
+ self.impact_text = getText(myroot.getElementsByTagName("impact")[0], format="xml")
+ self.impact_type = myroot.getElementsByTagName("impact")[0].getAttribute("type")
+ try:
+ self.background = getText(myroot.getElementsByTagName("background")[0], format="xml")
+ except IndexError:
+ self.background = ""
+
+ # finally the interesting tags (product, affected, package)
+ self.glsatype = myroot.getElementsByTagName("product")[0].getAttribute("type")
+ self.product = getText(myroot.getElementsByTagName("product")[0], format="strip")
+ self.affected = myroot.getElementsByTagName("affected")[0]
+ self.packages = {}
+ for p in self.affected.getElementsByTagName("package"):
+ name = p.getAttribute("name")
+ try:
+ name = portage.dep.Atom(name)
+ except portage.exception.InvalidAtom:
+ raise GlsaFormatException(_("invalid package name: %s") % name)
+ if name != name.cp:
+ raise GlsaFormatException(_("invalid package name: %s") % name)
+ name = name.cp
+ if name not in self.packages:
+ self.packages[name] = []
+ tmp = {}
+ tmp["arch"] = p.getAttribute("arch")
+ tmp["auto"] = (p.getAttribute("auto") == "yes")
+ tmp["vul_vers"] = [makeVersion(v) for v in p.getElementsByTagName("vulnerable")]
+ tmp["unaff_vers"] = [makeVersion(v) for v in p.getElementsByTagName("unaffected")]
+ tmp["vul_atoms"] = [makeAtom(name, v) for v in p.getElementsByTagName("vulnerable")]
+ tmp["unaff_atoms"] = [makeAtom(name, v) for v in p.getElementsByTagName("unaffected")]
+ self.packages[name].append(tmp)
+ # TODO: services aren't really used yet
+ self.services = self.affected.getElementsByTagName("service")
+ return None
+
+ def dump(self, outstream=sys.stdout):
+ """
+ Dumps a plaintext representation of this GLSA to I{outfile} or
+ B{stdout} if it is ommitted. You can specify an alternate
+ I{encoding} if needed (default is latin1).
+
+ @type outstream: File
+ @param outfile: Stream that should be used for writing
+ (defaults to sys.stdout)
+ """
+ width = 76
+ outstream.write(("GLSA %s: \n%s" % (self.nr, self.title)).center(width)+"\n")
+ outstream.write((width*"=")+"\n")
+ outstream.write(wrap(self.synopsis, width, caption=_("Synopsis: "))+"\n")
+ outstream.write(_("Announced on: %s\n") % self.announced)
+ outstream.write(_("Last revised on: %s : %02d\n\n") % (self.revised, self.count))
+ if self.glsatype == "ebuild":
+ for k in self.packages:
+ pkg = self.packages[k]
+ for path in pkg:
+ vul_vers = "".join(path["vul_vers"])
+ unaff_vers = "".join(path["unaff_vers"])
+ outstream.write(_("Affected package: %s\n") % k)
+ outstream.write(_("Affected archs: "))
+ if path["arch"] == "*":
+ outstream.write(_("All\n"))
+ else:
+ outstream.write("%s\n" % path["arch"])
+ outstream.write(_("Vulnerable: %s\n") % vul_vers)
+ outstream.write(_("Unaffected: %s\n\n") % unaff_vers)
+ elif self.glsatype == "infrastructure":
+ pass
+ if len(self.bugs) > 0:
+ outstream.write(_("\nRelated bugs: "))
+ for i in range(0, len(self.bugs)):
+ outstream.write(self.bugs[i])
+ if i < len(self.bugs)-1:
+ outstream.write(", ")
+ else:
+ outstream.write("\n")
+ if self.background:
+ outstream.write("\n"+wrap(self.background, width, caption=_("Background: ")))
+ outstream.write("\n"+wrap(self.description, width, caption=_("Description: ")))
+ outstream.write("\n"+wrap(self.impact_text, width, caption=_("Impact: ")))
+ outstream.write("\n"+wrap(self.workaround, width, caption=_("Workaround: ")))
+ outstream.write("\n"+wrap(self.resolution, width, caption=_("Resolution: ")))
+ myreferences = ""
+ for r in self.references:
+ myreferences += (r.replace(" ", SPACE_ESCAPE)+NEWLINE_ESCAPE+" ")
+ outstream.write("\n"+wrap(myreferences, width, caption=_("References: ")))
+ outstream.write("\n")
+
+ def isVulnerable(self):
+ """
+ Tests if the system is affected by this GLSA by checking if any
+ vulnerable package versions are installed. Also checks for affected
+ architectures.
+
+ @rtype: Boolean
+ @returns: True if the system is affected, False if not
+ """
+ rValue = False
+ for k in self.packages:
+ pkg = self.packages[k]
+ for path in pkg:
+ if path["arch"] == "*" or self.config["ARCH"] in path["arch"].split():
+ for v in path["vul_atoms"]:
+ rValue = rValue \
+ or (len(match(v, self.vardbapi)) > 0 \
+ and getMinUpgrade(path["vul_atoms"], path["unaff_atoms"], \
+ self.portdbapi, self.vardbapi))
+ return rValue
+
+ def isApplied(self):
+ """
+ Looks if the GLSA IDis in the GLSA checkfile to check if this
+ GLSA was already applied.
+
+ @rtype: Boolean
+ @returns: True if the GLSA was applied, False if not
+ """
+ return (self.nr in get_applied_glsas(self.config))
+
+ def inject(self):
+ """
+ Puts the ID of this GLSA into the GLSA checkfile, so it won't
+ show up on future checks. Should be called after a GLSA is
+ applied or on explicit user request.
+
+ @rtype: None
+ @returns: None
+ """
+ if not self.isApplied():
+ checkfile = io.open(
+ _unicode_encode(os.path.join(self.config["EROOT"],
+ CACHE_PATH, "glsa"),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='a+', encoding=_encodings['content'], errors='strict')
+ checkfile.write(_unicode_decode(self.nr + "\n"))
+ checkfile.close()
+ return None
+
+ def getMergeList(self, least_change=True):
+ """
+ Returns the list of package-versions that have to be merged to
+ apply this GLSA properly. The versions are as low as possible
+ while avoiding downgrades (see L{getMinUpgrade}).
+
+ @type least_change: Boolean
+ @param least_change: True if the smallest possible upgrade should be selected,
+ False for an emerge-like algorithm
+ @rtype: List of Strings
+ @return: list of package-versions that have to be merged
+ """
+ rValue = []
+ for pkg in self.packages:
+ for path in self.packages[pkg]:
+ update = getMinUpgrade(path["vul_atoms"], path["unaff_atoms"], \
+ self.portdbapi, self.vardbapi, minimize=least_change)
+ if update:
+ rValue.append(update)
+ return rValue
diff --git a/portage_with_autodep/pym/portage/localization.py b/portage_with_autodep/pym/portage/localization.py
new file mode 100644
index 0000000..d16c4b1
--- /dev/null
+++ b/portage_with_autodep/pym/portage/localization.py
@@ -0,0 +1,20 @@
+# localization.py -- Code to manage/help portage localization.
+# Copyright 2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+
+# We define this to make the transition easier for us.
+def _(mystr):
+ return mystr
+
+
+def localization_example():
+ # Dict references allow translators to rearrange word order.
+ print(_("You can use this string for translating."))
+ print(_("Strings can be formatted with %(mystr)s like this.") % {"mystr": "VALUES"})
+
+ a_value = "value.of.a"
+ b_value = 123
+ c_value = [1,2,3,4]
+ print(_("A: %(a)s -- B: %(b)s -- C: %(c)s") % {"a":a_value,"b":b_value,"c":c_value})
+
diff --git a/portage_with_autodep/pym/portage/locks.py b/portage_with_autodep/pym/portage/locks.py
new file mode 100644
index 0000000..9ed1d6a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/locks.py
@@ -0,0 +1,395 @@
+# portage: Lock management code
+# Copyright 2004-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ["lockdir", "unlockdir", "lockfile", "unlockfile", \
+ "hardlock_name", "hardlink_is_mine", "hardlink_lockfile", \
+ "unhardlink_lockfile", "hardlock_cleanup"]
+
+import errno
+import fcntl
+import stat
+import sys
+import time
+
+import portage
+from portage import os
+from portage.const import PORTAGE_BIN_PATH
+from portage.exception import DirectoryNotFound, FileNotFound, \
+ InvalidData, TryAgain, OperationNotPermitted, PermissionDenied
+from portage.data import portage_gid
+from portage.util import writemsg
+from portage.localization import _
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+HARDLINK_FD = -2
+_default_lock_fn = fcntl.lockf
+
+# Used by emerge in order to disable the "waiting for lock" message
+# so that it doesn't interfere with the status display.
+_quiet = False
+
+def lockdir(mydir, flags=0):
+ return lockfile(mydir, wantnewlockfile=1, flags=flags)
+def unlockdir(mylock):
+ return unlockfile(mylock)
+
+def lockfile(mypath, wantnewlockfile=0, unlinkfile=0,
+ waiting_msg=None, flags=0):
+ """
+ If wantnewlockfile is True then this creates a lockfile in the parent
+ directory as the file: '.' + basename + '.portage_lockfile'.
+ """
+
+ if not mypath:
+ raise InvalidData(_("Empty path given"))
+
+ if isinstance(mypath, basestring) and mypath[-1] == '/':
+ mypath = mypath[:-1]
+
+ if hasattr(mypath, 'fileno'):
+ mypath = mypath.fileno()
+ if isinstance(mypath, int):
+ lockfilename = mypath
+ wantnewlockfile = 0
+ unlinkfile = 0
+ elif wantnewlockfile:
+ base, tail = os.path.split(mypath)
+ lockfilename = os.path.join(base, "." + tail + ".portage_lockfile")
+ del base, tail
+ unlinkfile = 1
+ else:
+ lockfilename = mypath
+
+ if isinstance(mypath, basestring):
+ if not os.path.exists(os.path.dirname(mypath)):
+ raise DirectoryNotFound(os.path.dirname(mypath))
+ preexisting = os.path.exists(lockfilename)
+ old_mask = os.umask(000)
+ try:
+ try:
+ myfd = os.open(lockfilename, os.O_CREAT|os.O_RDWR, 0o660)
+ except OSError as e:
+ func_call = "open('%s')" % lockfilename
+ if e.errno == OperationNotPermitted.errno:
+ raise OperationNotPermitted(func_call)
+ elif e.errno == PermissionDenied.errno:
+ raise PermissionDenied(func_call)
+ else:
+ raise
+
+ if not preexisting:
+ try:
+ if os.stat(lockfilename).st_gid != portage_gid:
+ os.chown(lockfilename, -1, portage_gid)
+ except OSError as e:
+ if e.errno in (errno.ENOENT, errno.ESTALE):
+ return lockfile(mypath,
+ wantnewlockfile=wantnewlockfile,
+ unlinkfile=unlinkfile, waiting_msg=waiting_msg,
+ flags=flags)
+ else:
+ writemsg("%s: chown('%s', -1, %d)\n" % \
+ (e, lockfilename, portage_gid), noiselevel=-1)
+ writemsg(_("Cannot chown a lockfile: '%s'\n") % \
+ lockfilename, noiselevel=-1)
+ writemsg(_("Group IDs of current user: %s\n") % \
+ " ".join(str(n) for n in os.getgroups()),
+ noiselevel=-1)
+ finally:
+ os.umask(old_mask)
+
+ elif isinstance(mypath, int):
+ myfd = mypath
+
+ else:
+ raise ValueError(_("Unknown type passed in '%s': '%s'") % \
+ (type(mypath), mypath))
+
+ # try for a non-blocking lock, if it's held, throw a message
+ # we're waiting on lockfile and use a blocking attempt.
+ locking_method = _default_lock_fn
+ try:
+ locking_method(myfd, fcntl.LOCK_EX|fcntl.LOCK_NB)
+ except IOError as e:
+ if not hasattr(e, "errno"):
+ raise
+ if e.errno in (errno.EACCES, errno.EAGAIN):
+ # resource temp unavailable; eg, someone beat us to the lock.
+ if flags & os.O_NONBLOCK:
+ os.close(myfd)
+ raise TryAgain(mypath)
+
+ global _quiet
+ if _quiet:
+ out = None
+ else:
+ out = portage.output.EOutput()
+ if waiting_msg is None:
+ if isinstance(mypath, int):
+ waiting_msg = _("waiting for lock on fd %i") % myfd
+ else:
+ waiting_msg = _("waiting for lock on %s\n") % lockfilename
+ if out is not None:
+ out.ebegin(waiting_msg)
+ # try for the exclusive lock now.
+ try:
+ locking_method(myfd, fcntl.LOCK_EX)
+ except EnvironmentError as e:
+ if out is not None:
+ out.eend(1, str(e))
+ raise
+ if out is not None:
+ out.eend(os.EX_OK)
+ elif e.errno == errno.ENOLCK:
+ # We're not allowed to lock on this FS.
+ os.close(myfd)
+ link_success = False
+ if lockfilename == str(lockfilename):
+ if wantnewlockfile:
+ try:
+ if os.stat(lockfilename)[stat.ST_NLINK] == 1:
+ os.unlink(lockfilename)
+ except OSError:
+ pass
+ link_success = hardlink_lockfile(lockfilename)
+ if not link_success:
+ raise
+ locking_method = None
+ myfd = HARDLINK_FD
+ else:
+ raise
+
+
+ if isinstance(lockfilename, basestring) and \
+ myfd != HARDLINK_FD and _fstat_nlink(myfd) == 0:
+ # The file was deleted on us... Keep trying to make one...
+ os.close(myfd)
+ writemsg(_("lockfile recurse\n"), 1)
+ lockfilename, myfd, unlinkfile, locking_method = lockfile(
+ mypath, wantnewlockfile=wantnewlockfile, unlinkfile=unlinkfile,
+ waiting_msg=waiting_msg, flags=flags)
+
+ writemsg(str((lockfilename,myfd,unlinkfile))+"\n",1)
+ return (lockfilename,myfd,unlinkfile,locking_method)
+
+def _fstat_nlink(fd):
+ """
+ @param fd: an open file descriptor
+ @type fd: Integer
+ @rtype: Integer
+ @return: the current number of hardlinks to the file
+ """
+ try:
+ return os.fstat(fd).st_nlink
+ except EnvironmentError as e:
+ if e.errno in (errno.ENOENT, errno.ESTALE):
+ # Some filesystems such as CIFS return
+ # ENOENT which means st_nlink == 0.
+ return 0
+ raise
+
+def unlockfile(mytuple):
+
+ #XXX: Compatability hack.
+ if len(mytuple) == 3:
+ lockfilename,myfd,unlinkfile = mytuple
+ locking_method = fcntl.flock
+ elif len(mytuple) == 4:
+ lockfilename,myfd,unlinkfile,locking_method = mytuple
+ else:
+ raise InvalidData
+
+ if(myfd == HARDLINK_FD):
+ unhardlink_lockfile(lockfilename)
+ return True
+
+ # myfd may be None here due to myfd = mypath in lockfile()
+ if isinstance(lockfilename, basestring) and \
+ not os.path.exists(lockfilename):
+ writemsg(_("lockfile does not exist '%s'\n") % lockfilename,1)
+ if myfd is not None:
+ os.close(myfd)
+ return False
+
+ try:
+ if myfd is None:
+ myfd = os.open(lockfilename, os.O_WRONLY,0o660)
+ unlinkfile = 1
+ locking_method(myfd,fcntl.LOCK_UN)
+ except OSError:
+ if isinstance(lockfilename, basestring):
+ os.close(myfd)
+ raise IOError(_("Failed to unlock file '%s'\n") % lockfilename)
+
+ try:
+ # This sleep call was added to allow other processes that are
+ # waiting for a lock to be able to grab it before it is deleted.
+ # lockfile() already accounts for this situation, however, and
+ # the sleep here adds more time than is saved overall, so am
+ # commenting until it is proved necessary.
+ #time.sleep(0.0001)
+ if unlinkfile:
+ locking_method(myfd,fcntl.LOCK_EX|fcntl.LOCK_NB)
+ # We won the lock, so there isn't competition for it.
+ # We can safely delete the file.
+ writemsg(_("Got the lockfile...\n"), 1)
+ if _fstat_nlink(myfd) == 1:
+ os.unlink(lockfilename)
+ writemsg(_("Unlinked lockfile...\n"), 1)
+ locking_method(myfd,fcntl.LOCK_UN)
+ else:
+ writemsg(_("lockfile does not exist '%s'\n") % lockfilename, 1)
+ os.close(myfd)
+ return False
+ except SystemExit:
+ raise
+ except Exception as e:
+ writemsg(_("Failed to get lock... someone took it.\n"), 1)
+ writemsg(str(e)+"\n",1)
+
+ # why test lockfilename? because we may have been handed an
+ # fd originally, and the caller might not like having their
+ # open fd closed automatically on them.
+ if isinstance(lockfilename, basestring):
+ os.close(myfd)
+
+ return True
+
+
+
+
+def hardlock_name(path):
+ return path+".hardlock-"+os.uname()[1]+"-"+str(os.getpid())
+
+def hardlink_is_mine(link,lock):
+ try:
+ return os.stat(link).st_nlink == 2
+ except OSError:
+ return False
+
+def hardlink_lockfile(lockfilename, max_wait=14400):
+ """Does the NFS, hardlink shuffle to ensure locking on the disk.
+ We create a PRIVATE lockfile, that is just a placeholder on the disk.
+ Then we HARDLINK the real lockfile to that private file.
+ If our file can 2 references, then we have the lock. :)
+ Otherwise we lather, rise, and repeat.
+ We default to a 4 hour timeout.
+ """
+
+ start_time = time.time()
+ myhardlock = hardlock_name(lockfilename)
+ reported_waiting = False
+
+ while(time.time() < (start_time + max_wait)):
+ # We only need it to exist.
+ myfd = os.open(myhardlock, os.O_CREAT|os.O_RDWR,0o660)
+ os.close(myfd)
+
+ if not os.path.exists(myhardlock):
+ raise FileNotFound(
+ _("Created lockfile is missing: %(filename)s") % \
+ {"filename" : myhardlock})
+
+ try:
+ res = os.link(myhardlock, lockfilename)
+ except OSError:
+ pass
+
+ if hardlink_is_mine(myhardlock, lockfilename):
+ # We have the lock.
+ if reported_waiting:
+ writemsg("\n", noiselevel=-1)
+ return True
+
+ if reported_waiting:
+ writemsg(".", noiselevel=-1)
+ else:
+ reported_waiting = True
+ msg = _("\nWaiting on (hardlink) lockfile: (one '.' per 3 seconds)\n"
+ "%(bin_path)s/clean_locks can fix stuck locks.\n"
+ "Lockfile: %(lockfilename)s\n") % \
+ {"bin_path": PORTAGE_BIN_PATH, "lockfilename": lockfilename}
+ writemsg(msg, noiselevel=-1)
+ time.sleep(3)
+
+ os.unlink(myhardlock)
+ return False
+
+def unhardlink_lockfile(lockfilename):
+ myhardlock = hardlock_name(lockfilename)
+ if hardlink_is_mine(myhardlock, lockfilename):
+ # Make sure not to touch lockfilename unless we really have a lock.
+ try:
+ os.unlink(lockfilename)
+ except OSError:
+ pass
+ try:
+ os.unlink(myhardlock)
+ except OSError:
+ pass
+
+def hardlock_cleanup(path, remove_all_locks=False):
+ mypid = str(os.getpid())
+ myhost = os.uname()[1]
+ mydl = os.listdir(path)
+
+ results = []
+ mycount = 0
+
+ mylist = {}
+ for x in mydl:
+ if os.path.isfile(path+"/"+x):
+ parts = x.split(".hardlock-")
+ if len(parts) == 2:
+ filename = parts[0]
+ hostpid = parts[1].split("-")
+ host = "-".join(hostpid[:-1])
+ pid = hostpid[-1]
+
+ if filename not in mylist:
+ mylist[filename] = {}
+ if host not in mylist[filename]:
+ mylist[filename][host] = []
+ mylist[filename][host].append(pid)
+
+ mycount += 1
+
+
+ results.append(_("Found %(count)s locks") % {"count":mycount})
+
+ for x in mylist:
+ if myhost in mylist[x] or remove_all_locks:
+ mylockname = hardlock_name(path+"/"+x)
+ if hardlink_is_mine(mylockname, path+"/"+x) or \
+ not os.path.exists(path+"/"+x) or \
+ remove_all_locks:
+ for y in mylist[x]:
+ for z in mylist[x][y]:
+ filename = path+"/"+x+".hardlock-"+y+"-"+z
+ if filename == mylockname:
+ continue
+ try:
+ # We're sweeping through, unlinking everyone's locks.
+ os.unlink(filename)
+ results.append(_("Unlinked: ") + filename)
+ except OSError:
+ pass
+ try:
+ os.unlink(path+"/"+x)
+ results.append(_("Unlinked: ") + path+"/"+x)
+ os.unlink(mylockname)
+ results.append(_("Unlinked: ") + mylockname)
+ except OSError:
+ pass
+ else:
+ try:
+ os.unlink(mylockname)
+ results.append(_("Unlinked: ") + mylockname)
+ except OSError:
+ pass
+
+ return results
+
diff --git a/portage_with_autodep/pym/portage/mail.py b/portage_with_autodep/pym/portage/mail.py
new file mode 100644
index 0000000..17dfcaf
--- /dev/null
+++ b/portage_with_autodep/pym/portage/mail.py
@@ -0,0 +1,177 @@
+# Copyright 1998-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# Since python ebuilds remove the 'email' module when USE=build
+# is enabled, use a local import so that
+# portage.proxy.lazyimport._preload_portage_submodules()
+# can load this module even though the 'email' module is missing.
+# The elog mail modules won't work, but at least an ImportError
+# won't cause portage to crash during stage builds. Since the
+# 'smtlib' module imports the 'email' module, that's imported
+# locally as well.
+
+import socket
+import sys
+import time
+
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode, _unicode_encode
+from portage.localization import _
+import portage
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+ def _force_ascii_if_necessary(s):
+ # Force ascii encoding in order to avoid UnicodeEncodeError
+ # from smtplib.sendmail with python3 (bug #291331).
+ s = _unicode_encode(s,
+ encoding='ascii', errors='backslashreplace')
+ s = _unicode_decode(s,
+ encoding='ascii', errors='replace')
+ return s
+
+else:
+
+ def _force_ascii_if_necessary(s):
+ return s
+
+def TextMessage(_text):
+ from email.mime.text import MIMEText
+ mimetext = MIMEText(_text)
+ if sys.hexversion >= 0x3000000:
+ mimetext.set_charset("UTF-8")
+ return mimetext
+
+def create_message(sender, recipient, subject, body, attachments=None):
+
+ from email.header import Header
+ from email.mime.base import MIMEBase as BaseMessage
+ from email.mime.multipart import MIMEMultipart as MultipartMessage
+
+ if sys.hexversion < 0x3000000:
+ sender = _unicode_encode(sender,
+ encoding=_encodings['content'], errors='strict')
+ recipient = _unicode_encode(recipient,
+ encoding=_encodings['content'], errors='strict')
+ subject = _unicode_encode(subject,
+ encoding=_encodings['content'], errors='backslashreplace')
+ body = _unicode_encode(body,
+ encoding=_encodings['content'], errors='backslashreplace')
+
+ if attachments == None:
+ mymessage = TextMessage(body)
+ else:
+ mymessage = MultipartMessage()
+ mymessage.attach(TextMessage(body))
+ for x in attachments:
+ if isinstance(x, BaseMessage):
+ mymessage.attach(x)
+ elif isinstance(x, basestring):
+ if sys.hexversion < 0x3000000:
+ x = _unicode_encode(x,
+ encoding=_encodings['content'],
+ errors='backslashreplace')
+ mymessage.attach(TextMessage(x))
+ else:
+ raise portage.exception.PortageException(_("Can't handle type of attachment: %s") % type(x))
+
+ mymessage.set_unixfrom(sender)
+ mymessage["To"] = recipient
+ mymessage["From"] = sender
+
+ # Use Header as a workaround so that long subject lines are wrapped
+ # correctly by <=python-2.6 (gentoo bug #263370, python issue #1974).
+ # Also, need to force ascii for python3, in order to avoid
+ # UnicodeEncodeError with non-ascii characters:
+ # File "/usr/lib/python3.1/email/header.py", line 189, in __init__
+ # self.append(s, charset, errors)
+ # File "/usr/lib/python3.1/email/header.py", line 262, in append
+ # input_bytes = s.encode(input_charset, errors)
+ #UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-9: ordinal not in range(128)
+ mymessage["Subject"] = Header(_force_ascii_if_necessary(subject))
+ mymessage["Date"] = time.strftime("%a, %d %b %Y %H:%M:%S %z")
+
+ return mymessage
+
+def send_mail(mysettings, message):
+
+ import smtplib
+
+ mymailhost = "localhost"
+ mymailport = 25
+ mymailuser = ""
+ mymailpasswd = ""
+ myrecipient = "root@localhost"
+
+ # Syntax for PORTAGE_ELOG_MAILURI (if defined):
+ # address [[user:passwd@]mailserver[:port]]
+ # where address: recipient address
+ # user: username for smtp auth (defaults to none)
+ # passwd: password for smtp auth (defaults to none)
+ # mailserver: smtp server that should be used to deliver the mail (defaults to localhost)
+ # alternatively this can also be the absolute path to a sendmail binary if you don't want to use smtp
+ # port: port to use on the given smtp server (defaults to 25, values > 100000 indicate that starttls should be used on (port-100000))
+ if " " in mysettings.get("PORTAGE_ELOG_MAILURI", ""):
+ myrecipient, mymailuri = mysettings["PORTAGE_ELOG_MAILURI"].split()
+ if "@" in mymailuri:
+ myauthdata, myconndata = mymailuri.rsplit("@", 1)
+ try:
+ mymailuser,mymailpasswd = myauthdata.split(":")
+ except ValueError:
+ print(_("!!! invalid SMTP AUTH configuration, trying unauthenticated ..."))
+ else:
+ myconndata = mymailuri
+ if ":" in myconndata:
+ mymailhost,mymailport = myconndata.split(":")
+ else:
+ mymailhost = myconndata
+ else:
+ myrecipient = mysettings.get("PORTAGE_ELOG_MAILURI", "")
+
+ myfrom = message.get("From")
+
+ if sys.hexversion < 0x3000000:
+ myrecipient = _unicode_encode(myrecipient,
+ encoding=_encodings['content'], errors='strict')
+ mymailhost = _unicode_encode(mymailhost,
+ encoding=_encodings['content'], errors='strict')
+ mymailport = _unicode_encode(mymailport,
+ encoding=_encodings['content'], errors='strict')
+ myfrom = _unicode_encode(myfrom,
+ encoding=_encodings['content'], errors='strict')
+ mymailuser = _unicode_encode(mymailuser,
+ encoding=_encodings['content'], errors='strict')
+ mymailpasswd = _unicode_encode(mymailpasswd,
+ encoding=_encodings['content'], errors='strict')
+
+ # user wants to use a sendmail binary instead of smtp
+ if mymailhost[0] == os.sep and os.path.exists(mymailhost):
+ fd = os.popen(mymailhost+" -f "+myfrom+" "+myrecipient, "w")
+ fd.write(_force_ascii_if_necessary(message.as_string()))
+ if fd.close() != None:
+ sys.stderr.write(_("!!! %s returned with a non-zero exit code. This generally indicates an error.\n") % mymailhost)
+ else:
+ try:
+ if int(mymailport) > 100000:
+ myconn = smtplib.SMTP(mymailhost, int(mymailport) - 100000)
+ myconn.ehlo()
+ if not myconn.has_extn("STARTTLS"):
+ raise portage.exception.PortageException(_("!!! TLS support requested for logmail but not supported by server"))
+ myconn.starttls()
+ myconn.ehlo()
+ else:
+ myconn = smtplib.SMTP(mymailhost, mymailport)
+ if mymailuser != "" and mymailpasswd != "":
+ myconn.login(mymailuser, mymailpasswd)
+
+ message_str = _force_ascii_if_necessary(message.as_string())
+ myconn.sendmail(myfrom, myrecipient, message_str)
+ myconn.quit()
+ except smtplib.SMTPException as e:
+ raise portage.exception.PortageException(_("!!! An error occurred while trying to send logmail:\n")+str(e))
+ except socket.error as e:
+ raise portage.exception.PortageException(_("!!! A network error occurred while trying to send logmail:\n%s\nSure you configured PORTAGE_ELOG_MAILURI correctly?") % str(e))
+ return
+
diff --git a/portage_with_autodep/pym/portage/manifest.py b/portage_with_autodep/pym/portage/manifest.py
new file mode 100644
index 0000000..13efab7
--- /dev/null
+++ b/portage_with_autodep/pym/portage/manifest.py
@@ -0,0 +1,538 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import errno
+import io
+
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.checksum:hashfunc_map,perform_multiple_checksums,verify_all',
+ 'portage.util:write_atomic',
+)
+
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+from portage.exception import DigestException, FileNotFound, \
+ InvalidDataType, MissingParameter, PermissionDenied, \
+ PortageException, PortagePackageException
+from portage.localization import _
+
+class FileNotInManifestException(PortageException):
+ pass
+
+def manifest2AuxfileFilter(filename):
+ filename = filename.strip(os.sep)
+ mysplit = filename.split(os.path.sep)
+ if "CVS" in mysplit:
+ return False
+ for x in mysplit:
+ if x[:1] == '.':
+ return False
+ return not filename[:7] == 'digest-'
+
+def manifest2MiscfileFilter(filename):
+ filename = filename.strip(os.sep)
+ return not (filename in ["CVS", ".svn", "files", "Manifest"] or filename.endswith(".ebuild"))
+
+def guessManifestFileType(filename):
+ """ Perform a best effort guess of which type the given filename is, avoid using this if possible """
+ if filename.startswith("files" + os.sep + "digest-"):
+ return None
+ if filename.startswith("files" + os.sep):
+ return "AUX"
+ elif filename.endswith(".ebuild"):
+ return "EBUILD"
+ elif filename in ["ChangeLog", "metadata.xml"]:
+ return "MISC"
+ else:
+ return "DIST"
+
+def parseManifest2(mysplit):
+ myentry = None
+ if len(mysplit) > 4 and mysplit[0] in portage.const.MANIFEST2_IDENTIFIERS:
+ mytype = mysplit[0]
+ myname = mysplit[1]
+ try:
+ mysize = int(mysplit[2])
+ except ValueError:
+ return None
+ myhashes = dict(zip(mysplit[3::2], mysplit[4::2]))
+ myhashes["size"] = mysize
+ myentry = Manifest2Entry(type=mytype, name=myname, hashes=myhashes)
+ return myentry
+
+class ManifestEntry(object):
+ __slots__ = ("type", "name", "hashes")
+ def __init__(self, **kwargs):
+ for k, v in kwargs.items():
+ setattr(self, k, v)
+
+class Manifest2Entry(ManifestEntry):
+ def __str__(self):
+ myline = " ".join([self.type, self.name, str(self.hashes["size"])])
+ myhashkeys = list(self.hashes)
+ myhashkeys.remove("size")
+ myhashkeys.sort()
+ for h in myhashkeys:
+ myline += " " + h + " " + str(self.hashes[h])
+ return myline
+
+ def __eq__(self, other):
+ if not isinstance(other, Manifest2Entry) or \
+ self.type != other.type or \
+ self.name != other.name or \
+ self.hashes != other.hashes:
+ return False
+ return True
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+class Manifest(object):
+ parsers = (parseManifest2,)
+ def __init__(self, pkgdir, distdir, fetchlist_dict=None,
+ manifest1_compat=False, from_scratch=False):
+ """ create new Manifest instance for package in pkgdir
+ and add compability entries for old portage versions if manifest1_compat == True.
+ Do not parse Manifest file if from_scratch == True (only for internal use)
+ The fetchlist_dict parameter is required only for generation of
+ a Manifest (not needed for parsing and checking sums)."""
+ self.pkgdir = _unicode_decode(pkgdir).rstrip(os.sep) + os.sep
+ self.fhashdict = {}
+ self.hashes = set()
+ self.hashes.update(portage.const.MANIFEST2_HASH_FUNCTIONS)
+ if manifest1_compat:
+ raise NotImplementedError("manifest1 support has been removed")
+ self.hashes.difference_update(hashname for hashname in \
+ list(self.hashes) if hashname not in hashfunc_map)
+ self.hashes.add("size")
+ if manifest1_compat:
+ raise NotImplementedError("manifest1 support has been removed")
+ self.hashes.add(portage.const.MANIFEST2_REQUIRED_HASH)
+ for t in portage.const.MANIFEST2_IDENTIFIERS:
+ self.fhashdict[t] = {}
+ if not from_scratch:
+ self._read()
+ if fetchlist_dict != None:
+ self.fetchlist_dict = fetchlist_dict
+ else:
+ self.fetchlist_dict = {}
+ self.distdir = distdir
+ self.guessType = guessManifestFileType
+
+ def getFullname(self):
+ """ Returns the absolute path to the Manifest file for this instance """
+ return os.path.join(self.pkgdir, "Manifest")
+
+ def getDigests(self):
+ """ Compability function for old digest/manifest code, returns dict of filename:{hashfunction:hashvalue} """
+ rval = {}
+ for t in portage.const.MANIFEST2_IDENTIFIERS:
+ rval.update(self.fhashdict[t])
+ return rval
+
+ def getTypeDigests(self, ftype):
+ """ Similar to getDigests(), but restricted to files of the given type. """
+ return self.fhashdict[ftype]
+
+ def _readManifest(self, file_path, myhashdict=None, **kwargs):
+ """Parse a manifest. If myhashdict is given then data will be added too it.
+ Otherwise, a new dict will be created and returned."""
+ try:
+ fd = io.open(_unicode_encode(file_path,
+ encoding=_encodings['fs'], errors='strict'), mode='r',
+ encoding=_encodings['repo.content'], errors='replace')
+ if myhashdict is None:
+ myhashdict = {}
+ self._parseDigests(fd, myhashdict=myhashdict, **kwargs)
+ fd.close()
+ return myhashdict
+ except (OSError, IOError) as e:
+ if e.errno == errno.ENOENT:
+ raise FileNotFound(file_path)
+ else:
+ raise
+
+ def _read(self):
+ """ Parse Manifest file for this instance """
+ try:
+ self._readManifest(self.getFullname(), myhashdict=self.fhashdict)
+ except FileNotFound:
+ pass
+
+ def _parseManifestLines(self, mylines):
+ """Parse manifest lines and return a list of manifest entries."""
+ for myline in mylines:
+ myentry = None
+ mysplit = myline.split()
+ for parser in self.parsers:
+ myentry = parser(mysplit)
+ if myentry is not None:
+ yield myentry
+ break # go to the next line
+
+ def _parseDigests(self, mylines, myhashdict=None, mytype=None):
+ """Parse manifest entries and store the data in myhashdict. If mytype
+ is specified, it will override the type for all parsed entries."""
+ if myhashdict is None:
+ myhashdict = {}
+ for myentry in self._parseManifestLines(mylines):
+ if mytype is None:
+ myentry_type = myentry.type
+ else:
+ myentry_type = mytype
+ myhashdict.setdefault(myentry_type, {})
+ myhashdict[myentry_type].setdefault(myentry.name, {})
+ myhashdict[myentry_type][myentry.name].update(myentry.hashes)
+ return myhashdict
+
+ def _getDigestData(self, distlist):
+ """create a hash dict for a specific list of files"""
+ myhashdict = {}
+ for myname in distlist:
+ for mytype in self.fhashdict:
+ if myname in self.fhashdict[mytype]:
+ myhashdict.setdefault(mytype, {})
+ myhashdict[mytype].setdefault(myname, {})
+ myhashdict[mytype][myname].update(self.fhashdict[mytype][myname])
+ return myhashdict
+
+ def _createManifestEntries(self):
+ valid_hashes = set(portage.const.MANIFEST2_HASH_FUNCTIONS)
+ valid_hashes.add('size')
+ mytypes = list(self.fhashdict)
+ mytypes.sort()
+ for t in mytypes:
+ myfiles = list(self.fhashdict[t])
+ myfiles.sort()
+ for f in myfiles:
+ myentry = Manifest2Entry(
+ type=t, name=f, hashes=self.fhashdict[t][f].copy())
+ for h in list(myentry.hashes):
+ if h not in valid_hashes:
+ del myentry.hashes[h]
+ yield myentry
+
+ def checkIntegrity(self):
+ for t in self.fhashdict:
+ for f in self.fhashdict[t]:
+ if portage.const.MANIFEST2_REQUIRED_HASH not in self.fhashdict[t][f]:
+ raise MissingParameter(_("Missing %s checksum: %s %s") % (portage.const.MANIFEST2_REQUIRED_HASH, t, f))
+
+ def write(self, sign=False, force=False):
+ """ Write Manifest instance to disk, optionally signing it """
+ self.checkIntegrity()
+ try:
+ myentries = list(self._createManifestEntries())
+ update_manifest = True
+ if not force:
+ try:
+ f = io.open(_unicode_encode(self.getFullname(),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'],
+ errors='replace')
+ oldentries = list(self._parseManifestLines(f))
+ f.close()
+ if len(oldentries) == len(myentries):
+ update_manifest = False
+ for i in range(len(oldentries)):
+ if oldentries[i] != myentries[i]:
+ update_manifest = True
+ break
+ except (IOError, OSError) as e:
+ if e.errno == errno.ENOENT:
+ pass
+ else:
+ raise
+ if update_manifest:
+ write_atomic(self.getFullname(),
+ "".join("%s\n" % str(myentry) for myentry in myentries))
+ if sign:
+ self.sign()
+ except (IOError, OSError) as e:
+ if e.errno == errno.EACCES:
+ raise PermissionDenied(str(e))
+ raise
+
+ def sign(self):
+ """ Sign the Manifest """
+ raise NotImplementedError()
+
+ def validateSignature(self):
+ """ Validate signature on Manifest """
+ raise NotImplementedError()
+
+ def addFile(self, ftype, fname, hashdict=None, ignoreMissing=False):
+ """ Add entry to Manifest optionally using hashdict to avoid recalculation of hashes """
+ if ftype == "AUX" and not fname.startswith("files/"):
+ fname = os.path.join("files", fname)
+ if not os.path.exists(self.pkgdir+fname) and not ignoreMissing:
+ raise FileNotFound(fname)
+ if not ftype in portage.const.MANIFEST2_IDENTIFIERS:
+ raise InvalidDataType(ftype)
+ if ftype == "AUX" and fname.startswith("files"):
+ fname = fname[6:]
+ self.fhashdict[ftype][fname] = {}
+ if hashdict != None:
+ self.fhashdict[ftype][fname].update(hashdict)
+ if not portage.const.MANIFEST2_REQUIRED_HASH in self.fhashdict[ftype][fname]:
+ self.updateFileHashes(ftype, fname, checkExisting=False, ignoreMissing=ignoreMissing)
+
+ def removeFile(self, ftype, fname):
+ """ Remove given entry from Manifest """
+ del self.fhashdict[ftype][fname]
+
+ def hasFile(self, ftype, fname):
+ """ Return whether the Manifest contains an entry for the given type,filename pair """
+ return (fname in self.fhashdict[ftype])
+
+ def findFile(self, fname):
+ """ Return entrytype of the given file if present in Manifest or None if not present """
+ for t in portage.const.MANIFEST2_IDENTIFIERS:
+ if fname in self.fhashdict[t]:
+ return t
+ return None
+
+ def create(self, checkExisting=False, assumeDistHashesSometimes=False,
+ assumeDistHashesAlways=False, requiredDistfiles=[]):
+ """ Recreate this Manifest from scratch. This will not use any
+ existing checksums unless assumeDistHashesSometimes or
+ assumeDistHashesAlways is true (assumeDistHashesSometimes will only
+ cause DIST checksums to be reused if the file doesn't exist in
+ DISTDIR). The requiredDistfiles parameter specifies a list of
+ distfiles to raise a FileNotFound exception for (if no file or existing
+ checksums are available), and defaults to all distfiles when not
+ specified."""
+ if checkExisting:
+ self.checkAllHashes()
+ if assumeDistHashesSometimes or assumeDistHashesAlways:
+ distfilehashes = self.fhashdict["DIST"]
+ else:
+ distfilehashes = {}
+ self.__init__(self.pkgdir, self.distdir,
+ fetchlist_dict=self.fetchlist_dict, from_scratch=True,
+ manifest1_compat=False)
+ cpvlist = []
+ pn = os.path.basename(self.pkgdir.rstrip(os.path.sep))
+ cat = self._pkgdir_category()
+
+ pkgdir = self.pkgdir
+
+ for pkgdir, pkgdir_dirs, pkgdir_files in os.walk(pkgdir):
+ break
+ for f in pkgdir_files:
+ try:
+ f = _unicode_decode(f,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ continue
+ if f[:1] == ".":
+ continue
+ pf = None
+ if f[-7:] == '.ebuild':
+ pf = f[:-7]
+ if pf is not None:
+ mytype = "EBUILD"
+ ps = portage.versions._pkgsplit(pf)
+ cpv = "%s/%s" % (cat, pf)
+ if not ps:
+ raise PortagePackageException(
+ _("Invalid package name: '%s'") % cpv)
+ if ps[0] != pn:
+ raise PortagePackageException(
+ _("Package name does not "
+ "match directory name: '%s'") % cpv)
+ cpvlist.append(cpv)
+ elif manifest2MiscfileFilter(f):
+ mytype = "MISC"
+ else:
+ continue
+ self.fhashdict[mytype][f] = perform_multiple_checksums(self.pkgdir+f, self.hashes)
+ recursive_files = []
+
+ pkgdir = self.pkgdir
+ cut_len = len(os.path.join(pkgdir, "files") + os.sep)
+ for parentdir, dirs, files in os.walk(os.path.join(pkgdir, "files")):
+ for f in files:
+ try:
+ f = _unicode_decode(f,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ continue
+ full_path = os.path.join(parentdir, f)
+ recursive_files.append(full_path[cut_len:])
+ for f in recursive_files:
+ if not manifest2AuxfileFilter(f):
+ continue
+ self.fhashdict["AUX"][f] = perform_multiple_checksums(
+ os.path.join(self.pkgdir, "files", f.lstrip(os.sep)), self.hashes)
+ distlist = set()
+ for cpv in cpvlist:
+ distlist.update(self._getCpvDistfiles(cpv))
+ if requiredDistfiles is None:
+ # This allows us to force removal of stale digests for the
+ # ebuild --force digest option (no distfiles are required).
+ requiredDistfiles = set()
+ elif len(requiredDistfiles) == 0:
+ # repoman passes in an empty list, which implies that all distfiles
+ # are required.
+ requiredDistfiles = distlist.copy()
+ required_hash_types = set()
+ required_hash_types.add("size")
+ required_hash_types.add(portage.const.MANIFEST2_REQUIRED_HASH)
+ for f in distlist:
+ fname = os.path.join(self.distdir, f)
+ mystat = None
+ try:
+ mystat = os.stat(fname)
+ except OSError:
+ pass
+ if f in distfilehashes and \
+ not required_hash_types.difference(distfilehashes[f]) and \
+ ((assumeDistHashesSometimes and mystat is None) or \
+ (assumeDistHashesAlways and mystat is None) or \
+ (assumeDistHashesAlways and mystat is not None and \
+ len(distfilehashes[f]) == len(self.hashes) and \
+ distfilehashes[f]["size"] == mystat.st_size)):
+ self.fhashdict["DIST"][f] = distfilehashes[f]
+ else:
+ try:
+ self.fhashdict["DIST"][f] = perform_multiple_checksums(fname, self.hashes)
+ except FileNotFound:
+ if f in requiredDistfiles:
+ raise
+
+ def _pkgdir_category(self):
+ return self.pkgdir.rstrip(os.sep).split(os.sep)[-2]
+
+ def _getAbsname(self, ftype, fname):
+ if ftype == "DIST":
+ absname = os.path.join(self.distdir, fname)
+ elif ftype == "AUX":
+ absname = os.path.join(self.pkgdir, "files", fname)
+ else:
+ absname = os.path.join(self.pkgdir, fname)
+ return absname
+
+ def checkAllHashes(self, ignoreMissingFiles=False):
+ for t in portage.const.MANIFEST2_IDENTIFIERS:
+ self.checkTypeHashes(t, ignoreMissingFiles=ignoreMissingFiles)
+
+ def checkTypeHashes(self, idtype, ignoreMissingFiles=False):
+ for f in self.fhashdict[idtype]:
+ self.checkFileHashes(idtype, f, ignoreMissing=ignoreMissingFiles)
+
+ def checkFileHashes(self, ftype, fname, ignoreMissing=False):
+ myhashes = self.fhashdict[ftype][fname]
+ try:
+ ok,reason = verify_all(self._getAbsname(ftype, fname), self.fhashdict[ftype][fname])
+ if not ok:
+ raise DigestException(tuple([self._getAbsname(ftype, fname)]+list(reason)))
+ return ok, reason
+ except FileNotFound as e:
+ if not ignoreMissing:
+ raise
+ return False, _("File Not Found: '%s'") % str(e)
+
+ def checkCpvHashes(self, cpv, checkDistfiles=True, onlyDistfiles=False, checkMiscfiles=False):
+ """ check the hashes for all files associated to the given cpv, include all
+ AUX files and optionally all MISC files. """
+ if not onlyDistfiles:
+ self.checkTypeHashes("AUX", ignoreMissingFiles=False)
+ if checkMiscfiles:
+ self.checkTypeHashes("MISC", ignoreMissingFiles=False)
+ ebuildname = "%s.ebuild" % self._catsplit(cpv)[1]
+ self.checkFileHashes("EBUILD", ebuildname, ignoreMissing=False)
+ if checkDistfiles or onlyDistfiles:
+ for f in self._getCpvDistfiles(cpv):
+ self.checkFileHashes("DIST", f, ignoreMissing=False)
+
+ def _getCpvDistfiles(self, cpv):
+ """ Get a list of all DIST files associated to the given cpv """
+ return self.fetchlist_dict[cpv]
+
+ def getDistfilesSize(self, fetchlist):
+ total_bytes = 0
+ for f in fetchlist:
+ total_bytes += int(self.fhashdict["DIST"][f]["size"])
+ return total_bytes
+
+ def updateFileHashes(self, ftype, fname, checkExisting=True, ignoreMissing=True, reuseExisting=False):
+ """ Regenerate hashes for the given file """
+ if checkExisting:
+ self.checkFileHashes(ftype, fname, ignoreMissing=ignoreMissing)
+ if not ignoreMissing and fname not in self.fhashdict[ftype]:
+ raise FileNotInManifestException(fname)
+ if fname not in self.fhashdict[ftype]:
+ self.fhashdict[ftype][fname] = {}
+ myhashkeys = list(self.hashes)
+ if reuseExisting:
+ for k in [h for h in self.fhashdict[ftype][fname] if h in myhashkeys]:
+ myhashkeys.remove(k)
+ myhashes = perform_multiple_checksums(self._getAbsname(ftype, fname), myhashkeys)
+ self.fhashdict[ftype][fname].update(myhashes)
+
+ def updateTypeHashes(self, idtype, checkExisting=False, ignoreMissingFiles=True):
+ """ Regenerate all hashes for all files of the given type """
+ for fname in self.fhashdict[idtype]:
+ self.updateFileHashes(idtype, fname, checkExisting)
+
+ def updateAllHashes(self, checkExisting=False, ignoreMissingFiles=True):
+ """ Regenerate all hashes for all files in this Manifest. """
+ for idtype in portage.const.MANIFEST2_IDENTIFIERS:
+ self.updateTypeHashes(idtype, checkExisting=checkExisting,
+ ignoreMissingFiles=ignoreMissingFiles)
+
+ def updateCpvHashes(self, cpv, ignoreMissingFiles=True):
+ """ Regenerate all hashes associated to the given cpv (includes all AUX and MISC
+ files)."""
+ self.updateTypeHashes("AUX", ignoreMissingFiles=ignoreMissingFiles)
+ self.updateTypeHashes("MISC", ignoreMissingFiles=ignoreMissingFiles)
+ ebuildname = "%s.ebuild" % self._catsplit(cpv)[1]
+ self.updateFileHashes("EBUILD", ebuildname, ignoreMissingFiles=ignoreMissingFiles)
+ for f in self._getCpvDistfiles(cpv):
+ self.updateFileHashes("DIST", f, ignoreMissingFiles=ignoreMissingFiles)
+
+ def updateHashesGuessType(self, fname, *args, **kwargs):
+ """ Regenerate hashes for the given file (guesses the type and then
+ calls updateFileHashes)."""
+ mytype = self.guessType(fname)
+ if mytype == "AUX":
+ fname = fname[len("files" + os.sep):]
+ elif mytype is None:
+ return
+ myrealtype = self.findFile(fname)
+ if myrealtype is not None:
+ mytype = myrealtype
+ return self.updateFileHashes(mytype, fname, *args, **kwargs)
+
+ def getFileData(self, ftype, fname, key):
+ """ Return the value of a specific (type,filename,key) triple, mainly useful
+ to get the size for distfiles."""
+ return self.fhashdict[ftype][fname][key]
+
+ def getVersions(self):
+ """ Returns a list of manifest versions present in the manifest file. """
+ rVal = []
+ mfname = self.getFullname()
+ if not os.path.exists(mfname):
+ return rVal
+ myfile = io.open(_unicode_encode(mfname,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'], errors='replace')
+ lines = myfile.readlines()
+ myfile.close()
+ for l in lines:
+ mysplit = l.split()
+ if len(mysplit) == 4 and mysplit[0] in portage.const.MANIFEST1_HASH_FUNCTIONS and not 1 in rVal:
+ rVal.append(1)
+ elif len(mysplit) > 4 and mysplit[0] in portage.const.MANIFEST2_IDENTIFIERS and ((len(mysplit) - 3) % 2) == 0 and not 2 in rVal:
+ rVal.append(2)
+ return rVal
+
+ def _catsplit(self, pkg_key):
+ """Split a category and package, returning a list of [cat, pkg].
+ This is compatible with portage.catsplit()"""
+ return pkg_key.split("/", 1)
diff --git a/portage_with_autodep/pym/portage/news.py b/portage_with_autodep/pym/portage/news.py
new file mode 100644
index 0000000..866e5b0
--- /dev/null
+++ b/portage_with_autodep/pym/portage/news.py
@@ -0,0 +1,351 @@
+# portage: news management code
+# Copyright 2006-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ["NewsManager", "NewsItem", "DisplayRestriction",
+ "DisplayProfileRestriction", "DisplayKeywordRestriction",
+ "DisplayInstalledRestriction"]
+
+import io
+import logging
+import os as _os
+import re
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+from portage.util import apply_secpass_permissions, ensure_dirs, \
+ grabfile, normalize_path, write_atomic, writemsg_level
+from portage.data import portage_gid
+from portage.dep import isvalidatom
+from portage.localization import _
+from portage.locks import lockfile, unlockfile
+from portage.exception import InvalidLocation, OperationNotPermitted, \
+ PermissionDenied
+
+class NewsManager(object):
+ """
+ This object manages GLEP 42 style news items. It will cache news items
+ that have previously shown up and notify users when there are relevant news
+ items that apply to their packages that the user has not previously read.
+
+ Creating a news manager requires:
+ root - typically ${ROOT} see man make.conf and man emerge for details
+ news_path - path to news items; usually $REPODIR/metadata/news
+ unread_path - path to the news.repoid.unread file; this helps us track news items
+
+ """
+
+ def __init__(self, portdb, vardb, news_path, unread_path, language_id='en'):
+ self.news_path = news_path
+ self.unread_path = unread_path
+ self.target_root = vardb.root
+ self.language_id = language_id
+ self.config = vardb.settings
+ self.vdb = vardb
+ self.portdb = portdb
+
+ # GLEP 42 says:
+ # All news item related files should be root owned and in the
+ # portage group with the group write (and, for directories,
+ # execute) bits set. News files should be world readable.
+ self._uid = int(self.config["PORTAGE_INST_UID"])
+ self._gid = portage_gid
+ self._file_mode = 0o0064
+ self._dir_mode = 0o0074
+ self._mode_mask = 0o0000
+
+ portdir = portdb.porttree_root
+ profiles_base = os.path.join(portdir, 'profiles') + os.path.sep
+ profile_path = None
+ if portdb.settings.profile_path:
+ profile_path = normalize_path(
+ os.path.realpath(portdb.settings.profile_path))
+ if profile_path.startswith(profiles_base):
+ profile_path = profile_path[len(profiles_base):]
+ self._profile_path = profile_path
+
+ def _unread_filename(self, repoid):
+ return os.path.join(self.unread_path, 'news-%s.unread' % repoid)
+
+ def _skip_filename(self, repoid):
+ return os.path.join(self.unread_path, 'news-%s.skip' % repoid)
+
+ def _news_dir(self, repoid):
+ repo_path = self.portdb.getRepositoryPath(repoid)
+ if repo_path is None:
+ raise AssertionError(_("Invalid repoID: %s") % repoid)
+ return os.path.join(repo_path, self.news_path)
+
+ def updateItems(self, repoid):
+ """
+ Figure out which news items from NEWS_PATH are both unread and relevant to
+ the user (according to the GLEP 42 standards of relevancy). Then add these
+ items into the news.repoid.unread file.
+ """
+
+ # Ensure that the unread path exists and is writable.
+
+ try:
+ ensure_dirs(self.unread_path, uid=self._uid, gid=self._gid,
+ mode=self._dir_mode, mask=self._mode_mask)
+ except (OperationNotPermitted, PermissionDenied):
+ return
+
+ if not os.access(self.unread_path, os.W_OK):
+ return
+
+ news_dir = self._news_dir(repoid)
+ try:
+ news = _os.listdir(_unicode_encode(news_dir,
+ encoding=_encodings['fs'], errors='strict'))
+ except OSError:
+ return
+
+ skip_filename = self._skip_filename(repoid)
+ unread_filename = self._unread_filename(repoid)
+ unread_lock = lockfile(unread_filename, wantnewlockfile=1)
+ try:
+ try:
+ unread = set(grabfile(unread_filename))
+ unread_orig = unread.copy()
+ skip = set(grabfile(skip_filename))
+ skip_orig = skip.copy()
+ except PermissionDenied:
+ return
+
+ updates = []
+ for itemid in news:
+ try:
+ itemid = _unicode_decode(itemid,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ itemid = _unicode_decode(itemid,
+ encoding=_encodings['fs'], errors='replace')
+ writemsg_level(
+ _("!!! Invalid encoding in news item name: '%s'\n") % \
+ itemid, level=logging.ERROR, noiselevel=-1)
+ continue
+
+ if itemid in skip:
+ continue
+ filename = os.path.join(news_dir, itemid,
+ itemid + "." + self.language_id + ".txt")
+ if not os.path.isfile(filename):
+ continue
+ item = NewsItem(filename, itemid)
+ if not item.isValid():
+ continue
+ if item.isRelevant(profile=self._profile_path,
+ config=self.config, vardb=self.vdb):
+ unread.add(item.name)
+ skip.add(item.name)
+
+ if unread != unread_orig:
+ write_atomic(unread_filename,
+ "".join("%s\n" % x for x in sorted(unread)))
+ apply_secpass_permissions(unread_filename,
+ uid=self._uid, gid=self._gid,
+ mode=self._file_mode, mask=self._mode_mask)
+
+ if skip != skip_orig:
+ write_atomic(skip_filename,
+ "".join("%s\n" % x for x in sorted(skip)))
+ apply_secpass_permissions(skip_filename,
+ uid=self._uid, gid=self._gid,
+ mode=self._file_mode, mask=self._mode_mask)
+
+ finally:
+ unlockfile(unread_lock)
+
+ def getUnreadItems(self, repoid, update=False):
+ """
+ Determine if there are unread relevant items in news.repoid.unread.
+ If there are unread items return their number.
+ If update is specified, updateNewsItems( repoid ) will be called to
+ check for new items.
+ """
+
+ if update:
+ self.updateItems(repoid)
+
+ unread_filename = self._unread_filename(repoid)
+ unread_lock = None
+ try:
+ unread_lock = lockfile(unread_filename, wantnewlockfile=1)
+ except (InvalidLocation, OperationNotPermitted, PermissionDenied):
+ pass
+ try:
+ try:
+ return len(grabfile(unread_filename))
+ except PermissionDenied:
+ return 0
+ finally:
+ if unread_lock:
+ unlockfile(unread_lock)
+
+_formatRE = re.compile("News-Item-Format:\s*([^\s]*)\s*$")
+_installedRE = re.compile("Display-If-Installed:(.*)\n")
+_profileRE = re.compile("Display-If-Profile:(.*)\n")
+_keywordRE = re.compile("Display-If-Keyword:(.*)\n")
+
+class NewsItem(object):
+ """
+ This class encapsulates a GLEP 42 style news item.
+ It's purpose is to wrap parsing of these news items such that portage can determine
+ whether a particular item is 'relevant' or not. This requires parsing the item
+ and determining 'relevancy restrictions'; these include "Display if Installed" or
+ "display if arch: x86" and so forth.
+
+ Creation of a news item involves passing in the path to the particular news item.
+ """
+
+ def __init__(self, path, name):
+ """
+ For a given news item we only want if it path is a file.
+ """
+ self.path = path
+ self.name = name
+ self._parsed = False
+ self._valid = True
+
+ def isRelevant(self, vardb, config, profile):
+ """
+ This function takes a dict of keyword arguments; one should pass in any
+ objects need to do to lookups (like what keywords we are on, what profile,
+ and a vardb so we can look at installed packages).
+ Each restriction will pluck out the items that are required for it to match
+ or raise a ValueError exception if the required object is not present.
+
+ Restrictions of the form Display-X are OR'd with like-restrictions;
+ otherwise restrictions are AND'd. any_match is the ORing and
+ all_match is the ANDing.
+ """
+
+ if not self._parsed:
+ self.parse()
+
+ if not len(self.restrictions):
+ return True
+
+ kwargs = \
+ { 'vardb' : vardb,
+ 'config' : config,
+ 'profile' : profile }
+
+ all_match = True
+ for values in self.restrictions.values():
+ any_match = False
+ for restriction in values:
+ if restriction.checkRestriction(**kwargs):
+ any_match = True
+ if not any_match:
+ all_match = False
+
+ return all_match
+
+ def isValid(self):
+ if not self._parsed:
+ self.parse()
+ return self._valid
+
+ def parse(self):
+ lines = io.open(_unicode_encode(self.path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'], errors='replace'
+ ).readlines()
+ self.restrictions = {}
+ invalids = []
+ for i, line in enumerate(lines):
+ # Optimization to ignore regex matchines on lines that
+ # will never match
+ format_match = _formatRE.match(line)
+ if format_match is not None and format_match.group(1) != '1.0':
+ invalids.append((i + 1, line.rstrip('\n')))
+ break
+ if not line.startswith('D'):
+ continue
+ restricts = { _installedRE : DisplayInstalledRestriction,
+ _profileRE : DisplayProfileRestriction,
+ _keywordRE : DisplayKeywordRestriction }
+ for regex, restriction in restricts.items():
+ match = regex.match(line)
+ if match:
+ restrict = restriction(match.groups()[0].strip())
+ if not restrict.isValid():
+ invalids.append((i + 1, line.rstrip("\n")))
+ else:
+ self.restrictions.setdefault(
+ id(restriction), []).append(restrict)
+ continue
+ if invalids:
+ self._valid = False
+ msg = []
+ msg.append(_("Invalid news item: %s") % (self.path,))
+ for lineno, line in invalids:
+ msg.append(_(" line %d: %s") % (lineno, line))
+ writemsg_level("".join("!!! %s\n" % x for x in msg),
+ level=logging.ERROR, noiselevel=-1)
+
+ self._parsed = True
+
+class DisplayRestriction(object):
+ """
+ A base restriction object representing a restriction of display.
+ news items may have 'relevancy restrictions' preventing them from
+ being important. In this case we need a manner of figuring out if
+ a particular item is relevant or not. If any of it's restrictions
+ are met, then it is displayed
+ """
+
+ def isValid(self):
+ return True
+
+ def checkRestriction(self, **kwargs):
+ raise NotImplementedError('Derived class should override this method')
+
+class DisplayProfileRestriction(DisplayRestriction):
+ """
+ A profile restriction where a particular item shall only be displayed
+ if the user is running a specific profile.
+ """
+
+ def __init__(self, profile):
+ self.profile = profile
+
+ def checkRestriction(self, **kwargs):
+ if self.profile == kwargs['profile']:
+ return True
+ return False
+
+class DisplayKeywordRestriction(DisplayRestriction):
+ """
+ A keyword restriction where a particular item shall only be displayed
+ if the user is running a specific keyword.
+ """
+
+ def __init__(self, keyword):
+ self.keyword = keyword
+
+ def checkRestriction(self, **kwargs):
+ if kwargs['config']['ARCH'] == self.keyword:
+ return True
+ return False
+
+class DisplayInstalledRestriction(DisplayRestriction):
+ """
+ An Installation restriction where a particular item shall only be displayed
+ if the user has that item installed.
+ """
+
+ def __init__(self, atom):
+ self.atom = atom
+
+ def isValid(self):
+ return isvalidatom(self.atom)
+
+ def checkRestriction(self, **kwargs):
+ vdb = kwargs['vardb']
+ if vdb.match(self.atom):
+ return True
+ return False
diff --git a/portage_with_autodep/pym/portage/output.py b/portage_with_autodep/pym/portage/output.py
new file mode 100644
index 0000000..0e8245f
--- /dev/null
+++ b/portage_with_autodep/pym/portage/output.py
@@ -0,0 +1,794 @@
+# Copyright 1998-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__docformat__ = "epytext"
+
+import errno
+import io
+import formatter
+import re
+import sys
+
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.util:writemsg',
+)
+
+from portage import os
+from portage import _encodings
+from portage import _unicode_encode
+from portage import _unicode_decode
+from portage.const import COLOR_MAP_FILE
+from portage.exception import CommandNotFound, FileNotFound, \
+ ParseError, PermissionDenied, PortageException
+from portage.localization import _
+
+havecolor=1
+dotitles=1
+
+_styles = {}
+"""Maps style class to tuple of attribute names."""
+
+codes = {}
+"""Maps attribute name to ansi code."""
+
+esc_seq = "\x1b["
+
+codes["normal"] = esc_seq + "0m"
+codes["reset"] = esc_seq + "39;49;00m"
+
+codes["bold"] = esc_seq + "01m"
+codes["faint"] = esc_seq + "02m"
+codes["standout"] = esc_seq + "03m"
+codes["underline"] = esc_seq + "04m"
+codes["blink"] = esc_seq + "05m"
+codes["overline"] = esc_seq + "06m"
+codes["reverse"] = esc_seq + "07m"
+codes["invisible"] = esc_seq + "08m"
+
+codes["no-attr"] = esc_seq + "22m"
+codes["no-standout"] = esc_seq + "23m"
+codes["no-underline"] = esc_seq + "24m"
+codes["no-blink"] = esc_seq + "25m"
+codes["no-overline"] = esc_seq + "26m"
+codes["no-reverse"] = esc_seq + "27m"
+
+codes["bg_black"] = esc_seq + "40m"
+codes["bg_darkred"] = esc_seq + "41m"
+codes["bg_darkgreen"] = esc_seq + "42m"
+codes["bg_brown"] = esc_seq + "43m"
+codes["bg_darkblue"] = esc_seq + "44m"
+codes["bg_purple"] = esc_seq + "45m"
+codes["bg_teal"] = esc_seq + "46m"
+codes["bg_lightgray"] = esc_seq + "47m"
+codes["bg_default"] = esc_seq + "49m"
+codes["bg_darkyellow"] = codes["bg_brown"]
+
+def color(fg, bg="default", attr=["normal"]):
+ mystr = codes[fg]
+ for x in [bg]+attr:
+ mystr += codes[x]
+ return mystr
+
+
+ansi_codes = []
+for x in range(30, 38):
+ ansi_codes.append("%im" % x)
+ ansi_codes.append("%i;01m" % x)
+
+rgb_ansi_colors = ['0x000000', '0x555555', '0xAA0000', '0xFF5555', '0x00AA00',
+ '0x55FF55', '0xAA5500', '0xFFFF55', '0x0000AA', '0x5555FF', '0xAA00AA',
+ '0xFF55FF', '0x00AAAA', '0x55FFFF', '0xAAAAAA', '0xFFFFFF']
+
+for x in range(len(rgb_ansi_colors)):
+ codes[rgb_ansi_colors[x]] = esc_seq + ansi_codes[x]
+
+del x
+
+codes["black"] = codes["0x000000"]
+codes["darkgray"] = codes["0x555555"]
+
+codes["red"] = codes["0xFF5555"]
+codes["darkred"] = codes["0xAA0000"]
+
+codes["green"] = codes["0x55FF55"]
+codes["darkgreen"] = codes["0x00AA00"]
+
+codes["yellow"] = codes["0xFFFF55"]
+codes["brown"] = codes["0xAA5500"]
+
+codes["blue"] = codes["0x5555FF"]
+codes["darkblue"] = codes["0x0000AA"]
+
+codes["fuchsia"] = codes["0xFF55FF"]
+codes["purple"] = codes["0xAA00AA"]
+
+codes["turquoise"] = codes["0x55FFFF"]
+codes["teal"] = codes["0x00AAAA"]
+
+codes["white"] = codes["0xFFFFFF"]
+codes["lightgray"] = codes["0xAAAAAA"]
+
+codes["darkteal"] = codes["turquoise"]
+# Some terminals have darkyellow instead of brown.
+codes["0xAAAA00"] = codes["brown"]
+codes["darkyellow"] = codes["0xAAAA00"]
+
+
+
+# Colors from /etc/init.d/functions.sh
+_styles["NORMAL"] = ( "normal", )
+_styles["GOOD"] = ( "green", )
+_styles["WARN"] = ( "yellow", )
+_styles["BAD"] = ( "red", )
+_styles["HILITE"] = ( "teal", )
+_styles["BRACKET"] = ( "blue", )
+
+# Portage functions
+_styles["INFORM"] = ( "darkgreen", )
+_styles["UNMERGE_WARN"] = ( "red", )
+_styles["SECURITY_WARN"] = ( "red", )
+_styles["MERGE_LIST_PROGRESS"] = ( "yellow", )
+_styles["PKG_BLOCKER"] = ( "red", )
+_styles["PKG_BLOCKER_SATISFIED"] = ( "darkblue", )
+_styles["PKG_MERGE"] = ( "darkgreen", )
+_styles["PKG_MERGE_SYSTEM"] = ( "darkgreen", )
+_styles["PKG_MERGE_WORLD"] = ( "green", )
+_styles["PKG_BINARY_MERGE"] = ( "purple", )
+_styles["PKG_BINARY_MERGE_SYSTEM"] = ( "purple", )
+_styles["PKG_BINARY_MERGE_WORLD"] = ( "fuchsia", )
+_styles["PKG_UNINSTALL"] = ( "red", )
+_styles["PKG_NOMERGE"] = ( "darkblue", )
+_styles["PKG_NOMERGE_SYSTEM"] = ( "darkblue", )
+_styles["PKG_NOMERGE_WORLD"] = ( "blue", )
+_styles["PROMPT_CHOICE_DEFAULT"] = ( "green", )
+_styles["PROMPT_CHOICE_OTHER"] = ( "red", )
+
+def _parse_color_map(config_root='/', onerror=None):
+ """
+ Parse /etc/portage/color.map and return a dict of error codes.
+
+ @param onerror: an optional callback to handle any ParseError that would
+ otherwise be raised
+ @type onerror: callable
+ @rtype: dict
+ @return: a dictionary mapping color classes to color codes
+ """
+ global codes, _styles
+ myfile = os.path.join(config_root, COLOR_MAP_FILE)
+ ansi_code_pattern = re.compile("^[0-9;]*m$")
+ quotes = '\'"'
+ def strip_quotes(token):
+ if token[0] in quotes and token[0] == token[-1]:
+ token = token[1:-1]
+ return token
+ try:
+ lineno=0
+ for line in io.open(_unicode_encode(myfile,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'], errors='replace'):
+ lineno += 1
+
+ commenter_pos = line.find("#")
+ line = line[:commenter_pos].strip()
+
+ if len(line) == 0:
+ continue
+
+ split_line = line.split("=")
+ if len(split_line) != 2:
+ e = ParseError(_("'%s', line %s: expected exactly one occurrence of '=' operator") % \
+ (myfile, lineno))
+ raise e
+ if onerror:
+ onerror(e)
+ else:
+ raise e
+ continue
+
+ k = strip_quotes(split_line[0].strip())
+ v = strip_quotes(split_line[1].strip())
+ if not k in _styles and not k in codes:
+ e = ParseError(_("'%s', line %s: Unknown variable: '%s'") % \
+ (myfile, lineno, k))
+ if onerror:
+ onerror(e)
+ else:
+ raise e
+ continue
+ if ansi_code_pattern.match(v):
+ if k in _styles:
+ _styles[k] = ( esc_seq + v, )
+ elif k in codes:
+ codes[k] = esc_seq + v
+ else:
+ code_list = []
+ for x in v.split():
+ if x in codes:
+ if k in _styles:
+ code_list.append(x)
+ elif k in codes:
+ code_list.append(codes[x])
+ else:
+ e = ParseError(_("'%s', line %s: Undefined: '%s'") % \
+ (myfile, lineno, x))
+ if onerror:
+ onerror(e)
+ else:
+ raise e
+ if k in _styles:
+ _styles[k] = tuple(code_list)
+ elif k in codes:
+ codes[k] = "".join(code_list)
+ except (IOError, OSError) as e:
+ if e.errno == errno.ENOENT:
+ raise FileNotFound(myfile)
+ elif e.errno == errno.EACCES:
+ raise PermissionDenied(myfile)
+ raise
+
+def nc_len(mystr):
+ tmp = re.sub(esc_seq + "^m]+m", "", mystr);
+ return len(tmp)
+
+_legal_terms_re = re.compile(r'^(xterm|xterm-color|Eterm|aterm|rxvt|screen|kterm|rxvt-unicode|gnome|interix)')
+_disable_xtermTitle = None
+_max_xtermTitle_len = 253
+
+def xtermTitle(mystr, raw=False):
+ global _disable_xtermTitle
+ if _disable_xtermTitle is None:
+ _disable_xtermTitle = not (sys.stderr.isatty() and \
+ 'TERM' in os.environ and \
+ _legal_terms_re.match(os.environ['TERM']) is not None)
+
+ if dotitles and not _disable_xtermTitle:
+ # If the title string is too big then the terminal can
+ # misbehave. Therefore, truncate it if it's too big.
+ if len(mystr) > _max_xtermTitle_len:
+ mystr = mystr[:_max_xtermTitle_len]
+ if not raw:
+ mystr = '\x1b]0;%s\x07' % mystr
+
+ # avoid potential UnicodeEncodeError
+ mystr = _unicode_encode(mystr,
+ encoding=_encodings['stdio'], errors='backslashreplace')
+ f = sys.stderr
+ if sys.hexversion >= 0x3000000:
+ f = f.buffer
+ f.write(mystr)
+ f.flush()
+
+default_xterm_title = None
+
+def xtermTitleReset():
+ global default_xterm_title
+ if default_xterm_title is None:
+ prompt_command = os.environ.get('PROMPT_COMMAND')
+ if prompt_command == "":
+ default_xterm_title = ""
+ elif prompt_command is not None:
+ if dotitles and \
+ 'TERM' in os.environ and \
+ _legal_terms_re.match(os.environ['TERM']) is not None and \
+ sys.stderr.isatty():
+ from portage.process import find_binary, spawn
+ shell = os.environ.get("SHELL")
+ if not shell or not os.access(shell, os.EX_OK):
+ shell = find_binary("sh")
+ if shell:
+ spawn([shell, "-c", prompt_command], env=os.environ,
+ fd_pipes={0:sys.stdin.fileno(),1:sys.stderr.fileno(),
+ 2:sys.stderr.fileno()})
+ else:
+ os.system(prompt_command)
+ return
+ else:
+ pwd = os.environ.get('PWD','')
+ home = os.environ.get('HOME', '')
+ if home != '' and pwd.startswith(home):
+ pwd = '~' + pwd[len(home):]
+ default_xterm_title = '\x1b]0;%s@%s:%s\x07' % (
+ os.environ.get('LOGNAME', ''),
+ os.environ.get('HOSTNAME', '').split('.', 1)[0], pwd)
+ xtermTitle(default_xterm_title, raw=True)
+
+def notitles():
+ "turn off title setting"
+ dotitles=0
+
+def nocolor():
+ "turn off colorization"
+ global havecolor
+ havecolor=0
+
+def resetColor():
+ return codes["reset"]
+
+def style_to_ansi_code(style):
+ """
+ @param style: A style name
+ @type style: String
+ @rtype: String
+ @return: A string containing one or more ansi escape codes that are
+ used to render the given style.
+ """
+ ret = ""
+ for attr_name in _styles[style]:
+ # allow stuff that has found it's way through ansi_code_pattern
+ ret += codes.get(attr_name, attr_name)
+ return ret
+
+def colorize(color_key, text):
+ global havecolor
+ if havecolor:
+ if color_key in codes:
+ return codes[color_key] + text + codes["reset"]
+ elif color_key in _styles:
+ return style_to_ansi_code(color_key) + text + codes["reset"]
+ else:
+ return text
+ else:
+ return text
+
+compat_functions_colors = ["bold","white","teal","turquoise","darkteal",
+ "fuchsia","purple","blue","darkblue","green","darkgreen","yellow",
+ "brown","darkyellow","red","darkred"]
+
+def create_color_func(color_key):
+ def derived_func(*args):
+ newargs = list(args)
+ newargs.insert(0, color_key)
+ return colorize(*newargs)
+ return derived_func
+
+for c in compat_functions_colors:
+ globals()[c] = create_color_func(c)
+
+class ConsoleStyleFile(object):
+ """
+ A file-like object that behaves something like
+ the colorize() function. Style identifiers
+ passed in via the new_styles() method will be used to
+ apply console codes to output.
+ """
+ def __init__(self, f):
+ self._file = f
+ self._styles = None
+ self.write_listener = None
+
+ def new_styles(self, styles):
+ self._styles = styles
+
+ def write(self, s):
+ # In python-2.6, DumbWriter.send_line_break() can write
+ # non-unicode '\n' which fails with TypeError if self._file
+ # is a text stream such as io.StringIO. Therefore, make sure
+ # input is converted to unicode when necessary.
+ s = _unicode_decode(s)
+ global havecolor
+ if havecolor and self._styles:
+ styled_s = []
+ for style in self._styles:
+ styled_s.append(style_to_ansi_code(style))
+ styled_s.append(s)
+ styled_s.append(codes["reset"])
+ self._write(self._file, "".join(styled_s))
+ else:
+ self._write(self._file, s)
+ if self.write_listener:
+ self._write(self.write_listener, s)
+
+ def _write(self, f, s):
+ # avoid potential UnicodeEncodeError
+ if f in (sys.stdout, sys.stderr):
+ s = _unicode_encode(s,
+ encoding=_encodings['stdio'], errors='backslashreplace')
+ if sys.hexversion >= 0x3000000:
+ f = f.buffer
+ f.write(s)
+
+ def writelines(self, lines):
+ for s in lines:
+ self.write(s)
+
+ def flush(self):
+ self._file.flush()
+
+ def close(self):
+ self._file.close()
+
+class StyleWriter(formatter.DumbWriter):
+ """
+ This is just a DumbWriter with a hook in the new_styles() method
+ that passes a styles tuple as a single argument to a callable
+ style_listener attribute.
+ """
+ def __init__(self, **kwargs):
+ formatter.DumbWriter.__init__(self, **kwargs)
+ self.style_listener = None
+
+ def new_styles(self, styles):
+ formatter.DumbWriter.new_styles(self, styles)
+ if self.style_listener:
+ self.style_listener(styles)
+
+def get_term_size():
+ """
+ Get the number of lines and columns of the tty that is connected to
+ stdout. Returns a tuple of (lines, columns) or (-1, -1) if an error
+ occurs. The curses module is used if available, otherwise the output of
+ `stty size` is parsed.
+ """
+ if not sys.stdout.isatty():
+ return -1, -1
+ try:
+ import curses
+ try:
+ curses.setupterm()
+ return curses.tigetnum('lines'), curses.tigetnum('cols')
+ except curses.error:
+ pass
+ except ImportError:
+ pass
+ st, out = portage.subprocess_getstatusoutput('stty size')
+ if st == os.EX_OK:
+ out = out.split()
+ if len(out) == 2:
+ try:
+ return int(out[0]), int(out[1])
+ except ValueError:
+ pass
+ return -1, -1
+
+def set_term_size(lines, columns, fd):
+ """
+ Set the number of lines and columns for the tty that is connected to fd.
+ For portability, this simply calls `stty rows $lines columns $columns`.
+ """
+ from portage.process import spawn
+ cmd = ["stty", "rows", str(lines), "columns", str(columns)]
+ try:
+ spawn(cmd, env=os.environ, fd_pipes={0:fd})
+ except CommandNotFound:
+ writemsg(_("portage: stty: command not found\n"), noiselevel=-1)
+
+class EOutput(object):
+ """
+ Performs fancy terminal formatting for status and informational messages.
+
+ The provided methods produce identical terminal output to the eponymous
+ functions in the shell script C{/sbin/functions.sh} and also accept
+ identical parameters.
+
+ This is not currently a drop-in replacement however, as the output-related
+ functions in C{/sbin/functions.sh} are oriented for use mainly by system
+ init scripts and ebuilds and their output can be customized via certain
+ C{RC_*} environment variables (see C{/etc/conf.d/rc}). B{EOutput} is not
+ customizable in this manner since it's intended for more general uses.
+ Likewise, no logging is provided.
+
+ @ivar quiet: Specifies if output should be silenced.
+ @type quiet: BooleanType
+ @ivar term_columns: Width of terminal in characters. Defaults to the value
+ specified by the shell's C{COLUMNS} variable, else to the queried tty
+ size, else to C{80}.
+ @type term_columns: IntType
+ """
+
+ def __init__(self, quiet=False):
+ self.__last_e_cmd = ""
+ self.__last_e_len = 0
+ self.quiet = quiet
+ lines, columns = get_term_size()
+ if columns <= 0:
+ columns = 80
+ self.term_columns = columns
+ sys.stdout.flush()
+ sys.stderr.flush()
+
+ def _write(self, f, s):
+ # avoid potential UnicodeEncodeError
+ writemsg(s, noiselevel=-1, fd=f)
+
+ def __eend(self, caller, errno, msg):
+ if errno == 0:
+ status_brackets = colorize("BRACKET", "[ ") + colorize("GOOD", "ok") + colorize("BRACKET", " ]")
+ else:
+ status_brackets = colorize("BRACKET", "[ ") + colorize("BAD", "!!") + colorize("BRACKET", " ]")
+ if msg:
+ if caller == "eend":
+ self.eerror(msg[0])
+ elif caller == "ewend":
+ self.ewarn(msg[0])
+ if self.__last_e_cmd != "ebegin":
+ self.__last_e_len = 0
+ if not self.quiet:
+ out = sys.stdout
+ self._write(out,
+ "%*s%s\n" % ((self.term_columns - self.__last_e_len - 7),
+ "", status_brackets))
+
+ def ebegin(self, msg):
+ """
+ Shows a message indicating the start of a process.
+
+ @param msg: A very brief (shorter than one line) description of the
+ starting process.
+ @type msg: StringType
+ """
+ msg += " ..."
+ if not self.quiet:
+ self.einfon(msg)
+ self.__last_e_len = len(msg) + 3
+ self.__last_e_cmd = "ebegin"
+
+ def eend(self, errno, *msg):
+ """
+ Indicates the completion of a process, optionally displaying a message
+ via L{eerror} if the process's exit status isn't C{0}.
+
+ @param errno: A standard UNIX C{errno} code returned by processes upon
+ exit.
+ @type errno: IntType
+ @param msg: I{(optional)} An error message, typically a standard UNIX
+ error string corresponding to C{errno}.
+ @type msg: StringType
+ """
+ if not self.quiet:
+ self.__eend("eend", errno, msg)
+ self.__last_e_cmd = "eend"
+
+ def eerror(self, msg):
+ """
+ Shows an error message.
+
+ @param msg: A very brief (shorter than one line) error message.
+ @type msg: StringType
+ """
+ out = sys.stderr
+ if not self.quiet:
+ if self.__last_e_cmd == "ebegin":
+ self._write(out, "\n")
+ self._write(out, colorize("BAD", " * ") + msg + "\n")
+ self.__last_e_cmd = "eerror"
+
+ def einfo(self, msg):
+ """
+ Shows an informative message terminated with a newline.
+
+ @param msg: A very brief (shorter than one line) informative message.
+ @type msg: StringType
+ """
+ out = sys.stdout
+ if not self.quiet:
+ if self.__last_e_cmd == "ebegin":
+ self._write(out, "\n")
+ self._write(out, colorize("GOOD", " * ") + msg + "\n")
+ self.__last_e_cmd = "einfo"
+
+ def einfon(self, msg):
+ """
+ Shows an informative message terminated without a newline.
+
+ @param msg: A very brief (shorter than one line) informative message.
+ @type msg: StringType
+ """
+ out = sys.stdout
+ if not self.quiet:
+ if self.__last_e_cmd == "ebegin":
+ self._write(out, "\n")
+ self._write(out, colorize("GOOD", " * ") + msg)
+ self.__last_e_cmd = "einfon"
+
+ def ewarn(self, msg):
+ """
+ Shows a warning message.
+
+ @param msg: A very brief (shorter than one line) warning message.
+ @type msg: StringType
+ """
+ out = sys.stderr
+ if not self.quiet:
+ if self.__last_e_cmd == "ebegin":
+ self._write(out, "\n")
+ self._write(out, colorize("WARN", " * ") + msg + "\n")
+ self.__last_e_cmd = "ewarn"
+
+ def ewend(self, errno, *msg):
+ """
+ Indicates the completion of a process, optionally displaying a message
+ via L{ewarn} if the process's exit status isn't C{0}.
+
+ @param errno: A standard UNIX C{errno} code returned by processes upon
+ exit.
+ @type errno: IntType
+ @param msg: I{(optional)} A warning message, typically a standard UNIX
+ error string corresponding to C{errno}.
+ @type msg: StringType
+ """
+ if not self.quiet:
+ self.__eend("ewend", errno, msg)
+ self.__last_e_cmd = "ewend"
+
+class ProgressBar(object):
+ """The interface is copied from the ProgressBar class from the EasyDialogs
+ module (which is Mac only)."""
+ def __init__(self, title=None, maxval=0, label=None):
+ self._title = title
+ self._maxval = maxval
+ self._label = maxval
+ self._curval = 0
+
+ @property
+ def curval(self):
+ """
+ The current value (of type integer or long integer) of the progress
+ bar. The normal access methods coerce curval between 0 and maxval. This
+ attribute should not be altered directly.
+ """
+ return self._curval
+
+ @property
+ def maxval(self):
+ """
+ The maximum value (of type integer or long integer) of the progress
+ bar; the progress bar (thermometer style) is full when curval equals
+ maxval. If maxval is 0, the bar will be indeterminate (barber-pole).
+ This attribute should not be altered directly.
+ """
+ return self._maxval
+
+ def title(self, newstr):
+ """Sets the text in the title bar of the progress dialog to newstr."""
+ self._title = newstr
+
+ def label(self, newstr):
+ """Sets the text in the progress box of the progress dialog to newstr."""
+ self._label = newstr
+
+ def set(self, value, maxval=None):
+ """
+ Sets the progress bar's curval to value, and also maxval to max if the
+ latter is provided. value is first coerced between 0 and maxval. The
+ thermometer bar is updated to reflect the changes, including a change
+ from indeterminate to determinate or vice versa.
+ """
+ if maxval is not None:
+ self._maxval = maxval
+ if value < 0:
+ value = 0
+ elif value > self._maxval:
+ value = self._maxval
+ self._curval = value
+
+ def inc(self, n=1):
+ """Increments the progress bar's curval by n, or by 1 if n is not
+ provided. (Note that n may be negative, in which case the effect is a
+ decrement.) The progress bar is updated to reflect the change. If the
+ bar is indeterminate, this causes one ``spin'' of the barber pole. The
+ resulting curval is coerced between 0 and maxval if incrementing causes
+ it to fall outside this range.
+ """
+ self.set(self._curval+n)
+
+class TermProgressBar(ProgressBar):
+ """A tty progress bar similar to wget's."""
+ def __init__(self, **kwargs):
+ ProgressBar.__init__(self, **kwargs)
+ lines, self.term_columns = get_term_size()
+ self.file = sys.stdout
+ self._min_columns = 11
+ self._max_columns = 80
+ # for indeterminate mode, ranges from 0.0 to 1.0
+ self._position = 0.0
+
+ def set(self, value, maxval=None):
+ ProgressBar.set(self, value, maxval=maxval)
+ self._display_image(self._create_image())
+
+ def _display_image(self, image):
+ self.file.write('\r')
+ self.file.write(image)
+ self.file.flush()
+
+ def _create_image(self):
+ cols = self.term_columns
+ if cols > self._max_columns:
+ cols = self._max_columns
+ min_columns = self._min_columns
+ curval = self._curval
+ maxval = self._maxval
+ position = self._position
+ percentage_str_width = 4
+ square_brackets_width = 2
+ if cols < percentage_str_width:
+ return ""
+ bar_space = cols - percentage_str_width - square_brackets_width
+ if maxval == 0:
+ max_bar_width = bar_space-3
+ image = " "
+ if cols < min_columns:
+ return image
+ if position <= 0.5:
+ offset = 2 * position
+ else:
+ offset = 2 * (1 - position)
+ delta = 0.5 / max_bar_width
+ position += delta
+ if position >= 1.0:
+ position = 0.0
+ # make sure it touches the ends
+ if 1.0 - position < delta:
+ position = 1.0
+ if position < 0.5 and 0.5 - position < delta:
+ position = 0.5
+ self._position = position
+ bar_width = int(offset * max_bar_width)
+ image = image + "[" + (bar_width * " ") + \
+ "<=>" + ((max_bar_width - bar_width) * " ") + "]"
+ return image
+ else:
+ percentage = int(100 * float(curval) / maxval)
+ if percentage == 100:
+ percentage_str_width += 1
+ bar_space -= 1
+ max_bar_width = bar_space - 1
+ image = ("%d%% " % percentage).rjust(percentage_str_width)
+ if cols < min_columns:
+ return image
+ offset = float(curval) / maxval
+ bar_width = int(offset * max_bar_width)
+ image = image + "[" + (bar_width * "=") + \
+ ">" + ((max_bar_width - bar_width) * " ") + "]"
+ return image
+
+_color_map_loaded = False
+
+def _init(config_root='/'):
+ """
+ Load color.map from the given config_root. This is called automatically
+ on first access of the codes or _styles attributes (unless it has already
+ been called for some other reason).
+ """
+
+ global _color_map_loaded, codes, _styles
+ if _color_map_loaded:
+ return
+
+ _color_map_loaded = True
+ codes = object.__getattribute__(codes, '_attr')
+ _styles = object.__getattribute__(_styles, '_attr')
+
+ for k, v in codes.items():
+ codes[k] = _unicode_decode(v)
+
+ for k, v in _styles.items():
+ _styles[k] = _unicode_decode(v)
+
+ try:
+ _parse_color_map(config_root=config_root,
+ onerror=lambda e: writemsg("%s\n" % str(e), noiselevel=-1))
+ except FileNotFound:
+ pass
+ except PermissionDenied as e:
+ writemsg(_("Permission denied: '%s'\n") % str(e), noiselevel=-1)
+ del e
+ except PortageException as e:
+ writemsg("%s\n" % str(e), noiselevel=-1)
+ del e
+
+class _LazyInitColorMap(portage.proxy.objectproxy.ObjectProxy):
+
+ __slots__ = ('_attr',)
+
+ def __init__(self, attr):
+ portage.proxy.objectproxy.ObjectProxy.__init__(self)
+ object.__setattr__(self, '_attr', attr)
+
+ def _get_target(self):
+ _init()
+ return object.__getattribute__(self, '_attr')
+
+codes = _LazyInitColorMap(codes)
+_styles = _LazyInitColorMap(_styles)
diff --git a/portage_with_autodep/pym/portage/package/__init__.py b/portage_with_autodep/pym/portage/package/__init__.py
new file mode 100644
index 0000000..21a391a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/package/ebuild/__init__.py b/portage_with_autodep/pym/portage/package/ebuild/__init__.py
new file mode 100644
index 0000000..21a391a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_config/KeywordsManager.py b/portage_with_autodep/pym/portage/package/ebuild/_config/KeywordsManager.py
new file mode 100644
index 0000000..cd22554
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_config/KeywordsManager.py
@@ -0,0 +1,284 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = (
+ 'KeywordsManager',
+)
+
+from _emerge.Package import Package
+from portage import os
+from portage.dep import ExtendedAtomDict, _repo_separator, _slot_separator
+from portage.localization import _
+from portage.package.ebuild._config.helper import ordered_by_atom_specificity
+from portage.util import grabdict_package, stack_lists, writemsg
+from portage.versions import cpv_getkey
+
+class KeywordsManager(object):
+ """Manager class to handle keywords processing and validation"""
+
+ def __init__(self, profiles, abs_user_config, user_config=True,
+ global_accept_keywords=""):
+ self._pkeywords_list = []
+ rawpkeywords = [grabdict_package(
+ os.path.join(x, "package.keywords"), recursive=1,
+ verify_eapi=True) \
+ for x in profiles]
+ for pkeyworddict in rawpkeywords:
+ if not pkeyworddict:
+ # Omit non-existent files from the stack.
+ continue
+ cpdict = {}
+ for k, v in pkeyworddict.items():
+ cpdict.setdefault(k.cp, {})[k] = v
+ self._pkeywords_list.append(cpdict)
+ self._pkeywords_list = tuple(self._pkeywords_list)
+
+ self._p_accept_keywords = []
+ raw_p_accept_keywords = [grabdict_package(
+ os.path.join(x, "package.accept_keywords"), recursive=1,
+ verify_eapi=True) \
+ for x in profiles]
+ for d in raw_p_accept_keywords:
+ if not d:
+ # Omit non-existent files from the stack.
+ continue
+ cpdict = {}
+ for k, v in d.items():
+ cpdict.setdefault(k.cp, {})[k] = tuple(v)
+ self._p_accept_keywords.append(cpdict)
+ self._p_accept_keywords = tuple(self._p_accept_keywords)
+
+ self.pkeywordsdict = ExtendedAtomDict(dict)
+
+ if user_config:
+ pkgdict = grabdict_package(
+ os.path.join(abs_user_config, "package.keywords"),
+ recursive=1, allow_wildcard=True, allow_repo=True,
+ verify_eapi=False)
+
+ for k, v in grabdict_package(
+ os.path.join(abs_user_config, "package.accept_keywords"),
+ recursive=1, allow_wildcard=True, allow_repo=True,
+ verify_eapi=False).items():
+ pkgdict.setdefault(k, []).extend(v)
+
+ accept_keywords_defaults = global_accept_keywords.split()
+ accept_keywords_defaults = tuple('~' + keyword for keyword in \
+ accept_keywords_defaults if keyword[:1] not in "~-")
+ for k, v in pkgdict.items():
+ # default to ~arch if no specific keyword is given
+ if not v:
+ v = accept_keywords_defaults
+ else:
+ v = tuple(v)
+ self.pkeywordsdict.setdefault(k.cp, {})[k] = v
+
+
+ def getKeywords(self, cpv, slot, keywords, repo):
+ cp = cpv_getkey(cpv)
+ pkg = "".join((cpv, _slot_separator, slot))
+ if repo and repo != Package.UNKNOWN_REPO:
+ pkg = "".join((pkg, _repo_separator, repo))
+ keywords = [[x for x in keywords.split() if x != "-*"]]
+ for pkeywords_dict in self._pkeywords_list:
+ cpdict = pkeywords_dict.get(cp)
+ if cpdict:
+ pkg_keywords = ordered_by_atom_specificity(cpdict, pkg)
+ if pkg_keywords:
+ keywords.extend(pkg_keywords)
+ return stack_lists(keywords, incremental=True)
+
+
+ def getMissingKeywords(self,
+ cpv,
+ slot,
+ keywords,
+ repo,
+ global_accept_keywords,
+ backuped_accept_keywords):
+ """
+ Take a package and return a list of any KEYWORDS that the user may
+ need to accept for the given package. If the KEYWORDS are empty
+ and the the ** keyword has not been accepted, the returned list will
+ contain ** alone (in order to distinguish from the case of "none
+ missing").
+
+ @param cpv: The package name (for package.keywords support)
+ @type cpv: String
+ @param slot: The 'SLOT' key from the raw package metadata
+ @type slot: String
+ @param keywords: The 'KEYWORDS' key from the raw package metadata
+ @type keywords: String
+ @param global_accept_keywords: The current value of ACCEPT_KEYWORDS
+ @type global_accept_keywords: String
+ @param backuped_accept_keywords: ACCEPT_KEYWORDS from the backup env
+ @type backuped_accept_keywords: String
+ @rtype: List
+ @return: A list of KEYWORDS that have not been accepted.
+ """
+
+ mygroups = self.getKeywords(cpv, slot, keywords, repo)
+ # Repoman may modify this attribute as necessary.
+ pgroups = global_accept_keywords.split()
+
+ unmaskgroups = self.getPKeywords(cpv, slot, repo,
+ global_accept_keywords)
+ pgroups.extend(unmaskgroups)
+
+ # Hack: Need to check the env directly here as otherwise stacking
+ # doesn't work properly as negative values are lost in the config
+ # object (bug #139600)
+ egroups = backuped_accept_keywords.split()
+
+ if unmaskgroups or egroups:
+ pgroups = self._getEgroups(egroups, pgroups)
+ else:
+ pgroups = set(pgroups)
+
+ return self._getMissingKeywords(cpv, pgroups, mygroups)
+
+
+ def getRawMissingKeywords(self,
+ cpv,
+ slot,
+ keywords,
+ repo,
+ global_accept_keywords):
+ """
+ Take a package and return a list of any KEYWORDS that the user may
+ need to accept for the given package. If the KEYWORDS are empty,
+ the returned list will contain ** alone (in order to distinguish
+ from the case of "none missing"). This DOES NOT apply any user config
+ package.accept_keywords acceptance.
+
+ @param cpv: The package name (for package.keywords support)
+ @type cpv: String
+ @param slot: The 'SLOT' key from the raw package metadata
+ @type slot: String
+ @param keywords: The 'KEYWORDS' key from the raw package metadata
+ @type keywords: String
+ @param global_accept_keywords: The current value of ACCEPT_KEYWORDS
+ @type global_accept_keywords: String
+ @rtype: List
+ @return: lists of KEYWORDS that have not been accepted
+ and the keywords it looked for.
+ """
+
+ mygroups = self.getKeywords(cpv, slot, keywords, repo)
+ pgroups = global_accept_keywords.split()
+ pgroups = set(pgroups)
+ return self._getMissingKeywords(cpv, pgroups, mygroups)
+
+
+ @staticmethod
+ def _getEgroups(egroups, mygroups):
+ """gets any keywords defined in the environment
+
+ @param backuped_accept_keywords: ACCEPT_KEYWORDS from the backup env
+ @type backuped_accept_keywords: String
+ @rtype: List
+ @return: list of KEYWORDS that have been accepted
+ """
+ mygroups = list(mygroups)
+ mygroups.extend(egroups)
+ inc_pgroups = set()
+ for x in mygroups:
+ if x[:1] == "-":
+ if x == "-*":
+ inc_pgroups.clear()
+ else:
+ inc_pgroups.discard(x[1:])
+ else:
+ inc_pgroups.add(x)
+ return inc_pgroups
+
+
+ @staticmethod
+ def _getMissingKeywords(cpv, pgroups, mygroups):
+ """Determines the missing keywords
+
+ @param pgroups: The pkg keywords accepted
+ @type pgroups: list
+ @param mygroups: The ebuild keywords
+ @type mygroups: list
+ """
+ match = False
+ hasstable = False
+ hastesting = False
+ for gp in mygroups:
+ if gp == "*" or (gp == "-*" and len(mygroups) == 1):
+ writemsg(_("--- WARNING: Package '%(cpv)s' uses"
+ " '%(keyword)s' keyword.\n") % {"cpv": cpv, "keyword": gp},
+ noiselevel=-1)
+ if gp == "*":
+ match = True
+ break
+ elif gp in pgroups:
+ match = True
+ break
+ elif gp.startswith("~"):
+ hastesting = True
+ elif not gp.startswith("-"):
+ hasstable = True
+ if not match and \
+ ((hastesting and "~*" in pgroups) or \
+ (hasstable and "*" in pgroups) or "**" in pgroups):
+ match = True
+ if match:
+ missing = []
+ else:
+ if not mygroups:
+ # If KEYWORDS is empty then we still have to return something
+ # in order to distinguish from the case of "none missing".
+ mygroups.append("**")
+ missing = mygroups
+ return missing
+
+
+ def getPKeywords(self, cpv, slot, repo, global_accept_keywords):
+ """Gets any package.keywords settings for cp for the given
+ cpv, slot and repo
+
+ @param cpv: The package name (for package.keywords support)
+ @type cpv: String
+ @param slot: The 'SLOT' key from the raw package metadata
+ @type slot: String
+ @param keywords: The 'KEYWORDS' key from the raw package metadata
+ @type keywords: String
+ @param global_accept_keywords: The current value of ACCEPT_KEYWORDS
+ @type global_accept_keywords: String
+ @param backuped_accept_keywords: ACCEPT_KEYWORDS from the backup env
+ @type backuped_accept_keywords: String
+ @rtype: List
+ @return: list of KEYWORDS that have been accepted
+ """
+
+ pgroups = global_accept_keywords.split()
+ cp = cpv_getkey(cpv)
+
+ unmaskgroups = []
+ if self._p_accept_keywords:
+ cpv_slot = "%s:%s" % (cpv, slot)
+ accept_keywords_defaults = tuple('~' + keyword for keyword in \
+ pgroups if keyword[:1] not in "~-")
+ for d in self._p_accept_keywords:
+ cpdict = d.get(cp)
+ if cpdict:
+ pkg_accept_keywords = \
+ ordered_by_atom_specificity(cpdict, cpv_slot)
+ if pkg_accept_keywords:
+ for x in pkg_accept_keywords:
+ if not x:
+ x = accept_keywords_defaults
+ unmaskgroups.extend(x)
+
+ pkgdict = self.pkeywordsdict.get(cp)
+ if pkgdict:
+ cpv_slot = "%s:%s" % (cpv, slot)
+ pkg_accept_keywords = \
+ ordered_by_atom_specificity(pkgdict, cpv_slot, repo=repo)
+ if pkg_accept_keywords:
+ for x in pkg_accept_keywords:
+ unmaskgroups.extend(x)
+ return unmaskgroups
+
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_config/LicenseManager.py b/portage_with_autodep/pym/portage/package/ebuild/_config/LicenseManager.py
new file mode 100644
index 0000000..effd55b
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_config/LicenseManager.py
@@ -0,0 +1,236 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = (
+ 'LicenseManager',
+)
+
+from portage import os
+from portage.dep import ExtendedAtomDict, use_reduce
+from portage.exception import InvalidDependString
+from portage.localization import _
+from portage.util import grabdict, grabdict_package, writemsg
+from portage.versions import cpv_getkey
+
+from portage.package.ebuild._config.helper import ordered_by_atom_specificity
+
+
+class LicenseManager(object):
+
+ def __init__(self, license_group_locations, abs_user_config, user_config=True):
+
+ self._accept_license_str = None
+ self._accept_license = None
+ self._license_groups = {}
+ self._plicensedict = ExtendedAtomDict(dict)
+ self._undef_lic_groups = set()
+
+ if user_config:
+ license_group_locations = list(license_group_locations) + [abs_user_config]
+
+ self._read_license_groups(license_group_locations)
+
+ if user_config:
+ self._read_user_config(abs_user_config)
+
+ def _read_user_config(self, abs_user_config):
+ licdict = grabdict_package(os.path.join(
+ abs_user_config, "package.license"), recursive=1, allow_wildcard=True, allow_repo=True, verify_eapi=False)
+ for k, v in licdict.items():
+ self._plicensedict.setdefault(k.cp, {})[k] = \
+ self.expandLicenseTokens(v)
+
+ def _read_license_groups(self, locations):
+ for loc in locations:
+ for k, v in grabdict(
+ os.path.join(loc, "license_groups")).items():
+ self._license_groups.setdefault(k, []).extend(v)
+
+ for k, v in self._license_groups.items():
+ self._license_groups[k] = frozenset(v)
+
+ def extract_global_changes(self, old=""):
+ ret = old
+ atom_license_map = self._plicensedict.get("*/*")
+ if atom_license_map is not None:
+ v = atom_license_map.pop("*/*", None)
+ if v is not None:
+ ret = " ".join(v)
+ if old:
+ ret = old + " " + ret
+ if not atom_license_map:
+ #No tokens left in atom_license_map, remove it.
+ del self._plicensedict["*/*"]
+ return ret
+
+ def expandLicenseTokens(self, tokens):
+ """ Take a token from ACCEPT_LICENSE or package.license and expand it
+ if it's a group token (indicated by @) or just return it if it's not a
+ group. If a group is negated then negate all group elements."""
+ expanded_tokens = []
+ for x in tokens:
+ expanded_tokens.extend(self._expandLicenseToken(x, None))
+ return expanded_tokens
+
+ def _expandLicenseToken(self, token, traversed_groups):
+ negate = False
+ rValue = []
+ if token.startswith("-"):
+ negate = True
+ license_name = token[1:]
+ else:
+ license_name = token
+ if not license_name.startswith("@"):
+ rValue.append(token)
+ return rValue
+ group_name = license_name[1:]
+ if traversed_groups is None:
+ traversed_groups = set()
+ license_group = self._license_groups.get(group_name)
+ if group_name in traversed_groups:
+ writemsg(_("Circular license group reference"
+ " detected in '%s'\n") % group_name, noiselevel=-1)
+ rValue.append("@"+group_name)
+ elif license_group:
+ traversed_groups.add(group_name)
+ for l in license_group:
+ if l.startswith("-"):
+ writemsg(_("Skipping invalid element %s"
+ " in license group '%s'\n") % (l, group_name),
+ noiselevel=-1)
+ else:
+ rValue.extend(self._expandLicenseToken(l, traversed_groups))
+ else:
+ if self._license_groups and \
+ group_name not in self._undef_lic_groups:
+ self._undef_lic_groups.add(group_name)
+ writemsg(_("Undefined license group '%s'\n") % group_name,
+ noiselevel=-1)
+ rValue.append("@"+group_name)
+ if negate:
+ rValue = ["-" + token for token in rValue]
+ return rValue
+
+ def _getPkgAcceptLicense(self, cpv, slot, repo):
+ """
+ Get an ACCEPT_LICENSE list, accounting for package.license.
+ """
+ accept_license = self._accept_license
+ cp = cpv_getkey(cpv)
+ cpdict = self._plicensedict.get(cp)
+ if cpdict:
+ cpv_slot = "%s:%s" % (cpv, slot)
+ plicence_list = ordered_by_atom_specificity(cpdict, cpv_slot, repo)
+ if plicence_list:
+ accept_license = list(self._accept_license)
+ for x in plicence_list:
+ accept_license.extend(x)
+ return accept_license
+
+ def get_prunned_accept_license(self, cpv, use, lic, slot, repo):
+ """
+ Generate a pruned version of ACCEPT_LICENSE, by intersection with
+ LICENSE. This is required since otherwise ACCEPT_LICENSE might be
+ too big (bigger than ARG_MAX), causing execve() calls to fail with
+ E2BIG errors as in bug #262647.
+ """
+ try:
+ licenses = set(use_reduce(lic, uselist=use, flat=True))
+ except InvalidDependString:
+ licenses = set()
+ licenses.discard('||')
+
+ accept_license = self._getPkgAcceptLicense(cpv, slot, repo)
+
+ if accept_license:
+ acceptable_licenses = set()
+ for x in accept_license:
+ if x == '*':
+ acceptable_licenses.update(licenses)
+ elif x == '-*':
+ acceptable_licenses.clear()
+ elif x[:1] == '-':
+ acceptable_licenses.discard(x[1:])
+ elif x in licenses:
+ acceptable_licenses.add(x)
+
+ licenses = acceptable_licenses
+ return ' '.join(sorted(licenses))
+
+ def getMissingLicenses(self, cpv, use, lic, slot, repo):
+ """
+ Take a LICENSE string and return a list of any licenses that the user
+ may need to accept for the given package. The returned list will not
+ contain any licenses that have already been accepted. This method
+ can throw an InvalidDependString exception.
+
+ @param cpv: The package name (for package.license support)
+ @type cpv: String
+ @param use: "USE" from the cpv's metadata
+ @type use: String
+ @param lic: "LICENSE" from the cpv's metadata
+ @type lic: String
+ @param slot: "SLOT" from the cpv's metadata
+ @type slot: String
+ @rtype: List
+ @return: A list of licenses that have not been accepted.
+ """
+
+ licenses = set(use_reduce(lic, matchall=1, flat=True))
+ licenses.discard('||')
+
+ acceptable_licenses = set()
+ for x in self._getPkgAcceptLicense(cpv, slot, repo):
+ if x == '*':
+ acceptable_licenses.update(licenses)
+ elif x == '-*':
+ acceptable_licenses.clear()
+ elif x[:1] == '-':
+ acceptable_licenses.discard(x[1:])
+ else:
+ acceptable_licenses.add(x)
+
+ license_str = lic
+ if "?" in license_str:
+ use = use.split()
+ else:
+ use = []
+
+ license_struct = use_reduce(license_str, uselist=use, opconvert=True)
+ return self._getMaskedLicenses(license_struct, acceptable_licenses)
+
+ def _getMaskedLicenses(self, license_struct, acceptable_licenses):
+ if not license_struct:
+ return []
+ if license_struct[0] == "||":
+ ret = []
+ for element in license_struct[1:]:
+ if isinstance(element, list):
+ if element:
+ tmp = self._getMaskedLicenses(element, acceptable_licenses)
+ if not tmp:
+ return []
+ ret.extend(tmp)
+ else:
+ if element in acceptable_licenses:
+ return []
+ ret.append(element)
+ # Return all masked licenses, since we don't know which combination
+ # (if any) the user will decide to unmask.
+ return ret
+
+ ret = []
+ for element in license_struct:
+ if isinstance(element, list):
+ if element:
+ ret.extend(self._getMaskedLicenses(element,
+ acceptable_licenses))
+ else:
+ if element not in acceptable_licenses:
+ ret.append(element)
+ return ret
+
+ def set_accept_license_str(self, accept_license_str):
+ if accept_license_str != self._accept_license_str:
+ self._accept_license_str = accept_license_str
+ self._accept_license = tuple(self.expandLicenseTokens(accept_license_str.split()))
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_config/LocationsManager.py b/portage_with_autodep/pym/portage/package/ebuild/_config/LocationsManager.py
new file mode 100644
index 0000000..c2b115b
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_config/LocationsManager.py
@@ -0,0 +1,182 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = (
+ 'LocationsManager',
+)
+
+import io
+from portage import os, eapi_is_supported, _encodings, _unicode_encode
+from portage.const import CUSTOM_PROFILE_PATH, GLOBAL_CONFIG_PATH, \
+ PROFILE_PATH, USER_CONFIG_PATH
+from portage.exception import DirectoryNotFound, ParseError
+from portage.localization import _
+from portage.util import ensure_dirs, grabfile, \
+ normalize_path, shlex_split, writemsg
+
+
+class LocationsManager(object):
+
+ def __init__(self, config_root=None, eprefix=None, config_profile_path=None, local_config=True, \
+ target_root=None):
+ self.user_profile_dir = None
+ self._local_repo_conf_path = None
+ self.eprefix = eprefix
+ self.config_root = config_root
+ self.target_root = target_root
+ self._user_config = local_config
+
+ if self.eprefix is None:
+ self.eprefix = ""
+
+ if self.config_root is None:
+ self.config_root = self.eprefix + os.sep
+
+ self.config_root = normalize_path(os.path.abspath(
+ self.config_root)).rstrip(os.path.sep) + os.path.sep
+
+ self._check_var_directory("PORTAGE_CONFIGROOT", self.config_root)
+ self.abs_user_config = os.path.join(self.config_root, USER_CONFIG_PATH)
+
+ if config_profile_path is None:
+ config_profile_path = \
+ os.path.join(self.config_root, PROFILE_PATH)
+ if os.path.isdir(config_profile_path):
+ self.profile_path = config_profile_path
+ else:
+ config_profile_path = \
+ os.path.join(self.abs_user_config, 'make.profile')
+ if os.path.isdir(config_profile_path):
+ self.profile_path = config_profile_path
+ else:
+ self.profile_path = None
+ else:
+ # NOTE: repoman may pass in an empty string
+ # here, in order to create an empty profile
+ # for checking dependencies of packages with
+ # empty KEYWORDS.
+ self.profile_path = config_profile_path
+
+
+ # The symlink might not exist or might not be a symlink.
+ self.profiles = []
+ if self.profile_path:
+ try:
+ self._addProfile(os.path.realpath(self.profile_path))
+ except ParseError as e:
+ writemsg(_("!!! Unable to parse profile: '%s'\n") % \
+ self.profile_path, noiselevel=-1)
+ writemsg("!!! ParseError: %s\n" % str(e), noiselevel=-1)
+ self.profiles = []
+
+ if self._user_config and self.profiles:
+ custom_prof = os.path.join(
+ self.config_root, CUSTOM_PROFILE_PATH)
+ if os.path.exists(custom_prof):
+ self.user_profile_dir = custom_prof
+ self.profiles.append(custom_prof)
+ del custom_prof
+
+ self.profiles = tuple(self.profiles)
+
+ def _check_var_directory(self, varname, var):
+ if not os.path.isdir(var):
+ writemsg(_("!!! Error: %s='%s' is not a directory. "
+ "Please correct this.\n") % (varname, var),
+ noiselevel=-1)
+ raise DirectoryNotFound(var)
+
+ def _addProfile(self, currentPath):
+ parentsFile = os.path.join(currentPath, "parent")
+ eapi_file = os.path.join(currentPath, "eapi")
+ try:
+ eapi = io.open(_unicode_encode(eapi_file,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'], errors='replace'
+ ).readline().strip()
+ except IOError:
+ pass
+ else:
+ if not eapi_is_supported(eapi):
+ raise ParseError(_(
+ "Profile contains unsupported "
+ "EAPI '%s': '%s'") % \
+ (eapi, os.path.realpath(eapi_file),))
+ if os.path.exists(parentsFile):
+ parents = grabfile(parentsFile)
+ if not parents:
+ raise ParseError(
+ _("Empty parent file: '%s'") % parentsFile)
+ for parentPath in parents:
+ parentPath = normalize_path(os.path.join(
+ currentPath, parentPath))
+ if os.path.exists(parentPath):
+ self._addProfile(parentPath)
+ else:
+ raise ParseError(
+ _("Parent '%s' not found: '%s'") % \
+ (parentPath, parentsFile))
+ self.profiles.append(currentPath)
+
+ def set_root_override(self, root_overwrite=None):
+ # Allow ROOT setting to come from make.conf if it's not overridden
+ # by the constructor argument (from the calling environment).
+ if self.target_root is None and root_overwrite is not None:
+ self.target_root = root_overwrite
+ if not self.target_root.strip():
+ self.target_root = None
+ if self.target_root is None:
+ self.target_root = "/"
+
+ self.target_root = normalize_path(os.path.abspath(
+ self.target_root)).rstrip(os.path.sep) + os.path.sep
+
+ ensure_dirs(self.target_root)
+ self._check_var_directory("ROOT", self.target_root)
+
+ self.eroot = self.target_root.rstrip(os.sep) + self.eprefix + os.sep
+
+ # make.globals should not be relative to config_root
+ # because it only contains constants. However, if EPREFIX
+ # is set then there are two possible scenarios:
+ # 1) If $ROOT == "/" then make.globals should be
+ # relative to EPREFIX.
+ # 2) If $ROOT != "/" then the correct location of
+ # make.globals needs to be specified in the constructor
+ # parameters, since it's a property of the host system
+ # (and the current config represents the target system).
+ self.global_config_path = GLOBAL_CONFIG_PATH
+ if self.eprefix:
+ if self.target_root == "/":
+ # case (1) above
+ self.global_config_path = os.path.join(self.eprefix,
+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
+ else:
+ # case (2) above
+ # For now, just assume make.globals is relative
+ # to EPREFIX.
+ # TODO: Pass in more info to the constructor,
+ # so we know the host system configuration.
+ self.global_config_path = os.path.join(self.eprefix,
+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
+
+ def set_port_dirs(self, portdir, portdir_overlay):
+ self.portdir = portdir
+ self.portdir_overlay = portdir_overlay
+ if self.portdir_overlay is None:
+ self.portdir_overlay = ""
+
+ self.overlay_profiles = []
+ for ov in shlex_split(self.portdir_overlay):
+ ov = normalize_path(ov)
+ profiles_dir = os.path.join(ov, "profiles")
+ if os.path.isdir(profiles_dir):
+ self.overlay_profiles.append(profiles_dir)
+
+ self.profile_locations = [os.path.join(portdir, "profiles")] + self.overlay_profiles
+ self.profile_and_user_locations = self.profile_locations[:]
+ if self._user_config:
+ self.profile_and_user_locations.append(self.abs_user_config)
+
+ self.profile_locations = tuple(self.profile_locations)
+ self.profile_and_user_locations = tuple(self.profile_and_user_locations)
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_config/MaskManager.py b/portage_with_autodep/pym/portage/package/ebuild/_config/MaskManager.py
new file mode 100644
index 0000000..df93e10
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_config/MaskManager.py
@@ -0,0 +1,189 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = (
+ 'MaskManager',
+)
+
+from portage import os
+from portage.dep import ExtendedAtomDict, match_from_list, _repo_separator, _slot_separator
+from portage.util import append_repo, grabfile_package, stack_lists
+from portage.versions import cpv_getkey
+from _emerge.Package import Package
+
+class MaskManager(object):
+
+ def __init__(self, repositories, profiles, abs_user_config,
+ user_config=True, strict_umatched_removal=False):
+ self._punmaskdict = ExtendedAtomDict(list)
+ self._pmaskdict = ExtendedAtomDict(list)
+ # Preserves atoms that are eliminated by negative
+ # incrementals in user_pkgmasklines.
+ self._pmaskdict_raw = ExtendedAtomDict(list)
+
+ #Read profile/package.mask from every repo.
+ #Repositories inherit masks from their parent profiles and
+ #are able to remove mask from them with -atoms.
+ #Such a removal affects only the current repo, but not the parent.
+ #Add ::repo specs to every atom to make sure atoms only affect
+ #packages from the current repo.
+
+ # Cache the repository-wide package.mask files as a particular
+ # repo may be often referenced by others as the master.
+ pmask_cache = {}
+
+ def grab_pmask(loc):
+ if loc not in pmask_cache:
+ pmask_cache[loc] = grabfile_package(
+ os.path.join(loc, "profiles", "package.mask"),
+ recursive=1, remember_source_file=True, verify_eapi=True)
+ return pmask_cache[loc]
+
+ repo_pkgmasklines = []
+ for repo in repositories.repos_with_profiles():
+ lines = []
+ repo_lines = grab_pmask(repo.location)
+ for master in repo.masters:
+ master_lines = grab_pmask(master.location)
+ lines.append(stack_lists([master_lines, repo_lines], incremental=1,
+ remember_source_file=True, warn_for_unmatched_removal=True,
+ strict_warn_for_unmatched_removal=strict_umatched_removal))
+ if not repo.masters:
+ lines.append(stack_lists([repo_lines], incremental=1,
+ remember_source_file=True, warn_for_unmatched_removal=True,
+ strict_warn_for_unmatched_removal=strict_umatched_removal))
+ repo_pkgmasklines.extend(append_repo(stack_lists(lines), repo.name, remember_source_file=True))
+
+ repo_pkgunmasklines = []
+ for repo in repositories.repos_with_profiles():
+ repo_lines = grabfile_package(os.path.join(repo.location, "profiles", "package.unmask"), \
+ recursive=1, remember_source_file=True, verify_eapi=True)
+ lines = stack_lists([repo_lines], incremental=1, \
+ remember_source_file=True, warn_for_unmatched_removal=True,
+ strict_warn_for_unmatched_removal=strict_umatched_removal)
+ repo_pkgunmasklines.extend(append_repo(lines, repo.name, remember_source_file=True))
+
+ #Read package.mask from the user's profile. Stack them in the end
+ #to allow profiles to override masks from their parent profiles.
+ profile_pkgmasklines = []
+ profile_pkgunmasklines = []
+ for x in profiles:
+ profile_pkgmasklines.append(grabfile_package(
+ os.path.join(x, "package.mask"), recursive=1, remember_source_file=True, verify_eapi=True))
+ profile_pkgunmasklines.append(grabfile_package(
+ os.path.join(x, "package.unmask"), recursive=1, remember_source_file=True, verify_eapi=True))
+ profile_pkgmasklines = stack_lists(profile_pkgmasklines, incremental=1, \
+ remember_source_file=True, warn_for_unmatched_removal=True,
+ strict_warn_for_unmatched_removal=strict_umatched_removal)
+ profile_pkgunmasklines = stack_lists(profile_pkgunmasklines, incremental=1, \
+ remember_source_file=True, warn_for_unmatched_removal=True,
+ strict_warn_for_unmatched_removal=strict_umatched_removal)
+
+ #Read /etc/portage/package.mask. Don't stack it to allow the user to
+ #remove mask atoms from everywhere with -atoms.
+ user_pkgmasklines = []
+ user_pkgunmasklines = []
+ if user_config:
+ user_pkgmasklines = grabfile_package(
+ os.path.join(abs_user_config, "package.mask"), recursive=1, \
+ allow_wildcard=True, allow_repo=True, remember_source_file=True, verify_eapi=False)
+ user_pkgunmasklines = grabfile_package(
+ os.path.join(abs_user_config, "package.unmask"), recursive=1, \
+ allow_wildcard=True, allow_repo=True, remember_source_file=True, verify_eapi=False)
+
+ #Stack everything together. At this point, only user_pkgmasklines may contain -atoms.
+ #Don't warn for unmatched -atoms here, since we don't do it for any other user config file.
+ raw_pkgmasklines = stack_lists([repo_pkgmasklines, profile_pkgmasklines], \
+ incremental=1, remember_source_file=True, warn_for_unmatched_removal=False, ignore_repo=True)
+ pkgmasklines = stack_lists([repo_pkgmasklines, profile_pkgmasklines, user_pkgmasklines], \
+ incremental=1, remember_source_file=True, warn_for_unmatched_removal=False, ignore_repo=True)
+ pkgunmasklines = stack_lists([repo_pkgunmasklines, profile_pkgunmasklines, user_pkgunmasklines], \
+ incremental=1, remember_source_file=True, warn_for_unmatched_removal=False, ignore_repo=True)
+
+ for x, source_file in raw_pkgmasklines:
+ self._pmaskdict_raw.setdefault(x.cp, []).append(x)
+
+ for x, source_file in pkgmasklines:
+ self._pmaskdict.setdefault(x.cp, []).append(x)
+
+ for x, source_file in pkgunmasklines:
+ self._punmaskdict.setdefault(x.cp, []).append(x)
+
+ for d in (self._pmaskdict_raw, self._pmaskdict, self._punmaskdict):
+ for k, v in d.items():
+ d[k] = tuple(v)
+
+ def _getMaskAtom(self, cpv, slot, repo, unmask_atoms=None):
+ """
+ Take a package and return a matching package.mask atom, or None if no
+ such atom exists or it has been cancelled by package.unmask. PROVIDE
+ is not checked, so atoms will not be found for old-style virtuals.
+
+ @param cpv: The package name
+ @type cpv: String
+ @param slot: The package's slot
+ @type slot: String
+ @param repo: The package's repository [optional]
+ @type repo: String
+ @param unmask_atoms: if desired pass in self._punmaskdict.get(cp)
+ @type unmask_atoms: list
+ @rtype: String
+ @return: A matching atom string or None if one is not found.
+ """
+
+ cp = cpv_getkey(cpv)
+ mask_atoms = self._pmaskdict.get(cp)
+ if mask_atoms:
+ pkg = "".join((cpv, _slot_separator, slot))
+ if repo and repo != Package.UNKNOWN_REPO:
+ pkg = "".join((pkg, _repo_separator, repo))
+ pkg_list = [pkg]
+ for x in mask_atoms:
+ if not match_from_list(x, pkg_list):
+ continue
+ if unmask_atoms:
+ for y in unmask_atoms:
+ if match_from_list(y, pkg_list):
+ return None
+ return x
+ return None
+
+
+ def getMaskAtom(self, cpv, slot, repo):
+ """
+ Take a package and return a matching package.mask atom, or None if no
+ such atom exists or it has been cancelled by package.unmask. PROVIDE
+ is not checked, so atoms will not be found for old-style virtuals.
+
+ @param cpv: The package name
+ @type cpv: String
+ @param slot: The package's slot
+ @type slot: String
+ @param repo: The package's repository [optional]
+ @type repo: String
+ @rtype: String
+ @return: A matching atom string or None if one is not found.
+ """
+
+ cp = cpv_getkey(cpv)
+ return self._getMaskAtom(cpv, slot, repo, self._punmaskdict.get(cp))
+
+
+ def getRawMaskAtom(self, cpv, slot, repo):
+ """
+ Take a package and return a matching package.mask atom, or None if no
+ such atom exists. It HAS NOT! been cancelled by any package.unmask.
+ PROVIDE is not checked, so atoms will not be found for old-style
+ virtuals.
+
+ @param cpv: The package name
+ @type cpv: String
+ @param slot: The package's slot
+ @type slot: String
+ @param repo: The package's repository [optional]
+ @type repo: String
+ @rtype: String
+ @return: A matching atom string or None if one is not found.
+ """
+
+ return self._getMaskAtom(cpv, slot, repo)
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_config/UseManager.py b/portage_with_autodep/pym/portage/package/ebuild/_config/UseManager.py
new file mode 100644
index 0000000..d7ef0f6
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_config/UseManager.py
@@ -0,0 +1,235 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = (
+ 'UseManager',
+)
+
+from _emerge.Package import Package
+from portage import os
+from portage.dep import ExtendedAtomDict, remove_slot, _get_useflag_re
+from portage.localization import _
+from portage.util import grabfile, grabdict_package, read_corresponding_eapi_file, stack_lists, writemsg
+from portage.versions import cpv_getkey
+
+from portage.package.ebuild._config.helper import ordered_by_atom_specificity
+
+class UseManager(object):
+
+ def __init__(self, repositories, profiles, abs_user_config, user_config=True):
+ # file variable
+ #--------------------------------
+ # repositories
+ #--------------------------------
+ # use.mask _repo_usemask_dict
+ # use.force _repo_useforce_dict
+ # package.use.mask _repo_pusemask_dict
+ # package.use.force _repo_puseforce_dict
+ #--------------------------------
+ # profiles
+ #--------------------------------
+ # use.mask _usemask_list
+ # use.force _useforce_list
+ # package.use.mask _pusemask_list
+ # package.use _pkgprofileuse
+ # package.use.force _puseforce_list
+ #--------------------------------
+ # user config
+ #--------------------------------
+ # package.use _pusedict
+
+ # Dynamic variables tracked by the config class
+ #--------------------------------
+ # profiles
+ #--------------------------------
+ # usemask
+ # useforce
+ #--------------------------------
+ # user config
+ #--------------------------------
+ # puse
+
+ self._repo_usemask_dict = self._parse_repository_files_to_dict_of_tuples("use.mask", repositories)
+ self._repo_useforce_dict = self._parse_repository_files_to_dict_of_tuples("use.force", repositories)
+ self._repo_pusemask_dict = self._parse_repository_files_to_dict_of_dicts("package.use.mask", repositories)
+ self._repo_puseforce_dict = self._parse_repository_files_to_dict_of_dicts("package.use.force", repositories)
+ self._repo_puse_dict = self._parse_repository_files_to_dict_of_dicts("package.use", repositories)
+
+ self._usemask_list = self._parse_profile_files_to_tuple_of_tuples("use.mask", profiles)
+ self._useforce_list = self._parse_profile_files_to_tuple_of_tuples("use.force", profiles)
+ self._pusemask_list = self._parse_profile_files_to_tuple_of_dicts("package.use.mask", profiles)
+ self._pkgprofileuse = self._parse_profile_files_to_tuple_of_dicts("package.use", profiles, juststrings=True)
+ self._puseforce_list = self._parse_profile_files_to_tuple_of_dicts("package.use.force", profiles)
+
+ self._pusedict = self._parse_user_files_to_extatomdict("package.use", abs_user_config, user_config)
+
+ self.repositories = repositories
+
+ def _parse_file_to_tuple(self, file_name):
+ ret = []
+ lines = grabfile(file_name, recursive=1)
+ eapi = read_corresponding_eapi_file(file_name)
+ useflag_re = _get_useflag_re(eapi)
+ for prefixed_useflag in lines:
+ if prefixed_useflag[:1] == "-":
+ useflag = prefixed_useflag[1:]
+ else:
+ useflag = prefixed_useflag
+ if useflag_re.match(useflag) is None:
+ writemsg(_("--- Invalid USE flag in '%s': '%s'\n") %
+ (file_name, prefixed_useflag), noiselevel=-1)
+ else:
+ ret.append(prefixed_useflag)
+ return tuple(ret)
+
+ def _parse_file_to_dict(self, file_name, juststrings=False):
+ ret = {}
+ location_dict = {}
+ file_dict = grabdict_package(file_name, recursive=1, verify_eapi=True)
+ eapi = read_corresponding_eapi_file(file_name)
+ useflag_re = _get_useflag_re(eapi)
+ for k, v in file_dict.items():
+ useflags = []
+ for prefixed_useflag in v:
+ if prefixed_useflag[:1] == "-":
+ useflag = prefixed_useflag[1:]
+ else:
+ useflag = prefixed_useflag
+ if useflag_re.match(useflag) is None:
+ writemsg(_("--- Invalid USE flag for '%s' in '%s': '%s'\n") %
+ (k, file_name, prefixed_useflag), noiselevel=-1)
+ else:
+ useflags.append(prefixed_useflag)
+ location_dict.setdefault(k, []).extend(useflags)
+ for k, v in location_dict.items():
+ if juststrings:
+ v = " ".join(v)
+ else:
+ v = tuple(v)
+ ret.setdefault(k.cp, {})[k] = v
+ return ret
+
+ def _parse_user_files_to_extatomdict(self, file_name, location, user_config):
+ ret = ExtendedAtomDict(dict)
+ if user_config:
+ pusedict = grabdict_package(
+ os.path.join(location, file_name), recursive=1, allow_wildcard=True, allow_repo=True, verify_eapi=False)
+ for k, v in pusedict.items():
+ ret.setdefault(k.cp, {})[k] = tuple(v)
+
+ return ret
+
+ def _parse_repository_files_to_dict_of_tuples(self, file_name, repositories):
+ ret = {}
+ for repo in repositories.repos_with_profiles():
+ ret[repo.name] = self._parse_file_to_tuple(os.path.join(repo.location, "profiles", file_name))
+ return ret
+
+ def _parse_repository_files_to_dict_of_dicts(self, file_name, repositories):
+ ret = {}
+ for repo in repositories.repos_with_profiles():
+ ret[repo.name] = self._parse_file_to_dict(os.path.join(repo.location, "profiles", file_name))
+ return ret
+
+ def _parse_profile_files_to_tuple_of_tuples(self, file_name, locations):
+ return tuple(self._parse_file_to_tuple(os.path.join(profile, file_name)) for profile in locations)
+
+ def _parse_profile_files_to_tuple_of_dicts(self, file_name, locations, juststrings=False):
+ return tuple(self._parse_file_to_dict(os.path.join(profile, file_name), juststrings) for profile in locations)
+
+ def getUseMask(self, pkg=None):
+ if pkg is None:
+ return frozenset(stack_lists(
+ self._usemask_list, incremental=True))
+
+ cp = getattr(pkg, "cp", None)
+ if cp is None:
+ cp = cpv_getkey(remove_slot(pkg))
+ usemask = []
+ if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO:
+ repos = []
+ try:
+ repos.extend(repo.name for repo in
+ self.repositories[pkg.repo].masters)
+ except KeyError:
+ pass
+ repos.append(pkg.repo)
+ for repo in repos:
+ usemask.append(self._repo_usemask_dict.get(repo, {}))
+ cpdict = self._repo_pusemask_dict.get(repo, {}).get(cp)
+ if cpdict:
+ pkg_usemask = ordered_by_atom_specificity(cpdict, pkg)
+ if pkg_usemask:
+ usemask.extend(pkg_usemask)
+ for i, pusemask_dict in enumerate(self._pusemask_list):
+ if self._usemask_list[i]:
+ usemask.append(self._usemask_list[i])
+ cpdict = pusemask_dict.get(cp)
+ if cpdict:
+ pkg_usemask = ordered_by_atom_specificity(cpdict, pkg)
+ if pkg_usemask:
+ usemask.extend(pkg_usemask)
+ return frozenset(stack_lists(usemask, incremental=True))
+
+ def getUseForce(self, pkg=None):
+ if pkg is None:
+ return frozenset(stack_lists(
+ self._useforce_list, incremental=True))
+
+ cp = getattr(pkg, "cp", None)
+ if cp is None:
+ cp = cpv_getkey(remove_slot(pkg))
+ useforce = []
+ if hasattr(pkg, "repo") and pkg.repo != Package.UNKNOWN_REPO:
+ repos = []
+ try:
+ repos.extend(repo.name for repo in
+ self.repositories[pkg.repo].masters)
+ except KeyError:
+ pass
+ repos.append(pkg.repo)
+ for repo in repos:
+ useforce.append(self._repo_useforce_dict.get(repo, {}))
+ cpdict = self._repo_puseforce_dict.get(repo, {}).get(cp)
+ if cpdict:
+ pkg_useforce = ordered_by_atom_specificity(cpdict, pkg)
+ if pkg_useforce:
+ useforce.extend(pkg_useforce)
+ for i, puseforce_dict in enumerate(self._puseforce_list):
+ if self._useforce_list[i]:
+ useforce.append(self._useforce_list[i])
+ cpdict = puseforce_dict.get(cp)
+ if cpdict:
+ pkg_useforce = ordered_by_atom_specificity(cpdict, pkg)
+ if pkg_useforce:
+ useforce.extend(pkg_useforce)
+ return frozenset(stack_lists(useforce, incremental=True))
+
+ def getPUSE(self, pkg):
+ cp = getattr(pkg, "cp", None)
+ if cp is None:
+ cp = cpv_getkey(remove_slot(pkg))
+ ret = ""
+ cpdict = self._pusedict.get(cp)
+ if cpdict:
+ puse_matches = ordered_by_atom_specificity(cpdict, pkg)
+ if puse_matches:
+ puse_list = []
+ for x in puse_matches:
+ puse_list.extend(x)
+ ret = " ".join(puse_list)
+ return ret
+
+ def extract_global_USE_changes(self, old=""):
+ ret = old
+ cpdict = self._pusedict.get("*/*")
+ if cpdict is not None:
+ v = cpdict.pop("*/*", None)
+ if v is not None:
+ ret = " ".join(v)
+ if old:
+ ret = old + " " + ret
+ if not cpdict:
+ #No tokens left in atom_license_map, remove it.
+ del self._pusedict["*/*"]
+ return ret
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_config/VirtualsManager.py b/portage_with_autodep/pym/portage/package/ebuild/_config/VirtualsManager.py
new file mode 100644
index 0000000..c4d1e36
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_config/VirtualsManager.py
@@ -0,0 +1,233 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = (
+ 'VirtualsManager',
+)
+
+from copy import deepcopy
+
+from portage import os
+from portage.dep import Atom
+from portage.exception import InvalidAtom
+from portage.localization import _
+from portage.util import grabdict, stack_dictlist, writemsg
+from portage.versions import cpv_getkey
+
+class VirtualsManager(object):
+
+ def __init__(self, *args, **kwargs):
+ if kwargs.get("_copy"):
+ return
+
+ assert len(args) == 1, "VirtualsManager.__init__ takes one positional argument"
+ assert not kwargs, "unknown keyword argument(s) '%s' passed to VirtualsManager.__init__" % \
+ ", ".join(kwargs)
+
+ profiles = args[0]
+ self._virtuals = None
+ self._dirVirtuals = None
+ self._virts_p = None
+
+ # Virtuals obtained from the vartree
+ self._treeVirtuals = None
+ # Virtuals added by the depgraph via self.add_depgraph_virtuals().
+ self._depgraphVirtuals = {}
+
+ #Initialise _dirVirtuals.
+ self._read_dirVirtuals(profiles)
+
+ #We could initialise _treeVirtuals here, but some consumers want to
+ #pass their own vartree.
+
+ def _read_dirVirtuals(self, profiles):
+ """
+ Read the 'virtuals' file in all profiles.
+ """
+ virtuals_list = []
+ for x in profiles:
+ virtuals_file = os.path.join(x, "virtuals")
+ virtuals_dict = grabdict(virtuals_file)
+ atoms_dict = {}
+ for k, v in virtuals_dict.items():
+ try:
+ virt_atom = Atom(k)
+ except InvalidAtom:
+ virt_atom = None
+ else:
+ if virt_atom.blocker or \
+ str(virt_atom) != str(virt_atom.cp):
+ virt_atom = None
+ if virt_atom is None:
+ writemsg(_("--- Invalid virtuals atom in %s: %s\n") % \
+ (virtuals_file, k), noiselevel=-1)
+ continue
+ providers = []
+ for atom in v:
+ atom_orig = atom
+ if atom[:1] == '-':
+ # allow incrementals
+ atom = atom[1:]
+ try:
+ atom = Atom(atom)
+ except InvalidAtom:
+ atom = None
+ else:
+ if atom.blocker:
+ atom = None
+ if atom is None:
+ writemsg(_("--- Invalid atom in %s: %s\n") % \
+ (virtuals_file, atom_orig), noiselevel=-1)
+ else:
+ if atom_orig == str(atom):
+ # normal atom, so return as Atom instance
+ providers.append(atom)
+ else:
+ # atom has special prefix, so return as string
+ providers.append(atom_orig)
+ if providers:
+ atoms_dict[virt_atom] = providers
+ if atoms_dict:
+ virtuals_list.append(atoms_dict)
+
+ self._dirVirtuals = stack_dictlist(virtuals_list, incremental=True)
+
+ for virt in self._dirVirtuals:
+ # Preference for virtuals decreases from left to right.
+ self._dirVirtuals[virt].reverse()
+
+ def __deepcopy__(self, memo=None):
+ if memo is None:
+ memo = {}
+ result = VirtualsManager(_copy=True)
+ memo[id(self)] = result
+
+ # immutable attributes (internal policy ensures lack of mutation)
+ # _treeVirtuals is initilised by _populate_treeVirtuals().
+ # Before that it's 'None'.
+ result._treeVirtuals = self._treeVirtuals
+ memo[id(self._treeVirtuals)] = self._treeVirtuals
+ # _dirVirtuals is initilised by __init__.
+ result._dirVirtuals = self._dirVirtuals
+ memo[id(self._dirVirtuals)] = self._dirVirtuals
+
+ # mutable attributes (change when add_depgraph_virtuals() is called)
+ result._virtuals = deepcopy(self._virtuals, memo)
+ result._depgraphVirtuals = deepcopy(self._depgraphVirtuals, memo)
+ result._virts_p = deepcopy(self._virts_p, memo)
+
+ return result
+
+ def _compile_virtuals(self):
+ """Stack installed and profile virtuals. Preference for virtuals
+ decreases from left to right.
+ Order of preference:
+ 1. installed and in profile
+ 2. installed only
+ 3. profile only
+ """
+
+ assert self._treeVirtuals is not None, "_populate_treeVirtuals() must be called before " + \
+ "any query about virtuals"
+
+ # Virtuals by profile+tree preferences.
+ ptVirtuals = {}
+
+ for virt, installed_list in self._treeVirtuals.items():
+ profile_list = self._dirVirtuals.get(virt, None)
+ if not profile_list:
+ continue
+ for cp in installed_list:
+ if cp in profile_list:
+ ptVirtuals.setdefault(virt, [])
+ ptVirtuals[virt].append(cp)
+
+ virtuals = stack_dictlist([ptVirtuals, self._treeVirtuals,
+ self._dirVirtuals, self._depgraphVirtuals])
+ self._virtuals = virtuals
+ self._virts_p = None
+
+ def getvirtuals(self):
+ """
+ Computes self._virtuals if necessary and returns it.
+ self._virtuals is only computed on the first call.
+ """
+ if self._virtuals is None:
+ self._compile_virtuals()
+
+ return self._virtuals
+
+ def _populate_treeVirtuals(self, vartree):
+ """
+ Initialize _treeVirtuals from the given vartree.
+ It must not have been initialized already, otherwise
+ our assumptions about immutability don't hold.
+ """
+ assert self._treeVirtuals is None, "treeVirtuals must not be reinitialized"
+
+ self._treeVirtuals = {}
+
+ for provide, cpv_list in vartree.get_all_provides().items():
+ try:
+ provide = Atom(provide)
+ except InvalidAtom:
+ continue
+ self._treeVirtuals[provide.cp] = \
+ [Atom(cpv_getkey(cpv)) for cpv in cpv_list]
+
+ def populate_treeVirtuals_if_needed(self, vartree):
+ """
+ Initialize _treeVirtuals if it hasn't been done already.
+ This is a hack for consumers that already have an populated vartree.
+ """
+ if self._treeVirtuals is not None:
+ return
+
+ self._populate_treeVirtuals(vartree)
+
+ def add_depgraph_virtuals(self, mycpv, virts):
+ """This updates the preferences for old-style virtuals,
+ affecting the behavior of dep_expand() and dep_check()
+ calls. It can change dbapi.match() behavior since that
+ calls dep_expand(). However, dbapi instances have
+ internal match caches that are not invalidated when
+ preferences are updated here. This can potentially
+ lead to some inconsistency (relevant to bug #1343)."""
+
+ #Ensure that self._virtuals is populated.
+ if self._virtuals is None:
+ self.getvirtuals()
+
+ modified = False
+ cp = Atom(cpv_getkey(mycpv))
+ for virt in virts:
+ try:
+ virt = Atom(virt).cp
+ except InvalidAtom:
+ continue
+ providers = self._virtuals.get(virt)
+ if providers and cp in providers:
+ continue
+ providers = self._depgraphVirtuals.get(virt)
+ if providers is None:
+ providers = []
+ self._depgraphVirtuals[virt] = providers
+ if cp not in providers:
+ providers.append(cp)
+ modified = True
+
+ if modified:
+ self._compile_virtuals()
+
+ def get_virts_p(self):
+ if self._virts_p is not None:
+ return self._virts_p
+
+ virts = self.getvirtuals()
+ virts_p = {}
+ for x in virts:
+ vkeysplit = x.split("/")
+ if vkeysplit[1] not in virts_p:
+ virts_p[vkeysplit[1]] = virts[x]
+ self._virts_p = virts_p
+ return virts_p
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_config/__init__.py b/portage_with_autodep/pym/portage/package/ebuild/_config/__init__.py
new file mode 100644
index 0000000..21a391a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_config/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_config/env_var_validation.py b/portage_with_autodep/pym/portage/package/ebuild/_config/env_var_validation.py
new file mode 100644
index 0000000..d3db545
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_config/env_var_validation.py
@@ -0,0 +1,23 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from portage.process import find_binary
+from portage.util import shlex_split
+
+def validate_cmd_var(v):
+ """
+ Validate an evironment variable value to see if it
+ contains an executable command as the first token.
+ returns (valid, token_list) where 'valid' is boolean and 'token_list'
+ is the (possibly empty) list of tokens split by shlex.
+ """
+ invalid = False
+ v_split = shlex_split(v)
+ if not v_split:
+ invalid = True
+ elif os.path.isabs(v_split[0]):
+ invalid = not os.access(v_split[0], os.EX_OK)
+ elif find_binary(v_split[0]) is None:
+ invalid = True
+ return (not invalid, v_split)
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_config/features_set.py b/portage_with_autodep/pym/portage/package/ebuild/_config/features_set.py
new file mode 100644
index 0000000..62236fd
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_config/features_set.py
@@ -0,0 +1,128 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = (
+ 'features_set',
+)
+
+import logging
+
+from portage.const import SUPPORTED_FEATURES
+from portage.localization import _
+from portage.output import colorize
+from portage.util import writemsg_level
+
+class features_set(object):
+ """
+ Provides relevant set operations needed for access and modification of
+ config.features. The FEATURES variable is automatically synchronized
+ upon modification.
+
+ Modifications result in a permanent override that will cause the change
+ to propagate to the incremental stacking mechanism in config.regenerate().
+ This eliminates the need to call config.backup_changes() when FEATURES
+ is modified, since any overrides are guaranteed to persist despite calls
+ to config.reset().
+ """
+
+ def __init__(self, settings):
+ self._settings = settings
+ self._features = set()
+
+ def __contains__(self, k):
+ return k in self._features
+
+ def __iter__(self):
+ return iter(self._features)
+
+ def _sync_env_var(self):
+ self._settings['FEATURES'] = ' '.join(sorted(self._features))
+
+ def add(self, k):
+ self._settings.modifying()
+ self._settings._features_overrides.append(k)
+ if k not in self._features:
+ self._features.add(k)
+ self._sync_env_var()
+
+ def update(self, values):
+ self._settings.modifying()
+ values = list(values)
+ self._settings._features_overrides.extend(values)
+ need_sync = False
+ for k in values:
+ if k in self._features:
+ continue
+ self._features.add(k)
+ need_sync = True
+ if need_sync:
+ self._sync_env_var()
+
+ def difference_update(self, values):
+ self._settings.modifying()
+ values = list(values)
+ self._settings._features_overrides.extend('-' + k for k in values)
+ remove_us = self._features.intersection(values)
+ if remove_us:
+ self._features.difference_update(values)
+ self._sync_env_var()
+
+ def remove(self, k):
+ """
+ This never raises KeyError, since it records a permanent override
+ that will prevent the given flag from ever being added again by
+ incremental stacking in config.regenerate().
+ """
+ self.discard(k)
+
+ def discard(self, k):
+ self._settings.modifying()
+ self._settings._features_overrides.append('-' + k)
+ if k in self._features:
+ self._features.remove(k)
+ self._sync_env_var()
+
+ def _validate(self):
+ """
+ Implements unknown-features-warn and unknown-features-filter.
+ """
+ if 'unknown-features-warn' in self._features:
+ unknown_features = \
+ self._features.difference(SUPPORTED_FEATURES)
+ if unknown_features:
+ unknown_features = unknown_features.difference(
+ self._settings._unknown_features)
+ if unknown_features:
+ self._settings._unknown_features.update(unknown_features)
+ writemsg_level(colorize("BAD",
+ _("FEATURES variable contains unknown value(s): %s") % \
+ ", ".join(sorted(unknown_features))) \
+ + "\n", level=logging.WARNING, noiselevel=-1)
+
+ if 'unknown-features-filter' in self._features:
+ unknown_features = \
+ self._features.difference(SUPPORTED_FEATURES)
+ if unknown_features:
+ self.difference_update(unknown_features)
+ self._prune_overrides()
+
+ def _prune_overrides(self):
+ """
+ If there are lots of invalid package.env FEATURES settings
+ then unknown-features-filter can make _features_overrides
+ grow larger and larger, so prune it. This performs incremental
+ stacking with preservation of negative values since they need
+ to persist for future config.regenerate() calls.
+ """
+ overrides_set = set(self._settings._features_overrides)
+ positive = set()
+ negative = set()
+ for x in self._settings._features_overrides:
+ if x[:1] == '-':
+ positive.discard(x[1:])
+ negative.add(x[1:])
+ else:
+ positive.add(x)
+ negative.discard(x)
+ self._settings._features_overrides[:] = \
+ list(positive) + list('-' + x for x in negative)
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_config/helper.py b/portage_with_autodep/pym/portage/package/ebuild/_config/helper.py
new file mode 100644
index 0000000..4f46781
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_config/helper.py
@@ -0,0 +1,64 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = (
+ 'ordered_by_atom_specificity', 'prune_incremental',
+)
+
+from _emerge.Package import Package
+from portage.dep import best_match_to_list, _repo_separator
+
+def ordered_by_atom_specificity(cpdict, pkg, repo=None):
+ """
+ Return a list of matched values from the given cpdict,
+ in ascending order by atom specificity. The rationale
+ for this order is that package.* config files are
+ typically written in ChangeLog like fashion, so it's
+ most friendly if the order that the atoms are written
+ does not matter. Therefore, settings from more specific
+ atoms override those of less specific atoms. Without
+ this behavior, settings from relatively unspecific atoms
+ would (somewhat confusingly) override the settings of
+ more specific atoms, requiring people to make adjustments
+ to the order that atoms are listed in the config file in
+ order to achieve desired results (and thus corrupting
+ the ChangeLog like ordering of the file).
+ """
+ if repo and repo != Package.UNKNOWN_REPO:
+ pkg = pkg + _repo_separator + repo
+
+ results = []
+ keys = list(cpdict)
+
+ while keys:
+ bestmatch = best_match_to_list(pkg, keys)
+ if bestmatch:
+ keys.remove(bestmatch)
+ results.append(cpdict[bestmatch])
+ else:
+ break
+
+ if results:
+ # reverse, so the most specific atoms come last
+ results.reverse()
+
+ return results
+
+def prune_incremental(split):
+ """
+ Prune off any parts of an incremental variable that are
+ made irrelevant by the latest occuring * or -*. This
+ could be more aggressive but that might be confusing
+ and the point is just to reduce noise a bit.
+ """
+ for i, x in enumerate(reversed(split)):
+ if x == '*':
+ split = split[-i-1:]
+ break
+ elif x == '-*':
+ if i == 0:
+ split = []
+ else:
+ split = split[-i:]
+ break
+ return split
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_config/special_env_vars.py b/portage_with_autodep/pym/portage/package/ebuild/_config/special_env_vars.py
new file mode 100644
index 0000000..6d42809
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_config/special_env_vars.py
@@ -0,0 +1,185 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = (
+ 'case_insensitive_vars', 'default_globals', 'env_blacklist', \
+ 'environ_filter', 'environ_whitelist', 'environ_whitelist_re',
+)
+
+import re
+
+# Blacklisted variables are internal variables that are never allowed
+# to enter the config instance from the external environment or
+# configuration files.
+env_blacklist = frozenset((
+ "A", "AA", "CATEGORY", "DEPEND", "DESCRIPTION", "EAPI",
+ "EBUILD_FORCE_TEST", "EBUILD_PHASE", "EBUILD_SKIP_MANIFEST",
+ "ED", "EMERGE_FROM", "EPREFIX", "EROOT",
+ "HOMEPAGE", "INHERITED", "IUSE",
+ "KEYWORDS", "LICENSE", "MERGE_TYPE",
+ "PDEPEND", "PF", "PKGUSE", "PORTAGE_BACKGROUND",
+ "PORTAGE_BACKGROUND_UNMERGE", "PORTAGE_BUILDIR_LOCKED",
+ "PORTAGE_BUILT_USE", "PORTAGE_CONFIGROOT", "PORTAGE_IUSE",
+ "PORTAGE_NONFATAL", "PORTAGE_REPO_NAME", "PORTAGE_SANDBOX_COMPAT_LEVEL",
+ "PORTAGE_USE", "PROPERTIES", "PROVIDE", "RDEPEND", "RESTRICT",
+ "ROOT", "SLOT", "SRC_URI"
+))
+
+environ_whitelist = []
+
+# Whitelisted variables are always allowed to enter the ebuild
+# environment. Generally, this only includes special portage
+# variables. Ebuilds can unset variables that are not whitelisted
+# and rely on them remaining unset for future phases, without them
+# leaking back in from various locations (bug #189417). It's very
+# important to set our special BASH_ENV variable in the ebuild
+# environment in order to prevent sandbox from sourcing /etc/profile
+# in it's bashrc (causing major leakage).
+environ_whitelist += [
+ "ACCEPT_LICENSE", "BASH_ENV", "BUILD_PREFIX", "D",
+ "DISTDIR", "DOC_SYMLINKS_DIR", "EAPI", "EBUILD",
+ "EBUILD_FORCE_TEST",
+ "EBUILD_PHASE", "ECLASSDIR", "ECLASS_DEPTH", "ED",
+ "EMERGE_FROM", "EPREFIX", "EROOT",
+ "FEATURES", "FILESDIR", "HOME", "MERGE_TYPE", "NOCOLOR", "PATH",
+ "PKGDIR",
+ "PKGUSE", "PKG_LOGDIR", "PKG_TMPDIR",
+ "PORTAGE_ACTUAL_DISTDIR", "PORTAGE_ARCHLIST",
+ "PORTAGE_BASHRC", "PM_EBUILD_HOOK_DIR",
+ "PORTAGE_BINPKG_FILE", "PORTAGE_BINPKG_TAR_OPTS",
+ "PORTAGE_BINPKG_TMPFILE",
+ "PORTAGE_BIN_PATH",
+ "PORTAGE_BUILDDIR", "PORTAGE_BUNZIP2_COMMAND", "PORTAGE_BZIP2_COMMAND",
+ "PORTAGE_COLORMAP",
+ "PORTAGE_CONFIGROOT", "PORTAGE_DEBUG", "PORTAGE_DEPCACHEDIR",
+ "PORTAGE_EBUILD_EXIT_FILE", "PORTAGE_FEATURES",
+ "PORTAGE_GID", "PORTAGE_GRPNAME",
+ "PORTAGE_INST_GID", "PORTAGE_INST_UID",
+ "PORTAGE_IPC_DAEMON", "PORTAGE_IUSE",
+ "PORTAGE_LOG_FILE",
+ "PORTAGE_PYM_PATH", "PORTAGE_PYTHON", "PORTAGE_QUIET",
+ "PORTAGE_REPO_NAME", "PORTAGE_RESTRICT",
+ "PORTAGE_SANDBOX_COMPAT_LEVEL", "PORTAGE_SIGPIPE_STATUS",
+ "PORTAGE_TMPDIR", "PORTAGE_UPDATE_ENV", "PORTAGE_USERNAME",
+ "PORTAGE_VERBOSE", "PORTAGE_WORKDIR_MODE",
+ "PORTDIR", "PORTDIR_OVERLAY", "PREROOTPATH", "PROFILE_PATHS",
+ "REPLACING_VERSIONS", "REPLACED_BY_VERSION",
+ "ROOT", "ROOTPATH", "T", "TMP", "TMPDIR",
+ "USE_EXPAND", "USE_ORDER", "WORKDIR",
+ "XARGS",
+]
+
+# user config variables
+environ_whitelist += [
+ "DOC_SYMLINKS_DIR", "INSTALL_MASK", "PKG_INSTALL_MASK"
+]
+
+environ_whitelist += [
+ "A", "AA", "CATEGORY", "P", "PF", "PN", "PR", "PV", "PVR"
+]
+
+# misc variables inherited from the calling environment
+environ_whitelist += [
+ "COLORTERM", "DISPLAY", "EDITOR", "LESS",
+ "LESSOPEN", "LOGNAME", "LS_COLORS", "PAGER",
+ "TERM", "TERMCAP", "USER",
+ 'ftp_proxy', 'http_proxy', 'no_proxy',
+]
+
+# tempdir settings
+environ_whitelist += [
+ "TMPDIR", "TEMP", "TMP",
+]
+
+# localization settings
+environ_whitelist += [
+ "LANG", "LC_COLLATE", "LC_CTYPE", "LC_MESSAGES",
+ "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "LC_PAPER",
+ "LC_ALL",
+]
+
+# other variables inherited from the calling environment
+environ_whitelist += [
+ "CVS_RSH", "ECHANGELOG_USER",
+ "GPG_AGENT_INFO", "LOG_SOCKET",
+ "SSH_AGENT_PID", "SSH_AUTH_SOCK"
+ "STY", "WINDOW", "XAUTHORITY",
+]
+
+environ_whitelist = frozenset(environ_whitelist)
+
+environ_whitelist_re = re.compile(r'^(CCACHE_|DISTCC_).*')
+
+# Filter selected variables in the config.environ() method so that
+# they don't needlessly propagate down into the ebuild environment.
+environ_filter = []
+
+# Exclude anything that could be extremely long here (like SRC_URI)
+# since that could cause execve() calls to fail with E2BIG errors. For
+# example, see bug #262647.
+environ_filter += [
+ 'DEPEND', 'RDEPEND', 'PDEPEND', 'SRC_URI',
+]
+
+# misc variables inherited from the calling environment
+environ_filter += [
+ "INFOPATH", "MANPATH", "USER",
+]
+
+# variables that break bash
+environ_filter += [
+ "HISTFILE", "POSIXLY_CORRECT",
+]
+
+# portage config variables and variables set directly by portage
+environ_filter += [
+ "ACCEPT_CHOSTS", "ACCEPT_KEYWORDS", "ACCEPT_PROPERTIES", "AUTOCLEAN",
+ "CLEAN_DELAY", "COLLISION_IGNORE", "CONFIG_PROTECT",
+ "CONFIG_PROTECT_MASK", "EGENCACHE_DEFAULT_OPTS", "EMERGE_DEFAULT_OPTS",
+ "EMERGE_LOG_DIR",
+ "EMERGE_WARNING_DELAY",
+ "FETCHCOMMAND", "FETCHCOMMAND_FTP",
+ "FETCHCOMMAND_HTTP", "FETCHCOMMAND_HTTPS",
+ "FETCHCOMMAND_RSYNC", "FETCHCOMMAND_SFTP",
+ "GENTOO_MIRRORS", "NOCONFMEM", "O",
+ "PORTAGE_BACKGROUND", "PORTAGE_BACKGROUND_UNMERGE",
+ "PORTAGE_BINHOST_CHUNKSIZE", "PORTAGE_BUILDIR_LOCKED", "PORTAGE_CALLER",
+ "PORTAGE_ELOG_CLASSES",
+ "PORTAGE_ELOG_MAILFROM", "PORTAGE_ELOG_MAILSUBJECT",
+ "PORTAGE_ELOG_MAILURI", "PORTAGE_ELOG_SYSTEM",
+ "PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS", "PORTAGE_FETCH_RESUME_MIN_SIZE",
+ "PORTAGE_GPG_DIR",
+ "PORTAGE_GPG_KEY", "PORTAGE_GPG_SIGNING_COMMAND",
+ "PORTAGE_IONICE_COMMAND",
+ "PORTAGE_PACKAGE_EMPTY_ABORT",
+ "PORTAGE_REPO_DUPLICATE_WARN",
+ "PORTAGE_RO_DISTDIRS",
+ "PORTAGE_RSYNC_EXTRA_OPTS", "PORTAGE_RSYNC_OPTS",
+ "PORTAGE_RSYNC_RETRIES", "PORTAGE_SYNC_STALE",
+ "PORTAGE_USE", "PORT_LOGDIR",
+ "QUICKPKG_DEFAULT_OPTS",
+ "RESUMECOMMAND", "RESUMECOMMAND_FTP",
+ "RESUMECOMMAND_HTTP", "RESUMECOMMAND_HTTPS",
+ "RESUMECOMMAND_RSYNC", "RESUMECOMMAND_SFTP",
+ "SYNC", "USE_EXPAND_HIDDEN", "USE_ORDER",
+]
+
+environ_filter = frozenset(environ_filter)
+
+# Variables that are not allowed to have per-repo or per-package
+# settings.
+global_only_vars = frozenset([
+ "CONFIG_PROTECT",
+])
+
+default_globals = {
+ 'ACCEPT_LICENSE': '* -@EULA',
+ 'ACCEPT_PROPERTIES': '*',
+ 'PORTAGE_BZIP2_COMMAND': 'bzip2',
+}
+
+validate_commands = ('PORTAGE_BZIP2_COMMAND', 'PORTAGE_BUNZIP2_COMMAND',)
+
+# To enhance usability, make some vars case insensitive
+# by forcing them to lower case.
+case_insensitive_vars = ('AUTOCLEAN', 'NOCOLOR',)
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_ipc/ExitCommand.py b/portage_with_autodep/pym/portage/package/ebuild/_ipc/ExitCommand.py
new file mode 100644
index 0000000..f14050b
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_ipc/ExitCommand.py
@@ -0,0 +1,27 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.package.ebuild._ipc.IpcCommand import IpcCommand
+
+class ExitCommand(IpcCommand):
+
+ __slots__ = ('exitcode', 'reply_hook',)
+
+ def __init__(self):
+ IpcCommand.__init__(self)
+ self.reply_hook = None
+ self.exitcode = None
+
+ def __call__(self, argv):
+
+ if self.exitcode is not None:
+ # Ignore all but the first call, since if die is called
+ # then we certainly want to honor that exitcode, even
+ # the ebuild process manages to send a second exit
+ # command.
+ self.reply_hook = None
+ else:
+ self.exitcode = int(argv[1])
+
+ # (stdout, stderr, returncode)
+ return ('', '', 0)
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_ipc/IpcCommand.py b/portage_with_autodep/pym/portage/package/ebuild/_ipc/IpcCommand.py
new file mode 100644
index 0000000..efb27f0
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_ipc/IpcCommand.py
@@ -0,0 +1,9 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+class IpcCommand(object):
+
+ __slots__ = ()
+
+ def __call__(self, argv):
+ raise NotImplementedError(self)
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_ipc/QueryCommand.py b/portage_with_autodep/pym/portage/package/ebuild/_ipc/QueryCommand.py
new file mode 100644
index 0000000..fb6e61e
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_ipc/QueryCommand.py
@@ -0,0 +1,98 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import io
+
+import portage
+from portage import os
+from portage import _unicode_decode
+from portage.dep import Atom
+from portage.elog import messages as elog_messages
+from portage.exception import InvalidAtom
+from portage.package.ebuild._ipc.IpcCommand import IpcCommand
+from portage.util import normalize_path
+from portage.versions import best
+
+class QueryCommand(IpcCommand):
+
+ __slots__ = ('phase', 'settings',)
+
+ _db = None
+
+ def __init__(self, settings, phase):
+ IpcCommand.__init__(self)
+ self.settings = settings
+ self.phase = phase
+
+ def __call__(self, argv):
+ """
+ @returns: tuple of (stdout, stderr, returncode)
+ """
+
+ cmd, root, atom_str = argv
+
+ try:
+ atom = Atom(atom_str)
+ except InvalidAtom:
+ return ('', 'invalid atom: %s\n' % atom_str, 2)
+
+ warnings = []
+ try:
+ atom = Atom(atom_str, eapi=self.settings.get('EAPI'))
+ except InvalidAtom as e:
+ warnings.append(_unicode_decode("QA Notice: %s: %s") % (cmd, e))
+
+ use = self.settings.get('PORTAGE_BUILT_USE')
+ if use is None:
+ use = self.settings['PORTAGE_USE']
+
+ use = frozenset(use.split())
+ atom = atom.evaluate_conditionals(use)
+
+ db = self._db
+ if db is None:
+ db = portage.db
+
+ warnings_str = ''
+ if warnings:
+ warnings_str = self._elog('eqawarn', warnings)
+
+ root = normalize_path(root).rstrip(os.path.sep) + os.path.sep
+ if root not in db:
+ return ('', 'invalid ROOT: %s\n' % root, 2)
+
+ vardb = db[root]["vartree"].dbapi
+
+ if cmd == 'has_version':
+ if vardb.match(atom):
+ returncode = 0
+ else:
+ returncode = 1
+ return ('', warnings_str, returncode)
+ elif cmd == 'best_version':
+ m = best(vardb.match(atom))
+ return ('%s\n' % m, warnings_str, 0)
+ else:
+ return ('', 'invalid command: %s\n' % cmd, 2)
+
+ def _elog(self, elog_funcname, lines):
+ """
+ This returns a string, to be returned via ipc and displayed at the
+ appropriate place in the build output. We wouldn't want to open the
+ log here since it is already opened by AbstractEbuildProcess and we
+ don't want to corrupt it, especially if it is being written with
+ compression.
+ """
+ out = io.StringIO()
+ phase = self.phase
+ elog_func = getattr(elog_messages, elog_funcname)
+ global_havecolor = portage.output.havecolor
+ try:
+ portage.output.havecolor = \
+ self.settings.get('NOCOLOR', 'false').lower() in ('no', 'false')
+ for line in lines:
+ elog_func(line, phase=phase, key=self.settings.mycpv, out=out)
+ finally:
+ portage.output.havecolor = global_havecolor
+ msg = out.getvalue()
+ return msg
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_ipc/__init__.py b/portage_with_autodep/pym/portage/package/ebuild/_ipc/__init__.py
new file mode 100644
index 0000000..21a391a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_ipc/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/package/ebuild/_spawn_nofetch.py b/portage_with_autodep/pym/portage/package/ebuild/_spawn_nofetch.py
new file mode 100644
index 0000000..befdc89
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/_spawn_nofetch.py
@@ -0,0 +1,82 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import shutil
+import tempfile
+
+from portage import os
+from portage.const import EBUILD_PHASES
+from portage.elog import elog_process
+from portage.package.ebuild.config import config
+from portage.package.ebuild.doebuild import doebuild_environment
+from portage.package.ebuild.prepare_build_dirs import prepare_build_dirs
+from _emerge.EbuildPhase import EbuildPhase
+from _emerge.PollScheduler import PollScheduler
+
+def spawn_nofetch(portdb, ebuild_path, settings=None):
+ """
+ This spawns pkg_nofetch if appropriate. The settings parameter
+ is useful only if setcpv has already been called in order
+ to cache metadata. It will be cloned internally, in order to
+ prevent any changes from interfering with the calling code.
+ If settings is None then a suitable config instance will be
+ acquired from the given portdbapi instance.
+
+ A private PORTAGE_BUILDDIR will be created and cleaned up, in
+ order to avoid any interference with any other processes.
+ If PORTAGE_TMPDIR is writable, that will be used, otherwise
+ the default directory for the tempfile module will be used.
+
+ We only call the pkg_nofetch phase if either RESTRICT=fetch
+ is set or the package has explicitly overridden the default
+ pkg_nofetch implementation. This allows specialized messages
+ to be displayed for problematic packages even though they do
+ not set RESTRICT=fetch (bug #336499).
+
+ This function does nothing if the PORTAGE_PARALLEL_FETCHONLY
+ variable is set in the config instance.
+ """
+
+ if settings is None:
+ settings = config(clone=portdb.settings)
+ else:
+ settings = config(clone=settings)
+
+ if 'PORTAGE_PARALLEL_FETCHONLY' in settings:
+ return
+
+ # We must create our private PORTAGE_TMPDIR before calling
+ # doebuild_environment(), since lots of variables such
+ # as PORTAGE_BUILDDIR refer to paths inside PORTAGE_TMPDIR.
+ portage_tmpdir = settings.get('PORTAGE_TMPDIR')
+ if not portage_tmpdir or not os.access(portage_tmpdir, os.W_OK):
+ portage_tmpdir = None
+ private_tmpdir = tempfile.mkdtemp(dir=portage_tmpdir)
+ settings['PORTAGE_TMPDIR'] = private_tmpdir
+ settings.backup_changes('PORTAGE_TMPDIR')
+ # private temp dir was just created, so it's not locked yet
+ settings.pop('PORTAGE_BUILDIR_LOCKED', None)
+
+ try:
+ doebuild_environment(ebuild_path, 'nofetch',
+ settings=settings, db=portdb)
+ restrict = settings['PORTAGE_RESTRICT'].split()
+ defined_phases = settings['DEFINED_PHASES'].split()
+ if not defined_phases:
+ # When DEFINED_PHASES is undefined, assume all
+ # phases are defined.
+ defined_phases = EBUILD_PHASES
+
+ if 'fetch' not in restrict and \
+ 'nofetch' not in defined_phases:
+ return
+
+ prepare_build_dirs(settings=settings)
+ ebuild_phase = EbuildPhase(background=False,
+ phase='nofetch', scheduler=PollScheduler().sched_iface,
+ settings=settings)
+ ebuild_phase.start()
+ ebuild_phase.wait()
+ elog_process(settings.mycpv, settings)
+ finally:
+ shutil.rmtree(private_tmpdir)
diff --git a/portage_with_autodep/pym/portage/package/ebuild/config.py b/portage_with_autodep/pym/portage/package/ebuild/config.py
new file mode 100644
index 0000000..a8c6ad6
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/config.py
@@ -0,0 +1,2224 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = [
+ 'autouse', 'best_from_dict', 'check_config_instance', 'config',
+]
+
+import copy
+from itertools import chain
+import logging
+import re
+import sys
+import warnings
+
+from _emerge.Package import Package
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.data:portage_gid',
+)
+from portage import bsd_chflags, \
+ load_mod, os, selinux, _unicode_decode
+from portage.const import CACHE_PATH, \
+ DEPCACHE_PATH, INCREMENTALS, MAKE_CONF_FILE, \
+ MODULES_FILE_PATH, PORTAGE_BIN_PATH, PORTAGE_PYM_PATH, \
+ PRIVATE_PATH, PROFILE_PATH, USER_CONFIG_PATH, \
+ USER_VIRTUALS_FILE
+from portage.const import _SANDBOX_COMPAT_LEVEL
+from portage.dbapi import dbapi
+from portage.dbapi.porttree import portdbapi
+from portage.dbapi.vartree import vartree
+from portage.dep import Atom, isvalidatom, match_from_list, use_reduce, _repo_separator, _slot_separator
+from portage.eapi import eapi_exports_AA, eapi_exports_merge_type, \
+ eapi_supports_prefix, eapi_exports_replace_vars
+from portage.env.loaders import KeyValuePairFileLoader
+from portage.exception import InvalidDependString, PortageException
+from portage.localization import _
+from portage.output import colorize
+from portage.process import fakeroot_capable, sandbox_capable
+from portage.repository.config import load_repository_config
+from portage.util import ensure_dirs, getconfig, grabdict, \
+ grabdict_package, grabfile, grabfile_package, LazyItemsDict, \
+ normalize_path, shlex_split, stack_dictlist, stack_dicts, stack_lists, \
+ writemsg, writemsg_level
+from portage.versions import catpkgsplit, catsplit, cpv_getkey
+
+from portage.package.ebuild._config import special_env_vars
+from portage.package.ebuild._config.env_var_validation import validate_cmd_var
+from portage.package.ebuild._config.features_set import features_set
+from portage.package.ebuild._config.KeywordsManager import KeywordsManager
+from portage.package.ebuild._config.LicenseManager import LicenseManager
+from portage.package.ebuild._config.UseManager import UseManager
+from portage.package.ebuild._config.LocationsManager import LocationsManager
+from portage.package.ebuild._config.MaskManager import MaskManager
+from portage.package.ebuild._config.VirtualsManager import VirtualsManager
+from portage.package.ebuild._config.helper import ordered_by_atom_specificity, prune_incremental
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+def autouse(myvartree, use_cache=1, mysettings=None):
+ warnings.warn("portage.autouse() is deprecated",
+ DeprecationWarning, stacklevel=2)
+ return ""
+
+def check_config_instance(test):
+ if not isinstance(test, config):
+ raise TypeError("Invalid type for config object: %s (should be %s)" % (test.__class__, config))
+
+def best_from_dict(key, top_dict, key_order, EmptyOnError=1, FullCopy=1, AllowEmpty=1):
+ for x in key_order:
+ if x in top_dict and key in top_dict[x]:
+ if FullCopy:
+ return copy.deepcopy(top_dict[x][key])
+ else:
+ return top_dict[x][key]
+ if EmptyOnError:
+ return ""
+ else:
+ raise KeyError("Key not found in list; '%s'" % key)
+
+def _lazy_iuse_regex(iuse_implicit):
+ """
+ The PORTAGE_IUSE value is lazily evaluated since re.escape() is slow
+ and the value is only used when an ebuild phase needs to be executed
+ (it's used only to generate QA notices).
+ """
+ # Escape anything except ".*" which is supposed to pass through from
+ # _get_implicit_iuse().
+ regex = sorted(re.escape(x) for x in iuse_implicit)
+ regex = "^(%s)$" % "|".join(regex)
+ regex = regex.replace("\\.\\*", ".*")
+ return regex
+
+class _iuse_implicit_match_cache(object):
+
+ def __init__(self, settings):
+ self._iuse_implicit_re = re.compile("^(%s)$" % \
+ "|".join(settings._get_implicit_iuse()))
+ self._cache = {}
+
+ def __call__(self, flag):
+ """
+ Returns True if the flag is matched, False otherwise.
+ """
+ try:
+ return self._cache[flag]
+ except KeyError:
+ m = self._iuse_implicit_re.match(flag) is not None
+ self._cache[flag] = m
+ return m
+
+class config(object):
+ """
+ This class encompasses the main portage configuration. Data is pulled from
+ ROOT/PORTDIR/profiles/, from ROOT/etc/make.profile incrementally through all
+ parent profiles as well as from ROOT/PORTAGE_CONFIGROOT/* for user specified
+ overrides.
+
+ Generally if you need data like USE flags, FEATURES, environment variables,
+ virtuals ...etc you look in here.
+ """
+
+ _setcpv_aux_keys = ('DEFINED_PHASES', 'DEPEND', 'EAPI',
+ 'INHERITED', 'IUSE', 'REQUIRED_USE', 'KEYWORDS', 'LICENSE', 'PDEPEND',
+ 'PROPERTIES', 'PROVIDE', 'RDEPEND', 'SLOT',
+ 'repository', 'RESTRICT', 'LICENSE',)
+
+ _case_insensitive_vars = special_env_vars.case_insensitive_vars
+ _default_globals = special_env_vars.default_globals
+ _env_blacklist = special_env_vars.env_blacklist
+ _environ_filter = special_env_vars.environ_filter
+ _environ_whitelist = special_env_vars.environ_whitelist
+ _environ_whitelist_re = special_env_vars.environ_whitelist_re
+ _global_only_vars = special_env_vars.global_only_vars
+
+ def __init__(self, clone=None, mycpv=None, config_profile_path=None,
+ config_incrementals=None, config_root=None, target_root=None,
+ _eprefix=None, local_config=True, env=None, _unmatched_removal=False):
+ """
+ @param clone: If provided, init will use deepcopy to copy by value the instance.
+ @type clone: Instance of config class.
+ @param mycpv: CPV to load up (see setcpv), this is the same as calling init with mycpv=None
+ and then calling instance.setcpv(mycpv).
+ @type mycpv: String
+ @param config_profile_path: Configurable path to the profile (usually PROFILE_PATH from portage.const)
+ @type config_profile_path: String
+ @param config_incrementals: List of incremental variables
+ (defaults to portage.const.INCREMENTALS)
+ @type config_incrementals: List
+ @param config_root: path to read local config from (defaults to "/", see PORTAGE_CONFIGROOT)
+ @type config_root: String
+ @param target_root: __init__ override of $ROOT env variable.
+ @type target_root: String
+ @param _eprefix: set the EPREFIX variable (private, used by internal tests)
+ @type _eprefix: String
+ @param local_config: Enables loading of local config (/etc/portage); used most by repoman to
+ ignore local config (keywording and unmasking)
+ @type local_config: Boolean
+ @param env: The calling environment which is used to override settings.
+ Defaults to os.environ if unspecified.
+ @type env: dict
+ @param _unmatched_removal: Enabled by repoman when the
+ --unmatched-removal option is given.
+ @type _unmatched_removal: Boolean
+ """
+
+ # rename local _eprefix variable for convenience
+ eprefix = _eprefix
+ del _eprefix
+
+ # When initializing the global portage.settings instance, avoid
+ # raising exceptions whenever possible since exceptions thrown
+ # from 'import portage' or 'import portage.exceptions' statements
+ # can practically render the api unusable for api consumers.
+ tolerant = hasattr(portage, '_initializing_globals')
+ self._tolerant = tolerant
+
+ self.locked = 0
+ self.mycpv = None
+ self._setcpv_args_hash = None
+ self.puse = ""
+ self._penv = []
+ self.modifiedkeys = []
+ self.uvlist = []
+ self._accept_chost_re = None
+ self._accept_properties = None
+ self._features_overrides = []
+ self._make_defaults = None
+
+ # _unknown_features records unknown features that
+ # have triggered warning messages, and ensures that
+ # the same warning isn't shown twice.
+ self._unknown_features = set()
+
+ self.local_config = local_config
+
+ if clone:
+ # For immutable attributes, use shallow copy for
+ # speed and memory conservation.
+ self._tolerant = clone._tolerant
+ self.categories = clone.categories
+ self.depcachedir = clone.depcachedir
+ self.incrementals = clone.incrementals
+ self.module_priority = clone.module_priority
+ self.profile_path = clone.profile_path
+ self.profiles = clone.profiles
+ self.packages = clone.packages
+ self.repositories = clone.repositories
+ self._iuse_implicit_match = clone._iuse_implicit_match
+ self._non_user_variables = clone._non_user_variables
+ self._repo_make_defaults = clone._repo_make_defaults
+ self.usemask = clone.usemask
+ self.useforce = clone.useforce
+ self.puse = clone.puse
+ self.user_profile_dir = clone.user_profile_dir
+ self.local_config = clone.local_config
+ self.make_defaults_use = clone.make_defaults_use
+ self.mycpv = clone.mycpv
+ self._setcpv_args_hash = clone._setcpv_args_hash
+
+ # immutable attributes (internal policy ensures lack of mutation)
+ self._keywords_manager = clone._keywords_manager
+ self._use_manager = clone._use_manager
+ self._mask_manager = clone._mask_manager
+
+ # shared mutable attributes
+ self._unknown_features = clone._unknown_features
+
+ self.modules = copy.deepcopy(clone.modules)
+ self._penv = copy.deepcopy(clone._penv)
+
+ self.configdict = copy.deepcopy(clone.configdict)
+ self.configlist = [
+ self.configdict['env.d'],
+ self.configdict['repo'],
+ self.configdict['pkginternal'],
+ self.configdict['globals'],
+ self.configdict['defaults'],
+ self.configdict['conf'],
+ self.configdict['pkg'],
+ self.configdict['env'],
+ ]
+ self.lookuplist = self.configlist[:]
+ self.lookuplist.reverse()
+ self._use_expand_dict = copy.deepcopy(clone._use_expand_dict)
+ self.backupenv = self.configdict["backupenv"]
+ self.prevmaskdict = copy.deepcopy(clone.prevmaskdict)
+ self.pprovideddict = copy.deepcopy(clone.pprovideddict)
+ self.features = features_set(self)
+ self.features._features = copy.deepcopy(clone.features._features)
+ self._features_overrides = copy.deepcopy(clone._features_overrides)
+
+ #Strictly speaking _license_manager is not immutable. Users need to ensure that
+ #extract_global_changes() is called right after __init__ (if at all).
+ #It also has the mutable member _undef_lic_groups. It is used to track
+ #undefined license groups, to not display an error message for the same
+ #group again and again. Because of this, it's useful to share it between
+ #all LicenseManager instances.
+ self._license_manager = clone._license_manager
+
+ self._virtuals_manager = copy.deepcopy(clone._virtuals_manager)
+
+ self._accept_properties = copy.deepcopy(clone._accept_properties)
+ self._ppropertiesdict = copy.deepcopy(clone._ppropertiesdict)
+ self._penvdict = copy.deepcopy(clone._penvdict)
+ self._expand_map = copy.deepcopy(clone._expand_map)
+
+ else:
+ locations_manager = LocationsManager(config_root=config_root,
+ config_profile_path=config_profile_path, eprefix=eprefix,
+ local_config=local_config, target_root=target_root)
+
+ eprefix = locations_manager.eprefix
+ config_root = locations_manager.config_root
+ self.profiles = locations_manager.profiles
+ self.profile_path = locations_manager.profile_path
+ self.user_profile_dir = locations_manager.user_profile_dir
+ abs_user_config = locations_manager.abs_user_config
+
+ make_conf = getconfig(
+ os.path.join(config_root, MAKE_CONF_FILE),
+ tolerant=tolerant, allow_sourcing=True) or {}
+
+ make_conf.update(getconfig(
+ os.path.join(abs_user_config, 'make.conf'),
+ tolerant=tolerant, allow_sourcing=True,
+ expand=make_conf) or {})
+
+ # Allow ROOT setting to come from make.conf if it's not overridden
+ # by the constructor argument (from the calling environment).
+ locations_manager.set_root_override(make_conf.get("ROOT"))
+ target_root = locations_manager.target_root
+ eroot = locations_manager.eroot
+ self.global_config_path = locations_manager.global_config_path
+
+ if config_incrementals is None:
+ self.incrementals = INCREMENTALS
+ else:
+ self.incrementals = config_incrementals
+ if not isinstance(self.incrementals, frozenset):
+ self.incrementals = frozenset(self.incrementals)
+
+ self.module_priority = ("user", "default")
+ self.modules = {}
+ modules_loader = KeyValuePairFileLoader(
+ os.path.join(config_root, MODULES_FILE_PATH), None, None)
+ modules_dict, modules_errors = modules_loader.load()
+ self.modules["user"] = modules_dict
+ if self.modules["user"] is None:
+ self.modules["user"] = {}
+ self.modules["default"] = {
+ "portdbapi.metadbmodule": "portage.cache.metadata.database",
+ "portdbapi.auxdbmodule": "portage.cache.flat_hash.database",
+ }
+
+ self.configlist=[]
+
+ # back up our incremental variables:
+ self.configdict={}
+ self._use_expand_dict = {}
+ # configlist will contain: [ env.d, globals, defaults, conf, pkg, backupenv, env ]
+ self.configlist.append({})
+ self.configdict["env.d"] = self.configlist[-1]
+
+ self.configlist.append({})
+ self.configdict["repo"] = self.configlist[-1]
+
+ self.configlist.append({})
+ self.configdict["pkginternal"] = self.configlist[-1]
+
+ self.packages_list = [grabfile_package(os.path.join(x, "packages"), verify_eapi=True) for x in self.profiles]
+ self.packages = tuple(stack_lists(self.packages_list, incremental=1))
+ del self.packages_list
+ #self.packages = grab_stacked("packages", self.profiles, grabfile, incremental_lines=1)
+
+ # revmaskdict
+ self.prevmaskdict={}
+ for x in self.packages:
+ # Negative atoms are filtered by the above stack_lists() call.
+ if not isinstance(x, Atom):
+ x = Atom(x.lstrip('*'))
+ self.prevmaskdict.setdefault(x.cp, []).append(x)
+
+ # The expand_map is used for variable substitution
+ # in getconfig() calls, and the getconfig() calls
+ # update expand_map with the value of each variable
+ # assignment that occurs. Variable substitution occurs
+ # in the following order, which corresponds to the
+ # order of appearance in self.lookuplist:
+ #
+ # * env.d
+ # * make.globals
+ # * make.defaults
+ # * make.conf
+ #
+ # Notably absent is "env", since we want to avoid any
+ # interaction with the calling environment that might
+ # lead to unexpected results.
+ expand_map = {}
+ self._expand_map = expand_map
+
+ env_d = getconfig(os.path.join(eroot, "etc", "profile.env"),
+ expand=expand_map)
+ # env_d will be None if profile.env doesn't exist.
+ if env_d:
+ self.configdict["env.d"].update(env_d)
+ expand_map.update(env_d)
+
+ # backupenv is used for calculating incremental variables.
+ if env is None:
+ env = os.environ
+
+ # Avoid potential UnicodeDecodeError exceptions later.
+ env_unicode = dict((_unicode_decode(k), _unicode_decode(v))
+ for k, v in env.items())
+
+ self.backupenv = env_unicode
+
+ if env_d:
+ # Remove duplicate values so they don't override updated
+ # profile.env values later (profile.env is reloaded in each
+ # call to self.regenerate).
+ for k, v in env_d.items():
+ try:
+ if self.backupenv[k] == v:
+ del self.backupenv[k]
+ except KeyError:
+ pass
+ del k, v
+
+ self.configdict["env"] = LazyItemsDict(self.backupenv)
+
+ for x in (self.global_config_path,):
+ self.mygcfg = getconfig(os.path.join(x, "make.globals"),
+ expand=expand_map)
+ if self.mygcfg:
+ break
+
+ if self.mygcfg is None:
+ self.mygcfg = {}
+
+ for k, v in self._default_globals.items():
+ self.mygcfg.setdefault(k, v)
+
+ self.configlist.append(self.mygcfg)
+ self.configdict["globals"]=self.configlist[-1]
+
+ self.make_defaults_use = []
+ self.mygcfg = {}
+ if self.profiles:
+ mygcfg_dlists = [getconfig(os.path.join(x, "make.defaults"),
+ expand=expand_map) for x in self.profiles]
+ self._make_defaults = mygcfg_dlists
+ self.mygcfg = stack_dicts(mygcfg_dlists,
+ incrementals=self.incrementals)
+ if self.mygcfg is None:
+ self.mygcfg = {}
+ self.configlist.append(self.mygcfg)
+ self.configdict["defaults"]=self.configlist[-1]
+
+ self.mygcfg = getconfig(
+ os.path.join(config_root, MAKE_CONF_FILE),
+ tolerant=tolerant, allow_sourcing=True,
+ expand=expand_map) or {}
+
+ self.mygcfg.update(getconfig(
+ os.path.join(abs_user_config, 'make.conf'),
+ tolerant=tolerant, allow_sourcing=True,
+ expand=expand_map) or {})
+
+ # Don't allow the user to override certain variables in make.conf
+ profile_only_variables = self.configdict["defaults"].get(
+ "PROFILE_ONLY_VARIABLES", "").split()
+ profile_only_variables = stack_lists([profile_only_variables])
+ non_user_variables = set()
+ non_user_variables.update(profile_only_variables)
+ non_user_variables.update(self._env_blacklist)
+ non_user_variables.update(self._global_only_vars)
+ non_user_variables = frozenset(non_user_variables)
+ self._non_user_variables = non_user_variables
+
+ for k in profile_only_variables:
+ self.mygcfg.pop(k, None)
+
+ self.configlist.append(self.mygcfg)
+ self.configdict["conf"]=self.configlist[-1]
+
+ self.configlist.append(LazyItemsDict())
+ self.configdict["pkg"]=self.configlist[-1]
+
+ self.configdict["backupenv"] = self.backupenv
+
+ # Don't allow the user to override certain variables in the env
+ for k in profile_only_variables:
+ self.backupenv.pop(k, None)
+
+ self.configlist.append(self.configdict["env"])
+
+ # make lookuplist for loading package.*
+ self.lookuplist=self.configlist[:]
+ self.lookuplist.reverse()
+
+ # Blacklist vars that could interfere with portage internals.
+ for blacklisted in self._env_blacklist:
+ for cfg in self.lookuplist:
+ cfg.pop(blacklisted, None)
+ self.backupenv.pop(blacklisted, None)
+ del blacklisted, cfg
+
+ self["PORTAGE_CONFIGROOT"] = config_root
+ self.backup_changes("PORTAGE_CONFIGROOT")
+ self["ROOT"] = target_root
+ self.backup_changes("ROOT")
+
+ self["EPREFIX"] = eprefix
+ self.backup_changes("EPREFIX")
+ self["EROOT"] = eroot
+ self.backup_changes("EROOT")
+
+ self["PORTAGE_SANDBOX_COMPAT_LEVEL"] = _SANDBOX_COMPAT_LEVEL
+ self.backup_changes("PORTAGE_SANDBOX_COMPAT_LEVEL")
+
+ self._ppropertiesdict = portage.dep.ExtendedAtomDict(dict)
+ self._penvdict = portage.dep.ExtendedAtomDict(dict)
+
+ #Loading Repositories
+ self.repositories = load_repository_config(self)
+
+ #filling PORTDIR and PORTDIR_OVERLAY variable for compatibility
+ main_repo = self.repositories.mainRepo()
+ if main_repo is not None:
+ main_repo = main_repo.user_location
+ self["PORTDIR"] = main_repo
+ self.backup_changes("PORTDIR")
+
+ # repoman controls PORTDIR_OVERLAY via the environment, so no
+ # special cases are needed here.
+ portdir_overlay = list(self.repositories.repoUserLocationList())
+ if portdir_overlay and portdir_overlay[0] == self["PORTDIR"]:
+ portdir_overlay = portdir_overlay[1:]
+
+ new_ov = []
+ if portdir_overlay:
+ whitespace_re = re.compile(r"\s")
+ for ov in portdir_overlay:
+ ov = normalize_path(ov)
+ if os.path.isdir(ov):
+ if whitespace_re.search(ov) is not None:
+ ov = portage._shell_quote(ov)
+ new_ov.append(ov)
+ else:
+ writemsg(_("!!! Invalid PORTDIR_OVERLAY"
+ " (not a dir): '%s'\n") % ov, noiselevel=-1)
+
+ self["PORTDIR_OVERLAY"] = " ".join(new_ov)
+ self.backup_changes("PORTDIR_OVERLAY")
+
+ locations_manager.set_port_dirs(self["PORTDIR"], self["PORTDIR_OVERLAY"])
+
+ self._repo_make_defaults = {}
+ for repo in self.repositories.repos_with_profiles():
+ d = getconfig(os.path.join(repo.location, "profiles", "make.defaults"),
+ expand=self.configdict["globals"].copy()) or {}
+ if d:
+ for k in chain(self._env_blacklist,
+ profile_only_variables, self._global_only_vars):
+ d.pop(k, None)
+ self._repo_make_defaults[repo.name] = d
+
+ #Read package.keywords and package.accept_keywords.
+ self._keywords_manager = KeywordsManager(self.profiles, abs_user_config, \
+ local_config, global_accept_keywords=self.configdict["defaults"].get("ACCEPT_KEYWORDS", ""))
+
+ #Read all USE related files from profiles and optionally from user config.
+ self._use_manager = UseManager(self.repositories, self.profiles, abs_user_config, user_config=local_config)
+ #Initialize all USE related variables we track ourselves.
+ self.usemask = self._use_manager.getUseMask()
+ self.useforce = self._use_manager.getUseForce()
+ self.configdict["conf"]["USE"] = \
+ self._use_manager.extract_global_USE_changes( \
+ self.configdict["conf"].get("USE", ""))
+
+ #Read license_groups and optionally license_groups and package.license from user config
+ self._license_manager = LicenseManager(locations_manager.profile_locations, \
+ abs_user_config, user_config=local_config)
+ #Extract '*/*' entries from package.license
+ self.configdict["conf"]["ACCEPT_LICENSE"] = \
+ self._license_manager.extract_global_changes( \
+ self.configdict["conf"].get("ACCEPT_LICENSE", ""))
+
+ #Read package.mask and package.unmask from profiles and optionally from user config
+ self._mask_manager = MaskManager(self.repositories, self.profiles,
+ abs_user_config, user_config=local_config,
+ strict_umatched_removal=_unmatched_removal)
+
+ self._virtuals_manager = VirtualsManager(self.profiles)
+
+ if local_config:
+ #package.properties
+ propdict = grabdict_package(os.path.join(
+ abs_user_config, "package.properties"), recursive=1, allow_wildcard=True, \
+ allow_repo=True, verify_eapi=False)
+ v = propdict.pop("*/*", None)
+ if v is not None:
+ if "ACCEPT_PROPERTIES" in self.configdict["conf"]:
+ self.configdict["conf"]["ACCEPT_PROPERTIES"] += " " + " ".join(v)
+ else:
+ self.configdict["conf"]["ACCEPT_PROPERTIES"] = " ".join(v)
+ for k, v in propdict.items():
+ self._ppropertiesdict.setdefault(k.cp, {})[k] = v
+
+ #package.env
+ penvdict = grabdict_package(os.path.join(
+ abs_user_config, "package.env"), recursive=1, allow_wildcard=True, \
+ allow_repo=True, verify_eapi=False)
+ v = penvdict.pop("*/*", None)
+ if v is not None:
+ global_wildcard_conf = {}
+ self._grab_pkg_env(v, global_wildcard_conf)
+ incrementals = self.incrementals
+ conf_configdict = self.configdict["conf"]
+ for k, v in global_wildcard_conf.items():
+ if k in incrementals:
+ if k in conf_configdict:
+ conf_configdict[k] = \
+ conf_configdict[k] + " " + v
+ else:
+ conf_configdict[k] = v
+ else:
+ conf_configdict[k] = v
+ expand_map[k] = v
+
+ for k, v in penvdict.items():
+ self._penvdict.setdefault(k.cp, {})[k] = v
+
+ #getting categories from an external file now
+ self.categories = [grabfile(os.path.join(x, "categories")) \
+ for x in locations_manager.profile_and_user_locations]
+ category_re = dbapi._category_re
+ self.categories = tuple(sorted(
+ x for x in stack_lists(self.categories, incremental=1)
+ if category_re.match(x) is not None))
+
+ archlist = [grabfile(os.path.join(x, "arch.list")) \
+ for x in locations_manager.profile_and_user_locations]
+ archlist = stack_lists(archlist, incremental=1)
+ self.configdict["conf"]["PORTAGE_ARCHLIST"] = " ".join(archlist)
+
+ pkgprovidedlines = [grabfile(os.path.join(x, "package.provided"), recursive=1) for x in self.profiles]
+ pkgprovidedlines = stack_lists(pkgprovidedlines, incremental=1)
+ has_invalid_data = False
+ for x in range(len(pkgprovidedlines)-1, -1, -1):
+ myline = pkgprovidedlines[x]
+ if not isvalidatom("=" + myline):
+ writemsg(_("Invalid package name in package.provided: %s\n") % \
+ myline, noiselevel=-1)
+ has_invalid_data = True
+ del pkgprovidedlines[x]
+ continue
+ cpvr = catpkgsplit(pkgprovidedlines[x])
+ if not cpvr or cpvr[0] == "null":
+ writemsg(_("Invalid package name in package.provided: ")+pkgprovidedlines[x]+"\n",
+ noiselevel=-1)
+ has_invalid_data = True
+ del pkgprovidedlines[x]
+ continue
+ if cpvr[0] == "virtual":
+ writemsg(_("Virtual package in package.provided: %s\n") % \
+ myline, noiselevel=-1)
+ has_invalid_data = True
+ del pkgprovidedlines[x]
+ continue
+ if has_invalid_data:
+ writemsg(_("See portage(5) for correct package.provided usage.\n"),
+ noiselevel=-1)
+ self.pprovideddict = {}
+ for x in pkgprovidedlines:
+ x_split = catpkgsplit(x)
+ if x_split is None:
+ continue
+ mycatpkg = cpv_getkey(x)
+ if mycatpkg in self.pprovideddict:
+ self.pprovideddict[mycatpkg].append(x)
+ else:
+ self.pprovideddict[mycatpkg]=[x]
+
+ # reasonable defaults; this is important as without USE_ORDER,
+ # USE will always be "" (nothing set)!
+ if "USE_ORDER" not in self:
+ self.backupenv["USE_ORDER"] = "env:pkg:conf:defaults:pkginternal:repo:env.d"
+
+ self["PORTAGE_GID"] = str(portage_gid)
+ self.backup_changes("PORTAGE_GID")
+
+ self.depcachedir = DEPCACHE_PATH
+ if eprefix:
+ # See comments about make.globals and EPREFIX
+ # above. DEPCACHE_PATH is similar.
+ if target_root == "/":
+ # case (1) above
+ self.depcachedir = os.path.join(eprefix,
+ DEPCACHE_PATH.lstrip(os.sep))
+ else:
+ # case (2) above
+ # For now, just assume DEPCACHE_PATH is relative
+ # to EPREFIX.
+ # TODO: Pass in more info to the constructor,
+ # so we know the host system configuration.
+ self.depcachedir = os.path.join(eprefix,
+ DEPCACHE_PATH.lstrip(os.sep))
+
+ if self.get("PORTAGE_DEPCACHEDIR", None):
+ self.depcachedir = self["PORTAGE_DEPCACHEDIR"]
+ self["PORTAGE_DEPCACHEDIR"] = self.depcachedir
+ self.backup_changes("PORTAGE_DEPCACHEDIR")
+
+ if "CBUILD" not in self and "CHOST" in self:
+ self["CBUILD"] = self["CHOST"]
+ self.backup_changes("CBUILD")
+
+ self["PORTAGE_BIN_PATH"] = PORTAGE_BIN_PATH
+ self.backup_changes("PORTAGE_BIN_PATH")
+ self["PORTAGE_PYM_PATH"] = PORTAGE_PYM_PATH
+ self.backup_changes("PORTAGE_PYM_PATH")
+
+ for var in ("PORTAGE_INST_UID", "PORTAGE_INST_GID"):
+ try:
+ self[var] = str(int(self.get(var, "0")))
+ except ValueError:
+ writemsg(_("!!! %s='%s' is not a valid integer. "
+ "Falling back to '0'.\n") % (var, self[var]),
+ noiselevel=-1)
+ self[var] = "0"
+ self.backup_changes(var)
+
+ # initialize self.features
+ self.regenerate()
+
+ if bsd_chflags:
+ self.features.add('chflags')
+
+ if 'parse-eapi-ebuild-head' in self.features:
+ portage._validate_cache_for_unsupported_eapis = False
+
+ self._iuse_implicit_match = _iuse_implicit_match_cache(self)
+
+ self._validate_commands()
+
+ for k in self._case_insensitive_vars:
+ if k in self:
+ self[k] = self[k].lower()
+ self.backup_changes(k)
+
+ if mycpv:
+ self.setcpv(mycpv)
+
+ def _validate_commands(self):
+ for k in special_env_vars.validate_commands:
+ v = self.get(k)
+ if v is not None:
+ valid, v_split = validate_cmd_var(v)
+
+ if not valid:
+ if v_split:
+ writemsg_level(_("%s setting is invalid: '%s'\n") % \
+ (k, v), level=logging.ERROR, noiselevel=-1)
+
+ # before deleting the invalid setting, backup
+ # the default value if available
+ v = self.configdict['globals'].get(k)
+ if v is not None:
+ default_valid, v_split = validate_cmd_var(v)
+ if not default_valid:
+ if v_split:
+ writemsg_level(
+ _("%s setting from make.globals" + \
+ " is invalid: '%s'\n") % \
+ (k, v), level=logging.ERROR, noiselevel=-1)
+ # make.globals seems corrupt, so try for
+ # a hardcoded default instead
+ v = self._default_globals.get(k)
+
+ # delete all settings for this key,
+ # including the invalid one
+ del self[k]
+ self.backupenv.pop(k, None)
+ if v:
+ # restore validated default
+ self.configdict['globals'][k] = v
+
+ def _init_dirs(self):
+ """
+ Create a few directories that are critical to portage operation
+ """
+ if not os.access(self["EROOT"], os.W_OK):
+ return
+
+ # gid, mode, mask, preserve_perms
+ dir_mode_map = {
+ "tmp" : ( -1, 0o1777, 0, True),
+ "var/tmp" : ( -1, 0o1777, 0, True),
+ PRIVATE_PATH : (portage_gid, 0o2750, 0o2, False),
+ CACHE_PATH : (portage_gid, 0o755, 0o2, False)
+ }
+
+ for mypath, (gid, mode, modemask, preserve_perms) \
+ in dir_mode_map.items():
+ mydir = os.path.join(self["EROOT"], mypath)
+ if preserve_perms and os.path.isdir(mydir):
+ # Only adjust permissions on some directories if
+ # they don't exist yet. This gives freedom to the
+ # user to adjust permissions to suit their taste.
+ continue
+ try:
+ ensure_dirs(mydir, gid=gid, mode=mode, mask=modemask)
+ except PortageException as e:
+ writemsg(_("!!! Directory initialization failed: '%s'\n") % mydir,
+ noiselevel=-1)
+ writemsg("!!! %s\n" % str(e),
+ noiselevel=-1)
+
+ @property
+ def pkeywordsdict(self):
+ result = self._keywords_manager.pkeywordsdict.copy()
+ for k, v in result.items():
+ result[k] = v.copy()
+ return result
+
+ @property
+ def pmaskdict(self):
+ return self._mask_manager._pmaskdict.copy()
+
+ @property
+ def punmaskdict(self):
+ return self._mask_manager._punmaskdict.copy()
+
+ def expandLicenseTokens(self, tokens):
+ """ Take a token from ACCEPT_LICENSE or package.license and expand it
+ if it's a group token (indicated by @) or just return it if it's not a
+ group. If a group is negated then negate all group elements."""
+ return self._license_manager.expandLicenseTokens(tokens)
+
+ def validate(self):
+ """Validate miscellaneous settings and display warnings if necessary.
+ (This code was previously in the global scope of portage.py)"""
+
+ groups = self["ACCEPT_KEYWORDS"].split()
+ archlist = self.archlist()
+ if not archlist:
+ writemsg(_("--- 'profiles/arch.list' is empty or "
+ "not available. Empty portage tree?\n"), noiselevel=1)
+ else:
+ for group in groups:
+ if group not in archlist and \
+ not (group.startswith("-") and group[1:] in archlist) and \
+ group not in ("*", "~*", "**"):
+ writemsg(_("!!! INVALID ACCEPT_KEYWORDS: %s\n") % str(group),
+ noiselevel=-1)
+
+ abs_profile_path = os.path.join(self["PORTAGE_CONFIGROOT"],
+ PROFILE_PATH)
+ if (not self.profile_path or \
+ not os.path.exists(os.path.join(self.profile_path, "parent"))) and \
+ os.path.exists(os.path.join(self["PORTDIR"], "profiles")):
+ writemsg(_("\n\n!!! %s is not a symlink and will probably prevent most merges.\n") % abs_profile_path,
+ noiselevel=-1)
+ writemsg(_("!!! It should point into a profile within %s/profiles/\n") % self["PORTDIR"])
+ writemsg(_("!!! (You can safely ignore this message when syncing. It's harmless.)\n\n\n"))
+
+ abs_user_virtuals = os.path.join(self["PORTAGE_CONFIGROOT"],
+ USER_VIRTUALS_FILE)
+ if os.path.exists(abs_user_virtuals):
+ writemsg("\n!!! /etc/portage/virtuals is deprecated in favor of\n")
+ writemsg("!!! /etc/portage/profile/virtuals. Please move it to\n")
+ writemsg("!!! this new location.\n\n")
+
+ if not sandbox_capable and \
+ ("sandbox" in self.features or "usersandbox" in self.features):
+ if self.profile_path is not None and \
+ os.path.realpath(self.profile_path) == \
+ os.path.realpath(os.path.join(
+ self["PORTAGE_CONFIGROOT"], PROFILE_PATH)):
+ # Don't show this warning when running repoman and the
+ # sandbox feature came from a profile that doesn't belong
+ # to the user.
+ writemsg(colorize("BAD", _("!!! Problem with sandbox"
+ " binary. Disabling...\n\n")), noiselevel=-1)
+
+ if "fakeroot" in self.features and \
+ not fakeroot_capable:
+ writemsg(_("!!! FEATURES=fakeroot is enabled, but the "
+ "fakeroot binary is not installed.\n"), noiselevel=-1)
+
+ def load_best_module(self,property_string):
+ best_mod = best_from_dict(property_string,self.modules,self.module_priority)
+ mod = None
+ try:
+ mod = load_mod(best_mod)
+ except ImportError:
+ if not best_mod.startswith("cache."):
+ raise
+ else:
+ best_mod = "portage." + best_mod
+ try:
+ mod = load_mod(best_mod)
+ except ImportError:
+ raise
+ return mod
+
+ def lock(self):
+ self.locked = 1
+
+ def unlock(self):
+ self.locked = 0
+
+ def modifying(self):
+ if self.locked:
+ raise Exception(_("Configuration is locked."))
+
+ def backup_changes(self,key=None):
+ self.modifying()
+ if key and key in self.configdict["env"]:
+ self.backupenv[key] = copy.deepcopy(self.configdict["env"][key])
+ else:
+ raise KeyError(_("No such key defined in environment: %s") % key)
+
+ def reset(self, keeping_pkg=0, use_cache=None):
+ """
+ Restore environment from self.backupenv, call self.regenerate()
+ @param keeping_pkg: Should we keep the setcpv() data or delete it.
+ @type keeping_pkg: Boolean
+ @rype: None
+ """
+
+ if use_cache is not None:
+ warnings.warn("The use_cache parameter for config.reset() is deprecated and without effect.",
+ DeprecationWarning, stacklevel=2)
+
+ self.modifying()
+ self.configdict["env"].clear()
+ self.configdict["env"].update(self.backupenv)
+
+ self.modifiedkeys = []
+ if not keeping_pkg:
+ self.mycpv = None
+ self._setcpv_args_hash = None
+ self.puse = ""
+ del self._penv[:]
+ self.configdict["pkg"].clear()
+ self.configdict["pkginternal"].clear()
+ self.configdict["repo"].clear()
+ self.configdict["defaults"]["USE"] = \
+ " ".join(self.make_defaults_use)
+ self.usemask = self._use_manager.getUseMask()
+ self.useforce = self._use_manager.getUseForce()
+ self.regenerate()
+
+ class _lazy_vars(object):
+
+ __slots__ = ('built_use', 'settings', 'values')
+
+ def __init__(self, built_use, settings):
+ self.built_use = built_use
+ self.settings = settings
+ self.values = None
+
+ def __getitem__(self, k):
+ if self.values is None:
+ self.values = self._init_values()
+ return self.values[k]
+
+ def _init_values(self):
+ values = {}
+ settings = self.settings
+ use = self.built_use
+ if use is None:
+ use = frozenset(settings['PORTAGE_USE'].split())
+
+ values['ACCEPT_LICENSE'] = settings._license_manager.get_prunned_accept_license( \
+ settings.mycpv, use, settings['LICENSE'], settings['SLOT'], settings.get('PORTAGE_REPO_NAME'))
+ values['PORTAGE_RESTRICT'] = self._restrict(use, settings)
+ return values
+
+ def _restrict(self, use, settings):
+ try:
+ restrict = set(use_reduce(settings['RESTRICT'], uselist=use, flat=True))
+ except InvalidDependString:
+ restrict = set()
+ return ' '.join(sorted(restrict))
+
+ class _lazy_use_expand(object):
+ """
+ Lazily evaluate USE_EXPAND variables since they are only needed when
+ an ebuild shell is spawned. Variables values are made consistent with
+ the previously calculated USE settings.
+ """
+
+ def __init__(self, use, usemask, iuse_implicit,
+ use_expand_split, use_expand_dict):
+ self._use = use
+ self._usemask = usemask
+ self._iuse_implicit = iuse_implicit
+ self._use_expand_split = use_expand_split
+ self._use_expand_dict = use_expand_dict
+
+ def __getitem__(self, key):
+ prefix = key.lower() + '_'
+ prefix_len = len(prefix)
+ expand_flags = set( x[prefix_len:] for x in self._use \
+ if x[:prefix_len] == prefix )
+ var_split = self._use_expand_dict.get(key, '').split()
+ # Preserve the order of var_split because it can matter for things
+ # like LINGUAS.
+ var_split = [ x for x in var_split if x in expand_flags ]
+ var_split.extend(expand_flags.difference(var_split))
+ has_wildcard = '*' in expand_flags
+ if has_wildcard:
+ var_split = [ x for x in var_split if x != "*" ]
+ has_iuse = set()
+ for x in self._iuse_implicit:
+ if x[:prefix_len] == prefix:
+ has_iuse.add(x[prefix_len:])
+ if has_wildcard:
+ # * means to enable everything in IUSE that's not masked
+ if has_iuse:
+ usemask = self._usemask
+ for suffix in has_iuse:
+ x = prefix + suffix
+ if x not in usemask:
+ if suffix not in expand_flags:
+ var_split.append(suffix)
+ else:
+ # If there is a wildcard and no matching flags in IUSE then
+ # LINGUAS should be unset so that all .mo files are
+ # installed.
+ var_split = []
+ # Make the flags unique and filter them according to IUSE.
+ # Also, continue to preserve order for things like LINGUAS
+ # and filter any duplicates that variable may contain.
+ filtered_var_split = []
+ remaining = has_iuse.intersection(var_split)
+ for x in var_split:
+ if x in remaining:
+ remaining.remove(x)
+ filtered_var_split.append(x)
+ var_split = filtered_var_split
+
+ if var_split:
+ value = ' '.join(var_split)
+ else:
+ # Don't export empty USE_EXPAND vars unless the user config
+ # exports them as empty. This is required for vars such as
+ # LINGUAS, where unset and empty have different meanings.
+ if has_wildcard:
+ # ebuild.sh will see this and unset the variable so
+ # that things like LINGUAS work properly
+ value = '*'
+ else:
+ if has_iuse:
+ value = ''
+ else:
+ # It's not in IUSE, so just allow the variable content
+ # to pass through if it is defined somewhere. This
+ # allows packages that support LINGUAS but don't
+ # declare it in IUSE to use the variable outside of the
+ # USE_EXPAND context.
+ value = None
+
+ return value
+
+ def setcpv(self, mycpv, use_cache=None, mydb=None):
+ """
+ Load a particular CPV into the config, this lets us see the
+ Default USE flags for a particular ebuild as well as the USE
+ flags from package.use.
+
+ @param mycpv: A cpv to load
+ @type mycpv: string
+ @param mydb: a dbapi instance that supports aux_get with the IUSE key.
+ @type mydb: dbapi or derivative.
+ @rtype: None
+ """
+
+ if use_cache is not None:
+ warnings.warn("The use_cache parameter for config.setcpv() is deprecated and without effect.",
+ DeprecationWarning, stacklevel=2)
+
+ self.modifying()
+
+ pkg = None
+ built_use = None
+ explicit_iuse = None
+ if not isinstance(mycpv, basestring):
+ pkg = mycpv
+ mycpv = pkg.cpv
+ mydb = pkg.metadata
+ explicit_iuse = pkg.iuse.all
+ args_hash = (mycpv, id(pkg))
+ if pkg.built:
+ built_use = pkg.use.enabled
+ else:
+ args_hash = (mycpv, id(mydb))
+
+ if args_hash == self._setcpv_args_hash:
+ return
+ self._setcpv_args_hash = args_hash
+
+ has_changed = False
+ self.mycpv = mycpv
+ cat, pf = catsplit(mycpv)
+ cp = cpv_getkey(mycpv)
+ cpv_slot = self.mycpv
+ pkginternaluse = ""
+ iuse = ""
+ pkg_configdict = self.configdict["pkg"]
+ previous_iuse = pkg_configdict.get("IUSE")
+ previous_features = pkg_configdict.get("FEATURES")
+
+ aux_keys = self._setcpv_aux_keys
+
+ # Discard any existing metadata and package.env settings from
+ # the previous package instance.
+ pkg_configdict.clear()
+
+ pkg_configdict["CATEGORY"] = cat
+ pkg_configdict["PF"] = pf
+ repository = None
+ if mydb:
+ if not hasattr(mydb, "aux_get"):
+ for k in aux_keys:
+ if k in mydb:
+ # Make these lazy, since __getitem__ triggers
+ # evaluation of USE conditionals which can't
+ # occur until PORTAGE_USE is calculated below.
+ pkg_configdict.addLazySingleton(k,
+ mydb.__getitem__, k)
+ else:
+ # When calling dbapi.aux_get(), grab USE for built/installed
+ # packages since we want to save it PORTAGE_BUILT_USE for
+ # evaluating conditional USE deps in atoms passed via IPC to
+ # helpers like has_version and best_version.
+ aux_keys = list(aux_keys)
+ aux_keys.append('USE')
+ for k, v in zip(aux_keys, mydb.aux_get(self.mycpv, aux_keys)):
+ pkg_configdict[k] = v
+ built_use = frozenset(pkg_configdict.pop('USE').split())
+ if not built_use:
+ # Empty USE means this dbapi instance does not contain
+ # built packages.
+ built_use = None
+
+ repository = pkg_configdict.pop("repository", None)
+ if repository is not None:
+ pkg_configdict["PORTAGE_REPO_NAME"] = repository
+ slot = pkg_configdict["SLOT"]
+ iuse = pkg_configdict["IUSE"]
+ if pkg is None:
+ cpv_slot = "%s:%s" % (self.mycpv, slot)
+ else:
+ cpv_slot = pkg
+ pkginternaluse = []
+ for x in iuse.split():
+ if x.startswith("+"):
+ pkginternaluse.append(x[1:])
+ elif x.startswith("-"):
+ pkginternaluse.append(x)
+ pkginternaluse = " ".join(pkginternaluse)
+ if pkginternaluse != self.configdict["pkginternal"].get("USE", ""):
+ self.configdict["pkginternal"]["USE"] = pkginternaluse
+ has_changed = True
+
+ repo_env = []
+ if repository and repository != Package.UNKNOWN_REPO:
+ repos = []
+ try:
+ repos.extend(repo.name for repo in
+ self.repositories[repository].masters)
+ except KeyError:
+ pass
+ repos.append(repository)
+ for repo in repos:
+ d = self._repo_make_defaults.get(repo)
+ if d is None:
+ d = {}
+ else:
+ # make a copy, since we might modify it with
+ # package.use settings
+ d = d.copy()
+ cpdict = self._use_manager._repo_puse_dict.get(repo, {}).get(cp)
+ if cpdict:
+ repo_puse = ordered_by_atom_specificity(cpdict, cpv_slot)
+ if repo_puse:
+ for x in repo_puse:
+ d["USE"] = d.get("USE", "") + " " + " ".join(x)
+ if d:
+ repo_env.append(d)
+
+ if repo_env or self.configdict["repo"]:
+ self.configdict["repo"].clear()
+ self.configdict["repo"].update(stack_dicts(repo_env,
+ incrementals=self.incrementals))
+ has_changed = True
+
+ defaults = []
+ for i, pkgprofileuse_dict in enumerate(self._use_manager._pkgprofileuse):
+ if self.make_defaults_use[i]:
+ defaults.append(self.make_defaults_use[i])
+ cpdict = pkgprofileuse_dict.get(cp)
+ if cpdict:
+ pkg_defaults = ordered_by_atom_specificity(cpdict, cpv_slot)
+ if pkg_defaults:
+ defaults.extend(pkg_defaults)
+ defaults = " ".join(defaults)
+ if defaults != self.configdict["defaults"].get("USE",""):
+ self.configdict["defaults"]["USE"] = defaults
+ has_changed = True
+
+ useforce = self._use_manager.getUseForce(cpv_slot)
+ if useforce != self.useforce:
+ self.useforce = useforce
+ has_changed = True
+
+ usemask = self._use_manager.getUseMask(cpv_slot)
+ if usemask != self.usemask:
+ self.usemask = usemask
+ has_changed = True
+
+ oldpuse = self.puse
+ self.puse = self._use_manager.getPUSE(cpv_slot)
+ if oldpuse != self.puse:
+ has_changed = True
+ self.configdict["pkg"]["PKGUSE"] = self.puse[:] # For saving to PUSE file
+ self.configdict["pkg"]["USE"] = self.puse[:] # this gets appended to USE
+
+ if previous_features:
+ # The package from the previous setcpv call had package.env
+ # settings which modified FEATURES. Therefore, trigger a
+ # regenerate() call in order to ensure that self.features
+ # is accurate.
+ has_changed = True
+
+ self._penv = []
+ cpdict = self._penvdict.get(cp)
+ if cpdict:
+ penv_matches = ordered_by_atom_specificity(cpdict, cpv_slot)
+ if penv_matches:
+ for x in penv_matches:
+ self._penv.extend(x)
+
+ protected_pkg_keys = set(pkg_configdict)
+ protected_pkg_keys.discard('USE')
+
+ # If there are _any_ package.env settings for this package
+ # then it automatically triggers config.reset(), in order
+ # to account for possible incremental interaction between
+ # package.use, package.env, and overrides from the calling
+ # environment (configdict['env']).
+ if self._penv:
+ has_changed = True
+ # USE is special because package.use settings override
+ # it. Discard any package.use settings here and they'll
+ # be added back later.
+ pkg_configdict.pop('USE', None)
+ self._grab_pkg_env(self._penv, pkg_configdict,
+ protected_keys=protected_pkg_keys)
+
+ # Now add package.use settings, which override USE from
+ # package.env
+ if self.puse:
+ if 'USE' in pkg_configdict:
+ pkg_configdict['USE'] = \
+ pkg_configdict['USE'] + " " + self.puse
+ else:
+ pkg_configdict['USE'] = self.puse
+
+ if has_changed:
+ self.reset(keeping_pkg=1)
+
+ env_configdict = self.configdict['env']
+
+ # Ensure that "pkg" values are always preferred over "env" values.
+ # This must occur _after_ the above reset() call, since reset()
+ # copies values from self.backupenv.
+ for k in protected_pkg_keys:
+ env_configdict.pop(k, None)
+
+ lazy_vars = self._lazy_vars(built_use, self)
+ env_configdict.addLazySingleton('ACCEPT_LICENSE',
+ lazy_vars.__getitem__, 'ACCEPT_LICENSE')
+ env_configdict.addLazySingleton('PORTAGE_RESTRICT',
+ lazy_vars.__getitem__, 'PORTAGE_RESTRICT')
+
+ if built_use is not None:
+ pkg_configdict['PORTAGE_BUILT_USE'] = ' '.join(built_use)
+
+ # If reset() has not been called, it's safe to return
+ # early if IUSE has not changed.
+ if not has_changed and previous_iuse == iuse:
+ return
+
+ # Filter out USE flags that aren't part of IUSE. This has to
+ # be done for every setcpv() call since practically every
+ # package has different IUSE.
+ use = set(self["USE"].split())
+ if explicit_iuse is None:
+ explicit_iuse = frozenset(x.lstrip("+-") for x in iuse.split())
+ iuse_implicit_match = self._iuse_implicit_match
+ portage_iuse = self._get_implicit_iuse()
+ portage_iuse.update(explicit_iuse)
+
+ # PORTAGE_IUSE is not always needed so it's lazily evaluated.
+ self.configdict["env"].addLazySingleton(
+ "PORTAGE_IUSE", _lazy_iuse_regex, portage_iuse)
+
+ ebuild_force_test = self.get("EBUILD_FORCE_TEST") == "1"
+ if ebuild_force_test and \
+ not hasattr(self, "_ebuild_force_test_msg_shown"):
+ self._ebuild_force_test_msg_shown = True
+ writemsg(_("Forcing test.\n"), noiselevel=-1)
+ if "test" in self.features:
+ if "test" in self.usemask and not ebuild_force_test:
+ # "test" is in IUSE and USE=test is masked, so execution
+ # of src_test() probably is not reliable. Therefore,
+ # temporarily disable FEATURES=test just for this package.
+ self["FEATURES"] = " ".join(x for x in self.features \
+ if x != "test")
+ use.discard("test")
+ else:
+ use.add("test")
+ if ebuild_force_test and "test" in self.usemask:
+ self.usemask = \
+ frozenset(x for x in self.usemask if x != "test")
+
+ # Allow _* flags from USE_EXPAND wildcards to pass through here.
+ use.difference_update([x for x in use \
+ if (x not in explicit_iuse and \
+ not iuse_implicit_match(x)) and x[-2:] != '_*'])
+
+ # Use the calculated USE flags to regenerate the USE_EXPAND flags so
+ # that they are consistent. For optimal performance, use slice
+ # comparison instead of startswith().
+ use_expand_split = set(x.lower() for \
+ x in self.get('USE_EXPAND', '').split())
+ lazy_use_expand = self._lazy_use_expand(use, self.usemask,
+ portage_iuse, use_expand_split, self._use_expand_dict)
+
+ use_expand_iuses = {}
+ for x in portage_iuse:
+ x_split = x.split('_')
+ if len(x_split) == 1:
+ continue
+ for i in range(len(x_split) - 1):
+ k = '_'.join(x_split[:i+1])
+ if k in use_expand_split:
+ v = use_expand_iuses.get(k)
+ if v is None:
+ v = set()
+ use_expand_iuses[k] = v
+ v.add(x)
+ break
+
+ # If it's not in IUSE, variable content is allowed
+ # to pass through if it is defined somewhere. This
+ # allows packages that support LINGUAS but don't
+ # declare it in IUSE to use the variable outside of the
+ # USE_EXPAND context.
+ for k, use_expand_iuse in use_expand_iuses.items():
+ if k + '_*' in use:
+ use.update( x for x in use_expand_iuse if x not in usemask )
+ k = k.upper()
+ self.configdict['env'].addLazySingleton(k,
+ lazy_use_expand.__getitem__, k)
+
+ # Filtered for the ebuild environment. Store this in a separate
+ # attribute since we still want to be able to see global USE
+ # settings for things like emerge --info.
+
+ self.configdict["env"]["PORTAGE_USE"] = \
+ " ".join(sorted(x for x in use if x[-2:] != '_*'))
+
+ def _grab_pkg_env(self, penv, container, protected_keys=None):
+ if protected_keys is None:
+ protected_keys = ()
+ abs_user_config = os.path.join(
+ self['PORTAGE_CONFIGROOT'], USER_CONFIG_PATH)
+ non_user_variables = self._non_user_variables
+ # Make a copy since we don't want per-package settings
+ # to pollute the global expand_map.
+ expand_map = self._expand_map.copy()
+ incrementals = self.incrementals
+ for envname in penv:
+ penvfile = os.path.join(abs_user_config, "env", envname)
+ penvconfig = getconfig(penvfile, tolerant=self._tolerant,
+ allow_sourcing=True, expand=expand_map)
+ if penvconfig is None:
+ writemsg("!!! %s references non-existent file: %s\n" % \
+ (os.path.join(abs_user_config, 'package.env'), penvfile),
+ noiselevel=-1)
+ else:
+ for k, v in penvconfig.items():
+ if k in protected_keys or \
+ k in non_user_variables:
+ writemsg("!!! Illegal variable " + \
+ "'%s' assigned in '%s'\n" % \
+ (k, penvfile), noiselevel=-1)
+ elif k in incrementals:
+ if k in container:
+ container[k] = container[k] + " " + v
+ else:
+ container[k] = v
+ else:
+ container[k] = v
+
+ def _get_implicit_iuse(self):
+ """
+ Some flags are considered to
+ be implicit members of IUSE:
+ * Flags derived from ARCH
+ * Flags derived from USE_EXPAND_HIDDEN variables
+ * Masked flags, such as those from {,package}use.mask
+ * Forced flags, such as those from {,package}use.force
+ * build and bootstrap flags used by bootstrap.sh
+ """
+ iuse_implicit = set()
+ # Flags derived from ARCH.
+ arch = self.configdict["defaults"].get("ARCH")
+ if arch:
+ iuse_implicit.add(arch)
+ iuse_implicit.update(self.get("PORTAGE_ARCHLIST", "").split())
+
+ # Flags derived from USE_EXPAND_HIDDEN variables
+ # such as ELIBC, KERNEL, and USERLAND.
+ use_expand_hidden = self.get("USE_EXPAND_HIDDEN", "").split()
+ for x in use_expand_hidden:
+ iuse_implicit.add(x.lower() + "_.*")
+
+ # Flags that have been masked or forced.
+ iuse_implicit.update(self.usemask)
+ iuse_implicit.update(self.useforce)
+
+ # build and bootstrap flags used by bootstrap.sh
+ iuse_implicit.add("build")
+ iuse_implicit.add("bootstrap")
+
+ # Controlled by FEATURES=test. Make this implicit, so handling
+ # of FEATURES=test is consistent regardless of explicit IUSE.
+ # Users may use use.mask/package.use.mask to control
+ # FEATURES=test for all ebuilds, regardless of explicit IUSE.
+ iuse_implicit.add("test")
+
+ return iuse_implicit
+
+ def _getUseMask(self, pkg):
+ return self._use_manager.getUseMask(pkg)
+
+ def _getUseForce(self, pkg):
+ return self._use_manager.getUseForce(pkg)
+
+ def _getMaskAtom(self, cpv, metadata):
+ """
+ Take a package and return a matching package.mask atom, or None if no
+ such atom exists or it has been cancelled by package.unmask. PROVIDE
+ is not checked, so atoms will not be found for old-style virtuals.
+
+ @param cpv: The package name
+ @type cpv: String
+ @param metadata: A dictionary of raw package metadata
+ @type metadata: dict
+ @rtype: String
+ @return: A matching atom string or None if one is not found.
+ """
+ return self._mask_manager.getMaskAtom(cpv, metadata["SLOT"], metadata.get('repository'))
+
+ def _getRawMaskAtom(self, cpv, metadata):
+ """
+ Take a package and return a matching package.mask atom, or None if no
+ such atom exists or it has been cancelled by package.unmask. PROVIDE
+ is not checked, so atoms will not be found for old-style virtuals.
+
+ @param cpv: The package name
+ @type cpv: String
+ @param metadata: A dictionary of raw package metadata
+ @type metadata: dict
+ @rtype: String
+ @return: A matching atom string or None if one is not found.
+ """
+ return self._mask_manager.getRawMaskAtom(cpv, metadata["SLOT"], metadata.get('repository'))
+
+
+ def _getProfileMaskAtom(self, cpv, metadata):
+ """
+ Take a package and return a matching profile atom, or None if no
+ such atom exists. Note that a profile atom may or may not have a "*"
+ prefix. PROVIDE is not checked, so atoms will not be found for
+ old-style virtuals.
+
+ @param cpv: The package name
+ @type cpv: String
+ @param metadata: A dictionary of raw package metadata
+ @type metadata: dict
+ @rtype: String
+ @return: A matching profile atom string or None if one is not found.
+ """
+
+ cp = cpv_getkey(cpv)
+ profile_atoms = self.prevmaskdict.get(cp)
+ if profile_atoms:
+ pkg = "".join((cpv, _slot_separator, metadata["SLOT"]))
+ repo = metadata.get("repository")
+ if repo and repo != Package.UNKNOWN_REPO:
+ pkg = "".join((pkg, _repo_separator, repo))
+ pkg_list = [pkg]
+ for x in profile_atoms:
+ if match_from_list(x, pkg_list):
+ continue
+ return x
+ return None
+
+ def _getKeywords(self, cpv, metadata):
+ return self._keywords_manager.getKeywords(cpv, metadata["SLOT"], \
+ metadata.get("KEYWORDS", ""), metadata.get("repository"))
+
+ def _getMissingKeywords(self, cpv, metadata):
+ """
+ Take a package and return a list of any KEYWORDS that the user may
+ need to accept for the given package. If the KEYWORDS are empty
+ and the the ** keyword has not been accepted, the returned list will
+ contain ** alone (in order to distinguish from the case of "none
+ missing").
+
+ @param cpv: The package name (for package.keywords support)
+ @type cpv: String
+ @param metadata: A dictionary of raw package metadata
+ @type metadata: dict
+ @rtype: List
+ @return: A list of KEYWORDS that have not been accepted.
+ """
+
+ # Hack: Need to check the env directly here as otherwise stacking
+ # doesn't work properly as negative values are lost in the config
+ # object (bug #139600)
+ backuped_accept_keywords = self.configdict["backupenv"].get("ACCEPT_KEYWORDS", "")
+ global_accept_keywords = self["ACCEPT_KEYWORDS"]
+
+ return self._keywords_manager.getMissingKeywords(cpv, metadata["SLOT"], \
+ metadata.get("KEYWORDS", ""), metadata.get('repository'), \
+ global_accept_keywords, backuped_accept_keywords)
+
+ def _getRawMissingKeywords(self, cpv, metadata):
+ """
+ Take a package and return a list of any KEYWORDS that the user may
+ need to accept for the given package. If the KEYWORDS are empty,
+ the returned list will contain ** alone (in order to distinguish
+ from the case of "none missing"). This DOES NOT apply any user config
+ package.accept_keywords acceptance.
+
+ @param cpv: The package name (for package.keywords support)
+ @type cpv: String
+ @param metadata: A dictionary of raw package metadata
+ @type metadata: dict
+ @rtype: List
+ @return: lists of KEYWORDS that have not been accepted
+ and the keywords it looked for.
+ """
+ return self._keywords_manager.getRawMissingKeywords(cpv, metadata["SLOT"], \
+ metadata.get("KEYWORDS", ""), metadata.get('repository'), \
+ self.get("ACCEPT_KEYWORDS", ""))
+
+ def _getPKeywords(self, cpv, metadata):
+ global_accept_keywords = self.get("ACCEPT_KEYWORDS", "")
+
+ return self._keywords_manager.getPKeywords(cpv, metadata["SLOT"], \
+ metadata.get('repository'), global_accept_keywords)
+
+ def _getMissingLicenses(self, cpv, metadata):
+ """
+ Take a LICENSE string and return a list of any licenses that the user
+ may need to accept for the given package. The returned list will not
+ contain any licenses that have already been accepted. This method
+ can throw an InvalidDependString exception.
+
+ @param cpv: The package name (for package.license support)
+ @type cpv: String
+ @param metadata: A dictionary of raw package metadata
+ @type metadata: dict
+ @rtype: List
+ @return: A list of licenses that have not been accepted.
+ """
+ return self._license_manager.getMissingLicenses( \
+ cpv, metadata["USE"], metadata["LICENSE"], metadata["SLOT"], metadata.get('repository'))
+
+ def _getMissingProperties(self, cpv, metadata):
+ """
+ Take a PROPERTIES string and return a list of any properties the user
+ may need to accept for the given package. The returned list will not
+ contain any properties that have already been accepted. This method
+ can throw an InvalidDependString exception.
+
+ @param cpv: The package name (for package.properties support)
+ @type cpv: String
+ @param metadata: A dictionary of raw package metadata
+ @type metadata: dict
+ @rtype: List
+ @return: A list of properties that have not been accepted.
+ """
+ accept_properties = self._accept_properties
+ cp = cpv_getkey(cpv)
+ cpdict = self._ppropertiesdict.get(cp)
+ if cpdict:
+ cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
+ pproperties_list = ordered_by_atom_specificity(cpdict, cpv_slot, repo=metadata.get('repository'))
+ if pproperties_list:
+ accept_properties = list(self._accept_properties)
+ for x in pproperties_list:
+ accept_properties.extend(x)
+
+ properties_str = metadata.get("PROPERTIES", "")
+ properties = set(use_reduce(properties_str, matchall=1, flat=True))
+ properties.discard('||')
+
+ acceptable_properties = set()
+ for x in accept_properties:
+ if x == '*':
+ acceptable_properties.update(properties)
+ elif x == '-*':
+ acceptable_properties.clear()
+ elif x[:1] == '-':
+ acceptable_properties.discard(x[1:])
+ else:
+ acceptable_properties.add(x)
+
+ if "?" in properties_str:
+ use = metadata["USE"].split()
+ else:
+ use = []
+
+ properties_struct = use_reduce(properties_str, uselist=use, opconvert=True)
+ return self._getMaskedProperties(properties_struct, acceptable_properties)
+
+ def _getMaskedProperties(self, properties_struct, acceptable_properties):
+ if not properties_struct:
+ return []
+ if properties_struct[0] == "||":
+ ret = []
+ for element in properties_struct[1:]:
+ if isinstance(element, list):
+ if element:
+ tmp = self._getMaskedProperties(
+ element, acceptable_properties)
+ if not tmp:
+ return []
+ ret.extend(tmp)
+ else:
+ if element in acceptable_properties:
+ return[]
+ ret.append(element)
+ # Return all masked properties, since we don't know which combination
+ # (if any) the user will decide to unmask
+ return ret
+
+ ret = []
+ for element in properties_struct:
+ if isinstance(element, list):
+ if element:
+ ret.extend(self._getMaskedProperties(element,
+ acceptable_properties))
+ else:
+ if element not in acceptable_properties:
+ ret.append(element)
+ return ret
+
+ def _accept_chost(self, cpv, metadata):
+ """
+ @return True if pkg CHOST is accepted, False otherwise.
+ """
+ if self._accept_chost_re is None:
+ accept_chost = self.get("ACCEPT_CHOSTS", "").split()
+ if not accept_chost:
+ chost = self.get("CHOST")
+ if chost:
+ accept_chost.append(chost)
+ if not accept_chost:
+ self._accept_chost_re = re.compile(".*")
+ elif len(accept_chost) == 1:
+ try:
+ self._accept_chost_re = re.compile(r'^%s$' % accept_chost[0])
+ except re.error as e:
+ writemsg(_("!!! Invalid ACCEPT_CHOSTS value: '%s': %s\n") % \
+ (accept_chost[0], e), noiselevel=-1)
+ self._accept_chost_re = re.compile("^$")
+ else:
+ try:
+ self._accept_chost_re = re.compile(
+ r'^(%s)$' % "|".join(accept_chost))
+ except re.error as e:
+ writemsg(_("!!! Invalid ACCEPT_CHOSTS value: '%s': %s\n") % \
+ (" ".join(accept_chost), e), noiselevel=-1)
+ self._accept_chost_re = re.compile("^$")
+
+ pkg_chost = metadata.get('CHOST', '')
+ return not pkg_chost or \
+ self._accept_chost_re.match(pkg_chost) is not None
+
+ def setinst(self, mycpv, mydbapi):
+ """This updates the preferences for old-style virtuals,
+ affecting the behavior of dep_expand() and dep_check()
+ calls. It can change dbapi.match() behavior since that
+ calls dep_expand(). However, dbapi instances have
+ internal match caches that are not invalidated when
+ preferences are updated here. This can potentially
+ lead to some inconsistency (relevant to bug #1343)."""
+ self.modifying()
+
+ # Grab the virtuals this package provides and add them into the tree virtuals.
+ if not hasattr(mydbapi, "aux_get"):
+ provides = mydbapi["PROVIDE"]
+ else:
+ provides = mydbapi.aux_get(mycpv, ["PROVIDE"])[0]
+ if not provides:
+ return
+ if isinstance(mydbapi, portdbapi):
+ self.setcpv(mycpv, mydb=mydbapi)
+ myuse = self["PORTAGE_USE"]
+ elif not hasattr(mydbapi, "aux_get"):
+ myuse = mydbapi["USE"]
+ else:
+ myuse = mydbapi.aux_get(mycpv, ["USE"])[0]
+ virts = use_reduce(provides, uselist=myuse.split(), flat=True)
+
+ # Ensure that we don't trigger the _treeVirtuals
+ # assertion in VirtualsManager._compile_virtuals().
+ self.getvirtuals()
+ self._virtuals_manager.add_depgraph_virtuals(mycpv, virts)
+
+ def reload(self):
+ """Reload things like /etc/profile.env that can change during runtime."""
+ env_d_filename = os.path.join(self["EROOT"], "etc", "profile.env")
+ self.configdict["env.d"].clear()
+ env_d = getconfig(env_d_filename, expand=False)
+ if env_d:
+ # env_d will be None if profile.env doesn't exist.
+ self.configdict["env.d"].update(env_d)
+
+ def regenerate(self, useonly=0, use_cache=None):
+ """
+ Regenerate settings
+ This involves regenerating valid USE flags, re-expanding USE_EXPAND flags
+ re-stacking USE flags (-flag and -*), as well as any other INCREMENTAL
+ variables. This also updates the env.d configdict; useful in case an ebuild
+ changes the environment.
+
+ If FEATURES has already stacked, it is not stacked twice.
+
+ @param useonly: Only regenerate USE flags (not any other incrementals)
+ @type useonly: Boolean
+ @rtype: None
+ """
+
+ if use_cache is not None:
+ warnings.warn("The use_cache parameter for config.regenerate() is deprecated and without effect.",
+ DeprecationWarning, stacklevel=2)
+
+ self.modifying()
+
+ if useonly:
+ myincrementals=["USE"]
+ else:
+ myincrementals = self.incrementals
+ myincrementals = set(myincrementals)
+
+ # Process USE last because it depends on USE_EXPAND which is also
+ # an incremental!
+ myincrementals.discard("USE")
+
+ mydbs = self.configlist[:-1]
+ mydbs.append(self.backupenv)
+
+ # ACCEPT_LICENSE is a lazily evaluated incremental, so that * can be
+ # used to match all licenses without every having to explicitly expand
+ # it to all licenses.
+ if self.local_config:
+ mysplit = []
+ for curdb in mydbs:
+ mysplit.extend(curdb.get('ACCEPT_LICENSE', '').split())
+ mysplit = prune_incremental(mysplit)
+ accept_license_str = ' '.join(mysplit)
+ self.configlist[-1]['ACCEPT_LICENSE'] = accept_license_str
+ self._license_manager.set_accept_license_str(accept_license_str)
+ else:
+ # repoman will accept any license
+ self._license_manager.set_accept_license_str("*")
+
+ # ACCEPT_PROPERTIES works like ACCEPT_LICENSE, without groups
+ if self.local_config:
+ mysplit = []
+ for curdb in mydbs:
+ mysplit.extend(curdb.get('ACCEPT_PROPERTIES', '').split())
+ mysplit = prune_incremental(mysplit)
+ self.configlist[-1]['ACCEPT_PROPERTIES'] = ' '.join(mysplit)
+ if tuple(mysplit) != self._accept_properties:
+ self._accept_properties = tuple(mysplit)
+ else:
+ # repoman will accept any property
+ self._accept_properties = ('*',)
+
+ increment_lists = {}
+ for k in myincrementals:
+ incremental_list = []
+ increment_lists[k] = incremental_list
+ for curdb in mydbs:
+ v = curdb.get(k)
+ if v is not None:
+ incremental_list.append(v.split())
+
+ if 'FEATURES' in increment_lists:
+ increment_lists['FEATURES'].append(self._features_overrides)
+
+ myflags = set()
+ for mykey, incremental_list in increment_lists.items():
+
+ myflags.clear()
+ for mysplit in incremental_list:
+
+ for x in mysplit:
+ if x=="-*":
+ # "-*" is a special "minus" var that means "unset all settings".
+ # so USE="-* gnome" will have *just* gnome enabled.
+ myflags.clear()
+ continue
+
+ if x[0]=="+":
+ # Not legal. People assume too much. Complain.
+ writemsg(colorize("BAD",
+ _("%s values should not start with a '+': %s") % (mykey,x)) \
+ + "\n", noiselevel=-1)
+ x=x[1:]
+ if not x:
+ continue
+
+ if (x[0]=="-"):
+ myflags.discard(x[1:])
+ continue
+
+ # We got here, so add it now.
+ myflags.add(x)
+
+ #store setting in last element of configlist, the original environment:
+ if myflags or mykey in self:
+ self.configlist[-1][mykey] = " ".join(sorted(myflags))
+
+ # Do the USE calculation last because it depends on USE_EXPAND.
+ use_expand = self.get("USE_EXPAND", "").split()
+ use_expand_dict = self._use_expand_dict
+ use_expand_dict.clear()
+ for k in use_expand:
+ v = self.get(k)
+ if v is not None:
+ use_expand_dict[k] = v
+
+ # In order to best accomodate the long-standing practice of
+ # setting default USE_EXPAND variables in the profile's
+ # make.defaults, we translate these variables into their
+ # equivalent USE flags so that useful incremental behavior
+ # is enabled (for sub-profiles).
+ configdict_defaults = self.configdict['defaults']
+ if self._make_defaults is not None:
+ for i, cfg in enumerate(self._make_defaults):
+ if not cfg:
+ self.make_defaults_use.append("")
+ continue
+ use = cfg.get("USE", "")
+ expand_use = []
+ for k in use_expand_dict:
+ v = cfg.get(k)
+ if v is None:
+ continue
+ prefix = k.lower() + '_'
+ if k in myincrementals:
+ for x in v.split():
+ if x[:1] == '-':
+ expand_use.append('-' + prefix + x[1:])
+ else:
+ expand_use.append(prefix + x)
+ else:
+ for x in v.split():
+ expand_use.append(prefix + x)
+ if expand_use:
+ expand_use.append(use)
+ use = ' '.join(expand_use)
+ self.make_defaults_use.append(use)
+ self.make_defaults_use = tuple(self.make_defaults_use)
+ configdict_defaults['USE'] = ' '.join(
+ stack_lists([x.split() for x in self.make_defaults_use]))
+ # Set to None so this code only runs once.
+ self._make_defaults = None
+
+ if not self.uvlist:
+ for x in self["USE_ORDER"].split(":"):
+ if x in self.configdict:
+ self.uvlist.append(self.configdict[x])
+ self.uvlist.reverse()
+
+ # For optimal performance, use slice
+ # comparison instead of startswith().
+ iuse = self.configdict["pkg"].get("IUSE")
+ if iuse is not None:
+ iuse = [x.lstrip("+-") for x in iuse.split()]
+ myflags = set()
+ for curdb in self.uvlist:
+ cur_use_expand = [x for x in use_expand if x in curdb]
+ mysplit = curdb.get("USE", "").split()
+ if not mysplit and not cur_use_expand:
+ continue
+ for x in mysplit:
+ if x == "-*":
+ myflags.clear()
+ continue
+
+ if x[0] == "+":
+ writemsg(colorize("BAD", _("USE flags should not start "
+ "with a '+': %s\n") % x), noiselevel=-1)
+ x = x[1:]
+ if not x:
+ continue
+
+ if x[0] == "-":
+ if x[-2:] == '_*':
+ prefix = x[1:-1]
+ prefix_len = len(prefix)
+ myflags.difference_update(
+ [y for y in myflags if \
+ y[:prefix_len] == prefix])
+ myflags.discard(x[1:])
+ continue
+
+ if iuse is not None and x[-2:] == '_*':
+ # Expand wildcards here, so that cases like
+ # USE="linguas_* -linguas_en_US" work correctly.
+ prefix = x[:-1]
+ prefix_len = len(prefix)
+ has_iuse = False
+ for y in iuse:
+ if y[:prefix_len] == prefix:
+ has_iuse = True
+ myflags.add(y)
+ if not has_iuse:
+ # There are no matching IUSE, so allow the
+ # wildcard to pass through. This allows
+ # linguas_* to trigger unset LINGUAS in
+ # cases when no linguas_ flags are in IUSE.
+ myflags.add(x)
+ else:
+ myflags.add(x)
+
+ if curdb is configdict_defaults:
+ # USE_EXPAND flags from make.defaults are handled
+ # earlier, in order to provide useful incremental
+ # behavior (for sub-profiles).
+ continue
+
+ for var in cur_use_expand:
+ var_lower = var.lower()
+ is_not_incremental = var not in myincrementals
+ if is_not_incremental:
+ prefix = var_lower + "_"
+ prefix_len = len(prefix)
+ for x in list(myflags):
+ if x[:prefix_len] == prefix:
+ myflags.remove(x)
+ for x in curdb[var].split():
+ if x[0] == "+":
+ if is_not_incremental:
+ writemsg(colorize("BAD", _("Invalid '+' "
+ "operator in non-incremental variable "
+ "'%s': '%s'\n") % (var, x)), noiselevel=-1)
+ continue
+ else:
+ writemsg(colorize("BAD", _("Invalid '+' "
+ "operator in incremental variable "
+ "'%s': '%s'\n") % (var, x)), noiselevel=-1)
+ x = x[1:]
+ if x[0] == "-":
+ if is_not_incremental:
+ writemsg(colorize("BAD", _("Invalid '-' "
+ "operator in non-incremental variable "
+ "'%s': '%s'\n") % (var, x)), noiselevel=-1)
+ continue
+ myflags.discard(var_lower + "_" + x[1:])
+ continue
+ myflags.add(var_lower + "_" + x)
+
+ if hasattr(self, "features"):
+ self.features._features.clear()
+ else:
+ self.features = features_set(self)
+ self.features._features.update(self.get('FEATURES', '').split())
+ self.features._sync_env_var()
+ self.features._validate()
+
+ myflags.update(self.useforce)
+ arch = self.configdict["defaults"].get("ARCH")
+ if arch:
+ myflags.add(arch)
+
+ myflags.difference_update(self.usemask)
+ self.configlist[-1]["USE"]= " ".join(sorted(myflags))
+
+ if self.mycpv is None:
+ # Generate global USE_EXPAND variables settings that are
+ # consistent with USE, for display by emerge --info. For
+ # package instances, these are instead generated via
+ # setcpv().
+ for k in use_expand:
+ prefix = k.lower() + '_'
+ prefix_len = len(prefix)
+ expand_flags = set( x[prefix_len:] for x in myflags \
+ if x[:prefix_len] == prefix )
+ var_split = use_expand_dict.get(k, '').split()
+ var_split = [ x for x in var_split if x in expand_flags ]
+ var_split.extend(sorted(expand_flags.difference(var_split)))
+ if var_split:
+ self.configlist[-1][k] = ' '.join(var_split)
+ elif k in self:
+ self.configlist[-1][k] = ''
+
+ @property
+ def virts_p(self):
+ warnings.warn("portage config.virts_p attribute " + \
+ "is deprecated, use config.get_virts_p()",
+ DeprecationWarning, stacklevel=2)
+ return self.get_virts_p()
+
+ @property
+ def virtuals(self):
+ warnings.warn("portage config.virtuals attribute " + \
+ "is deprecated, use config.getvirtuals()",
+ DeprecationWarning, stacklevel=2)
+ return self.getvirtuals()
+
+ def get_virts_p(self):
+ # Ensure that we don't trigger the _treeVirtuals
+ # assertion in VirtualsManager._compile_virtuals().
+ self.getvirtuals()
+ return self._virtuals_manager.get_virts_p()
+
+ def getvirtuals(self):
+ if self._virtuals_manager._treeVirtuals is None:
+ #Hack around the fact that VirtualsManager needs a vartree
+ #and vartree needs a config instance.
+ #This code should be part of VirtualsManager.getvirtuals().
+ if self.local_config:
+ temp_vartree = vartree(settings=self)
+ self._virtuals_manager._populate_treeVirtuals(temp_vartree)
+ else:
+ self._virtuals_manager._treeVirtuals = {}
+
+ return self._virtuals_manager.getvirtuals()
+
+ def _populate_treeVirtuals_if_needed(self, vartree):
+ """Reduce the provides into a list by CP."""
+ if self._virtuals_manager._treeVirtuals is None:
+ if self.local_config:
+ self._virtuals_manager._populate_treeVirtuals(vartree)
+ else:
+ self._virtuals_manager._treeVirtuals = {}
+
+ def __delitem__(self,mykey):
+ self.modifying()
+ for x in self.lookuplist:
+ if x != None:
+ if mykey in x:
+ del x[mykey]
+
+ def __getitem__(self,mykey):
+ for d in self.lookuplist:
+ if mykey in d:
+ return d[mykey]
+ return '' # for backward compat, don't raise KeyError
+
+ def get(self, k, x=None):
+ for d in self.lookuplist:
+ if k in d:
+ return d[k]
+ return x
+
+ def pop(self, key, *args):
+ if len(args) > 1:
+ raise TypeError(
+ "pop expected at most 2 arguments, got " + \
+ repr(1 + len(args)))
+ v = self
+ for d in reversed(self.lookuplist):
+ v = d.pop(key, v)
+ if v is self:
+ if args:
+ return args[0]
+ raise KeyError(key)
+ return v
+
+ def __contains__(self, mykey):
+ """Called to implement membership test operators (in and not in)."""
+ for d in self.lookuplist:
+ if mykey in d:
+ return True
+ return False
+
+ def setdefault(self, k, x=None):
+ v = self.get(k)
+ if v is not None:
+ return v
+ else:
+ self[k] = x
+ return x
+
+ def keys(self):
+ return list(self)
+
+ def __iter__(self):
+ keys = set()
+ for d in self.lookuplist:
+ keys.update(d)
+ return iter(keys)
+
+ def iterkeys(self):
+ return iter(self)
+
+ def iteritems(self):
+ for k in self:
+ yield (k, self[k])
+
+ def items(self):
+ return list(self.iteritems())
+
+ def __setitem__(self,mykey,myvalue):
+ "set a value; will be thrown away at reset() time"
+ if not isinstance(myvalue, basestring):
+ raise ValueError("Invalid type being used as a value: '%s': '%s'" % (str(mykey),str(myvalue)))
+
+ # Avoid potential UnicodeDecodeError exceptions later.
+ mykey = _unicode_decode(mykey)
+ myvalue = _unicode_decode(myvalue)
+
+ self.modifying()
+ self.modifiedkeys.append(mykey)
+ self.configdict["env"][mykey]=myvalue
+
+ def environ(self):
+ "return our locally-maintained environment"
+ mydict={}
+ environ_filter = self._environ_filter
+
+ eapi = self.get('EAPI')
+ phase = self.get('EBUILD_PHASE')
+ filter_calling_env = False
+ if self.mycpv is not None and \
+ phase not in ('clean', 'cleanrm', 'depend', 'fetch'):
+ temp_dir = self.get('T')
+ if temp_dir is not None and \
+ os.path.exists(os.path.join(temp_dir, 'environment')):
+ filter_calling_env = True
+
+ environ_whitelist = self._environ_whitelist
+ for x in self:
+ if x in environ_filter:
+ continue
+ myvalue = self[x]
+ if not isinstance(myvalue, basestring):
+ writemsg(_("!!! Non-string value in config: %s=%s\n") % \
+ (x, myvalue), noiselevel=-1)
+ continue
+ if filter_calling_env and \
+ x not in environ_whitelist and \
+ not self._environ_whitelist_re.match(x):
+ # Do not allow anything to leak into the ebuild
+ # environment unless it is explicitly whitelisted.
+ # This ensures that variables unset by the ebuild
+ # remain unset (bug #189417).
+ continue
+ mydict[x] = myvalue
+ if "HOME" not in mydict and "BUILD_PREFIX" in mydict:
+ writemsg("*** HOME not set. Setting to "+mydict["BUILD_PREFIX"]+"\n")
+ mydict["HOME"]=mydict["BUILD_PREFIX"][:]
+
+ if filter_calling_env:
+ if phase:
+ whitelist = []
+ if "rpm" == phase:
+ whitelist.append("RPMDIR")
+ for k in whitelist:
+ v = self.get(k)
+ if v is not None:
+ mydict[k] = v
+
+ # At some point we may want to stop exporting FEATURES to the ebuild
+ # environment, in order to prevent ebuilds from abusing it. In
+ # preparation for that, export it as PORTAGE_FEATURES so that bashrc
+ # users will be able to migrate any FEATURES conditional code to
+ # use this alternative variable.
+ mydict["PORTAGE_FEATURES"] = self["FEATURES"]
+
+ # Filtered by IUSE and implicit IUSE.
+ mydict["USE"] = self.get("PORTAGE_USE", "")
+
+ # Don't export AA to the ebuild environment in EAPIs that forbid it
+ if not eapi_exports_AA(eapi):
+ mydict.pop("AA", None)
+
+ if not eapi_exports_merge_type(eapi):
+ mydict.pop("MERGE_TYPE", None)
+
+ # Prefix variables are supported starting with EAPI 3.
+ if phase == 'depend' or eapi is None or not eapi_supports_prefix(eapi):
+ mydict.pop("ED", None)
+ mydict.pop("EPREFIX", None)
+ mydict.pop("EROOT", None)
+
+ if phase == 'depend':
+ mydict.pop('FILESDIR', None)
+
+ if phase not in ("pretend", "setup", "preinst", "postinst") or \
+ not eapi_exports_replace_vars(eapi):
+ mydict.pop("REPLACING_VERSIONS", None)
+
+ if phase not in ("prerm", "postrm") or \
+ not eapi_exports_replace_vars(eapi):
+ mydict.pop("REPLACED_BY_VERSION", None)
+
+ return mydict
+
+ def thirdpartymirrors(self):
+ if getattr(self, "_thirdpartymirrors", None) is None:
+ profileroots = [os.path.join(self["PORTDIR"], "profiles")]
+ for x in shlex_split(self.get("PORTDIR_OVERLAY", "")):
+ profileroots.insert(0, os.path.join(x, "profiles"))
+ thirdparty_lists = [grabdict(os.path.join(x, "thirdpartymirrors")) for x in profileroots]
+ self._thirdpartymirrors = stack_dictlist(thirdparty_lists, incremental=True)
+ return self._thirdpartymirrors
+
+ def archlist(self):
+ _archlist = []
+ for myarch in self["PORTAGE_ARCHLIST"].split():
+ _archlist.append(myarch)
+ _archlist.append("~" + myarch)
+ return _archlist
+
+ def selinux_enabled(self):
+ if getattr(self, "_selinux_enabled", None) is None:
+ self._selinux_enabled = 0
+ if "selinux" in self["USE"].split():
+ if selinux:
+ if selinux.is_selinux_enabled() == 1:
+ self._selinux_enabled = 1
+ else:
+ self._selinux_enabled = 0
+ else:
+ writemsg(_("!!! SELinux module not found. Please verify that it was installed.\n"),
+ noiselevel=-1)
+ self._selinux_enabled = 0
+
+ return self._selinux_enabled
+
+ if sys.hexversion >= 0x3000000:
+ keys = __iter__
+ items = iteritems
diff --git a/portage_with_autodep/pym/portage/package/ebuild/deprecated_profile_check.py b/portage_with_autodep/pym/portage/package/ebuild/deprecated_profile_check.py
new file mode 100644
index 0000000..3fab4da
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/deprecated_profile_check.py
@@ -0,0 +1,42 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['deprecated_profile_check']
+
+import io
+
+from portage import os, _encodings, _unicode_encode
+from portage.const import DEPRECATED_PROFILE_FILE
+from portage.localization import _
+from portage.output import colorize
+from portage.util import writemsg
+
+def deprecated_profile_check(settings=None):
+ config_root = "/"
+ if settings is not None:
+ config_root = settings["PORTAGE_CONFIGROOT"]
+ deprecated_profile_file = os.path.join(config_root,
+ DEPRECATED_PROFILE_FILE)
+ if not os.access(deprecated_profile_file, os.R_OK):
+ return False
+ dcontent = io.open(_unicode_encode(deprecated_profile_file,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'], errors='replace').readlines()
+ writemsg(colorize("BAD", _("\n!!! Your current profile is "
+ "deprecated and not supported anymore.")) + "\n", noiselevel=-1)
+ writemsg(colorize("BAD", _("!!! Use eselect profile to update your "
+ "profile.")) + "\n", noiselevel=-1)
+ if not dcontent:
+ writemsg(colorize("BAD", _("!!! Please refer to the "
+ "Gentoo Upgrading Guide.")) + "\n", noiselevel=-1)
+ return True
+ newprofile = dcontent[0]
+ writemsg(colorize("BAD", _("!!! Please upgrade to the "
+ "following profile if possible:")) + "\n", noiselevel=-1)
+ writemsg(8*" " + colorize("GOOD", newprofile) + "\n", noiselevel=-1)
+ if len(dcontent) > 1:
+ writemsg(_("To upgrade do the following steps:\n"), noiselevel=-1)
+ for myline in dcontent[1:]:
+ writemsg(myline, noiselevel=-1)
+ writemsg("\n\n", noiselevel=-1)
+ return True
diff --git a/portage_with_autodep/pym/portage/package/ebuild/digestcheck.py b/portage_with_autodep/pym/portage/package/ebuild/digestcheck.py
new file mode 100644
index 0000000..1e34b14
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/digestcheck.py
@@ -0,0 +1,167 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['digestcheck']
+
+import warnings
+
+from portage import os, _encodings, _unicode_decode
+from portage.exception import DigestException, FileNotFound
+from portage.localization import _
+from portage.manifest import Manifest
+from portage.output import EOutput
+from portage.util import writemsg
+
+def digestcheck(myfiles, mysettings, strict=False, justmanifest=None, mf=None):
+ """
+ Verifies checksums. Assumes all files have been downloaded.
+ @rtype: int
+ @returns: 1 on success and 0 on failure
+ """
+
+ if justmanifest is not None:
+ warnings.warn("The justmanifest parameter of the " + \
+ "portage.package.ebuild.digestcheck.digestcheck()" + \
+ " function is now unused.",
+ DeprecationWarning, stacklevel=2)
+ justmanifest = None
+
+ if mysettings.get("EBUILD_SKIP_MANIFEST") == "1":
+ return 1
+ allow_missing = "allow-missing-manifests" in mysettings.features
+ pkgdir = mysettings["O"]
+ manifest_path = os.path.join(pkgdir, "Manifest")
+ if not os.path.exists(manifest_path):
+ if allow_missing:
+ return 1
+ writemsg(_("!!! Manifest file not found: '%s'\n") % manifest_path,
+ noiselevel=-1)
+ if strict:
+ return 0
+ else:
+ return 1
+ if mf is None:
+ mf = Manifest(pkgdir, mysettings["DISTDIR"])
+ manifest_empty = True
+ for d in mf.fhashdict.values():
+ if d:
+ manifest_empty = False
+ break
+ if manifest_empty:
+ writemsg(_("!!! Manifest is empty: '%s'\n") % manifest_path,
+ noiselevel=-1)
+ if strict:
+ return 0
+ else:
+ return 1
+ eout = EOutput()
+ eout.quiet = mysettings.get("PORTAGE_QUIET", None) == "1"
+ try:
+ if strict and "PORTAGE_PARALLEL_FETCHONLY" not in mysettings:
+ eout.ebegin(_("checking ebuild checksums ;-)"))
+ mf.checkTypeHashes("EBUILD")
+ eout.eend(0)
+ eout.ebegin(_("checking auxfile checksums ;-)"))
+ mf.checkTypeHashes("AUX")
+ eout.eend(0)
+ eout.ebegin(_("checking miscfile checksums ;-)"))
+ mf.checkTypeHashes("MISC", ignoreMissingFiles=True)
+ eout.eend(0)
+ for f in myfiles:
+ eout.ebegin(_("checking %s ;-)") % f)
+ ftype = mf.findFile(f)
+ if ftype is None:
+ eout.eend(1)
+ writemsg(_("\n!!! Missing digest for '%s'\n") % (f,),
+ noiselevel=-1)
+ return 0
+ mf.checkFileHashes(ftype, f)
+ eout.eend(0)
+ except FileNotFound as e:
+ eout.eend(1)
+ writemsg(_("\n!!! A file listed in the Manifest could not be found: %s\n") % str(e),
+ noiselevel=-1)
+ return 0
+ except DigestException as e:
+ eout.eend(1)
+ writemsg(_("\n!!! Digest verification failed:\n"), noiselevel=-1)
+ writemsg("!!! %s\n" % e.value[0], noiselevel=-1)
+ writemsg(_("!!! Reason: %s\n") % e.value[1], noiselevel=-1)
+ writemsg(_("!!! Got: %s\n") % e.value[2], noiselevel=-1)
+ writemsg(_("!!! Expected: %s\n") % e.value[3], noiselevel=-1)
+ return 0
+ if allow_missing:
+ # In this case we ignore any missing digests that
+ # would otherwise be detected below.
+ return 1
+ # Make sure that all of the ebuilds are actually listed in the Manifest.
+ for f in os.listdir(pkgdir):
+ pf = None
+ if f[-7:] == '.ebuild':
+ pf = f[:-7]
+ if pf is not None and not mf.hasFile("EBUILD", f):
+ writemsg(_("!!! A file is not listed in the Manifest: '%s'\n") % \
+ os.path.join(pkgdir, f), noiselevel=-1)
+ if strict:
+ return 0
+ # epatch will just grab all the patches out of a directory, so we have to
+ # make sure there aren't any foreign files that it might grab.
+ filesdir = os.path.join(pkgdir, "files")
+
+ for parent, dirs, files in os.walk(filesdir):
+ try:
+ parent = _unicode_decode(parent,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ parent = _unicode_decode(parent,
+ encoding=_encodings['fs'], errors='replace')
+ writemsg(_("!!! Path contains invalid "
+ "character(s) for encoding '%s': '%s'") \
+ % (_encodings['fs'], parent), noiselevel=-1)
+ if strict:
+ return 0
+ continue
+ for d in dirs:
+ d_bytes = d
+ try:
+ d = _unicode_decode(d,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ d = _unicode_decode(d,
+ encoding=_encodings['fs'], errors='replace')
+ writemsg(_("!!! Path contains invalid "
+ "character(s) for encoding '%s': '%s'") \
+ % (_encodings['fs'], os.path.join(parent, d)),
+ noiselevel=-1)
+ if strict:
+ return 0
+ dirs.remove(d_bytes)
+ continue
+ if d.startswith(".") or d == "CVS":
+ dirs.remove(d_bytes)
+ for f in files:
+ try:
+ f = _unicode_decode(f,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ f = _unicode_decode(f,
+ encoding=_encodings['fs'], errors='replace')
+ if f.startswith("."):
+ continue
+ f = os.path.join(parent, f)[len(filesdir) + 1:]
+ writemsg(_("!!! File name contains invalid "
+ "character(s) for encoding '%s': '%s'") \
+ % (_encodings['fs'], f), noiselevel=-1)
+ if strict:
+ return 0
+ continue
+ if f.startswith("."):
+ continue
+ f = os.path.join(parent, f)[len(filesdir) + 1:]
+ file_type = mf.findFile(f)
+ if file_type != "AUX" and not f.startswith("digest-"):
+ writemsg(_("!!! A file is not listed in the Manifest: '%s'\n") % \
+ os.path.join(filesdir, f), noiselevel=-1)
+ if strict:
+ return 0
+ return 1
diff --git a/portage_with_autodep/pym/portage/package/ebuild/digestgen.py b/portage_with_autodep/pym/portage/package/ebuild/digestgen.py
new file mode 100644
index 0000000..eb7210e
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/digestgen.py
@@ -0,0 +1,202 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['digestgen']
+
+import errno
+
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.package.ebuild._spawn_nofetch:spawn_nofetch',
+)
+
+from portage import os
+from portage.const import MANIFEST2_REQUIRED_HASH
+from portage.dbapi.porttree import FetchlistDict
+from portage.dep import use_reduce
+from portage.exception import InvalidDependString, FileNotFound, \
+ PermissionDenied, PortagePackageException
+from portage.localization import _
+from portage.manifest import Manifest
+from portage.output import colorize
+from portage.package.ebuild.fetch import fetch
+from portage.util import writemsg, writemsg_stdout
+from portage.versions import catsplit
+
+def digestgen(myarchives=None, mysettings=None, myportdb=None):
+ """
+ Generates a digest file if missing. Fetches files if necessary.
+ NOTE: myarchives and mysettings used to be positional arguments,
+ so their order must be preserved for backward compatibility.
+ @param mysettings: the ebuild config (mysettings["O"] must correspond
+ to the ebuild's parent directory)
+ @type mysettings: config
+ @param myportdb: a portdbapi instance
+ @type myportdb: portdbapi
+ @rtype: int
+ @returns: 1 on success and 0 on failure
+ """
+ if mysettings is None or myportdb is None:
+ raise TypeError("portage.digestgen(): 'mysettings' and 'myportdb' parameter are required.")
+
+ try:
+ portage._doebuild_manifest_exempt_depend += 1
+ distfiles_map = {}
+ fetchlist_dict = FetchlistDict(mysettings["O"], mysettings, myportdb)
+ for cpv in fetchlist_dict:
+ try:
+ for myfile in fetchlist_dict[cpv]:
+ distfiles_map.setdefault(myfile, []).append(cpv)
+ except InvalidDependString as e:
+ writemsg("!!! %s\n" % str(e), noiselevel=-1)
+ del e
+ return 0
+ mytree = os.path.dirname(os.path.dirname(mysettings["O"]))
+ manifest1_compat = False
+ mf = Manifest(mysettings["O"], mysettings["DISTDIR"],
+ fetchlist_dict=fetchlist_dict, manifest1_compat=manifest1_compat)
+ # Don't require all hashes since that can trigger excessive
+ # fetches when sufficient digests already exist. To ease transition
+ # while Manifest 1 is being removed, only require hashes that will
+ # exist before and after the transition.
+ required_hash_types = set()
+ required_hash_types.add("size")
+ required_hash_types.add(MANIFEST2_REQUIRED_HASH)
+ dist_hashes = mf.fhashdict.get("DIST", {})
+
+ # To avoid accidental regeneration of digests with the incorrect
+ # files (such as partially downloaded files), trigger the fetch
+ # code if the file exists and it's size doesn't match the current
+ # manifest entry. If there really is a legitimate reason for the
+ # digest to change, `ebuild --force digest` can be used to avoid
+ # triggering this code (or else the old digests can be manually
+ # removed from the Manifest).
+ missing_files = []
+ for myfile in distfiles_map:
+ myhashes = dist_hashes.get(myfile)
+ if not myhashes:
+ try:
+ st = os.stat(os.path.join(mysettings["DISTDIR"], myfile))
+ except OSError:
+ st = None
+ if st is None or st.st_size == 0:
+ missing_files.append(myfile)
+ continue
+ size = myhashes.get("size")
+
+ try:
+ st = os.stat(os.path.join(mysettings["DISTDIR"], myfile))
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ if size == 0:
+ missing_files.append(myfile)
+ continue
+ if required_hash_types.difference(myhashes):
+ missing_files.append(myfile)
+ continue
+ else:
+ if st.st_size == 0 or size is not None and size != st.st_size:
+ missing_files.append(myfile)
+ continue
+
+ if missing_files:
+ mytree = os.path.realpath(os.path.dirname(
+ os.path.dirname(mysettings["O"])))
+ for myfile in missing_files:
+ uris = set()
+ all_restrict = set()
+ for cpv in distfiles_map[myfile]:
+ uris.update(myportdb.getFetchMap(
+ cpv, mytree=mytree)[myfile])
+ restrict = myportdb.aux_get(cpv, ['RESTRICT'],
+ mytree=mytree)[0]
+ # Here we ignore conditional parts of RESTRICT since
+ # they don't apply unconditionally. Assume such
+ # conditionals only apply on the client side where
+ # digestgen() does not need to be called.
+ all_restrict.update(use_reduce(restrict,
+ flat=True, matchnone=True))
+
+ # fetch() uses CATEGORY and PF to display a message
+ # when fetch restriction is triggered.
+ cat, pf = catsplit(cpv)
+ mysettings["CATEGORY"] = cat
+ mysettings["PF"] = pf
+
+ # fetch() uses PORTAGE_RESTRICT to control fetch
+ # restriction, which is only applied to files that
+ # are not fetchable via a mirror:// URI.
+ mysettings["PORTAGE_RESTRICT"] = " ".join(all_restrict)
+
+ try:
+ st = os.stat(os.path.join(
+ mysettings["DISTDIR"],myfile))
+ except OSError:
+ st = None
+
+ if not fetch({myfile : uris}, mysettings):
+ myebuild = os.path.join(mysettings["O"],
+ catsplit(cpv)[1] + ".ebuild")
+ spawn_nofetch(myportdb, myebuild,
+ settings=mysettings)
+ writemsg(_("!!! Fetch failed for %s, can't update "
+ "Manifest\n") % myfile, noiselevel=-1)
+ if myfile in dist_hashes and \
+ st is not None and st.st_size > 0:
+ # stat result is obtained before calling fetch(),
+ # since fetch may rename the existing file if the
+ # digest does not match.
+ writemsg(_("!!! If you would like to "
+ "forcefully replace the existing "
+ "Manifest entry\n!!! for %s, use "
+ "the following command:\n") % myfile + \
+ "!!! " + colorize("INFORM",
+ "ebuild --force %s manifest" % \
+ os.path.basename(myebuild)) + "\n",
+ noiselevel=-1)
+ return 0
+ writemsg_stdout(_(">>> Creating Manifest for %s\n") % mysettings["O"])
+ try:
+ mf.create(assumeDistHashesSometimes=True,
+ assumeDistHashesAlways=(
+ "assume-digests" in mysettings.features))
+ except FileNotFound as e:
+ writemsg(_("!!! File %s doesn't exist, can't update "
+ "Manifest\n") % e, noiselevel=-1)
+ return 0
+ except PortagePackageException as e:
+ writemsg(("!!! %s\n") % (e,), noiselevel=-1)
+ return 0
+ try:
+ mf.write(sign=False)
+ except PermissionDenied as e:
+ writemsg(_("!!! Permission Denied: %s\n") % (e,), noiselevel=-1)
+ return 0
+ if "assume-digests" not in mysettings.features:
+ distlist = list(mf.fhashdict.get("DIST", {}))
+ distlist.sort()
+ auto_assumed = []
+ for filename in distlist:
+ if not os.path.exists(
+ os.path.join(mysettings["DISTDIR"], filename)):
+ auto_assumed.append(filename)
+ if auto_assumed:
+ mytree = os.path.realpath(
+ os.path.dirname(os.path.dirname(mysettings["O"])))
+ cp = os.path.sep.join(mysettings["O"].split(os.path.sep)[-2:])
+ pkgs = myportdb.cp_list(cp, mytree=mytree)
+ pkgs.sort()
+ writemsg_stdout(" digest.assumed" + colorize("WARN",
+ str(len(auto_assumed)).rjust(18)) + "\n")
+ for pkg_key in pkgs:
+ fetchlist = myportdb.getFetchMap(pkg_key, mytree=mytree)
+ pv = pkg_key.split("/")[1]
+ for filename in auto_assumed:
+ if filename in fetchlist:
+ writemsg_stdout(
+ " %s::%s\n" % (pv, filename))
+ return 1
+ finally:
+ portage._doebuild_manifest_exempt_depend -= 1
diff --git a/portage_with_autodep/pym/portage/package/ebuild/doebuild.py b/portage_with_autodep/pym/portage/package/ebuild/doebuild.py
new file mode 100644
index 0000000..c76c1ed
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/doebuild.py
@@ -0,0 +1,1791 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['doebuild', 'doebuild_environment', 'spawn', 'spawnebuild']
+
+import gzip
+import errno
+import io
+from itertools import chain
+import logging
+import os as _os
+import re
+import shutil
+import signal
+import stat
+import sys
+import tempfile
+from textwrap import wrap
+import time
+import warnings
+import zlib
+
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.package.ebuild.config:check_config_instance',
+ 'portage.package.ebuild.digestcheck:digestcheck',
+ 'portage.package.ebuild.digestgen:digestgen',
+ 'portage.package.ebuild.fetch:fetch',
+ 'portage.package.ebuild._spawn_nofetch:spawn_nofetch',
+ 'portage.util.ExtractKernelVersion:ExtractKernelVersion'
+)
+
+from portage import auxdbkeys, bsd_chflags, \
+ eapi_is_supported, merge, os, selinux, \
+ unmerge, _encodings, _parse_eapi_ebuild_head, _os_merge, \
+ _shell_quote, _unicode_decode, _unicode_encode
+from portage.const import EBUILD_SH_ENV_FILE, EBUILD_SH_ENV_DIR, \
+ EBUILD_SH_BINARY, INVALID_ENV_FILE, MISC_SH_BINARY
+from portage.data import portage_gid, portage_uid, secpass, \
+ uid, userpriv_groups
+from portage.dbapi.porttree import _parse_uri_map
+from portage.dep import Atom, check_required_use, \
+ human_readable_required_use, paren_enclose, use_reduce
+from portage.eapi import eapi_exports_KV, eapi_exports_merge_type, \
+ eapi_exports_replace_vars, eapi_has_required_use, \
+ eapi_has_src_prepare_and_src_configure, eapi_has_pkg_pretend
+from portage.elog import elog_process
+from portage.elog.messages import eerror, eqawarn
+from portage.exception import DigestException, FileNotFound, \
+ IncorrectParameter, InvalidDependString, PermissionDenied, \
+ UnsupportedAPIException
+from portage.localization import _
+from portage.manifest import Manifest
+from portage.output import style_to_ansi_code
+from portage.package.ebuild.prepare_build_dirs import prepare_build_dirs
+from portage.util import apply_recursive_permissions, \
+ apply_secpass_permissions, noiselimit, normalize_path, \
+ writemsg, writemsg_stdout, write_atomic
+from portage.util.lafilefixer import rewrite_lafile
+from portage.versions import _pkgsplit
+from _emerge.BinpkgEnvExtractor import BinpkgEnvExtractor
+from _emerge.EbuildBuildDir import EbuildBuildDir
+from _emerge.EbuildPhase import EbuildPhase
+from _emerge.EbuildSpawnProcess import EbuildSpawnProcess
+from _emerge.Package import Package
+from _emerge.PollScheduler import PollScheduler
+from _emerge.RootConfig import RootConfig
+
+_unsandboxed_phases = frozenset([
+ "clean", "cleanrm", "config",
+ "help", "info", "postinst",
+ "preinst", "pretend", "postrm",
+ "prerm", "setup"
+])
+
+def _doebuild_spawn(phase, settings, actionmap=None, **kwargs):
+ """
+ All proper ebuild phases which execute ebuild.sh are spawned
+ via this function. No exceptions.
+ """
+
+ if phase in _unsandboxed_phases:
+ kwargs['free'] = True
+
+ if phase == 'depend':
+ kwargs['droppriv'] = 'userpriv' in settings.features
+
+ if actionmap is not None and phase in actionmap:
+ kwargs.update(actionmap[phase]["args"])
+ cmd = actionmap[phase]["cmd"] % phase
+ else:
+ if phase == 'cleanrm':
+ ebuild_sh_arg = 'clean'
+ else:
+ ebuild_sh_arg = phase
+
+ cmd = "%s %s" % (_shell_quote(
+ os.path.join(settings["PORTAGE_BIN_PATH"],
+ os.path.basename(EBUILD_SH_BINARY))),
+ ebuild_sh_arg)
+
+ settings['EBUILD_PHASE'] = phase
+ try:
+ return spawn(cmd, settings, **kwargs)
+ finally:
+ settings.pop('EBUILD_PHASE', None)
+
+def _spawn_phase(phase, settings, actionmap=None, **kwargs):
+ if kwargs.get('returnpid'):
+ return _doebuild_spawn(phase, settings, actionmap=actionmap, **kwargs)
+
+ ebuild_phase = EbuildPhase(actionmap=actionmap, background=False,
+ phase=phase, scheduler=PollScheduler().sched_iface,
+ settings=settings)
+ ebuild_phase.start()
+ ebuild_phase.wait()
+ return ebuild_phase.returncode
+
+def doebuild_environment(myebuild, mydo, myroot=None, settings=None,
+ debug=False, use_cache=None, db=None):
+ """
+ Create and store environment variable in the config instance
+ that's passed in as the "settings" parameter. This will raise
+ UnsupportedAPIException if the given ebuild has an unsupported
+ EAPI. All EAPI dependent code comes last, so that essential
+ variables like PORTAGE_BUILDDIR are still initialized even in
+ cases when UnsupportedAPIException needs to be raised, which
+ can be useful when uninstalling a package that has corrupt
+ EAPI metadata.
+ The myroot and use_cache parameters are unused.
+ """
+ myroot = None
+ use_cache = None
+
+ if settings is None:
+ raise TypeError("settings argument is required")
+
+ if db is None:
+ raise TypeError("db argument is required")
+
+ mysettings = settings
+ mydbapi = db
+ ebuild_path = os.path.abspath(myebuild)
+ pkg_dir = os.path.dirname(ebuild_path)
+ mytree = os.path.dirname(os.path.dirname(pkg_dir))
+
+ if "CATEGORY" in mysettings.configdict["pkg"]:
+ cat = mysettings.configdict["pkg"]["CATEGORY"]
+ else:
+ cat = os.path.basename(normalize_path(os.path.join(pkg_dir, "..")))
+
+ mypv = os.path.basename(ebuild_path)[:-7]
+
+ mycpv = cat+"/"+mypv
+ mysplit = _pkgsplit(mypv)
+ if mysplit is None:
+ raise IncorrectParameter(
+ _("Invalid ebuild path: '%s'") % myebuild)
+
+ # Make a backup of PORTAGE_TMPDIR prior to calling config.reset()
+ # so that the caller can override it.
+ tmpdir = mysettings["PORTAGE_TMPDIR"]
+
+ if mydo == 'depend':
+ if mycpv != mysettings.mycpv:
+ # Don't pass in mydbapi here since the resulting aux_get
+ # call would lead to infinite 'depend' phase recursion.
+ mysettings.setcpv(mycpv)
+ else:
+ # If EAPI isn't in configdict["pkg"], it means that setcpv()
+ # hasn't been called with the mydb argument, so we have to
+ # call it here (portage code always calls setcpv properly,
+ # but api consumers might not).
+ if mycpv != mysettings.mycpv or \
+ "EAPI" not in mysettings.configdict["pkg"]:
+ # Reload env.d variables and reset any previous settings.
+ mysettings.reload()
+ mysettings.reset()
+ mysettings.setcpv(mycpv, mydb=mydbapi)
+
+ # config.reset() might have reverted a change made by the caller,
+ # so restore it to its original value. Sandbox needs canonical
+ # paths, so realpath it.
+ mysettings["PORTAGE_TMPDIR"] = os.path.realpath(tmpdir)
+
+ mysettings.pop("EBUILD_PHASE", None) # remove from backupenv
+ mysettings["EBUILD_PHASE"] = mydo
+
+ # Set requested Python interpreter for Portage helpers.
+ mysettings['PORTAGE_PYTHON'] = portage._python_interpreter
+
+ # This is used by assert_sigpipe_ok() that's used by the ebuild
+ # unpack() helper. SIGPIPE is typically 13, but its better not
+ # to assume that.
+ mysettings['PORTAGE_SIGPIPE_STATUS'] = str(128 + signal.SIGPIPE)
+
+ # We are disabling user-specific bashrc files.
+ mysettings["BASH_ENV"] = INVALID_ENV_FILE
+
+ if debug: # Otherwise it overrides emerge's settings.
+ # We have no other way to set debug... debug can't be passed in
+ # due to how it's coded... Don't overwrite this so we can use it.
+ mysettings["PORTAGE_DEBUG"] = "1"
+
+ mysettings["EBUILD"] = ebuild_path
+ mysettings["O"] = pkg_dir
+ mysettings.configdict["pkg"]["CATEGORY"] = cat
+ mysettings["FILESDIR"] = pkg_dir+"/files"
+ mysettings["PF"] = mypv
+
+ if hasattr(mydbapi, '_repo_info'):
+ repo_info = mydbapi._repo_info[mytree]
+ mysettings['PORTDIR'] = repo_info.portdir
+ mysettings['PORTDIR_OVERLAY'] = repo_info.portdir_overlay
+ mysettings.configdict["pkg"]["PORTAGE_REPO_NAME"] = repo_info.name
+
+ mysettings["PORTDIR"] = os.path.realpath(mysettings["PORTDIR"])
+ mysettings["DISTDIR"] = os.path.realpath(mysettings["DISTDIR"])
+ mysettings["RPMDIR"] = os.path.realpath(mysettings["RPMDIR"])
+
+ mysettings["ECLASSDIR"] = mysettings["PORTDIR"]+"/eclass"
+ mysettings["SANDBOX_LOG"] = mycpv.replace("/", "_-_")
+
+ mysettings["PROFILE_PATHS"] = "\n".join(mysettings.profiles)
+ mysettings["P"] = mysplit[0]+"-"+mysplit[1]
+ mysettings["PN"] = mysplit[0]
+ mysettings["PV"] = mysplit[1]
+ mysettings["PR"] = mysplit[2]
+
+ if noiselimit < 0:
+ mysettings["PORTAGE_QUIET"] = "1"
+
+ if mysplit[2] == "r0":
+ mysettings["PVR"]=mysplit[1]
+ else:
+ mysettings["PVR"]=mysplit[1]+"-"+mysplit[2]
+
+ if "PATH" in mysettings:
+ mysplit=mysettings["PATH"].split(":")
+ else:
+ mysplit=[]
+ # Note: PORTAGE_BIN_PATH may differ from the global constant
+ # when portage is reinstalling itself.
+ portage_bin_path = mysettings["PORTAGE_BIN_PATH"]
+ if portage_bin_path not in mysplit:
+ mysettings["PATH"] = portage_bin_path + ":" + mysettings["PATH"]
+
+ # All temporary directories should be subdirectories of
+ # $PORTAGE_TMPDIR/portage, since it's common for /tmp and /var/tmp
+ # to be mounted with the "noexec" option (see bug #346899).
+ mysettings["BUILD_PREFIX"] = mysettings["PORTAGE_TMPDIR"]+"/portage"
+ mysettings["PKG_TMPDIR"] = mysettings["BUILD_PREFIX"]+"/._unmerge_"
+
+ # Package {pre,post}inst and {pre,post}rm may overlap, so they must have separate
+ # locations in order to prevent interference.
+ if mydo in ("unmerge", "prerm", "postrm", "cleanrm"):
+ mysettings["PORTAGE_BUILDDIR"] = os.path.join(
+ mysettings["PKG_TMPDIR"],
+ mysettings["CATEGORY"], mysettings["PF"])
+ else:
+ mysettings["PORTAGE_BUILDDIR"] = os.path.join(
+ mysettings["BUILD_PREFIX"],
+ mysettings["CATEGORY"], mysettings["PF"])
+
+ mysettings["HOME"] = os.path.join(mysettings["PORTAGE_BUILDDIR"], "homedir")
+ mysettings["WORKDIR"] = os.path.join(mysettings["PORTAGE_BUILDDIR"], "work")
+ mysettings["D"] = os.path.join(mysettings["PORTAGE_BUILDDIR"], "image") + os.sep
+ mysettings["T"] = os.path.join(mysettings["PORTAGE_BUILDDIR"], "temp")
+
+ # Prefix forward compatability
+ mysettings["ED"] = mysettings["D"]
+
+ mysettings["PORTAGE_BASHRC"] = os.path.join(
+ mysettings["PORTAGE_CONFIGROOT"], EBUILD_SH_ENV_FILE)
+ mysettings["PM_EBUILD_HOOK_DIR"] = os.path.join(
+ mysettings["PORTAGE_CONFIGROOT"], EBUILD_SH_ENV_DIR)
+
+ # Allow color.map to control colors associated with einfo, ewarn, etc...
+ mycolors = []
+ for c in ("GOOD", "WARN", "BAD", "HILITE", "BRACKET"):
+ mycolors.append("%s=$'%s'" % \
+ (c, style_to_ansi_code(c)))
+ mysettings["PORTAGE_COLORMAP"] = "\n".join(mycolors)
+
+ # All EAPI dependent code comes last, so that essential variables
+ # like PORTAGE_BUILDDIR are still initialized even in cases when
+ # UnsupportedAPIException needs to be raised, which can be useful
+ # when uninstalling a package that has corrupt EAPI metadata.
+ eapi = None
+ if mydo == 'depend' and 'EAPI' not in mysettings.configdict['pkg']:
+ if eapi is None and 'parse-eapi-ebuild-head' in mysettings.features:
+ eapi = _parse_eapi_ebuild_head(
+ io.open(_unicode_encode(ebuild_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'], errors='replace'))
+
+ if eapi is not None:
+ if not eapi_is_supported(eapi):
+ raise UnsupportedAPIException(mycpv, eapi)
+ mysettings.configdict['pkg']['EAPI'] = eapi
+
+ if mydo != "depend":
+ # Metadata vars such as EAPI and RESTRICT are
+ # set by the above config.setcpv() call.
+ eapi = mysettings["EAPI"]
+ if not eapi_is_supported(eapi):
+ # can't do anything with this.
+ raise UnsupportedAPIException(mycpv, eapi)
+
+ if hasattr(mydbapi, "getFetchMap") and \
+ ("A" not in mysettings.configdict["pkg"] or \
+ "AA" not in mysettings.configdict["pkg"]):
+ src_uri, = mydbapi.aux_get(mysettings.mycpv,
+ ["SRC_URI"], mytree=mytree)
+ metadata = {
+ "EAPI" : eapi,
+ "SRC_URI" : src_uri,
+ }
+ use = frozenset(mysettings["PORTAGE_USE"].split())
+ try:
+ uri_map = _parse_uri_map(mysettings.mycpv, metadata, use=use)
+ except InvalidDependString:
+ mysettings.configdict["pkg"]["A"] = ""
+ else:
+ mysettings.configdict["pkg"]["A"] = " ".join(uri_map)
+
+ try:
+ uri_map = _parse_uri_map(mysettings.mycpv, metadata)
+ except InvalidDependString:
+ mysettings.configdict["pkg"]["AA"] = ""
+ else:
+ mysettings.configdict["pkg"]["AA"] = " ".join(uri_map)
+
+ if not eapi_exports_KV(eapi):
+ # Discard KV for EAPIs that don't support it. Cache KV is restored
+ # from the backupenv whenever config.reset() is called.
+ mysettings.pop('KV', None)
+ elif mydo != 'depend' and 'KV' not in mysettings and \
+ mydo in ('compile', 'config', 'configure', 'info',
+ 'install', 'nofetch', 'postinst', 'postrm', 'preinst',
+ 'prepare', 'prerm', 'setup', 'test', 'unpack'):
+ mykv, err1 = ExtractKernelVersion(
+ os.path.join(mysettings['EROOT'], "usr/src/linux"))
+ if mykv:
+ # Regular source tree
+ mysettings["KV"] = mykv
+ else:
+ mysettings["KV"] = ""
+ mysettings.backup_changes("KV")
+
+_doebuild_manifest_cache = None
+_doebuild_broken_ebuilds = set()
+_doebuild_broken_manifests = set()
+_doebuild_commands_without_builddir = (
+ 'clean', 'cleanrm', 'depend', 'digest',
+ 'fetch', 'fetchall', 'help', 'manifest'
+)
+
+def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
+ fetchonly=0, cleanup=0, dbkey=None, use_cache=1, fetchall=0, tree=None,
+ mydbapi=None, vartree=None, prev_mtimes=None,
+ fd_pipes=None, returnpid=False):
+ """
+ Wrapper function that invokes specific ebuild phases through the spawning
+ of ebuild.sh
+
+ @param myebuild: name of the ebuild to invoke the phase on (CPV)
+ @type myebuild: String
+ @param mydo: Phase to run
+ @type mydo: String
+ @param myroot: $ROOT (usually '/', see man make.conf)
+ @type myroot: String
+ @param mysettings: Portage Configuration
+ @type mysettings: instance of portage.config
+ @param debug: Turns on various debug information (eg, debug for spawn)
+ @type debug: Boolean
+ @param listonly: Used to wrap fetch(); passed such that fetch only lists files required.
+ @type listonly: Boolean
+ @param fetchonly: Used to wrap fetch(); passed such that files are only fetched (no other actions)
+ @type fetchonly: Boolean
+ @param cleanup: Passed to prepare_build_dirs (TODO: what does it do?)
+ @type cleanup: Boolean
+ @param dbkey: A file path where metadata generated by the 'depend' phase
+ will be written.
+ @type dbkey: String
+ @param use_cache: Enables the cache
+ @type use_cache: Boolean
+ @param fetchall: Used to wrap fetch(), fetches all URIs (even ones invalid due to USE conditionals)
+ @type fetchall: Boolean
+ @param tree: Which tree to use ('vartree','porttree','bintree', etc..), defaults to 'porttree'
+ @type tree: String
+ @param mydbapi: a dbapi instance to pass to various functions; this should be a portdbapi instance.
+ @type mydbapi: portdbapi instance
+ @param vartree: A instance of vartree; used for aux_get calls, defaults to db[myroot]['vartree']
+ @type vartree: vartree instance
+ @param prev_mtimes: A dict of { filename:mtime } keys used by merge() to do config_protection
+ @type prev_mtimes: dictionary
+ @param fd_pipes: A dict of mapping for pipes, { '0': stdin, '1': stdout }
+ for example.
+ @type fd_pipes: Dictionary
+ @param returnpid: Return a list of process IDs for a successful spawn, or
+ an integer value if spawn is unsuccessful. NOTE: This requires the
+ caller clean up all returned PIDs.
+ @type returnpid: Boolean
+ @rtype: Boolean
+ @returns:
+ 1. 0 for success
+ 2. 1 for error
+
+ Most errors have an accompanying error message.
+
+ listonly and fetchonly are only really necessary for operations involving 'fetch'
+ prev_mtimes are only necessary for merge operations.
+ Other variables may not be strictly required, many have defaults that are set inside of doebuild.
+
+ """
+
+ if not tree:
+ writemsg("Warning: tree not specified to doebuild\n")
+ tree = "porttree"
+
+ # chunked out deps for each phase, so that ebuild binary can use it
+ # to collapse targets down.
+ actionmap_deps={
+ "pretend" : [],
+ "setup": ["pretend"],
+ "unpack": ["setup"],
+ "prepare": ["unpack"],
+ "configure": ["prepare"],
+ "compile":["configure"],
+ "test": ["compile"],
+ "install":["test"],
+ "rpm": ["install"],
+ "package":["install"],
+ }
+
+ if mydbapi is None:
+ mydbapi = portage.db[myroot][tree].dbapi
+
+ if vartree is None and mydo in ("merge", "qmerge", "unmerge"):
+ vartree = portage.db[myroot]["vartree"]
+
+ features = mysettings.features
+
+ clean_phases = ("clean", "cleanrm")
+ validcommands = ["help","clean","prerm","postrm","cleanrm","preinst","postinst",
+ "config", "info", "setup", "depend", "pretend",
+ "fetch", "fetchall", "digest",
+ "unpack", "prepare", "configure", "compile", "test",
+ "install", "rpm", "qmerge", "merge",
+ "package","unmerge", "manifest"]
+
+ if mydo not in validcommands:
+ validcommands.sort()
+ writemsg("!!! doebuild: '%s' is not one of the following valid commands:" % mydo,
+ noiselevel=-1)
+ for vcount in range(len(validcommands)):
+ if vcount%6 == 0:
+ writemsg("\n!!! ", noiselevel=-1)
+ writemsg(validcommands[vcount].ljust(11), noiselevel=-1)
+ writemsg("\n", noiselevel=-1)
+ return 1
+
+ if returnpid and mydo != 'depend':
+ warnings.warn("portage.doebuild() called " + \
+ "with returnpid parameter enabled. This usage will " + \
+ "not be supported in the future.",
+ DeprecationWarning, stacklevel=2)
+
+ if mydo == "fetchall":
+ fetchall = 1
+ mydo = "fetch"
+
+ parallel_fetchonly = mydo in ("fetch", "fetchall") and \
+ "PORTAGE_PARALLEL_FETCHONLY" in mysettings
+
+ if mydo not in clean_phases and not os.path.exists(myebuild):
+ writemsg("!!! doebuild: %s not found for %s\n" % (myebuild, mydo),
+ noiselevel=-1)
+ return 1
+
+ global _doebuild_manifest_cache
+ mf = None
+ if "strict" in features and \
+ "digest" not in features and \
+ tree == "porttree" and \
+ mydo not in ("digest", "manifest", "help") and \
+ not portage._doebuild_manifest_exempt_depend:
+ # Always verify the ebuild checksums before executing it.
+ global _doebuild_broken_ebuilds
+
+ if myebuild in _doebuild_broken_ebuilds:
+ return 1
+
+ pkgdir = os.path.dirname(myebuild)
+ manifest_path = os.path.join(pkgdir, "Manifest")
+
+ # Avoid checking the same Manifest several times in a row during a
+ # regen with an empty cache.
+ if _doebuild_manifest_cache is None or \
+ _doebuild_manifest_cache.getFullname() != manifest_path:
+ _doebuild_manifest_cache = None
+ if not os.path.exists(manifest_path):
+ out = portage.output.EOutput()
+ out.eerror(_("Manifest not found for '%s'") % (myebuild,))
+ _doebuild_broken_ebuilds.add(myebuild)
+ return 1
+ mf = Manifest(pkgdir, mysettings["DISTDIR"])
+
+ else:
+ mf = _doebuild_manifest_cache
+
+ try:
+ mf.checkFileHashes("EBUILD", os.path.basename(myebuild))
+ except KeyError:
+ out = portage.output.EOutput()
+ out.eerror(_("Missing digest for '%s'") % (myebuild,))
+ _doebuild_broken_ebuilds.add(myebuild)
+ return 1
+ except FileNotFound:
+ out = portage.output.EOutput()
+ out.eerror(_("A file listed in the Manifest "
+ "could not be found: '%s'") % (myebuild,))
+ _doebuild_broken_ebuilds.add(myebuild)
+ return 1
+ except DigestException as e:
+ out = portage.output.EOutput()
+ out.eerror(_("Digest verification failed:"))
+ out.eerror("%s" % e.value[0])
+ out.eerror(_("Reason: %s") % e.value[1])
+ out.eerror(_("Got: %s") % e.value[2])
+ out.eerror(_("Expected: %s") % e.value[3])
+ _doebuild_broken_ebuilds.add(myebuild)
+ return 1
+
+ if mf.getFullname() in _doebuild_broken_manifests:
+ return 1
+
+ if mf is not _doebuild_manifest_cache:
+
+ # Make sure that all of the ebuilds are
+ # actually listed in the Manifest.
+ for f in os.listdir(pkgdir):
+ pf = None
+ if f[-7:] == '.ebuild':
+ pf = f[:-7]
+ if pf is not None and not mf.hasFile("EBUILD", f):
+ f = os.path.join(pkgdir, f)
+ if f not in _doebuild_broken_ebuilds:
+ out = portage.output.EOutput()
+ out.eerror(_("A file is not listed in the "
+ "Manifest: '%s'") % (f,))
+ _doebuild_broken_manifests.add(manifest_path)
+ return 1
+
+ # Only cache it if the above stray files test succeeds.
+ _doebuild_manifest_cache = mf
+
+ logfile=None
+ builddir_lock = None
+ tmpdir = None
+ tmpdir_orig = None
+
+ try:
+ if mydo in ("digest", "manifest", "help"):
+ # Temporarily exempt the depend phase from manifest checks, in case
+ # aux_get calls trigger cache generation.
+ portage._doebuild_manifest_exempt_depend += 1
+
+ # If we don't need much space and we don't need a constant location,
+ # we can temporarily override PORTAGE_TMPDIR with a random temp dir
+ # so that there's no need for locking and it can be used even if the
+ # user isn't in the portage group.
+ if mydo in ("info",):
+ tmpdir = tempfile.mkdtemp()
+ tmpdir_orig = mysettings["PORTAGE_TMPDIR"]
+ mysettings["PORTAGE_TMPDIR"] = tmpdir
+
+ doebuild_environment(myebuild, mydo, myroot, mysettings, debug,
+ use_cache, mydbapi)
+
+ if mydo in clean_phases:
+ builddir_lock = None
+ if not returnpid and \
+ 'PORTAGE_BUILDIR_LOCKED' not in mysettings:
+ builddir_lock = EbuildBuildDir(
+ scheduler=PollScheduler().sched_iface,
+ settings=mysettings)
+ builddir_lock.lock()
+ try:
+ return _spawn_phase(mydo, mysettings,
+ fd_pipes=fd_pipes, returnpid=returnpid)
+ finally:
+ if builddir_lock is not None:
+ builddir_lock.unlock()
+
+ restrict = set(mysettings.get('PORTAGE_RESTRICT', '').split())
+ # get possible slot information from the deps file
+ if mydo == "depend":
+ writemsg("!!! DEBUG: dbkey: %s\n" % str(dbkey), 2)
+ if returnpid:
+ return _spawn_phase(mydo, mysettings,
+ fd_pipes=fd_pipes, returnpid=returnpid)
+ elif isinstance(dbkey, dict):
+ warnings.warn("portage.doebuild() called " + \
+ "with dict dbkey argument. This usage will " + \
+ "not be supported in the future.",
+ DeprecationWarning, stacklevel=2)
+ mysettings["dbkey"] = ""
+ pr, pw = os.pipe()
+ fd_pipes = {
+ 0:sys.stdin.fileno(),
+ 1:sys.stdout.fileno(),
+ 2:sys.stderr.fileno(),
+ 9:pw}
+ mypids = _spawn_phase(mydo, mysettings, returnpid=True,
+ fd_pipes=fd_pipes)
+ os.close(pw) # belongs exclusively to the child process now
+ f = os.fdopen(pr, 'rb', 0)
+ for k, v in zip(auxdbkeys,
+ (_unicode_decode(line).rstrip('\n') for line in f)):
+ dbkey[k] = v
+ f.close()
+ retval = os.waitpid(mypids[0], 0)[1]
+ portage.process.spawned_pids.remove(mypids[0])
+ # If it got a signal, return the signal that was sent, but
+ # shift in order to distinguish it from a return value. (just
+ # like portage.process.spawn() would do).
+ if retval & 0xff:
+ retval = (retval & 0xff) << 8
+ else:
+ # Otherwise, return its exit code.
+ retval = retval >> 8
+ if retval == os.EX_OK and len(dbkey) != len(auxdbkeys):
+ # Don't trust bash's returncode if the
+ # number of lines is incorrect.
+ retval = 1
+ return retval
+ elif dbkey:
+ mysettings["dbkey"] = dbkey
+ else:
+ mysettings["dbkey"] = \
+ os.path.join(mysettings.depcachedir, "aux_db_key_temp")
+
+ return _spawn_phase(mydo, mysettings,
+ fd_pipes=fd_pipes, returnpid=returnpid)
+
+ # Validate dependency metadata here to ensure that ebuilds with invalid
+ # data are never installed via the ebuild command. Don't bother when
+ # returnpid == True since there's no need to do this every time emerge
+ # executes a phase.
+ if tree == "porttree":
+ rval = _validate_deps(mysettings, myroot, mydo, mydbapi)
+ if rval != os.EX_OK:
+ return rval
+
+ # The info phase is special because it uses mkdtemp so and
+ # user (not necessarily in the portage group) can run it.
+ if mydo not in ('info',) and \
+ mydo not in _doebuild_commands_without_builddir:
+ rval = _check_temp_dir(mysettings)
+ if rval != os.EX_OK:
+ return rval
+
+ if mydo == "unmerge":
+ return unmerge(mysettings["CATEGORY"],
+ mysettings["PF"], myroot, mysettings, vartree=vartree)
+
+ # Build directory creation isn't required for any of these.
+ # In the fetch phase, the directory is needed only for RESTRICT=fetch
+ # in order to satisfy the sane $PWD requirement (from bug #239560)
+ # when pkg_nofetch is spawned.
+ have_build_dirs = False
+ if not parallel_fetchonly and \
+ mydo not in ('digest', 'fetch', 'help', 'manifest'):
+ if not returnpid and \
+ 'PORTAGE_BUILDIR_LOCKED' not in mysettings:
+ builddir_lock = EbuildBuildDir(
+ scheduler=PollScheduler().sched_iface,
+ settings=mysettings)
+ builddir_lock.lock()
+ mystatus = prepare_build_dirs(myroot, mysettings, cleanup)
+ if mystatus:
+ return mystatus
+ have_build_dirs = True
+
+ # emerge handles logging externally
+ if not returnpid:
+ # PORTAGE_LOG_FILE is set by the
+ # above prepare_build_dirs() call.
+ logfile = mysettings.get("PORTAGE_LOG_FILE")
+
+ if have_build_dirs:
+ rval = _prepare_env_file(mysettings)
+ if rval != os.EX_OK:
+ return rval
+
+ if eapi_exports_merge_type(mysettings["EAPI"]) and \
+ "MERGE_TYPE" not in mysettings.configdict["pkg"]:
+ if tree == "porttree":
+ mysettings.configdict["pkg"]["EMERGE_FROM"] = "ebuild"
+ mysettings.configdict["pkg"]["MERGE_TYPE"] = "source"
+ elif tree == "bintree":
+ mysettings.configdict["pkg"]["EMERGE_FROM"] = "binary"
+ mysettings.configdict["pkg"]["MERGE_TYPE"] = "binary"
+
+ # NOTE: It's not possible to set REPLACED_BY_VERSION for prerm
+ # and postrm here, since we don't necessarily know what
+ # versions are being installed. This could be a problem
+ # for API consumers if they don't use dblink.treewalk()
+ # to execute prerm and postrm.
+ if eapi_exports_replace_vars(mysettings["EAPI"]) and \
+ (mydo in ("postinst", "preinst", "pretend", "setup") or \
+ ("noauto" not in features and not returnpid and \
+ (mydo in actionmap_deps or mydo in ("merge", "package", "qmerge")))):
+ if not vartree:
+ writemsg("Warning: vartree not given to doebuild. " + \
+ "Cannot set REPLACING_VERSIONS in pkg_{pretend,setup}\n")
+ else:
+ vardb = vartree.dbapi
+ cpv = mysettings.mycpv
+ cp = portage.versions.cpv_getkey(cpv)
+ slot = mysettings["SLOT"]
+ cpv_slot = cp + ":" + slot
+ mysettings["REPLACING_VERSIONS"] = " ".join(
+ set(portage.versions.cpv_getversion(match) \
+ for match in vardb.match(cpv_slot) + \
+ vardb.match('='+cpv)))
+
+ # if any of these are being called, handle them -- running them out of
+ # the sandbox -- and stop now.
+ if mydo in ("config", "help", "info", "postinst",
+ "preinst", "pretend", "postrm", "prerm"):
+ return _spawn_phase(mydo, mysettings,
+ fd_pipes=fd_pipes, logfile=logfile, returnpid=returnpid)
+
+ mycpv = "/".join((mysettings["CATEGORY"], mysettings["PF"]))
+
+ # Only try and fetch the files if we are going to need them ...
+ # otherwise, if user has FEATURES=noauto and they run `ebuild clean
+ # unpack compile install`, we will try and fetch 4 times :/
+ need_distfiles = tree == "porttree" and \
+ (mydo in ("fetch", "unpack") or \
+ mydo not in ("digest", "manifest") and "noauto" not in features)
+ alist = set(mysettings.configdict["pkg"].get("A", "").split())
+ if need_distfiles:
+
+ src_uri, = mydbapi.aux_get(mysettings.mycpv,
+ ["SRC_URI"], mytree=os.path.dirname(os.path.dirname(
+ os.path.dirname(myebuild))))
+ metadata = {
+ "EAPI" : mysettings["EAPI"],
+ "SRC_URI" : src_uri,
+ }
+ use = frozenset(mysettings["PORTAGE_USE"].split())
+ try:
+ alist = _parse_uri_map(mysettings.mycpv, metadata, use=use)
+ aalist = _parse_uri_map(mysettings.mycpv, metadata)
+ except InvalidDependString as e:
+ writemsg("!!! %s\n" % str(e), noiselevel=-1)
+ writemsg(_("!!! Invalid SRC_URI for '%s'.\n") % mycpv,
+ noiselevel=-1)
+ del e
+ return 1
+
+ if "mirror" in features or fetchall:
+ fetchme = aalist
+ else:
+ fetchme = alist
+
+ dist_digests = None
+ if mf is not None:
+ dist_digests = mf.getTypeDigests("DIST")
+ if not fetch(fetchme, mysettings, listonly=listonly,
+ fetchonly=fetchonly, allow_missing_digests=True,
+ digests=dist_digests):
+ spawn_nofetch(mydbapi, myebuild, settings=mysettings)
+ if listonly:
+ # The convention for listonly mode is to report
+ # success in any case, even though fetch() may
+ # return unsuccessfully in order to trigger the
+ # nofetch phase.
+ return 0
+ return 1
+
+ if mydo == "fetch":
+ # Files are already checked inside fetch(),
+ # so do not check them again.
+ checkme = []
+ else:
+ checkme = alist
+
+ if mydo == "fetch" and listonly:
+ return 0
+
+ try:
+ if mydo == "manifest":
+ mf = None
+ _doebuild_manifest_cache = None
+ return not digestgen(mysettings=mysettings, myportdb=mydbapi)
+ elif mydo == "digest":
+ mf = None
+ _doebuild_manifest_cache = None
+ return not digestgen(mysettings=mysettings, myportdb=mydbapi)
+ elif mydo != 'fetch' and \
+ "digest" in mysettings.features:
+ # Don't do this when called by emerge or when called just
+ # for fetch (especially parallel-fetch) since it's not needed
+ # and it can interfere with parallel tasks.
+ mf = None
+ _doebuild_manifest_cache = None
+ digestgen(mysettings=mysettings, myportdb=mydbapi)
+ except PermissionDenied as e:
+ writemsg(_("!!! Permission Denied: %s\n") % (e,), noiselevel=-1)
+ if mydo in ("digest", "manifest"):
+ return 1
+
+ # See above comment about fetching only when needed
+ if tree == 'porttree' and \
+ not digestcheck(checkme, mysettings, "strict" in features, mf=mf):
+ return 1
+
+ if mydo == "fetch":
+ return 0
+
+ # remove PORTAGE_ACTUAL_DISTDIR once cvs/svn is supported via SRC_URI
+ if tree == 'porttree' and \
+ ((mydo != "setup" and "noauto" not in features) \
+ or mydo in ("install", "unpack")):
+ _prepare_fake_distdir(mysettings, alist)
+
+ #initial dep checks complete; time to process main commands
+ actionmap = _spawn_actionmap(mysettings)
+
+ # merge the deps in so we have again a 'full' actionmap
+ # be glad when this can die.
+ for x in actionmap:
+ if len(actionmap_deps.get(x, [])):
+ actionmap[x]["dep"] = ' '.join(actionmap_deps[x])
+
+ if mydo in actionmap:
+ bintree = None
+ if mydo == "package":
+ # Make sure the package directory exists before executing
+ # this phase. This can raise PermissionDenied if
+ # the current user doesn't have write access to $PKGDIR.
+ if hasattr(portage, 'db'):
+ bintree = portage.db[mysettings["ROOT"]]["bintree"]
+ mysettings["PORTAGE_BINPKG_TMPFILE"] = \
+ bintree.getname(mysettings.mycpv) + \
+ ".%s" % (os.getpid(),)
+ bintree._ensure_dir(os.path.dirname(
+ mysettings["PORTAGE_BINPKG_TMPFILE"]))
+ else:
+ parent_dir = os.path.join(mysettings["PKGDIR"],
+ mysettings["CATEGORY"])
+ portage.util.ensure_dirs(parent_dir)
+ if not os.access(parent_dir, os.W_OK):
+ raise PermissionDenied(
+ "access('%s', os.W_OK)" % parent_dir)
+ retval = spawnebuild(mydo,
+ actionmap, mysettings, debug, logfile=logfile,
+ fd_pipes=fd_pipes, returnpid=returnpid)
+
+ if retval == os.EX_OK:
+ if mydo == "package" and bintree is not None:
+ bintree.inject(mysettings.mycpv,
+ filename=mysettings["PORTAGE_BINPKG_TMPFILE"])
+ elif mydo=="qmerge":
+ # check to ensure install was run. this *only* pops up when users
+ # forget it and are using ebuild
+ if not os.path.exists(
+ os.path.join(mysettings["PORTAGE_BUILDDIR"], ".installed")):
+ writemsg(_("!!! mydo=qmerge, but the install phase has not been run\n"),
+ noiselevel=-1)
+ return 1
+ # qmerge is a special phase that implies noclean.
+ if "noclean" not in mysettings.features:
+ mysettings.features.add("noclean")
+ #qmerge is specifically not supposed to do a runtime dep check
+ retval = merge(
+ mysettings["CATEGORY"], mysettings["PF"], mysettings["D"],
+ os.path.join(mysettings["PORTAGE_BUILDDIR"], "build-info"),
+ myroot, mysettings, myebuild=mysettings["EBUILD"], mytree=tree,
+ mydbapi=mydbapi, vartree=vartree, prev_mtimes=prev_mtimes)
+ elif mydo=="merge":
+ retval = spawnebuild("install", actionmap, mysettings, debug,
+ alwaysdep=1, logfile=logfile, fd_pipes=fd_pipes,
+ returnpid=returnpid)
+ if retval != os.EX_OK:
+ # The merge phase handles this already. Callers don't know how
+ # far this function got, so we have to call elog_process() here
+ # so that it's only called once.
+ elog_process(mysettings.mycpv, mysettings)
+ if retval == os.EX_OK:
+ retval = merge(mysettings["CATEGORY"], mysettings["PF"],
+ mysettings["D"], os.path.join(mysettings["PORTAGE_BUILDDIR"],
+ "build-info"), myroot, mysettings,
+ myebuild=mysettings["EBUILD"], mytree=tree, mydbapi=mydbapi,
+ vartree=vartree, prev_mtimes=prev_mtimes)
+ else:
+ writemsg_stdout(_("!!! Unknown mydo: %s\n") % mydo, noiselevel=-1)
+ return 1
+
+ return retval
+
+ finally:
+
+ if builddir_lock is not None:
+ builddir_lock.unlock()
+ if tmpdir:
+ mysettings["PORTAGE_TMPDIR"] = tmpdir_orig
+ shutil.rmtree(tmpdir)
+
+ mysettings.pop("REPLACING_VERSIONS", None)
+
+ # Make sure that DISTDIR is restored to it's normal value before we return!
+ if "PORTAGE_ACTUAL_DISTDIR" in mysettings:
+ mysettings["DISTDIR"] = mysettings["PORTAGE_ACTUAL_DISTDIR"]
+ del mysettings["PORTAGE_ACTUAL_DISTDIR"]
+
+ if logfile and not returnpid:
+ try:
+ if os.stat(logfile).st_size == 0:
+ os.unlink(logfile)
+ except OSError:
+ pass
+
+ if mydo in ("digest", "manifest", "help"):
+ # If necessary, depend phase has been triggered by aux_get calls
+ # and the exemption is no longer needed.
+ portage._doebuild_manifest_exempt_depend -= 1
+
+def _check_temp_dir(settings):
+ if "PORTAGE_TMPDIR" not in settings or \
+ not os.path.isdir(settings["PORTAGE_TMPDIR"]):
+ writemsg(_("The directory specified in your "
+ "PORTAGE_TMPDIR variable, '%s',\n"
+ "does not exist. Please create this directory or "
+ "correct your PORTAGE_TMPDIR setting.\n") % \
+ settings.get("PORTAGE_TMPDIR", ""), noiselevel=-1)
+ return 1
+
+ # as some people use a separate PORTAGE_TMPDIR mount
+ # we prefer that as the checks below would otherwise be pointless
+ # for those people.
+ if os.path.exists(os.path.join(settings["PORTAGE_TMPDIR"], "portage")):
+ checkdir = os.path.join(settings["PORTAGE_TMPDIR"], "portage")
+ else:
+ checkdir = settings["PORTAGE_TMPDIR"]
+
+ if not os.access(checkdir, os.W_OK):
+ writemsg(_("%s is not writable.\n"
+ "Likely cause is that you've mounted it as readonly.\n") % checkdir,
+ noiselevel=-1)
+ return 1
+
+ else:
+ fd = tempfile.NamedTemporaryFile(prefix="exectest-", dir=checkdir)
+ os.chmod(fd.name, 0o755)
+ if not os.access(fd.name, os.X_OK):
+ writemsg(_("Can not execute files in %s\n"
+ "Likely cause is that you've mounted it with one of the\n"
+ "following mount options: 'noexec', 'user', 'users'\n\n"
+ "Please make sure that portage can execute files in this directory.\n") % checkdir,
+ noiselevel=-1)
+ return 1
+
+ return os.EX_OK
+
+def _prepare_env_file(settings):
+ """
+ Extract environment.bz2 if it exists, but only if the destination
+ environment file doesn't already exist. There are lots of possible
+ states when doebuild() calls this function, and we want to avoid
+ clobbering an existing environment file.
+ """
+
+ env_extractor = BinpkgEnvExtractor(background=False,
+ scheduler=PollScheduler().sched_iface, settings=settings)
+
+ if env_extractor.dest_env_exists():
+ # There are lots of possible states when doebuild()
+ # calls this function, and we want to avoid
+ # clobbering an existing environment file.
+ return os.EX_OK
+
+ if not env_extractor.saved_env_exists():
+ # If the environment.bz2 doesn't exist, then ebuild.sh will
+ # source the ebuild as a fallback.
+ return os.EX_OK
+
+ env_extractor.start()
+ env_extractor.wait()
+ return env_extractor.returncode
+
+def _prepare_fake_distdir(settings, alist):
+ orig_distdir = settings["DISTDIR"]
+ settings["PORTAGE_ACTUAL_DISTDIR"] = orig_distdir
+ edpath = settings["DISTDIR"] = \
+ os.path.join(settings["PORTAGE_BUILDDIR"], "distdir")
+ portage.util.ensure_dirs(edpath, gid=portage_gid, mode=0o755)
+
+ # Remove any unexpected files or directories.
+ for x in os.listdir(edpath):
+ symlink_path = os.path.join(edpath, x)
+ st = os.lstat(symlink_path)
+ if x in alist and stat.S_ISLNK(st.st_mode):
+ continue
+ if stat.S_ISDIR(st.st_mode):
+ shutil.rmtree(symlink_path)
+ else:
+ os.unlink(symlink_path)
+
+ # Check for existing symlinks and recreate if necessary.
+ for x in alist:
+ symlink_path = os.path.join(edpath, x)
+ target = os.path.join(orig_distdir, x)
+ try:
+ link_target = os.readlink(symlink_path)
+ except OSError:
+ os.symlink(target, symlink_path)
+ else:
+ if link_target != target:
+ os.unlink(symlink_path)
+ os.symlink(target, symlink_path)
+
+def _spawn_actionmap(settings):
+ features = settings.features
+ restrict = settings["PORTAGE_RESTRICT"].split()
+ nosandbox = (("userpriv" in features) and \
+ ("usersandbox" not in features) and \
+ "userpriv" not in restrict and \
+ "nouserpriv" not in restrict)
+ if nosandbox and ("userpriv" not in features or \
+ "userpriv" in restrict or \
+ "nouserpriv" in restrict):
+ nosandbox = ("sandbox" not in features and \
+ "usersandbox" not in features)
+
+ if "depcheck" in features or "depcheckstrict" in features:
+ nosandbox = True
+
+ if not portage.process.sandbox_capable:
+ nosandbox = True
+
+ sesandbox = settings.selinux_enabled() and \
+ "sesandbox" in features
+
+ droppriv = "userpriv" in features and \
+ "userpriv" not in restrict and \
+ secpass >= 2
+
+ fakeroot = "fakeroot" in features
+
+ portage_bin_path = settings["PORTAGE_BIN_PATH"]
+ ebuild_sh_binary = os.path.join(portage_bin_path,
+ os.path.basename(EBUILD_SH_BINARY))
+ misc_sh_binary = os.path.join(portage_bin_path,
+ os.path.basename(MISC_SH_BINARY))
+ ebuild_sh = _shell_quote(ebuild_sh_binary) + " %s"
+ misc_sh = _shell_quote(misc_sh_binary) + " dyn_%s"
+
+ # args are for the to spawn function
+ actionmap = {
+"pretend": {"cmd":ebuild_sh, "args":{"droppriv":0, "free":1, "sesandbox":0, "fakeroot":0}},
+"setup": {"cmd":ebuild_sh, "args":{"droppriv":0, "free":1, "sesandbox":0, "fakeroot":0}},
+"unpack": {"cmd":ebuild_sh, "args":{"droppriv":droppriv, "free":0, "sesandbox":sesandbox, "fakeroot":0}},
+"prepare": {"cmd":ebuild_sh, "args":{"droppriv":droppriv, "free":0, "sesandbox":sesandbox, "fakeroot":0}},
+"configure":{"cmd":ebuild_sh, "args":{"droppriv":droppriv, "free":nosandbox, "sesandbox":sesandbox, "fakeroot":0}},
+"compile": {"cmd":ebuild_sh, "args":{"droppriv":droppriv, "free":nosandbox, "sesandbox":sesandbox, "fakeroot":0}},
+"test": {"cmd":ebuild_sh, "args":{"droppriv":droppriv, "free":nosandbox, "sesandbox":sesandbox, "fakeroot":0}},
+"install": {"cmd":ebuild_sh, "args":{"droppriv":0, "free":0, "sesandbox":sesandbox, "fakeroot":fakeroot}},
+"rpm": {"cmd":misc_sh, "args":{"droppriv":0, "free":0, "sesandbox":0, "fakeroot":fakeroot}},
+"package": {"cmd":misc_sh, "args":{"droppriv":0, "free":0, "sesandbox":0, "fakeroot":fakeroot}},
+ }
+
+ return actionmap
+
+def _validate_deps(mysettings, myroot, mydo, mydbapi):
+
+ invalid_dep_exempt_phases = \
+ set(["clean", "cleanrm", "help", "prerm", "postrm"])
+ all_keys = set(Package.metadata_keys)
+ all_keys.add("SRC_URI")
+ all_keys = tuple(all_keys)
+ metadata = dict(zip(all_keys,
+ mydbapi.aux_get(mysettings.mycpv, all_keys)))
+
+ class FakeTree(object):
+ def __init__(self, mydb):
+ self.dbapi = mydb
+
+ root_config = RootConfig(mysettings, {"porttree":FakeTree(mydbapi)}, None)
+
+ pkg = Package(built=False, cpv=mysettings.mycpv,
+ metadata=metadata, root_config=root_config,
+ type_name="ebuild")
+
+ msgs = []
+ if pkg.invalid:
+ for k, v in pkg.invalid.items():
+ for msg in v:
+ msgs.append(" %s\n" % (msg,))
+
+ if msgs:
+ portage.util.writemsg_level(_("Error(s) in metadata for '%s':\n") % \
+ (mysettings.mycpv,), level=logging.ERROR, noiselevel=-1)
+ for x in msgs:
+ portage.util.writemsg_level(x,
+ level=logging.ERROR, noiselevel=-1)
+ if mydo not in invalid_dep_exempt_phases:
+ return 1
+
+ if not pkg.built and \
+ mydo not in ("digest", "help", "manifest") and \
+ pkg.metadata["REQUIRED_USE"] and \
+ eapi_has_required_use(pkg.metadata["EAPI"]):
+ result = check_required_use(pkg.metadata["REQUIRED_USE"],
+ pkg.use.enabled, pkg.iuse.is_valid_flag)
+ if not result:
+ reduced_noise = result.tounicode()
+ writemsg("\n %s\n" % _("The following REQUIRED_USE flag" + \
+ " constraints are unsatisfied:"), noiselevel=-1)
+ writemsg(" %s\n" % reduced_noise,
+ noiselevel=-1)
+ normalized_required_use = \
+ " ".join(pkg.metadata["REQUIRED_USE"].split())
+ if reduced_noise != normalized_required_use:
+ writemsg("\n %s\n" % _("The above constraints " + \
+ "are a subset of the following complete expression:"),
+ noiselevel=-1)
+ writemsg(" %s\n" % \
+ human_readable_required_use(normalized_required_use),
+ noiselevel=-1)
+ writemsg("\n", noiselevel=-1)
+ return 1
+
+ return os.EX_OK
+
+# XXX This would be to replace getstatusoutput completely.
+# XXX Issue: cannot block execution. Deadlock condition.
+def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakeroot=0, **keywords):
+ """
+ Spawn a subprocess with extra portage-specific options.
+ Optiosn include:
+
+ Sandbox: Sandbox means the spawned process will be limited in its ability t
+ read and write files (normally this means it is restricted to ${D}/)
+ SElinux Sandbox: Enables sandboxing on SElinux
+ Reduced Privileges: Drops privilages such that the process runs as portage:portage
+ instead of as root.
+
+ Notes: os.system cannot be used because it messes with signal handling. Instead we
+ use the portage.process spawn* family of functions.
+
+ This function waits for the process to terminate.
+
+ @param mystring: Command to run
+ @type mystring: String
+ @param mysettings: Either a Dict of Key,Value pairs or an instance of portage.config
+ @type mysettings: Dictionary or config instance
+ @param debug: Ignored
+ @type debug: Boolean
+ @param free: Enable sandboxing for this process
+ @type free: Boolean
+ @param droppriv: Drop to portage:portage when running this command
+ @type droppriv: Boolean
+ @param sesandbox: Enable SELinux Sandboxing (toggles a context switch)
+ @type sesandbox: Boolean
+ @param fakeroot: Run this command with faked root privileges
+ @type fakeroot: Boolean
+ @param keywords: Extra options encoded as a dict, to be passed to spawn
+ @type keywords: Dictionary
+ @rtype: Integer
+ @returns:
+ 1. The return code of the spawned process.
+ """
+
+ check_config_instance(mysettings)
+
+ fd_pipes = keywords.get("fd_pipes")
+ if fd_pipes is None:
+ fd_pipes = {
+ 0:sys.stdin.fileno(),
+ 1:sys.stdout.fileno(),
+ 2:sys.stderr.fileno(),
+ }
+ # In some cases the above print statements don't flush stdout, so
+ # it needs to be flushed before allowing a child process to use it
+ # so that output always shows in the correct order.
+ stdout_filenos = (sys.stdout.fileno(), sys.stderr.fileno())
+ for fd in fd_pipes.values():
+ if fd in stdout_filenos:
+ sys.stdout.flush()
+ sys.stderr.flush()
+ break
+
+ features = mysettings.features
+ # TODO: Enable fakeroot to be used together with droppriv. The
+ # fake ownership/permissions will have to be converted to real
+ # permissions in the merge phase.
+ fakeroot = fakeroot and uid != 0 and portage.process.fakeroot_capable
+ if droppriv and not uid and portage_gid and portage_uid:
+ keywords.update({"uid":portage_uid,"gid":portage_gid,
+ "groups":userpriv_groups,"umask":0o02})
+ if not free:
+ free=((droppriv and "usersandbox" not in features) or \
+ (not droppriv and "sandbox" not in features and \
+ "usersandbox" not in features and not fakeroot))
+
+ if not free and not (fakeroot or portage.process.sandbox_capable):
+ free = True
+
+ if mysettings.mycpv is not None:
+ keywords["opt_name"] = "[%s]" % mysettings.mycpv
+ else:
+ keywords["opt_name"] = "[%s/%s]" % \
+ (mysettings.get("CATEGORY",""), mysettings.get("PF",""))
+
+ if "depcheck" in features or "depcheckstrict" in features:
+ keywords["opt_name"] += " bash"
+ spawn_func = portage.process.spawn_autodep
+ elif free or "SANDBOX_ACTIVE" in os.environ:
+ keywords["opt_name"] += " bash"
+ spawn_func = portage.process.spawn_bash
+ elif fakeroot:
+ keywords["opt_name"] += " fakeroot"
+ keywords["fakeroot_state"] = os.path.join(mysettings["T"], "fakeroot.state")
+ spawn_func = portage.process.spawn_fakeroot
+ else:
+ keywords["opt_name"] += " sandbox"
+ spawn_func = portage.process.spawn_sandbox
+
+ if sesandbox:
+ spawn_func = selinux.spawn_wrapper(spawn_func,
+ mysettings["PORTAGE_SANDBOX_T"])
+
+ if keywords.get("returnpid"):
+ return spawn_func(mystring, env=mysettings.environ(), **keywords)
+
+ proc = EbuildSpawnProcess(
+ background=False, args=mystring,
+ scheduler=PollScheduler().sched_iface, spawn_func=spawn_func,
+ settings=mysettings, **keywords)
+
+ proc.start()
+ proc.wait()
+
+ return proc.returncode
+
+# parse actionmap to spawn ebuild with the appropriate args
+def spawnebuild(mydo, actionmap, mysettings, debug, alwaysdep=0,
+ logfile=None, fd_pipes=None, returnpid=False):
+
+ if returnpid:
+ warnings.warn("portage.spawnebuild() called " + \
+ "with returnpid parameter enabled. This usage will " + \
+ "not be supported in the future.",
+ DeprecationWarning, stacklevel=2)
+
+ if not returnpid and \
+ (alwaysdep or "noauto" not in mysettings.features):
+ # process dependency first
+ if "dep" in actionmap[mydo]:
+ retval = spawnebuild(actionmap[mydo]["dep"], actionmap,
+ mysettings, debug, alwaysdep=alwaysdep, logfile=logfile,
+ fd_pipes=fd_pipes, returnpid=returnpid)
+ if retval:
+ return retval
+
+ eapi = mysettings["EAPI"]
+
+ if mydo in ("configure", "prepare") and not eapi_has_src_prepare_and_src_configure(eapi):
+ return os.EX_OK
+
+ if mydo == "pretend" and not eapi_has_pkg_pretend(eapi):
+ return os.EX_OK
+
+ return _spawn_phase(mydo, mysettings,
+ actionmap=actionmap, logfile=logfile,
+ fd_pipes=fd_pipes, returnpid=returnpid)
+
+_post_phase_cmds = {
+
+ "install" : [
+ "install_qa_check",
+ "install_symlink_html_docs"],
+
+ "preinst" : [
+ "preinst_sfperms",
+ "preinst_selinux_labels",
+ "preinst_suid_scan",
+ "preinst_mask"]
+}
+
+def _post_phase_userpriv_perms(mysettings):
+ if "userpriv" in mysettings.features and secpass >= 2:
+ """ Privileged phases may have left files that need to be made
+ writable to a less privileged user."""
+ apply_recursive_permissions(mysettings["T"],
+ uid=portage_uid, gid=portage_gid, dirmode=0o70, dirmask=0,
+ filemode=0o60, filemask=0)
+
+def _check_build_log(mysettings, out=None):
+ """
+ Search the content of $PORTAGE_LOG_FILE if it exists
+ and generate the following QA Notices when appropriate:
+
+ * Automake "maintainer mode"
+ * command not found
+ * Unrecognized configure options
+ """
+ logfile = mysettings.get("PORTAGE_LOG_FILE")
+ if logfile is None:
+ return
+ try:
+ f = open(_unicode_encode(logfile, encoding=_encodings['fs'],
+ errors='strict'), mode='rb')
+ except EnvironmentError:
+ return
+
+ if logfile.endswith('.gz'):
+ f = gzip.GzipFile(filename='', mode='rb', fileobj=f)
+
+ am_maintainer_mode = []
+ bash_command_not_found = []
+ bash_command_not_found_re = re.compile(
+ r'(.*): line (\d*): (.*): command not found$')
+ command_not_found_exclude_re = re.compile(r'/configure: line ')
+ helper_missing_file = []
+ helper_missing_file_re = re.compile(
+ r'^!!! (do|new).*: .* does not exist$')
+
+ configure_opts_warn = []
+ configure_opts_warn_re = re.compile(
+ r'^configure: WARNING: [Uu]nrecognized options: ')
+
+ # Exclude output from dev-libs/yaz-3.0.47 which looks like this:
+ #
+ #Configuration:
+ # Automake: ${SHELL} /var/tmp/portage/dev-libs/yaz-3.0.47/work/yaz-3.0.47/config/missing --run automake-1.10
+ am_maintainer_mode_re = re.compile(r'/missing --run ')
+ am_maintainer_mode_exclude_re = \
+ re.compile(r'(/missing --run (autoheader|autotest|help2man|makeinfo)|^\s*Automake:\s)')
+
+ make_jobserver_re = \
+ re.compile(r'g?make\[\d+\]: warning: jobserver unavailable:')
+ make_jobserver = []
+
+ def _eerror(lines):
+ for line in lines:
+ eerror(line, phase="install", key=mysettings.mycpv, out=out)
+
+ try:
+ for line in f:
+ line = _unicode_decode(line)
+ if am_maintainer_mode_re.search(line) is not None and \
+ am_maintainer_mode_exclude_re.search(line) is None:
+ am_maintainer_mode.append(line.rstrip("\n"))
+
+ if bash_command_not_found_re.match(line) is not None and \
+ command_not_found_exclude_re.search(line) is None:
+ bash_command_not_found.append(line.rstrip("\n"))
+
+ if helper_missing_file_re.match(line) is not None:
+ helper_missing_file.append(line.rstrip("\n"))
+
+ if configure_opts_warn_re.match(line) is not None:
+ configure_opts_warn.append(line.rstrip("\n"))
+
+ if make_jobserver_re.match(line) is not None:
+ make_jobserver.append(line.rstrip("\n"))
+
+ except zlib.error as e:
+ _eerror(["portage encountered a zlib error: '%s'" % (e,),
+ "while reading the log file: '%s'" % logfile])
+ finally:
+ f.close()
+
+ def _eqawarn(lines):
+ for line in lines:
+ eqawarn(line, phase="install", key=mysettings.mycpv, out=out)
+ wrap_width = 70
+
+ if am_maintainer_mode:
+ msg = [_("QA Notice: Automake \"maintainer mode\" detected:")]
+ msg.append("")
+ msg.extend("\t" + line for line in am_maintainer_mode)
+ msg.append("")
+ msg.extend(wrap(_(
+ "If you patch Makefile.am, "
+ "configure.in, or configure.ac then you "
+ "should use autotools.eclass and "
+ "eautomake or eautoreconf. Exceptions "
+ "are limited to system packages "
+ "for which it is impossible to run "
+ "autotools during stage building. "
+ "See http://www.gentoo.org/p"
+ "roj/en/qa/autofailure.xml for more information."),
+ wrap_width))
+ _eqawarn(msg)
+
+ if bash_command_not_found:
+ msg = [_("QA Notice: command not found:")]
+ msg.append("")
+ msg.extend("\t" + line for line in bash_command_not_found)
+ _eqawarn(msg)
+
+ if helper_missing_file:
+ msg = [_("QA Notice: file does not exist:")]
+ msg.append("")
+ msg.extend("\t" + line[4:] for line in helper_missing_file)
+ _eqawarn(msg)
+
+ if configure_opts_warn:
+ msg = [_("QA Notice: Unrecognized configure options:")]
+ msg.append("")
+ msg.extend("\t" + line for line in configure_opts_warn)
+ _eqawarn(msg)
+
+ if make_jobserver:
+ msg = [_("QA Notice: make jobserver unavailable:")]
+ msg.append("")
+ msg.extend("\t" + line for line in make_jobserver)
+ _eqawarn(msg)
+
+def _post_src_install_chost_fix(settings):
+ """
+ It's possible that the ebuild has changed the
+ CHOST variable, so revert it to the initial
+ setting.
+ """
+ if settings.get('CATEGORY') == 'virtual':
+ return
+
+ chost = settings.get('CHOST')
+ if chost:
+ write_atomic(os.path.join(settings['PORTAGE_BUILDDIR'],
+ 'build-info', 'CHOST'), chost + '\n')
+
+_vdb_use_conditional_keys = ('DEPEND', 'LICENSE', 'PDEPEND',
+ 'PROPERTIES', 'PROVIDE', 'RDEPEND', 'RESTRICT',)
+_vdb_use_conditional_atoms = frozenset(['DEPEND', 'PDEPEND', 'RDEPEND'])
+
+def _preinst_bsdflags(mysettings):
+ if bsd_chflags:
+ # Save all the file flags for restoration later.
+ os.system("mtree -c -p %s -k flags > %s" % \
+ (_shell_quote(mysettings["D"]),
+ _shell_quote(os.path.join(mysettings["T"], "bsdflags.mtree"))))
+
+ # Remove all the file flags to avoid EPERM errors.
+ os.system("chflags -R noschg,nouchg,nosappnd,nouappnd %s" % \
+ (_shell_quote(mysettings["D"]),))
+ os.system("chflags -R nosunlnk,nouunlnk %s 2>/dev/null" % \
+ (_shell_quote(mysettings["D"]),))
+
+
+def _postinst_bsdflags(mysettings):
+ if bsd_chflags:
+ # Restore all of the flags saved above.
+ os.system("mtree -e -p %s -U -k flags < %s > /dev/null" % \
+ (_shell_quote(mysettings["ROOT"]),
+ _shell_quote(os.path.join(mysettings["T"], "bsdflags.mtree"))))
+
+def _post_src_install_uid_fix(mysettings, out):
+ """
+ Files in $D with user and group bits that match the "portage"
+ user or group are automatically mapped to PORTAGE_INST_UID and
+ PORTAGE_INST_GID if necessary. The chown system call may clear
+ S_ISUID and S_ISGID bits, so those bits are restored if
+ necessary.
+ """
+
+ os = _os_merge
+
+ inst_uid = int(mysettings["PORTAGE_INST_UID"])
+ inst_gid = int(mysettings["PORTAGE_INST_GID"])
+
+ _preinst_bsdflags(mysettings)
+
+ destdir = mysettings["D"]
+ unicode_errors = []
+
+ while True:
+
+ unicode_error = False
+ size = 0
+ counted_inodes = set()
+ fixlafiles_announced = False
+ fixlafiles = "fixlafiles" in mysettings.features
+
+ for parent, dirs, files in os.walk(destdir):
+ try:
+ parent = _unicode_decode(parent,
+ encoding=_encodings['merge'], errors='strict')
+ except UnicodeDecodeError:
+ new_parent = _unicode_decode(parent,
+ encoding=_encodings['merge'], errors='replace')
+ new_parent = _unicode_encode(new_parent,
+ encoding=_encodings['merge'], errors='backslashreplace')
+ new_parent = _unicode_decode(new_parent,
+ encoding=_encodings['merge'], errors='replace')
+ os.rename(parent, new_parent)
+ unicode_error = True
+ unicode_errors.append(new_parent[len(destdir):])
+ break
+
+ for fname in chain(dirs, files):
+ try:
+ fname = _unicode_decode(fname,
+ encoding=_encodings['merge'], errors='strict')
+ except UnicodeDecodeError:
+ fpath = _os.path.join(
+ parent.encode(_encodings['merge']), fname)
+ new_fname = _unicode_decode(fname,
+ encoding=_encodings['merge'], errors='replace')
+ new_fname = _unicode_encode(new_fname,
+ encoding=_encodings['merge'], errors='backslashreplace')
+ new_fname = _unicode_decode(new_fname,
+ encoding=_encodings['merge'], errors='replace')
+ new_fpath = os.path.join(parent, new_fname)
+ os.rename(fpath, new_fpath)
+ unicode_error = True
+ unicode_errors.append(new_fpath[len(destdir):])
+ fname = new_fname
+ fpath = new_fpath
+ else:
+ fpath = os.path.join(parent, fname)
+
+ if fixlafiles and \
+ fname.endswith(".la") and os.path.isfile(fpath):
+ f = open(_unicode_encode(fpath,
+ encoding=_encodings['merge'], errors='strict'),
+ mode='rb')
+ has_lafile_header = b'.la - a libtool library file' \
+ in f.readline()
+ f.seek(0)
+ contents = f.read()
+ f.close()
+ try:
+ needs_update, new_contents = rewrite_lafile(contents)
+ except portage.exception.InvalidData as e:
+ needs_update = False
+ if not fixlafiles_announced:
+ fixlafiles_announced = True
+ writemsg("Fixing .la files\n", fd=out)
+
+ # Suppress warnings if the file does not have the
+ # expected header (bug #340725). Even if the header is
+ # missing, we still call rewrite_lafile() since some
+ # valid libtool archives may not have the header.
+ msg = " %s is not a valid libtool archive, skipping\n" % fpath[len(destdir):]
+ qa_msg = "QA Notice: invalid .la file found: %s, %s" % (fpath[len(destdir):], e)
+ if has_lafile_header:
+ writemsg(msg, fd=out)
+ eqawarn(qa_msg, key=mysettings.mycpv, out=out)
+
+ if needs_update:
+ if not fixlafiles_announced:
+ fixlafiles_announced = True
+ writemsg("Fixing .la files\n", fd=out)
+ writemsg(" %s\n" % fpath[len(destdir):], fd=out)
+ # write_atomic succeeds even in some cases in which
+ # a normal write might fail due to file permission
+ # settings on some operating systems such as HP-UX
+ write_atomic(_unicode_encode(fpath,
+ encoding=_encodings['merge'], errors='strict'),
+ new_contents, mode='wb')
+
+ mystat = os.lstat(fpath)
+ if stat.S_ISREG(mystat.st_mode) and \
+ mystat.st_ino not in counted_inodes:
+ counted_inodes.add(mystat.st_ino)
+ size += mystat.st_size
+ if mystat.st_uid != portage_uid and \
+ mystat.st_gid != portage_gid:
+ continue
+ myuid = -1
+ mygid = -1
+ if mystat.st_uid == portage_uid:
+ myuid = inst_uid
+ if mystat.st_gid == portage_gid:
+ mygid = inst_gid
+ apply_secpass_permissions(
+ _unicode_encode(fpath, encoding=_encodings['merge']),
+ uid=myuid, gid=mygid,
+ mode=mystat.st_mode, stat_cached=mystat,
+ follow_links=False)
+
+ if unicode_error:
+ break
+
+ if not unicode_error:
+ break
+
+ if unicode_errors:
+ for l in _merge_unicode_error(unicode_errors):
+ eerror(l, phase='install', key=mysettings.mycpv, out=out)
+
+ build_info_dir = os.path.join(mysettings['PORTAGE_BUILDDIR'],
+ 'build-info')
+
+ io.open(_unicode_encode(os.path.join(build_info_dir,
+ 'SIZE'), encoding=_encodings['fs'], errors='strict'),
+ mode='w', encoding=_encodings['repo.content'],
+ errors='strict').write(_unicode_decode(str(size) + '\n'))
+
+ io.open(_unicode_encode(os.path.join(build_info_dir,
+ 'BUILD_TIME'), encoding=_encodings['fs'], errors='strict'),
+ mode='w', encoding=_encodings['repo.content'],
+ errors='strict').write(_unicode_decode("%.0f\n" % (time.time(),)))
+
+ use = frozenset(mysettings['PORTAGE_USE'].split())
+ for k in _vdb_use_conditional_keys:
+ v = mysettings.configdict['pkg'].get(k)
+ filename = os.path.join(build_info_dir, k)
+ if v is None:
+ try:
+ os.unlink(filename)
+ except OSError:
+ pass
+ continue
+
+ if k.endswith('DEPEND'):
+ token_class = Atom
+ else:
+ token_class = None
+
+ v = use_reduce(v, uselist=use, token_class=token_class)
+ v = paren_enclose(v)
+ if not v:
+ try:
+ os.unlink(filename)
+ except OSError:
+ pass
+ continue
+ io.open(_unicode_encode(os.path.join(build_info_dir,
+ k), encoding=_encodings['fs'], errors='strict'),
+ mode='w', encoding=_encodings['repo.content'],
+ errors='strict').write(_unicode_decode(v + '\n'))
+
+ _reapply_bsdflags_to_image(mysettings)
+
+def _reapply_bsdflags_to_image(mysettings):
+ """
+ Reapply flags saved and removed by _preinst_bsdflags.
+ """
+ if bsd_chflags:
+ os.system("mtree -e -p %s -U -k flags < %s > /dev/null" % \
+ (_shell_quote(mysettings["D"]),
+ _shell_quote(os.path.join(mysettings["T"], "bsdflags.mtree"))))
+
+def _post_src_install_soname_symlinks(mysettings, out):
+ """
+ Check that libraries in $D have corresponding soname symlinks.
+ If symlinks are missing then create them and trigger a QA Notice.
+ This requires $PORTAGE_BUILDDIR/build-info/NEEDED.ELF.2 for
+ operation.
+ """
+
+ image_dir = mysettings["D"]
+ needed_filename = os.path.join(mysettings["PORTAGE_BUILDDIR"],
+ "build-info", "NEEDED.ELF.2")
+
+ try:
+ lines = io.open(_unicode_encode(needed_filename,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'],
+ errors='replace').readlines()
+ except IOError as e:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
+ raise
+ return
+
+ libpaths = set(portage.util.getlibpaths(
+ mysettings["ROOT"], env=mysettings))
+ libpath_inodes = set()
+ for libpath in libpaths:
+ libdir = os.path.join(mysettings["ROOT"], libpath.lstrip(os.sep))
+ try:
+ s = os.stat(libdir)
+ except OSError:
+ continue
+ else:
+ libpath_inodes.add((s.st_dev, s.st_ino))
+
+ is_libdir_cache = {}
+
+ def is_libdir(obj_parent):
+ try:
+ return is_libdir_cache[obj_parent]
+ except KeyError:
+ pass
+
+ rval = False
+ if obj_parent in libpaths:
+ rval = True
+ else:
+ parent_path = os.path.join(mysettings["ROOT"],
+ obj_parent.lstrip(os.sep))
+ try:
+ s = os.stat(parent_path)
+ except OSError:
+ pass
+ else:
+ if (s.st_dev, s.st_ino) in libpath_inodes:
+ rval = True
+
+ is_libdir_cache[obj_parent] = rval
+ return rval
+
+ missing_symlinks = []
+
+ # Parse NEEDED.ELF.2 like LinkageMapELF.rebuild() does.
+ for l in lines:
+ l = l.rstrip("\n")
+ if not l:
+ continue
+ fields = l.split(";")
+ if len(fields) < 5:
+ portage.util.writemsg_level(_("\nWrong number of fields " \
+ "in %s: %s\n\n") % (needed_filename, l),
+ level=logging.ERROR, noiselevel=-1)
+ continue
+
+ obj, soname = fields[1:3]
+ if not soname:
+ continue
+ if not is_libdir(os.path.dirname(obj)):
+ continue
+
+ obj_file_path = os.path.join(image_dir, obj.lstrip(os.sep))
+ sym_file_path = os.path.join(os.path.dirname(obj_file_path), soname)
+ try:
+ os.lstat(sym_file_path)
+ except OSError as e:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
+ raise
+ else:
+ continue
+
+ missing_symlinks.append((obj, soname))
+
+ if not missing_symlinks:
+ return
+
+ qa_msg = ["QA Notice: Missing soname symlink(s) " + \
+ "will be automatically created:"]
+ qa_msg.append("")
+ qa_msg.extend("\t%s -> %s" % (os.path.join(
+ os.path.dirname(obj).lstrip(os.sep), soname),
+ os.path.basename(obj))
+ for obj, soname in missing_symlinks)
+ qa_msg.append("")
+ for line in qa_msg:
+ eqawarn(line, key=mysettings.mycpv, out=out)
+
+ _preinst_bsdflags(mysettings)
+ for obj, soname in missing_symlinks:
+ obj_file_path = os.path.join(image_dir, obj.lstrip(os.sep))
+ sym_file_path = os.path.join(os.path.dirname(obj_file_path), soname)
+ os.symlink(os.path.basename(obj_file_path), sym_file_path)
+ _reapply_bsdflags_to_image(mysettings)
+
+def _merge_unicode_error(errors):
+ lines = []
+
+ msg = _("This package installs one or more file names containing "
+ "characters that do not match your current locale "
+ "settings. The current setting for filesystem encoding is '%s'.") \
+ % _encodings['merge']
+ lines.extend(wrap(msg, 72))
+
+ lines.append("")
+ errors.sort()
+ lines.extend("\t" + x for x in errors)
+ lines.append("")
+
+ if _encodings['merge'].lower().replace('_', '').replace('-', '') != 'utf8':
+ msg = _("For best results, UTF-8 encoding is recommended. See "
+ "the Gentoo Linux Localization Guide for instructions "
+ "about how to configure your locale for UTF-8 encoding:")
+ lines.extend(wrap(msg, 72))
+ lines.append("")
+ lines.append("\t" + \
+ "http://www.gentoo.org/doc/en/guide-localization.xml")
+ lines.append("")
+
+ return lines
diff --git a/portage_with_autodep/pym/portage/package/ebuild/fetch.py b/portage_with_autodep/pym/portage/package/ebuild/fetch.py
new file mode 100644
index 0000000..5cbbf87
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/fetch.py
@@ -0,0 +1,1129 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+__all__ = ['fetch']
+
+import errno
+import io
+import logging
+import random
+import re
+import shutil
+import stat
+import sys
+import tempfile
+
+
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.package.ebuild.config:check_config_instance,config',
+ 'portage.package.ebuild.doebuild:doebuild_environment,' + \
+ '_doebuild_spawn',
+ 'portage.package.ebuild.prepare_build_dirs:prepare_build_dirs',
+)
+
+from portage import OrderedDict, os, selinux, _encodings, \
+ _shell_quote, _unicode_encode
+from portage.checksum import hashfunc_map, perform_md5, verify_all
+from portage.const import BASH_BINARY, CUSTOM_MIRRORS_FILE, \
+ GLOBAL_CONFIG_PATH
+from portage.data import portage_gid, portage_uid, secpass, userpriv_groups
+from portage.exception import FileNotFound, OperationNotPermitted, \
+ PortageException, TryAgain
+from portage.localization import _
+from portage.locks import lockfile, unlockfile
+from portage.manifest import Manifest
+from portage.output import colorize, EOutput
+from portage.util import apply_recursive_permissions, \
+ apply_secpass_permissions, ensure_dirs, grabdict, shlex_split, \
+ varexpand, writemsg, writemsg_level, writemsg_stdout
+from portage.process import spawn
+
+_userpriv_spawn_kwargs = (
+ ("uid", portage_uid),
+ ("gid", portage_gid),
+ ("groups", userpriv_groups),
+ ("umask", 0o02),
+)
+
+def _spawn_fetch(settings, args, **kwargs):
+ """
+ Spawn a process with appropriate settings for fetching, including
+ userfetch and selinux support.
+ """
+
+ global _userpriv_spawn_kwargs
+
+ # Redirect all output to stdout since some fetchers like
+ # wget pollute stderr (if portage detects a problem then it
+ # can send it's own message to stderr).
+ if "fd_pipes" not in kwargs:
+
+ kwargs["fd_pipes"] = {
+ 0 : sys.stdin.fileno(),
+ 1 : sys.stdout.fileno(),
+ 2 : sys.stdout.fileno(),
+ }
+
+ if "userfetch" in settings.features and \
+ os.getuid() == 0 and portage_gid and portage_uid:
+ kwargs.update(_userpriv_spawn_kwargs)
+
+ spawn_func = spawn
+
+ if settings.selinux_enabled():
+ spawn_func = selinux.spawn_wrapper(spawn_func,
+ settings["PORTAGE_FETCH_T"])
+
+ # bash is an allowed entrypoint, while most binaries are not
+ if args[0] != BASH_BINARY:
+ args = [BASH_BINARY, "-c", "exec \"$@\"", args[0]] + args
+
+ # Ensure that EBUILD_PHASE is set to fetch, so that config.environ()
+ # does not filter the calling environment (which may contain needed
+ # proxy variables, as in bug #315421).
+ phase_backup = settings.get('EBUILD_PHASE')
+ settings['EBUILD_PHASE'] = 'fetch'
+ try:
+ rval = spawn_func(args, env=settings.environ(), **kwargs)
+ finally:
+ if phase_backup is None:
+ settings.pop('EBUILD_PHASE', None)
+ else:
+ settings['EBUILD_PHASE'] = phase_backup
+
+ return rval
+
+_userpriv_test_write_file_cache = {}
+_userpriv_test_write_cmd_script = ">> %(file_path)s 2>/dev/null ; rval=$? ; " + \
+ "rm -f %(file_path)s ; exit $rval"
+
+def _userpriv_test_write_file(settings, file_path):
+ """
+ Drop privileges and try to open a file for writing. The file may or
+ may not exist, and the parent directory is assumed to exist. The file
+ is removed before returning.
+
+ @param settings: A config instance which is passed to _spawn_fetch()
+ @param file_path: A file path to open and write.
+ @return: True if write succeeds, False otherwise.
+ """
+
+ global _userpriv_test_write_file_cache, _userpriv_test_write_cmd_script
+ rval = _userpriv_test_write_file_cache.get(file_path)
+ if rval is not None:
+ return rval
+
+ args = [BASH_BINARY, "-c", _userpriv_test_write_cmd_script % \
+ {"file_path" : _shell_quote(file_path)}]
+
+ returncode = _spawn_fetch(settings, args)
+
+ rval = returncode == os.EX_OK
+ _userpriv_test_write_file_cache[file_path] = rval
+ return rval
+
+def _checksum_failure_temp_file(distdir, basename):
+ """
+ First try to find a duplicate temp file with the same checksum and return
+ that filename if available. Otherwise, use mkstemp to create a new unique
+ filename._checksum_failure_.$RANDOM, rename the given file, and return the
+ new filename. In any case, filename will be renamed or removed before this
+ function returns a temp filename.
+ """
+
+ filename = os.path.join(distdir, basename)
+ size = os.stat(filename).st_size
+ checksum = None
+ tempfile_re = re.compile(re.escape(basename) + r'\._checksum_failure_\..*')
+ for temp_filename in os.listdir(distdir):
+ if not tempfile_re.match(temp_filename):
+ continue
+ temp_filename = os.path.join(distdir, temp_filename)
+ try:
+ if size != os.stat(temp_filename).st_size:
+ continue
+ except OSError:
+ continue
+ try:
+ temp_checksum = perform_md5(temp_filename)
+ except FileNotFound:
+ # Apparently the temp file disappeared. Let it go.
+ continue
+ if checksum is None:
+ checksum = perform_md5(filename)
+ if checksum == temp_checksum:
+ os.unlink(filename)
+ return temp_filename
+
+ fd, temp_filename = \
+ tempfile.mkstemp("", basename + "._checksum_failure_.", distdir)
+ os.close(fd)
+ os.rename(filename, temp_filename)
+ return temp_filename
+
+def _check_digests(filename, digests, show_errors=1):
+ """
+ Check digests and display a message if an error occurs.
+ @return True if all digests match, False otherwise.
+ """
+ verified_ok, reason = verify_all(filename, digests)
+ if not verified_ok:
+ if show_errors:
+ writemsg(_("!!! Previously fetched"
+ " file: '%s'\n") % filename, noiselevel=-1)
+ writemsg(_("!!! Reason: %s\n") % reason[0],
+ noiselevel=-1)
+ writemsg(_("!!! Got: %s\n"
+ "!!! Expected: %s\n") % \
+ (reason[1], reason[2]), noiselevel=-1)
+ return False
+ return True
+
+def _check_distfile(filename, digests, eout, show_errors=1):
+ """
+ @return a tuple of (match, stat_obj) where match is True if filename
+ matches all given digests (if any) and stat_obj is a stat result, or
+ None if the file does not exist.
+ """
+ if digests is None:
+ digests = {}
+ size = digests.get("size")
+ if size is not None and len(digests) == 1:
+ digests = None
+
+ try:
+ st = os.stat(filename)
+ except OSError:
+ return (False, None)
+ if size is not None and size != st.st_size:
+ return (False, st)
+ if not digests:
+ if size is not None:
+ eout.ebegin(_("%s size ;-)") % os.path.basename(filename))
+ eout.eend(0)
+ elif st.st_size == 0:
+ # Zero-byte distfiles are always invalid.
+ return (False, st)
+ else:
+ if _check_digests(filename, digests, show_errors=show_errors):
+ eout.ebegin("%s %s ;-)" % (os.path.basename(filename),
+ " ".join(sorted(digests))))
+ eout.eend(0)
+ else:
+ return (False, st)
+ return (True, st)
+
+_fetch_resume_size_re = re.compile('(^[\d]+)([KMGTPEZY]?$)')
+
+_size_suffix_map = {
+ '' : 0,
+ 'K' : 10,
+ 'M' : 20,
+ 'G' : 30,
+ 'T' : 40,
+ 'P' : 50,
+ 'E' : 60,
+ 'Z' : 70,
+ 'Y' : 80,
+}
+
+def fetch(myuris, mysettings, listonly=0, fetchonly=0,
+ locks_in_subdir=".locks", use_locks=1, try_mirrors=1, digests=None,
+ allow_missing_digests=True):
+ "fetch files. Will use digest file if available."
+
+ if not myuris:
+ return 1
+
+ features = mysettings.features
+ restrict = mysettings.get("PORTAGE_RESTRICT","").split()
+
+ userfetch = secpass >= 2 and "userfetch" in features
+ userpriv = secpass >= 2 and "userpriv" in features
+
+ # 'nomirror' is bad/negative logic. You Restrict mirroring, not no-mirroring.
+ restrict_mirror = "mirror" in restrict or "nomirror" in restrict
+ if restrict_mirror:
+ if ("mirror" in features) and ("lmirror" not in features):
+ # lmirror should allow you to bypass mirror restrictions.
+ # XXX: This is not a good thing, and is temporary at best.
+ print(_(">>> \"mirror\" mode desired and \"mirror\" restriction found; skipping fetch."))
+ return 1
+
+ # Generally, downloading the same file repeatedly from
+ # every single available mirror is a waste of bandwidth
+ # and time, so there needs to be a cap.
+ checksum_failure_max_tries = 5
+ v = checksum_failure_max_tries
+ try:
+ v = int(mysettings.get("PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS",
+ checksum_failure_max_tries))
+ except (ValueError, OverflowError):
+ writemsg(_("!!! Variable PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS"
+ " contains non-integer value: '%s'\n") % \
+ mysettings["PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS"], noiselevel=-1)
+ writemsg(_("!!! Using PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS "
+ "default value: %s\n") % checksum_failure_max_tries,
+ noiselevel=-1)
+ v = checksum_failure_max_tries
+ if v < 1:
+ writemsg(_("!!! Variable PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS"
+ " contains value less than 1: '%s'\n") % v, noiselevel=-1)
+ writemsg(_("!!! Using PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS "
+ "default value: %s\n") % checksum_failure_max_tries,
+ noiselevel=-1)
+ v = checksum_failure_max_tries
+ checksum_failure_max_tries = v
+ del v
+
+ fetch_resume_size_default = "350K"
+ fetch_resume_size = mysettings.get("PORTAGE_FETCH_RESUME_MIN_SIZE")
+ if fetch_resume_size is not None:
+ fetch_resume_size = "".join(fetch_resume_size.split())
+ if not fetch_resume_size:
+ # If it's undefined or empty, silently use the default.
+ fetch_resume_size = fetch_resume_size_default
+ match = _fetch_resume_size_re.match(fetch_resume_size)
+ if match is None or \
+ (match.group(2).upper() not in _size_suffix_map):
+ writemsg(_("!!! Variable PORTAGE_FETCH_RESUME_MIN_SIZE"
+ " contains an unrecognized format: '%s'\n") % \
+ mysettings["PORTAGE_FETCH_RESUME_MIN_SIZE"], noiselevel=-1)
+ writemsg(_("!!! Using PORTAGE_FETCH_RESUME_MIN_SIZE "
+ "default value: %s\n") % fetch_resume_size_default,
+ noiselevel=-1)
+ fetch_resume_size = None
+ if fetch_resume_size is None:
+ fetch_resume_size = fetch_resume_size_default
+ match = _fetch_resume_size_re.match(fetch_resume_size)
+ fetch_resume_size = int(match.group(1)) * \
+ 2 ** _size_suffix_map[match.group(2).upper()]
+
+ # Behave like the package has RESTRICT="primaryuri" after a
+ # couple of checksum failures, to increase the probablility
+ # of success before checksum_failure_max_tries is reached.
+ checksum_failure_primaryuri = 2
+ thirdpartymirrors = mysettings.thirdpartymirrors()
+
+ # In the background parallel-fetch process, it's safe to skip checksum
+ # verification of pre-existing files in $DISTDIR that have the correct
+ # file size. The parent process will verify their checksums prior to
+ # the unpack phase.
+
+ parallel_fetchonly = "PORTAGE_PARALLEL_FETCHONLY" in mysettings
+ if parallel_fetchonly:
+ fetchonly = 1
+
+ check_config_instance(mysettings)
+
+ custommirrors = grabdict(os.path.join(mysettings["PORTAGE_CONFIGROOT"],
+ CUSTOM_MIRRORS_FILE), recursive=1)
+
+ mymirrors=[]
+
+ if listonly or ("distlocks" not in features):
+ use_locks = 0
+
+ fetch_to_ro = 0
+ if "skiprocheck" in features:
+ fetch_to_ro = 1
+
+ if not os.access(mysettings["DISTDIR"],os.W_OK) and fetch_to_ro:
+ if use_locks:
+ writemsg(colorize("BAD",
+ _("!!! For fetching to a read-only filesystem, "
+ "locking should be turned off.\n")), noiselevel=-1)
+ writemsg(_("!!! This can be done by adding -distlocks to "
+ "FEATURES in /etc/make.conf\n"), noiselevel=-1)
+# use_locks = 0
+
+ # local mirrors are always added
+ if "local" in custommirrors:
+ mymirrors += custommirrors["local"]
+
+ if restrict_mirror:
+ # We don't add any mirrors.
+ pass
+ else:
+ if try_mirrors:
+ mymirrors += [x.rstrip("/") for x in mysettings["GENTOO_MIRRORS"].split() if x]
+
+ skip_manifest = mysettings.get("EBUILD_SKIP_MANIFEST") == "1"
+ if skip_manifest:
+ allow_missing_digests = True
+ pkgdir = mysettings.get("O")
+ if digests is None and not (pkgdir is None or skip_manifest):
+ mydigests = Manifest(
+ pkgdir, mysettings["DISTDIR"]).getTypeDigests("DIST")
+ elif digests is None or skip_manifest:
+ # no digests because fetch was not called for a specific package
+ mydigests = {}
+ else:
+ mydigests = digests
+
+ ro_distdirs = [x for x in \
+ shlex_split(mysettings.get("PORTAGE_RO_DISTDIRS", "")) \
+ if os.path.isdir(x)]
+
+ fsmirrors = []
+ for x in range(len(mymirrors)-1,-1,-1):
+ if mymirrors[x] and mymirrors[x][0]=='/':
+ fsmirrors += [mymirrors[x]]
+ del mymirrors[x]
+
+ restrict_fetch = "fetch" in restrict
+ force_mirror = "force-mirror" in features and not restrict_mirror
+ custom_local_mirrors = custommirrors.get("local", [])
+ if restrict_fetch:
+ # With fetch restriction, a normal uri may only be fetched from
+ # custom local mirrors (if available). A mirror:// uri may also
+ # be fetched from specific mirrors (effectively overriding fetch
+ # restriction, but only for specific mirrors).
+ locations = custom_local_mirrors
+ else:
+ locations = mymirrors
+
+ file_uri_tuples = []
+ # Check for 'items' attribute since OrderedDict is not a dict.
+ if hasattr(myuris, 'items'):
+ for myfile, uri_set in myuris.items():
+ for myuri in uri_set:
+ file_uri_tuples.append((myfile, myuri))
+ else:
+ for myuri in myuris:
+ file_uri_tuples.append((os.path.basename(myuri), myuri))
+
+ filedict = OrderedDict()
+ primaryuri_indexes={}
+ primaryuri_dict = {}
+ thirdpartymirror_uris = {}
+ for myfile, myuri in file_uri_tuples:
+ if myfile not in filedict:
+ filedict[myfile]=[]
+ for y in range(0,len(locations)):
+ filedict[myfile].append(locations[y]+"/distfiles/"+myfile)
+ if myuri[:9]=="mirror://":
+ eidx = myuri.find("/", 9)
+ if eidx != -1:
+ mirrorname = myuri[9:eidx]
+ path = myuri[eidx+1:]
+
+ # Try user-defined mirrors first
+ if mirrorname in custommirrors:
+ for cmirr in custommirrors[mirrorname]:
+ filedict[myfile].append(
+ cmirr.rstrip("/") + "/" + path)
+
+ # now try the official mirrors
+ if mirrorname in thirdpartymirrors:
+ random.shuffle(thirdpartymirrors[mirrorname])
+
+ uris = [locmirr.rstrip("/") + "/" + path \
+ for locmirr in thirdpartymirrors[mirrorname]]
+ filedict[myfile].extend(uris)
+ thirdpartymirror_uris.setdefault(myfile, []).extend(uris)
+
+ if not filedict[myfile]:
+ writemsg(_("No known mirror by the name: %s\n") % (mirrorname))
+ else:
+ writemsg(_("Invalid mirror definition in SRC_URI:\n"), noiselevel=-1)
+ writemsg(" %s\n" % (myuri), noiselevel=-1)
+ else:
+ if restrict_fetch or force_mirror:
+ # Only fetch from specific mirrors is allowed.
+ continue
+ if "primaryuri" in restrict:
+ # Use the source site first.
+ if myfile in primaryuri_indexes:
+ primaryuri_indexes[myfile] += 1
+ else:
+ primaryuri_indexes[myfile] = 0
+ filedict[myfile].insert(primaryuri_indexes[myfile], myuri)
+ else:
+ filedict[myfile].append(myuri)
+ primaryuris = primaryuri_dict.get(myfile)
+ if primaryuris is None:
+ primaryuris = []
+ primaryuri_dict[myfile] = primaryuris
+ primaryuris.append(myuri)
+
+ # Prefer thirdpartymirrors over normal mirrors in cases when
+ # the file does not yet exist on the normal mirrors.
+ for myfile, uris in thirdpartymirror_uris.items():
+ primaryuri_dict.setdefault(myfile, []).extend(uris)
+
+ can_fetch=True
+
+ if listonly:
+ can_fetch = False
+
+ if can_fetch and not fetch_to_ro:
+ global _userpriv_test_write_file_cache
+ dirmode = 0o070
+ filemode = 0o60
+ modemask = 0o2
+ dir_gid = portage_gid
+ if "FAKED_MODE" in mysettings:
+ # When inside fakeroot, directories with portage's gid appear
+ # to have root's gid. Therefore, use root's gid instead of
+ # portage's gid to avoid spurrious permissions adjustments
+ # when inside fakeroot.
+ dir_gid = 0
+ distdir_dirs = [""]
+ try:
+
+ for x in distdir_dirs:
+ mydir = os.path.join(mysettings["DISTDIR"], x)
+ write_test_file = os.path.join(
+ mydir, ".__portage_test_write__")
+
+ try:
+ st = os.stat(mydir)
+ except OSError:
+ st = None
+
+ if st is not None and stat.S_ISDIR(st.st_mode):
+ if not (userfetch or userpriv):
+ continue
+ if _userpriv_test_write_file(mysettings, write_test_file):
+ continue
+
+ _userpriv_test_write_file_cache.pop(write_test_file, None)
+ if ensure_dirs(mydir, gid=dir_gid, mode=dirmode, mask=modemask):
+ if st is None:
+ # The directory has just been created
+ # and therefore it must be empty.
+ continue
+ writemsg(_("Adjusting permissions recursively: '%s'\n") % mydir,
+ noiselevel=-1)
+ def onerror(e):
+ raise # bail out on the first error that occurs during recursion
+ if not apply_recursive_permissions(mydir,
+ gid=dir_gid, dirmode=dirmode, dirmask=modemask,
+ filemode=filemode, filemask=modemask, onerror=onerror):
+ raise OperationNotPermitted(
+ _("Failed to apply recursive permissions for the portage group."))
+ except PortageException as e:
+ if not os.path.isdir(mysettings["DISTDIR"]):
+ writemsg("!!! %s\n" % str(e), noiselevel=-1)
+ writemsg(_("!!! Directory Not Found: DISTDIR='%s'\n") % mysettings["DISTDIR"], noiselevel=-1)
+ writemsg(_("!!! Fetching will fail!\n"), noiselevel=-1)
+
+ if can_fetch and \
+ not fetch_to_ro and \
+ not os.access(mysettings["DISTDIR"], os.W_OK):
+ writemsg(_("!!! No write access to '%s'\n") % mysettings["DISTDIR"],
+ noiselevel=-1)
+ can_fetch = False
+
+ distdir_writable = can_fetch and not fetch_to_ro
+ failed_files = set()
+ restrict_fetch_msg = False
+
+ for myfile in filedict:
+ """
+ fetched status
+ 0 nonexistent
+ 1 partially downloaded
+ 2 completely downloaded
+ """
+ fetched = 0
+
+ orig_digests = mydigests.get(myfile, {})
+
+ if not (allow_missing_digests or listonly):
+ verifiable_hash_types = set(orig_digests).intersection(hashfunc_map)
+ verifiable_hash_types.discard("size")
+ if not verifiable_hash_types:
+ expected = set(hashfunc_map)
+ expected.discard("size")
+ expected = " ".join(sorted(expected))
+ got = set(orig_digests)
+ got.discard("size")
+ got = " ".join(sorted(got))
+ reason = (_("Insufficient data for checksum verification"),
+ got, expected)
+ writemsg(_("!!! Fetched file: %s VERIFY FAILED!\n") % myfile,
+ noiselevel=-1)
+ writemsg(_("!!! Reason: %s\n") % reason[0],
+ noiselevel=-1)
+ writemsg(_("!!! Got: %s\n!!! Expected: %s\n") % \
+ (reason[1], reason[2]), noiselevel=-1)
+
+ if fetchonly:
+ failed_files.add(myfile)
+ continue
+ else:
+ return 0
+
+ size = orig_digests.get("size")
+ if size == 0:
+ # Zero-byte distfiles are always invalid, so discard their digests.
+ del mydigests[myfile]
+ orig_digests.clear()
+ size = None
+ pruned_digests = orig_digests
+ if parallel_fetchonly:
+ pruned_digests = {}
+ if size is not None:
+ pruned_digests["size"] = size
+
+ myfile_path = os.path.join(mysettings["DISTDIR"], myfile)
+ has_space = True
+ has_space_superuser = True
+ file_lock = None
+ if listonly:
+ writemsg_stdout("\n", noiselevel=-1)
+ else:
+ # check if there is enough space in DISTDIR to completely store myfile
+ # overestimate the filesize so we aren't bitten by FS overhead
+ vfs_stat = None
+ if size is not None and hasattr(os, "statvfs"):
+ try:
+ vfs_stat = os.statvfs(mysettings["DISTDIR"])
+ except OSError as e:
+ writemsg_level("!!! statvfs('%s'): %s\n" %
+ (mysettings["DISTDIR"], e),
+ noiselevel=-1, level=logging.ERROR)
+ del e
+
+ if vfs_stat is not None:
+ try:
+ mysize = os.stat(myfile_path).st_size
+ except OSError as e:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
+ raise
+ del e
+ mysize = 0
+ if (size - mysize + vfs_stat.f_bsize) >= \
+ (vfs_stat.f_bsize * vfs_stat.f_bavail):
+
+ if (size - mysize + vfs_stat.f_bsize) >= \
+ (vfs_stat.f_bsize * vfs_stat.f_bfree):
+ has_space_superuser = False
+
+ if not has_space_superuser:
+ has_space = False
+ elif secpass < 2:
+ has_space = False
+ elif userfetch:
+ has_space = False
+
+ if not has_space:
+ writemsg(_("!!! Insufficient space to store %s in %s\n") % \
+ (myfile, mysettings["DISTDIR"]), noiselevel=-1)
+
+ if has_space_superuser:
+ writemsg(_("!!! Insufficient privileges to use "
+ "remaining space.\n"), noiselevel=-1)
+ if userfetch:
+ writemsg(_("!!! You may set FEATURES=\"-userfetch\""
+ " in /etc/make.conf in order to fetch with\n"
+ "!!! superuser privileges.\n"), noiselevel=-1)
+
+ if distdir_writable and use_locks:
+
+ lock_kwargs = {}
+ if fetchonly:
+ lock_kwargs["flags"] = os.O_NONBLOCK
+
+ try:
+ file_lock = lockfile(myfile_path,
+ wantnewlockfile=1, **lock_kwargs)
+ except TryAgain:
+ writemsg(_(">>> File '%s' is already locked by "
+ "another fetcher. Continuing...\n") % myfile,
+ noiselevel=-1)
+ continue
+ try:
+ if not listonly:
+
+ eout = EOutput()
+ eout.quiet = mysettings.get("PORTAGE_QUIET") == "1"
+ match, mystat = _check_distfile(
+ myfile_path, pruned_digests, eout)
+ if match:
+ if distdir_writable:
+ try:
+ apply_secpass_permissions(myfile_path,
+ gid=portage_gid, mode=0o664, mask=0o2,
+ stat_cached=mystat)
+ except PortageException as e:
+ if not os.access(myfile_path, os.R_OK):
+ writemsg(_("!!! Failed to adjust permissions:"
+ " %s\n") % str(e), noiselevel=-1)
+ del e
+ continue
+
+ if distdir_writable and mystat is None:
+ # Remove broken symlinks if necessary.
+ try:
+ os.unlink(myfile_path)
+ except OSError:
+ pass
+
+ if mystat is not None:
+ if stat.S_ISDIR(mystat.st_mode):
+ writemsg_level(
+ _("!!! Unable to fetch file since "
+ "a directory is in the way: \n"
+ "!!! %s\n") % myfile_path,
+ level=logging.ERROR, noiselevel=-1)
+ return 0
+
+ if mystat.st_size == 0:
+ if distdir_writable:
+ try:
+ os.unlink(myfile_path)
+ except OSError:
+ pass
+ elif distdir_writable:
+ if mystat.st_size < fetch_resume_size and \
+ mystat.st_size < size:
+ # If the file already exists and the size does not
+ # match the existing digests, it may be that the
+ # user is attempting to update the digest. In this
+ # case, the digestgen() function will advise the
+ # user to use `ebuild --force foo.ebuild manifest`
+ # in order to force the old digests to be replaced.
+ # Since the user may want to keep this file, rename
+ # it instead of deleting it.
+ writemsg(_(">>> Renaming distfile with size "
+ "%d (smaller than " "PORTAGE_FETCH_RESU"
+ "ME_MIN_SIZE)\n") % mystat.st_size)
+ temp_filename = \
+ _checksum_failure_temp_file(
+ mysettings["DISTDIR"], myfile)
+ writemsg_stdout(_("Refetching... "
+ "File renamed to '%s'\n\n") % \
+ temp_filename, noiselevel=-1)
+ elif mystat.st_size >= size:
+ temp_filename = \
+ _checksum_failure_temp_file(
+ mysettings["DISTDIR"], myfile)
+ writemsg_stdout(_("Refetching... "
+ "File renamed to '%s'\n\n") % \
+ temp_filename, noiselevel=-1)
+
+ if distdir_writable and ro_distdirs:
+ readonly_file = None
+ for x in ro_distdirs:
+ filename = os.path.join(x, myfile)
+ match, mystat = _check_distfile(
+ filename, pruned_digests, eout)
+ if match:
+ readonly_file = filename
+ break
+ if readonly_file is not None:
+ try:
+ os.unlink(myfile_path)
+ except OSError as e:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
+ raise
+ del e
+ os.symlink(readonly_file, myfile_path)
+ continue
+
+ if fsmirrors and not os.path.exists(myfile_path) and has_space:
+ for mydir in fsmirrors:
+ mirror_file = os.path.join(mydir, myfile)
+ try:
+ shutil.copyfile(mirror_file, myfile_path)
+ writemsg(_("Local mirror has file: %s\n") % myfile)
+ break
+ except (IOError, OSError) as e:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
+ raise
+ del e
+
+ try:
+ mystat = os.stat(myfile_path)
+ except OSError as e:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
+ raise
+ del e
+ else:
+ try:
+ apply_secpass_permissions(
+ myfile_path, gid=portage_gid, mode=0o664, mask=0o2,
+ stat_cached=mystat)
+ except PortageException as e:
+ if not os.access(myfile_path, os.R_OK):
+ writemsg(_("!!! Failed to adjust permissions:"
+ " %s\n") % str(e), noiselevel=-1)
+
+ # If the file is empty then it's obviously invalid. Remove
+ # the empty file and try to download if possible.
+ if mystat.st_size == 0:
+ if distdir_writable:
+ try:
+ os.unlink(myfile_path)
+ except EnvironmentError:
+ pass
+ elif myfile not in mydigests:
+ # We don't have a digest, but the file exists. We must
+ # assume that it is fully downloaded.
+ continue
+ else:
+ if mystat.st_size < mydigests[myfile]["size"] and \
+ not restrict_fetch:
+ fetched = 1 # Try to resume this download.
+ elif parallel_fetchonly and \
+ mystat.st_size == mydigests[myfile]["size"]:
+ eout = EOutput()
+ eout.quiet = \
+ mysettings.get("PORTAGE_QUIET") == "1"
+ eout.ebegin(
+ "%s size ;-)" % (myfile, ))
+ eout.eend(0)
+ continue
+ else:
+ verified_ok, reason = verify_all(
+ myfile_path, mydigests[myfile])
+ if not verified_ok:
+ writemsg(_("!!! Previously fetched"
+ " file: '%s'\n") % myfile, noiselevel=-1)
+ writemsg(_("!!! Reason: %s\n") % reason[0],
+ noiselevel=-1)
+ writemsg(_("!!! Got: %s\n"
+ "!!! Expected: %s\n") % \
+ (reason[1], reason[2]), noiselevel=-1)
+ if reason[0] == _("Insufficient data for checksum verification"):
+ return 0
+ if distdir_writable:
+ temp_filename = \
+ _checksum_failure_temp_file(
+ mysettings["DISTDIR"], myfile)
+ writemsg_stdout(_("Refetching... "
+ "File renamed to '%s'\n\n") % \
+ temp_filename, noiselevel=-1)
+ else:
+ eout = EOutput()
+ eout.quiet = \
+ mysettings.get("PORTAGE_QUIET", None) == "1"
+ digests = mydigests.get(myfile)
+ if digests:
+ digests = list(digests)
+ digests.sort()
+ eout.ebegin(
+ "%s %s ;-)" % (myfile, " ".join(digests)))
+ eout.eend(0)
+ continue # fetch any remaining files
+
+ # Create a reversed list since that is optimal for list.pop().
+ uri_list = filedict[myfile][:]
+ uri_list.reverse()
+ checksum_failure_count = 0
+ tried_locations = set()
+ while uri_list:
+ loc = uri_list.pop()
+ # Eliminate duplicates here in case we've switched to
+ # "primaryuri" mode on the fly due to a checksum failure.
+ if loc in tried_locations:
+ continue
+ tried_locations.add(loc)
+ if listonly:
+ writemsg_stdout(loc+" ", noiselevel=-1)
+ continue
+ # allow different fetchcommands per protocol
+ protocol = loc[0:loc.find("://")]
+
+ global_config_path = GLOBAL_CONFIG_PATH
+ if mysettings['EPREFIX']:
+ global_config_path = os.path.join(mysettings['EPREFIX'],
+ GLOBAL_CONFIG_PATH.lstrip(os.sep))
+
+ missing_file_param = False
+ fetchcommand_var = "FETCHCOMMAND_" + protocol.upper()
+ fetchcommand = mysettings.get(fetchcommand_var)
+ if fetchcommand is None:
+ fetchcommand_var = "FETCHCOMMAND"
+ fetchcommand = mysettings.get(fetchcommand_var)
+ if fetchcommand is None:
+ writemsg_level(
+ _("!!! %s is unset. It should "
+ "have been defined in\n!!! %s/make.globals.\n") \
+ % (fetchcommand_var, global_config_path),
+ level=logging.ERROR, noiselevel=-1)
+ return 0
+ if "${FILE}" not in fetchcommand:
+ writemsg_level(
+ _("!!! %s does not contain the required ${FILE}"
+ " parameter.\n") % fetchcommand_var,
+ level=logging.ERROR, noiselevel=-1)
+ missing_file_param = True
+
+ resumecommand_var = "RESUMECOMMAND_" + protocol.upper()
+ resumecommand = mysettings.get(resumecommand_var)
+ if resumecommand is None:
+ resumecommand_var = "RESUMECOMMAND"
+ resumecommand = mysettings.get(resumecommand_var)
+ if resumecommand is None:
+ writemsg_level(
+ _("!!! %s is unset. It should "
+ "have been defined in\n!!! %s/make.globals.\n") \
+ % (resumecommand_var, global_config_path),
+ level=logging.ERROR, noiselevel=-1)
+ return 0
+ if "${FILE}" not in resumecommand:
+ writemsg_level(
+ _("!!! %s does not contain the required ${FILE}"
+ " parameter.\n") % resumecommand_var,
+ level=logging.ERROR, noiselevel=-1)
+ missing_file_param = True
+
+ if missing_file_param:
+ writemsg_level(
+ _("!!! Refer to the make.conf(5) man page for "
+ "information about how to\n!!! correctly specify "
+ "FETCHCOMMAND and RESUMECOMMAND.\n"),
+ level=logging.ERROR, noiselevel=-1)
+ if myfile != os.path.basename(loc):
+ return 0
+
+ if not can_fetch:
+ if fetched != 2:
+ try:
+ mysize = os.stat(myfile_path).st_size
+ except OSError as e:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
+ raise
+ del e
+ mysize = 0
+
+ if mysize == 0:
+ writemsg(_("!!! File %s isn't fetched but unable to get it.\n") % myfile,
+ noiselevel=-1)
+ elif size is None or size > mysize:
+ writemsg(_("!!! File %s isn't fully fetched, but unable to complete it\n") % myfile,
+ noiselevel=-1)
+ else:
+ writemsg(_("!!! File %s is incorrect size, "
+ "but unable to retry.\n") % myfile, noiselevel=-1)
+ return 0
+ else:
+ continue
+
+ if fetched != 2 and has_space:
+ #we either need to resume or start the download
+ if fetched == 1:
+ try:
+ mystat = os.stat(myfile_path)
+ except OSError as e:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
+ raise
+ del e
+ fetched = 0
+ else:
+ if mystat.st_size < fetch_resume_size:
+ writemsg(_(">>> Deleting distfile with size "
+ "%d (smaller than " "PORTAGE_FETCH_RESU"
+ "ME_MIN_SIZE)\n") % mystat.st_size)
+ try:
+ os.unlink(myfile_path)
+ except OSError as e:
+ if e.errno not in \
+ (errno.ENOENT, errno.ESTALE):
+ raise
+ del e
+ fetched = 0
+ if fetched == 1:
+ #resume mode:
+ writemsg(_(">>> Resuming download...\n"))
+ locfetch=resumecommand
+ command_var = resumecommand_var
+ else:
+ #normal mode:
+ locfetch=fetchcommand
+ command_var = fetchcommand_var
+ writemsg_stdout(_(">>> Downloading '%s'\n") % \
+ re.sub(r'//(.+):.+@(.+)/',r'//\1:*password*@\2/', loc))
+ variables = {
+ "DISTDIR": mysettings["DISTDIR"],
+ "URI": loc,
+ "FILE": myfile
+ }
+
+ myfetch = shlex_split(locfetch)
+ myfetch = [varexpand(x, mydict=variables) for x in myfetch]
+ myret = -1
+ try:
+
+ myret = _spawn_fetch(mysettings, myfetch)
+
+ finally:
+ try:
+ apply_secpass_permissions(myfile_path,
+ gid=portage_gid, mode=0o664, mask=0o2)
+ except FileNotFound:
+ pass
+ except PortageException as e:
+ if not os.access(myfile_path, os.R_OK):
+ writemsg(_("!!! Failed to adjust permissions:"
+ " %s\n") % str(e), noiselevel=-1)
+ del e
+
+ # If the file is empty then it's obviously invalid. Don't
+ # trust the return value from the fetcher. Remove the
+ # empty file and try to download again.
+ try:
+ if os.stat(myfile_path).st_size == 0:
+ os.unlink(myfile_path)
+ fetched = 0
+ continue
+ except EnvironmentError:
+ pass
+
+ if mydigests is not None and myfile in mydigests:
+ try:
+ mystat = os.stat(myfile_path)
+ except OSError as e:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
+ raise
+ del e
+ fetched = 0
+ else:
+
+ if stat.S_ISDIR(mystat.st_mode):
+ # This can happen if FETCHCOMMAND erroneously
+ # contains wget's -P option where it should
+ # instead have -O.
+ writemsg_level(
+ _("!!! The command specified in the "
+ "%s variable appears to have\n!!! "
+ "created a directory instead of a "
+ "normal file.\n") % command_var,
+ level=logging.ERROR, noiselevel=-1)
+ writemsg_level(
+ _("!!! Refer to the make.conf(5) "
+ "man page for information about how "
+ "to\n!!! correctly specify "
+ "FETCHCOMMAND and RESUMECOMMAND.\n"),
+ level=logging.ERROR, noiselevel=-1)
+ return 0
+
+ # no exception? file exists. let digestcheck() report
+ # an appropriately for size or checksum errors
+
+ # If the fetcher reported success and the file is
+ # too small, it's probably because the digest is
+ # bad (upstream changed the distfile). In this
+ # case we don't want to attempt to resume. Show a
+ # digest verification failure to that the user gets
+ # a clue about what just happened.
+ if myret != os.EX_OK and \
+ mystat.st_size < mydigests[myfile]["size"]:
+ # Fetch failed... Try the next one... Kill 404 files though.
+ if (mystat[stat.ST_SIZE]<100000) and (len(myfile)>4) and not ((myfile[-5:]==".html") or (myfile[-4:]==".htm")):
+ html404=re.compile("<title>.*(not found|404).*</title>",re.I|re.M)
+ if html404.search(io.open(
+ _unicode_encode(myfile_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'], errors='replace'
+ ).read()):
+ try:
+ os.unlink(mysettings["DISTDIR"]+"/"+myfile)
+ writemsg(_(">>> Deleting invalid distfile. (Improper 404 redirect from server.)\n"))
+ fetched = 0
+ continue
+ except (IOError, OSError):
+ pass
+ fetched = 1
+ continue
+ if True:
+ # File is the correct size--check the checksums for the fetched
+ # file NOW, for those users who don't have a stable/continuous
+ # net connection. This way we have a chance to try to download
+ # from another mirror...
+ verified_ok,reason = verify_all(mysettings["DISTDIR"]+"/"+myfile, mydigests[myfile])
+ if not verified_ok:
+ print(reason)
+ writemsg(_("!!! Fetched file: %s VERIFY FAILED!\n") % myfile,
+ noiselevel=-1)
+ writemsg(_("!!! Reason: %s\n") % reason[0],
+ noiselevel=-1)
+ writemsg(_("!!! Got: %s\n!!! Expected: %s\n") % \
+ (reason[1], reason[2]), noiselevel=-1)
+ if reason[0] == _("Insufficient data for checksum verification"):
+ return 0
+ temp_filename = \
+ _checksum_failure_temp_file(
+ mysettings["DISTDIR"], myfile)
+ writemsg_stdout(_("Refetching... "
+ "File renamed to '%s'\n\n") % \
+ temp_filename, noiselevel=-1)
+ fetched=0
+ checksum_failure_count += 1
+ if checksum_failure_count == \
+ checksum_failure_primaryuri:
+ # Switch to "primaryuri" mode in order
+ # to increase the probablility of
+ # of success.
+ primaryuris = \
+ primaryuri_dict.get(myfile)
+ if primaryuris:
+ uri_list.extend(
+ reversed(primaryuris))
+ if checksum_failure_count >= \
+ checksum_failure_max_tries:
+ break
+ else:
+ eout = EOutput()
+ eout.quiet = mysettings.get("PORTAGE_QUIET", None) == "1"
+ digests = mydigests.get(myfile)
+ if digests:
+ eout.ebegin("%s %s ;-)" % \
+ (myfile, " ".join(sorted(digests))))
+ eout.eend(0)
+ fetched=2
+ break
+ else:
+ if not myret:
+ fetched=2
+ break
+ elif mydigests!=None:
+ writemsg(_("No digest file available and download failed.\n\n"),
+ noiselevel=-1)
+ finally:
+ if use_locks and file_lock:
+ unlockfile(file_lock)
+ file_lock = None
+
+ if listonly:
+ writemsg_stdout("\n", noiselevel=-1)
+ if fetched != 2:
+ if restrict_fetch and not restrict_fetch_msg:
+ restrict_fetch_msg = True
+ msg = _("\n!!! %s/%s"
+ " has fetch restriction turned on.\n"
+ "!!! This probably means that this "
+ "ebuild's files must be downloaded\n"
+ "!!! manually. See the comments in"
+ " the ebuild for more information.\n\n") % \
+ (mysettings["CATEGORY"], mysettings["PF"])
+ writemsg_level(msg,
+ level=logging.ERROR, noiselevel=-1)
+ elif restrict_fetch:
+ pass
+ elif listonly:
+ pass
+ elif not filedict[myfile]:
+ writemsg(_("Warning: No mirrors available for file"
+ " '%s'\n") % (myfile), noiselevel=-1)
+ else:
+ writemsg(_("!!! Couldn't download '%s'. Aborting.\n") % myfile,
+ noiselevel=-1)
+
+ if listonly:
+ failed_files.add(myfile)
+ continue
+ elif fetchonly:
+ failed_files.add(myfile)
+ continue
+ return 0
+ if failed_files:
+ return 0
+ return 1
diff --git a/portage_with_autodep/pym/portage/package/ebuild/getmaskingreason.py b/portage_with_autodep/pym/portage/package/ebuild/getmaskingreason.py
new file mode 100644
index 0000000..f2af638
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/getmaskingreason.py
@@ -0,0 +1,124 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['getmaskingreason']
+
+import portage
+from portage import os
+from portage.const import USER_CONFIG_PATH
+from portage.dep import Atom, match_from_list, _slot_separator, _repo_separator
+from portage.exception import InvalidAtom
+from portage.localization import _
+from portage.repository.config import _gen_valid_repo
+from portage.util import grablines, normalize_path
+from portage.versions import catpkgsplit
+from _emerge.Package import Package
+
+def getmaskingreason(mycpv, metadata=None, settings=None,
+ portdb=None, return_location=False, myrepo=None):
+ """
+ If specified, the myrepo argument is assumed to be valid. This
+ should be a safe assumption since portdbapi methods always
+ return valid repo names and valid "repository" metadata from
+ aux_get.
+ """
+ if settings is None:
+ settings = portage.settings
+ if portdb is None:
+ portdb = portage.portdb
+ mysplit = catpkgsplit(mycpv)
+ if not mysplit:
+ raise ValueError(_("invalid CPV: %s") % mycpv)
+
+ if metadata is None:
+ db_keys = list(portdb._aux_cache_keys)
+ try:
+ metadata = dict(zip(db_keys,
+ portdb.aux_get(mycpv, db_keys, myrepo=myrepo)))
+ except KeyError:
+ if not portdb.cpv_exists(mycpv):
+ raise
+ else:
+ if myrepo is None:
+ myrepo = _gen_valid_repo(metadata["repository"])
+
+ elif myrepo is None:
+ myrepo = metadata.get("repository")
+ if myrepo is not None:
+ myrepo = _gen_valid_repo(metadata["repository"])
+
+ if metadata is not None and \
+ not portage.eapi_is_supported(metadata["EAPI"]):
+ # Return early since otherwise we might produce invalid
+ # results given that the EAPI is not supported. Also,
+ # metadata is mostly useless in this case since it doesn't
+ # contain essential things like SLOT.
+ if return_location:
+ return (None, None)
+ else:
+ return None
+
+ # Sometimes we can't access SLOT or repository due to corruption.
+ pkg = mycpv
+ if metadata is not None:
+ pkg = "".join((mycpv, _slot_separator, metadata["SLOT"]))
+ # At this point myrepo should be None, a valid name, or
+ # Package.UNKNOWN_REPO which we ignore.
+ if myrepo is not None and myrepo != Package.UNKNOWN_REPO:
+ pkg = "".join((pkg, _repo_separator, myrepo))
+ cpv_slot_list = [pkg]
+
+ mycp=mysplit[0]+"/"+mysplit[1]
+
+ # XXX- This is a temporary duplicate of code from the config constructor.
+ locations = [os.path.join(settings["PORTDIR"], "profiles")]
+ locations.extend(settings.profiles)
+ for ov in settings["PORTDIR_OVERLAY"].split():
+ profdir = os.path.join(normalize_path(ov), "profiles")
+ if os.path.isdir(profdir):
+ locations.append(profdir)
+ locations.append(os.path.join(settings["PORTAGE_CONFIGROOT"],
+ USER_CONFIG_PATH))
+ locations.reverse()
+ pmasklists = []
+ for profile in locations:
+ pmask_filename = os.path.join(profile, "package.mask")
+ pmasklists.append((pmask_filename, grablines(pmask_filename, recursive=1)))
+
+ pmaskdict = settings._mask_manager._pmaskdict
+ if mycp in pmaskdict:
+ for x in pmaskdict[mycp]:
+ if match_from_list(x, cpv_slot_list):
+ x = x.without_repo
+ for pmask in pmasklists:
+ comment = ""
+ comment_valid = -1
+ pmask_filename = pmask[0]
+ for i in range(len(pmask[1])):
+ l = pmask[1][i].strip()
+ try:
+ l_atom = Atom(l, allow_repo=True,
+ allow_wildcard=True).without_repo
+ except InvalidAtom:
+ l_atom = None
+ if l == "":
+ comment = ""
+ comment_valid = -1
+ elif l[0] == "#":
+ comment += (l+"\n")
+ comment_valid = i + 1
+ elif l_atom == x:
+ if comment_valid != i:
+ comment = ""
+ if return_location:
+ return (comment, pmask_filename)
+ else:
+ return comment
+ elif comment_valid != -1:
+ # Apparently this comment applies to multiple masks, so
+ # it remains valid until a blank line is encountered.
+ comment_valid += 1
+ if return_location:
+ return (None, None)
+ else:
+ return None
diff --git a/portage_with_autodep/pym/portage/package/ebuild/getmaskingstatus.py b/portage_with_autodep/pym/portage/package/ebuild/getmaskingstatus.py
new file mode 100644
index 0000000..4c65fcc
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/getmaskingstatus.py
@@ -0,0 +1,174 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['getmaskingstatus']
+
+import sys
+
+import portage
+from portage import eapi_is_supported, _eapi_is_deprecated
+from portage.dep import match_from_list, _slot_separator, _repo_separator
+from portage.localization import _
+from portage.package.ebuild.config import config
+from portage.versions import catpkgsplit, cpv_getkey
+from _emerge.Package import Package
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+class _UnmaskHint(object):
+
+ __slots__ = ('key', 'value')
+
+ def __init__(self, key, value):
+ self.key = key
+ self.value = value
+
+class _MaskReason(object):
+
+ __slots__ = ('category', 'message', 'unmask_hint')
+
+ def __init__(self, category, message, unmask_hint=None):
+ self.category = category
+ self.message = message
+ self.unmask_hint = unmask_hint
+
+def getmaskingstatus(mycpv, settings=None, portdb=None, myrepo=None):
+ if settings is None:
+ settings = config(clone=portage.settings)
+ if portdb is None:
+ portdb = portage.portdb
+
+ return [mreason.message for \
+ mreason in _getmaskingstatus(mycpv, settings, portdb,myrepo)]
+
+def _getmaskingstatus(mycpv, settings, portdb, myrepo=None):
+
+ metadata = None
+ installed = False
+ if not isinstance(mycpv, basestring):
+ # emerge passed in a Package instance
+ pkg = mycpv
+ mycpv = pkg.cpv
+ metadata = pkg.metadata
+ installed = pkg.installed
+
+ mysplit = catpkgsplit(mycpv)
+ if not mysplit:
+ raise ValueError(_("invalid CPV: %s") % mycpv)
+ if metadata is None:
+ db_keys = list(portdb._aux_cache_keys)
+ try:
+ metadata = dict(zip(db_keys, portdb.aux_get(mycpv, db_keys, myrepo=myrepo)))
+ except KeyError:
+ if not portdb.cpv_exists(mycpv):
+ raise
+ return [_MaskReason("corruption", "corruption")]
+ if "?" in metadata["LICENSE"]:
+ settings.setcpv(mycpv, mydb=metadata)
+ metadata["USE"] = settings["PORTAGE_USE"]
+ else:
+ metadata["USE"] = ""
+
+ rValue = []
+
+ # profile checking
+ if settings._getProfileMaskAtom(mycpv, metadata):
+ rValue.append(_MaskReason("profile", "profile"))
+
+ # package.mask checking
+ if settings._getMaskAtom(mycpv, metadata):
+ rValue.append(_MaskReason("package.mask", "package.mask", _UnmaskHint("p_mask", None)))
+
+ # keywords checking
+ eapi = metadata["EAPI"]
+ mygroups = settings._getKeywords(mycpv, metadata)
+ licenses = metadata["LICENSE"]
+ properties = metadata["PROPERTIES"]
+ if eapi.startswith("-"):
+ eapi = eapi[1:]
+ if not eapi_is_supported(eapi):
+ return [_MaskReason("EAPI", "EAPI %s" % eapi)]
+ elif _eapi_is_deprecated(eapi) and not installed:
+ return [_MaskReason("EAPI", "EAPI %s" % eapi)]
+ egroups = settings.configdict["backupenv"].get(
+ "ACCEPT_KEYWORDS", "").split()
+ global_accept_keywords = settings.get("ACCEPT_KEYWORDS", "")
+ pgroups = global_accept_keywords.split()
+ myarch = settings["ARCH"]
+ if pgroups and myarch not in pgroups:
+ """For operating systems other than Linux, ARCH is not necessarily a
+ valid keyword."""
+ myarch = pgroups[0].lstrip("~")
+
+ # NOTE: This logic is copied from KeywordsManager.getMissingKeywords().
+ unmaskgroups = settings._keywords_manager.getPKeywords(mycpv,
+ metadata["SLOT"], metadata["repository"], global_accept_keywords)
+ pgroups.extend(unmaskgroups)
+ if unmaskgroups or egroups:
+ pgroups = settings._keywords_manager._getEgroups(egroups, pgroups)
+ else:
+ pgroups = set(pgroups)
+
+ kmask = "missing"
+ kmask_hint = None
+
+ if '**' in pgroups:
+ kmask = None
+ else:
+ for keyword in pgroups:
+ if keyword in mygroups:
+ kmask = None
+ break
+
+ if kmask:
+ for gp in mygroups:
+ if gp=="*":
+ kmask=None
+ break
+ elif gp=="-"+myarch and myarch in pgroups:
+ kmask="-"+myarch
+ break
+ elif gp=="~"+myarch and myarch in pgroups:
+ kmask="~"+myarch
+ kmask_hint = _UnmaskHint("unstable keyword", kmask)
+ break
+
+ if kmask == "missing":
+ kmask_hint = _UnmaskHint("unstable keyword", "**")
+
+ try:
+ missing_licenses = settings._getMissingLicenses(mycpv, metadata)
+ if missing_licenses:
+ allowed_tokens = set(["||", "(", ")"])
+ allowed_tokens.update(missing_licenses)
+ license_split = licenses.split()
+ license_split = [x for x in license_split \
+ if x in allowed_tokens]
+ msg = license_split[:]
+ msg.append("license(s)")
+ rValue.append(_MaskReason("LICENSE", " ".join(msg), _UnmaskHint("license", set(missing_licenses))))
+ except portage.exception.InvalidDependString as e:
+ rValue.append(_MaskReason("invalid", "LICENSE: "+str(e)))
+
+ try:
+ missing_properties = settings._getMissingProperties(mycpv, metadata)
+ if missing_properties:
+ allowed_tokens = set(["||", "(", ")"])
+ allowed_tokens.update(missing_properties)
+ properties_split = properties.split()
+ properties_split = [x for x in properties_split \
+ if x in allowed_tokens]
+ msg = properties_split[:]
+ msg.append("properties")
+ rValue.append(_MaskReason("PROPERTIES", " ".join(msg)))
+ except portage.exception.InvalidDependString as e:
+ rValue.append(_MaskReason("invalid", "PROPERTIES: "+str(e)))
+
+ # Only show KEYWORDS masks for installed packages
+ # if they're not masked for any other reason.
+ if kmask and (not installed or not rValue):
+ rValue.append(_MaskReason("KEYWORDS",
+ kmask + " keyword", unmask_hint=kmask_hint))
+
+ return rValue
diff --git a/portage_with_autodep/pym/portage/package/ebuild/prepare_build_dirs.py b/portage_with_autodep/pym/portage/package/ebuild/prepare_build_dirs.py
new file mode 100644
index 0000000..616dc2e
--- /dev/null
+++ b/portage_with_autodep/pym/portage/package/ebuild/prepare_build_dirs.py
@@ -0,0 +1,370 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['prepare_build_dirs']
+
+import errno
+import gzip
+import shutil
+import stat
+import time
+
+from portage import os, _encodings, _unicode_encode, _unicode_decode
+from portage.data import portage_gid, portage_uid, secpass
+from portage.exception import DirectoryNotFound, FileNotFound, \
+ OperationNotPermitted, PermissionDenied, PortageException
+from portage.localization import _
+from portage.output import colorize
+from portage.util import apply_recursive_permissions, \
+ apply_secpass_permissions, ensure_dirs, normalize_path, writemsg
+
+def prepare_build_dirs(myroot=None, settings=None, cleanup=False):
+ """
+ The myroot parameter is ignored.
+ """
+ myroot = None
+
+ if settings is None:
+ raise TypeError("settings argument is required")
+
+ mysettings = settings
+ clean_dirs = [mysettings["HOME"]]
+
+ # We enable cleanup when we want to make sure old cruft (such as the old
+ # environment) doesn't interfere with the current phase.
+ if cleanup and 'keeptemp' not in mysettings.features:
+ clean_dirs.append(mysettings["T"])
+
+ for clean_dir in clean_dirs:
+ try:
+ shutil.rmtree(clean_dir)
+ except OSError as oe:
+ if errno.ENOENT == oe.errno:
+ pass
+ elif errno.EPERM == oe.errno:
+ writemsg("%s\n" % oe, noiselevel=-1)
+ writemsg(_("Operation Not Permitted: rmtree('%s')\n") % \
+ clean_dir, noiselevel=-1)
+ return 1
+ else:
+ raise
+
+ def makedirs(dir_path):
+ try:
+ os.makedirs(dir_path)
+ except OSError as oe:
+ if errno.EEXIST == oe.errno:
+ pass
+ elif errno.EPERM == oe.errno:
+ writemsg("%s\n" % oe, noiselevel=-1)
+ writemsg(_("Operation Not Permitted: makedirs('%s')\n") % \
+ dir_path, noiselevel=-1)
+ return False
+ else:
+ raise
+ return True
+
+ mysettings["PKG_LOGDIR"] = os.path.join(mysettings["T"], "logging")
+
+ mydirs = [os.path.dirname(mysettings["PORTAGE_BUILDDIR"])]
+ mydirs.append(os.path.dirname(mydirs[-1]))
+
+ try:
+ for mydir in mydirs:
+ ensure_dirs(mydir)
+ try:
+ apply_secpass_permissions(mydir,
+ gid=portage_gid, uid=portage_uid, mode=0o70, mask=0)
+ except PortageException:
+ if not os.path.isdir(mydir):
+ raise
+ for dir_key in ("PORTAGE_BUILDDIR", "HOME", "PKG_LOGDIR", "T"):
+ """These directories don't necessarily need to be group writable.
+ However, the setup phase is commonly run as a privileged user prior
+ to the other phases being run by an unprivileged user. Currently,
+ we use the portage group to ensure that the unprivleged user still
+ has write access to these directories in any case."""
+ ensure_dirs(mysettings[dir_key], mode=0o775)
+ apply_secpass_permissions(mysettings[dir_key],
+ uid=portage_uid, gid=portage_gid)
+ except PermissionDenied as e:
+ writemsg(_("Permission Denied: %s\n") % str(e), noiselevel=-1)
+ return 1
+ except OperationNotPermitted as e:
+ writemsg(_("Operation Not Permitted: %s\n") % str(e), noiselevel=-1)
+ return 1
+ except FileNotFound as e:
+ writemsg(_("File Not Found: '%s'\n") % str(e), noiselevel=-1)
+ return 1
+
+ # Reset state for things like noauto and keepwork in FEATURES.
+ for x in ('.die_hooks',):
+ try:
+ os.unlink(os.path.join(mysettings['PORTAGE_BUILDDIR'], x))
+ except OSError:
+ pass
+
+ _prepare_workdir(mysettings)
+ if mysettings.get("EBUILD_PHASE") not in ("info", "fetch", "pretend"):
+ # Avoid spurious permissions adjustments when fetching with
+ # a temporary PORTAGE_TMPDIR setting (for fetchonly).
+ _prepare_features_dirs(mysettings)
+
+def _adjust_perms_msg(settings, msg):
+
+ def write(msg):
+ writemsg(msg, noiselevel=-1)
+
+ background = settings.get("PORTAGE_BACKGROUND") == "1"
+ log_path = settings.get("PORTAGE_LOG_FILE")
+ log_file = None
+
+ if background and log_path is not None:
+ try:
+ log_file = open(_unicode_encode(log_path,
+ encoding=_encodings['fs'], errors='strict'), mode='ab')
+ except IOError:
+ def write(msg):
+ pass
+ else:
+ if log_path.endswith('.gz'):
+ log_file = gzip.GzipFile(filename='',
+ mode='ab', fileobj=log_file)
+ def write(msg):
+ log_file.write(_unicode_encode(msg))
+ log_file.flush()
+
+ try:
+ write(msg)
+ finally:
+ if log_file is not None:
+ log_file.close()
+
+def _prepare_features_dirs(mysettings):
+
+ # Use default ABI libdir in accordance with bug #355283.
+ libdir = None
+ default_abi = mysettings.get("DEFAULT_ABI")
+ if default_abi:
+ libdir = mysettings.get("LIBDIR_" + default_abi)
+ if not libdir:
+ libdir = "lib"
+
+ features_dirs = {
+ "ccache":{
+ "path_dir": "/usr/%s/ccache/bin" % (libdir,),
+ "basedir_var":"CCACHE_DIR",
+ "default_dir":os.path.join(mysettings["PORTAGE_TMPDIR"], "ccache"),
+ "always_recurse":False},
+ "distcc":{
+ "path_dir": "/usr/%s/distcc/bin" % (libdir,),
+ "basedir_var":"DISTCC_DIR",
+ "default_dir":os.path.join(mysettings["BUILD_PREFIX"], ".distcc"),
+ "subdirs":("lock", "state"),
+ "always_recurse":True}
+ }
+ dirmode = 0o2070
+ filemode = 0o60
+ modemask = 0o2
+ restrict = mysettings.get("PORTAGE_RESTRICT","").split()
+ droppriv = secpass >= 2 and \
+ "userpriv" in mysettings.features and \
+ "userpriv" not in restrict
+ for myfeature, kwargs in features_dirs.items():
+ if myfeature in mysettings.features:
+ failure = False
+ basedir = mysettings.get(kwargs["basedir_var"])
+ if basedir is None or not basedir.strip():
+ basedir = kwargs["default_dir"]
+ mysettings[kwargs["basedir_var"]] = basedir
+ try:
+ path_dir = kwargs["path_dir"]
+ if not os.path.isdir(path_dir):
+ raise DirectoryNotFound(path_dir)
+
+ mydirs = [mysettings[kwargs["basedir_var"]]]
+ if "subdirs" in kwargs:
+ for subdir in kwargs["subdirs"]:
+ mydirs.append(os.path.join(basedir, subdir))
+ for mydir in mydirs:
+ modified = ensure_dirs(mydir)
+ # Generally, we only want to apply permissions for
+ # initial creation. Otherwise, we don't know exactly what
+ # permissions the user wants, so should leave them as-is.
+ droppriv_fix = False
+ if droppriv:
+ st = os.stat(mydir)
+ if st.st_gid != portage_gid or \
+ not dirmode == (stat.S_IMODE(st.st_mode) & dirmode):
+ droppriv_fix = True
+ if not droppriv_fix:
+ # Check permissions of files in the directory.
+ for filename in os.listdir(mydir):
+ try:
+ subdir_st = os.lstat(
+ os.path.join(mydir, filename))
+ except OSError:
+ continue
+ if subdir_st.st_gid != portage_gid or \
+ ((stat.S_ISDIR(subdir_st.st_mode) and \
+ not dirmode == (stat.S_IMODE(subdir_st.st_mode) & dirmode))):
+ droppriv_fix = True
+ break
+
+ if droppriv_fix:
+ _adjust_perms_msg(mysettings,
+ colorize("WARN", " * ") + \
+ _("Adjusting permissions "
+ "for FEATURES=userpriv: '%s'\n") % mydir)
+ elif modified:
+ _adjust_perms_msg(mysettings,
+ colorize("WARN", " * ") + \
+ _("Adjusting permissions "
+ "for FEATURES=%s: '%s'\n") % (myfeature, mydir))
+
+ if modified or kwargs["always_recurse"] or droppriv_fix:
+ def onerror(e):
+ raise # The feature is disabled if a single error
+ # occurs during permissions adjustment.
+ if not apply_recursive_permissions(mydir,
+ gid=portage_gid, dirmode=dirmode, dirmask=modemask,
+ filemode=filemode, filemask=modemask, onerror=onerror):
+ raise OperationNotPermitted(
+ _("Failed to apply recursive permissions for the portage group."))
+
+ except DirectoryNotFound as e:
+ failure = True
+ writemsg(_("\n!!! Directory does not exist: '%s'\n") % \
+ (e,), noiselevel=-1)
+ writemsg(_("!!! Disabled FEATURES='%s'\n") % myfeature,
+ noiselevel=-1)
+
+ except PortageException as e:
+ failure = True
+ writemsg("\n!!! %s\n" % str(e), noiselevel=-1)
+ writemsg(_("!!! Failed resetting perms on %s='%s'\n") % \
+ (kwargs["basedir_var"], basedir), noiselevel=-1)
+ writemsg(_("!!! Disabled FEATURES='%s'\n") % myfeature,
+ noiselevel=-1)
+
+ if failure:
+ mysettings.features.remove(myfeature)
+ time.sleep(5)
+
+def _prepare_workdir(mysettings):
+ workdir_mode = 0o700
+ try:
+ mode = mysettings["PORTAGE_WORKDIR_MODE"]
+ if mode.isdigit():
+ parsed_mode = int(mode, 8)
+ elif mode == "":
+ raise KeyError()
+ else:
+ raise ValueError()
+ if parsed_mode & 0o7777 != parsed_mode:
+ raise ValueError("Invalid file mode: %s" % mode)
+ else:
+ workdir_mode = parsed_mode
+ except KeyError as e:
+ writemsg(_("!!! PORTAGE_WORKDIR_MODE is unset, using %s.\n") % oct(workdir_mode))
+ except ValueError as e:
+ if len(str(e)) > 0:
+ writemsg("%s\n" % e)
+ writemsg(_("!!! Unable to parse PORTAGE_WORKDIR_MODE='%s', using %s.\n") % \
+ (mysettings["PORTAGE_WORKDIR_MODE"], oct(workdir_mode)))
+ mysettings["PORTAGE_WORKDIR_MODE"] = oct(workdir_mode).replace('o', '')
+ try:
+ apply_secpass_permissions(mysettings["WORKDIR"],
+ uid=portage_uid, gid=portage_gid, mode=workdir_mode)
+ except FileNotFound:
+ pass # ebuild.sh will create it
+
+ if mysettings.get("PORT_LOGDIR", "") == "":
+ while "PORT_LOGDIR" in mysettings:
+ del mysettings["PORT_LOGDIR"]
+ if "PORT_LOGDIR" in mysettings:
+ try:
+ modified = ensure_dirs(mysettings["PORT_LOGDIR"])
+ if modified:
+ # Only initialize group/mode if the directory doesn't
+ # exist, so that we don't override permissions if they
+ # were previously set by the administrator.
+ # NOTE: These permissions should be compatible with our
+ # default logrotate config as discussed in bug 374287.
+ apply_secpass_permissions(mysettings["PORT_LOGDIR"],
+ uid=portage_uid, gid=portage_gid, mode=0o2770)
+ except PortageException as e:
+ writemsg("!!! %s\n" % str(e), noiselevel=-1)
+ writemsg(_("!!! Permission issues with PORT_LOGDIR='%s'\n") % \
+ mysettings["PORT_LOGDIR"], noiselevel=-1)
+ writemsg(_("!!! Disabling logging.\n"), noiselevel=-1)
+ while "PORT_LOGDIR" in mysettings:
+ del mysettings["PORT_LOGDIR"]
+
+ compress_log_ext = ''
+ if 'compress-build-logs' in mysettings.features:
+ compress_log_ext = '.gz'
+
+ logdir_subdir_ok = False
+ if "PORT_LOGDIR" in mysettings and \
+ os.access(mysettings["PORT_LOGDIR"], os.W_OK):
+ logdir = normalize_path(mysettings["PORT_LOGDIR"])
+ logid_path = os.path.join(mysettings["PORTAGE_BUILDDIR"], ".logid")
+ if not os.path.exists(logid_path):
+ open(_unicode_encode(logid_path), 'w')
+ logid_time = _unicode_decode(time.strftime("%Y%m%d-%H%M%S",
+ time.gmtime(os.stat(logid_path).st_mtime)),
+ encoding=_encodings['content'], errors='replace')
+
+ if "split-log" in mysettings.features:
+ log_subdir = os.path.join(logdir, "build", mysettings["CATEGORY"])
+ mysettings["PORTAGE_LOG_FILE"] = os.path.join(
+ log_subdir, "%s:%s.log%s" %
+ (mysettings["PF"], logid_time, compress_log_ext))
+ else:
+ log_subdir = logdir
+ mysettings["PORTAGE_LOG_FILE"] = os.path.join(
+ logdir, "%s:%s:%s.log%s" % \
+ (mysettings["CATEGORY"], mysettings["PF"], logid_time,
+ compress_log_ext))
+
+ if log_subdir is logdir:
+ logdir_subdir_ok = True
+ else:
+ try:
+ _ensure_log_subdirs(logdir, log_subdir)
+ except PortageException as e:
+ writemsg(_unicode_decode("!!! %s\n") % (e,), noiselevel=-1)
+
+ if os.access(log_subdir, os.W_OK):
+ logdir_subdir_ok = True
+ else:
+ writemsg(_unicode_decode("!!! %s: %s\n") %
+ (_("Permission Denied"), log_subdir), noiselevel=-1)
+
+ if not logdir_subdir_ok:
+ # NOTE: When sesandbox is enabled, the local SELinux security policies
+ # may not allow output to be piped out of the sesandbox domain. The
+ # current policy will allow it to work when a pty is available, but
+ # not through a normal pipe. See bug #162404.
+ mysettings["PORTAGE_LOG_FILE"] = os.path.join(
+ mysettings["T"], "build.log%s" % compress_log_ext)
+
+def _ensure_log_subdirs(logdir, subdir):
+ """
+ This assumes that logdir exists, and creates subdirectories down
+ to subdir as necessary. The gid of logdir is copied to all
+ subdirectories, along with 0x2070 mode bits if present. Both logdir
+ and subdir are assumed to be normalized absolute paths.
+ """
+ st = os.stat(logdir)
+ gid = st.st_gid
+ grp_mode = 0o2070 & st.st_mode
+
+ logdir_split_len = len(logdir.split(os.sep))
+ subdir_split = subdir.split(os.sep)[logdir_split_len:]
+ subdir_split.reverse()
+ current = logdir
+ while subdir_split:
+ current = os.path.join(current, subdir_split.pop())
+ ensure_dirs(current, gid=gid, mode=grp_mode, mask=0)
diff --git a/portage_with_autodep/pym/portage/process.py b/portage_with_autodep/pym/portage/process.py
new file mode 100644
index 0000000..6866a2f
--- /dev/null
+++ b/portage_with_autodep/pym/portage/process.py
@@ -0,0 +1,427 @@
+# portage.py -- core Portage functionality
+# Copyright 1998-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+
+import atexit
+import signal
+import sys
+import traceback
+
+from portage import os
+from portage import _encodings
+from portage import _unicode_encode
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.util:dump_traceback',
+)
+
+from portage.const import BASH_BINARY, SANDBOX_BINARY, FAKEROOT_BINARY, AUTODEP_LIBRARY
+from portage.exception import CommandNotFound
+
+try:
+ import resource
+ max_fd_limit = resource.getrlimit(resource.RLIMIT_NOFILE)[0]
+except ImportError:
+ max_fd_limit = 256
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+if os.path.isdir("/proc/%i/fd" % os.getpid()):
+ def get_open_fds():
+ return (int(fd) for fd in os.listdir("/proc/%i/fd" % os.getpid()) \
+ if fd.isdigit())
+else:
+ def get_open_fds():
+ return range(max_fd_limit)
+
+sandbox_capable = (os.path.isfile(SANDBOX_BINARY) and
+ os.access(SANDBOX_BINARY, os.X_OK))
+
+autodep_capable = (os.path.isfile(AUTODEP_LIBRARY) and
+ os.access(AUTODEP_LIBRARY, os.X_OK))
+
+fakeroot_capable = (os.path.isfile(FAKEROOT_BINARY) and
+ os.access(FAKEROOT_BINARY, os.X_OK))
+
+def spawn_bash(mycommand, debug=False, opt_name=None, **keywords):
+ """
+ Spawns a bash shell running a specific commands
+
+ @param mycommand: The command for bash to run
+ @type mycommand: String
+ @param debug: Turn bash debugging on (set -x)
+ @type debug: Boolean
+ @param opt_name: Name of the spawned process (detaults to binary name)
+ @type opt_name: String
+ @param keywords: Extra Dictionary arguments to pass to spawn
+ @type keywords: Dictionary
+ """
+
+ args = [BASH_BINARY]
+ if not opt_name:
+ opt_name = os.path.basename(mycommand.split()[0])
+ if debug:
+ # Print commands and their arguments as they are executed.
+ args.append("-x")
+ args.append("-c")
+ args.append(mycommand)
+ return spawn(args, opt_name=opt_name, **keywords)
+
+def spawn_autodep(mycommand, opt_name=None, **keywords):
+ if not autodep_capable:
+ return spawn_bash(mycommand, opt_name=opt_name, **keywords)
+ if "env" not in keywords or "LOG_SOCKET" not in keywords["env"]:
+ return spawn_bash(mycommand, opt_name=opt_name, **keywords)
+
+ # Core part: tell the loader to preload logging library
+ keywords["env"]["LD_PRELOAD"]=AUTODEP_LIBRARY
+ return spawn_bash(mycommand, opt_name=opt_name, **keywords)
+
+def spawn_sandbox(mycommand, opt_name=None, **keywords):
+ if not sandbox_capable:
+ return spawn_bash(mycommand, opt_name=opt_name, **keywords)
+ args=[SANDBOX_BINARY]
+ if not opt_name:
+ opt_name = os.path.basename(mycommand.split()[0])
+ args.append(mycommand)
+ return spawn(args, opt_name=opt_name, **keywords)
+
+def spawn_fakeroot(mycommand, fakeroot_state=None, opt_name=None, **keywords):
+ args=[FAKEROOT_BINARY]
+ if not opt_name:
+ opt_name = os.path.basename(mycommand.split()[0])
+ if fakeroot_state:
+ open(fakeroot_state, "a").close()
+ args.append("-s")
+ args.append(fakeroot_state)
+ args.append("-i")
+ args.append(fakeroot_state)
+ args.append("--")
+ args.append(BASH_BINARY)
+ args.append("-c")
+ args.append(mycommand)
+ return spawn(args, opt_name=opt_name, **keywords)
+
+_exithandlers = []
+def atexit_register(func, *args, **kargs):
+ """Wrapper around atexit.register that is needed in order to track
+ what is registered. For example, when portage restarts itself via
+ os.execv, the atexit module does not work so we have to do it
+ manually by calling the run_exitfuncs() function in this module."""
+ _exithandlers.append((func, args, kargs))
+
+def run_exitfuncs():
+ """This should behave identically to the routine performed by
+ the atexit module at exit time. It's only necessary to call this
+ function when atexit will not work (because of os.execv, for
+ example)."""
+
+ # This function is a copy of the private atexit._run_exitfuncs()
+ # from the python 2.4.2 sources. The only difference from the
+ # original function is in the output to stderr.
+ exc_info = None
+ while _exithandlers:
+ func, targs, kargs = _exithandlers.pop()
+ try:
+ func(*targs, **kargs)
+ except SystemExit:
+ exc_info = sys.exc_info()
+ except: # No idea what they called, so we need this broad except here.
+ dump_traceback("Error in portage.process.run_exitfuncs", noiselevel=0)
+ exc_info = sys.exc_info()
+
+ if exc_info is not None:
+ if sys.hexversion >= 0x3000000:
+ raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])
+ else:
+ exec("raise exc_info[0], exc_info[1], exc_info[2]")
+
+atexit.register(run_exitfuncs)
+
+# We need to make sure that any processes spawned are killed off when
+# we exit. spawn() takes care of adding and removing pids to this list
+# as it creates and cleans up processes.
+spawned_pids = []
+def cleanup():
+ while spawned_pids:
+ pid = spawned_pids.pop()
+ try:
+ # With waitpid and WNOHANG, only check the
+ # first element of the tuple since the second
+ # element may vary (bug #337465).
+ if os.waitpid(pid, os.WNOHANG)[0] == 0:
+ os.kill(pid, signal.SIGTERM)
+ os.waitpid(pid, 0)
+ except OSError:
+ # This pid has been cleaned up outside
+ # of spawn().
+ pass
+
+atexit_register(cleanup)
+
+def spawn(mycommand, env={}, opt_name=None, fd_pipes=None, returnpid=False,
+ uid=None, gid=None, groups=None, umask=None, logfile=None,
+ path_lookup=True, pre_exec=None):
+ """
+ Spawns a given command.
+
+ @param mycommand: the command to execute
+ @type mycommand: String or List (Popen style list)
+ @param env: A dict of Key=Value pairs for env variables
+ @type env: Dictionary
+ @param opt_name: an optional name for the spawn'd process (defaults to the binary name)
+ @type opt_name: String
+ @param fd_pipes: A dict of mapping for pipes, { '0': stdin, '1': stdout } for example
+ @type fd_pipes: Dictionary
+ @param returnpid: Return the Process IDs for a successful spawn.
+ NOTE: This requires the caller clean up all the PIDs, otherwise spawn will clean them.
+ @type returnpid: Boolean
+ @param uid: User ID to spawn as; useful for dropping privilages
+ @type uid: Integer
+ @param gid: Group ID to spawn as; useful for dropping privilages
+ @type gid: Integer
+ @param groups: Group ID's to spawn in: useful for having the process run in multiple group contexts.
+ @type groups: List
+ @param umask: An integer representing the umask for the process (see man chmod for umask details)
+ @type umask: Integer
+ @param logfile: name of a file to use for logging purposes
+ @type logfile: String
+ @param path_lookup: If the binary is not fully specified then look for it in PATH
+ @type path_lookup: Boolean
+ @param pre_exec: A function to be called with no arguments just prior to the exec call.
+ @type pre_exec: callable
+
+ logfile requires stdout and stderr to be assigned to this process (ie not pointed
+ somewhere else.)
+
+ """
+
+ # mycommand is either a str or a list
+ if isinstance(mycommand, basestring):
+ mycommand = mycommand.split()
+
+ if sys.hexversion < 0x3000000:
+ # Avoid a potential UnicodeEncodeError from os.execve().
+ env_bytes = {}
+ for k, v in env.items():
+ env_bytes[_unicode_encode(k, encoding=_encodings['content'])] = \
+ _unicode_encode(v, encoding=_encodings['content'])
+ env = env_bytes
+ del env_bytes
+
+ # If an absolute path to an executable file isn't given
+ # search for it unless we've been told not to.
+ binary = mycommand[0]
+ if binary not in (BASH_BINARY, SANDBOX_BINARY, FAKEROOT_BINARY) and \
+ (not os.path.isabs(binary) or not os.path.isfile(binary)
+ or not os.access(binary, os.X_OK)):
+ binary = path_lookup and find_binary(binary) or None
+ if not binary:
+ raise CommandNotFound(mycommand[0])
+
+ # If we haven't been told what file descriptors to use
+ # default to propagating our stdin, stdout and stderr.
+ if fd_pipes is None:
+ fd_pipes = {
+ 0:sys.stdin.fileno(),
+ 1:sys.stdout.fileno(),
+ 2:sys.stderr.fileno(),
+ }
+
+ # mypids will hold the pids of all processes created.
+ mypids = []
+
+ if logfile:
+ # Using a log file requires that stdout and stderr
+ # are assigned to the process we're running.
+ if 1 not in fd_pipes or 2 not in fd_pipes:
+ raise ValueError(fd_pipes)
+
+ # Create a pipe
+ (pr, pw) = os.pipe()
+
+ # Create a tee process, giving it our stdout and stderr
+ # as well as the read end of the pipe.
+ mypids.extend(spawn(('tee', '-i', '-a', logfile),
+ returnpid=True, fd_pipes={0:pr,
+ 1:fd_pipes[1], 2:fd_pipes[2]}))
+
+ # We don't need the read end of the pipe, so close it.
+ os.close(pr)
+
+ # Assign the write end of the pipe to our stdout and stderr.
+ fd_pipes[1] = pw
+ fd_pipes[2] = pw
+
+ pid = os.fork()
+
+ if not pid:
+ try:
+ _exec(binary, mycommand, opt_name, fd_pipes,
+ env, gid, groups, uid, umask, pre_exec)
+ except SystemExit:
+ raise
+ except Exception as e:
+ # We need to catch _any_ exception so that it doesn't
+ # propagate out of this function and cause exiting
+ # with anything other than os._exit()
+ sys.stderr.write("%s:\n %s\n" % (e, " ".join(mycommand)))
+ traceback.print_exc()
+ sys.stderr.flush()
+ os._exit(1)
+
+ # Add the pid to our local and the global pid lists.
+ mypids.append(pid)
+ spawned_pids.append(pid)
+
+ # If we started a tee process the write side of the pipe is no
+ # longer needed, so close it.
+ if logfile:
+ os.close(pw)
+
+ # If the caller wants to handle cleaning up the processes, we tell
+ # it about all processes that were created.
+ if returnpid:
+ return mypids
+
+ # Otherwise we clean them up.
+ while mypids:
+
+ # Pull the last reader in the pipe chain. If all processes
+ # in the pipe are well behaved, it will die when the process
+ # it is reading from dies.
+ pid = mypids.pop(0)
+
+ # and wait for it.
+ retval = os.waitpid(pid, 0)[1]
+
+ # When it's done, we can remove it from the
+ # global pid list as well.
+ spawned_pids.remove(pid)
+
+ if retval:
+ # If it failed, kill off anything else that
+ # isn't dead yet.
+ for pid in mypids:
+ # With waitpid and WNOHANG, only check the
+ # first element of the tuple since the second
+ # element may vary (bug #337465).
+ if os.waitpid(pid, os.WNOHANG)[0] == 0:
+ os.kill(pid, signal.SIGTERM)
+ os.waitpid(pid, 0)
+ spawned_pids.remove(pid)
+
+ # If it got a signal, return the signal that was sent.
+ if (retval & 0xff):
+ return ((retval & 0xff) << 8)
+
+ # Otherwise, return its exit code.
+ return (retval >> 8)
+
+ # Everything succeeded
+ return 0
+
+def _exec(binary, mycommand, opt_name, fd_pipes, env, gid, groups, uid, umask,
+ pre_exec):
+
+ """
+ Execute a given binary with options
+
+ @param binary: Name of program to execute
+ @type binary: String
+ @param mycommand: Options for program
+ @type mycommand: String
+ @param opt_name: Name of process (defaults to binary)
+ @type opt_name: String
+ @param fd_pipes: Mapping pipes to destination; { 0:0, 1:1, 2:2 }
+ @type fd_pipes: Dictionary
+ @param env: Key,Value mapping for Environmental Variables
+ @type env: Dictionary
+ @param gid: Group ID to run the process under
+ @type gid: Integer
+ @param groups: Groups the Process should be in.
+ @type groups: Integer
+ @param uid: User ID to run the process under
+ @type uid: Integer
+ @param umask: an int representing a unix umask (see man chmod for umask details)
+ @type umask: Integer
+ @param pre_exec: A function to be called with no arguments just prior to the exec call.
+ @type pre_exec: callable
+ @rtype: None
+ @returns: Never returns (calls os.execve)
+ """
+
+ # If the process we're creating hasn't been given a name
+ # assign it the name of the executable.
+ if not opt_name:
+ opt_name = os.path.basename(binary)
+
+ # Set up the command's argument list.
+ myargs = [opt_name]
+ myargs.extend(mycommand[1:])
+
+ # Use default signal handlers in order to avoid problems
+ # killing subprocesses as reported in bug #353239.
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+ signal.signal(signal.SIGTERM, signal.SIG_DFL)
+
+ # Quiet killing of subprocesses by SIGPIPE (see bug #309001).
+ signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+
+ # Avoid issues triggered by inheritance of SIGQUIT handler from
+ # the parent process (see bug #289486).
+ signal.signal(signal.SIGQUIT, signal.SIG_DFL)
+
+ _setup_pipes(fd_pipes)
+
+ # Set requested process permissions.
+ if gid:
+ os.setgid(gid)
+ if groups:
+ os.setgroups(groups)
+ if uid:
+ os.setuid(uid)
+ if umask:
+ os.umask(umask)
+ if pre_exec:
+ pre_exec()
+
+ # And switch to the new process.
+ os.execve(binary, myargs, env)
+
+def _setup_pipes(fd_pipes):
+ """Setup pipes for a forked process."""
+ my_fds = {}
+ # To protect from cases where direct assignment could
+ # clobber needed fds ({1:2, 2:1}) we first dupe the fds
+ # into unused fds.
+ for fd in fd_pipes:
+ my_fds[fd] = os.dup(fd_pipes[fd])
+ # Then assign them to what they should be.
+ for fd in my_fds:
+ os.dup2(my_fds[fd], fd)
+ # Then close _all_ fds that haven't been explicitly
+ # requested to be kept open.
+ for fd in get_open_fds():
+ if fd not in my_fds:
+ try:
+ os.close(fd)
+ except OSError:
+ pass
+
+def find_binary(binary):
+ """
+ Given a binary name, find the binary in PATH
+
+ @param binary: Name of the binary to find
+ @type string
+ @rtype: None or string
+ @returns: full path to binary or None if the binary could not be located.
+ """
+ for path in os.environ.get("PATH", "").split(":"):
+ filename = "%s/%s" % (path, binary)
+ if os.access(filename, os.X_OK) and os.path.isfile(filename):
+ return filename
+ return None
diff --git a/portage_with_autodep/pym/portage/proxy/__init__.py b/portage_with_autodep/pym/portage/proxy/__init__.py
new file mode 100644
index 0000000..f98c564
--- /dev/null
+++ b/portage_with_autodep/pym/portage/proxy/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/proxy/lazyimport.py b/portage_with_autodep/pym/portage/proxy/lazyimport.py
new file mode 100644
index 0000000..ad4a542
--- /dev/null
+++ b/portage_with_autodep/pym/portage/proxy/lazyimport.py
@@ -0,0 +1,212 @@
+# Copyright 2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['lazyimport']
+
+import sys
+import types
+
+try:
+ import threading
+except ImportError:
+ import dummy_threading as threading
+
+from portage.proxy.objectproxy import ObjectProxy
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+_module_proxies = {}
+_module_proxies_lock = threading.RLock()
+
+def _preload_portage_submodules():
+ """
+ Load lazily referenced portage submodules into memory,
+ so imports won't fail during portage upgrade/downgrade.
+ Note that this recursively loads only the modules that
+ are lazily referenced by currently imported modules,
+ so some portage submodules may still remain unimported
+ after this function is called.
+ """
+ imported = set()
+ while True:
+ remaining = False
+ for name in list(_module_proxies):
+ if name.startswith('portage.'):
+ if name in imported:
+ continue
+ imported.add(name)
+ remaining = True
+ __import__(name)
+ _unregister_module_proxy(name)
+ if not remaining:
+ break
+
+def _register_module_proxy(name, proxy):
+ _module_proxies_lock.acquire()
+ try:
+ proxy_list = _module_proxies.get(name)
+ if proxy_list is None:
+ proxy_list = []
+ _module_proxies[name] = proxy_list
+ proxy_list.append(proxy)
+ finally:
+ _module_proxies_lock.release()
+
+def _unregister_module_proxy(name):
+ """
+ Destroy all proxies that reference the give module name. Also, check
+ for other proxies referenced by modules that have been imported and
+ destroy those proxies too. This way, destruction of a single proxy
+ can trigger destruction of all the rest. If a target module appears
+ to be partially imported (indicated when an AttributeError is caught),
+ this function will leave in place proxies that reference it.
+ """
+ _module_proxies_lock.acquire()
+ try:
+ if name in _module_proxies:
+ modules = sys.modules
+ for name, proxy_list in list(_module_proxies.items()):
+ if name not in modules:
+ continue
+ # First delete this name from the dict so that
+ # if this same thread reenters below, it won't
+ # enter this path again.
+ del _module_proxies[name]
+ try:
+ while proxy_list:
+ proxy = proxy_list.pop()
+ object.__getattribute__(proxy, '_get_target')()
+ except AttributeError:
+ # Apparently the target module is only partially
+ # imported, so proxies that reference it cannot
+ # be destroyed yet.
+ proxy_list.append(proxy)
+ _module_proxies[name] = proxy_list
+ finally:
+ _module_proxies_lock.release()
+
+class _LazyImport(ObjectProxy):
+
+ __slots__ = ('_scope', '_alias', '_name', '_target')
+
+ def __init__(self, scope, alias, name):
+ ObjectProxy.__init__(self)
+ object.__setattr__(self, '_scope', scope)
+ object.__setattr__(self, '_alias', alias)
+ object.__setattr__(self, '_name', name)
+ _register_module_proxy(name, self)
+
+ def _get_target(self):
+ try:
+ return object.__getattribute__(self, '_target')
+ except AttributeError:
+ pass
+ name = object.__getattribute__(self, '_name')
+ __import__(name)
+ target = sys.modules[name]
+ object.__setattr__(self, '_target', target)
+ object.__getattribute__(self, '_scope')[
+ object.__getattribute__(self, '_alias')] = target
+ _unregister_module_proxy(name)
+ return target
+
+class _LazyImportFrom(_LazyImport):
+
+ __slots__ = ('_attr_name',)
+
+ def __init__(self, scope, name, attr_name, alias):
+ object.__setattr__(self, '_attr_name', attr_name)
+ _LazyImport.__init__(self, scope, alias, name)
+
+ def _get_target(self):
+ try:
+ return object.__getattribute__(self, '_target')
+ except AttributeError:
+ pass
+ name = object.__getattribute__(self, '_name')
+ attr_name = object.__getattribute__(self, '_attr_name')
+ __import__(name)
+ # If called by _unregister_module_proxy() and the target module is
+ # partially imported, then the following getattr call may raise an
+ # AttributeError for _unregister_module_proxy() to handle.
+ target = getattr(sys.modules[name], attr_name)
+ object.__setattr__(self, '_target', target)
+ object.__getattribute__(self, '_scope')[
+ object.__getattribute__(self, '_alias')] = target
+ _unregister_module_proxy(name)
+ return target
+
+def lazyimport(scope, *args):
+ """
+ Create a proxy in the given scope in order to performa a lazy import.
+
+ Syntax Result
+ foo import foo
+ foo:bar,baz from foo import bar, baz
+ foo:bar@baz from foo import bar as baz
+
+ @param scope: the scope in which to place the import, typically globals()
+ @type myfilename: dict
+ @param args: module names to import
+ @type args: strings
+ """
+
+ modules = sys.modules
+
+ for s in args:
+ parts = s.split(':', 1)
+ if len(parts) == 1:
+ name = s
+
+ if not name or not isinstance(name, basestring):
+ raise ValueError(name)
+
+ components = name.split('.')
+ parent_scope = scope
+ for i in range(len(components)):
+ alias = components[i]
+ if i < len(components) - 1:
+ parent_name = ".".join(components[:i+1])
+ __import__(parent_name)
+ mod = modules.get(parent_name)
+ if not isinstance(mod, types.ModuleType):
+ # raise an exception
+ __import__(name)
+ parent_scope[alias] = mod
+ parent_scope = mod.__dict__
+ continue
+
+ already_imported = modules.get(name)
+ if already_imported is not None:
+ parent_scope[alias] = already_imported
+ else:
+ parent_scope[alias] = \
+ _LazyImport(parent_scope, alias, name)
+
+ else:
+ name, fromlist = parts
+ already_imported = modules.get(name)
+ fromlist = fromlist.split(',')
+ for s in fromlist:
+ if not s:
+ # This happens if there's an extra comma in fromlist.
+ raise ValueError('Empty module attribute name')
+ alias = s.split('@', 1)
+ if len(alias) == 1:
+ alias = alias[0]
+ attr_name = alias
+ else:
+ attr_name, alias = alias
+ if already_imported is not None:
+ try:
+ scope[alias] = getattr(already_imported, attr_name)
+ except AttributeError:
+ # Apparently the target module is only partially
+ # imported, so create a proxy.
+ already_imported = None
+ scope[alias] = \
+ _LazyImportFrom(scope, name, attr_name, alias)
+ else:
+ scope[alias] = \
+ _LazyImportFrom(scope, name, attr_name, alias)
diff --git a/portage_with_autodep/pym/portage/proxy/objectproxy.py b/portage_with_autodep/pym/portage/proxy/objectproxy.py
new file mode 100644
index 0000000..92b36d1
--- /dev/null
+++ b/portage_with_autodep/pym/portage/proxy/objectproxy.py
@@ -0,0 +1,91 @@
+# Copyright 2008-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+
+__all__ = ['ObjectProxy']
+
+class ObjectProxy(object):
+
+ """
+ Object that acts as a proxy to another object, forwarding
+ attribute accesses and method calls. This can be useful
+ for implementing lazy initialization.
+ """
+
+ __slots__ = ()
+
+ def _get_target(self):
+ raise NotImplementedError(self)
+
+ def __getattribute__(self, attr):
+ result = object.__getattribute__(self, '_get_target')()
+ return getattr(result, attr)
+
+ def __setattr__(self, attr, value):
+ result = object.__getattribute__(self, '_get_target')()
+ setattr(result, attr, value)
+
+ def __call__(self, *args, **kwargs):
+ result = object.__getattribute__(self, '_get_target')()
+ return result(*args, **kwargs)
+
+ def __setitem__(self, key, value):
+ object.__getattribute__(self, '_get_target')()[key] = value
+
+ def __getitem__(self, key):
+ return object.__getattribute__(self, '_get_target')()[key]
+
+ def __delitem__(self, key):
+ del object.__getattribute__(self, '_get_target')()[key]
+
+ def __contains__(self, key):
+ return key in object.__getattribute__(self, '_get_target')()
+
+ def __iter__(self):
+ return iter(object.__getattribute__(self, '_get_target')())
+
+ def __len__(self):
+ return len(object.__getattribute__(self, '_get_target')())
+
+ def __repr__(self):
+ return repr(object.__getattribute__(self, '_get_target')())
+
+ def __str__(self):
+ return str(object.__getattribute__(self, '_get_target')())
+
+ def __add__(self, other):
+ return self.__str__() + other
+
+ def __hash__(self):
+ return hash(object.__getattribute__(self, '_get_target')())
+
+ def __ge__(self, other):
+ return object.__getattribute__(self, '_get_target')() >= other
+
+ def __gt__(self, other):
+ return object.__getattribute__(self, '_get_target')() > other
+
+ def __le__(self, other):
+ return object.__getattribute__(self, '_get_target')() <= other
+
+ def __lt__(self, other):
+ return object.__getattribute__(self, '_get_target')() < other
+
+ def __eq__(self, other):
+ return object.__getattribute__(self, '_get_target')() == other
+
+ def __ne__(self, other):
+ return object.__getattribute__(self, '_get_target')() != other
+
+ def __bool__(self):
+ return bool(object.__getattribute__(self, '_get_target')())
+
+ if sys.hexversion < 0x3000000:
+ __nonzero__ = __bool__
+
+ def __unicode__(self):
+ return unicode(object.__getattribute__(self, '_get_target')())
+
+ def __int__(self):
+ return int(object.__getattribute__(self, '_get_target')())
diff --git a/portage_with_autodep/pym/portage/repository/__init__.py b/portage_with_autodep/pym/portage/repository/__init__.py
new file mode 100644
index 0000000..21a391a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/repository/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/repository/config.py b/portage_with_autodep/pym/portage/repository/config.py
new file mode 100644
index 0000000..9f0bb99
--- /dev/null
+++ b/portage_with_autodep/pym/portage/repository/config.py
@@ -0,0 +1,504 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import io
+import logging
+import re
+
+try:
+ from configparser import SafeConfigParser, ParsingError
+except ImportError:
+ from ConfigParser import SafeConfigParser, ParsingError
+from portage import os
+from portage.const import USER_CONFIG_PATH, REPO_NAME_LOC
+from portage.env.loaders import KeyValuePairFileLoader
+from portage.util import normalize_path, writemsg, writemsg_level, shlex_split
+from portage.localization import _
+from portage import _unicode_encode
+from portage import _encodings
+
+_repo_name_sub_re = re.compile(r'[^\w-]')
+
+def _gen_valid_repo(name):
+ """
+ Substitute hyphen in place of characters that don't conform to PMS 3.1.5,
+ and strip hyphen from left side if necessary. This returns None if the
+ given name contains no valid characters.
+ """
+ name = _repo_name_sub_re.sub(' ', name.strip())
+ name = '-'.join(name.split())
+ name = name.lstrip('-')
+ if not name:
+ name = None
+ return name
+
+class RepoConfig(object):
+ """Stores config of one repository"""
+
+ __slots__ = ['aliases', 'eclass_overrides', 'eclass_locations', 'location', 'user_location', 'masters', 'main_repo',
+ 'missing_repo_name', 'name', 'priority', 'sync', 'format']
+
+ def __init__(self, name, repo_opts):
+ """Build a RepoConfig with options in repo_opts
+ Try to read repo_name in repository location, but if
+ it is not found use variable name as repository name"""
+ aliases = repo_opts.get('aliases')
+ if aliases is not None:
+ aliases = tuple(aliases.split())
+ self.aliases = aliases
+
+ eclass_overrides = repo_opts.get('eclass-overrides')
+ if eclass_overrides is not None:
+ eclass_overrides = tuple(eclass_overrides.split())
+ self.eclass_overrides = eclass_overrides
+ #Locations are computed later.
+ self.eclass_locations = None
+
+ #Masters are only read from layout.conf.
+ self.masters = None
+
+ #The main-repo key makes only sense for the 'DEFAULT' section.
+ self.main_repo = repo_opts.get('main-repo')
+
+ priority = repo_opts.get('priority')
+ if priority is not None:
+ try:
+ priority = int(priority)
+ except ValueError:
+ priority = None
+ self.priority = priority
+
+ sync = repo_opts.get('sync')
+ if sync is not None:
+ sync = sync.strip()
+ self.sync = sync
+
+ format = repo_opts.get('format')
+ if format is not None:
+ format = format.strip()
+ self.format = format
+
+ location = repo_opts.get('location')
+ self.user_location = location
+ if location is not None and location.strip():
+ if os.path.isdir(location):
+ location = os.path.realpath(location)
+ else:
+ location = None
+ self.location = location
+
+ missing = True
+ if self.location is not None:
+ name, missing = self._read_repo_name(self.location)
+ # We must ensure that the name conforms to PMS 3.1.5
+ # in order to avoid InvalidAtom exceptions when we
+ # use it to generate atoms.
+ name = _gen_valid_repo(name)
+ if not name:
+ # name only contains invalid characters
+ name = "x-" + os.path.basename(self.location)
+ name = _gen_valid_repo(name)
+ # If basename only contains whitespace then the
+ # end result is name = 'x-'.
+
+ elif name == "DEFAULT":
+ missing = False
+ self.name = name
+ self.missing_repo_name = missing
+
+ def update(self, new_repo):
+ """Update repository with options in another RepoConfig"""
+ if new_repo.aliases is not None:
+ self.aliases = new_repo.aliases
+ if new_repo.eclass_overrides is not None:
+ self.eclass_overrides = new_repo.eclass_overrides
+ if new_repo.masters is not None:
+ self.masters = new_repo.masters
+ if new_repo.name is not None:
+ self.name = new_repo.name
+ self.missing_repo_name = new_repo.missing_repo_name
+ if new_repo.user_location is not None:
+ self.user_location = new_repo.user_location
+ if new_repo.location is not None:
+ self.location = new_repo.location
+ if new_repo.priority is not None:
+ self.priority = new_repo.priority
+ if new_repo.sync is not None:
+ self.sync = new_repo.sync
+
+ def _read_repo_name(self, repo_path):
+ """
+ Read repo_name from repo_path.
+ Returns repo_name, missing.
+ """
+ repo_name_path = os.path.join(repo_path, REPO_NAME_LOC)
+ try:
+ return io.open(
+ _unicode_encode(repo_name_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'],
+ errors='replace').readline().strip(), False
+ except EnvironmentError:
+ return "x-" + os.path.basename(repo_path), True
+
+ def info_string(self):
+ """
+ Returns a formatted string containing informations about the repository.
+ Used by emerge --info.
+ """
+ indent = " " * 4
+ repo_msg = []
+ repo_msg.append(self.name)
+ if self.format:
+ repo_msg.append(indent + "format: " + self.format)
+ if self.user_location:
+ repo_msg.append(indent + "location: " + self.user_location)
+ if self.sync:
+ repo_msg.append(indent + "sync: " + self.sync)
+ if self.masters:
+ repo_msg.append(indent + "masters: " + " ".join(master.name for master in self.masters))
+ if self.priority is not None:
+ repo_msg.append(indent + "priority: " + str(self.priority))
+ if self.aliases:
+ repo_msg.append(indent + "aliases: " + " ".join(self.aliases))
+ if self.eclass_overrides:
+ repo_msg.append(indent + "eclass_overrides: " + \
+ " ".join(self.eclass_overrides))
+ repo_msg.append("")
+ return "\n".join(repo_msg)
+
+class RepoConfigLoader(object):
+ """Loads and store config of several repositories, loaded from PORTDIR_OVERLAY or repos.conf"""
+ def __init__(self, paths, settings):
+ """Load config from files in paths"""
+ def parse(paths, prepos, ignored_map, ignored_location_map):
+ """Parse files in paths to load config"""
+ parser = SafeConfigParser()
+ try:
+ parser.read(paths)
+ except ParsingError as e:
+ writemsg(_("!!! Error while reading repo config file: %s\n") % e, noiselevel=-1)
+ prepos['DEFAULT'] = RepoConfig("DEFAULT", parser.defaults())
+ for sname in parser.sections():
+ optdict = {}
+ for oname in parser.options(sname):
+ optdict[oname] = parser.get(sname, oname)
+
+ repo = RepoConfig(sname, optdict)
+ if repo.location and not os.path.exists(repo.location):
+ writemsg(_("!!! Invalid repos.conf entry '%s'"
+ " (not a dir): '%s'\n") % (sname, repo.location), noiselevel=-1)
+ continue
+
+ if repo.name in prepos:
+ old_location = prepos[repo.name].location
+ if old_location is not None and repo.location is not None and old_location != repo.location:
+ ignored_map.setdefault(repo.name, []).append(old_location)
+ ignored_location_map[old_location] = repo.name
+ prepos[repo.name].update(repo)
+ else:
+ prepos[repo.name] = repo
+
+ def add_overlays(portdir, portdir_overlay, prepos, ignored_map, ignored_location_map):
+ """Add overlays in PORTDIR_OVERLAY as repositories"""
+ overlays = []
+ if portdir:
+ portdir = normalize_path(portdir)
+ overlays.append(portdir)
+ port_ov = [normalize_path(i) for i in shlex_split(portdir_overlay)]
+ overlays.extend(port_ov)
+ default_repo_opts = {}
+ if prepos['DEFAULT'].aliases is not None:
+ default_repo_opts['aliases'] = \
+ ' '.join(prepos['DEFAULT'].aliases)
+ if prepos['DEFAULT'].eclass_overrides is not None:
+ default_repo_opts['eclass-overrides'] = \
+ ' '.join(prepos['DEFAULT'].eclass_overrides)
+ if prepos['DEFAULT'].masters is not None:
+ default_repo_opts['masters'] = \
+ ' '.join(prepos['DEFAULT'].masters)
+ if overlays:
+ #overlay priority is negative because we want them to be looked before any other repo
+ base_priority = 0
+ for ov in overlays:
+ if os.path.isdir(ov):
+ repo_opts = default_repo_opts.copy()
+ repo_opts['location'] = ov
+ repo = RepoConfig(None, repo_opts)
+ repo_conf_opts = prepos.get(repo.name)
+ if repo_conf_opts is not None:
+ if repo_conf_opts.aliases is not None:
+ repo_opts['aliases'] = \
+ ' '.join(repo_conf_opts.aliases)
+ if repo_conf_opts.eclass_overrides is not None:
+ repo_opts['eclass-overrides'] = \
+ ' '.join(repo_conf_opts.eclass_overrides)
+ if repo_conf_opts.masters is not None:
+ repo_opts['masters'] = \
+ ' '.join(repo_conf_opts.masters)
+ repo = RepoConfig(repo.name, repo_opts)
+ if repo.name in prepos:
+ old_location = prepos[repo.name].location
+ if old_location is not None and old_location != repo.location:
+ ignored_map.setdefault(repo.name, []).append(old_location)
+ ignored_location_map[old_location] = repo.name
+ if old_location == portdir:
+ portdir = repo.user_location
+ prepos[repo.name].update(repo)
+ repo = prepos[repo.name]
+ else:
+ prepos[repo.name] = repo
+
+ if ov == portdir and portdir not in port_ov:
+ repo.priority = -1000
+ else:
+ repo.priority = base_priority
+ base_priority += 1
+
+ else:
+ writemsg(_("!!! Invalid PORTDIR_OVERLAY"
+ " (not a dir): '%s'\n") % ov, noiselevel=-1)
+
+ return portdir
+
+ def repo_priority(r):
+ """
+ Key funtion for comparing repositories by priority.
+ None is equal priority zero.
+ """
+ x = prepos[r].priority
+ if x is None:
+ return 0
+ return x
+
+ prepos = {}
+ location_map = {}
+ treemap = {}
+ ignored_map = {}
+ ignored_location_map = {}
+
+ portdir = settings.get('PORTDIR', '')
+ portdir_overlay = settings.get('PORTDIR_OVERLAY', '')
+ parse(paths, prepos, ignored_map, ignored_location_map)
+ # If PORTDIR_OVERLAY contains a repo with the same repo_name as
+ # PORTDIR, then PORTDIR is overridden.
+ portdir = add_overlays(portdir, portdir_overlay, prepos,
+ ignored_map, ignored_location_map)
+ if portdir and portdir.strip():
+ portdir = os.path.realpath(portdir)
+
+ ignored_repos = tuple((repo_name, tuple(paths)) \
+ for repo_name, paths in ignored_map.items())
+
+ self.missing_repo_names = frozenset(repo.location
+ for repo in prepos.values()
+ if repo.location is not None and repo.missing_repo_name)
+
+ #Parse layout.conf and read masters key.
+ for repo in prepos.values():
+ if not repo.location:
+ continue
+ layout_filename = os.path.join(repo.location, "metadata", "layout.conf")
+ layout_file = KeyValuePairFileLoader(layout_filename, None, None)
+ layout_data, layout_errors = layout_file.load()
+
+ masters = layout_data.get('masters')
+ if masters and masters.strip():
+ masters = masters.split()
+ else:
+ masters = None
+ repo.masters = masters
+
+ aliases = layout_data.get('aliases')
+ if aliases and aliases.strip():
+ aliases = aliases.split()
+ else:
+ aliases = None
+ if aliases:
+ if repo.aliases:
+ aliases.extend(repo.aliases)
+ repo.aliases = tuple(sorted(set(aliases)))
+
+ #Take aliases into account.
+ new_prepos = {}
+ for repo_name, repo in prepos.items():
+ names = set()
+ names.add(repo_name)
+ if repo.aliases:
+ names.update(repo.aliases)
+
+ for name in names:
+ if name in new_prepos:
+ writemsg_level(_("!!! Repository name or alias '%s', " + \
+ "defined for repository '%s', overrides " + \
+ "existing alias or repository.\n") % (name, repo_name), level=logging.WARNING, noiselevel=-1)
+ new_prepos[name] = repo
+ prepos = new_prepos
+
+ for (name, r) in prepos.items():
+ if r.location is not None:
+ location_map[r.location] = name
+ treemap[name] = r.location
+
+ # filter duplicates from aliases, by only including
+ # items where repo.name == key
+ prepos_order = [repo.name for key, repo in prepos.items() \
+ if repo.name == key and repo.location is not None]
+ prepos_order.sort(key=repo_priority)
+
+ if portdir in location_map:
+ portdir_repo = prepos[location_map[portdir]]
+ portdir_sync = settings.get('SYNC', '')
+ #if SYNC variable is set and not overwritten by repos.conf
+ if portdir_sync and not portdir_repo.sync:
+ portdir_repo.sync = portdir_sync
+
+ if prepos['DEFAULT'].main_repo is None or \
+ prepos['DEFAULT'].main_repo not in prepos:
+ #setting main_repo if it was not set in repos.conf
+ if portdir in location_map:
+ prepos['DEFAULT'].main_repo = location_map[portdir]
+ elif portdir in ignored_location_map:
+ prepos['DEFAULT'].main_repo = ignored_location_map[portdir]
+ else:
+ prepos['DEFAULT'].main_repo = None
+ writemsg(_("!!! main-repo not set in DEFAULT and PORTDIR is empty. \n"), noiselevel=-1)
+
+ self.prepos = prepos
+ self.prepos_order = prepos_order
+ self.ignored_repos = ignored_repos
+ self.location_map = location_map
+ self.treemap = treemap
+ self._prepos_changed = True
+ self._repo_location_list = []
+
+ #The 'masters' key currently contains repo names. Replace them with the matching RepoConfig.
+ for repo_name, repo in prepos.items():
+ if repo_name == "DEFAULT":
+ continue
+ if repo.masters is None:
+ if self.mainRepo() and repo_name != self.mainRepo().name:
+ repo.masters = self.mainRepo(),
+ else:
+ repo.masters = ()
+ else:
+ if repo.masters and isinstance(repo.masters[0], RepoConfig):
+ # This one has already been processed
+ # because it has an alias.
+ continue
+ master_repos = []
+ for master_name in repo.masters:
+ if master_name not in prepos:
+ layout_filename = os.path.join(repo.user_location,
+ "metadata", "layout.conf")
+ writemsg_level(_("Unavailable repository '%s' " \
+ "referenced by masters entry in '%s'\n") % \
+ (master_name, layout_filename),
+ level=logging.ERROR, noiselevel=-1)
+ else:
+ master_repos.append(prepos[master_name])
+ repo.masters = tuple(master_repos)
+
+ #The 'eclass_overrides' key currently contains repo names. Replace them with the matching repo paths.
+ for repo_name, repo in prepos.items():
+ if repo_name == "DEFAULT":
+ continue
+
+ eclass_locations = []
+ eclass_locations.extend(master_repo.location for master_repo in repo.masters)
+ eclass_locations.append(repo.location)
+
+ if repo.eclass_overrides:
+ for other_repo_name in repo.eclass_overrides:
+ if other_repo_name in self.treemap:
+ eclass_locations.append(self.get_location_for_name(other_repo_name))
+ else:
+ writemsg_level(_("Unavailable repository '%s' " \
+ "referenced by eclass-overrides entry for " \
+ "'%s'\n") % (other_repo_name, repo_name), \
+ level=logging.ERROR, noiselevel=-1)
+ repo.eclass_locations = tuple(eclass_locations)
+
+ self._prepos_changed = True
+ self._repo_location_list = []
+
+ self._check_locations()
+
+ def repoLocationList(self):
+ """Get a list of repositories location. Replaces PORTDIR_OVERLAY"""
+ if self._prepos_changed:
+ _repo_location_list = []
+ for repo in self.prepos_order:
+ if self.prepos[repo].location is not None:
+ _repo_location_list.append(self.prepos[repo].location)
+ self._repo_location_list = tuple(_repo_location_list)
+
+ self._prepos_changed = False
+ return self._repo_location_list
+
+ def repoUserLocationList(self):
+ """Get a list of repositories location. Replaces PORTDIR_OVERLAY"""
+ user_location_list = []
+ for repo in self.prepos_order:
+ if self.prepos[repo].location is not None:
+ user_location_list.append(self.prepos[repo].user_location)
+ return tuple(user_location_list)
+
+ def mainRepoLocation(self):
+ """Returns the location of main repo"""
+ main_repo = self.prepos['DEFAULT'].main_repo
+ if main_repo is not None and main_repo in self.prepos:
+ return self.prepos[main_repo].location
+ else:
+ return ''
+
+ def mainRepo(self):
+ """Returns the main repo"""
+ maid_repo = self.prepos['DEFAULT'].main_repo
+ if maid_repo is None:
+ return None
+ return self.prepos[maid_repo]
+
+ def _check_locations(self):
+ """Check if repositories location are correct and show a warning message if not"""
+ for (name, r) in self.prepos.items():
+ if name != 'DEFAULT':
+ if r.location is None:
+ writemsg(_("!!! Location not set for repository %s\n") % name, noiselevel=-1)
+ else:
+ if not os.path.isdir(r.location):
+ self.prepos_order.remove(name)
+ writemsg(_("!!! Invalid Repository Location"
+ " (not a dir): '%s'\n") % r.location, noiselevel=-1)
+
+ def repos_with_profiles(self):
+ for repo_name in self.prepos_order:
+ repo = self.prepos[repo_name]
+ if repo.format != "unavailable":
+ yield repo
+
+ def get_name_for_location(self, location):
+ return self.location_map[location]
+
+ def get_location_for_name(self, repo_name):
+ if repo_name is None:
+ # This simplifies code in places where
+ # we want to be able to pass in Atom.repo
+ # even if it is None.
+ return None
+ return self.treemap[repo_name]
+
+ def __getitem__(self, repo_name):
+ return self.prepos[repo_name]
+
+ def __iter__(self):
+ for repo_name in self.prepos_order:
+ yield self.prepos[repo_name]
+
+def load_repository_config(settings):
+ #~ repoconfigpaths = [os.path.join(settings.global_config_path, "repos.conf")]
+ repoconfigpaths = []
+ if settings.local_config:
+ repoconfigpaths.append(os.path.join(settings["PORTAGE_CONFIGROOT"],
+ USER_CONFIG_PATH, "repos.conf"))
+ return RepoConfigLoader(repoconfigpaths, settings)
diff --git a/portage_with_autodep/pym/portage/tests/__init__.py b/portage_with_autodep/pym/portage/tests/__init__.py
new file mode 100644
index 0000000..a647aa2
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/__init__.py
@@ -0,0 +1,244 @@
+# tests/__init__.py -- Portage Unit Test functionality
+# Copyright 2006-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+import time
+import unittest
+
+try:
+ from unittest.runner import _TextTestResult # new in python-2.7
+except ImportError:
+ from unittest import _TextTestResult
+
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+
+def main():
+
+ TEST_FILE = b'__test__'
+ svn_dirname = b'.svn'
+ suite = unittest.TestSuite()
+ basedir = os.path.dirname(os.path.realpath(__file__))
+ testDirs = []
+
+ if len(sys.argv) > 1:
+ suite.addTests(getTestFromCommandLine(sys.argv[1:], basedir))
+ return TextTestRunner(verbosity=2).run(suite)
+
+ # the os.walk help mentions relative paths as being quirky
+ # I was tired of adding dirs to the list, so now we add __test__
+ # to each dir we want tested.
+ for root, dirs, files in os.walk(basedir):
+ if svn_dirname in dirs:
+ dirs.remove(svn_dirname)
+ try:
+ root = _unicode_decode(root,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ continue
+
+ if TEST_FILE in files:
+ testDirs.append(root)
+
+ for mydir in testDirs:
+ suite.addTests(getTests(os.path.join(basedir, mydir), basedir) )
+ return TextTestRunner(verbosity=2).run(suite)
+
+def my_import(name):
+ mod = __import__(name)
+ components = name.split('.')
+ for comp in components[1:]:
+ mod = getattr(mod, comp)
+ return mod
+
+def getTestFromCommandLine(args, base_path):
+ ret = []
+ for arg in args:
+ realpath = os.path.realpath(arg)
+ path = os.path.dirname(realpath)
+ f = realpath[len(path)+1:]
+
+ if not f.startswith("test") or not f.endswith(".py"):
+ raise Exception("Invalid argument: '%s'" % arg)
+
+ mymodule = f[:-3]
+
+ parent_path = path[len(base_path)+1:]
+ parent_module = ".".join(("portage", "tests", parent_path))
+ parent_module = parent_module.replace('/', '.')
+ result = []
+
+ # Make the trailing / a . for module importing
+ modname = ".".join((parent_module, mymodule))
+ mod = my_import(modname)
+ ret.append(unittest.TestLoader().loadTestsFromModule(mod))
+ return ret
+
+def getTests(path, base_path):
+ """
+
+ path is the path to a given subdir ( 'portage/' for example)
+ This does a simple filter on files in that dir to give us modules
+ to import
+
+ """
+ files = os.listdir(path)
+ files = [ f[:-3] for f in files if f.startswith("test") and f.endswith(".py") ]
+ parent_path = path[len(base_path)+1:]
+ parent_module = ".".join(("portage", "tests", parent_path))
+ parent_module = parent_module.replace('/', '.')
+ result = []
+ for mymodule in files:
+ # Make the trailing / a . for module importing
+ modname = ".".join((parent_module, mymodule))
+ mod = my_import(modname)
+ result.append(unittest.TestLoader().loadTestsFromModule(mod))
+ return result
+
+class TextTestResult(_TextTestResult):
+ """
+ We need a subclass of unittest._TextTestResult to handle tests with TODO
+
+ This just adds an addTodo method that can be used to add tests
+ that are marked TODO; these can be displayed later
+ by the test runner.
+ """
+
+ def __init__(self, stream, descriptions, verbosity):
+ super(TextTestResult, self).__init__(stream, descriptions, verbosity)
+ self.todoed = []
+
+ def addTodo(self, test, info):
+ self.todoed.append((test,info))
+ if self.showAll:
+ self.stream.writeln("TODO")
+ elif self.dots:
+ self.stream.write(".")
+
+ def printErrors(self):
+ if self.dots or self.showAll:
+ self.stream.writeln()
+ self.printErrorList('ERROR', self.errors)
+ self.printErrorList('FAIL', self.failures)
+ self.printErrorList('TODO', self.todoed)
+
+class TestCase(unittest.TestCase):
+ """
+ We need a way to mark a unit test as "ok to fail"
+ This way someone can add a broken test and mark it as failed
+ and then fix the code later. This may not be a great approach
+ (broken code!!??!11oneone) but it does happen at times.
+ """
+
+ def __init__(self, methodName='runTest'):
+ # This method exists because unittest.py in python 2.4 stores
+ # the methodName as __testMethodName while 2.5 uses
+ # _testMethodName.
+ self._testMethodName = methodName
+ unittest.TestCase.__init__(self, methodName)
+ self.todo = False
+
+ def defaultTestResult(self):
+ return TextTestResult()
+
+ def run(self, result=None):
+ if result is None: result = self.defaultTestResult()
+ result.startTest(self)
+ testMethod = getattr(self, self._testMethodName)
+ try:
+ try:
+ self.setUp()
+ except SystemExit:
+ raise
+ except KeyboardInterrupt:
+ raise
+ except:
+ result.addError(self, sys.exc_info())
+ return
+ ok = False
+ try:
+ testMethod()
+ ok = True
+ except self.failureException:
+ if self.todo:
+ result.addTodo(self,"%s: TODO" % testMethod)
+ else:
+ result.addFailure(self, sys.exc_info())
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except:
+ result.addError(self, sys.exc_info())
+ try:
+ self.tearDown()
+ except SystemExit:
+ raise
+ except KeyboardInterrupt:
+ raise
+ except:
+ result.addError(self, sys.exc_info())
+ ok = False
+ if ok: result.addSuccess(self)
+ finally:
+ result.stopTest(self)
+
+ def assertRaisesMsg(self, msg, excClass, callableObj, *args, **kwargs):
+ """Fail unless an exception of class excClass is thrown
+ by callableObj when invoked with arguments args and keyword
+ arguments kwargs. If a different type of exception is
+ thrown, it will not be caught, and the test case will be
+ deemed to have suffered an error, exactly as for an
+ unexpected exception.
+ """
+ try:
+ callableObj(*args, **kwargs)
+ except excClass:
+ return
+ else:
+ if hasattr(excClass,'__name__'): excName = excClass.__name__
+ else: excName = str(excClass)
+ raise self.failureException("%s not raised: %s" % (excName, msg))
+
+class TextTestRunner(unittest.TextTestRunner):
+ """
+ We subclass unittest.TextTestRunner to output SKIP for tests that fail but are skippable
+ """
+
+ def _makeResult(self):
+ return TextTestResult(self.stream, self.descriptions, self.verbosity)
+
+ def run(self, test):
+ """
+ Run the given test case or test suite.
+ """
+ result = self._makeResult()
+ startTime = time.time()
+ test(result)
+ stopTime = time.time()
+ timeTaken = stopTime - startTime
+ result.printErrors()
+ self.stream.writeln(result.separator2)
+ run = result.testsRun
+ self.stream.writeln("Ran %d test%s in %.3fs" %
+ (run, run != 1 and "s" or "", timeTaken))
+ self.stream.writeln()
+ if not result.wasSuccessful():
+ self.stream.write("FAILED (")
+ failed = len(result.failures)
+ errored = len(result.errors)
+ if failed:
+ self.stream.write("failures=%d" % failed)
+ if errored:
+ if failed: self.stream.write(", ")
+ self.stream.write("errors=%d" % errored)
+ self.stream.writeln(")")
+ else:
+ self.stream.writeln("OK")
+ return result
+
+test_cps = ['sys-apps/portage','virtual/portage']
+test_versions = ['1.0', '1.0-r1','2.3_p4','1.0_alpha57']
+test_slots = [ None, '1','gentoo-sources-2.6.17','spankywashere']
+test_usedeps = ['foo','-bar', ('foo','bar'),
+ ('foo','-bar'), ('foo?', '!bar?') ]
diff --git a/portage_with_autodep/pym/portage/tests/bin/__init__.py b/portage_with_autodep/pym/portage/tests/bin/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/bin/__init__.py
diff --git a/portage_with_autodep/pym/portage/tests/bin/__test__ b/portage_with_autodep/pym/portage/tests/bin/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/bin/__test__
diff --git a/portage_with_autodep/pym/portage/tests/bin/setup_env.py b/portage_with_autodep/pym/portage/tests/bin/setup_env.py
new file mode 100644
index 0000000..e07643d
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/bin/setup_env.py
@@ -0,0 +1,85 @@
+# setup_env.py -- Make sure bin subdir has sane env for testing
+# Copyright 2007-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import tempfile
+
+from portage import os
+from portage import shutil
+from portage.tests import TestCase
+from portage.process import spawn
+
+basepath = os.path.join(os.path.dirname(os.path.dirname(
+ os.path.abspath(__file__))),
+ "..", "..", "..")
+bindir = os.path.join(basepath, "bin")
+pymdir = os.path.join(basepath, "pym")
+basedir = None
+env = None
+
+def binTestsCleanup():
+ global basedir
+ if basedir is None:
+ return
+ if os.access(basedir, os.W_OK):
+ shutil.rmtree(basedir)
+ basedir = None
+
+def binTestsInit():
+ binTestsCleanup()
+ global basedir, env
+ basedir = tempfile.mkdtemp()
+ env = os.environ.copy()
+ env["D"] = os.path.join(basedir, "image")
+ env["T"] = os.path.join(basedir, "temp")
+ env["S"] = os.path.join(basedir, "workdir")
+ env["PF"] = "portage-tests-0.09-r1"
+ env["PATH"] = bindir + ":" + env["PATH"]
+ env["PORTAGE_BIN_PATH"] = bindir
+ env["PORTAGE_PYM_PATH"] = pymdir
+ os.mkdir(env["D"])
+ os.mkdir(env["T"])
+ os.mkdir(env["S"])
+
+class BinTestCase(TestCase):
+ def init(self):
+ binTestsInit()
+ def cleanup(self):
+ binTestsCleanup()
+
+def _exists_in_D(path):
+ # Note: do not use os.path.join() here, we assume D to end in /
+ return os.access(env["D"] + path, os.W_OK)
+def exists_in_D(path):
+ if not _exists_in_D(path):
+ raise TestCase.failureException
+def xexists_in_D(path):
+ if _exists_in_D(path):
+ raise TestCase.failureException
+
+def portage_func(func, args, exit_status=0):
+ # we don't care about the output of the programs,
+ # just their exit value and the state of $D
+ global env
+ f = open('/dev/null', 'wb')
+ fd_pipes = {0:0,1:f.fileno(),2:f.fileno()}
+ def pre_exec():
+ os.chdir(env["S"])
+ spawn([func] + args.split(), env=env,
+ fd_pipes=fd_pipes, pre_exec=pre_exec)
+ f.close()
+
+def create_portage_wrapper(bin):
+ def derived_func(*args):
+ newargs = list(args)
+ newargs.insert(0, bin)
+ return portage_func(*newargs)
+ return derived_func
+
+for bin in os.listdir(os.path.join(bindir, "ebuild-helpers")):
+ if bin.startswith("do") or \
+ bin.startswith("new") or \
+ bin.startswith("prep") or \
+ bin in ["ecompress","ecompressdir","fowners","fperms"]:
+ globals()[bin] = create_portage_wrapper(
+ os.path.join(bindir, "ebuild-helpers", bin))
diff --git a/portage_with_autodep/pym/portage/tests/bin/test_dobin.py b/portage_with_autodep/pym/portage/tests/bin/test_dobin.py
new file mode 100644
index 0000000..6f50d7a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/bin/test_dobin.py
@@ -0,0 +1,16 @@
+# test_dobin.py -- Portage Unit Testing Functionality
+# Copyright 2007-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests.bin.setup_env import BinTestCase, dobin, xexists_in_D
+
+class DoBin(BinTestCase):
+ def testDoBin(self):
+ self.init()
+ try:
+ dobin("does-not-exist", 1)
+ xexists_in_D("does-not-exist")
+ xexists_in_D("/bin/does-not-exist")
+ xexists_in_D("/usr/bin/does-not-exist")
+ finally:
+ self.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/bin/test_dodir.py b/portage_with_autodep/pym/portage/tests/bin/test_dodir.py
new file mode 100644
index 0000000..f4eb9b2
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/bin/test_dodir.py
@@ -0,0 +1,16 @@
+# test_dodir.py -- Portage Unit Testing Functionality
+# Copyright 2007-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests.bin.setup_env import BinTestCase, dodir, exists_in_D
+
+class DoDir(BinTestCase):
+ def testDoDir(self):
+ self.init()
+ try:
+ dodir("usr /usr")
+ exists_in_D("/usr")
+ dodir("/var/lib/moocow")
+ exists_in_D("/var/lib/moocow")
+ finally:
+ self.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/dbapi/__init__.py b/portage_with_autodep/pym/portage/tests/dbapi/__init__.py
new file mode 100644
index 0000000..532918b
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dbapi/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/tests/dbapi/__test__ b/portage_with_autodep/pym/portage/tests/dbapi/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dbapi/__test__
diff --git a/portage_with_autodep/pym/portage/tests/dbapi/test_fakedbapi.py b/portage_with_autodep/pym/portage/tests/dbapi/test_fakedbapi.py
new file mode 100644
index 0000000..a2c5f77
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dbapi/test_fakedbapi.py
@@ -0,0 +1,58 @@
+# Copyright 2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import shutil
+import tempfile
+
+from portage import os
+from portage.dbapi.virtual import fakedbapi
+from portage.package.ebuild.config import config
+from portage.tests import TestCase
+
+class TestFakedbapi(TestCase):
+
+ def testFakedbapi(self):
+ packages = (
+ ("sys-apps/portage-2.1.10", {
+ "EAPI" : "2",
+ "IUSE" : "ipc doc",
+ "repository" : "gentoo",
+ "SLOT" : "0",
+ "USE" : "ipc missing-iuse",
+ }),
+ ("virtual/package-manager-0", {
+ "EAPI" : "0",
+ "repository" : "gentoo",
+ "SLOT" : "0",
+ }),
+ )
+
+ match_tests = (
+ ("sys-apps/portage:0[ipc]", ["sys-apps/portage-2.1.10"]),
+ ("sys-apps/portage:0[-ipc]", []),
+ ("sys-apps/portage:0[doc]", []),
+ ("sys-apps/portage:0[-doc]", ["sys-apps/portage-2.1.10"]),
+ ("sys-apps/portage:0", ["sys-apps/portage-2.1.10"]),
+ ("sys-apps/portage:0[missing-iuse]", []),
+ ("sys-apps/portage:0[-missing-iuse]", []),
+ ("sys-apps/portage:0::gentoo[ipc]", ["sys-apps/portage-2.1.10"]),
+ ("sys-apps/portage:0::multilib[ipc]", []),
+ ("virtual/package-manager", ["virtual/package-manager-0"]),
+ )
+
+ tempdir = tempfile.mkdtemp()
+ try:
+ portdir = os.path.join(tempdir, "usr/portage")
+ os.makedirs(portdir)
+ env = {
+ "PORTDIR": portdir,
+ }
+ fakedb = fakedbapi(settings=config(config_profile_path="",
+ env=env, _eprefix=tempdir))
+ for cpv, metadata in packages:
+ fakedb.cpv_inject(cpv, metadata=metadata)
+
+ for atom, expected_result in match_tests:
+ self.assertEqual( fakedb.match(atom), expected_result )
+ finally:
+ shutil.rmtree(tempdir)
diff --git a/portage_with_autodep/pym/portage/tests/dep/__init__.py b/portage_with_autodep/pym/portage/tests/dep/__init__.py
new file mode 100644
index 0000000..9c3f524
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/__init__.py
@@ -0,0 +1,3 @@
+# tests/portage.dep/__init__.py -- Portage Unit Test functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/tests/dep/__test__ b/portage_with_autodep/pym/portage/tests/dep/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/__test__
diff --git a/portage_with_autodep/pym/portage/tests/dep/testAtom.py b/portage_with_autodep/pym/portage/tests/dep/testAtom.py
new file mode 100644
index 0000000..092cacf
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/testAtom.py
@@ -0,0 +1,315 @@
+# Copyright 2006, 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import Atom
+from portage.exception import InvalidAtom
+
+class TestAtom(TestCase):
+
+ def testAtom(self):
+
+ tests = (
+ ( "=sys-apps/portage-2.1-r1:0[doc,a=,!b=,c?,!d?,-e]",
+ ('=', 'sys-apps/portage', '2.1-r1', '0', '[doc,a=,!b=,c?,!d?,-e]', None), False, False ),
+ ( "=sys-apps/portage-2.1-r1*:0[doc]",
+ ('=*', 'sys-apps/portage', '2.1-r1', '0', '[doc]', None), False, False ),
+ ( "sys-apps/portage:0[doc]",
+ (None, 'sys-apps/portage', None, '0', '[doc]', None), False, False ),
+ ( "sys-apps/portage:0[doc]",
+ (None, 'sys-apps/portage', None, '0', '[doc]', None), False, False ),
+ ( "*/*",
+ (None, '*/*', None, None, None, None), True, False ),
+ ( "sys-apps/*",
+ (None, 'sys-apps/*', None, None, None, None), True, False ),
+ ( "*/portage",
+ (None, '*/portage', None, None, None, None), True, False ),
+ ( "s*s-*/portage:1",
+ (None, 's*s-*/portage', None, '1', None, None), True, False ),
+ ( "*/po*ge:2",
+ (None, '*/po*ge', None, '2', None, None), True, False ),
+ ( "!dev-libs/A",
+ (None, 'dev-libs/A', None, None, None, None), True, True ),
+ ( "!!dev-libs/A",
+ (None, 'dev-libs/A', None, None, None, None), True, True ),
+ ( "!!dev-libs/A",
+ (None, 'dev-libs/A', None, None, None, None), True, True ),
+ ( "dev-libs/A[foo(+)]",
+ (None, 'dev-libs/A', None, None, "[foo(+)]", None), True, True ),
+ ( "dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]",
+ (None, 'dev-libs/A', None, None, "[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", None), True, True ),
+ ( "dev-libs/A:2[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]",
+ (None, 'dev-libs/A', None, "2", "[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", None), True, True ),
+
+ ( "=sys-apps/portage-2.1-r1:0::repo_name[doc,a=,!b=,c?,!d?,-e]",
+ ('=', 'sys-apps/portage', '2.1-r1', '0', '[doc,a=,!b=,c?,!d?,-e]', 'repo_name'), False, True ),
+ ( "=sys-apps/portage-2.1-r1*:0::repo_name[doc]",
+ ('=*', 'sys-apps/portage', '2.1-r1', '0', '[doc]', 'repo_name'), False, True ),
+ ( "sys-apps/portage:0::repo_name[doc]",
+ (None, 'sys-apps/portage', None, '0', '[doc]', 'repo_name'), False, True ),
+
+ ( "*/*::repo_name",
+ (None, '*/*', None, None, None, 'repo_name'), True, True ),
+ ( "sys-apps/*::repo_name",
+ (None, 'sys-apps/*', None, None, None, 'repo_name'), True, True ),
+ ( "*/portage::repo_name",
+ (None, '*/portage', None, None, None, 'repo_name'), True, True ),
+ ( "s*s-*/portage:1::repo_name",
+ (None, 's*s-*/portage', None, '1', None, 'repo_name'), True, True ),
+ )
+
+ tests_xfail = (
+ ( Atom("sys-apps/portage"), False, False ),
+ ( "cat/pkg[a!]", False, False ),
+ ( "cat/pkg[!a]", False, False ),
+ ( "cat/pkg[!a!]", False, False ),
+ ( "cat/pkg[!a-]", False, False ),
+ ( "cat/pkg[-a=]", False, False ),
+ ( "cat/pkg[-a?]", False, False ),
+ ( "cat/pkg[-a!]", False, False ),
+ ( "cat/pkg[=a]", False, False ),
+ ( "cat/pkg[=a=]", False, False ),
+ ( "cat/pkg[=a?]", False, False ),
+ ( "cat/pkg[=a!]", False, False ),
+ ( "cat/pkg[=a-]", False, False ),
+ ( "cat/pkg[?a]", False, False ),
+ ( "cat/pkg[?a=]", False, False ),
+ ( "cat/pkg[?a?]", False, False ),
+ ( "cat/pkg[?a!]", False, False ),
+ ( "cat/pkg[?a-]", False, False ),
+ ( "sys-apps/portage[doc]:0", False, False ),
+ ( "*/*", False, False ),
+ ( "sys-apps/*", False, False ),
+ ( "*/portage", False, False ),
+ ( "*/**", True, False ),
+ ( "*/portage[use]", True, False ),
+ ( "cat/pkg[a()]", False, False ),
+ ( "cat/pkg[a(]", False, False ),
+ ( "cat/pkg[a)]", False, False ),
+ ( "cat/pkg[a(,b]", False, False ),
+ ( "cat/pkg[a),b]", False, False ),
+ ( "cat/pkg[a(*)]", False, False ),
+ ( "cat/pkg[a(*)]", True, False ),
+ ( "cat/pkg[a(+-)]", False, False ),
+ ( "cat/pkg[a()]", False, False ),
+ ( "cat/pkg[(+)a]", False, False ),
+ ( "cat/pkg[a=(+)]", False, False ),
+ ( "cat/pkg[!(+)a=]", False, False ),
+ ( "cat/pkg[!a=(+)]", False, False ),
+ ( "cat/pkg[a?(+)]", False, False ),
+ ( "cat/pkg[!a?(+)]", False, False ),
+ ( "cat/pkg[!(+)a?]", False, False ),
+ ( "cat/pkg[-(+)a]", False, False ),
+ ( "cat/pkg[a(+),-a]", False, False ),
+ ( "cat/pkg[a(-),-a]", False, False ),
+ ( "cat/pkg[-a,a(+)]", False, False ),
+ ( "cat/pkg[-a,a(-)]", False, False ),
+ ( "cat/pkg[-a(+),a(-)]", False, False ),
+ ( "cat/pkg[-a(-),a(+)]", False, False ),
+ ( "sys-apps/portage[doc]::repo_name", False, False ),
+ ( "sys-apps/portage:0[doc]::repo_name", False, False ),
+ ( "sys-apps/portage[doc]:0::repo_name", False, False ),
+ ( "=sys-apps/portage-2.1-r1:0::repo_name[doc,a=,!b=,c?,!d?,-e]", False, False ),
+ ( "=sys-apps/portage-2.1-r1*:0::repo_name[doc]", False, False ),
+ ( "sys-apps/portage:0::repo_name[doc]", False, False ),
+ ( "*/*::repo_name", True, False ),
+ )
+
+ for atom, parts, allow_wildcard, allow_repo in tests:
+ a = Atom(atom, allow_wildcard=allow_wildcard, allow_repo=allow_repo)
+ op, cp, ver, slot, use, repo = parts
+ self.assertEqual( op, a.operator,
+ msg="Atom('%s').operator = %s == '%s'" % ( atom, a.operator, op ) )
+ self.assertEqual( cp, a.cp,
+ msg="Atom('%s').cp = %s == '%s'" % ( atom, a.cp, cp ) )
+ if ver is not None:
+ cpv = "%s-%s" % (cp, ver)
+ else:
+ cpv = cp
+ self.assertEqual( cpv, a.cpv,
+ msg="Atom('%s').cpv = %s == '%s'" % ( atom, a.cpv, cpv ) )
+ self.assertEqual( slot, a.slot,
+ msg="Atom('%s').slot = %s == '%s'" % ( atom, a.slot, slot ) )
+ self.assertEqual( repo, a.repo,
+ msg="Atom('%s').repo == %s == '%s'" % ( atom, a.repo, repo ) )
+
+ if a.use:
+ returned_use = str(a.use)
+ else:
+ returned_use = None
+ self.assertEqual( use, returned_use,
+ msg="Atom('%s').use = %s == '%s'" % ( atom, returned_use, use ) )
+
+ for atom, allow_wildcard, allow_repo in tests_xfail:
+ self.assertRaisesMsg(atom, (InvalidAtom, TypeError), Atom, atom, \
+ allow_wildcard=allow_wildcard, allow_repo=allow_repo)
+
+ def test_intersects(self):
+ test_cases = (
+ ("dev-libs/A", "dev-libs/A", True),
+ ("dev-libs/A", "dev-libs/B", False),
+ ("dev-libs/A", "sci-libs/A", False),
+ ("dev-libs/A[foo]", "sci-libs/A[bar]", False),
+ ("dev-libs/A[foo(+)]", "sci-libs/A[foo(-)]", False),
+ ("=dev-libs/A-1", "=dev-libs/A-1-r1", False),
+ ("~dev-libs/A-1", "=dev-libs/A-1", False),
+ ("=dev-libs/A-1:1", "=dev-libs/A-1", True),
+ ("=dev-libs/A-1:1", "=dev-libs/A-1:1", True),
+ ("=dev-libs/A-1:1", "=dev-libs/A-1:2", False),
+ )
+
+ for atom, other, expected_result in test_cases:
+ self.assertEqual(Atom(atom).intersects(Atom(other)), expected_result, \
+ "%s and %s should intersect: %s" % (atom, other, expected_result))
+
+ def test_violated_conditionals(self):
+ test_cases = (
+ ("dev-libs/A", ["foo"], ["foo"], None, "dev-libs/A"),
+ ("dev-libs/A[foo]", [], ["foo"], None, "dev-libs/A[foo]"),
+ ("dev-libs/A[foo]", ["foo"], ["foo"], None, "dev-libs/A"),
+ ("dev-libs/A[foo]", [], ["foo"], [], "dev-libs/A[foo]"),
+ ("dev-libs/A[foo]", ["foo"], ["foo"], [], "dev-libs/A"),
+
+ ("dev-libs/A:0[foo]", ["foo"], ["foo"], [], "dev-libs/A:0"),
+
+ ("dev-libs/A[foo,-bar]", [], ["foo", "bar"], None, "dev-libs/A[foo]"),
+ ("dev-libs/A[-foo,bar]", [], ["foo", "bar"], None, "dev-libs/A[bar]"),
+
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", [], ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[a,!c=]"),
+
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["a"], ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[!c=]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["b"], ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[a,b=,!c=]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["c"], ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[a]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["d"], ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[a,!c=]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["e"], ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[a,!c=,!e?]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["f"], ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[a,!c=,-f]"),
+
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["a"], ["a", "b", "c", "d", "e", "f"], ["a"], "dev-libs/A[!c=]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["b"], ["a", "b", "c", "d", "e", "f"], ["b"], "dev-libs/A[a,!c=]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["c"], ["a", "b", "c", "d", "e", "f"], ["c"], "dev-libs/A[a,!c=]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["d"], ["a", "b", "c", "d", "e", "f"], ["d"], "dev-libs/A[a,!c=]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["e"], ["a", "b", "c", "d", "e", "f"], ["e"], "dev-libs/A[a,!c=]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["f"], ["a", "b", "c", "d", "e", "f"], ["f"], "dev-libs/A[a,!c=,-f]"),
+
+ ("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["a"], ["a", "b", "c", "d", "e", "f"], ["a"], "dev-libs/A[!c(+)=]"),
+ ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["b"], ["a", "b", "c", "d", "e", "f"], ["b"], "dev-libs/A[a(-),!c(-)=]"),
+ ("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["c"], ["a", "b", "c", "d", "e", "f"], ["c"], "dev-libs/A[a(+),!c(+)=]"),
+ ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["d"], ["a", "b", "c", "d", "e", "f"], ["d"], "dev-libs/A[a(-),!c(-)=]"),
+ ("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["e"], ["a", "b", "c", "d", "e", "f"], ["e"], "dev-libs/A[a(+),!c(+)=]"),
+ ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["f"], ["a", "b", "c", "d", "e", "f"], ["f"], "dev-libs/A[a(-),!c(-)=,-f(+)]"),
+
+ ("dev-libs/A[a(+),b(+)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["a"], ["a"], ["a"], "dev-libs/A[b(+)=,!e(+)?]"),
+ ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["b"], ["b"], ["b"], "dev-libs/A[a(-),!c(-)=,-f(+)]"),
+ ("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["c"], ["c"], ["c"], "dev-libs/A[!c(+)=,!e(+)?]"),
+ ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["d"], ["d"], ["d"], "dev-libs/A[a(-),b(+)=,!c(-)=,-f(+)]"),
+ ("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["e"], ["e"], ["e"], "dev-libs/A"),
+ ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["f"], ["f"], ["f"], "dev-libs/A[a(-),b(+)=,!c(-)=,-f(+)]"),
+
+ #Some more test cases to trigger all remaining code paths
+ ("dev-libs/B[x?]", [], ["x"], ["x"], "dev-libs/B[x?]"),
+ ("dev-libs/B[x(+)?]", [], [], ["x"], "dev-libs/B"),
+ ("dev-libs/B[x(-)?]", [], [], ["x"], "dev-libs/B[x(-)?]"),
+
+ ("dev-libs/C[x=]", [], ["x"], ["x"], "dev-libs/C[x=]"),
+ ("dev-libs/C[x(+)=]", [], [], ["x"], "dev-libs/C"),
+ ("dev-libs/C[x(-)=]", [], [], ["x"], "dev-libs/C[x(-)=]"),
+
+ ("dev-libs/D[!x=]", [], ["x"], ["x"], "dev-libs/D"),
+ ("dev-libs/D[!x(+)=]", [], [], ["x"], "dev-libs/D[!x(+)=]"),
+ ("dev-libs/D[!x(-)=]", [], [], ["x"], "dev-libs/D"),
+
+ #Missing IUSE test cases
+ ("dev-libs/B[x]", [], [], [], "dev-libs/B[x]"),
+ ("dev-libs/B[-x]", [], [], [], "dev-libs/B[-x]"),
+ ("dev-libs/B[x?]", [], [], [], "dev-libs/B[x?]"),
+ ("dev-libs/B[x=]", [], [], [], "dev-libs/B[x=]"),
+ ("dev-libs/B[!x=]", [], [], ["x"], "dev-libs/B[!x=]"),
+ ("dev-libs/B[!x?]", [], [], ["x"], "dev-libs/B[!x?]"),
+ )
+
+ test_cases_xfail = (
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", [], ["a", "b", "c", "d", "e", "f"], None),
+ )
+
+ class use_flag_validator(object):
+ def __init__(self, iuse):
+ self.iuse = iuse
+
+ def is_valid_flag(self, flag):
+ return flag in iuse
+
+ for atom, other_use, iuse, parent_use, expected_violated_atom in test_cases:
+ a = Atom(atom)
+ validator = use_flag_validator(iuse)
+ violated_atom = a.violated_conditionals(other_use, validator.is_valid_flag, parent_use)
+ if parent_use is None:
+ fail_msg = "Atom: %s, other_use: %s, iuse: %s, parent_use: %s, got: %s, expected: %s" % \
+ (atom, " ".join(other_use), " ".join(iuse), "None", str(violated_atom), expected_violated_atom)
+ else:
+ fail_msg = "Atom: %s, other_use: %s, iuse: %s, parent_use: %s, got: %s, expected: %s" % \
+ (atom, " ".join(other_use), " ".join(iuse), " ".join(parent_use), str(violated_atom), expected_violated_atom)
+ self.assertEqual(str(violated_atom), expected_violated_atom, fail_msg)
+
+ for atom, other_use, iuse, parent_use in test_cases_xfail:
+ a = Atom(atom)
+ validator = use_flag_validator(iuse)
+ self.assertRaisesMsg(atom, InvalidAtom, \
+ a.violated_conditionals, other_use, validator.is_valid_flag, parent_use)
+
+ def test_evaluate_conditionals(self):
+ test_cases = (
+ ("dev-libs/A[foo]", [], "dev-libs/A[foo]"),
+ ("dev-libs/A[foo]", ["foo"], "dev-libs/A[foo]"),
+
+ ("dev-libs/A:0[foo=]", ["foo"], "dev-libs/A:0[foo]"),
+
+ ("dev-libs/A[foo,-bar]", [], "dev-libs/A[foo,-bar]"),
+ ("dev-libs/A[-foo,bar]", [], "dev-libs/A[-foo,bar]"),
+
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", [], "dev-libs/A[a,-b,c,-e,-f]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["a"], "dev-libs/A[a,-b,c,-e,-f]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["b"], "dev-libs/A[a,b,c,-e,-f]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["c"], "dev-libs/A[a,-b,-c,-e,-f]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["d"], "dev-libs/A[a,-b,c,d,-e,-f]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["e"], "dev-libs/A[a,-b,c,-f]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["f"], "dev-libs/A[a,-b,c,-e,-f]"),
+ ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["d"], "dev-libs/A[a(-),-b(+),c(-),d(+),-e(-),-f(+)]"),
+ ("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["f"], "dev-libs/A[a(+),-b(-),c(+),-e(+),-f(-)]"),
+ )
+
+ for atom, use, expected_atom in test_cases:
+ a = Atom(atom)
+ b = a.evaluate_conditionals(use)
+ self.assertEqual(str(b), expected_atom)
+ self.assertEqual(str(b.unevaluated_atom), atom)
+
+ def test__eval_qa_conditionals(self):
+ test_cases = (
+ ("dev-libs/A[foo]", [], [], "dev-libs/A[foo]"),
+ ("dev-libs/A[foo]", ["foo"], [], "dev-libs/A[foo]"),
+ ("dev-libs/A[foo]", [], ["foo"], "dev-libs/A[foo]"),
+
+ ("dev-libs/A:0[foo]", [], [], "dev-libs/A:0[foo]"),
+ ("dev-libs/A:0[foo]", ["foo"], [], "dev-libs/A:0[foo]"),
+ ("dev-libs/A:0[foo]", [], ["foo"], "dev-libs/A:0[foo]"),
+ ("dev-libs/A:0[foo=]", [], ["foo"], "dev-libs/A:0[foo]"),
+
+ ("dev-libs/A[foo,-bar]", ["foo"], ["bar"], "dev-libs/A[foo,-bar]"),
+ ("dev-libs/A[-foo,bar]", ["foo", "bar"], [], "dev-libs/A[-foo,bar]"),
+
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["a", "b", "c"], [], "dev-libs/A[a,-b,c,d,-e,-f]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", [], ["a", "b", "c"], "dev-libs/A[a,b,-c,d,-e,-f]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["d", "e", "f"], [], "dev-libs/A[a,b,-b,c,-c,-e,-f]"),
+ ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", [], ["d", "e", "f"], "dev-libs/A[a,b,-b,c,-c,d,-f]"),
+
+ ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", \
+ ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[a(-),-b(+),c(-),-e(-),-f(+)]"),
+ ("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", \
+ [], ["a", "b", "c", "d", "e", "f"], "dev-libs/A[a(+),b(-),-c(+),d(-),-f(-)]"),
+ )
+
+ for atom, use_mask, use_force, expected_atom in test_cases:
+ a = Atom(atom)
+ b = a._eval_qa_conditionals(use_mask, use_force)
+ self.assertEqual(str(b), expected_atom)
+ self.assertEqual(str(b.unevaluated_atom), atom)
diff --git a/portage_with_autodep/pym/portage/tests/dep/testCheckRequiredUse.py b/portage_with_autodep/pym/portage/tests/dep/testCheckRequiredUse.py
new file mode 100644
index 0000000..54791e0
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/testCheckRequiredUse.py
@@ -0,0 +1,219 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import check_required_use
+from portage.exception import InvalidDependString
+
+class TestCheckRequiredUse(TestCase):
+
+ def testCheckRequiredUse(self):
+ test_cases = (
+ ( "|| ( a b )", [], ["a", "b"], False),
+ ( "|| ( a b )", ["a"], ["a", "b"], True),
+ ( "|| ( a b )", ["b"], ["a", "b"], True),
+ ( "|| ( a b )", ["a", "b"], ["a", "b"], True),
+
+ ( "^^ ( a b )", [], ["a", "b"], False),
+ ( "^^ ( a b )", ["a"], ["a", "b"], True),
+ ( "^^ ( a b )", ["b"], ["a", "b"], True),
+ ( "^^ ( a b )", ["a", "b"], ["a", "b"], False),
+
+ ( "^^ ( || ( a b ) c )", [], ["a", "b", "c"], False),
+ ( "^^ ( || ( a b ) c )", ["a"], ["a", "b", "c"], True),
+
+ ( "^^ ( || ( ( a b ) ) ( c ) )", [], ["a", "b", "c"], False),
+ ( "( ^^ ( ( || ( ( a ) ( b ) ) ) ( ( c ) ) ) )", ["a"], ["a", "b", "c"], True),
+
+ ( "a || ( b c )", ["a"], ["a", "b", "c"], False),
+ ( "|| ( b c ) a", ["a"], ["a", "b", "c"], False),
+
+ ( "|| ( a b c )", ["a"], ["a", "b", "c"], True),
+ ( "|| ( a b c )", ["b"], ["a", "b", "c"], True),
+ ( "|| ( a b c )", ["c"], ["a", "b", "c"], True),
+
+ ( "^^ ( a b c )", ["a"], ["a", "b", "c"], True),
+ ( "^^ ( a b c )", ["b"], ["a", "b", "c"], True),
+ ( "^^ ( a b c )", ["c"], ["a", "b", "c"], True),
+ ( "^^ ( a b c )", ["a", "b"], ["a", "b", "c"], False),
+ ( "^^ ( a b c )", ["b", "c"], ["a", "b", "c"], False),
+ ( "^^ ( a b c )", ["a", "c"], ["a", "b", "c"], False),
+ ( "^^ ( a b c )", ["a", "b", "c"], ["a", "b", "c"], False),
+
+ ( "a? ( ^^ ( b c ) )", [], ["a", "b", "c"], True),
+ ( "a? ( ^^ ( b c ) )", ["a"], ["a", "b", "c"], False),
+ ( "a? ( ^^ ( b c ) )", ["b"], ["a", "b", "c"], True),
+ ( "a? ( ^^ ( b c ) )", ["c"], ["a", "b", "c"], True),
+ ( "a? ( ^^ ( b c ) )", ["a", "b"], ["a", "b", "c"], True),
+ ( "a? ( ^^ ( b c ) )", ["a", "b", "c"], ["a", "b", "c"], False),
+
+ ( "^^ ( a? ( !b ) !c? ( d ) )", [], ["a", "b", "c", "d"], False),
+ ( "^^ ( a? ( !b ) !c? ( d ) )", ["a"], ["a", "b", "c", "d"], True),
+ ( "^^ ( a? ( !b ) !c? ( d ) )", ["c"], ["a", "b", "c", "d"], True),
+ ( "^^ ( a? ( !b ) !c? ( d ) )", ["a", "c"], ["a", "b", "c", "d"], True),
+ ( "^^ ( a? ( !b ) !c? ( d ) )", ["a", "b", "c"], ["a", "b", "c", "d"], False),
+ ( "^^ ( a? ( !b ) !c? ( d ) )", ["a", "b", "d"], ["a", "b", "c", "d"], True),
+ ( "^^ ( a? ( !b ) !c? ( d ) )", ["a", "b", "d"], ["a", "b", "c", "d"], True),
+ ( "^^ ( a? ( !b ) !c? ( d ) )", ["a", "d"], ["a", "b", "c", "d"], False),
+
+ ( "|| ( ^^ ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"], False),
+ ( "|| ( ^^ ( a b ) ^^ ( b c ) )", ["a"], ["a", "b", "c"], True),
+ ( "|| ( ^^ ( a b ) ^^ ( b c ) )", ["b"], ["a", "b", "c"], True),
+ ( "|| ( ^^ ( a b ) ^^ ( b c ) )", ["c"], ["a", "b", "c"], True),
+ ( "|| ( ^^ ( a b ) ^^ ( b c ) )", ["a", "b"], ["a", "b", "c"], True),
+ ( "|| ( ^^ ( a b ) ^^ ( b c ) )", ["a", "c"], ["a", "b", "c"], True),
+ ( "|| ( ^^ ( a b ) ^^ ( b c ) )", ["b", "c"], ["a", "b", "c"], True),
+ ( "|| ( ^^ ( a b ) ^^ ( b c ) )", ["a", "b", "c"], ["a", "b", "c"], False),
+
+ ( "^^ ( || ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"], False),
+ ( "^^ ( || ( a b ) ^^ ( b c ) )", ["a"], ["a", "b", "c"], True),
+ ( "^^ ( || ( a b ) ^^ ( b c ) )", ["b"], ["a", "b", "c"], False),
+ ( "^^ ( || ( a b ) ^^ ( b c ) )", ["c"], ["a", "b", "c"], True),
+ ( "^^ ( || ( a b ) ^^ ( b c ) )", ["a", "b"], ["a", "b", "c"], False),
+ ( "^^ ( || ( a b ) ^^ ( b c ) )", ["a", "c"], ["a", "b", "c"], False),
+ ( "^^ ( || ( a b ) ^^ ( b c ) )", ["b", "c"], ["a", "b", "c"], True),
+ ( "^^ ( || ( a b ) ^^ ( b c ) )", ["a", "b", "c"], ["a", "b", "c"], True),
+
+ ( "|| ( ( a b ) c )", ["a", "b", "c"], ["a", "b", "c"], True),
+ ( "|| ( ( a b ) c )", ["b", "c"], ["a", "b", "c"], True),
+ ( "|| ( ( a b ) c )", ["a", "c"], ["a", "b", "c"], True),
+ ( "|| ( ( a b ) c )", ["a", "b"], ["a", "b", "c"], True),
+ ( "|| ( ( a b ) c )", ["a"], ["a", "b", "c"], False),
+ ( "|| ( ( a b ) c )", ["b"], ["a", "b", "c"], False),
+ ( "|| ( ( a b ) c )", ["c"], ["a", "b", "c"], True),
+ ( "|| ( ( a b ) c )", [], ["a", "b", "c"], False),
+
+ ( "^^ ( ( a b ) c )", ["a", "b", "c"], ["a", "b", "c"], False),
+ ( "^^ ( ( a b ) c )", ["b", "c"], ["a", "b", "c"], True),
+ ( "^^ ( ( a b ) c )", ["a", "c"], ["a", "b", "c"], True),
+ ( "^^ ( ( a b ) c )", ["a", "b"], ["a", "b", "c"], True),
+ ( "^^ ( ( a b ) c )", ["a"], ["a", "b", "c"], False),
+ ( "^^ ( ( a b ) c )", ["b"], ["a", "b", "c"], False),
+ ( "^^ ( ( a b ) c )", ["c"], ["a", "b", "c"], True),
+ ( "^^ ( ( a b ) c )", [], ["a", "b", "c"], False),
+ )
+
+ test_cases_xfail = (
+ ( "^^ ( || ( a b ) ^^ ( b c ) )", [], ["a", "b"]),
+ ( "^^ ( || ( a b ) ^^ ( b c )", [], ["a", "b", "c"]),
+ ( "^^( || ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"]),
+ ( "^^ || ( a b ) ^^ ( b c )", [], ["a", "b", "c"]),
+ ( "^^ ( ( || ) ( a b ) ^^ ( b c ) )", [], ["a", "b", "c"]),
+ ( "^^ ( || ( a b ) ) ^^ ( b c ) )", [], ["a", "b", "c"]),
+ )
+
+ for required_use, use, iuse, expected in test_cases:
+ self.assertEqual(bool(check_required_use(required_use, use, iuse.__contains__)), \
+ expected, required_use + ", USE = " + " ".join(use))
+
+ for required_use, use, iuse in test_cases_xfail:
+ self.assertRaisesMsg(required_use + ", USE = " + " ".join(use), \
+ InvalidDependString, check_required_use, required_use, use, iuse.__contains__)
+
+ def testCheckRequiredUseFilterSatisfied(self):
+ """
+ Test filtering of satisfied parts of REQUIRED_USE,
+ in order to reduce noise for bug #353234.
+ """
+ test_cases = (
+ (
+ "bindist? ( !amr !faac !win32codecs ) cdio? ( !cdparanoia !cddb ) dvdnav? ( dvd )",
+ ("cdio", "cdparanoia"),
+ "cdio? ( !cdparanoia )"
+ ),
+ (
+ "|| ( !amr !faac !win32codecs ) cdio? ( !cdparanoia !cddb ) ^^ ( foo bar )",
+ ["cdio", "cdparanoia", "foo"],
+ "cdio? ( !cdparanoia )"
+ ),
+ (
+ "^^ ( || ( a b ) c )",
+ ("a", "b", "c"),
+ "^^ ( || ( a b ) c )"
+ ),
+ (
+ "^^ ( || ( ( a b ) ) ( c ) )",
+ ("a", "b", "c"),
+ "^^ ( ( a b ) c )"
+ ),
+ (
+ "a? ( ( c e ) ( b d ) )",
+ ("a", "c", "e"),
+ "a? ( b d )"
+ ),
+ (
+ "a? ( ( c e ) ( b d ) )",
+ ("a", "b", "c", "e"),
+ "a? ( d )"
+ ),
+ (
+ "a? ( ( c e ) ( c e b c d e c ) )",
+ ("a", "c", "e"),
+ "a? ( b d )"
+ ),
+ (
+ "^^ ( || ( a b ) ^^ ( b c ) )",
+ ("a", "b"),
+ "^^ ( || ( a b ) ^^ ( b c ) )"
+ ),
+ (
+ "^^ ( || ( a b ) ^^ ( b c ) )",
+ ["a", "c"],
+ "^^ ( || ( a b ) ^^ ( b c ) )"
+ ),
+ (
+ "^^ ( || ( a b ) ^^ ( b c ) )",
+ ["b", "c"],
+ ""
+ ),
+ (
+ "^^ ( || ( a b ) ^^ ( b c ) )",
+ ["a", "b", "c"],
+ ""
+ ),
+ (
+ "^^ ( ( a b c ) ( b c d ) )",
+ ["a", "b", "c"],
+ ""
+ ),
+ (
+ "^^ ( ( a b c ) ( b c d ) )",
+ ["a", "b", "c", "d"],
+ "^^ ( ( a b c ) ( b c d ) )"
+ ),
+ (
+ "^^ ( ( a b c ) ( b c !d ) )",
+ ["a", "b", "c"],
+ "^^ ( ( a b c ) ( b c !d ) )"
+ ),
+ (
+ "^^ ( ( a b c ) ( b c !d ) )",
+ ["a", "b", "c", "d"],
+ ""
+ ),
+ (
+ "( ( ( a ) ) ( ( ( b c ) ) ) )",
+ [""],
+ "a b c"
+ ),
+ (
+ "|| ( ( ( ( a ) ) ( ( ( b c ) ) ) ) )",
+ [""],
+ "a b c"
+ ),
+ (
+ "|| ( ( a ( ( ) ( ) ) ( ( ) ) ( b ( ) c ) ) )",
+ [""],
+ "a b c"
+ ),
+ (
+ "|| ( ( a b c ) ) || ( ( d e f ) )",
+ [""],
+ "a b c d e f"
+ ),
+ )
+ for required_use, use, expected in test_cases:
+ result = check_required_use(required_use, use, lambda k: True).tounicode()
+ self.assertEqual(result, expected,
+ "REQUIRED_USE = '%s', USE = '%s', '%s' != '%s'" % \
+ (required_use, " ".join(use), result, expected))
diff --git a/portage_with_autodep/pym/portage/tests/dep/testExtendedAtomDict.py b/portage_with_autodep/pym/portage/tests/dep/testExtendedAtomDict.py
new file mode 100644
index 0000000..69d092e
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/testExtendedAtomDict.py
@@ -0,0 +1,18 @@
+# test_isvalidatom.py -- Portage Unit Testing Functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import ExtendedAtomDict
+
+class TestExtendedAtomDict(TestCase):
+
+ def testExtendedAtomDict(self):
+ d = ExtendedAtomDict(dict)
+ d["*/*"] = { "test1": "x" }
+ d["dev-libs/*"] = { "test2": "y" }
+ d.setdefault("sys-apps/portage", {})["test3"] = "z"
+ self.assertEqual(d.get("dev-libs/A"), { "test1": "x", "test2": "y" })
+ self.assertEqual(d.get("sys-apps/portage"), { "test1": "x", "test3": "z" })
+ self.assertEqual(d["dev-libs/*"], { "test2": "y" })
+ self.assertEqual(d["sys-apps/portage"], {'test1': 'x', 'test3': 'z'})
diff --git a/portage_with_autodep/pym/portage/tests/dep/testExtractAffectingUSE.py b/portage_with_autodep/pym/portage/tests/dep/testExtractAffectingUSE.py
new file mode 100644
index 0000000..026a552
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/testExtractAffectingUSE.py
@@ -0,0 +1,75 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import extract_affecting_use
+from portage.exception import InvalidDependString
+
+class TestExtractAffectingUSE(TestCase):
+
+ def testExtractAffectingUSE(self):
+ test_cases = (
+ ("a? ( A ) !b? ( B ) !c? ( C ) d? ( D )", "A", ("a",)),
+ ("a? ( A ) !b? ( B ) !c? ( C ) d? ( D )", "B", ("b",)),
+ ("a? ( A ) !b? ( B ) !c? ( C ) d? ( D )", "C", ("c",)),
+ ("a? ( A ) !b? ( B ) !c? ( C ) d? ( D )", "D", ("d",)),
+
+ ("a? ( b? ( AB ) )", "AB", ("a", "b")),
+ ("a? ( b? ( c? ( ABC ) ) )", "ABC", ("a", "b", "c")),
+
+ ("a? ( A b? ( c? ( ABC ) AB ) )", "A", ("a",)),
+ ("a? ( A b? ( c? ( ABC ) AB ) )", "AB", ("a", "b")),
+ ("a? ( A b? ( c? ( ABC ) AB ) )", "ABC", ("a", "b", "c")),
+ ("a? ( A b? ( c? ( ABC ) AB ) ) X", "X", []),
+ ("X a? ( A b? ( c? ( ABC ) AB ) )", "X", []),
+
+ ("ab? ( || ( A B ) )", "A", ("ab",)),
+ ("!ab? ( || ( A B ) )", "B", ("ab",)),
+ ("ab? ( || ( A || ( b? ( || ( B C ) ) ) ) )", "A", ("ab",)),
+ ("ab? ( || ( A || ( b? ( || ( B C ) ) ) ) )", "B", ("ab", "b")),
+ ("ab? ( || ( A || ( b? ( || ( B C ) ) ) ) )", "C", ("ab", "b")),
+
+ ("( ab? ( || ( ( A ) || ( b? ( ( ( || ( B ( C ) ) ) ) ) ) ) ) )", "A", ("ab",)),
+ ("( ab? ( || ( ( A ) || ( b? ( ( ( || ( B ( C ) ) ) ) ) ) ) ) )", "B", ("ab", "b")),
+ ("( ab? ( || ( ( A ) || ( b? ( ( ( || ( B ( C ) ) ) ) ) ) ) ) )", "C", ("ab", "b")),
+
+ ("a? ( A )", "B", []),
+
+ ("a? ( || ( A B ) )", "B", ["a"]),
+
+ # test USE dep defaults for bug #363073
+ ("a? ( >=dev-lang/php-5.2[pcre(+)] )", ">=dev-lang/php-5.2[pcre(+)]", ["a"]),
+ )
+
+ test_cases_xfail = (
+ ("? ( A )", "A"),
+ ("!? ( A )", "A"),
+ ("( A", "A"),
+ ("A )", "A"),
+
+ ("||( A B )", "A"),
+ ("|| (A B )", "A"),
+ ("|| ( A B)", "A"),
+ ("|| ( A B", "A"),
+ ("|| A B )", "A"),
+ ("|| A B", "A"),
+ ("|| ( A B ) )", "A"),
+ ("|| || B C", "A"),
+ ("|| ( A B || )", "A"),
+ ("a? A", "A"),
+ ("( || ( || || ( A ) foo? ( B ) ) )", "A"),
+ ("( || ( || bar? ( A ) foo? ( B ) ) )", "A"),
+ )
+
+ for dep, atom, expected in test_cases:
+ expected = set(expected)
+ result = extract_affecting_use(dep, atom, eapi="0")
+ fail_msg = "dep: " + dep + ", atom: " + atom + ", got: " + \
+ " ".join(sorted(result)) + ", expected: " + " ".join(sorted(expected))
+ self.assertEqual(result, expected, fail_msg)
+
+ for dep, atom in test_cases_xfail:
+ fail_msg = "dep: " + dep + ", atom: " + atom + ", got: " + \
+ " ".join(sorted(result)) + ", expected: " + " ".join(sorted(expected))
+ self.assertRaisesMsg(fail_msg, \
+ InvalidDependString, extract_affecting_use, dep, atom, eapi="0")
diff --git a/portage_with_autodep/pym/portage/tests/dep/testStandalone.py b/portage_with_autodep/pym/portage/tests/dep/testStandalone.py
new file mode 100644
index 0000000..e9f01df
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/testStandalone.py
@@ -0,0 +1,36 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import cpvequal
+from portage.exception import PortageException
+
+class TestStandalone(TestCase):
+ """ Test some small functions portage.dep
+ """
+
+ def testCPVequal(self):
+
+ test_cases = (
+ ( "sys-apps/portage-2.1","sys-apps/portage-2.1", True ),
+ ( "sys-apps/portage-2.1","sys-apps/portage-2.0", False ),
+ ( "sys-apps/portage-2.1","sys-apps/portage-2.1-r1", False ),
+ ( "sys-apps/portage-2.1-r1","sys-apps/portage-2.1", False ),
+ ( "sys-apps/portage-2.1_alpha3","sys-apps/portage-2.1", False ),
+ ( "sys-apps/portage-2.1_alpha3_p6","sys-apps/portage-2.1_alpha3", False ),
+ ( "sys-apps/portage-2.1_alpha3","sys-apps/portage-2.1", False ),
+ ( "sys-apps/portage-2.1","sys-apps/X-2.1", False ),
+ ( "sys-apps/portage-2.1","portage-2.1", False ),
+ )
+
+ test_cases_xfail = (
+ ( "sys-apps/portage","sys-apps/portage" ),
+ ( "sys-apps/portage-2.1-6","sys-apps/portage-2.1-6" ),
+ )
+
+ for cpv1, cpv2, expected_result in test_cases:
+ self.assertEqual(cpvequal(cpv1, cpv2), expected_result)
+
+ for cpv1, cpv2 in test_cases_xfail:
+ self.assertRaisesMsg("cpvequal("+cpv1+", "+cpv2+")", \
+ PortageException, cpvequal, cpv1, cpv2)
diff --git a/portage_with_autodep/pym/portage/tests/dep/test_best_match_to_list.py b/portage_with_autodep/pym/portage/tests/dep/test_best_match_to_list.py
new file mode 100644
index 0000000..d050adc
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/test_best_match_to_list.py
@@ -0,0 +1,43 @@
+# test_best_match_to_list.py -- Portage Unit Testing Functionality
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import Atom, best_match_to_list
+
+class Test_best_match_to_list(TestCase):
+
+ def best_match_to_list_wrapper(self, mypkg, mylist):
+ """
+ This function uses best_match_to_list to create sorted
+ list of matching atoms.
+ """
+ ret = []
+ while mylist:
+ m = best_match_to_list(mypkg, mylist)
+ if m is not None:
+ ret.append(m)
+ mylist.remove(m)
+ else:
+ break
+
+ return ret
+
+ def testBest_match_to_list(self):
+ tests = [
+ ("dev-libs/A-1", [Atom("dev-libs/A"), Atom("=dev-libs/A-1")], \
+ [Atom("=dev-libs/A-1"), Atom("dev-libs/A")]),
+ ("dev-libs/A-1", [Atom("dev-libs/B"), Atom("=dev-libs/A-1:0")], \
+ [Atom("=dev-libs/A-1:0")]),
+ ("dev-libs/A-1", [Atom("dev-libs/*", allow_wildcard=True), Atom("=dev-libs/A-1:0")], \
+ [Atom("=dev-libs/A-1:0"), Atom("dev-libs/*", allow_wildcard=True)]),
+ ("dev-libs/A-1:0", [Atom("dev-*/*", allow_wildcard=True), Atom("dev-*/*:0", allow_wildcard=True),\
+ Atom("dev-libs/A"), Atom("<=dev-libs/A-2"), Atom("dev-libs/A:0"), \
+ Atom("=dev-libs/A-1*"), Atom("~dev-libs/A-1"), Atom("=dev-libs/A-1")], \
+ [Atom("=dev-libs/A-1"), Atom("~dev-libs/A-1"), Atom("=dev-libs/A-1*"), \
+ Atom("dev-libs/A:0"), Atom("<=dev-libs/A-2"), Atom("dev-libs/A"), \
+ Atom("dev-*/*:0", allow_wildcard=True), Atom("dev-*/*", allow_wildcard=True)])
+ ]
+
+ for pkg, atom_list, result in tests:
+ self.assertEqual( self.best_match_to_list_wrapper( pkg, atom_list ), result )
diff --git a/portage_with_autodep/pym/portage/tests/dep/test_dep_getcpv.py b/portage_with_autodep/pym/portage/tests/dep/test_dep_getcpv.py
new file mode 100644
index 0000000..8a0a8aa
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/test_dep_getcpv.py
@@ -0,0 +1,35 @@
+# test_dep_getcpv.py -- Portage Unit Testing Functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import dep_getcpv
+
+class DepGetCPV(TestCase):
+ """ A simple testcase for isvalidatom
+ """
+
+ def testDepGetCPV(self):
+
+ prefix_ops = ["<", ">", "=", "~", "<=",
+ ">=", "!=", "!<", "!>", "!~"]
+
+ bad_prefix_ops = [ ">~", "<~", "~>", "~<" ]
+ postfix_ops = [ ("=", "*"), ]
+
+ cpvs = ["sys-apps/portage-2.1", "sys-apps/portage-2.1",
+ "sys-apps/portage-2.1"]
+ slots = [None, ":foo", ":2"]
+ for cpv in cpvs:
+ for slot in slots:
+ for prefix in prefix_ops:
+ mycpv = prefix + cpv
+ if slot:
+ mycpv += slot
+ self.assertEqual( dep_getcpv( mycpv ), cpv )
+
+ for prefix, postfix in postfix_ops:
+ mycpv = prefix + cpv + postfix
+ if slot:
+ mycpv += slot
+ self.assertEqual( dep_getcpv( mycpv ), cpv )
diff --git a/portage_with_autodep/pym/portage/tests/dep/test_dep_getrepo.py b/portage_with_autodep/pym/portage/tests/dep/test_dep_getrepo.py
new file mode 100644
index 0000000..78ead8c
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/test_dep_getrepo.py
@@ -0,0 +1,29 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import dep_getrepo
+
+class DepGetRepo(TestCase):
+ """ A simple testcase for isvalidatom
+ """
+
+ def testDepGetRepo(self):
+
+ repo_char = "::"
+ repos = ( "a", "repo-name", "repo_name", "repo123", None )
+ cpvs = ["sys-apps/portage"]
+ versions = ["2.1.1","2.1-r1", None]
+ uses = ["[use]", None]
+ for cpv in cpvs:
+ for version in versions:
+ for use in uses:
+ for repo in repos:
+ pkg = cpv
+ if version:
+ pkg = '=' + pkg + '-' + version
+ if repo is not None:
+ pkg = pkg + repo_char + repo
+ if use:
+ pkg = pkg + use
+ self.assertEqual( dep_getrepo( pkg ), repo )
diff --git a/portage_with_autodep/pym/portage/tests/dep/test_dep_getslot.py b/portage_with_autodep/pym/portage/tests/dep/test_dep_getslot.py
new file mode 100644
index 0000000..206cecc
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/test_dep_getslot.py
@@ -0,0 +1,28 @@
+# test_dep_getslot.py -- Portage Unit Testing Functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import dep_getslot
+
+class DepGetSlot(TestCase):
+ """ A simple testcase for isvalidatom
+ """
+
+ def testDepGetSlot(self):
+
+ slot_char = ":"
+ slots = ( "a", "1.2", "1", "IloveVapier", None )
+ cpvs = ["sys-apps/portage"]
+ versions = ["2.1.1","2.1-r1"]
+ for cpv in cpvs:
+ for version in versions:
+ for slot in slots:
+ mycpv = cpv
+ if version:
+ mycpv = '=' + mycpv + '-' + version
+ if slot is not None:
+ self.assertEqual( dep_getslot(
+ mycpv + slot_char + slot ), slot )
+ else:
+ self.assertEqual( dep_getslot( mycpv ), slot )
diff --git a/portage_with_autodep/pym/portage/tests/dep/test_dep_getusedeps.py b/portage_with_autodep/pym/portage/tests/dep/test_dep_getusedeps.py
new file mode 100644
index 0000000..d2494f7
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/test_dep_getusedeps.py
@@ -0,0 +1,35 @@
+# test_dep_getusedeps.py -- Portage Unit Testing Functionality
+# Copyright 2007-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import dep_getusedeps
+
+from portage.tests import test_cps, test_slots, test_versions, test_usedeps
+
+class DepGetUseDeps(TestCase):
+ """ A simple testcase for dep_getusedeps
+ """
+
+ def testDepGetUseDeps(self):
+
+ for mycpv in test_cps:
+ for version in test_versions:
+ for slot in test_slots:
+ for use in test_usedeps:
+ cpv = mycpv[:]
+ if version:
+ cpv += version
+ if slot:
+ cpv += ":" + slot
+ if isinstance(use, tuple):
+ cpv += "[%s]" % (",".join(use),)
+ self.assertEqual( dep_getusedeps(
+ cpv ), use )
+ else:
+ if len(use):
+ self.assertEqual( dep_getusedeps(
+ cpv + "[" + use + "]" ), (use,) )
+ else:
+ self.assertEqual( dep_getusedeps(
+ cpv + "[" + use + "]" ), () )
diff --git a/portage_with_autodep/pym/portage/tests/dep/test_get_operator.py b/portage_with_autodep/pym/portage/tests/dep/test_get_operator.py
new file mode 100644
index 0000000..4f9848f
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/test_get_operator.py
@@ -0,0 +1,33 @@
+# test_get_operator.py -- Portage Unit Testing Functionality
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import get_operator
+
+class GetOperator(TestCase):
+
+ def testGetOperator(self):
+
+ # get_operator does not validate operators
+ tests = [ ( "~", "~" ), ( "=", "=" ), ( ">", ">" ),
+ ( ">=", ">=" ), ( "<=", "<=" ),
+ ]
+
+ test_cpvs = ["sys-apps/portage-2.1"]
+ slots = [ None,"1","linux-2.5.6" ]
+ for cpv in test_cpvs:
+ for test in tests:
+ for slot in slots:
+ atom = cpv[:]
+ if slot:
+ atom += ":" + slot
+ result = get_operator( test[0] + atom )
+ self.assertEqual( result, test[1],
+ msg="get_operator(%s) != %s" % (test[0] + atom, test[1]) )
+
+ result = get_operator( "sys-apps/portage" )
+ self.assertEqual( result, None )
+
+ result = get_operator( "=sys-apps/portage-2.1*" )
+ self.assertEqual( result , "=*" )
diff --git a/portage_with_autodep/pym/portage/tests/dep/test_get_required_use_flags.py b/portage_with_autodep/pym/portage/tests/dep/test_get_required_use_flags.py
new file mode 100644
index 0000000..06f8110
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/test_get_required_use_flags.py
@@ -0,0 +1,42 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import get_required_use_flags
+from portage.exception import InvalidDependString
+
+class TestCheckRequiredUse(TestCase):
+
+ def testCheckRequiredUse(self):
+ test_cases = (
+ ("a b c", ["a", "b", "c"]),
+
+ ("|| ( a b c )", ["a", "b", "c"]),
+ ("^^ ( a b c )", ["a", "b", "c"]),
+
+ ("|| ( a b ^^ ( d e f ) )", ["a", "b", "d", "e", "f"]),
+ ("^^ ( a b || ( d e f ) )", ["a", "b", "d", "e", "f"]),
+
+ ("( ^^ ( a ( b ) ( || ( ( d e ) ( f ) ) ) ) )", ["a", "b", "d", "e", "f"]),
+
+ ("a? ( ^^ ( b c ) )", ["a", "b", "c"]),
+ ("a? ( ^^ ( !b !d? ( c ) ) )", ["a", "b", "c", "d"]),
+ )
+
+ test_cases_xfail = (
+ ("^^ ( || ( a b ) ^^ ( b c )"),
+ ("^^( || ( a b ) ^^ ( b c ) )"),
+ ("^^ || ( a b ) ^^ ( b c )"),
+ ("^^ ( ( || ) ( a b ) ^^ ( b c ) )"),
+ ("^^ ( || ( a b ) ) ^^ ( b c ) )"),
+ )
+
+ for required_use, expected in test_cases:
+ result = get_required_use_flags(required_use)
+ expected = set(expected)
+ self.assertEqual(result, expected, \
+ "REQUIRED_USE: '%s', expected: '%s', got: '%s'" % (required_use, expected, result))
+
+ for required_use in test_cases_xfail:
+ self.assertRaisesMsg("REQUIRED_USE: '%s'" % (required_use,), \
+ InvalidDependString, get_required_use_flags, required_use)
diff --git a/portage_with_autodep/pym/portage/tests/dep/test_isjustname.py b/portage_with_autodep/pym/portage/tests/dep/test_isjustname.py
new file mode 100644
index 0000000..c16fb54
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/test_isjustname.py
@@ -0,0 +1,24 @@
+# test_isjustname.py -- Portage Unit Testing Functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import isjustname
+
+class IsJustName(TestCase):
+
+ def testIsJustName(self):
+
+ cats = ( "", "sys-apps/", "foo/", "virtual/" )
+ pkgs = ( "portage", "paludis", "pkgcore", "notARealPkg" )
+ vers = ( "", "-2.0-r3", "-1.0_pre2", "-3.1b" )
+
+ for pkg in pkgs:
+ for cat in cats:
+ for ver in vers:
+ if len(ver):
+ self.assertFalse( isjustname( cat + pkg + ver ),
+ msg="isjustname(%s) is True!" % (cat + pkg + ver) )
+ else:
+ self.assertTrue( isjustname( cat + pkg + ver ),
+ msg="isjustname(%s) is False!" % (cat + pkg + ver) )
diff --git a/portage_with_autodep/pym/portage/tests/dep/test_isvalidatom.py b/portage_with_autodep/pym/portage/tests/dep/test_isvalidatom.py
new file mode 100644
index 0000000..173ab0d
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/test_isvalidatom.py
@@ -0,0 +1,146 @@
+# Copyright 2006-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import isvalidatom
+
+class IsValidAtomTestCase(object):
+ def __init__(self, atom, expected, allow_wildcard=False, allow_repo=False):
+ self.atom = atom
+ self.expected = expected
+ self.allow_wildcard = allow_wildcard
+ self.allow_repo = allow_repo
+
+class IsValidAtom(TestCase):
+
+ def testIsValidAtom(self):
+
+ test_cases = (
+ IsValidAtomTestCase("sys-apps/portage", True),
+ IsValidAtomTestCase("=sys-apps/portage-2.1", True),
+ IsValidAtomTestCase("=sys-apps/portage-2.1*", True),
+ IsValidAtomTestCase(">=sys-apps/portage-2.1", True),
+ IsValidAtomTestCase("<=sys-apps/portage-2.1", True),
+ IsValidAtomTestCase(">sys-apps/portage-2.1", True),
+ IsValidAtomTestCase("<sys-apps/portage-2.1", True),
+ IsValidAtomTestCase("~sys-apps/portage-2.1", True),
+ IsValidAtomTestCase("sys-apps/portage:foo", True),
+ IsValidAtomTestCase("sys-apps/portage-2.1:foo", False),
+ IsValidAtomTestCase( "sys-apps/portage-2.1:", False),
+ IsValidAtomTestCase("sys-apps/portage-2.1:", False),
+ IsValidAtomTestCase("sys-apps/portage-2.1:[foo]", False),
+ IsValidAtomTestCase("sys-apps/portage", True),
+ IsValidAtomTestCase("sys-apps/portage", True),
+ IsValidAtomTestCase("sys-apps/portage", True),
+ IsValidAtomTestCase("sys-apps/portage", True),
+ IsValidAtomTestCase("sys-apps/portage", True),
+ IsValidAtomTestCase("sys-apps/portage", True),
+ IsValidAtomTestCase("sys-apps/portage", True),
+
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[bar?,!baz?,!doc=,build=]", True),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[doc?]", True),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[!doc?]", True),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[doc=]", True),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[!doc=]", True),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[!doc]", False),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[!-doc]", False),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[!-doc=]", False),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[!-doc?]", False),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[-doc?]", False),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[-doc=]", False),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[-doc!=]", False),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[-doc=]", False),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[bar][-baz][doc?][!build?]", False),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[bar,-baz,doc?,!build?]", True),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[bar,-baz,doc?,!build?,]", False),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[,bar,-baz,doc?,!build?]", False),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[bar,-baz][doc?,!build?]", False),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo[bar][doc,build]", False),
+ IsValidAtomTestCase(">~cate-gory/foo-1.0", False),
+ IsValidAtomTestCase(">~category/foo-1.0", False),
+ IsValidAtomTestCase("<~category/foo-1.0", False),
+ IsValidAtomTestCase("###cat/foo-1.0", False),
+ IsValidAtomTestCase("~sys-apps/portage", False),
+ IsValidAtomTestCase("portage", False),
+ IsValidAtomTestCase("=portage", False),
+ IsValidAtomTestCase(">=portage-2.1", False),
+ IsValidAtomTestCase("~portage-2.1", False),
+ IsValidAtomTestCase("=portage-2.1*", False),
+ IsValidAtomTestCase("null/portage", True),
+ IsValidAtomTestCase("null/portage*:0", False),
+ IsValidAtomTestCase(">=null/portage-2.1", True),
+ IsValidAtomTestCase(">=null/portage", False),
+ IsValidAtomTestCase(">null/portage", False),
+ IsValidAtomTestCase("=null/portage*", False),
+ IsValidAtomTestCase("=null/portage", False),
+ IsValidAtomTestCase("~null/portage", False),
+ IsValidAtomTestCase("<=null/portage", False),
+ IsValidAtomTestCase("<null/portage", False),
+ IsValidAtomTestCase("~null/portage-2.1", True),
+ IsValidAtomTestCase("=null/portage-2.1*", True),
+ IsValidAtomTestCase("null/portage-2.1*", False),
+ IsValidAtomTestCase("app-doc/php-docs-20071125", False),
+ IsValidAtomTestCase("app-doc/php-docs-20071125-r2", False),
+ IsValidAtomTestCase("=foo/bar-1-r1-1-r1", False),
+ IsValidAtomTestCase("foo/-z-1", False),
+
+ # These are invalid because pkg name must not end in hyphen
+ # followed by numbers
+ IsValidAtomTestCase("=foo/bar-1-r1-1-r1", False),
+ IsValidAtomTestCase("=foo/bar-123-1", False),
+ IsValidAtomTestCase("=foo/bar-123-1*", False),
+ IsValidAtomTestCase("foo/bar-123", False),
+ IsValidAtomTestCase("=foo/bar-123-1-r1", False),
+ IsValidAtomTestCase("=foo/bar-123-1-r1*", False),
+ IsValidAtomTestCase("foo/bar-123-r1", False),
+ IsValidAtomTestCase("foo/bar-1", False),
+
+ IsValidAtomTestCase("=foo/bar--baz-1-r1", True),
+ IsValidAtomTestCase("=foo/bar-baz--1-r1", True),
+ IsValidAtomTestCase("=foo/bar-baz---1-r1", True),
+ IsValidAtomTestCase("=foo/bar-baz---1", True),
+ IsValidAtomTestCase("=foo/bar-baz-1--r1", False),
+ IsValidAtomTestCase("games-strategy/ufo2000", True),
+ IsValidAtomTestCase("~games-strategy/ufo2000-0.1", True),
+ IsValidAtomTestCase("=media-libs/x264-20060810", True),
+ IsValidAtomTestCase("foo/b", True),
+ IsValidAtomTestCase("app-text/7plus", True),
+ IsValidAtomTestCase("foo/666", True),
+ IsValidAtomTestCase("=dev-libs/poppler-qt3-0.11*", True),
+
+ #Testing atoms with repositories
+ IsValidAtomTestCase("sys-apps/portage::repo_123-name", True, allow_repo=True),
+ IsValidAtomTestCase("=sys-apps/portage-2.1::repo", True, allow_repo=True),
+ IsValidAtomTestCase("=sys-apps/portage-2.1*::repo", True, allow_repo=True),
+ IsValidAtomTestCase("sys-apps/portage:foo::repo", True, allow_repo=True),
+ IsValidAtomTestCase("sys-apps/portage-2.1:foo::repo", False, allow_repo=True),
+ IsValidAtomTestCase("sys-apps/portage-2.1:::repo", False, allow_repo=True),
+ IsValidAtomTestCase("sys-apps/portage-2.1:::repo[foo]", False, allow_repo=True),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo::repo[bar?,!baz?,!doc=,build=]", True, allow_repo=True),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo::repo[doc?]", True, allow_repo=True),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo::repo[!doc]", False, allow_repo=True),
+ IsValidAtomTestCase("###cat/foo-1.0::repo", False, allow_repo=True),
+ IsValidAtomTestCase("~sys-apps/portage::repo", False, allow_repo=True),
+ IsValidAtomTestCase("portage::repo", False, allow_repo=True),
+ IsValidAtomTestCase("=portage::repo", False, allow_repo=True),
+ IsValidAtomTestCase("null/portage::repo", True, allow_repo=True),
+ IsValidAtomTestCase("app-doc/php-docs-20071125::repo", False, allow_repo=True),
+ IsValidAtomTestCase("=foo/bar-1-r1-1-r1::repo", False, allow_repo=True),
+
+ IsValidAtomTestCase("sys-apps/portage::repo_123-name", False, allow_repo=False),
+ IsValidAtomTestCase("=sys-apps/portage-2.1::repo", False, allow_repo=False),
+ IsValidAtomTestCase("=sys-apps/portage-2.1*::repo", False, allow_repo=False),
+ IsValidAtomTestCase("sys-apps/portage:foo::repo", False, allow_repo=False),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo::repo[bar?,!baz?,!doc=,build=]", False, allow_repo=False),
+ IsValidAtomTestCase("=sys-apps/portage-2.2*:foo::repo[doc?]", False, allow_repo=False),
+ IsValidAtomTestCase("null/portage::repo", False, allow_repo=False),
+ )
+
+ for test_case in test_cases:
+ if test_case.expected:
+ atom_type = "valid"
+ else:
+ atom_type = "invalid"
+ self.assertEqual( bool(isvalidatom(test_case.atom, allow_wildcard=test_case.allow_wildcard, \
+ allow_repo=test_case.allow_repo)), test_case.expected,
+ msg="isvalidatom(%s) != %s" % ( test_case.atom, test_case.expected ) )
diff --git a/portage_with_autodep/pym/portage/tests/dep/test_match_from_list.py b/portage_with_autodep/pym/portage/tests/dep/test_match_from_list.py
new file mode 100644
index 0000000..afba414
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/test_match_from_list.py
@@ -0,0 +1,108 @@
+# Copyright 2006, 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+from portage.tests import TestCase
+from portage.dep import Atom, match_from_list, _repo_separator
+from portage.versions import catpkgsplit
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+class Package(object):
+ """
+ Provides a minimal subset of attributes of _emerge.Package.Package
+ """
+ def __init__(self, atom):
+ atom = Atom(atom, allow_repo=True)
+ self.cp = atom.cp
+ self.cpv = atom.cpv
+ self.cpv_split = catpkgsplit(self.cpv)
+ self.slot = atom.slot
+ self.repo = atom.repo
+ if atom.use:
+ self.use = self._use_class(atom.use.enabled)
+ self.iuse = self._iuse_class(atom.use.required)
+ else:
+ self.use = self._use_class([])
+ self.iuse = self._iuse_class([])
+
+ class _use_class(object):
+ def __init__(self, use):
+ self.enabled = frozenset(use)
+
+ class _iuse_class(object):
+ def __init__(self, iuse):
+ self.all = frozenset(iuse)
+
+ def is_valid_flag(self, flags):
+ if isinstance(flags, basestring):
+ flags = [flags]
+ for flag in flags:
+ if not flag in self.all:
+ return False
+ return True
+
+class Test_match_from_list(TestCase):
+
+ def testMatch_from_list(self):
+ tests = (
+ ("=sys-apps/portage-45*", [], [] ),
+ ("=sys-apps/portage-45*", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+ ("!=sys-apps/portage-45*", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+ ("!!=sys-apps/portage-45*", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+ ("=sys-apps/portage-045", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+ ("=sys-apps/portage-045", ["sys-apps/portage-046"], [] ),
+ ("~sys-apps/portage-045", ["sys-apps/portage-045-r1"], ["sys-apps/portage-045-r1"] ),
+ ("~sys-apps/portage-045", ["sys-apps/portage-046-r1"], [] ),
+ ("<=sys-apps/portage-045", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+ ("<=sys-apps/portage-045", ["sys-apps/portage-046"], [] ),
+ ("<sys-apps/portage-046", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+ ("<sys-apps/portage-046", ["sys-apps/portage-046"], [] ),
+ (">=sys-apps/portage-045", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+ (">=sys-apps/portage-047", ["sys-apps/portage-046-r1"], [] ),
+ (">sys-apps/portage-044", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+ (">sys-apps/portage-047", ["sys-apps/portage-046-r1"], [] ),
+ ("sys-apps/portage:0", [Package("=sys-apps/portage-045:0")], ["sys-apps/portage-045"] ),
+ ("sys-apps/portage:0", [Package("=sys-apps/portage-045:1")], [] ),
+ ("=sys-fs/udev-1*", ["sys-fs/udev-123"], ["sys-fs/udev-123"]),
+ ("=sys-fs/udev-4*", ["sys-fs/udev-456"], ["sys-fs/udev-456"] ),
+ ("*/*", ["sys-fs/udev-456"], ["sys-fs/udev-456"] ),
+ ("sys-fs/*", ["sys-fs/udev-456"], ["sys-fs/udev-456"] ),
+ ("*/udev", ["sys-fs/udev-456"], ["sys-fs/udev-456"] ),
+ ("=sys-apps/portage-2*", ["sys-apps/portage-2.1"], ["sys-apps/portage-2.1"] ),
+ ("=sys-apps/portage-2.1*", ["sys-apps/portage-2.1.2"], ["sys-apps/portage-2.1.2"] ),
+ ("dev-libs/*", ["sys-apps/portage-2.1.2"], [] ),
+ ("*/tar", ["sys-apps/portage-2.1.2"], [] ),
+ ("*/*", ["dev-libs/A-1", "dev-libs/B-1"], ["dev-libs/A-1", "dev-libs/B-1"] ),
+ ("dev-libs/*", ["dev-libs/A-1", "sci-libs/B-1"], ["dev-libs/A-1"] ),
+
+ ("dev-libs/A[foo]", [Package("=dev-libs/A-1[foo]"), Package("=dev-libs/A-2[-foo]")], ["dev-libs/A-1"] ),
+ ("dev-libs/A[-foo]", [Package("=dev-libs/A-1[foo]"), Package("=dev-libs/A-2[-foo]")], ["dev-libs/A-2"] ),
+ ("dev-libs/A[-foo]", [Package("=dev-libs/A-1[foo]"), Package("=dev-libs/A-2")], [] ),
+ ("dev-libs/A[foo,bar]", [Package("=dev-libs/A-1[foo]"), Package("=dev-libs/A-2[-foo]")], [] ),
+ ("dev-libs/A[foo,bar]", [Package("=dev-libs/A-1[foo]"), Package("=dev-libs/A-2[-foo,bar]")], [] ),
+ ("dev-libs/A[foo,bar]", [Package("=dev-libs/A-1[foo]"), Package("=dev-libs/A-2[foo,bar]")], ["dev-libs/A-2"] ),
+ ("dev-libs/A[foo,bar(+)]", [Package("=dev-libs/A-1[-foo]"), Package("=dev-libs/A-2[foo]")], ["dev-libs/A-2"] ),
+ ("dev-libs/A[foo,bar(-)]", [Package("=dev-libs/A-1[-foo]"), Package("=dev-libs/A-2[foo]")], [] ),
+ ("dev-libs/A[foo,-bar(-)]", [Package("=dev-libs/A-1[-foo,bar]"), Package("=dev-libs/A-2[foo]")], ["dev-libs/A-2"] ),
+
+ ("dev-libs/A::repo1", [Package("=dev-libs/A-1::repo1"), Package("=dev-libs/A-1::repo2")], ["dev-libs/A-1::repo1"] ),
+ ("dev-libs/A::repo2", [Package("=dev-libs/A-1::repo1"), Package("=dev-libs/A-1::repo2")], ["dev-libs/A-1::repo2"] ),
+ ("dev-libs/A::repo2[foo]", [Package("=dev-libs/A-1::repo1[foo]"), Package("=dev-libs/A-1::repo2[-foo]")], [] ),
+ ("dev-libs/A::repo2[foo]", [Package("=dev-libs/A-1::repo1[-foo]"), Package("=dev-libs/A-1::repo2[foo]")], ["dev-libs/A-1::repo2"] ),
+ ("dev-libs/A:1::repo2[foo]", [Package("=dev-libs/A-1:1::repo1"), Package("=dev-libs/A-1:2::repo2")], [] ),
+ ("dev-libs/A:1::repo2[foo]", [Package("=dev-libs/A-1:2::repo1"), Package("=dev-libs/A-1:1::repo2[foo]")], ["dev-libs/A-1::repo2"] ),
+ )
+
+ for atom, cpv_list, expected_result in tests:
+ result = []
+ for pkg in match_from_list( atom, cpv_list ):
+ if isinstance(pkg, Package):
+ if pkg.repo:
+ result.append(pkg.cpv + _repo_separator + pkg.repo)
+ else:
+ result.append(pkg.cpv)
+ else:
+ result.append(pkg)
+ self.assertEqual( result, expected_result )
diff --git a/portage_with_autodep/pym/portage/tests/dep/test_paren_reduce.py b/portage_with_autodep/pym/portage/tests/dep/test_paren_reduce.py
new file mode 100644
index 0000000..9a147a0
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/test_paren_reduce.py
@@ -0,0 +1,66 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import paren_reduce
+from portage.exception import InvalidDependString
+
+class TestParenReduce(TestCase):
+
+ def testParenReduce(self):
+
+ test_cases = (
+ ( "A", ["A"]),
+ ( "( A )", ["A"]),
+ ( "|| ( A B )", [ "||", ["A", "B"] ]),
+ ( "|| ( A || ( B C ) )", [ "||", ["A", "||", ["B", "C"]]]),
+ ( "|| ( A || ( B C D ) )", [ "||", ["A", "||", ["B", "C", "D"]] ]),
+ ( "|| ( A || ( B || ( C D ) E ) )", [ "||", ["A", "||", ["B", "||", ["C", "D"], "E"]] ]),
+ ( "a? ( A )", ["a?", ["A"]]),
+
+ ( "( || ( ( ( A ) B ) ) )", ["A", "B"]),
+ ( "( || ( || ( ( A ) B ) ) )", [ "||", ["A", "B"] ]),
+ ( "|| ( A )", ["A"]),
+ ( "( || ( || ( || ( A ) foo? ( B ) ) ) )", [ "||", ["A", "foo?", ["B"] ]]),
+ ( "( || ( || ( bar? ( A ) || ( foo? ( B ) ) ) ) )", [ "||", ["bar?", ["A"], "foo?", ["B"] ]]),
+ ( "A || ( ) foo? ( ) B", ["A", "B"]),
+
+ ( "|| ( A ) || ( B )", ["A", "B"]),
+ ( "foo? ( A ) foo? ( B )", ["foo?", ["A"], "foo?", ["B"]]),
+
+ ( "|| ( ( A B ) C )", [ "||", [ ["A", "B"], "C"] ]),
+ ( "|| ( ( A B ) ( C ) )", [ "||", [ ["A", "B"], "C"] ]),
+ # test USE dep defaults for bug #354003
+ ( ">=dev-lang/php-5.2[pcre(+)]", [ ">=dev-lang/php-5.2[pcre(+)]" ]),
+ )
+
+ test_cases_xfail = (
+ "( A",
+ "A )",
+
+ "||( A B )",
+ "|| (A B )",
+ "|| ( A B)",
+ "|| ( A B",
+ "|| A B )",
+
+ "|| A B",
+ "|| ( A B ) )",
+ "|| || B C",
+
+ "|| ( A B || )",
+
+ "a? A",
+
+ ( "( || ( || || ( A ) foo? ( B ) ) )"),
+ ( "( || ( || bar? ( A ) foo? ( B ) ) )"),
+ )
+
+ for dep_str, expected_result in test_cases:
+ self.assertEqual(paren_reduce(dep_str), expected_result,
+ "input: '%s' result: %s != %s" % (dep_str,
+ paren_reduce(dep_str), expected_result))
+
+ for dep_str in test_cases_xfail:
+ self.assertRaisesMsg(dep_str,
+ InvalidDependString, paren_reduce, dep_str)
diff --git a/portage_with_autodep/pym/portage/tests/dep/test_use_reduce.py b/portage_with_autodep/pym/portage/tests/dep/test_use_reduce.py
new file mode 100644
index 0000000..1618430
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/dep/test_use_reduce.py
@@ -0,0 +1,627 @@
+# Copyright 2009-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.exception import InvalidDependString
+from portage.dep import Atom, use_reduce
+
+class UseReduceTestCase(object):
+ def __init__(self, deparray, uselist=[], masklist=[], \
+ matchall=0, excludeall=[], is_src_uri=False, \
+ eapi="0", opconvert=False, flat=False, expected_result=None, \
+ is_valid_flag=None, token_class=None):
+ self.deparray = deparray
+ self.uselist = uselist
+ self.masklist = masklist
+ self.matchall = matchall
+ self.excludeall = excludeall
+ self.is_src_uri = is_src_uri
+ self.eapi = eapi
+ self.opconvert = opconvert
+ self.flat = flat
+ self.is_valid_flag = is_valid_flag
+ self.token_class = token_class
+ self.expected_result = expected_result
+
+ def run(self):
+ try:
+ return use_reduce(self.deparray, self.uselist, self.masklist, \
+ self.matchall, self.excludeall, self.is_src_uri, self.eapi, \
+ self.opconvert, self.flat, self.is_valid_flag, self.token_class)
+ except InvalidDependString as e:
+ raise InvalidDependString("%s: %s" % (e, self.deparray))
+
+class UseReduce(TestCase):
+
+ def always_true(self, ununsed_parameter):
+ return True
+
+ def always_false(self, ununsed_parameter):
+ return False
+
+ def testUseReduce(self):
+
+ EAPI_WITH_SRC_URI_ARROWS = "2"
+ EAPI_WITHOUT_SRC_URI_ARROWS = "0"
+
+ test_cases = (
+ UseReduceTestCase(
+ "a? ( A ) b? ( B ) !c? ( C ) !d? ( D )",
+ uselist = ["a", "b", "c", "d"],
+ expected_result = ["A", "B"]
+ ),
+ UseReduceTestCase(
+ "a? ( A ) b? ( B ) !c? ( C ) !d? ( D )",
+ uselist = ["a", "b", "c"],
+ expected_result = ["A", "B", "D"]
+ ),
+ UseReduceTestCase(
+ "a? ( A ) b? ( B ) !c? ( C ) !d? ( D )",
+ uselist = ["b", "c"],
+ expected_result = ["B", "D"]
+ ),
+
+ UseReduceTestCase(
+ "a? ( A ) b? ( B ) !c? ( C ) !d? ( D )",
+ matchall = True,
+ expected_result = ["A", "B", "C", "D"]
+ ),
+ UseReduceTestCase(
+ "a? ( A ) b? ( B ) !c? ( C ) !d? ( D )",
+ masklist = ["a", "c"],
+ expected_result = ["C", "D"]
+ ),
+ UseReduceTestCase(
+ "a? ( A ) b? ( B ) !c? ( C ) !d? ( D )",
+ matchall = True,
+ masklist = ["a", "c"],
+ expected_result = ["B", "C", "D"]
+ ),
+ UseReduceTestCase(
+ "a? ( A ) b? ( B ) !c? ( C ) !d? ( D )",
+ uselist = ["a", "b"],
+ masklist = ["a", "c"],
+ expected_result = ["B", "C", "D"]
+ ),
+ UseReduceTestCase(
+ "a? ( A ) b? ( B ) !c? ( C ) !d? ( D )",
+ excludeall = ["a", "c"],
+ expected_result = ["D"]
+ ),
+ UseReduceTestCase(
+ "a? ( A ) b? ( B ) !c? ( C ) !d? ( D )",
+ uselist = ["b"],
+ excludeall = ["a", "c"],
+ expected_result = ["B", "D"]
+ ),
+ UseReduceTestCase(
+ "a? ( A ) b? ( B ) !c? ( C ) !d? ( D )",
+ matchall = True,
+ excludeall = ["a", "c"],
+ expected_result = ["A", "B", "D"]
+ ),
+ UseReduceTestCase(
+ "a? ( A ) b? ( B ) !c? ( C ) !d? ( D )",
+ matchall = True,
+ excludeall = ["a", "c"],
+ masklist = ["b"],
+ expected_result = ["A", "D"]
+ ),
+
+
+ UseReduceTestCase(
+ "a? ( b? ( AB ) )",
+ uselist = ["a", "b"],
+ expected_result = ["AB"]
+ ),
+ UseReduceTestCase(
+ "a? ( b? ( AB ) C )",
+ uselist = ["a"],
+ expected_result = ["C"]
+ ),
+ UseReduceTestCase(
+ "a? ( b? ( || ( AB CD ) ) )",
+ uselist = ["a", "b"],
+ expected_result = ["||", ["AB", "CD"]]
+ ),
+ UseReduceTestCase(
+ "|| ( || ( a? ( A ) b? ( B ) ) )",
+ uselist = ["a", "b"],
+ expected_result = ["||", ["A", "B"]]
+ ),
+ UseReduceTestCase(
+ "|| ( || ( a? ( A ) b? ( B ) ) )",
+ uselist = ["a"],
+ expected_result = ["A"]
+ ),
+ UseReduceTestCase(
+ "|| ( || ( a? ( A ) b? ( B ) ) )",
+ uselist = [],
+ expected_result = []
+ ),
+ UseReduceTestCase(
+ "|| ( || ( a? ( || ( A c? ( C ) ) ) b? ( B ) ) )",
+ uselist = [],
+ expected_result = []
+ ),
+ UseReduceTestCase(
+ "|| ( || ( a? ( || ( A c? ( C ) ) ) b? ( B ) ) )",
+ uselist = ["a"],
+ expected_result = ["A"]
+ ),
+ UseReduceTestCase(
+ "|| ( || ( a? ( || ( A c? ( C ) ) ) b? ( B ) ) )",
+ uselist = ["b"],
+ expected_result = ["B"]
+ ),
+ UseReduceTestCase(
+ "|| ( || ( a? ( || ( A c? ( C ) ) ) b? ( B ) ) )",
+ uselist = ["c"],
+ expected_result = []
+ ),
+ UseReduceTestCase(
+ "|| ( || ( a? ( || ( A c? ( C ) ) ) b? ( B ) ) )",
+ uselist = ["a", "c"],
+ expected_result = ["||", [ "A", "C"]]
+ ),
+
+ #paren_reduce tests
+ UseReduceTestCase(
+ "A",
+ expected_result = ["A"]),
+ UseReduceTestCase(
+ "( A )",
+ expected_result = ["A"]),
+ UseReduceTestCase(
+ "|| ( A B )",
+ expected_result = [ "||", ["A", "B"] ]),
+ UseReduceTestCase(
+ "|| ( ( A B ) C )",
+ expected_result = [ "||", [ ["A", "B"], "C"] ]),
+ UseReduceTestCase(
+ "|| ( ( A B ) ( C ) )",
+ expected_result = [ "||", [ ["A", "B"], "C"] ]),
+ UseReduceTestCase(
+ "|| ( A || ( B C ) )",
+ expected_result = [ "||", ["A", "B", "C"]]),
+ UseReduceTestCase(
+ "|| ( A || ( B C D ) )",
+ expected_result = [ "||", ["A", "B", "C", "D"] ]),
+ UseReduceTestCase(
+ "|| ( A || ( B || ( C D ) E ) )",
+ expected_result = [ "||", ["A", "B", "C", "D", "E"] ]),
+ UseReduceTestCase(
+ "( || ( ( ( A ) B ) ) )",
+ expected_result = ["A", "B"] ),
+ UseReduceTestCase(
+ "( || ( || ( ( A ) B ) ) )",
+ expected_result = [ "||", ["A", "B"] ]),
+ UseReduceTestCase(
+ "( || ( || ( ( A ) B ) ) )",
+ expected_result = [ "||", ["A", "B"] ]),
+ UseReduceTestCase(
+ "|| ( A )",
+ expected_result = ["A"]),
+ UseReduceTestCase(
+ "( || ( || ( || ( A ) foo? ( B ) ) ) )",
+ expected_result = ["A"]),
+ UseReduceTestCase(
+ "( || ( || ( || ( A ) foo? ( B ) ) ) )",
+ uselist = ["foo"],
+ expected_result = [ "||", ["A", "B"] ]),
+ UseReduceTestCase(
+ "( || ( || ( bar? ( A ) || ( foo? ( B ) ) ) ) )",
+ expected_result = []),
+ UseReduceTestCase(
+ "( || ( || ( bar? ( A ) || ( foo? ( B ) ) ) ) )",
+ uselist = ["foo", "bar"],
+ expected_result = [ "||", [ "A", "B" ] ]),
+ UseReduceTestCase(
+ "A || ( bar? ( C ) ) foo? ( bar? ( C ) ) B",
+ expected_result = ["A", "B"]),
+ UseReduceTestCase(
+ "|| ( A ) || ( B )",
+ expected_result = ["A", "B"]),
+ UseReduceTestCase(
+ "foo? ( A ) foo? ( B )",
+ expected_result = []),
+ UseReduceTestCase(
+ "foo? ( A ) foo? ( B )",
+ uselist = ["foo"],
+ expected_result = ["A", "B"]),
+ UseReduceTestCase(
+ "|| ( A B ) C",
+ expected_result = ['||', ['A', 'B'], 'C']),
+ UseReduceTestCase(
+ "A || ( B C )",
+ expected_result = ['A', '||', ['B', 'C']]),
+
+ #SRC_URI stuff
+ UseReduceTestCase(
+ "http://foo/bar -> blah.tbz2",
+ is_src_uri = True,
+ eapi = EAPI_WITH_SRC_URI_ARROWS,
+ expected_result = ["http://foo/bar", "->", "blah.tbz2"]),
+ UseReduceTestCase(
+ "foo? ( http://foo/bar -> blah.tbz2 )",
+ uselist = [],
+ is_src_uri = True,
+ eapi = EAPI_WITH_SRC_URI_ARROWS,
+ expected_result = []),
+ UseReduceTestCase(
+ "foo? ( http://foo/bar -> blah.tbz2 )",
+ uselist = ["foo"],
+ is_src_uri = True,
+ eapi = EAPI_WITH_SRC_URI_ARROWS,
+ expected_result = ["http://foo/bar", "->", "blah.tbz2"]),
+ UseReduceTestCase(
+ "http://foo/bar -> bar.tbz2 foo? ( ftp://foo/a )",
+ uselist = [],
+ is_src_uri = True,
+ eapi = EAPI_WITH_SRC_URI_ARROWS,
+ expected_result = ["http://foo/bar", "->", "bar.tbz2"]),
+ UseReduceTestCase(
+ "http://foo/bar -> bar.tbz2 foo? ( ftp://foo/a )",
+ uselist = ["foo"],
+ is_src_uri = True,
+ eapi = EAPI_WITH_SRC_URI_ARROWS,
+ expected_result = ["http://foo/bar", "->", "bar.tbz2", "ftp://foo/a"]),
+ UseReduceTestCase(
+ "http://foo.com/foo http://foo/bar -> blah.tbz2",
+ uselist = ["foo"],
+ is_src_uri = True,
+ eapi = EAPI_WITH_SRC_URI_ARROWS,
+ expected_result = ["http://foo.com/foo", "http://foo/bar", "->", "blah.tbz2"]),
+
+ #opconvert tests
+ UseReduceTestCase(
+ "A",
+ opconvert = True,
+ expected_result = ["A"]),
+ UseReduceTestCase(
+ "( A )",
+ opconvert = True,
+ expected_result = ["A"]),
+ UseReduceTestCase(
+ "|| ( A B )",
+ opconvert = True,
+ expected_result = [['||', 'A', 'B']]),
+ UseReduceTestCase(
+ "|| ( ( A B ) C )",
+ opconvert = True,
+ expected_result = [['||', ['A', 'B'], 'C']]),
+ UseReduceTestCase(
+ "|| ( A || ( B C ) )",
+ opconvert = True,
+ expected_result = [['||', 'A', 'B', 'C']]),
+ UseReduceTestCase(
+ "|| ( A || ( B C D ) )",
+ opconvert = True,
+ expected_result = [['||', 'A', 'B', 'C', 'D']]),
+ UseReduceTestCase(
+ "|| ( A || ( B || ( C D ) E ) )",
+ expected_result = [ "||", ["A", "B", "C", "D", "E"] ]),
+ UseReduceTestCase(
+ "( || ( ( ( A ) B ) ) )",
+ opconvert = True,
+ expected_result = [ "A", "B" ] ),
+ UseReduceTestCase(
+ "( || ( || ( ( A ) B ) ) )",
+ opconvert = True,
+ expected_result = [['||', 'A', 'B']]),
+ UseReduceTestCase(
+ "|| ( A B ) C",
+ opconvert = True,
+ expected_result = [['||', 'A', 'B'], 'C']),
+ UseReduceTestCase(
+ "A || ( B C )",
+ opconvert = True,
+ expected_result = ['A', ['||', 'B', 'C']]),
+ UseReduceTestCase(
+ "A foo? ( || ( B || ( bar? ( || ( C D E ) ) !bar? ( F ) ) ) ) G",
+ uselist = ["foo", "bar"],
+ opconvert = True,
+ expected_result = ['A', ['||', 'B', 'C', 'D', 'E'], 'G']),
+ UseReduceTestCase(
+ "A foo? ( || ( B || ( bar? ( || ( C D E ) ) !bar? ( F ) ) ) ) G",
+ uselist = ["foo", "bar"],
+ opconvert = False,
+ expected_result = ['A', '||', ['B', 'C', 'D', 'E'], 'G']),
+
+ UseReduceTestCase(
+ "|| ( A )",
+ opconvert = True,
+ expected_result = ["A"]),
+ UseReduceTestCase(
+ "( || ( || ( || ( A ) foo? ( B ) ) ) )",
+ expected_result = ["A"]),
+ UseReduceTestCase(
+ "( || ( || ( || ( A ) foo? ( B ) ) ) )",
+ uselist = ["foo"],
+ opconvert = True,
+ expected_result = [['||', 'A', 'B']]),
+ UseReduceTestCase(
+ "( || ( || ( bar? ( A ) || ( foo? ( B ) ) ) ) )",
+ opconvert = True,
+ expected_result = []),
+ UseReduceTestCase(
+ "( || ( || ( bar? ( A ) || ( foo? ( B ) ) ) ) )",
+ uselist = ["foo", "bar"],
+ opconvert = True,
+ expected_result = [['||', 'A', 'B']]),
+ UseReduceTestCase(
+ "A || ( bar? ( C ) ) foo? ( bar? ( C ) ) B",
+ opconvert = True,
+ expected_result = ["A", "B"]),
+ UseReduceTestCase(
+ "|| ( A ) || ( B )",
+ opconvert = True,
+ expected_result = ["A", "B"]),
+ UseReduceTestCase(
+ "foo? ( A ) foo? ( B )",
+ opconvert = True,
+ expected_result = []),
+ UseReduceTestCase(
+ "foo? ( A ) foo? ( B )",
+ uselist = ["foo"],
+ opconvert = True,
+ expected_result = ["A", "B"]),
+ UseReduceTestCase(
+ "|| ( foo? ( || ( A B ) ) )",
+ uselist = ["foo"],
+ opconvert = True,
+ expected_result = [['||', 'A', 'B']]),
+
+ UseReduceTestCase(
+ "|| ( ( A B ) foo? ( || ( C D ) ) )",
+ uselist = ["foo"],
+ opconvert = True,
+ expected_result = [['||', ['A', 'B'], 'C', 'D']]),
+
+ UseReduceTestCase(
+ "|| ( ( A B ) foo? ( || ( C D ) ) )",
+ uselist = ["foo"],
+ opconvert = False,
+ expected_result = ['||', [['A', 'B'], 'C', 'D']]),
+
+ UseReduceTestCase(
+ "|| ( ( A B ) || ( C D ) )",
+ expected_result = ['||', [['A', 'B'], 'C', 'D']]),
+
+ UseReduceTestCase(
+ "|| ( ( A B ) || ( C D || ( E ( F G ) || ( H ) ) ) )",
+ expected_result = ['||', [['A', 'B'], 'C', 'D', 'E', ['F', 'G'], 'H']]),
+
+ UseReduceTestCase(
+ "|| ( ( A B ) || ( C D || ( E ( F G ) || ( H ) ) ) )",
+ opconvert = True,
+ expected_result = [['||', ['A', 'B'], 'C', 'D', 'E', ['F', 'G'], 'H']]),
+
+ UseReduceTestCase(
+ "|| ( foo? ( A B ) )",
+ uselist = ["foo"],
+ expected_result = ['A', 'B']),
+
+ UseReduceTestCase(
+ "|| ( || ( foo? ( A B ) ) )",
+ uselist = ["foo"],
+ expected_result = ['A', 'B']),
+
+ UseReduceTestCase(
+ "|| ( || ( || ( a? ( b? ( c? ( || ( || ( || ( d? ( e? ( f? ( A B ) ) ) ) ) ) ) ) ) ) ) )",
+ uselist = ["a", "b", "c", "d", "e", "f"],
+ expected_result = ['A', 'B']),
+
+ UseReduceTestCase(
+ "|| ( || ( ( || ( a? ( ( b? ( c? ( || ( || ( || ( ( d? ( e? ( f? ( A B ) ) ) ) ) ) ) ) ) ) ) ) ) ) )",
+ uselist = ["a", "b", "c", "d", "e", "f"],
+ expected_result = ['A', 'B']),
+
+ UseReduceTestCase(
+ "|| ( ( A ( || ( B ) ) ) )",
+ expected_result = ['A', 'B']),
+
+ UseReduceTestCase(
+ "|| ( ( A B ) || ( foo? ( bar? ( ( C D || ( baz? ( E ) ( F G ) || ( H ) ) ) ) ) ) )",
+ uselist = ["foo", "bar", "baz"],
+ expected_result = ['||', [['A', 'B'], ['C', 'D', '||', ['E', ['F', 'G'], 'H']]]]),
+
+ UseReduceTestCase(
+ "|| ( ( A B ) || ( foo? ( bar? ( ( C D || ( baz? ( E ) ( F G ) || ( H ) ) ) ) ) ) )",
+ uselist = ["foo", "bar", "baz"],
+ opconvert = True,
+ expected_result = [['||', ['A', 'B'], ['C', 'D', ['||', 'E', ['F', 'G'], 'H']]]]),
+
+ UseReduceTestCase(
+ "|| ( foo? ( A B ) )",
+ uselist = ["foo"],
+ opconvert=True,
+ expected_result = ['A', 'B']),
+
+ UseReduceTestCase(
+ "|| ( || ( foo? ( A B ) ) )",
+ uselist = ["foo"],
+ opconvert=True,
+ expected_result = ['A', 'B']),
+
+ UseReduceTestCase(
+ "|| ( || ( || ( a? ( b? ( c? ( || ( || ( || ( d? ( e? ( f? ( A B ) ) ) ) ) ) ) ) ) ) ) )",
+ uselist = ["a", "b", "c", "d", "e", "f"],
+ opconvert=True,
+ expected_result = ['A', 'B']),
+
+ #flat test
+ UseReduceTestCase(
+ "A",
+ flat = True,
+ expected_result = ["A"]),
+ UseReduceTestCase(
+ "( A )",
+ flat = True,
+ expected_result = ["A"]),
+ UseReduceTestCase(
+ "|| ( A B )",
+ flat = True,
+ expected_result = [ "||", "A", "B" ] ),
+ UseReduceTestCase(
+ "|| ( A || ( B C ) )",
+ flat = True,
+ expected_result = [ "||", "A", "||", "B", "C" ]),
+ UseReduceTestCase(
+ "|| ( A || ( B C D ) )",
+ flat = True,
+ expected_result = [ "||", "A", "||", "B", "C", "D" ]),
+ UseReduceTestCase(
+ "|| ( A || ( B || ( C D ) E ) )",
+ flat = True,
+ expected_result = [ "||", "A", "||", "B", "||", "C", "D", "E" ]),
+ UseReduceTestCase(
+ "( || ( ( ( A ) B ) ) )",
+ flat = True,
+ expected_result = [ "||", "A", "B"] ),
+ UseReduceTestCase(
+ "( || ( || ( ( A ) B ) ) )",
+ flat = True,
+ expected_result = [ "||", "||", "A", "B" ]),
+ UseReduceTestCase(
+ "( || ( || ( ( A ) B ) ) )",
+ flat = True,
+ expected_result = [ "||", "||", "A", "B" ]),
+ UseReduceTestCase(
+ "|| ( A )",
+ flat = True,
+ expected_result = ["||", "A"]),
+ UseReduceTestCase(
+ "( || ( || ( || ( A ) foo? ( B ) ) ) )",
+ expected_result = ["A"]),
+ UseReduceTestCase(
+ "( || ( || ( || ( A ) foo? ( B ) ) ) )",
+ uselist = ["foo"],
+ flat = True,
+ expected_result = [ "||", "||","||", "A", "B" ]),
+ UseReduceTestCase(
+ "( || ( || ( bar? ( A ) || ( foo? ( B ) ) ) ) )",
+ flat = True,
+ expected_result = ["||", "||","||"]),
+ UseReduceTestCase(
+ "( || ( || ( bar? ( A ) || ( foo? ( B ) ) ) ) )",
+ uselist = ["foo", "bar"],
+ flat = True,
+ expected_result = [ "||", "||", "A", "||", "B" ]),
+ UseReduceTestCase(
+ "A || ( bar? ( C ) ) foo? ( bar? ( C ) ) B",
+ flat = True,
+ expected_result = ["A", "||", "B"]),
+ UseReduceTestCase(
+ "|| ( A ) || ( B )",
+ flat = True,
+ expected_result = ["||", "A", "||", "B"]),
+ UseReduceTestCase(
+ "foo? ( A ) foo? ( B )",
+ flat = True,
+ expected_result = []),
+ UseReduceTestCase(
+ "foo? ( A ) foo? ( B )",
+ uselist = ["foo"],
+ flat = True,
+ expected_result = ["A", "B"]),
+
+ #use flag validation
+ UseReduceTestCase(
+ "foo? ( A )",
+ uselist = ["foo"],
+ is_valid_flag = self.always_true,
+ expected_result = ["A"]),
+ UseReduceTestCase(
+ "foo? ( A )",
+ is_valid_flag = self.always_true,
+ expected_result = []),
+
+ #token_class
+ UseReduceTestCase(
+ "foo? ( dev-libs/A )",
+ uselist = ["foo"],
+ token_class=Atom,
+ expected_result = ["dev-libs/A"]),
+ UseReduceTestCase(
+ "foo? ( dev-libs/A )",
+ token_class=Atom,
+ expected_result = []),
+ )
+
+ test_cases_xfail = (
+ UseReduceTestCase("? ( A )"),
+ UseReduceTestCase("!? ( A )"),
+ UseReduceTestCase("( A"),
+ UseReduceTestCase("A )"),
+ UseReduceTestCase("||( A B )"),
+ UseReduceTestCase("|| (A B )"),
+ UseReduceTestCase("|| ( A B)"),
+ UseReduceTestCase("|| ( A B"),
+ UseReduceTestCase("|| A B )"),
+ UseReduceTestCase("|| A B"),
+ UseReduceTestCase("|| ( A B ) )"),
+ UseReduceTestCase("|| || B C"),
+ UseReduceTestCase("|| ( A B || )"),
+ UseReduceTestCase("a? A"),
+ UseReduceTestCase("( || ( || || ( A ) foo? ( B ) ) )"),
+ UseReduceTestCase("( || ( || bar? ( A ) foo? ( B ) ) )"),
+ UseReduceTestCase("foo?"),
+ UseReduceTestCase("foo? || ( A )"),
+ UseReduceTestCase("|| ( )"),
+ UseReduceTestCase("foo? ( )"),
+
+ #SRC_URI stuff
+ UseReduceTestCase("http://foo/bar -> blah.tbz2", is_src_uri = True, eapi = EAPI_WITHOUT_SRC_URI_ARROWS),
+ UseReduceTestCase("|| ( http://foo/bar -> blah.tbz2 )", is_src_uri = True, eapi = EAPI_WITH_SRC_URI_ARROWS),
+ UseReduceTestCase("http://foo/bar -> foo? ( ftp://foo/a )", is_src_uri = True, eapi = EAPI_WITH_SRC_URI_ARROWS),
+ UseReduceTestCase("http://foo/bar blah.tbz2 ->", is_src_uri = True, eapi = EAPI_WITH_SRC_URI_ARROWS),
+ UseReduceTestCase("-> http://foo/bar blah.tbz2 )", is_src_uri = True, eapi = EAPI_WITH_SRC_URI_ARROWS),
+ UseReduceTestCase("http://foo/bar ->", is_src_uri = True, eapi = EAPI_WITH_SRC_URI_ARROWS),
+ UseReduceTestCase("http://foo/bar -> foo? ( http://foo.com/foo )", is_src_uri = True, eapi = EAPI_WITH_SRC_URI_ARROWS),
+ UseReduceTestCase("foo? ( http://foo/bar -> ) blah.tbz2", is_src_uri = True, eapi = EAPI_WITH_SRC_URI_ARROWS),
+ UseReduceTestCase("http://foo/bar -> foo/blah.tbz2", is_src_uri = True, eapi = EAPI_WITH_SRC_URI_ARROWS),
+ UseReduceTestCase("http://foo/bar -> -> bar.tbz2 foo? ( ftp://foo/a )", is_src_uri = True, eapi = EAPI_WITH_SRC_URI_ARROWS),
+
+ UseReduceTestCase("http://foo/bar -> bar.tbz2 foo? ( ftp://foo/a )", is_src_uri = False, eapi = EAPI_WITH_SRC_URI_ARROWS),
+
+ UseReduceTestCase(
+ "A",
+ opconvert = True,
+ flat = True),
+
+ #use flag validation
+ UseReduceTestCase("1.0? ( A )"),
+ UseReduceTestCase("!1.0? ( A )"),
+ UseReduceTestCase("!? ( A )"),
+ UseReduceTestCase("!?? ( A )"),
+ UseReduceTestCase(
+ "foo? ( A )",
+ is_valid_flag = self.always_false,
+ ),
+ UseReduceTestCase(
+ "foo? ( A )",
+ uselist = ["foo"],
+ is_valid_flag = self.always_false,
+ ),
+
+ #token_class
+ UseReduceTestCase(
+ "foo? ( A )",
+ uselist = ["foo"],
+ token_class=Atom),
+ UseReduceTestCase(
+ "A(B",
+ token_class=Atom),
+ )
+
+ for test_case in test_cases:
+ # If it fails then show the input, since lots of our
+ # test cases have the same output but different input,
+ # making it difficult deduce which test has failed.
+ self.assertEqual(test_case.run(), test_case.expected_result,
+ "input: '%s' result: %s != %s" % (test_case.deparray,
+ test_case.run(), test_case.expected_result))
+
+ for test_case in test_cases_xfail:
+ self.assertRaisesMsg(test_case.deparray, (InvalidDependString, ValueError), test_case.run)
diff --git a/portage_with_autodep/pym/portage/tests/ebuild/__init__.py b/portage_with_autodep/pym/portage/tests/ebuild/__init__.py
new file mode 100644
index 0000000..e2d487e
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/ebuild/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 1998-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/tests/ebuild/__test__ b/portage_with_autodep/pym/portage/tests/ebuild/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/ebuild/__test__
diff --git a/portage_with_autodep/pym/portage/tests/ebuild/test_array_fromfile_eof.py b/portage_with_autodep/pym/portage/tests/ebuild/test_array_fromfile_eof.py
new file mode 100644
index 0000000..d8277f2
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/ebuild/test_array_fromfile_eof.py
@@ -0,0 +1,43 @@
+# Copyright 2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import array
+import tempfile
+
+from portage import _unicode_decode
+from portage import _unicode_encode
+from portage.tests import TestCase
+
+class ArrayFromfileEofTestCase(TestCase):
+
+ def testArrayFromfileEof(self):
+ # This tests if the following python issue is fixed
+ # in the currently running version of python:
+ # http://bugs.python.org/issue5334
+
+ input_data = "an arbitrary string"
+ input_bytes = _unicode_encode(input_data,
+ encoding='utf_8', errors='strict')
+ f = tempfile.TemporaryFile()
+ f.write(input_bytes)
+
+ f.seek(0)
+ data = []
+ eof = False
+ while not eof:
+ a = array.array('B')
+ try:
+ a.fromfile(f, len(input_bytes) + 1)
+ except (EOFError, IOError):
+ # python-3.0 lost data here
+ eof = True
+
+ if not a:
+ eof = True
+ else:
+ data.append(_unicode_decode(a.tostring(),
+ encoding='utf_8', errors='strict'))
+
+ f.close()
+
+ self.assertEqual(input_data, ''.join(data))
diff --git a/portage_with_autodep/pym/portage/tests/ebuild/test_config.py b/portage_with_autodep/pym/portage/tests/ebuild/test_config.py
new file mode 100644
index 0000000..7bec8c6
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/ebuild/test_config.py
@@ -0,0 +1,198 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import portage
+from portage import os
+from portage.package.ebuild.config import config
+from portage.package.ebuild._config.LicenseManager import LicenseManager
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class ConfigTestCase(TestCase):
+
+ def testClone(self):
+ """
+ Test the clone via constructor.
+ """
+
+ ebuilds = {
+ "dev-libs/A-1": { },
+ }
+
+ playground = ResolverPlayground(ebuilds=ebuilds)
+ try:
+ settings = config(clone=playground.settings)
+ result = playground.run(["=dev-libs/A-1"])
+ pkg, existing_node = result.depgraph._select_package(
+ playground.root, "=dev-libs/A-1")
+ settings.setcpv(pkg)
+
+ # clone after setcpv tests deepcopy of LazyItemsDict
+ settings2 = config(clone=settings)
+ finally:
+ playground.cleanup()
+
+ def testFeaturesMutation(self):
+ """
+ Test whether mutation of config.features updates the FEATURES
+ variable and persists through config.regenerate() calls. Also
+ verify that features_set._prune_overrides() works correctly.
+ """
+ playground = ResolverPlayground()
+ try:
+ settings = config(clone=playground.settings)
+
+ settings.features.add('noclean')
+ self.assertEqual('noclean' in settings['FEATURES'].split(), True)
+ settings.regenerate()
+ self.assertEqual('noclean' in settings['FEATURES'].split(),True)
+
+ settings.features.discard('noclean')
+ self.assertEqual('noclean' in settings['FEATURES'].split(), False)
+ settings.regenerate()
+ self.assertEqual('noclean' in settings['FEATURES'].split(), False)
+
+ settings.features.add('noclean')
+ self.assertEqual('noclean' in settings['FEATURES'].split(), True)
+ settings.regenerate()
+ self.assertEqual('noclean' in settings['FEATURES'].split(),True)
+
+ # before: ['noclean', '-noclean', 'noclean']
+ settings.features._prune_overrides()
+ # after: ['noclean']
+ self.assertEqual(settings._features_overrides.count('noclean'), 1)
+ self.assertEqual(settings._features_overrides.count('-noclean'), 0)
+
+ settings.features.remove('noclean')
+
+ # before: ['noclean', '-noclean']
+ settings.features._prune_overrides()
+ # after: ['-noclean']
+ self.assertEqual(settings._features_overrides.count('noclean'), 0)
+ self.assertEqual(settings._features_overrides.count('-noclean'), 1)
+ finally:
+ playground.cleanup()
+
+ def testLicenseManager(self):
+
+ user_config = {
+ "package.license":
+ (
+ "dev-libs/* TEST",
+ "dev-libs/A -TEST2",
+ "=dev-libs/A-2 TEST3 @TEST",
+ "*/* @EULA TEST2",
+ "=dev-libs/C-1 *",
+ "=dev-libs/C-2 -*",
+ ),
+ }
+
+ playground = ResolverPlayground(user_config=user_config)
+ try:
+ portage.util.noiselimit = -2
+
+ license_group_locations = (os.path.join(playground.portdir, "profiles"),)
+ pkg_license = os.path.join(playground.eroot, "etc", "portage")
+
+ lic_man = LicenseManager(license_group_locations, pkg_license)
+
+ self.assertEqual(lic_man._accept_license_str, None)
+ self.assertEqual(lic_man._accept_license, None)
+ self.assertEqual(lic_man._license_groups, {"EULA": frozenset(["TEST"])})
+ self.assertEqual(lic_man._undef_lic_groups, set(["TEST"]))
+
+ self.assertEqual(lic_man.extract_global_changes(), "TEST TEST2")
+ self.assertEqual(lic_man.extract_global_changes(), "")
+
+ lic_man.set_accept_license_str("TEST TEST2")
+ self.assertEqual(lic_man._getPkgAcceptLicense("dev-libs/B-1", "0", None), ["TEST", "TEST2", "TEST"])
+ self.assertEqual(lic_man._getPkgAcceptLicense("dev-libs/A-1", "0", None), ["TEST", "TEST2", "TEST", "-TEST2"])
+ self.assertEqual(lic_man._getPkgAcceptLicense("dev-libs/A-2", "0", None), ["TEST", "TEST2", "TEST", "-TEST2", "TEST3", "@TEST"])
+
+ self.assertEqual(lic_man.get_prunned_accept_license("dev-libs/B-1", [], "TEST", "0", None), "TEST")
+ self.assertEqual(lic_man.get_prunned_accept_license("dev-libs/A-1", [], "-TEST2", "0", None), "")
+ self.assertEqual(lic_man.get_prunned_accept_license("dev-libs/A-2", [], "|| ( TEST TEST2 )", "0", None), "TEST")
+ self.assertEqual(lic_man.get_prunned_accept_license("dev-libs/C-1", [], "TEST5", "0", None), "TEST5")
+ self.assertEqual(lic_man.get_prunned_accept_license("dev-libs/C-2", [], "TEST2", "0", None), "")
+
+ self.assertEqual(lic_man.getMissingLicenses("dev-libs/B-1", [], "TEST", "0", None), [])
+ self.assertEqual(lic_man.getMissingLicenses("dev-libs/A-1", [], "-TEST2", "0", None), ["-TEST2"])
+ self.assertEqual(lic_man.getMissingLicenses("dev-libs/A-2", [], "|| ( TEST TEST2 )", "0", None), [])
+ self.assertEqual(lic_man.getMissingLicenses("dev-libs/A-3", [], "|| ( TEST2 || ( TEST3 TEST4 ) )", "0", None), ["TEST2", "TEST3", "TEST4"])
+ self.assertEqual(lic_man.getMissingLicenses("dev-libs/C-1", [], "TEST5", "0", None), [])
+ self.assertEqual(lic_man.getMissingLicenses("dev-libs/C-2", [], "TEST2", "0", None), ["TEST2"])
+ self.assertEqual(lic_man.getMissingLicenses("dev-libs/D-1", [], "", "0", None), [])
+ finally:
+ portage.util.noiselimit = 0
+ playground.cleanup()
+
+ def testPackageMaskOrder(self):
+
+ ebuilds = {
+ "dev-libs/A-1": { },
+ "dev-libs/B-1": { },
+ "dev-libs/C-1": { },
+ "dev-libs/D-1": { },
+ "dev-libs/E-1": { },
+ }
+
+ repo_configs = {
+ "test_repo": {
+ "package.mask":
+ (
+ "dev-libs/A",
+ "dev-libs/C",
+ ),
+ }
+ }
+
+ profile = {
+ "package.mask":
+ (
+ "-dev-libs/A",
+ "dev-libs/B",
+ "-dev-libs/B",
+ "dev-libs/D",
+ ),
+ }
+
+ user_config = {
+ "package.mask":
+ (
+ "-dev-libs/C",
+ "-dev-libs/D",
+ "dev-libs/E",
+ ),
+ }
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A"],
+ options = { "--autounmask": 'n' },
+ success = False),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/B"],
+ success = True,
+ mergelist = ["dev-libs/B-1"]),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/C"],
+ success = True,
+ mergelist = ["dev-libs/C-1"]),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/D"],
+ success = True,
+ mergelist = ["dev-libs/D-1"]),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/E"],
+ options = { "--autounmask": 'n' },
+ success = False),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds, repo_configs=repo_configs, \
+ profile=profile, user_config=user_config)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/ebuild/test_doebuild_spawn.py b/portage_with_autodep/pym/portage/tests/ebuild/test_doebuild_spawn.py
new file mode 100644
index 0000000..ed08b2a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/ebuild/test_doebuild_spawn.py
@@ -0,0 +1,82 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from portage import _python_interpreter
+from portage import _shell_quote
+from portage.const import EBUILD_SH_BINARY
+from portage.package.ebuild.config import config
+from portage.package.ebuild.doebuild import spawn as doebuild_spawn
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground
+from _emerge.EbuildPhase import EbuildPhase
+from _emerge.MiscFunctionsProcess import MiscFunctionsProcess
+from _emerge.Package import Package
+from _emerge.PollScheduler import PollScheduler
+
+class DoebuildSpawnTestCase(TestCase):
+ """
+ Invoke portage.package.ebuild.doebuild.spawn() with a
+ minimal environment. This gives coverage to some of
+ the ebuild execution internals, like ebuild.sh,
+ AbstractEbuildProcess, and EbuildIpcDaemon.
+ """
+
+ def testDoebuildSpawn(self):
+ playground = ResolverPlayground()
+ try:
+ settings = config(clone=playground.settings)
+ cpv = 'sys-apps/portage-2.1'
+ metadata = {
+ 'EAPI' : '2',
+ 'INHERITED' : 'python eutils',
+ 'IUSE' : 'build doc epydoc python3 selinux',
+ 'LICENSE' : 'GPL-2',
+ 'PROVIDE' : 'virtual/portage',
+ 'RDEPEND' : '>=app-shells/bash-3.2_p17 >=dev-lang/python-2.6',
+ 'SLOT' : '0',
+ }
+ root_config = playground.trees[playground.root]['root_config']
+ pkg = Package(built=False, cpv=cpv, installed=False,
+ metadata=metadata, root_config=root_config,
+ type_name='ebuild')
+ settings.setcpv(pkg)
+ settings['PORTAGE_PYTHON'] = _python_interpreter
+ settings['PORTAGE_BUILDDIR'] = os.path.join(
+ settings['PORTAGE_TMPDIR'], cpv)
+ settings['T'] = os.path.join(
+ settings['PORTAGE_BUILDDIR'], 'temp')
+ for x in ('PORTAGE_BUILDDIR', 'T'):
+ os.makedirs(settings[x])
+ # Create a fake environment, to pretend as if the ebuild
+ # has been sourced already.
+ open(os.path.join(settings['T'], 'environment'), 'wb')
+
+ scheduler = PollScheduler().sched_iface
+ for phase in ('_internal_test',):
+
+ # Test EbuildSpawnProcess by calling doebuild.spawn() with
+ # returnpid=False. This case is no longer used by portage
+ # internals since EbuildPhase is used instead and that passes
+ # returnpid=True to doebuild.spawn().
+ rval = doebuild_spawn("%s %s" % (_shell_quote(
+ os.path.join(settings["PORTAGE_BIN_PATH"],
+ os.path.basename(EBUILD_SH_BINARY))), phase),
+ settings, free=1)
+ self.assertEqual(rval, os.EX_OK)
+
+ ebuild_phase = EbuildPhase(background=False,
+ phase=phase, scheduler=scheduler,
+ settings=settings)
+ ebuild_phase.start()
+ ebuild_phase.wait()
+ self.assertEqual(ebuild_phase.returncode, os.EX_OK)
+
+ ebuild_phase = MiscFunctionsProcess(background=False,
+ commands=['success_hooks'],
+ scheduler=scheduler, settings=settings)
+ ebuild_phase.start()
+ ebuild_phase.wait()
+ self.assertEqual(ebuild_phase.returncode, os.EX_OK)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/ebuild/test_ipc_daemon.py b/portage_with_autodep/pym/portage/tests/ebuild/test_ipc_daemon.py
new file mode 100644
index 0000000..b5b4796
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/ebuild/test_ipc_daemon.py
@@ -0,0 +1,124 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import shutil
+import tempfile
+import time
+from portage import os
+from portage import _python_interpreter
+from portage.tests import TestCase
+from portage.const import PORTAGE_BIN_PATH
+from portage.const import PORTAGE_PYM_PATH
+from portage.const import BASH_BINARY
+from portage.package.ebuild._ipc.ExitCommand import ExitCommand
+from portage.util import ensure_dirs
+from _emerge.SpawnProcess import SpawnProcess
+from _emerge.EbuildBuildDir import EbuildBuildDir
+from _emerge.EbuildIpcDaemon import EbuildIpcDaemon
+from _emerge.TaskScheduler import TaskScheduler
+
+class IpcDaemonTestCase(TestCase):
+
+ _SCHEDULE_TIMEOUT = 40000 # 40 seconds
+
+ def testIpcDaemon(self):
+ tmpdir = tempfile.mkdtemp()
+ build_dir = None
+ try:
+ env = {}
+
+ # Pass along PORTAGE_USERNAME and PORTAGE_GRPNAME since they
+ # need to be inherited by ebuild subprocesses.
+ if 'PORTAGE_USERNAME' in os.environ:
+ env['PORTAGE_USERNAME'] = os.environ['PORTAGE_USERNAME']
+ if 'PORTAGE_GRPNAME' in os.environ:
+ env['PORTAGE_GRPNAME'] = os.environ['PORTAGE_GRPNAME']
+
+ env['PORTAGE_PYTHON'] = _python_interpreter
+ env['PORTAGE_BIN_PATH'] = PORTAGE_BIN_PATH
+ env['PORTAGE_PYM_PATH'] = PORTAGE_PYM_PATH
+ env['PORTAGE_BUILDDIR'] = os.path.join(tmpdir, 'cat', 'pkg-1')
+
+ task_scheduler = TaskScheduler(max_jobs=2)
+ build_dir = EbuildBuildDir(
+ scheduler=task_scheduler.sched_iface,
+ settings=env)
+ build_dir.lock()
+ ensure_dirs(env['PORTAGE_BUILDDIR'])
+
+ input_fifo = os.path.join(env['PORTAGE_BUILDDIR'], '.ipc_in')
+ output_fifo = os.path.join(env['PORTAGE_BUILDDIR'], '.ipc_out')
+ os.mkfifo(input_fifo)
+ os.mkfifo(output_fifo)
+
+ for exitcode in (0, 1, 2):
+ exit_command = ExitCommand()
+ commands = {'exit' : exit_command}
+ daemon = EbuildIpcDaemon(commands=commands,
+ input_fifo=input_fifo,
+ output_fifo=output_fifo,
+ scheduler=task_scheduler.sched_iface)
+ proc = SpawnProcess(
+ args=[BASH_BINARY, "-c",
+ '"$PORTAGE_BIN_PATH"/ebuild-ipc exit %d' % exitcode],
+ env=env, scheduler=task_scheduler.sched_iface)
+
+ self.received_command = False
+ def exit_command_callback():
+ self.received_command = True
+ proc.cancel()
+ daemon.cancel()
+
+ exit_command.reply_hook = exit_command_callback
+ task_scheduler.add(daemon)
+ task_scheduler.add(proc)
+ start_time = time.time()
+ task_scheduler.run(timeout=self._SCHEDULE_TIMEOUT)
+ task_scheduler.clear()
+
+ self.assertEqual(self.received_command, True,
+ "command not received after %d seconds" % \
+ (time.time() - start_time,))
+ self.assertEqual(proc.isAlive(), False)
+ self.assertEqual(daemon.isAlive(), False)
+ self.assertEqual(exit_command.exitcode, exitcode)
+
+ # Intentionally short timeout test for QueueScheduler.run()
+ sleep_time_s = 10 # 10.000 seconds
+ short_timeout_ms = 10 # 0.010 seconds
+
+ for i in range(3):
+ exit_command = ExitCommand()
+ commands = {'exit' : exit_command}
+ daemon = EbuildIpcDaemon(commands=commands,
+ input_fifo=input_fifo,
+ output_fifo=output_fifo,
+ scheduler=task_scheduler.sched_iface)
+ proc = SpawnProcess(
+ args=[BASH_BINARY, "-c", 'exec sleep %d' % sleep_time_s],
+ env=env, scheduler=task_scheduler.sched_iface)
+
+ self.received_command = False
+ def exit_command_callback():
+ self.received_command = True
+ proc.cancel()
+ daemon.cancel()
+
+ exit_command.reply_hook = exit_command_callback
+ task_scheduler.add(daemon)
+ task_scheduler.add(proc)
+ start_time = time.time()
+ task_scheduler.run(timeout=short_timeout_ms)
+ task_scheduler.clear()
+
+ self.assertEqual(self.received_command, False,
+ "command received after %d seconds" % \
+ (time.time() - start_time,))
+ self.assertEqual(proc.isAlive(), False)
+ self.assertEqual(daemon.isAlive(), False)
+ self.assertEqual(proc.returncode == os.EX_OK, False)
+
+ finally:
+ if build_dir is not None:
+ build_dir.unlock()
+ shutil.rmtree(tmpdir)
diff --git a/portage_with_autodep/pym/portage/tests/ebuild/test_pty_eof.py b/portage_with_autodep/pym/portage/tests/ebuild/test_pty_eof.py
new file mode 100644
index 0000000..4b6ff21
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/ebuild/test_pty_eof.py
@@ -0,0 +1,32 @@
+# Copyright 2009-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.util._pty import _can_test_pty_eof, _test_pty_eof
+
+class PtyEofFdopenBufferedTestCase(TestCase):
+
+ def testPtyEofFdopenBuffered(self):
+ # This tests if the following python issue is fixed yet:
+ # http://bugs.python.org/issue5380
+ # Since it might not be fixed, mark as todo.
+ self.todo = True
+ # The result is only valid if openpty does not raise EnvironmentError.
+ if _can_test_pty_eof():
+ try:
+ self.assertEqual(_test_pty_eof(fdopen_buffered=True), True)
+ except EnvironmentError:
+ pass
+
+class PtyEofFdopenUnBufferedTestCase(TestCase):
+ def testPtyEofFdopenUnBuffered(self):
+ # New development: It appears that array.fromfile() is usable
+ # with python3 as long as fdopen is called with a bufsize
+ # argument of 0.
+
+ # The result is only valid if openpty does not raise EnvironmentError.
+ if _can_test_pty_eof():
+ try:
+ self.assertEqual(_test_pty_eof(), True)
+ except EnvironmentError:
+ pass
diff --git a/portage_with_autodep/pym/portage/tests/ebuild/test_spawn.py b/portage_with_autodep/pym/portage/tests/ebuild/test_spawn.py
new file mode 100644
index 0000000..fea4738
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/ebuild/test_spawn.py
@@ -0,0 +1,52 @@
+# Copyright 1998-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import errno
+import io
+import sys
+import tempfile
+from portage import os
+from portage import _encodings
+from portage import _unicode_encode
+from portage.const import BASH_BINARY
+from portage.tests import TestCase
+from _emerge.SpawnProcess import SpawnProcess
+from _emerge.PollScheduler import PollScheduler
+
+class SpawnTestCase(TestCase):
+
+ def testLogfile(self):
+ logfile = None
+ try:
+ fd, logfile = tempfile.mkstemp()
+ os.close(fd)
+ null_fd = os.open('/dev/null', os.O_RDWR)
+ test_string = 2 * "blah blah blah\n"
+ scheduler = PollScheduler().sched_iface
+ proc = SpawnProcess(
+ args=[BASH_BINARY, "-c",
+ "echo -n '%s'" % test_string],
+ env={}, fd_pipes={0:sys.stdin.fileno(), 1:null_fd, 2:null_fd},
+ scheduler=scheduler,
+ logfile=logfile)
+ proc.start()
+ os.close(null_fd)
+ self.assertEqual(proc.wait(), os.EX_OK)
+ f = io.open(_unicode_encode(logfile,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'], errors='strict')
+ log_content = f.read()
+ f.close()
+ # When logging passes through a pty, this comparison will fail
+ # unless the oflag terminal attributes have the termios.OPOST
+ # bit disabled. Otherwise, tranformations such as \n -> \r\n
+ # may occur.
+ self.assertEqual(test_string, log_content)
+ finally:
+ if logfile:
+ try:
+ os.unlink(logfile)
+ except EnvironmentError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
diff --git a/portage_with_autodep/pym/portage/tests/env/__init__.py b/portage_with_autodep/pym/portage/tests/env/__init__.py
new file mode 100644
index 0000000..cbeabe5
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/env/__init__.py
@@ -0,0 +1,4 @@
+# tests/portage/env/__init__.py -- Portage Unit Test functionality
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
diff --git a/portage_with_autodep/pym/portage/tests/env/__test__ b/portage_with_autodep/pym/portage/tests/env/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/env/__test__
diff --git a/portage_with_autodep/pym/portage/tests/env/config/__init__.py b/portage_with_autodep/pym/portage/tests/env/config/__init__.py
new file mode 100644
index 0000000..ef5cc43
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/env/config/__init__.py
@@ -0,0 +1,4 @@
+# tests/portage/env/config/__init__.py -- Portage Unit Test functionality
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
diff --git a/portage_with_autodep/pym/portage/tests/env/config/__test__ b/portage_with_autodep/pym/portage/tests/env/config/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/env/config/__test__
diff --git a/portage_with_autodep/pym/portage/tests/env/config/test_PackageKeywordsFile.py b/portage_with_autodep/pym/portage/tests/env/config/test_PackageKeywordsFile.py
new file mode 100644
index 0000000..f1e9e98
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/env/config/test_PackageKeywordsFile.py
@@ -0,0 +1,40 @@
+# test_PackageKeywordsFile.py -- Portage Unit Testing Functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from portage.tests import TestCase
+from portage.env.config import PackageKeywordsFile
+from tempfile import mkstemp
+
+class PackageKeywordsFileTestCase(TestCase):
+
+ cpv = ['sys-apps/portage']
+ keywords = ['~x86', 'amd64', '-mips']
+
+ def testPackageKeywordsFile(self):
+ """
+ A simple test to ensure the load works properly
+ """
+
+ self.BuildFile()
+ try:
+ f = PackageKeywordsFile(self.fname)
+ f.load()
+ i = 0
+ for cpv, keyword in f.items():
+ self.assertEqual( cpv, self.cpv[i] )
+ [k for k in keyword if self.assertTrue(k in self.keywords)]
+ i = i + 1
+ finally:
+ self.NukeFile()
+
+ def BuildFile(self):
+ fd, self.fname = mkstemp()
+ f = os.fdopen(fd, 'w')
+ for c in self.cpv:
+ f.write("%s %s\n" % (c,' '.join(self.keywords)))
+ f.close()
+
+ def NukeFile(self):
+ os.unlink(self.fname)
diff --git a/portage_with_autodep/pym/portage/tests/env/config/test_PackageMaskFile.py b/portage_with_autodep/pym/portage/tests/env/config/test_PackageMaskFile.py
new file mode 100644
index 0000000..0c5b30f
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/env/config/test_PackageMaskFile.py
@@ -0,0 +1,29 @@
+# test_PackageMaskFile.py -- Portage Unit Testing Functionality
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from portage.env.config import PackageMaskFile
+from portage.tests import TestCase, test_cps
+from tempfile import mkstemp
+
+class PackageMaskFileTestCase(TestCase):
+
+ def testPackageMaskFile(self):
+ self.BuildFile()
+ try:
+ f = PackageMaskFile(self.fname)
+ f.load()
+ for atom in f:
+ self.assertTrue(atom in test_cps)
+ finally:
+ self.NukeFile()
+
+ def BuildFile(self):
+ fd, self.fname = mkstemp()
+ f = os.fdopen(fd, 'w')
+ f.write("\n".join(test_cps))
+ f.close()
+
+ def NukeFile(self):
+ os.unlink(self.fname)
diff --git a/portage_with_autodep/pym/portage/tests/env/config/test_PackageUseFile.py b/portage_with_autodep/pym/portage/tests/env/config/test_PackageUseFile.py
new file mode 100644
index 0000000..7a38067
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/env/config/test_PackageUseFile.py
@@ -0,0 +1,37 @@
+# test_PackageUseFile.py -- Portage Unit Testing Functionality
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from portage.tests import TestCase
+from portage.env.config import PackageUseFile
+from tempfile import mkstemp
+
+
+class PackageUseFileTestCase(TestCase):
+
+ cpv = 'sys-apps/portage'
+ useflags = ['cdrom', 'far', 'boo', 'flag', 'blat']
+
+ def testPackageUseFile(self):
+ """
+ A simple test to ensure the load works properly
+ """
+ self.BuildFile()
+ try:
+ f = PackageUseFile(self.fname)
+ f.load()
+ for cpv, use in f.items():
+ self.assertEqual( cpv, self.cpv )
+ [flag for flag in use if self.assertTrue(flag in self.useflags)]
+ finally:
+ self.NukeFile()
+
+ def BuildFile(self):
+ fd, self.fname = mkstemp()
+ f = os.fdopen(fd, 'w')
+ f.write("%s %s" % (self.cpv, ' '.join(self.useflags)))
+ f.close()
+
+ def NukeFile(self):
+ os.unlink(self.fname)
diff --git a/portage_with_autodep/pym/portage/tests/env/config/test_PortageModulesFile.py b/portage_with_autodep/pym/portage/tests/env/config/test_PortageModulesFile.py
new file mode 100644
index 0000000..2cd1a8a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/env/config/test_PortageModulesFile.py
@@ -0,0 +1,39 @@
+# Copyright 2006-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from portage.tests import TestCase
+from portage.env.config import PortageModulesFile
+from tempfile import mkstemp
+
+class PortageModulesFileTestCase(TestCase):
+
+ keys = ['foo.bar','baz','bob','extra_key']
+ invalid_keys = ['',""]
+ modules = ['spanky','zmedico','antarus','ricer','5','6']
+
+ def setUp(self):
+ self.items = {}
+ for k, v in zip(self.keys + self.invalid_keys,
+ self.modules):
+ self.items[k] = v
+
+ def testPortageModulesFile(self):
+ self.BuildFile()
+ f = PortageModulesFile(self.fname)
+ f.load()
+ for k in self.keys:
+ self.assertEqual(f[k], self.items[k])
+ for ik in self.invalid_keys:
+ self.assertEqual(False, ik in f)
+ self.NukeFile()
+
+ def BuildFile(self):
+ fd, self.fname = mkstemp()
+ f = os.fdopen(fd, 'w')
+ for k, v in self.items.items():
+ f.write('%s=%s\n' % (k,v))
+ f.close()
+
+ def NukeFile(self):
+ os.unlink(self.fname)
diff --git a/portage_with_autodep/pym/portage/tests/lafilefixer/__init__.py b/portage_with_autodep/pym/portage/tests/lafilefixer/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/lafilefixer/__init__.py
diff --git a/portage_with_autodep/pym/portage/tests/lafilefixer/__test__ b/portage_with_autodep/pym/portage/tests/lafilefixer/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/lafilefixer/__test__
diff --git a/portage_with_autodep/pym/portage/tests/lafilefixer/test_lafilefixer.py b/portage_with_autodep/pym/portage/tests/lafilefixer/test_lafilefixer.py
new file mode 100644
index 0000000..0bcffaa
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/lafilefixer/test_lafilefixer.py
@@ -0,0 +1,145 @@
+# test_lafilefixer.py -- Portage Unit Testing Functionality
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.exception import InvalidData
+
+class test_lafilefixer(TestCase):
+
+ def get_test_cases_clean(self):
+ yield b"dlname='libfoo.so.1'\n" + \
+ b"library_names='libfoo.so.1.0.2 libfoo.so.1 libfoo.so'\n" + \
+ b"old_library='libpdf.a'\n" + \
+ b"dependency_libs=' -lm'\n" + \
+ b"current=6\n" + \
+ b"age=0\n" + \
+ b"revision=2\n" + \
+ b"installed=yes\n" + \
+ b"dlopen=''\n" + \
+ b"dlpreopen=''\n" + \
+ b"libdir='/usr/lib64'\n"
+ yield b"dlname='libfoo.so.1'\n" + \
+ b"library_names='libfoo.so.1.0.2 libfoo.so.1 libfoo.so'\n" + \
+ b"old_library='libpdf.a'\n" + \
+ b"dependency_libs=' -lm'\n" + \
+ b"current=6\n" + \
+ b"age=0\n" + \
+ b"revision=2\n" + \
+ b"installed=yes\n" + \
+ b"dlopen=''\n" + \
+ b"dlpreopen=''\n" + \
+ b"libdir='/usr/lib64'\n"
+ yield b"dependency_libs=' liba.la /usr/lib64/bar.la -lc'\n"
+
+ def get_test_cases_update(self):
+ #.la -> -l*
+ yield b"dlname='libfoo.so.1'\n" + \
+ b"library_names='libfoo.so.1.0.2 libfoo.so.1 libfoo.so'\n" + \
+ b"old_library='libpdf.a'\n" + \
+ b"dependency_libs=' /usr/lib64/liba.la /usr/lib64/libb.la -lc'\n", \
+ b"dlname='libfoo.so.1'\n" + \
+ b"library_names='libfoo.so.1.0.2 libfoo.so.1 libfoo.so'\n" + \
+ b"old_library='libpdf.a'\n" + \
+ b"dependency_libs=' -L/usr/lib64 -la -lb -lc'\n"
+ #move stuff into inherited_linker_flags
+ yield b"dlname='libfoo.so.1'\n" + \
+ b"library_names='libfoo.so.1.0.2 libfoo.so.1 libfoo.so'\n" + \
+ b"old_library='libpdf.a'\n" + \
+ b"dependency_libs=' /usr/lib64/liba.la -pthread /usr/lib64/libb.la -lc'\n" + \
+ b"inherited_linker_flags=''\n", \
+ b"dlname='libfoo.so.1'\n" + \
+ b"library_names='libfoo.so.1.0.2 libfoo.so.1 libfoo.so'\n" + \
+ b"old_library='libpdf.a'\n" + \
+ b"dependency_libs=' -L/usr/lib64 -la -lb -lc'\n" + \
+ b"inherited_linker_flags=' -pthread'\n"
+ #reorder
+ yield b"dlname='libfoo.so.1'\n" + \
+ b"library_names='libfoo.so.1.0.2 libfoo.so.1 libfoo.so'\n" + \
+ b"old_library='libpdf.a'\n" + \
+ b"dependency_libs=' /usr/lib64/liba.la -R/usr/lib64 /usr/lib64/libb.la -lc'\n", \
+ b"dlname='libfoo.so.1'\n" + \
+ b"library_names='libfoo.so.1.0.2 libfoo.so.1 libfoo.so'\n" + \
+ b"old_library='libpdf.a'\n" + \
+ b"dependency_libs=' -R/usr/lib64 -L/usr/lib64 -la -lb -lc'\n"
+ #remove duplicates from dependency_libs (the original version didn't do it for inherited_linker_flags)
+ yield b"dlname='libfoo.so.1'\n" + \
+ b"library_names='libfoo.so.1.0.2 libfoo.so.1 libfoo.so'\n" + \
+ b"old_library='libpdf.a'\n" + \
+ b"dependency_libs=' /usr/lib64/liba.la /usr/lib64/libc.la -pthread -mt" + \
+ b" -L/usr/lib -R/usr/lib64 -lc /usr/lib64/libb.la -lc'\n" +\
+ b"inherited_linker_flags=' -pthread -pthread'\n", \
+ b"dlname='libfoo.so.1'\n" + \
+ b"library_names='libfoo.so.1.0.2 libfoo.so.1 libfoo.so'\n" + \
+ b"old_library='libpdf.a'\n" + \
+ b"dependency_libs=' -R/usr/lib64 -L/usr/lib64 -L/usr/lib -la -lc -lb'\n" +\
+ b"inherited_linker_flags=' -pthread -pthread -mt'\n"
+ #-L rewriting
+ yield b"dependency_libs=' -L/usr/X11R6/lib'\n", \
+ b"dependency_libs=' -L/usr/lib'\n"
+ yield b"dependency_libs=' -L/usr/local/lib'\n", \
+ b"dependency_libs=' -L/usr/lib'\n"
+ yield b"dependency_libs=' -L/usr/lib64/pkgconfig/../..'\n", \
+ b"dependency_libs=' -L/usr'\n"
+ yield b"dependency_libs=' -L/usr/lib/pkgconfig/..'\n", \
+ b"dependency_libs=' -L/usr/lib'\n"
+ yield b"dependency_libs=' -L/usr/lib/pkgconfig/../.. -L/usr/lib/pkgconfig/..'\n", \
+ b"dependency_libs=' -L/usr -L/usr/lib'\n"
+ #we once got a backtrace on this one
+ yield b"dependency_libs=' /usr/lib64/libMagickCore.la -L/usr/lib64 -llcms2 /usr/lib64/libtiff.la " + \
+ b"-ljbig -lc /usr/lib64/libfreetype.la /usr/lib64/libjpeg.la /usr/lib64/libXext.la " + \
+ b"/usr/lib64/libXt.la /usr/lib64/libSM.la -lICE -luuid /usr/lib64/libICE.la /usr/lib64/libX11.la " + \
+ b"/usr/lib64/libxcb.la /usr/lib64/libXau.la /usr/lib64/libXdmcp.la -lbz2 -lz -lm " + \
+ b"/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.4/libgomp.la -lrt -lpthread /usr/lib64/libltdl.la -ldl " + \
+ b"/usr/lib64/libfpx.la -lstdc++'", \
+ b"dependency_libs=' -L/usr/lib64 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.4 -lMagickCore -llcms2 " + \
+ b"-ltiff -ljbig -lc -lfreetype -ljpeg -lXext -lXt -lSM -lICE -luuid -lX11 -lxcb -lXau -lXdmcp " + \
+ b"-lbz2 -lz -lm -lgomp -lrt -lpthread -lltdl -ldl -lfpx -lstdc++'"
+
+
+ def get_test_cases_broken(self):
+ yield b""
+ #no dependency_libs
+ yield b"dlname='libfoo.so.1'\n" + \
+ b"current=6\n" + \
+ b"age=0\n" + \
+ b"revision=2\n"
+ #borken dependency_libs
+ yield b"dlname='libfoo.so.1'\n" + \
+ b"library_names='libfoo.so.1.0.2 libfoo.so.1 libfoo.so'\n" + \
+ b"old_library='libpdf.a'\n" + \
+ b"dependency_libs=' /usr/lib64/liba.la /usr/lib64/libb.la -lc' \n"
+ #borken dependency_libs
+ yield b"dlname='libfoo.so.1'\n" + \
+ b"library_names='libfoo.so.1.0.2 libfoo.so.1 libfoo.so'\n" + \
+ b"old_library='libpdf.a'\n" + \
+ b"dependency_libs=' /usr/lib64/liba.la /usr/lib64/libb.la -lc\n"
+ #crap in dependency_libs
+ yield b"dlname='libfoo.so.1'\n" + \
+ b"library_names='libfoo.so.1.0.2 libfoo.so.1 libfoo.so'\n" + \
+ b"old_library='libpdf.a'\n" + \
+ b"dependency_libs=' /usr/lib64/liba.la /usr/lib64/libb.la -lc /-lstdc++'\n"
+ #dependency_libs twice
+ yield b"dlname='libfoo.so.1'\n" + \
+ b"library_names='libfoo.so.1.0.2 libfoo.so.1 libfoo.so'\n" + \
+ b"old_library='libpdf.a'\n" + \
+ b"dependency_libs=' /usr/lib64/liba.la /usr/lib64/libb.la -lc /-lstdc++'\n" +\
+ b"dependency_libs=' /usr/lib64/liba.la /usr/lib64/libb.la -lc /-lstdc++'\n"
+ #inherited_linker_flags twice
+ yield b"dlname='libfoo.so.1'\n" + \
+ b"library_names='libfoo.so.1.0.2 libfoo.so.1 libfoo.so'\n" + \
+ b"old_library='libpdf.a'\n" + \
+ b"inherited_linker_flags=''\n" +\
+ b"inherited_linker_flags=''\n"
+
+ def testlafilefixer(self):
+ from portage.util.lafilefixer import _parse_lafile_contents, rewrite_lafile
+
+ for clean_contents in self.get_test_cases_clean():
+ self.assertEqual(rewrite_lafile(clean_contents), (False, None))
+
+ for original_contents, fixed_contents in self.get_test_cases_update():
+ self.assertEqual(rewrite_lafile(original_contents), (True, fixed_contents))
+
+ for broken_contents in self.get_test_cases_broken():
+ self.assertRaises(InvalidData, rewrite_lafile, broken_contents)
diff --git a/portage_with_autodep/pym/portage/tests/lazyimport/__init__.py b/portage_with_autodep/pym/portage/tests/lazyimport/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/lazyimport/__init__.py
diff --git a/portage_with_autodep/pym/portage/tests/lazyimport/__test__ b/portage_with_autodep/pym/portage/tests/lazyimport/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/lazyimport/__test__
diff --git a/portage_with_autodep/pym/portage/tests/lazyimport/test_lazy_import_portage_baseline.py b/portage_with_autodep/pym/portage/tests/lazyimport/test_lazy_import_portage_baseline.py
new file mode 100644
index 0000000..08ccfa7
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/lazyimport/test_lazy_import_portage_baseline.py
@@ -0,0 +1,81 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import re
+import portage
+from portage import os
+from portage.const import PORTAGE_PYM_PATH
+from portage.tests import TestCase
+
+from _emerge.PollScheduler import PollScheduler
+from _emerge.PipeReader import PipeReader
+from _emerge.SpawnProcess import SpawnProcess
+
+class LazyImportPortageBaselineTestCase(TestCase):
+
+ _module_re = re.compile(r'^(portage|repoman|_emerge)\.')
+
+ _baseline_imports = frozenset([
+ 'portage.const', 'portage.localization',
+ 'portage.proxy', 'portage.proxy.lazyimport',
+ 'portage.proxy.objectproxy',
+ 'portage._selinux',
+ ])
+
+ _baseline_import_cmd = [portage._python_interpreter, '-c', '''
+import os
+import sys
+sys.path.insert(0, os.environ["PORTAGE_PYM_PATH"])
+import portage
+sys.stdout.write(" ".join(k for k in sys.modules
+ if sys.modules[k] is not None))
+''']
+
+ def testLazyImportPortageBaseline(self):
+ """
+ Check what modules are imported by a baseline module import.
+ """
+
+ env = os.environ.copy()
+ pythonpath = env.get('PYTHONPATH')
+ if pythonpath is not None and not pythonpath.strip():
+ pythonpath = None
+ if pythonpath is None:
+ pythonpath = ''
+ else:
+ pythonpath = ':' + pythonpath
+ pythonpath = PORTAGE_PYM_PATH + pythonpath
+ env[pythonpath] = pythonpath
+
+ # If python is patched to insert the path of the
+ # currently installed portage module into sys.path,
+ # then the above PYTHONPATH override doesn't help.
+ env['PORTAGE_PYM_PATH'] = PORTAGE_PYM_PATH
+
+ scheduler = PollScheduler().sched_iface
+ master_fd, slave_fd = os.pipe()
+ master_file = os.fdopen(master_fd, 'rb', 0)
+ slave_file = os.fdopen(slave_fd, 'wb')
+ producer = SpawnProcess(
+ args=self._baseline_import_cmd,
+ env=env, fd_pipes={1:slave_fd},
+ scheduler=scheduler)
+ producer.start()
+ slave_file.close()
+
+ consumer = PipeReader(
+ input_files={"producer" : master_file},
+ scheduler=scheduler)
+
+ consumer.start()
+ consumer.wait()
+ self.assertEqual(producer.wait(), os.EX_OK)
+ self.assertEqual(consumer.wait(), os.EX_OK)
+
+ output = consumer.getvalue().decode('ascii', 'replace').split()
+
+ unexpected_modules = " ".join(sorted(x for x in output \
+ if self._module_re.match(x) is not None and \
+ x not in self._baseline_imports))
+
+ self.assertEqual("", unexpected_modules)
diff --git a/portage_with_autodep/pym/portage/tests/lazyimport/test_preload_portage_submodules.py b/portage_with_autodep/pym/portage/tests/lazyimport/test_preload_portage_submodules.py
new file mode 100644
index 0000000..9d20eba
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/lazyimport/test_preload_portage_submodules.py
@@ -0,0 +1,16 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import portage
+from portage.tests import TestCase
+
+class PreloadPortageSubmodulesTestCase(TestCase):
+
+ def testPreloadPortageSubmodules(self):
+ """
+ Verify that _preload_portage_submodules() doesn't leave any
+ remaining proxies that refer to the portage.* namespace.
+ """
+ portage.proxy.lazyimport._preload_portage_submodules()
+ for name in portage.proxy.lazyimport._module_proxies:
+ self.assertEqual(name.startswith('portage.'), False)
diff --git a/portage_with_autodep/pym/portage/tests/lint/__init__.py b/portage_with_autodep/pym/portage/tests/lint/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/lint/__init__.py
diff --git a/portage_with_autodep/pym/portage/tests/lint/__test__ b/portage_with_autodep/pym/portage/tests/lint/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/lint/__test__
diff --git a/portage_with_autodep/pym/portage/tests/lint/test_bash_syntax.py b/portage_with_autodep/pym/portage/tests/lint/test_bash_syntax.py
new file mode 100644
index 0000000..aef8d74
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/lint/test_bash_syntax.py
@@ -0,0 +1,42 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import stat
+
+from portage.const import BASH_BINARY, PORTAGE_BIN_PATH
+from portage.tests import TestCase
+from portage import os
+from portage import subprocess_getstatusoutput
+from portage import _encodings
+from portage import _shell_quote
+from portage import _unicode_decode, _unicode_encode
+
+class BashSyntaxTestCase(TestCase):
+
+ def testBashSyntax(self):
+ for parent, dirs, files in os.walk(PORTAGE_BIN_PATH):
+ parent = _unicode_decode(parent,
+ encoding=_encodings['fs'], errors='strict')
+ for x in files:
+ x = _unicode_decode(x,
+ encoding=_encodings['fs'], errors='strict')
+ ext = x.split('.')[-1]
+ if ext in ('.py', '.pyc', '.pyo'):
+ continue
+ x = os.path.join(parent, x)
+ st = os.lstat(x)
+ if not stat.S_ISREG(st.st_mode):
+ continue
+
+ # Check for bash shebang
+ f = open(_unicode_encode(x,
+ encoding=_encodings['fs'], errors='strict'), 'rb')
+ line = _unicode_decode(f.readline(),
+ encoding=_encodings['content'], errors='replace')
+ f.close()
+ if line[:2] == '#!' and \
+ 'bash' in line:
+ cmd = "%s -n %s" % (_shell_quote(BASH_BINARY), _shell_quote(x))
+ status, output = subprocess_getstatusoutput(cmd)
+ self.assertEqual(os.WIFEXITED(status) and \
+ os.WEXITSTATUS(status) == os.EX_OK, True, msg=output)
diff --git a/portage_with_autodep/pym/portage/tests/lint/test_compile_modules.py b/portage_with_autodep/pym/portage/tests/lint/test_compile_modules.py
new file mode 100644
index 0000000..f90a666
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/lint/test_compile_modules.py
@@ -0,0 +1,46 @@
+# Copyright 2009-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import itertools
+import stat
+
+from portage.const import PORTAGE_BIN_PATH, PORTAGE_PYM_PATH
+from portage.tests import TestCase
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode, _unicode_encode
+
+import py_compile
+
+class CompileModulesTestCase(TestCase):
+
+ def testCompileModules(self):
+ for parent, dirs, files in itertools.chain(
+ os.walk(PORTAGE_BIN_PATH),
+ os.walk(PORTAGE_PYM_PATH)):
+ parent = _unicode_decode(parent,
+ encoding=_encodings['fs'], errors='strict')
+ for x in files:
+ x = _unicode_decode(x,
+ encoding=_encodings['fs'], errors='strict')
+ if x[-4:] in ('.pyc', '.pyo'):
+ continue
+ x = os.path.join(parent, x)
+ st = os.lstat(x)
+ if not stat.S_ISREG(st.st_mode):
+ continue
+ do_compile = False
+ if x[-3:] == '.py':
+ do_compile = True
+ else:
+ # Check for python shebang
+ f = open(_unicode_encode(x,
+ encoding=_encodings['fs'], errors='strict'), 'rb')
+ line = _unicode_decode(f.readline(),
+ encoding=_encodings['content'], errors='replace')
+ f.close()
+ if line[:2] == '#!' and \
+ 'python' in line:
+ do_compile = True
+ if do_compile:
+ py_compile.compile(x, cfile='/dev/null', doraise=True)
diff --git a/portage_with_autodep/pym/portage/tests/lint/test_import_modules.py b/portage_with_autodep/pym/portage/tests/lint/test_import_modules.py
new file mode 100644
index 0000000..8d257c5
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/lint/test_import_modules.py
@@ -0,0 +1,40 @@
+# Copyright 2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.const import PORTAGE_PYM_PATH
+from portage.tests import TestCase
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+
+class ImportModulesTestCase(TestCase):
+
+ def testImportModules(self):
+ expected_failures = frozenset((
+ ))
+
+ for mod in self._iter_modules(PORTAGE_PYM_PATH):
+ try:
+ __import__(mod)
+ except ImportError as e:
+ if mod not in expected_failures:
+ self.assertTrue(False, "failed to import '%s': %s" % (mod, e))
+ del e
+
+ def _iter_modules(self, base_dir):
+ for parent, dirs, files in os.walk(base_dir):
+ parent = _unicode_decode(parent,
+ encoding=_encodings['fs'], errors='strict')
+ parent_mod = parent[len(PORTAGE_PYM_PATH)+1:]
+ parent_mod = parent_mod.replace("/", ".")
+ for x in files:
+ x = _unicode_decode(x,
+ encoding=_encodings['fs'], errors='strict')
+ if x[-3:] != '.py':
+ continue
+ x = x[:-3]
+ if x[-8:] == '__init__':
+ x = parent_mod
+ else:
+ x = parent_mod + "." + x
+ yield x
diff --git a/portage_with_autodep/pym/portage/tests/locks/__init__.py b/portage_with_autodep/pym/portage/tests/locks/__init__.py
new file mode 100644
index 0000000..21a391a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/locks/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/tests/locks/__test__ b/portage_with_autodep/pym/portage/tests/locks/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/locks/__test__
diff --git a/portage_with_autodep/pym/portage/tests/locks/test_asynchronous_lock.py b/portage_with_autodep/pym/portage/tests/locks/test_asynchronous_lock.py
new file mode 100644
index 0000000..8946caf
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/locks/test_asynchronous_lock.py
@@ -0,0 +1,124 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import shutil
+import signal
+import tempfile
+
+from portage import os
+from portage.tests import TestCase
+from _emerge.AsynchronousLock import AsynchronousLock
+from _emerge.PollScheduler import PollScheduler
+
+class AsynchronousLockTestCase(TestCase):
+
+ def testAsynchronousLock(self):
+ scheduler = PollScheduler().sched_iface
+ tempdir = tempfile.mkdtemp()
+ try:
+ path = os.path.join(tempdir, 'lock_me')
+ for force_async in (True, False):
+ for force_dummy in (True, False):
+ async_lock = AsynchronousLock(path=path,
+ scheduler=scheduler, _force_async=force_async,
+ _force_thread=True,
+ _force_dummy=force_dummy)
+ async_lock.start()
+ self.assertEqual(async_lock.wait(), os.EX_OK)
+ self.assertEqual(async_lock.returncode, os.EX_OK)
+ async_lock.unlock()
+
+ async_lock = AsynchronousLock(path=path,
+ scheduler=scheduler, _force_async=force_async,
+ _force_process=True)
+ async_lock.start()
+ self.assertEqual(async_lock.wait(), os.EX_OK)
+ self.assertEqual(async_lock.returncode, os.EX_OK)
+ async_lock.unlock()
+
+ finally:
+ shutil.rmtree(tempdir)
+
+ def testAsynchronousLockWait(self):
+ scheduler = PollScheduler().sched_iface
+ tempdir = tempfile.mkdtemp()
+ try:
+ path = os.path.join(tempdir, 'lock_me')
+ lock1 = AsynchronousLock(path=path, scheduler=scheduler)
+ lock1.start()
+ self.assertEqual(lock1.wait(), os.EX_OK)
+ self.assertEqual(lock1.returncode, os.EX_OK)
+
+ # lock2 requires _force_async=True since the portage.locks
+ # module is not designed to work as intended here if the
+ # same process tries to lock the same file more than
+ # one time concurrently.
+ lock2 = AsynchronousLock(path=path, scheduler=scheduler,
+ _force_async=True, _force_process=True)
+ lock2.start()
+ # lock2 should be waiting for lock1 to release
+ self.assertEqual(lock2.poll(), None)
+ self.assertEqual(lock2.returncode, None)
+
+ lock1.unlock()
+ self.assertEqual(lock2.wait(), os.EX_OK)
+ self.assertEqual(lock2.returncode, os.EX_OK)
+ lock2.unlock()
+ finally:
+ shutil.rmtree(tempdir)
+
+ def testAsynchronousLockWaitCancel(self):
+ scheduler = PollScheduler().sched_iface
+ tempdir = tempfile.mkdtemp()
+ try:
+ path = os.path.join(tempdir, 'lock_me')
+ lock1 = AsynchronousLock(path=path, scheduler=scheduler)
+ lock1.start()
+ self.assertEqual(lock1.wait(), os.EX_OK)
+ self.assertEqual(lock1.returncode, os.EX_OK)
+ lock2 = AsynchronousLock(path=path, scheduler=scheduler,
+ _force_async=True, _force_process=True)
+ lock2.start()
+ # lock2 should be waiting for lock1 to release
+ self.assertEqual(lock2.poll(), None)
+ self.assertEqual(lock2.returncode, None)
+
+ # Cancel lock2 and then check wait() and returncode results.
+ lock2.cancel()
+ self.assertEqual(lock2.wait() == os.EX_OK, False)
+ self.assertEqual(lock2.returncode == os.EX_OK, False)
+ self.assertEqual(lock2.returncode is None, False)
+ lock1.unlock()
+ finally:
+ shutil.rmtree(tempdir)
+
+ def testAsynchronousLockWaitKill(self):
+ scheduler = PollScheduler().sched_iface
+ tempdir = tempfile.mkdtemp()
+ try:
+ path = os.path.join(tempdir, 'lock_me')
+ lock1 = AsynchronousLock(path=path, scheduler=scheduler)
+ lock1.start()
+ self.assertEqual(lock1.wait(), os.EX_OK)
+ self.assertEqual(lock1.returncode, os.EX_OK)
+ lock2 = AsynchronousLock(path=path, scheduler=scheduler,
+ _force_async=True, _force_process=True)
+ lock2.start()
+ # lock2 should be waiting for lock1 to release
+ self.assertEqual(lock2.poll(), None)
+ self.assertEqual(lock2.returncode, None)
+
+ # Kill lock2's process and then check wait() and
+ # returncode results. This is intended to simulate
+ # a SIGINT sent via the controlling tty.
+ self.assertEqual(lock2._imp is not None, True)
+ self.assertEqual(lock2._imp._proc is not None, True)
+ self.assertEqual(lock2._imp._proc.pid is not None, True)
+ lock2._imp._kill_test = True
+ os.kill(lock2._imp._proc.pid, signal.SIGTERM)
+ self.assertEqual(lock2.wait() == os.EX_OK, False)
+ self.assertEqual(lock2.returncode == os.EX_OK, False)
+ self.assertEqual(lock2.returncode is None, False)
+ lock1.unlock()
+ finally:
+ shutil.rmtree(tempdir)
diff --git a/portage_with_autodep/pym/portage/tests/locks/test_lock_nonblock.py b/portage_with_autodep/pym/portage/tests/locks/test_lock_nonblock.py
new file mode 100644
index 0000000..d5748ad
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/locks/test_lock_nonblock.py
@@ -0,0 +1,46 @@
+# Copyright 2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import shutil
+import tempfile
+import traceback
+
+import portage
+from portage import os
+from portage.tests import TestCase
+
+class LockNonblockTestCase(TestCase):
+
+ def testLockNonblock(self):
+ tempdir = tempfile.mkdtemp()
+ try:
+ path = os.path.join(tempdir, 'lock_me')
+ lock1 = portage.locks.lockfile(path)
+ pid = os.fork()
+ if pid == 0:
+ portage.process._setup_pipes({0:0, 1:1, 2:2})
+ rval = 2
+ try:
+ try:
+ lock2 = portage.locks.lockfile(path, flags=os.O_NONBLOCK)
+ except portage.exception.TryAgain:
+ rval = os.EX_OK
+ else:
+ rval = 1
+ portage.locks.unlockfile(lock2)
+ except SystemExit:
+ raise
+ except:
+ traceback.print_exc()
+ finally:
+ os._exit(rval)
+
+ self.assertEqual(pid > 0, True)
+ pid, status = os.waitpid(pid, 0)
+ self.assertEqual(os.WIFEXITED(status), True)
+ self.assertEqual(os.WEXITSTATUS(status), os.EX_OK)
+
+ portage.locks.unlockfile(lock1)
+ finally:
+ shutil.rmtree(tempdir)
+
diff --git a/portage_with_autodep/pym/portage/tests/news/__init__.py b/portage_with_autodep/pym/portage/tests/news/__init__.py
new file mode 100644
index 0000000..28a753f
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/news/__init__.py
@@ -0,0 +1,3 @@
+# tests/portage.news/__init__.py -- Portage Unit Test functionality
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/tests/news/__test__ b/portage_with_autodep/pym/portage/tests/news/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/news/__test__
diff --git a/portage_with_autodep/pym/portage/tests/news/test_NewsItem.py b/portage_with_autodep/pym/portage/tests/news/test_NewsItem.py
new file mode 100644
index 0000000..a4e76f3
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/news/test_NewsItem.py
@@ -0,0 +1,95 @@
+# test_NewsItem.py -- Portage Unit Testing Functionality
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from portage.tests import TestCase
+from portage.news import NewsItem
+from portage.dbapi.virtual import testdbapi
+from tempfile import mkstemp
+# TODO(antarus) Make newsitem use a loader so we can load using a string instead of a tempfile
+
+class NewsItemTestCase(TestCase):
+ """These tests suck: they use your running config instead of making their own"""
+ fakeItem = """
+Title: YourSQL Upgrades from 4.0 to 4.1
+Author: Ciaran McCreesh <ciaranm@gentoo.org>
+Content-Type: text/plain
+Posted: 01-Nov-2005
+Revision: 1
+#Display-If-Installed:
+#Display-If-Profile:
+#Display-If-Arch:
+
+YourSQL databases created using YourSQL version 4.0 are incompatible
+with YourSQL version 4.1 or later. There is no reliable way to
+automate the database format conversion, so action from the system
+administrator is required before an upgrade can take place.
+
+Please see the Gentoo YourSQL Upgrade Guide for instructions:
+
+ http://www.gentoo.org/doc/en/yoursql-upgrading.xml
+
+Also see the official YourSQL documentation:
+
+ http://dev.yoursql.com/doc/refman/4.1/en/upgrading-from-4-0.html
+
+After upgrading, you should also recompile any packages which link
+against YourSQL:
+
+ revdep-rebuild --library=libyoursqlclient.so.12
+
+The revdep-rebuild tool is provided by app-portage/gentoolkit.
+"""
+ def setUp(self):
+ self.profile = "/usr/portage/profiles/default-linux/x86/2007.0/"
+ self.keywords = "x86"
+ # Use fake/test dbapi to avoid slow tests
+ self.vardb = testdbapi()
+ # self.vardb.inject_cpv('sys-apps/portage-2.0', { 'SLOT' : 0 })
+ # Consumers only use ARCH, so avoid portage.settings by using a dict
+ self.settings = { 'ARCH' : 'x86' }
+
+ def testDisplayIfProfile(self):
+ tmpItem = self.fakeItem[:].replace("#Display-If-Profile:", "Display-If-Profile: %s" %
+ self.profile)
+
+ item = self._processItem(tmpItem)
+ try:
+ self.assertTrue(item.isRelevant(self.vardb, self.settings, self.profile),
+ msg="Expected %s to be relevant, but it was not!" % tmpItem)
+ finally:
+ os.unlink(item.path)
+
+ def testDisplayIfInstalled(self):
+ tmpItem = self.fakeItem[:].replace("#Display-If-Installed:", "Display-If-Installed: %s" %
+ "sys-apps/portage")
+
+ try:
+ item = self._processItem(tmpItem)
+ self.assertTrue(item.isRelevant(self.vardb, self.settings, self.profile),
+ msg="Expected %s to be relevant, but it was not!" % tmpItem)
+ finally:
+ os.unlink(item.path)
+
+ def testDisplayIfKeyword(self):
+ tmpItem = self.fakeItem[:].replace("#Display-If-Keyword:", "Display-If-Keyword: %s" %
+ self.keywords)
+
+ try:
+ item = self._processItem(tmpItem)
+ self.assertTrue(item.isRelevant(self.vardb, self.settings, self.profile),
+ msg="Expected %s to be relevant, but it was not!" % tmpItem)
+ finally:
+ os.unlink(item.path)
+
+ def _processItem(self, item):
+ filename = None
+ fd, filename = mkstemp()
+ f = os.fdopen(fd, 'w')
+ f.write(item)
+ f.close()
+ try:
+ return NewsItem(filename, 0)
+ except TypeError:
+ self.fail("Error while processing news item %s" % filename)
diff --git a/portage_with_autodep/pym/portage/tests/process/__init__.py b/portage_with_autodep/pym/portage/tests/process/__init__.py
new file mode 100644
index 0000000..d19e353
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/process/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 1998-2008 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/tests/process/__test__ b/portage_with_autodep/pym/portage/tests/process/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/process/__test__
diff --git a/portage_with_autodep/pym/portage/tests/process/test_poll.py b/portage_with_autodep/pym/portage/tests/process/test_poll.py
new file mode 100644
index 0000000..ee6ee0c
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/process/test_poll.py
@@ -0,0 +1,39 @@
+# Copyright 1998-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from portage.tests import TestCase
+from _emerge.PollScheduler import PollScheduler
+from _emerge.PipeReader import PipeReader
+from _emerge.SpawnProcess import SpawnProcess
+
+class PipeReaderTestCase(TestCase):
+
+ def testPipeReader(self):
+ """
+ Use a poll loop to read data from a pipe and assert that
+ the data written to the pipe is identical to the data
+ read from the pipe.
+ """
+
+ test_string = 2 * "blah blah blah\n"
+
+ scheduler = PollScheduler().sched_iface
+ master_fd, slave_fd = os.pipe()
+ master_file = os.fdopen(master_fd, 'rb', 0)
+ slave_file = os.fdopen(slave_fd, 'wb')
+ producer = SpawnProcess(
+ args=["bash", "-c", "echo -n '%s'" % test_string],
+ env=os.environ, fd_pipes={1:slave_fd},
+ scheduler=scheduler)
+ producer.start()
+ slave_file.close()
+
+ consumer = PipeReader(
+ input_files={"producer" : master_file},
+ scheduler=scheduler)
+
+ consumer.start()
+ consumer.wait()
+ output = consumer.getvalue().decode('ascii', 'replace')
+ self.assertEqual(test_string, output)
diff --git a/portage_with_autodep/pym/portage/tests/resolver/ResolverPlayground.py b/portage_with_autodep/pym/portage/tests/resolver/ResolverPlayground.py
new file mode 100644
index 0000000..6a8e3c1
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/ResolverPlayground.py
@@ -0,0 +1,690 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from itertools import permutations
+import shutil
+import sys
+import tempfile
+import portage
+from portage import os
+from portage.const import PORTAGE_BASE_PATH
+from portage.dbapi.vartree import vartree
+from portage.dbapi.porttree import portagetree
+from portage.dbapi.bintree import binarytree
+from portage.dep import Atom, _repo_separator
+from portage.package.ebuild.config import config
+from portage.package.ebuild.digestgen import digestgen
+from portage._sets import load_default_config
+from portage._sets.base import InternalPackageSet
+from portage.versions import catsplit
+
+import _emerge
+from _emerge.actions import calc_depclean
+from _emerge.Blocker import Blocker
+from _emerge.create_depgraph_params import create_depgraph_params
+from _emerge.depgraph import backtrack_depgraph
+from _emerge.RootConfig import RootConfig
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+class ResolverPlayground(object):
+ """
+ This class helps to create the necessary files on disk and
+ the needed settings instances, etc. for the resolver to do
+ its work.
+ """
+
+ config_files = frozenset(("package.use", "package.mask", "package.keywords", \
+ "package.unmask", "package.properties", "package.license", "use.mask", "use.force"))
+
+ def __init__(self, ebuilds={}, installed={}, profile={}, repo_configs={}, \
+ user_config={}, sets={}, world=[], debug=False):
+ """
+ ebuilds: cpv -> metadata mapping simulating available ebuilds.
+ installed: cpv -> metadata mapping simulating installed packages.
+ If a metadata key is missing, it gets a default value.
+ profile: settings defined by the profile.
+ """
+ self.debug = debug
+ self.root = "/"
+ self.eprefix = tempfile.mkdtemp()
+ self.eroot = self.root + self.eprefix.lstrip(os.sep) + os.sep
+ self.portdir = os.path.join(self.eroot, "usr/portage")
+ self.vdbdir = os.path.join(self.eroot, "var/db/pkg")
+ os.makedirs(self.portdir)
+ os.makedirs(self.vdbdir)
+
+ if not debug:
+ portage.util.noiselimit = -2
+
+ self.repo_dirs = {}
+ #Make sure the main repo is always created
+ self._get_repo_dir("test_repo")
+
+ self._create_ebuilds(ebuilds)
+ self._create_installed(installed)
+ self._create_profile(ebuilds, installed, profile, repo_configs, user_config, sets)
+ self._create_world(world)
+
+ self.settings, self.trees = self._load_config()
+
+ self._create_ebuild_manifests(ebuilds)
+
+ portage.util.noiselimit = 0
+
+ def _get_repo_dir(self, repo):
+ """
+ Create the repo directory if needed.
+ """
+ if repo not in self.repo_dirs:
+ if repo == "test_repo":
+ repo_path = self.portdir
+ else:
+ repo_path = os.path.join(self.eroot, "usr", "local", repo)
+
+ self.repo_dirs[repo] = repo_path
+ profile_path = os.path.join(repo_path, "profiles")
+
+ try:
+ os.makedirs(profile_path)
+ except os.error:
+ pass
+
+ repo_name_file = os.path.join(profile_path, "repo_name")
+ f = open(repo_name_file, "w")
+ f.write("%s\n" % repo)
+ f.close()
+
+ return self.repo_dirs[repo]
+
+ def _create_ebuilds(self, ebuilds):
+ for cpv in ebuilds:
+ a = Atom("=" + cpv, allow_repo=True)
+ repo = a.repo
+ if repo is None:
+ repo = "test_repo"
+
+ metadata = ebuilds[cpv].copy()
+ eapi = metadata.pop("EAPI", 0)
+ lic = metadata.pop("LICENSE", "")
+ properties = metadata.pop("PROPERTIES", "")
+ slot = metadata.pop("SLOT", 0)
+ keywords = metadata.pop("KEYWORDS", "x86")
+ iuse = metadata.pop("IUSE", "")
+ depend = metadata.pop("DEPEND", "")
+ rdepend = metadata.pop("RDEPEND", None)
+ pdepend = metadata.pop("PDEPEND", None)
+ required_use = metadata.pop("REQUIRED_USE", None)
+
+ if metadata:
+ raise ValueError("metadata of ebuild '%s' contains unknown keys: %s" % (cpv, metadata.keys()))
+
+ repo_dir = self._get_repo_dir(repo)
+ ebuild_dir = os.path.join(repo_dir, a.cp)
+ ebuild_path = os.path.join(ebuild_dir, a.cpv.split("/")[1] + ".ebuild")
+ try:
+ os.makedirs(ebuild_dir)
+ except os.error:
+ pass
+
+ f = open(ebuild_path, "w")
+ f.write('EAPI="' + str(eapi) + '"\n')
+ f.write('LICENSE="' + str(lic) + '"\n')
+ f.write('PROPERTIES="' + str(properties) + '"\n')
+ f.write('SLOT="' + str(slot) + '"\n')
+ f.write('KEYWORDS="' + str(keywords) + '"\n')
+ f.write('IUSE="' + str(iuse) + '"\n')
+ f.write('DEPEND="' + str(depend) + '"\n')
+ if rdepend is not None:
+ f.write('RDEPEND="' + str(rdepend) + '"\n')
+ if pdepend is not None:
+ f.write('PDEPEND="' + str(pdepend) + '"\n')
+ if required_use is not None:
+ f.write('REQUIRED_USE="' + str(required_use) + '"\n')
+ f.close()
+
+ def _create_ebuild_manifests(self, ebuilds):
+ tmpsettings = config(clone=self.settings)
+ tmpsettings['PORTAGE_QUIET'] = '1'
+ for cpv in ebuilds:
+ a = Atom("=" + cpv, allow_repo=True)
+ repo = a.repo
+ if repo is None:
+ repo = "test_repo"
+
+ repo_dir = self._get_repo_dir(repo)
+ ebuild_dir = os.path.join(repo_dir, a.cp)
+ ebuild_path = os.path.join(ebuild_dir, a.cpv.split("/")[1] + ".ebuild")
+
+ portdb = self.trees[self.root]["porttree"].dbapi
+ tmpsettings['O'] = ebuild_dir
+ if not digestgen(mysettings=tmpsettings, myportdb=portdb):
+ raise AssertionError('digest creation failed for %s' % ebuild_path)
+
+ def _create_installed(self, installed):
+ for cpv in installed:
+ a = Atom("=" + cpv, allow_repo=True)
+ repo = a.repo
+ if repo is None:
+ repo = "test_repo"
+
+ vdb_pkg_dir = os.path.join(self.vdbdir, a.cpv)
+ try:
+ os.makedirs(vdb_pkg_dir)
+ except os.error:
+ pass
+
+ metadata = installed[cpv].copy()
+ eapi = metadata.pop("EAPI", 0)
+ lic = metadata.pop("LICENSE", "")
+ properties = metadata.pop("PROPERTIES", "")
+ slot = metadata.pop("SLOT", 0)
+ keywords = metadata.pop("KEYWORDS", "~x86")
+ iuse = metadata.pop("IUSE", "")
+ use = metadata.pop("USE", "")
+ depend = metadata.pop("DEPEND", "")
+ rdepend = metadata.pop("RDEPEND", None)
+ pdepend = metadata.pop("PDEPEND", None)
+ required_use = metadata.pop("REQUIRED_USE", None)
+
+ if metadata:
+ raise ValueError("metadata of installed '%s' contains unknown keys: %s" % (cpv, metadata.keys()))
+
+ def write_key(key, value):
+ f = open(os.path.join(vdb_pkg_dir, key), "w")
+ f.write(str(value) + "\n")
+ f.close()
+
+ write_key("EAPI", eapi)
+ write_key("LICENSE", lic)
+ write_key("PROPERTIES", properties)
+ write_key("SLOT", slot)
+ write_key("LICENSE", lic)
+ write_key("PROPERTIES", properties)
+ write_key("repository", repo)
+ write_key("KEYWORDS", keywords)
+ write_key("IUSE", iuse)
+ write_key("USE", use)
+ write_key("DEPEND", depend)
+ if rdepend is not None:
+ write_key("RDEPEND", rdepend)
+ if pdepend is not None:
+ write_key("PDEPEND", pdepend)
+ if required_use is not None:
+ write_key("REQUIRED_USE", required_use)
+
+ def _create_profile(self, ebuilds, installed, profile, repo_configs, user_config, sets):
+
+ for repo in self.repo_dirs:
+ repo_dir = self._get_repo_dir(repo)
+ profile_dir = os.path.join(self._get_repo_dir(repo), "profiles")
+
+ #Create $REPO/profiles/categories
+ categories = set()
+ for cpv in ebuilds:
+ ebuilds_repo = Atom("="+cpv, allow_repo=True).repo
+ if ebuilds_repo is None:
+ ebuilds_repo = "test_repo"
+ if ebuilds_repo == repo:
+ categories.add(catsplit(cpv)[0])
+
+ categories_file = os.path.join(profile_dir, "categories")
+ f = open(categories_file, "w")
+ for cat in categories:
+ f.write(cat + "\n")
+ f.close()
+
+ #Create $REPO/profiles/license_groups
+ license_file = os.path.join(profile_dir, "license_groups")
+ f = open(license_file, "w")
+ f.write("EULA TEST\n")
+ f.close()
+
+ repo_config = repo_configs.get(repo)
+ if repo_config:
+ for config_file, lines in repo_config.items():
+ if config_file not in self.config_files:
+ raise ValueError("Unknown config file: '%s'" % config_file)
+
+ file_name = os.path.join(profile_dir, config_file)
+ f = open(file_name, "w")
+ for line in lines:
+ f.write("%s\n" % line)
+ f.close()
+
+ #Create $profile_dir/eclass (we fail to digest the ebuilds if it's not there)
+ os.makedirs(os.path.join(repo_dir, "eclass"))
+
+ if repo == "test_repo":
+ #Create a minimal profile in /usr/portage
+ sub_profile_dir = os.path.join(profile_dir, "default", "linux", "x86", "test_profile")
+ os.makedirs(sub_profile_dir)
+
+ eapi_file = os.path.join(sub_profile_dir, "eapi")
+ f = open(eapi_file, "w")
+ f.write("0\n")
+ f.close()
+
+ make_defaults_file = os.path.join(sub_profile_dir, "make.defaults")
+ f = open(make_defaults_file, "w")
+ f.write("ARCH=\"x86\"\n")
+ f.write("ACCEPT_KEYWORDS=\"x86\"\n")
+ f.close()
+
+ use_force_file = os.path.join(sub_profile_dir, "use.force")
+ f = open(use_force_file, "w")
+ f.write("x86\n")
+ f.close()
+
+ if profile:
+ for config_file, lines in profile.items():
+ if config_file not in self.config_files:
+ raise ValueError("Unknown config file: '%s'" % config_file)
+
+ file_name = os.path.join(sub_profile_dir, config_file)
+ f = open(file_name, "w")
+ for line in lines:
+ f.write("%s\n" % line)
+ f.close()
+
+ #Create profile symlink
+ os.makedirs(os.path.join(self.eroot, "etc"))
+ os.symlink(sub_profile_dir, os.path.join(self.eroot, "etc", "make.profile"))
+
+ user_config_dir = os.path.join(self.eroot, "etc", "portage")
+
+ try:
+ os.makedirs(user_config_dir)
+ except os.error:
+ pass
+
+ repos_conf_file = os.path.join(user_config_dir, "repos.conf")
+ f = open(repos_conf_file, "w")
+ priority = 0
+ for repo in sorted(self.repo_dirs.keys()):
+ f.write("[%s]\n" % repo)
+ f.write("LOCATION=%s\n" % self.repo_dirs[repo])
+ if repo == "test_repo":
+ f.write("PRIORITY=%s\n" % -1000)
+ else:
+ f.write("PRIORITY=%s\n" % priority)
+ priority += 1
+ f.close()
+
+ for config_file, lines in user_config.items():
+ if config_file not in self.config_files:
+ raise ValueError("Unknown config file: '%s'" % config_file)
+
+ file_name = os.path.join(user_config_dir, config_file)
+ f = open(file_name, "w")
+ for line in lines:
+ f.write("%s\n" % line)
+ f.close()
+
+ #Create /usr/share/portage/config/sets/portage.conf
+ default_sets_conf_dir = os.path.join(self.eroot, "usr/share/portage/config/sets")
+
+ try:
+ os.makedirs(default_sets_conf_dir)
+ except os.error:
+ pass
+
+ provided_sets_portage_conf = \
+ os.path.join(PORTAGE_BASE_PATH, "cnf/sets/portage.conf")
+ os.symlink(provided_sets_portage_conf, os.path.join(default_sets_conf_dir, "portage.conf"))
+
+ set_config_dir = os.path.join(user_config_dir, "sets")
+
+ try:
+ os.makedirs(set_config_dir)
+ except os.error:
+ pass
+
+ for sets_file, lines in sets.items():
+ file_name = os.path.join(set_config_dir, sets_file)
+ f = open(file_name, "w")
+ for line in lines:
+ f.write("%s\n" % line)
+ f.close()
+
+ user_config_dir = os.path.join(self.eroot, "etc", "portage")
+
+ try:
+ os.makedirs(user_config_dir)
+ except os.error:
+ pass
+
+ for config_file, lines in user_config.items():
+ if config_file not in self.config_files:
+ raise ValueError("Unknown config file: '%s'" % config_file)
+
+ file_name = os.path.join(user_config_dir, config_file)
+ f = open(file_name, "w")
+ for line in lines:
+ f.write("%s\n" % line)
+ f.close()
+
+ def _create_world(self, world):
+ #Create /var/lib/portage/world
+ var_lib_portage = os.path.join(self.eroot, "var", "lib", "portage")
+ os.makedirs(var_lib_portage)
+
+ world_file = os.path.join(var_lib_portage, "world")
+
+ f = open(world_file, "w")
+ for atom in world:
+ f.write("%s\n" % atom)
+ f.close()
+
+ def _load_config(self):
+ portdir_overlay = []
+ for repo_name in sorted(self.repo_dirs):
+ path = self.repo_dirs[repo_name]
+ if path != self.portdir:
+ portdir_overlay.append(path)
+
+ env = {
+ "ACCEPT_KEYWORDS": "x86",
+ "PORTDIR": self.portdir,
+ "PORTDIR_OVERLAY": " ".join(portdir_overlay),
+ 'PORTAGE_TMPDIR' : os.path.join(self.eroot, 'var/tmp'),
+ }
+
+ # Pass along PORTAGE_USERNAME and PORTAGE_GRPNAME since they
+ # need to be inherited by ebuild subprocesses.
+ if 'PORTAGE_USERNAME' in os.environ:
+ env['PORTAGE_USERNAME'] = os.environ['PORTAGE_USERNAME']
+ if 'PORTAGE_GRPNAME' in os.environ:
+ env['PORTAGE_GRPNAME'] = os.environ['PORTAGE_GRPNAME']
+
+ settings = config(_eprefix=self.eprefix, env=env)
+ settings.lock()
+
+ trees = {
+ self.root: {
+ "vartree": vartree(settings=settings),
+ "porttree": portagetree(self.root, settings=settings),
+ "bintree": binarytree(self.root,
+ os.path.join(self.eroot, "usr/portage/packages"),
+ settings=settings)
+ }
+ }
+
+ for root, root_trees in trees.items():
+ settings = root_trees["vartree"].settings
+ settings._init_dirs()
+ setconfig = load_default_config(settings, root_trees)
+ root_trees["root_config"] = RootConfig(settings, root_trees, setconfig)
+
+ return settings, trees
+
+ def run(self, atoms, options={}, action=None):
+ options = options.copy()
+ options["--pretend"] = True
+ if self.debug:
+ options["--debug"] = True
+
+ global_noiselimit = portage.util.noiselimit
+ global_emergelog_disable = _emerge.emergelog._disable
+ try:
+
+ if not self.debug:
+ portage.util.noiselimit = -2
+ _emerge.emergelog._disable = True
+
+ if options.get("--depclean"):
+ rval, cleanlist, ordered, req_pkg_count = \
+ calc_depclean(self.settings, self.trees, None,
+ options, "depclean", InternalPackageSet(initial_atoms=atoms, allow_wildcard=True), None)
+ result = ResolverPlaygroundDepcleanResult( \
+ atoms, rval, cleanlist, ordered, req_pkg_count)
+ else:
+ params = create_depgraph_params(options, action)
+ success, depgraph, favorites = backtrack_depgraph(
+ self.settings, self.trees, options, params, action, atoms, None)
+ depgraph._show_merge_list()
+ depgraph.display_problems()
+ result = ResolverPlaygroundResult(atoms, success, depgraph, favorites)
+ finally:
+ portage.util.noiselimit = global_noiselimit
+ _emerge.emergelog._disable = global_emergelog_disable
+
+ return result
+
+ def run_TestCase(self, test_case):
+ if not isinstance(test_case, ResolverPlaygroundTestCase):
+ raise TypeError("ResolverPlayground needs a ResolverPlaygroundTestCase")
+ for atoms in test_case.requests:
+ result = self.run(atoms, test_case.options, test_case.action)
+ if not test_case.compare_with_result(result):
+ return
+
+ def cleanup(self):
+ portdb = self.trees[self.root]["porttree"].dbapi
+ portdb.close_caches()
+ portage.dbapi.porttree.portdbapi.portdbapi_instances.remove(portdb)
+ if self.debug:
+ print("\nEROOT=%s" % self.eroot)
+ else:
+ shutil.rmtree(self.eroot)
+
+class ResolverPlaygroundTestCase(object):
+
+ def __init__(self, request, **kwargs):
+ self.all_permutations = kwargs.pop("all_permutations", False)
+ self.ignore_mergelist_order = kwargs.pop("ignore_mergelist_order", False)
+ self.ambiguous_merge_order = kwargs.pop("ambiguous_merge_order", False)
+ self.check_repo_names = kwargs.pop("check_repo_names", False)
+ self.merge_order_assertions = kwargs.pop("merge_order_assertions", False)
+
+ if self.all_permutations:
+ self.requests = list(permutations(request))
+ else:
+ self.requests = [request]
+
+ self.options = kwargs.pop("options", {})
+ self.action = kwargs.pop("action", None)
+ self.test_success = True
+ self.fail_msg = None
+ self._checks = kwargs.copy()
+
+ def compare_with_result(self, result):
+ checks = dict.fromkeys(result.checks)
+ for key, value in self._checks.items():
+ if not key in checks:
+ raise KeyError("Not an available check: '%s'" % key)
+ checks[key] = value
+
+ fail_msgs = []
+ for key, value in checks.items():
+ got = getattr(result, key)
+ expected = value
+
+ if key in result.optional_checks and expected is None:
+ continue
+
+ if key == "mergelist":
+ if not self.check_repo_names:
+ #Strip repo names if we don't check them
+ if got:
+ new_got = []
+ for cpv in got:
+ if cpv[:1] == "!":
+ new_got.append(cpv)
+ continue
+ a = Atom("="+cpv, allow_repo=True)
+ new_got.append(a.cpv)
+ got = new_got
+ if expected:
+ new_expected = []
+ for obj in expected:
+ if isinstance(obj, basestring):
+ if obj[:1] == "!":
+ new_expected.append(obj)
+ continue
+ a = Atom("="+obj, allow_repo=True)
+ new_expected.append(a.cpv)
+ continue
+ new_expected.append(set())
+ for cpv in obj:
+ if cpv[:1] != "!":
+ cpv = Atom("="+cpv, allow_repo=True).cpv
+ new_expected[-1].add(cpv)
+ expected = new_expected
+ if self.ignore_mergelist_order and got is not None:
+ got = set(got)
+ expected = set(expected)
+
+ if self.ambiguous_merge_order and got:
+ expected_stack = list(reversed(expected))
+ got_stack = list(reversed(got))
+ new_expected = []
+ match = True
+ while got_stack and expected_stack:
+ got_token = got_stack.pop()
+ expected_obj = expected_stack.pop()
+ if isinstance(expected_obj, basestring):
+ new_expected.append(expected_obj)
+ if got_token == expected_obj:
+ continue
+ # result doesn't match, so stop early
+ match = False
+ break
+ expected_obj = set(expected_obj)
+ try:
+ expected_obj.remove(got_token)
+ except KeyError:
+ # result doesn't match, so stop early
+ match = False
+ break
+ new_expected.append(got_token)
+ while got_stack and expected_obj:
+ got_token = got_stack.pop()
+ try:
+ expected_obj.remove(got_token)
+ except KeyError:
+ match = False
+ break
+ new_expected.append(got_token)
+ if not match:
+ # result doesn't match, so stop early
+ break
+ if expected_obj:
+ # result does not match, so stop early
+ match = False
+ new_expected.append(tuple(expected_obj))
+ break
+ if expected_stack:
+ # result does not match, add leftovers to new_expected
+ match = False
+ expected_stack.reverse()
+ new_expected.extend(expected_stack)
+ expected = new_expected
+
+ if match and self.merge_order_assertions:
+ for node1, node2 in self.merge_order_assertions:
+ if not (got.index(node1) < got.index(node2)):
+ fail_msgs.append("atoms: (" + \
+ ", ".join(result.atoms) + "), key: " + \
+ ("merge_order_assertions, expected: %s" % \
+ str((node1, node2))) + \
+ ", got: " + str(got))
+
+ elif key in ("unstable_keywords", "needed_p_mask_changes") and expected is not None:
+ expected = set(expected)
+
+ if got != expected:
+ fail_msgs.append("atoms: (" + ", ".join(result.atoms) + "), key: " + \
+ key + ", expected: " + str(expected) + ", got: " + str(got))
+ if fail_msgs:
+ self.test_success = False
+ self.fail_msg = "\n".join(fail_msgs)
+ return False
+ return True
+
+class ResolverPlaygroundResult(object):
+
+ checks = (
+ "success", "mergelist", "use_changes", "license_changes", "unstable_keywords", "slot_collision_solutions",
+ "circular_dependency_solutions", "needed_p_mask_changes",
+ )
+ optional_checks = (
+ )
+
+ def __init__(self, atoms, success, mydepgraph, favorites):
+ self.atoms = atoms
+ self.success = success
+ self.depgraph = mydepgraph
+ self.favorites = favorites
+ self.mergelist = None
+ self.use_changes = None
+ self.license_changes = None
+ self.unstable_keywords = None
+ self.needed_p_mask_changes = None
+ self.slot_collision_solutions = None
+ self.circular_dependency_solutions = None
+
+ if self.depgraph._dynamic_config._serialized_tasks_cache is not None:
+ self.mergelist = []
+ for x in self.depgraph._dynamic_config._serialized_tasks_cache:
+ if isinstance(x, Blocker):
+ self.mergelist.append(x.atom)
+ else:
+ repo_str = ""
+ if x.metadata["repository"] != "test_repo":
+ repo_str = _repo_separator + x.metadata["repository"]
+ self.mergelist.append(x.cpv + repo_str)
+
+ if self.depgraph._dynamic_config._needed_use_config_changes:
+ self.use_changes = {}
+ for pkg, needed_use_config_changes in \
+ self.depgraph._dynamic_config._needed_use_config_changes.items():
+ new_use, changes = needed_use_config_changes
+ self.use_changes[pkg.cpv] = changes
+
+ if self.depgraph._dynamic_config._needed_unstable_keywords:
+ self.unstable_keywords = set()
+ for pkg in self.depgraph._dynamic_config._needed_unstable_keywords:
+ self.unstable_keywords.add(pkg.cpv)
+
+ if self.depgraph._dynamic_config._needed_p_mask_changes:
+ self.needed_p_mask_changes = set()
+ for pkg in self.depgraph._dynamic_config._needed_p_mask_changes:
+ self.needed_p_mask_changes.add(pkg.cpv)
+
+ if self.depgraph._dynamic_config._needed_license_changes:
+ self.license_changes = {}
+ for pkg, missing_licenses in self.depgraph._dynamic_config._needed_license_changes.items():
+ self.license_changes[pkg.cpv] = missing_licenses
+
+ if self.depgraph._dynamic_config._slot_conflict_handler is not None:
+ self.slot_collision_solutions = []
+ handler = self.depgraph._dynamic_config._slot_conflict_handler
+
+ for change in handler.changes:
+ new_change = {}
+ for pkg in change:
+ new_change[pkg.cpv] = change[pkg]
+ self.slot_collision_solutions.append(new_change)
+
+ if self.depgraph._dynamic_config._circular_dependency_handler is not None:
+ handler = self.depgraph._dynamic_config._circular_dependency_handler
+ sol = handler.solutions
+ self.circular_dependency_solutions = dict( zip([x.cpv for x in sol.keys()], sol.values()) )
+
+class ResolverPlaygroundDepcleanResult(object):
+
+ checks = (
+ "success", "cleanlist", "ordered", "req_pkg_count",
+ )
+ optional_checks = (
+ "ordered", "req_pkg_count",
+ )
+
+ def __init__(self, atoms, rval, cleanlist, ordered, req_pkg_count):
+ self.atoms = atoms
+ self.success = rval == 0
+ self.cleanlist = cleanlist
+ self.ordered = ordered
+ self.req_pkg_count = req_pkg_count
diff --git a/portage_with_autodep/pym/portage/tests/resolver/__init__.py b/portage_with_autodep/pym/portage/tests/resolver/__init__.py
new file mode 100644
index 0000000..21a391a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/tests/resolver/__test__ b/portage_with_autodep/pym/portage/tests/resolver/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/__test__
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_autounmask.py b/portage_with_autodep/pym/portage/tests/resolver/test_autounmask.py
new file mode 100644
index 0000000..54c435f
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_autounmask.py
@@ -0,0 +1,326 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class AutounmaskTestCase(TestCase):
+
+ def testAutounmask(self):
+
+ ebuilds = {
+ #ebuilds to test use changes
+ "dev-libs/A-1": { "SLOT": 1, "DEPEND": "dev-libs/B[foo]", "EAPI": 2},
+ "dev-libs/A-2": { "SLOT": 2, "DEPEND": "dev-libs/B[bar]", "EAPI": 2},
+ "dev-libs/B-1": { "DEPEND": "foo? ( dev-libs/C ) bar? ( dev-libs/D )", "IUSE": "foo bar"},
+ "dev-libs/C-1": {},
+ "dev-libs/D-1": {},
+
+ #ebuilds to test if we allow changing of masked or forced flags
+ "dev-libs/E-1": { "SLOT": 1, "DEPEND": "dev-libs/F[masked-flag]", "EAPI": 2},
+ "dev-libs/E-2": { "SLOT": 2, "DEPEND": "dev-libs/G[-forced-flag]", "EAPI": 2},
+ "dev-libs/F-1": { "IUSE": "masked-flag"},
+ "dev-libs/G-1": { "IUSE": "forced-flag"},
+
+ #ebuilds to test keyword changes
+ "app-misc/Z-1": { "KEYWORDS": "~x86", "DEPEND": "app-misc/Y" },
+ "app-misc/Y-1": { "KEYWORDS": "~x86" },
+ "app-misc/W-1": {},
+ "app-misc/W-2": { "KEYWORDS": "~x86" },
+ "app-misc/V-1": { "KEYWORDS": "~x86", "DEPEND": ">=app-misc/W-2"},
+
+ #ebuilds to test mask and keyword changes
+ "app-text/A-1": {},
+ "app-text/B-1": { "KEYWORDS": "~x86" },
+ "app-text/C-1": { "KEYWORDS": "" },
+ "app-text/D-1": { "KEYWORDS": "~x86" },
+ "app-text/D-2": { "KEYWORDS": "" },
+
+ #ebuilds for mixed test for || dep handling
+ "sci-libs/K-1": { "DEPEND": " || ( sci-libs/L[bar] || ( sci-libs/M sci-libs/P ) )", "EAPI": 2},
+ "sci-libs/K-2": { "DEPEND": " || ( sci-libs/L[bar] || ( sci-libs/P sci-libs/M ) )", "EAPI": 2},
+ "sci-libs/K-3": { "DEPEND": " || ( sci-libs/M || ( sci-libs/L[bar] sci-libs/P ) )", "EAPI": 2},
+ "sci-libs/K-4": { "DEPEND": " || ( sci-libs/M || ( sci-libs/P sci-libs/L[bar] ) )", "EAPI": 2},
+ "sci-libs/K-5": { "DEPEND": " || ( sci-libs/P || ( sci-libs/L[bar] sci-libs/M ) )", "EAPI": 2},
+ "sci-libs/K-6": { "DEPEND": " || ( sci-libs/P || ( sci-libs/M sci-libs/L[bar] ) )", "EAPI": 2},
+ "sci-libs/K-7": { "DEPEND": " || ( sci-libs/M sci-libs/L[bar] )", "EAPI": 2},
+ "sci-libs/K-8": { "DEPEND": " || ( sci-libs/L[bar] sci-libs/M )", "EAPI": 2},
+
+ "sci-libs/L-1": { "IUSE": "bar" },
+ "sci-libs/M-1": { "KEYWORDS": "~x86" },
+ "sci-libs/P-1": { },
+
+ #ebuilds to test these nice "required by cat/pkg[foo]" messages
+ "dev-util/Q-1": { "DEPEND": "foo? ( dev-util/R[bar] )", "IUSE": "+foo", "EAPI": 2 },
+ "dev-util/Q-2": { "RDEPEND": "!foo? ( dev-util/R[bar] )", "IUSE": "foo", "EAPI": 2 },
+ "dev-util/R-1": { "IUSE": "bar" },
+
+ #ebuilds to test interaction with REQUIRED_USE
+ "app-portage/A-1": { "DEPEND": "app-portage/B[foo]", "EAPI": 2 },
+ "app-portage/A-2": { "DEPEND": "app-portage/B[foo=]", "IUSE": "+foo", "REQUIRED_USE": "foo", "EAPI": "4" },
+
+ "app-portage/B-1": { "IUSE": "foo +bar", "REQUIRED_USE": "^^ ( foo bar )", "EAPI": "4" },
+ "app-portage/C-1": { "IUSE": "+foo +bar", "REQUIRED_USE": "^^ ( foo bar )", "EAPI": "4" },
+ }
+
+ test_cases = (
+ #Test USE changes.
+ #The simple case.
+
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A:1"],
+ options = {"--autounmask": "n"},
+ success = False),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A:1"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["dev-libs/C-1", "dev-libs/B-1", "dev-libs/A-1"],
+ use_changes = { "dev-libs/B-1": {"foo": True} } ),
+
+ #Make sure we restart if needed.
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A:1", "dev-libs/B"],
+ options = {"--autounmask": True},
+ all_permutations = True,
+ success = False,
+ mergelist = ["dev-libs/C-1", "dev-libs/B-1", "dev-libs/A-1"],
+ use_changes = { "dev-libs/B-1": {"foo": True} } ),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A:1", "dev-libs/A:2", "dev-libs/B"],
+ options = {"--autounmask": True},
+ all_permutations = True,
+ success = False,
+ mergelist = ["dev-libs/D-1", "dev-libs/C-1", "dev-libs/B-1", "dev-libs/A-1", "dev-libs/A-2"],
+ ignore_mergelist_order = True,
+ use_changes = { "dev-libs/B-1": {"foo": True, "bar": True} } ),
+
+ #Test keywording.
+ #The simple case.
+
+ ResolverPlaygroundTestCase(
+ ["app-misc/Z"],
+ options = {"--autounmask": "n"},
+ success = False),
+ ResolverPlaygroundTestCase(
+ ["app-misc/Z"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["app-misc/Y-1", "app-misc/Z-1"],
+ unstable_keywords = ["app-misc/Y-1", "app-misc/Z-1"]),
+
+ #Make sure that the backtracking for slot conflicts handles our mess.
+
+ ResolverPlaygroundTestCase(
+ ["=app-misc/V-1", "app-misc/W"],
+ options = {"--autounmask": True},
+ all_permutations = True,
+ success = False,
+ mergelist = ["app-misc/W-2", "app-misc/V-1"],
+ unstable_keywords = ["app-misc/W-2", "app-misc/V-1"]),
+
+ #Mixed testing
+ #Make sure we don't change use for something in a || dep if there is another choice
+ #that needs no change.
+
+ ResolverPlaygroundTestCase(
+ ["=sci-libs/K-1"],
+ options = {"--autounmask": True},
+ success = True,
+ mergelist = ["sci-libs/P-1", "sci-libs/K-1"]),
+ ResolverPlaygroundTestCase(
+ ["=sci-libs/K-2"],
+ options = {"--autounmask": True},
+ success = True,
+ mergelist = ["sci-libs/P-1", "sci-libs/K-2"]),
+ ResolverPlaygroundTestCase(
+ ["=sci-libs/K-3"],
+ options = {"--autounmask": True},
+ success = True,
+ mergelist = ["sci-libs/P-1", "sci-libs/K-3"]),
+ ResolverPlaygroundTestCase(
+ ["=sci-libs/K-4"],
+ options = {"--autounmask": True},
+ success = True,
+ mergelist = ["sci-libs/P-1", "sci-libs/K-4"]),
+ ResolverPlaygroundTestCase(
+ ["=sci-libs/K-5"],
+ options = {"--autounmask": True},
+ success = True,
+ mergelist = ["sci-libs/P-1", "sci-libs/K-5"]),
+ ResolverPlaygroundTestCase(
+ ["=sci-libs/K-6"],
+ options = {"--autounmask": True},
+ success = True,
+ mergelist = ["sci-libs/P-1", "sci-libs/K-6"]),
+
+ #Make sure we prefer use changes over keyword changes.
+ ResolverPlaygroundTestCase(
+ ["=sci-libs/K-7"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["sci-libs/L-1", "sci-libs/K-7"],
+ use_changes = { "sci-libs/L-1": { "bar": True } }),
+ ResolverPlaygroundTestCase(
+ ["=sci-libs/K-8"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["sci-libs/L-1", "sci-libs/K-8"],
+ use_changes = { "sci-libs/L-1": { "bar": True } }),
+
+ #Test these nice "required by cat/pkg[foo]" messages.
+ ResolverPlaygroundTestCase(
+ ["=dev-util/Q-1"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["dev-util/R-1", "dev-util/Q-1"],
+ use_changes = { "dev-util/R-1": { "bar": True } }),
+ ResolverPlaygroundTestCase(
+ ["=dev-util/Q-2"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["dev-util/R-1", "dev-util/Q-2"],
+ use_changes = { "dev-util/R-1": { "bar": True } }),
+
+ #Test interaction with REQUIRED_USE.
+ ResolverPlaygroundTestCase(
+ ["=app-portage/A-1"],
+ options = { "--autounmask": True },
+ use_changes = None,
+ success = False),
+ ResolverPlaygroundTestCase(
+ ["=app-portage/A-2"],
+ options = { "--autounmask": True },
+ use_changes = None,
+ success = False),
+ ResolverPlaygroundTestCase(
+ ["=app-portage/C-1"],
+ options = { "--autounmask": True },
+ use_changes = None,
+ success = False),
+
+ #Make sure we don't change masked/forced flags.
+ ResolverPlaygroundTestCase(
+ ["dev-libs/E:1"],
+ options = {"--autounmask": True},
+ use_changes = None,
+ success = False),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/E:2"],
+ options = {"--autounmask": True},
+ use_changes = None,
+ success = False),
+
+ #Test mask and keyword changes.
+ ResolverPlaygroundTestCase(
+ ["app-text/A"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["app-text/A-1"],
+ needed_p_mask_changes = ["app-text/A-1"]),
+ ResolverPlaygroundTestCase(
+ ["app-text/B"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["app-text/B-1"],
+ unstable_keywords = ["app-text/B-1"],
+ needed_p_mask_changes = ["app-text/B-1"]),
+ ResolverPlaygroundTestCase(
+ ["app-text/C"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["app-text/C-1"],
+ unstable_keywords = ["app-text/C-1"],
+ needed_p_mask_changes = ["app-text/C-1"]),
+ #Make sure unstable keyword is preferred over missing keyword
+ ResolverPlaygroundTestCase(
+ ["app-text/D"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["app-text/D-1"],
+ unstable_keywords = ["app-text/D-1"]),
+ #Test missing keyword
+ ResolverPlaygroundTestCase(
+ ["=app-text/D-2"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["app-text/D-2"],
+ unstable_keywords = ["app-text/D-2"])
+ )
+
+ profile = {
+ "use.mask":
+ (
+ "masked-flag",
+ ),
+ "use.force":
+ (
+ "forced-flag",
+ ),
+ "package.mask":
+ (
+ "app-text/A",
+ "app-text/B",
+ "app-text/C",
+ ),
+ }
+
+ playground = ResolverPlayground(ebuilds=ebuilds, profile=profile)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
+
+ def testAutounmaskForLicenses(self):
+
+ ebuilds = {
+ "dev-libs/A-1": { "LICENSE": "TEST" },
+ "dev-libs/B-1": { "LICENSE": "TEST", "IUSE": "foo", "KEYWORDS": "~x86"},
+ "dev-libs/C-1": { "DEPEND": "dev-libs/B[foo]", "EAPI": 2 },
+
+ "dev-libs/D-1": { "DEPEND": "dev-libs/E dev-libs/F", "LICENSE": "TEST" },
+ "dev-libs/E-1": { "LICENSE": "TEST" },
+ "dev-libs/E-2": { "LICENSE": "TEST" },
+ "dev-libs/F-1": { "DEPEND": "=dev-libs/E-1", "LICENSE": "TEST" },
+ }
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/A-1"],
+ options = {"--autounmask": 'n'},
+ success = False),
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/A-1"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["dev-libs/A-1"],
+ license_changes = { "dev-libs/A-1": set(["TEST"]) }),
+
+ #Test license+keyword+use change at once.
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/C-1"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["dev-libs/B-1", "dev-libs/C-1"],
+ license_changes = { "dev-libs/B-1": set(["TEST"]) },
+ unstable_keywords = ["dev-libs/B-1"],
+ use_changes = { "dev-libs/B-1": { "foo": True } }),
+
+ #Test license with backtracking.
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/D-1"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["dev-libs/E-1", "dev-libs/F-1", "dev-libs/D-1"],
+ license_changes = { "dev-libs/D-1": set(["TEST"]), "dev-libs/E-1": set(["TEST"]), "dev-libs/E-2": set(["TEST"]), "dev-libs/F-1": set(["TEST"]) }),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_backtracking.py b/portage_with_autodep/pym/portage/tests/resolver/test_backtracking.py
new file mode 100644
index 0000000..fc49306
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_backtracking.py
@@ -0,0 +1,169 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class BacktrackingTestCase(TestCase):
+
+ def testBacktracking(self):
+ ebuilds = {
+ "dev-libs/A-1": {},
+ "dev-libs/A-2": {},
+ "dev-libs/B-1": { "DEPEND": "dev-libs/A" },
+ }
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/A-1", "dev-libs/B"],
+ all_permutations = True,
+ mergelist = ["dev-libs/A-1", "dev-libs/B-1"],
+ success = True),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds)
+
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
+
+
+ def testHittingTheBacktrackLimit(self):
+ ebuilds = {
+ "dev-libs/A-1": {},
+ "dev-libs/A-2": {},
+ "dev-libs/B-1": {},
+ "dev-libs/B-2": {},
+ "dev-libs/C-1": { "DEPEND": "dev-libs/A dev-libs/B" },
+ "dev-libs/D-1": { "DEPEND": "=dev-libs/A-1 =dev-libs/B-1" },
+ }
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["dev-libs/C", "dev-libs/D"],
+ all_permutations = True,
+ mergelist = ["dev-libs/A-1", "dev-libs/B-1", "dev-libs/C-1", "dev-libs/D-1"],
+ ignore_mergelist_order = True,
+ success = True),
+ #This one hits the backtrack limit. Be aware that this depends on the argument order.
+ ResolverPlaygroundTestCase(
+ ["dev-libs/D", "dev-libs/C"],
+ options = { "--backtrack": 1 },
+ mergelist = ["dev-libs/A-1", "dev-libs/B-1", "dev-libs/A-2", "dev-libs/B-2", "dev-libs/C-1", "dev-libs/D-1"],
+ ignore_mergelist_order = True,
+ slot_collision_solutions = [],
+ success = False),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds)
+
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
+
+
+ def testBacktrackingGoodVersionFirst(self):
+ """
+ When backtracking due to slot conflicts, we masked the version that has been pulled
+ in first. This is not always a good idea. Mask the highest version instead.
+ """
+
+ ebuilds = {
+ "dev-libs/A-1": { "DEPEND": "=dev-libs/C-1 dev-libs/B" },
+ "dev-libs/B-1": { "DEPEND": "=dev-libs/C-1" },
+ "dev-libs/B-2": { "DEPEND": "=dev-libs/C-2" },
+ "dev-libs/C-1": { },
+ "dev-libs/C-2": { },
+ }
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A"],
+ mergelist = ["dev-libs/C-1", "dev-libs/B-1", "dev-libs/A-1", ],
+ success = True),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds)
+
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
+
+ def testBacktrackWithoutUpdates(self):
+ """
+ If --update is not given we might have to mask the old installed version later.
+ """
+
+ ebuilds = {
+ "dev-libs/A-1": { "DEPEND": "dev-libs/Z" },
+ "dev-libs/B-1": { "DEPEND": ">=dev-libs/Z-2" },
+ "dev-libs/Z-1": { },
+ "dev-libs/Z-2": { },
+ }
+
+ installed = {
+ "dev-libs/Z-1": { "USE": "" },
+ }
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["dev-libs/B", "dev-libs/A"],
+ all_permutations = True,
+ mergelist = ["dev-libs/Z-2", "dev-libs/B-1", "dev-libs/A-1", ],
+ ignore_mergelist_order = True,
+ success = True),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)
+
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
+
+ def testBacktrackMissedUpdates(self):
+ """
+ An update is missed due to a dependency on an older version.
+ """
+
+ ebuilds = {
+ "dev-libs/A-1": { },
+ "dev-libs/A-2": { },
+ "dev-libs/B-1": { "RDEPEND": "<=dev-libs/A-1" },
+ }
+
+ installed = {
+ "dev-libs/A-1": { "USE": "" },
+ "dev-libs/B-1": { "USE": "", "RDEPEND": "<=dev-libs/A-1" },
+ }
+
+ options = {'--update' : True, '--deep' : True, '--selective' : True}
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A", "dev-libs/B"],
+ options = options,
+ all_permutations = True,
+ mergelist = [],
+ success = True),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)
+
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_circular_dependencies.py b/portage_with_autodep/pym/portage/tests/resolver/test_circular_dependencies.py
new file mode 100644
index 0000000..f8331ac
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_circular_dependencies.py
@@ -0,0 +1,84 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class CircularDependencyTestCase(TestCase):
+
+ #TODO:
+ # use config change by autounmask
+ # conflict on parent's parent
+ # difference in RDEPEND and DEPEND
+ # is there anything else than priority buildtime and runtime?
+ # play with use.{mask,force}
+ # play with REQUIRED_USE
+
+
+ def testCircularDependency(self):
+
+ ebuilds = {
+ "dev-libs/Z-1": { "DEPEND": "foo? ( !bar? ( dev-libs/Y ) )", "IUSE": "+foo bar", "EAPI": 1 },
+ "dev-libs/Z-2": { "DEPEND": "foo? ( dev-libs/Y ) !bar? ( dev-libs/Y )", "IUSE": "+foo bar", "EAPI": 1 },
+ "dev-libs/Z-3": { "DEPEND": "foo? ( !bar? ( dev-libs/Y ) ) foo? ( dev-libs/Y ) !bar? ( dev-libs/Y )", "IUSE": "+foo bar", "EAPI": 1 },
+ "dev-libs/Y-1": { "DEPEND": "dev-libs/Z" },
+ "dev-libs/W-1": { "DEPEND": "dev-libs/Z[foo] dev-libs/Y", "EAPI": 2 },
+ "dev-libs/W-2": { "DEPEND": "dev-libs/Z[foo=] dev-libs/Y", "IUSE": "+foo", "EAPI": 2 },
+ "dev-libs/W-3": { "DEPEND": "dev-libs/Z[bar] dev-libs/Y", "EAPI": 2 },
+
+ "app-misc/A-1": { "DEPEND": "foo? ( =app-misc/B-1 )", "IUSE": "+foo bar", "REQUIRED_USE": "^^ ( foo bar )", "EAPI": "4" },
+ "app-misc/A-2": { "DEPEND": "foo? ( =app-misc/B-2 ) bar? ( =app-misc/B-2 )", "IUSE": "+foo bar", "REQUIRED_USE": "^^ ( foo bar )", "EAPI": "4" },
+ "app-misc/B-1": { "DEPEND": "=app-misc/A-1" },
+ "app-misc/B-2": { "DEPEND": "=app-misc/A-2" },
+ }
+
+ test_cases = (
+ #Simple tests
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/Z-1"],
+ circular_dependency_solutions = { "dev-libs/Y-1": frozenset([frozenset([("foo", False)]), frozenset([("bar", True)])])},
+ success = False),
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/Z-2"],
+ circular_dependency_solutions = { "dev-libs/Y-1": frozenset([frozenset([("foo", False), ("bar", True)])])},
+ success = False),
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/Z-3"],
+ circular_dependency_solutions = { "dev-libs/Y-1": frozenset([frozenset([("foo", False), ("bar", True)])])},
+ success = False),
+
+ #Conflict on parent
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/W-1"],
+ circular_dependency_solutions = {},
+ success = False),
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/W-2"],
+ circular_dependency_solutions = { "dev-libs/Y-1": frozenset([frozenset([("foo", False), ("bar", True)])])},
+ success = False),
+
+ #Conflict with autounmask
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/W-3"],
+ circular_dependency_solutions = { "dev-libs/Y-1": frozenset([frozenset([("foo", False)])])},
+ use_changes = { "dev-libs/Z-3": {"bar": True}},
+ success = False),
+
+ #Conflict with REQUIRED_USE
+ ResolverPlaygroundTestCase(
+ ["=app-misc/B-1"],
+ circular_dependency_solutions = { "app-misc/B-1": frozenset([frozenset([("foo", False), ("bar", True)])])},
+ success = False),
+ ResolverPlaygroundTestCase(
+ ["=app-misc/B-2"],
+ circular_dependency_solutions = {},
+ success = False),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_depclean.py b/portage_with_autodep/pym/portage/tests/resolver/test_depclean.py
new file mode 100644
index 0000000..ba70144
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_depclean.py
@@ -0,0 +1,285 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class SimpleDepcleanTestCase(TestCase):
+
+ def testSimpleDepclean(self):
+ ebuilds = {
+ "dev-libs/A-1": {},
+ "dev-libs/B-1": {},
+ }
+ installed = {
+ "dev-libs/A-1": {},
+ "dev-libs/B-1": {},
+ }
+
+ world = (
+ "dev-libs/A",
+ )
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ [],
+ options = {"--depclean": True},
+ success = True,
+ cleanlist = ["dev-libs/B-1"]),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds, installed=installed, world=world)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
+
+class DepcleanWithDepsTestCase(TestCase):
+
+ def testDepcleanWithDeps(self):
+ ebuilds = {
+ "dev-libs/A-1": { "RDEPEND": "dev-libs/C" },
+ "dev-libs/B-1": { "RDEPEND": "dev-libs/D" },
+ "dev-libs/C-1": {},
+ "dev-libs/D-1": { "RDEPEND": "dev-libs/E" },
+ "dev-libs/E-1": { "RDEPEND": "dev-libs/F" },
+ "dev-libs/F-1": {},
+ }
+ installed = {
+ "dev-libs/A-1": { "RDEPEND": "dev-libs/C" },
+ "dev-libs/B-1": { "RDEPEND": "dev-libs/D" },
+ "dev-libs/C-1": {},
+ "dev-libs/D-1": { "RDEPEND": "dev-libs/E" },
+ "dev-libs/E-1": { "RDEPEND": "dev-libs/F" },
+ "dev-libs/F-1": {},
+ }
+
+ world = (
+ "dev-libs/A",
+ )
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ [],
+ options = {"--depclean": True},
+ success = True,
+ cleanlist = ["dev-libs/B-1", "dev-libs/D-1",
+ "dev-libs/E-1", "dev-libs/F-1"]),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds, installed=installed, world=world)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
+
+
+class DepcleanWithInstalledMaskedTestCase(TestCase):
+
+ def testDepcleanWithInstalledMasked(self):
+ """
+ Test case for bug 332719.
+ emerge --declean ignores that B is masked by license and removes C.
+ The next emerge -uDN world doesn't take B and installs C again.
+ """
+ ebuilds = {
+ "dev-libs/A-1": { "RDEPEND": "|| ( dev-libs/B dev-libs/C )" },
+ "dev-libs/B-1": { "LICENSE": "TEST", "KEYWORDS": "x86" },
+ "dev-libs/C-1": { "KEYWORDS": "x86" },
+ }
+ installed = {
+ "dev-libs/A-1": { "RDEPEND": "|| ( dev-libs/B dev-libs/C )" },
+ "dev-libs/B-1": { "LICENSE": "TEST", "KEYWORDS": "x86" },
+ "dev-libs/C-1": { "KEYWORDS": "x86" },
+ }
+
+ world = (
+ "dev-libs/A",
+ )
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ [],
+ options = {"--depclean": True},
+ success = True,
+ #cleanlist = ["dev-libs/C-1"]),
+ cleanlist = ["dev-libs/B-1"]),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds, installed=installed, world=world)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
+
+class DepcleanInstalledKeywordMaskedSlotTestCase(TestCase):
+
+ def testDepcleanInstalledKeywordMaskedSlot(self):
+ """
+ Verify that depclean removes newer slot
+ masked by KEYWORDS (see bug #350285).
+ """
+ ebuilds = {
+ "dev-libs/A-1": { "RDEPEND": "|| ( =dev-libs/B-2.7* =dev-libs/B-2.6* )" },
+ "dev-libs/B-2.6": { "SLOT":"2.6", "KEYWORDS": "x86" },
+ "dev-libs/B-2.7": { "SLOT":"2.7", "KEYWORDS": "~x86" },
+ }
+ installed = {
+ "dev-libs/A-1": { "EAPI" : "3", "RDEPEND": "|| ( dev-libs/B:2.7 dev-libs/B:2.6 )" },
+ "dev-libs/B-2.6": { "SLOT":"2.6", "KEYWORDS": "x86" },
+ "dev-libs/B-2.7": { "SLOT":"2.7", "KEYWORDS": "~x86" },
+ }
+
+ world = (
+ "dev-libs/A",
+ )
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ [],
+ options = {"--depclean": True},
+ success = True,
+ cleanlist = ["dev-libs/B-2.7"]),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds, installed=installed, world=world)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
+
+class DepcleanWithExcludeTestCase(TestCase):
+
+ def testDepcleanWithExclude(self):
+
+ installed = {
+ "dev-libs/A-1": {},
+ "dev-libs/B-1": { "RDEPEND": "dev-libs/A" },
+ }
+
+ test_cases = (
+ #Without --exclude.
+ ResolverPlaygroundTestCase(
+ [],
+ options = {"--depclean": True},
+ success = True,
+ cleanlist = ["dev-libs/B-1", "dev-libs/A-1"]),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A"],
+ options = {"--depclean": True},
+ success = True,
+ cleanlist = []),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/B"],
+ options = {"--depclean": True},
+ success = True,
+ cleanlist = ["dev-libs/B-1"]),
+
+ #With --exclude
+ ResolverPlaygroundTestCase(
+ [],
+ options = {"--depclean": True, "--exclude": ["dev-libs/A"]},
+ success = True,
+ cleanlist = ["dev-libs/B-1"]),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/B"],
+ options = {"--depclean": True, "--exclude": ["dev-libs/B"]},
+ success = True,
+ cleanlist = []),
+ )
+
+ playground = ResolverPlayground(installed=installed)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
+
+class DepcleanWithExcludeAndSlotsTestCase(TestCase):
+
+ def testDepcleanWithExcludeAndSlots(self):
+
+ installed = {
+ "dev-libs/Z-1": { "SLOT": 1},
+ "dev-libs/Z-2": { "SLOT": 2},
+ "dev-libs/Y-1": { "RDEPEND": "=dev-libs/Z-1", "SLOT": 1 },
+ "dev-libs/Y-2": { "RDEPEND": "=dev-libs/Z-2", "SLOT": 2 },
+ }
+
+ world = [ "dev-libs/Y" ]
+
+ test_cases = (
+ #Without --exclude.
+ ResolverPlaygroundTestCase(
+ [],
+ options = {"--depclean": True},
+ success = True,
+ cleanlist = ["dev-libs/Y-1", "dev-libs/Z-1"]),
+ ResolverPlaygroundTestCase(
+ [],
+ options = {"--depclean": True, "--exclude": ["dev-libs/Z"]},
+ success = True,
+ cleanlist = ["dev-libs/Y-1"]),
+ ResolverPlaygroundTestCase(
+ [],
+ options = {"--depclean": True, "--exclude": ["dev-libs/Y"]},
+ success = True,
+ cleanlist = []),
+ )
+
+ playground = ResolverPlayground(installed=installed, world=world)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
+
+class DepcleanAndWildcardsTestCase(TestCase):
+
+ def testDepcleanAndWildcards(self):
+
+ installed = {
+ "dev-libs/A-1": { "RDEPEND": "dev-libs/B" },
+ "dev-libs/B-1": {},
+ }
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["*/*"],
+ options = {"--depclean": True},
+ success = True,
+ cleanlist = ["dev-libs/A-1", "dev-libs/B-1"]),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/*"],
+ options = {"--depclean": True},
+ success = True,
+ cleanlist = ["dev-libs/A-1", "dev-libs/B-1"]),
+ ResolverPlaygroundTestCase(
+ ["*/A"],
+ options = {"--depclean": True},
+ success = True,
+ cleanlist = ["dev-libs/A-1"]),
+ ResolverPlaygroundTestCase(
+ ["*/B"],
+ options = {"--depclean": True},
+ success = True,
+ cleanlist = []),
+ )
+
+ playground = ResolverPlayground(installed=installed)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_depth.py b/portage_with_autodep/pym/portage/tests/resolver/test_depth.py
new file mode 100644
index 0000000..cb1e2dd
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_depth.py
@@ -0,0 +1,252 @@
+# Copyright 2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+ ResolverPlaygroundTestCase)
+
+class ResolverDepthTestCase(TestCase):
+
+ def testResolverDepth(self):
+
+ ebuilds = {
+ "dev-libs/A-1": {"RDEPEND" : "dev-libs/B"},
+ "dev-libs/A-2": {"RDEPEND" : "dev-libs/B"},
+ "dev-libs/B-1": {"RDEPEND" : "dev-libs/C"},
+ "dev-libs/B-2": {"RDEPEND" : "dev-libs/C"},
+ "dev-libs/C-1": {},
+ "dev-libs/C-2": {},
+
+ "virtual/libusb-0" : {"EAPI" :"2", "SLOT" : "0", "RDEPEND" : "|| ( >=dev-libs/libusb-0.1.12-r1:0 dev-libs/libusb-compat >=sys-freebsd/freebsd-lib-8.0[usb] )"},
+ "virtual/libusb-1" : {"EAPI" :"2", "SLOT" : "1", "RDEPEND" : ">=dev-libs/libusb-1.0.4:1"},
+ "dev-libs/libusb-0.1.13" : {},
+ "dev-libs/libusb-1.0.5" : {"SLOT":"1"},
+ "dev-libs/libusb-compat-1" : {},
+ "sys-freebsd/freebsd-lib-8": {"IUSE" : "+usb"},
+
+ "sys-fs/udev-164" : {"EAPI" : "1", "RDEPEND" : "virtual/libusb:0"},
+
+ "virtual/jre-1.5.0" : {"SLOT" : "1.5", "RDEPEND" : "|| ( =dev-java/sun-jre-bin-1.5.0* =virtual/jdk-1.5.0* )"},
+ "virtual/jre-1.5.0-r1" : {"SLOT" : "1.5", "RDEPEND" : "|| ( =dev-java/sun-jre-bin-1.5.0* =virtual/jdk-1.5.0* )"},
+ "virtual/jre-1.6.0" : {"SLOT" : "1.6", "RDEPEND" : "|| ( =dev-java/sun-jre-bin-1.6.0* =virtual/jdk-1.6.0* )"},
+ "virtual/jre-1.6.0-r1" : {"SLOT" : "1.6", "RDEPEND" : "|| ( =dev-java/sun-jre-bin-1.6.0* =virtual/jdk-1.6.0* )"},
+ "virtual/jdk-1.5.0" : {"SLOT" : "1.5", "RDEPEND" : "|| ( =dev-java/sun-jdk-1.5.0* dev-java/gcj-jdk )"},
+ "virtual/jdk-1.5.0-r1" : {"SLOT" : "1.5", "RDEPEND" : "|| ( =dev-java/sun-jdk-1.5.0* dev-java/gcj-jdk )"},
+ "virtual/jdk-1.6.0" : {"SLOT" : "1.6", "RDEPEND" : "|| ( =dev-java/icedtea-6* =dev-java/sun-jdk-1.6.0* )"},
+ "virtual/jdk-1.6.0-r1" : {"SLOT" : "1.6", "RDEPEND" : "|| ( =dev-java/icedtea-6* =dev-java/sun-jdk-1.6.0* )"},
+ "dev-java/gcj-jdk-4.5" : {},
+ "dev-java/gcj-jdk-4.5-r1" : {},
+ "dev-java/icedtea-6.1" : {},
+ "dev-java/icedtea-6.1-r1" : {},
+ "dev-java/sun-jdk-1.5" : {"SLOT" : "1.5"},
+ "dev-java/sun-jdk-1.6" : {"SLOT" : "1.6"},
+ "dev-java/sun-jre-bin-1.5" : {"SLOT" : "1.5"},
+ "dev-java/sun-jre-bin-1.6" : {"SLOT" : "1.6"},
+
+ "dev-java/ant-core-1.8" : {"DEPEND" : ">=virtual/jdk-1.4"},
+ "dev-db/hsqldb-1.8" : {"RDEPEND" : ">=virtual/jre-1.6"},
+ }
+
+ installed = {
+ "dev-libs/A-1": {"RDEPEND" : "dev-libs/B"},
+ "dev-libs/B-1": {"RDEPEND" : "dev-libs/C"},
+ "dev-libs/C-1": {},
+
+ "virtual/jre-1.5.0" : {"SLOT" : "1.5", "RDEPEND" : "|| ( =virtual/jdk-1.5.0* =dev-java/sun-jre-bin-1.5.0* )"},
+ "virtual/jre-1.6.0" : {"SLOT" : "1.6", "RDEPEND" : "|| ( =virtual/jdk-1.6.0* =dev-java/sun-jre-bin-1.6.0* )"},
+ "virtual/jdk-1.5.0" : {"SLOT" : "1.5", "RDEPEND" : "|| ( =dev-java/sun-jdk-1.5.0* dev-java/gcj-jdk )"},
+ "virtual/jdk-1.6.0" : {"SLOT" : "1.6", "RDEPEND" : "|| ( =dev-java/icedtea-6* =dev-java/sun-jdk-1.6.0* )"},
+ "dev-java/gcj-jdk-4.5" : {},
+ "dev-java/icedtea-6.1" : {},
+
+ "virtual/libusb-0" : {"EAPI" :"2", "SLOT" : "0", "RDEPEND" : "|| ( >=dev-libs/libusb-0.1.12-r1:0 dev-libs/libusb-compat >=sys-freebsd/freebsd-lib-8.0[usb] )"},
+ }
+
+ world = ["dev-libs/A"]
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A"],
+ options = {"--update": True, "--deep": 0},
+ success = True,
+ mergelist = ["dev-libs/A-2"]),
+
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A"],
+ options = {"--update": True, "--deep": 1},
+ success = True,
+ mergelist = ["dev-libs/B-2", "dev-libs/A-2"]),
+
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A"],
+ options = {"--update": True, "--deep": 2},
+ success = True,
+ mergelist = ["dev-libs/C-2", "dev-libs/B-2", "dev-libs/A-2"]),
+
+ ResolverPlaygroundTestCase(
+ ["@world"],
+ options = {"--update": True, "--deep": True},
+ success = True,
+ mergelist = ["dev-libs/C-2", "dev-libs/B-2", "dev-libs/A-2"]),
+
+ ResolverPlaygroundTestCase(
+ ["@world"],
+ options = {"--emptytree": True},
+ success = True,
+ mergelist = ["dev-libs/C-2", "dev-libs/B-2", "dev-libs/A-2"]),
+
+ ResolverPlaygroundTestCase(
+ ["@world"],
+ options = {"--selective": True, "--deep": True},
+ success = True,
+ mergelist = []),
+
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A"],
+ options = {"--deep": 2},
+ success = True,
+ mergelist = ["dev-libs/A-2"]),
+
+ ResolverPlaygroundTestCase(
+ ["virtual/jre"],
+ options = {},
+ success = True,
+ mergelist = ['virtual/jre-1.6.0-r1']),
+
+ ResolverPlaygroundTestCase(
+ ["virtual/jre"],
+ options = {"--deep" : True},
+ success = True,
+ mergelist = ['virtual/jre-1.6.0-r1']),
+
+ # Test bug #141118, where we avoid pulling in
+ # redundant deps, satisfying nested virtuals
+ # as efficiently as possible.
+ ResolverPlaygroundTestCase(
+ ["virtual/jre"],
+ options = {"--selective" : True, "--deep" : True},
+ success = True,
+ mergelist = []),
+
+ # Test bug #150361, where depgraph._greedy_slots()
+ # is triggered by --update with AtomArg.
+ ResolverPlaygroundTestCase(
+ ["virtual/jre"],
+ options = {"--update" : True},
+ success = True,
+ ambiguous_merge_order = True,
+ mergelist = [('virtual/jre-1.6.0-r1', 'virtual/jre-1.5.0-r1')]),
+
+ # Recursively traversed virtual dependencies, and their
+ # direct dependencies, are considered to have the same
+ # depth as direct dependencies.
+ ResolverPlaygroundTestCase(
+ ["virtual/jre"],
+ options = {"--update" : True, "--deep" : 1},
+ success = True,
+ ambiguous_merge_order = True,
+ merge_order_assertions=(('dev-java/icedtea-6.1-r1', 'virtual/jdk-1.6.0-r1'), ('virtual/jdk-1.6.0-r1', 'virtual/jre-1.6.0-r1'),
+ ('dev-java/gcj-jdk-4.5-r1', 'virtual/jdk-1.5.0-r1'), ('virtual/jdk-1.5.0-r1', 'virtual/jre-1.5.0-r1')),
+ mergelist = [('dev-java/icedtea-6.1-r1', 'dev-java/gcj-jdk-4.5-r1', 'virtual/jdk-1.6.0-r1', 'virtual/jdk-1.5.0-r1', 'virtual/jre-1.6.0-r1', 'virtual/jre-1.5.0-r1')]),
+
+ ResolverPlaygroundTestCase(
+ ["virtual/jre:1.5"],
+ options = {"--update" : True},
+ success = True,
+ mergelist = ['virtual/jre-1.5.0-r1']),
+
+ ResolverPlaygroundTestCase(
+ ["virtual/jre:1.6"],
+ options = {"--update" : True},
+ success = True,
+ mergelist = ['virtual/jre-1.6.0-r1']),
+
+ # Test that we don't pull in any unnecessary updates
+ # when --update is not specified, even though we
+ # specified --deep.
+ ResolverPlaygroundTestCase(
+ ["dev-java/ant-core"],
+ options = {"--deep" : True},
+ success = True,
+ mergelist = ["dev-java/ant-core-1.8"]),
+
+ ResolverPlaygroundTestCase(
+ ["dev-java/ant-core"],
+ options = {"--update" : True},
+ success = True,
+ mergelist = ["dev-java/ant-core-1.8"]),
+
+ # Recursively traversed virtual dependencies, and their
+ # direct dependencies, are considered to have the same
+ # depth as direct dependencies.
+ ResolverPlaygroundTestCase(
+ ["dev-java/ant-core"],
+ options = {"--update" : True, "--deep" : 1},
+ success = True,
+ mergelist = ['dev-java/icedtea-6.1-r1', 'virtual/jdk-1.6.0-r1', 'dev-java/ant-core-1.8']),
+
+ ResolverPlaygroundTestCase(
+ ["dev-db/hsqldb"],
+ options = {"--deep" : True},
+ success = True,
+ mergelist = ["dev-db/hsqldb-1.8"]),
+
+ # Don't traverse deps of an installed package with --deep=0,
+ # even if it's a virtual.
+ ResolverPlaygroundTestCase(
+ ["virtual/libusb:0"],
+ options = {"--selective" : True, "--deep" : 0},
+ success = True,
+ mergelist = []),
+
+ # Satisfy unsatisfied dep of installed package with --deep=1.
+ ResolverPlaygroundTestCase(
+ ["virtual/libusb:0"],
+ options = {"--selective" : True, "--deep" : 1},
+ success = True,
+ mergelist = ['dev-libs/libusb-0.1.13']),
+
+ # Pull in direct dep of virtual, even with --deep=0.
+ ResolverPlaygroundTestCase(
+ ["sys-fs/udev"],
+ options = {"--deep" : 0},
+ success = True,
+ mergelist = ['dev-libs/libusb-0.1.13', 'sys-fs/udev-164']),
+
+ # Test --nodeps with direct virtual deps.
+ ResolverPlaygroundTestCase(
+ ["sys-fs/udev"],
+ options = {"--nodeps" : True},
+ success = True,
+ mergelist = ["sys-fs/udev-164"]),
+
+ # Test that --nodeps overrides --deep.
+ ResolverPlaygroundTestCase(
+ ["sys-fs/udev"],
+ options = {"--nodeps" : True, "--deep" : True},
+ success = True,
+ mergelist = ["sys-fs/udev-164"]),
+
+ # Test that --nodeps overrides --emptytree.
+ ResolverPlaygroundTestCase(
+ ["sys-fs/udev"],
+ options = {"--nodeps" : True, "--emptytree" : True},
+ success = True,
+ mergelist = ["sys-fs/udev-164"]),
+
+ # Test --emptytree with virtuals.
+ ResolverPlaygroundTestCase(
+ ["sys-fs/udev"],
+ options = {"--emptytree" : True},
+ success = True,
+ mergelist = ['dev-libs/libusb-0.1.13', 'virtual/libusb-0', 'sys-fs/udev-164']),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds, installed=installed,
+ world=world)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_eapi.py b/portage_with_autodep/pym/portage/tests/resolver/test_eapi.py
new file mode 100644
index 0000000..525b585
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_eapi.py
@@ -0,0 +1,115 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class EAPITestCase(TestCase):
+
+ def testEAPI(self):
+
+ ebuilds = {
+ #EAPI-1: IUSE-defaults
+ "dev-libs/A-1.0": { "EAPI": 0, "IUSE": "+foo" },
+ "dev-libs/A-1.1": { "EAPI": 1, "IUSE": "+foo" },
+ "dev-libs/A-1.2": { "EAPI": 2, "IUSE": "+foo" },
+ "dev-libs/A-1.3": { "EAPI": 3, "IUSE": "+foo" },
+ "dev-libs/A-1.4": { "EAPI": "4", "IUSE": "+foo" },
+
+ #EAPI-1: slot deps
+ "dev-libs/A-2.0": { "EAPI": 0, "DEPEND": "dev-libs/B:0" },
+ "dev-libs/A-2.1": { "EAPI": 1, "DEPEND": "dev-libs/B:0" },
+ "dev-libs/A-2.2": { "EAPI": 2, "DEPEND": "dev-libs/B:0" },
+ "dev-libs/A-2.3": { "EAPI": 3, "DEPEND": "dev-libs/B:0" },
+ "dev-libs/A-2.4": { "EAPI": "4", "DEPEND": "dev-libs/B:0" },
+
+ #EAPI-2: use deps
+ "dev-libs/A-3.0": { "EAPI": 0, "DEPEND": "dev-libs/B[foo]" },
+ "dev-libs/A-3.1": { "EAPI": 1, "DEPEND": "dev-libs/B[foo]" },
+ "dev-libs/A-3.2": { "EAPI": 2, "DEPEND": "dev-libs/B[foo]" },
+ "dev-libs/A-3.3": { "EAPI": 3, "DEPEND": "dev-libs/B[foo]" },
+ "dev-libs/A-3.4": { "EAPI": "4", "DEPEND": "dev-libs/B[foo]" },
+
+ #EAPI-2: strong blocks
+ "dev-libs/A-4.0": { "EAPI": 0, "DEPEND": "!!dev-libs/B" },
+ "dev-libs/A-4.1": { "EAPI": 1, "DEPEND": "!!dev-libs/B" },
+ "dev-libs/A-4.2": { "EAPI": 2, "DEPEND": "!!dev-libs/B" },
+ "dev-libs/A-4.3": { "EAPI": 3, "DEPEND": "!!dev-libs/B" },
+ "dev-libs/A-4.4": { "EAPI": "4", "DEPEND": "!!dev-libs/B" },
+
+ #EAPI-4: slot operator deps
+ #~ "dev-libs/A-5.0": { "EAPI": 0, "DEPEND": "dev-libs/B:*" },
+ #~ "dev-libs/A-5.1": { "EAPI": 1, "DEPEND": "dev-libs/B:*" },
+ #~ "dev-libs/A-5.2": { "EAPI": 2, "DEPEND": "dev-libs/B:*" },
+ #~ "dev-libs/A-5.3": { "EAPI": 3, "DEPEND": "dev-libs/B:*" },
+ #~ "dev-libs/A-5.4": { "EAPI": "4", "DEPEND": "dev-libs/B:*" },
+
+ #EAPI-4: use dep defaults
+ "dev-libs/A-6.0": { "EAPI": 0, "DEPEND": "dev-libs/B[bar(+)]" },
+ "dev-libs/A-6.1": { "EAPI": 1, "DEPEND": "dev-libs/B[bar(+)]" },
+ "dev-libs/A-6.2": { "EAPI": 2, "DEPEND": "dev-libs/B[bar(+)]" },
+ "dev-libs/A-6.3": { "EAPI": 3, "DEPEND": "dev-libs/B[bar(+)]" },
+ "dev-libs/A-6.4": { "EAPI": "4", "DEPEND": "dev-libs/B[bar(+)]" },
+
+ #EAPI-4: REQUIRED_USE
+ "dev-libs/A-7.0": { "EAPI": 0, "IUSE": "foo bar", "REQUIRED_USE": "|| ( foo bar )" },
+ "dev-libs/A-7.1": { "EAPI": 1, "IUSE": "foo +bar", "REQUIRED_USE": "|| ( foo bar )" },
+ "dev-libs/A-7.2": { "EAPI": 2, "IUSE": "foo +bar", "REQUIRED_USE": "|| ( foo bar )" },
+ "dev-libs/A-7.3": { "EAPI": 3, "IUSE": "foo +bar", "REQUIRED_USE": "|| ( foo bar )" },
+ "dev-libs/A-7.4": { "EAPI": "4", "IUSE": "foo +bar", "REQUIRED_USE": "|| ( foo bar )" },
+
+ "dev-libs/B-1": {"EAPI": 1, "IUSE": "+foo"},
+ }
+
+ test_cases = (
+ ResolverPlaygroundTestCase(["=dev-libs/A-1.0"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-1.1"], success = True, mergelist = ["dev-libs/A-1.1"]),
+ ResolverPlaygroundTestCase(["=dev-libs/A-1.2"], success = True, mergelist = ["dev-libs/A-1.2"]),
+ ResolverPlaygroundTestCase(["=dev-libs/A-1.3"], success = True, mergelist = ["dev-libs/A-1.3"]),
+ ResolverPlaygroundTestCase(["=dev-libs/A-1.4"], success = True, mergelist = ["dev-libs/A-1.4"]),
+
+ ResolverPlaygroundTestCase(["=dev-libs/A-2.0"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-2.1"], success = True, mergelist = ["dev-libs/B-1", "dev-libs/A-2.1"]),
+ ResolverPlaygroundTestCase(["=dev-libs/A-2.2"], success = True, mergelist = ["dev-libs/B-1", "dev-libs/A-2.2"]),
+ ResolverPlaygroundTestCase(["=dev-libs/A-2.3"], success = True, mergelist = ["dev-libs/B-1", "dev-libs/A-2.3"]),
+ ResolverPlaygroundTestCase(["=dev-libs/A-2.4"], success = True, mergelist = ["dev-libs/B-1", "dev-libs/A-2.4"]),
+
+ ResolverPlaygroundTestCase(["=dev-libs/A-3.0"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-3.1"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-3.2"], success = True, mergelist = ["dev-libs/B-1", "dev-libs/A-3.2"]),
+ ResolverPlaygroundTestCase(["=dev-libs/A-3.3"], success = True, mergelist = ["dev-libs/B-1", "dev-libs/A-3.3"]),
+ ResolverPlaygroundTestCase(["=dev-libs/A-3.4"], success = True, mergelist = ["dev-libs/B-1", "dev-libs/A-3.4"]),
+
+ ResolverPlaygroundTestCase(["=dev-libs/A-4.0"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-4.1"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-4.2"], success = True, mergelist = ["dev-libs/A-4.2"]),
+ ResolverPlaygroundTestCase(["=dev-libs/A-4.3"], success = True, mergelist = ["dev-libs/A-4.3"]),
+ ResolverPlaygroundTestCase(["=dev-libs/A-4.4"], success = True, mergelist = ["dev-libs/A-4.4"]),
+
+ ResolverPlaygroundTestCase(["=dev-libs/A-5.0"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-5.1"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-5.2"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-5.3"], success = False),
+ # not implemented: EAPI-4: slot operator deps
+ #~ ResolverPlaygroundTestCase(["=dev-libs/A-5.4"], success = True, mergelist = ["dev-libs/B-1", "dev-libs/A-5.4"]),
+
+ ResolverPlaygroundTestCase(["=dev-libs/A-6.0"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-6.1"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-6.2"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-6.3"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-6.4"], success = True, mergelist = ["dev-libs/B-1", "dev-libs/A-6.4"]),
+
+ ResolverPlaygroundTestCase(["=dev-libs/A-7.0"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-7.1"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-7.2"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-7.3"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-7.4"], success = True, mergelist = ["dev-libs/A-7.4"]),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_merge_order.py b/portage_with_autodep/pym/portage/tests/resolver/test_merge_order.py
new file mode 100644
index 0000000..0a52c81
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_merge_order.py
@@ -0,0 +1,453 @@
+# Copyright 2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import portage
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+ ResolverPlaygroundTestCase)
+
+class MergeOrderTestCase(TestCase):
+
+ def testMergeOrder(self):
+ ebuilds = {
+ "app-misc/blocker-buildtime-a-1" : {},
+ "app-misc/blocker-buildtime-unbuilt-a-1" : {
+ "DEPEND" : "!app-misc/installed-blocker-a",
+ },
+ "app-misc/blocker-buildtime-unbuilt-hard-a-1" : {
+ "EAPI" : "2",
+ "DEPEND" : "!!app-misc/installed-blocker-a",
+ },
+ "app-misc/blocker-update-order-a-1" : {},
+ "app-misc/blocker-update-order-hard-a-1" : {},
+ "app-misc/blocker-update-order-hard-unsolvable-a-1" : {},
+ "app-misc/blocker-runtime-a-1" : {},
+ "app-misc/blocker-runtime-b-1" : {},
+ "app-misc/blocker-runtime-hard-a-1" : {},
+ "app-misc/circ-buildtime-a-0": {},
+ "app-misc/circ-buildtime-a-1": {
+ "RDEPEND": "app-misc/circ-buildtime-b",
+ },
+ "app-misc/circ-buildtime-b-1": {
+ "RDEPEND": "app-misc/circ-buildtime-c",
+ },
+ "app-misc/circ-buildtime-c-1": {
+ "DEPEND": "app-misc/circ-buildtime-a",
+ },
+ "app-misc/circ-buildtime-unsolvable-a-1": {
+ "RDEPEND": "app-misc/circ-buildtime-unsolvable-b",
+ },
+ "app-misc/circ-buildtime-unsolvable-b-1": {
+ "RDEPEND": "app-misc/circ-buildtime-unsolvable-c",
+ },
+ "app-misc/circ-buildtime-unsolvable-c-1": {
+ "DEPEND": "app-misc/circ-buildtime-unsolvable-a",
+ },
+ "app-misc/circ-post-runtime-a-1": {
+ "PDEPEND": "app-misc/circ-post-runtime-b",
+ },
+ "app-misc/circ-post-runtime-b-1": {
+ "RDEPEND": "app-misc/circ-post-runtime-c",
+ },
+ "app-misc/circ-post-runtime-c-1": {
+ "RDEPEND": "app-misc/circ-post-runtime-a",
+ },
+ "app-misc/circ-runtime-a-1": {
+ "RDEPEND": "app-misc/circ-runtime-b",
+ },
+ "app-misc/circ-runtime-b-1": {
+ "RDEPEND": "app-misc/circ-runtime-c",
+ },
+ "app-misc/circ-runtime-c-1": {
+ "RDEPEND": "app-misc/circ-runtime-a",
+ },
+ "app-misc/circ-satisfied-a-0": {
+ "RDEPEND": "app-misc/circ-satisfied-b",
+ },
+ "app-misc/circ-satisfied-a-1": {
+ "RDEPEND": "app-misc/circ-satisfied-b",
+ },
+ "app-misc/circ-satisfied-b-0": {
+ "RDEPEND": "app-misc/circ-satisfied-c",
+ },
+ "app-misc/circ-satisfied-b-1": {
+ "RDEPEND": "app-misc/circ-satisfied-c",
+ },
+ "app-misc/circ-satisfied-c-0": {
+ "DEPEND": "app-misc/circ-satisfied-a",
+ "RDEPEND": "app-misc/circ-satisfied-a",
+ },
+ "app-misc/circ-satisfied-c-1": {
+ "DEPEND": "app-misc/circ-satisfied-a",
+ "RDEPEND": "app-misc/circ-satisfied-a",
+ },
+ "app-misc/circ-smallest-a-1": {
+ "RDEPEND": "app-misc/circ-smallest-b",
+ },
+ "app-misc/circ-smallest-b-1": {
+ "RDEPEND": "app-misc/circ-smallest-a",
+ },
+ "app-misc/circ-smallest-c-1": {
+ "RDEPEND": "app-misc/circ-smallest-d",
+ },
+ "app-misc/circ-smallest-d-1": {
+ "RDEPEND": "app-misc/circ-smallest-e",
+ },
+ "app-misc/circ-smallest-e-1": {
+ "RDEPEND": "app-misc/circ-smallest-c",
+ },
+ "app-misc/circ-smallest-f-1": {
+ "RDEPEND": "app-misc/circ-smallest-g app-misc/circ-smallest-a app-misc/circ-smallest-c",
+ },
+ "app-misc/circ-smallest-g-1": {
+ "RDEPEND": "app-misc/circ-smallest-f",
+ },
+ "app-misc/installed-blocker-a-1" : {
+ "EAPI" : "2",
+ "DEPEND" : "!app-misc/blocker-buildtime-a",
+ "RDEPEND" : "!app-misc/blocker-runtime-a !app-misc/blocker-runtime-b !!app-misc/blocker-runtime-hard-a",
+ },
+ "app-misc/installed-old-version-blocks-a-1" : {
+ "RDEPEND" : "!app-misc/blocker-update-order-a",
+ },
+ "app-misc/installed-old-version-blocks-a-2" : {},
+ "app-misc/installed-old-version-blocks-hard-a-1" : {
+ "EAPI" : "2",
+ "RDEPEND" : "!!app-misc/blocker-update-order-hard-a",
+ },
+ "app-misc/installed-old-version-blocks-hard-a-2" : {},
+ "app-misc/installed-old-version-blocks-hard-unsolvable-a-1" : {
+ "EAPI" : "2",
+ "RDEPEND" : "!!app-misc/blocker-update-order-hard-unsolvable-a",
+ },
+ "app-misc/installed-old-version-blocks-hard-unsolvable-a-2" : {
+ "DEPEND" : "app-misc/blocker-update-order-hard-unsolvable-a",
+ "RDEPEND" : "",
+ },
+ "app-misc/some-app-a-1": {
+ "RDEPEND": "app-misc/circ-runtime-a app-misc/circ-runtime-b",
+ },
+ "app-misc/some-app-b-1": {
+ "RDEPEND": "app-misc/circ-post-runtime-a app-misc/circ-post-runtime-b",
+ },
+ "app-misc/some-app-c-1": {
+ "RDEPEND": "app-misc/circ-buildtime-a app-misc/circ-buildtime-b",
+ },
+ "app-admin/eselect-python-20100321" : {},
+ "sys-apps/portage-2.1.9.42" : {
+ "DEPEND" : "dev-lang/python",
+ "RDEPEND" : "dev-lang/python",
+ },
+ "sys-apps/portage-2.1.9.49" : {
+ "DEPEND" : "dev-lang/python >=app-admin/eselect-python-20091230",
+ "RDEPEND" : "dev-lang/python",
+ },
+ "dev-lang/python-3.1" : {},
+ "dev-lang/python-3.2" : {},
+ "virtual/libc-0" : {
+ "RDEPEND" : "sys-libs/glibc",
+ },
+ "sys-devel/gcc-4.5.2" : {},
+ "sys-devel/binutils-2.18" : {},
+ "sys-devel/binutils-2.20.1" : {},
+ "sys-libs/glibc-2.11" : {
+ "DEPEND" : "virtual/os-headers sys-devel/gcc sys-devel/binutils",
+ "RDEPEND": "",
+ },
+ "sys-libs/glibc-2.13" : {
+ "DEPEND" : "virtual/os-headers sys-devel/gcc sys-devel/binutils",
+ "RDEPEND": "",
+ },
+ "virtual/os-headers-0" : {
+ "RDEPEND" : "sys-kernel/linux-headers",
+ },
+ "sys-kernel/linux-headers-2.6.38": {
+ "DEPEND" : "app-arch/xz-utils",
+ "RDEPEND": "",
+ },
+ "sys-kernel/linux-headers-2.6.39": {
+ "DEPEND" : "app-arch/xz-utils",
+ "RDEPEND": "",
+ },
+ "app-arch/xz-utils-5.0.1" : {},
+ "app-arch/xz-utils-5.0.2" : {},
+ "dev-util/pkgconfig-0.25-r2" : {},
+ "kde-base/kdelibs-3.5.7" : {
+ "PDEPEND" : "kde-misc/kdnssd-avahi",
+ },
+ "kde-misc/kdnssd-avahi-0.1.2" : {
+ "DEPEND" : "kde-base/kdelibs app-arch/xz-utils dev-util/pkgconfig",
+ "RDEPEND" : "kde-base/kdelibs",
+ },
+ "kde-base/kdnssd-3.5.7" : {
+ "DEPEND" : "kde-base/kdelibs",
+ "RDEPEND" : "kde-base/kdelibs",
+ },
+ "kde-base/libkdegames-3.5.7" : {
+ "DEPEND" : "kde-base/kdelibs",
+ "RDEPEND" : "kde-base/kdelibs",
+ },
+ "kde-base/kmines-3.5.7" : {
+ "DEPEND" : "kde-base/libkdegames",
+ "RDEPEND" : "kde-base/libkdegames",
+ },
+ "media-video/libav-0.7_pre20110327" : {
+ "EAPI" : "2",
+ "IUSE" : "X +encode",
+ "RDEPEND" : "!media-video/ffmpeg",
+ },
+ "media-video/ffmpeg-0.7_rc1" : {
+ "EAPI" : "2",
+ "IUSE" : "X +encode",
+ },
+ "virtual/ffmpeg-0.6.90" : {
+ "EAPI" : "2",
+ "IUSE" : "X +encode",
+ "RDEPEND" : "|| ( >=media-video/ffmpeg-0.6.90_rc0-r2[X=,encode=] >=media-video/libav-0.6.90_rc[X=,encode=] )",
+ },
+ }
+
+ installed = {
+ "app-misc/circ-buildtime-a-0": {},
+ "app-misc/circ-satisfied-a-0": {
+ "RDEPEND": "app-misc/circ-satisfied-b",
+ },
+ "app-misc/circ-satisfied-b-0": {
+ "RDEPEND": "app-misc/circ-satisfied-c",
+ },
+ "app-misc/circ-satisfied-c-0": {
+ "DEPEND": "app-misc/circ-satisfied-a",
+ "RDEPEND": "app-misc/circ-satisfied-a",
+ },
+ "app-misc/installed-blocker-a-1" : {
+ "EAPI" : "2",
+ "DEPEND" : "!app-misc/blocker-buildtime-a",
+ "RDEPEND" : "!app-misc/blocker-runtime-a !app-misc/blocker-runtime-b !!app-misc/blocker-runtime-hard-a",
+ },
+ "app-misc/installed-old-version-blocks-a-1" : {
+ "RDEPEND" : "!app-misc/blocker-update-order-a",
+ },
+ "app-misc/installed-old-version-blocks-hard-a-1" : {
+ "EAPI" : "2",
+ "RDEPEND" : "!!app-misc/blocker-update-order-hard-a",
+ },
+ "app-misc/installed-old-version-blocks-hard-unsolvable-a-1" : {
+ "EAPI" : "2",
+ "RDEPEND" : "!!app-misc/blocker-update-order-hard-unsolvable-a",
+ },
+ "sys-apps/portage-2.1.9.42" : {
+ "DEPEND" : "dev-lang/python",
+ "RDEPEND" : "dev-lang/python",
+ },
+ "dev-lang/python-3.1" : {},
+ "virtual/libc-0" : {
+ "RDEPEND" : "sys-libs/glibc",
+ },
+ "sys-devel/binutils-2.18" : {},
+ "sys-libs/glibc-2.11" : {
+ "DEPEND" : "virtual/os-headers sys-devel/gcc sys-devel/binutils",
+ "RDEPEND": "",
+ },
+ "virtual/os-headers-0" : {
+ "RDEPEND" : "sys-kernel/linux-headers",
+ },
+ "sys-kernel/linux-headers-2.6.38": {
+ "DEPEND" : "app-arch/xz-utils",
+ "RDEPEND": "",
+ },
+ "app-arch/xz-utils-5.0.1" : {},
+ "media-video/ffmpeg-0.7_rc1" : {
+ "EAPI" : "2",
+ "IUSE" : "X +encode",
+ "USE" : "encode",
+ },
+ "virtual/ffmpeg-0.6.90" : {
+ "EAPI" : "2",
+ "IUSE" : "X +encode",
+ "USE" : "encode",
+ "RDEPEND" : "|| ( >=media-video/ffmpeg-0.6.90_rc0-r2[X=,encode=] >=media-video/libav-0.6.90_rc[X=,encode=] )",
+ },
+ }
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["app-misc/some-app-a"],
+ success = True,
+ ambiguous_merge_order = True,
+ mergelist = [("app-misc/circ-runtime-a-1", "app-misc/circ-runtime-b-1", "app-misc/circ-runtime-c-1"), "app-misc/some-app-a-1"]),
+ ResolverPlaygroundTestCase(
+ ["app-misc/some-app-a"],
+ success = True,
+ ambiguous_merge_order = True,
+ mergelist = [("app-misc/circ-runtime-c-1", "app-misc/circ-runtime-b-1", "app-misc/circ-runtime-a-1"), "app-misc/some-app-a-1"]),
+ # Test unsolvable circular dep that is RDEPEND in one
+ # direction and DEPEND in the other.
+ ResolverPlaygroundTestCase(
+ ["app-misc/circ-buildtime-unsolvable-a"],
+ success = False,
+ circular_dependency_solutions = {}),
+ # Test optimal merge order for a circular dep that is
+ # RDEPEND in one direction and DEPEND in the other.
+ # This requires an installed instance of the DEPEND
+ # package in order to be solvable.
+ ResolverPlaygroundTestCase(
+ ["app-misc/some-app-c", "app-misc/circ-buildtime-a"],
+ success = True,
+ ambiguous_merge_order = True,
+ mergelist = [("app-misc/circ-buildtime-b-1", "app-misc/circ-buildtime-c-1"), "app-misc/circ-buildtime-a-1", "app-misc/some-app-c-1"]),
+ # Test optimal merge order for a circular dep that is
+ # RDEPEND in one direction and PDEPEND in the other.
+ ResolverPlaygroundTestCase(
+ ["app-misc/some-app-b"],
+ success = True,
+ ambiguous_merge_order = True,
+ mergelist = ["app-misc/circ-post-runtime-a-1", ("app-misc/circ-post-runtime-b-1", "app-misc/circ-post-runtime-c-1"), "app-misc/some-app-b-1"]),
+ # Test optimal merge order for a circular dep that is
+ # RDEPEND in one direction and DEPEND in the other,
+ # with all dependencies initially satisfied. Optimally,
+ # the DEPEND/buildtime dep should be updated before the
+ # package that depends on it, even though it's feasible
+ # to update it later since it is already satisfied.
+ ResolverPlaygroundTestCase(
+ ["app-misc/circ-satisfied-a", "app-misc/circ-satisfied-b", "app-misc/circ-satisfied-c"],
+ success = True,
+ all_permutations = True,
+ ambiguous_merge_order = True,
+ merge_order_assertions = (("app-misc/circ-satisfied-a-1", "app-misc/circ-satisfied-c-1"),),
+ mergelist = [("app-misc/circ-satisfied-a-1", "app-misc/circ-satisfied-b-1", "app-misc/circ-satisfied-c-1")]),
+ # In the case of multiple runtime cycles, where some cycles
+ # may depend on smaller independent cycles, it's optimal
+ # to merge smaller independent cycles before other cycles
+ # that depend on them.
+ ResolverPlaygroundTestCase(
+ ["app-misc/circ-smallest-a", "app-misc/circ-smallest-c", "app-misc/circ-smallest-f"],
+ success = True,
+ ambiguous_merge_order = True,
+ all_permutations = True,
+ mergelist = [('app-misc/circ-smallest-a-1', 'app-misc/circ-smallest-b-1'),
+ ('app-misc/circ-smallest-c-1', 'app-misc/circ-smallest-d-1', 'app-misc/circ-smallest-e-1'),
+ ('app-misc/circ-smallest-f-1', 'app-misc/circ-smallest-g-1')]),
+ # installed package has buildtime-only blocker
+ # that should be ignored
+ ResolverPlaygroundTestCase(
+ ["app-misc/blocker-buildtime-a"],
+ success = True,
+ mergelist = ["app-misc/blocker-buildtime-a-1"]),
+ # We're installing a package that an old version of
+ # an installed package blocks. However, an update is
+ # available to the old package. The old package should
+ # be updated first, in order to solve the blocker without
+ # any need for blocking packages to temporarily overlap.
+ ResolverPlaygroundTestCase(
+ ["app-misc/blocker-update-order-a", "app-misc/installed-old-version-blocks-a"],
+ success = True,
+ all_permutations = True,
+ mergelist = ["app-misc/installed-old-version-blocks-a-2", "app-misc/blocker-update-order-a-1"]),
+ # This is the same as above but with a hard blocker. The hard
+ # blocker is solved automatically since the update makes it
+ # irrelevant.
+ ResolverPlaygroundTestCase(
+ ["app-misc/blocker-update-order-hard-a", "app-misc/installed-old-version-blocks-hard-a"],
+ success = True,
+ all_permutations = True,
+ mergelist = ["app-misc/installed-old-version-blocks-hard-a-2", "app-misc/blocker-update-order-hard-a-1"]),
+ # This is similar to the above case except that it's unsolvable
+ # due to merge order, unless bug 250286 is implemented so that
+ # the installed blocker will be unmerged before installation
+ # of the package it blocks (rather than after like a soft blocker
+ # would be handled). The "unmerge before" behavior requested
+ # in bug 250286 must be optional since essential programs or
+ # libraries may be temporarily unavailable during a
+ # non-overlapping update like this.
+ ResolverPlaygroundTestCase(
+ ["app-misc/blocker-update-order-hard-unsolvable-a", "app-misc/installed-old-version-blocks-hard-unsolvable-a"],
+ success = False,
+ all_permutations = True,
+ ambiguous_merge_order = True,
+ merge_order_assertions = (('app-misc/blocker-update-order-hard-unsolvable-a-1', 'app-misc/installed-old-version-blocks-hard-unsolvable-a-2'),),
+ mergelist = [('app-misc/blocker-update-order-hard-unsolvable-a-1', 'app-misc/installed-old-version-blocks-hard-unsolvable-a-2', '!!app-misc/blocker-update-order-hard-unsolvable-a')]),
+ # The installed package has runtime blockers that
+ # should cause it to be uninstalled. The uninstall
+ # task is executed only after blocking packages have
+ # been merged.
+ # TODO: distinguish between install/uninstall tasks in mergelist
+ ResolverPlaygroundTestCase(
+ ["app-misc/blocker-runtime-a", "app-misc/blocker-runtime-b"],
+ success = True,
+ all_permutations = True,
+ ambiguous_merge_order = True,
+ mergelist = [("app-misc/blocker-runtime-a-1", "app-misc/blocker-runtime-b-1"), "app-misc/installed-blocker-a-1", ("!app-misc/blocker-runtime-a", "!app-misc/blocker-runtime-b")]),
+ # We have a soft buildtime blocker against an installed
+ # package that should cause it to be uninstalled. Note that with
+ # soft blockers, the blocking packages are allowed to temporarily
+ # overlap. This allows any essential programs/libraries provided
+ # by both packages to be available at all times.
+ # TODO: distinguish between install/uninstall tasks in mergelist
+ ResolverPlaygroundTestCase(
+ ["app-misc/blocker-buildtime-unbuilt-a"],
+ success = True,
+ mergelist = ["app-misc/blocker-buildtime-unbuilt-a-1", "app-misc/installed-blocker-a-1", "!app-misc/installed-blocker-a"]),
+ # We have a hard buildtime blocker against an installed
+ # package that will not resolve automatically (unless
+ # the option requested in bug 250286 is implemented).
+ ResolverPlaygroundTestCase(
+ ["app-misc/blocker-buildtime-unbuilt-hard-a"],
+ success = False,
+ mergelist = ['app-misc/blocker-buildtime-unbuilt-hard-a-1', '!!app-misc/installed-blocker-a']),
+ # An installed package has a hard runtime blocker that
+ # will not resolve automatically (unless the option
+ # requested in bug 250286 is implemented).
+ ResolverPlaygroundTestCase(
+ ["app-misc/blocker-runtime-hard-a"],
+ success = False,
+ mergelist = ['app-misc/blocker-runtime-hard-a-1', '!!app-misc/blocker-runtime-hard-a']),
+ # Test swapping of providers for a new-style virtual package,
+ # which relies on delayed evaluation of disjunctive (virtual
+ # and ||) deps as required to solve bug #264434. Note that
+ # this behavior is not supported for old-style PROVIDE virtuals,
+ # as reported in bug #339164.
+ ResolverPlaygroundTestCase(
+ ["media-video/libav"],
+ success=True,
+ mergelist = ['media-video/libav-0.7_pre20110327', 'media-video/ffmpeg-0.7_rc1', '!media-video/ffmpeg']),
+ # Test that PORTAGE_PACKAGE_ATOM is merged asap. Optimally,
+ # satisfied deps are always merged after the asap nodes that
+ # depend on them.
+ ResolverPlaygroundTestCase(
+ ["dev-lang/python", portage.const.PORTAGE_PACKAGE_ATOM],
+ success = True,
+ all_permutations = True,
+ mergelist = ['app-admin/eselect-python-20100321', 'sys-apps/portage-2.1.9.49', 'dev-lang/python-3.2']),
+ # Test that OS_HEADERS_PACKAGE_ATOM and LIBC_PACKAGE_ATOM
+ # are merged asap, in order to account for implicit
+ # dependencies. See bug #303567. Optimally, satisfied deps
+ # are always merged after the asap nodes that depend on them.
+ ResolverPlaygroundTestCase(
+ ["app-arch/xz-utils", "sys-kernel/linux-headers", "sys-devel/binutils", "sys-libs/glibc"],
+ options = {"--complete-graph" : True},
+ success = True,
+ all_permutations = True,
+ ambiguous_merge_order = True,
+ mergelist = ['sys-kernel/linux-headers-2.6.39', 'sys-devel/gcc-4.5.2', 'sys-libs/glibc-2.13', ('app-arch/xz-utils-5.0.2', 'sys-devel/binutils-2.20.1')]),
+ # Test asap install of PDEPEND for bug #180045.
+ ResolverPlaygroundTestCase(
+ ["kde-base/kmines", "kde-base/kdnssd", "kde-base/kdelibs", "app-arch/xz-utils"],
+ success = True,
+ all_permutations = True,
+ ambiguous_merge_order = True,
+ merge_order_assertions = (
+ ('dev-util/pkgconfig-0.25-r2', 'kde-misc/kdnssd-avahi-0.1.2'),
+ ('kde-misc/kdnssd-avahi-0.1.2', 'kde-base/libkdegames-3.5.7'),
+ ('kde-misc/kdnssd-avahi-0.1.2', 'kde-base/kdnssd-3.5.7'),
+ ('kde-base/libkdegames-3.5.7', 'kde-base/kmines-3.5.7'),
+ ),
+ mergelist = [('kde-base/kdelibs-3.5.7', 'dev-util/pkgconfig-0.25-r2', 'kde-misc/kdnssd-avahi-0.1.2', 'app-arch/xz-utils-5.0.2', 'kde-base/libkdegames-3.5.7', 'kde-base/kdnssd-3.5.7', 'kde-base/kmines-3.5.7')]),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_missing_iuse_and_evaluated_atoms.py b/portage_with_autodep/pym/portage/tests/resolver/test_missing_iuse_and_evaluated_atoms.py
new file mode 100644
index 0000000..a860e7b
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_missing_iuse_and_evaluated_atoms.py
@@ -0,0 +1,31 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class MissingIUSEandEvaluatedAtomsTestCase(TestCase):
+
+ def testMissingIUSEandEvaluatedAtoms(self):
+ ebuilds = {
+ "dev-libs/A-1": { "DEPEND": "dev-libs/B[foo?]", "IUSE": "foo bar", "EAPI": 2 },
+ "dev-libs/A-2": { "DEPEND": "dev-libs/B[foo?,bar]", "IUSE": "foo bar", "EAPI": 2 },
+ "dev-libs/B-1": { "IUSE": "bar" },
+ }
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/A-1"],
+ success = False),
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/A-2"],
+ success = False),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds, debug=False)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_multirepo.py b/portage_with_autodep/pym/portage/tests/resolver/test_multirepo.py
new file mode 100644
index 0000000..34c6d45
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_multirepo.py
@@ -0,0 +1,318 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class MultirepoTestCase(TestCase):
+
+ def testMultirepo(self):
+ ebuilds = {
+ #Simple repo selection
+ "dev-libs/A-1": { },
+ "dev-libs/A-1::repo1": { },
+ "dev-libs/A-2::repo1": { },
+ "dev-libs/A-1::repo2": { },
+
+ #Packages in exactly one repo
+ "dev-libs/B-1": { },
+ "dev-libs/C-1::repo1": { },
+
+ #Package in repository 1 and 2, but 1 must be used
+ "dev-libs/D-1::repo1": { },
+ "dev-libs/D-1::repo2": { },
+
+ "dev-libs/E-1": { },
+ "dev-libs/E-1::repo1": { },
+ "dev-libs/E-1::repo2": { "SLOT": "1" },
+
+ "dev-libs/F-1::repo1": { "SLOT": "1" },
+ "dev-libs/F-1::repo2": { "SLOT": "1" },
+
+ "dev-libs/G-1::repo1": { "EAPI" : "4", "IUSE":"+x +y", "REQUIRED_USE" : "" },
+ "dev-libs/G-1::repo2": { "EAPI" : "4", "IUSE":"+x +y", "REQUIRED_USE" : "^^ ( x y )" },
+
+ "dev-libs/H-1": { "KEYWORDS": "x86", "EAPI" : "3",
+ "RDEPEND" : "|| ( dev-libs/I:2 dev-libs/I:1 )" },
+
+ "dev-libs/I-1::repo2": { "SLOT" : "1"},
+ "dev-libs/I-2::repo2": { "SLOT" : "2"},
+ }
+
+ installed = {
+ "dev-libs/H-1": { "RDEPEND" : "|| ( dev-libs/I:2 dev-libs/I:1 )"},
+ "dev-libs/I-2::repo1": {"SLOT" : "2"},
+ }
+
+ sets = {
+ "multirepotest":
+ ( "dev-libs/A::test_repo", )
+ }
+
+ test_cases = (
+ #Simple repo selection
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/A-2::repo1"]),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A::test_repo"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/A-1"]),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A::repo2"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/A-1::repo2"]),
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/A-1::repo1"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/A-1::repo1"]),
+ ResolverPlaygroundTestCase(
+ ["@multirepotest"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/A-1"]),
+
+ #Packages in exactly one repo
+ ResolverPlaygroundTestCase(
+ ["dev-libs/B"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/B-1"]),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/C"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/C-1::repo1"]),
+
+ #Package in repository 1 and 2, but 2 must be used
+ ResolverPlaygroundTestCase(
+ ["dev-libs/D"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/D-1::repo2"]),
+
+ #Atoms with slots
+ ResolverPlaygroundTestCase(
+ ["dev-libs/E"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/E-1::repo2"]),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/E:1::repo2"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/E-1::repo2"]),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/E:1"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/E-1::repo2"]),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/F:1"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/F-1::repo2"]),
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/F-1:1"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/F-1::repo2"]),
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/F-1:1::repo1"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/F-1::repo1"]),
+
+ # Dependency on installed dev-libs/C-2 ebuild for which ebuild is
+ # not available from the same repo should not unnecessarily
+ # reinstall the same version from a different repo.
+ ResolverPlaygroundTestCase(
+ ["dev-libs/H"],
+ options = {"--update": True, "--deep": True},
+ success = True,
+ mergelist = []),
+
+ # Check interaction between repo priority and unsatisfied
+ # REQUIRED_USE, for bug #350254.
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/G-1"],
+ check_repo_names = True,
+ success = False),
+
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds,
+ installed=installed, sets=sets)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
+
+
+ def testMultirepoUserConfig(self):
+ ebuilds = {
+ #package.use test
+ "dev-libs/A-1": { "IUSE": "foo" },
+ "dev-libs/A-2::repo1": { "IUSE": "foo" },
+ "dev-libs/A-3::repo2": { },
+ "dev-libs/B-1": { "DEPEND": "dev-libs/A", "EAPI": 2 },
+ "dev-libs/B-2": { "DEPEND": "dev-libs/A[foo]", "EAPI": 2 },
+ "dev-libs/B-3": { "DEPEND": "dev-libs/A[-foo]", "EAPI": 2 },
+
+ #package.keywords test
+ "dev-libs/C-1": { "KEYWORDS": "~x86" },
+ "dev-libs/C-1::repo1": { "KEYWORDS": "~x86" },
+
+ #package.license
+ "dev-libs/D-1": { "LICENSE": "TEST" },
+ "dev-libs/D-1::repo1": { "LICENSE": "TEST" },
+
+ #package.mask
+ "dev-libs/E-1": { },
+ "dev-libs/E-1::repo1": { },
+ "dev-libs/H-1": { },
+ "dev-libs/H-1::repo1": { },
+ "dev-libs/I-1::repo2": { "SLOT" : "1"},
+ "dev-libs/I-2::repo2": { "SLOT" : "2"},
+ "dev-libs/J-1": { "KEYWORDS": "x86", "EAPI" : "3",
+ "RDEPEND" : "|| ( dev-libs/I:2 dev-libs/I:1 )" },
+
+ #package.properties
+ "dev-libs/F-1": { "PROPERTIES": "bar"},
+ "dev-libs/F-1::repo1": { "PROPERTIES": "bar"},
+
+ #package.unmask
+ "dev-libs/G-1": { },
+ "dev-libs/G-1::repo1": { },
+
+ #package.mask with wildcards
+ "dev-libs/Z-1::repo3": { },
+ }
+
+ installed = {
+ "dev-libs/J-1": { "RDEPEND" : "|| ( dev-libs/I:2 dev-libs/I:1 )"},
+ "dev-libs/I-2::repo1": {"SLOT" : "2"},
+ }
+
+ user_config = {
+ "package.use":
+ (
+ "dev-libs/A::repo1 foo",
+ ),
+ "package.keywords":
+ (
+ "=dev-libs/C-1::test_repo",
+ ),
+ "package.license":
+ (
+ "=dev-libs/D-1::test_repo TEST",
+ ),
+ "package.mask":
+ (
+ "dev-libs/E::repo1",
+ "dev-libs/H",
+ "dev-libs/I::repo1",
+ #needed for package.unmask test
+ "dev-libs/G",
+ #wildcard test
+ "*/*::repo3",
+ ),
+ "package.properties":
+ (
+ "dev-libs/F::repo1 -bar",
+ ),
+ "package.unmask":
+ (
+ "dev-libs/G::test_repo",
+ ),
+ }
+
+ test_cases = (
+ #package.use test
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/B-1"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/A-3::repo2", "dev-libs/B-1"]),
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/B-2"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/A-2::repo1", "dev-libs/B-2"]),
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/B-3"],
+ options = { "--autounmask": 'n' },
+ success = False,
+ check_repo_names = True),
+
+ #package.keywords test
+ ResolverPlaygroundTestCase(
+ ["dev-libs/C"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/C-1"]),
+
+ #package.license test
+ ResolverPlaygroundTestCase(
+ ["dev-libs/D"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/D-1"]),
+
+ #package.mask test
+ ResolverPlaygroundTestCase(
+ ["dev-libs/E"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/E-1"]),
+
+ # Dependency on installed dev-libs/C-2 ebuild for which ebuild is
+ # masked from the same repo should not unnecessarily pull
+ # in a different slot. It should just pull in the same slot from
+ # a different repo (bug #351828).
+ ResolverPlaygroundTestCase(
+ ["dev-libs/J"],
+ options = {"--update": True, "--deep": True},
+ success = True,
+ mergelist = ["dev-libs/I-2"]),
+
+ #package.properties test
+ ResolverPlaygroundTestCase(
+ ["dev-libs/F"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/F-1"]),
+
+ #package.mask test
+ ResolverPlaygroundTestCase(
+ ["dev-libs/G"],
+ success = True,
+ check_repo_names = True,
+ mergelist = ["dev-libs/G-1"]),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/H"],
+ options = { "--autounmask": 'n' },
+ success = False),
+
+ #package.mask with wildcards
+ ResolverPlaygroundTestCase(
+ ["dev-libs/Z"],
+ options = { "--autounmask": 'n' },
+ success = False),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds,
+ installed=installed, user_config=user_config)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_multislot.py b/portage_with_autodep/pym/portage/tests/resolver/test_multislot.py
new file mode 100644
index 0000000..8615419
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_multislot.py
@@ -0,0 +1,40 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class MultSlotTestCase(TestCase):
+
+ def testMultiSlotSelective(self):
+ """
+ Test that a package isn't reinstalled due to SLOT dependency
+ interaction with USE=multislot (bug #220341).
+ """
+
+ ebuilds = {
+ "sys-devel/gcc-4.4.4": { "SLOT": "4.4" },
+ }
+
+ installed = {
+ "sys-devel/gcc-4.4.4": { "SLOT": "i686-pc-linux-gnu-4.4.4" },
+ }
+
+ options = {'--update' : True, '--deep' : True, '--selective' : True}
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["sys-devel/gcc:4.4"],
+ options = options,
+ mergelist = [],
+ success = True),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)
+
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_old_dep_chain_display.py b/portage_with_autodep/pym/portage/tests/resolver/test_old_dep_chain_display.py
new file mode 100644
index 0000000..8aedf59
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_old_dep_chain_display.py
@@ -0,0 +1,35 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class OldDepChainDisplayTestCase(TestCase):
+
+ def testOldDepChainDisplay(self):
+ ebuilds = {
+ "dev-libs/A-1": { "DEPEND": "foo? ( dev-libs/B[-bar] )", "IUSE": "+foo", "EAPI": "2" },
+ "dev-libs/A-2": { "DEPEND": "foo? ( dev-libs/C )", "IUSE": "+foo", "EAPI": "1" },
+ "dev-libs/B-1": { "IUSE": "bar", "DEPEND": "!bar? ( dev-libs/D[-baz] )", "EAPI": "2" },
+ "dev-libs/C-1": { "KEYWORDS": "~x86" },
+ "dev-libs/D-1": { "IUSE": "+baz", "EAPI": "1" },
+ }
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/A-1"],
+ options = { "--autounmask": 'n' },
+ success = False),
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/A-2"],
+ options = { "--autounmask": 'n' },
+ success = False),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_output.py b/portage_with_autodep/pym/portage/tests/resolver/test_output.py
new file mode 100644
index 0000000..34efe9c
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_output.py
@@ -0,0 +1,88 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class MergelistOutputTestCase(TestCase):
+
+ def testMergelistOutput(self):
+ """
+ This test doesn't check if the output is correct, but makes sure
+ that we don't backtrace somewhere in the output code.
+ """
+ ebuilds = {
+ "dev-libs/A-1": { "DEPEND": "dev-libs/B dev-libs/C", "IUSE": "+foo", "EAPI": 1 },
+ "dev-libs/B-1": { "DEPEND": "dev-libs/D", "IUSE": "foo +bar", "EAPI": 1 },
+ "dev-libs/C-1": { "DEPEND": "dev-libs/E", "IUSE": "foo bar" },
+ "dev-libs/D-1": { "IUSE": "" },
+ "dev-libs/E-1": {},
+
+ #reinstall for flags
+ "dev-libs/Z-1": { "IUSE": "+foo", "EAPI": 1 },
+ "dev-libs/Y-1": { "IUSE": "foo", "EAPI": 1 },
+ "dev-libs/X-1": {},
+ "dev-libs/W-1": { "IUSE": "+foo", "EAPI": 1 },
+ }
+
+ installed = {
+ "dev-libs/Z-1": { "USE": "", "IUSE": "foo" },
+ "dev-libs/Y-1": { "USE": "foo", "IUSE": "+foo", "EAPI": 1 },
+ "dev-libs/X-1": { "USE": "foo", "IUSE": "+foo", "EAPI": 1 },
+ "dev-libs/W-1": { },
+ }
+
+ option_cobos = (
+ (),
+ ("verbose",),
+ ("tree",),
+ ("tree", "unordered-display",),
+ ("verbose",),
+ ("verbose", "tree",),
+ ("verbose", "tree", "unordered-display",),
+ )
+
+ test_cases = []
+ for options in option_cobos:
+ testcase_opts = {}
+ for opt in options:
+ testcase_opts["--" + opt] = True
+
+ test_cases.append(ResolverPlaygroundTestCase(
+ ["dev-libs/A"],
+ options = testcase_opts,
+ success = True,
+ ignore_mergelist_order=True,
+ mergelist = ["dev-libs/D-1", "dev-libs/E-1", "dev-libs/C-1", "dev-libs/B-1", "dev-libs/A-1"]))
+
+ test_cases.append(ResolverPlaygroundTestCase(
+ ["dev-libs/Z"],
+ options = testcase_opts,
+ success = True,
+ mergelist = ["dev-libs/Z-1"]))
+
+ test_cases.append(ResolverPlaygroundTestCase(
+ ["dev-libs/Y"],
+ options = testcase_opts,
+ success = True,
+ mergelist = ["dev-libs/Y-1"]))
+
+ test_cases.append(ResolverPlaygroundTestCase(
+ ["dev-libs/X"],
+ options = testcase_opts,
+ success = True,
+ mergelist = ["dev-libs/X-1"]))
+
+ test_cases.append(ResolverPlaygroundTestCase(
+ ["dev-libs/W"],
+ options = testcase_opts,
+ success = True,
+ mergelist = ["dev-libs/W-1"]))
+
+ playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_rebuild.py b/portage_with_autodep/pym/portage/tests/resolver/test_rebuild.py
new file mode 100644
index 0000000..b9c4d6d
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_rebuild.py
@@ -0,0 +1,138 @@
+# Copyright 2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+ ResolverPlaygroundTestCase)
+
+class RebuildTestCase(TestCase):
+
+ def testRebuild(self):
+ """
+ Rebuild packages when dependencies that are used at both build-time and
+ run-time are upgraded.
+ """
+
+ ebuilds = {
+ "sys-libs/x-1": { },
+ "sys-libs/x-1-r1": { },
+ "sys-libs/x-2": { },
+ "sys-apps/a-1": { "DEPEND" : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
+ "sys-apps/a-2": { "DEPEND" : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
+ "sys-apps/b-1": { "DEPEND" : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
+ "sys-apps/b-2": { "DEPEND" : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
+ "sys-apps/c-1": { "DEPEND" : "sys-libs/x", "RDEPEND" : ""},
+ "sys-apps/c-2": { "DEPEND" : "sys-libs/x", "RDEPEND" : ""},
+ "sys-apps/d-1": { "RDEPEND" : "sys-libs/x"},
+ "sys-apps/d-2": { "RDEPEND" : "sys-libs/x"},
+ "sys-apps/e-2": { "DEPEND" : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
+ "sys-apps/f-2": { "DEPEND" : "sys-apps/a", "RDEPEND" : "sys-apps/a"},
+ "sys-apps/g-2": { "DEPEND" : "sys-apps/b sys-libs/x",
+ "RDEPEND" : "sys-apps/b"},
+ }
+
+ installed = {
+ "sys-libs/x-1": { },
+ "sys-apps/a-1": { "DEPEND" : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
+ "sys-apps/b-1": { "DEPEND" : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
+ "sys-apps/c-1": { "DEPEND" : "sys-libs/x", "RDEPEND" : ""},
+ "sys-apps/d-1": { "RDEPEND" : "sys-libs/x"},
+ "sys-apps/e-1": { "DEPEND" : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
+ "sys-apps/f-1": { "DEPEND" : "sys-apps/a", "RDEPEND" : "sys-apps/a"},
+ "sys-apps/g-1": { "DEPEND" : "sys-apps/b sys-libs/x",
+ "RDEPEND" : "sys-apps/b"},
+ }
+
+ world = ["sys-apps/a", "sys-apps/b", "sys-apps/c", "sys-apps/d",
+ "sys-apps/e", "sys-apps/f", "sys-apps/g"]
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["sys-libs/x"],
+ options = {"--rebuild-if-unbuilt" : True,
+ "--rebuild-exclude" : ["sys-apps/b"]},
+ mergelist = ['sys-libs/x-2', 'sys-apps/a-2', 'sys-apps/e-2'],
+ ignore_mergelist_order = True,
+ success = True),
+
+ ResolverPlaygroundTestCase(
+ ["sys-libs/x"],
+ options = {"--rebuild-if-unbuilt" : True},
+ mergelist = ['sys-libs/x-2', 'sys-apps/a-2', 'sys-apps/b-2',
+ 'sys-apps/e-2', 'sys-apps/g-2'],
+ ignore_mergelist_order = True,
+ success = True),
+
+ ResolverPlaygroundTestCase(
+ ["sys-libs/x"],
+ options = {"--rebuild-if-unbuilt" : True,
+ "--rebuild-ignore" : ["sys-libs/x"]},
+ mergelist = ['sys-libs/x-2'],
+ ignore_mergelist_order = True,
+ success = True),
+
+ ResolverPlaygroundTestCase(
+ ["sys-libs/x"],
+ options = {"--rebuild-if-unbuilt" : True,
+ "--rebuild-ignore" : ["sys-apps/b"]},
+ mergelist = ['sys-libs/x-2', 'sys-apps/a-2', 'sys-apps/b-2',
+ 'sys-apps/e-2'],
+ ignore_mergelist_order = True,
+ success = True),
+
+ ResolverPlaygroundTestCase(
+ ["=sys-libs/x-1-r1"],
+ options = {"--rebuild-if-unbuilt" : True},
+ mergelist = ['sys-libs/x-1-r1', 'sys-apps/a-2',
+ 'sys-apps/b-2', 'sys-apps/e-2', 'sys-apps/g-2'],
+ ignore_mergelist_order = True,
+ success = True),
+
+ ResolverPlaygroundTestCase(
+ ["=sys-libs/x-1-r1"],
+ options = {"--rebuild-if-new-rev" : True},
+ mergelist = ['sys-libs/x-1-r1', 'sys-apps/a-2',
+ 'sys-apps/b-2', 'sys-apps/e-2', 'sys-apps/g-2'],
+ ignore_mergelist_order = True,
+ success = True),
+
+ ResolverPlaygroundTestCase(
+ ["=sys-libs/x-1-r1"],
+ options = {"--rebuild-if-new-ver" : True},
+ mergelist = ['sys-libs/x-1-r1'],
+ ignore_mergelist_order = True,
+ success = True),
+
+ ResolverPlaygroundTestCase(
+ ["sys-libs/x"],
+ options = {"--rebuild-if-new-ver" : True},
+ mergelist = ['sys-libs/x-2', 'sys-apps/a-2',
+ 'sys-apps/b-2', 'sys-apps/e-2', 'sys-apps/g-2'],
+ ignore_mergelist_order = True,
+ success = True),
+
+ ResolverPlaygroundTestCase(
+ ["=sys-libs/x-1"],
+ options = {"--rebuild-if-new-rev" : True},
+ mergelist = ['sys-libs/x-1'],
+ ignore_mergelist_order = True,
+ success = True),
+
+ ResolverPlaygroundTestCase(
+ ["=sys-libs/x-1"],
+ options = {"--rebuild-if-unbuilt" : True},
+ mergelist = ['sys-libs/x-1', 'sys-apps/a-2',
+ 'sys-apps/b-2', 'sys-apps/e-2', 'sys-apps/g-2'],
+ ignore_mergelist_order = True,
+ success = True),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds,
+ installed=installed, world=world)
+
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_required_use.py b/portage_with_autodep/pym/portage/tests/resolver/test_required_use.py
new file mode 100644
index 0000000..c8810fa
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_required_use.py
@@ -0,0 +1,114 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class RequiredUSETestCase(TestCase):
+
+ def testRequiredUSE(self):
+ """
+ Only simple REQUIRED_USE values here. The parser is tested under in dep/testCheckRequiredUse
+ """
+
+ ebuilds = {
+ "dev-libs/A-1" : {"EAPI": "4", "IUSE": "foo bar", "REQUIRED_USE": "|| ( foo bar )"},
+ "dev-libs/A-2" : {"EAPI": "4", "IUSE": "foo +bar", "REQUIRED_USE": "|| ( foo bar )"},
+ "dev-libs/A-3" : {"EAPI": "4", "IUSE": "+foo bar", "REQUIRED_USE": "|| ( foo bar )"},
+ "dev-libs/A-4" : {"EAPI": "4", "IUSE": "+foo +bar", "REQUIRED_USE": "|| ( foo bar )"},
+ "dev-libs/A-5" : {"EAPI": "4", "IUSE": "+foo +bar", "REQUIRED_USE": "|| ( )"},
+
+ "dev-libs/B-1" : {"EAPI": "4", "IUSE": "foo bar", "REQUIRED_USE": "^^ ( foo bar )"},
+ "dev-libs/B-2" : {"EAPI": "4", "IUSE": "foo +bar", "REQUIRED_USE": "^^ ( foo bar )"},
+ "dev-libs/B-3" : {"EAPI": "4", "IUSE": "+foo bar", "REQUIRED_USE": "^^ ( foo bar )"},
+ "dev-libs/B-4" : {"EAPI": "4", "IUSE": "+foo +bar", "REQUIRED_USE": "^^ ( foo bar )"},
+ "dev-libs/B-5" : {"EAPI": "4", "IUSE": "+foo +bar", "REQUIRED_USE": "^^ ( )"},
+
+ "dev-libs/C-1" : {"EAPI": "4", "IUSE": "+foo bar", "REQUIRED_USE": "foo? ( !bar )"},
+ "dev-libs/C-2" : {"EAPI": "4", "IUSE": "+foo +bar", "REQUIRED_USE": "foo? ( !bar )"},
+ "dev-libs/C-3" : {"EAPI": "4", "IUSE": "+foo +bar", "REQUIRED_USE": "foo? ( bar )"},
+ "dev-libs/C-4" : {"EAPI": "4", "IUSE": "+foo bar", "REQUIRED_USE": "foo? ( bar )"},
+ "dev-libs/C-5" : {"EAPI": "4", "IUSE": "foo bar", "REQUIRED_USE": "foo? ( bar )"},
+ "dev-libs/C-6" : {"EAPI": "4", "IUSE": "foo +bar", "REQUIRED_USE": "foo? ( bar )"},
+ "dev-libs/C-7" : {"EAPI": "4", "IUSE": "foo +bar", "REQUIRED_USE": "!foo? ( bar )"},
+ "dev-libs/C-8" : {"EAPI": "4", "IUSE": "+foo +bar", "REQUIRED_USE": "!foo? ( bar )"},
+ "dev-libs/C-9" : {"EAPI": "4", "IUSE": "+foo bar", "REQUIRED_USE": "!foo? ( bar )"},
+ "dev-libs/C-10": {"EAPI": "4", "IUSE": "foo bar", "REQUIRED_USE": "!foo? ( bar )"},
+ "dev-libs/C-11": {"EAPI": "4", "IUSE": "foo bar", "REQUIRED_USE": "!foo? ( !bar )"},
+ "dev-libs/C-12": {"EAPI": "4", "IUSE": "foo +bar", "REQUIRED_USE": "!foo? ( !bar )"},
+ "dev-libs/C-13": {"EAPI": "4", "IUSE": "+foo +bar", "REQUIRED_USE": "!foo? ( !bar )"},
+ "dev-libs/C-14": {"EAPI": "4", "IUSE": "+foo bar", "REQUIRED_USE": "!foo? ( !bar )"},
+
+ "dev-libs/D-1" : {"EAPI": "4", "IUSE": "+w +x +y z", "REQUIRED_USE": "w? ( x || ( y z ) )"},
+ "dev-libs/D-2" : {"EAPI": "4", "IUSE": "+w +x +y +z", "REQUIRED_USE": "w? ( x || ( y z ) )"},
+ "dev-libs/D-3" : {"EAPI": "4", "IUSE": "+w +x y z", "REQUIRED_USE": "w? ( x || ( y z ) )"},
+ "dev-libs/D-4" : {"EAPI": "4", "IUSE": "+w x +y +z", "REQUIRED_USE": "w? ( x || ( y z ) )"},
+ "dev-libs/D-5" : {"EAPI": "4", "IUSE": "w x y z", "REQUIRED_USE": "w? ( x || ( y z ) )"},
+ }
+
+ test_cases = (
+ ResolverPlaygroundTestCase(["=dev-libs/A-1"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/A-2"], success = True, mergelist=["dev-libs/A-2"]),
+ ResolverPlaygroundTestCase(["=dev-libs/A-3"], success = True, mergelist=["dev-libs/A-3"]),
+ ResolverPlaygroundTestCase(["=dev-libs/A-4"], success = True, mergelist=["dev-libs/A-4"]),
+ ResolverPlaygroundTestCase(["=dev-libs/A-5"], success = True, mergelist=["dev-libs/A-5"]),
+
+ ResolverPlaygroundTestCase(["=dev-libs/B-1"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/B-2"], success = True, mergelist=["dev-libs/B-2"]),
+ ResolverPlaygroundTestCase(["=dev-libs/B-3"], success = True, mergelist=["dev-libs/B-3"]),
+ ResolverPlaygroundTestCase(["=dev-libs/B-4"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/B-5"], success = True, mergelist=["dev-libs/B-5"]),
+
+ ResolverPlaygroundTestCase(["=dev-libs/C-1"], success = True, mergelist=["dev-libs/C-1"]),
+ ResolverPlaygroundTestCase(["=dev-libs/C-2"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/C-3"], success = True, mergelist=["dev-libs/C-3"]),
+ ResolverPlaygroundTestCase(["=dev-libs/C-4"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/C-5"], success = True, mergelist=["dev-libs/C-5"]),
+ ResolverPlaygroundTestCase(["=dev-libs/C-6"], success = True, mergelist=["dev-libs/C-6"]),
+ ResolverPlaygroundTestCase(["=dev-libs/C-7"], success = True, mergelist=["dev-libs/C-7"]),
+ ResolverPlaygroundTestCase(["=dev-libs/C-8"], success = True, mergelist=["dev-libs/C-8"]),
+ ResolverPlaygroundTestCase(["=dev-libs/C-9"], success = True, mergelist=["dev-libs/C-9"]),
+ ResolverPlaygroundTestCase(["=dev-libs/C-10"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/C-11"], success = True, mergelist=["dev-libs/C-11"]),
+ ResolverPlaygroundTestCase(["=dev-libs/C-12"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/C-13"], success = True, mergelist=["dev-libs/C-13"]),
+ ResolverPlaygroundTestCase(["=dev-libs/C-14"], success = True, mergelist=["dev-libs/C-14"]),
+
+ ResolverPlaygroundTestCase(["=dev-libs/D-1"], success = True, mergelist=["dev-libs/D-1"]),
+ ResolverPlaygroundTestCase(["=dev-libs/D-2"], success = True, mergelist=["dev-libs/D-2"]),
+ ResolverPlaygroundTestCase(["=dev-libs/D-3"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/D-4"], success = False),
+ ResolverPlaygroundTestCase(["=dev-libs/D-5"], success = True, mergelist=["dev-libs/D-5"]),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
+
+ def testRequiredUseOrDeps(self):
+
+ ebuilds = {
+ "dev-libs/A-1": { "IUSE": "+x +y", "REQUIRED_USE": "^^ ( x y )", "EAPI": "4" },
+ "dev-libs/B-1": { "IUSE": "+x +y", "REQUIRED_USE": "", "EAPI": "4" },
+ "app-misc/p-1": { "RDEPEND": "|| ( =dev-libs/A-1 =dev-libs/B-1 )" },
+ }
+
+ test_cases = (
+ # This should fail and show a REQUIRED_USE error for
+ # dev-libs/A-1, since this choice it preferred.
+ ResolverPlaygroundTestCase(
+ ["=app-misc/p-1"],
+ success = False),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_simple.py b/portage_with_autodep/pym/portage/tests/resolver/test_simple.py
new file mode 100644
index 0000000..0bcfc4b
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_simple.py
@@ -0,0 +1,57 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class SimpleResolverTestCase(TestCase):
+
+ def testSimple(self):
+ ebuilds = {
+ "dev-libs/A-1": { "KEYWORDS": "x86" },
+ "dev-libs/A-2": { "KEYWORDS": "~x86" },
+ "dev-libs/B-1.2": {},
+
+ "app-misc/Z-1": { "DEPEND": "|| ( app-misc/Y ( app-misc/X app-misc/W ) )", "RDEPEND": "" },
+ "app-misc/Y-1": { "KEYWORDS": "~x86" },
+ "app-misc/X-1": {},
+ "app-misc/W-1": {},
+ }
+ installed = {
+ "dev-libs/A-1": {},
+ "dev-libs/B-1.1": {},
+ }
+
+ test_cases = (
+ ResolverPlaygroundTestCase(["dev-libs/A"], success = True, mergelist = ["dev-libs/A-1"]),
+ ResolverPlaygroundTestCase(["=dev-libs/A-2"], options = { "--autounmask": 'n' }, success = False),
+
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A"],
+ options = {"--noreplace": True},
+ success = True,
+ mergelist = []),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/B"],
+ options = {"--noreplace": True},
+ success = True,
+ mergelist = []),
+ ResolverPlaygroundTestCase(
+ ["dev-libs/B"],
+ options = {"--update": True},
+ success = True,
+ mergelist = ["dev-libs/B-1.2"]),
+
+ ResolverPlaygroundTestCase(
+ ["app-misc/Z"],
+ success = True,
+ mergelist = ["app-misc/W-1", "app-misc/X-1", "app-misc/Z-1"]),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_slot_collisions.py b/portage_with_autodep/pym/portage/tests/resolver/test_slot_collisions.py
new file mode 100644
index 0000000..4867cea
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_slot_collisions.py
@@ -0,0 +1,143 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class SlotCollisionTestCase(TestCase):
+
+ def testSlotCollision(self):
+
+ ebuilds = {
+ "dev-libs/A-1": { "PDEPEND": "foo? ( dev-libs/B )", "IUSE": "foo" },
+ "dev-libs/B-1": { "IUSE": "foo" },
+ "dev-libs/C-1": { "DEPEND": "dev-libs/A[foo]", "EAPI": 2 },
+ "dev-libs/D-1": { "DEPEND": "dev-libs/A[foo=] dev-libs/B[foo=]", "IUSE": "foo", "EAPI": 2 },
+ "dev-libs/E-1": { },
+ "dev-libs/E-2": { "IUSE": "foo" },
+
+ "app-misc/Z-1": { },
+ "app-misc/Z-2": { },
+ "app-misc/Y-1": { "DEPEND": "=app-misc/Z-1" },
+ "app-misc/Y-2": { "DEPEND": ">app-misc/Z-1" },
+ "app-misc/X-1": { "DEPEND": "=app-misc/Z-2" },
+ "app-misc/X-2": { "DEPEND": "<app-misc/Z-2" },
+
+ "sci-libs/K-1": { "IUSE": "+foo", "EAPI": 1 },
+ "sci-libs/L-1": { "DEPEND": "sci-libs/K[-foo]", "EAPI": 2 },
+ "sci-libs/M-1": { "DEPEND": "sci-libs/K[foo=]", "IUSE": "+foo", "EAPI": 2 },
+
+ "sci-libs/Q-1": { "SLOT": "1", "IUSE": "+bar foo", "EAPI": 1 },
+ "sci-libs/Q-2": { "SLOT": "2", "IUSE": "+bar +foo", "EAPI": 2, "PDEPEND": "sci-libs/Q:1[bar?,foo?]" },
+ "sci-libs/P-1": { "DEPEND": "sci-libs/Q:1[foo=]", "IUSE": "foo", "EAPI": 2 },
+
+ "sys-libs/A-1": { "RDEPEND": "foo? ( sys-libs/J[foo=] )", "IUSE": "+foo", "EAPI": "4" },
+ "sys-libs/B-1": { "RDEPEND": "bar? ( sys-libs/J[bar=] )", "IUSE": "+bar", "EAPI": "4" },
+ "sys-libs/C-1": { "RDEPEND": "sys-libs/J[bar]", "EAPI": "4" },
+ "sys-libs/D-1": { "RDEPEND": "sys-libs/J[bar?]", "IUSE": "bar", "EAPI": "4" },
+ "sys-libs/E-1": { "RDEPEND": "sys-libs/J[foo(+)?]", "IUSE": "+foo", "EAPI": "4" },
+ "sys-libs/F-1": { "RDEPEND": "sys-libs/J[foo(+)]", "EAPI": "4" },
+ "sys-libs/J-1": { "IUSE": "+foo", "EAPI": "4" },
+ "sys-libs/J-2": { "IUSE": "+bar", "EAPI": "4" },
+
+ "app-misc/A-1": { "IUSE": "foo +bar", "REQUIRED_USE": "^^ ( foo bar )", "EAPI": "4" },
+ "app-misc/B-1": { "DEPEND": "=app-misc/A-1[foo=]", "IUSE": "foo", "EAPI": 2 },
+ "app-misc/C-1": { "DEPEND": "=app-misc/A-1[foo]", "EAPI": 2 },
+ "app-misc/E-1": { "RDEPEND": "dev-libs/E[foo?]", "IUSE": "foo", "EAPI": "2" },
+ "app-misc/F-1": { "RDEPEND": "=dev-libs/E-1", "IUSE": "foo", "EAPI": "2" },
+ }
+ installed = {
+ "dev-libs/A-1": { "PDEPEND": "foo? ( dev-libs/B )", "IUSE": "foo", "USE": "foo" },
+ "dev-libs/B-1": { "IUSE": "foo", "USE": "foo" },
+ "dev-libs/C-1": { "DEPEND": "dev-libs/A[foo]", "EAPI": 2 },
+ "dev-libs/D-1": { "DEPEND": "dev-libs/A[foo=] dev-libs/B[foo=]", "IUSE": "foo", "USE": "foo", "EAPI": 2 },
+
+ "sci-libs/K-1": { "IUSE": "foo", "USE": "" },
+ "sci-libs/L-1": { "DEPEND": "sci-libs/K[-foo]" },
+
+ "sci-libs/Q-1": { "SLOT": "1", "IUSE": "+bar +foo", "USE": "bar foo", "EAPI": 1 },
+ "sci-libs/Q-2": { "SLOT": "2", "IUSE": "+bar +foo", "USE": "bar foo", "EAPI": 2, "PDEPEND": "sci-libs/Q:1[bar?,foo?]" },
+
+ "app-misc/A-1": { "IUSE": "+foo bar", "USE": "foo", "REQUIRED_USE": "^^ ( foo bar )", "EAPI": "4" },
+ }
+
+ test_cases = (
+ #A qt-*[qt3support] like mess.
+ ResolverPlaygroundTestCase(
+ ["dev-libs/A", "dev-libs/B", "dev-libs/C", "dev-libs/D"],
+ options = { "--autounmask": 'n' },
+ success = False,
+ mergelist = ["dev-libs/A-1", "dev-libs/B-1", "dev-libs/C-1", "dev-libs/D-1"],
+ ignore_mergelist_order = True,
+ slot_collision_solutions = [ {"dev-libs/A-1": {"foo": True}, "dev-libs/D-1": {"foo": True}} ]),
+
+ ResolverPlaygroundTestCase(
+ ["sys-libs/A", "sys-libs/B", "sys-libs/C", "sys-libs/D", "sys-libs/E", "sys-libs/F"],
+ options = { "--autounmask": 'n' },
+ success = False,
+ ignore_mergelist_order = True,
+ slot_collision_solutions = [],
+ mergelist = ['sys-libs/J-2', 'sys-libs/J-1', 'sys-libs/A-1', 'sys-libs/B-1', 'sys-libs/C-1', 'sys-libs/D-1', 'sys-libs/E-1', 'sys-libs/F-1'],
+ ),
+
+ #A version based conflicts, nothing we can do.
+ ResolverPlaygroundTestCase(
+ ["=app-misc/X-1", "=app-misc/Y-1"],
+ success = False,
+ mergelist = ["app-misc/Z-1", "app-misc/Z-2", "app-misc/X-1", "app-misc/Y-1"],
+ ignore_mergelist_order = True,
+ slot_collision_solutions = []
+ ),
+ ResolverPlaygroundTestCase(
+ ["=app-misc/X-2", "=app-misc/Y-2"],
+ success = False,
+ mergelist = ["app-misc/Z-1", "app-misc/Z-2", "app-misc/X-2", "app-misc/Y-2"],
+ ignore_mergelist_order = True,
+ slot_collision_solutions = []
+ ),
+
+ ResolverPlaygroundTestCase(
+ ["=app-misc/E-1", "=app-misc/F-1"],
+ success = False,
+ mergelist = ["dev-libs/E-1", "dev-libs/E-2", "app-misc/E-1", "app-misc/F-1"],
+ ignore_mergelist_order = True,
+ slot_collision_solutions = []
+ ),
+
+ #Simple cases.
+ ResolverPlaygroundTestCase(
+ ["sci-libs/L", "sci-libs/M"],
+ success = False,
+ mergelist = ["sci-libs/L-1", "sci-libs/M-1", "sci-libs/K-1"],
+ ignore_mergelist_order = True,
+ slot_collision_solutions = [{"sci-libs/K-1": {"foo": False}, "sci-libs/M-1": {"foo": False}}]
+ ),
+
+ #Avoid duplicates.
+ ResolverPlaygroundTestCase(
+ ["sci-libs/P", "sci-libs/Q:2"],
+ success = False,
+ options = { "--update": True, "--complete-graph": True, "--autounmask": 'n' },
+ mergelist = ["sci-libs/P-1", "sci-libs/Q-1"],
+ ignore_mergelist_order = True,
+ all_permutations=True,
+ slot_collision_solutions = [{"sci-libs/Q-1": {"foo": True}, "sci-libs/P-1": {"foo": True}}]
+ ),
+
+ #Conflict with REQUIRED_USE
+ ResolverPlaygroundTestCase(
+ ["=app-misc/C-1", "=app-misc/B-1"],
+ all_permutations = True,
+ slot_collision_solutions = [],
+ mergelist = ["app-misc/A-1", "app-misc/C-1", "app-misc/B-1"],
+ ignore_mergelist_order = True,
+ success = False),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/resolver/test_use_dep_defaults.py b/portage_with_autodep/pym/portage/tests/resolver/test_use_dep_defaults.py
new file mode 100644
index 0000000..7d17106
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/resolver/test_use_dep_defaults.py
@@ -0,0 +1,40 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class UseDepDefaultsTestCase(TestCase):
+
+ def testUseDepDefaultse(self):
+
+ ebuilds = {
+ "dev-libs/A-1": { "DEPEND": "dev-libs/B[foo]", "RDEPEND": "dev-libs/B[foo]", "EAPI": "2" },
+ "dev-libs/A-2": { "DEPEND": "dev-libs/B[foo(+)]", "RDEPEND": "dev-libs/B[foo(+)]", "EAPI": "4" },
+ "dev-libs/A-3": { "DEPEND": "dev-libs/B[foo(-)]", "RDEPEND": "dev-libs/B[foo(-)]", "EAPI": "4" },
+ "dev-libs/B-1": { "IUSE": "+foo", "EAPI": "1" },
+ "dev-libs/B-2": {},
+ }
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/A-1"],
+ success = True,
+ mergelist = ["dev-libs/B-1", "dev-libs/A-1"]),
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/A-2"],
+ success = True,
+ mergelist = ["dev-libs/B-2", "dev-libs/A-2"]),
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/A-3"],
+ success = True,
+ mergelist = ["dev-libs/B-1", "dev-libs/A-3"]),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
diff --git a/portage_with_autodep/pym/portage/tests/runTests b/portage_with_autodep/pym/portage/tests/runTests
new file mode 100755
index 0000000..6b3311d
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/runTests
@@ -0,0 +1,46 @@
+#!/usr/bin/python
+# runTests.py -- Portage Unit Test Functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import os, sys
+import os.path as osp
+import grp
+import pwd
+import signal
+
+def debug_signal(signum, frame):
+ import pdb
+ pdb.set_trace()
+signal.signal(signal.SIGUSR1, debug_signal)
+
+# Pretend that the current user's uid/gid are the 'portage' uid/gid,
+# so things go smoothly regardless of the current user and global
+# user/group configuration.
+os.environ["PORTAGE_USERNAME"] = pwd.getpwuid(os.getuid()).pw_name
+os.environ["PORTAGE_GRPNAME"] = grp.getgrgid(os.getgid()).gr_name
+
+# Insert our parent dir so we can do shiny import "tests"
+# This line courtesy of Marienz and Pkgcore ;)
+sys.path.insert(0, osp.dirname(osp.dirname(osp.dirname(osp.abspath(__file__)))))
+
+import portage
+
+# Ensure that we don't instantiate portage.settings, so that tests should
+# work the same regardless of global configuration file state/existence.
+portage._disable_legacy_globals()
+
+import portage.tests as tests
+from portage.const import PORTAGE_BIN_PATH
+path = os.environ.get("PATH", "").split(":")
+path = [x for x in path if x]
+if not path or not os.path.samefile(path[0], PORTAGE_BIN_PATH):
+ path.insert(0, PORTAGE_BIN_PATH)
+ os.environ["PATH"] = ":".join(path)
+del path
+
+
+if __name__ == "__main__":
+ result = tests.main()
+ if not result.wasSuccessful():
+ sys.exit(1)
diff --git a/portage_with_autodep/pym/portage/tests/sets/__init__.py b/portage_with_autodep/pym/portage/tests/sets/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/sets/__init__.py
diff --git a/portage_with_autodep/pym/portage/tests/sets/base/__init__.py b/portage_with_autodep/pym/portage/tests/sets/base/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/sets/base/__init__.py
diff --git a/portage_with_autodep/pym/portage/tests/sets/base/__test__ b/portage_with_autodep/pym/portage/tests/sets/base/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/sets/base/__test__
diff --git a/portage_with_autodep/pym/portage/tests/sets/base/testInternalPackageSet.py b/portage_with_autodep/pym/portage/tests/sets/base/testInternalPackageSet.py
new file mode 100644
index 0000000..e0a3478
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/sets/base/testInternalPackageSet.py
@@ -0,0 +1,61 @@
+# testConfigFileSet.py -- Portage Unit Testing Functionality
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.dep import Atom
+from portage.exception import InvalidAtom
+from portage.tests import TestCase
+from portage._sets.base import InternalPackageSet
+
+class InternalPackageSetTestCase(TestCase):
+ """Simple Test Case for InternalPackageSet"""
+
+ def testInternalPackageSet(self):
+ i1_atoms = set(("dev-libs/A", ">=dev-libs/A-1", "dev-libs/B"))
+ i2_atoms = set(("dev-libs/A", "dev-libs/*", "dev-libs/C"))
+
+ i1 = InternalPackageSet(initial_atoms=i1_atoms)
+ i2 = InternalPackageSet(initial_atoms=i2_atoms, allow_wildcard=True)
+ self.assertRaises(InvalidAtom, InternalPackageSet, initial_atoms=i2_atoms)
+
+ self.assertEqual(i1.getAtoms(), i1_atoms)
+ self.assertEqual(i2.getAtoms(), i2_atoms)
+
+ new_atom = Atom("*/*", allow_wildcard=True)
+ self.assertRaises(InvalidAtom, i1.add, new_atom)
+ i2.add(new_atom)
+
+ i2_atoms.add(new_atom)
+
+ self.assertEqual(i1.getAtoms(), i1_atoms)
+ self.assertEqual(i2.getAtoms(), i2_atoms)
+
+ removed_atom = Atom("dev-libs/A")
+
+ i1.remove(removed_atom)
+ i2.remove(removed_atom)
+
+ i1_atoms.remove(removed_atom)
+ i2_atoms.remove(removed_atom)
+
+ self.assertEqual(i1.getAtoms(), i1_atoms)
+ self.assertEqual(i2.getAtoms(), i2_atoms)
+
+ update_atoms = [Atom("dev-libs/C"), Atom("dev-*/C", allow_wildcard=True)]
+
+ self.assertRaises(InvalidAtom, i1.update, update_atoms)
+ i2.update(update_atoms)
+
+ i2_atoms.update(update_atoms)
+
+ self.assertEqual(i1.getAtoms(), i1_atoms)
+ self.assertEqual(i2.getAtoms(), i2_atoms)
+
+ replace_atoms = [Atom("dev-libs/D"), Atom("*-libs/C", allow_wildcard=True)]
+
+ self.assertRaises(InvalidAtom, i1.replace, replace_atoms)
+ i2.replace(replace_atoms)
+
+ i2_atoms = set(replace_atoms)
+
+ self.assertEqual(i2.getAtoms(), i2_atoms)
diff --git a/portage_with_autodep/pym/portage/tests/sets/files/__init__.py b/portage_with_autodep/pym/portage/tests/sets/files/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/sets/files/__init__.py
diff --git a/portage_with_autodep/pym/portage/tests/sets/files/__test__ b/portage_with_autodep/pym/portage/tests/sets/files/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/sets/files/__test__
diff --git a/portage_with_autodep/pym/portage/tests/sets/files/testConfigFileSet.py b/portage_with_autodep/pym/portage/tests/sets/files/testConfigFileSet.py
new file mode 100644
index 0000000..3ec26a0
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/sets/files/testConfigFileSet.py
@@ -0,0 +1,32 @@
+# testConfigFileSet.py -- Portage Unit Testing Functionality
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import tempfile
+
+from portage import os
+from portage.tests import TestCase, test_cps
+from portage._sets.files import ConfigFileSet
+
+class ConfigFileSetTestCase(TestCase):
+ """Simple Test Case for ConfigFileSet"""
+
+ def setUp(self):
+ fd, self.testfile = tempfile.mkstemp(suffix=".testdata", prefix=self.__class__.__name__, text=True)
+ f = os.fdopen(fd, 'w')
+ for i in range(0, len(test_cps)):
+ atom = test_cps[i]
+ if i % 2 == 0:
+ f.write(atom + ' abc def\n')
+ else:
+ f.write(atom + '\n')
+ f.close()
+
+ def tearDown(self):
+ os.unlink(self.testfile)
+
+ def testConfigStaticFileSet(self):
+ s = ConfigFileSet(self.testfile)
+ s.load()
+ self.assertEqual(set(test_cps), s.getAtoms())
+
diff --git a/portage_with_autodep/pym/portage/tests/sets/files/testStaticFileSet.py b/portage_with_autodep/pym/portage/tests/sets/files/testStaticFileSet.py
new file mode 100644
index 0000000..d515a67
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/sets/files/testStaticFileSet.py
@@ -0,0 +1,27 @@
+# testStaticFileSet.py -- Portage Unit Testing Functionality
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import tempfile
+
+from portage import os
+from portage.tests import TestCase, test_cps
+from portage._sets.files import StaticFileSet
+
+class StaticFileSetTestCase(TestCase):
+ """Simple Test Case for StaticFileSet"""
+
+ def setUp(self):
+ fd, self.testfile = tempfile.mkstemp(suffix=".testdata", prefix=self.__class__.__name__, text=True)
+ f = os.fdopen(fd, 'w')
+ f.write("\n".join(test_cps))
+ f.close()
+
+ def tearDown(self):
+ os.unlink(self.testfile)
+
+ def testSampleStaticFileSet(self):
+ s = StaticFileSet(self.testfile)
+ s.load()
+ self.assertEqual(set(test_cps), s.getAtoms())
+
diff --git a/portage_with_autodep/pym/portage/tests/sets/shell/__init__.py b/portage_with_autodep/pym/portage/tests/sets/shell/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/sets/shell/__init__.py
diff --git a/portage_with_autodep/pym/portage/tests/sets/shell/__test__ b/portage_with_autodep/pym/portage/tests/sets/shell/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/sets/shell/__test__
diff --git a/portage_with_autodep/pym/portage/tests/sets/shell/testShell.py b/portage_with_autodep/pym/portage/tests/sets/shell/testShell.py
new file mode 100644
index 0000000..2cdd833
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/sets/shell/testShell.py
@@ -0,0 +1,28 @@
+# testCommandOututSet.py -- Portage Unit Testing Functionality
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.process import find_binary
+from portage.tests import TestCase, test_cps
+from portage._sets.shell import CommandOutputSet
+
+class CommandOutputSetTestCase(TestCase):
+ """Simple Test Case for CommandOutputSet"""
+
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def testCommand(self):
+
+ input = set(test_cps)
+ command = find_binary("bash")
+ command += " -c '"
+ for a in input:
+ command += " echo -e \"%s\" ; " % a
+ command += "'"
+ s = CommandOutputSet(command)
+ atoms = s.getAtoms()
+ self.assertEqual(atoms, input)
diff --git a/portage_with_autodep/pym/portage/tests/unicode/__init__.py b/portage_with_autodep/pym/portage/tests/unicode/__init__.py
new file mode 100644
index 0000000..21a391a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/unicode/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/tests/unicode/__test__ b/portage_with_autodep/pym/portage/tests/unicode/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/unicode/__test__
diff --git a/portage_with_autodep/pym/portage/tests/unicode/test_string_format.py b/portage_with_autodep/pym/portage/tests/unicode/test_string_format.py
new file mode 100644
index 0000000..fb6e8e0
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/unicode/test_string_format.py
@@ -0,0 +1,108 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+
+from portage import _encodings, _unicode_decode
+from portage.exception import PortageException
+from portage.tests import TestCase
+from _emerge.DependencyArg import DependencyArg
+from _emerge.UseFlagDisplay import UseFlagDisplay
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+STR_IS_UNICODE = sys.hexversion >= 0x3000000
+
+class StringFormatTestCase(TestCase):
+ """
+ Test that string formatting works correctly in the current interpretter,
+ which may be either python2 or python3.
+ """
+
+ # In order to get some unicode test strings in a way that works in
+ # both python2 and python3, write them here as byte strings and
+ # decode them before use. This assumes _encodings['content'] is
+ # utf_8.
+
+ unicode_strings = (
+ b'\xE2\x80\x98',
+ b'\xE2\x80\x99',
+ )
+
+ def testDependencyArg(self):
+
+ self.assertEqual(_encodings['content'], 'utf_8')
+
+ for arg_bytes in self.unicode_strings:
+ arg_unicode = _unicode_decode(arg_bytes, encoding=_encodings['content'])
+ dependency_arg = DependencyArg(arg=arg_unicode)
+
+ # Force unicode format string so that __unicode__() is
+ # called in python2.
+ formatted_str = _unicode_decode("%s") % (dependency_arg,)
+ self.assertEqual(formatted_str, arg_unicode)
+
+ if STR_IS_UNICODE:
+
+ # Test the __str__ method which returns unicode in python3
+ formatted_str = "%s" % (dependency_arg,)
+ self.assertEqual(formatted_str, arg_unicode)
+
+ else:
+
+ # Test the __str__ method which returns encoded bytes in python2
+ formatted_bytes = "%s" % (dependency_arg,)
+ self.assertEqual(formatted_bytes, arg_bytes)
+
+ def testPortageException(self):
+
+ self.assertEqual(_encodings['content'], 'utf_8')
+
+ for arg_bytes in self.unicode_strings:
+ arg_unicode = _unicode_decode(arg_bytes, encoding=_encodings['content'])
+ e = PortageException(arg_unicode)
+
+ # Force unicode format string so that __unicode__() is
+ # called in python2.
+ formatted_str = _unicode_decode("%s") % (e,)
+ self.assertEqual(formatted_str, arg_unicode)
+
+ if STR_IS_UNICODE:
+
+ # Test the __str__ method which returns unicode in python3
+ formatted_str = "%s" % (e,)
+ self.assertEqual(formatted_str, arg_unicode)
+
+ else:
+
+ # Test the __str__ method which returns encoded bytes in python2
+ formatted_bytes = "%s" % (e,)
+ self.assertEqual(formatted_bytes, arg_bytes)
+
+ def testUseFlagDisplay(self):
+
+ self.assertEqual(_encodings['content'], 'utf_8')
+
+ for enabled in (True, False):
+ for forced in (True, False):
+ for arg_bytes in self.unicode_strings:
+ arg_unicode = _unicode_decode(arg_bytes, encoding=_encodings['content'])
+ e = UseFlagDisplay(arg_unicode, enabled, forced)
+
+ # Force unicode format string so that __unicode__() is
+ # called in python2.
+ formatted_str = _unicode_decode("%s") % (e,)
+ self.assertEqual(isinstance(formatted_str, basestring), True)
+
+ if STR_IS_UNICODE:
+
+ # Test the __str__ method which returns unicode in python3
+ formatted_str = "%s" % (e,)
+ self.assertEqual(isinstance(formatted_str, str), True)
+
+ else:
+
+ # Test the __str__ method which returns encoded bytes in python2
+ formatted_bytes = "%s" % (e,)
+ self.assertEqual(isinstance(formatted_bytes, bytes), True)
diff --git a/portage_with_autodep/pym/portage/tests/util/__init__.py b/portage_with_autodep/pym/portage/tests/util/__init__.py
new file mode 100644
index 0000000..69ce189
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/util/__init__.py
@@ -0,0 +1,4 @@
+# tests/portage.util/__init__.py -- Portage Unit Test functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
diff --git a/portage_with_autodep/pym/portage/tests/util/__test__ b/portage_with_autodep/pym/portage/tests/util/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/util/__test__
diff --git a/portage_with_autodep/pym/portage/tests/util/test_digraph.py b/portage_with_autodep/pym/portage/tests/util/test_digraph.py
new file mode 100644
index 0000000..b65c0b1
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/util/test_digraph.py
@@ -0,0 +1,201 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.util.digraph import digraph
+#~ from portage.util import noiselimit
+import portage.util
+
+class DigraphTest(TestCase):
+
+ def testBackwardCompatibility(self):
+ g = digraph()
+ f = g.copy()
+ g.addnode("A", None)
+ self.assertEqual("A" in g, True)
+ self.assertEqual(bool(g), True)
+ self.assertEqual(g.allnodes(), ["A"])
+ self.assertEqual(g.allzeros(), ["A"])
+ self.assertEqual(g.hasnode("A"), True)
+
+ def testDigraphEmptyGraph(self):
+ g = digraph()
+ f = g.clone()
+ for x in g, f:
+ self.assertEqual(bool(x), False)
+ self.assertEqual(x.contains("A"), False)
+ self.assertEqual(x.firstzero(), None)
+ self.assertRaises(KeyError, x.remove, "A")
+ x.delnode("A")
+ self.assertEqual(list(x), [])
+ self.assertEqual(x.get("A"), None)
+ self.assertEqual(x.get("A", "default"), "default")
+ self.assertEqual(x.all_nodes(), [])
+ self.assertEqual(x.leaf_nodes(), [])
+ self.assertEqual(x.root_nodes(), [])
+ self.assertRaises(KeyError, x.child_nodes, "A")
+ self.assertRaises(KeyError, x.parent_nodes, "A")
+ self.assertEqual(x.hasallzeros(), True)
+ self.assertRaises(KeyError, list, x.bfs("A"))
+ self.assertRaises(KeyError, x.shortest_path, "A", "B")
+ self.assertRaises(KeyError, x.remove_edge, "A", "B")
+ self.assertEqual(x.get_cycles(), [])
+ x.difference_update("A")
+ portage.util.noiselimit = -2
+ x.debug_print()
+ portage.util.noiselimit = 0
+
+ def testDigraphCircle(self):
+ g = digraph()
+ g.add("A", "B", -1)
+ g.add("B", "C", 0)
+ g.add("C", "D", 1)
+ g.add("D", "A", 2)
+
+ f = g.clone()
+ for x in g, f:
+ self.assertEqual(bool(x), True)
+ self.assertEqual(x.contains("A"), True)
+ self.assertEqual(x.firstzero(), None)
+ self.assertRaises(KeyError, x.remove, "Z")
+ x.delnode("Z")
+ self.assertEqual(list(x), ["A", "B", "C", "D"])
+ self.assertEqual(x.get("A"), "A")
+ self.assertEqual(x.get("A", "default"), "A")
+ self.assertEqual(x.all_nodes(), ["A", "B", "C", "D"])
+ self.assertEqual(x.leaf_nodes(), [])
+ self.assertEqual(x.root_nodes(), [])
+ self.assertEqual(x.child_nodes("A"), ["D"])
+ self.assertEqual(x.child_nodes("A", ignore_priority=2), [])
+ self.assertEqual(x.parent_nodes("A"), ["B"])
+ self.assertEqual(x.parent_nodes("A", ignore_priority=-2), ["B"])
+ self.assertEqual(x.parent_nodes("A", ignore_priority=-1), [])
+ self.assertEqual(x.hasallzeros(), False)
+ self.assertEqual(list(x.bfs("A")), [(None, "A"), ("A", "D"), ("D", "C"), ("C", "B")])
+ self.assertEqual(x.shortest_path("A", "D"), ["A", "D"])
+ self.assertEqual(x.shortest_path("D", "A"), ["D", "C", "B", "A"])
+ self.assertEqual(x.shortest_path("A", "D", ignore_priority=2), None)
+ self.assertEqual(x.shortest_path("D", "A", ignore_priority=-2), ["D", "C", "B", "A"])
+ cycles = set(tuple(y) for y in x.get_cycles())
+ self.assertEqual(cycles, set([("D", "C", "B", "A"), ("C", "B", "A", "D"), ("B", "A", "D", "C"), \
+ ("A", "D", "C", "B")]))
+ x.remove_edge("A", "B")
+ self.assertEqual(x.get_cycles(), [])
+ x.difference_update(["D"])
+ self.assertEqual(x.all_nodes(), ["A", "B", "C"])
+ portage.util.noiselimit = -2
+ x.debug_print()
+ portage.util.noiselimit = 0
+
+ def testDigraphTree(self):
+ g = digraph()
+ g.add("B", "A", -1)
+ g.add("C", "A", 0)
+ g.add("D", "C", 1)
+ g.add("E", "C", 2)
+
+ f = g.clone()
+ for x in g, f:
+ self.assertEqual(bool(x), True)
+ self.assertEqual(x.contains("A"), True)
+ self.assertEqual(x.firstzero(), "B")
+ self.assertRaises(KeyError, x.remove, "Z")
+ x.delnode("Z")
+ self.assertEqual(set(x), set(["A", "B", "C", "D", "E"]))
+ self.assertEqual(x.get("A"), "A")
+ self.assertEqual(x.get("A", "default"), "A")
+ self.assertEqual(set(x.all_nodes()), set(["A", "B", "C", "D", "E"]))
+ self.assertEqual(set(x.leaf_nodes()), set(["B", "D", "E"]))
+ self.assertEqual(set(x.leaf_nodes(ignore_priority=0)), set(["A", "B", "D", "E"]))
+ self.assertEqual(x.root_nodes(), ["A"])
+ self.assertEqual(set(x.root_nodes(ignore_priority=0)), set(["A", "B", "C"]))
+ self.assertEqual(set(x.child_nodes("A")), set(["B", "C"]))
+ self.assertEqual(x.child_nodes("A", ignore_priority=2), [])
+ self.assertEqual(x.parent_nodes("B"), ["A"])
+ self.assertEqual(x.parent_nodes("B", ignore_priority=-2), ["A"])
+ self.assertEqual(x.parent_nodes("B", ignore_priority=-1), [])
+ self.assertEqual(x.hasallzeros(), False)
+ self.assertEqual(list(x.bfs("A")), [(None, "A"), ("A", "C"), ("A", "B"), ("C", "E"), ("C", "D")])
+ self.assertEqual(x.shortest_path("A", "D"), ["A", "C", "D"])
+ self.assertEqual(x.shortest_path("D", "A"), None)
+ self.assertEqual(x.shortest_path("A", "D", ignore_priority=2), None)
+ cycles = set(tuple(y) for y in x.get_cycles())
+ self.assertEqual(cycles, set())
+ x.remove("D")
+ self.assertEqual(set(x.all_nodes()), set(["A", "B", "C", "E"]))
+ x.remove("C")
+ self.assertEqual(set(x.all_nodes()), set(["A", "B", "E"]))
+ portage.util.noiselimit = -2
+ x.debug_print()
+ portage.util.noiselimit = 0
+ self.assertRaises(KeyError, x.remove_edge, "A", "E")
+
+ def testDigraphCompleteGraph(self):
+ g = digraph()
+ g.add("A", "B", -1)
+ g.add("B", "A", 1)
+ g.add("A", "C", 1)
+ g.add("C", "A", -1)
+ g.add("C", "B", 1)
+ g.add("B", "C", 1)
+
+ f = g.clone()
+ for x in g, f:
+ self.assertEqual(bool(x), True)
+ self.assertEqual(x.contains("A"), True)
+ self.assertEqual(x.firstzero(), None)
+ self.assertRaises(KeyError, x.remove, "Z")
+ x.delnode("Z")
+ self.assertEqual(list(x), ["A", "B", "C"])
+ self.assertEqual(x.get("A"), "A")
+ self.assertEqual(x.get("A", "default"), "A")
+ self.assertEqual(x.all_nodes(), ["A", "B", "C"])
+ self.assertEqual(x.leaf_nodes(), [])
+ self.assertEqual(x.root_nodes(), [])
+ self.assertEqual(set(x.child_nodes("A")), set(["B", "C"]))
+ self.assertEqual(x.child_nodes("A", ignore_priority=0), ["B"])
+ self.assertEqual(set(x.parent_nodes("A")), set(["B", "C"]))
+ self.assertEqual(x.parent_nodes("A", ignore_priority=0), ["C"])
+ self.assertEqual(x.parent_nodes("A", ignore_priority=1), [])
+ self.assertEqual(x.hasallzeros(), False)
+ self.assertEqual(list(x.bfs("A")), [(None, "A"), ("A", "C"), ("A", "B")])
+ self.assertEqual(x.shortest_path("A", "C"), ["A", "C"])
+ self.assertEqual(x.shortest_path("C", "A"), ["C", "A"])
+ self.assertEqual(x.shortest_path("A", "C", ignore_priority=0), ["A", "B", "C"])
+ self.assertEqual(x.shortest_path("C", "A", ignore_priority=0), ["C", "A"])
+ cycles = set(tuple(y) for y in x.get_cycles())
+ self.assertEqual(cycles, set([("C", "A"), ("A", "B"), ("A", "C")]))
+ x.remove_edge("A", "B")
+ self.assertEqual(x.get_cycles(), [["C", "A"], ["A", "C"], ["C", "B"]])
+ x.difference_update(["C"])
+ self.assertEqual(x.all_nodes(), ["A", "B"])
+ portage.util.noiselimit = -2
+ x.debug_print()
+ portage.util.noiselimit = 0
+
+ def testDigraphIgnorePriority(self):
+
+ def always_true(dummy):
+ return True
+
+ def always_false(dummy):
+ return False
+
+ g = digraph()
+ g.add("A", "B")
+
+ self.assertEqual(g.parent_nodes("A"), ["B"])
+ self.assertEqual(g.parent_nodes("A", ignore_priority=always_false), ["B"])
+ self.assertEqual(g.parent_nodes("A", ignore_priority=always_true), [])
+
+ self.assertEqual(g.child_nodes("B"), ["A"])
+ self.assertEqual(g.child_nodes("B", ignore_priority=always_false), ["A"])
+ self.assertEqual(g.child_nodes("B", ignore_priority=always_true), [])
+
+ self.assertEqual(g.leaf_nodes(), ["A"])
+ self.assertEqual(g.leaf_nodes(ignore_priority=always_false), ["A"])
+ self.assertEqual(g.leaf_nodes(ignore_priority=always_true), ["A", "B"])
+
+ self.assertEqual(g.root_nodes(), ["B"])
+ self.assertEqual(g.root_nodes(ignore_priority=always_false), ["B"])
+ self.assertEqual(g.root_nodes(ignore_priority=always_true), ["A", "B"])
diff --git a/portage_with_autodep/pym/portage/tests/util/test_getconfig.py b/portage_with_autodep/pym/portage/tests/util/test_getconfig.py
new file mode 100644
index 0000000..22e0bfc
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/util/test_getconfig.py
@@ -0,0 +1,29 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from portage.const import PORTAGE_BASE_PATH
+from portage.tests import TestCase
+from portage.util import getconfig
+
+class GetConfigTestCase(TestCase):
+ """
+ Test that getconfig() produces that same result as bash would when
+ sourcing the same input.
+ """
+
+ _cases = {
+ 'FETCHCOMMAND' : '/usr/bin/wget -t 3 -T 60 --passive-ftp -O "${DISTDIR}/${FILE}" "${URI}"',
+ 'FETCHCOMMAND_RSYNC' : 'rsync -avP "${URI}" "${DISTDIR}/${FILE}"',
+ 'FETCHCOMMAND_SFTP' : 'bash -c "x=\\${2#sftp://} ; host=\\${x%%/*} ; port=\\${host##*:} ; host=\\${host%:*} ; [[ \\${host} = \\${port} ]] && port=22 ; exec sftp -P \\${port} \\"\\${host}:/\\${x#*/}\\" \\"\\$1\\"" sftp "${DISTDIR}/${FILE}" "${URI}"',
+ 'FETCHCOMMAND_SSH' : 'bash -c "x=\\${2#ssh://} ; host=\\${x%%/*} ; port=\\${host##*:} ; host=\\${host%:*} ; [[ \\${host} = \\${port} ]] && port=22 ; exec rsync --rsh=\\"ssh -p\\${port}\\" -avP \\"\\${host}:/\\${x#*/}\\" \\"\\$1\\"" rsync "${DISTDIR}/${FILE}" "${URI}"',
+ 'PORTAGE_ELOG_MAILSUBJECT' : '[portage] ebuild log for ${PACKAGE} on ${HOST}'
+ }
+
+ def testGetConfig(self):
+
+ make_globals_file = os.path.join(PORTAGE_BASE_PATH,
+ 'cnf', 'make.globals')
+ d = getconfig(make_globals_file)
+ for k, v in self._cases.items():
+ self.assertEqual(d[k], v)
diff --git a/portage_with_autodep/pym/portage/tests/util/test_grabdict.py b/portage_with_autodep/pym/portage/tests/util/test_grabdict.py
new file mode 100644
index 0000000..e62a75d
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/util/test_grabdict.py
@@ -0,0 +1,11 @@
+# test_grabDict.py -- Portage Unit Testing Functionality
+# Copyright 2006-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+#from portage.util import grabdict
+
+class GrabDictTestCase(TestCase):
+
+ def testGrabDictPass(self):
+ pass
diff --git a/portage_with_autodep/pym/portage/tests/util/test_normalizedPath.py b/portage_with_autodep/pym/portage/tests/util/test_normalizedPath.py
new file mode 100644
index 0000000..f993886
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/util/test_normalizedPath.py
@@ -0,0 +1,14 @@
+# test_normalizePath.py -- Portage Unit Testing Functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+
+class NormalizePathTestCase(TestCase):
+
+ def testNormalizePath(self):
+
+ from portage.util import normalize_path
+ path = "///foo/bar/baz"
+ good = "/foo/bar/baz"
+ self.assertEqual(normalize_path(path), good)
diff --git a/portage_with_autodep/pym/portage/tests/util/test_stackDictList.py b/portage_with_autodep/pym/portage/tests/util/test_stackDictList.py
new file mode 100644
index 0000000..678001c
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/util/test_stackDictList.py
@@ -0,0 +1,17 @@
+# test_stackDictList.py -- Portage Unit Testing Functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+
+class StackDictListTestCase(TestCase):
+
+ def testStackDictList(self):
+ from portage.util import stack_dictlist
+
+ tests = [ ({'a':'b'},{'x':'y'},False,{'a':['b'],'x':['y']}) ]
+ tests.append(( {'KEYWORDS':['alpha','x86']},{'KEYWORDS':['-*']},True,{} ))
+ tests.append(( {'KEYWORDS':['alpha','x86']},{'KEYWORDS':['-x86']},True,{'KEYWORDS':['alpha']} ))
+ for test in tests:
+ self.assertEqual(
+ stack_dictlist([test[0],test[1]],incremental=test[2]), test[3] )
diff --git a/portage_with_autodep/pym/portage/tests/util/test_stackDicts.py b/portage_with_autodep/pym/portage/tests/util/test_stackDicts.py
new file mode 100644
index 0000000..0d2cadd
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/util/test_stackDicts.py
@@ -0,0 +1,36 @@
+# test_stackDicts.py -- Portage Unit Testing Functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.util import stack_dicts
+
+
+class StackDictsTestCase(TestCase):
+
+ def testStackDictsPass(self):
+
+ tests = [ ( [ { "a":"b" }, { "b":"c" } ], { "a":"b", "b":"c" },
+ False, [], False ),
+ ( [ { "a":"b" }, { "a":"c" } ], { "a":"b c" },
+ True, [], False ),
+ ( [ { "a":"b" }, { "a":"c" } ], { "a":"b c" },
+ False, ["a"], False ),
+ ( [ { "a":"b" }, None ], { "a":"b" },
+ False, [], True ),
+ ( [ None ], {}, False, [], False ),
+ ( [ None, {}], {}, False, [], True ) ]
+
+
+ for test in tests:
+ result = stack_dicts( test[0], test[2], test[3], test[4] )
+ self.assertEqual( result, test[1] )
+
+ def testStackDictsFail(self):
+
+ tests = [ ( [ None, {} ], None, False, [], True ),
+ ( [ { "a":"b"}, {"a":"c" } ], { "a":"b c" },
+ False, [], False ) ]
+ for test in tests:
+ result = stack_dicts( test[0], test[2], test[3], test[4] )
+ self.assertNotEqual( result , test[1] )
diff --git a/portage_with_autodep/pym/portage/tests/util/test_stackLists.py b/portage_with_autodep/pym/portage/tests/util/test_stackLists.py
new file mode 100644
index 0000000..8d01ea5
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/util/test_stackLists.py
@@ -0,0 +1,19 @@
+# test_stackLists.py -- Portage Unit Testing Functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.util import stack_lists
+
+class StackListsTestCase(TestCase):
+
+ def testStackLists(self):
+
+ tests = [ ( [ ['a','b','c'], ['d','e','f'] ], ['a','c','b','e','d','f'], False ),
+ ( [ ['a','x'], ['b','x'] ], ['a','x','b'], False ),
+ ( [ ['a','b','c'], ['-*'] ], [], True ),
+ ( [ ['a'], ['-a'] ], [], True ) ]
+
+ for test in tests:
+ result = stack_lists( test[0], test[2] )
+ self.assertEqual( result , test[1] )
diff --git a/portage_with_autodep/pym/portage/tests/util/test_uniqueArray.py b/portage_with_autodep/pym/portage/tests/util/test_uniqueArray.py
new file mode 100644
index 0000000..2a1a209
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/util/test_uniqueArray.py
@@ -0,0 +1,24 @@
+# test_uniqueArray.py -- Portage Unit Testing Functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from portage.tests import TestCase
+from portage.util import unique_array
+
+class UniqueArrayTestCase(TestCase):
+
+ def testUniqueArrayPass(self):
+ """
+ test portage.util.uniqueArray()
+ """
+
+ tests = [ ( ["a","a","a",os,os,[],[],[]], ['a',os,[]] ),
+ ( [1,1,1,2,3,4,4] , [1,2,3,4]) ]
+
+ for test in tests:
+ result = unique_array( test[0] )
+ for item in test[1]:
+ number = result.count(item)
+ self.assertFalse( number is not 1, msg="%s contains %s of %s, \
+ should be only 1" % (result, number, item) )
diff --git a/portage_with_autodep/pym/portage/tests/util/test_varExpand.py b/portage_with_autodep/pym/portage/tests/util/test_varExpand.py
new file mode 100644
index 0000000..7b528d6
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/util/test_varExpand.py
@@ -0,0 +1,92 @@
+# test_varExpand.py -- Portage Unit Testing Functionality
+# Copyright 2006-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.util import varexpand
+
+class VarExpandTestCase(TestCase):
+
+ def testVarExpandPass(self):
+
+ varDict = { "a":"5", "b":"7", "c":"-5" }
+ for key in varDict:
+ result = varexpand( "$%s" % key, varDict )
+
+ self.assertFalse( result != varDict[key],
+ msg="Got %s != %s, from varexpand( %s, %s )" % \
+ ( result, varDict[key], "$%s" % key, varDict ) )
+ result = varexpand( "${%s}" % key, varDict )
+ self.assertFalse( result != varDict[key],
+ msg="Got %s != %s, from varexpand( %s, %s )" % \
+ ( result, varDict[key], "${%s}" % key, varDict ) )
+
+ def testVarExpandBackslashes(self):
+ """
+ We want to behave like bash does when expanding a variable
+ assignment in a sourced file, in which case it performs
+ backslash removal for \\ and \$ but nothing more. It also
+ removes escaped newline characters. Note that we don't
+ handle escaped quotes here, since getconfig() uses shlex
+ to handle that earlier.
+ """
+
+ varDict = {}
+ tests = [
+ ("\\", "\\"),
+ ("\\\\", "\\"),
+ ("\\\\\\", "\\\\"),
+ ("\\\\\\\\", "\\\\"),
+ ("\\$", "$"),
+ ("\\\\$", "\\$"),
+ ("\\a", "\\a"),
+ ("\\b", "\\b"),
+ ("\\n", "\\n"),
+ ("\\r", "\\r"),
+ ("\\t", "\\t"),
+ ("\\\n", ""),
+ ("\\\"", "\\\""),
+ ("\\'", "\\'"),
+ ]
+ for test in tests:
+ result = varexpand( test[0], varDict )
+ self.assertFalse( result != test[1],
+ msg="Got %s != %s from varexpand( %s, %s )" \
+ % ( result, test[1], test[0], varDict ) )
+
+ def testVarExpandDoubleQuotes(self):
+
+ varDict = { "a":"5" }
+ tests = [ ("\"${a}\"", "\"5\"") ]
+ for test in tests:
+ result = varexpand( test[0], varDict )
+ self.assertFalse( result != test[1],
+ msg="Got %s != %s from varexpand( %s, %s )" \
+ % ( result, test[1], test[0], varDict ) )
+
+ def testVarExpandSingleQuotes(self):
+
+ varDict = { "a":"5" }
+ tests = [ ("\'${a}\'", "\'${a}\'") ]
+ for test in tests:
+ result = varexpand( test[0], varDict )
+ self.assertFalse( result != test[1],
+ msg="Got %s != %s from varexpand( %s, %s )" \
+ % ( result, test[1], test[0], varDict ) )
+
+ def testVarExpandFail(self):
+
+ varDict = { "a":"5", "b":"7", "c":"15" }
+
+ testVars = [ "fail" ]
+
+ for var in testVars:
+ result = varexpand( "$%s" % var, varDict )
+ self.assertFalse( len(result),
+ msg="Got %s == %s, from varexpand( %s, %s )" \
+ % ( result, var, "$%s" % var, varDict ) )
+
+ result = varexpand( "${%s}" % var, varDict )
+ self.assertFalse( len(result),
+ msg="Got %s == %s, from varexpand( %s, %s )" \
+ % ( result, var, "${%s}" % var, varDict ) )
diff --git a/portage_with_autodep/pym/portage/tests/versions/__init__.py b/portage_with_autodep/pym/portage/tests/versions/__init__.py
new file mode 100644
index 0000000..2b14180
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/versions/__init__.py
@@ -0,0 +1,3 @@
+# tests/portage.versions/__init__.py -- Portage Unit Test functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/tests/versions/__test__ b/portage_with_autodep/pym/portage/tests/versions/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/versions/__test__
diff --git a/portage_with_autodep/pym/portage/tests/versions/test_cpv_sort_key.py b/portage_with_autodep/pym/portage/tests/versions/test_cpv_sort_key.py
new file mode 100644
index 0000000..a223d78
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/versions/test_cpv_sort_key.py
@@ -0,0 +1,16 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.versions import cpv_sort_key
+
+class CpvSortKeyTestCase(TestCase):
+
+ def testCpvSortKey(self):
+
+ tests = [ (("a/b-2_alpha", "a", "b", "a/b-2", "a/a-1", "a/b-1"),
+ ( "a", "a/a-1", "a/b-1", "a/b-2_alpha", "a/b-2", "b")),
+ ]
+
+ for test in tests:
+ self.assertEqual( tuple(sorted(test[0], key=cpv_sort_key())), test[1] )
diff --git a/portage_with_autodep/pym/portage/tests/versions/test_vercmp.py b/portage_with_autodep/pym/portage/tests/versions/test_vercmp.py
new file mode 100644
index 0000000..aa7969c
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/versions/test_vercmp.py
@@ -0,0 +1,80 @@
+# test_vercmp.py -- Portage Unit Testing Functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.versions import vercmp
+
+class VerCmpTestCase(TestCase):
+ """ A simple testCase for portage.versions.vercmp()
+ """
+
+ def testVerCmpGreater(self):
+
+ tests = [ ( "6.0", "5.0"), ("5.0","5"),
+ ("1.0-r1", "1.0-r0"),
+ ("1.0-r1", "1.0"),
+ ("cvs.9999", "9999"),
+ ("999999999999999999999999999999", "999999999999999999999999999998"),
+ ("1.0.0", "1.0"),
+ ("1.0.0", "1.0b"),
+ ("1b", "1"),
+ ("1b_p1", "1_p1"),
+ ("1.1b", "1.1"),
+ ("12.2.5", "12.2b"),
+ ]
+ for test in tests:
+ self.assertFalse( vercmp( test[0], test[1] ) <= 0, msg="%s < %s? Wrong!" % (test[0],test[1]) )
+
+ def testVerCmpLess(self):
+ """
+ pre < alpha < beta < rc < p -> test each of these, they are inductive (or should be..)
+ """
+ tests = [ ( "4.0", "5.0"), ("5", "5.0"), ("1.0_pre2","1.0_p2"),
+ ("1.0_alpha2", "1.0_p2"),("1.0_alpha1", "1.0_beta1"),("1.0_beta3","1.0_rc3"),
+ ("1.001000000000000000001", "1.001000000000000000002"),
+ ("1.00100000000", "1.0010000000000000001"),
+ ("9999", "cvs.9999"),
+ ("999999999999999999999999999998", "999999999999999999999999999999"),
+ ("1.01", "1.1"),
+ ("1.0-r0", "1.0-r1"),
+ ("1.0", "1.0-r1"),
+ ("1.0", "1.0.0"),
+ ("1.0b", "1.0.0"),
+ ("1_p1", "1b_p1"),
+ ("1", "1b"),
+ ("1.1", "1.1b"),
+ ("12.2b", "12.2.5"),
+ ]
+ for test in tests:
+ self.assertFalse( vercmp( test[0], test[1]) >= 0, msg="%s > %s? Wrong!" % (test[0],test[1]))
+
+
+ def testVerCmpEqual(self):
+
+ tests = [ ("4.0", "4.0"),
+ ("1.0", "1.0"),
+ ("1.0-r0", "1.0"),
+ ("1.0", "1.0-r0"),
+ ("1.0-r0", "1.0-r0"),
+ ("1.0-r1", "1.0-r1")]
+ for test in tests:
+ self.assertFalse( vercmp( test[0], test[1]) != 0, msg="%s != %s? Wrong!" % (test[0],test[1]))
+
+ def testVerNotEqual(self):
+
+ tests = [ ("1","2"),("1.0_alpha","1.0_pre"),("1.0_beta","1.0_alpha"),
+ ("0", "0.0"),
+ ("cvs.9999", "9999"),
+ ("1.0-r0", "1.0-r1"),
+ ("1.0-r1", "1.0-r0"),
+ ("1.0", "1.0-r1"),
+ ("1.0-r1", "1.0"),
+ ("1.0", "1.0.0"),
+ ("1_p1", "1b_p1"),
+ ("1b", "1"),
+ ("1.1b", "1.1"),
+ ("12.2b", "12.2"),
+ ]
+ for test in tests:
+ self.assertFalse( vercmp( test[0], test[1]) == 0, msg="%s == %s? Wrong!" % (test[0],test[1]))
diff --git a/portage_with_autodep/pym/portage/tests/xpak/__init__.py b/portage_with_autodep/pym/portage/tests/xpak/__init__.py
new file mode 100644
index 0000000..9c3f524
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/xpak/__init__.py
@@ -0,0 +1,3 @@
+# tests/portage.dep/__init__.py -- Portage Unit Test functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/tests/xpak/__test__ b/portage_with_autodep/pym/portage/tests/xpak/__test__
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/xpak/__test__
diff --git a/portage_with_autodep/pym/portage/tests/xpak/test_decodeint.py b/portage_with_autodep/pym/portage/tests/xpak/test_decodeint.py
new file mode 100644
index 0000000..2da5735
--- /dev/null
+++ b/portage_with_autodep/pym/portage/tests/xpak/test_decodeint.py
@@ -0,0 +1,16 @@
+# xpak/test_decodeint.py
+# Copright Gentoo Foundation 2006
+# Portage Unit Testing Functionality
+
+from portage.tests import TestCase
+from portage.xpak import decodeint, encodeint
+
+class testDecodeIntTestCase(TestCase):
+
+ def testDecodeInt(self):
+
+ for n in range(1000):
+ self.assertEqual(decodeint(encodeint(n)), n)
+
+ for n in (2 ** 32 - 1,):
+ self.assertEqual(decodeint(encodeint(n)), n)
diff --git a/portage_with_autodep/pym/portage/update.py b/portage_with_autodep/pym/portage/update.py
new file mode 100644
index 0000000..52ab506
--- /dev/null
+++ b/portage_with_autodep/pym/portage/update.py
@@ -0,0 +1,320 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import errno
+import io
+import re
+import stat
+import sys
+
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.dep:Atom,dep_getkey,isvalidatom,' + \
+ 'remove_slot',
+ 'portage.util:ConfigProtect,new_protect_filename,' + \
+ 'normalize_path,write_atomic,writemsg',
+ 'portage.util.listdir:_ignorecvs_dirs',
+ 'portage.versions:ververify'
+)
+
+from portage.const import USER_CONFIG_PATH
+from portage.exception import DirectoryNotFound, InvalidAtom, PortageException
+from portage.localization import _
+
+if sys.hexversion >= 0x3000000:
+ long = int
+
+ignored_dbentries = ("CONTENTS", "environment.bz2")
+
+def update_dbentry(update_cmd, mycontent):
+ if update_cmd[0] == "move":
+ old_value = str(update_cmd[1])
+ if old_value in mycontent:
+ new_value = str(update_cmd[2])
+ old_value = re.escape(old_value);
+ mycontent = re.sub(old_value+"(:|$|\\s)", new_value+"\\1", mycontent)
+ def myreplace(matchobj):
+ # Strip slot and * operator if necessary
+ # so that ververify works.
+ ver = remove_slot(matchobj.group(2))
+ ver = ver.rstrip("*")
+ if ververify(ver):
+ return "%s-%s" % (new_value, matchobj.group(2))
+ else:
+ return "".join(matchobj.groups())
+ mycontent = re.sub("(%s-)(\\S*)" % old_value, myreplace, mycontent)
+ elif update_cmd[0] == "slotmove" and update_cmd[1].operator is None:
+ pkg, origslot, newslot = update_cmd[1:]
+ old_value = "%s:%s" % (pkg, origslot)
+ if old_value in mycontent:
+ old_value = re.escape(old_value)
+ new_value = "%s:%s" % (pkg, newslot)
+ mycontent = re.sub(old_value+"($|\\s)", new_value+"\\1", mycontent)
+ return mycontent
+
+def update_dbentries(update_iter, mydata):
+ """Performs update commands and returns a
+ dict containing only the updated items."""
+ updated_items = {}
+ for k, mycontent in mydata.items():
+ k_unicode = _unicode_decode(k,
+ encoding=_encodings['repo.content'], errors='replace')
+ if k_unicode not in ignored_dbentries:
+ orig_content = mycontent
+ mycontent = _unicode_decode(mycontent,
+ encoding=_encodings['repo.content'], errors='replace')
+ is_encoded = mycontent is not orig_content
+ orig_content = mycontent
+ for update_cmd in update_iter:
+ mycontent = update_dbentry(update_cmd, mycontent)
+ if mycontent != orig_content:
+ if is_encoded:
+ mycontent = _unicode_encode(mycontent,
+ encoding=_encodings['repo.content'],
+ errors='backslashreplace')
+ updated_items[k] = mycontent
+ return updated_items
+
+def fixdbentries(update_iter, dbdir):
+ """Performs update commands which result in search and replace operations
+ for each of the files in dbdir (excluding CONTENTS and environment.bz2).
+ Returns True when actual modifications are necessary and False otherwise."""
+ mydata = {}
+ for myfile in [f for f in os.listdir(dbdir) if f not in ignored_dbentries]:
+ file_path = os.path.join(dbdir, myfile)
+ mydata[myfile] = io.open(_unicode_encode(file_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'],
+ errors='replace').read()
+ updated_items = update_dbentries(update_iter, mydata)
+ for myfile, mycontent in updated_items.items():
+ file_path = os.path.join(dbdir, myfile)
+ write_atomic(file_path, mycontent, encoding=_encodings['repo.content'])
+ return len(updated_items) > 0
+
+def grab_updates(updpath, prev_mtimes=None):
+ """Returns all the updates from the given directory as a sorted list of
+ tuples, each containing (file_path, statobj, content). If prev_mtimes is
+ given then updates are only returned if one or more files have different
+ mtimes. When a change is detected for a given file, updates will be
+ returned for that file and any files that come after it in the entire
+ sequence. This ensures that all relevant updates are returned for cases
+ in which the destination package of an earlier move corresponds to
+ the source package of a move that comes somewhere later in the entire
+ sequence of files.
+ """
+ try:
+ mylist = os.listdir(updpath)
+ except OSError as oe:
+ if oe.errno == errno.ENOENT:
+ raise DirectoryNotFound(updpath)
+ raise
+ if prev_mtimes is None:
+ prev_mtimes = {}
+ # validate the file name (filter out CVS directory, etc...)
+ mylist = [myfile for myfile in mylist if len(myfile) == 7 and myfile[1:3] == "Q-"]
+ if len(mylist) == 0:
+ return []
+
+ # update names are mangled to make them sort properly
+ mylist = [myfile[3:]+"-"+myfile[:2] for myfile in mylist]
+ mylist.sort()
+ mylist = [myfile[5:]+"-"+myfile[:4] for myfile in mylist]
+
+ update_data = []
+ for myfile in mylist:
+ file_path = os.path.join(updpath, myfile)
+ mystat = os.stat(file_path)
+ if update_data or \
+ file_path not in prev_mtimes or \
+ long(prev_mtimes[file_path]) != mystat[stat.ST_MTIME]:
+ content = io.open(_unicode_encode(file_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'], errors='replace'
+ ).read()
+ update_data.append((file_path, mystat, content))
+ return update_data
+
+def parse_updates(mycontent):
+ """Valid updates are returned as a list of split update commands."""
+ myupd = []
+ errors = []
+ mylines = mycontent.splitlines()
+ for myline in mylines:
+ mysplit = myline.split()
+ if len(mysplit) == 0:
+ continue
+ if mysplit[0] not in ("move", "slotmove"):
+ errors.append(_("ERROR: Update type not recognized '%s'") % myline)
+ continue
+ if mysplit[0] == "move":
+ if len(mysplit) != 3:
+ errors.append(_("ERROR: Update command invalid '%s'") % myline)
+ continue
+ for i in (1, 2):
+ try:
+ atom = Atom(mysplit[i])
+ except InvalidAtom:
+ atom = None
+ else:
+ if atom.blocker or atom != atom.cp:
+ atom = None
+ if atom is not None:
+ mysplit[i] = atom
+ else:
+ errors.append(
+ _("ERROR: Malformed update entry '%s'") % myline)
+ break
+ if mysplit[0] == "slotmove":
+ if len(mysplit)!=4:
+ errors.append(_("ERROR: Update command invalid '%s'") % myline)
+ continue
+ pkg, origslot, newslot = mysplit[1], mysplit[2], mysplit[3]
+ try:
+ atom = Atom(pkg)
+ except InvalidAtom:
+ atom = None
+ else:
+ if atom.blocker:
+ atom = None
+ if atom is not None:
+ mysplit[1] = atom
+ else:
+ errors.append(_("ERROR: Malformed update entry '%s'") % myline)
+ continue
+
+ # The list of valid updates is filtered by continue statements above.
+ myupd.append(mysplit)
+ return myupd, errors
+
+def update_config_files(config_root, protect, protect_mask, update_iter, match_callback = None):
+ """Perform global updates on /etc/portage/package.*.
+ config_root - location of files to update
+ protect - list of paths from CONFIG_PROTECT
+ protect_mask - list of paths from CONFIG_PROTECT_MASK
+ update_iter - list of update commands as returned from parse_updates(),
+ or dict of {repo_name: list}
+ match_callback - a callback which will be called with three arguments:
+ match_callback(repo_name, old_atom, new_atom)
+ and should return boolean value determining whether to perform the update"""
+
+ repo_dict = None
+ if isinstance(update_iter, dict):
+ repo_dict = update_iter
+ if match_callback is None:
+ def match_callback(repo_name, atoma, atomb):
+ return True
+ config_root = normalize_path(config_root)
+ update_files = {}
+ file_contents = {}
+ myxfiles = [
+ "package.accept_keywords", "package.env",
+ "package.keywords", "package.license",
+ "package.mask", "package.properties",
+ "package.unmask", "package.use"
+ ]
+ myxfiles += [os.path.join("profile", x) for x in myxfiles]
+ abs_user_config = os.path.join(config_root, USER_CONFIG_PATH)
+ recursivefiles = []
+ for x in myxfiles:
+ config_file = os.path.join(abs_user_config, x)
+ if os.path.isdir(config_file):
+ for parent, dirs, files in os.walk(config_file):
+ try:
+ parent = _unicode_decode(parent,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ continue
+ for y_enc in list(dirs):
+ try:
+ y = _unicode_decode(y_enc,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ dirs.remove(y_enc)
+ continue
+ if y.startswith(".") or y in _ignorecvs_dirs:
+ dirs.remove(y_enc)
+ for y in files:
+ try:
+ y = _unicode_decode(y,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ continue
+ if y.startswith("."):
+ continue
+ recursivefiles.append(
+ os.path.join(parent, y)[len(abs_user_config) + 1:])
+ else:
+ recursivefiles.append(x)
+ myxfiles = recursivefiles
+ for x in myxfiles:
+ try:
+ file_contents[x] = io.open(
+ _unicode_encode(os.path.join(abs_user_config, x),
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'],
+ errors='replace').readlines()
+ except IOError:
+ continue
+
+ # update /etc/portage/packages.*
+ ignore_line_re = re.compile(r'^#|^\s*$')
+ if repo_dict is None:
+ update_items = [(None, update_iter)]
+ else:
+ update_items = [x for x in repo_dict.items() if x[0] != 'DEFAULT']
+ for repo_name, update_iter in update_items:
+ for update_cmd in update_iter:
+ for x, contents in file_contents.items():
+ skip_next = False
+ for pos, line in enumerate(contents):
+ if skip_next:
+ skip_next = False
+ continue
+ if ignore_line_re.match(line):
+ continue
+ atom = line.split()[0]
+ if atom[:1] == "-":
+ # package.mask supports incrementals
+ atom = atom[1:]
+ if not isvalidatom(atom):
+ continue
+ new_atom = update_dbentry(update_cmd, atom)
+ if atom != new_atom:
+ if match_callback(repo_name, atom, new_atom):
+ # add a comment with the update command, so
+ # the user can clearly see what happened
+ contents[pos] = "# %s\n" % \
+ " ".join("%s" % (x,) for x in update_cmd)
+ contents.insert(pos + 1,
+ line.replace("%s" % (atom,),
+ "%s" % (new_atom,), 1))
+ # we've inserted an additional line, so we need to
+ # skip it when it's reached in the next iteration
+ skip_next = True
+ update_files[x] = 1
+ sys.stdout.write("p")
+ sys.stdout.flush()
+
+ protect_obj = ConfigProtect(
+ config_root, protect, protect_mask)
+ for x in update_files:
+ updating_file = os.path.join(abs_user_config, x)
+ if protect_obj.isprotected(updating_file):
+ updating_file = new_protect_filename(updating_file)
+ try:
+ write_atomic(updating_file, "".join(file_contents[x]))
+ except PortageException as e:
+ writemsg("\n!!! %s\n" % str(e), noiselevel=-1)
+ writemsg(_("!!! An error occurred while updating a config file:") + \
+ " '%s'\n" % updating_file, noiselevel=-1)
+ continue
+
+def dep_transform(mydep, oldkey, newkey):
+ if dep_getkey(mydep) == oldkey:
+ return mydep.replace(oldkey, newkey, 1)
+ return mydep
diff --git a/portage_with_autodep/pym/portage/util/ExtractKernelVersion.py b/portage_with_autodep/pym/portage/util/ExtractKernelVersion.py
new file mode 100644
index 0000000..5cb9747
--- /dev/null
+++ b/portage_with_autodep/pym/portage/util/ExtractKernelVersion.py
@@ -0,0 +1,76 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['ExtractKernelVersion']
+
+import io
+
+from portage import os, _encodings, _unicode_encode
+from portage.util import getconfig, grabfile
+
+def ExtractKernelVersion(base_dir):
+ """
+ Try to figure out what kernel version we are running
+ @param base_dir: Path to sources (usually /usr/src/linux)
+ @type base_dir: string
+ @rtype: tuple( version[string], error[string])
+ @returns:
+ 1. tuple( version[string], error[string])
+ Either version or error is populated (but never both)
+
+ """
+ lines = []
+ pathname = os.path.join(base_dir, 'Makefile')
+ try:
+ f = io.open(_unicode_encode(pathname,
+ encoding=_encodings['fs'], errors='strict'), mode='r',
+ encoding=_encodings['content'], errors='replace')
+ except OSError as details:
+ return (None, str(details))
+ except IOError as details:
+ return (None, str(details))
+
+ try:
+ for i in range(4):
+ lines.append(f.readline())
+ except OSError as details:
+ return (None, str(details))
+ except IOError as details:
+ return (None, str(details))
+
+ lines = [l.strip() for l in lines]
+
+ version = ''
+
+ #XXX: The following code relies on the ordering of vars within the Makefile
+ for line in lines:
+ # split on the '=' then remove annoying whitespace
+ items = line.split("=")
+ items = [i.strip() for i in items]
+ if items[0] == 'VERSION' or \
+ items[0] == 'PATCHLEVEL':
+ version += items[1]
+ version += "."
+ elif items[0] == 'SUBLEVEL':
+ version += items[1]
+ elif items[0] == 'EXTRAVERSION' and \
+ items[-1] != items[0]:
+ version += items[1]
+
+ # Grab a list of files named localversion* and sort them
+ localversions = os.listdir(base_dir)
+ for x in range(len(localversions)-1,-1,-1):
+ if localversions[x][:12] != "localversion":
+ del localversions[x]
+ localversions.sort()
+
+ # Append the contents of each to the version string, stripping ALL whitespace
+ for lv in localversions:
+ version += "".join( " ".join( grabfile( base_dir+ "/" + lv ) ).split() )
+
+ # Check the .config for a CONFIG_LOCALVERSION and append that too, also stripping whitespace
+ kernelconfig = getconfig(base_dir+"/.config")
+ if kernelconfig and "CONFIG_LOCALVERSION" in kernelconfig:
+ version += "".join(kernelconfig["CONFIG_LOCALVERSION"].split())
+
+ return (version,None)
diff --git a/portage_with_autodep/pym/portage/util/__init__.py b/portage_with_autodep/pym/portage/util/__init__.py
new file mode 100644
index 0000000..4aa63d5
--- /dev/null
+++ b/portage_with_autodep/pym/portage/util/__init__.py
@@ -0,0 +1,1602 @@
+# Copyright 2004-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['apply_permissions', 'apply_recursive_permissions',
+ 'apply_secpass_permissions', 'apply_stat_permissions', 'atomic_ofstream',
+ 'cmp_sort_key', 'ConfigProtect', 'dump_traceback', 'ensure_dirs',
+ 'find_updated_config_files', 'getconfig', 'getlibpaths', 'grabdict',
+ 'grabdict_package', 'grabfile', 'grabfile_package', 'grablines',
+ 'initialize_logger', 'LazyItemsDict', 'map_dictlist_vals',
+ 'new_protect_filename', 'normalize_path', 'pickle_read', 'stack_dictlist',
+ 'stack_dicts', 'stack_lists', 'unique_array', 'unique_everseen', 'varexpand',
+ 'write_atomic', 'writedict', 'writemsg', 'writemsg_level', 'writemsg_stdout']
+
+from copy import deepcopy
+import errno
+import io
+try:
+ from itertools import filterfalse
+except ImportError:
+ from itertools import ifilterfalse as filterfalse
+import logging
+import re
+import shlex
+import stat
+import string
+import sys
+import traceback
+
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'pickle',
+ 'portage.dep:Atom',
+ 'portage.util.listdir:_ignorecvs_dirs'
+)
+
+from portage import os
+from portage import subprocess_getstatusoutput
+from portage import _encodings
+from portage import _os_merge
+from portage import _unicode_encode
+from portage import _unicode_decode
+from portage.exception import InvalidAtom, PortageException, FileNotFound, \
+ OperationNotPermitted, PermissionDenied, ReadOnlyFileSystem
+from portage.localization import _
+from portage.proxy.objectproxy import ObjectProxy
+from portage.cache.mappings import UserDict
+
+noiselimit = 0
+
+def initialize_logger(level=logging.WARN):
+ """Sets up basic logging of portage activities
+ Args:
+ level: the level to emit messages at ('info', 'debug', 'warning' ...)
+ Returns:
+ None
+ """
+ logging.basicConfig(level=logging.WARN, format='[%(levelname)-4s] %(message)s')
+
+def writemsg(mystr,noiselevel=0,fd=None):
+ """Prints out warning and debug messages based on the noiselimit setting"""
+ global noiselimit
+ if fd is None:
+ fd = sys.stderr
+ if noiselevel <= noiselimit:
+ # avoid potential UnicodeEncodeError
+ if isinstance(fd, io.StringIO):
+ mystr = _unicode_decode(mystr,
+ encoding=_encodings['content'], errors='replace')
+ else:
+ mystr = _unicode_encode(mystr,
+ encoding=_encodings['stdio'], errors='backslashreplace')
+ if sys.hexversion >= 0x3000000 and fd in (sys.stdout, sys.stderr):
+ fd = fd.buffer
+ fd.write(mystr)
+ fd.flush()
+
+def writemsg_stdout(mystr,noiselevel=0):
+ """Prints messages stdout based on the noiselimit setting"""
+ writemsg(mystr, noiselevel=noiselevel, fd=sys.stdout)
+
+def writemsg_level(msg, level=0, noiselevel=0):
+ """
+ Show a message for the given level as defined by the logging module
+ (default is 0). When level >= logging.WARNING then the message is
+ sent to stderr, otherwise it is sent to stdout. The noiselevel is
+ passed directly to writemsg().
+
+ @type msg: str
+ @param msg: a message string, including newline if appropriate
+ @type level: int
+ @param level: a numeric logging level (see the logging module)
+ @type noiselevel: int
+ @param noiselevel: passed directly to writemsg
+ """
+ if level >= logging.WARNING:
+ fd = sys.stderr
+ else:
+ fd = sys.stdout
+ writemsg(msg, noiselevel=noiselevel, fd=fd)
+
+def normalize_path(mypath):
+ """
+ os.path.normpath("//foo") returns "//foo" instead of "/foo"
+ We dislike this behavior so we create our own normpath func
+ to fix it.
+ """
+ if sys.hexversion >= 0x3000000 and isinstance(mypath, bytes):
+ path_sep = os.path.sep.encode()
+ else:
+ path_sep = os.path.sep
+
+ if mypath.startswith(path_sep):
+ # posixpath.normpath collapses 3 or more leading slashes to just 1.
+ return os.path.normpath(2*path_sep + mypath)
+ else:
+ return os.path.normpath(mypath)
+
+def grabfile(myfilename, compat_level=0, recursive=0, remember_source_file=False):
+ """This function grabs the lines in a file, normalizes whitespace and returns lines in a list; if a line
+ begins with a #, it is ignored, as are empty lines"""
+
+ mylines=grablines(myfilename, recursive, remember_source_file=True)
+ newlines=[]
+
+ for x, source_file in mylines:
+ #the split/join thing removes leading and trailing whitespace, and converts any whitespace in the line
+ #into single spaces.
+ myline = x.split()
+ if x and x[0] != "#":
+ mylinetemp = []
+ for item in myline:
+ if item[:1] != "#":
+ mylinetemp.append(item)
+ else:
+ break
+ myline = mylinetemp
+
+ myline = " ".join(myline)
+ if not myline:
+ continue
+ if myline[0]=="#":
+ # Check if we have a compat-level string. BC-integration data.
+ # '##COMPAT==>N<==' 'some string attached to it'
+ mylinetest = myline.split("<==",1)
+ if len(mylinetest) == 2:
+ myline_potential = mylinetest[1]
+ mylinetest = mylinetest[0].split("##COMPAT==>")
+ if len(mylinetest) == 2:
+ if compat_level >= int(mylinetest[1]):
+ # It's a compat line, and the key matches.
+ newlines.append(myline_potential)
+ continue
+ else:
+ continue
+ if remember_source_file:
+ newlines.append((myline, source_file))
+ else:
+ newlines.append(myline)
+ return newlines
+
+def map_dictlist_vals(func,myDict):
+ """Performs a function on each value of each key in a dictlist.
+ Returns a new dictlist."""
+ new_dl = {}
+ for key in myDict:
+ new_dl[key] = []
+ new_dl[key] = [func(x) for x in myDict[key]]
+ return new_dl
+
+def stack_dictlist(original_dicts, incremental=0, incrementals=[], ignore_none=0):
+ """
+ Stacks an array of dict-types into one array. Optionally merging or
+ overwriting matching key/value pairs for the dict[key]->list.
+ Returns a single dict. Higher index in lists is preferenced.
+
+ Example usage:
+ >>> from portage.util import stack_dictlist
+ >>> print stack_dictlist( [{'a':'b'},{'x':'y'}])
+ >>> {'a':'b','x':'y'}
+ >>> print stack_dictlist( [{'a':'b'},{'a':'c'}], incremental = True )
+ >>> {'a':['b','c'] }
+ >>> a = {'KEYWORDS':['x86','alpha']}
+ >>> b = {'KEYWORDS':['-x86']}
+ >>> print stack_dictlist( [a,b] )
+ >>> { 'KEYWORDS':['x86','alpha','-x86']}
+ >>> print stack_dictlist( [a,b], incremental=True)
+ >>> { 'KEYWORDS':['alpha'] }
+ >>> print stack_dictlist( [a,b], incrementals=['KEYWORDS'])
+ >>> { 'KEYWORDS':['alpha'] }
+
+ @param original_dicts a list of (dictionary objects or None)
+ @type list
+ @param incremental True or false depending on whether new keys should overwrite
+ keys which already exist.
+ @type boolean
+ @param incrementals A list of items that should be incremental (-foo removes foo from
+ the returned dict).
+ @type list
+ @param ignore_none Appears to be ignored, but probably was used long long ago.
+ @type boolean
+
+ """
+ final_dict = {}
+ for mydict in original_dicts:
+ if mydict is None:
+ continue
+ for y in mydict:
+ if not y in final_dict:
+ final_dict[y] = []
+
+ for thing in mydict[y]:
+ if thing:
+ if incremental or y in incrementals:
+ if thing == "-*":
+ final_dict[y] = []
+ continue
+ elif thing[:1] == '-':
+ try:
+ final_dict[y].remove(thing[1:])
+ except ValueError:
+ pass
+ continue
+ if thing not in final_dict[y]:
+ final_dict[y].append(thing)
+ if y in final_dict and not final_dict[y]:
+ del final_dict[y]
+ return final_dict
+
+def stack_dicts(dicts, incremental=0, incrementals=[], ignore_none=0):
+ """Stacks an array of dict-types into one array. Optionally merging or
+ overwriting matching key/value pairs for the dict[key]->string.
+ Returns a single dict."""
+ final_dict = {}
+ for mydict in dicts:
+ if not mydict:
+ continue
+ for k, v in mydict.items():
+ if k in final_dict and (incremental or (k in incrementals)):
+ final_dict[k] += " " + v
+ else:
+ final_dict[k] = v
+ return final_dict
+
+def append_repo(atom_list, repo_name, remember_source_file=False):
+ """
+ Takes a list of valid atoms without repo spec and appends ::repo_name.
+ """
+ if remember_source_file:
+ return [(Atom(atom + "::" + repo_name, allow_wildcard=True, allow_repo=True), source) \
+ for atom, source in atom_list]
+ else:
+ return [Atom(atom + "::" + repo_name, allow_wildcard=True, allow_repo=True) \
+ for atom in atom_list]
+
+def stack_lists(lists, incremental=1, remember_source_file=False,
+ warn_for_unmatched_removal=False, strict_warn_for_unmatched_removal=False, ignore_repo=False):
+ """Stacks an array of list-types into one array. Optionally removing
+ distinct values using '-value' notation. Higher index is preferenced.
+
+ all elements must be hashable."""
+ matched_removals = set()
+ unmatched_removals = {}
+ new_list = {}
+ for sub_list in lists:
+ for token in sub_list:
+ token_key = token
+ if remember_source_file:
+ token, source_file = token
+ else:
+ source_file = False
+
+ if token is None:
+ continue
+
+ if incremental:
+ if token == "-*":
+ new_list.clear()
+ elif token[:1] == '-':
+ matched = False
+ if ignore_repo and not "::" in token:
+ #Let -cat/pkg remove cat/pkg::repo.
+ to_be_removed = []
+ token_slice = token[1:]
+ for atom in new_list:
+ atom_without_repo = atom
+ if atom.repo is not None:
+ # Atom.without_repo instantiates a new Atom,
+ # which is unnecessary here, so use string
+ # replacement instead.
+ atom_without_repo = \
+ atom.replace("::" + atom.repo, "", 1)
+ if atom_without_repo == token_slice:
+ to_be_removed.append(atom)
+ if to_be_removed:
+ matched = True
+ for atom in to_be_removed:
+ new_list.pop(atom)
+ else:
+ try:
+ new_list.pop(token[1:])
+ matched = True
+ except KeyError:
+ pass
+
+ if not matched:
+ if source_file and \
+ (strict_warn_for_unmatched_removal or \
+ token_key not in matched_removals):
+ unmatched_removals.setdefault(source_file, set()).add(token)
+ else:
+ matched_removals.add(token_key)
+ else:
+ new_list[token] = source_file
+ else:
+ new_list[token] = source_file
+
+ if warn_for_unmatched_removal:
+ for source_file, tokens in unmatched_removals.items():
+ if len(tokens) > 3:
+ selected = [tokens.pop(), tokens.pop(), tokens.pop()]
+ writemsg(_("--- Unmatch removal atoms in %s: %s and %s more\n") % \
+ (source_file, ", ".join(selected), len(tokens)),
+ noiselevel=-1)
+ else:
+ writemsg(_("--- Unmatch removal atom(s) in %s: %s\n") % (source_file, ", ".join(tokens)),
+ noiselevel=-1)
+
+ if remember_source_file:
+ return list(new_list.items())
+ else:
+ return list(new_list)
+
+def grabdict(myfilename, juststrings=0, empty=0, recursive=0, incremental=1):
+ """
+ This function grabs the lines in a file, normalizes whitespace and returns lines in a dictionary
+
+ @param myfilename: file to process
+ @type myfilename: string (path)
+ @param juststrings: only return strings
+ @type juststrings: Boolean (integer)
+ @param empty: Ignore certain lines
+ @type empty: Boolean (integer)
+ @param recursive: Recursively grab ( support for /etc/portage/package.keywords/* and friends )
+ @type recursive: Boolean (integer)
+ @param incremental: Append to the return list, don't overwrite
+ @type incremental: Boolean (integer)
+ @rtype: Dictionary
+ @returns:
+ 1. Returns the lines in a file in a dictionary, for example:
+ 'sys-apps/portage x86 amd64 ppc'
+ would return
+ { "sys-apps/portage" : [ 'x86', 'amd64', 'ppc' ]
+ the line syntax is key : [list of values]
+ """
+ newdict={}
+ for x in grablines(myfilename, recursive):
+ #the split/join thing removes leading and trailing whitespace, and converts any whitespace in the line
+ #into single spaces.
+ if x[0] == "#":
+ continue
+ myline=x.split()
+ mylinetemp = []
+ for item in myline:
+ if item[:1] != "#":
+ mylinetemp.append(item)
+ else:
+ break
+ myline = mylinetemp
+ if len(myline) < 2 and empty == 0:
+ continue
+ if len(myline) < 1 and empty == 1:
+ continue
+ if incremental:
+ newdict.setdefault(myline[0], []).extend(myline[1:])
+ else:
+ newdict[myline[0]] = myline[1:]
+ if juststrings:
+ for k, v in newdict.items():
+ newdict[k] = " ".join(v)
+ return newdict
+
+def read_corresponding_eapi_file(filename):
+ """
+ Read the 'eapi' file from the directory 'filename' is in.
+ Returns "0" if the file is not present or invalid.
+ """
+ default = "0"
+ eapi_file = os.path.join(os.path.dirname(filename), "eapi")
+ try:
+ f = open(eapi_file, "r")
+ lines = f.readlines()
+ if len(lines) == 1:
+ eapi = lines[0].rstrip("\n")
+ else:
+ writemsg(_("--- Invalid 'eapi' file (doesn't contain exactly one line): %s\n") % (eapi_file),
+ noiselevel=-1)
+ eapi = default
+ f.close()
+ except IOError:
+ eapi = default
+
+ return eapi
+
+def grabdict_package(myfilename, juststrings=0, recursive=0, allow_wildcard=False, allow_repo=False,
+ verify_eapi=False, eapi=None):
+ """ Does the same thing as grabdict except it validates keys
+ with isvalidatom()"""
+ pkgs=grabdict(myfilename, juststrings, empty=1, recursive=recursive)
+ if not pkgs:
+ return pkgs
+ if verify_eapi and eapi is None:
+ eapi = read_corresponding_eapi_file(myfilename)
+
+ # We need to call keys() here in order to avoid the possibility of
+ # "RuntimeError: dictionary changed size during iteration"
+ # when an invalid atom is deleted.
+ atoms = {}
+ for k, v in pkgs.items():
+ try:
+ k = Atom(k, allow_wildcard=allow_wildcard, allow_repo=allow_repo, eapi=eapi)
+ except InvalidAtom as e:
+ writemsg(_("--- Invalid atom in %s: %s\n") % (myfilename, e),
+ noiselevel=-1)
+ else:
+ atoms[k] = v
+ return atoms
+
+def grabfile_package(myfilename, compatlevel=0, recursive=0, allow_wildcard=False, allow_repo=False,
+ remember_source_file=False, verify_eapi=False, eapi=None):
+
+ pkgs=grabfile(myfilename, compatlevel, recursive=recursive, remember_source_file=True)
+ if not pkgs:
+ return pkgs
+ if verify_eapi and eapi is None:
+ eapi = read_corresponding_eapi_file(myfilename)
+ mybasename = os.path.basename(myfilename)
+ atoms = []
+ for pkg, source_file in pkgs:
+ pkg_orig = pkg
+ # for packages and package.mask files
+ if pkg[:1] == "-":
+ pkg = pkg[1:]
+ if pkg[:1] == '*' and mybasename == 'packages':
+ pkg = pkg[1:]
+ try:
+ pkg = Atom(pkg, allow_wildcard=allow_wildcard, allow_repo=allow_repo, eapi=eapi)
+ except InvalidAtom as e:
+ writemsg(_("--- Invalid atom in %s: %s\n") % (myfilename, e),
+ noiselevel=-1)
+ else:
+ if pkg_orig == str(pkg):
+ # normal atom, so return as Atom instance
+ if remember_source_file:
+ atoms.append((pkg, source_file))
+ else:
+ atoms.append(pkg)
+ else:
+ # atom has special prefix, so return as string
+ if remember_source_file:
+ atoms.append((pkg_orig, source_file))
+ else:
+ atoms.append(pkg_orig)
+ return atoms
+
+def grablines(myfilename, recursive=0, remember_source_file=False):
+ mylines=[]
+ if recursive and os.path.isdir(myfilename):
+ if os.path.basename(myfilename) in _ignorecvs_dirs:
+ return mylines
+ dirlist = os.listdir(myfilename)
+ dirlist.sort()
+ for f in dirlist:
+ if not f.startswith(".") and not f.endswith("~"):
+ mylines.extend(grablines(
+ os.path.join(myfilename, f), recursive, remember_source_file))
+ else:
+ try:
+ myfile = io.open(_unicode_encode(myfilename,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'], errors='replace')
+ if remember_source_file:
+ mylines = [(line, myfilename) for line in myfile.readlines()]
+ else:
+ mylines = myfile.readlines()
+ myfile.close()
+ except IOError as e:
+ if e.errno == PermissionDenied.errno:
+ raise PermissionDenied(myfilename)
+ pass
+ return mylines
+
+def writedict(mydict,myfilename,writekey=True):
+ """Writes out a dict to a file; writekey=0 mode doesn't write out
+ the key and assumes all values are strings, not lists."""
+ lines = []
+ if not writekey:
+ for v in mydict.values():
+ lines.append(v + "\n")
+ else:
+ for k, v in mydict.items():
+ lines.append("%s %s\n" % (k, " ".join(v)))
+ write_atomic(myfilename, "".join(lines))
+
+def shlex_split(s):
+ """
+ This is equivalent to shlex.split but it temporarily encodes unicode
+ strings to bytes since shlex.split() doesn't handle unicode strings.
+ """
+ is_unicode = sys.hexversion < 0x3000000 and isinstance(s, unicode)
+ if is_unicode:
+ s = _unicode_encode(s)
+ rval = shlex.split(s)
+ if is_unicode:
+ rval = [_unicode_decode(x) for x in rval]
+ return rval
+
+class _tolerant_shlex(shlex.shlex):
+ def sourcehook(self, newfile):
+ try:
+ return shlex.shlex.sourcehook(self, newfile)
+ except EnvironmentError as e:
+ writemsg(_("!!! Parse error in '%s': source command failed: %s\n") % \
+ (self.infile, str(e)), noiselevel=-1)
+ return (newfile, io.StringIO())
+
+_invalid_var_name_re = re.compile(r'^\d|\W')
+
+def getconfig(mycfg, tolerant=0, allow_sourcing=False, expand=True):
+ if isinstance(expand, dict):
+ # Some existing variable definitions have been
+ # passed in, for use in substitutions.
+ expand_map = expand
+ expand = True
+ else:
+ expand_map = {}
+ mykeys = {}
+ try:
+ # NOTE: shlex doesn't support unicode objects with Python 2
+ # (produces spurious \0 characters).
+ if sys.hexversion < 0x3000000:
+ content = open(_unicode_encode(mycfg,
+ encoding=_encodings['fs'], errors='strict'), 'rb').read()
+ else:
+ content = open(_unicode_encode(mycfg,
+ encoding=_encodings['fs'], errors='strict'), mode='r',
+ encoding=_encodings['content'], errors='replace').read()
+ except IOError as e:
+ if e.errno == PermissionDenied.errno:
+ raise PermissionDenied(mycfg)
+ if e.errno != errno.ENOENT:
+ writemsg("open('%s', 'r'): %s\n" % (mycfg, e), noiselevel=-1)
+ if e.errno not in (errno.EISDIR,):
+ raise
+ return None
+
+ # Workaround for avoiding a silent error in shlex that is
+ # triggered by a source statement at the end of the file
+ # without a trailing newline after the source statement.
+ if content and content[-1] != '\n':
+ content += '\n'
+
+ # Warn about dos-style line endings since that prevents
+ # people from being able to source them with bash.
+ if '\r' in content:
+ writemsg(("!!! " + _("Please use dos2unix to convert line endings " + \
+ "in config file: '%s'") + "\n") % mycfg, noiselevel=-1)
+
+ try:
+ if tolerant:
+ shlex_class = _tolerant_shlex
+ else:
+ shlex_class = shlex.shlex
+ # The default shlex.sourcehook() implementation
+ # only joins relative paths when the infile
+ # attribute is properly set.
+ lex = shlex_class(content, infile=mycfg, posix=True)
+ lex.wordchars = string.digits + string.ascii_letters + \
+ "~!@#$%*_\:;?,./-+{}"
+ lex.quotes="\"'"
+ if allow_sourcing:
+ lex.source="source"
+ while 1:
+ key=lex.get_token()
+ if key == "export":
+ key = lex.get_token()
+ if key is None:
+ #normal end of file
+ break;
+ equ=lex.get_token()
+ if (equ==''):
+ #unexpected end of file
+ #lex.error_leader(self.filename,lex.lineno)
+ if not tolerant:
+ writemsg(_("!!! Unexpected end of config file: variable %s\n") % key,
+ noiselevel=-1)
+ raise Exception(_("ParseError: Unexpected EOF: %s: on/before line %s") % (mycfg, lex.lineno))
+ else:
+ return mykeys
+ elif (equ!='='):
+ #invalid token
+ #lex.error_leader(self.filename,lex.lineno)
+ if not tolerant:
+ raise Exception(_("ParseError: Invalid token "
+ "'%s' (not '='): %s: line %s") % \
+ (equ, mycfg, lex.lineno))
+ else:
+ return mykeys
+ val=lex.get_token()
+ if val is None:
+ #unexpected end of file
+ #lex.error_leader(self.filename,lex.lineno)
+ if not tolerant:
+ writemsg(_("!!! Unexpected end of config file: variable %s\n") % key,
+ noiselevel=-1)
+ raise portage.exception.CorruptionError(_("ParseError: Unexpected EOF: %s: line %s") % (mycfg, lex.lineno))
+ else:
+ return mykeys
+ key = _unicode_decode(key)
+ val = _unicode_decode(val)
+
+ if _invalid_var_name_re.search(key) is not None:
+ if not tolerant:
+ raise Exception(_(
+ "ParseError: Invalid variable name '%s': line %s") % \
+ (key, lex.lineno - 1))
+ writemsg(_("!!! Invalid variable name '%s': line %s in %s\n") \
+ % (key, lex.lineno - 1, mycfg), noiselevel=-1)
+ continue
+
+ if expand:
+ mykeys[key] = varexpand(val, expand_map)
+ expand_map[key] = mykeys[key]
+ else:
+ mykeys[key] = val
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ raise portage.exception.ParseError(str(e)+" in "+mycfg)
+ return mykeys
+
+#cache expansions of constant strings
+cexpand={}
+def varexpand(mystring, mydict=None):
+ if mydict is None:
+ mydict = {}
+ newstring = cexpand.get(" "+mystring, None)
+ if newstring is not None:
+ return newstring
+
+ """
+ new variable expansion code. Preserves quotes, handles \n, etc.
+ This code is used by the configfile code, as well as others (parser)
+ This would be a good bunch of code to port to C.
+ """
+ numvars=0
+ mystring=" "+mystring
+ #in single, double quotes
+ insing=0
+ indoub=0
+ pos=1
+ newstring=" "
+ while (pos<len(mystring)):
+ if (mystring[pos]=="'") and (mystring[pos-1]!="\\"):
+ if (indoub):
+ newstring=newstring+"'"
+ else:
+ newstring += "'" # Quote removal is handled by shlex.
+ insing=not insing
+ pos=pos+1
+ continue
+ elif (mystring[pos]=='"') and (mystring[pos-1]!="\\"):
+ if (insing):
+ newstring=newstring+'"'
+ else:
+ newstring += '"' # Quote removal is handled by shlex.
+ indoub=not indoub
+ pos=pos+1
+ continue
+ if (not insing):
+ #expansion time
+ if (mystring[pos]=="\n"):
+ #convert newlines to spaces
+ newstring=newstring+" "
+ pos=pos+1
+ elif (mystring[pos]=="\\"):
+ # For backslash expansion, this function used to behave like
+ # echo -e, but that's not needed for our purposes. We want to
+ # behave like bash does when expanding a variable assignment
+ # in a sourced file, in which case it performs backslash
+ # removal for \\ and \$ but nothing more. It also removes
+ # escaped newline characters. Note that we don't handle
+ # escaped quotes here, since getconfig() uses shlex
+ # to handle that earlier.
+ if (pos+1>=len(mystring)):
+ newstring=newstring+mystring[pos]
+ break
+ else:
+ a = mystring[pos + 1]
+ pos = pos + 2
+ if a in ("\\", "$"):
+ newstring = newstring + a
+ elif a == "\n":
+ pass
+ else:
+ newstring = newstring + mystring[pos-2:pos]
+ continue
+ elif (mystring[pos]=="$") and (mystring[pos-1]!="\\"):
+ pos=pos+1
+ if mystring[pos]=="{":
+ pos=pos+1
+ braced=True
+ else:
+ braced=False
+ myvstart=pos
+ validchars=string.ascii_letters+string.digits+"_"
+ while mystring[pos] in validchars:
+ if (pos+1)>=len(mystring):
+ if braced:
+ cexpand[mystring]=""
+ return ""
+ else:
+ pos=pos+1
+ break
+ pos=pos+1
+ myvarname=mystring[myvstart:pos]
+ if braced:
+ if mystring[pos]!="}":
+ cexpand[mystring]=""
+ return ""
+ else:
+ pos=pos+1
+ if len(myvarname)==0:
+ cexpand[mystring]=""
+ return ""
+ numvars=numvars+1
+ if myvarname in mydict:
+ newstring=newstring+mydict[myvarname]
+ else:
+ newstring=newstring+mystring[pos]
+ pos=pos+1
+ else:
+ newstring=newstring+mystring[pos]
+ pos=pos+1
+ if numvars==0:
+ cexpand[mystring]=newstring[1:]
+ return newstring[1:]
+
+# broken and removed, but can still be imported
+pickle_write = None
+
+def pickle_read(filename,default=None,debug=0):
+ if not os.access(filename, os.R_OK):
+ writemsg(_("pickle_read(): File not readable. '")+filename+"'\n",1)
+ return default
+ data = None
+ try:
+ myf = open(_unicode_encode(filename,
+ encoding=_encodings['fs'], errors='strict'), 'rb')
+ mypickle = pickle.Unpickler(myf)
+ data = mypickle.load()
+ myf.close()
+ del mypickle,myf
+ writemsg(_("pickle_read(): Loaded pickle. '")+filename+"'\n",1)
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ writemsg(_("!!! Failed to load pickle: ")+str(e)+"\n",1)
+ data = default
+ return data
+
+def dump_traceback(msg, noiselevel=1):
+ info = sys.exc_info()
+ if not info[2]:
+ stack = traceback.extract_stack()[:-1]
+ error = None
+ else:
+ stack = traceback.extract_tb(info[2])
+ error = str(info[1])
+ writemsg("\n====================================\n", noiselevel=noiselevel)
+ writemsg("%s\n\n" % msg, noiselevel=noiselevel)
+ for line in traceback.format_list(stack):
+ writemsg(line, noiselevel=noiselevel)
+ if error:
+ writemsg(error+"\n", noiselevel=noiselevel)
+ writemsg("====================================\n\n", noiselevel=noiselevel)
+
+class cmp_sort_key(object):
+ """
+ In python-3.0 the list.sort() method no longer has a "cmp" keyword
+ argument. This class acts as an adapter which converts a cmp function
+ into one that's suitable for use as the "key" keyword argument to
+ list.sort(), making it easier to port code for python-3.0 compatibility.
+ It works by generating key objects which use the given cmp function to
+ implement their __lt__ method.
+ """
+ __slots__ = ("_cmp_func",)
+
+ def __init__(self, cmp_func):
+ """
+ @type cmp_func: callable which takes 2 positional arguments
+ @param cmp_func: A cmp function.
+ """
+ self._cmp_func = cmp_func
+
+ def __call__(self, lhs):
+ return self._cmp_key(self._cmp_func, lhs)
+
+ class _cmp_key(object):
+ __slots__ = ("_cmp_func", "_obj")
+
+ def __init__(self, cmp_func, obj):
+ self._cmp_func = cmp_func
+ self._obj = obj
+
+ def __lt__(self, other):
+ if other.__class__ is not self.__class__:
+ raise TypeError("Expected type %s, got %s" % \
+ (self.__class__, other.__class__))
+ return self._cmp_func(self._obj, other._obj) < 0
+
+def unique_array(s):
+ """lifted from python cookbook, credit: Tim Peters
+ Return a list of the elements in s in arbitrary order, sans duplicates"""
+ n = len(s)
+ # assume all elements are hashable, if so, it's linear
+ try:
+ return list(set(s))
+ except TypeError:
+ pass
+
+ # so much for linear. abuse sort.
+ try:
+ t = list(s)
+ t.sort()
+ except TypeError:
+ pass
+ else:
+ assert n > 0
+ last = t[0]
+ lasti = i = 1
+ while i < n:
+ if t[i] != last:
+ t[lasti] = last = t[i]
+ lasti += 1
+ i += 1
+ return t[:lasti]
+
+ # blah. back to original portage.unique_array
+ u = []
+ for x in s:
+ if x not in u:
+ u.append(x)
+ return u
+
+def unique_everseen(iterable, key=None):
+ """
+ List unique elements, preserving order. Remember all elements ever seen.
+ Taken from itertools documentation.
+ """
+ # unique_everseen('AAAABBBCCDAABBB') --> A B C D
+ # unique_everseen('ABBCcAD', str.lower) --> A B C D
+ seen = set()
+ seen_add = seen.add
+ if key is None:
+ for element in filterfalse(seen.__contains__, iterable):
+ seen_add(element)
+ yield element
+ else:
+ for element in iterable:
+ k = key(element)
+ if k not in seen:
+ seen_add(k)
+ yield element
+
+def apply_permissions(filename, uid=-1, gid=-1, mode=-1, mask=-1,
+ stat_cached=None, follow_links=True):
+ """Apply user, group, and mode bits to a file if the existing bits do not
+ already match. The default behavior is to force an exact match of mode
+ bits. When mask=0 is specified, mode bits on the target file are allowed
+ to be a superset of the mode argument (via logical OR). When mask>0, the
+ mode bits that the target file is allowed to have are restricted via
+ logical XOR.
+ Returns True if the permissions were modified and False otherwise."""
+
+ modified = False
+
+ if stat_cached is None:
+ try:
+ if follow_links:
+ stat_cached = os.stat(filename)
+ else:
+ stat_cached = os.lstat(filename)
+ except OSError as oe:
+ func_call = "stat('%s')" % filename
+ if oe.errno == errno.EPERM:
+ raise OperationNotPermitted(func_call)
+ elif oe.errno == errno.EACCES:
+ raise PermissionDenied(func_call)
+ elif oe.errno == errno.ENOENT:
+ raise FileNotFound(filename)
+ else:
+ raise
+
+ if (uid != -1 and uid != stat_cached.st_uid) or \
+ (gid != -1 and gid != stat_cached.st_gid):
+ try:
+ if follow_links:
+ os.chown(filename, uid, gid)
+ else:
+ portage.data.lchown(filename, uid, gid)
+ modified = True
+ except OSError as oe:
+ func_call = "chown('%s', %i, %i)" % (filename, uid, gid)
+ if oe.errno == errno.EPERM:
+ raise OperationNotPermitted(func_call)
+ elif oe.errno == errno.EACCES:
+ raise PermissionDenied(func_call)
+ elif oe.errno == errno.EROFS:
+ raise ReadOnlyFileSystem(func_call)
+ elif oe.errno == errno.ENOENT:
+ raise FileNotFound(filename)
+ else:
+ raise
+
+ new_mode = -1
+ st_mode = stat_cached.st_mode & 0o7777 # protect from unwanted bits
+ if mask >= 0:
+ if mode == -1:
+ mode = 0 # Don't add any mode bits when mode is unspecified.
+ else:
+ mode = mode & 0o7777
+ if (mode & st_mode != mode) or \
+ ((mask ^ st_mode) & st_mode != st_mode):
+ new_mode = mode | st_mode
+ new_mode = (mask ^ new_mode) & new_mode
+ elif mode != -1:
+ mode = mode & 0o7777 # protect from unwanted bits
+ if mode != st_mode:
+ new_mode = mode
+
+ # The chown system call may clear S_ISUID and S_ISGID
+ # bits, so those bits are restored if necessary.
+ if modified and new_mode == -1 and \
+ (st_mode & stat.S_ISUID or st_mode & stat.S_ISGID):
+ if mode == -1:
+ new_mode = st_mode
+ else:
+ mode = mode & 0o7777
+ if mask >= 0:
+ new_mode = mode | st_mode
+ new_mode = (mask ^ new_mode) & new_mode
+ else:
+ new_mode = mode
+ if not (new_mode & stat.S_ISUID or new_mode & stat.S_ISGID):
+ new_mode = -1
+
+ if not follow_links and stat.S_ISLNK(stat_cached.st_mode):
+ # Mode doesn't matter for symlinks.
+ new_mode = -1
+
+ if new_mode != -1:
+ try:
+ os.chmod(filename, new_mode)
+ modified = True
+ except OSError as oe:
+ func_call = "chmod('%s', %s)" % (filename, oct(new_mode))
+ if oe.errno == errno.EPERM:
+ raise OperationNotPermitted(func_call)
+ elif oe.errno == errno.EACCES:
+ raise PermissionDenied(func_call)
+ elif oe.errno == errno.EROFS:
+ raise ReadOnlyFileSystem(func_call)
+ elif oe.errno == errno.ENOENT:
+ raise FileNotFound(filename)
+ raise
+ return modified
+
+def apply_stat_permissions(filename, newstat, **kwargs):
+ """A wrapper around apply_secpass_permissions that gets
+ uid, gid, and mode from a stat object"""
+ return apply_secpass_permissions(filename, uid=newstat.st_uid, gid=newstat.st_gid,
+ mode=newstat.st_mode, **kwargs)
+
+def apply_recursive_permissions(top, uid=-1, gid=-1,
+ dirmode=-1, dirmask=-1, filemode=-1, filemask=-1, onerror=None):
+ """A wrapper around apply_secpass_permissions that applies permissions
+ recursively. If optional argument onerror is specified, it should be a
+ function; it will be called with one argument, a PortageException instance.
+ Returns True if all permissions are applied and False if some are left
+ unapplied."""
+
+ # Avoid issues with circular symbolic links, as in bug #339670.
+ follow_links = False
+
+ if onerror is None:
+ # Default behavior is to dump errors to stderr so they won't
+ # go unnoticed. Callers can pass in a quiet instance.
+ def onerror(e):
+ if isinstance(e, OperationNotPermitted):
+ writemsg(_("Operation Not Permitted: %s\n") % str(e),
+ noiselevel=-1)
+ elif isinstance(e, FileNotFound):
+ writemsg(_("File Not Found: '%s'\n") % str(e), noiselevel=-1)
+ else:
+ raise
+
+ all_applied = True
+ for dirpath, dirnames, filenames in os.walk(top):
+ try:
+ applied = apply_secpass_permissions(dirpath,
+ uid=uid, gid=gid, mode=dirmode, mask=dirmask,
+ follow_links=follow_links)
+ if not applied:
+ all_applied = False
+ except PortageException as e:
+ all_applied = False
+ onerror(e)
+
+ for name in filenames:
+ try:
+ applied = apply_secpass_permissions(os.path.join(dirpath, name),
+ uid=uid, gid=gid, mode=filemode, mask=filemask,
+ follow_links=follow_links)
+ if not applied:
+ all_applied = False
+ except PortageException as e:
+ # Ignore InvalidLocation exceptions such as FileNotFound
+ # and DirectoryNotFound since sometimes things disappear,
+ # like when adjusting permissions on DISTCC_DIR.
+ if not isinstance(e, portage.exception.InvalidLocation):
+ all_applied = False
+ onerror(e)
+ return all_applied
+
+def apply_secpass_permissions(filename, uid=-1, gid=-1, mode=-1, mask=-1,
+ stat_cached=None, follow_links=True):
+ """A wrapper around apply_permissions that uses secpass and simple
+ logic to apply as much of the permissions as possible without
+ generating an obviously avoidable permission exception. Despite
+ attempts to avoid an exception, it's possible that one will be raised
+ anyway, so be prepared.
+ Returns True if all permissions are applied and False if some are left
+ unapplied."""
+
+ if stat_cached is None:
+ try:
+ if follow_links:
+ stat_cached = os.stat(filename)
+ else:
+ stat_cached = os.lstat(filename)
+ except OSError as oe:
+ func_call = "stat('%s')" % filename
+ if oe.errno == errno.EPERM:
+ raise OperationNotPermitted(func_call)
+ elif oe.errno == errno.EACCES:
+ raise PermissionDenied(func_call)
+ elif oe.errno == errno.ENOENT:
+ raise FileNotFound(filename)
+ else:
+ raise
+
+ all_applied = True
+
+ if portage.data.secpass < 2:
+
+ if uid != -1 and \
+ uid != stat_cached.st_uid:
+ all_applied = False
+ uid = -1
+
+ if gid != -1 and \
+ gid != stat_cached.st_gid and \
+ gid not in os.getgroups():
+ all_applied = False
+ gid = -1
+
+ apply_permissions(filename, uid=uid, gid=gid, mode=mode, mask=mask,
+ stat_cached=stat_cached, follow_links=follow_links)
+ return all_applied
+
+class atomic_ofstream(ObjectProxy):
+ """Write a file atomically via os.rename(). Atomic replacement prevents
+ interprocess interference and prevents corruption of the target
+ file when the write is interrupted (for example, when an 'out of space'
+ error occurs)."""
+
+ def __init__(self, filename, mode='w', follow_links=True, **kargs):
+ """Opens a temporary filename.pid in the same directory as filename."""
+ ObjectProxy.__init__(self)
+ object.__setattr__(self, '_aborted', False)
+ if 'b' in mode:
+ open_func = open
+ else:
+ open_func = io.open
+ kargs.setdefault('encoding', _encodings['content'])
+ kargs.setdefault('errors', 'backslashreplace')
+
+ if follow_links:
+ canonical_path = os.path.realpath(filename)
+ object.__setattr__(self, '_real_name', canonical_path)
+ tmp_name = "%s.%i" % (canonical_path, os.getpid())
+ try:
+ object.__setattr__(self, '_file',
+ open_func(_unicode_encode(tmp_name,
+ encoding=_encodings['fs'], errors='strict'),
+ mode=mode, **kargs))
+ return
+ except IOError as e:
+ if canonical_path == filename:
+ raise
+ # Ignore this error, since it's irrelevant
+ # and the below open call will produce a
+ # new error if necessary.
+
+ object.__setattr__(self, '_real_name', filename)
+ tmp_name = "%s.%i" % (filename, os.getpid())
+ object.__setattr__(self, '_file',
+ open_func(_unicode_encode(tmp_name,
+ encoding=_encodings['fs'], errors='strict'),
+ mode=mode, **kargs))
+
+ def _get_target(self):
+ return object.__getattribute__(self, '_file')
+
+ if sys.hexversion >= 0x3000000:
+
+ def __getattribute__(self, attr):
+ if attr in ('close', 'abort', '__del__'):
+ return object.__getattribute__(self, attr)
+ return getattr(object.__getattribute__(self, '_file'), attr)
+
+ else:
+
+ # For TextIOWrapper, automatically coerce write calls to
+ # unicode, in order to avoid TypeError when writing raw
+ # bytes with python2.
+
+ def __getattribute__(self, attr):
+ if attr in ('close', 'abort', 'write', '__del__'):
+ return object.__getattribute__(self, attr)
+ return getattr(object.__getattribute__(self, '_file'), attr)
+
+ def write(self, s):
+ f = object.__getattribute__(self, '_file')
+ if isinstance(f, io.TextIOWrapper):
+ s = _unicode_decode(s)
+ return f.write(s)
+
+ def close(self):
+ """Closes the temporary file, copies permissions (if possible),
+ and performs the atomic replacement via os.rename(). If the abort()
+ method has been called, then the temp file is closed and removed."""
+ f = object.__getattribute__(self, '_file')
+ real_name = object.__getattribute__(self, '_real_name')
+ if not f.closed:
+ try:
+ f.close()
+ if not object.__getattribute__(self, '_aborted'):
+ try:
+ apply_stat_permissions(f.name, os.stat(real_name))
+ except OperationNotPermitted:
+ pass
+ except FileNotFound:
+ pass
+ except OSError as oe: # from the above os.stat call
+ if oe.errno in (errno.ENOENT, errno.EPERM):
+ pass
+ else:
+ raise
+ os.rename(f.name, real_name)
+ finally:
+ # Make sure we cleanup the temp file
+ # even if an exception is raised.
+ try:
+ os.unlink(f.name)
+ except OSError as oe:
+ pass
+
+ def abort(self):
+ """If an error occurs while writing the file, the user should
+ call this method in order to leave the target file unchanged.
+ This will call close() automatically."""
+ if not object.__getattribute__(self, '_aborted'):
+ object.__setattr__(self, '_aborted', True)
+ self.close()
+
+ def __del__(self):
+ """If the user does not explicitely call close(), it is
+ assumed that an error has occurred, so we abort()."""
+ try:
+ f = object.__getattribute__(self, '_file')
+ except AttributeError:
+ pass
+ else:
+ if not f.closed:
+ self.abort()
+ # ensure destructor from the base class is called
+ base_destructor = getattr(ObjectProxy, '__del__', None)
+ if base_destructor is not None:
+ base_destructor(self)
+
+def write_atomic(file_path, content, **kwargs):
+ f = None
+ try:
+ f = atomic_ofstream(file_path, **kwargs)
+ f.write(content)
+ f.close()
+ except (IOError, OSError) as e:
+ if f:
+ f.abort()
+ func_call = "write_atomic('%s')" % file_path
+ if e.errno == errno.EPERM:
+ raise OperationNotPermitted(func_call)
+ elif e.errno == errno.EACCES:
+ raise PermissionDenied(func_call)
+ elif e.errno == errno.EROFS:
+ raise ReadOnlyFileSystem(func_call)
+ elif e.errno == errno.ENOENT:
+ raise FileNotFound(file_path)
+ else:
+ raise
+
+def ensure_dirs(dir_path, **kwargs):
+ """Create a directory and call apply_permissions.
+ Returns True if a directory is created or the permissions needed to be
+ modified, and False otherwise.
+
+ This function's handling of EEXIST errors makes it useful for atomic
+ directory creation, in which multiple processes may be competing to
+ create the same directory.
+ """
+
+ created_dir = False
+
+ try:
+ os.makedirs(dir_path)
+ created_dir = True
+ except OSError as oe:
+ func_call = "makedirs('%s')" % dir_path
+ if oe.errno in (errno.EEXIST,):
+ pass
+ else:
+ if os.path.isdir(dir_path):
+ # NOTE: DragonFly raises EPERM for makedir('/')
+ # and that is supposed to be ignored here.
+ # Also, sometimes mkdir raises EISDIR on FreeBSD
+ # and we want to ignore that too (bug #187518).
+ pass
+ elif oe.errno == errno.EPERM:
+ raise OperationNotPermitted(func_call)
+ elif oe.errno == errno.EACCES:
+ raise PermissionDenied(func_call)
+ elif oe.errno == errno.EROFS:
+ raise ReadOnlyFileSystem(func_call)
+ else:
+ raise
+ if kwargs:
+ perms_modified = apply_permissions(dir_path, **kwargs)
+ else:
+ perms_modified = False
+ return created_dir or perms_modified
+
+class LazyItemsDict(UserDict):
+ """A mapping object that behaves like a standard dict except that it allows
+ for lazy initialization of values via callable objects. Lazy items can be
+ overwritten and deleted just as normal items."""
+
+ __slots__ = ('lazy_items',)
+
+ def __init__(self, *args, **kwargs):
+
+ self.lazy_items = {}
+ UserDict.__init__(self, *args, **kwargs)
+
+ def addLazyItem(self, item_key, value_callable, *pargs, **kwargs):
+ """Add a lazy item for the given key. When the item is requested,
+ value_callable will be called with *pargs and **kwargs arguments."""
+ self.lazy_items[item_key] = \
+ self._LazyItem(value_callable, pargs, kwargs, False)
+ # make it show up in self.keys(), etc...
+ UserDict.__setitem__(self, item_key, None)
+
+ def addLazySingleton(self, item_key, value_callable, *pargs, **kwargs):
+ """This is like addLazyItem except value_callable will only be called
+ a maximum of 1 time and the result will be cached for future requests."""
+ self.lazy_items[item_key] = \
+ self._LazyItem(value_callable, pargs, kwargs, True)
+ # make it show up in self.keys(), etc...
+ UserDict.__setitem__(self, item_key, None)
+
+ def update(self, *args, **kwargs):
+ if len(args) > 1:
+ raise TypeError(
+ "expected at most 1 positional argument, got " + \
+ repr(len(args)))
+ if args:
+ map_obj = args[0]
+ else:
+ map_obj = None
+ if map_obj is None:
+ pass
+ elif isinstance(map_obj, LazyItemsDict):
+ for k in map_obj:
+ if k in map_obj.lazy_items:
+ UserDict.__setitem__(self, k, None)
+ else:
+ UserDict.__setitem__(self, k, map_obj[k])
+ self.lazy_items.update(map_obj.lazy_items)
+ else:
+ UserDict.update(self, map_obj)
+ if kwargs:
+ UserDict.update(self, kwargs)
+
+ def __getitem__(self, item_key):
+ if item_key in self.lazy_items:
+ lazy_item = self.lazy_items[item_key]
+ pargs = lazy_item.pargs
+ if pargs is None:
+ pargs = ()
+ kwargs = lazy_item.kwargs
+ if kwargs is None:
+ kwargs = {}
+ result = lazy_item.func(*pargs, **kwargs)
+ if lazy_item.singleton:
+ self[item_key] = result
+ return result
+
+ else:
+ return UserDict.__getitem__(self, item_key)
+
+ def __setitem__(self, item_key, value):
+ if item_key in self.lazy_items:
+ del self.lazy_items[item_key]
+ UserDict.__setitem__(self, item_key, value)
+
+ def __delitem__(self, item_key):
+ if item_key in self.lazy_items:
+ del self.lazy_items[item_key]
+ UserDict.__delitem__(self, item_key)
+
+ def clear(self):
+ self.lazy_items.clear()
+ UserDict.clear(self)
+
+ def copy(self):
+ return self.__copy__()
+
+ def __copy__(self):
+ return self.__class__(self)
+
+ def __deepcopy__(self, memo=None):
+ """
+ This forces evaluation of each contained lazy item, and deepcopy of
+ the result. A TypeError is raised if any contained lazy item is not
+ a singleton, since it is not necessarily possible for the behavior
+ of this type of item to be safely preserved.
+ """
+ if memo is None:
+ memo = {}
+ result = self.__class__()
+ memo[id(self)] = result
+ for k in self:
+ k_copy = deepcopy(k, memo)
+ lazy_item = self.lazy_items.get(k)
+ if lazy_item is not None:
+ if not lazy_item.singleton:
+ raise TypeError(_unicode_decode("LazyItemsDict " + \
+ "deepcopy is unsafe with lazy items that are " + \
+ "not singletons: key=%s value=%s") % (k, lazy_item,))
+ UserDict.__setitem__(result, k_copy, deepcopy(self[k], memo))
+ return result
+
+ class _LazyItem(object):
+
+ __slots__ = ('func', 'pargs', 'kwargs', 'singleton')
+
+ def __init__(self, func, pargs, kwargs, singleton):
+
+ if not pargs:
+ pargs = None
+ if not kwargs:
+ kwargs = None
+
+ self.func = func
+ self.pargs = pargs
+ self.kwargs = kwargs
+ self.singleton = singleton
+
+ def __copy__(self):
+ return self.__class__(self.func, self.pargs,
+ self.kwargs, self.singleton)
+
+ def __deepcopy__(self, memo=None):
+ """
+ Override this since the default implementation can fail silently,
+ leaving some attributes unset.
+ """
+ if memo is None:
+ memo = {}
+ result = self.__copy__()
+ memo[id(self)] = result
+ result.func = deepcopy(self.func, memo)
+ result.pargs = deepcopy(self.pargs, memo)
+ result.kwargs = deepcopy(self.kwargs, memo)
+ result.singleton = deepcopy(self.singleton, memo)
+ return result
+
+class ConfigProtect(object):
+ def __init__(self, myroot, protect_list, mask_list):
+ self.myroot = myroot
+ self.protect_list = protect_list
+ self.mask_list = mask_list
+ self.updateprotect()
+
+ def updateprotect(self):
+ """Update internal state for isprotected() calls. Nonexistent paths
+ are ignored."""
+
+ os = _os_merge
+
+ self.protect = []
+ self._dirs = set()
+ for x in self.protect_list:
+ ppath = normalize_path(
+ os.path.join(self.myroot, x.lstrip(os.path.sep)))
+ try:
+ if stat.S_ISDIR(os.stat(ppath).st_mode):
+ self._dirs.add(ppath)
+ self.protect.append(ppath)
+ except OSError:
+ # If it doesn't exist, there's no need to protect it.
+ pass
+
+ self.protectmask = []
+ for x in self.mask_list:
+ ppath = normalize_path(
+ os.path.join(self.myroot, x.lstrip(os.path.sep)))
+ try:
+ """Use lstat so that anything, even a broken symlink can be
+ protected."""
+ if stat.S_ISDIR(os.lstat(ppath).st_mode):
+ self._dirs.add(ppath)
+ self.protectmask.append(ppath)
+ """Now use stat in case this is a symlink to a directory."""
+ if stat.S_ISDIR(os.stat(ppath).st_mode):
+ self._dirs.add(ppath)
+ except OSError:
+ # If it doesn't exist, there's no need to mask it.
+ pass
+
+ def isprotected(self, obj):
+ """Returns True if obj is protected, False otherwise. The caller must
+ ensure that obj is normalized with a single leading slash. A trailing
+ slash is optional for directories."""
+ masked = 0
+ protected = 0
+ sep = os.path.sep
+ for ppath in self.protect:
+ if len(ppath) > masked and obj.startswith(ppath):
+ if ppath in self._dirs:
+ if obj != ppath and not obj.startswith(ppath + sep):
+ # /etc/foo does not match /etc/foobaz
+ continue
+ elif obj != ppath:
+ # force exact match when CONFIG_PROTECT lists a
+ # non-directory
+ continue
+ protected = len(ppath)
+ #config file management
+ for pmpath in self.protectmask:
+ if len(pmpath) >= protected and obj.startswith(pmpath):
+ if pmpath in self._dirs:
+ if obj != pmpath and \
+ not obj.startswith(pmpath + sep):
+ # /etc/foo does not match /etc/foobaz
+ continue
+ elif obj != pmpath:
+ # force exact match when CONFIG_PROTECT_MASK lists
+ # a non-directory
+ continue
+ #skip, it's in the mask
+ masked = len(pmpath)
+ return protected > masked
+
+def new_protect_filename(mydest, newmd5=None, force=False):
+ """Resolves a config-protect filename for merging, optionally
+ using the last filename if the md5 matches. If force is True,
+ then a new filename will be generated even if mydest does not
+ exist yet.
+ (dest,md5) ==> 'string' --- path_to_target_filename
+ (dest) ==> ('next', 'highest') --- next_target and most-recent_target
+ """
+
+ # config protection filename format:
+ # ._cfg0000_foo
+ # 0123456789012
+
+ os = _os_merge
+
+ prot_num = -1
+ last_pfile = ""
+
+ if not force and \
+ not os.path.exists(mydest):
+ return mydest
+
+ real_filename = os.path.basename(mydest)
+ real_dirname = os.path.dirname(mydest)
+ for pfile in os.listdir(real_dirname):
+ if pfile[0:5] != "._cfg":
+ continue
+ if pfile[10:] != real_filename:
+ continue
+ try:
+ new_prot_num = int(pfile[5:9])
+ if new_prot_num > prot_num:
+ prot_num = new_prot_num
+ last_pfile = pfile
+ except ValueError:
+ continue
+ prot_num = prot_num + 1
+
+ new_pfile = normalize_path(os.path.join(real_dirname,
+ "._cfg" + str(prot_num).zfill(4) + "_" + real_filename))
+ old_pfile = normalize_path(os.path.join(real_dirname, last_pfile))
+ if last_pfile and newmd5:
+ try:
+ last_pfile_md5 = portage.checksum._perform_md5_merge(old_pfile)
+ except FileNotFound:
+ # The file suddenly disappeared or it's a broken symlink.
+ pass
+ else:
+ if last_pfile_md5 == newmd5:
+ return old_pfile
+ return new_pfile
+
+def find_updated_config_files(target_root, config_protect):
+ """
+ Return a tuple of configuration files that needs to be updated.
+ The tuple contains lists organized like this:
+ [ protected_dir, file_list ]
+ If the protected config isn't a protected_dir but a procted_file, list is:
+ [ protected_file, None ]
+ If no configuration files needs to be updated, None is returned
+ """
+
+ os = _os_merge
+
+ if config_protect:
+ # directories with some protect files in them
+ for x in config_protect:
+ files = []
+
+ x = os.path.join(target_root, x.lstrip(os.path.sep))
+ if not os.access(x, os.W_OK):
+ continue
+ try:
+ mymode = os.lstat(x).st_mode
+ except OSError:
+ continue
+
+ if stat.S_ISLNK(mymode):
+ # We want to treat it like a directory if it
+ # is a symlink to an existing directory.
+ try:
+ real_mode = os.stat(x).st_mode
+ if stat.S_ISDIR(real_mode):
+ mymode = real_mode
+ except OSError:
+ pass
+
+ if stat.S_ISDIR(mymode):
+ mycommand = \
+ "find '%s' -name '.*' -type d -prune -o -name '._cfg????_*'" % x
+ else:
+ mycommand = "find '%s' -maxdepth 1 -name '._cfg????_%s'" % \
+ os.path.split(x.rstrip(os.path.sep))
+ mycommand += " ! -name '.*~' ! -iname '.*.bak' -print0"
+ a = subprocess_getstatusoutput(mycommand)
+
+ if a[0] == 0:
+ files = a[1].split('\0')
+ # split always produces an empty string as the last element
+ if files and not files[-1]:
+ del files[-1]
+ if files:
+ if stat.S_ISDIR(mymode):
+ yield (x, files)
+ else:
+ yield (x, None)
+
+def getlibpaths(root, env=None):
+ """ Return a list of paths that are used for library lookups """
+ if env is None:
+ env = os.environ
+ # the following is based on the information from ld.so(8)
+ rval = env.get("LD_LIBRARY_PATH", "").split(":")
+ rval.extend(grabfile(os.path.join(root, "etc", "ld.so.conf")))
+ rval.append("/usr/lib")
+ rval.append("/lib")
+
+ return [normalize_path(x) for x in rval if x]
diff --git a/portage_with_autodep/pym/portage/util/_dyn_libs/LinkageMapELF.py b/portage_with_autodep/pym/portage/util/_dyn_libs/LinkageMapELF.py
new file mode 100644
index 0000000..52670d9
--- /dev/null
+++ b/portage_with_autodep/pym/portage/util/_dyn_libs/LinkageMapELF.py
@@ -0,0 +1,805 @@
+# Copyright 1998-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import errno
+import logging
+import subprocess
+
+import portage
+from portage import _encodings
+from portage import _os_merge
+from portage import _unicode_decode
+from portage import _unicode_encode
+from portage.cache.mappings import slot_dict_class
+from portage.exception import CommandNotFound
+from portage.localization import _
+from portage.util import getlibpaths
+from portage.util import grabfile
+from portage.util import normalize_path
+from portage.util import writemsg_level
+
+class LinkageMapELF(object):
+
+ """Models dynamic linker dependencies."""
+
+ _needed_aux_key = "NEEDED.ELF.2"
+ _soname_map_class = slot_dict_class(
+ ("consumers", "providers"), prefix="")
+
+ class _obj_properies_class(object):
+
+ __slots__ = ("arch", "needed", "runpaths", "soname", "alt_paths",
+ "owner",)
+
+ def __init__(self, arch, needed, runpaths, soname, alt_paths, owner):
+ self.arch = arch
+ self.needed = needed
+ self.runpaths = runpaths
+ self.soname = soname
+ self.alt_paths = alt_paths
+ self.owner = owner
+
+ def __init__(self, vardbapi):
+ self._dbapi = vardbapi
+ self._root = self._dbapi.settings['ROOT']
+ self._libs = {}
+ self._obj_properties = {}
+ self._obj_key_cache = {}
+ self._defpath = set()
+ self._path_key_cache = {}
+
+ def _clear_cache(self):
+ self._libs.clear()
+ self._obj_properties.clear()
+ self._obj_key_cache.clear()
+ self._defpath.clear()
+ self._path_key_cache.clear()
+
+ def _path_key(self, path):
+ key = self._path_key_cache.get(path)
+ if key is None:
+ key = self._ObjectKey(path, self._root)
+ self._path_key_cache[path] = key
+ return key
+
+ def _obj_key(self, path):
+ key = self._obj_key_cache.get(path)
+ if key is None:
+ key = self._ObjectKey(path, self._root)
+ self._obj_key_cache[path] = key
+ return key
+
+ class _ObjectKey(object):
+
+ """Helper class used as _obj_properties keys for objects."""
+
+ __slots__ = ("_key",)
+
+ def __init__(self, obj, root):
+ """
+ This takes a path to an object.
+
+ @param object: path to a file
+ @type object: string (example: '/usr/bin/bar')
+
+ """
+ self._key = self._generate_object_key(obj, root)
+
+ def __hash__(self):
+ return hash(self._key)
+
+ def __eq__(self, other):
+ return self._key == other._key
+
+ def _generate_object_key(self, obj, root):
+ """
+ Generate object key for a given object.
+
+ @param object: path to a file
+ @type object: string (example: '/usr/bin/bar')
+ @rtype: 2-tuple of types (long, int) if object exists. string if
+ object does not exist.
+ @return:
+ 1. 2-tuple of object's inode and device from a stat call, if object
+ exists.
+ 2. realpath of object if object does not exist.
+
+ """
+
+ os = _os_merge
+
+ try:
+ _unicode_encode(obj,
+ encoding=_encodings['merge'], errors='strict')
+ except UnicodeEncodeError:
+ # The package appears to have been merged with a
+ # different value of sys.getfilesystemencoding(),
+ # so fall back to utf_8 if appropriate.
+ try:
+ _unicode_encode(obj,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeEncodeError:
+ pass
+ else:
+ os = portage.os
+
+ abs_path = os.path.join(root, obj.lstrip(os.sep))
+ try:
+ object_stat = os.stat(abs_path)
+ except OSError:
+ # Use the realpath as the key if the file does not exists on the
+ # filesystem.
+ return os.path.realpath(abs_path)
+ # Return a tuple of the device and inode.
+ return (object_stat.st_dev, object_stat.st_ino)
+
+ def file_exists(self):
+ """
+ Determine if the file for this key exists on the filesystem.
+
+ @rtype: Boolean
+ @return:
+ 1. True if the file exists.
+ 2. False if the file does not exist or is a broken symlink.
+
+ """
+ return isinstance(self._key, tuple)
+
+ class _LibGraphNode(_ObjectKey):
+ __slots__ = ("alt_paths",)
+
+ def __init__(self, key):
+ """
+ Create a _LibGraphNode from an existing _ObjectKey.
+ This re-uses the _key attribute in order to avoid repeating
+ any previous stat calls, which helps to avoid potential race
+ conditions due to inconsistent stat results when the
+ file system is being modified concurrently.
+ """
+ self._key = key._key
+ self.alt_paths = set()
+
+ def __str__(self):
+ return str(sorted(self.alt_paths))
+
+ def rebuild(self, exclude_pkgs=None, include_file=None,
+ preserve_paths=None):
+ """
+ Raises CommandNotFound if there are preserved libs
+ and the scanelf binary is not available.
+
+ @param exclude_pkgs: A set of packages that should be excluded from
+ the LinkageMap, since they are being unmerged and their NEEDED
+ entries are therefore irrelevant and would only serve to corrupt
+ the LinkageMap.
+ @type exclude_pkgs: set
+ @param include_file: The path of a file containing NEEDED entries for
+ a package which does not exist in the vardbapi yet because it is
+ currently being merged.
+ @type include_file: String
+ @param preserve_paths: Libraries preserved by a package instance that
+ is currently being merged. They need to be explicitly passed to the
+ LinkageMap, since they are not registered in the
+ PreservedLibsRegistry yet.
+ @type preserve_paths: set
+ """
+
+ os = _os_merge
+ root = self._root
+ root_len = len(root) - 1
+ self._clear_cache()
+ self._defpath.update(getlibpaths(self._root, env=self._dbapi.settings))
+ libs = self._libs
+ obj_properties = self._obj_properties
+
+ lines = []
+
+ # Data from include_file is processed first so that it
+ # overrides any data from previously installed files.
+ if include_file is not None:
+ for line in grabfile(include_file):
+ lines.append((None, include_file, line))
+
+ aux_keys = [self._needed_aux_key]
+ can_lock = os.access(os.path.dirname(self._dbapi._dbroot), os.W_OK)
+ if can_lock:
+ self._dbapi.lock()
+ try:
+ for cpv in self._dbapi.cpv_all():
+ if exclude_pkgs is not None and cpv in exclude_pkgs:
+ continue
+ needed_file = self._dbapi.getpath(cpv,
+ filename=self._needed_aux_key)
+ for line in self._dbapi.aux_get(cpv, aux_keys)[0].splitlines():
+ lines.append((cpv, needed_file, line))
+ finally:
+ if can_lock:
+ self._dbapi.unlock()
+
+ # have to call scanelf for preserved libs here as they aren't
+ # registered in NEEDED.ELF.2 files
+ plibs = {}
+ if preserve_paths is not None:
+ plibs.update((x, None) for x in preserve_paths)
+ if self._dbapi._plib_registry and \
+ self._dbapi._plib_registry.hasEntries():
+ for cpv, items in \
+ self._dbapi._plib_registry.getPreservedLibs().items():
+ if exclude_pkgs is not None and cpv in exclude_pkgs:
+ # These preserved libs will either be unmerged,
+ # rendering them irrelevant, or they will be
+ # preserved in the replacement package and are
+ # already represented via the preserve_paths
+ # parameter.
+ continue
+ plibs.update((x, cpv) for x in items)
+ if plibs:
+ args = ["/usr/bin/scanelf", "-qF", "%a;%F;%S;%r;%n"]
+ args.extend(os.path.join(root, x.lstrip("." + os.sep)) \
+ for x in plibs)
+ try:
+ proc = subprocess.Popen(args, stdout=subprocess.PIPE)
+ except EnvironmentError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ raise CommandNotFound(args[0])
+ else:
+ for l in proc.stdout:
+ try:
+ l = _unicode_decode(l,
+ encoding=_encodings['content'], errors='strict')
+ except UnicodeDecodeError:
+ l = _unicode_decode(l,
+ encoding=_encodings['content'], errors='replace')
+ writemsg_level(_("\nError decoding characters " \
+ "returned from scanelf: %s\n\n") % (l,),
+ level=logging.ERROR, noiselevel=-1)
+ l = l[3:].rstrip("\n")
+ if not l:
+ continue
+ fields = l.split(";")
+ if len(fields) < 5:
+ writemsg_level(_("\nWrong number of fields " \
+ "returned from scanelf: %s\n\n") % (l,),
+ level=logging.ERROR, noiselevel=-1)
+ continue
+ fields[1] = fields[1][root_len:]
+ owner = plibs.pop(fields[1], None)
+ lines.append((owner, "scanelf", ";".join(fields)))
+ proc.wait()
+
+ if plibs:
+ # Preserved libraries that did not appear in the scanelf output.
+ # This is known to happen with statically linked libraries.
+ # Generate dummy lines for these, so we can assume that every
+ # preserved library has an entry in self._obj_properties. This
+ # is important in order to prevent findConsumers from raising
+ # an unwanted KeyError.
+ for x, cpv in plibs.items():
+ lines.append((cpv, "plibs", ";".join(['', x, '', '', ''])))
+
+ # Share identical frozenset instances when available,
+ # in order to conserve memory.
+ frozensets = {}
+
+ for owner, location, l in lines:
+ l = l.rstrip("\n")
+ if not l:
+ continue
+ fields = l.split(";")
+ if len(fields) < 5:
+ writemsg_level(_("\nWrong number of fields " \
+ "in %s: %s\n\n") % (location, l),
+ level=logging.ERROR, noiselevel=-1)
+ continue
+ arch = fields[0]
+ obj = fields[1]
+ soname = fields[2]
+ path = frozenset(normalize_path(x) \
+ for x in filter(None, fields[3].replace(
+ "${ORIGIN}", os.path.dirname(obj)).replace(
+ "$ORIGIN", os.path.dirname(obj)).split(":")))
+ path = frozensets.setdefault(path, path)
+ needed = frozenset(x for x in fields[4].split(",") if x)
+ needed = frozensets.setdefault(needed, needed)
+
+ obj_key = self._obj_key(obj)
+ indexed = True
+ myprops = obj_properties.get(obj_key)
+ if myprops is None:
+ indexed = False
+ myprops = self._obj_properies_class(
+ arch, needed, path, soname, [], owner)
+ obj_properties[obj_key] = myprops
+ # All object paths are added into the obj_properties tuple.
+ myprops.alt_paths.append(obj)
+
+ # Don't index the same file more that once since only one
+ # set of data can be correct and therefore mixing data
+ # may corrupt the index (include_file overrides previously
+ # installed).
+ if indexed:
+ continue
+
+ arch_map = libs.get(arch)
+ if arch_map is None:
+ arch_map = {}
+ libs[arch] = arch_map
+ if soname:
+ soname_map = arch_map.get(soname)
+ if soname_map is None:
+ soname_map = self._soname_map_class(
+ providers=[], consumers=[])
+ arch_map[soname] = soname_map
+ soname_map.providers.append(obj_key)
+ for needed_soname in needed:
+ soname_map = arch_map.get(needed_soname)
+ if soname_map is None:
+ soname_map = self._soname_map_class(
+ providers=[], consumers=[])
+ arch_map[needed_soname] = soname_map
+ soname_map.consumers.append(obj_key)
+
+ for arch, sonames in libs.items():
+ for soname_node in sonames.values():
+ soname_node.providers = tuple(set(soname_node.providers))
+ soname_node.consumers = tuple(set(soname_node.consumers))
+
+ def listBrokenBinaries(self, debug=False):
+ """
+ Find binaries and their needed sonames, which have no providers.
+
+ @param debug: Boolean to enable debug output
+ @type debug: Boolean
+ @rtype: dict (example: {'/usr/bin/foo': set(['libbar.so'])})
+ @return: The return value is an object -> set-of-sonames mapping, where
+ object is a broken binary and the set consists of sonames needed by
+ object that have no corresponding libraries to fulfill the dependency.
+
+ """
+
+ os = _os_merge
+
+ class _LibraryCache(object):
+
+ """
+ Caches properties associated with paths.
+
+ The purpose of this class is to prevent multiple instances of
+ _ObjectKey for the same paths.
+
+ """
+
+ def __init__(cache_self):
+ cache_self.cache = {}
+
+ def get(cache_self, obj):
+ """
+ Caches and returns properties associated with an object.
+
+ @param obj: absolute path (can be symlink)
+ @type obj: string (example: '/usr/lib/libfoo.so')
+ @rtype: 4-tuple with types
+ (string or None, string or None, 2-tuple, Boolean)
+ @return: 4-tuple with the following components:
+ 1. arch as a string or None if it does not exist,
+ 2. soname as a string or None if it does not exist,
+ 3. obj_key as 2-tuple,
+ 4. Boolean representing whether the object exists.
+ (example: ('libfoo.so.1', (123L, 456L), True))
+
+ """
+ if obj in cache_self.cache:
+ return cache_self.cache[obj]
+ else:
+ obj_key = self._obj_key(obj)
+ # Check that the library exists on the filesystem.
+ if obj_key.file_exists():
+ # Get the arch and soname from LinkageMap._obj_properties if
+ # it exists. Otherwise, None.
+ obj_props = self._obj_properties.get(obj_key)
+ if obj_props is None:
+ arch = None
+ soname = None
+ else:
+ arch = obj_props.arch
+ soname = obj_props.soname
+ return cache_self.cache.setdefault(obj, \
+ (arch, soname, obj_key, True))
+ else:
+ return cache_self.cache.setdefault(obj, \
+ (None, None, obj_key, False))
+
+ rValue = {}
+ cache = _LibraryCache()
+ providers = self.listProviders()
+
+ # Iterate over all obj_keys and their providers.
+ for obj_key, sonames in providers.items():
+ obj_props = self._obj_properties[obj_key]
+ arch = obj_props.arch
+ path = obj_props.runpaths
+ objs = obj_props.alt_paths
+ path = path.union(self._defpath)
+ # Iterate over each needed soname and the set of library paths that
+ # fulfill the soname to determine if the dependency is broken.
+ for soname, libraries in sonames.items():
+ # validLibraries is used to store libraries, which satisfy soname,
+ # so if no valid libraries are found, the soname is not satisfied
+ # for obj_key. If unsatisfied, objects associated with obj_key
+ # must be emerged.
+ validLibraries = set()
+ # It could be the case that the library to satisfy the soname is
+ # not in the obj's runpath, but a symlink to the library is (eg
+ # libnvidia-tls.so.1 in nvidia-drivers). Also, since LinkageMap
+ # does not catalog symlinks, broken or missing symlinks may go
+ # unnoticed. As a result of these cases, check that a file with
+ # the same name as the soname exists in obj's runpath.
+ # XXX If we catalog symlinks in LinkageMap, this could be improved.
+ for directory in path:
+ cachedArch, cachedSoname, cachedKey, cachedExists = \
+ cache.get(os.path.join(directory, soname))
+ # Check that this library provides the needed soname. Doing
+ # this, however, will cause consumers of libraries missing
+ # sonames to be unnecessarily emerged. (eg libmix.so)
+ if cachedSoname == soname and cachedArch == arch:
+ validLibraries.add(cachedKey)
+ if debug and cachedKey not in \
+ set(map(self._obj_key_cache.get, libraries)):
+ # XXX This is most often due to soname symlinks not in
+ # a library's directory. We could catalog symlinks in
+ # LinkageMap to avoid checking for this edge case here.
+ writemsg_level(
+ _("Found provider outside of findProviders:") + \
+ (" %s -> %s %s\n" % (os.path.join(directory, soname),
+ self._obj_properties[cachedKey].alt_paths, libraries)),
+ level=logging.DEBUG,
+ noiselevel=-1)
+ # A valid library has been found, so there is no need to
+ # continue.
+ break
+ if debug and cachedArch == arch and \
+ cachedKey in self._obj_properties:
+ writemsg_level((_("Broken symlink or missing/bad soname: " + \
+ "%(dir_soname)s -> %(cachedKey)s " + \
+ "with soname %(cachedSoname)s but expecting %(soname)s") % \
+ {"dir_soname":os.path.join(directory, soname),
+ "cachedKey": self._obj_properties[cachedKey],
+ "cachedSoname": cachedSoname, "soname":soname}) + "\n",
+ level=logging.DEBUG,
+ noiselevel=-1)
+ # This conditional checks if there are no libraries to satisfy the
+ # soname (empty set).
+ if not validLibraries:
+ for obj in objs:
+ rValue.setdefault(obj, set()).add(soname)
+ # If no valid libraries have been found by this point, then
+ # there are no files named with the soname within obj's runpath,
+ # but if there are libraries (from the providers mapping), it is
+ # likely that soname symlinks or the actual libraries are
+ # missing or broken. Thus those libraries are added to rValue
+ # in order to emerge corrupt library packages.
+ for lib in libraries:
+ rValue.setdefault(lib, set()).add(soname)
+ if debug:
+ if not os.path.isfile(lib):
+ writemsg_level(_("Missing library:") + " %s\n" % (lib,),
+ level=logging.DEBUG,
+ noiselevel=-1)
+ else:
+ writemsg_level(_("Possibly missing symlink:") + \
+ "%s\n" % (os.path.join(os.path.dirname(lib), soname)),
+ level=logging.DEBUG,
+ noiselevel=-1)
+ return rValue
+
+ def listProviders(self):
+ """
+ Find the providers for all object keys in LinkageMap.
+
+ @rtype: dict (example:
+ {(123L, 456L): {'libbar.so': set(['/lib/libbar.so.1.5'])}})
+ @return: The return value is an object key -> providers mapping, where
+ providers is a mapping of soname -> set-of-library-paths returned
+ from the findProviders method.
+
+ """
+ rValue = {}
+ if not self._libs:
+ self.rebuild()
+ # Iterate over all object keys within LinkageMap.
+ for obj_key in self._obj_properties:
+ rValue.setdefault(obj_key, self.findProviders(obj_key))
+ return rValue
+
+ def isMasterLink(self, obj):
+ """
+ Determine whether an object is a "master" symlink, which means
+ that its basename is the same as the beginning part of the
+ soname and it lacks the soname's version component.
+
+ Examples:
+
+ soname | master symlink name
+ --------------------------------------------
+ libarchive.so.2.8.4 | libarchive.so
+ libproc-3.2.8.so | libproc.so
+
+ @param obj: absolute path to an object
+ @type obj: string (example: '/usr/bin/foo')
+ @rtype: Boolean
+ @return:
+ 1. True if obj is a master link
+ 2. False if obj is not a master link
+
+ """
+ os = _os_merge
+ obj_key = self._obj_key(obj)
+ if obj_key not in self._obj_properties:
+ raise KeyError("%s (%s) not in object list" % (obj_key, obj))
+ basename = os.path.basename(obj)
+ soname = self._obj_properties[obj_key].soname
+ return len(basename) < len(soname) and \
+ basename.endswith(".so") and \
+ soname.startswith(basename[:-3])
+
+ def listLibraryObjects(self):
+ """
+ Return a list of library objects.
+
+ Known limitation: library objects lacking an soname are not included.
+
+ @rtype: list of strings
+ @return: list of paths to all providers
+
+ """
+ rValue = []
+ if not self._libs:
+ self.rebuild()
+ for arch_map in self._libs.values():
+ for soname_map in arch_map.values():
+ for obj_key in soname_map.providers:
+ rValue.extend(self._obj_properties[obj_key].alt_paths)
+ return rValue
+
+ def getOwners(self, obj):
+ """
+ Return the package(s) associated with an object. Raises KeyError
+ if the object is unknown. Returns an empty tuple if the owner(s)
+ are unknown.
+
+ NOTE: For preserved libraries, the owner(s) may have been
+ previously uninstalled, but these uninstalled owners can be
+ returned by this method since they are registered in the
+ PreservedLibsRegistry.
+
+ @param obj: absolute path to an object
+ @type obj: string (example: '/usr/bin/bar')
+ @rtype: tuple
+ @return: a tuple of cpv
+ """
+ if not self._libs:
+ self.rebuild()
+ if isinstance(obj, self._ObjectKey):
+ obj_key = obj
+ else:
+ obj_key = self._obj_key_cache.get(obj)
+ if obj_key is None:
+ raise KeyError("%s not in object list" % obj)
+ obj_props = self._obj_properties.get(obj_key)
+ if obj_props is None:
+ raise KeyError("%s not in object list" % obj_key)
+ if obj_props.owner is None:
+ return ()
+ return (obj_props.owner,)
+
+ def getSoname(self, obj):
+ """
+ Return the soname associated with an object.
+
+ @param obj: absolute path to an object
+ @type obj: string (example: '/usr/bin/bar')
+ @rtype: string
+ @return: soname as a string
+
+ """
+ if not self._libs:
+ self.rebuild()
+ if isinstance(obj, self._ObjectKey):
+ obj_key = obj
+ if obj_key not in self._obj_properties:
+ raise KeyError("%s not in object list" % obj_key)
+ return self._obj_properties[obj_key].soname
+ if obj not in self._obj_key_cache:
+ raise KeyError("%s not in object list" % obj)
+ return self._obj_properties[self._obj_key_cache[obj]].soname
+
+ def findProviders(self, obj):
+ """
+ Find providers for an object or object key.
+
+ This method may be called with a key from _obj_properties.
+
+ In some cases, not all valid libraries are returned. This may occur when
+ an soname symlink referencing a library is in an object's runpath while
+ the actual library is not. We should consider cataloging symlinks within
+ LinkageMap as this would avoid those cases and would be a better model of
+ library dependencies (since the dynamic linker actually searches for
+ files named with the soname in the runpaths).
+
+ @param obj: absolute path to an object or a key from _obj_properties
+ @type obj: string (example: '/usr/bin/bar') or _ObjectKey
+ @rtype: dict (example: {'libbar.so': set(['/lib/libbar.so.1.5'])})
+ @return: The return value is a soname -> set-of-library-paths, where
+ set-of-library-paths satisfy soname.
+
+ """
+
+ os = _os_merge
+
+ rValue = {}
+
+ if not self._libs:
+ self.rebuild()
+
+ # Determine the obj_key from the arguments.
+ if isinstance(obj, self._ObjectKey):
+ obj_key = obj
+ if obj_key not in self._obj_properties:
+ raise KeyError("%s not in object list" % obj_key)
+ else:
+ obj_key = self._obj_key(obj)
+ if obj_key not in self._obj_properties:
+ raise KeyError("%s (%s) not in object list" % (obj_key, obj))
+
+ obj_props = self._obj_properties[obj_key]
+ arch = obj_props.arch
+ needed = obj_props.needed
+ path = obj_props.runpaths
+ path_keys = set(self._path_key(x) for x in path.union(self._defpath))
+ for soname in needed:
+ rValue[soname] = set()
+ if arch not in self._libs or soname not in self._libs[arch]:
+ continue
+ # For each potential provider of the soname, add it to rValue if it
+ # resides in the obj's runpath.
+ for provider_key in self._libs[arch][soname].providers:
+ providers = self._obj_properties[provider_key].alt_paths
+ for provider in providers:
+ if self._path_key(os.path.dirname(provider)) in path_keys:
+ rValue[soname].add(provider)
+ return rValue
+
+ def findConsumers(self, obj, exclude_providers=None):
+ """
+ Find consumers of an object or object key.
+
+ This method may be called with a key from _obj_properties. If this
+ method is going to be called with an object key, to avoid not catching
+ shadowed libraries, do not pass new _ObjectKey instances to this method.
+ Instead pass the obj as a string.
+
+ In some cases, not all consumers are returned. This may occur when
+ an soname symlink referencing a library is in an object's runpath while
+ the actual library is not. For example, this problem is noticeable for
+ binutils since it's libraries are added to the path via symlinks that
+ are gemerated in the /usr/$CHOST/lib/ directory by binutils-config.
+ Failure to recognize consumers of these symlinks makes preserve-libs
+ fail to preserve binutils libs that are needed by these unrecognized
+ consumers.
+
+ Note that library consumption via dlopen (common for kde plugins) is
+ currently undetected. However, it is possible to use the
+ corresponding libtool archive (*.la) files to detect such consumers
+ (revdep-rebuild is able to detect them).
+
+ The exclude_providers argument is useful for determining whether
+ removal of one or more packages will create unsatisfied consumers. When
+ this option is given, consumers are excluded from the results if there
+ is an alternative provider (which is not excluded) of the required
+ soname such that the consumers will remain satisfied if the files
+ owned by exclude_providers are removed.
+
+ @param obj: absolute path to an object or a key from _obj_properties
+ @type obj: string (example: '/usr/bin/bar') or _ObjectKey
+ @param exclude_providers: A collection of callables that each take a
+ single argument referring to the path of a library (example:
+ '/usr/lib/libssl.so.0.9.8'), and return True if the library is
+ owned by a provider which is planned for removal.
+ @type exclude_providers: collection
+ @rtype: set of strings (example: set(['/bin/foo', '/usr/bin/bar']))
+ @return: The return value is a soname -> set-of-library-paths, where
+ set-of-library-paths satisfy soname.
+
+ """
+
+ os = _os_merge
+
+ if not self._libs:
+ self.rebuild()
+
+ # Determine the obj_key and the set of objects matching the arguments.
+ if isinstance(obj, self._ObjectKey):
+ obj_key = obj
+ if obj_key not in self._obj_properties:
+ raise KeyError("%s not in object list" % obj_key)
+ objs = self._obj_properties[obj_key].alt_paths
+ else:
+ objs = set([obj])
+ obj_key = self._obj_key(obj)
+ if obj_key not in self._obj_properties:
+ raise KeyError("%s (%s) not in object list" % (obj_key, obj))
+
+ # If there is another version of this lib with the
+ # same soname and the soname symlink points to that
+ # other version, this lib will be shadowed and won't
+ # have any consumers.
+ if not isinstance(obj, self._ObjectKey):
+ soname = self._obj_properties[obj_key].soname
+ soname_link = os.path.join(self._root,
+ os.path.dirname(obj).lstrip(os.path.sep), soname)
+ obj_path = os.path.join(self._root, obj.lstrip(os.sep))
+ try:
+ soname_st = os.stat(soname_link)
+ obj_st = os.stat(obj_path)
+ except OSError:
+ pass
+ else:
+ if (obj_st.st_dev, obj_st.st_ino) != \
+ (soname_st.st_dev, soname_st.st_ino):
+ return set()
+
+ obj_props = self._obj_properties[obj_key]
+ arch = obj_props.arch
+ soname = obj_props.soname
+
+ soname_node = None
+ arch_map = self._libs.get(arch)
+ if arch_map is not None:
+ soname_node = arch_map.get(soname)
+
+ defpath_keys = set(self._path_key(x) for x in self._defpath)
+ satisfied_consumer_keys = set()
+ if soname_node is not None:
+ if exclude_providers is not None:
+ relevant_dir_keys = set()
+ for provider_key in soname_node.providers:
+ provider_objs = self._obj_properties[provider_key].alt_paths
+ for p in provider_objs:
+ provider_excluded = False
+ for excluded_provider_isowner in exclude_providers:
+ if excluded_provider_isowner(p):
+ provider_excluded = True
+ break
+ if not provider_excluded:
+ # This provider is not excluded. It will
+ # satisfy a consumer of this soname if it
+ # is in the default ld.so path or the
+ # consumer's runpath.
+ relevant_dir_keys.add(
+ self._path_key(os.path.dirname(p)))
+
+ if relevant_dir_keys:
+ for consumer_key in soname_node.consumers:
+ path = self._obj_properties[consumer_key].runpaths
+ path_keys = defpath_keys.copy()
+ path_keys.update(self._path_key(x) for x in path)
+ if relevant_dir_keys.intersection(path_keys):
+ satisfied_consumer_keys.add(consumer_key)
+
+ rValue = set()
+ if soname_node is not None:
+ # For each potential consumer, add it to rValue if an object from the
+ # arguments resides in the consumer's runpath.
+ objs_dir_keys = set(self._path_key(os.path.dirname(x))
+ for x in objs)
+ for consumer_key in soname_node.consumers:
+ if consumer_key in satisfied_consumer_keys:
+ continue
+ consumer_props = self._obj_properties[consumer_key]
+ path = consumer_props.runpaths
+ consumer_objs = consumer_props.alt_paths
+ path_keys = defpath_keys.union(self._path_key(x) for x in path)
+ if objs_dir_keys.intersection(path_keys):
+ rValue.update(consumer_objs)
+ return rValue
diff --git a/portage_with_autodep/pym/portage/util/_dyn_libs/PreservedLibsRegistry.py b/portage_with_autodep/pym/portage/util/_dyn_libs/PreservedLibsRegistry.py
new file mode 100644
index 0000000..602cf87
--- /dev/null
+++ b/portage_with_autodep/pym/portage/util/_dyn_libs/PreservedLibsRegistry.py
@@ -0,0 +1,172 @@
+# Copyright 1998-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import errno
+import logging
+import sys
+
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+
+from portage import os
+from portage import _encodings
+from portage import _os_merge
+from portage import _unicode_decode
+from portage import _unicode_encode
+from portage.exception import PermissionDenied
+from portage.localization import _
+from portage.util import atomic_ofstream
+from portage.util import writemsg_level
+from portage.versions import cpv_getkey
+from portage.locks import lockfile, unlockfile
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+class PreservedLibsRegistry(object):
+ """ This class handles the tracking of preserved library objects """
+ def __init__(self, root, filename):
+ """
+ @param root: root used to check existence of paths in pruneNonExisting
+ @type root: String
+ @param filename: absolute path for saving the preserved libs records
+ @type filename: String
+ """
+ self._root = root
+ self._filename = filename
+ self._data = None
+ self._lock = None
+
+ def lock(self):
+ """Grab an exclusive lock on the preserved libs registry."""
+ if self._lock is not None:
+ raise AssertionError("already locked")
+ self._lock = lockfile(self._filename)
+
+ def unlock(self):
+ """Release our exclusive lock on the preserved libs registry."""
+ if self._lock is None:
+ raise AssertionError("not locked")
+ unlockfile(self._lock)
+ self._lock = None
+
+ def load(self):
+ """ Reload the registry data from file """
+ self._data = None
+ try:
+ self._data = pickle.load(
+ open(_unicode_encode(self._filename,
+ encoding=_encodings['fs'], errors='strict'), 'rb'))
+ except (ValueError, pickle.UnpicklingError) as e:
+ writemsg_level(_("!!! Error loading '%s': %s\n") % \
+ (self._filename, e), level=logging.ERROR, noiselevel=-1)
+ except (EOFError, IOError) as e:
+ if isinstance(e, EOFError) or e.errno == errno.ENOENT:
+ pass
+ elif e.errno == PermissionDenied.errno:
+ raise PermissionDenied(self._filename)
+ else:
+ raise
+ if self._data is None:
+ self._data = {}
+ self._data_orig = self._data.copy()
+ self.pruneNonExisting()
+
+ def store(self):
+ """
+ Store the registry data to the file. The existing inode will be
+ replaced atomically, so if that inode is currently being used
+ for a lock then that lock will be rendered useless. Therefore,
+ it is important not to call this method until the current lock
+ is ready to be immediately released.
+ """
+ if os.environ.get("SANDBOX_ON") == "1" or \
+ self._data == self._data_orig:
+ return
+ try:
+ f = atomic_ofstream(self._filename, 'wb')
+ pickle.dump(self._data, f, protocol=2)
+ f.close()
+ except EnvironmentError as e:
+ if e.errno != PermissionDenied.errno:
+ writemsg_level("!!! %s %s\n" % (e, self._filename),
+ level=logging.ERROR, noiselevel=-1)
+ else:
+ self._data_orig = self._data.copy()
+
+ def _normalize_counter(self, counter):
+ """
+ For simplicity, normalize as a unicode string
+ and strip whitespace. This avoids the need for
+ int conversion and a possible ValueError resulting
+ from vardb corruption.
+ """
+ if not isinstance(counter, basestring):
+ counter = str(counter)
+ return _unicode_decode(counter).strip()
+
+ def register(self, cpv, slot, counter, paths):
+ """ Register new objects in the registry. If there is a record with the
+ same packagename (internally derived from cpv) and slot it is
+ overwritten with the new data.
+ @param cpv: package instance that owns the objects
+ @type cpv: CPV (as String)
+ @param slot: the value of SLOT of the given package instance
+ @type slot: String
+ @param counter: vdb counter value for the package instance
+ @type counter: String
+ @param paths: absolute paths of objects that got preserved during an update
+ @type paths: List
+ """
+ cp = cpv_getkey(cpv)
+ cps = cp+":"+slot
+ counter = self._normalize_counter(counter)
+ if len(paths) == 0 and cps in self._data \
+ and self._data[cps][0] == cpv and \
+ self._normalize_counter(self._data[cps][1]) == counter:
+ del self._data[cps]
+ elif len(paths) > 0:
+ self._data[cps] = (cpv, counter, paths)
+
+ def unregister(self, cpv, slot, counter):
+ """ Remove a previous registration of preserved objects for the given package.
+ @param cpv: package instance whose records should be removed
+ @type cpv: CPV (as String)
+ @param slot: the value of SLOT of the given package instance
+ @type slot: String
+ """
+ self.register(cpv, slot, counter, [])
+
+ def pruneNonExisting(self):
+ """ Remove all records for objects that no longer exist on the filesystem. """
+
+ os = _os_merge
+
+ for cps in list(self._data):
+ cpv, counter, paths = self._data[cps]
+ paths = [f for f in paths \
+ if os.path.exists(os.path.join(self._root, f.lstrip(os.sep)))]
+ if len(paths) > 0:
+ self._data[cps] = (cpv, counter, paths)
+ else:
+ del self._data[cps]
+
+ def hasEntries(self):
+ """ Check if this registry contains any records. """
+ if self._data is None:
+ self.load()
+ return len(self._data) > 0
+
+ def getPreservedLibs(self):
+ """ Return a mapping of packages->preserved objects.
+ @returns mapping of package instances to preserved objects
+ @rtype Dict cpv->list-of-paths
+ """
+ if self._data is None:
+ self.load()
+ rValue = {}
+ for cps in self._data:
+ rValue[self._data[cps][0]] = self._data[cps][2]
+ return rValue
diff --git a/portage_with_autodep/pym/portage/util/_dyn_libs/__init__.py b/portage_with_autodep/pym/portage/util/_dyn_libs/__init__.py
new file mode 100644
index 0000000..21a391a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/util/_dyn_libs/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/util/_pty.py b/portage_with_autodep/pym/portage/util/_pty.py
new file mode 100644
index 0000000..f45ff0a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/util/_pty.py
@@ -0,0 +1,212 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import array
+import fcntl
+import platform
+import pty
+import select
+import sys
+import termios
+
+from portage import os, _unicode_decode, _unicode_encode
+from portage.output import get_term_size, set_term_size
+from portage.process import spawn_bash
+from portage.util import writemsg
+
+def _can_test_pty_eof():
+ """
+ The _test_pty_eof() function seems to hang on most
+ kernels other than Linux.
+ This was reported for the following kernels which used to work fine
+ without this EOF test: Darwin, AIX, FreeBSD. They seem to hang on
+ the slave_file.close() call. Note that Python's implementation of
+ openpty on Solaris already caused random hangs without this EOF test
+ and hence is globally disabled.
+ @rtype: bool
+ @returns: True if _test_pty_eof() won't hang, False otherwise.
+ """
+ return platform.system() in ("Linux",)
+
+def _test_pty_eof(fdopen_buffered=False):
+ """
+ Returns True if this issues is fixed for the currently
+ running version of python: http://bugs.python.org/issue5380
+ Raises an EnvironmentError from openpty() if it fails.
+
+ NOTE: This issue is only problematic when array.fromfile()
+ is used, rather than os.read(). However, array.fromfile()
+ is preferred since it is approximately 10% faster.
+
+ New development: It appears that array.fromfile() is usable
+ with python3 as long as fdopen is called with a bufsize
+ argument of 0.
+ """
+
+ use_fork = False
+
+ test_string = 2 * "blah blah blah\n"
+ test_string = _unicode_decode(test_string,
+ encoding='utf_8', errors='strict')
+
+ # may raise EnvironmentError
+ master_fd, slave_fd = pty.openpty()
+
+ # Non-blocking mode is required for Darwin kernel.
+ fcntl.fcntl(master_fd, fcntl.F_SETFL,
+ fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
+
+ # Disable post-processing of output since otherwise weird
+ # things like \n -> \r\n transformations may occur.
+ mode = termios.tcgetattr(slave_fd)
+ mode[1] &= ~termios.OPOST
+ termios.tcsetattr(slave_fd, termios.TCSANOW, mode)
+
+ # Simulate a subprocess writing some data to the
+ # slave end of the pipe, and then exiting.
+ pid = None
+ if use_fork:
+ pids = spawn_bash(_unicode_encode("echo -n '%s'" % test_string,
+ encoding='utf_8', errors='strict'), env=os.environ,
+ fd_pipes={0:sys.stdin.fileno(), 1:slave_fd, 2:slave_fd},
+ returnpid=True)
+ if isinstance(pids, int):
+ os.close(master_fd)
+ os.close(slave_fd)
+ raise EnvironmentError('spawn failed')
+ pid = pids[0]
+ else:
+ os.write(slave_fd, _unicode_encode(test_string,
+ encoding='utf_8', errors='strict'))
+ os.close(slave_fd)
+
+ # If using a fork, we must wait for the child here,
+ # in order to avoid a race condition that would
+ # lead to inconsistent results.
+ if pid is not None:
+ os.waitpid(pid, 0)
+
+ if fdopen_buffered:
+ master_file = os.fdopen(master_fd, 'rb')
+ else:
+ master_file = os.fdopen(master_fd, 'rb', 0)
+ eof = False
+ data = []
+ iwtd = [master_file]
+ owtd = []
+ ewtd = []
+
+ while not eof:
+
+ events = select.select(iwtd, owtd, ewtd)
+ if not events[0]:
+ eof = True
+ break
+
+ buf = array.array('B')
+ try:
+ buf.fromfile(master_file, 1024)
+ except (EOFError, IOError):
+ eof = True
+
+ if not buf:
+ eof = True
+ else:
+ data.append(_unicode_decode(buf.tostring(),
+ encoding='utf_8', errors='strict'))
+
+ master_file.close()
+
+ return test_string == ''.join(data)
+
+# If _test_pty_eof() can't be used for runtime detection of
+# http://bugs.python.org/issue5380, openpty can't safely be used
+# unless we can guarantee that the current version of python has
+# been fixed (affects all current versions of python3). When
+# this issue is fixed in python3, we can add another sys.hexversion
+# conditional to enable openpty support in the fixed versions.
+if sys.hexversion >= 0x3000000 and not _can_test_pty_eof():
+ _disable_openpty = True
+else:
+ # Disable the use of openpty on Solaris as it seems Python's openpty
+ # implementation doesn't play nice on Solaris with Portage's
+ # behaviour causing hangs/deadlocks.
+ # Additional note for the future: on Interix, pipes do NOT work, so
+ # _disable_openpty on Interix must *never* be True
+ _disable_openpty = platform.system() in ("SunOS",)
+_tested_pty = False
+
+if not _can_test_pty_eof():
+ # Skip _test_pty_eof() on systems where it hangs.
+ _tested_pty = True
+
+_fbsd_test_pty = platform.system() == 'FreeBSD'
+
+def _create_pty_or_pipe(copy_term_size=None):
+ """
+ Try to create a pty and if then fails then create a normal
+ pipe instead.
+
+ @param copy_term_size: If a tty file descriptor is given
+ then the term size will be copied to the pty.
+ @type copy_term_size: int
+ @rtype: tuple
+ @returns: A tuple of (is_pty, master_fd, slave_fd) where
+ is_pty is True if a pty was successfully allocated, and
+ False if a normal pipe was allocated.
+ """
+
+ got_pty = False
+
+ global _disable_openpty, _fbsd_test_pty, _tested_pty
+ if not (_tested_pty or _disable_openpty):
+ try:
+ if not _test_pty_eof():
+ _disable_openpty = True
+ except EnvironmentError as e:
+ _disable_openpty = True
+ writemsg("openpty failed: '%s'\n" % str(e),
+ noiselevel=-1)
+ del e
+ _tested_pty = True
+
+ if _fbsd_test_pty and not _disable_openpty:
+ # Test for python openpty breakage after freebsd7 to freebsd8
+ # upgrade, which results in a 'Function not implemented' error
+ # and the process being killed.
+ pid = os.fork()
+ if pid == 0:
+ pty.openpty()
+ os._exit(os.EX_OK)
+ pid, status = os.waitpid(pid, 0)
+ if (status & 0xff) == 140:
+ _disable_openpty = True
+ _fbsd_test_pty = False
+
+ if _disable_openpty:
+ master_fd, slave_fd = os.pipe()
+ else:
+ try:
+ master_fd, slave_fd = pty.openpty()
+ got_pty = True
+ except EnvironmentError as e:
+ _disable_openpty = True
+ writemsg("openpty failed: '%s'\n" % str(e),
+ noiselevel=-1)
+ del e
+ master_fd, slave_fd = os.pipe()
+
+ if got_pty:
+ # Disable post-processing of output since otherwise weird
+ # things like \n -> \r\n transformations may occur.
+ mode = termios.tcgetattr(slave_fd)
+ mode[1] &= ~termios.OPOST
+ termios.tcsetattr(slave_fd, termios.TCSANOW, mode)
+
+ if got_pty and \
+ copy_term_size is not None and \
+ os.isatty(copy_term_size):
+ rows, columns = get_term_size()
+ set_term_size(rows, columns, slave_fd)
+
+ return (got_pty, master_fd, slave_fd)
diff --git a/portage_with_autodep/pym/portage/util/digraph.py b/portage_with_autodep/pym/portage/util/digraph.py
new file mode 100644
index 0000000..1bbe10f
--- /dev/null
+++ b/portage_with_autodep/pym/portage/util/digraph.py
@@ -0,0 +1,342 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['digraph']
+
+from collections import deque
+import sys
+
+from portage import _unicode_decode
+from portage.util import writemsg
+
+class digraph(object):
+ """
+ A directed graph object.
+ """
+
+ def __init__(self):
+ """Create an empty digraph"""
+
+ # { node : ( { child : priority } , { parent : priority } ) }
+ self.nodes = {}
+ self.order = []
+
+ def add(self, node, parent, priority=0):
+ """Adds the specified node with the specified parent.
+
+ If the dep is a soft-dep and the node already has a hard
+ relationship to the parent, the relationship is left as hard."""
+
+ if node not in self.nodes:
+ self.nodes[node] = ({}, {}, node)
+ self.order.append(node)
+
+ if not parent:
+ return
+
+ if parent not in self.nodes:
+ self.nodes[parent] = ({}, {}, parent)
+ self.order.append(parent)
+
+ priorities = self.nodes[node][1].get(parent)
+ if priorities is None:
+ priorities = []
+ self.nodes[node][1][parent] = priorities
+ self.nodes[parent][0][node] = priorities
+ priorities.append(priority)
+ priorities.sort()
+
+ def remove(self, node):
+ """Removes the specified node from the digraph, also removing
+ and ties to other nodes in the digraph. Raises KeyError if the
+ node doesn't exist."""
+
+ if node not in self.nodes:
+ raise KeyError(node)
+
+ for parent in self.nodes[node][1]:
+ del self.nodes[parent][0][node]
+ for child in self.nodes[node][0]:
+ del self.nodes[child][1][node]
+
+ del self.nodes[node]
+ self.order.remove(node)
+
+ def difference_update(self, t):
+ """
+ Remove all given nodes from node_set. This is more efficient
+ than multiple calls to the remove() method.
+ """
+ if isinstance(t, (list, tuple)) or \
+ not hasattr(t, "__contains__"):
+ t = frozenset(t)
+ order = []
+ for node in self.order:
+ if node not in t:
+ order.append(node)
+ continue
+ for parent in self.nodes[node][1]:
+ del self.nodes[parent][0][node]
+ for child in self.nodes[node][0]:
+ del self.nodes[child][1][node]
+ del self.nodes[node]
+ self.order = order
+
+ def remove_edge(self, child, parent):
+ """
+ Remove edge in the direction from child to parent. Note that it is
+ possible for a remaining edge to exist in the opposite direction.
+ Any endpoint vertices that become isolated will remain in the graph.
+ """
+
+ # Nothing should be modified when a KeyError is raised.
+ for k in parent, child:
+ if k not in self.nodes:
+ raise KeyError(k)
+
+ # Make sure the edge exists.
+ if child not in self.nodes[parent][0]:
+ raise KeyError(child)
+ if parent not in self.nodes[child][1]:
+ raise KeyError(parent)
+
+ # Remove the edge.
+ del self.nodes[child][1][parent]
+ del self.nodes[parent][0][child]
+
+ def __iter__(self):
+ return iter(self.order)
+
+ def contains(self, node):
+ """Checks if the digraph contains mynode"""
+ return node in self.nodes
+
+ def get(self, key, default=None):
+ node_data = self.nodes.get(key, self)
+ if node_data is self:
+ return default
+ return node_data[2]
+
+ def all_nodes(self):
+ """Return a list of all nodes in the graph"""
+ return self.order[:]
+
+ def child_nodes(self, node, ignore_priority=None):
+ """Return all children of the specified node"""
+ if ignore_priority is None:
+ return list(self.nodes[node][0])
+ children = []
+ if hasattr(ignore_priority, '__call__'):
+ for child, priorities in self.nodes[node][0].items():
+ for priority in priorities:
+ if not ignore_priority(priority):
+ children.append(child)
+ break
+ else:
+ for child, priorities in self.nodes[node][0].items():
+ if ignore_priority < priorities[-1]:
+ children.append(child)
+ return children
+
+ def parent_nodes(self, node, ignore_priority=None):
+ """Return all parents of the specified node"""
+ if ignore_priority is None:
+ return list(self.nodes[node][1])
+ parents = []
+ if hasattr(ignore_priority, '__call__'):
+ for parent, priorities in self.nodes[node][1].items():
+ for priority in priorities:
+ if not ignore_priority(priority):
+ parents.append(parent)
+ break
+ else:
+ for parent, priorities in self.nodes[node][1].items():
+ if ignore_priority < priorities[-1]:
+ parents.append(parent)
+ return parents
+
+ def leaf_nodes(self, ignore_priority=None):
+ """Return all nodes that have no children
+
+ If ignore_soft_deps is True, soft deps are not counted as
+ children in calculations."""
+
+ leaf_nodes = []
+ if ignore_priority is None:
+ for node in self.order:
+ if not self.nodes[node][0]:
+ leaf_nodes.append(node)
+ elif hasattr(ignore_priority, '__call__'):
+ for node in self.order:
+ is_leaf_node = True
+ for child, priorities in self.nodes[node][0].items():
+ for priority in priorities:
+ if not ignore_priority(priority):
+ is_leaf_node = False
+ break
+ if not is_leaf_node:
+ break
+ if is_leaf_node:
+ leaf_nodes.append(node)
+ else:
+ for node in self.order:
+ is_leaf_node = True
+ for child, priorities in self.nodes[node][0].items():
+ if ignore_priority < priorities[-1]:
+ is_leaf_node = False
+ break
+ if is_leaf_node:
+ leaf_nodes.append(node)
+ return leaf_nodes
+
+ def root_nodes(self, ignore_priority=None):
+ """Return all nodes that have no parents.
+
+ If ignore_soft_deps is True, soft deps are not counted as
+ parents in calculations."""
+
+ root_nodes = []
+ if ignore_priority is None:
+ for node in self.order:
+ if not self.nodes[node][1]:
+ root_nodes.append(node)
+ elif hasattr(ignore_priority, '__call__'):
+ for node in self.order:
+ is_root_node = True
+ for parent, priorities in self.nodes[node][1].items():
+ for priority in priorities:
+ if not ignore_priority(priority):
+ is_root_node = False
+ break
+ if not is_root_node:
+ break
+ if is_root_node:
+ root_nodes.append(node)
+ else:
+ for node in self.order:
+ is_root_node = True
+ for parent, priorities in self.nodes[node][1].items():
+ if ignore_priority < priorities[-1]:
+ is_root_node = False
+ break
+ if is_root_node:
+ root_nodes.append(node)
+ return root_nodes
+
+ def __bool__(self):
+ return bool(self.nodes)
+
+ def is_empty(self):
+ """Checks if the digraph is empty"""
+ return len(self.nodes) == 0
+
+ def clone(self):
+ clone = digraph()
+ clone.nodes = {}
+ memo = {}
+ for children, parents, node in self.nodes.values():
+ children_clone = {}
+ for child, priorities in children.items():
+ priorities_clone = memo.get(id(priorities))
+ if priorities_clone is None:
+ priorities_clone = priorities[:]
+ memo[id(priorities)] = priorities_clone
+ children_clone[child] = priorities_clone
+ parents_clone = {}
+ for parent, priorities in parents.items():
+ priorities_clone = memo.get(id(priorities))
+ if priorities_clone is None:
+ priorities_clone = priorities[:]
+ memo[id(priorities)] = priorities_clone
+ parents_clone[parent] = priorities_clone
+ clone.nodes[node] = (children_clone, parents_clone, node)
+ clone.order = self.order[:]
+ return clone
+
+ def delnode(self, node):
+ try:
+ self.remove(node)
+ except KeyError:
+ pass
+
+ def firstzero(self):
+ leaf_nodes = self.leaf_nodes()
+ if leaf_nodes:
+ return leaf_nodes[0]
+ return None
+
+ def hasallzeros(self, ignore_priority=None):
+ return len(self.leaf_nodes(ignore_priority=ignore_priority)) == \
+ len(self.order)
+
+ def debug_print(self):
+ def output(s):
+ writemsg(s, noiselevel=-1)
+ # Use _unicode_decode() to force unicode format
+ # strings for python-2.x safety, ensuring that
+ # node.__unicode__() is used when necessary.
+ for node in self.nodes:
+ output(_unicode_decode("%s ") % (node,))
+ if self.nodes[node][0]:
+ output("depends on\n")
+ else:
+ output("(no children)\n")
+ for child, priorities in self.nodes[node][0].items():
+ output(_unicode_decode(" %s (%s)\n") % \
+ (child, priorities[-1],))
+
+ def bfs(self, start, ignore_priority=None):
+ if start not in self:
+ raise KeyError(start)
+
+ queue, enqueued = deque([(None, start)]), set([start])
+ while queue:
+ parent, n = queue.popleft()
+ yield parent, n
+ new = set(self.child_nodes(n, ignore_priority)) - enqueued
+ enqueued |= new
+ queue.extend([(n, child) for child in new])
+
+ def shortest_path(self, start, end, ignore_priority=None):
+ if start not in self:
+ raise KeyError(start)
+ elif end not in self:
+ raise KeyError(end)
+
+ paths = {None: []}
+ for parent, child in self.bfs(start, ignore_priority):
+ paths[child] = paths[parent] + [child]
+ if child == end:
+ return paths[child]
+ return None
+
+ def get_cycles(self, ignore_priority=None, max_length=None):
+ """
+ Returns all cycles that have at most length 'max_length'.
+ If 'max_length' is 'None', all cycles are returned.
+ """
+ all_cycles = []
+ for node in self.nodes:
+ shortest_path = None
+ for child in self.child_nodes(node, ignore_priority):
+ path = self.shortest_path(child, node, ignore_priority)
+ if path is None:
+ continue
+ if not shortest_path or len(shortest_path) > len(path):
+ shortest_path = path
+ if shortest_path:
+ if not max_length or len(shortest_path) <= max_length:
+ all_cycles.append(shortest_path)
+ return all_cycles
+
+ # Backward compatibility
+ addnode = add
+ allnodes = all_nodes
+ allzeros = leaf_nodes
+ hasnode = contains
+ __contains__ = contains
+ empty = is_empty
+ copy = clone
+
+ if sys.hexversion < 0x3000000:
+ __nonzero__ = __bool__
diff --git a/portage_with_autodep/pym/portage/util/env_update.py b/portage_with_autodep/pym/portage/util/env_update.py
new file mode 100644
index 0000000..eb8a0d9
--- /dev/null
+++ b/portage_with_autodep/pym/portage/util/env_update.py
@@ -0,0 +1,293 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['env_update']
+
+import errno
+import io
+import stat
+import sys
+import time
+
+import portage
+from portage import os, _encodings, _unicode_encode
+from portage.checksum import prelink_capable
+from portage.data import ostype
+from portage.exception import ParseError
+from portage.localization import _
+from portage.process import find_binary
+from portage.util import atomic_ofstream, ensure_dirs, getconfig, \
+ normalize_path, writemsg
+from portage.util.listdir import listdir
+
+if sys.hexversion >= 0x3000000:
+ long = int
+
+def env_update(makelinks=1, target_root=None, prev_mtimes=None, contents=None,
+ env=None, writemsg_level=None):
+ """
+ Parse /etc/env.d and use it to generate /etc/profile.env, csh.env,
+ ld.so.conf, and prelink.conf. Finally, run ldconfig. When ldconfig is
+ called, its -X option will be used in order to avoid potential
+ interference with installed soname symlinks that are required for
+ correct operation of FEATURES=preserve-libs for downgrade operations.
+ It's not necessary for ldconfig to create soname symlinks, since
+ portage will use NEEDED.ELF.2 data to automatically create them
+ after src_install if they happen to be missing.
+ @param makelinks: True if ldconfig should be called, False otherwise
+ @param target_root: root that is passed to the ldconfig -r option,
+ defaults to portage.settings["ROOT"].
+ @type target_root: String (Path)
+ """
+ if writemsg_level is None:
+ writemsg_level = portage.util.writemsg_level
+ if target_root is None:
+ target_root = portage.settings["ROOT"]
+ if prev_mtimes is None:
+ prev_mtimes = portage.mtimedb["ldpath"]
+ if env is None:
+ env = os.environ
+ envd_dir = os.path.join(target_root, "etc", "env.d")
+ ensure_dirs(envd_dir, mode=0o755)
+ fns = listdir(envd_dir, EmptyOnError=1)
+ fns.sort()
+ templist = []
+ for x in fns:
+ if len(x) < 3:
+ continue
+ if not x[0].isdigit() or not x[1].isdigit():
+ continue
+ if x.startswith(".") or x.endswith("~") or x.endswith(".bak"):
+ continue
+ templist.append(x)
+ fns = templist
+ del templist
+
+ space_separated = set(["CONFIG_PROTECT", "CONFIG_PROTECT_MASK"])
+ colon_separated = set(["ADA_INCLUDE_PATH", "ADA_OBJECTS_PATH",
+ "CLASSPATH", "INFODIR", "INFOPATH", "KDEDIRS", "LDPATH", "MANPATH",
+ "PATH", "PKG_CONFIG_PATH", "PRELINK_PATH", "PRELINK_PATH_MASK",
+ "PYTHONPATH", "ROOTPATH"])
+
+ config_list = []
+
+ for x in fns:
+ file_path = os.path.join(envd_dir, x)
+ try:
+ myconfig = getconfig(file_path, expand=False)
+ except ParseError as e:
+ writemsg("!!! '%s'\n" % str(e), noiselevel=-1)
+ del e
+ continue
+ if myconfig is None:
+ # broken symlink or file removed by a concurrent process
+ writemsg("!!! File Not Found: '%s'\n" % file_path, noiselevel=-1)
+ continue
+
+ config_list.append(myconfig)
+ if "SPACE_SEPARATED" in myconfig:
+ space_separated.update(myconfig["SPACE_SEPARATED"].split())
+ del myconfig["SPACE_SEPARATED"]
+ if "COLON_SEPARATED" in myconfig:
+ colon_separated.update(myconfig["COLON_SEPARATED"].split())
+ del myconfig["COLON_SEPARATED"]
+
+ env = {}
+ specials = {}
+ for var in space_separated:
+ mylist = []
+ for myconfig in config_list:
+ if var in myconfig:
+ for item in myconfig[var].split():
+ if item and not item in mylist:
+ mylist.append(item)
+ del myconfig[var] # prepare for env.update(myconfig)
+ if mylist:
+ env[var] = " ".join(mylist)
+ specials[var] = mylist
+
+ for var in colon_separated:
+ mylist = []
+ for myconfig in config_list:
+ if var in myconfig:
+ for item in myconfig[var].split(":"):
+ if item and not item in mylist:
+ mylist.append(item)
+ del myconfig[var] # prepare for env.update(myconfig)
+ if mylist:
+ env[var] = ":".join(mylist)
+ specials[var] = mylist
+
+ for myconfig in config_list:
+ """Cumulative variables have already been deleted from myconfig so that
+ they won't be overwritten by this dict.update call."""
+ env.update(myconfig)
+
+ ldsoconf_path = os.path.join(target_root, "etc", "ld.so.conf")
+ try:
+ myld = io.open(_unicode_encode(ldsoconf_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'], errors='replace')
+ myldlines=myld.readlines()
+ myld.close()
+ oldld=[]
+ for x in myldlines:
+ #each line has at least one char (a newline)
+ if x[:1] == "#":
+ continue
+ oldld.append(x[:-1])
+ except (IOError, OSError) as e:
+ if e.errno != errno.ENOENT:
+ raise
+ oldld = None
+
+ ld_cache_update=False
+
+ newld = specials["LDPATH"]
+ if (oldld != newld):
+ #ld.so.conf needs updating and ldconfig needs to be run
+ myfd = atomic_ofstream(ldsoconf_path)
+ myfd.write("# ld.so.conf autogenerated by env-update; make all changes to\n")
+ myfd.write("# contents of /etc/env.d directory\n")
+ for x in specials["LDPATH"]:
+ myfd.write(x + "\n")
+ myfd.close()
+ ld_cache_update=True
+
+ # Update prelink.conf if we are prelink-enabled
+ if prelink_capable:
+ newprelink = atomic_ofstream(
+ os.path.join(target_root, "etc", "prelink.conf"))
+ newprelink.write("# prelink.conf autogenerated by env-update; make all changes to\n")
+ newprelink.write("# contents of /etc/env.d directory\n")
+
+ for x in ["/bin","/sbin","/usr/bin","/usr/sbin","/lib","/usr/lib"]:
+ newprelink.write("-l %s\n" % (x,));
+ prelink_paths = []
+ prelink_paths += specials.get("LDPATH", [])
+ prelink_paths += specials.get("PATH", [])
+ prelink_paths += specials.get("PRELINK_PATH", [])
+ prelink_path_mask = specials.get("PRELINK_PATH_MASK", [])
+ for x in prelink_paths:
+ if not x:
+ continue
+ if x[-1:] != '/':
+ x += "/"
+ plmasked = 0
+ for y in prelink_path_mask:
+ if not y:
+ continue
+ if y[-1] != '/':
+ y += "/"
+ if y == x[0:len(y)]:
+ plmasked = 1
+ break
+ if not plmasked:
+ newprelink.write("-h %s\n" % (x,))
+ for x in prelink_path_mask:
+ newprelink.write("-b %s\n" % (x,))
+ newprelink.close()
+
+ current_time = long(time.time())
+ mtime_changed = False
+ lib_dirs = set()
+ for lib_dir in set(specials["LDPATH"] + \
+ ['usr/lib','usr/lib64','usr/lib32','lib','lib64','lib32']):
+ x = os.path.join(target_root, lib_dir.lstrip(os.sep))
+ try:
+ newldpathtime = os.stat(x)[stat.ST_MTIME]
+ lib_dirs.add(normalize_path(x))
+ except OSError as oe:
+ if oe.errno == errno.ENOENT:
+ try:
+ del prev_mtimes[x]
+ except KeyError:
+ pass
+ # ignore this path because it doesn't exist
+ continue
+ raise
+ if newldpathtime == current_time:
+ # Reset mtime to avoid the potential ambiguity of times that
+ # differ by less than 1 second.
+ newldpathtime -= 1
+ os.utime(x, (newldpathtime, newldpathtime))
+ prev_mtimes[x] = newldpathtime
+ mtime_changed = True
+ elif x in prev_mtimes:
+ if prev_mtimes[x] == newldpathtime:
+ pass
+ else:
+ prev_mtimes[x] = newldpathtime
+ mtime_changed = True
+ else:
+ prev_mtimes[x] = newldpathtime
+ mtime_changed = True
+
+ if mtime_changed:
+ ld_cache_update = True
+
+ if makelinks and \
+ not ld_cache_update and \
+ contents is not None:
+ libdir_contents_changed = False
+ for mypath, mydata in contents.items():
+ if mydata[0] not in ("obj", "sym"):
+ continue
+ head, tail = os.path.split(mypath)
+ if head in lib_dirs:
+ libdir_contents_changed = True
+ break
+ if not libdir_contents_changed:
+ makelinks = False
+
+ ldconfig = "/sbin/ldconfig"
+ if "CHOST" in env and "CBUILD" in env and \
+ env["CHOST"] != env["CBUILD"]:
+ ldconfig = find_binary("%s-ldconfig" % env["CHOST"])
+
+ # Only run ldconfig as needed
+ if (ld_cache_update or makelinks) and ldconfig:
+ # ldconfig has very different behaviour between FreeBSD and Linux
+ if ostype == "Linux" or ostype.lower().endswith("gnu"):
+ # We can't update links if we haven't cleaned other versions first, as
+ # an older package installed ON TOP of a newer version will cause ldconfig
+ # to overwrite the symlinks we just made. -X means no links. After 'clean'
+ # we can safely create links.
+ writemsg_level(_(">>> Regenerating %setc/ld.so.cache...\n") % \
+ (target_root,))
+ os.system("cd / ; %s -X -r '%s'" % (ldconfig, target_root))
+ elif ostype in ("FreeBSD","DragonFly"):
+ writemsg_level(_(">>> Regenerating %svar/run/ld-elf.so.hints...\n") % \
+ target_root)
+ os.system(("cd / ; %s -elf -i " + \
+ "-f '%svar/run/ld-elf.so.hints' '%setc/ld.so.conf'") % \
+ (ldconfig, target_root, target_root))
+
+ del specials["LDPATH"]
+
+ penvnotice = "# THIS FILE IS AUTOMATICALLY GENERATED BY env-update.\n"
+ penvnotice += "# DO NOT EDIT THIS FILE. CHANGES TO STARTUP PROFILES\n"
+ cenvnotice = penvnotice[:]
+ penvnotice += "# GO INTO /etc/profile NOT /etc/profile.env\n\n"
+ cenvnotice += "# GO INTO /etc/csh.cshrc NOT /etc/csh.env\n\n"
+
+ #create /etc/profile.env for bash support
+ outfile = atomic_ofstream(os.path.join(target_root, "etc", "profile.env"))
+ outfile.write(penvnotice)
+
+ env_keys = [ x for x in env if x != "LDPATH" ]
+ env_keys.sort()
+ for k in env_keys:
+ v = env[k]
+ if v.startswith('$') and not v.startswith('${'):
+ outfile.write("export %s=$'%s'\n" % (k, v[1:]))
+ else:
+ outfile.write("export %s='%s'\n" % (k, v))
+ outfile.close()
+
+ #create /etc/csh.env for (t)csh support
+ outfile = atomic_ofstream(os.path.join(target_root, "etc", "csh.env"))
+ outfile.write(cenvnotice)
+ for x in env_keys:
+ outfile.write("setenv %s '%s'\n" % (x, env[x]))
+ outfile.close()
diff --git a/portage_with_autodep/pym/portage/util/lafilefixer.py b/portage_with_autodep/pym/portage/util/lafilefixer.py
new file mode 100644
index 0000000..2b093d8
--- /dev/null
+++ b/portage_with_autodep/pym/portage/util/lafilefixer.py
@@ -0,0 +1,185 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import os as _os
+import re
+
+from portage import _unicode_decode
+from portage.exception import InvalidData
+
+#########################################################
+# This an re-implementaion of dev-util/lafilefixer-0.5.
+# rewrite_lafile() takes the contents of an lafile as a string
+# It then parses the dependency_libs and inherited_linker_flags
+# entries.
+# We insist on dependency_libs being present. inherited_linker_flags
+# is optional.
+# There are strict rules about the syntax imposed by libtool's libltdl.
+# See 'parse_dotla_file' and 'trim' functions in libltdl/ltdl.c.
+# Note that duplicated entries of dependency_libs and inherited_linker_flags
+# are ignored by libtool (last one wins), but we treat it as error (like
+# lafilefixer does).
+# What it does:
+# * Replaces all .la files with absolut paths in dependency_libs with
+# corresponding -l* and -L* entries
+# (/usr/lib64/libfoo.la -> -L/usr/lib64 -lfoo)
+# * Moves various flags (see flag_re below) to inherited_linker_flags,
+# if such an entry was present.
+# * Reorders dependency_libs such that all -R* entries precede -L* entries
+# and these precede all other entries.
+# * Remove duplicated entries from dependency_libs
+# * Takes care that no entry to inherited_linker_flags is added that is
+# already there.
+#########################################################
+
+#These regexes are used to parse the interesting entries in the la file
+dep_libs_re = re.compile(b"dependency_libs='(?P<value>[^']*)'$")
+inh_link_flags_re = re.compile(b"inherited_linker_flags='(?P<value>[^']*)'$")
+
+#regexes for replacing stuff in -L entries.
+#replace 'X11R6/lib' and 'local/lib' with 'lib', no idea what's this about.
+X11_local_sub = re.compile(b"X11R6/lib|local/lib")
+#get rid of the '..'
+pkgconfig_sub1 = re.compile(b"usr/lib[^/]*/pkgconfig/\.\./\.\.")
+pkgconfig_sub2 = re.compile(b"(?P<usrlib>usr/lib[^/]*)/pkgconfig/\.\.")
+
+#detect flags that should go into inherited_linker_flags instead of dependency_libs
+flag_re = re.compile(b"-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads")
+
+def _parse_lafile_contents(contents):
+ """
+ Parses 'dependency_libs' and 'inherited_linker_flags' lines.
+ """
+
+ dep_libs = None
+ inh_link_flags = None
+
+ for line in contents.split(b"\n"):
+ m = dep_libs_re.match(line)
+ if m:
+ if dep_libs is not None:
+ raise InvalidData("duplicated dependency_libs entry")
+ dep_libs = m.group("value")
+ continue
+
+ m = inh_link_flags_re.match(line)
+ if m:
+ if inh_link_flags is not None:
+ raise InvalidData("duplicated inherited_linker_flags entry")
+ inh_link_flags = m.group("value")
+ continue
+
+ return dep_libs, inh_link_flags
+
+def rewrite_lafile(contents):
+ """
+ Given the contents of an .la file, parse and fix it.
+ This operates with strings of raw bytes (assumed to contain some ascii
+ characters), in order to avoid any potential character encoding issues.
+ Raises 'InvalidData' if the .la file is invalid.
+ @param contents: the contents of a libtool archive file
+ @type contents: bytes
+ @rtype: tuple
+ @returns: (True, fixed_contents) if something needed to be
+ fixed, (False, None) otherwise.
+ """
+ #Parse the 'dependency_libs' and 'inherited_linker_flags' lines.
+ dep_libs, inh_link_flags = \
+ _parse_lafile_contents(contents)
+
+ if dep_libs is None:
+ raise InvalidData("missing or invalid dependency_libs")
+
+ new_dep_libs = []
+ new_inh_link_flags = []
+ librpath = []
+ libladir = []
+
+ if inh_link_flags is not None:
+ new_inh_link_flags = inh_link_flags.split()
+
+ #Check entries in 'dependency_libs'.
+ for dep_libs_entry in dep_libs.split():
+ if dep_libs_entry.startswith(b"-l"):
+ #-lfoo, keep it
+ if dep_libs_entry not in new_dep_libs:
+ new_dep_libs.append(dep_libs_entry)
+
+ elif dep_libs_entry.endswith(b".la"):
+ #Two cases:
+ #1) /usr/lib64/libfoo.la, turn it into -lfoo and append -L/usr/lib64 to libladir
+ #2) libfoo.la, keep it
+ dir, file = _os.path.split(dep_libs_entry)
+
+ if not dir or not file.startswith(b"lib"):
+ if dep_libs_entry not in new_dep_libs:
+ new_dep_libs.append(dep_libs_entry)
+ else:
+ #/usr/lib64/libfoo.la -> -lfoo
+ lib = b"-l" + file[3:-3]
+ if lib not in new_dep_libs:
+ new_dep_libs.append(lib)
+ #/usr/lib64/libfoo.la -> -L/usr/lib64
+ ladir = b"-L" + dir
+ if ladir not in libladir:
+ libladir.append(ladir)
+
+ elif dep_libs_entry.startswith(b"-L"):
+ #Do some replacement magic and store them in 'libladir'.
+ #This allows us to place all -L entries at the beginning
+ #of 'dependency_libs'.
+ ladir = dep_libs_entry
+
+ ladir = X11_local_sub.sub(b"lib", ladir)
+ ladir = pkgconfig_sub1.sub(b"usr", ladir)
+ ladir = pkgconfig_sub2.sub(b"\g<usrlib>", ladir)
+
+ if ladir not in libladir:
+ libladir.append(ladir)
+
+ elif dep_libs_entry.startswith(b"-R"):
+ if dep_libs_entry not in librpath:
+ librpath.append(dep_libs_entry)
+
+ elif flag_re.match(dep_libs_entry):
+ #All this stuff goes into inh_link_flags, if the la file has such an entry.
+ #If it doesn't, they stay in 'dependency_libs'.
+ if inh_link_flags is not None:
+ if dep_libs_entry not in new_inh_link_flags:
+ new_inh_link_flags.append(dep_libs_entry)
+ else:
+ if dep_libs_entry not in new_dep_libs:
+ new_dep_libs.append(dep_libs_entry)
+
+ else:
+ raise InvalidData("Error: Unexpected entry '%s' in 'dependency_libs'" \
+ % _unicode_decode(dep_libs_entry))
+
+ #What should 'dependency_libs' and 'inherited_linker_flags' look like?
+ expected_dep_libs = b""
+ for x in (librpath, libladir, new_dep_libs):
+ if x:
+ expected_dep_libs += b" " + b" ".join(x)
+
+ expected_inh_link_flags = b""
+ if new_inh_link_flags:
+ expected_inh_link_flags += b" " + b" ".join(new_inh_link_flags)
+
+ #Don't touch the file if we don't need to, otherwise put the expected values into
+ #'contents' and write it into the la file.
+
+ changed = False
+ if dep_libs != expected_dep_libs:
+ contents = contents.replace(b"dependency_libs='" + dep_libs + b"'", \
+ b"dependency_libs='" + expected_dep_libs + b"'")
+ changed = True
+
+ if inh_link_flags is not None and expected_inh_link_flags != inh_link_flags:
+ contents = contents.replace(b"inherited_linker_flags='" + inh_link_flags + b"'", \
+ b"inherited_linker_flags='" + expected_inh_link_flags + b"'")
+ changed = True
+
+ if changed:
+ return True, contents
+ else:
+ return False, None
diff --git a/portage_with_autodep/pym/portage/util/listdir.py b/portage_with_autodep/pym/portage/util/listdir.py
new file mode 100644
index 0000000..5753d2f
--- /dev/null
+++ b/portage_with_autodep/pym/portage/util/listdir.py
@@ -0,0 +1,151 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['cacheddir', 'listdir']
+
+import errno
+import stat
+import time
+
+from portage import os
+from portage.exception import DirectoryNotFound, PermissionDenied, PortageException
+from portage.util import normalize_path, writemsg
+
+_ignorecvs_dirs = ('CVS', 'RCS', 'SCCS', '.svn', '.git')
+dircache = {}
+cacheHit = 0
+cacheMiss = 0
+cacheStale = 0
+
+def cacheddir(my_original_path, ignorecvs, ignorelist, EmptyOnError, followSymlinks=True):
+ global cacheHit,cacheMiss,cacheStale
+ mypath = normalize_path(my_original_path)
+ if mypath in dircache:
+ cacheHit += 1
+ cached_mtime, list, ftype = dircache[mypath]
+ else:
+ cacheMiss += 1
+ cached_mtime, list, ftype = -1, [], []
+ try:
+ pathstat = os.stat(mypath)
+ if stat.S_ISDIR(pathstat[stat.ST_MODE]):
+ mtime = pathstat.st_mtime
+ else:
+ raise DirectoryNotFound(mypath)
+ except EnvironmentError as e:
+ if e.errno == PermissionDenied.errno:
+ raise PermissionDenied(mypath)
+ del e
+ return [], []
+ except PortageException:
+ return [], []
+ # Python retuns mtime in seconds, so if it was changed in the last few seconds, it could be invalid
+ if mtime != cached_mtime or time.time() - mtime < 4:
+ if mypath in dircache:
+ cacheStale += 1
+ try:
+ list = os.listdir(mypath)
+ except EnvironmentError as e:
+ if e.errno != errno.EACCES:
+ raise
+ del e
+ raise PermissionDenied(mypath)
+ ftype = []
+ for x in list:
+ try:
+ if followSymlinks:
+ pathstat = os.stat(mypath+"/"+x)
+ else:
+ pathstat = os.lstat(mypath+"/"+x)
+
+ if stat.S_ISREG(pathstat[stat.ST_MODE]):
+ ftype.append(0)
+ elif stat.S_ISDIR(pathstat[stat.ST_MODE]):
+ ftype.append(1)
+ elif stat.S_ISLNK(pathstat[stat.ST_MODE]):
+ ftype.append(2)
+ else:
+ ftype.append(3)
+ except (IOError, OSError):
+ ftype.append(3)
+ dircache[mypath] = mtime, list, ftype
+
+ ret_list = []
+ ret_ftype = []
+ for x in range(0, len(list)):
+ if list[x] in ignorelist:
+ pass
+ elif ignorecvs:
+ if list[x][:2] != ".#" and \
+ not (ftype[x] == 1 and list[x] in _ignorecvs_dirs):
+ ret_list.append(list[x])
+ ret_ftype.append(ftype[x])
+ else:
+ ret_list.append(list[x])
+ ret_ftype.append(ftype[x])
+
+ writemsg("cacheddirStats: H:%d/M:%d/S:%d\n" % (cacheHit, cacheMiss, cacheStale),10)
+ return ret_list, ret_ftype
+
+def listdir(mypath, recursive=False, filesonly=False, ignorecvs=False, ignorelist=[], followSymlinks=True,
+ EmptyOnError=False, dirsonly=False):
+ """
+ Portage-specific implementation of os.listdir
+
+ @param mypath: Path whose contents you wish to list
+ @type mypath: String
+ @param recursive: Recursively scan directories contained within mypath
+ @type recursive: Boolean
+ @param filesonly; Only return files, not more directories
+ @type filesonly: Boolean
+ @param ignorecvs: Ignore CVS directories ('CVS','SCCS','.svn','.git')
+ @type ignorecvs: Boolean
+ @param ignorelist: List of filenames/directories to exclude
+ @type ignorelist: List
+ @param followSymlinks: Follow Symlink'd files and directories
+ @type followSymlinks: Boolean
+ @param EmptyOnError: Return [] if an error occurs (deprecated, always True)
+ @type EmptyOnError: Boolean
+ @param dirsonly: Only return directories.
+ @type dirsonly: Boolean
+ @rtype: List
+ @returns: A list of files and directories (or just files or just directories) or an empty list.
+ """
+
+ list, ftype = cacheddir(mypath, ignorecvs, ignorelist, EmptyOnError, followSymlinks)
+
+ if list is None:
+ list=[]
+ if ftype is None:
+ ftype=[]
+
+ if not (filesonly or dirsonly or recursive):
+ return list
+
+ if recursive:
+ x=0
+ while x<len(ftype):
+ if ftype[x] == 1:
+ l,f = cacheddir(mypath+"/"+list[x], ignorecvs, ignorelist, EmptyOnError,
+ followSymlinks)
+
+ l=l[:]
+ for y in range(0,len(l)):
+ l[y]=list[x]+"/"+l[y]
+ list=list+l
+ ftype=ftype+f
+ x+=1
+ if filesonly:
+ rlist=[]
+ for x in range(0,len(ftype)):
+ if ftype[x]==0:
+ rlist=rlist+[list[x]]
+ elif dirsonly:
+ rlist = []
+ for x in range(0, len(ftype)):
+ if ftype[x] == 1:
+ rlist = rlist + [list[x]]
+ else:
+ rlist=list
+
+ return rlist
diff --git a/portage_with_autodep/pym/portage/util/movefile.py b/portage_with_autodep/pym/portage/util/movefile.py
new file mode 100644
index 0000000..30cb6f1
--- /dev/null
+++ b/portage_with_autodep/pym/portage/util/movefile.py
@@ -0,0 +1,242 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['movefile']
+
+import errno
+import os as _os
+import shutil as _shutil
+import stat
+
+import portage
+from portage import bsd_chflags, _encodings, _os_overrides, _selinux, \
+ _unicode_decode, _unicode_func_wrapper, _unicode_module_wrapper
+from portage.const import MOVE_BINARY
+from portage.localization import _
+from portage.process import spawn
+from portage.util import writemsg
+
+def movefile(src, dest, newmtime=None, sstat=None, mysettings=None,
+ hardlink_candidates=None, encoding=_encodings['fs']):
+ """moves a file from src to dest, preserving all permissions and attributes; mtime will
+ be preserved even when moving across filesystems. Returns true on success and false on
+ failure. Move is atomic."""
+ #print "movefile("+str(src)+","+str(dest)+","+str(newmtime)+","+str(sstat)+")"
+
+ if mysettings is None:
+ mysettings = portage.settings
+
+ selinux_enabled = mysettings.selinux_enabled()
+ if selinux_enabled:
+ selinux = _unicode_module_wrapper(_selinux, encoding=encoding)
+
+ lchown = _unicode_func_wrapper(portage.data.lchown, encoding=encoding)
+ os = _unicode_module_wrapper(_os,
+ encoding=encoding, overrides=_os_overrides)
+ shutil = _unicode_module_wrapper(_shutil, encoding=encoding)
+
+ try:
+ if not sstat:
+ sstat=os.lstat(src)
+
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ print(_("!!! Stating source file failed... movefile()"))
+ print("!!!",e)
+ return None
+
+ destexists=1
+ try:
+ dstat=os.lstat(dest)
+ except (OSError, IOError):
+ dstat=os.lstat(os.path.dirname(dest))
+ destexists=0
+
+ if bsd_chflags:
+ if destexists and dstat.st_flags != 0:
+ bsd_chflags.lchflags(dest, 0)
+ # Use normal stat/chflags for the parent since we want to
+ # follow any symlinks to the real parent directory.
+ pflags = os.stat(os.path.dirname(dest)).st_flags
+ if pflags != 0:
+ bsd_chflags.chflags(os.path.dirname(dest), 0)
+
+ if destexists:
+ if stat.S_ISLNK(dstat[stat.ST_MODE]):
+ try:
+ os.unlink(dest)
+ destexists=0
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ pass
+
+ if stat.S_ISLNK(sstat[stat.ST_MODE]):
+ try:
+ target=os.readlink(src)
+ if mysettings and mysettings["D"]:
+ if target.find(mysettings["D"])==0:
+ target=target[len(mysettings["D"]):]
+ if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
+ os.unlink(dest)
+ try:
+ if selinux_enabled:
+ selinux.symlink(target, dest, src)
+ else:
+ os.symlink(target, dest)
+ except OSError as e:
+ # Some programs will create symlinks automatically, so we have
+ # to tolerate these links being recreated during the merge
+ # process. In any case, if the link is pointing at the right
+ # place, we're in good shape.
+ if e.errno not in (errno.ENOENT, errno.EEXIST) or \
+ target != os.readlink(dest):
+ raise
+ lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
+ # utime() only works on the target of a symlink, so it's not
+ # possible to perserve mtime on symlinks.
+ return os.lstat(dest)[stat.ST_MTIME]
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ print(_("!!! failed to properly create symlink:"))
+ print("!!!",dest,"->",target)
+ print("!!!",e)
+ return None
+
+ hardlinked = False
+ # Since identical files might be merged to multiple filesystems,
+ # so os.link() calls might fail for some paths, so try them all.
+ # For atomic replacement, first create the link as a temp file
+ # and them use os.rename() to replace the destination.
+ if hardlink_candidates:
+ head, tail = os.path.split(dest)
+ hardlink_tmp = os.path.join(head, ".%s._portage_merge_.%s" % \
+ (tail, os.getpid()))
+ try:
+ os.unlink(hardlink_tmp)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ writemsg(_("!!! Failed to remove hardlink temp file: %s\n") % \
+ (hardlink_tmp,), noiselevel=-1)
+ writemsg("!!! %s\n" % (e,), noiselevel=-1)
+ return None
+ del e
+ for hardlink_src in hardlink_candidates:
+ try:
+ os.link(hardlink_src, hardlink_tmp)
+ except OSError:
+ continue
+ else:
+ try:
+ os.rename(hardlink_tmp, dest)
+ except OSError as e:
+ writemsg(_("!!! Failed to rename %s to %s\n") % \
+ (hardlink_tmp, dest), noiselevel=-1)
+ writemsg("!!! %s\n" % (e,), noiselevel=-1)
+ return None
+ hardlinked = True
+ break
+
+ renamefailed=1
+ if hardlinked:
+ renamefailed = False
+ if not hardlinked and (selinux_enabled or sstat.st_dev == dstat.st_dev):
+ try:
+ if selinux_enabled:
+ selinux.rename(src, dest)
+ else:
+ os.rename(src,dest)
+ renamefailed=0
+ except OSError as e:
+ if e.errno != errno.EXDEV:
+ # Some random error.
+ print(_("!!! Failed to move %(src)s to %(dest)s") % {"src": src, "dest": dest})
+ print("!!!",e)
+ return None
+ # Invalid cross-device-link 'bind' mounted or actually Cross-Device
+ if renamefailed:
+ didcopy=0
+ if stat.S_ISREG(sstat[stat.ST_MODE]):
+ try: # For safety copy then move it over.
+ if selinux_enabled:
+ selinux.copyfile(src, dest + "#new")
+ selinux.rename(dest + "#new", dest)
+ else:
+ shutil.copyfile(src,dest+"#new")
+ os.rename(dest+"#new",dest)
+ didcopy=1
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ print(_('!!! copy %(src)s -> %(dest)s failed.') % {"src": src, "dest": dest})
+ print("!!!",e)
+ return None
+ else:
+ #we don't yet handle special, so we need to fall back to /bin/mv
+ a = spawn([MOVE_BINARY, '-f', src, dest], env=os.environ)
+ if a != os.EX_OK:
+ writemsg(_("!!! Failed to move special file:\n"), noiselevel=-1)
+ writemsg(_("!!! '%(src)s' to '%(dest)s'\n") % \
+ {"src": _unicode_decode(src, encoding=encoding),
+ "dest": _unicode_decode(dest, encoding=encoding)}, noiselevel=-1)
+ writemsg("!!! %s\n" % a, noiselevel=-1)
+ return None # failure
+ try:
+ if didcopy:
+ if stat.S_ISLNK(sstat[stat.ST_MODE]):
+ lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
+ else:
+ os.chown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
+ os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
+ os.unlink(src)
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ print(_("!!! Failed to chown/chmod/unlink in movefile()"))
+ print("!!!",dest)
+ print("!!!",e)
+ return None
+
+ # Always use stat_obj[stat.ST_MTIME] for the integral timestamp which
+ # is returned, since the stat_obj.st_mtime float attribute rounds *up*
+ # if the nanosecond part of the timestamp is 999999881 ns or greater.
+ try:
+ if hardlinked:
+ newmtime = os.stat(dest)[stat.ST_MTIME]
+ else:
+ # Note: It is not possible to preserve nanosecond precision
+ # (supported in POSIX.1-2008 via utimensat) with the IEEE 754
+ # double precision float which only has a 53 bit significand.
+ if newmtime is not None:
+ os.utime(dest, (newmtime, newmtime))
+ else:
+ newmtime = sstat[stat.ST_MTIME]
+ if renamefailed:
+ # If rename succeeded then timestamps are automatically
+ # preserved with complete precision because the source
+ # and destination inode are the same. Otherwise, round
+ # down to the nearest whole second since python's float
+ # st_mtime cannot be used to preserve the st_mtim.tv_nsec
+ # field with complete precision. Note that we have to use
+ # stat_obj[stat.ST_MTIME] here because the float
+ # stat_obj.st_mtime rounds *up* sometimes.
+ os.utime(dest, (newmtime, newmtime))
+ except OSError:
+ # The utime can fail here with EPERM even though the move succeeded.
+ # Instead of failing, use stat to return the mtime if possible.
+ try:
+ newmtime = os.stat(dest)[stat.ST_MTIME]
+ except OSError as e:
+ writemsg(_("!!! Failed to stat in movefile()\n"), noiselevel=-1)
+ writemsg("!!! %s\n" % dest, noiselevel=-1)
+ writemsg("!!! %s\n" % str(e), noiselevel=-1)
+ return None
+
+ if bsd_chflags:
+ # Restore the flags we saved before moving
+ if pflags:
+ bsd_chflags.chflags(os.path.dirname(dest), pflags)
+
+ return newmtime
diff --git a/portage_with_autodep/pym/portage/util/mtimedb.py b/portage_with_autodep/pym/portage/util/mtimedb.py
new file mode 100644
index 0000000..67f93e8
--- /dev/null
+++ b/portage_with_autodep/pym/portage/util/mtimedb.py
@@ -0,0 +1,81 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['MtimeDB']
+
+import copy
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+
+import portage
+from portage import _unicode_encode
+from portage.data import portage_gid, uid
+from portage.localization import _
+from portage.util import apply_secpass_permissions, atomic_ofstream, writemsg
+
+class MtimeDB(dict):
+ def __init__(self, filename):
+ dict.__init__(self)
+ self.filename = filename
+ self._load(filename)
+
+ def _load(self, filename):
+ try:
+ f = open(_unicode_encode(filename), 'rb')
+ mypickle = pickle.Unpickler(f)
+ try:
+ mypickle.find_global = None
+ except AttributeError:
+ # TODO: If py3k, override Unpickler.find_class().
+ pass
+ d = mypickle.load()
+ f.close()
+ del f
+ except (IOError, OSError, EOFError, ValueError, pickle.UnpicklingError) as e:
+ if isinstance(e, pickle.UnpicklingError):
+ writemsg(_("!!! Error loading '%s': %s\n") % \
+ (filename, str(e)), noiselevel=-1)
+ del e
+ d = {}
+
+ if "old" in d:
+ d["updates"] = d["old"]
+ del d["old"]
+ if "cur" in d:
+ del d["cur"]
+
+ d.setdefault("starttime", 0)
+ d.setdefault("version", "")
+ for k in ("info", "ldpath", "updates"):
+ d.setdefault(k, {})
+
+ mtimedbkeys = set(("info", "ldpath", "resume", "resume_backup",
+ "starttime", "updates", "version"))
+
+ for k in list(d):
+ if k not in mtimedbkeys:
+ writemsg(_("Deleting invalid mtimedb key: %s\n") % str(k))
+ del d[k]
+ self.update(d)
+ self._clean_data = copy.deepcopy(d)
+
+ def commit(self):
+ if not self.filename:
+ return
+ d = {}
+ d.update(self)
+ # Only commit if the internal state has changed.
+ if d != self._clean_data:
+ d["version"] = str(portage.VERSION)
+ try:
+ f = atomic_ofstream(self.filename, mode='wb')
+ except EnvironmentError:
+ pass
+ else:
+ pickle.dump(d, f, protocol=2)
+ f.close()
+ apply_secpass_permissions(self.filename,
+ uid=uid, gid=portage_gid, mode=0o644)
+ self._clean_data = copy.deepcopy(d)
diff --git a/portage_with_autodep/pym/portage/versions.py b/portage_with_autodep/pym/portage/versions.py
new file mode 100644
index 0000000..f8691d1
--- /dev/null
+++ b/portage_with_autodep/pym/portage/versions.py
@@ -0,0 +1,403 @@
+# versions.py -- core Portage functionality
+# Copyright 1998-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = [
+ 'best', 'catpkgsplit', 'catsplit',
+ 'cpv_getkey', 'cpv_getversion', 'cpv_sort_key', 'pkgcmp', 'pkgsplit',
+ 'ververify', 'vercmp'
+]
+
+import re
+import warnings
+
+import portage
+portage.proxy.lazyimport.lazyimport(globals(),
+ 'portage.util:cmp_sort_key'
+)
+from portage.localization import _
+
+# \w is [a-zA-Z0-9_]
+
+# 2.1.1 A category name may contain any of the characters [A-Za-z0-9+_.-].
+# It must not begin with a hyphen or a dot.
+_cat = r'[\w+][\w+.-]*'
+
+# 2.1.2 A package name may contain any of the characters [A-Za-z0-9+_-].
+# It must not begin with a hyphen,
+# and must not end in a hyphen followed by one or more digits.
+_pkg = r'[\w+][\w+-]*?'
+
+_v = r'(cvs\.)?(\d+)((\.\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\d*)*)'
+_rev = r'\d+'
+_vr = _v + '(-r(' + _rev + '))?'
+
+_cp = '(' + _cat + '/' + _pkg + '(-' + _vr + ')?)'
+_cpv = '(' + _cp + '-' + _vr + ')'
+_pv = '(?P<pn>' + _pkg + '(?P<pn_inval>-' + _vr + ')?)' + '-(?P<ver>' + _v + ')(-r(?P<rev>' + _rev + '))?'
+
+ver_regexp = re.compile("^" + _vr + "$")
+suffix_regexp = re.compile("^(alpha|beta|rc|pre|p)(\\d*)$")
+suffix_value = {"pre": -2, "p": 0, "alpha": -4, "beta": -3, "rc": -1}
+endversion_keys = ["pre", "p", "alpha", "beta", "rc"]
+
+def ververify(myver, silent=1):
+ if ver_regexp.match(myver):
+ return 1
+ else:
+ if not silent:
+ print(_("!!! syntax error in version: %s") % myver)
+ return 0
+
+vercmp_cache = {}
+def vercmp(ver1, ver2, silent=1):
+ """
+ Compare two versions
+ Example usage:
+ >>> from portage.versions import vercmp
+ >>> vercmp('1.0-r1','1.2-r3')
+ negative number
+ >>> vercmp('1.3','1.2-r3')
+ positive number
+ >>> vercmp('1.0_p3','1.0_p3')
+ 0
+
+ @param pkg1: version to compare with (see ver_regexp in portage.versions.py)
+ @type pkg1: string (example: "2.1.2-r3")
+ @param pkg2: version to compare againts (see ver_regexp in portage.versions.py)
+ @type pkg2: string (example: "2.1.2_rc5")
+ @rtype: None or float
+ @return:
+ 1. positive if ver1 is greater than ver2
+ 2. negative if ver1 is less than ver2
+ 3. 0 if ver1 equals ver2
+ 4. None if ver1 or ver2 are invalid (see ver_regexp in portage.versions.py)
+ """
+
+ if ver1 == ver2:
+ return 0
+ mykey=ver1+":"+ver2
+ try:
+ return vercmp_cache[mykey]
+ except KeyError:
+ pass
+ match1 = ver_regexp.match(ver1)
+ match2 = ver_regexp.match(ver2)
+
+ # checking that the versions are valid
+ if not match1 or not match1.groups():
+ if not silent:
+ print(_("!!! syntax error in version: %s") % ver1)
+ return None
+ if not match2 or not match2.groups():
+ if not silent:
+ print(_("!!! syntax error in version: %s") % ver2)
+ return None
+
+ # shortcut for cvs ebuilds (new style)
+ if match1.group(1) and not match2.group(1):
+ vercmp_cache[mykey] = 1
+ return 1
+ elif match2.group(1) and not match1.group(1):
+ vercmp_cache[mykey] = -1
+ return -1
+
+ # building lists of the version parts before the suffix
+ # first part is simple
+ list1 = [int(match1.group(2))]
+ list2 = [int(match2.group(2))]
+
+ # this part would greatly benefit from a fixed-length version pattern
+ if match1.group(3) or match2.group(3):
+ vlist1 = match1.group(3)[1:].split(".")
+ vlist2 = match2.group(3)[1:].split(".")
+
+ for i in range(0, max(len(vlist1), len(vlist2))):
+ # Implcit .0 is given a value of -1, so that 1.0.0 > 1.0, since it
+ # would be ambiguous if two versions that aren't literally equal
+ # are given the same value (in sorting, for example).
+ if len(vlist1) <= i or len(vlist1[i]) == 0:
+ list1.append(-1)
+ list2.append(int(vlist2[i]))
+ elif len(vlist2) <= i or len(vlist2[i]) == 0:
+ list1.append(int(vlist1[i]))
+ list2.append(-1)
+ # Let's make life easy and use integers unless we're forced to use floats
+ elif (vlist1[i][0] != "0" and vlist2[i][0] != "0"):
+ list1.append(int(vlist1[i]))
+ list2.append(int(vlist2[i]))
+ # now we have to use floats so 1.02 compares correctly against 1.1
+ else:
+ # list1.append(float("0."+vlist1[i]))
+ # list2.append(float("0."+vlist2[i]))
+ # Since python floats have limited range, we multiply both
+ # floating point representations by a constant so that they are
+ # transformed into whole numbers. This allows the practically
+ # infinite range of a python int to be exploited. The
+ # multiplication is done by padding both literal strings with
+ # zeros as necessary to ensure equal length.
+ max_len = max(len(vlist1[i]), len(vlist2[i]))
+ list1.append(int(vlist1[i].ljust(max_len, "0")))
+ list2.append(int(vlist2[i].ljust(max_len, "0")))
+
+ # and now the final letter
+ # NOTE: Behavior changed in r2309 (between portage-2.0.x and portage-2.1).
+ # The new behavior is 12.2.5 > 12.2b which, depending on how you look at,
+ # may seem counter-intuitive. However, if you really think about it, it
+ # seems like it's probably safe to assume that this is the behavior that
+ # is intended by anyone who would use versions such as these.
+ if len(match1.group(5)):
+ list1.append(ord(match1.group(5)))
+ if len(match2.group(5)):
+ list2.append(ord(match2.group(5)))
+
+ for i in range(0, max(len(list1), len(list2))):
+ if len(list1) <= i:
+ vercmp_cache[mykey] = -1
+ return -1
+ elif len(list2) <= i:
+ vercmp_cache[mykey] = 1
+ return 1
+ elif list1[i] != list2[i]:
+ a = list1[i]
+ b = list2[i]
+ rval = (a > b) - (a < b)
+ vercmp_cache[mykey] = rval
+ return rval
+
+ # main version is equal, so now compare the _suffix part
+ list1 = match1.group(6).split("_")[1:]
+ list2 = match2.group(6).split("_")[1:]
+
+ for i in range(0, max(len(list1), len(list2))):
+ # Implicit _p0 is given a value of -1, so that 1 < 1_p0
+ if len(list1) <= i:
+ s1 = ("p","-1")
+ else:
+ s1 = suffix_regexp.match(list1[i]).groups()
+ if len(list2) <= i:
+ s2 = ("p","-1")
+ else:
+ s2 = suffix_regexp.match(list2[i]).groups()
+ if s1[0] != s2[0]:
+ a = suffix_value[s1[0]]
+ b = suffix_value[s2[0]]
+ rval = (a > b) - (a < b)
+ vercmp_cache[mykey] = rval
+ return rval
+ if s1[1] != s2[1]:
+ # it's possible that the s(1|2)[1] == ''
+ # in such a case, fudge it.
+ try:
+ r1 = int(s1[1])
+ except ValueError:
+ r1 = 0
+ try:
+ r2 = int(s2[1])
+ except ValueError:
+ r2 = 0
+ rval = (r1 > r2) - (r1 < r2)
+ if rval:
+ vercmp_cache[mykey] = rval
+ return rval
+
+ # the suffix part is equal to, so finally check the revision
+ if match1.group(10):
+ r1 = int(match1.group(10))
+ else:
+ r1 = 0
+ if match2.group(10):
+ r2 = int(match2.group(10))
+ else:
+ r2 = 0
+ rval = (r1 > r2) - (r1 < r2)
+ vercmp_cache[mykey] = rval
+ return rval
+
+def pkgcmp(pkg1, pkg2):
+ """
+ Compare 2 package versions created in pkgsplit format.
+
+ Example usage:
+ >>> from portage.versions import *
+ >>> pkgcmp(pkgsplit('test-1.0-r1'),pkgsplit('test-1.2-r3'))
+ -1
+ >>> pkgcmp(pkgsplit('test-1.3'),pkgsplit('test-1.2-r3'))
+ 1
+
+ @param pkg1: package to compare with
+ @type pkg1: list (example: ['test', '1.0', 'r1'])
+ @param pkg2: package to compare againts
+ @type pkg2: list (example: ['test', '1.0', 'r1'])
+ @rtype: None or integer
+ @return:
+ 1. None if package names are not the same
+ 2. 1 if pkg1 is greater than pkg2
+ 3. -1 if pkg1 is less than pkg2
+ 4. 0 if pkg1 equals pkg2
+ """
+ if pkg1[0] != pkg2[0]:
+ return None
+ return vercmp("-".join(pkg1[1:]), "-".join(pkg2[1:]))
+
+_pv_re = re.compile('^' + _pv + '$', re.VERBOSE)
+
+def _pkgsplit(mypkg):
+ """
+ @param mypkg: pv
+ @return:
+ 1. None if input is invalid.
+ 2. (pn, ver, rev) if input is pv
+ """
+ m = _pv_re.match(mypkg)
+ if m is None:
+ return None
+
+ if m.group('pn_inval') is not None:
+ # package name appears to have a version-like suffix
+ return None
+
+ rev = m.group('rev')
+ if rev is None:
+ rev = '0'
+ rev = 'r' + rev
+
+ return (m.group('pn'), m.group('ver'), rev)
+
+_cat_re = re.compile('^%s$' % _cat)
+_missing_cat = 'null'
+catcache={}
+def catpkgsplit(mydata,silent=1):
+ """
+ Takes a Category/Package-Version-Rev and returns a list of each.
+
+ @param mydata: Data to split
+ @type mydata: string
+ @param silent: suppress error messages
+ @type silent: Boolean (integer)
+ @rype: list
+ @return:
+ 1. If each exists, it returns [cat, pkgname, version, rev]
+ 2. If cat is not specificed in mydata, cat will be "null"
+ 3. if rev does not exist it will be '-r0'
+ """
+
+ try:
+ return catcache[mydata]
+ except KeyError:
+ pass
+ mysplit = mydata.split('/', 1)
+ p_split=None
+ if len(mysplit)==1:
+ cat = _missing_cat
+ p_split = _pkgsplit(mydata)
+ elif len(mysplit)==2:
+ cat = mysplit[0]
+ if _cat_re.match(cat) is not None:
+ p_split = _pkgsplit(mysplit[1])
+ if not p_split:
+ catcache[mydata]=None
+ return None
+ retval = (cat, p_split[0], p_split[1], p_split[2])
+ catcache[mydata]=retval
+ return retval
+
+def pkgsplit(mypkg, silent=1):
+ """
+ @param mypkg: either a pv or cpv
+ @return:
+ 1. None if input is invalid.
+ 2. (pn, ver, rev) if input is pv
+ 3. (cp, ver, rev) if input is a cpv
+ """
+ catpsplit = catpkgsplit(mypkg)
+ if catpsplit is None:
+ return None
+ cat, pn, ver, rev = catpsplit
+ if cat is _missing_cat and '/' not in mypkg:
+ return (pn, ver, rev)
+ else:
+ return (cat + '/' + pn, ver, rev)
+
+def cpv_getkey(mycpv):
+ """Calls catpkgsplit on a cpv and returns only the cp."""
+ mysplit = catpkgsplit(mycpv)
+ if mysplit is not None:
+ return mysplit[0] + '/' + mysplit[1]
+
+ warnings.warn("portage.versions.cpv_getkey() " + \
+ "called with invalid cpv: '%s'" % (mycpv,),
+ DeprecationWarning, stacklevel=2)
+
+ myslash = mycpv.split("/", 1)
+ mysplit = _pkgsplit(myslash[-1])
+ if mysplit is None:
+ return None
+ mylen = len(myslash)
+ if mylen == 2:
+ return myslash[0] + "/" + mysplit[0]
+ else:
+ return mysplit[0]
+
+def cpv_getversion(mycpv):
+ """Returns the v (including revision) from an cpv."""
+ cp = cpv_getkey(mycpv)
+ if cp is None:
+ return None
+ return mycpv[len(cp+"-"):]
+
+def cpv_sort_key():
+ """
+ Create an object for sorting cpvs, to be used as the 'key' parameter
+ in places like list.sort() or sorted(). This calls catpkgsplit() once for
+ each cpv and caches the result. If a given cpv is invalid or two cpvs
+ have different category/package names, then plain string (> and <)
+ comparison is used.
+
+ @rtype: key object for sorting
+ @return: object for use as the 'key' parameter in places like
+ list.sort() or sorted()
+ """
+
+ split_cache = {}
+
+ def cmp_cpv(cpv1, cpv2):
+
+ split1 = split_cache.get(cpv1, False)
+ if split1 is False:
+ split1 = catpkgsplit(cpv1)
+ if split1 is not None:
+ split1 = (split1[:2], '-'.join(split1[2:]))
+ split_cache[cpv1] = split1
+
+ split2 = split_cache.get(cpv2, False)
+ if split2 is False:
+ split2 = catpkgsplit(cpv2)
+ if split2 is not None:
+ split2 = (split2[:2], '-'.join(split2[2:]))
+ split_cache[cpv2] = split2
+
+ if split1 is None or split2 is None or split1[0] != split2[0]:
+ return (cpv1 > cpv2) - (cpv1 < cpv2)
+
+ return vercmp(split1[1], split2[1])
+
+ return cmp_sort_key(cmp_cpv)
+
+def catsplit(mydep):
+ return mydep.split("/", 1)
+
+def best(mymatches):
+ """Accepts None arguments; assumes matches are valid."""
+ if not mymatches:
+ return ""
+ if len(mymatches) == 1:
+ return mymatches[0]
+ bestmatch = mymatches[0]
+ p2 = catpkgsplit(bestmatch)[1:]
+ for x in mymatches[1:]:
+ p1 = catpkgsplit(x)[1:]
+ if pkgcmp(p1, p2) > 0:
+ bestmatch = x
+ p2 = catpkgsplit(bestmatch)[1:]
+ return bestmatch
diff --git a/portage_with_autodep/pym/portage/xml/__init__.py b/portage_with_autodep/pym/portage/xml/__init__.py
new file mode 100644
index 0000000..21a391a
--- /dev/null
+++ b/portage_with_autodep/pym/portage/xml/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/portage_with_autodep/pym/portage/xml/metadata.py b/portage_with_autodep/pym/portage/xml/metadata.py
new file mode 100644
index 0000000..7acc1f3
--- /dev/null
+++ b/portage_with_autodep/pym/portage/xml/metadata.py
@@ -0,0 +1,376 @@
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+"""Provides an easy-to-use python interface to Gentoo's metadata.xml file.
+
+ Example usage:
+ >>> from portage.xml.metadata import MetaDataXML
+ >>> pkg_md = MetaDataXML('/usr/portage/app-misc/gourmet/metadata.xml')
+ >>> pkg_md
+ <MetaDataXML '/usr/portage/app-misc/gourmet/metadata.xml'>
+ >>> pkg_md.herds()
+ ['no-herd']
+ >>> for maint in pkg_md.maintainers():
+ ... print "{0} ({1})".format(maint.email, maint.name)
+ ...
+ nixphoeni@gentoo.org (Joe Sapp)
+ >>> for flag in pkg_md.use():
+ ... print flag.name, "->", flag.description
+ ...
+ rtf -> Enable export to RTF
+ gnome-print -> Enable printing support using gnome-print
+ >>> upstream = pkg_md.upstream()
+ >>> upstream
+ [<_Upstream {'docs': [], 'remoteid': [], 'maintainer':
+ [<_Maintainer 'Thomas_Hinkle@alumni.brown.edu'>], 'bugtracker': [],
+ 'changelog': []}>]
+ >>> upstream[0].maintainer[0].name
+ 'Thomas Mills Hinkle'
+"""
+
+__all__ = ('MetaDataXML',)
+
+try:
+ import xml.etree.cElementTree as etree
+except ImportError:
+ import xml.etree.ElementTree as etree
+
+import re
+import portage
+from portage import os
+from portage.util import unique_everseen
+
+class _Maintainer(object):
+ """An object for representing one maintainer.
+
+ @type email: str or None
+ @ivar email: Maintainer's email address. Used for both Gentoo and upstream.
+ @type name: str or None
+ @ivar name: Maintainer's name. Used for both Gentoo and upstream.
+ @type description: str or None
+ @ivar description: Description of what a maintainer does. Gentoo only.
+ @type restrict: str or None
+ @ivar restrict: e.g. &gt;=portage-2.2 means only maintains versions
+ of Portage greater than 2.2. Should be DEPEND string with < and >
+ converted to &lt; and &gt; respectively.
+ @type status: str or None
+ @ivar status: If set, either 'active' or 'inactive'. Upstream only.
+ """
+
+ def __init__(self, node):
+ self.email = None
+ self.name = None
+ self.description = None
+ self.restrict = node.get('restrict')
+ self.status = node.get('status')
+ maint_attrs = node.getchildren()
+ for attr in maint_attrs:
+ setattr(self, attr.tag, attr.text)
+
+ def __repr__(self):
+ return "<%s %r>" % (self.__class__.__name__, self.email)
+
+
+class _Useflag(object):
+ """An object for representing one USE flag.
+
+ @todo: Is there any way to have a keyword option to leave in
+ <pkg> and <cat> for later processing?
+ @type name: str or None
+ @ivar name: USE flag
+ @type restrict: str or None
+ @ivar restrict: e.g. &gt;=portage-2.2 means flag is only available in
+ versions greater than 2.2
+ @type description: str
+ @ivar description: description of the USE flag
+ """
+
+ def __init__(self, node):
+ self.name = node.get('name')
+ self.restrict = node.get('restrict')
+ _desc = ''
+ if node.text:
+ _desc = node.text
+ for child in node.getchildren():
+ _desc += child.text if child.text else ''
+ _desc += child.tail if child.tail else ''
+ # This takes care of tabs and newlines left from the file
+ self.description = re.sub('\s+', ' ', _desc)
+
+ def __repr__(self):
+ return "<%s %r>" % (self.__class__.__name__, self.name)
+
+
+class _Upstream(object):
+ """An object for representing one package's upstream.
+
+ @type maintainers: list
+ @ivar maintainers: L{_Maintainer} objects for each upstream maintainer
+ @type changelogs: list
+ @ivar changelogs: URLs to upstream's ChangeLog file in str format
+ @type docs: list
+ @ivar docs: Sequence of tuples containing URLs to upstream documentation
+ in the first slot and 'lang' attribute in the second, e.g.,
+ [('http.../docs/en/tut.html', None), ('http.../doc/fr/tut.html', 'fr')]
+ @type bugtrackers: list
+ @ivar bugtrackers: URLs to upstream's bugtracker. May also contain an email
+ address if prepended with 'mailto:'
+ @type remoteids: list
+ @ivar remoteids: Sequence of tuples containing the project's hosting site
+ name in the first slot and the project's ID name or number for that
+ site in the second, e.g., [('sourceforge', 'systemrescuecd')]
+ """
+
+ def __init__(self, node):
+ self.node = node
+ self.maintainers = self.upstream_maintainers()
+ self.changelogs = self.upstream_changelogs()
+ self.docs = self.upstream_documentation()
+ self.bugtrackers = self.upstream_bugtrackers()
+ self.remoteids = self.upstream_remoteids()
+
+ def __repr__(self):
+ return "<%s %r>" % (self.__class__.__name__, self.__dict__)
+
+ def upstream_bugtrackers(self):
+ """Retrieve upstream bugtracker location from xml node."""
+ return [e.text for e in self.node.findall('bugs-to')]
+
+ def upstream_changelogs(self):
+ """Retrieve upstream changelog location from xml node."""
+ return [e.text for e in self.node.findall('changelog')]
+
+ def upstream_documentation(self):
+ """Retrieve upstream documentation location from xml node."""
+ result = []
+ for elem in self.node.findall('doc'):
+ lang = elem.get('lang')
+ result.append((elem.text, lang))
+ return result
+
+ def upstream_maintainers(self):
+ """Retrieve upstream maintainer information from xml node."""
+ return [_Maintainer(m) for m in self.node.findall('maintainer')]
+
+ def upstream_remoteids(self):
+ """Retrieve upstream remote ID from xml node."""
+ return [(e.text, e.get('type')) for e in self.node.findall('remote-id')]
+
+
+class MetaDataXML(object):
+ """Access metadata.xml"""
+
+ def __init__(self, metadata_xml_path, herds):
+ """Parse a valid metadata.xml file.
+
+ @type metadata_xml_path: str
+ @param metadata_xml_path: path to a valid metadata.xml file
+ @type herds: str or ElementTree
+ @param herds: path to a herds.xml, or a pre-parsed ElementTree
+ @raise IOError: if C{metadata_xml_path} can not be read
+ """
+
+ self.metadata_xml_path = metadata_xml_path
+ self._xml_tree = None
+
+ try:
+ self._xml_tree = etree.parse(metadata_xml_path)
+ except ImportError:
+ pass
+
+ if isinstance(herds, etree.ElementTree):
+ herds_etree = herds
+ herds_path = None
+ else:
+ herds_etree = None
+ herds_path = herds
+
+ # Used for caching
+ self._herdstree = herds_etree
+ self._herds_path = herds_path
+ self._descriptions = None
+ self._maintainers = None
+ self._herds = None
+ self._useflags = None
+ self._upstream = None
+
+ def __repr__(self):
+ return "<%s %r>" % (self.__class__.__name__, self.metadata_xml_path)
+
+ def _get_herd_email(self, herd):
+ """Get a herd's email address.
+
+ @type herd: str
+ @param herd: herd whose email you want
+ @rtype: str or None
+ @return: email address or None if herd is not in herds.xml
+ @raise IOError: if $PORTDIR/metadata/herds.xml can not be read
+ """
+
+ if self._herdstree is None:
+ try:
+ self._herdstree = etree.parse(self._herds_path)
+ except (ImportError, IOError, SyntaxError):
+ return None
+
+ # Some special herds are not listed in herds.xml
+ if herd in ('no-herd', 'maintainer-wanted', 'maintainer-needed'):
+ return None
+
+ for node in self._herdstree.getiterator('herd'):
+ if node.findtext('name') == herd:
+ return node.findtext('email')
+
+ def herds(self, include_email=False):
+ """Return a list of text nodes for <herd>.
+
+ @type include_email: bool
+ @keyword include_email: if True, also look up the herd's email
+ @rtype: tuple
+ @return: if include_email is False, return a list of strings;
+ if include_email is True, return a list of tuples containing:
+ [('herd1', 'herd1@gentoo.org'), ('no-herd', None);
+ """
+ if self._herds is None:
+ if self._xml_tree is None:
+ self._herds = tuple()
+ else:
+ herds = []
+ for elem in self._xml_tree.findall('herd'):
+ text = elem.text
+ if text is None:
+ text = ''
+ if include_email:
+ herd_mail = self._get_herd_email(text)
+ herds.append((text, herd_mail))
+ else:
+ herds.append(text)
+ self._herds = tuple(herds)
+
+ return self._herds
+
+ def descriptions(self):
+ """Return a list of text nodes for <longdescription>.
+
+ @rtype: list
+ @return: package description in string format
+ @todo: Support the C{lang} attribute
+ """
+ if self._descriptions is None:
+ if self._xml_tree is None:
+ self._descriptions = tuple()
+ else:
+ self._descriptions = tuple(e.text \
+ for e in self._xml_tree.findall("longdescription"))
+
+ return self._descriptions
+
+ def maintainers(self):
+ """Get maintainers' name, email and description.
+
+ @rtype: list
+ @return: a sequence of L{_Maintainer} objects in document order.
+ """
+
+ if self._maintainers is None:
+ if self._xml_tree is None:
+ self._maintainers = tuple()
+ else:
+ self._maintainers = tuple(_Maintainer(node) \
+ for node in self._xml_tree.findall('maintainer'))
+
+ return self._maintainers
+
+ def use(self):
+ """Get names and descriptions for USE flags defined in metadata.
+
+ @rtype: list
+ @return: a sequence of L{_Useflag} objects in document order.
+ """
+
+ if self._useflags is None:
+ if self._xml_tree is None:
+ self._useflags = tuple()
+ else:
+ self._useflags = tuple(_Useflag(node) \
+ for node in self._xml_tree.getiterator('flag'))
+
+ return self._useflags
+
+ def upstream(self):
+ """Get upstream contact information.
+
+ @rtype: list
+ @return: a sequence of L{_Upstream} objects in document order.
+ """
+
+ if self._upstream is None:
+ if self._xml_tree is None:
+ self._upstream = tuple()
+ else:
+ self._upstream = tuple(_Upstream(node) \
+ for node in self._xml_tree.findall('upstream'))
+
+ return self._upstream
+
+ def format_maintainer_string(self):
+ """Format string containing maintainers and herds (emails if possible).
+ Used by emerge to display maintainer information.
+ Entries are sorted according to the rules stated on the bug wranglers page.
+
+ @rtype: String
+ @return: a string containing maintainers and herds
+ """
+ maintainers = []
+ for maintainer in self.maintainers():
+ if maintainer.email is None or not maintainer.email.strip():
+ if maintainer.name and maintainer.name.strip():
+ maintainers.append(maintainer.name)
+ else:
+ maintainers.append(maintainer.email)
+
+ for herd, email in self.herds(include_email=True):
+ if herd == "no-herd":
+ continue
+ if email is None or not email.strip():
+ if herd and herd.strip():
+ maintainers.append(herd)
+ else:
+ maintainers.append(email)
+
+ maintainers = list(unique_everseen(maintainers))
+
+ maint_str = ""
+ if maintainers:
+ maint_str = maintainers[0]
+ maintainers = maintainers[1:]
+ if maintainers:
+ maint_str += " " + ",".join(maintainers)
+
+ return maint_str
+
+ def format_upstream_string(self):
+ """Format string containing upstream maintainers and bugtrackers.
+ Used by emerge to display upstream information.
+
+ @rtype: String
+ @return: a string containing upstream maintainers and bugtrackers
+ """
+ maintainers = []
+ for upstream in self.upstream():
+ for maintainer in upstream.maintainers:
+ if maintainer.email is None or not maintainer.email.strip():
+ if maintainer.name and maintainer.name.strip():
+ maintainers.append(maintainer.name)
+ else:
+ maintainers.append(maintainer.email)
+
+ for bugtracker in upstream.bugtrackers:
+ if bugtracker.startswith("mailto:"):
+ bugtracker = bugtracker[7:]
+ maintainers.append(bugtracker)
+
+
+ maintainers = list(unique_everseen(maintainers))
+ maint_str = " ".join(maintainers)
+ return maint_str
diff --git a/portage_with_autodep/pym/portage/xpak.py b/portage_with_autodep/pym/portage/xpak.py
new file mode 100644
index 0000000..7487d67
--- /dev/null
+++ b/portage_with_autodep/pym/portage/xpak.py
@@ -0,0 +1,497 @@
+# Copyright 2001-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+
+# The format for a tbz2/xpak:
+#
+# tbz2: tar.bz2 + xpak + (xpak_offset) + "STOP"
+# xpak: "XPAKPACK" + (index_len) + (data_len) + index + data + "XPAKSTOP"
+# index: (pathname_len) + pathname + (data_offset) + (data_len)
+# index entries are concatenated end-to-end.
+# data: concatenated data chunks, end-to-end.
+#
+# [tarball]XPAKPACKIIIIDDDD[index][data]XPAKSTOPOOOOSTOP
+#
+# (integer) == encodeint(integer) ===> 4 characters (big-endian copy)
+# '+' means concatenate the fields ===> All chunks are strings
+
+__all__ = ['addtolist', 'decodeint', 'encodeint', 'getboth',
+ 'getindex', 'getindex_mem', 'getitem', 'listindex',
+ 'searchindex', 'tbz2', 'xpak_mem', 'xpak', 'xpand',
+ 'xsplit', 'xsplit_mem']
+
+import array
+import errno
+import shutil
+import sys
+
+import portage
+from portage import os
+from portage import normalize_path
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+
+def addtolist(mylist, curdir):
+ """(list, dir) --- Takes an array(list) and appends all files from dir down
+ the directory tree. Returns nothing. list is modified."""
+ curdir = normalize_path(_unicode_decode(curdir,
+ encoding=_encodings['fs'], errors='strict'))
+ for parent, dirs, files in os.walk(curdir):
+
+ parent = _unicode_decode(parent,
+ encoding=_encodings['fs'], errors='strict')
+ if parent != curdir:
+ mylist.append(parent[len(curdir) + 1:] + os.sep)
+
+ for x in dirs:
+ try:
+ _unicode_decode(x, encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ dirs.remove(x)
+
+ for x in files:
+ try:
+ x = _unicode_decode(x,
+ encoding=_encodings['fs'], errors='strict')
+ except UnicodeDecodeError:
+ continue
+ mylist.append(os.path.join(parent, x)[len(curdir) + 1:])
+
+def encodeint(myint):
+ """Takes a 4 byte integer and converts it into a string of 4 characters.
+ Returns the characters in a string."""
+ a = array.array('B')
+ a.append((myint >> 24 ) & 0xff)
+ a.append((myint >> 16 ) & 0xff)
+ a.append((myint >> 8 ) & 0xff)
+ a.append(myint & 0xff)
+ return a.tostring()
+
+def decodeint(mystring):
+ """Takes a 4 byte string and converts it into a 4 byte integer.
+ Returns an integer."""
+ if sys.hexversion < 0x3000000:
+ mystring = [ord(x) for x in mystring]
+ myint = 0
+ myint += mystring[3]
+ myint += mystring[2] << 8
+ myint += mystring[1] << 16
+ myint += mystring[0] << 24
+ return myint
+
+def xpak(rootdir,outfile=None):
+ """(rootdir,outfile) -- creates an xpak segment of the directory 'rootdir'
+ and under the name 'outfile' if it is specified. Otherwise it returns the
+ xpak segment."""
+
+ mylist=[]
+
+ addtolist(mylist, rootdir)
+ mylist.sort()
+ mydata = {}
+ for x in mylist:
+ if x == 'CONTENTS':
+ # CONTENTS is generated during the merge process.
+ continue
+ x = _unicode_encode(x, encoding=_encodings['fs'], errors='strict')
+ mydata[x] = open(os.path.join(rootdir, x), 'rb').read()
+
+ xpak_segment = xpak_mem(mydata)
+ if outfile:
+ outf = open(_unicode_encode(outfile,
+ encoding=_encodings['fs'], errors='strict'), 'wb')
+ outf.write(xpak_segment)
+ outf.close()
+ else:
+ return xpak_segment
+
+def xpak_mem(mydata):
+ """Create an xpack segement from a map object."""
+
+ mydata_encoded = {}
+ for k, v in mydata.items():
+ k = _unicode_encode(k,
+ encoding=_encodings['repo.content'], errors='backslashreplace')
+ v = _unicode_encode(v,
+ encoding=_encodings['repo.content'], errors='backslashreplace')
+ mydata_encoded[k] = v
+ mydata = mydata_encoded
+ del mydata_encoded
+
+ indexglob = b''
+ indexpos=0
+ dataglob = b''
+ datapos=0
+ for x, newglob in mydata.items():
+ mydatasize=len(newglob)
+ indexglob=indexglob+encodeint(len(x))+x+encodeint(datapos)+encodeint(mydatasize)
+ indexpos=indexpos+4+len(x)+4+4
+ dataglob=dataglob+newglob
+ datapos=datapos+mydatasize
+ return b'XPAKPACK' \
+ + encodeint(len(indexglob)) \
+ + encodeint(len(dataglob)) \
+ + indexglob \
+ + dataglob \
+ + b'XPAKSTOP'
+
+def xsplit(infile):
+ """(infile) -- Splits the infile into two files.
+ 'infile.index' contains the index segment.
+ 'infile.dat' contails the data segment."""
+ infile = _unicode_decode(infile,
+ encoding=_encodings['fs'], errors='strict')
+ myfile = open(_unicode_encode(infile,
+ encoding=_encodings['fs'], errors='strict'), 'rb')
+ mydat=myfile.read()
+ myfile.close()
+
+ splits = xsplit_mem(mydat)
+ if not splits:
+ return False
+
+ myfile = open(_unicode_encode(infile + '.index',
+ encoding=_encodings['fs'], errors='strict'), 'wb')
+ myfile.write(splits[0])
+ myfile.close()
+ myfile = open(_unicode_encode(infile + '.dat',
+ encoding=_encodings['fs'], errors='strict'), 'wb')
+ myfile.write(splits[1])
+ myfile.close()
+ return True
+
+def xsplit_mem(mydat):
+ if mydat[0:8] != b'XPAKPACK':
+ return None
+ if mydat[-8:] != b'XPAKSTOP':
+ return None
+ indexsize=decodeint(mydat[8:12])
+ return (mydat[16:indexsize+16], mydat[indexsize+16:-8])
+
+def getindex(infile):
+ """(infile) -- grabs the index segment from the infile and returns it."""
+ myfile = open(_unicode_encode(infile,
+ encoding=_encodings['fs'], errors='strict'), 'rb')
+ myheader=myfile.read(16)
+ if myheader[0:8] != b'XPAKPACK':
+ myfile.close()
+ return
+ indexsize=decodeint(myheader[8:12])
+ myindex=myfile.read(indexsize)
+ myfile.close()
+ return myindex
+
+def getboth(infile):
+ """(infile) -- grabs the index and data segments from the infile.
+ Returns an array [indexSegment,dataSegment]"""
+ myfile = open(_unicode_encode(infile,
+ encoding=_encodings['fs'], errors='strict'), 'rb')
+ myheader=myfile.read(16)
+ if myheader[0:8] != b'XPAKPACK':
+ myfile.close()
+ return
+ indexsize=decodeint(myheader[8:12])
+ datasize=decodeint(myheader[12:16])
+ myindex=myfile.read(indexsize)
+ mydata=myfile.read(datasize)
+ myfile.close()
+ return myindex, mydata
+
+def listindex(myindex):
+ """Print to the terminal the filenames listed in the indexglob passed in."""
+ for x in getindex_mem(myindex):
+ print(x)
+
+def getindex_mem(myindex):
+ """Returns the filenames listed in the indexglob passed in."""
+ myindexlen=len(myindex)
+ startpos=0
+ myret=[]
+ while ((startpos+8)<myindexlen):
+ mytestlen=decodeint(myindex[startpos:startpos+4])
+ myret=myret+[myindex[startpos+4:startpos+4+mytestlen]]
+ startpos=startpos+mytestlen+12
+ return myret
+
+def searchindex(myindex,myitem):
+ """(index,item) -- Finds the offset and length of the file 'item' in the
+ datasegment via the index 'index' provided."""
+ myitem = _unicode_encode(myitem,
+ encoding=_encodings['repo.content'], errors='backslashreplace')
+ mylen=len(myitem)
+ myindexlen=len(myindex)
+ startpos=0
+ while ((startpos+8)<myindexlen):
+ mytestlen=decodeint(myindex[startpos:startpos+4])
+ if mytestlen==mylen:
+ if myitem==myindex[startpos+4:startpos+4+mytestlen]:
+ #found
+ datapos=decodeint(myindex[startpos+4+mytestlen:startpos+8+mytestlen]);
+ datalen=decodeint(myindex[startpos+8+mytestlen:startpos+12+mytestlen]);
+ return datapos, datalen
+ startpos=startpos+mytestlen+12
+
+def getitem(myid,myitem):
+ myindex=myid[0]
+ mydata=myid[1]
+ myloc=searchindex(myindex,myitem)
+ if not myloc:
+ return None
+ return mydata[myloc[0]:myloc[0]+myloc[1]]
+
+def xpand(myid,mydest):
+ myindex=myid[0]
+ mydata=myid[1]
+ try:
+ origdir=os.getcwd()
+ except SystemExit as e:
+ raise
+ except:
+ os.chdir("/")
+ origdir="/"
+ os.chdir(mydest)
+ myindexlen=len(myindex)
+ startpos=0
+ while ((startpos+8)<myindexlen):
+ namelen=decodeint(myindex[startpos:startpos+4])
+ datapos=decodeint(myindex[startpos+4+namelen:startpos+8+namelen]);
+ datalen=decodeint(myindex[startpos+8+namelen:startpos+12+namelen]);
+ myname=myindex[startpos+4:startpos+4+namelen]
+ dirname=os.path.dirname(myname)
+ if dirname:
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
+ mydat = open(_unicode_encode(myname,
+ encoding=_encodings['fs'], errors='strict'), 'wb')
+ mydat.write(mydata[datapos:datapos+datalen])
+ mydat.close()
+ startpos=startpos+namelen+12
+ os.chdir(origdir)
+
+class tbz2(object):
+ def __init__(self,myfile):
+ self.file=myfile
+ self.filestat=None
+ self.index = b''
+ self.infosize=0
+ self.xpaksize=0
+ self.indexsize=None
+ self.datasize=None
+ self.indexpos=None
+ self.datapos=None
+
+ def decompose(self,datadir,cleanup=1):
+ """Alias for unpackinfo() --- Complement to recompose() but optionally
+ deletes the destination directory. Extracts the xpak from the tbz2 into
+ the directory provided. Raises IOError if scan() fails.
+ Returns result of upackinfo()."""
+ if not self.scan():
+ raise IOError
+ if cleanup:
+ self.cleanup(datadir)
+ if not os.path.exists(datadir):
+ os.makedirs(datadir)
+ return self.unpackinfo(datadir)
+ def compose(self,datadir,cleanup=0):
+ """Alias for recompose()."""
+ return self.recompose(datadir,cleanup)
+
+ def recompose(self, datadir, cleanup=0, break_hardlinks=True):
+ """Creates an xpak segment from the datadir provided, truncates the tbz2
+ to the end of regular data if an xpak segment already exists, and adds
+ the new segment to the file with terminating info."""
+ xpdata = xpak(datadir)
+ self.recompose_mem(xpdata, break_hardlinks=break_hardlinks)
+ if cleanup:
+ self.cleanup(datadir)
+
+ def recompose_mem(self, xpdata, break_hardlinks=True):
+ """
+ Update the xpak segment.
+ @param xpdata: A new xpak segment to be written, like that returned
+ from the xpak_mem() function.
+ @param break_hardlinks: If hardlinks exist, create a copy in order
+ to break them. This makes it safe to use hardlinks to create
+ cheap snapshots of the repository, which is useful for solving
+ race conditions on binhosts as described here:
+ http://code.google.com/p/chromium-os/issues/detail?id=3225.
+ Default is True.
+ """
+ self.scan() # Don't care about condition... We'll rewrite the data anyway.
+
+ if break_hardlinks and self.filestat.st_nlink > 1:
+ tmp_fname = "%s.%d" % (self.file, os.getpid())
+ shutil.copyfile(self.file, tmp_fname)
+ try:
+ portage.util.apply_stat_permissions(self.file, self.filestat)
+ except portage.exception.OperationNotPermitted:
+ pass
+ os.rename(tmp_fname, self.file)
+
+ myfile = open(_unicode_encode(self.file,
+ encoding=_encodings['fs'], errors='strict'), 'ab+')
+ if not myfile:
+ raise IOError
+ myfile.seek(-self.xpaksize,2) # 0,2 or -0,2 just mean EOF.
+ myfile.truncate()
+ myfile.write(xpdata+encodeint(len(xpdata)) + b'STOP')
+ myfile.flush()
+ myfile.close()
+ return 1
+
+ def cleanup(self, datadir):
+ datadir_split = os.path.split(datadir)
+ if len(datadir_split) >= 2 and len(datadir_split[1]) > 0:
+ # This is potentially dangerous,
+ # thus the above sanity check.
+ try:
+ shutil.rmtree(datadir)
+ except OSError as oe:
+ if oe.errno == errno.ENOENT:
+ pass
+ else:
+ raise oe
+
+ def scan(self):
+ """Scans the tbz2 to locate the xpak segment and setup internal values.
+ This function is called by relevant functions already."""
+ try:
+ mystat=os.stat(self.file)
+ if self.filestat:
+ changed=0
+ if mystat.st_size != self.filestat.st_size \
+ or mystat.st_mtime != self.filestat.st_mtime \
+ or mystat.st_ctime != self.filestat.st_ctime:
+ changed = True
+ if not changed:
+ return 1
+ self.filestat=mystat
+ a = open(_unicode_encode(self.file,
+ encoding=_encodings['fs'], errors='strict'), 'rb')
+ a.seek(-16,2)
+ trailer=a.read()
+ self.infosize=0
+ self.xpaksize=0
+ if trailer[-4:] != b'STOP':
+ a.close()
+ return 0
+ if trailer[0:8] != b'XPAKSTOP':
+ a.close()
+ return 0
+ self.infosize=decodeint(trailer[8:12])
+ self.xpaksize=self.infosize+8
+ a.seek(-(self.xpaksize),2)
+ header=a.read(16)
+ if header[0:8] != b'XPAKPACK':
+ a.close()
+ return 0
+ self.indexsize=decodeint(header[8:12])
+ self.datasize=decodeint(header[12:16])
+ self.indexpos=a.tell()
+ self.index=a.read(self.indexsize)
+ self.datapos=a.tell()
+ a.close()
+ return 2
+ except SystemExit as e:
+ raise
+ except:
+ return 0
+
+ def filelist(self):
+ """Return an array of each file listed in the index."""
+ if not self.scan():
+ return None
+ return getindex_mem(self.index)
+
+ def getfile(self,myfile,mydefault=None):
+ """Finds 'myfile' in the data segment and returns it."""
+ if not self.scan():
+ return None
+ myresult=searchindex(self.index,myfile)
+ if not myresult:
+ return mydefault
+ a = open(_unicode_encode(self.file,
+ encoding=_encodings['fs'], errors='strict'), 'rb')
+ a.seek(self.datapos+myresult[0],0)
+ myreturn=a.read(myresult[1])
+ a.close()
+ return myreturn
+
+ def getelements(self,myfile):
+ """A split/array representation of tbz2.getfile()"""
+ mydat=self.getfile(myfile)
+ if not mydat:
+ return []
+ return mydat.split()
+
+ def unpackinfo(self,mydest):
+ """Unpacks all the files from the dataSegment into 'mydest'."""
+ if not self.scan():
+ return 0
+ try:
+ origdir=os.getcwd()
+ except SystemExit as e:
+ raise
+ except:
+ os.chdir("/")
+ origdir="/"
+ a = open(_unicode_encode(self.file,
+ encoding=_encodings['fs'], errors='strict'), 'rb')
+ if not os.path.exists(mydest):
+ os.makedirs(mydest)
+ os.chdir(mydest)
+ startpos=0
+ while ((startpos+8)<self.indexsize):
+ namelen=decodeint(self.index[startpos:startpos+4])
+ datapos=decodeint(self.index[startpos+4+namelen:startpos+8+namelen]);
+ datalen=decodeint(self.index[startpos+8+namelen:startpos+12+namelen]);
+ myname=self.index[startpos+4:startpos+4+namelen]
+ myname = _unicode_decode(myname,
+ encoding=_encodings['repo.content'], errors='replace')
+ dirname=os.path.dirname(myname)
+ if dirname:
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
+ mydat = open(_unicode_encode(myname,
+ encoding=_encodings['fs'], errors='strict'), 'wb')
+ a.seek(self.datapos+datapos)
+ mydat.write(a.read(datalen))
+ mydat.close()
+ startpos=startpos+namelen+12
+ a.close()
+ os.chdir(origdir)
+ return 1
+
+ def get_data(self):
+ """Returns all the files from the dataSegment as a map object."""
+ if not self.scan():
+ return {}
+ a = open(_unicode_encode(self.file,
+ encoding=_encodings['fs'], errors='strict'), 'rb')
+ mydata = {}
+ startpos=0
+ while ((startpos+8)<self.indexsize):
+ namelen=decodeint(self.index[startpos:startpos+4])
+ datapos=decodeint(self.index[startpos+4+namelen:startpos+8+namelen]);
+ datalen=decodeint(self.index[startpos+8+namelen:startpos+12+namelen]);
+ myname=self.index[startpos+4:startpos+4+namelen]
+ a.seek(self.datapos+datapos)
+ mydata[myname] = a.read(datalen)
+ startpos=startpos+namelen+12
+ a.close()
+ return mydata
+
+ def getboth(self):
+ """Returns an array [indexSegment,dataSegment]"""
+ if not self.scan():
+ return None
+
+ a = open(_unicode_encode(self.file,
+ encoding=_encodings['fs'], errors='strict'), 'rb')
+ a.seek(self.datapos)
+ mydata =a.read(self.datasize)
+ a.close()
+
+ return self.index, mydata
+
diff --git a/portage_with_autodep/pym/repoman/__init__.py b/portage_with_autodep/pym/repoman/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/portage_with_autodep/pym/repoman/__init__.py
diff --git a/portage_with_autodep/pym/repoman/checks.py b/portage_with_autodep/pym/repoman/checks.py
new file mode 100644
index 0000000..e7472df
--- /dev/null
+++ b/portage_with_autodep/pym/repoman/checks.py
@@ -0,0 +1,707 @@
+# repoman: Checks
+# Copyright 2007, 2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+"""This module contains functions used in Repoman to ascertain the quality
+and correctness of an ebuild."""
+
+import re
+import time
+import repoman.errors as errors
+from portage.eapi import eapi_supports_prefix, eapi_has_implicit_rdepend, \
+ eapi_has_src_prepare_and_src_configure, eapi_has_dosed_dohard, \
+ eapi_exports_AA, eapi_exports_KV
+
+class LineCheck(object):
+ """Run a check on a line of an ebuild."""
+ """A regular expression to determine whether to ignore the line"""
+ ignore_line = False
+ """True if lines containing nothing more than comments with optional
+ leading whitespace should be ignored"""
+ ignore_comment = True
+
+ def new(self, pkg):
+ pass
+
+ def check_eapi(self, eapi):
+ """ returns if the check should be run in the given EAPI (default is True) """
+ return True
+
+ def check(self, num, line):
+ """Run the check on line and return error if there is one"""
+ if self.re.match(line):
+ return self.error
+
+ def end(self):
+ pass
+
+class PhaseCheck(LineCheck):
+ """ basic class for function detection """
+
+ func_end_re = re.compile(r'^\}$')
+ phases_re = re.compile('(%s)' % '|'.join((
+ 'pkg_pretend', 'pkg_setup', 'src_unpack', 'src_prepare',
+ 'src_configure', 'src_compile', 'src_test', 'src_install',
+ 'pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm',
+ 'pkg_config')))
+ in_phase = ''
+
+ def check(self, num, line):
+ m = self.phases_re.match(line)
+ if m is not None:
+ self.in_phase = m.group(1)
+ if self.in_phase != '' and \
+ self.func_end_re.match(line) is not None:
+ self.in_phase = ''
+
+ return self.phase_check(num, line)
+
+ def phase_check(self, num, line):
+ """ override this function for your checks """
+ pass
+
+class EbuildHeader(LineCheck):
+ """Ensure ebuilds have proper headers
+ Copyright header errors
+ CVS header errors
+ License header errors
+
+ Args:
+ modification_year - Year the ebuild was last modified
+ """
+
+ repoman_check_name = 'ebuild.badheader'
+
+ gentoo_copyright = r'^# Copyright ((1999|2\d\d\d)-)?%s Gentoo Foundation$'
+ # Why a regex here, use a string match
+ # gentoo_license = re.compile(r'^# Distributed under the terms of the GNU General Public License v2$')
+ gentoo_license = '# Distributed under the terms of the GNU General Public License v2'
+ cvs_header = re.compile(r'^# \$Header: .*\$$')
+
+ def new(self, pkg):
+ if pkg.mtime is None:
+ self.modification_year = r'2\d\d\d'
+ else:
+ self.modification_year = str(time.gmtime(pkg.mtime)[0])
+ self.gentoo_copyright_re = re.compile(
+ self.gentoo_copyright % self.modification_year)
+
+ def check(self, num, line):
+ if num > 2:
+ return
+ elif num == 0:
+ if not self.gentoo_copyright_re.match(line):
+ return errors.COPYRIGHT_ERROR
+ elif num == 1 and line.rstrip('\n') != self.gentoo_license:
+ return errors.LICENSE_ERROR
+ elif num == 2:
+ if not self.cvs_header.match(line):
+ return errors.CVS_HEADER_ERROR
+
+
+class EbuildWhitespace(LineCheck):
+ """Ensure ebuilds have proper whitespacing"""
+
+ repoman_check_name = 'ebuild.minorsyn'
+
+ ignore_line = re.compile(r'(^$)|(^(\t)*#)')
+ ignore_comment = False
+ leading_spaces = re.compile(r'^[\S\t]')
+ trailing_whitespace = re.compile(r'.*([\S]$)')
+
+ def check(self, num, line):
+ if self.leading_spaces.match(line) is None:
+ return errors.LEADING_SPACES_ERROR
+ if self.trailing_whitespace.match(line) is None:
+ return errors.TRAILING_WHITESPACE_ERROR
+
+class EbuildBlankLine(LineCheck):
+ repoman_check_name = 'ebuild.minorsyn'
+ ignore_comment = False
+ blank_line = re.compile(r'^$')
+
+ def new(self, pkg):
+ self.line_is_blank = False
+
+ def check(self, num, line):
+ if self.line_is_blank and self.blank_line.match(line):
+ return 'Useless blank line on line: %d'
+ if self.blank_line.match(line):
+ self.line_is_blank = True
+ else:
+ self.line_is_blank = False
+
+ def end(self):
+ if self.line_is_blank:
+ yield 'Useless blank line on last line'
+
+class EbuildQuote(LineCheck):
+ """Ensure ebuilds have valid quoting around things like D,FILESDIR, etc..."""
+
+ repoman_check_name = 'ebuild.minorsyn'
+ _message_commands = ["die", "echo", "eerror",
+ "einfo", "elog", "eqawarn", "ewarn"]
+ _message_re = re.compile(r'\s(' + "|".join(_message_commands) + \
+ r')\s+"[^"]*"\s*$')
+ _ignored_commands = ["local", "export"] + _message_commands
+ ignore_line = re.compile(r'(^$)|(^\s*#.*)|(^\s*\w+=.*)' + \
+ r'|(^\s*(' + "|".join(_ignored_commands) + r')\s+)')
+ ignore_comment = False
+ var_names = ["D", "DISTDIR", "FILESDIR", "S", "T", "ROOT", "WORKDIR"]
+
+ # EAPI=3/Prefix vars
+ var_names += ["ED", "EPREFIX", "EROOT"]
+
+ # variables for games.eclass
+ var_names += ["Ddir", "GAMES_PREFIX_OPT", "GAMES_DATADIR",
+ "GAMES_DATADIR_BASE", "GAMES_SYSCONFDIR", "GAMES_STATEDIR",
+ "GAMES_LOGDIR", "GAMES_BINDIR"]
+
+ var_names = "(%s)" % "|".join(var_names)
+ var_reference = re.compile(r'\$(\{'+var_names+'\}|' + \
+ var_names + '\W)')
+ missing_quotes = re.compile(r'(\s|^)[^"\'\s]*\$\{?' + var_names + \
+ r'\}?[^"\'\s]*(\s|$)')
+ cond_begin = re.compile(r'(^|\s+)\[\[($|\\$|\s+)')
+ cond_end = re.compile(r'(^|\s+)\]\]($|\\$|\s+)')
+
+ def check(self, num, line):
+ if self.var_reference.search(line) is None:
+ return
+ # There can be multiple matches / violations on a single line. We
+ # have to make sure none of the matches are violators. Once we've
+ # found one violator, any remaining matches on the same line can
+ # be ignored.
+ pos = 0
+ while pos <= len(line) - 1:
+ missing_quotes = self.missing_quotes.search(line, pos)
+ if not missing_quotes:
+ break
+ # If the last character of the previous match is a whitespace
+ # character, that character may be needed for the next
+ # missing_quotes match, so search overlaps by 1 character.
+ group = missing_quotes.group()
+ pos = missing_quotes.end() - 1
+
+ # Filter out some false positives that can
+ # get through the missing_quotes regex.
+ if self.var_reference.search(group) is None:
+ continue
+
+ # Filter matches that appear to be an
+ # argument to a message command.
+ # For example: false || ewarn "foo $WORKDIR/bar baz"
+ message_match = self._message_re.search(line)
+ if message_match is not None and \
+ message_match.start() < pos and \
+ message_match.end() > pos:
+ break
+
+ # This is an attempt to avoid false positives without getting
+ # too complex, while possibly allowing some (hopefully
+ # unlikely) violations to slip through. We just assume
+ # everything is correct if the there is a ' [[ ' or a ' ]] '
+ # anywhere in the whole line (possibly continued over one
+ # line).
+ if self.cond_begin.search(line) is not None:
+ continue
+ if self.cond_end.search(line) is not None:
+ continue
+
+ # Any remaining matches on the same line can be ignored.
+ return errors.MISSING_QUOTES_ERROR
+
+
+class EbuildAssignment(LineCheck):
+ """Ensure ebuilds don't assign to readonly variables."""
+
+ repoman_check_name = 'variable.readonly'
+
+ readonly_assignment = re.compile(r'^\s*(export\s+)?(A|CATEGORY|P|PV|PN|PR|PVR|PF|D|WORKDIR|FILESDIR|FEATURES|USE)=')
+ line_continuation = re.compile(r'([^#]*\S)(\s+|\t)\\$')
+ ignore_line = re.compile(r'(^$)|(^(\t)*#)')
+ ignore_comment = False
+
+ def __init__(self):
+ self.previous_line = None
+
+ def check(self, num, line):
+ match = self.readonly_assignment.match(line)
+ e = None
+ if match and (not self.previous_line or not self.line_continuation.match(self.previous_line)):
+ e = errors.READONLY_ASSIGNMENT_ERROR
+ self.previous_line = line
+ return e
+
+class Eapi3EbuildAssignment(EbuildAssignment):
+ """Ensure ebuilds don't assign to readonly EAPI 3-introduced variables."""
+
+ readonly_assignment = re.compile(r'\s*(export\s+)?(ED|EPREFIX|EROOT)=')
+
+ def check_eapi(self, eapi):
+ return eapi_supports_prefix(eapi)
+
+class EbuildNestedDie(LineCheck):
+ """Check ebuild for nested die statements (die statements in subshells"""
+
+ repoman_check_name = 'ebuild.nesteddie'
+ nesteddie_re = re.compile(r'^[^#]*\s\(\s[^)]*\bdie\b')
+
+ def check(self, num, line):
+ if self.nesteddie_re.match(line):
+ return errors.NESTED_DIE_ERROR
+
+
+class EbuildUselessDodoc(LineCheck):
+ """Check ebuild for useless files in dodoc arguments."""
+ repoman_check_name = 'ebuild.minorsyn'
+ uselessdodoc_re = re.compile(
+ r'^\s*dodoc(\s+|\s+.*\s+)(ABOUT-NLS|COPYING|LICENCE|LICENSE)($|\s)')
+
+ def check(self, num, line):
+ match = self.uselessdodoc_re.match(line)
+ if match:
+ return "Useless dodoc '%s'" % (match.group(2), ) + " on line: %d"
+
+
+class EbuildUselessCdS(LineCheck):
+ """Check for redundant cd ${S} statements"""
+ repoman_check_name = 'ebuild.minorsyn'
+ method_re = re.compile(r'^\s*src_(prepare|configure|compile|install|test)\s*\(\)')
+ cds_re = re.compile(r'^\s*cd\s+("\$(\{S\}|S)"|\$(\{S\}|S))\s')
+
+ def __init__(self):
+ self.check_next_line = False
+
+ def check(self, num, line):
+ if self.check_next_line:
+ self.check_next_line = False
+ if self.cds_re.match(line):
+ return errors.REDUNDANT_CD_S_ERROR
+ elif self.method_re.match(line):
+ self.check_next_line = True
+
+class EapiDefinition(LineCheck):
+ """ Check that EAPI is defined before inherits"""
+ repoman_check_name = 'EAPI.definition'
+
+ eapi_re = re.compile(r'^EAPI=')
+ inherit_re = re.compile(r'^\s*inherit\s')
+
+ def new(self, pkg):
+ self.inherit_line = None
+
+ def check(self, num, line):
+ if self.eapi_re.match(line) is not None:
+ if self.inherit_line is not None:
+ return errors.EAPI_DEFINED_AFTER_INHERIT
+ elif self.inherit_re.match(line) is not None:
+ self.inherit_line = line
+
+class EbuildPatches(LineCheck):
+ """Ensure ebuilds use bash arrays for PATCHES to ensure white space safety"""
+ repoman_check_name = 'ebuild.patches'
+ re = re.compile(r'^\s*PATCHES=[^\(]')
+ error = errors.PATCHES_ERROR
+
+class EbuildQuotedA(LineCheck):
+ """Ensure ebuilds have no quoting around ${A}"""
+
+ repoman_check_name = 'ebuild.minorsyn'
+ a_quoted = re.compile(r'.*\"\$(\{A\}|A)\"')
+
+ def check(self, num, line):
+ match = self.a_quoted.match(line)
+ if match:
+ return "Quoted \"${A}\" on line: %d"
+
+class EprefixifyDefined(LineCheck):
+ """ Check that prefix.eclass is inherited if needed"""
+
+ repoman_check_name = 'eprefixify.defined'
+
+ _eprefixify_re = re.compile(r'\beprefixify\b')
+ _inherit_prefix_re = re.compile(r'^\s*inherit\s(.*\s)?prefix\b')
+
+ def new(self, pkg):
+ self._prefix_inherited = False
+
+ def check(self, num, line):
+ if self._eprefixify_re.search(line) is not None:
+ if not self._prefix_inherited:
+ return errors.EPREFIXIFY_MISSING_INHERIT
+ elif self._inherit_prefix_re.search(line) is not None:
+ self._prefix_inherited = True
+
+class NoOffsetWithHelpers(LineCheck):
+ """ Check that the image location, the alternate root offset, and the
+ offset prefix (D, ROOT, ED, EROOT and EPREFIX) are not used with
+ helpers """
+
+ repoman_check_name = 'variable.usedwithhelpers'
+ # Ignore matches in quoted strings like this:
+ # elog "installed into ${ROOT}usr/share/php5/apc/."
+ re = re.compile(r'^[^#"\']*\b(dodir|dohard|exeinto|insinto|into)\s+"?\$\{?(D|ROOT|ED|EROOT|EPREFIX)\b.*')
+ error = errors.NO_OFFSET_WITH_HELPERS
+
+class ImplicitRuntimeDeps(LineCheck):
+ """
+ Detect the case where DEPEND is set and RDEPEND is unset in the ebuild,
+ since this triggers implicit RDEPEND=$DEPEND assignment (prior to EAPI 4).
+ """
+
+ repoman_check_name = 'RDEPEND.implicit'
+ _assignment_re = re.compile(r'^\s*(R?DEPEND)\+?=')
+
+ def new(self, pkg):
+ self._rdepend = False
+ self._depend = False
+
+ def check_eapi(self, eapi):
+ # Beginning with EAPI 4, there is no
+ # implicit RDEPEND=$DEPEND assignment
+ # to be concerned with.
+ return eapi_has_implicit_rdepend(eapi)
+
+ def check(self, num, line):
+ if not self._rdepend:
+ m = self._assignment_re.match(line)
+ if m is None:
+ pass
+ elif m.group(1) == "RDEPEND":
+ self._rdepend = True
+ elif m.group(1) == "DEPEND":
+ self._depend = True
+
+ def end(self):
+ if self._depend and not self._rdepend:
+ yield 'RDEPEND is not explicitly assigned'
+
+class InheritDeprecated(LineCheck):
+ """Check if ebuild directly or indirectly inherits a deprecated eclass."""
+
+ repoman_check_name = 'inherit.deprecated'
+
+ # deprecated eclass : new eclass (False if no new eclass)
+ deprecated_classes = {
+ "gems": "ruby-fakegem",
+ "git": "git-2",
+ "mozconfig-2": "mozconfig-3",
+ "mozcoreconf": "mozcoreconf-2",
+ "php-ext-pecl-r1": "php-ext-pecl-r2",
+ "php-ext-source-r1": "php-ext-source-r2",
+ "php-pear": "php-pear-r1",
+ "qt3": False,
+ "qt4": "qt4-r2",
+ "ruby": "ruby-ng",
+ "ruby-gnome2": "ruby-ng-gnome2",
+ "x-modular": "xorg-2",
+ }
+
+ _inherit_re = re.compile(r'^\s*inherit\s(.*)$')
+
+ def new(self, pkg):
+ self._errors = []
+ self._indirect_deprecated = set(eclass for eclass in \
+ self.deprecated_classes if eclass in pkg.inherited)
+
+ def check(self, num, line):
+
+ direct_inherits = None
+ m = self._inherit_re.match(line)
+ if m is not None:
+ direct_inherits = m.group(1)
+ if direct_inherits:
+ direct_inherits = direct_inherits.split()
+
+ if not direct_inherits:
+ return
+
+ for eclass in direct_inherits:
+ replacement = self.deprecated_classes.get(eclass)
+ if replacement is None:
+ pass
+ elif replacement is False:
+ self._indirect_deprecated.discard(eclass)
+ self._errors.append("please migrate from " + \
+ "'%s' (no replacement) on line: %d" % (eclass, num + 1))
+ else:
+ self._indirect_deprecated.discard(eclass)
+ self._errors.append("please migrate from " + \
+ "'%s' to '%s' on line: %d" % \
+ (eclass, replacement, num + 1))
+
+ def end(self):
+ for error in self._errors:
+ yield error
+ del self._errors
+
+ for eclass in self._indirect_deprecated:
+ replacement = self.deprecated_classes[eclass]
+ if replacement is False:
+ yield "please migrate from indirect " + \
+ "inherit of '%s' (no replacement)" % (eclass,)
+ else:
+ yield "please migrate from indirect " + \
+ "inherit of '%s' to '%s'" % \
+ (eclass, replacement)
+ del self._indirect_deprecated
+
+class InheritAutotools(LineCheck):
+ """
+ Make sure appropriate functions are called in
+ ebuilds that inherit autotools.eclass.
+ """
+
+ repoman_check_name = 'inherit.autotools'
+ _inherit_autotools_re = re.compile(r'^\s*inherit\s(.*\s)?autotools(\s|$)')
+ _autotools_funcs = (
+ "eaclocal", "eautoconf", "eautoheader",
+ "eautomake", "eautoreconf", "_elibtoolize")
+ _autotools_func_re = re.compile(r'\b(' + \
+ "|".join(_autotools_funcs) + r')\b')
+ # Exempt eclasses:
+ # git - An EGIT_BOOTSTRAP variable may be used to call one of
+ # the autotools functions.
+ # subversion - An ESVN_BOOTSTRAP variable may be used to call one of
+ # the autotools functions.
+ _exempt_eclasses = frozenset(["git", "subversion"])
+
+ def new(self, pkg):
+ self._inherit_autotools = None
+ self._autotools_func_call = None
+ self._disabled = self._exempt_eclasses.intersection(pkg.inherited)
+
+ def check(self, num, line):
+ if self._disabled:
+ return
+ if self._inherit_autotools is None:
+ self._inherit_autotools = self._inherit_autotools_re.match(line)
+ if self._inherit_autotools is not None and \
+ self._autotools_func_call is None:
+ self._autotools_func_call = self._autotools_func_re.search(line)
+
+ def end(self):
+ if self._inherit_autotools and self._autotools_func_call is None:
+ yield 'no eauto* function called'
+
+class IUseUndefined(LineCheck):
+ """
+ Make sure the ebuild defines IUSE (style guideline
+ says to define IUSE even when empty).
+ """
+
+ repoman_check_name = 'IUSE.undefined'
+ _iuse_def_re = re.compile(r'^IUSE=.*')
+
+ def new(self, pkg):
+ self._iuse_def = None
+
+ def check(self, num, line):
+ if self._iuse_def is None:
+ self._iuse_def = self._iuse_def_re.match(line)
+
+ def end(self):
+ if self._iuse_def is None:
+ yield 'IUSE is not defined'
+
+class EMakeParallelDisabled(PhaseCheck):
+ """Check for emake -j1 calls which disable parallelization."""
+ repoman_check_name = 'upstream.workaround'
+ re = re.compile(r'^\s*emake\s+.*-j\s*1\b')
+ error = errors.EMAKE_PARALLEL_DISABLED
+
+ def phase_check(self, num, line):
+ if self.in_phase == 'src_compile' or self.in_phase == 'src_install':
+ if self.re.match(line):
+ return self.error
+
+class EMakeParallelDisabledViaMAKEOPTS(LineCheck):
+ """Check for MAKEOPTS=-j1 that disables parallelization."""
+ repoman_check_name = 'upstream.workaround'
+ re = re.compile(r'^\s*MAKEOPTS=(\'|")?.*-j\s*1\b')
+ error = errors.EMAKE_PARALLEL_DISABLED_VIA_MAKEOPTS
+
+class NoAsNeeded(LineCheck):
+ """Check for calls to the no-as-needed function."""
+ repoman_check_name = 'upstream.workaround'
+ re = re.compile(r'.*\$\(no-as-needed\)')
+ error = errors.NO_AS_NEEDED
+
+class PreserveOldLib(LineCheck):
+ """Check for calls to the preserve_old_lib function."""
+ repoman_check_name = 'upstream.workaround'
+ re = re.compile(r'.*preserve_old_lib')
+ error = errors.PRESERVE_OLD_LIB
+
+class SandboxAddpredict(LineCheck):
+ """Check for calls to the addpredict function."""
+ repoman_check_name = 'upstream.workaround'
+ re = re.compile(r'(^|\s)addpredict\b')
+ error = errors.SANDBOX_ADDPREDICT
+
+class DeprecatedBindnowFlags(LineCheck):
+ """Check for calls to the deprecated bindnow-flags function."""
+ repoman_check_name = 'ebuild.minorsyn'
+ re = re.compile(r'.*\$\(bindnow-flags\)')
+ error = errors.DEPRECATED_BINDNOW_FLAGS
+
+class WantAutoDefaultValue(LineCheck):
+ """Check setting WANT_AUTO* to latest (default value)."""
+ repoman_check_name = 'ebuild.minorsyn'
+ _re = re.compile(r'^WANT_AUTO(CONF|MAKE)=(\'|")?latest')
+
+ def check(self, num, line):
+ m = self._re.match(line)
+ if m is not None:
+ return 'WANT_AUTO' + m.group(1) + \
+ ' redundantly set to default value "latest" on line: %d'
+
+class SrcCompileEconf(PhaseCheck):
+ repoman_check_name = 'ebuild.minorsyn'
+ configure_re = re.compile(r'\s(econf|./configure)')
+
+ def check_eapi(self, eapi):
+ return eapi_has_src_prepare_and_src_configure(eapi)
+
+ def phase_check(self, num, line):
+ if self.in_phase == 'src_compile':
+ m = self.configure_re.match(line)
+ if m is not None:
+ return ("'%s'" % m.group(1)) + \
+ " call should be moved to src_configure from line: %d"
+
+class SrcUnpackPatches(PhaseCheck):
+ repoman_check_name = 'ebuild.minorsyn'
+ src_prepare_tools_re = re.compile(r'\s(e?patch|sed)\s')
+
+ def check_eapi(self, eapi):
+ return eapi_has_src_prepare_and_src_configure(eapi)
+
+ def phase_check(self, num, line):
+ if self.in_phase == 'src_unpack':
+ m = self.src_prepare_tools_re.search(line)
+ if m is not None:
+ return ("'%s'" % m.group(1)) + \
+ " call should be moved to src_prepare from line: %d"
+
+class BuiltWithUse(LineCheck):
+ repoman_check_name = 'ebuild.minorsyn'
+ re = re.compile(r'(^|.*\b)built_with_use\b')
+ error = errors.BUILT_WITH_USE
+
+class DeprecatedUseq(LineCheck):
+ """Checks for use of the deprecated useq function"""
+ repoman_check_name = 'ebuild.minorsyn'
+ re = re.compile(r'(^|.*\b)useq\b')
+ error = errors.USEQ_ERROR
+
+class DeprecatedHasq(LineCheck):
+ """Checks for use of the deprecated hasq function"""
+ repoman_check_name = 'ebuild.minorsyn'
+ re = re.compile(r'(^|.*\b)hasq\b')
+ error = errors.HASQ_ERROR
+
+# EAPI-3 checks
+class Eapi3DeprecatedFuncs(LineCheck):
+ repoman_check_name = 'EAPI.deprecated'
+ deprecated_commands_re = re.compile(r'^\s*(check_license)\b')
+
+ def check_eapi(self, eapi):
+ return eapi not in ('0', '1', '2')
+
+ def check(self, num, line):
+ m = self.deprecated_commands_re.match(line)
+ if m is not None:
+ return ("'%s'" % m.group(1)) + \
+ " has been deprecated in EAPI=3 on line: %d"
+
+# EAPI-4 checks
+class Eapi4IncompatibleFuncs(LineCheck):
+ repoman_check_name = 'EAPI.incompatible'
+ banned_commands_re = re.compile(r'^\s*(dosed|dohard)')
+
+ def check_eapi(self, eapi):
+ return not eapi_has_dosed_dohard(eapi)
+
+ def check(self, num, line):
+ m = self.banned_commands_re.match(line)
+ if m is not None:
+ return ("'%s'" % m.group(1)) + \
+ " has been banned in EAPI=4 on line: %d"
+
+class Eapi4GoneVars(LineCheck):
+ repoman_check_name = 'EAPI.incompatible'
+ undefined_vars_re = re.compile(r'.*\$(\{(AA|KV|EMERGE_FROM)\}|(AA|KV|EMERGE_FROM))')
+
+ def check_eapi(self, eapi):
+ # AA, KV, and EMERGE_FROM should not be referenced in EAPI 4 or later.
+ return not eapi_exports_AA(eapi)
+
+ def check(self, num, line):
+ m = self.undefined_vars_re.match(line)
+ if m is not None:
+ return ("variable '$%s'" % m.group(1)) + \
+ " is gone in EAPI=4 on line: %d"
+
+class PortageInternal(LineCheck):
+ repoman_check_name = 'portage.internal'
+ re = re.compile(r'[^#]*\b(ecompress|ecompressdir|prepall|prepalldocs|preplib)\b')
+
+ def check(self, num, line):
+ """Run the check on line and return error if there is one"""
+ m = self.re.match(line)
+ if m is not None:
+ return ("'%s'" % m.group(1)) + " called on line: %d"
+
+_constant_checks = tuple((c() for c in (
+ EbuildHeader, EbuildWhitespace, EbuildBlankLine, EbuildQuote,
+ EbuildAssignment, Eapi3EbuildAssignment, EbuildUselessDodoc,
+ EbuildUselessCdS, EbuildNestedDie,
+ EbuildPatches, EbuildQuotedA, EapiDefinition, EprefixifyDefined,
+ ImplicitRuntimeDeps, InheritAutotools, InheritDeprecated, IUseUndefined,
+ EMakeParallelDisabled, EMakeParallelDisabledViaMAKEOPTS, NoAsNeeded,
+ DeprecatedBindnowFlags, SrcUnpackPatches, WantAutoDefaultValue,
+ SrcCompileEconf, Eapi3DeprecatedFuncs, NoOffsetWithHelpers,
+ Eapi4IncompatibleFuncs, Eapi4GoneVars, BuiltWithUse,
+ PreserveOldLib, SandboxAddpredict, PortageInternal,
+ DeprecatedUseq, DeprecatedHasq)))
+
+_here_doc_re = re.compile(r'.*\s<<[-]?(\w+)$')
+_ignore_comment_re = re.compile(r'^\s*#')
+
+def run_checks(contents, pkg):
+ checks = _constant_checks
+ here_doc_delim = None
+
+ for lc in checks:
+ lc.new(pkg)
+ for num, line in enumerate(contents):
+
+ # Check if we're inside a here-document.
+ if here_doc_delim is not None:
+ if here_doc_delim.match(line):
+ here_doc_delim = None
+ if here_doc_delim is None:
+ here_doc = _here_doc_re.match(line)
+ if here_doc is not None:
+ here_doc_delim = re.compile(r'^\s*%s$' % here_doc.group(1))
+
+ if here_doc_delim is None:
+ # We're not in a here-document.
+ is_comment = _ignore_comment_re.match(line) is not None
+ for lc in checks:
+ if is_comment and lc.ignore_comment:
+ continue
+ if lc.check_eapi(pkg.metadata['EAPI']):
+ ignore = lc.ignore_line
+ if not ignore or not ignore.match(line):
+ e = lc.check(num, line)
+ if e:
+ yield lc.repoman_check_name, e % (num + 1)
+
+ for lc in checks:
+ i = lc.end()
+ if i is not None:
+ for e in i:
+ yield lc.repoman_check_name, e
diff --git a/portage_with_autodep/pym/repoman/errors.py b/portage_with_autodep/pym/repoman/errors.py
new file mode 100644
index 0000000..3209243
--- /dev/null
+++ b/portage_with_autodep/pym/repoman/errors.py
@@ -0,0 +1,26 @@
+# repoman: Error Messages
+# Copyright 2007-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+COPYRIGHT_ERROR = 'Invalid Gentoo Copyright on line: %d'
+LICENSE_ERROR = 'Invalid Gentoo/GPL License on line: %d'
+CVS_HEADER_ERROR = 'Malformed CVS Header on line: %d'
+LEADING_SPACES_ERROR = 'Ebuild contains leading spaces on line: %d'
+TRAILING_WHITESPACE_ERROR = 'Trailing whitespace error on line: %d'
+READONLY_ASSIGNMENT_ERROR = 'Ebuild contains assignment to read-only variable on line: %d'
+MISSING_QUOTES_ERROR = 'Unquoted Variable on line: %d'
+NESTED_DIE_ERROR = 'Ebuild calls die in a subshell on line: %d'
+PATCHES_ERROR = 'PATCHES is not a bash array on line: %d'
+REDUNDANT_CD_S_ERROR = 'Ebuild has redundant cd ${S} statement on line: %d'
+EMAKE_PARALLEL_DISABLED = 'Upstream parallel compilation bug (ebuild calls emake -j1 on line: %d)'
+EMAKE_PARALLEL_DISABLED_VIA_MAKEOPTS = 'Upstream parallel compilation bug (MAKEOPTS=-j1 on line: %d)'
+DEPRECATED_BINDNOW_FLAGS = 'Deprecated bindnow-flags call on line: %d'
+EAPI_DEFINED_AFTER_INHERIT = 'EAPI defined after inherit on line: %d'
+NO_AS_NEEDED = 'Upstream asneeded linking bug (no-as-needed on line: %d)'
+PRESERVE_OLD_LIB = 'Upstream ABI change workaround on line: %d'
+BUILT_WITH_USE = 'built_with_use on line: %d'
+EPREFIXIFY_MISSING_INHERIT = "prefix.eclass is not inherited, but eprefixify is used on line: %d"
+NO_OFFSET_WITH_HELPERS = "Helper function is used with D, ROOT, ED, EROOT or EPREFIX on line :%d"
+SANDBOX_ADDPREDICT = 'Ebuild calls addpredict on line: %d'
+USEQ_ERROR = 'Ebuild calls deprecated useq function on line: %d'
+HASQ_ERROR = 'Ebuild calls deprecated hasq function on line: %d'
diff --git a/portage_with_autodep/pym/repoman/herdbase.py b/portage_with_autodep/pym/repoman/herdbase.py
new file mode 100644
index 0000000..64b59e6
--- /dev/null
+++ b/portage_with_autodep/pym/repoman/herdbase.py
@@ -0,0 +1,110 @@
+# -*- coding: utf-8 -*-
+# repoman: Herd database analysis
+# Copyright 2010-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2 or later
+
+import errno
+import xml.etree.ElementTree
+try:
+ from xml.parsers.expat import ExpatError
+except ImportError:
+ # This means that python is built without xml support.
+ # We tolerate global scope import failures for optional
+ # modules, so that ImportModulesTestCase can succeed (or
+ # possibly alert us about unexpected import failures).
+ pass
+from portage.exception import FileNotFound, ParseError, PermissionDenied
+
+__all__ = [
+ "make_herd_base"
+]
+
+_SPECIAL_HERDS = set(('no-herd',))
+
+def _make_email(nick_name):
+ if not nick_name.endswith('@gentoo.org'):
+ nick_name = nick_name + '@gentoo.org'
+ return nick_name
+
+
+class HerdBase(object):
+ def __init__(self, herd_to_emails, all_emails):
+ self.herd_to_emails = herd_to_emails
+ self.all_emails = all_emails
+
+ def known_herd(self, herd_name):
+ if herd_name in _SPECIAL_HERDS:
+ return True
+ return herd_name in self.herd_to_emails
+
+ def known_maintainer(self, nick_name):
+ return _make_email(nick_name) in self.all_emails
+
+ def maintainer_in_herd(self, nick_name, herd_name):
+ return _make_email(nick_name) in self.herd_to_emails[herd_name]
+
+class _HerdsTreeBuilder(xml.etree.ElementTree.TreeBuilder):
+ """
+ Implements doctype() as required to avoid deprecation warnings with
+ >=python-2.7.
+ """
+ def doctype(self, name, pubid, system):
+ pass
+
+def make_herd_base(filename):
+ herd_to_emails = dict()
+ all_emails = set()
+
+ try:
+ xml_tree = xml.etree.ElementTree.parse(filename,
+ parser=xml.etree.ElementTree.XMLParser(
+ target=_HerdsTreeBuilder()))
+ except ExpatError as e:
+ raise ParseError("metadata.xml: " + str(e))
+ except EnvironmentError as e:
+ func_call = "open('%s')" % filename
+ if e.errno == errno.EACCES:
+ raise PermissionDenied(func_call)
+ elif e.errno == errno.ENOENT:
+ raise FileNotFound(filename)
+ raise
+
+ herds = xml_tree.findall('herd')
+ for h in herds:
+ _herd_name = h.find('name')
+ if _herd_name is None:
+ continue
+ herd_name = _herd_name.text.strip()
+ del _herd_name
+
+ maintainers = h.findall('maintainer')
+ herd_emails = set()
+ for m in maintainers:
+ _m_email = m.find('email')
+ if _m_email is None:
+ continue
+ m_email = _m_email.text.strip()
+
+ herd_emails.add(m_email)
+ all_emails.add(m_email)
+
+ herd_to_emails[herd_name] = herd_emails
+
+ return HerdBase(herd_to_emails, all_emails)
+
+
+if __name__ == '__main__':
+ h = make_herd_base('/usr/portage/metadata/herds.xml')
+
+ assert(h.known_herd('sound'))
+ assert(not h.known_herd('media-sound'))
+
+ assert(h.known_maintainer('sping'))
+ assert(h.known_maintainer('sping@gentoo.org'))
+ assert(not h.known_maintainer('portage'))
+
+ assert(h.maintainer_in_herd('zmedico@gentoo.org', 'tools-portage'))
+ assert(not h.maintainer_in_herd('pva@gentoo.org', 'tools-portage'))
+
+ import pprint
+ pprint.pprint(h.herd_to_emails)
diff --git a/portage_with_autodep/pym/repoman/utilities.py b/portage_with_autodep/pym/repoman/utilities.py
new file mode 100644
index 0000000..232739e
--- /dev/null
+++ b/portage_with_autodep/pym/repoman/utilities.py
@@ -0,0 +1,511 @@
+# repoman: Utilities
+# Copyright 2007-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+"""This module contains utility functions to help repoman find ebuilds to
+scan"""
+
+__all__ = [
+ "detect_vcs_conflicts",
+ "editor_is_executable",
+ "FindPackagesToScan",
+ "FindPortdir",
+ "FindVCS",
+ "format_qa_output",
+ "get_commit_message_with_editor",
+ "get_commit_message_with_stdin",
+ "have_profile_dir",
+ "parse_metadata_use",
+ "UnknownHerdsError",
+ "check_metadata"
+]
+
+import errno
+import io
+import logging
+import sys
+from portage import os
+from portage import subprocess_getstatusoutput
+from portage import _encodings
+from portage import _unicode_decode
+from portage import _unicode_encode
+from portage import output
+from portage.localization import _
+from portage.output import red, green
+from portage.process import find_binary
+from portage import exception
+from portage import util
+normalize_path = util.normalize_path
+util.initialize_logger()
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+def detect_vcs_conflicts(options, vcs):
+ """Determine if the checkout has problems like cvs conflicts.
+
+ If you want more vcs support here just keep adding if blocks...
+ This could be better.
+
+ TODO(antarus): Also this should probably not call sys.exit() as
+ repoman is run on >1 packages and one failure should not cause
+ subsequent packages to fail.
+
+ Args:
+ vcs - A string identifying the version control system in use
+ Returns:
+ None (calls sys.exit on fatal problems)
+ """
+ retval = ("","")
+ if vcs == 'cvs':
+ logging.info("Performing a " + output.green("cvs -n up") + \
+ " with a little magic grep to check for updates.")
+ retval = subprocess_getstatusoutput("cvs -n up 2>&1 | " + \
+ "egrep '^[^\?] .*' | " + \
+ "egrep -v '^. .*/digest-[^/]+|^cvs server: .* -- ignored$'")
+ if vcs == 'svn':
+ logging.info("Performing a " + output.green("svn status -u") + \
+ " with a little magic grep to check for updates.")
+ retval = subprocess_getstatusoutput("svn status -u 2>&1 | " + \
+ "egrep -v '^. +.*/digest-[^/]+' | " + \
+ "head -n-1")
+
+ if vcs in ['cvs', 'svn']:
+ mylines = retval[1].splitlines()
+ myupdates = []
+ for line in mylines:
+ if not line:
+ continue
+ if line[0] not in " UPMARD": # unmodified(svn),Updates,Patches,Modified,Added,Removed/Replaced(svn),Deleted(svn)
+ # Stray Manifest is fine, we will readd it anyway.
+ if line[0] == '?' and line[1:].lstrip() == 'Manifest':
+ continue
+ logging.error(red("!!! Please fix the following issues reported " + \
+ "from cvs: ")+green("(U,P,M,A,R,D are ok)"))
+ logging.error(red("!!! Note: This is a pretend/no-modify pass..."))
+ logging.error(retval[1])
+ sys.exit(1)
+ elif vcs == 'cvs' and line[0] in "UP":
+ myupdates.append(line[2:])
+ elif vcs == 'svn' and line[8] == '*':
+ myupdates.append(line[9:].lstrip(" 1234567890"))
+
+ if myupdates:
+ logging.info(green("Fetching trivial updates..."))
+ if options.pretend:
+ logging.info("(" + vcs + " update " + " ".join(myupdates) + ")")
+ retval = os.EX_OK
+ else:
+ retval = os.system(vcs + " update " + " ".join(myupdates))
+ if retval != os.EX_OK:
+ logging.fatal("!!! " + vcs + " exited with an error. Terminating.")
+ sys.exit(retval)
+
+
+def have_profile_dir(path, maxdepth=3, filename="profiles.desc"):
+ """
+ Try to figure out if 'path' has a profiles/
+ dir in it by checking for the given filename.
+ """
+ while path != "/" and maxdepth:
+ if os.path.exists(os.path.join(path, "profiles", filename)):
+ return normalize_path(path)
+ path = normalize_path(path + "/..")
+ maxdepth -= 1
+
+def parse_metadata_use(xml_tree):
+ """
+ Records are wrapped in XML as per GLEP 56
+ returns a dict with keys constisting of USE flag names and values
+ containing their respective descriptions
+ """
+ uselist = {}
+
+ usetags = xml_tree.findall("use")
+ if not usetags:
+ return uselist
+
+ # It's possible to have multiple 'use' elements.
+ for usetag in usetags:
+ flags = usetag.findall("flag")
+ if not flags:
+ # DTD allows use elements containing no flag elements.
+ continue
+
+ for flag in flags:
+ pkg_flag = flag.get("name")
+ if pkg_flag is None:
+ raise exception.ParseError("missing 'name' attribute for 'flag' tag")
+ flag_restrict = flag.get("restrict")
+
+ # emulate the Element.itertext() method from python-2.7
+ inner_text = []
+ stack = []
+ stack.append(flag)
+ while stack:
+ obj = stack.pop()
+ if isinstance(obj, basestring):
+ inner_text.append(obj)
+ continue
+ if isinstance(obj.text, basestring):
+ inner_text.append(obj.text)
+ if isinstance(obj.tail, basestring):
+ stack.append(obj.tail)
+ stack.extend(reversed(obj))
+
+ if pkg_flag not in uselist:
+ uselist[pkg_flag] = {}
+
+ # (flag_restrict can be None)
+ uselist[pkg_flag][flag_restrict] = " ".join("".join(inner_text).split())
+
+ return uselist
+
+class UnknownHerdsError(ValueError):
+ def __init__(self, herd_names):
+ _plural = len(herd_names) != 1
+ super(UnknownHerdsError, self).__init__(
+ 'Unknown %s %s' % (_plural and 'herds' or 'herd',
+ ','.join('"%s"' % e for e in herd_names)))
+
+
+def check_metadata_herds(xml_tree, herd_base):
+ herd_nodes = xml_tree.findall('herd')
+ unknown_herds = [name for name in
+ (e.text.strip() for e in herd_nodes if e.text is not None)
+ if not herd_base.known_herd(name)]
+
+ if unknown_herds:
+ raise UnknownHerdsError(unknown_herds)
+
+def check_metadata(xml_tree, herd_base):
+ if herd_base is not None:
+ check_metadata_herds(xml_tree, herd_base)
+
+def FindPackagesToScan(settings, startdir, reposplit):
+ """ Try to find packages that need to be scanned
+
+ Args:
+ settings - portage.config instance, preferably repoman_settings
+ startdir - directory that repoman was run in
+ reposplit - root of the repository
+ Returns:
+ A list of directories to scan
+ """
+
+
+ def AddPackagesInDir(path):
+ """ Given a list of dirs, add any packages in it """
+ ret = []
+ pkgdirs = os.listdir(path)
+ for d in pkgdirs:
+ if d == 'CVS' or d.startswith('.'):
+ continue
+ p = os.path.join(path, d)
+
+ if os.path.isdir(p):
+ cat_pkg_dir = os.path.join(*p.split(os.path.sep)[-2:])
+ logging.debug('adding %s to scanlist' % cat_pkg_dir)
+ ret.append(cat_pkg_dir)
+ return ret
+
+ scanlist = []
+ repolevel = len(reposplit)
+ if repolevel == 1: # root of the tree, startdir = repodir
+ for cat in settings.categories:
+ path = os.path.join(startdir, cat)
+ if not os.path.isdir(path):
+ continue
+ pkgdirs = os.listdir(path)
+ scanlist.extend(AddPackagesInDir(path))
+ elif repolevel == 2: # category level, startdir = catdir
+ # we only want 1 segment of the directory, is why we use catdir instead of startdir
+ catdir = reposplit[-2]
+ if catdir not in settings.categories:
+ logging.warn('%s is not a valid category according to profiles/categories, ' \
+ 'skipping checks in %s' % (catdir, catdir))
+ else:
+ scanlist = AddPackagesInDir(catdir)
+ elif repolevel == 3: # pkgdir level, startdir = pkgdir
+ catdir = reposplit[-2]
+ pkgdir = reposplit[-1]
+ if catdir not in settings.categories:
+ logging.warn('%s is not a valid category according to profiles/categories, ' \
+ 'skipping checks in %s' % (catdir, catdir))
+ else:
+ path = os.path.join(catdir, pkgdir)
+ logging.debug('adding %s to scanlist' % path)
+ scanlist.append(path)
+ return scanlist
+
+
+def format_qa_output(formatter, stats, fails, dofull, dofail, options, qawarnings):
+ """Helper function that formats output properly
+
+ Args:
+ formatter - a subclass of Formatter
+ stats - a dict of qa status items
+ fails - a dict of qa status failures
+ dofull - boolean to print full results or a summary
+ dofail - boolean to decide if failure was hard or soft
+
+ Returns:
+ None (modifies formatter)
+ """
+ full = options.mode == 'full'
+ # we only want key value pairs where value > 0
+ for category, number in \
+ filter(lambda myitem: myitem[1] > 0, iter(stats.items())):
+ formatter.add_literal_data(_unicode_decode(" " + category.ljust(30)))
+ if category in qawarnings:
+ formatter.push_style("WARN")
+ else:
+ formatter.push_style("BAD")
+ formatter.add_literal_data(_unicode_decode(str(number)))
+ formatter.pop_style()
+ formatter.add_line_break()
+ if not dofull:
+ if not full and dofail and category in qawarnings:
+ # warnings are considered noise when there are failures
+ continue
+ fails_list = fails[category]
+ if not full and len(fails_list) > 12:
+ fails_list = fails_list[:12]
+ for failure in fails_list:
+ formatter.add_literal_data(_unicode_decode(" " + failure))
+ formatter.add_line_break()
+
+
+def editor_is_executable(editor):
+ """
+ Given an EDITOR string, validate that it refers to
+ an executable. This uses shlex_split() to split the
+ first component and do a PATH lookup if necessary.
+
+ @param editor: An EDITOR value from the environment.
+ @type: string
+ @rtype: bool
+ @returns: True if an executable is found, False otherwise.
+ """
+ editor_split = util.shlex_split(editor)
+ if not editor_split:
+ return False
+ filename = editor_split[0]
+ if not os.path.isabs(filename):
+ return find_binary(filename) is not None
+ return os.access(filename, os.X_OK) and os.path.isfile(filename)
+
+
+def get_commit_message_with_editor(editor, message=None):
+ """
+ Execute editor with a temporary file as it's argument
+ and return the file content afterwards.
+
+ @param editor: An EDITOR value from the environment
+ @type: string
+ @param message: An iterable of lines to show in the editor.
+ @type: iterable
+ @rtype: string or None
+ @returns: A string on success or None if an error occurs.
+ """
+ from tempfile import mkstemp
+ fd, filename = mkstemp()
+ try:
+ os.write(fd, _unicode_encode(_(
+ "\n# Please enter the commit message " + \
+ "for your changes.\n# (Comment lines starting " + \
+ "with '#' will not be included)\n"),
+ encoding=_encodings['content'], errors='backslashreplace'))
+ if message:
+ os.write(fd, b"#\n")
+ for line in message:
+ os.write(fd, _unicode_encode("#" + line,
+ encoding=_encodings['content'], errors='backslashreplace'))
+ os.close(fd)
+ retval = os.system(editor + " '%s'" % filename)
+ if not (os.WIFEXITED(retval) and os.WEXITSTATUS(retval) == os.EX_OK):
+ return None
+ try:
+ mylines = io.open(_unicode_encode(filename,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'], errors='replace'
+ ).readlines()
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ return None
+ return "".join(line for line in mylines if not line.startswith("#"))
+ finally:
+ try:
+ os.unlink(filename)
+ except OSError:
+ pass
+
+
+def get_commit_message_with_stdin():
+ """
+ Read a commit message from the user and return it.
+
+ @rtype: string or None
+ @returns: A string on success or None if an error occurs.
+ """
+ print("Please enter a commit message. Use Ctrl-d to finish or Ctrl-c to abort.")
+ commitmessage = []
+ while True:
+ commitmessage.append(sys.stdin.readline())
+ if not commitmessage[-1]:
+ break
+ commitmessage = "".join(commitmessage)
+ return commitmessage
+
+
+def FindPortdir(settings):
+ """ Try to figure out what repo we are in and whether we are in a regular
+ tree or an overlay.
+
+ Basic logic is:
+
+ 1. Determine what directory we are in (supports symlinks).
+ 2. Build a list of directories from / to our current location
+ 3. Iterate over PORTDIR_OVERLAY, if we find a match, search for a profiles directory
+ in the overlay. If it has one, make it portdir, otherwise make it portdir_overlay.
+ 4. If we didn't find an overlay in PORTDIR_OVERLAY, see if we are in PORTDIR; if so, set
+ portdir_overlay to PORTDIR. If we aren't in PORTDIR, see if PWD has a profiles dir, if
+ so, set portdir_overlay and portdir to PWD, else make them False.
+ 5. If we haven't found portdir_overlay yet, it means the user is doing something odd, report
+ an error.
+ 6. If we haven't found a portdir yet, set portdir to PORTDIR.
+
+ Args:
+ settings - portage.config instance, preferably repoman_settings
+ Returns:
+ list(portdir, portdir_overlay, location)
+ """
+
+ portdir = None
+ portdir_overlay = None
+ location = os.getcwd()
+ pwd = os.environ.get('PWD', '')
+ if pwd and pwd != location and os.path.realpath(pwd) == location:
+ # getcwd() returns the canonical path but that makes it hard for repoman to
+ # orient itself if the user has symlinks in their portage tree structure.
+ # We use os.environ["PWD"], if available, to get the non-canonical path of
+ # the current working directory (from the shell).
+ location = pwd
+
+ location = normalize_path(location)
+
+ path_ids = {}
+ p = location
+ s = None
+ while True:
+ s = os.stat(p)
+ path_ids[(s.st_dev, s.st_ino)] = p
+ if p == "/":
+ break
+ p = os.path.dirname(p)
+ if location[-1] != "/":
+ location += "/"
+
+ for overlay in settings["PORTDIR_OVERLAY"].split():
+ overlay = os.path.realpath(overlay)
+ try:
+ s = os.stat(overlay)
+ except OSError:
+ continue
+ overlay = path_ids.get((s.st_dev, s.st_ino))
+ if overlay is None:
+ continue
+ if overlay[-1] != "/":
+ overlay += "/"
+ if True:
+ portdir_overlay = overlay
+ subdir = location[len(overlay):]
+ if subdir and subdir[-1] != "/":
+ subdir += "/"
+ if have_profile_dir(location, subdir.count("/")):
+ portdir = portdir_overlay
+ break
+
+ # Couldn't match location with anything from PORTDIR_OVERLAY,
+ # so fall back to have_profile_dir() checks alone. Assume that
+ # an overlay will contain at least a "repo_name" file while a
+ # master repo (portdir) will contain at least a "profiles.desc"
+ # file.
+ if not portdir_overlay:
+ portdir_overlay = have_profile_dir(location, filename="repo_name")
+ if portdir_overlay:
+ subdir = location[len(portdir_overlay):]
+ if subdir and subdir[-1] != os.sep:
+ subdir += os.sep
+ if have_profile_dir(location, subdir.count(os.sep)):
+ portdir = portdir_overlay
+
+ if not portdir_overlay:
+ if (settings["PORTDIR"] + os.path.sep).startswith(location):
+ portdir_overlay = settings["PORTDIR"]
+ else:
+ portdir_overlay = have_profile_dir(location)
+ portdir = portdir_overlay
+
+ if not portdir_overlay:
+ msg = 'Repoman is unable to determine PORTDIR or PORTDIR_OVERLAY' + \
+ ' from the current working directory'
+ logging.critical(msg)
+ return (None, None, None)
+
+ if not portdir:
+ portdir = settings["PORTDIR"]
+
+ if not portdir_overlay.endswith('/'):
+ portdir_overlay += '/'
+
+ if not portdir.endswith('/'):
+ portdir += '/'
+
+ return [normalize_path(x) for x in (portdir, portdir_overlay, location)]
+
+def FindVCS():
+ """ Try to figure out in what VCS' working tree we are. """
+
+ outvcs = []
+
+ def seek(depth = None):
+ """ Seek for distributed VCSes. """
+ retvcs = []
+ pathprep = ''
+
+ while depth is None or depth > 0:
+ if os.path.isdir(os.path.join(pathprep, '.git')):
+ retvcs.append('git')
+ if os.path.isdir(os.path.join(pathprep, '.bzr')):
+ retvcs.append('bzr')
+ if os.path.isdir(os.path.join(pathprep, '.hg')):
+ retvcs.append('hg')
+
+ if retvcs:
+ break
+ pathprep = os.path.join(pathprep, '..')
+ if os.path.realpath(pathprep).strip('/') == '':
+ break
+ if depth is not None:
+ depth = depth - 1
+
+ return retvcs
+
+ # Level zero VCS-es.
+ if os.path.isdir('CVS'):
+ outvcs.append('cvs')
+ if os.path.isdir('.svn'):
+ outvcs.append('svn')
+
+ # If we already found one of 'level zeros', just take a quick look
+ # at the current directory. Otherwise, seek parents till we get
+ # something or reach root.
+ if outvcs:
+ outvcs.extend(seek(1))
+ else:
+ outvcs = seek()
+
+ return outvcs