aboutsummaryrefslogtreecommitdiff
path: root/0.4.0/paludis
diff options
context:
space:
mode:
Diffstat (limited to '0.4.0/paludis')
-rw-r--r--0.4.0/paludis/Makefile.am.m469
-rw-r--r--0.4.0/paludis/about.hh.in117
-rw-r--r--0.4.0/paludis/about_TEST.cc86
-rw-r--r--0.4.0/paludis/args/Makefile.am46
-rw-r--r--0.4.0/paludis/args/args.cc27
-rw-r--r--0.4.0/paludis/args/args.hh35
-rw-r--r--0.4.0/paludis/args/args_TEST.cc161
-rw-r--r--0.4.0/paludis/args/args_dumper.cc81
-rw-r--r--0.4.0/paludis/args/args_dumper.hh79
-rw-r--r--0.4.0/paludis/args/args_error.cc35
-rw-r--r--0.4.0/paludis/args/args_error.hh53
-rw-r--r--0.4.0/paludis/args/args_group.cc47
-rw-r--r--0.4.0/paludis/args/args_group.hh98
-rw-r--r--0.4.0/paludis/args/args_handler.cc129
-rw-r--r--0.4.0/paludis/args/args_handler.hh129
-rw-r--r--0.4.0/paludis/args/args_option.cc134
-rw-r--r--0.4.0/paludis/args/args_option.hh359
-rw-r--r--0.4.0/paludis/args/args_visitor.cc97
-rw-r--r--0.4.0/paludis/args/args_visitor.hh96
-rw-r--r--0.4.0/paludis/args/bad_argument.cc35
-rw-r--r--0.4.0/paludis/args/bad_argument.hh53
-rw-r--r--0.4.0/paludis/args/bad_value.cc32
-rw-r--r--0.4.0/paludis/args/bad_value.hh53
-rw-r--r--0.4.0/paludis/args/missing_value.cc36
-rw-r--r--0.4.0/paludis/args/missing_value.hh55
-rw-r--r--0.4.0/paludis/config_file.cc473
-rw-r--r--0.4.0/paludis/config_file.hh504
-rw-r--r--0.4.0/paludis/config_file_TEST.cc305
-rwxr-xr-x0.4.0/paludis/config_file_TEST_cleanup.sh10
-rwxr-xr-x0.4.0/paludis/config_file_TEST_setup.sh9
-rw-r--r--0.4.0/paludis/contents.cc58
-rw-r--r--0.4.0/paludis/contents.hh173
-rw-r--r--0.4.0/paludis/default_config.cc654
-rw-r--r--0.4.0/paludis/default_config.hh365
-rw-r--r--0.4.0/paludis/default_environment.cc514
-rw-r--r--0.4.0/paludis/default_environment.hh82
-rw-r--r--0.4.0/paludis/dep_atom.cc289
-rw-r--r--0.4.0/paludis/dep_atom.hh487
-rw-r--r--0.4.0/paludis/dep_atom_TEST.cc169
-rw-r--r--0.4.0/paludis/dep_atom_dumper.cc86
-rw-r--r--0.4.0/paludis/dep_atom_dumper.hh69
-rw-r--r--0.4.0/paludis/dep_atom_dumper_TEST.cc65
-rw-r--r--0.4.0/paludis/dep_atom_flattener.cc90
-rw-r--r--0.4.0/paludis/dep_atom_flattener.hh106
-rw-r--r--0.4.0/paludis/dep_atom_pretty_printer.cc91
-rw-r--r--0.4.0/paludis/dep_atom_pretty_printer.hh82
-rw-r--r--0.4.0/paludis/dep_list.cc852
-rw-r--r--0.4.0/paludis/dep_list.hh419
-rw-r--r--0.4.0/paludis/dep_list_TEST.cc1377
-rw-r--r--0.4.0/paludis/dep_tag.cc146
-rw-r--r--0.4.0/paludis/dep_tag.hh245
-rw-r--r--0.4.0/paludis/digests/Makefile.am41
-rw-r--r--0.4.0/paludis/digests/md5.cc239
-rw-r--r--0.4.0/paludis/digests/md5.hh50
-rw-r--r--0.4.0/paludis/digests/md5_TEST.cc94
-rw-r--r--0.4.0/paludis/digests/rmd160.cc231
-rw-r--r--0.4.0/paludis/digests/rmd160.hh54
-rw-r--r--0.4.0/paludis/digests/rmd160_TEST.cc96
-rw-r--r--0.4.0/paludis/digests/sha256.cc228
-rw-r--r--0.4.0/paludis/digests/sha256.hh50
-rw-r--r--0.4.0/paludis/digests/sha256_TEST.cc420
-rw-r--r--0.4.0/paludis/ebuild.cc374
-rw-r--r--0.4.0/paludis/ebuild.hh462
-rw-r--r--0.4.0/paludis/environment.cc432
-rw-r--r--0.4.0/paludis/environment.hh229
-rw-r--r--0.4.0/paludis/fake_repository.cc273
-rw-r--r--0.4.0/paludis/fake_repository.hh147
-rw-r--r--0.4.0/paludis/files.m443
-rw-r--r--0.4.0/paludis/hashed_containers.cc108
-rw-r--r--0.4.0/paludis/hashed_containers.hh.in293
-rw-r--r--0.4.0/paludis/hashed_containers_TEST.cc50
-rw-r--r--0.4.0/paludis/mask_reasons.cc72
-rw-r--r--0.4.0/paludis/mask_reasons.hh70
-rw-r--r--0.4.0/paludis/match_package.cc135
-rw-r--r--0.4.0/paludis/match_package.hh149
-rw-r--r--0.4.0/paludis/name.cc273
-rw-r--r--0.4.0/paludis/name.hh438
-rw-r--r--0.4.0/paludis/name_TEST.cc209
-rw-r--r--0.4.0/paludis/nothing_repository.cc257
-rw-r--r--0.4.0/paludis/nothing_repository.hh167
-rw-r--r--0.4.0/paludis/package_database.cc245
-rw-r--r--0.4.0/paludis/package_database.hh341
-rw-r--r--0.4.0/paludis/package_database_TEST.cc197
-rw-r--r--0.4.0/paludis/package_database_entry.hh69
-rw-r--r--0.4.0/paludis/paludis.cc21
-rw-r--r--0.4.0/paludis/paludis.hh.m441
-rw-r--r--0.4.0/paludis/portage_dep_lexer.cc79
-rw-r--r--0.4.0/paludis/portage_dep_lexer.hh130
-rw-r--r--0.4.0/paludis/portage_dep_lexer_TEST.cc250
-rw-r--r--0.4.0/paludis/portage_dep_parser.cc286
-rw-r--r--0.4.0/paludis/portage_dep_parser.hh197
-rw-r--r--0.4.0/paludis/portage_dep_parser_TEST.cc257
-rw-r--r--0.4.0/paludis/portage_repository.cc2301
-rw-r--r--0.4.0/paludis/portage_repository.hh305
-rw-r--r--0.4.0/paludis/portage_repository_TEST.cc615
-rwxr-xr-x0.4.0/paludis/portage_repository_TEST_cleanup.sh10
-rwxr-xr-x0.4.0/paludis/portage_repository_TEST_setup.sh203
-rw-r--r--0.4.0/paludis/qa/Makefile.am.m464
-rw-r--r--0.4.0/paludis/qa/changelog_check.cc75
-rw-r--r--0.4.0/paludis/qa/changelog_check.hh51
-rw-r--r--0.4.0/paludis/qa/check.cc32
-rw-r--r--0.4.0/paludis/qa/check.hh60
-rw-r--r--0.4.0/paludis/qa/check_result.cc44
-rw-r--r--0.4.0/paludis/qa/check_result.hh93
-rw-r--r--0.4.0/paludis/qa/check_result_TEST.cc52
-rw-r--r--0.4.0/paludis/qa/create_metadata_check.cc64
-rw-r--r--0.4.0/paludis/qa/create_metadata_check.hh56
-rw-r--r--0.4.0/paludis/qa/defaults_check.cc165
-rw-r--r--0.4.0/paludis/qa/defaults_check.hh55
-rw-r--r--0.4.0/paludis/qa/dep_any_check.cc141
-rw-r--r--0.4.0/paludis/qa/dep_any_check.hh51
-rw-r--r--0.4.0/paludis/qa/dep_flags_check.cc161
-rw-r--r--0.4.0/paludis/qa/dep_flags_check.hh51
-rw-r--r--0.4.0/paludis/qa/dep_packages_check.cc146
-rw-r--r--0.4.0/paludis/qa/dep_packages_check.hh51
-rw-r--r--0.4.0/paludis/qa/deps_exist_check.cc137
-rw-r--r--0.4.0/paludis/qa/deps_exist_check.hh51
-rw-r--r--0.4.0/paludis/qa/deps_visible_check.cc140
-rw-r--r--0.4.0/paludis/qa/deps_visible_check.hh51
-rw-r--r--0.4.0/paludis/qa/description_check.cc79
-rw-r--r--0.4.0/paludis/qa/description_check.hh51
-rw-r--r--0.4.0/paludis/qa/digest_collisions_check.cc105
-rw-r--r--0.4.0/paludis/qa/digest_collisions_check.hh51
-rw-r--r--0.4.0/paludis/qa/ebuild_check.cc33
-rw-r--r--0.4.0/paludis/qa/ebuild_check.hh91
-rw-r--r--0.4.0/paludis/qa/ebuild_count.cc58
-rw-r--r--0.4.0/paludis/qa/ebuild_count.hh51
-rw-r--r--0.4.0/paludis/qa/environment.cc75
-rw-r--r--0.4.0/paludis/qa/environment.hh104
-rw-r--r--0.4.0/paludis/qa/extract_check.cc126
-rw-r--r--0.4.0/paludis/qa/extract_check.hh51
-rw-r--r--0.4.0/paludis/qa/file_check.cc33
-rw-r--r--0.4.0/paludis/qa/file_check.hh86
-rw-r--r--0.4.0/paludis/qa/file_name_check.cc53
-rw-r--r--0.4.0/paludis/qa/file_name_check.hh56
-rw-r--r--0.4.0/paludis/qa/file_permissions_check.cc60
-rw-r--r--0.4.0/paludis/qa/file_permissions_check.hh51
-rw-r--r--0.4.0/paludis/qa/file_permissions_check_TEST.cc90
-rwxr-xr-x0.4.0/paludis/qa/file_permissions_check_TEST_cleanup.sh11
-rwxr-xr-x0.4.0/paludis/qa/file_permissions_check_TEST_setup.sh14
-rw-r--r--0.4.0/paludis/qa/files.m450
-rw-r--r--0.4.0/paludis/qa/files_dir_size_check.cc87
-rw-r--r--0.4.0/paludis/qa/files_dir_size_check.hh51
-rw-r--r--0.4.0/paludis/qa/glep_31_check.cc126
-rw-r--r--0.4.0/paludis/qa/glep_31_check.hh55
-rw-r--r--0.4.0/paludis/qa/glep_31_check_TEST.cc77
-rw-r--r--0.4.0/paludis/qa/has_ebuilds_check.cc50
-rw-r--r--0.4.0/paludis/qa/has_ebuilds_check.hh51
-rw-r--r--0.4.0/paludis/qa/has_ebuilds_check_TEST.cc66
-rwxr-xr-x0.4.0/paludis/qa/has_ebuilds_check_TEST_cleanup.sh11
-rwxr-xr-x0.4.0/paludis/qa/has_ebuilds_check_TEST_setup.sh12
-rw-r--r--0.4.0/paludis/qa/has_misc_files_check.cc54
-rw-r--r--0.4.0/paludis/qa/has_misc_files_check.hh51
-rw-r--r--0.4.0/paludis/qa/has_misc_files_check_TEST.cc102
-rwxr-xr-x0.4.0/paludis/qa/has_misc_files_check_TEST_cleanup.sh12
-rwxr-xr-x0.4.0/paludis/qa/has_misc_files_check_TEST_setup.sh23
-rw-r--r--0.4.0/paludis/qa/homepage_check.cc71
-rw-r--r--0.4.0/paludis/qa/homepage_check.hh51
-rw-r--r--0.4.0/paludis/qa/inherits_check.cc89
-rw-r--r--0.4.0/paludis/qa/inherits_check.hh51
-rw-r--r--0.4.0/paludis/qa/iuse_check.cc92
-rw-r--r--0.4.0/paludis/qa/iuse_check.hh56
-rw-r--r--0.4.0/paludis/qa/keywords_check.cc81
-rw-r--r--0.4.0/paludis/qa/keywords_check.hh51
-rw-r--r--0.4.0/paludis/qa/license_check.cc138
-rw-r--r--0.4.0/paludis/qa/license_check.hh51
-rw-r--r--0.4.0/paludis/qa/message.cc24
-rw-r--r--0.4.0/paludis/qa/message.hh65
-rw-r--r--0.4.0/paludis/qa/message_TEST.cc42
-rw-r--r--0.4.0/paludis/qa/metadata_check.cc91
-rw-r--r--0.4.0/paludis/qa/metadata_check.hh51
-rw-r--r--0.4.0/paludis/qa/package_dir_check.cc33
-rw-r--r--0.4.0/paludis/qa/package_dir_check.hh80
-rw-r--r--0.4.0/paludis/qa/package_name_check.cc62
-rw-r--r--0.4.0/paludis/qa/package_name_check.hh56
-rw-r--r--0.4.0/paludis/qa/package_name_check_TEST.cc104
-rwxr-xr-x0.4.0/paludis/qa/package_name_check_TEST_cleanup.sh11
-rwxr-xr-x0.4.0/paludis/qa/package_name_check_TEST_setup.sh14
-rw-r--r--0.4.0/paludis/qa/parse_deps_check.cc95
-rw-r--r--0.4.0/paludis/qa/parse_deps_check.hh56
-rw-r--r--0.4.0/paludis/qa/pdepend_overlap_check.cc141
-rw-r--r--0.4.0/paludis/qa/pdepend_overlap_check.hh51
-rw-r--r--0.4.0/paludis/qa/qa.cc21
-rw-r--r--0.4.0/paludis/qa/qa.hh.m438
-rw-r--r--0.4.0/paludis/qa/restrict_check.cc95
-rw-r--r--0.4.0/paludis/qa/restrict_check.hh51
-rw-r--r--0.4.0/paludis/qa/slot_check.cc71
-rw-r--r--0.4.0/paludis/qa/slot_check.hh51
-rw-r--r--0.4.0/paludis/qa/src_uri_check.cc185
-rw-r--r--0.4.0/paludis/qa/src_uri_check.hh51
-rw-r--r--0.4.0/paludis/qa/whitespace_check.cc123
-rw-r--r--0.4.0/paludis/qa/whitespace_check.hh51
-rw-r--r--0.4.0/paludis/repository.cc113
-rw-r--r--0.4.0/paludis/repository.hh928
-rw-r--r--0.4.0/paludis/selinux/Makefile.am23
-rw-r--r--0.4.0/paludis/selinux/security_context.cc241
-rw-r--r--0.4.0/paludis/selinux/security_context.hh153
-rw-r--r--0.4.0/paludis/syncer.cc244
-rw-r--r--0.4.0/paludis/syncer.hh162
-rw-r--r--0.4.0/paludis/test_environment.cc64
-rw-r--r--0.4.0/paludis/test_environment.hh99
-rw-r--r--0.4.0/paludis/test_extras.cc81
-rw-r--r--0.4.0/paludis/util/Makefile.am.m467
-rw-r--r--0.4.0/paludis/util/attributes.hh54
-rw-r--r--0.4.0/paludis/util/collection.hh294
-rw-r--r--0.4.0/paludis/util/compare.hh160
-rw-r--r--0.4.0/paludis/util/comparison_policy.hh.m4444
-rw-r--r--0.4.0/paludis/util/comparison_policy_TEST.cc44
-rw-r--r--0.4.0/paludis/util/composite_pattern.hh66
-rw-r--r--0.4.0/paludis/util/container_entry.hh77
-rw-r--r--0.4.0/paludis/util/container_entry_TEST.cc65
-rw-r--r--0.4.0/paludis/util/counted_ptr.cc28
-rw-r--r--0.4.0/paludis/util/counted_ptr.hh606
-rw-r--r--0.4.0/paludis/util/counted_ptr_TEST.cc390
-rw-r--r--0.4.0/paludis/util/deleter.cc32
-rw-r--r--0.4.0/paludis/util/deleter.hh57
-rw-r--r--0.4.0/paludis/util/deleter_TEST.cc85
-rw-r--r--0.4.0/paludis/util/destringify.cc34
-rw-r--r--0.4.0/paludis/util/destringify.hh149
-rw-r--r--0.4.0/paludis/util/destringify_TEST.cc113
-rw-r--r--0.4.0/paludis/util/dir_iterator.cc143
-rw-r--r--0.4.0/paludis/util/dir_iterator.hh127
-rw-r--r--0.4.0/paludis/util/dir_iterator_TEST.cc97
-rwxr-xr-x0.4.0/paludis/util/dir_iterator_TEST_cleanup.sh9
-rwxr-xr-x0.4.0/paludis/util/dir_iterator_TEST_setup.sh6
-rw-r--r--0.4.0/paludis/util/exception.cc64
-rw-r--r--0.4.0/paludis/util/exception.hh158
-rw-r--r--0.4.0/paludis/util/files.m441
-rw-r--r--0.4.0/paludis/util/fs_entry.cc439
-rw-r--r--0.4.0/paludis/util/fs_entry.hh319
-rw-r--r--0.4.0/paludis/util/fs_entry_TEST.cc242
-rwxr-xr-x0.4.0/paludis/util/fs_entry_TEST_cleanup.sh9
-rwxr-xr-x0.4.0/paludis/util/fs_entry_TEST_setup.sh17
-rw-r--r--0.4.0/paludis/util/instantiation_policy.hh207
-rw-r--r--0.4.0/paludis/util/instantiation_policy_TEST.cc136
-rw-r--r--0.4.0/paludis/util/is_file_with_extension.cc44
-rw-r--r--0.4.0/paludis/util/is_file_with_extension.hh75
-rw-r--r--0.4.0/paludis/util/is_file_with_extension_TEST.cc94
-rwxr-xr-x0.4.0/paludis/util/is_file_with_extension_TEST_cleanup.sh9
-rwxr-xr-x0.4.0/paludis/util/is_file_with_extension_TEST_setup.sh6
-rw-r--r--0.4.0/paludis/util/iterator.hh536
-rw-r--r--0.4.0/paludis/util/iterator_TEST.cc339
-rw-r--r--0.4.0/paludis/util/join.hh67
-rw-r--r--0.4.0/paludis/util/join_TEST.cc102
-rw-r--r--0.4.0/paludis/util/log.cc151
-rw-r--r--0.4.0/paludis/util/log.hh121
-rw-r--r--0.4.0/paludis/util/log_TEST.cc74
-rw-r--r--0.4.0/paludis/util/private_implementation_pattern.hh70
-rw-r--r--0.4.0/paludis/util/pstream.cc99
-rw-r--r--0.4.0/paludis/util/pstream.hh193
-rw-r--r--0.4.0/paludis/util/pstream_TEST.cc111
-rw-r--r--0.4.0/paludis/util/random.cc43
-rw-r--r--0.4.0/paludis/util/random.hh61
-rw-r--r--0.4.0/paludis/util/random_TEST.cc121
-rw-r--r--0.4.0/paludis/util/save.hh78
-rw-r--r--0.4.0/paludis/util/save_TEST.cc68
-rw-r--r--0.4.0/paludis/util/smart_record.hh.m4924
-rw-r--r--0.4.0/paludis/util/smart_record_TEST.cc200
-rw-r--r--0.4.0/paludis/util/stringify.hh168
-rw-r--r--0.4.0/paludis/util/stringify_TEST.cc129
-rw-r--r--0.4.0/paludis/util/strip.cc99
-rw-r--r--0.4.0/paludis/util/strip.hh127
-rw-r--r--0.4.0/paludis/util/strip_TEST.cc123
-rw-r--r--0.4.0/paludis/util/system.cc186
-rw-r--r--0.4.0/paludis/util/system.hh148
-rw-r--r--0.4.0/paludis/util/system_TEST.cc183
-rwxr-xr-x0.4.0/paludis/util/system_TEST_cleanup.sh9
-rwxr-xr-x0.4.0/paludis/util/system_TEST_setup.sh5
-rw-r--r--0.4.0/paludis/util/test_extras.cc65
-rw-r--r--0.4.0/paludis/util/tokeniser.cc28
-rw-r--r--0.4.0/paludis/util/tokeniser.hh243
-rw-r--r--0.4.0/paludis/util/tokeniser_TEST.cc139
-rw-r--r--0.4.0/paludis/util/util.hh.m442
-rw-r--r--0.4.0/paludis/util/validated.hh111
-rw-r--r--0.4.0/paludis/util/validated_TEST.cc126
-rw-r--r--0.4.0/paludis/util/virtual_constructor.hh243
-rw-r--r--0.4.0/paludis/util/virtual_constructor_TEST.cc190
-rw-r--r--0.4.0/paludis/util/visitor.hh297
-rw-r--r--0.4.0/paludis/util/visitor_TEST.cc168
-rw-r--r--0.4.0/paludis/vdb_repository.cc1056
-rw-r--r--0.4.0/paludis/vdb_repository.hh224
-rw-r--r--0.4.0/paludis/vdb_repository_TEST.cc112
-rwxr-xr-x0.4.0/paludis/vdb_repository_TEST_cleanup.sh11
-rwxr-xr-x0.4.0/paludis/vdb_repository_TEST_setup.sh17
-rw-r--r--0.4.0/paludis/version_metadata.cc125
-rw-r--r--0.4.0/paludis/version_metadata.hh286
-rw-r--r--0.4.0/paludis/version_operator.cc142
-rw-r--r--0.4.0/paludis/version_operator.hh148
-rw-r--r--0.4.0/paludis/version_operator_TEST.cc114
-rw-r--r--0.4.0/paludis/version_spec.cc422
-rw-r--r--0.4.0/paludis/version_spec.hh135
-rw-r--r--0.4.0/paludis/version_spec_TEST.cc313
292 files changed, 43942 insertions, 0 deletions
diff --git a/0.4.0/paludis/Makefile.am.m4 b/0.4.0/paludis/Makefile.am.m4
new file mode 100644
index 000000000..7117e16be
--- /dev/null
+++ b/0.4.0/paludis/Makefile.am.m4
@@ -0,0 +1,69 @@
+ifdef(`__gnu__',`',`errprint(`This is not GNU m4...
+')m4exit(1)') include(`misc/generated-file.txt')
+
+dnl vim: set ft=m4 noet :
+
+define(`filelist', `')dnl
+define(`testlist', `')dnl
+define(`headerlist', `')dnl
+define(`testscriptlist', `')dnl
+define(`addtest', `define(`testlist', testlist `$1_TEST')dnl
+$1_TEST_SOURCES = $1_TEST.cc
+$1_TEST_LDADD = $(top_builddir)/paludis/util/test_extras.o \
+ $(top_builddir)/test/libtest.a \
+ libpaludis.a \
+ $(top_builddir)/paludis/util/libpaludisutil.a
+$1_TEST_CXXFLAGS = -I$(top_srcdir)
+')dnl
+define(`addtestscript', `define(`testscriptlist', testscriptlist `$1_TEST_setup.sh $1_TEST_cleanup.sh')')dnl
+define(`addhh', `define(`filelist', filelist `$1.hh')define(`headerlist', headerlist `$1.hh')')dnl
+define(`addcc', `define(`filelist', filelist `$1.cc')')dnl
+define(`addimpl', `define(`filelist', filelist `$1-impl.hh')')dnl
+define(`addthis', `dnl
+ifelse(`$2', `hh', `addhh(`$1')', `')dnl
+ifelse(`$2', `cc', `addcc(`$1')', `')dnl
+ifelse(`$2', `impl', `addimpl(`$1')', `')dnl
+ifelse(`$2', `test', `addtest(`$1')', `')dnl
+ifelse(`$2', `testscript', `addtestscript(`$1')', `')')dnl
+define(`add', `addthis(`$1',`$2')addthis(`$1',`$3')addthis(`$1',`$4')dnl
+addthis(`$1',`$5')addthis(`$1',`$6')')dnl
+
+include(`paludis/files.m4')
+
+CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda
+MAINTAINERCLEANFILES = Makefile.in Makefile.am about.hh paludis.hh \
+ hashed_containers.hh
+AM_CXXFLAGS = -I$(top_srcdir)
+DEFS= \
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -DLIBEXECDIR=\"$(libexecdir)\" \
+ -DDATADIR=\"$(datadir)\"
+EXTRA_DIST = about.hh.in Makefile.am.m4 paludis.hh.m4 files.m4 \
+ hashed_containers.hh.in testscriptlist
+SUBDIRS = digests util . args qa selinux
+
+libpaludis_a_SOURCES = filelist
+
+TESTS = testlist
+
+TESTS_ENVIRONMENT = env \
+ PALUDIS_EBUILD_DIR="$(top_srcdir)/ebuild/" \
+ PALUDIS_SKIP_CONFIG="yes" \
+ TEST_SCRIPT_DIR="$(srcdir)/" \
+ bash $(top_srcdir)/test/run_test.sh
+
+check_PROGRAMS = $(TESTS)
+check_SCRIPTS = testscriptlist
+lib_LIBRARIES = libpaludis.a
+paludis_includedir = $(includedir)/paludis/
+paludis_include_HEADERS = headerlist
+
+Makefile.am : Makefile.am.m4 files.m4
+ $(top_srcdir)/misc/do_m4.bash Makefile.am
+
+paludis.hh : paludis.hh.m4 files.m4
+ $(top_srcdir)/misc/do_m4.bash paludis.hh
+
+comparison_policy.hh : comparison_policy.hh.m4
+ $(top_srcdir)/misc/do_m4.bash comparison_policy.hh.m4
+
diff --git a/0.4.0/paludis/about.hh.in b/0.4.0/paludis/about.hh.in
new file mode 100644
index 000000000..cd171ec23
--- /dev/null
+++ b/0.4.0/paludis/about.hh.in
@@ -0,0 +1,117 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+@GENERATED_FILE@
+
+#ifndef PALUDIS_GUARD_PALUDIS_ABOUT_HH
+#define PALUDIS_GUARD_PALUDIS_ABOUT_HH 1
+
+/** \file
+ * Defines constants giving the Paludis version number and information about
+ * how Paludis was built.
+ *
+ * \ingroup grpabout
+ */
+
+/**
+ * The package name (eg Paludis).
+ *
+ * \ingroup grpabout
+ */
+#define PALUDIS_PACKAGE "@PACKAGE@"
+
+/**
+ * The major version (eg 0.4.1 -> 0).
+ *
+ * \ingroup grpabout
+ */
+#define PALUDIS_VERSION_MAJOR @VERSION_MAJOR@
+
+/**
+ * The minor version (eg 0.4.1 -> 4).
+ *
+ * \ingroup grpabout
+ */
+#define PALUDIS_VERSION_MINOR @VERSION_MINOR@
+
+/**
+ * The micro version (eg 0.4.1 -> 1).
+ *
+ * \ingroup grpabout
+ */
+#define PALUDIS_VERSION_MICRO @VERSION_MICRO@
+
+/**
+ * The version, two digits per part (eg 1.3.5 -> 10305).
+ *
+ * \ingroup grpabout
+ */
+#define PALUDIS_VERSION ((100 * 100 * PALUDIS_VERSION_MAJOR) \
+ + (100 * PALUDIS_VERSION_MINOR) + PALUDIS_VERSION_MICRO)
+
+/**
+ * The subversion revision, if applicable (eg "65" or "65M" or "").
+ *
+ * \ingroup grpabout
+ */
+#define PALUDIS_SUBVERSION_REVISION "@SVNVERSION@"
+
+/**
+ * The CXXFLAGS used to build Paludis.
+ *
+ * \ingroup grpabout
+ */
+#define PALUDIS_BUILD_CXXFLAGS "@CXXFLAGS@"
+
+/**
+ * The LDFLAGS used to build Paludis.
+ *
+ * \ingroup grpabout
+ */
+#define PALUDIS_BUILD_LDFLAGS "@LDFLAGS@"
+
+/**
+ * The compiler used to build Paludis.
+ *
+ * \ingroup grpabout
+ */
+#define PALUDIS_BUILD_CXX "@CXX@"
+
+/**
+ * The user who built Paludis.
+ *
+ * \ingroup grpabout
+ */
+#define PALUDIS_BUILD_USER "@BUILDUSER@"
+
+/**
+ * The host on which Paludis was built.
+ *
+ * \ingroup grpabout
+ */
+#define PALUDIS_BUILD_HOST "@BUILDHOST@"
+
+/**
+ * The date when Paludis was built.
+ *
+ * \ingroup grpabout
+ */
+#define PALUDIS_BUILD_DATE "@BUILDDATE@"
+
+#endif
diff --git a/0.4.0/paludis/about_TEST.cc b/0.4.0/paludis/about_TEST.cc
new file mode 100644
index 000000000..512647643
--- /dev/null
+++ b/0.4.0/paludis/about_TEST.cc
@@ -0,0 +1,86 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/about.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+using namespace paludis;
+
+/**
+ * \file
+ * Test cases for about.hh .
+ *
+ * \ingroup grptestcases
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Version tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct VersionTest : TestCase
+ {
+ VersionTest() : TestCase("about test") { }
+
+ void run()
+ {
+ TEST_CHECK(PALUDIS_VERSION_MAJOR >= 0);
+ TEST_CHECK(PALUDIS_VERSION_MAJOR <= 9);
+
+ TEST_CHECK(PALUDIS_VERSION_MINOR >= 0);
+ TEST_CHECK(PALUDIS_VERSION_MINOR <= 99);
+
+ TEST_CHECK(PALUDIS_VERSION_MICRO >= 0);
+ TEST_CHECK(PALUDIS_VERSION_MICRO <= 99);
+
+ TEST_CHECK(PALUDIS_VERSION >= 0);
+ TEST_CHECK(PALUDIS_VERSION <= 99999);
+ TEST_CHECK_EQUAL(PALUDIS_VERSION, 10000 * PALUDIS_VERSION_MAJOR +
+ 100 * PALUDIS_VERSION_MINOR + PALUDIS_VERSION_MICRO);
+
+ TEST_CHECK(std::string(PALUDIS_SUBVERSION_REVISION) != "i am a fish");
+ }
+ } test_case_about;
+
+ /**
+ * \test Build info tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct BuildInfoTest : TestCase
+ {
+ BuildInfoTest() : TestCase("build info test") { }
+
+ void run()
+ {
+ TEST_CHECK(! std::string(PALUDIS_BUILD_CXX).empty());
+ TEST_CHECK(! std::string(PALUDIS_BUILD_CXXFLAGS).empty());
+ TEST_CHECK(std::string(PALUDIS_BUILD_LDFLAGS) != "i am a fish");
+
+ TEST_CHECK(! std::string(PALUDIS_BUILD_USER).empty());
+ TEST_CHECK(! std::string(PALUDIS_BUILD_HOST).empty());
+ TEST_CHECK(! std::string(PALUDIS_BUILD_DATE).empty());
+ }
+ } test_case_build_info;
+}
+
diff --git a/0.4.0/paludis/args/Makefile.am b/0.4.0/paludis/args/Makefile.am
new file mode 100644
index 000000000..ddfdac14f
--- /dev/null
+++ b/0.4.0/paludis/args/Makefile.am
@@ -0,0 +1,46 @@
+CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda
+MAINTAINERCLEANFILES = Makefile.in
+AM_CXXFLAGS = -I$(top_srcdir)
+
+TESTS = \
+ args_TEST
+
+paludis_args_includedir = $(includedir)/paludis/args/
+
+paludis_args_include_HEADERS = \
+ args.hh \
+ args_error.hh \
+ args_group.hh \
+ args_handler.hh \
+ args_option.hh \
+ bad_argument.hh \
+ args_visitor.hh \
+ bad_value.hh \
+ missing_value.hh \
+ args_dumper.hh
+
+libpaludisargs_a_SOURCES = $(paludis_args_include_HEADERS) \
+ args.cc \
+ args_error.cc \
+ args_group.cc \
+ args_handler.cc \
+ args_option.cc \
+ bad_argument.cc \
+ args_visitor.cc \
+ bad_value.cc \
+ missing_value.cc \
+ args_dumper.cc
+
+TESTS_ENVIRONMENT = env -u PALUDIS_OPTIONS TEST_SCRIPT_DIR="$(srcdir)/" bash $(top_srcdir)/test/run_test.sh
+lib_LIBRARIES = libpaludisargs.a
+check_PROGRAMS = $(TESTS)
+
+test_ldadd = \
+ $(top_builddir)/test/libtest.a \
+ libpaludisargs.a \
+ $(top_builddir)/paludis/libpaludis.a \
+ $(top_builddir)/paludis/util/libpaludisutil.a
+
+args_TEST_SOURCES = args_TEST.cc
+args_TEST_LDADD = $(test_ldadd)
+
diff --git a/0.4.0/paludis/args/args.cc b/0.4.0/paludis/args/args.cc
new file mode 100644
index 000000000..fac59ce90
--- /dev/null
+++ b/0.4.0/paludis/args/args.cc
@@ -0,0 +1,27 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "args.hh"
+
+/** \file
+ * Implementation for args.hh .
+ *
+ * \ingroup grplibpaludisargs
+ */
+
diff --git a/0.4.0/paludis/args/args.hh b/0.4.0/paludis/args/args.hh
new file mode 100644
index 000000000..ce54edae0
--- /dev/null
+++ b/0.4.0/paludis/args/args.hh
@@ -0,0 +1,35 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_ARGS_ARGS_HH
+#define PALUDIS_GUARD_ARGS_ARGS_HH 1
+
+/** \file
+ * Master include file for command line argument handling.
+ *
+ * \ingroup grplibpaludisargs
+ */
+
+#include <paludis/args/args_error.hh>
+#include <paludis/args/args_group.hh>
+#include <paludis/args/args_handler.hh>
+#include <paludis/args/args_option.hh>
+#include <paludis/args/bad_argument.hh>
+
+#endif
diff --git a/0.4.0/paludis/args/args_TEST.cc b/0.4.0/paludis/args/args_TEST.cc
new file mode 100644
index 000000000..d94c7dd13
--- /dev/null
+++ b/0.4.0/paludis/args/args_TEST.cc
@@ -0,0 +1,161 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/args/args.hh>
+#include <paludis/args/missing_value.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace paludis;
+using namespace paludis::args;
+using namespace test;
+
+/** \file
+ * Test cases for paludis::args things.
+ *
+ * \ingroup grptestcases
+ */
+
+#ifndef DOXYGEN
+
+struct CommandLine : public ArgsHandler
+{
+ ArgsGroup group_one;
+ SwitchArg arg_foo;
+ SwitchArg arg_bar;
+ SwitchArg arg_dummy;
+
+ ArgsGroup group_two;
+ SwitchArg arg_baz;
+ AliasArg arg_other_baz;
+ StringArg arg_something;
+ IntegerArg arg_somenum;
+ EnumArg arg_enum;
+
+ ArgsGroup group_three;
+ EnumArg arg_other_enum;
+ StringSetArg arg_stringset;
+
+ CommandLine();
+ ~CommandLine();
+};
+
+CommandLine::CommandLine() :
+ group_one(this, "Group one"),
+ arg_foo(&group_one, "foo", 'f', "Enable foo"),
+ arg_bar(&group_one, "bar", 'b', "Enable bar"),
+ arg_dummy(&group_one, "dummy", 'd', "Enable something else"),
+
+ group_two(this, "Group two"),
+ arg_baz(&group_two, "baz", 'z', "Enable baz"),
+ arg_other_baz(&arg_baz, "other-baz"),
+ arg_something(&group_two, "something", 's', "Value of something"),
+ arg_somenum(&group_two, "num", 'n', "Some number"),
+ arg_enum(&group_two, "enum", 'e', "One of three", EnumArg::EnumArgOptions("one", "Option one")("two", "option two")("three", "option three"), "two"),
+
+ group_three(this, "Group three"),
+ arg_other_enum(&group_three, "something", '\0', "Blah.", EnumArg::EnumArgOptions("a", "A")("b", "B")("c", "C"), "b"),
+ arg_stringset(&group_three, "stringset", 't', "A StringSet.")
+{
+}
+
+CommandLine::~CommandLine()
+{
+}
+
+#endif
+
+namespace test_cases
+{
+ /**
+ * \test Simple args tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct ArgsTestSimple : TestCase
+ {
+ ArgsTestSimple() : TestCase("simple") { }
+
+ void run()
+ {
+ char * args[] = { "program-name", "--other-baz", "-fsne", "blah", "7", "three", "--", "--dummy",
+ "one", "two" };
+ CommandLine c1;
+ c1.run(10, args);
+ TEST_CHECK(c1.arg_foo.specified());
+ TEST_CHECK(! c1.arg_bar.specified());
+ TEST_CHECK(c1.arg_baz.specified());
+ TEST_CHECK(c1.arg_other_baz.specified());
+ TEST_CHECK(c1.arg_something.specified());
+ TEST_CHECK(c1.arg_something.argument() == "blah");
+ TEST_CHECK(c1.arg_somenum.specified());
+ TEST_CHECK(c1.arg_somenum.argument() == 7);
+ TEST_CHECK(c1.arg_enum.specified());
+ TEST_CHECK(c1.arg_enum.argument() == "three");
+ TEST_CHECK(! c1.arg_dummy.specified());
+ TEST_CHECK(! c1.arg_other_enum.specified());
+ TEST_CHECK(c1.arg_other_enum.argument() == "b");
+
+ TEST_CHECK_EQUAL(std::distance(c1.begin_parameters(), c1.end_parameters()), 3);
+ TEST_CHECK_EQUAL(*c1.begin_parameters(), "--dummy");
+ TEST_CHECK_EQUAL(*++c1.begin_parameters(), "one");
+ TEST_CHECK_EQUAL(*++(++(c1.begin_parameters())), "two");
+ }
+ } test_args_simple;
+
+ /**
+ * \test Missing parameters tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct ArgsTestNoParam : TestCase
+ {
+ ArgsTestNoParam() : TestCase("Missing parameters") { }
+
+ void run()
+ {
+ char *args[] = { "program-name", "-e" };
+ CommandLine c1;
+ TEST_CHECK_THROWS(c1.run(2, args), MissingValue);
+ }
+ } test_args_no_param;
+
+ /**
+ * \test String tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct ArgsTestStringSet : TestCase
+ {
+ ArgsTestStringSet() : TestCase("StringSet") { }
+
+ void run()
+ {
+ char *args[] = { "program-name", "--stringset", "one", "-t", "two", "-t", "three", "fnord" };
+ CommandLine c1;
+ c1.run(8, args);
+ TEST_CHECK(c1.arg_stringset.specified());
+ TEST_CHECK(std::find(c1.arg_stringset.args_begin(), c1.arg_stringset.args_end(), "one") != c1.arg_stringset.args_end());
+ TEST_CHECK(std::find(c1.arg_stringset.args_begin(), c1.arg_stringset.args_end(), "two") != c1.arg_stringset.args_end());
+ TEST_CHECK(std::find(c1.arg_stringset.args_begin(), c1.arg_stringset.args_end(), "three") != c1.arg_stringset.args_end());
+ TEST_CHECK(std::find(c1.arg_stringset.args_begin(), c1.arg_stringset.args_end(), "fnord") == c1.arg_stringset.args_end());
+ }
+ } test_args_string_set;
+}
+
diff --git a/0.4.0/paludis/args/args_dumper.cc b/0.4.0/paludis/args/args_dumper.cc
new file mode 100644
index 000000000..afdc747c0
--- /dev/null
+++ b/0.4.0/paludis/args/args_dumper.cc
@@ -0,0 +1,81 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/args/args_dumper.hh>
+#include <paludis/args/args_option.hh>
+
+#include <sstream>
+
+/** \file
+ * Implementation of ArgsDumper.
+ *
+ * \ingroup grplibpaludisargs
+ */
+
+using namespace paludis;
+using namespace paludis::args;
+
+ArgsDumper::ArgsDumper(std::ostream & os) :
+ _os(os)
+{
+}
+
+void ArgsDumper::visit(const ArgsOption * const a)
+{
+ std::stringstream p;
+ p << " --" << a->long_name();
+ if (a->short_name())
+ p << ", -" << a->short_name();
+ if (p.str().length() < 24)
+ p << std::string(24 - p.str().length(), ' ');
+ else
+ p << std::endl << std::string(24, ' ');
+ _os << p.str();
+ _os << " " << a->description() << std::endl;
+}
+
+#ifndef DOXYGEN
+#define VISIT(type) void ArgsDumper::visit(const type * const a) \
+ { visit(static_cast<const ArgsOption *>(a)); }
+
+VISIT(SwitchArg)
+VISIT(StringArg)
+VISIT(IntegerArg)
+VISIT(AliasArg)
+VISIT(StringSetArg)
+#endif
+
+void ArgsDumper::visit(const EnumArg * const a)
+{
+ visit(static_cast<const ArgsOption *>(a));
+ for (EnumArg::AllowedArgIterator it = a->begin_allowed_args(), it_end = a->end_allowed_args();
+ it != it_end; ++it)
+ {
+ std::stringstream p;
+ p << " " << (*it).first;
+ if (p.str().length() < 26)
+ p << std::string(26 - p.str().length(), ' ');
+ _os << p.str();
+ _os << " " << (*it).second;
+ if ((*it).first == a->default_arg())
+ _os << " (default)";
+ _os << std::endl;
+ }
+}
diff --git a/0.4.0/paludis/args/args_dumper.hh b/0.4.0/paludis/args/args_dumper.hh
new file mode 100644
index 000000000..34ba0a1b3
--- /dev/null
+++ b/0.4.0/paludis/args/args_dumper.hh
@@ -0,0 +1,79 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_ARGS_ARGS_DUMPER_HH
+#define PALUDIS_GUARD_PALUDIS_ARGS_ARGS_DUMPER_HH 1
+
+#include <ostream>
+#include <paludis/args/args_visitor.hh>
+#include <paludis/util/visitor.hh>
+
+namespace paludis
+{
+ namespace args
+ {
+ class ArgsOption;
+ class SwitchArg;
+ class StringArg;
+ class IntegerArg;
+ class AliasArg;
+ class EnumArg;
+
+ /**
+ * Visitor class. Prints help text appropriate to each command line option.
+ *
+ * \ingroup grplibpaludisargs
+ */
+ class ArgsDumper : public ArgsVisitorTypes::ConstVisitor
+ {
+ private:
+ std::ostream & _os;
+
+ public:
+ /**
+ * Constructor.
+ */
+ ArgsDumper(std::ostream & os);
+
+ /// Visit an ArgsOption.
+ void visit(const ArgsOption * const);
+
+ /// Visit a SwitchArg.
+ void visit(const SwitchArg * const);
+
+ /// Visit a StringArg.
+ void visit(const StringArg * const);
+
+ /// Visit an IntegerArg.
+ void visit(const IntegerArg * const);
+
+ /// Visit an AliasArg.
+ void visit(const AliasArg * const);
+
+ /// Visit an EnumArg.
+ void visit(const EnumArg * const);
+
+ /// Visit a StringSetArg.
+ void visit(const StringSetArg * const);
+ };
+ }
+}
+
+#endif
diff --git a/0.4.0/paludis/args/args_error.cc b/0.4.0/paludis/args/args_error.cc
new file mode 100644
index 000000000..46aaa0d27
--- /dev/null
+++ b/0.4.0/paludis/args/args_error.cc
@@ -0,0 +1,35 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "args_error.hh"
+
+/** \file
+ * Implementation for ArgsError.
+ *
+ * \ingroup grplibpaludisargs
+ * \ingroup grpexceptions
+ */
+
+using namespace paludis::args;
+
+ArgsError::ArgsError(const std::string & message) throw () :
+ paludis::Exception("Error handling command line: " + message)
+{
+}
+
diff --git a/0.4.0/paludis/args/args_error.hh b/0.4.0/paludis/args/args_error.hh
new file mode 100644
index 000000000..8d8355bfa
--- /dev/null
+++ b/0.4.0/paludis/args/args_error.hh
@@ -0,0 +1,53 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_ARGS_ARGS_ERROR_HH
+#define PALUDIS_GUARD_ARGS_ARGS_ERROR_HH 1
+
+#include <paludis/util/exception.hh>
+#include <string>
+
+/** \file
+ * Declaration for ArgsError.
+ *
+ * \ingroup grplibpaludisargs
+ */
+
+namespace paludis
+{
+ namespace args
+ {
+ /**
+ * Thrown if an invalid command line argument is provided.
+ *
+ * \ingroup grplibpaludisargs
+ * \ingroup grpexceptions
+ */
+ class ArgsError : public paludis::Exception
+ {
+ protected:
+ /**
+ * Constructor.
+ */
+ ArgsError(const std::string & message) throw ();
+ };
+ }
+}
+
+#endif
diff --git a/0.4.0/paludis/args/args_group.cc b/0.4.0/paludis/args/args_group.cc
new file mode 100644
index 000000000..593e3e7e8
--- /dev/null
+++ b/0.4.0/paludis/args/args_group.cc
@@ -0,0 +1,47 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "args.hh"
+
+/** \file
+ * Implementation for ArgsGroup.
+ *
+ * \ingroup grplibpaludisargs
+ */
+
+using namespace paludis::args;
+
+ArgsGroup::ArgsGroup(ArgsHandler * h, const std::string & name) :
+ _name(name),
+ _handler(h)
+{
+ h->add(this);
+}
+
+void
+ArgsGroup::add(ArgsOption * const value)
+{
+ /// \bug Should check for uniqueness of short and long names.
+ _args_options.push_back(value);
+}
+
+ArgsGroup::~ArgsGroup()
+{
+}
+
diff --git a/0.4.0/paludis/args/args_group.hh b/0.4.0/paludis/args/args_group.hh
new file mode 100644
index 000000000..c4d4aa53f
--- /dev/null
+++ b/0.4.0/paludis/args/args_group.hh
@@ -0,0 +1,98 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_ARGS_ARGS_GROUP_HH
+#define PALUDIS_GUARD_ARGS_ARGS_GROUP_HH 1
+
+#include <list>
+#include <paludis/args/args_option.hh>
+#include <string>
+
+/** \file
+ * Declaration for ArgsGroup.
+ *
+ * \ingroup grplibpaludisargs
+ */
+
+namespace paludis
+{
+
+ namespace args
+ {
+ class ArgsHandler;
+
+ /**
+ * Contains a related group of command line arguments.
+ *
+ * \ingroup grplibpaludisargs
+ */
+ class ArgsGroup
+ {
+ friend class ArgsHandler;
+ friend class ArgsOption;
+
+ private:
+ ArgsGroup(const ArgsGroup &);
+
+ void operator= (const ArgsGroup &);
+
+ const std::string _name;
+
+ std::list<ArgsOption *> _args_options;
+
+ ArgsHandler * _handler;
+
+ protected:
+ /**
+ * Add an ArgsOption instance (called by the ArgsOption
+ * constructor).
+ */
+ void add(ArgsOption * const value);
+
+ public:
+ /**
+ * Constructor.
+ */
+ ArgsGroup(ArgsHandler * h, const std::string & name);
+
+ /**
+ * Destructor.
+ */
+ ~ArgsGroup();
+
+ /**
+ * Fetch our name.
+ */
+ const std::string & name() const
+ {
+ return _name;
+ }
+
+ /**
+ * Fetch our handler.
+ */
+ ArgsHandler * handler() const
+ {
+ return _handler;
+ }
+ };
+ }
+}
+
+#endif
diff --git a/0.4.0/paludis/args/args_handler.cc b/0.4.0/paludis/args/args_handler.cc
new file mode 100644
index 000000000..a68165554
--- /dev/null
+++ b/0.4.0/paludis/args/args_handler.cc
@@ -0,0 +1,129 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "args.hh"
+#include "args_dumper.hh"
+#include <algorithm>
+#include <paludis/util/system.hh>
+
+/** \file
+ * Implementation for ArgsHandler.
+ *
+ * \ingroup grplibpaludisargs
+ */
+
+using namespace paludis::args;
+
+ArgsHandler::ArgsHandler()
+{
+}
+
+void
+ArgsHandler::add(ArgsGroup * const g)
+{
+ /// \bug Should check for name uniqueness.
+ _groups.push_back(g);
+}
+
+void
+ArgsHandler::run(const int argc, const char * const * const argv)
+{
+ std::list<std::string> args;
+
+ std::string env_options = paludis::getenv_with_default("PALUDIS_OPTIONS", "");
+
+ std::istringstream iss(env_options);
+ std::string option;
+ while(iss.good())
+ {
+ iss >> option;
+ if(!option.empty())
+ args.push_back(option);
+ }
+
+ args.insert(args.end(), &argv[1], &argv[argc]);
+
+ std::list<std::string>::iterator argit = args.begin(), arge = args.end();
+
+ ArgsVisitor visitor(&argit, arge);
+
+ for ( ; argit != arge; ++argit )
+ {
+ std::string arg = *argit;
+
+ if (arg == "--")
+ {
+ ++argit;
+ break;
+ }
+ else if (0 == arg.compare(0, 2, "--"))
+ {
+ arg.erase(0, 2);
+ std::map<std::string, ArgsOption*>::iterator it = _longopts.find(arg);
+ if (it == _longopts.end())
+ throw BadArgument("--" + arg);
+ (*it).second->accept(&visitor);
+ }
+ else if (arg[0] == '-')
+ {
+ arg.erase(0, 1);
+ for (std::string::iterator c = arg.begin(); c != arg.end(); ++c)
+ {
+ std::map<char, ArgsOption*>::iterator it = _shortopts.find(*c);
+ if (it == _shortopts.end())
+ {
+ throw BadArgument(std::string("-") + *c);
+ }
+ (*it).second->accept(&visitor);
+ }
+ }
+ else
+ {
+ _parameters.push_back(arg);
+ }
+ }
+
+ _parameters.insert(_parameters.end(), argit, args.end());
+}
+
+void
+ArgsHandler::dump_to_stream(std::ostream & s) const
+{
+ ArgsDumper dump(s);
+ std::list<ArgsGroup *>::const_iterator g(_groups.begin()), g_end(_groups.end());
+ for ( ; g != g_end ; ++g)
+ {
+ s << (*g)->name() << ":" << std::endl;
+
+ std::for_each((*g)->_args_options.begin(), (*g)->_args_options.end(),
+ accept_visitor(&dump));
+
+ s << std::endl;
+ }
+}
+
+#ifndef DOXYGEN
+std::ostream &
+paludis::args::operator<< (std::ostream & s, const ArgsHandler & h)
+{
+ h.dump_to_stream(s);
+ return s;
+}
+#endif
+
diff --git a/0.4.0/paludis/args/args_handler.hh b/0.4.0/paludis/args/args_handler.hh
new file mode 100644
index 000000000..42a517920
--- /dev/null
+++ b/0.4.0/paludis/args/args_handler.hh
@@ -0,0 +1,129 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_ARGS_ARGS_HANDLER_HH
+#define PALUDIS_GUARD_ARGS_ARGS_HANDLER_HH 1
+
+#include <map>
+#include <ostream>
+#include <paludis/args/args_group.hh>
+#include <paludis/util/instantiation_policy.hh>
+#include <string>
+
+/** \file
+ * Declaration for ArgsHandler.
+ *
+ * \ingroup grplibpaludisargs
+ */
+
+namespace paludis
+{
+ namespace args
+ {
+ /**
+ * Handles command line arguments.
+ *
+ * \ingroup grplibpaludisargs
+ */
+ class ArgsHandler : private InstantiationPolicy<ArgsHandler, instantiation_method::NonCopyableTag>
+ {
+ friend class ArgsGroup;
+ friend std::ostream & operator<< (std::ostream &, const ArgsHandler &);
+
+ private:
+ std::list<ArgsGroup *> _groups;
+ std::list<std::string> _parameters;
+
+ std::map<std::string, ArgsOption *> _longopts;
+ std::map<char, ArgsOption *> _shortopts;
+
+ protected:
+ /**
+ * Add an new ArgsGroup (called by the ArgsGroup constructor).
+ */
+ void add(ArgsGroup * const);
+
+ /**
+ * Dump, for --help output (called by operator<<).
+ */
+ void dump_to_stream(std::ostream & s) const;
+
+ public:
+ /**
+ * Constructor.
+ */
+ ArgsHandler();
+
+ /**
+ * Parse command line arguments.
+ */
+ void run(const int, const char * const * const);
+
+ /**
+ * Iterate over our parameters (non - and -- switches and their
+ * values).
+ */
+ typedef std::list<std::string>::const_iterator ParametersIterator;
+
+ /**
+ * Pointer to the start of our parameters.
+ */
+ ParametersIterator begin_parameters() const
+ {
+ return _parameters.begin();
+ }
+
+ /**
+ * Pointer to past the end of our parameters.
+ */
+ ParametersIterator end_parameters() const
+ {
+ return _parameters.end();
+ }
+
+ /**
+ * Do we have no parameters?
+ */
+ bool empty() const
+ {
+ return _parameters.empty();
+ }
+
+ /**
+ * Add an ArgsOption instance.
+ */
+ void add_option(ArgsOption *opt, const std::string long_name, const char short_name = '\0')
+ {
+ _longopts[long_name] = opt;
+ if (short_name != '\0')
+ _shortopts[short_name] = opt;
+ }
+
+ };
+
+ /**
+ * Output an ArgsHandler to an ostream, for --help output.
+ *
+ * \ingroup grplibpaludisargs
+ */
+ std::ostream & operator<< (std::ostream &, const ArgsHandler &);
+ }
+}
+
+#endif
diff --git a/0.4.0/paludis/args/args_option.cc b/0.4.0/paludis/args/args_option.cc
new file mode 100644
index 000000000..b7f4287bc
--- /dev/null
+++ b/0.4.0/paludis/args/args_option.cc
@@ -0,0 +1,134 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "args.hh"
+#include "bad_value.hh"
+
+/** \file
+ * Implementation for ArgsOption.
+ *
+ * \ingroup grplibpaludisargs
+ */
+
+using namespace paludis::args;
+
+ArgsOption::ArgsOption(ArgsGroup * const g, const std::string & long_name,
+ const char short_name, const std::string & description) :
+ _group(g),
+ _long_name(long_name),
+ _short_name(short_name),
+ _description(description),
+ _specified(false)
+{
+ g->add(this);
+ g->_handler->add_option(this, long_name, short_name);
+}
+
+ArgsOption::~ArgsOption()
+{
+}
+
+SwitchArg::SwitchArg(ArgsGroup * const group, std::string long_name, char short_name,
+ std::string description) :
+ ArgsOption(group, long_name, short_name, description)
+{
+}
+
+SwitchArg::~SwitchArg()
+{
+}
+
+AliasArg::AliasArg(ArgsOption * const other, const std::string & long_name) :
+ ArgsOption(other->group(), long_name, '\0', "Alias for --" + other->long_name()),
+ _other(other)
+{
+ other->group()->handler()->add_option(other, long_name);
+}
+
+StringArg::StringArg(ArgsGroup * const g, const std::string & long_name,
+ const char short_name, const std::string & description) :
+ ArgsOption(g, long_name, short_name, description)
+{
+}
+
+StringSetArg::StringSetArg(ArgsGroup * const g, const std::string & long_name,
+ const char short_name, const std::string & description) :
+ ArgsOption(g, long_name, short_name, description)
+{
+}
+
+IntegerArg::IntegerArg(ArgsGroup * const group, const std::string& long_name,
+ char short_name, const std::string& description) :
+ ArgsOption(group, long_name, short_name, description)
+{
+}
+
+namespace
+{
+ /**
+ * Is an arg a particular value?
+ *
+ * \ingroup grplibpaludisargs
+ */
+ struct ArgIs
+ {
+ /// The argument.
+ const std::string arg;
+
+ /// Constructor.
+ ArgIs(const std::string & a) :
+ arg(a)
+ {
+ }
+
+ /// Comparator.
+ bool operator() (const std::pair<std::string, std::string> & p) const
+ {
+ return p.first == arg;
+ }
+ };
+}
+
+void EnumArg::set_argument(const std::string & arg)
+{
+ if (_allowed_args.end() == std::find_if(_allowed_args.begin(),
+ _allowed_args.end(), ArgIs(arg)))
+ throw (BadValue("--" + long_name(), arg));
+
+ _argument = arg;
+}
+
+EnumArg::~EnumArg()
+{
+}
+
+EnumArg::EnumArgOptions::EnumArgOptions(std::string opt, std::string desc)
+{
+ _options.push_back(std::make_pair(opt, desc));
+}
+
+EnumArg::EnumArgOptions & EnumArg::EnumArgOptions::operator() (std::string opt, std::string desc)
+{
+ _options.push_back(std::make_pair(opt, desc));
+ return *this;
+}
+
+EnumArg::EnumArgOptions::~EnumArgOptions()
+{
+}
diff --git a/0.4.0/paludis/args/args_option.hh b/0.4.0/paludis/args/args_option.hh
new file mode 100644
index 000000000..bce3c863b
--- /dev/null
+++ b/0.4.0/paludis/args/args_option.hh
@@ -0,0 +1,359 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ * Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_ARGS_ARGS_OPTION_HH
+#define PALUDIS_GUARD_ARGS_ARGS_OPTION_HH 1
+
+#include <paludis/args/args_visitor.hh>
+#include <set>
+#include <string>
+#include <vector>
+
+/** \file
+ * Declaration for ArgsOption.
+ *
+ * \ingroup grplibpaludisargs
+ */
+
+namespace paludis
+{
+ namespace args
+ {
+ class ArgsGroup;
+
+ /**
+ * Base class for a command line option.
+ *
+ * \ingroup grplibpaludisargs
+ */
+ class ArgsOption : public virtual VisitableInterface<ArgsVisitorTypes>
+ {
+ friend class ArgsHandler;
+
+ private:
+ ArgsGroup * const _group;
+
+ const std::string _long_name;
+ const char _short_name;
+ const std::string _description;
+
+ bool _specified;
+
+ ArgsOption(const ArgsOption &);
+
+ void operator= (const ArgsOption &);
+
+ protected:
+ /**
+ * Constructor.
+ */
+ ArgsOption(ArgsGroup * const, const std::string & long_name,
+ const char short_name, const std::string & description);
+
+ /**
+ * Destructor.
+ */
+ ~ArgsOption();
+
+ public:
+ /**
+ * Fetch our long name.
+ */
+ const std::string & long_name() const
+ {
+ return _long_name;
+ }
+
+ /**
+ * Fetch our short name (may be 0).
+ */
+ char short_name() const
+ {
+ return _short_name;
+ }
+
+ /**
+ * Fetch our description.
+ */
+ const std::string & description() const
+ {
+ return _description;
+ }
+
+ /**
+ * Fetch whether or not we were specified on the
+ * command line.
+ */
+ virtual bool specified() const
+ {
+ return _specified;
+ }
+
+ /**
+ * Set the value returned by specified().
+ */
+ virtual void set_specified(const bool value)
+ {
+ _specified = value;
+ }
+
+ /**
+ * Fetch our group.
+ */
+ ArgsGroup * group()
+ {
+ return _group;
+ }
+ };
+
+ /**
+ * A SwitchArg is an option that can either be specified or not
+ * specified, and that takes no value (for example, --help).
+ *
+ * \ingroup grplibpaludisargs
+ */
+ class SwitchArg : public ArgsOption, public Visitable<SwitchArg, ArgsVisitorTypes>
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ SwitchArg(ArgsGroup * const group, std::string long_name, char short_name,
+ std::string description);
+
+ ~SwitchArg();
+ };
+
+ /**
+ * An option that takes a string argument.
+ *
+ * \ingroup grplibpaludisargs
+ */
+ class StringArg : public ArgsOption, public Visitable<StringArg, ArgsVisitorTypes>
+ {
+ private:
+ std::string _argument;
+
+ public:
+
+ /**
+ * Constructor
+ */
+ StringArg(ArgsGroup * const, const std::string & long_name,
+ const char short_name, const std::string & description);
+
+ /**
+ * Fetch the argument that was given to this option.
+ */
+ const std::string& argument() const { return _argument; }
+
+ /**
+ * Set the argument returned by argument().
+ */
+ void set_argument(const std::string& arg) { _argument = arg; }
+ };
+
+ /**
+ * An option that takes a set of strings.
+ *
+ * \ingroup grplibpaludisargs
+ */
+ class StringSetArg : public ArgsOption, public Visitable<StringSetArg, ArgsVisitorTypes>
+ {
+ private:
+ std::set<std::string> _args;
+
+ public:
+
+ /**
+ * Type used to iterate over specified args.
+ */
+ typedef std::set<std::string>::const_iterator Iterator;
+
+ /**
+ * Constructor
+ */
+ StringSetArg(ArgsGroup * const, const std::string & long_name,
+ const char short_name, const std::string & description);
+
+ /**
+ * Retrieve an iterator to the first arg
+ */
+ Iterator args_begin() const { return _args.begin(); }
+
+ /**
+ * Retrieve an iterator one past the last arg
+ */
+ Iterator args_end() const { return _args.end(); }
+
+ /**
+ * Add an argument to the set returned by [ args_begin(), args_end() )
+ */
+ void add_argument(const std::string & arg) { _args.insert(arg); }
+ };
+
+
+ /**
+ * An AliasArg is an alias for another argument.
+ *
+ * \ingroup grplibpaludisargs
+ */
+ class AliasArg : public ArgsOption, public Visitable<AliasArg, ArgsVisitorTypes>
+ {
+ private:
+ ArgsOption * const _other;
+
+ public:
+ /**
+ * Constructor.
+ */
+ AliasArg(ArgsOption * const other, const std::string & new_long_name);
+
+ virtual bool specified() const
+ {
+ return _other->specified();
+ }
+
+ virtual void set_specified(const bool value)
+ {
+ _other->set_specified(value);
+ }
+ };
+
+ /**
+ * An option that takes an integer argument.
+ *
+ * \ingroup grplibpaludisargs
+ */
+ class IntegerArg : public ArgsOption, public Visitable<IntegerArg, ArgsVisitorTypes>
+ {
+ private:
+ int _argument;
+
+ public:
+ /**
+ * Constructor
+ */
+ IntegerArg(ArgsGroup * const, const std::string & long_name,
+ const char short_name, const std::string & description);
+ /**
+ * Fetch the argument that was given to this option.
+ */
+ int argument() const { return _argument; }
+
+ /**
+ * Set the argument returned by argument().
+ */
+ void set_argument(const int arg) { _argument = arg; }
+ };
+
+ /**
+ * An option that takes one of a predefined set of string arguments.
+ *
+ * \ingroup grplibpaludisargs
+ */
+ class EnumArg : public ArgsOption, public Visitable<EnumArg, ArgsVisitorTypes>
+ {
+ private:
+ const std::vector<std::pair<std::string, std::string> > _allowed_args;
+ std::string _argument;
+ const std::string _default_arg;
+
+ public:
+
+ /**
+ * Helper class for passing available options and associated descriptions
+ * to the EnumArg constructor.
+ *
+ * \ingroup grplibpaludisargs
+ */
+ class EnumArgOptions
+ {
+ private:
+ friend class EnumArg;
+ std::vector<std::pair<std::string, std::string> > _options;
+
+ public:
+ /**
+ * Constructor
+ */
+ EnumArgOptions(const std::string, const std::string);
+
+ /**
+ * Destructor.
+ */
+ ~EnumArgOptions();
+
+ /**
+ * Adds another (option, description) pair.
+ */
+ EnumArgOptions& operator() (const std::string, const std::string);
+ };
+
+ /**
+ * Constructor.
+ */
+ EnumArg(ArgsGroup * const group, const std::string & long_name,
+ const char short_name, const std::string & description,
+ const EnumArgOptions & opts, const std::string & default_arg) :
+ ArgsOption(group, long_name, short_name, description),
+ _allowed_args(opts._options), _argument(default_arg),
+ _default_arg(default_arg)
+ {
+ }
+
+ ~EnumArg();
+
+ /**
+ * Fetch the argument that was given to this option.
+ */
+ const std::string & argument() const { return _argument; }
+
+ /**
+ * Set the argument returned by argument(), having verified that
+ * it is one of the arguments allowed for this option.
+ */
+ void set_argument(const std::string & arg);
+
+ /**
+ * Fetch the default option, as specified to the constructor.
+ */
+ const std::string & default_arg() const { return _default_arg; }
+
+ /**
+ * Type used to iterate over valid arguments to this option
+ */
+ typedef std::vector<std::pair<std::string, std::string> >::const_iterator AllowedArgIterator;
+
+ /**
+ * Returns an iterator pointing to a pair containing the first valid argument,
+ * and its description.
+ */
+ AllowedArgIterator begin_allowed_args() const { return _allowed_args.begin(); }
+
+ /**
+ * Returns an iterator pointing just beyond the last valid argument.
+ */
+ AllowedArgIterator end_allowed_args() const { return _allowed_args.end(); }
+ };
+ }
+}
+
+#endif
diff --git a/0.4.0/paludis/args/args_visitor.cc b/0.4.0/paludis/args/args_visitor.cc
new file mode 100644
index 000000000..979debd67
--- /dev/null
+++ b/0.4.0/paludis/args/args_visitor.cc
@@ -0,0 +1,97 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "args_option.hh"
+#include "bad_value.hh"
+#include "missing_value.hh"
+#include <paludis/util/visitor.hh>
+
+#include <paludis/util/destringify.hh>
+
+#include <sstream>
+
+/** \file
+ * Implementation for ArgsVisitor.
+ *
+ * \ingroup grplibpaludisargs
+ */
+
+using namespace paludis;
+using namespace args;
+
+ArgsVisitor::ArgsVisitor(std::list<std::string>::iterator *ai,
+ std::list<std::string>::iterator ae) : _args_index(ai), _args_end(ae)
+{
+}
+
+const std::string& ArgsVisitor::get_param(const ArgsOption * const arg)
+{
+ if (++(*_args_index) == _args_end)
+ {
+ throw MissingValue("--" + arg->long_name());
+ }
+ return **_args_index;
+}
+
+void ArgsVisitor::visit(ArgsOption * const arg)
+{
+ arg->set_specified(true);
+}
+
+void ArgsVisitor::visit(StringArg * const arg)
+{
+ visit(static_cast<ArgsOption *>(arg));
+ arg->set_argument(get_param(arg));
+}
+
+void ArgsVisitor::visit(AliasArg * const arg)
+{
+ visit(static_cast<ArgsOption *>(arg));
+}
+
+void ArgsVisitor::visit(SwitchArg * const arg)
+{
+ visit(static_cast<ArgsOption *>(arg));
+}
+
+void ArgsVisitor::visit(IntegerArg * const arg)
+{
+ visit(static_cast<ArgsOption*>(arg));
+ std::string param = get_param(arg);
+ try
+ {
+ arg->set_argument(destringify<int>(param));
+ }
+ catch(DestringifyError &e)
+ {
+ throw BadValue("--" + arg->long_name(), param);
+ }
+}
+
+void ArgsVisitor::visit(EnumArg * const arg)
+{
+ visit(static_cast<ArgsOption*>(arg));
+ arg->set_argument(get_param(arg));
+}
+
+void ArgsVisitor::visit(StringSetArg * const arg)
+{
+ visit(static_cast<ArgsOption *>(arg));
+ std::string param = get_param(arg);
+ arg->add_argument(param);
+}
diff --git a/0.4.0/paludis/args/args_visitor.hh b/0.4.0/paludis/args/args_visitor.hh
new file mode 100644
index 000000000..17a9eacba
--- /dev/null
+++ b/0.4.0/paludis/args/args_visitor.hh
@@ -0,0 +1,96 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ * Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_ARGS_ARGS_VISITOR_HH
+#define PALUDIS_GUARD_ARGS_ARGS_VISITOR_HH 1
+
+#include <list>
+#include <paludis/util/visitor.hh>
+#include <string>
+
+/** \file
+ * Declaration for ArgsVisitor
+ *
+ * \ingroup grplibpaludisargs
+ */
+
+namespace paludis
+{
+ namespace args
+ {
+ class ArgsOption;
+ class StringArg;
+ class AliasArg;
+ class SwitchArg;
+ class IntegerArg;
+ class EnumArg;
+ class StringSetArg;
+
+ /**
+ * Visitor types for visitors that can visit Args.
+ *
+ * \ingroup grplibpaludisargs
+ */
+ typedef VisitorTypes<ArgsOption *, StringArg *, AliasArg *, SwitchArg *,
+ IntegerArg *, EnumArg *, StringSetArg *> ArgsVisitorTypes;
+
+ /**
+ * Visitor class. Processes command-line options as they are found.
+ *
+ * \ingroup grplibpaludisargs
+ */
+ class ArgsVisitor : public ArgsVisitorTypes::Visitor
+ {
+ private:
+ std::list<std::string>::iterator *_args_index, _args_end;
+
+ const std::string& get_param(const ArgsOption * const);
+
+ public:
+ /**
+ * Constructor
+ */
+ ArgsVisitor(std::list<std::string>::iterator *, std::list<std::string>::iterator);
+
+ /// Visit an ArgsOption.
+ void visit(ArgsOption * const);
+
+ /// Visit a StringArg.
+ void visit(StringArg * const);
+
+ /// Visit an AliasArg.
+ void visit(AliasArg * const);
+
+ /// Visit a SwitchArg.
+ void visit(SwitchArg * const);
+
+ /// Visit an IntegerArg.
+ void visit(IntegerArg * const);
+
+ /// Visit an EnumArg.
+ void visit(EnumArg * const);
+
+ /// Visit a StringSetArg.
+ void visit(StringSetArg * const);
+ };
+ }
+}
+
+#endif
diff --git a/0.4.0/paludis/args/bad_argument.cc b/0.4.0/paludis/args/bad_argument.cc
new file mode 100644
index 000000000..af5554c20
--- /dev/null
+++ b/0.4.0/paludis/args/bad_argument.cc
@@ -0,0 +1,35 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "bad_argument.hh"
+
+/** \file
+ * Implementation for BadArgument.
+ *
+ * \ingroup Args
+ * \ingroup Exception
+ */
+
+using namespace paludis::args;
+
+BadArgument::BadArgument(const std::string & option) throw () :
+ ArgsError("Bad argument '" + option + "'")
+{
+}
+
diff --git a/0.4.0/paludis/args/bad_argument.hh b/0.4.0/paludis/args/bad_argument.hh
new file mode 100644
index 000000000..3b0e925d4
--- /dev/null
+++ b/0.4.0/paludis/args/bad_argument.hh
@@ -0,0 +1,53 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_ARGS_BAD_ARGUMENT_HH
+#define PALUDIS_GUARD_ARGS_BAD_ARGUMENT_HH 1
+
+#include <paludis/args/args_error.hh>
+
+/** \file
+ * Declaration for BadArgument.
+ *
+ * \ingroup grplibpaludisargs
+ * \ingroup grpexceptions
+ */
+
+namespace paludis
+{
+ namespace args
+ {
+ /**
+ * Thrown if an unrecognised command line argument is specified.
+ *
+ * \ingroup grplibpaludisargs
+ * \ingroup grpexceptions
+ */
+ class BadArgument : public ArgsError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ BadArgument(const std::string & option) throw ();
+ };
+ }
+}
+
+#endif
diff --git a/0.4.0/paludis/args/bad_value.cc b/0.4.0/paludis/args/bad_value.cc
new file mode 100644
index 000000000..5899bea4d
--- /dev/null
+++ b/0.4.0/paludis/args/bad_value.cc
@@ -0,0 +1,32 @@
+#include "bad_value.hh"
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** \file
+ * Implementation for BadValue
+ *
+ * \ingroup Args
+ * \ingroup Exception
+ */
+
+using namespace paludis::args;
+
+BadValue::BadValue(const std::string& option, const std::string& value) throw () :
+ ArgsError("Invalid parameter '" + value + "' for argument '" + option + "'")
+{
+}
diff --git a/0.4.0/paludis/args/bad_value.hh b/0.4.0/paludis/args/bad_value.hh
new file mode 100644
index 000000000..0392bbc9d
--- /dev/null
+++ b/0.4.0/paludis/args/bad_value.hh
@@ -0,0 +1,53 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_ARGS_BAD_VALUE_HH
+#define PALUDIS_GUARD_ARGS_BAD_VALUE_HH 1
+
+#include <paludis/args/args_error.hh>
+
+/** \file
+ * Declaration for BadValue.
+ *
+ * \ingroup grplibpaludisargs
+ * \ingroup grpexceptions
+ */
+
+namespace paludis
+{
+ namespace args
+ {
+ /**
+ * Thrown if an invalid parameter is passed to a valid command line argument.
+ *
+ * \ingroup grplibpaludisargs
+ * \ingroup grpexceptions
+ */
+ class BadValue : public ArgsError
+ {
+ public:
+ /**
+ * Constructor
+ */
+ BadValue(const std::string& option, const std::string& value) throw();
+ };
+ }
+}
+
+#endif
diff --git a/0.4.0/paludis/args/missing_value.cc b/0.4.0/paludis/args/missing_value.cc
new file mode 100644
index 000000000..2474ea5fa
--- /dev/null
+++ b/0.4.0/paludis/args/missing_value.cc
@@ -0,0 +1,36 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "missing_value.hh"
+
+/**
+ * \file
+ * Implementation of MissingValue
+ *
+ * \ingroup Args
+ * \ingroup Exception
+ */
+
+using namespace paludis::args;
+
+MissingValue::MissingValue(const std::string & arg) throw() :
+ ArgsError("No parameter given for '" + arg + "'")
+{
+}
diff --git a/0.4.0/paludis/args/missing_value.hh b/0.4.0/paludis/args/missing_value.hh
new file mode 100644
index 000000000..9873ff092
--- /dev/null
+++ b/0.4.0/paludis/args/missing_value.hh
@@ -0,0 +1,55 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_ARGS_MISSING_VALUE_HH
+#define PALUDIS_GUARD_PALUDIS_ARGS_MISSING_VALUE_HH 1
+
+#include <paludis/args/args_error.hh>
+
+/** \file
+ * Declaration for MissingValue
+ *
+ * \ingroup grplibpaludisargs
+ * \ingroup grpexceptions
+ */
+
+namespace paludis
+{
+ namespace args
+ {
+ /**
+ * Thrown if an argument is specified that needs a parameter,
+ * but no parameter is given.
+ *
+ * \ingroup grplibpaludisargs
+ * \ingroup grpexceptions
+ */
+ class MissingValue : public ArgsError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ MissingValue(const std::string & arg) throw ();
+ };
+ }
+}
+
+#endif
diff --git a/0.4.0/paludis/config_file.cc b/0.4.0/paludis/config_file.cc
new file mode 100644
index 000000000..c7e133494
--- /dev/null
+++ b/0.4.0/paludis/config_file.cc
@@ -0,0 +1,473 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ * Copyright (c) 2006 Danny van Dyk <kugelfang@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/config_file.hh>
+#include <paludis/util/exception.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/strip.hh>
+#include <paludis/util/tokeniser.hh>
+
+#include <fstream>
+#include <istream>
+
+/** \file
+ * Implementation for config_file.hh classes.
+ *
+ * \ingroup grpconfigfile
+ */
+
+using namespace paludis;
+
+ConfigFileError::ConfigFileError(const std::string & message) throw () :
+ ConfigurationError("Config file error: " + message)
+{
+}
+
+ConfigFile::ConfigFile(std::istream * const stream) :
+ _stream(stream),
+ _has_lines(false),
+ _destroy_stream(false)
+{
+}
+
+ConfigFile::ConfigFile(const std::string & filename) try :
+ _stream(_make_stream(filename)),
+ _has_lines(false),
+ _filename(filename),
+ _destroy_stream(true)
+{
+}
+catch (...)
+{
+ _destroy_stream = false;
+ throw;
+}
+
+ConfigFile::ConfigFile(const FSEntry & filename) try :
+ _stream(_make_stream(stringify(filename))),
+ _has_lines(false),
+ _filename(stringify(filename)),
+ _destroy_stream(true)
+{
+}
+catch (...)
+{
+ _destroy_stream = false;
+ throw;
+}
+
+ConfigFile::~ConfigFile()
+{
+ if (_stream && _destroy_stream)
+ delete _stream;
+}
+
+std::istream *
+ConfigFile::_make_stream(const std::string & filename)
+{
+ Context context("When creating the filestream for a ConfigFile from file '" + filename + "':");
+
+ std::ifstream * result(new std::ifstream(filename.c_str()));
+ if (! *result)
+ {
+ delete result;
+ throw ConfigFileError("Could not open '" + filename + "'");
+ }
+
+ return result;
+}
+
+void
+ConfigFile::need_lines() const
+{
+ if (_has_lines)
+ return;
+
+ std::string line, accum;
+ unsigned line_number(0);
+ while (std::getline(*_stream, line))
+ {
+ Context c("When handling line " + stringify(++line_number) +
+ (_filename.empty() ? std::string(":") : " in file '" + _filename + "':"));
+ normalise_line(line);
+
+ if (line.empty() || skip_line(line))
+ {
+ if (!accum.empty())
+ throw ConfigFileError("Line-continuation followed by a blank line or comment is invalid.");
+
+ continue;
+ }
+ if ('\\' == line.at(line.length() - 1))
+ {
+ line.erase(line.length() - 1);
+ accum += line;
+ continue;
+ }
+
+ accept_line(accum + line);
+ accum.clear();
+ }
+ if (! _stream->eof())
+ throw ConfigFileError("Error reading from file");
+ if (! accum.empty())
+ throw ConfigFileError("Line-continuation needs a continuation.");
+
+ _has_lines = true;
+}
+
+void
+ConfigFile::normalise_line(std::string & s) const
+{
+ s = strip_leading(strip_trailing(s, " \t\n"), " \t\n");
+}
+
+bool
+ConfigFile::skip_line(const std::string & s) const
+{
+ return (s.empty() || '#' == s.at(0));
+}
+
+LineConfigFile::LineConfigFile(std::istream * const s) :
+ ConfigFile(s)
+{
+ need_lines();
+}
+
+LineConfigFile::LineConfigFile(const std::string & filename) :
+ ConfigFile(filename)
+{
+ need_lines();
+}
+
+LineConfigFile::LineConfigFile(const FSEntry & filename) :
+ ConfigFile(filename)
+{
+ need_lines();
+}
+
+void
+LineConfigFile::accept_line(const std::string & s) const
+{
+ _lines.push_back(s);
+}
+
+KeyValueConfigFileError::KeyValueConfigFileError(const std::string & msg,
+ const std::string & filename) throw () :
+ ConfigurationError("Key/Value config file error" +
+ (filename.empty() ? ": " : " in file '" + filename + "': ") + msg)
+{
+}
+
+KeyValueConfigFile::KeyValueConfigFile(std::istream * const s) :
+ ConfigFile(s)
+{
+ need_lines();
+}
+
+KeyValueConfigFile::KeyValueConfigFile(const std::string & filename) :
+ ConfigFile(filename)
+{
+ need_lines();
+}
+
+KeyValueConfigFile::KeyValueConfigFile(const FSEntry & filename) :
+ ConfigFile(filename)
+{
+ need_lines();
+}
+
+KeyValueConfigFile::KeyValueConfigFile(std::istream * const s,
+ const std::map<std::string, std::string> & m) :
+ ConfigFile(s),
+ _entries(m.begin(), m.end())
+{
+ need_lines();
+}
+
+KeyValueConfigFile::KeyValueConfigFile(const std::string & filename,
+ const std::map<std::string, std::string> & m) :
+ ConfigFile(filename),
+ _entries(m.begin(), m.end())
+{
+ need_lines();
+}
+
+KeyValueConfigFile::KeyValueConfigFile(const FSEntry & filename,
+ const std::map<std::string, std::string> & m) :
+ ConfigFile(filename),
+ _entries(m.begin(), m.end())
+{
+ need_lines();
+}
+
+KeyValueConfigFile::~KeyValueConfigFile()
+{
+}
+
+void
+KeyValueConfigFile::accept_line(const std::string & line) const
+{
+ std::string::size_type p(line.find('='));
+ if (std::string::npos == p)
+ _entries[line] = "";
+ else
+ {
+ std::string key(line.substr(0, p)), value(line.substr(p + 1));
+ normalise_line(key);
+ normalise_line(value);
+ _entries[key] = replace_variables(strip_quotes(value));
+ }
+}
+
+std::string
+KeyValueConfigFile::replace_variables(const std::string & s) const
+{
+ std::string r;
+ std::string::size_type p(0), old_p(0);
+
+ while (p < s.length())
+ {
+ old_p = p;
+
+ if ('\\' == s[p])
+ {
+ if (++p >= s.length())
+ throw KeyValueConfigFileError("Backslash not followed by a character", filename());
+ r += s[p++];
+ }
+ else if ('$' != s[p])
+ r += s[p++];
+ else
+ {
+ std::string name;
+ if (++p >= s.length())
+ throw KeyValueConfigFileError("Dollar not followed by a character", filename());
+
+ if ('{' == s[p])
+ {
+ std::string::size_type q;
+ if (std::string::npos == ((q = s.find("}", p))))
+ throw KeyValueConfigFileError("Closing } not found", filename());
+
+ name = s.substr(p + 1, q - p - 1);
+ p = q + 1;
+ }
+ else
+ {
+ std::string::size_type q;
+ if (std::string::npos == ((q = s.find_first_not_of(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "_0123456789", p))))
+ q = s.length();
+
+ name = s.substr(p, q - p);
+ p = q;
+ }
+
+ if (name.empty())
+ throw KeyValueConfigFileError("Empty variable name", filename());
+ r += get(name);
+ }
+
+ if (p <= old_p)
+ throw InternalError(PALUDIS_HERE, "Infinite loop");
+ }
+
+ return r;
+}
+
+std::string
+KeyValueConfigFile::strip_quotes(const std::string & s) const
+{
+ if (s.empty())
+ return s;
+ if (std::string::npos != std::string("'\"").find(s[0]))
+ {
+ if (s.length() < 2)
+ throw KeyValueConfigFileError("Unterminated quote", filename());
+ if (s[s.length() - 1] != s[0])
+ throw KeyValueConfigFileError("Mismatched quote", filename());
+ return s.substr(1, s.length() - 2);
+ }
+ else
+ return s;
+}
+
+AdvisoryFileError::AdvisoryFileError(const std::string & msg,
+ const std::string & filename) throw () :
+ ConfigurationError("Advisory file error" +
+ (filename.empty() ? ": " : "in file '" + filename + "': ") + msg)
+{
+}
+
+AdvisoryFile::AdvisoryFile(std::istream * const s) :
+ ConfigFile(s),
+ _end_of_header(false)
+{
+ need_lines();
+ sanitise();
+}
+
+AdvisoryFile::AdvisoryFile(const std::string & filename) :
+ ConfigFile(filename),
+ _end_of_header(false)
+{
+ need_lines();
+ sanitise();
+}
+
+AdvisoryFile::AdvisoryFile(const FSEntry & filename) :
+ ConfigFile(filename),
+ _end_of_header(false)
+{
+ need_lines();
+ sanitise();
+}
+
+AdvisoryFile::AdvisoryFile(std::istream * const s,
+ const std::map<std::string, std::string> & m) :
+ ConfigFile(s),
+ _entries(m.begin(), m.end()),
+ _end_of_header(false)
+{
+ need_lines();
+ sanitise();
+}
+
+AdvisoryFile::AdvisoryFile(const std::string & filename,
+ const std::map<std::string, std::string> & m) :
+ ConfigFile(filename),
+ _entries(m.begin(), m.end()),
+ _end_of_header(false)
+{
+ need_lines();
+ sanitise();
+}
+
+AdvisoryFile::AdvisoryFile(const FSEntry & filename,
+ const std::map<std::string, std::string> & m) :
+ ConfigFile(filename),
+ _entries(m.begin(), m.end()),
+ _end_of_header(false)
+{
+ need_lines();
+ sanitise();
+}
+
+AdvisoryFile::~AdvisoryFile()
+{
+}
+
+void
+AdvisoryFile::accept_line(const std::string & line) const
+{
+ std::string::size_type p(line.find(':'));
+
+ if ((std::string::npos == p) || (_end_of_header))
+ {
+ _entries["Description"] += line + "\n";
+ _end_of_header = true;
+ }
+ else
+ {
+ std::string key(line.substr(0, p)), value(line.substr(p + 1));
+ normalise_line(key);
+ normalise_line(value);
+ if ((key == "Affected") || (key == "Bug-Id") || (key == "CVE") || (key == "Reference")
+ || (key == "Restart") || (key == "Unaffected"))
+ {
+ if (key == "Affected")
+ _affected.push_back(value);
+ else if (key == "Unaffected")
+ _unaffected.push_back(value);
+ else
+ {
+ if (! _entries[key].empty())
+ value = "\n" + value;
+ _entries[key] += value;
+ }
+ }
+ else
+ {
+ if (_entries[key].empty())
+ _entries[key] = value;
+ else
+ throw AdvisoryFileError("When adding value for key '" + key + "': Duplicate key found.");
+ }
+ }
+}
+
+void
+AdvisoryFile::sanitise()
+{
+ if (_entries["Id"].empty())
+ throw AdvisoryFileError("Missing mandatory key: 'Id'.");
+
+ if (_entries["Title"].empty())
+ throw AdvisoryFileError("Missing mandatory key: 'Title'.");
+
+ if (_entries["Access"].empty())
+ throw AdvisoryFileError("Missing mandatory key: 'Access'.");
+
+ if (_entries["Last-Modified"].empty())
+ throw AdvisoryFileError("Missing mandatory key: 'Last-Modified'.");
+
+ if (_entries["Revision"].empty())
+ throw AdvisoryFileError("Missing mandatory key: 'Revision'.");
+
+ if (_entries["Severity"].empty())
+ throw AdvisoryFileError("Missing mandatory key: 'Severity'.");
+
+ if (_entries["Spec-Version"].empty())
+ throw AdvisoryFileError("Missing mandatory key: 'Spec-Version'.");
+}
+
+NewsFile::NewsFile(const FSEntry & filename) :
+ ConfigFile(filename),
+ _in_header(true)
+{
+ need_lines();
+}
+
+void
+NewsFile::accept_line(const std::string & line) const
+{
+ if (_in_header)
+ {
+ std::string::size_type p(line.find(':'));
+ if (std::string::npos == p)
+ _in_header = false;
+ else
+ {
+ std::string k(strip_leading(strip_trailing(line.substr(0, p), " \t\n"), " \t\n"));
+ std::string v(strip_leading(strip_trailing(line.substr(p + 1), " \t\n"), " \t\n"));
+ if (k == "Display-If-Installed")
+ _display_if_installed.push_back(v);
+ else if (k == "Display-If-Keyword")
+ _display_if_keyword.push_back(v);
+ if (k == "Display-If-Profile")
+ _display_if_profile.push_back(v);
+ }
+ }
+}
diff --git a/0.4.0/paludis/config_file.hh b/0.4.0/paludis/config_file.hh
new file mode 100644
index 000000000..04c306cf5
--- /dev/null
+++ b/0.4.0/paludis/config_file.hh
@@ -0,0 +1,504 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_CONFIG_FILE_HH
+#define PALUDIS_GUARD_PALUDIS_CONFIG_FILE_HH 1
+
+#include <paludis/util/exception.hh>
+#include <paludis/util/instantiation_policy.hh>
+
+#include <iosfwd>
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+/** \file
+ * Declarations for the ConfigFile classes.
+ *
+ * \ingroup grpconfigfile
+ */
+
+namespace paludis
+{
+ class FSEntry;
+
+ /**
+ * Thrown if an error occurs when reading a ConfigFile.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grpconfigfile
+ */
+ class ConfigFileError : public ConfigurationError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ ConfigFileError(const std::string & message) throw ();
+ };
+
+ /**
+ * A ConfigFile is a file containing one entry per line, with lines
+ * starting with a # being ignored and leading and trailing whitespace
+ * being discarded.
+ *
+ * \ingroup grpconfigfile
+ */
+ class ConfigFile :
+ paludis::InstantiationPolicy<ConfigFile, instantiation_method::NonCopyableTag>
+ {
+ private:
+ std::istream * const _stream;
+
+ mutable bool _has_lines;
+
+ std::string _filename;
+
+ bool _destroy_stream;
+
+ static std::istream * _make_stream(const std::string & filename);
+
+ protected:
+ /**
+ * In-place normalise a line. By default, trims leading and
+ * trailing whitespace. Child classes may override.
+ */
+ virtual void normalise_line(std::string &) const;
+
+ /**
+ * Return whether to skip a line. By default, skips on blank
+ * lines and lines starting with a #. Child classes may
+ * override. This is called on a normalised line, not a raw
+ * string.
+ */
+ virtual bool skip_line(const std::string &) const;
+
+ /**
+ * Accept a normalised line that is not to be skipped.
+ */
+ virtual void accept_line(const std::string &) const = 0;
+
+ /**
+ * If we have not done so already, read in our lines.
+ */
+ void need_lines() const;
+
+ /**
+ * Constructor.
+ */
+ ConfigFile(std::istream * const stream);
+
+ /**
+ * Constructor, from a file.
+ */
+ ConfigFile(const std::string & filename);
+
+ /**
+ * Constructor, from a file.
+ */
+ ConfigFile(const FSEntry & filename);
+
+ /**
+ * Our filename, or blank if unknown.
+ */
+ std::string filename() const
+ {
+ return _filename;
+ }
+
+ public:
+ /**
+ * Destructor.
+ */
+ virtual ~ConfigFile();
+ };
+
+ /**
+ * A LineConfigFile is a ConfigFile that provides access to the
+ * normalised lines. Do not subclass.
+ *
+ * \ingroup grplineconfigfile
+ */
+ class LineConfigFile : protected ConfigFile
+ {
+ private:
+ mutable std::list<std::string> _lines;
+
+ protected:
+ void accept_line(const std::string &) const;
+
+ public:
+ /**
+ * Constructor, from a stream.
+ */
+ LineConfigFile(std::istream * const);
+
+ /**
+ * Constructor, from a filename.
+ */
+ LineConfigFile(const std::string & filename);
+
+ /**
+ * Constructor, from a filename.
+ */
+ LineConfigFile(const FSEntry & filename);
+
+ /**
+ * Iterator over our lines.
+ */
+ typedef std::list<std::string>::const_iterator Iterator;
+
+ /**
+ * Iterator to the start of our lines.
+ */
+ Iterator begin() const
+ {
+ return _lines.begin();
+ }
+
+ /**
+ * Iterator to past the end of our lines.
+ */
+ Iterator end() const
+ {
+ return _lines.end();
+ }
+ };
+
+ /**
+ * A KeyValueConfigFileError is thrown if bad data is encountered in
+ * a ConfigFile.
+ *
+ * \ingroup grpkvconfigfile
+ * \ingroup grpexceptions
+ */
+ class KeyValueConfigFileError : public ConfigurationError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ KeyValueConfigFileError(const std::string & message,
+ const std::string & filename = "") throw ();
+ };
+
+ /**
+ * A KeyValueConfigFile is a ConfigFile that provides access to the
+ * normalised lines. Do not subclass.
+ *
+ * \ingroup grpkvconfigfile
+ */
+ class KeyValueConfigFile : protected ConfigFile
+ {
+ private:
+ mutable std::map<std::string, std::string> _entries;
+
+ protected:
+ void accept_line(const std::string &) const;
+
+ /**
+ * Handle variable replacement.
+ */
+ std::string replace_variables(const std::string &) const;
+
+ /**
+ * Handle quote removal.
+ */
+ std::string strip_quotes(const std::string &) const;
+
+ public:
+ /**
+ * Constructor, from a stream.
+ */
+ KeyValueConfigFile(std::istream * const);
+
+ /**
+ * Constructor, from a filename.
+ */
+ KeyValueConfigFile(const std::string & filename);
+
+ /**
+ * Constructor, from a filename.
+ */
+ KeyValueConfigFile(const FSEntry & filename);
+
+ /**
+ * Constructor, from a stream, with defaults.
+ */
+ KeyValueConfigFile(std::istream * const,
+ const std::map<std::string, std::string> &);
+
+ /**
+ * Constructor, from a filename, with defaults.
+ */
+ KeyValueConfigFile(const std::string & filename,
+ const std::map<std::string, std::string> &);
+
+ /**
+ * Constructor, from a filename, with defaults.
+ */
+ KeyValueConfigFile(const FSEntry & filename,
+ const std::map<std::string, std::string> &);
+
+ /**
+ * Destructor.
+ */
+ ~KeyValueConfigFile();
+
+ /**
+ * Iterator over our key/values.
+ */
+ typedef std::map<std::string, std::string>::const_iterator Iterator;
+
+ /**
+ * Start of our key/values.
+ */
+ Iterator begin() const
+ {
+ return _entries.begin();
+ }
+
+ /**
+ * Past the end of our key/values.
+ */
+ Iterator end() const
+ {
+ return _entries.end();
+ }
+
+ /**
+ * Fetch the specified key, or a blank string.
+ */
+ std::string get(const std::string & key) const
+ {
+ return _entries[key];
+ }
+ };
+
+ /**
+ * An AdvisoryFileError is thrown if bad data is encountered in
+ * a ConfigFile.
+ *
+ * \ingroup grpadvisoryconfigfile
+ * \ingroup grpexceptions
+ */
+ class AdvisoryFileError : public ConfigurationError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ AdvisoryFileError(const std::string & message,
+ const std::string & filename = "") throw ();
+ };
+
+ /**
+ * An AdvisoryFile is a file containing all necessary information to
+ * update one or more packages in order to avoid a security problem.
+ *
+ * It uses a textformat with RFC 822 style headers, an empty line denotes
+ * the beginning of a multi-line description of the security problem.
+ *
+ * Valid header items are:
+ * Affected, Bug-Url, Committed-By, Id, Reviewed-By, Unaffected, Url
+ *
+ * \ingroup grpadvisoryconfigfile
+ */
+
+ class AdvisoryFile : protected ConfigFile
+ {
+ private:
+ mutable std::map<std::string, std::string> _entries;
+ mutable std::list<std::string> _affected;
+ mutable std::list<std::string> _unaffected;
+ mutable bool _end_of_header;
+
+ protected:
+ void accept_line(const std::string &) const;
+ /**
+ * Ensure that the AdvisoryFile contains all mandatory items.
+ */
+ void sanitise();
+
+ public:
+ /**
+ * Constructor, from a stream.
+ */
+ AdvisoryFile(std::istream * const);
+
+ /**
+ * Constructor, from a filename.
+ */
+ AdvisoryFile(const std::string & filename);
+
+ /**
+ * Constructor, from a filename.
+ */
+ AdvisoryFile(const FSEntry & filename);
+
+ /**
+ * Constructor, from a stream, with defaults.
+ */
+ AdvisoryFile(std::istream * const,
+ const std::map<std::string, std::string> &);
+
+ /**
+ * Constructor, from a filename, with defaults.
+ */
+ AdvisoryFile(const std::string & filename,
+ const std::map<std::string, std::string> &);
+
+ /**
+ * Constructor, from a filename, with defaults.
+ */
+ AdvisoryFile(const FSEntry & filename,
+ const std::map<std::string, std::string> &);
+
+ /**
+ * Destructor.
+ */
+ ~AdvisoryFile();
+
+ /**
+ * Iterator over our lines.
+ */
+ typedef std::map<std::string, std::string>::const_iterator EntriesIterator;
+ typedef std::list<std::string>::const_iterator LineIterator;
+
+ /**
+ * Iterator to the start of our lines.
+ */
+ EntriesIterator begin() const
+ {
+ return _entries.begin();
+ }
+
+ /**
+ * Iterator to past the end of our lines.
+ */
+ EntriesIterator end() const
+ {
+ return _entries.end();
+ }
+
+ /**
+ * Iterator to the start of our Affected: lines.
+ */
+ LineIterator begin_affected() const
+ {
+ return _affected.begin();
+ }
+
+ /**
+ * Iterator to past the end of our Affected: lines.
+ */
+ LineIterator end_affected() const
+ {
+ return _affected.end();
+ }
+
+ /**
+ * Iterator to the start of our Unaffected: lines.
+ */
+ LineIterator begin_unaffected() const
+ {
+ return _unaffected.begin();
+ }
+
+ /**
+ * Iterator to past the end of our Unaffected: lines.
+ */
+ LineIterator end_unaffected() const
+ {
+ return _unaffected.end();
+ }
+
+ /**
+ * Fetch the specified key, or a blank string.
+ */
+ std::string get(const std::string & key) const
+ {
+ return _entries[key];
+ }
+
+ };
+
+ /**
+ * A NewsFile represents a GLEP 42 news file.
+ *
+ * \ingroup grpconfigfile
+ */
+ class NewsFile :
+ protected ConfigFile
+ {
+ private:
+ mutable bool _in_header;
+ mutable std::list<std::string> _display_if_installed;
+ mutable std::list<std::string> _display_if_keyword;
+ mutable std::list<std::string> _display_if_profile;
+
+ protected:
+ void accept_line(const std::string &) const;
+
+ public:
+ /**
+ * Constructor, from a filename.
+ */
+ NewsFile(const FSEntry & filename);
+
+ typedef std::list<std::string>::const_iterator DisplayIfInstalledIterator;
+
+ DisplayIfInstalledIterator begin_display_if_installed() const
+ {
+ return _display_if_installed.begin();
+ }
+
+ DisplayIfInstalledIterator end_display_if_installed() const
+ {
+ return _display_if_installed.end();
+ }
+
+ typedef std::list<std::string>::const_iterator DisplayIfKeywordIterator;
+
+ DisplayIfKeywordIterator begin_display_if_keyword() const
+ {
+ return _display_if_keyword.begin();
+ }
+
+ DisplayIfKeywordIterator end_display_if_keyword() const
+ {
+ return _display_if_keyword.end();
+ }
+
+ typedef std::list<std::string>::const_iterator DisplayIfProfileIterator;
+
+ DisplayIfProfileIterator begin_display_if_profile() const
+ {
+ return _display_if_profile.begin();
+ }
+
+ DisplayIfProfileIterator end_display_if_profile() const
+ {
+ return _display_if_profile.end();
+ }
+ };
+}
+
+#endif
diff --git a/0.4.0/paludis/config_file_TEST.cc b/0.4.0/paludis/config_file_TEST.cc
new file mode 100644
index 000000000..0ac913a3a
--- /dev/null
+++ b/0.4.0/paludis/config_file_TEST.cc
@@ -0,0 +1,305 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/config_file.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/stringify.hh>
+#include <sstream>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <vector>
+#include <unistd.h>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for config_file.hh .
+ *
+ * \ingroup grptestcases
+ * \ingroup grpconfigfile
+ */
+
+namespace
+{
+ /**
+ * A ConfigFile descendent for use in tests.
+ *
+ * \ingroup grptestcases
+ */
+ class TestFile : protected ConfigFile
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ TestFile(std::istream * const stream) :
+ ConfigFile(stream)
+ {
+ need_lines();
+ }
+
+ /**
+ * Constructor.
+ */
+ TestFile(const std::string & filename) :
+ ConfigFile(filename)
+ {
+ need_lines();
+ }
+
+ /**
+ * Constructor.
+ */
+ TestFile(const FSEntry & filename) :
+ ConfigFile(filename)
+ {
+ need_lines();
+ }
+
+ /**
+ * Our lines.
+ */
+ mutable std::vector<std::string> lines;
+
+ protected:
+ void accept_line(const std::string & s) const
+ {
+ lines.push_back(s);
+ }
+ };
+}
+
+namespace test_cases
+{
+ /**
+ * \test Test ConfigFile.
+ *
+ * \ingroup grptestcases
+ */
+ struct ConfigFileTest : TestCase
+ {
+ ConfigFileTest() : TestCase("config file") { }
+
+ void run()
+ {
+ std::stringstream s;
+ s << "one" << std::endl;
+ s << " two \t " << std::endl;
+ s << " \t " << std::endl;
+ s << "" << std::endl;
+ s << "three" << std::endl;
+ s << "# blah" << std::endl;
+ s << " # blah" << std::endl;
+ s << "#" << std::endl;
+ s << " # \t " << std::endl;
+ s << "four four" << std::endl;
+ TestFile f(&s);
+ TEST_CHECK_EQUAL(f.lines.size(), 4);
+ TEST_CHECK_EQUAL(f.lines.at(0), "one");
+ TEST_CHECK_EQUAL(f.lines.at(1), "two");
+ TEST_CHECK_EQUAL(f.lines.at(2), "three");
+ TEST_CHECK_EQUAL(f.lines.at(3), "four four");
+ }
+ } test_config_file;
+
+ /**
+ * \test Test ConfigFile with file opening.
+ *
+ * \ingroup grptestcases
+ */
+ struct ConfigFileOpenFileTest : TestCase
+ {
+ ConfigFileOpenFileTest() : TestCase("config file open file") { }
+
+ void run()
+ {
+ FSEntry ff("config_file_TEST_dir/config_file");
+ TEST_CHECK(ff.is_regular_file());
+ TestFile f(ff);
+ TEST_CHECK_EQUAL(f.lines.size(), 1);
+ TEST_CHECK_EQUAL(f.lines.at(0), "I am a fish.");
+
+ FSEntry ff2("config_file_TEST_dir/not_a_config_file");
+ TEST_CHECK(! ff2.exists());
+ TestFile * f2(0);
+ TEST_CHECK_THROWS(f2 = new TestFile(ff2), ConfigFileError);
+
+ if (0 != geteuid())
+ {
+ FSEntry ff3("config_file_TEST_dir/unreadable_file");
+ TEST_CHECK(ff3.is_regular_file());
+ TestFile * f3(0);
+ TEST_CHECK_THROWS(f3 = new TestFile(ff3), ConfigFileError);
+ }
+ }
+ } test_config_file_open_file;
+
+ /**
+ * \test Test LineConfigFile.
+ *
+ * \ingroup grptestcases
+ */
+ struct LineConfigFileTest : TestCase
+ {
+ LineConfigFileTest() : TestCase("line config file") { }
+
+ void run()
+ {
+ std::stringstream s;
+ s << "one" << std::endl;
+ s << " two \t " << std::endl;
+ s << " \t " << std::endl;
+ s << "" << std::endl;
+ s << "three" << std::endl;
+ s << "# blah" << std::endl;
+ s << " # blah" << std::endl;
+ s << "#" << std::endl;
+ s << " # \t " << std::endl;
+ s << "four four" << std::endl;
+ LineConfigFile ff(&s);
+ std::vector<std::string> f(ff.begin(), ff.end());
+
+ TEST_CHECK_EQUAL(f.size(), 4);
+ TEST_CHECK_EQUAL(f.at(0), "one");
+ TEST_CHECK_EQUAL(f.at(1), "two");
+ TEST_CHECK_EQUAL(f.at(2), "three");
+ TEST_CHECK_EQUAL(f.at(3), "four four");
+ }
+ } test_line_config_file;
+
+ /**
+ * \test Test KeyValueConfigFile basics.
+ *
+ * \ingroup grptestcases
+ */
+ struct KeyValueConfigFileTest : TestCase
+ {
+ KeyValueConfigFileTest() : TestCase("key value config file") { }
+
+ void run()
+ {
+ std::stringstream s;
+ s << "one=first" << std::endl;
+ s << "two = second" << std::endl;
+ s << "three" << std::endl;
+ s << "four = \"fourth\" " << std::endl;
+ s << "five = ''" << std::endl;
+ KeyValueConfigFile ff(&s);
+
+ TEST_CHECK_EQUAL(ff.get("one"), "first");
+ TEST_CHECK_EQUAL(ff.get("two"), "second");
+ TEST_CHECK_EQUAL(ff.get("three"), "");
+ TEST_CHECK_EQUAL(ff.get("four"), "fourth");
+ TEST_CHECK_EQUAL(ff.get("five"), "");
+ TEST_CHECK_EQUAL(ff.get("six"), "");
+ }
+ } test_key_value_config_file;
+
+ /**
+ * \test Test KeyValueConfigFile variables.
+ *
+ * \ingroup grptestcases
+ */
+ struct KeyValueConfigFileVarsTest : TestCase
+ {
+ KeyValueConfigFileVarsTest() : TestCase("key value config file with vars") { }
+
+ void run()
+ {
+ std::stringstream s;
+ s << "x=foo" << std::endl;
+ s << "y = \"${x}\\\\${y}\\$${z}\"" << std::endl;
+ s << "z = $x$y$z" << std::endl;
+ KeyValueConfigFile ff(&s);
+
+ TEST_CHECK_EQUAL(ff.get("x"), "foo");
+ TEST_CHECK_EQUAL(ff.get("y"), "foo\\$");
+ TEST_CHECK_EQUAL(ff.get("z"), "foofoo\\$");
+
+ std::stringstream t;
+ std::map<std::string, std::string> t_defs;
+ t_defs.insert(std::make_pair("a", "moo"));
+ t_defs.insert(std::make_pair("d", "bar"));
+ t_defs.insert(std::make_pair("e", "baz"));
+ t << "a=foo" << std::endl;
+ t << "b=$a" << std::endl;
+ t << "c=$d" << std::endl;
+ t << "d=$d" << std::endl;
+ t << "f = " << std::endl;
+ t << "g = foo \\" << std::endl;
+ t << " bar" << std::endl;
+ KeyValueConfigFile fg(&t, t_defs);
+
+ TEST_CHECK_EQUAL(fg.get("a"), "foo");
+ TEST_CHECK_EQUAL(fg.get("b"), "foo");
+ TEST_CHECK_EQUAL(fg.get("c"), "bar");
+ TEST_CHECK_EQUAL(fg.get("d"), "bar");
+ TEST_CHECK_EQUAL(fg.get("e"), "baz");
+ TEST_CHECK_EQUAL(fg.get("f"), "");
+ TEST_CHECK_EQUAL(fg.get("g"), "foo bar");
+ }
+ } test_key_value_config_file_vars;
+
+ /**
+ * \test Test KeyValueConfigFile errors.
+ *
+ * \ingroup grptestcases
+ */
+ struct KeyValueConfigFileErrorsTest : TestCase
+ {
+ KeyValueConfigFileErrorsTest() : TestCase("key value config file with errors") { }
+
+ void run()
+ {
+ std::stringstream s1;
+ s1 << "x='" << std::endl;
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(&s1), ConfigurationError);
+
+ std::stringstream s2;
+ s2 << "x='moo\"" << std::endl;
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(&s2), ConfigurationError);
+
+ std::stringstream s3;
+ s3 << "x=${foo" << std::endl;
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(&s3), ConfigurationError);
+
+ std::stringstream s4;
+ s4 << "x=$~" << std::endl;
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(&s4), ConfigurationError);
+
+ std::stringstream s5;
+ s5 << "x=abc\\" << std::endl;
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(&s5), ConfigurationError);
+
+ std::stringstream s6;
+ s6 << "x=$" << std::endl;
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(&s6), ConfigurationError);
+
+ std::stringstream s7;
+ s7 << "x=blah \\" << std::endl;
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(&s7), ConfigurationError);
+
+ std::stringstream s8;
+ s8 << "x=blah \\" << std::endl << "# foo" << std::endl;
+ TEST_CHECK_THROWS(KeyValueConfigFile ff(&s8), ConfigurationError);
+ }
+ } test_key_value_config_file_errors;
+}
+
diff --git a/0.4.0/paludis/config_file_TEST_cleanup.sh b/0.4.0/paludis/config_file_TEST_cleanup.sh
new file mode 100755
index 000000000..b4ed3dbde
--- /dev/null
+++ b/0.4.0/paludis/config_file_TEST_cleanup.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -d config_file_TEST_dir ] ; then
+ rm -fr config_file_TEST_dir
+else
+ true
+fi
+
+
diff --git a/0.4.0/paludis/config_file_TEST_setup.sh b/0.4.0/paludis/config_file_TEST_setup.sh
new file mode 100755
index 000000000..a35809b84
--- /dev/null
+++ b/0.4.0/paludis/config_file_TEST_setup.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+mkdir config_file_TEST_dir || exit 2
+cd config_file_TEST_dir || exit 3
+echo "I am a fish." > config_file || exit 4
+echo "I am a fish too." > unreadable_file || exit 5
+chmod a-r unreadable_file || exit 6
+
diff --git a/0.4.0/paludis/contents.cc b/0.4.0/paludis/contents.cc
new file mode 100644
index 000000000..ad9acfa5c
--- /dev/null
+++ b/0.4.0/paludis/contents.cc
@@ -0,0 +1,58 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "contents.hh"
+
+/** \file
+ * Implementation for Contents classes.
+ *
+ * \ingroup grpcontents
+ */
+
+using namespace paludis;
+
+ContentsEntry::~ContentsEntry()
+{
+}
+
+ContentsFileEntry::ContentsFileEntry(const std::string & name) :
+ ContentsEntry(name)
+{
+}
+
+ContentsDirEntry::ContentsDirEntry(const std::string & name) :
+ ContentsEntry(name)
+{
+}
+
+ContentsMiscEntry::ContentsMiscEntry(const std::string & name) :
+ ContentsEntry(name)
+{
+}
+
+ContentsSymEntry::ContentsSymEntry(const std::string & name, const std::string & target) :
+ ContentsEntry(name),
+ _target(target)
+{
+}
+
+Contents::Contents()
+{
+}
+
diff --git a/0.4.0/paludis/contents.hh b/0.4.0/paludis/contents.hh
new file mode 100644
index 000000000..82dc47085
--- /dev/null
+++ b/0.4.0/paludis/contents.hh
@@ -0,0 +1,173 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_CONTENTS_HH
+#define PALUDIS_GUARD_PALUDIS_CONTENTS_HH 1
+
+#include <paludis/util/visitor.hh>
+#include <paludis/util/counted_ptr.hh>
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <string>
+
+/** \file
+ * Declarations for the Contents classes.
+ *
+ * \ingroup grpcontents
+ */
+
+namespace paludis
+{
+ struct ContentsEntry;
+ struct ContentsFileEntry;
+ struct ContentsDirEntry;
+ struct ContentsSymEntry;
+ struct ContentsMiscEntry;
+
+ /**
+ * Visit a contents heirarchy.
+ *
+ * \ingroup grpcontents
+ */
+ typedef VisitorTypes<ContentsFileEntry *, ContentsDirEntry *,
+ ContentsSymEntry *, ContentsMiscEntry *> ContentsVisitorTypes;
+
+ /**
+ * Base class for a contents entry.
+ *
+ * \ingroup grpcontents
+ */
+ class ContentsEntry :
+ private InstantiationPolicy<ContentsEntry, instantiation_method::NonCopyableTag>,
+ public InternalCounted<ContentsEntry>,
+ public virtual VisitableInterface<ContentsVisitorTypes>
+ {
+ private:
+ std::string _name;
+
+ protected:
+ ContentsEntry(const std::string & name) :
+ _name(name)
+ {
+ }
+
+ public:
+ virtual ~ContentsEntry();
+
+ std::string name() const
+ {
+ return _name;
+ }
+ };
+
+ /**
+ * A file contents entry.
+ *
+ * \ingroup grpcontents
+ */
+ class ContentsFileEntry :
+ public ContentsEntry,
+ public Visitable<ContentsFileEntry, ContentsVisitorTypes>
+ {
+ public:
+ ContentsFileEntry(const std::string & name);
+ };
+
+ /**
+ * A directory contents entry.
+ *
+ * \ingroup grpcontents
+ */
+ class ContentsDirEntry :
+ public ContentsEntry,
+ public Visitable<ContentsDirEntry, ContentsVisitorTypes>
+ {
+ public:
+ ContentsDirEntry(const std::string & name);
+ };
+
+ /**
+ * A misc contents entry.
+ *
+ * \ingroup grpcontents
+ */
+ class ContentsMiscEntry :
+ public ContentsEntry,
+ public Visitable<ContentsMiscEntry, ContentsVisitorTypes>
+ {
+ public:
+ ContentsMiscEntry(const std::string & name);
+ };
+
+ /**
+ * A sym contents entry.
+ *
+ * \ingroup grpcontents
+ */
+ class ContentsSymEntry :
+ public ContentsEntry,
+ public Visitable<ContentsSymEntry, ContentsVisitorTypes>
+ {
+ private:
+ std::string _target;
+
+ public:
+ ContentsSymEntry(const std::string & name, const std::string & target);
+
+ std::string target() const
+ {
+ return _target;
+ }
+ };
+
+ /**
+ * A package's contents.
+ *
+ * \ingroup grpcontents
+ */
+ class Contents :
+ private InstantiationPolicy<Contents, instantiation_method::NonCopyableTag>,
+ public InternalCounted<Contents>
+ {
+ private:
+ std::list<ContentsEntry::ConstPointer> _c;
+
+ public:
+ Contents();
+
+ void add(ContentsEntry::ConstPointer c)
+ {
+ _c.push_back(c);
+ }
+
+ typedef std::list<ContentsEntry::ConstPointer>::const_iterator Iterator;
+
+ Iterator begin() const
+ {
+ return _c.begin();
+ }
+
+ Iterator end() const
+ {
+ return _c.end();
+ }
+ };
+}
+
+#endif
diff --git a/0.4.0/paludis/default_config.cc b/0.4.0/paludis/default_config.cc
new file mode 100644
index 000000000..885b29dfc
--- /dev/null
+++ b/0.4.0/paludis/default_config.cc
@@ -0,0 +1,654 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/config_file.hh>
+#include <paludis/default_config.hh>
+#include <paludis/util/destringify.hh>
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/iterator.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/is_file_with_extension.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/tokeniser.hh>
+
+#include <fstream>
+#include <algorithm>
+#include <sstream>
+
+#include <ctype.h>
+
+/** \file
+ * Implementation of default_config.hh classes.
+ *
+ * \ingroup grpdefaultconfig
+ */
+
+using namespace paludis;
+
+namespace paludis
+{
+ /**
+ * Implementation data for DefaultConfig.
+ *
+ * \ingroup grpdefaultconfig
+ */
+ template<>
+ struct Implementation<DefaultConfig> :
+ InternalCounted<DefaultConfig>,
+ InstantiationPolicy<DefaultConfig, instantiation_method::NonCopyableTag>
+ {
+ static std::string config_suffix;
+ static bool config_suffix_can_be_set;
+ std::string paludis_command;
+ std::string root;
+ std::string config_dir;
+ std::string bashrc_files;
+
+ std::list<RepositoryConfigEntry> repos;
+
+ std::map<QualifiedPackageName, std::vector<
+ std::pair<PackageDepAtom::ConstPointer, KeywordName> > > keywords;
+
+ const std::vector<std::pair<PackageDepAtom::ConstPointer, KeywordName> > empty_keywords;
+
+ std::vector<KeywordName> default_keywords;
+
+ std::map<QualifiedPackageName, std::vector<
+ std::pair<PackageDepAtom::ConstPointer, std::string> > > licenses;
+
+ const std::vector<std::pair<PackageDepAtom::ConstPointer, std::string> > empty_licenses;
+
+ std::vector<std::string> default_licenses;
+
+ std::map<QualifiedPackageName, std::vector<PackageDepAtom::ConstPointer> > user_masks;
+
+ std::map<QualifiedPackageName, std::vector<PackageDepAtom::ConstPointer> > user_unmasks;
+
+ std::vector<PackageDepAtom::ConstPointer> empty_masks;
+
+ std::map<QualifiedPackageName, std::vector<UseConfigEntry> > use;
+
+ std::vector<UseConfigEntry> empty_use;
+
+ std::vector<std::pair<UseFlagName, UseFlagState> > default_use;
+
+ std::multimap<std::string, std::string> mirrors;
+
+ Implementation() :
+ paludis_command("paludis")
+ {
+ }
+ };
+}
+
+DefaultConfigError::DefaultConfigError(const std::string & msg) throw () :
+ ConfigurationError("Default configuration error: " + msg)
+{
+}
+
+DefaultConfig::DefaultConfig() :
+ PrivateImplementationPattern<DefaultConfig>(new Implementation<DefaultConfig>)
+{
+ _imp->config_suffix_can_be_set = false;
+
+ Context context("When loading default configuration:");
+
+ if (! getenv_with_default("PALUDIS_SKIP_CONFIG", "").empty())
+ return;
+
+ /* indirection */
+ std::string root_prefix;
+ std::string config_suffix;
+ if (! _imp->config_suffix.empty())
+ config_suffix = "-" + _imp->config_suffix;
+
+ FSEntry config_dir(FSEntry(getenv_with_default("PALUDIS_HOME", getenv_or_error("HOME"))) /
+ (".paludis" + config_suffix));
+ if (! config_dir.exists())
+ config_dir = (FSEntry(SYSCONFDIR) / ("paludis" + config_suffix));
+ if (! config_dir.exists())
+ throw DefaultConfigError("Can't find configuration directory");
+
+ Log::get_instance()->message(ll_debug, lc_no_context, "DefaultConfig initial directory is '"
+ + stringify(config_dir) + "'");
+
+ if ((config_dir / "specpath").exists())
+ {
+ KeyValueConfigFile specpath(config_dir / "specpath");
+ root_prefix = specpath.get("root");
+ config_suffix = specpath.get("config-suffix");
+
+ if (! root_prefix.empty() && stringify(FSEntry(root_prefix).realpath()) != "/")
+ {
+ config_dir = FSEntry(root_prefix) / SYSCONFDIR / ("paludis" + config_suffix);
+ if (! config_dir.exists())
+ throw DefaultConfigError("Can't find configuration directory under root ("
+ "tried '" + stringify(config_dir) + "'");
+ }
+ }
+
+ _imp->root = root_prefix;
+ _imp->config_dir = stringify(config_dir);
+
+ std::map<std::string, std::string> conf_vars;
+ conf_vars.insert(std::make_pair("ROOT", root_prefix));
+
+ Log::get_instance()->message(ll_debug, lc_no_context, "DefaultConfig real directory is '"
+ + stringify(config_dir) + "', root prefix is '" + root_prefix +
+ "', config suffix is '" + config_suffix + "'");
+
+ /* repositories */
+ {
+ std::list<FSEntry> dirs;
+ dirs.push_back(config_dir / "repositories");
+
+ std::list<FSEntry> repo_files;
+ for (std::list<FSEntry>::const_iterator dir(dirs.begin()), dir_end(dirs.end()) ;
+ dir != dir_end ; ++dir)
+ {
+ if (! dir->exists())
+ continue;
+
+ std::copy(DirIterator(*dir), DirIterator(),
+ filter_inserter(std::back_inserter(repo_files), IsFileWithExtension(".conf")));
+ }
+
+ for (std::list<FSEntry>::const_iterator repo_file(repo_files.begin()), repo_file_end(repo_files.end()) ;
+ repo_file != repo_file_end ; ++repo_file)
+ {
+ Context local_context("When reading repository file '" + stringify(*repo_file) + "':");
+
+ KeyValueConfigFile k(*repo_file, conf_vars);
+
+ std::string format(k.get("format"));
+ if (format.empty())
+ throw DefaultConfigError("Key 'format' not specified or empty");
+
+ int importance(0);
+ if (! k.get("importance").empty())
+ importance = destringify<int>(k.get("importance"));
+
+ std::map<std::string, std::string> keys(k.begin(), k.end());
+ keys["repo_file"] = stringify(*repo_file);
+ keys["root"] = root_prefix;
+ _imp->repos.push_back(RepositoryConfigEntry(format, importance, keys));
+ }
+
+ if (_imp->repos.empty())
+ throw DefaultConfigError("No repositories specified");
+
+ _imp->repos.sort();
+ }
+
+ /* keywords */
+ {
+ std::list<FSEntry> files;
+ files.push_back(config_dir / "keywords.conf");
+
+ for (std::list<FSEntry>::const_iterator file(files.begin()), file_end(files.end()) ;
+ file != file_end ; ++file)
+ {
+ Context local_context("When reading keywords file '" + stringify(*file) + "':");
+
+ if (! file->is_regular_file())
+ continue;
+
+ LineConfigFile f(*file);
+ for (LineConfigFile::Iterator line(f.begin()), line_end(f.end()) ;
+ line != line_end ; ++line)
+ {
+ std::vector<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(tokens));
+ if (tokens.empty())
+ continue;
+ if ("*" == tokens.at(0))
+ std::copy(next(tokens.begin()), tokens.end(),
+ create_inserter<KeywordName>(std::back_inserter(_imp->default_keywords)));
+ else
+ {
+ PackageDepAtom::ConstPointer a(new PackageDepAtom(tokens.at(0)));
+ for (std::vector<std::string>::const_iterator t(next(tokens.begin())), t_end(tokens.end()) ;
+ t != t_end ; ++t)
+ _imp->keywords[a->package()].push_back(std::make_pair(a, *t));
+ }
+ }
+ }
+
+ if (_imp->default_keywords.empty())
+ throw DefaultConfigError("No default keywords specified (a keywords.conf file should "
+ "contain an entry in the form '* keyword')");
+ }
+
+ /* licenses */
+ {
+ std::list<FSEntry> files;
+ files.push_back(config_dir / "licenses.conf");
+
+ for (std::list<FSEntry>::const_iterator file(files.begin()), file_end(files.end()) ;
+ file != file_end ; ++file)
+ {
+ Context local_context("When reading licenses file '" + stringify(*file) + "':");
+
+ if (! file->is_regular_file())
+ continue;
+
+ LineConfigFile f(*file);
+ for (LineConfigFile::Iterator line(f.begin()), line_end(f.end()) ;
+ line != line_end ; ++line)
+ {
+ std::vector<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(tokens));
+ if (tokens.empty())
+ continue;
+ if ("*" == tokens.at(0))
+ std::copy(next(tokens.begin()), tokens.end(), std::back_inserter(_imp->default_licenses));
+ else
+ {
+ PackageDepAtom::ConstPointer a(new PackageDepAtom(tokens.at(0)));
+ for (std::vector<std::string>::const_iterator t(next(tokens.begin())), t_end(tokens.end()) ;
+ t != t_end ; ++t)
+ _imp->licenses[a->package()].push_back(std::make_pair(a, *t));
+ }
+ }
+ }
+
+ if (_imp->default_licenses.empty())
+ throw DefaultConfigError("No default licenses specified (a licenses.conf file should "
+ "contain an entry in the form '* license license', or '* *' if you don't want any "
+ "license filtering)");
+ }
+
+ /* user mask */
+ {
+ std::list<FSEntry> files;
+ files.push_back(config_dir / "package_mask.conf");
+
+ for (std::list<FSEntry>::const_iterator file(files.begin()), file_end(files.end()) ;
+ file != file_end ; ++file)
+ {
+ Context local_context("When reading package_mask file '" + stringify(*file) + "':");
+
+ if (! file->is_regular_file())
+ continue;
+
+ LineConfigFile f(*file);
+ for (LineConfigFile::Iterator line(f.begin()), line_end(f.end()) ;
+ line != line_end ; ++line)
+ {
+ PackageDepAtom::ConstPointer a(new PackageDepAtom(*line));
+ _imp->user_masks[a->package()].push_back(a);
+ }
+ }
+ }
+
+ /* user unmask */
+ {
+ std::list<FSEntry> files;
+ files.push_back(config_dir / "package_unmask.conf");
+
+ for (std::list<FSEntry>::const_iterator file(files.begin()), file_end(files.end()) ;
+ file != file_end ; ++file)
+ {
+ Context local_context("When reading package_unmask file '" + stringify(*file) + "':");
+
+ if (! file->is_regular_file())
+ continue;
+
+ LineConfigFile f(*file);
+ for (LineConfigFile::Iterator line(f.begin()), line_end(f.end()) ;
+ line != line_end ; ++line)
+ {
+ PackageDepAtom::ConstPointer a(new PackageDepAtom(*line));
+ _imp->user_unmasks[a->package()].push_back(a);
+ }
+ }
+ }
+
+ /* use */
+ {
+ std::list<FSEntry> files;
+ files.push_back(config_dir / "use.conf");
+
+ for (std::list<FSEntry>::const_iterator file(files.begin()), file_end(files.end()) ;
+ file != file_end ; ++file)
+ {
+ Context local_context("When reading use file '" + stringify(*file) + "':");
+
+ if (! file->is_regular_file())
+ continue;
+
+ LineConfigFile f(*file);
+ for (LineConfigFile::Iterator line(f.begin()), line_end(f.end()) ;
+ line != line_end ; ++line)
+ {
+ std::vector<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(tokens));
+ if (tokens.empty())
+ continue;
+
+ std::string prefix;
+ if ("*" == tokens.at(0))
+ for (std::vector<std::string>::const_iterator t(next(tokens.begin())), t_end(tokens.end()) ;
+ t != t_end ; ++t)
+ {
+ if ('-' == t->at(0))
+ _imp->default_use.push_back(std::make_pair(UseFlagName(
+ prefix + t->substr(1)), use_disabled));
+ else if (':' == t->at(t->length() - 1))
+ {
+ prefix.clear();
+ std::transform(t->begin(), previous(t->end()), std::back_inserter(prefix),
+ &::tolower);
+ prefix.append("_");
+ }
+ else
+ _imp->default_use.push_back(std::make_pair(UseFlagName(
+ prefix + *t), use_enabled));
+ }
+ else
+ {
+ PackageDepAtom::ConstPointer a(new PackageDepAtom(tokens.at(0)));
+ for (std::vector<std::string>::const_iterator t(next(tokens.begin())), t_end(tokens.end()) ;
+ t != t_end ; ++t)
+ {
+ if ('-' == t->at(0))
+ _imp->use[a->package()].push_back(UseConfigEntry(
+ a, UseFlagName(prefix + t->substr(1)), use_disabled));
+ else if (':' == t->at(t->length() - 1))
+ {
+ prefix.clear();
+ std::transform(t->begin(), previous(t->end()), std::back_inserter(prefix),
+ &::tolower);
+ prefix.append("_");
+ }
+ else
+ _imp->use[a->package()].push_back(UseConfigEntry(
+ a, UseFlagName(prefix + *t), use_enabled));
+ }
+ }
+ }
+ }
+
+ if (_imp->default_keywords.empty())
+ throw DefaultConfigError("No default keywords specified (a keywords.conf file should "
+ "contain an entry in the form '* keyword')");
+ }
+
+ /* mirrors */
+ {
+ std::list<FSEntry> files;
+ files.push_back(config_dir / "mirrors.conf");
+
+ for (std::list<FSEntry>::const_iterator file(files.begin()), file_end(files.end()) ;
+ file != file_end ; ++file)
+ {
+ Context local_context("When reading mirrors file '" + stringify(*file) + "':");
+
+ if (! file->is_regular_file())
+ continue;
+
+ LineConfigFile f(*file);
+ for (LineConfigFile::Iterator line(f.begin()), line_end(f.end()) ;
+ line != line_end ; ++line)
+ {
+ std::vector<std::string> m;
+ WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(m));
+ if (m.size() < 2)
+ continue;
+ for (std::vector<std::string>::const_iterator mm(next(m.begin())),
+ mm_end(m.end()) ; mm != mm_end ; ++mm)
+ _imp->mirrors.insert(std::make_pair(m.at(0), *mm));
+ }
+ }
+ }
+
+ _imp->bashrc_files = stringify(config_dir / "bashrc");
+}
+
+DefaultConfig::~DefaultConfig()
+{
+}
+
+std::string Implementation<DefaultConfig>::config_suffix;
+bool Implementation<DefaultConfig>::config_suffix_can_be_set(true);
+
+void
+DefaultConfig::set_config_suffix(const std::string & s)
+{
+ if (! Implementation<DefaultConfig>::config_suffix_can_be_set)
+ throw InternalError(PALUDIS_HERE, "DefaultConfig::set_config_suffix called after "
+ "DefaultConfig has been instantiated.");
+
+ static const std::string allowed_chars(
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789-_+:");
+
+ if (std::string::npos != s.find_first_not_of(allowed_chars))
+ throw DefaultConfigError("Invalid config suffix '" + s + "'");
+
+ if (! s.empty())
+ if ('-' == s.at(0) || '-' == s.at(s.length() - 1))
+ throw DefaultConfigError("Invalid config suffix '" + s + "'");
+
+ Implementation<DefaultConfig>::config_suffix = s;
+}
+
+std::string
+DefaultConfig::bashrc_files() const
+{
+ return _imp->bashrc_files;
+}
+
+std::string
+DefaultConfig::config_suffix()
+{
+ return Implementation<DefaultConfig>::config_suffix;
+}
+
+DefaultConfig::RepositoryIterator
+DefaultConfig::begin_repositories() const
+{
+ return _imp->repos.begin();
+}
+
+DefaultConfig::RepositoryIterator
+DefaultConfig::end_repositories() const
+{
+ return _imp->repos.end();
+}
+
+DefaultConfig::PackageKeywordsIterator
+DefaultConfig::begin_package_keywords(const QualifiedPackageName & d) const
+{
+ std::map<QualifiedPackageName, std::vector<
+ std::pair<PackageDepAtom::ConstPointer, KeywordName> > >::const_iterator r;
+ if (_imp->keywords.end() != ((r = _imp->keywords.find(d))))
+ return r->second.begin();
+ else
+ return _imp->empty_keywords.begin();
+}
+
+DefaultConfig::PackageKeywordsIterator
+DefaultConfig::end_package_keywords(const QualifiedPackageName & d) const
+{
+ std::map<QualifiedPackageName, std::vector<
+ std::pair<PackageDepAtom::ConstPointer, KeywordName> > >::const_iterator r;
+ if (_imp->keywords.end() != ((r = _imp->keywords.find(d))))
+ return r->second.end();
+ else
+ return _imp->empty_keywords.end();
+}
+
+DefaultConfig::DefaultKeywordsIterator
+DefaultConfig::begin_default_keywords() const
+{
+ return _imp->default_keywords.begin();
+}
+
+DefaultConfig::DefaultKeywordsIterator
+DefaultConfig::end_default_keywords() const
+{
+ return _imp->default_keywords.end();
+}
+
+DefaultConfig::PackageLicensesIterator
+DefaultConfig::begin_package_licenses(const QualifiedPackageName & d) const
+{
+ std::map<QualifiedPackageName, std::vector<
+ std::pair<PackageDepAtom::ConstPointer, std::string> > >::const_iterator r;
+ if (_imp->licenses.end() != ((r = _imp->licenses.find(d))))
+ return r->second.begin();
+ else
+ return _imp->empty_licenses.begin();
+}
+
+DefaultConfig::PackageLicensesIterator
+DefaultConfig::end_package_licenses(const QualifiedPackageName & d) const
+{
+ std::map<QualifiedPackageName, std::vector<
+ std::pair<PackageDepAtom::ConstPointer, std::string> > >::const_iterator r;
+ if (_imp->licenses.end() != ((r = _imp->licenses.find(d))))
+ return r->second.end();
+ else
+ return _imp->empty_licenses.end();
+}
+
+DefaultConfig::DefaultLicensesIterator
+DefaultConfig::begin_default_licenses() const
+{
+ return _imp->default_licenses.begin();
+}
+
+DefaultConfig::DefaultLicensesIterator
+DefaultConfig::end_default_licenses() const
+{
+ return _imp->default_licenses.end();
+}
+
+DefaultConfig::UserMasksIterator
+DefaultConfig::begin_user_masks(const QualifiedPackageName & d) const
+{
+ std::map<QualifiedPackageName, std::vector<PackageDepAtom::ConstPointer> >::const_iterator r;
+ if (_imp->user_masks.end() != ((r = _imp->user_masks.find(d))))
+ return r->second.begin();
+ else
+ return _imp->empty_masks.begin();
+}
+
+DefaultConfig::UserMasksIterator
+DefaultConfig::end_user_masks(const QualifiedPackageName & d) const
+{
+ std::map<QualifiedPackageName, std::vector<PackageDepAtom::ConstPointer> >::const_iterator r;
+ if (_imp->user_masks.end() != ((r = _imp->user_masks.find(d))))
+ return r->second.end();
+ else
+ return _imp->empty_masks.end();
+}
+
+DefaultConfig::UserUnmasksIterator
+DefaultConfig::begin_user_unmasks(const QualifiedPackageName & d) const
+{
+ std::map<QualifiedPackageName, std::vector<PackageDepAtom::ConstPointer> >::const_iterator r;
+ if (_imp->user_unmasks.end() != ((r = _imp->user_unmasks.find(d))))
+ return r->second.begin();
+ else
+ return _imp->empty_masks.begin();
+}
+
+DefaultConfig::UserUnmasksIterator
+DefaultConfig::end_user_unmasks(const QualifiedPackageName & d) const
+{
+ std::map<QualifiedPackageName, std::vector<PackageDepAtom::ConstPointer> >::const_iterator r;
+ if (_imp->user_unmasks.end() != ((r = _imp->user_unmasks.find(d))))
+ return r->second.end();
+ else
+ return _imp->empty_masks.end();
+}
+
+DefaultConfig::UseConfigIterator
+DefaultConfig::begin_use_config(const QualifiedPackageName & q) const
+{
+ std::map<QualifiedPackageName, std::vector<UseConfigEntry> >::const_iterator r;
+ if (_imp->use.end() != ((r = _imp->use.find(q))))
+ return r->second.begin();
+ else
+ return _imp->empty_use.begin();
+}
+
+DefaultConfig::UseConfigIterator
+DefaultConfig::end_use_config(const QualifiedPackageName & q) const
+{
+ std::map<QualifiedPackageName, std::vector<UseConfigEntry> >::const_iterator r;
+ if (_imp->use.end() != ((r = _imp->use.find(q))))
+ return r->second.end();
+ else
+ return _imp->empty_use.end();
+}
+
+DefaultConfig::DefaultUseIterator
+DefaultConfig::begin_default_use() const
+{
+ return _imp->default_use.begin();
+}
+
+DefaultConfig::DefaultUseIterator
+DefaultConfig::end_default_use() const
+{
+ return _imp->default_use.end();
+}
+
+std::string
+DefaultConfig::paludis_command() const
+{
+ return _imp->paludis_command;
+}
+
+void
+DefaultConfig::set_paludis_command(const std::string & s)
+{
+ _imp->paludis_command = s;
+}
+
+std::string
+DefaultConfig::root() const
+{
+ return _imp->root;
+}
+
+std::string
+DefaultConfig::config_dir() const
+{
+ return _imp->config_dir;
+}
+
+DefaultConfig::MirrorIterator
+DefaultConfig::begin_mirrors(const std::string & m) const
+{
+ return _imp->mirrors.lower_bound(m);
+}
+
+DefaultConfig::MirrorIterator
+DefaultConfig::end_mirrors(const std::string & m) const
+{
+ return _imp->mirrors.upper_bound(m);
+}
+
diff --git a/0.4.0/paludis/default_config.hh b/0.4.0/paludis/default_config.hh
new file mode 100644
index 000000000..ed8989192
--- /dev/null
+++ b/0.4.0/paludis/default_config.hh
@@ -0,0 +1,365 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_DEFAULT_CONFIG_HH
+#define PALUDIS_GUARD_PALUDIS_DEFAULT_CONFIG_HH 1
+
+#include <paludis/dep_atom.hh>
+#include <paludis/name.hh>
+#include <paludis/util/exception.hh>
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/util/smart_record.hh>
+
+#include <map>
+#include <vector>
+#include <string>
+
+/** \file
+ * Declarations for the DefaultConfig class and related utilities.
+ *
+ * \ingroup grpdefaultconfig
+ */
+
+namespace paludis
+{
+ /**
+ * A DefaultConfigError is thrown if a configuration error is encountered
+ * by DefaultConfig.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grpdefaultconfig
+ */
+ class DefaultConfigError : public ConfigurationError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ DefaultConfigError(const std::string & msg) throw ();
+ };
+
+ /**
+ * Keys for RepositoryConfigEntry.
+ *
+ * \see RepositoryConfigEntry
+ *
+ * \ingroup grpdefaultconfig
+ */
+ enum RepositoryConfigEntryKeys
+ {
+ rce_format, ///< Our format
+ rce_importance, ///< Our importance, higher being more important
+ rce_keys, ///< Our key/value data
+ last_rce ///< Number of entries
+ };
+
+ /**
+ * Tag for RepositoryConfigEntry.
+ *
+ * \see RepositoryConfigEntry
+ *
+ * \ingroup grpdefaultconfig
+ */
+ struct RepositoryConfigEntryTag :
+ SmartRecordTag<comparison_mode::FullComparisonTag,
+ comparison_method::SmartRecordCompareByKeyTag<rce_importance> >,
+ SmartRecordKeys<RepositoryConfigEntryKeys, last_rce>,
+ SmartRecordKey<rce_format, std::string>,
+ SmartRecordKey<rce_importance, unsigned>,
+ SmartRecordKey<rce_keys, std::map<std::string, std::string> >
+ {
+ };
+
+ /**
+ * Holds an entry in a DefaultConfig's repository configuration data.
+ *
+ * \ingroup grpdefaultconfig
+ */
+ typedef MakeSmartRecord<RepositoryConfigEntryTag>::Type RepositoryConfigEntry;
+
+ /**
+ * Keys for UseConfigEntry.
+ *
+ * \see UseConfigEntry
+ *
+ * \ingroup grpdefaultconfig
+ */
+ enum UseConfigEntryKeys
+ {
+ uce_dep_atom, ///< A dependency atom
+ uce_flag_name, ///< The use flag name
+ uce_flag_state ///< The use flag state
+ };
+
+ /**
+ * Tag for UseConfigEntry.
+ *
+ * \see UseConfigEntry
+ *
+ * \ingroup grpdefaultconfig
+ */
+ struct UseConfigEntryTag :
+ SmartRecordTag<comparison_mode::NoComparisonTag, void>,
+ SmartRecordKeys<UseConfigEntryKeys, 3>,
+ SmartRecordKey<uce_dep_atom, PackageDepAtom::ConstPointer>,
+ SmartRecordKey<uce_flag_name, UseFlagName>,
+ SmartRecordKey<uce_flag_state, UseFlagState>
+ {
+ };
+
+ /**
+ * An entry in a DefaultConfig's use configuration data.
+ *
+ * \ingroup grpdefaultconfig
+ */
+ typedef MakeSmartRecord<UseConfigEntryTag>::Type UseConfigEntry;
+
+ /**
+ * DefaultConfig is used by DefaultEnvironment to access the user's
+ * configuration settings from on-disk configuration files.
+ *
+ * \ingroup grpdefaultconfig
+ */
+ class DefaultConfig :
+ public InstantiationPolicy<DefaultConfig, instantiation_method::SingletonAsNeededTag>,
+ private PrivateImplementationPattern<DefaultConfig>
+ {
+ friend class InstantiationPolicy<DefaultConfig, instantiation_method::SingletonAsNeededTag>;
+
+ private:
+ DefaultConfig();
+
+ ~DefaultConfig();
+
+ public:
+ /**
+ * Set config suffix. Must be called before we do anything, or not
+ * at all.
+ */
+ static void set_config_suffix(const std::string &);
+
+ /**
+ * Get config suffix.
+ */
+ static std::string config_suffix();
+
+ ///\name Repositories
+ ///{
+
+ /**
+ * An iterator for our repositories.
+ */
+ typedef std::list<RepositoryConfigEntry>::const_iterator RepositoryIterator;
+
+ /**
+ * Iterator to the start of our repositories.
+ */
+ RepositoryIterator begin_repositories() const;
+
+ /**
+ * Iterator to past the end of our repositories.
+ */
+ RepositoryIterator end_repositories() const;
+
+ ///}
+
+ ///\name Keywords
+ ///{
+
+ /**
+ * Iterate over our package.keywords entries.
+ */
+ typedef std::vector<std::pair<PackageDepAtom::ConstPointer, KeywordName> >::const_iterator
+ PackageKeywordsIterator;
+
+ /**
+ * Iterator to the start of the package.keywords entries for a
+ * particular package.
+ */
+ PackageKeywordsIterator begin_package_keywords(const QualifiedPackageName & d) const;
+
+ /**
+ * Iterator to past the end of the package.keywords entries for a
+ * particular file.
+ */
+ PackageKeywordsIterator end_package_keywords(const QualifiedPackageName & d) const;
+
+ /**
+ * Iterator over the default keywords entries.
+ */
+ typedef std::vector<KeywordName>::const_iterator DefaultKeywordsIterator;
+
+ /**
+ * Iterator to the start of our default keywords entries.
+ */
+ DefaultKeywordsIterator begin_default_keywords() const;
+
+ /**
+ * Iterator to past the end of our default keywords entries.
+ */
+ DefaultKeywordsIterator end_default_keywords() const;
+
+ ///}
+
+ ///\name Licenses
+ ///{
+
+ /**
+ * Iterate over our licenses entries.
+ */
+ typedef std::vector<std::pair<PackageDepAtom::ConstPointer, std::string> >::const_iterator
+ PackageLicensesIterator;
+
+ /**
+ * Iterator to the start of the licenses entries for a
+ * particular package.
+ */
+ PackageLicensesIterator begin_package_licenses(const QualifiedPackageName & d) const;
+
+ /**
+ * Iterator to past the end of the licenses entries for a
+ * particular file.
+ */
+ PackageLicensesIterator end_package_licenses(const QualifiedPackageName & d) const;
+
+ /**
+ * Iterator over the default licenses entries.
+ */
+ typedef std::vector<std::string>::const_iterator DefaultLicensesIterator;
+
+ /**
+ * Iterator to the start of our default license entries.
+ */
+ DefaultLicensesIterator begin_default_licenses() const;
+
+ /**
+ * Iterator to past the end of our default license entries.
+ */
+ DefaultLicensesIterator end_default_licenses() const;
+
+ ///}
+
+ ///\name Masks
+ ///{
+
+ /**
+ * Iterator over user package masks.
+ */
+ typedef IndirectIterator<std::vector<PackageDepAtom::ConstPointer>::const_iterator,
+ const PackageDepAtom> UserMasksIterator;
+
+ /**
+ * Iterator to the start of the user package masks.
+ */
+ UserMasksIterator begin_user_masks(const QualifiedPackageName & d) const;
+
+ /**
+ * Iterator to past the end of the user package masks.
+ */
+ UserMasksIterator end_user_masks(const QualifiedPackageName & d) const;
+
+ /**
+ * Iterator over the user package unmasks.
+ */
+ typedef IndirectIterator<std::vector<PackageDepAtom::ConstPointer>::const_iterator,
+ const PackageDepAtom> UserUnmasksIterator;
+
+ /**
+ * Iterator to the start of the user package unmasks.
+ */
+ UserUnmasksIterator begin_user_unmasks(const QualifiedPackageName & d) const;
+
+ /**
+ * Iterator to past the end of the user package unmasks.
+ */
+ UserUnmasksIterator end_user_unmasks(const QualifiedPackageName & d) const;
+
+ ///}
+
+ ///\name Use
+ ///{
+
+ /**
+ * Iterator to the start of the use configuration.
+ */
+ typedef std::vector<UseConfigEntry>::const_iterator UseConfigIterator;
+
+ /**
+ * Iterator to the start of the use configuration for a particular
+ * package.
+ */
+ UseConfigIterator begin_use_config(const QualifiedPackageName & q) const;
+
+ /**
+ * Iterator to past the end of the use configuration for a
+ * particular package.
+ */
+ UseConfigIterator end_use_config(const QualifiedPackageName & q) const;
+
+ /**
+ * Iterator over the default use settings.
+ */
+ typedef std::vector<std::pair<UseFlagName, UseFlagState> >::const_iterator DefaultUseIterator;
+
+ /**
+ * Iterator to the start of the default use settings.
+ */
+ DefaultUseIterator begin_default_use() const;
+
+ /**
+ * Iterator to past the end of the default use settings.
+ */
+ DefaultUseIterator end_default_use() const;
+
+ ///}
+
+ /**
+ * Our bashrc files.
+ */
+ std::string bashrc_files() const;
+
+ /**
+ * The paludis command.
+ */
+ std::string paludis_command() const;
+
+ /**
+ * Set the paludis command.
+ */
+ void set_paludis_command(const std::string & s);
+
+ /**
+ * The ROOT.
+ */
+ std::string root() const;
+
+ /**
+ * The config directory.
+ */
+ std::string config_dir() const;
+
+ typedef std::multimap<std::string, std::string>::const_iterator MirrorIterator;
+
+ MirrorIterator begin_mirrors(const std::string & m) const;
+
+ MirrorIterator end_mirrors(const std::string & m) const;
+ };
+}
+
+#endif
diff --git a/0.4.0/paludis/default_environment.cc b/0.4.0/paludis/default_environment.cc
new file mode 100644
index 000000000..6d2d32f61
--- /dev/null
+++ b/0.4.0/paludis/default_environment.cc
@@ -0,0 +1,514 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <list>
+#include <paludis/config_file.hh>
+#include <paludis/default_config.hh>
+#include <paludis/default_environment.hh>
+#include <paludis/match_package.hh>
+#include <paludis/package_database.hh>
+#include <paludis/repository.hh>
+#include <paludis/util/is_file_with_extension.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/dir_iterator.hh>
+#include <vector>
+
+using namespace paludis;
+
+DefaultEnvironment::DefaultEnvironment() :
+ Environment(PackageDatabase::Pointer(new PackageDatabase(this)))
+{
+ Context context("When loading default environment:");
+
+ for (DefaultConfig::RepositoryIterator r(DefaultConfig::get_instance()->begin_repositories()),
+ r_end(DefaultConfig::get_instance()->end_repositories()) ; r != r_end ; ++r)
+ package_database()->add_repository(
+ RepositoryMaker::get_instance()->find_maker(r->get<rce_format>())(
+ this, package_database().raw_pointer(), r->get<rce_keys>()));
+}
+
+DefaultEnvironment::~DefaultEnvironment()
+{
+}
+
+bool
+DefaultEnvironment::query_use(const UseFlagName & f, const PackageDatabaseEntry * e) const
+{
+ /* first check package database use masks... */
+ const Repository * const repo((e ?
+ package_database()->fetch_repository(e->get<pde_repository>()) :
+ package_database()->fetch_repository(package_database()->favourite_repository())
+ ).raw_pointer());
+
+ if (repo->get_interface<repo_use>())
+ if (repo->get_interface<repo_use>()->query_use_mask(f, e))
+ return false;
+
+ /* check use: per package user config */
+ if (e)
+ {
+ UseFlagState s(use_unspecified);
+
+ for (DefaultConfig::UseConfigIterator
+ u(DefaultConfig::get_instance()->begin_use_config(e->get<pde_name>())),
+ u_end(DefaultConfig::get_instance()->end_use_config(e->get<pde_name>())) ;
+ u != u_end ; ++u)
+ {
+ if (f != u->get<uce_flag_name>())
+ continue;
+
+ if (! match_package(this, *u->get<uce_dep_atom>(), *e))
+ continue;
+
+ switch (u->get<uce_flag_state>())
+ {
+ case use_enabled:
+ s = use_enabled;
+ continue;
+
+ case use_disabled:
+ s = use_disabled;
+ continue;
+
+ case use_unspecified:
+ continue;
+ }
+
+ throw InternalError(PALUDIS_HERE, "Bad state");
+ }
+
+ do
+ {
+ switch (s)
+ {
+ case use_enabled:
+ return true;
+
+ case use_disabled:
+ return false;
+
+ case use_unspecified:
+ continue;
+ }
+ throw InternalError(PALUDIS_HERE, "Bad state");
+ } while (false);
+ }
+
+ /* check use: general user config */
+ do
+ {
+ UseFlagState state(use_unspecified);
+
+ for (DefaultConfig::DefaultUseIterator
+ u(DefaultConfig::get_instance()->begin_default_use()),
+ u_end(DefaultConfig::get_instance()->end_default_use()) ;
+ u != u_end ; ++u)
+ if (f == u->first)
+ state = u->second;
+
+ switch (state)
+ {
+ case use_enabled:
+ return true;
+
+ case use_disabled:
+ return false;
+
+ case use_unspecified:
+ continue;
+ }
+
+ throw InternalError(PALUDIS_HERE, "bad state " + stringify(state));
+ } while (false);
+
+ /* check use: package database config */
+ if (repo->get_interface<repo_use>())
+ switch (repo->get_interface<repo_use>()->query_use(f, e))
+ {
+ case use_disabled:
+ case use_unspecified:
+ return false;
+
+ case use_enabled:
+ return true;
+ }
+
+ throw InternalError(PALUDIS_HERE, "bad state");
+}
+
+bool
+DefaultEnvironment::accept_keyword(const KeywordName & keyword, const PackageDatabaseEntry * const d) const
+{
+ if (keyword == KeywordName("*"))
+ return true;
+
+ Context context("When checking accept_keyword of '" + stringify(keyword) +
+ (d ? "' for " + stringify(*d) : stringify("'")) + ":");
+
+ bool result(false);
+
+ if (d)
+ for (DefaultConfig::PackageKeywordsIterator
+ k(DefaultConfig::get_instance()->begin_package_keywords(d->get<pde_name>())),
+ k_end(DefaultConfig::get_instance()->end_package_keywords(d->get<pde_name>())) ;
+ k != k_end ; ++k)
+ {
+ if (! match_package(this, k->first, d))
+ continue;
+
+ result |= k->second == keyword;
+ }
+
+ result |= DefaultConfig::get_instance()->end_default_keywords() !=
+ std::find(DefaultConfig::get_instance()->begin_default_keywords(),
+ DefaultConfig::get_instance()->end_default_keywords(),
+ keyword);
+
+ return result;
+}
+
+bool
+DefaultEnvironment::accept_license(const std::string & license, const PackageDatabaseEntry * const d) const
+{
+ if (license == "*")
+ return true;
+
+ Context context("When checking license of '" + license +
+ (d ? "' for " + stringify(*d) : stringify("'")) + ":");
+
+ bool result(false);
+
+ if (d)
+ for (DefaultConfig::PackageLicensesIterator
+ k(DefaultConfig::get_instance()->begin_package_licenses(d->get<pde_name>())),
+ k_end(DefaultConfig::get_instance()->end_package_licenses(d->get<pde_name>())) ;
+ k != k_end ; ++k)
+ {
+ if (! match_package(this, k->first, d))
+ continue;
+
+ result |= k->second == license;
+ result |= k->second == "*";
+ }
+
+ result |= DefaultConfig::get_instance()->end_default_licenses() !=
+ std::find(DefaultConfig::get_instance()->begin_default_licenses(),
+ DefaultConfig::get_instance()->end_default_licenses(),
+ license);
+
+ result |= DefaultConfig::get_instance()->end_default_licenses() !=
+ std::find(DefaultConfig::get_instance()->begin_default_licenses(),
+ DefaultConfig::get_instance()->end_default_licenses(),
+ "*");
+
+ return result;
+}
+
+bool
+DefaultEnvironment::query_user_masks(const PackageDatabaseEntry & d) const
+{
+ for (DefaultConfig::UserMasksIterator
+ k(DefaultConfig::get_instance()->begin_user_masks(d.get<pde_name>())),
+ k_end(DefaultConfig::get_instance()->end_user_masks(d.get<pde_name>())) ;
+ k != k_end ; ++k)
+ {
+ if (! match_package(this, *k, d))
+ continue;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool
+DefaultEnvironment::query_user_unmasks(const PackageDatabaseEntry & d) const
+{
+ for (DefaultConfig::UserMasksIterator
+ k(DefaultConfig::get_instance()->begin_user_unmasks(d.get<pde_name>())),
+ k_end(DefaultConfig::get_instance()->end_user_unmasks(d.get<pde_name>())) ;
+ k != k_end ; ++k)
+ {
+ if (! match_package(this, *k, d))
+ continue;
+
+ return true;
+ }
+
+ return false;
+}
+
+std::string
+DefaultEnvironment::bashrc_files() const
+{
+ return DefaultConfig::get_instance()->bashrc_files();
+}
+
+std::string
+DefaultEnvironment::paludis_command() const
+{
+ return DefaultConfig::get_instance()->paludis_command();
+}
+
+UseFlagNameCollection::Pointer
+DefaultEnvironment::query_enabled_use_matching(const std::string & prefix,
+ const PackageDatabaseEntry * e) const
+{
+ UseFlagNameCollection::Pointer result(new UseFlagNameCollection);
+
+ for (DefaultConfig::DefaultUseIterator
+ u(DefaultConfig::get_instance()->begin_default_use()),
+ u_end(DefaultConfig::get_instance()->end_default_use()) ;
+ u != u_end ; ++u)
+ {
+ if (0 != u->first.data().compare(0, prefix.length(), prefix))
+ continue;
+
+ switch (u->second)
+ {
+ case use_enabled:
+ result->insert(u->first);
+ break;
+
+ case use_disabled:
+ result->erase(u->first);
+ break;
+
+ case use_unspecified:
+ break;
+ }
+ }
+
+ if (e)
+ {
+ for (DefaultConfig::UseConfigIterator
+ u(DefaultConfig::get_instance()->begin_use_config(e->get<pde_name>())),
+ u_end(DefaultConfig::get_instance()->end_use_config(e->get<pde_name>())) ;
+ u != u_end ; ++u)
+ {
+ if (0 != u->get<uce_flag_name>().data().compare(0, prefix.length(), prefix))
+ continue;
+
+ if (! match_package(this, *u->get<uce_dep_atom>(), *e))
+ continue;
+
+ switch (u->get<uce_flag_state>())
+ {
+ case use_enabled:
+ result->insert(u->get<uce_flag_name>());
+ break;
+
+ case use_disabled:
+ result->erase(u->get<uce_flag_name>());
+ break;
+
+ case use_unspecified:
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+namespace
+{
+ void add_one_hook(const std::string & base, std::list<FSEntry> & result)
+ {
+ try
+ {
+ FSEntry r(base);
+ if (r.is_directory())
+ {
+ Log::get_instance()->message(ll_debug, lc_no_context, "Adding hook directory '"
+ + base + "'");
+ result.push_back(r);
+ }
+ else
+ Log::get_instance()->message(ll_debug, lc_no_context, "Skipping hook directory candidate '"
+ + base + "'");
+ }
+ catch (const FSError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "Caught exception '" +
+ e.message() + "' (" + e.what() + ") when checking hook "
+ "directory '" + base + "'");
+ }
+ }
+
+ const std::list<FSEntry> & get_hook_dirs()
+ {
+ static std::list<FSEntry> result;
+ static bool done_hooks(false);
+ if (! done_hooks)
+ {
+ add_one_hook(DefaultConfig::get_instance()->config_dir() + "/hooks", result);
+ if (getenv_with_default("PALUDIS_NO_GLOBAL_HOOKS", "").empty())
+ {
+ add_one_hook(LIBEXECDIR "/paludis/hooks", result);
+ add_one_hook(DATADIR "/paludis/hooks", result);
+ }
+ done_hooks = true;
+ }
+ return result;
+ }
+
+ struct Hooker
+ {
+ Hook hook;
+ std::string paludis_command;
+
+ Hooker(const Hook & h, const std::string & p) :
+ hook(h),
+ paludis_command(p)
+ {
+ }
+
+ void operator() (const FSEntry & f) const
+ {
+ Context context("When running hook script '" + stringify(f) +
+ "' for hook '" + hook.name() + "':");
+ Log::get_instance()->message(ll_debug, lc_no_context, "Starting hook script '" +
+ stringify(f) + "' for '" + hook.name() + "'");
+
+ MakeEnvCommand cmd(make_env_command("bash '" + stringify(f) + "'")
+ ("ROOT", DefaultConfig::get_instance()->root())
+ ("HOOK", hook.name())
+ ("HOOK_LOG_LEVEL", Log::get_instance()->log_level_string())
+ ("HOOK_CONFIG_SUFFIX", DefaultConfig::config_suffix())
+ ("PALUDIS_EBUILD_DIR", getenv_with_default("PALUDIS_EBUILD_DIR", LIBEXECDIR "/paludis"))
+ ("PALUDIS_COMMAND", paludis_command));
+
+ for (Hook::Iterator h(hook.begin()), h_end(hook.end()) ; h != h_end ; ++h)
+ cmd = cmd(h->first, h->second);
+
+ int exit_status(run_command(cmd));
+ if (0 == exit_status)
+ Log::get_instance()->message(ll_debug, lc_no_context, "Hook '" + stringify(f)
+ + "' returned success '" + stringify(exit_status) + "'");
+ else
+ Log::get_instance()->message(ll_warning, lc_no_context, "Hook '" + stringify(f)
+ + "' returned failure '" + stringify(exit_status) + "'");
+ }
+ };
+}
+
+void
+DefaultEnvironment::perform_hook(const Hook & hook) const
+{
+ Context context("When triggering hook '" + hook.name() + "'");
+ Log::get_instance()->message(ll_debug, lc_no_context, "Starting hook '" + hook.name() + "'");
+
+ const std::list<FSEntry> & hook_dirs(get_hook_dirs());
+
+ for (std::list<FSEntry>::const_iterator h(hook_dirs.begin()),
+ h_end(hook_dirs.end()) ; h != h_end ; ++h)
+ {
+ FSEntry hh(*h / hook.name());
+ if (! hh.is_directory())
+ continue;
+
+ std::list<FSEntry> hooks;
+ std::copy(DirIterator(hh), DirIterator(),
+ filter_inserter(std::back_inserter(hooks), IsFileWithExtension(".bash")));
+ std::for_each(hooks.begin(), hooks.end(), Hooker(hook, paludis_command()));
+ }
+}
+
+std::string
+DefaultEnvironment::hook_dirs() const
+{
+ const std::list<FSEntry> & hook_dirs(get_hook_dirs());
+ return join(hook_dirs.begin(), hook_dirs.end(), " ");
+}
+
+DepAtom::Pointer
+DefaultEnvironment::local_package_set(const std::string & s,
+ const PackageSetOptions &) const
+{
+ Context context("When looking for package set '" + s + "' in default environment:");
+
+ FSEntry ff(FSEntry(DefaultConfig::get_instance()->config_dir()) / "sets" / (s + ".conf"));
+ if (ff.exists())
+ {
+ LineConfigFile f(ff);
+ AllDepAtom::Pointer result(new AllDepAtom);
+ GeneralSetDepTag::Pointer tag(new GeneralSetDepTag(s));
+
+ for (LineConfigFile::Iterator line(f.begin()), line_end(f.end()) ;
+ line != line_end ; ++line)
+ {
+ std::vector<std::string> tokens;
+ WhitespaceTokeniser::get_instance()->tokenise(*line, std::back_inserter(tokens));
+ if (tokens.empty())
+ continue;
+
+ if (1 == tokens.size())
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Line '" + *line + "' in set file '"
+ + stringify(ff) + "' does not specify '*' or '?', assuming '*'");
+ PackageDepAtom::Pointer atom(new PackageDepAtom(tokens.at(0)));
+ atom->set_tag(tag);
+ result->add_child(atom);
+ }
+ else if ("*" == tokens.at(0))
+ {
+ PackageDepAtom::Pointer atom(new PackageDepAtom(tokens.at(1)));
+ atom->set_tag(tag);
+ result->add_child(atom);
+ }
+ else if ("?" == tokens.at(0))
+ {
+ PackageDepAtom::Pointer p(new PackageDepAtom(tokens.at(1)));
+ p->set_tag(tag);
+ if (! package_database()->query(
+ PackageDepAtom::Pointer(new PackageDepAtom(p->package())),
+ is_installed_only)->empty())
+ result->add_child(p);
+ }
+ else
+ Log::get_instance()->message(ll_warning, lc_context, "Line '" + *line + "' in set file '"
+ + stringify(ff) + "' does not start with '*' or '?' token, skipping");
+
+ if (tokens.size() > 2)
+ Log::get_instance()->message(ll_warning, lc_context, "Line '" + *line + "' in set file '"
+ + stringify(ff) + "' has trailing garbage");
+ }
+
+ return result;
+ }
+
+ return DepAtom::Pointer(0);
+}
+
+DefaultEnvironment::MirrorIterator
+DefaultEnvironment::begin_mirrors(const std::string & mirror) const
+{
+ return DefaultConfig::get_instance()->begin_mirrors(mirror);
+}
+
+DefaultEnvironment::MirrorIterator
+DefaultEnvironment::end_mirrors(const std::string & mirror) const
+{
+ return DefaultConfig::get_instance()->end_mirrors(mirror);
+}
+
diff --git a/0.4.0/paludis/default_environment.hh b/0.4.0/paludis/default_environment.hh
new file mode 100644
index 000000000..5c4ca0047
--- /dev/null
+++ b/0.4.0/paludis/default_environment.hh
@@ -0,0 +1,82 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_DEFAULT_ENVIRONMENT_HH
+#define PALUDIS_GUARD_PALUDIS_DEFAULT_ENVIRONMENT_HH 1
+
+#include <paludis/package_database.hh>
+#include <paludis/environment.hh>
+
+/** \file
+ * Declarations for the DefaultEnvironment class.
+ *
+ * \ingroup grpdefaultenvironment
+ */
+
+namespace paludis
+{
+ /**
+ * The DefaultEnvironment is an Environment that corresponds to the normal
+ * operating evironment.
+ *
+ * \ingroup grpdefaultenvironment
+ */
+ class DefaultEnvironment :
+ public Environment,
+ public InstantiationPolicy<DefaultEnvironment, instantiation_method::SingletonAsNeededTag>
+ {
+ friend class InstantiationPolicy<DefaultEnvironment, instantiation_method::SingletonAsNeededTag>;
+
+ private:
+ DefaultEnvironment();
+
+ ~DefaultEnvironment();
+
+ protected:
+ DepAtom::Pointer local_package_set(const std::string &,
+ const PackageSetOptions & = PackageSetOptions(false)) const;
+
+ public:
+ virtual bool query_use(const UseFlagName &, const PackageDatabaseEntry *) const;
+
+ virtual bool accept_keyword(const KeywordName &, const PackageDatabaseEntry * const) const;
+
+ virtual bool accept_license(const std::string &, const PackageDatabaseEntry * const) const;
+
+ virtual bool query_user_masks(const PackageDatabaseEntry &) const;
+
+ virtual bool query_user_unmasks(const PackageDatabaseEntry &) const;
+
+ virtual std::string bashrc_files() const;
+
+ virtual std::string hook_dirs() const;
+
+ virtual std::string paludis_command() const;
+
+ virtual UseFlagNameCollection::Pointer query_enabled_use_matching(
+ const std::string & prefix, const PackageDatabaseEntry *) const;
+
+ virtual void perform_hook(const Hook & hook) const;
+
+ virtual MirrorIterator begin_mirrors(const std::string & mirror) const;
+
+ virtual MirrorIterator end_mirrors(const std::string & mirror) const;
+ };
+}
+#endif
diff --git a/0.4.0/paludis/dep_atom.cc b/0.4.0/paludis/dep_atom.cc
new file mode 100644
index 000000000..86a0dd06d
--- /dev/null
+++ b/0.4.0/paludis/dep_atom.cc
@@ -0,0 +1,289 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/dep_atom.hh>
+#include <paludis/util/log.hh>
+
+/** \file
+ * Implementation for dep_atom.hh things.
+ *
+ * \ingroup grpdepatoms
+ */
+
+using namespace paludis;
+
+DepAtom::DepAtom()
+{
+}
+
+DepAtom::~DepAtom()
+{
+}
+
+const UseDepAtom *
+DepAtom::as_use_dep_atom() const
+{
+ return 0;
+}
+
+CompositeDepAtom::CompositeDepAtom()
+{
+}
+
+void
+CompositeDepAtom::add_child(DepAtom::ConstPointer c)
+{
+ _children.push_back(c);
+}
+
+AnyDepAtom::AnyDepAtom()
+{
+}
+
+AllDepAtom::AllDepAtom()
+{
+}
+
+UseDepAtom::UseDepAtom(const UseFlagName & flag, bool inverse) :
+ _flag(flag),
+ _inverse(inverse)
+{
+}
+
+const UseDepAtom *
+UseDepAtom::as_use_dep_atom() const
+{
+ return this;
+}
+
+BlockDepAtom::BlockDepAtom(PackageDepAtom::ConstPointer a) :
+ StringDepAtom("!" + a->text()),
+ _atom(a)
+{
+}
+
+PackageDepAtom::PackageDepAtom(const QualifiedPackageName & package) :
+ StringDepAtom(stringify(package)),
+ _package(package),
+ _version_operator("="),
+ _version_spec(0),
+ _slot(0),
+ _repository(0),
+ _use_requirements(0),
+ _tag(0)
+{
+}
+
+PackageDepAtom::PackageDepAtom(const std::string & ss) :
+ StringDepAtom(ss),
+ _package(CategoryNamePart("later"), PackageNamePart("later")),
+ _version_operator("="),
+ _version_spec(0),
+ _slot(0),
+ _repository(0),
+ _use_requirements(0),
+ _tag(0)
+{
+ Context context("When parsing package dep atom '" + ss + "':");
+
+ try
+ {
+ std::string s(ss);
+
+ if (s.empty())
+ throw PackageDepAtomError("Got empty dep atom");
+
+ std::string::size_type use_group_p;
+ while (std::string::npos != ((use_group_p = s.rfind('['))))
+ {
+ if (s.at(s.length() - 1) != ']')
+ throw PackageDepAtomError("Mismatched []");
+
+ std::string flag(s.substr(use_group_p + 1));
+ UseFlagState state(use_enabled);
+ if (flag.length() < 2)
+ throw PackageDepAtomError("Invalid [] contents");
+ flag.erase(flag.length() - 1);
+ if ('-' == flag.at(0))
+ {
+ state = use_disabled;
+ flag.erase(0, 1);
+ if (flag.empty())
+ throw PackageDepAtomError("Invalid [] contents");
+ }
+ UseFlagName name(flag);
+ if (0 == _use_requirements)
+ _use_requirements.assign(new UseRequirements);
+ if (! _use_requirements->insert(name, state))
+ throw PackageDepAtomError("Conflicting [] contents");
+
+ s.erase(use_group_p);
+ }
+
+ std::string::size_type repo_p;
+ if (std::string::npos != ((repo_p = s.rfind("::"))))
+ {
+ _repository.assign(new RepositoryName(s.substr(repo_p + 2)));
+ s.erase(repo_p);
+ }
+
+ std::string::size_type slot_p;
+ if (std::string::npos != ((slot_p = s.rfind(':'))))
+ {
+ _slot.assign(new SlotName(s.substr(slot_p + 1)));
+ s.erase(slot_p);
+ }
+
+ if (std::string::npos != std::string("<>=~").find(s.at(0)))
+ {
+ std::string::size_type p(1);
+ if (s.length() > 1 && std::string::npos != std::string("<>=~").find(s.at(1)))
+ ++p;
+ _version_operator = s.substr(0, p);
+
+ std::string::size_type q(p);
+
+ while (true)
+ {
+ if (p >= s.length())
+ throw PackageDepAtomError("Couldn't parse dep atom '" + ss + "'");
+ q = s.find('-', q + 1);
+ if ((std::string::npos == q) || (++q >= s.length()))
+ throw PackageDepAtomError("Couldn't parse dep atom '" + ss + "'");
+ if ((s.at(q) >= '0' && s.at(q) <= '9') || (0 == s.compare(q, 3, "scm")))
+ break;
+ }
+
+ std::string::size_type new_q(q);
+ while (true)
+ {
+ if (new_q >= s.length())
+ break;
+ new_q = s.find('-', new_q + 1);
+ if ((std::string::npos == new_q) || (++new_q >= s.length()))
+ break;
+ if (s.at(new_q) >= '0' && s.at(new_q) <= '9')
+ q = new_q;
+ }
+
+ _package = QualifiedPackageName(s.substr(p, q - p - 1));
+
+ if ('*' == s.at(s.length() - 1))
+ {
+ if (_version_operator != vo_equal)
+ Log::get_instance()->message(ll_qa, lc_context,
+ "Package dep atom '" + ss + "' uses * "
+ "with operator '" + stringify(_version_operator) +
+ "', pretending it uses the equals operator instead");
+ _version_operator = vo_equal_star;
+ _version_spec = CountedPtr<VersionSpec, count_policy::ExternalCountTag>(
+ new VersionSpec(s.substr(q, s.length() - q - 1)));
+ }
+ else
+ _version_spec = CountedPtr<VersionSpec, count_policy::ExternalCountTag>(
+ new VersionSpec(s.substr(q)));
+ }
+ else
+ _package = QualifiedPackageName(s);
+ }
+ catch (Exception &)
+ {
+ throw;
+ }
+ catch (const std::exception & e)
+ {
+ throw InternalError(PALUDIS_HERE, "caught std::exception '"
+ + stringify(e.what()) + "'");
+ }
+}
+
+PackageDepAtom::~PackageDepAtom()
+{
+}
+
+std::ostream &
+paludis::operator<< (std::ostream & s, const PackageDepAtom & a)
+{
+ if (a.version_spec_ptr())
+ {
+ if (a.version_operator() == vo_equal_star)
+ s << "=";
+ else
+ s << a.version_operator();
+ }
+
+ s << a.package();
+
+ if (a.version_spec_ptr())
+ {
+ s << "-" << *a.version_spec_ptr();
+
+ if (a.version_operator() == vo_equal_star)
+ s << "*";
+ }
+
+ if (a.slot_ptr())
+ s << ":" << *a.slot_ptr();
+ if (a.repository_ptr())
+ s << "::" << *a.repository_ptr();
+
+ if (a.use_requirements_ptr())
+ {
+ for (UseRequirements::Iterator u(a.use_requirements_ptr()->begin()),
+ u_end(a.use_requirements_ptr()->end()) ; u != u_end ; ++u)
+ s << "[" << (u->second == use_disabled ? "-" + stringify(u->first) :
+ stringify(u->first)) << "]";
+ }
+
+ return s;
+}
+
+PackageDepAtomError::PackageDepAtomError(const std::string & msg) throw () :
+ Exception(msg)
+{
+}
+
+StringDepAtom::StringDepAtom(const std::string & s) :
+ _str(s)
+{
+}
+
+PlainTextDepAtom::PlainTextDepAtom(const std::string & s) :
+ StringDepAtom(s)
+{
+}
+
+UseFlagState
+UseRequirements::state(const UseFlagName & u) const
+{
+ Iterator i(find(u));
+ if (end() == i)
+ return use_unspecified;
+ return i->second;
+}
+
+PackageDepAtom::Pointer
+PackageDepAtom::without_use_requirements() const
+{
+ std::string s(text());
+ if (std::string::npos != s.find('['))
+ s.erase(s.find('['));
+ return Pointer(new PackageDepAtom(s));
+}
+
diff --git a/0.4.0/paludis/dep_atom.hh b/0.4.0/paludis/dep_atom.hh
new file mode 100644
index 000000000..830ac116c
--- /dev/null
+++ b/0.4.0/paludis/dep_atom.hh
@@ -0,0 +1,487 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_DEP_ATOM_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_ATOM_HH 1
+
+#include <list>
+#include <paludis/dep_tag.hh>
+#include <paludis/name.hh>
+#include <paludis/util/attributes.hh>
+#include <paludis/util/composite_pattern.hh>
+#include <paludis/util/counted_ptr.hh>
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/util/visitor.hh>
+#include <paludis/version_operator.hh>
+#include <paludis/version_spec.hh>
+#include <map>
+
+/** \file
+ * Declarations for the DepAtom classes.
+ *
+ * \ingroup grpdepatoms
+ */
+
+namespace paludis
+{
+ class DepAtom;
+ class CompositeDepAtom;
+ class PackageDepAtom;
+ class PlainTextDepAtom;
+ class AllDepAtom;
+ class AnyDepAtom;
+ class UseDepAtom;
+ class BlockDepAtom;
+
+ /**
+ * Visitor types for a visitor that can visit a DepAtom heirarchy.
+ *
+ * \ingroup grpdepatoms
+ */
+ typedef VisitorTypes<PackageDepAtom *, PlainTextDepAtom *, AllDepAtom *, AnyDepAtom *,
+ UseDepAtom *, BlockDepAtom *> DepAtomVisitorTypes;
+
+ /**
+ * Base class for a dependency atom.
+ *
+ * \ingroup grpdepatoms
+ */
+ class DepAtom :
+ public virtual VisitableInterface<DepAtomVisitorTypes>,
+ public virtual Composite<DepAtom, CompositeDepAtom>,
+ private InstantiationPolicy<DepAtom, instantiation_method::NonCopyableTag>,
+ public InternalCounted<DepAtom>
+ {
+ protected:
+ DepAtom();
+
+ public:
+ /**
+ * Destructor.
+ */
+ virtual ~DepAtom();
+
+ /**
+ * Return us as a UseDepAtom, or 0 if we are not a
+ * UseDepAtom.
+ */
+ virtual const UseDepAtom * as_use_dep_atom() const;
+ };
+
+ /**
+ * Class for dependency atoms that have a number of child dependency
+ * atoms.
+ *
+ * \ingroup grpdepatoms
+ */
+ class CompositeDepAtom :
+ public DepAtom,
+ public virtual Composite<DepAtom, CompositeDepAtom>
+ {
+ private:
+ std::list<DepAtom::ConstPointer> _children;
+
+ protected:
+ /**
+ * Constructor.
+ */
+ CompositeDepAtom();
+
+ public:
+ /**
+ * Append a child to our collection.
+ */
+ virtual void add_child(DepAtom::ConstPointer);
+
+ /**
+ * Iterator for iterating over our children.
+ */
+ typedef std::list<DepAtom::ConstPointer>::const_iterator Iterator;
+
+ /**
+ * Iterator to the start of our children.
+ */
+ Iterator begin() const
+ {
+ return _children.begin();
+ }
+
+ /**
+ * Iterator to past the end of our children.
+ */
+ Iterator end() const
+ {
+ return _children.end();
+ }
+
+ /**
+ * A non-constant smart pointer to ourself.
+ */
+ typedef CountedPtr<CompositeDepAtom, count_policy::InternalCountTag> Pointer;
+
+ /**
+ * A constant smart pointer to ourself.
+ */
+ typedef CountedPtr<const CompositeDepAtom, count_policy::InternalCountTag> ConstPointer;
+ };
+
+ /**
+ * Represents a "|| ( )" dependency block.
+ *
+ * \ingroup grpdepatoms
+ */
+ class AnyDepAtom :
+ public CompositeDepAtom,
+ public Visitable<AnyDepAtom, DepAtomVisitorTypes>
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ AnyDepAtom();
+ };
+
+ /**
+ * Represents a ( first second third ) or top level group of dependency
+ * atoms.
+ *
+ * \ingroup grpdepatoms
+ */
+ class AllDepAtom :
+ public CompositeDepAtom,
+ public Visitable<AllDepAtom, DepAtomVisitorTypes>
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ AllDepAtom();
+ };
+
+ /**
+ * Represents a use? ( ) dependency atom.
+ *
+ * \ingroup grpdepatoms
+ */
+ class UseDepAtom :
+ public CompositeDepAtom,
+ public Visitable<UseDepAtom, DepAtomVisitorTypes>
+ {
+ private:
+ const UseFlagName _flag;
+ const bool _inverse;
+
+ public:
+ /**
+ * Constructor.
+ */
+ UseDepAtom(const UseFlagName &, bool);
+
+ /**
+ * Fetch our use flag name.
+ */
+ const UseFlagName & flag() const
+ {
+ return _flag;
+ }
+
+ /**
+ * Fetch whether we are a ! flag.
+ */
+ bool inverse() const
+ {
+ return _inverse;
+ }
+
+ virtual const UseDepAtom * as_use_dep_atom() const;
+ };
+
+ /**
+ * A StringDepAtom represents a non-composite dep atom with an associated
+ * piece of text.
+ *
+ * \ingroup grpdepatoms
+ */
+ class StringDepAtom :
+ public DepAtom
+ {
+ private:
+ const std::string _str;
+
+ protected:
+ /**
+ * Constructor.
+ */
+ StringDepAtom(const std::string &);
+
+ public:
+ /**
+ * Fetch our text.
+ */
+ const std::string & text() const
+ {
+ return _str;
+ }
+ };
+
+ /**
+ * A selection of USE flag requirements.
+ *
+ * \ingroup grpdepatoms
+ */
+ class UseRequirements :
+ public InternalCounted<UseRequirements>
+ {
+ private:
+ std::map<UseFlagName, UseFlagState> _reqs;
+
+ public:
+ typedef std::map<UseFlagName, UseFlagState>::const_iterator Iterator;
+
+ Iterator begin() const
+ {
+ return _reqs.begin();
+ }
+
+ Iterator end() const
+ {
+ return _reqs.end();
+ }
+
+ Iterator find(const UseFlagName & u) const
+ {
+ return _reqs.find(u);
+ }
+
+ bool insert(const UseFlagName & u, UseFlagState s)
+ {
+ return _reqs.insert(std::make_pair(u, s)).second;
+ }
+
+ UseFlagState state(const UseFlagName &) const;
+ };
+
+ /**
+ * A PackageDepAtom represents a package name (for example,
+ * 'app-editors/vim'), possibly with associated version and SLOT
+ * restrictions.
+ *
+ * \ingroup grpdepatoms
+ */
+ class PackageDepAtom :
+ public StringDepAtom,
+ public Visitable<PackageDepAtom, DepAtomVisitorTypes>
+ {
+ private:
+ QualifiedPackageName _package;
+ VersionOperator _version_operator;
+ CountedPtr<VersionSpec, count_policy::ExternalCountTag> _version_spec;
+ CountedPtr<SlotName, count_policy::ExternalCountTag> _slot;
+ CountedPtr<RepositoryName, count_policy::ExternalCountTag> _repository;
+ UseRequirements::Pointer _use_requirements;
+ DepTag::ConstPointer _tag;
+
+ public:
+ /**
+ * Constructor, no version or SLOT restrictions.
+ */
+ PackageDepAtom(const QualifiedPackageName & package);
+
+ /**
+ * Constructor, parse restrictions ourself.
+ */
+ PackageDepAtom(const std::string &);
+
+ /**
+ * Destructor.
+ */
+ ~PackageDepAtom();
+
+ /**
+ * Fetch the package name.
+ */
+ const QualifiedPackageName & package() const
+ {
+ return _package;
+ }
+
+ /**
+ * Fetch the version operator.
+ */
+ const VersionOperator version_operator() const
+ {
+ return _version_operator;
+ }
+
+ /**
+ * Fetch the version spec (may be a zero pointer).
+ */
+ CountedPtr<VersionSpec, count_policy::ExternalCountTag> version_spec_ptr() const
+ {
+ return _version_spec;
+ }
+
+ /**
+ * Fetch the slot name (may be a zero pointer).
+ */
+ CountedPtr<SlotName, count_policy::ExternalCountTag> slot_ptr() const
+ {
+ return _slot;
+ }
+
+ /**
+ * Fetch the repo name (may be a zero pointer).
+ */
+ CountedPtr<RepositoryName, count_policy::ExternalCountTag> repository_ptr() const
+ {
+ return _repository;
+ }
+
+ /**
+ * Fetch the use requirements (may be a zero pointer).
+ */
+ UseRequirements::ConstPointer use_requirements_ptr() const
+ {
+ return _use_requirements;
+ }
+
+ /**
+ * A non-constant smart pointer to ourself.
+ */
+ typedef CountedPtr<PackageDepAtom, count_policy::InternalCountTag> Pointer;
+
+ /**
+ * A constant smart pointer to ourself.
+ */
+ typedef CountedPtr<const PackageDepAtom, count_policy::InternalCountTag> ConstPointer;
+
+ /**
+ * Fetch our tag.
+ */
+ DepTag::ConstPointer tag() const
+ {
+ return _tag;
+ }
+
+ /**
+ * Set our tag.
+ */
+ void set_tag(const DepTag::ConstPointer & s)
+ {
+ _tag = s;
+ }
+
+ /**
+ * Fetch a copy of ourself without the USE requirements.
+ */
+ Pointer without_use_requirements() const;
+ };
+
+ /**
+ * A PlainTextDepAtom represents a plain text entry (for example,
+ * a URI in SRC_URI).
+ *
+ * \ingroup grpdepatoms
+ */
+ class PlainTextDepAtom :
+ public StringDepAtom,
+ public Visitable<PlainTextDepAtom, DepAtomVisitorTypes>
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ PlainTextDepAtom(const std::string &);
+
+ /**
+ * A non-constant smart pointer to ourself.
+ */
+ typedef CountedPtr<PlainTextDepAtom, count_policy::InternalCountTag> Pointer;
+
+ /**
+ * A constant smart pointer to ourself.
+ */
+ typedef CountedPtr<const PlainTextDepAtom, count_policy::InternalCountTag> ConstPointer;
+ };
+
+ /**
+ * Thrown if an invalid package dep atom specification is encountered.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grpdepatoms
+ */
+ class PackageDepAtomError :
+ public Exception
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ PackageDepAtomError(const std::string & msg) throw ();
+ };
+
+ /**
+ * A PackageDepAtom can be written to an ostream.
+ *
+ * \ingroup grpdepatoms
+ */
+ std::ostream & operator<< (std::ostream &, const PackageDepAtom &);
+
+ /**
+ * A BlockDepAtom represents a block on a package name (for example,
+ * 'app-editors/vim'), possibly with associated version and SLOT
+ * restrictions.
+ *
+ * \ingroup grpdepatoms
+ */
+ class BlockDepAtom :
+ public StringDepAtom,
+ public Visitable<BlockDepAtom, DepAtomVisitorTypes>
+ {
+ private:
+ PackageDepAtom::ConstPointer _atom;
+
+ public:
+ /**
+ * Constructor, with blocking atom.
+ */
+ BlockDepAtom(PackageDepAtom::ConstPointer atom);
+
+ /**
+ * Fetch the atom we're blocking.
+ */
+ PackageDepAtom::ConstPointer blocked_atom() const
+ {
+ return _atom;
+ }
+
+ /**
+ * A non-constant smart pointer to ourself.
+ */
+ typedef CountedPtr<BlockDepAtom, count_policy::InternalCountTag> Pointer;
+
+ /**
+ * A constant smart pointer to ourself.
+ */
+ typedef CountedPtr<const BlockDepAtom, count_policy::InternalCountTag> ConstPointer;
+ };
+
+}
+
+#endif
diff --git a/0.4.0/paludis/dep_atom_TEST.cc b/0.4.0/paludis/dep_atom_TEST.cc
new file mode 100644
index 000000000..646fe9cef
--- /dev/null
+++ b/0.4.0/paludis/dep_atom_TEST.cc
@@ -0,0 +1,169 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/dep_atom.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+/** \file
+ * Test cases for dep_atom.hh classes.
+ *
+ * \ingroup grptestcases
+ */
+
+using namespace paludis;
+using namespace test;
+
+namespace test_cases
+{
+ /**
+ * \test Test DepAtom as_ functions.
+ *
+ * \ingroup grptestcases
+ */
+ struct DepAtomAsTest : TestCase
+ {
+ DepAtomAsTest() : TestCase("dep atom as") { }
+
+ void run()
+ {
+ PackageDepAtom::Pointer x(new PackageDepAtom("foo/bar"));
+ TEST_CHECK(0 == x->as_use_dep_atom());
+
+ UseDepAtom::Pointer y(new UseDepAtom(UseFlagName("foo"), x));
+ TEST_CHECK(0 != y->as_use_dep_atom());
+ TEST_CHECK(y.raw_pointer() == y->as_use_dep_atom());
+ }
+ } test_dep_atom_as;
+
+ /**
+ * \test Test DepAtom composite functions.
+ *
+ * \ingroup grptestcases
+ */
+ struct DepAtomCompositeTest : TestCase
+ {
+ DepAtomCompositeTest() : TestCase("dep atom composite") { }
+
+ void run()
+ {
+ AllDepAtom::Pointer x(new AllDepAtom);
+ TEST_CHECK(x->begin() == x->end());
+
+ x->add_child(PackageDepAtom::Pointer(new PackageDepAtom("x/y")));
+ TEST_CHECK(x->begin() != x->end());
+ TEST_CHECK_EQUAL(1, std::distance(x->begin(), x->end()));
+
+ x->add_child(PackageDepAtom::Pointer(new PackageDepAtom("x/y")));
+ TEST_CHECK(x->begin() != x->end());
+ TEST_CHECK_EQUAL(2, std::distance(x->begin(), x->end()));
+ }
+ } test_dep_atom_composite;
+
+ /**
+ * \test Test PackageDepAtom.
+ *
+ * \ingroup grptestcases
+ */
+ struct PackageDepAtomTest : TestCase
+ {
+ PackageDepAtomTest() : TestCase("package dep atom") { }
+
+ void run()
+ {
+ PackageDepAtom a("foo/bar");
+ TEST_CHECK_STRINGIFY_EQUAL(a.package(), "foo/bar");
+ TEST_CHECK(! a.slot_ptr());
+ TEST_CHECK(! a.version_spec_ptr());
+
+ PackageDepAtom b(">=foo/bar-1.2.3");
+ TEST_CHECK_STRINGIFY_EQUAL(b.package(), "foo/bar");
+ TEST_CHECK(! b.slot_ptr());
+ TEST_CHECK(b.version_spec_ptr());
+ TEST_CHECK_STRINGIFY_EQUAL(*b.version_spec_ptr(), "1.2.3");
+ TEST_CHECK_EQUAL(b.version_operator(), vo_greater_equal);
+
+ PackageDepAtom c("foo/bar:baz");
+ TEST_CHECK_STRINGIFY_EQUAL(c.package(), "foo/bar");
+ TEST_CHECK(c.slot_ptr());
+ TEST_CHECK_STRINGIFY_EQUAL(*c.slot_ptr(), "baz");
+ TEST_CHECK(! c.version_spec_ptr());
+
+ PackageDepAtom d("=foo/bar-1.2*:1.2.1");
+ TEST_CHECK_STRINGIFY_EQUAL(d.package(), "foo/bar");
+ TEST_CHECK(d.slot_ptr());
+ TEST_CHECK_STRINGIFY_EQUAL(*d.slot_ptr(), "1.2.1");
+ TEST_CHECK(d.version_spec_ptr());
+ TEST_CHECK_STRINGIFY_EQUAL(*d.version_spec_ptr(), "1.2");
+ TEST_CHECK_EQUAL(d.version_operator(), vo_equal_star);
+
+ PackageDepAtom e("foo/bar:1.2.1");
+ TEST_CHECK_STRINGIFY_EQUAL(e.package(), "foo/bar");
+ TEST_CHECK(e.slot_ptr());
+ TEST_CHECK_STRINGIFY_EQUAL(*e.slot_ptr(), "1.2.1");
+ TEST_CHECK(! e.version_spec_ptr());
+
+ PackageDepAtom f("foo/bar:0");
+ TEST_CHECK_STRINGIFY_EQUAL(f.package(), "foo/bar");
+ TEST_CHECK(f.slot_ptr());
+ TEST_CHECK_STRINGIFY_EQUAL(*f.slot_ptr(), "0");
+ TEST_CHECK(! f.version_spec_ptr());
+
+ PackageDepAtom g("foo/bar-100dpi");
+ TEST_CHECK_STRINGIFY_EQUAL(g.package(), "foo/bar-100dpi");
+
+ PackageDepAtom h(">=foo/bar-100dpi-1.23");
+ TEST_CHECK_STRINGIFY_EQUAL(h.package(), "foo/bar-100dpi");
+ TEST_CHECK(h.version_spec_ptr());
+ TEST_CHECK_STRINGIFY_EQUAL(*h.version_spec_ptr(), "1.23");
+ TEST_CHECK_EQUAL(h.version_operator(), vo_greater_equal);
+
+ TEST_CHECK_THROWS(PackageDepAtom(""), PackageDepAtomError);
+
+ PackageDepAtom i("foo/bar[one][-two]");
+ TEST_CHECK_STRINGIFY_EQUAL(i.package(), "foo/bar");
+ TEST_CHECK(! i.version_spec_ptr());
+ TEST_CHECK(! i.repository_ptr());
+ TEST_CHECK(! i.slot_ptr());
+ TEST_CHECK(i.use_requirements_ptr());
+ TEST_CHECK(i.use_requirements_ptr()->find(UseFlagName("one")) !=
+ i.use_requirements_ptr()->end());
+ TEST_CHECK(i.use_requirements_ptr()->find(UseFlagName("two")) !=
+ i.use_requirements_ptr()->end());
+ TEST_CHECK(i.use_requirements_ptr()->find(UseFlagName("three")) ==
+ i.use_requirements_ptr()->end());
+ TEST_CHECK(i.use_requirements_ptr()->state(UseFlagName("one")) == use_enabled);
+ TEST_CHECK(i.use_requirements_ptr()->state(UseFlagName("two")) == use_disabled);
+ TEST_CHECK(i.use_requirements_ptr()->state(UseFlagName("moo")) == use_unspecified);
+
+ PackageDepAtom j("=foo/bar-scm-r3");
+ TEST_CHECK_STRINGIFY_EQUAL(j.package(), "foo/bar");
+ TEST_CHECK(j.version_spec_ptr());
+ TEST_CHECK_STRINGIFY_EQUAL(*j.version_spec_ptr(), "scm-r3");
+ TEST_CHECK_EQUAL(j.version_operator(), vo_equal);
+
+ PackageDepAtom k("=foo/bar-scm");
+ TEST_CHECK_STRINGIFY_EQUAL(k.package(), "foo/bar");
+ TEST_CHECK(k.version_spec_ptr());
+ TEST_CHECK_STRINGIFY_EQUAL(*k.version_spec_ptr(), "scm");
+ TEST_CHECK_EQUAL(k.version_operator(), vo_equal);
+ }
+ } test_package_dep_atom;
+}
+
diff --git a/0.4.0/paludis/dep_atom_dumper.cc b/0.4.0/paludis/dep_atom_dumper.cc
new file mode 100644
index 000000000..ce845d920
--- /dev/null
+++ b/0.4.0/paludis/dep_atom_dumper.cc
@@ -0,0 +1,86 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <algorithm>
+#include <paludis/dep_atom.hh>
+#include <paludis/dep_atom_dumper.hh>
+
+/** \file
+ * Implementation for dep_atom_dumper.hh.
+ *
+ * \ingroup grpdepatomdumper
+ */
+
+using namespace paludis;
+
+DepAtomDumper::DepAtomDumper(std::ostream * const o) :
+ _o(o)
+{
+}
+
+void
+DepAtomDumper::visit(const AllDepAtom * const a)
+{
+ *_o << "<all>";
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ *_o << "</all>";
+}
+
+void
+DepAtomDumper::visit(const AnyDepAtom * const a)
+{
+ *_o << "<any>";
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ *_o << "</any>";
+}
+
+void
+DepAtomDumper::visit(const UseDepAtom * const a)
+{
+ *_o << "<use flag=\"" << a->flag() << "\" inverse=\""
+ << (a->inverse() ? "true" : "false") << "\">";
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ *_o << "</use>";
+}
+
+void
+DepAtomDumper::visit(const PackageDepAtom * const p)
+{
+ *_o << "<package";
+ if (p->slot_ptr())
+ *_o << " slot=\"" << *p->slot_ptr() << "\"";
+ if (p->version_spec_ptr())
+ *_o << " version=\"" << p->version_operator() << *p->version_spec_ptr() << "\"";
+ *_o << ">" << p->package() << "</package>";
+}
+
+void
+DepAtomDumper::visit(const PlainTextDepAtom * const t)
+{
+ *_o << "<text>" << t->text() << "</text>";
+}
+
+void
+DepAtomDumper::visit(const BlockDepAtom * const b)
+{
+ *_o << "<block>";
+ b->blocked_atom()->accept(this);
+ *_o << "</block>";
+}
+
diff --git a/0.4.0/paludis/dep_atom_dumper.hh b/0.4.0/paludis/dep_atom_dumper.hh
new file mode 100644
index 000000000..44f39f0a3
--- /dev/null
+++ b/0.4.0/paludis/dep_atom_dumper.hh
@@ -0,0 +1,69 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_DEP_ATOM_DUMPER_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_ATOM_DUMPER_HH 1
+
+#include <ostream>
+#include <paludis/util/instantiation_policy.hh>
+
+/** \file
+ * Declarations for the DepAtomDumper class.
+ *
+ * \ingroup grpdepatomdumper
+ */
+
+namespace paludis
+{
+ /**
+ * Dump dependency atoms to a stream in pseudo-XML form, for testing.
+ *
+ * \ingroup grpdepatomdumper
+ */
+ class DepAtomDumper :
+ public DepAtomVisitorTypes::ConstVisitor,
+ private InstantiationPolicy<DepAtomDumper, instantiation_method::NonCopyableTag>
+ {
+ private:
+ std::ostream * const _o;
+
+ public:
+ /**
+ * Constructor.
+ */
+ DepAtomDumper(std::ostream * const o);
+
+ /// \name Visit functions
+ ///{
+ void visit(const AllDepAtom * const);
+
+ void visit(const AnyDepAtom * const);
+
+ void visit(const UseDepAtom * const);
+
+ void visit(const PackageDepAtom * const);
+
+ void visit(const PlainTextDepAtom * const);
+
+ void visit(const BlockDepAtom * const);
+ ///}
+ };
+}
+
+#endif
diff --git a/0.4.0/paludis/dep_atom_dumper_TEST.cc b/0.4.0/paludis/dep_atom_dumper_TEST.cc
new file mode 100644
index 000000000..c6bbc1ca3
--- /dev/null
+++ b/0.4.0/paludis/dep_atom_dumper_TEST.cc
@@ -0,0 +1,65 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/dep_atom.hh>
+#include <paludis/dep_atom_dumper.hh>
+#include <sstream>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for DepAtomDumper.
+ *
+ * \ingroup grptestcases
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test DepAtomDumper.
+ *
+ * \ingroup grptestcases
+ */
+ struct DepAtomDumperTest : TestCase
+ {
+ DepAtomDumperTest() : TestCase("dump") { }
+
+ void run()
+ {
+ std::stringstream s;
+ DepAtomDumper d(&s);
+ AllDepAtom::Pointer all(new AllDepAtom);
+ PackageDepAtom::Pointer p1(new PackageDepAtom("one/one"));
+ AnyDepAtom::Pointer any(new AnyDepAtom);
+ PackageDepAtom::Pointer p2(new PackageDepAtom("two/two"));
+ PackageDepAtom::Pointer p3(new PackageDepAtom("three/three"));
+ all->add_child(p1);
+ all->add_child(any);
+ any->add_child(p2);
+ any->add_child(p3);
+ all->accept(&d);
+ TEST_CHECK_EQUAL(s.str(), "<all><package>one/one</package>"
+ "<any><package>two/two</package><package>three/three</package></any></all>");
+ }
+ } test_dep_atom_dumper;
+}
+
diff --git a/0.4.0/paludis/dep_atom_flattener.cc b/0.4.0/paludis/dep_atom_flattener.cc
new file mode 100644
index 000000000..77c29ae38
--- /dev/null
+++ b/0.4.0/paludis/dep_atom_flattener.cc
@@ -0,0 +1,90 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/dep_atom.hh>
+#include <paludis/dep_atom_flattener.hh>
+
+/** \file
+ * Implementation of dep_atom_flattener.hh.
+ *
+ * \ingroup grpdepatomflattener
+ */
+
+using namespace paludis;
+
+DepAtomFlattener::DepAtomFlattener(
+ const Environment * const env,
+ const PackageDatabaseEntry * const pkg,
+ DepAtom::ConstPointer a) :
+ _env(env),
+ _pkg(pkg),
+ _a(a),
+ _done(false)
+{
+}
+
+DepAtomFlattener::~DepAtomFlattener()
+{
+}
+
+DepAtomFlattener::Iterator
+DepAtomFlattener::begin()
+{
+ if (! _done)
+ {
+ _a->accept(static_cast<DepAtomVisitorTypes::ConstVisitor *>(this));
+ _done = true;
+ }
+
+ return _atoms.begin();
+}
+
+void DepAtomFlattener::visit(const AllDepAtom * a)
+{
+ std::for_each(a->begin(), a->end(), accept_visitor(
+ static_cast<DepAtomVisitorTypes::ConstVisitor *>(this)));
+}
+
+void DepAtomFlattener::visit(const AnyDepAtom *)
+{
+ throw InternalError(PALUDIS_HERE, "Found unexpected AnyDepAtom");
+}
+
+void DepAtomFlattener::visit(const UseDepAtom * u)
+{
+ if (_env->query_use(u->flag(), _pkg) ^ u->inverse())
+ std::for_each(u->begin(), u->end(), accept_visitor(
+ static_cast<DepAtomVisitorTypes::ConstVisitor *>(this)));
+}
+
+void DepAtomFlattener::visit(const PlainTextDepAtom * p)
+{
+ _atoms.push_back(p);
+}
+
+void DepAtomFlattener::visit(const PackageDepAtom * p)
+{
+ _atoms.push_back(p);
+}
+
+void DepAtomFlattener::visit(const BlockDepAtom * p)
+{
+ _atoms.push_back(p);
+}
+
diff --git a/0.4.0/paludis/dep_atom_flattener.hh b/0.4.0/paludis/dep_atom_flattener.hh
new file mode 100644
index 000000000..ee2ab5193
--- /dev/null
+++ b/0.4.0/paludis/dep_atom_flattener.hh
@@ -0,0 +1,106 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_DEP_ATOM_FLATTENER_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_ATOM_FLATTENER_HH 1
+
+#include <list>
+#include <paludis/dep_atom.hh>
+#include <paludis/package_database.hh>
+#include <paludis/environment.hh>
+#include <paludis/util/attributes.hh>
+#include <paludis/util/instantiation_policy.hh>
+
+/** \file
+ * Declarations for DepAtomFlattener.
+ *
+ * \ingroup grpdepatomflattener
+ */
+
+namespace paludis
+{
+ /**
+ * Extract the enabled components of a dep heirarchy for a particular
+ * package.
+ *
+ * This is useful for picking out SRC_URI, PROVIDE etc components. It is
+ * <b>not</b> suitable for heirarchies that can contain || ( ) blocks.
+ *
+ * \ingroup grpdepatomflattener
+ */
+ class DepAtomFlattener :
+ private InstantiationPolicy<DepAtomFlattener, instantiation_method::NonCopyableTag>,
+ protected DepAtomVisitorTypes::ConstVisitor
+ {
+ private:
+ const Environment * const _env;
+
+ const PackageDatabaseEntry * const _pkg;
+
+ DepAtom::ConstPointer _a;
+
+ mutable std::list<const StringDepAtom *> _atoms;
+
+ mutable bool _done;
+
+ protected:
+ ///\name Visit methods
+ ///{
+ void visit(const AllDepAtom *);
+ void visit(const AnyDepAtom *) PALUDIS_ATTRIBUTE((noreturn));
+ void visit(const UseDepAtom *);
+ void visit(const PlainTextDepAtom *);
+ void visit(const PackageDepAtom *);
+ void visit(const BlockDepAtom *);
+ ///}
+
+ public:
+ /**
+ * Constructor.
+ */
+ DepAtomFlattener(const Environment * const,
+ const PackageDatabaseEntry * const,
+ const DepAtom::ConstPointer);
+
+ /**
+ * Destructor.
+ */
+ ~DepAtomFlattener();
+
+ /**
+ * Iterate over our dep atoms.
+ */
+ typedef std::list<const StringDepAtom *>::const_iterator Iterator;
+
+ /**
+ * Iterator to the start of our dep atoms.
+ */
+ Iterator begin();
+
+ /**
+ * Iterator to past the end of our dep atoms.
+ */
+ Iterator end() const
+ {
+ return _atoms.end();
+ }
+ };
+}
+
+#endif
diff --git a/0.4.0/paludis/dep_atom_pretty_printer.cc b/0.4.0/paludis/dep_atom_pretty_printer.cc
new file mode 100644
index 000000000..5de7f4aba
--- /dev/null
+++ b/0.4.0/paludis/dep_atom_pretty_printer.cc
@@ -0,0 +1,91 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <algorithm>
+#include <paludis/dep_atom.hh>
+#include <paludis/dep_atom_pretty_printer.hh>
+#include <paludis/util/save.hh>
+
+/** \file
+ * Implementation of dep_atom_pretty_printer.hh.
+ *
+ * \ingroup grpdepatomprettyprinter
+ */
+
+using namespace paludis;
+
+std::ostream &
+paludis::operator<< (std::ostream & s, const DepAtomPrettyPrinter & p)
+{
+ s << p._s.str();
+ return s;
+}
+
+void
+DepAtomPrettyPrinter::visit(const AllDepAtom * const a)
+{
+ _s << std::string(_indent, ' ') << "(" << std::endl;
+ {
+ Save<unsigned> old_indent(&_indent, _indent + 4);
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ }
+ _s << std::string(_indent, ' ') << ")" << std::endl;
+}
+
+void
+DepAtomPrettyPrinter::visit(const AnyDepAtom * const a)
+{
+ _s << std::string(_indent, ' ') << "|| (" << std::endl;
+ {
+ Save<unsigned> old_indent(&_indent, _indent + 4);
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ }
+ _s << std::string(_indent, ' ') << ")" << std::endl;
+}
+
+void
+DepAtomPrettyPrinter::visit(const UseDepAtom * const a)
+{
+ _s << std::string(_indent, ' ') << (a->inverse() ? "!" : "") <<
+ a->flag() << "? (" << std::endl;
+ {
+ Save<unsigned> old_indent(&_indent, _indent + 4);
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ }
+ _s << std::string(_indent, ' ') << ")" << std::endl;
+}
+
+void
+DepAtomPrettyPrinter::visit(const PackageDepAtom * const p)
+{
+ _s << std::string(_indent, ' ') << *p << std::endl;
+}
+
+void
+DepAtomPrettyPrinter::visit(const PlainTextDepAtom * const p)
+{
+ _s << std::string(_indent, ' ') << p->text() << std::endl;
+}
+
+void
+DepAtomPrettyPrinter::visit(const BlockDepAtom * const b)
+{
+ _s << std::string(_indent, ' ') << "!" << *b->blocked_atom() << std::endl;
+}
+
diff --git a/0.4.0/paludis/dep_atom_pretty_printer.hh b/0.4.0/paludis/dep_atom_pretty_printer.hh
new file mode 100644
index 000000000..59ac6beaf
--- /dev/null
+++ b/0.4.0/paludis/dep_atom_pretty_printer.hh
@@ -0,0 +1,82 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_DEP_ATOM_PRETTY_PRINTER_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_ATOM_PRETTY_PRINTER_HH 1
+
+#include <ostream>
+#include <paludis/dep_atom.hh>
+#include <sstream>
+
+/** \file
+ * Declarations for the DepAtomPrettyPrinter class.
+ *
+ * \ingroup grpdepatomprettyprinter
+ */
+
+namespace paludis
+{
+ /**
+ * Pretty print dependency atoms.
+ *
+ * \ingroup grpdepatomprettyprinter
+ */
+ class DepAtomPrettyPrinter :
+ public DepAtomVisitorTypes::ConstVisitor
+ {
+ friend std::ostream & operator<< (std::ostream &, const DepAtomPrettyPrinter &);
+
+ private:
+ std::stringstream _s;
+ unsigned _indent;
+
+ public:
+ /**
+ * Constructor.
+ */
+ DepAtomPrettyPrinter(unsigned initial_indent) :
+ _indent(initial_indent)
+ {
+ }
+
+ /// \name Visit functions
+ ///{
+ void visit(const AllDepAtom * const);
+
+ void visit(const AnyDepAtom * const);
+
+ void visit(const UseDepAtom * const);
+
+ void visit(const PackageDepAtom * const);
+
+ void visit(const PlainTextDepAtom * const);
+
+ void visit(const BlockDepAtom * const);
+ ///}
+ };
+
+ /**
+ * Output a DepAtomPrettyPrinter to an ostream.
+ *
+ * \ingroup grpdepatomprettyprinter
+ */
+ std::ostream & operator<< (std::ostream & s, const DepAtomPrettyPrinter & p);
+}
+
+#endif
diff --git a/0.4.0/paludis/dep_list.cc b/0.4.0/paludis/dep_list.cc
new file mode 100644
index 000000000..5348392d1
--- /dev/null
+++ b/0.4.0/paludis/dep_list.cc
@@ -0,0 +1,852 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/dep_atom.hh>
+#include <paludis/dep_atom_flattener.hh>
+#include <paludis/dep_list.hh>
+#include <paludis/match_package.hh>
+#include <paludis/util/container_entry.hh>
+#include <paludis/util/iterator.hh>
+#include <paludis/util/join.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/save.hh>
+#include <paludis/util/stringify.hh>
+
+#include <algorithm>
+#include <functional>
+#include <deque>
+#include <vector>
+
+using namespace paludis;
+
+std::ostream &
+paludis::operator<< (std::ostream & s, const DepListEntry & e)
+{
+ s << e.get<dle_name>() << "-" << e.get<dle_version>() << ":"
+ << e.get<dle_metadata>()->get<vm_slot>() << "::" << e.get<dle_repository>();
+ return s;
+}
+
+DepListError::DepListError(const std::string & m) throw () :
+ Exception(m)
+{
+}
+
+DepListStackTooDeepError::DepListStackTooDeepError(int level) throw () :
+ DepListError("DepList stack too deep (" + stringify(level) + " entries)")
+{
+}
+
+NoResolvableOptionError::NoResolvableOptionError() throw () :
+ DepListError("No resolvable || ( ) option")
+{
+}
+
+template <typename I_>
+NoResolvableOptionError::NoResolvableOptionError(I_ i, I_ end) throw () :
+ DepListError("No resolvable || ( ) option." + (i == end ?
+ std::string("") : " Failure messages are '" + join(i, end, "', '") + "'"))
+{
+}
+
+AllMaskedError::AllMaskedError(const std::string & query) throw () :
+ DepListError("Error searching for '" + query + "': no available versions"),
+ _query(query)
+{
+}
+
+UseRequirementsNotMetError::UseRequirementsNotMetError(const std::string & query) throw () :
+ DepListError("Error searching for '" + query + "': use requirements are not met"),
+ _query(query)
+{
+}
+
+BlockError::BlockError(const std::string & msg) throw () :
+ DepListError("Block: " + msg)
+{
+}
+
+namespace paludis
+{
+ /**
+ * Implementation data for DepList.
+ */
+ template<>
+ struct Implementation<DepList> :
+ InstantiationPolicy<Implementation<DepList>, instantiation_method::NonCopyableTag>,
+ InternalCounted<Implementation<DepList> >
+ {
+ ///\name Provided data
+ ///{
+ const Environment * const environment;
+ ///}
+
+ ///\name Generated data
+ ///{
+ std::list<DepListEntry> merge_list;
+ std::list<DepListEntry>::iterator merge_list_insert_pos;
+ bool check_existing_only;
+ bool match_found;
+ const DepListEntry * current_package;
+ ///}
+
+ ///\name Settings
+ ///{
+ DepListRdependOption rdepend_post;
+ bool recursive_deps;
+ bool drop_circular;
+ bool drop_self_circular;
+ bool drop_all;
+ bool ignore_installed;
+ bool reinstall;
+ bool no_unnecessary_upgrades;
+ ///}
+
+ ///\name Stack
+ ///{
+ int stack_depth;
+ int max_stack_depth;
+ ///}
+
+ /// Constructor.
+ Implementation(const Environment * const e) :
+ environment(e),
+ check_existing_only(false),
+ match_found(false),
+ current_package(0),
+ rdepend_post(dlro_as_needed),
+ recursive_deps(true),
+ drop_circular(false),
+ drop_self_circular(false),
+ drop_all(false),
+ ignore_installed(false),
+ reinstall(true),
+ stack_depth(0),
+ max_stack_depth(100)
+ {
+ }
+ };
+}
+
+DepList::DepList(const Environment * const e) :
+ PrivateImplementationPattern<DepList>(new Implementation<DepList>(e))
+{
+}
+
+DepList::~DepList()
+{
+}
+
+namespace
+{
+ struct IsSkip
+ {
+ bool operator() (const DepListEntry & e) const
+ {
+ return e.get<dle_flags>()[dlef_skip];
+ }
+ };
+}
+
+void
+DepList::add(DepAtom::ConstPointer atom)
+{
+ Context context("When adding dependencies:");
+
+ std::list<DepListEntry> save_merge_list(_imp->merge_list.begin(),
+ _imp->merge_list.end());
+
+ _imp->merge_list_insert_pos = _imp->merge_list.end();
+ _add(atom);
+
+ try
+ {
+ std::list<DepListEntry>::iterator i(_imp->merge_list.begin());
+ _imp->merge_list_insert_pos = _imp->merge_list.end();
+ while (i != _imp->merge_list.end())
+ {
+ if (! i->get<dle_flags>()[dlef_has_predeps] && ! _imp->drop_all)
+ throw InternalError(PALUDIS_HERE, "dle_has_predeps not set for " + stringify(*i));
+
+ else if (! i->get<dle_flags>()[dlef_has_trypredeps] && ! _imp->drop_all)
+ {
+ Save<const DepListEntry *> save_current_package(
+ &_imp->current_package, &*i);
+ _add_in_role(_imp->environment->package_database()->fetch_repository(
+ i->get<dle_repository>())->version_metadata(
+ i->get<dle_name>(), i->get<dle_version>())->get<vm_deps>().run_depend(),
+ "runtime dependencies");
+ i->get<dle_flags>().set(dlef_has_trypredeps);
+ }
+
+ else if (! i->get<dle_flags>()[dlef_has_postdeps] && ! _imp->drop_all)
+ {
+ Save<const DepListEntry *> save_current_package(
+ &_imp->current_package, &*i);
+ _add_in_role(_imp->environment->package_database()->fetch_repository(
+ i->get<dle_repository>())->version_metadata(
+ i->get<dle_name>(), i->get<dle_version>())->get<vm_deps>().post_depend(),
+ "post dependencies");
+ i->get<dle_flags>().set(dlef_has_postdeps);
+ }
+ else
+ ++i;
+ }
+
+ /* remove skip entries */
+ _imp->merge_list.remove_if(IsSkip());
+ }
+ catch (...)
+ {
+ _imp->merge_list.swap(save_merge_list);
+ throw;
+ }
+}
+
+void
+DepList::_add_raw(const DepAtom * const atom)
+{
+#if 0
+ /// \bug VV this is debug code. remove it once we're sure this works
+ std::list<DepListEntry> backup_merge_list(_imp->merge_list.begin(),
+ _imp->merge_list.end());
+#endif
+
+ /* keep track of stack depth */
+ Save<int> old_stack_depth(&_imp->stack_depth,
+ _imp->stack_depth + 1);
+ if (_imp->stack_depth > _imp->max_stack_depth)
+ throw DepListStackTooDeepError(_imp->stack_depth);
+
+ /* we need to make sure that merge_list doesn't get h0rked in the
+ * event of a failure. */
+ bool merge_list_was_empty(_imp->merge_list.empty()), irange_begin_is_begin(false);
+ std::list<DepListEntry>::iterator save_last, save_first, save_irange_begin, save_irange_end;
+ if (! merge_list_was_empty)
+ {
+ save_first = _imp->merge_list.begin();
+ save_last = previous(_imp->merge_list.end());
+
+ save_irange_end = _imp->merge_list_insert_pos;
+ if (_imp->merge_list_insert_pos == _imp->merge_list.begin())
+ irange_begin_is_begin = true;
+ else
+ save_irange_begin = previous(_imp->merge_list_insert_pos);
+ }
+
+ try
+ {
+ atom->accept(this);
+ }
+ catch (const InternalError &)
+ {
+ throw;
+ }
+ catch (...)
+ {
+ if (merge_list_was_empty)
+ _imp->merge_list.clear();
+ else
+ {
+ _imp->merge_list.erase(next(save_last), _imp->merge_list.end());
+ _imp->merge_list.erase(_imp->merge_list.begin(), save_first);
+ _imp->merge_list.erase(
+ irange_begin_is_begin ? _imp->merge_list.begin() : next(save_irange_begin),
+ save_irange_end);
+ }
+
+#if 0
+ /// \bug VV this is debug code. remove it once we're sure this works
+ if (backup_merge_list != _imp->merge_list)
+ {
+ Log::get_instance()->message(ll_warning, "Old merge_list: " + join(backup_merge_list.begin(),
+ backup_merge_list.end(), " -> "));
+ Log::get_instance()->message(ll_warning, "New merge_list: " + join(_imp->merge_list.begin(),
+ _imp->merge_list.end(), " -> "));
+ throw InternalError(PALUDIS_HERE, "merge list restore failed");
+ }
+#endif
+ throw;
+ }
+}
+
+void
+DepList::_add_in_role_raw(const DepAtom * const atom, const std::string & role)
+{
+ Context context("When adding " + role + ":");
+ _add_raw(atom);
+}
+
+DepList::Iterator
+DepList::begin() const
+{
+ return _imp->merge_list.begin();
+}
+
+DepList::Iterator
+DepList::end() const
+{
+ return _imp->merge_list.end();
+}
+
+void
+DepList::visit(const AllDepAtom * const v)
+{
+ std::for_each(v->begin(), v->end(), accept_visitor(
+ static_cast<DepAtomVisitorTypes::ConstVisitor *>(this)));
+}
+
+#ifndef DOXYGEN
+struct DepListEntryMatcher :
+ public std::unary_function<bool, const DepListEntry &>
+{
+ const Environment * const env;
+ const PackageDepAtom & atom;
+
+ DepListEntryMatcher(const Environment * const e, const PackageDepAtom & p) :
+ env(e),
+ atom(p)
+ {
+ }
+
+ bool operator() (const DepListEntry & e) const
+ {
+ return match_package(env, atom, e);
+ }
+};
+#endif
+
+void
+DepList::visit(const PackageDepAtom * const p)
+{
+ Context context("When resolving package dependency '" + stringify(*p) + "':");
+
+ PackageDatabaseEntryCollection::ConstPointer installed(
+ _imp->environment->package_database()->query(*p, is_installed_only));
+
+ /* if we're installed and we don't want to upgrade unnecessarily,
+ * stop if we're not on a top level target */
+ if ((! installed->empty()) && (_imp->no_unnecessary_upgrades))
+ if (0 != _imp->current_package)
+ return;
+
+ /* are we already on the merge list? */
+ {
+ std::list<DepListEntry>::iterator i;
+ if (_imp->merge_list.end() != ((i = std::find_if(
+ _imp->merge_list.begin(),
+ _imp->merge_list.end(),
+ DepListEntryMatcher(_imp->environment, *p)))))
+ {
+ /* what's our status? */
+ if (! i->get<dle_flags>()[dlef_has_predeps])
+ {
+ if (! installed->empty())
+ return;
+
+ else if (_imp->drop_circular)
+ {
+ if (_imp->current_package)
+ Log::get_instance()->message(ll_warning, lc_context, "Dropping circular dependency on " +
+ stringify(_imp->current_package->get<dle_name>()) + "-" +
+ stringify(_imp->current_package->get<dle_version>()));
+ return;
+ }
+
+ else if (_imp->current_package && _imp->drop_self_circular &&
+ match_package(_imp->environment, p, _imp->current_package))
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Dropping self-circular dependency on " +
+ stringify(_imp->current_package->get<dle_name>()) + "-" +
+ stringify(_imp->current_package->get<dle_version>()));
+ return;
+ }
+
+ else
+ throw CircularDependencyError(i, next(i));
+ }
+
+ if (p->tag())
+ i->get<dle_tag>().insert(p->tag());
+ return;
+ }
+ }
+
+ /* are we allowed to install things? */
+ if (_imp->check_existing_only)
+ {
+ _imp->match_found = ! installed->empty();
+ return;
+ }
+
+ /* find the matching package */
+ const PackageDatabaseEntry * match(0);
+ VersionMetadata::ConstPointer metadata(0);
+ PackageDatabaseEntryCollection::Pointer matches(0);
+
+ matches = _imp->environment->package_database()->query(*p, is_uninstalled_only);
+ for (PackageDatabaseEntryCollection::ReverseIterator e(matches->rbegin()),
+ e_end(matches->rend()) ; e != e_end ; ++e)
+ {
+ /* if we're already installed, only include us if we're a better version or
+ * if we're a top level target */
+ /// \todo SLOTs?
+ if ((! _imp->ignore_installed) && ((0 != _imp->current_package) || (! _imp->reinstall)))
+ if (! installed->empty())
+ if (e->get<pde_version>() <= installed->last()->get<pde_version>())
+ continue;
+
+ /* check masks */
+ if (_imp->environment->mask_reasons(*e).any())
+ continue;
+
+ metadata = _imp->environment->package_database()->fetch_repository(
+ e->get<pde_repository>())->version_metadata(e->get<pde_name>(), e->get<pde_version>());
+ match = &*e;
+ break;
+ }
+
+ std::list<DepListEntry>::iterator merge_entry;
+ std::set<DepTag::ConstPointer, DepTag::Comparator> tags;
+ if (p->tag())
+ tags.insert(p->tag());
+ if (! match)
+ {
+ if (! installed->empty())
+ {
+ if (_imp->recursive_deps)
+ {
+ metadata = _imp->environment->package_database()->fetch_repository(
+ installed->last()->get<pde_repository>())->version_metadata(
+ installed->last()->get<pde_name>(), installed->last()->get<pde_version>());
+ DepListEntryFlags flags;
+ flags.set(dlef_has_predeps);
+ flags.set(dlef_skip);
+ merge_entry = _imp->merge_list.insert(_imp->merge_list_insert_pos,
+ DepListEntry(installed->last()->get<pde_name>(),
+ installed->last()->get<pde_version>(), metadata,
+ installed->last()->get<pde_repository>(), flags, tags));
+ }
+ else
+ return;
+ }
+ else if (p->use_requirements_ptr())
+ {
+ /* if we *could* have a match except for the AllMaskedError,
+ * throw a UseRequirementsNotMetError error instead. */
+ if (! _imp->environment->package_database()->query(
+ p->without_use_requirements(), is_either)->empty())
+ throw UseRequirementsNotMetError(stringify(*p));
+ else
+ throw AllMaskedError(stringify(*p));
+ }
+ else
+ throw AllMaskedError(stringify(*p));
+ }
+ else
+ {
+ DepListEntryFlags flags;
+ merge_entry = _imp->merge_list.insert(_imp->merge_list_insert_pos,
+ DepListEntry(match->get<pde_name>(), match->get<pde_version>(),
+ metadata, match->get<pde_repository>(), flags, tags));
+ }
+
+ /* if we provide things, also insert them. */
+ if ((metadata->get_ebuild_interface()) && ! merge_entry->get<dle_flags>()[dlef_skip])
+ {
+ DepAtom::ConstPointer provide(metadata->get_ebuild_interface()->provide());
+
+ CountedPtr<PackageDatabaseEntry, count_policy::ExternalCountTag> e(0);
+
+ if (_imp->current_package)
+ e = CountedPtr<PackageDatabaseEntry, count_policy::ExternalCountTag>(
+ new PackageDatabaseEntry(
+ _imp->current_package->get<dle_name>(),
+ _imp->current_package->get<dle_version>(),
+ _imp->current_package->get<dle_repository>()));
+
+ DepAtomFlattener f(_imp->environment, e.raw_pointer(), provide);
+
+ for (DepAtomFlattener::Iterator p(f.begin()), p_end(f.end()) ; p != p_end ; ++p)
+ {
+ PackageDepAtom pp(QualifiedPackageName((*p)->text()));
+ if (_imp->merge_list.end() != std::find_if(
+ _imp->merge_list.begin(), _imp->merge_list.end(),
+ DepListEntryMatcher(_imp->environment, pp)))
+ continue;
+
+ VersionMetadata::Pointer p_metadata(new VersionMetadata::Ebuild(
+ merge_entry->get<dle_metadata>()->get<vm_deps>().get<vmd_parser>()));
+ p_metadata->set<vm_slot>(merge_entry->get<dle_metadata>()->get<vm_slot>());
+ p_metadata->get_ebuild_interface()->set<evm_virtual>(stringify(merge_entry->get<dle_name>()));
+
+ DepListEntryFlags flags;
+ flags.set(dlef_has_predeps);
+ flags.set(dlef_has_trypredeps);
+ flags.set(dlef_has_postdeps);
+ _imp->merge_list.insert(next(merge_entry),
+ DepListEntry(pp.package(), merge_entry->get<dle_version>(),
+ p_metadata, merge_entry->get<dle_repository>(), flags,
+ std::set<DepTag::ConstPointer, DepTag::Comparator>()));
+ }
+ }
+
+ Save<std::list<DepListEntry>::iterator> old_merge_list_insert_pos(
+ &_imp->merge_list_insert_pos, merge_entry);
+
+ context.change_context("When resolving package dependency '" + stringify(*p) +
+ "' -> '" + stringify(*merge_entry) + "':");
+
+ /* new current package */
+ Save<const DepListEntry *> old_current_package(&_imp->current_package,
+ &*merge_entry);
+
+ /* merge depends */
+ if ((! merge_entry->get<dle_flags>()[dlef_has_predeps]) && ! (_imp->drop_all))
+ _add_in_role(metadata->get<vm_deps>().build_depend(), "build dependencies");
+ merge_entry->get<dle_flags>().set(dlef_has_predeps);
+
+ /* merge rdepends */
+ if (! merge_entry->get<dle_flags>()[dlef_has_trypredeps] && dlro_always != _imp->rdepend_post
+ && ! _imp->drop_all)
+ {
+ try
+ {
+ _add_in_role(metadata->get<vm_deps>().run_depend(), "runtime dependencies");
+ merge_entry->get<dle_flags>().set(dlef_has_trypredeps);
+ }
+ catch (const CircularDependencyError &)
+ {
+ if (dlro_never == _imp->rdepend_post)
+ throw;
+ else if (_imp->current_package)
+ Log::get_instance()->message(ll_warning, lc_context, "Couldn't resolve runtime dependencies "
+ "for " + stringify(_imp->current_package->get<dle_name>()) + "-" +
+ stringify(_imp->current_package->get<dle_version>()) + " as build dependencies, "
+ "trying them as post dependencies");
+ }
+ }
+}
+
+void
+DepList::visit(const UseDepAtom * const u)
+{
+ CountedPtr<PackageDatabaseEntry, count_policy::ExternalCountTag> e(0);
+
+ if (_imp->current_package)
+ e = CountedPtr<PackageDatabaseEntry, count_policy::ExternalCountTag>(
+ new PackageDatabaseEntry(
+ _imp->current_package->get<dle_name>(),
+ _imp->current_package->get<dle_version>(),
+ _imp->current_package->get<dle_repository>()));
+
+ if (_imp->environment->query_use(u->flag(), e.raw_pointer()) ^ u->inverse())
+ std::for_each(u->begin(), u->end(), std::bind1st(std::mem_fun(&DepList::_add), this));
+}
+
+#ifndef DOXYGEN
+struct IsViable :
+ public std::unary_function<bool, DepAtom::ConstPointer>
+{
+ const Implementation<DepList> & _impl;
+ CountedPtr<PackageDatabaseEntry, count_policy::ExternalCountTag> e;
+
+ IsViable(const Implementation<DepList> & impl) :
+ _impl(impl),
+ e(0)
+ {
+ if (_impl.current_package)
+ e = CountedPtr<PackageDatabaseEntry, count_policy::ExternalCountTag>(
+ new PackageDatabaseEntry(
+ _impl.current_package->get<dle_name>(),
+ _impl.current_package->get<dle_version>(),
+ _impl.current_package->get<dle_repository>()));
+ }
+
+ bool operator() (DepAtom::ConstPointer a)
+ {
+ const UseDepAtom * const u(a->as_use_dep_atom());
+ if (0 != u)
+ return _impl.environment->query_use(u->flag(), e.raw_pointer()) ^ u->inverse();
+ else
+ return true;
+ }
+};
+#endif
+
+void
+DepList::visit(const AnyDepAtom * const a)
+{
+ /* try to resolve each of our children in return. note the annoying
+ * special case for use? () flags:
+ *
+ * || ( ) -> nothing
+ * || ( off1? ( blah1 ) off2? ( blah2 ) blah3 ) -> blah3
+ * || ( off1? ( blah1 ) off2? ( blah2 ) ) -> nothing
+ * || ( ( off1? ( blah1 ) ) blah2 ) -> nothing
+ *
+ * we handle this by keeping a list of 'viable children'.
+ */
+
+ std::list<DepAtom::ConstPointer> viable_children;
+ std::copy(a->begin(), a->end(), filter_inserter(
+ std::back_inserter(viable_children), IsViable(*_imp)));
+
+ if (viable_children.empty())
+ {
+ if (_imp->current_package)
+ Log::get_instance()->message(ll_qa, lc_context, "Package '" + stringify(*_imp->current_package)
+ + "' has suspicious || ( ) block that resolves to empty");
+ return;
+ }
+
+ bool found(false);
+ std::list<DepAtom::ConstPointer>::iterator found_i;
+ for (std::list<DepAtom::ConstPointer>::iterator i(viable_children.begin()),
+ i_end(viable_children.end()) ; i != i_end ; ++i)
+ {
+ Save<bool> save_check(&_imp->check_existing_only, true);
+ Save<bool> save_match(&_imp->match_found, true);
+ _add(*i);
+ if ((found = _imp->match_found))
+ {
+ found_i = i;
+ break;
+ }
+ }
+ if (found)
+ {
+ if (_imp->recursive_deps && ! _imp->check_existing_only)
+ _add(*found_i);
+ return;
+ }
+
+ if (_imp->check_existing_only)
+ {
+ _imp->match_found = false;
+ return;
+ }
+
+ /* try to merge each of our viable children in turn. */
+ std::deque<std::string> errors;
+ for (CompositeDepAtom::Iterator i(viable_children.begin()), i_end(viable_children.end()) ;
+ i != i_end ; ++i)
+ {
+ try
+ {
+ _add(*i);
+ return;
+ }
+ catch (const DepListStackTooDeepError &)
+ {
+ /* don't work around a stack too deep error. our item may be
+ * resolvable with a deeper stack. */
+ throw;
+ }
+ catch (const DepListError & e)
+ {
+ errors.push_back(e.message() + " (" + e.what() + ")");
+ }
+ }
+
+ /* no match */
+ throw NoResolvableOptionError(errors.begin(), errors.end());
+}
+
+void
+DepList::visit(const BlockDepAtom * const d)
+{
+ Context context("When checking block '!" + stringify(*(d->blocked_atom())) + "':");
+
+ /* special case: the provider of virtual/blah can DEPEND upon !virtual/blah. */
+ /* special case: foo/bar can DEPEND upon !foo/bar. */
+
+ /* are we already installed? */
+ PackageDatabaseEntryCollection::ConstPointer installed(_imp->environment->package_database()->
+ query(d->blocked_atom(), is_installed_only));
+ if (! installed->empty())
+ {
+ if (! _imp->current_package)
+ throw BlockError("'" + stringify(*(d->blocked_atom())) + "' blocked by installed package '"
+ + stringify(*installed->last()) + "' (no current package)");
+
+ for (PackageDatabaseEntryCollection::Iterator ii(installed->begin()),
+ ii_end(installed->end()) ; ii != ii_end ; ++ii)
+ {
+ if (_imp->current_package->get<dle_name>() == ii->get<pde_name>())
+ {
+ Log::get_instance()->message(ll_qa, lc_context, "Package '" + stringify(*_imp->current_package)
+ + "' has suspicious block upon '!" + stringify(*d->blocked_atom()) + "'");
+ continue;
+ }
+
+ DepAtom::ConstPointer provide(new AllDepAtom);
+ if (_imp->current_package->get<dle_metadata>()->get_ebuild_interface())
+ provide = _imp->current_package->get<dle_metadata>()->get_ebuild_interface()->provide();
+
+ CountedPtr<PackageDatabaseEntry, count_policy::ExternalCountTag> e(0);
+
+ e = CountedPtr<PackageDatabaseEntry, count_policy::ExternalCountTag>(
+ new PackageDatabaseEntry(
+ _imp->current_package->get<dle_name>(),
+ _imp->current_package->get<dle_version>(),
+ _imp->current_package->get<dle_repository>()));
+
+ DepAtomFlattener f(_imp->environment, e.raw_pointer(), provide);
+
+ bool skip(false);
+ for (IndirectIterator<DepAtomFlattener::Iterator, const StringDepAtom> i(f.begin()),
+ i_end(f.end()) ; i != i_end ; ++i)
+ if (QualifiedPackageName(i->text()) == d->blocked_atom()->package())
+ {
+ skip = true;
+ break;
+ }
+
+ if (skip)
+ Log::get_instance()->message(ll_qa, lc_context, "Ignoring block on '" +
+ stringify(*(d->blocked_atom())) + "' in '" +
+ stringify(*_imp->current_package) +
+ "' which is blocked by installed package '" + stringify(*ii) +
+ "' due to PROVIDE");
+ else
+ throw BlockError("'" + stringify(*(d->blocked_atom())) + "' blocked by installed package '"
+ + stringify(*installed->last()) + "' when trying to install package '" +
+ stringify(*_imp->current_package) + "'");
+ }
+ }
+
+ /* will we be installed by this point? */
+ std::list<DepListEntry>::iterator m(_imp->merge_list.begin());
+ while (m != _imp->merge_list.end())
+ {
+ if (_imp->merge_list.end() != ((m = std::find_if(m, _imp->merge_list.end(),
+ DepListEntryMatcher(_imp->environment, *(d->blocked_atom()))))))
+ {
+ if (! _imp->current_package)
+ throw BlockError("'" + stringify(*(d->blocked_atom())) + "' blocked by pending package '"
+ + stringify(*m) + "' (no current package)");
+
+ if (*_imp->current_package == *m)
+ {
+ Log::get_instance()->message(ll_qa,lc_context, "Package '" + stringify(*_imp->current_package)
+ + "' has suspicious block upon '!" + stringify(*d->blocked_atom()) + "'");
+ ++m;
+ continue;
+ }
+
+ DepAtom::ConstPointer provide(new AllDepAtom);
+ if (_imp->current_package->get<dle_metadata>()->get_ebuild_interface())
+ provide = _imp->current_package->get<dle_metadata>()->get_ebuild_interface()->provide();
+
+ CountedPtr<PackageDatabaseEntry, count_policy::ExternalCountTag> e(0);
+
+ e = CountedPtr<PackageDatabaseEntry, count_policy::ExternalCountTag>(
+ new PackageDatabaseEntry(
+ _imp->current_package->get<dle_name>(),
+ _imp->current_package->get<dle_version>(),
+ _imp->current_package->get<dle_repository>()));
+
+ DepAtomFlattener f(_imp->environment, e.raw_pointer(), provide);
+
+ bool skip(false);
+ for (IndirectIterator<DepAtomFlattener::Iterator, const StringDepAtom> i(f.begin()),
+ i_end(f.end()) ; i != i_end ; ++i)
+ if (QualifiedPackageName(i->text()) == d->blocked_atom()->package())
+ {
+ skip = true;
+ break;
+ }
+
+ if (skip)
+ Log::get_instance()->message(ll_qa, lc_context, "Ignoring block on '" +
+ stringify(*(d->blocked_atom())) + "' in '" +
+ stringify(*_imp->current_package) +
+ "' which is blocked by pending package '" + stringify(*m) +
+ "' due to PROVIDE");
+ else
+ throw BlockError("'" + stringify(*(d->blocked_atom())) + "' blocked by pending package '"
+ + stringify(*m) + "' when trying to install '"
+ + stringify(*_imp->current_package) + "'");
+
+ ++m;
+ }
+ }
+}
+
+void
+DepList::set_rdepend_post(const DepListRdependOption value)
+{
+ _imp->rdepend_post = value;
+}
+
+void
+DepList::set_drop_circular(const bool value)
+{
+ _imp->drop_circular = value;
+}
+
+void
+DepList::set_drop_self_circular(const bool value)
+{
+ _imp->drop_self_circular = value;
+}
+
+void
+DepList::set_drop_all(const bool value)
+{
+ _imp->drop_all = value;
+}
+
+void
+DepList::set_ignore_installed(const bool value)
+{
+ _imp->ignore_installed = value;
+}
+
+void
+DepList::set_recursive_deps(const bool value)
+{
+ _imp->recursive_deps = value;
+}
+
+void
+DepList::set_max_stack_depth(const int value)
+{
+ _imp->max_stack_depth = value;
+}
+
+void
+DepList::visit(const PlainTextDepAtom * const t)
+{
+ throw InternalError(PALUDIS_HERE, "Got unexpected PlainTextDepAtom '" + t->text() + "'");
+}
+
+void
+DepList::set_reinstall(const bool value)
+{
+ _imp->reinstall = value;
+}
+
+void
+DepList::set_no_unnecessary_upgrades(const bool value)
+{
+ _imp->no_unnecessary_upgrades = value;
+}
+
diff --git a/0.4.0/paludis/dep_list.hh b/0.4.0/paludis/dep_list.hh
new file mode 100644
index 000000000..88559244e
--- /dev/null
+++ b/0.4.0/paludis/dep_list.hh
@@ -0,0 +1,419 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_DEP_LIST_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_LIST_HH 1
+
+#include <algorithm>
+#include <bitset>
+#include <deque>
+#include <iterator>
+#include <list>
+#include <ostream>
+#include <set>
+#include <paludis/dep_atom.hh>
+#include <paludis/dep_tag.hh>
+#include <paludis/name.hh>
+#include <paludis/environment.hh>
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/smart_record.hh>
+#include <paludis/version_spec.hh>
+
+namespace paludis
+{
+ /**
+ * Keys for a DepListEntry.
+ *
+ * \see DepListEntry
+ * \ingroup grpdepresolver
+ */
+ enum DepListEntryKeys
+ {
+ dle_name, ///< Package name
+ dle_version, ///< Package version
+ dle_metadata, ///< Package SLOT
+ dle_repository, ///< Repository name
+ dle_flags, ///< Flags
+ dle_tag, ///< Our tag
+ last_dle ///< Number of entries
+ };
+
+ /**
+ * Flags for a DepListEntry.
+ *
+ * \see DepListEntry
+ * \ingroup grpdepresolver
+ */
+ enum DepListEntryFlag
+ {
+ dlef_has_predeps,
+ dlef_has_trypredeps,
+ dlef_has_postdeps,
+ dlef_skip,
+ last_dlef
+ };
+
+ /**
+ * Flags for a DepListEntry.
+ *
+ * \ingroup grpdepresolver
+ */
+ typedef std::bitset<last_dlef> DepListEntryFlags;
+
+ /**
+ * Tag for a DepListEntry.
+ *
+ * \ingroup grpdepresolver
+ */
+ struct DepListEntryTag :
+ SmartRecordTag<comparison_mode::EqualityComparisonTag, comparison_method::SmartRecordCompareByAllTag>,
+ SmartRecordKeys<DepListEntryKeys, last_dle>,
+ SmartRecordKey<dle_name, QualifiedPackageName>,
+ SmartRecordKey<dle_version, VersionSpec>,
+ SmartRecordKey<dle_metadata, VersionMetadata::ConstPointer>,
+ SmartRecordKey<dle_repository, RepositoryName>,
+ SmartRecordKey<dle_flags, DepListEntryFlags>,
+ SmartRecordKey<dle_tag, std::set<DepTag::ConstPointer, DepTag::Comparator> >
+ {
+ };
+
+ /**
+ * A DepListEntry represents an entry in a DepList.
+ *
+ * \ingroup grpdepresolver
+ */
+ typedef MakeSmartRecord<DepListEntryTag>::Type DepListEntry;
+
+ /**
+ * A DepListEntry can be written to a stream.
+ *
+ * \ingroup grpdepresolver
+ */
+ std::ostream & operator<< (std::ostream &, const DepListEntry &);
+
+ /**
+ * Thrown if an error occurs whilst building a DepList.
+ *
+ * \ingroup grpdepresolver
+ * \ingroup grpexceptions
+ */
+ class DepListError : public Exception
+ {
+ protected:
+ /**
+ * Constructor.
+ */
+ DepListError(const std::string &) throw ();
+ };
+
+ /**
+ * Thrown if a DepList's add stack gets too deep.
+ *
+ * \ingroup grpdepresolver
+ * \ingroup grpexceptions
+ */
+ class DepListStackTooDeepError : public DepListError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ DepListStackTooDeepError(int level) throw ();
+ };
+
+ /**
+ * Thrown if no entry in a || ( ) block is resolvable.
+ *
+ * \ingroup grpdepresolver
+ * \ingroup grpexceptions
+ */
+ class NoResolvableOptionError : public DepListError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ NoResolvableOptionError() throw ();
+
+ /**
+ * Constructor with failure reasons.
+ */
+ template <typename I_>
+ NoResolvableOptionError(I_ i, I_ end) throw ();
+ };
+
+ /**
+ * Thrown if all versions of a particular atom are masked.
+ *
+ * \ingroup grpdepresolver
+ * \ingroup grpexceptions
+ */
+ class AllMaskedError : public DepListError
+ {
+ private:
+ std::string _query;
+
+ public:
+ /**
+ * Constructor.
+ */
+ AllMaskedError(const std::string & query) throw ();
+
+ /**
+ * Destructor.
+ */
+ virtual ~AllMaskedError() throw ()
+ {
+ }
+
+ /**
+ * Our query.
+ */
+ const std::string & query() const
+ {
+ return _query;
+ }
+ };
+
+ /**
+ * Thrown if all versions of a particular atom are masked,
+ * but would not be if use requirements were not in effect.
+ *
+ * \ingroup grpdepresolver
+ * \ingroup grpexceptions
+ */
+ class UseRequirementsNotMetError : public DepListError
+ {
+ private:
+ std::string _query;
+
+ public:
+ /**
+ * Constructor.
+ */
+ UseRequirementsNotMetError(const std::string & query) throw ();
+
+ /**
+ * Destructor.
+ */
+ virtual ~UseRequirementsNotMetError() throw ()
+ {
+ }
+
+ /**
+ * Our query.
+ */
+ const std::string & query() const
+ {
+ return _query;
+ }
+ };
+
+ /**
+ * Thrown if a block is encountered.
+ *
+ * \ingroup grpdepresolver
+ * \ingroup grpexceptions
+ */
+ class BlockError : public DepListError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ BlockError(const std::string & msg) throw ();
+ };
+
+ /**
+ * Thrown if a circular dependency is encountered.
+ *
+ * \ingroup grpdepresolver
+ * \ingroup grpexceptions
+ */
+ class CircularDependencyError : public DepListError
+ {
+ private:
+ unsigned _cycle_size;
+
+ public:
+ /**
+ * Constructor, from a sequence of the items causing the circular
+ * dependency.
+ */
+ template <typename I_>
+ CircularDependencyError(I_ begin, const I_ end) throw () :
+ DepListError("Circular dependency: " + join(begin, end, " -> ")),
+ _cycle_size(std::distance(begin, end))
+ {
+ }
+
+ /**
+ * How large is our circular dependency cycle?
+ */
+ unsigned cycle_size() const
+ {
+ return _cycle_size;
+ }
+ };
+
+ /**
+ * Used in DepList::set_rdepend_post.
+ *
+ * \ingroup grpdepresolver
+ */
+ enum DepListRdependOption
+ {
+ /**
+ * RDEPENDs are always merged before the package; abort if this fails.
+ */
+ dlro_never,
+
+ /**
+ * RDEPENDs can be merged after the package, just before PDEPEND, if this is
+ * necessary for correct resolution
+ */
+ dlro_as_needed,
+
+ /**
+ * RDEPENDs are always merged with PDEPENDs.
+ */
+ dlro_always
+ };
+
+ /**
+ * Holds a list of dependencies in merge order.
+ *
+ * \ingroup grpdepresolver
+ */
+ class DepList :
+ private InstantiationPolicy<DepList, instantiation_method::NonCopyableTag>,
+ private PrivateImplementationPattern<DepList>,
+ protected DepAtomVisitorTypes::ConstVisitor
+ {
+ private:
+ void _add_raw(const DepAtom * const);
+
+ void _add(DepAtom::ConstPointer a)
+ {
+ _add_raw(a.raw_pointer());
+ }
+
+ void _add_in_role_raw(const DepAtom * const, const std::string & role);
+
+ void _add_in_role(DepAtom::ConstPointer a, const std::string & role)
+ {
+ _add_in_role_raw(a.raw_pointer(), role);
+ }
+
+ protected:
+ ///\name Visit functions
+ ///{
+ void visit(const PlainTextDepAtom * const) PALUDIS_ATTRIBUTE((noreturn));
+ void visit(const PackageDepAtom * const);
+ void visit(const UseDepAtom * const);
+ void visit(const AnyDepAtom * const);
+ void visit(const BlockDepAtom * const);
+ void visit(const AllDepAtom * const);
+ ///}
+
+ public:
+ /**
+ * Iterator for our children.
+ */
+ typedef std::list<DepListEntry>::const_iterator Iterator;
+
+ /**
+ * Constructor.
+ */
+ DepList(const Environment * const);
+
+ /**
+ * Destructor.
+ */
+ virtual ~DepList();
+
+ /**
+ * Add the packages required to resolve an additional dependency
+ * atom.
+ */
+ void add(DepAtom::ConstPointer);
+
+ /**
+ * Start of our dependency list.
+ */
+ Iterator begin() const;
+
+ /**
+ * One past the end of our dependency list.
+ */
+ Iterator end() const;
+
+ /**
+ * Behaviour: determines when RDEPEND entries can be treated as PDEPEND.
+ */
+ void set_rdepend_post(const DepListRdependOption value);
+
+ /**
+ * Behaviour: if set, a package that depends directly upon itself
+ * will be accepted.
+ */
+ void set_drop_self_circular(const bool value);
+
+ /**
+ * Behaviour: if set, any circular dependencies are treated as if
+ * they do not exist.
+ */
+ void set_drop_circular(const bool value);
+
+ /**
+ * Behaviour: if set, any dependencies are treated as if
+ * they do not exist.
+ */
+ void set_drop_all(const bool value);
+
+ /**
+ * Behaviour: ignore installed packages.
+ */
+ void set_ignore_installed(const bool value);
+
+ /**
+ * Behaviour: check nth level dependencies for packages that are
+ * already installed.
+ */
+ void set_recursive_deps(const bool value);
+
+ /**
+ * Behaviour: set the maximum stack depth.
+ */
+ void set_max_stack_depth(const int value);
+
+ /**
+ * Behaviour: set whether we reinstall first level deps.
+ */
+ void set_reinstall(const bool value);
+
+ /**
+ * Behaviour: set whether we upgrade unnecessarily.
+ */
+ void set_no_unnecessary_upgrades(const bool value);
+ };
+}
+
+#endif
diff --git a/0.4.0/paludis/dep_list_TEST.cc b/0.4.0/paludis/dep_list_TEST.cc
new file mode 100644
index 000000000..386973901
--- /dev/null
+++ b/0.4.0/paludis/dep_list_TEST.cc
@@ -0,0 +1,1377 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <deque>
+#include <paludis/paludis.hh>
+#include <string>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace paludis;
+using namespace test;
+
+namespace test_cases
+{
+ /**
+ * Convenience base class used by many of the DepList tests.
+ *
+ * \ingroup Test
+ */
+ class DepListTestCaseBase :
+ public TestCase
+ {
+#ifndef DOXYGEN
+ protected:
+ TestEnvironment env;
+ FakeRepository::Pointer repo;
+ std::deque<std::string> expected;
+ std::string merge_target;
+ bool done_populate;
+#endif
+
+ /**
+ * Constructor.
+ */
+ DepListTestCaseBase(const int i) :
+ TestCase("dep list " + stringify(i)),
+ env(),
+ repo(new FakeRepository(RepositoryName("repo"))),
+ done_populate(false)
+ {
+ env.package_database()->add_repository(repo);
+ }
+
+ /**
+ * Populate our repo member.
+ */
+ virtual void populate_repo() = 0;
+
+ /**
+ * Populate our expected member.
+ */
+ virtual void populate_expected() = 0;
+
+ /**
+ * Check expected is what we got.
+ */
+ virtual void check_lists()
+ {
+ TEST_CHECK(true);
+ DepList d(&env);
+ d.add(PortageDepParser::parse(merge_target));
+ TEST_CHECK(true);
+
+ unsigned n(0);
+ std::deque<std::string>::const_iterator exp(expected.begin());
+ DepList::Iterator got(d.begin());
+ while (true)
+ {
+ TestMessageSuffix s(stringify(n++), true);
+
+ TEST_CHECK((exp == expected.end()) == (got == d.end()));
+ if (got == d.end())
+ break;
+ TEST_CHECK_STRINGIFY_EQUAL(*got, *exp);
+ ++exp;
+ ++got;
+ }
+ }
+
+ public:
+ void run()
+ {
+ if (! done_populate)
+ {
+ populate_repo();
+ populate_expected();
+ done_populate = true;
+ }
+ check_lists();
+ }
+ };
+
+ /**
+ * Convenience sub base class used by the numbered DepList tests.
+ *
+ * \ingroup Test
+ */
+ template <int i_>
+ struct DepListTestCase : DepListTestCaseBase
+ {
+ /**
+ * Constructor.
+ */
+ DepListTestCase() :
+ DepListTestCaseBase(i_)
+ {
+ }
+ };
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase1 : DepListTestCase<1>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_1;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase2 : DepListTestCase<2>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two");
+ repo->add_version("cat", "two", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_2;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase3 : DepListTestCase<3>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two");
+ repo->add_version("cat", "two", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/three");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_3;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase4 : DepListTestCase<4>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two cat/three");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_4;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase5 : DepListTestCase<5>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two cat/three");
+ repo->add_version("cat", "two", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/three");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_5;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase6 : DepListTestCase<6>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two cat/three");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_6;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase7 : DepListTestCase<7>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two cat/three");
+ repo->add_version("cat", "two", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/four");
+ repo->add_version("cat", "three", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/four");
+ repo->add_version("cat", "four", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/four-1:0::repo");
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_7;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase8 : DepListTestCase<8>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two cat/three");
+ repo->add_version("cat", "two", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/four cat/three");
+ repo->add_version("cat", "three", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/four");
+ repo->add_version("cat", "four", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/four-1:0::repo");
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_8;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase9 : DepListTestCase<9>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two cat/three");
+ repo->add_version("cat", "two", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/four");
+ repo->add_version("cat", "three", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/four cat/two");
+ repo->add_version("cat", "four", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/four-1:0::repo");
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_9;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase10 : DepListTestCase<10>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( cat/two cat/three )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_10;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase11 : DepListTestCase<11>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two cat/three");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( cat/two cat/four )");
+ repo->add_version("cat", "four", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_11;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase12 : DepListTestCase<12>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( ( cat/two cat/three ) cat/four )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ repo->add_version("cat", "four", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_12;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase13 : DepListTestCase<13>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two cat/three cat/four");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ repo->add_version("cat", "four", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( ( cat/two cat/three ) cat/five )");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/four-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_13;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase14 : DepListTestCase<14>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( cat/two cat/three )");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_14;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase15 : DepListTestCase<15>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( cat/two cat/three )");
+ repo->add_version("cat", "two", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/four");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_15;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase16 : DepListTestCase<16>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two:slot2");
+ repo->add_version("cat", "two", "1.1")->set<vm_slot>(SlotName("slot1"));
+ repo->add_version("cat", "two", "1.2")->set<vm_slot>(SlotName("slot2"));
+ repo->add_version("cat", "two", "1.3")->set<vm_slot>(SlotName("slot3"));
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/two-1.2:slot2::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_16;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase17 : DepListTestCase<17>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("<cat/two-1.2-r2:slot2");
+ repo->add_version("cat", "two", "1.1")->set<vm_slot>(SlotName("slot1"));
+ repo->add_version("cat", "two", "1.2")->set<vm_slot>(SlotName("slot2"));
+ repo->add_version("cat", "two", "1.2-r1")->set<vm_slot>(SlotName("slot2"));
+ repo->add_version("cat", "two", "1.2-r2")->set<vm_slot>(SlotName("slot2"));
+ repo->add_version("cat", "two", "1.3")->set<vm_slot>(SlotName("slot3"));
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/two-1.2-r1:slot2::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_17;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase18 : DepListTestCase<18>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( )");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_18;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase19 : DepListTestCase<19>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("enabled? ( cat/two )");
+ repo->add_version("cat", "two", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_19;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase20 : DepListTestCase<20>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("!enabled? ( cat/two )");
+ repo->add_version("cat", "two", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_20;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase21 : DepListTestCase<21>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("disabled? ( cat/two )");
+ repo->add_version("cat", "two", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_21;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase22 : DepListTestCase<22>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("!disabled? ( cat/two )");
+ repo->add_version("cat", "two", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_22;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase23 : DepListTestCase<23>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( enabled? ( cat/two ) cat/three )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_23;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase24 : DepListTestCase<24>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( !enabled? ( cat/two ) cat/three )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_24;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase25 : DepListTestCase<25>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( disabled? ( cat/two ) cat/three )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_25;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase26 : DepListTestCase<26>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( !disabled? ( cat/two ) cat/three )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_26;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase27 : DepListTestCase<27>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>(
+ "cat/three || ( enabled? ( cat/two ) cat/three )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_27;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase28 : DepListTestCase<28>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/three || ( !enabled? ( cat/two ) cat/three )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_28;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase29 : DepListTestCase<29>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/three || ( disabled? ( cat/two ) cat/three )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_29;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase30 : DepListTestCase<30>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/three || ( !disabled? ( cat/two ) cat/three )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_30;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase31 : DepListTestCase<31>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/three || ( enabled? ( cat/three ) cat/two )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_31;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase32 : DepListTestCase<32>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/three || ( !enabled? ( cat/three ) cat/two )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_32;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase33 : DepListTestCase<33>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/three || ( disabled? ( cat/three ) cat/two )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_33;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase34 : DepListTestCase<34>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/three || ( !disabled? ( cat/three ) cat/two )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_34;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase35 : DepListTestCase<35>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( enabled1? ( cat/two ) enabled2? ( cat/three ) )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_35;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase36 : DepListTestCase<36>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( !enabled1? ( cat/two ) enabled2? ( cat/three ) )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_36;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase37 : DepListTestCase<37>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( !enabled1? ( cat/two ) !enabled2? ( cat/three ) )");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_37;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase38 : DepListTestCase<38>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("!cat/two");
+ repo->add_version("cat", "two", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target = "cat/one";
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_38;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase39 : DepListTestCase<39>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two !cat/two");
+ repo->add_version("cat", "two", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target="cat/one";
+ }
+
+ void check_lists()
+ {
+ TEST_CHECK(true);
+ DepList d(&env);
+ TEST_CHECK_THROWS(d.add(PortageDepParser::parse(merge_target)), DepListError);
+ TEST_CHECK(d.begin() == d.end());
+ }
+ } test_dep_list_39;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase40 : DepListTestCase<40>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two cat/three");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1")->get<vm_deps>().set<vmd_build_depend_string>("!cat/two");
+ }
+
+ void populate_expected()
+ {
+ merge_target="cat/one";
+ }
+
+ void check_lists()
+ {
+ TEST_CHECK(true);
+ DepList d(&env);
+ TEST_CHECK_THROWS(d.add(PortageDepParser::parse(merge_target)), DepListError);
+ TEST_CHECK(d.begin() == d.end());
+ }
+ } test_dep_list_40;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase41 : DepListTestCase<41>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/three cat/two");
+ repo->add_version("cat", "two", "1");
+ repo->add_version("cat", "three", "1")->get<vm_deps>().set<vmd_build_depend_string>("!cat/two");
+ }
+
+ void populate_expected()
+ {
+ merge_target="cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_41;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase42 : DepListTestCase<42>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( cat/two cat/three )");
+ repo->add_version("cat", "two", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/one");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target="cat/one";
+ expected.push_back("cat/three-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_42;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase43 : DepListTestCase<43>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("|| ( cat/two cat/three )");
+ repo->add_version("cat", "two", "1")->get<vm_deps>().set<vmd_run_depend_string>("cat/one");
+ repo->add_version("cat", "three", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target="cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_43;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase44 : DepListTestCase<44>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("( cat/two cat/two )");
+ repo->add_version("cat", "two", "1");
+ }
+
+ void populate_expected()
+ {
+ merge_target="cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_44;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase45 : DepListTestCase<45>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("( cat/two[enabled] )");
+ repo->add_version("cat", "two", "1")->get_ebuild_interface()->set<evm_iuse>("enabled");
+ }
+
+ void populate_expected()
+ {
+ merge_target="cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_45;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase46 : DepListTestCase<46>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("( cat/two[-disabled] )");
+ repo->add_version("cat", "two", "1")->get_ebuild_interface()->set<evm_iuse>("disabled");
+ }
+
+ void populate_expected()
+ {
+ merge_target="cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_46;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase47 : DepListTestCase<47>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("( cat/two[disabled] )");
+ repo->add_version("cat", "two", "1")->get_ebuild_interface()->set<evm_iuse>("disabled");
+ }
+
+ void populate_expected()
+ {
+ merge_target="cat/one";
+ }
+
+ void check_lists()
+ {
+ TEST_CHECK(true);
+ DepList d(&env);
+ TEST_CHECK_THROWS(d.add(PortageDepParser::parse(merge_target)), DepListError);
+ TEST_CHECK(d.begin() == d.end());
+ }
+ } test_dep_list_47;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase48 : DepListTestCase<48>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("( cat/two[-enabled] )");
+ repo->add_version("cat", "two", "1")->get_ebuild_interface()->set<evm_iuse>("enabled");
+ }
+
+ void populate_expected()
+ {
+ merge_target="cat/one";
+ }
+
+ void check_lists()
+ {
+ TEST_CHECK(true);
+ DepList d(&env);
+ TEST_CHECK_THROWS(d.add(PortageDepParser::parse(merge_target)), DepListError);
+ TEST_CHECK(d.begin() == d.end());
+ }
+ } test_dep_list_48;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase49 : DepListTestCase<49>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("( cat/two cat/two[enabled] )");
+ repo->add_version("cat", "two", "1")->get_ebuild_interface()->set<evm_iuse>("enabled");
+ }
+
+ void populate_expected()
+ {
+ merge_target="cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_49;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase50 : DepListTestCase<50>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("( cat/two cat/two[-disabled] )");
+ repo->add_version("cat", "two", "1")->get_ebuild_interface()->set<evm_iuse>("disabled");
+ }
+
+ void populate_expected()
+ {
+ merge_target="cat/one";
+ expected.push_back("cat/two-1:0::repo");
+ expected.push_back("cat/one-1:0::repo");
+ }
+ } test_dep_list_50;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase51 : DepListTestCase<51>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("( cat/two cat/two[disabled] )");
+ repo->add_version("cat", "two", "1")->get_ebuild_interface()->set<evm_iuse>("disabled");
+ }
+
+ void populate_expected()
+ {
+ merge_target="cat/one";
+ }
+
+ void check_lists()
+ {
+ TEST_CHECK(true);
+ DepList d(&env);
+ TEST_CHECK_THROWS(d.add(PortageDepParser::parse(merge_target)), DepListError);
+ TEST_CHECK(d.begin() == d.end());
+ }
+ } test_dep_list_51;
+
+ /**
+ * \test Test DepList resolution behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCase52 : DepListTestCase<52>
+ {
+ void populate_repo()
+ {
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("( cat/two cat/two[-enabled] )");
+ repo->add_version("cat", "two", "1")->get_ebuild_interface()->set<evm_iuse>("enabled");
+ }
+
+ void populate_expected()
+ {
+ merge_target="cat/one";
+ }
+
+ void check_lists()
+ {
+ TEST_CHECK(true);
+ DepList d(&env);
+ TEST_CHECK_THROWS(d.add(PortageDepParser::parse(merge_target)), DepListError);
+ TEST_CHECK(d.begin() == d.end());
+ }
+ } test_dep_list_52;
+
+ /**
+ * \test Test DepList transactional add behaviour.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCaseTransactionalAdd : TestCase
+ {
+ DepListTestCaseTransactionalAdd() : TestCase("dep list transactional add") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+ env.package_database()->add_repository(repo);
+
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two cat/three");
+ repo->add_version("cat", "two", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/four");
+ repo->add_version("cat", "three", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/four cat/two");
+ repo->add_version("cat", "four", "1");
+ repo->add_version("cat", "five", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/six cat/seven");
+ repo->add_version("cat", "six", "1");
+ repo->add_version("cat", "seven", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/doesnotexist");
+
+ DepList d(&env);
+ d.add(PortageDepParser::parse("cat/one"));
+ TEST_CHECK_EQUAL(join(d.begin(), d.end(), " "),
+ "cat/four-1:0::repo cat/two-1:0::repo cat/three-1:0::repo cat/one-1:0::repo");
+
+ TEST_CHECK_THROWS(d.add(PortageDepParser::parse("cat/five")), DepListError);
+
+ TEST_CHECK_EQUAL(join(d.begin(), d.end(), " "),
+ "cat/four-1:0::repo cat/two-1:0::repo cat/three-1:0::repo cat/one-1:0::repo");
+ }
+ } test_dep_list_transactional_add;
+
+ /**
+ * \test Test DepList transactional add behaviour on PDEPENDs.
+ *
+ * \ingroup Test
+ */
+ struct DepListTestCaseTransactionalAddPost : TestCase
+ {
+ DepListTestCaseTransactionalAddPost() : TestCase("dep list transactional add post") { }
+
+ void run()
+ {
+ TestEnvironment env;
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+ env.package_database()->add_repository(repo);
+
+ repo->add_version("cat", "one", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/two cat/three");
+ repo->add_version("cat", "two", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/four");
+ repo->add_version("cat", "three", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/four cat/two");
+ repo->add_version("cat", "four", "1");
+ repo->add_version("cat", "five", "1")->get<vm_deps>().set<vmd_build_depend_string>("cat/six cat/seven");
+ repo->add_version("cat", "six", "1");
+ repo->add_version("cat", "seven", "1")->get<vm_deps>().set<vmd_post_depend_string>("cat/doesnotexist");
+
+ DepList d(&env);
+ d.add(PortageDepParser::parse("cat/one"));
+ TEST_CHECK_EQUAL(join(d.begin(), d.end(), " "),
+ "cat/four-1:0::repo cat/two-1:0::repo cat/three-1:0::repo cat/one-1:0::repo");
+
+ TEST_CHECK_THROWS(d.add(PortageDepParser::parse("cat/five")), DepListError);
+
+ TEST_CHECK_EQUAL(join(d.begin(), d.end(), " "),
+ "cat/four-1:0::repo cat/two-1:0::repo cat/three-1:0::repo cat/one-1:0::repo");
+ }
+ } test_dep_list_transactional_add_post;
+}
+
diff --git a/0.4.0/paludis/dep_tag.cc b/0.4.0/paludis/dep_tag.cc
new file mode 100644
index 000000000..2c793c33a
--- /dev/null
+++ b/0.4.0/paludis/dep_tag.cc
@@ -0,0 +1,146 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "dep_tag.hh"
+
+/** \file
+ * Implementation for DepTag, DepTagCategory etc.
+ *
+ * \ingroup grpdeptag
+ */
+
+using namespace paludis;
+
+namespace
+{
+ /**
+ * Create the DepTagCategory for GLSAs.
+ *
+ * \see register_glsa_dep_tag
+ *
+ * \ingroup grpdeptag
+ */
+ DepTagCategory::ConstPointer
+ make_glsa_dep_tag()
+ {
+ return DepTagCategory::ConstPointer(new DepTagCategory(
+ "glsa",
+ "Security advisories",
+ "Your system is potentially affected by these security issues:",
+ "Please read the advisories carefully and take appropriate action."));
+ }
+
+ /**
+ * Register the GLSA dep tag category instance.
+ *
+ * \ingroup grpdeptag
+ */
+ static const DepTagCategoryMaker::RegisterMaker register_glsa_dep_tag("glsa",
+ &make_glsa_dep_tag);
+
+ /**
+ * Create the DepTagCategory for seneral sets.
+ *
+ * \see register_general_set_dep_tag
+ *
+ * \ingroup grpdeptag
+ */
+ DepTagCategory::ConstPointer
+ make_general_set_dep_tag()
+ {
+ return DepTagCategory::ConstPointer(new DepTagCategory(
+ "general",
+ "General sets",
+ "",
+ ""));
+ }
+
+ /**
+ * Register the general set dep tag category instance.
+ *
+ * \ingroup grpdeptag
+ */
+ static const DepTagCategoryMaker::RegisterMaker register_general_set_dep_tag("general",
+ &make_general_set_dep_tag);
+}
+
+DepTagCategory::DepTagCategory(const std::string & id,
+ const std::string & t, const std::string & pre,
+ const std::string & post) :
+ _id(id),
+ _title(t),
+ _pre_text(pre),
+ _post_text(post)
+{
+}
+
+NoSuchDepTagCategory::NoSuchDepTagCategory(const std::string & s) throw () :
+ Exception("No such dep tag category '" + s + "'")
+{
+}
+
+DepTag::DepTag()
+{
+}
+
+DepTag::~DepTag()
+{
+}
+
+GLSADepTag::GLSADepTag(const std::string & id, const std::string & glsa_title) :
+ _id(id),
+ _glsa_title(glsa_title)
+{
+}
+
+std::string
+GLSADepTag::short_text() const
+{
+ return "GLSA-" + _id;
+}
+
+std::string
+GLSADepTag::category() const
+{
+ return "glsa";
+}
+
+std::string
+GLSADepTag::glsa_title() const
+{
+ return _glsa_title;
+}
+
+GeneralSetDepTag::GeneralSetDepTag(const std::string & id) :
+ _id(id)
+{
+}
+
+std::string
+GeneralSetDepTag::short_text() const
+{
+ return _id;
+}
+
+std::string
+GeneralSetDepTag::category() const
+{
+ return "general";
+}
+
diff --git a/0.4.0/paludis/dep_tag.hh b/0.4.0/paludis/dep_tag.hh
new file mode 100644
index 000000000..1269c32b3
--- /dev/null
+++ b/0.4.0/paludis/dep_tag.hh
@@ -0,0 +1,245 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_DEP_TAG_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_TAG_HH 1
+
+/** \file
+ * Declarations for the DepTag and DepTagCategory classes.
+ *
+ * \ingroup grpdeptag
+ */
+
+#include <string>
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/util/visitor.hh>
+#include <paludis/util/counted_ptr.hh>
+#include <paludis/util/virtual_constructor.hh>
+#include <paludis/util/exception.hh>
+
+namespace paludis
+{
+ /**
+ * A DepTagCategory is identified by its name and has associated display
+ * information for a DepTag's category.
+ *
+ * It is usually accessed via DepTagCategoryMaker.
+ *
+ * \see DepTagCategoryMaker
+ * \see DepTag
+ *
+ * \ingroup grpdeptag
+ */
+ class DepTagCategory :
+ InstantiationPolicy<DepTagCategory, instantiation_method::NonCopyableTag>,
+ public InternalCounted<DepTagCategory>
+ {
+ private:
+ const std::string _id;
+ const std::string _title;
+ const std::string _pre_text;
+ const std::string _post_text;
+
+ public:
+ /**
+ * Constructor.
+ */
+ DepTagCategory(const std::string & id,
+ const std::string & t,
+ const std::string & pre,
+ const std::string & post);
+
+ /**
+ * Fetch our short ID (for example, 'GLSA').
+ */
+ std::string id() const
+ {
+ return _id;
+ }
+
+ /**
+ * Fetch our title (for example, 'Security advisories'), or an
+ * empty string if we're untitled.
+ */
+ std::string title() const
+ {
+ return _title;
+ }
+
+ /**
+ * Fetch our pre list text, or an empty string.
+ */
+ std::string pre_text() const
+ {
+ return _pre_text;
+ }
+
+ /**
+ * Fetch our post list text, or an empty string.
+ */
+ std::string post_text() const
+ {
+ return _post_text;
+ }
+ };
+
+ /**
+ * Thrown if DepTagCategoryMaker cannot find the named DepTagCategory.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grpdeptag
+ */
+ class NoSuchDepTagCategory :
+ public Exception
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ NoSuchDepTagCategory(const std::string &) throw ();
+ };
+
+ /**
+ * Virtual constructor for accessing DepTagCategory instances.
+ *
+ * \ingroup grpdeptag
+ */
+ typedef VirtualConstructor<std::string, DepTagCategory::ConstPointer (*) (),
+ virtual_constructor_not_found::ThrowException<NoSuchDepTagCategory> > DepTagCategoryMaker;
+
+ class DepTag;
+ class GLSADepTag;
+ class GeneralSetDepTag;
+
+ /**
+ * Visitor class for visiting the different DepTag subclasses.
+ *
+ * \ingroup grpdeptag
+ */
+ typedef VisitorTypes<GLSADepTag *, GeneralSetDepTag *> DepTagVisitorTypes;
+
+ /**
+ * A DepTag can be associated with a PackageDepAtom, and is transferred
+ * onto any associated DepListEntry instances.
+ *
+ * It is used for tagging dep list entries visually, for example to
+ * indicate an associated GLSA.
+ *
+ * \ingroup grpdeptag
+ */
+ class DepTag :
+ InstantiationPolicy<DepTag, instantiation_method::NonCopyableTag>,
+ public InternalCounted<DepTag>,
+ public virtual VisitableInterface<DepTagVisitorTypes>
+ {
+ protected:
+ /**
+ * Constructor.
+ */
+ DepTag();
+
+ public:
+ /**
+ * Destructor.
+ */
+ virtual ~DepTag();
+
+ /**
+ * Fetch our short text (for example, 'GLSA-1234') that is
+ * displayed with the dep list entry.
+ */
+ virtual std::string short_text() const = 0;
+
+ /**
+ * Fetch our DepTagCategory's tag.
+ */
+ virtual std::string category() const = 0;
+
+ /**
+ * Used for comparisons in containers containing pointers to DepTag
+ * instances.
+ *
+ * \ingroup grpdeptag
+ */
+ struct Comparator
+ {
+ /// Perform the comparison.
+ bool operator() (const DepTag::ConstPointer & d1,
+ const DepTag::ConstPointer & d2) const
+ {
+ return d1->short_text() < d2->short_text();
+ }
+ };
+ };
+
+ /**
+ * DepTag subclass for GLSAs.
+ *
+ * \ingroup grpdeptag
+ */
+ class GLSADepTag :
+ public DepTag,
+ public Visitable<GLSADepTag, DepTagVisitorTypes>
+ {
+ private:
+ const std::string _id;
+ const std::string _glsa_title;
+
+ public:
+ /**
+ * Constructor.
+ */
+ GLSADepTag(const std::string & id, const std::string & glsa_title);
+
+ virtual std::string short_text() const;
+
+ virtual std::string category() const;
+
+ /**
+ * Fetch our GLSA title (for example, 'Yet another PHP remote access
+ * hole').
+ */
+ std::string glsa_title() const;
+ };
+
+ /**
+ * DepTag subclass for general sets.
+ *
+ * \ingroup grpdeptag
+ */
+ class GeneralSetDepTag :
+ public DepTag,
+ public Visitable<GeneralSetDepTag, DepTagVisitorTypes>
+ {
+ private:
+ const std::string _id;
+
+ public:
+ /**
+ * Constructor.
+ */
+ GeneralSetDepTag(const std::string & id);
+
+ virtual std::string short_text() const;
+
+ virtual std::string category() const;
+ };
+}
+
+#endif
diff --git a/0.4.0/paludis/digests/Makefile.am b/0.4.0/paludis/digests/Makefile.am
new file mode 100644
index 000000000..7d82bf4b2
--- /dev/null
+++ b/0.4.0/paludis/digests/Makefile.am
@@ -0,0 +1,41 @@
+MAINTAINERCLEANFILES = Makefile.in
+CLEANFILES = *~
+SUBDIRS = .
+
+libexecprogdir = $(libexecdir)/paludis/digests/
+
+paludis_digests_includedir = $(includedir)/paludis/digests/
+
+paludis_digests_include_HEADERS = \
+ sha256.hh \
+ rmd160.hh \
+ md5.hh
+
+libpaludisdigests_a_SOURCES = \
+ $(paludis_digests_include_HEADERS) \
+ sha256.cc \
+ rmd160.cc \
+ md5.cc
+
+lib_LIBRARIES = libpaludisdigests.a
+
+TESTS = sha256_TEST rmd160_TEST md5_TEST
+EXTRA_DIST = sha256_TEST.cc rmd160_TEST.cc md5_TEST.cc
+
+check_PROGRAMS = $(TESTS)
+
+AM_CXXFLAGS = -I$(top_srcdir)
+
+sha256_TEST_SOURCES = sha256_TEST.cc
+sha256_TEST_CXXFLAGS = -I$(top_srcdir)
+sha256_TEST_LDADD = $(top_builddir)/test/libtest.a libpaludisdigests.a
+
+rmd160_TEST_SOURCES = rmd160_TEST.cc
+rmd160_TEST_CXXFLAGS = -I$(top_srcdir)
+rmd160_TEST_LDADD = $(top_builddir)/test/libtest.a libpaludisdigests.a
+
+md5_TEST_SOURCES = md5_TEST.cc
+md5_TEST_CXXFLAGS = -I$(top_srcdir)
+md5_TEST_LDADD = $(top_builddir)/test/libtest.a libpaludisdigests.a
+
+
diff --git a/0.4.0/paludis/digests/md5.cc b/0.4.0/paludis/digests/md5.cc
new file mode 100644
index 000000000..b7a4e4a2b
--- /dev/null
+++ b/0.4.0/paludis/digests/md5.cc
@@ -0,0 +1,239 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/digests/md5.hh>
+#include <sstream>
+#include <istream>
+#include <iomanip>
+
+using namespace paludis;
+
+/*
+ * Implemented based upon the description in RFC1321.
+ */
+
+namespace
+{
+ inline uint32_t _rl(uint32_t x, unsigned int shift) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _rl(uint32_t x, unsigned int shift)
+ {
+ return (x << shift) | (x >> (32 - shift));
+ }
+
+ inline uint32_t _f(uint32_t x, uint32_t y, uint32_t z) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _f(uint32_t x, uint32_t y, uint32_t z)
+ {
+ return (x & y) | (~x & z);
+ }
+
+ inline uint32_t _g(uint32_t x, uint32_t y, uint32_t z) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _g(uint32_t x, uint32_t y, uint32_t z)
+ {
+ return (x & z) | (y & ~z);
+ }
+
+ inline uint32_t _h(uint32_t x, uint32_t y, uint32_t z) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _h(uint32_t x, uint32_t y, uint32_t z)
+ {
+ return x ^ y ^ z;
+ }
+
+ inline uint32_t _i(uint32_t x, uint32_t y, uint32_t z) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _i(uint32_t x, uint32_t y, uint32_t z)
+ {
+ return y ^ (x | ~z);
+ }
+
+ inline uint32_t _x(unsigned i, const uint8_t * const block) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _x(unsigned i, const uint8_t * const block)
+ {
+ return
+ (block[(i << 2) + 3] << 24) |
+ (block[(i << 2) + 2] << 16) |
+ (block[(i << 2) + 1] << 8) |
+ (block[(i << 2) + 0]);
+ }
+
+ inline uint32_t _e(const uint32_t x) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _e(const uint32_t x)
+ {
+ return
+ ((x & 0xff) << 24) |
+ ((x & 0xff00) << 8) |
+ ((x & 0xff0000) >> 8) |
+ ((x & 0xff000000) >> 24);
+ }
+}
+
+void
+MD5::_update(const uint8_t * const block)
+{
+ uint32_t a(_r[0]), b(_r[1]), c(_r[2]), d(_r[3]), f, g, t;
+
+ for (int i(0) ; i < 16 ; ++i)
+ {
+ f = _f(b, c, d);
+ g = i;
+
+ t = d;
+ d = c;
+ c = b;
+ b = _rl(a + f + _t[i] + _x(g, block), _s[i]) + b;
+ a = t;
+ }
+
+ for (int i(16) ; i < 32 ; ++i)
+ {
+ f = _g(b, c, d);
+ g = (5 * i + 1) & 0x0f;
+
+ t = d;
+ d = c;
+ c = b;
+ b = _rl(a + f + _t[i] + _x(g, block), _s[i]) + b;
+ a = t;
+ }
+
+ for (int i(32) ; i < 48 ; ++i)
+ {
+ f = _h(b, c, d);
+ g = (3 * i + 5) & 0x0f;
+
+ t = d;
+ d = c;
+ c = b;
+ b = _rl(a + f + _t[i] + _x(g, block), _s[i]) + b;
+ a = t;
+ }
+
+ for (int i(48) ; i < 64 ; ++i)
+ {
+ f = _i(b, c, d);
+ g = (7 * i) & 0x0f;
+
+ t = d;
+ d = c;
+ c = b;
+ b = _rl(a + f + _t[i] + _x(g, block), _s[i]) + b;
+ a = t;
+ }
+
+ _r[0] += a;
+ _r[1] += b;
+ _r[2] += c;
+ _r[3] += d;
+}
+
+MD5::MD5(std::istream & stream) :
+ _size(0),
+ _done_one_pad(false)
+{
+ _r[0] = 0x67452301;
+ _r[1] = 0xefcdab89;
+ _r[2] = 0x98badcfe;
+ _r[3] = 0x10325476;
+
+ uint8_t buffer[64];
+ int c, s(0);
+ while (-1 != ((c = _get(stream))))
+ {
+ buffer[s++] = c;
+ if (64 == s)
+ {
+ _update(&buffer[0]);
+ s = 0;
+ }
+ }
+ while (56 != s)
+ {
+ buffer[s++] = 0;
+ if (64 == s)
+ {
+ _update(&buffer[0]);
+ s = 0;
+ }
+ }
+
+ buffer[56] = static_cast<uint8_t>(_size >> (0 * 8));
+ buffer[57] = static_cast<uint8_t>(_size >> (1 * 8));
+ buffer[58] = static_cast<uint8_t>(_size >> (2 * 8));
+ buffer[59] = static_cast<uint8_t>(_size >> (3 * 8));
+ buffer[60] = static_cast<uint8_t>(_size >> (4 * 8));
+ buffer[61] = static_cast<uint8_t>(_size >> (5 * 8));
+ buffer[62] = static_cast<uint8_t>(_size >> (6 * 8));
+ buffer[63] = static_cast<uint8_t>(_size >> (7 * 8));
+ _update(&buffer[0]);
+}
+
+std::string
+MD5::hexsum() const
+{
+ std::stringstream result;
+
+ for (int j(0) ; j < 4 ; ++j)
+ result << std::hex << std::right << std::setw(8) << std::setfill('0') <<
+ _e(static_cast<unsigned int>(_r[j])) << std::flush;
+
+ return result.str();
+}
+
+int
+MD5::_get(std::istream & stream)
+{
+ char c;
+ if (stream.get(c))
+ {
+ _size += 8;
+ return static_cast<unsigned char>(c);
+ }
+ else if (! _done_one_pad)
+ {
+ _done_one_pad = true;
+ return 0x80;
+ }
+ else
+ return -1;
+}
+
+const uint8_t MD5::_s[64] = {
+ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
+ 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
+ 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
+ 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
+};
+
+const uint32_t MD5::_t[64] = {
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+};
+
diff --git a/0.4.0/paludis/digests/md5.hh b/0.4.0/paludis/digests/md5.hh
new file mode 100644
index 000000000..cc96cad4f
--- /dev/null
+++ b/0.4.0/paludis/digests/md5.hh
@@ -0,0 +1,50 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_EBUILD_DIGESTS_MD5_HH
+#define PALUDIS_GUARD_EBUILD_DIGESTS_MD5_HH 1
+
+#include <iosfwd>
+#include <string>
+#include <inttypes.h>
+#include <paludis/util/attributes.hh>
+
+namespace paludis
+{
+ class MD5
+ {
+ private:
+ static const uint32_t _t[64];
+ static const uint8_t _s[64];
+ uint32_t _r[4];
+ uint64_t _size;
+ bool _done_one_pad;
+
+ void _update(const uint8_t * const block);
+
+ inline int _get(std::istream & stream);
+
+ public:
+ MD5(std::istream & stream);
+
+ std::string hexsum() const;
+ };
+}
+
+#endif
diff --git a/0.4.0/paludis/digests/md5_TEST.cc b/0.4.0/paludis/digests/md5_TEST.cc
new file mode 100644
index 000000000..2b97a3fae
--- /dev/null
+++ b/0.4.0/paludis/digests/md5_TEST.cc
@@ -0,0 +1,94 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/digests/md5.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace paludis;
+using namespace test;
+
+namespace
+{
+ unsigned char dehex_c(unsigned char c)
+ {
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'a' && c <= 'f')
+ return c + 10 - 'a';
+ else
+ throw "meh!";
+ }
+
+ std::string dehex(const std::string & s)
+ {
+ std::string result;
+ std::string::size_type p(0);
+ while (p < s.length())
+ {
+ unsigned char c;
+ c = (dehex_c(s.at(p)) << 4) + dehex_c(s.at(p + 1));
+ result.append(1, c);
+ p += 2;
+ }
+ return result;
+ }
+}
+
+namespace test_cases
+{
+ struct MD5TestCase : TestCase
+ {
+ std::string data;
+ std::string expected;
+
+ MD5TestCase(const std::string & s, const std::string & d,
+ const std::string & e) :
+ TestCase("md5 " + s),
+ data(d),
+ expected(e)
+ {
+ }
+
+ void run()
+ {
+ std::stringstream ss(data);
+ MD5 s(ss);
+ TEST_CHECK_EQUAL(s.hexsum(), expected);
+ }
+ };
+
+ MD5TestCase t_0("empty", "", "d41d8cd98f00b204e9800998ecf8427e");
+ MD5TestCase t_1("a", "a", "0cc175b9c0f1b6a831c399e269772661");
+ MD5TestCase t_2("abc", "abc", "900150983cd24fb0d6963f7d28e17f72");
+ MD5TestCase t_3("message digest", "message digest", "f96b697d7cb7938d525a2f31aaf161d0");
+ MD5TestCase t_4("a..z", "abcdefghijklmnopqrstuvwxyz",
+ "c3fcd3d76192e4007dfb496cca67e13b");
+ MD5TestCase t_6("A...Za...z0...9",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ "d174ab98d277d9f5a5611c2c9f419d9f");
+ MD5TestCase t_7("8 times 1234567890",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "57edf4a22be3c955ac49da2e2107b67a");
+ MD5TestCase t_8("one million times a",
+ std::string(1000000, 'a'),
+ "7707d6ae4e027c70eea2a935c2296f21");
+}
+
+
diff --git a/0.4.0/paludis/digests/rmd160.cc b/0.4.0/paludis/digests/rmd160.cc
new file mode 100644
index 000000000..d8973ebc9
--- /dev/null
+++ b/0.4.0/paludis/digests/rmd160.cc
@@ -0,0 +1,231 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "rmd160.hh"
+#include <paludis/util/attributes.hh>
+#include <sstream>
+#include <istream>
+#include <iomanip>
+
+using namespace paludis;
+
+/*
+ * Implemented based upon the description at:
+ * http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
+ */
+
+namespace
+{
+ inline uint32_t rl(uint32_t x, unsigned int shift) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t rl(uint32_t x, unsigned int shift)
+ {
+ return (x << shift) | (x >> (32 - shift));
+ }
+
+ inline uint32_t _f(uint32_t j, uint32_t x, uint32_t y, uint32_t z) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _f(uint32_t j, uint32_t x, uint32_t y, uint32_t z)
+ {
+ switch (j / 16)
+ {
+ case 0:
+ return x ^ y ^ z;
+
+ case 1:
+ return (x & y) | (~x & z);
+
+ case 2:
+ return (x | ~y) ^ z;
+
+ case 3:
+ return (x & z) | (y & ~z);
+
+ case 4:
+ return x ^ (y | ~z);
+ }
+
+ throw 0;
+ }
+
+ inline uint32_t _x(unsigned i, const uint8_t * const block) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _x(unsigned i, const uint8_t * const block)
+ {
+ return
+ (block[(i << 2) + 3] << 24) |
+ (block[(i << 2) + 2] << 16) |
+ (block[(i << 2) + 1] << 8) |
+ (block[(i << 2) + 0]);
+ }
+
+ inline uint32_t _e(const uint32_t x) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _e(const uint32_t x)
+ {
+ return
+ ((x & 0xff) << 24) |
+ ((x & 0xff00) << 8) |
+ ((x & 0xff0000) >> 8) |
+ ((x & 0xff000000) >> 24);
+ }
+}
+
+void
+RMD160::_update(const uint8_t * const block)
+{
+ uint32_t a(_h[0]), b(_h[1]), c(_h[2]), d(_h[3]), e(_h[4]);
+ uint32_t ap(_h[0]), bp(_h[1]), cp(_h[2]), dp(_h[3]), ep(_h[4]);
+ uint32_t t;
+
+ for (unsigned j(0) ; j <= 79 ; ++j)
+ {
+ t = a + _f(j, b, c, d) + _x(_r[j], block) + _k[j / 16];
+ t = rl(t, _s[j]) + e;
+ a = e;
+ e = d;
+ d = rl(c, 10);
+ c = b;
+ b = t;
+
+ t = ap + _f(79 - j, bp, cp, dp) + _x(_rp[j], block) + _kp[j / 16];
+ t = rl(t, _sp[j]) + ep;
+ ap = ep;
+ ep = dp;
+ dp = rl(cp, 10);
+ cp = bp;
+ bp = t;
+ }
+
+ t = _h[1] + c + dp;
+ _h[1] = _h[2] + d + ep;
+ _h[2] = _h[3] + e + ap;
+ _h[3] = _h[4] + a + bp;
+ _h[4] = _h[0] + b + cp;
+ _h[0] = t;
+}
+
+RMD160::RMD160(std::istream & stream) :
+ _size(0),
+ _done_one_pad(false)
+{
+ _h[0] = 0x67452301;
+ _h[1] = 0xefcdab89;
+ _h[2] = 0x98badcfe;
+ _h[3] = 0x10325476;
+ _h[4] = 0xc3d2e1f0;
+
+ uint8_t buffer[64];
+ int c, s(0);
+ while (-1 != ((c = _get(stream))))
+ {
+ buffer[s++] = c;
+ if (64 == s)
+ {
+ _update(&buffer[0]);
+ s = 0;
+ }
+ }
+ while (56 != s)
+ {
+ buffer[s++] = 0;
+ if (64 == s)
+ {
+ _update(&buffer[0]);
+ s = 0;
+ }
+ }
+
+ buffer[56] = static_cast<uint8_t>(_size >> (0 * 8));
+ buffer[57] = static_cast<uint8_t>(_size >> (1 * 8));
+ buffer[58] = static_cast<uint8_t>(_size >> (2 * 8));
+ buffer[59] = static_cast<uint8_t>(_size >> (3 * 8));
+ buffer[60] = static_cast<uint8_t>(_size >> (4 * 8));
+ buffer[61] = static_cast<uint8_t>(_size >> (5 * 8));
+ buffer[62] = static_cast<uint8_t>(_size >> (6 * 8));
+ buffer[63] = static_cast<uint8_t>(_size >> (7 * 8));
+ _update(&buffer[0]);
+}
+
+std::string
+RMD160::hexsum() const
+{
+ std::stringstream result;
+
+ for (int j(0) ; j < 5 ; ++j)
+ result << std::hex << std::right << std::setw(8) << std::setfill('0') <<
+ _e(static_cast<unsigned int>(_h[j])) << std::flush;
+
+ return result.str();
+}
+
+int
+RMD160::_get(std::istream & stream)
+{
+ char c;
+ if (stream.get(c))
+ {
+ _size += 8;
+ return static_cast<unsigned char>(c);
+ }
+ else if (! _done_one_pad)
+ {
+ _done_one_pad = true;
+ return 0x80;
+ }
+ else
+ return -1;
+}
+
+const uint8_t RMD160::_r[80] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
+ 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
+ 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
+ 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
+};
+
+const uint8_t RMD160::_rp[80] = {
+ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
+ 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
+ 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
+ 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
+ 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
+};
+
+const uint8_t RMD160::_s[80] = {
+ 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
+ 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
+ 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
+ 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
+ 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
+};
+
+const uint8_t RMD160::_sp[80] = {
+ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
+ 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
+ 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
+ 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
+ 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
+};
+
+const uint32_t RMD160::_k[5] = {
+ 0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e
+};
+
+const uint32_t RMD160::_kp[5] = {
+ 0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x00000000
+};
+
diff --git a/0.4.0/paludis/digests/rmd160.hh b/0.4.0/paludis/digests/rmd160.hh
new file mode 100644
index 000000000..7e074de8c
--- /dev/null
+++ b/0.4.0/paludis/digests/rmd160.hh
@@ -0,0 +1,54 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_EBUILD_DIGESTS_RMD160_HH
+#define PALUDIS_GUARD_EBUILD_DIGESTS_RMD160_HH 1
+
+#include <iosfwd>
+#include <string>
+#include <inttypes.h>
+#include <paludis/util/attributes.hh>
+
+namespace paludis
+{
+ class RMD160
+ {
+ private:
+ static const uint8_t _r[80], _rp[80];
+ static const uint8_t _s[80], _sp[80];
+ static const uint32_t _k[5], _kp[5];
+
+ uint32_t _h[5];
+ uint64_t _size;
+ bool _done_one_pad;
+
+ void _update(const uint8_t * const block);
+
+ inline int _get(std::istream & stream);
+
+ public:
+ RMD160(std::istream & stream);
+
+ std::string hexsum() const;
+ };
+
+}
+
+#endif
+
diff --git a/0.4.0/paludis/digests/rmd160_TEST.cc b/0.4.0/paludis/digests/rmd160_TEST.cc
new file mode 100644
index 000000000..0a1d13b30
--- /dev/null
+++ b/0.4.0/paludis/digests/rmd160_TEST.cc
@@ -0,0 +1,96 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/digests/rmd160.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+using namespace paludis;
+
+namespace
+{
+ unsigned char dehex_c(unsigned char c)
+ {
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'a' && c <= 'f')
+ return c + 10 - 'a';
+ else
+ throw "meh!";
+ }
+
+ std::string dehex(const std::string & s)
+ {
+ std::string result;
+ std::string::size_type p(0);
+ while (p < s.length())
+ {
+ unsigned char c;
+ c = (dehex_c(s.at(p)) << 4) + dehex_c(s.at(p + 1));
+ result.append(1, c);
+ p += 2;
+ }
+ return result;
+ }
+}
+
+namespace test_cases
+{
+ struct RMD160TestCase : TestCase
+ {
+ std::string data;
+ std::string expected;
+
+ RMD160TestCase(const std::string & s, const std::string & d,
+ const std::string & e) :
+ TestCase("rmd160 " + s),
+ data(d),
+ expected(e)
+ {
+ }
+
+ void run()
+ {
+ std::stringstream ss(data);
+ RMD160 s(ss);
+ TEST_CHECK_EQUAL(s.hexsum(), expected);
+ }
+ };
+
+ RMD160TestCase t_0("empty", "", "9c1185a5c5e9fc54612808977ee8f548b2258d31");
+ RMD160TestCase t_1("a", "a", "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe");
+ RMD160TestCase t_2("abc", "abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc");
+ RMD160TestCase t_3("message digest", "message digest", "5d0689ef49d2fae572b881b123a85ffa21595f36");
+ RMD160TestCase t_4("a..z", "abcdefghijklmnopqrstuvwxyz",
+ "f71c27109c692c1b56bbdceb5b9d2865b3708dbc");
+ RMD160TestCase t_5("abcdbcde...nopq",
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ "12a053384a9c0c88e405a06c27dcf49ada62eb2b");
+ RMD160TestCase t_6("A...Za...z0...9",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ "b0e20b6e3116640286ed3a87a5713079b21f5189");
+ RMD160TestCase t_7("8 times 1234567890",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "9b752e45573d4b39f4dbd3323cab82bf63326bfb");
+ RMD160TestCase t_8("one million times a",
+ std::string(1000000, 'a'),
+ "52783243c1697bdbe16d37f97f68f08325dc1528");
+}
+
diff --git a/0.4.0/paludis/digests/sha256.cc b/0.4.0/paludis/digests/sha256.cc
new file mode 100644
index 000000000..d2f1a63d5
--- /dev/null
+++ b/0.4.0/paludis/digests/sha256.cc
@@ -0,0 +1,228 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "sha256.hh"
+#include <paludis/util/attributes.hh>
+#include <istream>
+#include <iomanip>
+#include <sstream>
+
+using namespace paludis;
+
+/*
+ * Implemented based upon the description at:
+ * http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf
+ */
+
+namespace
+{
+ inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z)
+ {
+ return (x & y) ^ (~x & z);
+ }
+
+ inline uint32_t maj(uint32_t x, uint32_t y, uint32_t z) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t maj(uint32_t x, uint32_t y, uint32_t z)
+ {
+ return (x & y) ^ (x & z) ^ (y & z);
+ }
+
+ inline uint32_t rr(uint32_t x, unsigned int shift) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t rr(uint32_t x, unsigned int shift)
+ {
+ return (x >> shift) | (x << (32 - shift));
+ }
+
+ inline uint32_t sigma0(uint32_t x) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t sigma0(uint32_t x)
+ {
+ return rr(x, 2) ^ rr(x, 13) ^ rr(x, 22);
+ }
+
+ inline uint32_t sigma1(uint32_t x) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t sigma1(uint32_t x)
+ {
+ return rr(x, 6) ^ rr(x, 11) ^ rr(x, 25);
+ }
+
+ inline uint32_t lsigma0(uint32_t x) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t lsigma0(uint32_t x)
+ {
+ return rr(x, 7) ^ rr(x, 18) ^ (x >> 3);
+ }
+
+ inline uint32_t lsigma1(uint32_t x) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t lsigma1(uint32_t x)
+ {
+ return rr(x, 17) ^ rr(x, 19) ^ (x >> 10);
+ }
+
+ inline void wload(unsigned j, const uint8_t * const block,
+ uint32_t * const dest) PALUDIS_ATTRIBUTE((always_inline));
+ inline void wload(unsigned j, const uint8_t * const block,
+ uint32_t * const dest)
+ {
+ dest[j] =
+ (block[(j << 2) + 0] << 24) |
+ (block[(j << 2) + 1] << 16) |
+ (block[(j << 2) + 2] << 8) |
+ (block[(j << 2) + 3]);
+ }
+
+ inline void wblend(unsigned j, uint32_t * const dest) PALUDIS_ATTRIBUTE((always_inline));
+ inline void wblend(unsigned j, uint32_t * const dest)
+ {
+ dest[j] = lsigma1(dest[j - 2]) + dest[j - 7] + lsigma0(dest[j - 15]) + dest[j - 16];
+ }
+}
+
+void
+SHA256::_update(const uint8_t * const block)
+{
+ uint32_t a(_h[0]), b(_h[1]), c(_h[2]), d(_h[3]), e(_h[4]), f(_h[5]),
+ g(_h[6]), h(_h[7]);
+
+ uint32_t w[64];
+
+ for (uint32_t j(0) ; j < 16 ; ++j)
+ wload(j, block, &w[0]);
+
+ for (uint32_t j(16) ; j <= 63 ; ++j)
+ wblend(j, &w[0]);
+
+ for (uint32_t j(0) ; j <= 63 ; ++j)
+ {
+ uint32_t t1(h + sigma1(e) + ch(e, f, g) + _k[j] + w[j]);
+ uint32_t t2(sigma0(a) + maj(a, b, c));
+ h = g;
+ g = f;
+ f = e;
+ e = d + t1;
+ d = c;
+ c = b;
+ b = a;
+ a = t1 + t2;
+ }
+
+ _h[0] += a;
+ _h[1] += b;
+ _h[2] += c;
+ _h[3] += d;
+ _h[4] += e;
+ _h[5] += f;
+ _h[6] += g;
+ _h[7] += h;
+}
+
+SHA256::SHA256(std::istream & stream) :
+ _size(0),
+ _done_one_pad(false)
+{
+ _h[0] = 0x6a09e667;
+ _h[1] = 0xbb67ae85;
+ _h[2] = 0x3c6ef372;
+ _h[3] = 0xa54ff53a;
+ _h[4] = 0x510e527f;
+ _h[5] = 0x9b05688c;
+ _h[6] = 0x1f83d9ab;
+ _h[7] = 0x5be0cd19;
+
+ uint8_t buffer[64];
+ int c, s(0);
+ while (-1 != ((c = _get(stream))))
+ {
+ buffer[s++] = c;
+ if (64 == s)
+ {
+ _update(&buffer[0]);
+ s = 0;
+ }
+ }
+ while (56 != s)
+ {
+ buffer[s++] = 0;
+ if (64 == s)
+ {
+ _update(&buffer[0]);
+ s = 0;
+ }
+ }
+
+ buffer[56] = static_cast<uint8_t>(_size >> (7 * 8));
+ buffer[57] = static_cast<uint8_t>(_size >> (6 * 8));
+ buffer[58] = static_cast<uint8_t>(_size >> (5 * 8));
+ buffer[59] = static_cast<uint8_t>(_size >> (4 * 8));
+ buffer[60] = static_cast<uint8_t>(_size >> (3 * 8));
+ buffer[61] = static_cast<uint8_t>(_size >> (2 * 8));
+ buffer[62] = static_cast<uint8_t>(_size >> (1 * 8));
+ buffer[63] = static_cast<uint8_t>(_size >> (0 * 8));
+ _update(&buffer[0]);
+}
+
+std::string
+SHA256::hexsum() const
+{
+ std::stringstream result;
+
+ for (int j(0) ; j < 8 ; ++j)
+ result << std::hex << std::right << std::setw(8) << std::setfill('0') <<
+ static_cast<unsigned int>(_h[j]) << std::flush;
+
+ return result.str();
+}
+
+int
+SHA256::_get(std::istream & stream)
+{
+ char c;
+ if (stream.get(c))
+ {
+ _size += 8;
+ return static_cast<unsigned char>(c);
+ }
+ else if (! _done_one_pad)
+ {
+ _done_one_pad = true;
+ return 0x80;
+ }
+ else
+ return -1;
+}
+
+const uint32_t
+paludis::SHA256::_k[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
diff --git a/0.4.0/paludis/digests/sha256.hh b/0.4.0/paludis/digests/sha256.hh
new file mode 100644
index 000000000..c17514819
--- /dev/null
+++ b/0.4.0/paludis/digests/sha256.hh
@@ -0,0 +1,50 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_EBUILD_DIGESTS_SHA256_HH
+#define PALUDIS_GUARD_EBUILD_DIGESTS_SHA256_HH 1
+
+#include <iosfwd>
+#include <string>
+#include <paludis/util/attributes.hh>
+#include <inttypes.h>
+
+namespace paludis
+{
+ class SHA256
+ {
+ private:
+ static const uint32_t _k[64];
+
+ uint32_t _h[8];
+ uint64_t _size;
+ bool _done_one_pad;
+
+ void _update(const uint8_t * const block);
+
+ inline int _get(std::istream & stream);
+
+ public:
+ SHA256(std::istream & stream);
+
+ std::string hexsum() const;
+ };
+}
+
+#endif
diff --git a/0.4.0/paludis/digests/sha256_TEST.cc b/0.4.0/paludis/digests/sha256_TEST.cc
new file mode 100644
index 000000000..d7f2cab05
--- /dev/null
+++ b/0.4.0/paludis/digests/sha256_TEST.cc
@@ -0,0 +1,420 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/digests/sha256.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+using namespace paludis;
+
+namespace
+{
+ unsigned char dehex_c(unsigned char c)
+ {
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'a' && c <= 'f')
+ return c + 10 - 'a';
+ else
+ throw "meh!";
+ }
+
+ std::string dehex(const std::string & s)
+ {
+ std::string result;
+ std::string::size_type p(0);
+ while (p < s.length())
+ {
+ unsigned char c;
+ c = (dehex_c(s.at(p)) << 4) + dehex_c(s.at(p + 1));
+ result.append(1, c);
+ p += 2;
+ }
+ return result;
+ }
+}
+
+namespace test_cases
+{
+ struct SHA256TestCase : TestCase
+ {
+ std::string data;
+ std::string expected;
+
+ SHA256TestCase(const std::string & s, const std::string & d,
+ const std::string & e) :
+ TestCase("sha256 " + s),
+ data(d),
+ expected(e)
+ {
+ }
+
+ void run()
+ {
+ std::stringstream ss(data);
+ SHA256 s(ss);
+ TEST_CHECK_EQUAL(s.hexsum(), expected);
+ }
+ };
+
+ SHA256TestCase t1("empty", "",
+ "e3b0c442""98fc1c14""9afbf4c8""996fb924"
+ "27ae41e4""649b934c""a495991b""7852b855");
+ SHA256TestCase t2("abc", "abc",
+ "ba7816bf""8f01cfea""414140de""5dae2223"
+ "b00361a3""96177a9c""b410ff61""f20015ad");
+ SHA256TestCase t3("abcd...", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ "248d6a61""d20638b8""e5c02693""0c3e6039"
+ "a33ce459""64ff2167""f6ecedd4""19db06c1");
+
+ /*
+ * the following tests are from:
+ * http://csrc.ncsl.nist.gov/cryptval/
+ */
+
+ SHA256TestCase t_11_SHA256ShortMsg("t 11 SHA256ShortMsg",
+ dehex("bd"), "68325720aabd7c82f30f554b313d0570c95accbb"
+ "7dc4b5aae11204c08ffe732b");
+
+ SHA256TestCase t_14_SHA256ShortMsg("t 14 SHA256ShortMsg",
+ dehex("5fd4"), "7c4fbf484498d21b487b9d61de8914b2eadaf269"
+ "8712936d47c3ada2558f6788");
+
+ SHA256TestCase t_17_SHA256ShortMsg("t 17 SHA256ShortMsg",
+ dehex("b0bd69"), "4096804221093ddccfbf46831490ea63e9e99414"
+ "858f8d75ff7f642c7ca61803");
+
+ SHA256TestCase t_20_SHA256ShortMsg("t 20 SHA256ShortMsg",
+ dehex("c98c8e55"), "7abc22c0ae5af26ce93dbb94433a0e0b2e119d01"
+ "4f8e7f65bd56c61ccccd9504");
+
+ SHA256TestCase t_23_SHA256ShortMsg("t 23 SHA256ShortMsg",
+ dehex("81a723d966"), "7516fb8bb11350df2bf386bc3c33bd0f52cb4c67"
+ "c6e4745e0488e62c2aea2605");
+
+ SHA256TestCase t_26_SHA256ShortMsg("t 26 SHA256ShortMsg",
+ dehex("c97a2db566e5"), "0eb0281b27a4604709b0513b43ad29fdcff9a7a9"
+ "58554abc689d7fe35af703e4");
+
+ SHA256TestCase t_29_SHA256ShortMsg("t 29 SHA256ShortMsg",
+ dehex("f53210aa6ed72e"), "dee684641421d1ba5a65c71f986a117cbb3d619a"
+ "052a0b3409306c629575c00f");
+
+ SHA256TestCase t_32_SHA256ShortMsg("t 32 SHA256ShortMsg",
+ dehex("0df1cd526b5a4edd"), "47f527210d6e8f940b5082fec01b7305908fa2b4"
+ "9ea3ae597c19a3986097153c");
+
+ SHA256TestCase t_35_SHA256ShortMsg("t 35 SHA256ShortMsg",
+ dehex("b80233e2c53ab32cc3"), "c60d239cc6da3ad31f4de0c2d58a73ccf3f9279e"
+ "504fa60ad55a31dcf686f3ca");
+
+ SHA256TestCase t_38_SHA256ShortMsg("t 38 SHA256ShortMsg",
+ dehex("5d54ed5b52d879aeb5dd"), "e0164d90dbfcf173bb88044fac596ccd03b8d247"
+ "c79907aaa5701767fad7b576");
+
+ SHA256TestCase t_41_SHA256ShortMsg("t 41 SHA256ShortMsg",
+ dehex("df866ecb67ab00515f6247"), "dc990ef3109a7bcf626199db9ab7801213ceb0ad"
+ "2ee398963b5061e39c05c7b5");
+
+ SHA256TestCase t_44_SHA256ShortMsg("t 44 SHA256ShortMsg",
+ dehex("0757de9485a2eaea51126077"), "c1c9a4daadcc8678835872c7f1f8824376ac7b41"
+ "2e1fc2285069b41afd51397e");
+
+ SHA256TestCase t_47_SHA256ShortMsg("t 47 SHA256ShortMsg",
+ dehex("7c66f5d443c11cfb39dd0aa715"), "6840619417b4d8ecaa7902f8eaf2e82be2638dec"
+ "97cb7e8fcc377007cc176718");
+
+ SHA256TestCase t_50_SHA256ShortMsg("t 50 SHA256ShortMsg",
+ dehex("329624fed35639fe54957b7d47a9"), "0f5308ff22b828e18bd65afbc427e3c1a6789628"
+ "32519df5f2f803f68f55e10b");
+
+ SHA256TestCase t_53_SHA256ShortMsg("t 53 SHA256ShortMsg",
+ dehex("c34e59652acc043873ecf6a4ab1060"), "0fdf1604ac0d717ec9587b4de5444aaade807589"
+ "d90eb326eaf6acb58a051e79");
+
+ SHA256TestCase t_56_SHA256ShortMsg("t 56 SHA256ShortMsg",
+ dehex("fdf4700984ee11b70af1880d0e0fefd4"), "b01ae16eed3b4a770f127b98469ba26fe3d8e9f5"
+ "9d8a2983214afe6cff0e6b6c");
+
+ SHA256TestCase t_59_SHA256ShortMsg("t 59 SHA256ShortMsg",
+ dehex("ea40aadbefedb0e0d78d067c6cd65c2c87"), "36157bbe61931d58a3a644953eaf131bbc2591c6"
+ "73a1f20353f51ca5054fc1c2");
+
+ SHA256TestCase t_62_SHA256ShortMsg("t 62 SHA256ShortMsg",
+ dehex("6d1092004670efab3af483d265d8e7b3da73"), "67fbf35d360d72b101410794ccf197106c0e784a"
+ "fa9c80206a550b600dbf1f16");
+
+ SHA256TestCase t_65_SHA256ShortMsg("t 65 SHA256ShortMsg",
+ dehex("55a10148ae7b09ac4e71df438135bc70e873eb"), "cbe7965513af46dfd596dc5839cb82a5c6c73280"
+ "34b1dd0042a9f4b71fb14430");
+
+ SHA256TestCase t_68_SHA256ShortMsg("t 68 SHA256ShortMsg",
+ dehex("a03f8fcd777bd933b4b0af8c5ce3d61308565649"), "ddfce4e8c7b38845e2a81b7fc27a06366467a9e1"
+ "11316014013f9701e2413ce0");
+
+ SHA256TestCase t_71_SHA256ShortMsg("t 71 SHA256ShortMsg",
+ dehex("8e5d6cba8d4b206381e33ca7339bec504f3d6119"
+ "ba"), "92f678a3e59d0dd3610eec3222b8c6ebd28eead5"
+ "30723fbd226747534da22b6c");
+
+ SHA256TestCase t_74_SHA256ShortMsg("t 74 SHA256ShortMsg",
+ dehex("96db1b62eed85f2628d0c25da534401fe80d13d0"
+ "9beb"), "725bab4457c789d6a4cc4736b9c2c662cda18407"
+ "150844d74d6aa4efd72dbb05");
+
+ SHA256TestCase t_77_SHA256ShortMsg("t 77 SHA256ShortMsg",
+ dehex("1c482a45dfbcda549729126b533477edfaf7476f"
+ "de498f"), "6523f24f225b996aad1a8b317e6e0f8e97673dcf"
+ "f3fd62a27ff9f3888ea1302d");
+
+ SHA256TestCase t_80_SHA256ShortMsg("t 80 SHA256ShortMsg",
+ dehex("0f677d8e4c6d6a057492670d99adb870adf68a36"
+ "ead37919"), "44acbbc6b48bf37ee088b9c8546fc46e5a5f0d63"
+ "7b5e444f628de186144087fd");
+
+ SHA256TestCase t_83_SHA256ShortMsg("t 83 SHA256ShortMsg",
+ dehex("c09056d597816542bffe4bb33e475dfb2d629301"
+ "6906ddc18c"), "f4baeaef70588a0820d63c2401dd84f98adf7366"
+ "782d196f8698d7dfd3db1c29");
+
+ SHA256TestCase t_86_SHA256ShortMsg("t 86 SHA256ShortMsg",
+ dehex("72f313fdcf52d0749c9937cc2e53f50b44d65a54"
+ "4876bab7d2f8"), "cfa67aa52fd675fca985f69f9ca58af62baead8c"
+ "39723bb6bfbae8a5d4bb9beb");
+
+ SHA256TestCase t_89_SHA256ShortMsg("t 89 SHA256ShortMsg",
+ dehex("09f6fe6cbe6744149f792a4a827e4e8909627abf"
+ "75301bf7bbd7f5"), "657633891dc6274d6aeda78e7313dfb960eac9a2"
+ "4d29293a057b9746a18de4ec");
+
+ SHA256TestCase t_92_SHA256ShortMsg("t 92 SHA256ShortMsg",
+ dehex("9e1cfeb335bc331744247df4bbd56876a7f69298"
+ "aaf6b9e7a8731889"), "930058dd21cb48b2cf90eaca55322ddf48582687"
+ "838a584928440504a2fde578");
+
+ SHA256TestCase t_95_SHA256ShortMsg("t 95 SHA256ShortMsg",
+ dehex("b8913001efb1b7f4bd975e349c5b2cbe66045bf0"
+ "d2fb019b3bc0f059a4"), "a0eb0b7fad1d1b6de4f9096724a621720538a9c3"
+ "f2f6d11134d68cb9ee52fc88");
+
+ SHA256TestCase t_98_SHA256ShortMsg("t 98 SHA256ShortMsg",
+ dehex("8f08537d50928c911a68b071d65b9e8f038264d3"
+ "b62c5f33de18a484cde9"), "10aad5cd4484387373577a881974f1a550782108"
+ "bc88b4e2e8085e9c3e938bbb");
+
+ SHA256TestCase t_101_SHA256ShortMsg("t 101 SHA256ShortMsg",
+ dehex("fd846162c4da936d004ffe0cbe844d940f1c2953"
+ "157cf4765dceba2a6f4c64"), "c13ba769aea0e478816f2f608b5cec3fe14672ea"
+ "033088a8641cfe69b4ff57cb");
+
+ SHA256TestCase t_104_SHA256ShortMsg("t 104 SHA256ShortMsg",
+ dehex("8cf53d90077df9a043bf8d10b470b144784411c9"
+ "3a4d504556834dae3ea4a5bb"), "56059e8cb3c2978b198208bf5ca1e1ea5659b737"
+ "a506324b7cec75b5ebaf057d");
+
+ SHA256TestCase t_107_SHA256ShortMsg("t 107 SHA256ShortMsg",
+ dehex("1bbc2b15253c126e301f9f64b97be4ce13e96337"
+ "687e2e78fbfd4c8daf4a5fa1cd"), "d973b5dcdae4cf2599f4db4068e4aa354f22d890"
+ "1adc463ca3938c465578147b");
+
+ SHA256TestCase t_110_SHA256ShortMsg("t 110 SHA256ShortMsg",
+ dehex("c1bdb3bfc65dfe9a393331266c58d05fb9c8b747"
+ "6bb717dadc29bc43dabd91504fc9"), "57844e1d762e6b7bb86dbfcc5c5a59578d39cc66"
+ "5d1ddbe4de03a61778061af1");
+
+ SHA256TestCase t_113_SHA256ShortMsg("t 113 SHA256ShortMsg",
+ dehex("26eb621a45bd9c9c764ccbb672b99f2a8379c7bb"
+ "f4fb07eec58a8b0ea4747b72196ccf"), "73dc27bd45daccd0f811381230cf7f2a1d3ed120"
+ "2e9a770af733146b1e166315");
+
+ SHA256TestCase t_116_SHA256ShortMsg("t 116 SHA256ShortMsg",
+ dehex("7e3e3986109162e0c56357048bbd86ff49b93644"
+ "b7fb064e7280968650978466f02c9adf"), "682c474799f5103252c3e2efef7f747783e514b5"
+ "4e93b8303b0e07ee4218f78e");
+
+ SHA256TestCase t_119_SHA256ShortMsg("t 119 SHA256ShortMsg",
+ dehex("763c1a9ea50bd72bfc516989ddf3eff2f208f64f"
+ "ccea3cf0ca8dba7f3d10e237c99226510f"), "54d6cb2b09825eab064c8952113b9897a3344737"
+ "cd186a8e6be0a0b258da3e57");
+
+ SHA256TestCase t_122_SHA256ShortMsg("t 122 SHA256ShortMsg",
+ dehex("e1a7ffea8417e7cd49b96e355fd44f3f7a150fab"
+ "6dd8343dfba3b262eaf3a6175a3c4607552b"), "83baa80caade404c446833ecef2e595bba6dce2c"
+ "b7f7422fad2972a9fe327aca");
+
+ SHA256TestCase t_125_SHA256ShortMsg("t 125 SHA256ShortMsg",
+ dehex("692a18effad8317a11a5cddb917f7389e1be6dba"
+ "34572a300e52e056047e758bc363a0be53784c"), "0c0c6a6b27a6d7a7a5130d70db3b8bc1bd8001d1"
+ "03efe72f45b082cadbd03742");
+
+ SHA256TestCase t_128_SHA256ShortMsg("t 128 SHA256ShortMsg",
+ dehex("73fda1e1cb7dc9a9ece858d040d7105cc126eab1"
+ "53fb0bb55703f4317dfff97bd980f4523aee3a09"), "9878f8804e00828b39261843f2b3eda19a7e9b9f"
+ "f4cc2e23f7ea1f62f4491ff2");
+
+ SHA256TestCase t_131_SHA256ShortMsg("t 131 SHA256ShortMsg",
+ dehex("2321d88c19e3e6a8309a09a5428c01991e164468"
+ "23f13b2f0db4ade30e9a7c3521868fb99b440f48"
+ "02"), "f1bd3a8a74c8f0093038499ef63794d86fc6d826"
+ "02a802a435718e61e7b396cc");
+
+ SHA256TestCase t_134_SHA256ShortMsg("t 134 SHA256ShortMsg",
+ dehex("b9eaebda29172b052bcc1e3a9c7f2eced43c084a"
+ "86f89f61e7237425137c167aac29e4cac4071afa"
+ "fd3f"), "ea43ec91285145d8f29915b227a0e35c89f90d96"
+ "8f9a14332dad275cfd52d619");
+
+ SHA256TestCase t_137_SHA256ShortMsg("t 137 SHA256ShortMsg",
+ dehex("332daf07d3a6775b18572549a6e12b8a27d81b7c"
+ "4abcc5bd0b2b9ff936546b0026af131cd3ecd8a1"
+ "0c29ab"), "a573959ba6b1c3bebfd6288c806b72a65650d23b"
+ "d46d123816a2a6a0e47d1e66");
+
+ SHA256TestCase t_140_SHA256ShortMsg("t 140 SHA256ShortMsg",
+ dehex("30ac7eace1f2e41034c25a3d3e2db979c23dfaa7"
+ "a4914b0da147625b3e1f12e9fedc1c41d8ee47dd"
+ "e84fb332"), "c0c3f40d34e711bfadf517b3a78140e379fba5f7"
+ "edf2c1bc3ce82469dae4d2d5");
+
+ SHA256TestCase t_143_SHA256ShortMsg("t 143 SHA256ShortMsg",
+ dehex("02c3964c4ad9c4af97d373099302c2cd770ad06c"
+ "7d8bd11c970161d861e917a854265e223da28031"
+ "ee38041534"), "c13c622bf08a3d3cf1fd6fa5e26e505e551b1643"
+ "bc5a0f59ed29541235218f77");
+
+ SHA256TestCase t_146_SHA256ShortMsg("t 146 SHA256ShortMsg",
+ dehex("b9eed82edcf0c7ba69f6f6ac5722cb61daecaf30"
+ "437511582117ad36ad410ebc6582511ef6e32dce"
+ "5f7a30ab543c"), "6ac64caaeda4763d28a44b363823a6b819285410"
+ "fb4162af6ca657396f6028d0");
+
+ SHA256TestCase t_149_SHA256ShortMsg("t 149 SHA256ShortMsg",
+ dehex("b574865024828bf651df070ac0cec1849aa64709"
+ "01d2e30fa01dcb43862d9827344cf900f46fa9ef"
+ "6d709e5e759f84"), "4c839e8f8f373c25a9a3351257c6152258ff8e6a"
+ "88dad42f30f2bbecab56c20b");
+
+ SHA256TestCase t_152_SHA256ShortMsg("t 152 SHA256ShortMsg",
+ dehex("eebcf5cd6b12c90db64ff71a0e08ccd956e170a5"
+ "0dad769480d6b1fb3eff4934cde90f9e9b930ee6"
+ "37a66285c10f4e8a"), "c117b9dce689c399ec99008788cd5d24d8396fab"
+ "7d96315c4f3fe6d56da63bb3");
+
+ SHA256TestCase t_155_SHA256ShortMsg("t 155 SHA256ShortMsg",
+ dehex("1b7a73770d168da45bf2e512eee45153e02f4dfe"
+ "3b42e50304a3d63d7826f0469562be8fdc6569b0"
+ "56a7dafcd53d1f597c"), "0b42cfc3dd3d3198f06c30e087837ec6a6dd35d0"
+ "8e54e886c682709f8f42457a");
+
+ SHA256TestCase t_158_SHA256ShortMsg("t 158 SHA256ShortMsg",
+ dehex("0072ae2f3bda67736b9c66e2130260b3a4847bc3"
+ "968e037cb6835efcc2014273336725cd5a94f592"
+ "aef20a0a65b459a4415b"), "217cf25b8b343c28336b1c1e9bed29e0c96045bc"
+ "93daf426e490b608b0905c90");
+
+ SHA256TestCase t_161_SHA256ShortMsg("t 161 SHA256ShortMsg",
+ dehex("2ac748680f3bc1bf098c4be38c7194643b0d009e"
+ "51c43630404cdfaf9807aa9b299094916c9466c3"
+ "1fe37fa630c6d3eadc9434"), "3ea59e2e79513679a22e962f22408306f7e8f6e5"
+ "62c2f1f210e279fad8eaacc6");
+
+ SHA256TestCase t_164_SHA256ShortMsg("t 164 SHA256ShortMsg",
+ dehex("893d1a8863d234ee50e5a8c7650a4de047230ad0"
+ "3d268dde8921401ff97b79dfb97cf2426b0f782b"
+ "79c7e75daa2155e1f4098ea7"), "f7808e03e5d5af43c2bffb66e35d1ecbd79f4d8f"
+ "ec44f821f73a235d17c70a89");
+
+ SHA256TestCase t_167_SHA256ShortMsg("t 167 SHA256ShortMsg",
+ dehex("cf673b96eaf241cfa3e262dc6fe65f08bcc2be56"
+ "d8a2c9710eaddae212ded6859f0ff83e5e57d0e8"
+ "0a968b8ed24e74defeb5bbdad6"), "9bdb7cf0492ace4620a47660acd127f951767b07"
+ "38b5504451d6ed56e4fa3cbd");
+
+ SHA256TestCase t_170_SHA256ShortMsg("t 170 SHA256ShortMsg",
+ dehex("0d545be1f47b966214691c21278704e89a17d52d"
+ "d96aeeeacc5325a9a1ddafdecd39407a4dfa72bd"
+ "32856b4c5cc2ba838618830c8399"), "ad53e0db7e63211c8b00947908ce29660c4376e2"
+ "44e19cd30a659af65dc6f1fe");
+
+ SHA256TestCase t_173_SHA256ShortMsg("t 173 SHA256ShortMsg",
+ dehex("9eabfcd3603337df3dcd119d6287a9bc8bb94d65"
+ "0ef29bcf1b32e60d425adc2a35e06577d0c7ce24"
+ "56cf260efee9e8d8aeeddb3d068f37"), "83eeed2dfeb8d2604ab5ec1ac9b5dcab8cc22225"
+ "18468bc5c24c16ce72e70687");
+
+ SHA256TestCase t_176_SHA256ShortMsg("t 176 SHA256ShortMsg",
+ dehex("2fc7b9e8b8dcaac64ecef4c5f91877543ac36ae4"
+ "94d9faf84b1d347b6cf925570db84043d6f500dc"
+ "c153cef81d6f2437d913f3dbffad42d9"), "6ef7e9f12267ebc4901267da147effdcdebcd6ec"
+ "5393c7f62ec4c4f06ca72649");
+
+ SHA256TestCase t_179_SHA256ShortMsg("t 179 SHA256ShortMsg",
+ dehex("cf95929ab732f9ef5e8c3e6b4ed753852ee74e4f"
+ "ddf31b56c29a6ec95d23fcde2209eb7288b787f0"
+ "5d9036735c32ae2f01fc650d9cce4995a5"), "3e5854169da065407fa465a4694f3fcb1d141480"
+ "a8f84c970a0f63364ec8f590");
+
+ SHA256TestCase t_182_SHA256ShortMsg("t 182 SHA256ShortMsg",
+ dehex("826378013988684c40f4d917c7ed8b72aba66fd6"
+ "8f085d0b2eb20948ef3f349dbbc71f8e0ba84501"
+ "4586495a48902ee44505c673d2f76d473950"), "5b506b823ef6658939aca22f52bbe5a4b849c31b"
+ "8fa1d09139352e501137bc04");
+
+ SHA256TestCase t_185_SHA256ShortMsg("t 185 SHA256ShortMsg",
+ dehex("0cab6d38ce9849fcbd589f7235a6d2c2cb933e26"
+ "e1ca6f4e78189104452c280c069b024e16276937"
+ "3f409d5cd0cb8160f0239418325d23ee6ad1bd"), "92943076cda4c46718e55df64d7580e12b8fb2c2"
+ "911e87851246ccf6791fa3e6");
+
+ SHA256TestCase t_188_SHA256ShortMsg("t 188 SHA256ShortMsg",
+ dehex("3fb4a8c5b57c14731179256608614c95c9725dda"
+ "d5fbfa99111d4fa319d3015ad830601556e8e4c6"
+ "d012d7da0e2c4f60f1605f6e4c058ec0f46988a3"), "8e90da3eb146935264576f874fcc5a64b7a90ab6"
+ "c8a36c15d855b0179f52f899");
+
+ SHA256TestCase t_191_SHA256ShortMsg("t 191 SHA256ShortMsg",
+ dehex("9050a6d002c90f6036c592b0f6b866713e7894d2"
+ "9645f4a19e0858b3ebd8078711c26d2601ca104d"
+ "962dc6ce6ae92634ee7f3ca6baf8810e2126097a"
+ "09"), "03c516677735ae83dbe5a7e4c22c1ac1bfedcd46"
+ "e7dd785f8bfe38e148eda632");
+
+ SHA256TestCase t_194_SHA256ShortMsg("t 194 SHA256ShortMsg",
+ dehex("d659ec136bacfa0b5c906aabedc93c01c5f1efa3"
+ "f370a1432ea8778461703f0c67c454da12bac2da"
+ "73b8abb755e5eaf10bddf52f6ca908d61bee80da"
+ "0c64"), "fff2852957a0eeb577e73fd7d827f650261dfb9a"
+ "8a65f52df4bbbc9b2d0ae50e");
+
+ SHA256TestCase t_197_SHA256ShortMsg("t 197 SHA256ShortMsg",
+ dehex("b498555658332b197bc5cb7adc5c1997aabbdcf1"
+ "f7ffcc2b6b82eb0f350019d247f8e399c3559d3b"
+ "b04eb049f28b344c7989c24db83f839b59028dc8"
+ "2fa670"), "bfbbf242f79bff4ae0aafb4ccf69b24fdca4342d"
+ "83db1dfd1822c74a9e218e8d");
+
+ SHA256TestCase t_200_SHA256ShortMsg("t 200 SHA256ShortMsg",
+ dehex("3592ecfd1eac618fd390e7a9c24b656532509367"
+ "c21a0eac1212ac83c0b20cd896eb72b801c4d212"
+ "c5452bbbf09317b50c5c9fb1997553d2bbc29bb4"
+ "2f5748ad"), "105a60865830ac3a371d3843324d4bb5fa8ec0e0"
+ "2ddaa389ad8da4f10215c454");
+}
+
diff --git a/0.4.0/paludis/ebuild.cc b/0.4.0/paludis/ebuild.cc
new file mode 100644
index 000000000..3b83690d7
--- /dev/null
+++ b/0.4.0/paludis/ebuild.cc
@@ -0,0 +1,374 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/ebuild.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/strip.hh>
+#include <paludis/util/pstream.hh>
+#include <paludis/util/log.hh>
+#include <paludis/environment.hh>
+#include <paludis/config_file.hh>
+#include <paludis/portage_dep_parser.hh>
+#include <sys/resource.h>
+#include <sys/time.h>
+
+/** \file
+ * Implementation for ebuild.hh things.
+ *
+ * \ingroup grpebuildinterface
+ */
+
+using namespace paludis;
+
+EbuildCommand::EbuildCommand(const EbuildCommandParams & p) :
+ params(p)
+{
+}
+
+EbuildCommand::~EbuildCommand()
+{
+}
+
+bool
+EbuildCommand::success()
+{
+ return true;
+}
+
+bool
+EbuildCommand::use_sandbox() const
+{
+ return true;
+}
+
+bool
+EbuildCommand::failure()
+{
+ return false;
+}
+
+bool
+EbuildCommand::operator() ()
+{
+ std::string ebuild_cmd(getenv_with_default("PALUDIS_EBUILD_DIR", LIBEXECDIR "/paludis") +
+ "/ebuild.bash '" +
+ stringify(params.get<ecpk_ebuild_dir>()) + "/" +
+ stringify(params.get<ecpk_db_entry>()->get<pde_name>().get<qpn_package>()) + "-" +
+ stringify(params.get<ecpk_db_entry>()->get<pde_version>()) +
+ ".ebuild' " + commands());
+
+ if (use_sandbox())
+ ebuild_cmd = make_sandbox_command(ebuild_cmd);
+
+ MakeEnvCommand cmd(extend_command(make_env_command(ebuild_cmd)
+ ("P", stringify(params.get<ecpk_db_entry>()->get<pde_name>().get<qpn_package>()) + "-" +
+ stringify(params.get<ecpk_db_entry>()->get<pde_version>().remove_revision()))
+ ("PV", stringify(params.get<ecpk_db_entry>()->get<pde_version>().remove_revision()))
+ ("PR", stringify(params.get<ecpk_db_entry>()->get<pde_version>().revision_only()))
+ ("PN", stringify(params.get<ecpk_db_entry>()->get<pde_name>().get<qpn_package>()))
+ ("PVR", stringify(params.get<ecpk_db_entry>()->get<pde_version>()))
+ ("PF", stringify(params.get<ecpk_db_entry>()->get<pde_name>().get<qpn_package>()) + "-" +
+ stringify(params.get<ecpk_db_entry>()->get<pde_version>()))
+ ("CATEGORY", stringify(params.get<ecpk_db_entry>()->get<pde_name>().get<qpn_category>()))
+ ("REPOSITORY", stringify(params.get<ecpk_db_entry>()->get<pde_repository>()))
+ ("FILESDIR", stringify(params.get<ecpk_files_dir>()))
+ ("ECLASSDIR", stringify(*params.get<ecpk_eclassdirs>()->begin()))
+ ("ECLASSDIRS", join(params.get<ecpk_eclassdirs>()->begin(),
+ params.get<ecpk_eclassdirs>()->end(), " "))
+ ("PORTDIR", stringify(params.get<ecpk_portdir>()))
+ ("DISTDIR", stringify(params.get<ecpk_distdir>()))
+ ("PALUDIS_TMPDIR", stringify(params.get<ecpk_buildroot>()))
+ ("PALUDIS_CONFIG_DIR", SYSCONFDIR "/paludis/")
+ ("PALUDIS_BASHRC_FILES", params.get<ecpk_environment>()->bashrc_files())
+ ("PALUDIS_HOOK_DIRS", params.get<ecpk_environment>()->hook_dirs())
+ ("PALUDIS_COMMAND", params.get<ecpk_environment>()->paludis_command())
+ ("KV", kernel_version())
+ ("PALUDIS_EBUILD_LOG_LEVEL", Log::get_instance()->log_level_string())
+ ("PALUDIS_EBUILD_DIR", getenv_with_default("PALUDIS_EBUILD_DIR", LIBEXECDIR "/paludis"))));
+
+ if (do_run_command(add_portage_vars(cmd)))
+ return success();
+ else
+ return failure();
+}
+
+MakeEnvCommand
+EbuildCommand::add_portage_vars(const MakeEnvCommand & cmd) const
+{
+ return cmd
+ ("PORTAGE_ACTUAL_DISTDIR", stringify(params.get<ecpk_distdir>()))
+ ("PORTAGE_BASHRC", "/dev/null")
+ ("PORTAGE_BUILDDIR", stringify(params.get<ecpk_buildroot>()) + "/" +
+ stringify(params.get<ecpk_db_entry>()->get<pde_name>().get<qpn_category>()) + "/" +
+ stringify(params.get<ecpk_db_entry>()->get<pde_name>().get<qpn_package>()) + "-" +
+ stringify(params.get<ecpk_db_entry>()->get<pde_version>()))
+ ("PORTAGE_CALLER", params.get<ecpk_environment>()->paludis_command())
+ ("PORTAGE_GID", "0")
+ ("PORTAGE_INST_GID", "0")
+ ("PORTAGE_INST_UID", "0")
+ ("PORTAGE_MASTER_PID", stringify(::getpid()))
+ ("PORTAGE_NICENCESS", stringify(::getpriority(PRIO_PROCESS, 0)))
+ ("PORTAGE_TMPDIR", stringify(params.get<ecpk_buildroot>()))
+ ("PORTAGE_TMPFS", "/dev/shm")
+ ("PORTAGE_WORKDIR_MODE", "0700");
+}
+
+bool
+EbuildCommand::do_run_command(const std::string & cmd)
+{
+ return 0 == run_command(cmd);
+}
+
+EbuildMetadataCommand::EbuildMetadataCommand(const EbuildCommandParams & p) :
+ EbuildCommand(p),
+ _metadata(0)
+{
+}
+
+std::string
+EbuildMetadataCommand::commands() const
+{
+ return "metadata";
+}
+
+bool
+EbuildMetadataCommand::failure()
+{
+ return EbuildCommand::failure();
+}
+
+MakeEnvCommand
+EbuildMetadataCommand::extend_command(const MakeEnvCommand & cmd)
+{
+ return cmd;
+}
+
+bool
+EbuildMetadataCommand::do_run_command(const std::string & cmd)
+{
+ PStream prog(cmd);
+ KeyValueConfigFile f(&prog);
+ _metadata.assign(new VersionMetadata::Ebuild(PortageDepParser::parse_depend));
+
+ bool ok(false);
+ try
+ {
+ _metadata->get<vm_deps>().set<vmd_build_depend_string>(f.get("DEPEND"));
+ _metadata->get<vm_deps>().set<vmd_run_depend_string>(f.get("RDEPEND"));
+ _metadata->set<vm_slot>(SlotName(f.get("SLOT")));
+ _metadata->get_ebuild_interface()->set<evm_src_uri>(f.get("SRC_URI"));
+ _metadata->get_ebuild_interface()->set<evm_restrict>(f.get("RESTRICT"));
+ _metadata->set<vm_homepage>(f.get("HOMEPAGE"));
+ _metadata->set<vm_license>(f.get("LICENSE"));
+ _metadata->set<vm_description>(f.get("DESCRIPTION"));
+ _metadata->get_ebuild_interface()->set<evm_keywords>(f.get("KEYWORDS"));
+ _metadata->get_ebuild_interface()->set<evm_inherited>(f.get("INHERITED"));
+ _metadata->get_ebuild_interface()->set<evm_iuse>(f.get("IUSE"));
+ _metadata->get<vm_deps>().set<vmd_post_depend_string>(f.get("PDEPEND"));
+ _metadata->get_ebuild_interface()->set<evm_provide>(f.get("PROVIDE"));
+ _metadata->set<vm_eapi>(f.get("EAPI"));
+ _metadata->get_ebuild_interface()->set<evm_virtual>("");
+
+ if (0 == prog.exit_status())
+ ok = true;
+ }
+ catch (const NameError &)
+ {
+ }
+
+ if (ok)
+ return true;
+ else
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Could not generate cache for '"
+ + stringify(*params.get<ecpk_db_entry>()) + "'");
+ _metadata->set<vm_eapi>("UNKNOWN");
+
+ return false;
+ }
+}
+
+EbuildVariableCommand::EbuildVariableCommand(const EbuildCommandParams & p,
+ const std::string & var) :
+ EbuildCommand(p),
+ _var(var)
+{
+}
+
+std::string
+EbuildVariableCommand::commands() const
+{
+ return "variable";
+}
+
+bool
+EbuildVariableCommand::failure()
+{
+ return EbuildCommand::failure();
+}
+
+MakeEnvCommand
+EbuildVariableCommand::extend_command(const MakeEnvCommand & cmd)
+{
+ return cmd("PALUDIS_VARIABLE", _var);
+}
+
+bool
+EbuildVariableCommand::do_run_command(const std::string & cmd)
+{
+ PStream prog(cmd);
+ _result = strip_trailing_string(
+ std::string((std::istreambuf_iterator<char>(prog)),
+ std::istreambuf_iterator<char>()), "\n");
+
+ return (0 == prog.exit_status());
+}
+
+std::string
+EbuildFetchCommand::commands() const
+{
+ if (fetch_params.get<ecfpk_no_fetch>())
+ return "nofetch";
+ else
+ return "fetch";
+}
+
+bool
+EbuildFetchCommand::failure()
+{
+ throw PackageFetchActionError("Fetch failed for '" + stringify(
+ *params.get<ecpk_db_entry>()) + "'");
+}
+
+MakeEnvCommand
+EbuildFetchCommand::extend_command(const MakeEnvCommand & cmd)
+{
+ MakeEnvCommand result(cmd
+ ("A", fetch_params.get<ecfpk_a>())
+ ("AA", fetch_params.get<ecfpk_aa>())
+ ("USE", fetch_params.get<ecfpk_use>())
+ ("USE_EXPAND", fetch_params.get<ecfpk_use_expand>())
+ ("FLAT_SRC_URI", fetch_params.get<ecfpk_flat_src_uri>())
+ ("ROOT", fetch_params.get<ecfpk_root>())
+ ("PALUDIS_PROFILE_DIR", stringify(*fetch_params.get<ecfpk_profiles>()->begin()))
+ ("PALUDIS_PROFILE_DIRS", join(fetch_params.get<ecfpk_profiles>()->begin(),
+ fetch_params.get<ecfpk_profiles>()->end(), " ")));
+
+ for (std::map<std::string, std::string>::const_iterator
+ i(fetch_params.get<ecfpk_expand_vars>().begin()),
+ j(fetch_params.get<ecfpk_expand_vars>().end()) ; i != j ; ++i)
+ result = result(i->first, i->second);
+
+ return result;
+}
+
+EbuildFetchCommand::EbuildFetchCommand(const EbuildCommandParams & p,
+ const EbuildFetchCommandParams & f) :
+ EbuildCommand(p),
+ fetch_params(f)
+{
+}
+
+std::string
+EbuildInstallCommand::commands() const
+{
+ if (install_params.get<ecipk_merge_only>())
+ return "merge";
+ else
+ return "init setup unpack compile test install strip preinst "
+ "merge postinst tidyup";
+}
+
+bool
+EbuildInstallCommand::failure()
+{
+ throw PackageInstallActionError("Install failed for '" + stringify(
+ *params.get<ecpk_db_entry>()) + "'");
+}
+
+MakeEnvCommand
+EbuildInstallCommand::extend_command(const MakeEnvCommand & cmd)
+{
+ MakeEnvCommand result(cmd
+ ("A", install_params.get<ecipk_a>())
+ ("AA", install_params.get<ecipk_aa>())
+ ("USE", install_params.get<ecipk_use>())
+ ("USE_EXPAND", install_params.get<ecipk_use_expand>())
+ ("ROOT", install_params.get<ecipk_root>())
+ ("PALUDIS_EBUILD_OVERRIDE_CONFIG_PROTECT_MASK",
+ install_params.get<ecipk_disable_cfgpro>() ? "/" : "")
+ ("PALUDIS_PROFILE_DIR", stringify(*install_params.get<ecipk_profiles>()->begin()))
+ ("PALUDIS_PROFILE_DIRS", join(install_params.get<ecipk_profiles>()->begin(),
+ install_params.get<ecipk_profiles>()->end(), " "))
+ ("SLOT", stringify(install_params.get<ecipk_slot>())));
+
+ for (std::map<std::string, std::string>::const_iterator
+ i(install_params.get<ecipk_expand_vars>().begin()),
+ j(install_params.get<ecipk_expand_vars>().end()) ; i != j ; ++i)
+ result = result(i->first, i->second);
+
+ return result;
+}
+
+EbuildInstallCommand::EbuildInstallCommand(const EbuildCommandParams & p,
+ const EbuildInstallCommandParams & f) :
+ EbuildCommand(p),
+ install_params(f)
+{
+}
+
+std::string
+EbuildUninstallCommand::commands() const
+{
+ if (uninstall_params.get<ecupk_unmerge_only>())
+ return "unmerge";
+ else
+ return "prerm unmerge postrm";
+}
+
+bool
+EbuildUninstallCommand::failure()
+{
+ throw PackageUninstallActionError("Uninstall failed for '" + stringify(
+ *params.get<ecpk_db_entry>()) + "'");
+}
+
+MakeEnvCommand
+EbuildUninstallCommand::extend_command(const MakeEnvCommand & cmd)
+{
+ MakeEnvCommand result(cmd
+ ("ROOT", uninstall_params.get<ecupk_root>())
+ ("PALUDIS_EBUILD_OVERRIDE_CONFIG_PROTECT_MASK",
+ uninstall_params.get<ecupk_disable_cfgpro>() ? "/" : ""));
+
+ if (uninstall_params.get<ecupk_load_environment>())
+ result = result
+ ("PALUDIS_LOAD_ENVIRONMENT", stringify(*uninstall_params.get<ecupk_load_environment>()))
+ ("PALUDIS_SKIP_INHERIT", "yes");
+
+ return result;
+}
+
+EbuildUninstallCommand::EbuildUninstallCommand(const EbuildCommandParams & p,
+ const EbuildUninstallCommandParams & f) :
+ EbuildCommand(p),
+ uninstall_params(f)
+{
+}
+
diff --git a/0.4.0/paludis/ebuild.hh b/0.4.0/paludis/ebuild.hh
new file mode 100644
index 000000000..6ca83e95b
--- /dev/null
+++ b/0.4.0/paludis/ebuild.hh
@@ -0,0 +1,462 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_EBUILD_HH
+#define PALUDIS_GUARD_PALUDIS_EBUILD_HH 1
+
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/util/smart_record.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/attributes.hh>
+#include <paludis/package_database.hh>
+#include <string>
+#include <map>
+
+/** \file
+ * Declarations for the EbuildCommand classes.
+ *
+ * \ingroup grpebuildinterface
+ */
+
+namespace paludis
+{
+ /**
+ * Keys for EbuildCommandParams.
+ *
+ * \see EbuildCommandParams
+ *
+ * \ingroup grpebuildinterface
+ */
+ enum EbuildCommandParamsKeys
+ {
+ ecpk_environment,
+ ecpk_db_entry,
+ ecpk_ebuild_dir,
+ ecpk_files_dir,
+ ecpk_eclassdirs,
+ ecpk_portdir,
+ ecpk_distdir,
+ ecpk_buildroot,
+ last_ecpk
+ };
+
+ class Environment;
+ class MakeEnvCommand;
+
+ /**
+ * Tag for EbuildCommandParams.
+ *
+ * \see EbuildCommandParams.
+ *
+ * \ingroup grpebuildinterface
+ */
+ struct EbuildCommandParamsTag :
+ SmartRecordTag<comparison_mode::NoComparisonTag, void>,
+ SmartRecordKeys<EbuildCommandParamsKeys, last_ecpk>,
+ SmartRecordKey<ecpk_environment, const Environment *>,
+ SmartRecordKey<ecpk_db_entry, const PackageDatabaseEntry *>,
+ SmartRecordKey<ecpk_ebuild_dir, const FSEntry>,
+ SmartRecordKey<ecpk_files_dir, const FSEntry>,
+ SmartRecordKey<ecpk_eclassdirs, FSEntryCollection::ConstPointer>,
+ SmartRecordKey<ecpk_portdir, const FSEntry>,
+ SmartRecordKey<ecpk_distdir, const FSEntry>,
+ SmartRecordKey<ecpk_buildroot, const FSEntry>
+ {
+ };
+
+ /**
+ * Parameters for EbuildCommand's constructor.
+ *
+ * \ingroup grpebuildinterface
+ */
+ typedef MakeSmartRecord<EbuildCommandParamsTag>::Type EbuildCommandParams;
+
+ /**
+ * An EbuildCommand is the base class from which specific ebuild
+ * command interfaces are descended.
+ *
+ * \ingroup grpebuildinterface
+ */
+ class EbuildCommand :
+ private InstantiationPolicy<EbuildCommand, instantiation_method::NonCopyableTag>
+ {
+ protected:
+ /**
+ * Our parameters.
+ */
+ const EbuildCommandParams params;
+
+ /**
+ * Constructor.
+ */
+ EbuildCommand(const EbuildCommandParams &);
+
+ /**
+ * Override in descendents: which commands (for example, 'prerm
+ * unmerge postrm') do we give to ebuild.bash?
+ */
+ virtual std::string commands() const = 0;
+
+ /**
+ * Actions to be taken after a successful command.
+ *
+ * The return value of this function is used for the return value
+ * of operator().
+ */
+ virtual bool success();
+
+ /**
+ * Should the sandbox, if available, be used?
+ */
+ virtual bool use_sandbox() const;
+
+ /**
+ * Actions to be taken after a failed command.
+ *
+ * The return value of this function is used for the return value
+ * of operator(). In some descendents, this function throws and
+ * does not return.
+ */
+ virtual bool failure() = 0;
+
+ /**
+ * Run the specified command. Can be overridden if, for example,
+ * the command output needs to be captured.
+ *
+ * \return Whether the command succeeded.
+ */
+ virtual bool do_run_command(const std::string &);
+
+ /**
+ * Add Portage emulation vars.
+ */
+ virtual MakeEnvCommand add_portage_vars(const MakeEnvCommand &) const;
+
+ /**
+ * Extend the command to be run.
+ */
+ virtual MakeEnvCommand extend_command(const MakeEnvCommand &) = 0;
+
+ public:
+ /**
+ * Destructor.
+ */
+ virtual ~EbuildCommand();
+
+ /**
+ * Run the command.
+ */
+ virtual bool operator() ();
+ };
+
+ /**
+ * An EbuildMetadataCommand is used to generate metadata for a particular
+ * ebuild in a PortageRepository.
+ *
+ * \ingroup grpebuildinterface
+ */
+ class EbuildMetadataCommand :
+ public EbuildCommand
+ {
+ private:
+ VersionMetadata::Ebuild::Pointer _metadata;
+
+ protected:
+ virtual std::string commands() const;
+
+ virtual bool failure();
+
+ virtual MakeEnvCommand extend_command(const MakeEnvCommand &);
+
+ virtual bool do_run_command(const std::string &);
+
+ public:
+ /**
+ * Constructor.
+ */
+ EbuildMetadataCommand(const EbuildCommandParams &);
+
+ /**
+ * Return a pointer to our generated metadata. If operator() has not
+ * yet been called, will be a zero pointer.
+ */
+ VersionMetadata::Pointer metadata() const
+ {
+ return _metadata;
+ }
+ };
+
+ /**
+ * An EbuildVariableCommand is used to fetch the value of an environment
+ * variable for a particular ebuild in a PortageRepository.
+ *
+ * \ingroup grpebuildinterface
+ */
+ class EbuildVariableCommand :
+ public EbuildCommand
+ {
+ private:
+ std::string _result;
+ const std::string _var;
+
+ protected:
+ virtual std::string commands() const;
+
+ virtual MakeEnvCommand extend_command(const MakeEnvCommand &);
+
+ virtual bool do_run_command(const std::string &);
+
+ virtual bool failure();
+
+ public:
+ /**
+ * Constructor.
+ */
+ EbuildVariableCommand(const EbuildCommandParams &, const std::string &);
+
+ /**
+ * Fetch our result.
+ */
+ std::string result() const
+ {
+ return _result;
+ }
+ };
+
+ /**
+ * Keys for EbuildFetchCommandParams.
+ *
+ * \see EbuildFetchCommandParams
+ *
+ * \ingroup grpebuildinterface
+ */
+ enum EbuildFetchCommandParamsKeys
+ {
+ ecfpk_a,
+ ecfpk_aa,
+ ecfpk_use,
+ ecfpk_use_expand,
+ ecfpk_flat_src_uri,
+ ecfpk_root,
+ ecfpk_profiles,
+ ecfpk_expand_vars,
+ ecfpk_no_fetch,
+ last_ecfpk
+ };
+
+ /**
+ * Tag for EbuildFetchCommandParams.
+ *
+ * \see EbuildFetchCommandParams
+ *
+ * \ingroup grpebuildinterface
+ */
+ struct EbuildFetchCommandParamsTag :
+ SmartRecordTag<comparison_mode::NoComparisonTag, void>,
+ SmartRecordKeys<EbuildFetchCommandParamsKeys, last_ecfpk>,
+ SmartRecordKey<ecfpk_a, std::string>,
+ SmartRecordKey<ecfpk_aa, std::string>,
+ SmartRecordKey<ecfpk_use, std::string>,
+ SmartRecordKey<ecfpk_use_expand, std::string>,
+ SmartRecordKey<ecfpk_flat_src_uri, std::string>,
+ SmartRecordKey<ecfpk_root, std::string>,
+ SmartRecordKey<ecfpk_profiles, FSEntryCollection::ConstPointer>,
+ SmartRecordKey<ecfpk_expand_vars, std::map<std::string, std::string> >,
+ SmartRecordKey<ecfpk_no_fetch, bool>
+ {
+ };
+
+ /**
+ * Parameters for EbuildFetchCommand's constructor.
+ *
+ * \ingroup grpebuildinterface
+ */
+ typedef MakeSmartRecord<EbuildFetchCommandParamsTag>::Type EbuildFetchCommandParams;
+
+ /**
+ * An EbuildFetchCommand is used to download and verify the digests for a
+ * particular ebuild in a PortageRepository. On failure it throws.
+ *
+ * \ingroup grpebuildinterface
+ */
+ class EbuildFetchCommand :
+ public EbuildCommand
+ {
+ protected:
+ /// Parameters for fetch.
+ const EbuildFetchCommandParams fetch_params;
+
+ virtual std::string commands() const;
+
+ virtual bool failure() PALUDIS_ATTRIBUTE((noreturn));
+
+ virtual MakeEnvCommand extend_command(const MakeEnvCommand &);
+
+ public:
+ /**
+ * Constructor.
+ */
+ EbuildFetchCommand(const EbuildCommandParams &, const EbuildFetchCommandParams &);
+ };
+
+ /**
+ * Keys for EbuildInstallCommandParams.
+ *
+ * \see EbuildInstallCommandParams
+ *
+ * \ingroup grpebuildinterface
+ */
+ enum EbuildInstallCommandParamsKeys
+ {
+ ecipk_a,
+ ecipk_aa,
+ ecipk_use,
+ ecipk_use_expand,
+ ecipk_root,
+ ecipk_profiles,
+ ecipk_expand_vars,
+ ecipk_disable_cfgpro,
+ ecipk_merge_only,
+ ecipk_slot,
+ last_ecipk
+ };
+
+ /**
+ * Tag for EbuildInstallCommandParams.
+ *
+ * \see EbuildInstallCommandParams
+ *
+ * \ingroup grpebuildinterface
+ */
+ struct EbuildInstallCommandParamsTag :
+ SmartRecordTag<comparison_mode::NoComparisonTag, void>,
+ SmartRecordKeys<EbuildInstallCommandParamsKeys, last_ecipk>,
+ SmartRecordKey<ecipk_a, std::string>,
+ SmartRecordKey<ecipk_aa, std::string>,
+ SmartRecordKey<ecipk_use, std::string>,
+ SmartRecordKey<ecipk_use_expand, std::string>,
+ SmartRecordKey<ecipk_root, std::string>,
+ SmartRecordKey<ecipk_profiles, FSEntryCollection::ConstPointer>,
+ SmartRecordKey<ecipk_expand_vars, std::map<std::string, std::string> >,
+ SmartRecordKey<ecipk_disable_cfgpro, bool>,
+ SmartRecordKey<ecipk_merge_only, bool>,
+ SmartRecordKey<ecipk_slot, SlotName>
+ {
+ };
+
+ /**
+ * Parameters for EbuildInstallCommand's constructor.
+ *
+ * \ingroup grpebuildinterface
+ */
+ typedef MakeSmartRecord<EbuildInstallCommandParamsTag>::Type EbuildInstallCommandParams;
+
+ /**
+ * An EbuildInstallCommand is used to install an ebuild from a
+ * PortageRepository. On failure it throws.
+ *
+ * \ingroup grpebuildinterface
+ */
+ class EbuildInstallCommand :
+ public EbuildCommand
+ {
+ protected:
+ /// Parameters for install.
+ const EbuildInstallCommandParams install_params;
+
+ virtual std::string commands() const;
+
+ virtual bool failure() PALUDIS_ATTRIBUTE((noreturn));
+
+ virtual MakeEnvCommand extend_command(const MakeEnvCommand &);
+
+ public:
+ /**
+ * Constructor.
+ */
+ EbuildInstallCommand(const EbuildCommandParams &, const EbuildInstallCommandParams &);
+ };
+
+ /**
+ * Keys for EbuildUninstallCommandParams.
+ *
+ * \see EbuildUninstallCommandParams
+ *
+ * \ingroup grpebuildinterface
+ */
+ enum EbuildUninstallCommandParamsKeys
+ {
+ ecupk_root,
+ ecupk_disable_cfgpro,
+ ecupk_unmerge_only,
+ ecupk_load_environment,
+ last_ecupk
+ };
+
+ /**
+ * Tags for EbuildUninstallCommandParams.
+ *
+ * \see EbuildUninstallCommandParams
+ *
+ * \ingroup grpebuildinterface
+ */
+ struct EbuildUninstallCommandParamsTag :
+ SmartRecordTag<comparison_mode::NoComparisonTag, void>,
+ SmartRecordKeys<EbuildUninstallCommandParamsKeys, last_ecupk>,
+ SmartRecordKey<ecupk_root, std::string>,
+ SmartRecordKey<ecupk_disable_cfgpro, bool>,
+ SmartRecordKey<ecupk_unmerge_only, bool>,
+ SmartRecordKey<ecupk_load_environment, const FSEntry * const>
+ {
+ };
+
+ /**
+ * Parameters for EbuildUninstallCommand's constructor.
+ *
+ * \ingroup grpebuildinterface
+ */
+ typedef MakeSmartRecord<EbuildUninstallCommandParamsTag>::Type EbuildUninstallCommandParams;
+
+ /**
+ * An EbuildUninstallCommand is used to uninstall a package in a VDBRepository.
+ *
+ * \ingroup grpebuildinterface
+ */
+ class EbuildUninstallCommand :
+ public EbuildCommand
+ {
+ protected:
+ /// Parameters for uninstall.
+ const EbuildUninstallCommandParams uninstall_params;
+
+ virtual std::string commands() const;
+
+ virtual bool failure() PALUDIS_ATTRIBUTE((noreturn));
+
+ virtual MakeEnvCommand extend_command(const MakeEnvCommand &);
+
+ public:
+ /**
+ * Constructor.
+ */
+ EbuildUninstallCommand(const EbuildCommandParams &, const EbuildUninstallCommandParams &);
+ };
+}
+
+#endif
diff --git a/0.4.0/paludis/environment.cc b/0.4.0/paludis/environment.cc
new file mode 100644
index 000000000..14f1f2d54
--- /dev/null
+++ b/0.4.0/paludis/environment.cc
@@ -0,0 +1,432 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/package_database.hh>
+#include <paludis/dep_atom.hh>
+#include <paludis/environment.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/save.hh>
+#include <paludis/util/tokeniser.hh>
+
+/** \file
+ * Implementation of Environment.
+ *
+ * \ingroup grpenvironment
+ */
+
+using namespace paludis;
+
+Environment::Environment(PackageDatabase::Pointer d) :
+ _package_database(d),
+ _has_provide_map(false)
+{
+}
+
+Environment::~Environment()
+{
+}
+
+namespace
+{
+ /**
+ * Check whether licences for a package are accepted.
+ */
+ struct LicenceChecker :
+ DepAtomVisitorTypes::ConstVisitor
+ {
+ /// Are all necessary licences ok?
+ bool ok;
+
+ /// Our environment.
+ const Environment * const env;
+
+ /// Our package database.
+ const PackageDatabaseEntry * const db_entry;
+
+ /// Constructor
+ LicenceChecker(const Environment * const e, const PackageDatabaseEntry * const d) :
+ ok(true),
+ env(e),
+ db_entry(d)
+ {
+ }
+
+ ///\name Visit methods
+ ///{
+ void visit(const AllDepAtom * atom)
+ {
+ std::for_each(atom->begin(), atom->end(), accept_visitor(this));
+ }
+
+ void visit(const AnyDepAtom * atom)
+ {
+ bool local_ok(false);
+
+ if (atom->begin() == atom->end())
+ local_ok = true;
+ else
+ {
+ for (CompositeDepAtom::Iterator i(atom->begin()), i_end(atom->end()) ;
+ i != i_end ; ++i)
+ {
+ Save<bool> save_ok(&ok, true);
+ (*i)->accept(this);
+ local_ok |= ok;
+ }
+ }
+
+ ok &= local_ok;
+ }
+
+ void visit(const UseDepAtom * atom)
+ {
+ if (env->query_use(atom->flag(), db_entry))
+ std::for_each(atom->begin(), atom->end(), accept_visitor(this));
+ }
+
+ void visit(const PlainTextDepAtom * atom)
+ {
+ if (! env->accept_license(atom->text(), db_entry))
+ ok = false;
+ }
+
+ void visit(const PackageDepAtom *) PALUDIS_ATTRIBUTE((noreturn))
+ {
+ throw InternalError(PALUDIS_HERE, "Encountered PackageDepAtom in licence?");
+ }
+
+ void visit(const BlockDepAtom *) PALUDIS_ATTRIBUTE((noreturn))
+ {
+ throw InternalError(PALUDIS_HERE, "Encountered BlockDepAtom in licence?");
+ }
+ ///}
+ };
+}
+
+MaskReasons
+Environment::mask_reasons(const PackageDatabaseEntry & e) const
+{
+ Context context("When checking mask reasons for '" + stringify(e) + "'");
+
+ MaskReasons result;
+ VersionMetadata::ConstPointer metadata(package_database()->fetch_repository(
+ e.get<pde_repository>())->version_metadata(e.get<pde_name>(), e.get<pde_version>()));
+
+ if (metadata->get<vm_eapi>() != "0" && metadata->get<vm_eapi>() != ""
+ && metadata->get<vm_eapi>() != "paludis-1")
+ result.set(mr_eapi);
+ else
+ {
+ if (metadata->get_ebuild_interface())
+ {
+ std::set<KeywordName> keywords;
+ WhitespaceTokeniser::get_instance()->tokenise(
+ metadata->get_ebuild_interface()->get<evm_keywords>(),
+ create_inserter<KeywordName>(std::inserter(keywords, keywords.end())));
+
+ result.set(mr_keyword);
+ for (std::set<KeywordName>::const_iterator i(keywords.begin()),
+ i_end(keywords.end()) ; i != i_end ; ++i)
+ if (accept_keyword(*i, &e))
+ {
+ result.reset(mr_keyword);
+ break;
+ }
+
+ if (! metadata->get_ebuild_interface()->get<evm_virtual>().empty())
+ {
+ QualifiedPackageName n(metadata->get_ebuild_interface()->get<evm_virtual>());
+
+ PackageDatabaseEntry ee(n, e.get<pde_version>(), e.get<pde_repository>());
+ std::set<KeywordName> keywords;
+ WhitespaceTokeniser::get_instance()->tokenise(
+ metadata->get_ebuild_interface()->get<evm_keywords>(),
+ create_inserter<KeywordName>(std::inserter(keywords, keywords.end())));
+
+ for (std::set<KeywordName>::const_iterator i(keywords.begin()),
+ i_end(keywords.end()) ; i != i_end ; ++i)
+ if (accept_keyword(*i, &ee))
+ {
+ result.reset(mr_keyword);
+ break;
+ }
+ }
+ }
+
+ LicenceChecker lc(this, &e);
+ metadata->license()->accept(&lc);
+ if (! lc.ok)
+ result.set(mr_license);
+
+ if (! query_user_unmasks(e))
+ {
+ if (query_user_masks(e))
+ result.set(mr_user_mask);
+
+ const Repository * const repo(package_database()->fetch_repository(
+ e.get<pde_repository>()).raw_pointer());
+
+ if (repo->get_interface<repo_mask>())
+ {
+ if (repo->get_interface<repo_mask>()->query_profile_masks(e.get<pde_name>(),
+ e.get<pde_version>()))
+ result.set(mr_profile_mask);
+
+ if (repo->get_interface<repo_mask>()->query_repository_masks(e.get<pde_name>(),
+ e.get<pde_version>()))
+ result.set(mr_repository_mask);
+
+ if (metadata->get_ebuild_interface())
+ if (! metadata->get_ebuild_interface()->get<evm_virtual>().empty())
+ {
+ QualifiedPackageName n(metadata->get_ebuild_interface()->get<evm_virtual>());
+
+ if (repo->get_interface<repo_mask>()->query_profile_masks(n,
+ e.get<pde_version>()))
+ result.set(mr_profile_mask);
+
+ if (repo->get_interface<repo_mask>()->query_repository_masks(n,
+ e.get<pde_version>()))
+ result.set(mr_repository_mask);
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+Environment::ProvideMapIterator
+Environment::begin_provide_map() const
+{
+ if (! _has_provide_map)
+ {
+ Context context("When scanning for PROVIDEs:");
+
+ for (PackageDatabase::RepositoryIterator r(package_database()->begin_repositories()),
+ r_end(package_database()->end_repositories()) ; r != r_end ; ++r)
+ {
+ if (! (*r)->get_interface<repo_installed>())
+ continue;
+
+ std::copy((*r)->begin_provide_map(), (*r)->end_provide_map(),
+ std::inserter(_provide_map, _provide_map.begin()));
+ }
+
+ _has_provide_map = true;
+ }
+
+ return _provide_map.begin();
+}
+
+Environment::ProvideMapIterator
+Environment::end_provide_map() const
+{
+ return _provide_map.end();
+}
+
+DepAtom::Pointer
+Environment::package_set(const std::string & s, const PackageSetOptions & o) const
+{
+ if (s == "everything" || s == "system" || s == "world" || s == "security")
+ {
+ AllDepAtom::Pointer result(new AllDepAtom);
+
+ for (PackageDatabase::RepositoryIterator r(package_database()->begin_repositories()),
+ r_end(package_database()->end_repositories()) ;
+ r != r_end ; ++r)
+ {
+ if (! (*r)->get_interface<repo_sets>())
+ continue;
+
+ DepAtom::Pointer add((*r)->get_interface<repo_sets>()->package_set(s, o));
+ if (0 != add)
+ result->add_child(add);
+
+ if ("system" != s)
+ {
+ add = (*r)->get_interface<repo_sets>()->package_set("system");
+ if (0 != add)
+ result->add_child(add);
+ }
+ }
+
+ return result;
+ }
+ else
+ {
+ DepAtom::Pointer rr(local_package_set(s));
+ if (0 != rr)
+ return rr;
+
+ for (PackageDatabase::RepositoryIterator r(package_database()->begin_repositories()),
+ r_end(package_database()->end_repositories()) ;
+ r != r_end ; ++r)
+ {
+ if (! (*r)->get_interface<repo_sets>())
+ continue;
+
+ DepAtom::Pointer result((*r)->get_interface<repo_sets>()->package_set(s));
+ if (0 != result)
+ return result;
+ }
+
+ return DepAtom::Pointer(0);
+ }
+}
+
+namespace
+{
+ /**
+ * Find package targets that are appropriate for adding to or removing
+ * from the world file.
+ */
+ struct WorldTargetFinder :
+ DepAtomVisitorTypes::ConstVisitor
+ {
+ /// Matches
+ std::list<const PackageDepAtom *> items;
+
+ void (* add_callback)(const PackageDepAtom *);
+ void (* skip_callback)(const PackageDepAtom *, const std::string & why);
+
+ bool inside_any;
+ bool inside_use;
+
+ WorldTargetFinder(void (* a)(const PackageDepAtom *),
+ void (* s)(const PackageDepAtom *, const std::string &)) :
+ add_callback(a),
+ skip_callback(s),
+ inside_any(false),
+ inside_use(false)
+ {
+ }
+
+ ///\name Visit methods
+ ///{
+ void visit(const AllDepAtom * a)
+ {
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ }
+
+ void visit(const AnyDepAtom * a)
+ {
+ Save<bool> save_inside_any(&inside_any, true);
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ }
+
+ void visit(const UseDepAtom * a)
+ {
+ Save<bool> save_inside_use(&inside_use, true);
+ std::for_each(a->begin(), a->end(), accept_visitor(this));
+ }
+
+ void visit(const PlainTextDepAtom *)
+ {
+ }
+
+ void visit(const PackageDepAtom * a)
+ {
+ if (inside_any)
+ {
+ if (skip_callback)
+ (*skip_callback)(a, "inside || ( ) block");
+ }
+ else if (inside_use)
+ {
+ if (skip_callback)
+ (*skip_callback)(a, "inside use? ( ) block");
+ }
+ else if (a->slot_ptr())
+ {
+ if (skip_callback)
+ (*skip_callback)(a, ":slot restrictions");
+ }
+ else if (a->version_spec_ptr())
+ {
+ if (skip_callback)
+ (*skip_callback)(a, "version restrictions");
+ }
+ else
+ {
+ items.push_back(a);
+ if (add_callback)
+ (*add_callback)(a);
+ }
+ }
+
+ void visit(const BlockDepAtom *)
+ {
+ }
+ ///}
+
+ };
+}
+
+void
+Environment::add_appropriate_to_world(DepAtom::ConstPointer a,
+ void (* add_callback)(const PackageDepAtom *),
+ void (* skip_callback)(const PackageDepAtom *, const std::string & why)) const
+{
+ WorldTargetFinder w(add_callback, skip_callback);
+ a->accept(&w);
+ for (std::list<const PackageDepAtom *>::const_iterator i(w.items.begin()),
+ i_end(w.items.end()) ; i != i_end ; ++i)
+ {
+ for (PackageDatabase::RepositoryIterator r(package_database()->begin_repositories()),
+ r_end(package_database()->end_repositories()) ;
+ r != r_end ; ++r)
+ if ((*r)->get_interface<repo_world>())
+ (*r)->get_interface<repo_world>()->add_to_world((*i)->package());
+ }
+}
+
+void
+Environment::remove_appropriate_from_world(DepAtom::ConstPointer a,
+ void (* remove_callback)(const PackageDepAtom *)) const
+{
+ WorldTargetFinder w(0, 0);
+ a->accept(&w);
+ for (std::list<const PackageDepAtom *>::const_iterator i(w.items.begin()),
+ i_end(w.items.end()) ; i != i_end ; ++i)
+ {
+ for (PackageDatabase::RepositoryIterator r(package_database()->begin_repositories()),
+ r_end(package_database()->end_repositories()) ;
+ r != r_end ; ++r)
+ if ((*r)->get_interface<repo_world>())
+ (*r)->get_interface<repo_world>()->remove_from_world((*i)->package());
+
+ if (remove_callback)
+ (*remove_callback)(*i);
+ }
+}
+
+Hook::Hook(const std::string & n) :
+ _name(n)
+{
+}
+
+Hook
+Hook::operator() (const std::string & k, const std::string & v) const
+{
+ Hook result(*this);
+ result._extra_env.insert(std::make_pair(k, v));
+ return result;
+}
+
diff --git a/0.4.0/paludis/environment.hh b/0.4.0/paludis/environment.hh
new file mode 100644
index 000000000..d613fc3d3
--- /dev/null
+++ b/0.4.0/paludis/environment.hh
@@ -0,0 +1,229 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_ENVIRONMENT_HH
+#define PALUDIS_GUARD_PALUDIS_ENVIRONMENT_HH 1
+
+#include <paludis/mask_reasons.hh>
+#include <paludis/name.hh>
+#include <paludis/package_database.hh>
+#include <paludis/util/counted_ptr.hh>
+#include <paludis/util/instantiation_policy.hh>
+
+/** \file
+ * Declarations for the Environment class.
+ *
+ * \ingroup grpenvironment
+ */
+
+namespace paludis
+{
+ /**
+ * Represents the data for an Environment hook call.
+ *
+ * \ingroup grpenvironment
+ */
+ class Hook
+ {
+ private:
+ std::map<std::string, std::string> _extra_env;
+
+ std::string _name;
+
+ public:
+ Hook(const std::string & name);
+
+ Hook operator() (const std::string & key, const std::string & value) const;
+
+ typedef std::map<std::string, std::string>::const_iterator Iterator;
+
+ Iterator begin() const
+ {
+ return _extra_env.begin();
+ }
+
+ Iterator end() const
+ {
+ return _extra_env.end();
+ }
+
+ std::string name() const
+ {
+ return _name;
+ }
+ };
+
+ /**
+ * Represents a working environment, which contains an available packages
+ * database and provides various methods for querying package visibility
+ * and options.
+ *
+ * \ingroup grpenvironment
+ */
+ class Environment :
+ private InstantiationPolicy<Environment, instantiation_method::NonCopyableTag>
+ {
+ private:
+ PackageDatabase::Pointer _package_database;
+
+ mutable bool _has_provide_map;
+
+ mutable std::map<QualifiedPackageName, QualifiedPackageName> _provide_map;
+
+ protected:
+ /**
+ * Constructor.
+ */
+ Environment(PackageDatabase::Pointer);
+
+ /**
+ * Local package set, or zero.
+ */
+ virtual DepAtom::Pointer local_package_set(const std::string &,
+ const PackageSetOptions & = PackageSetOptions(false)) const
+ {
+ return DepAtom::Pointer(0);
+ }
+
+ public:
+ /**
+ * Does the user want the specified USE flag set for a
+ * particular package?
+ */
+ virtual bool query_use(const UseFlagName &, const PackageDatabaseEntry *) const = 0;
+
+ /**
+ * Fetch a list of enabled USE flags that start with a given prefix,
+ * for USE_EXPAND.
+ */
+ virtual UseFlagNameCollection::Pointer query_enabled_use_matching(
+ const std::string & prefix, const PackageDatabaseEntry *) const = 0;
+
+ /**
+ * Is the specified KEYWORD accepted?
+ */
+ virtual bool accept_keyword(const KeywordName &, const PackageDatabaseEntry * const) const = 0;
+
+ /**
+ * Is the specified LICENSE accepted?
+ */
+ virtual bool accept_license(const std::string &, const PackageDatabaseEntry * const) const = 0;
+
+ /**
+ * Fetch the masks for a particular package.
+ */
+ MaskReasons mask_reasons(const PackageDatabaseEntry &) const;
+
+ /**
+ * Are there any user masks on a package?
+ */
+ virtual bool query_user_masks(const PackageDatabaseEntry &) const = 0;
+
+ /**
+ * Are there any user unmasks on a package?
+ */
+ virtual bool query_user_unmasks(const PackageDatabaseEntry &) const = 0;
+
+ /**
+ * Fetch our package database.
+ */
+ PackageDatabase::Pointer package_database() const
+ {
+ return _package_database;
+ }
+
+ /**
+ * Our bashrc files.
+ */
+ virtual std::string bashrc_files() const = 0;
+
+ /**
+ * Our hook directories.
+ */
+ virtual std::string hook_dirs() const = 0;
+
+ /**
+ * How to run paludis.
+ */
+ virtual std::string paludis_command() const = 0;
+
+ /**
+ * Destructor.
+ */
+ virtual ~Environment();
+
+ /**
+ * Iterator over our provide map.
+ */
+ typedef std::map<QualifiedPackageName, QualifiedPackageName>::const_iterator ProvideMapIterator;
+
+ /**
+ * Iterator to the start of our provide map.
+ */
+ ProvideMapIterator begin_provide_map() const;
+
+ /**
+ * Iterator to past the end of our provide map.
+ */
+ ProvideMapIterator end_provide_map() const;
+
+ /**
+ * Iterator over named mirror entries.
+ */
+ typedef std::multimap<std::string, std::string>::const_iterator MirrorIterator;
+
+ /**
+ * Iterator to the start of our mirrors.
+ */
+ virtual MirrorIterator begin_mirrors(const std::string & mirror) const = 0;
+
+ /**
+ * Iterator to past the end of our mirrors.
+ */
+ virtual MirrorIterator end_mirrors(const std::string & mirror) const = 0;
+
+ /**
+ * Fetch a named package set.
+ */
+ DepAtom::Pointer package_set(const std::string &,
+ const PackageSetOptions & = PackageSetOptions(false)) const;
+
+ /**
+ * Add packages to world, if they are not there already, and if they are
+ * not a restricted atom.
+ */
+ void
+ add_appropriate_to_world(DepAtom::ConstPointer a,
+ void (* add_callback)(const PackageDepAtom *) = 0,
+ void (* skip_callback)(const PackageDepAtom *, const std::string &) = 0) const;
+
+ /**
+ * Remove packages from world, if they are there.
+ */
+ void remove_appropriate_from_world(DepAtom::ConstPointer,
+ void (* remove_callback)(const PackageDepAtom *) = 0) const;
+
+ /**
+ * Perform a hook.
+ */
+ virtual void perform_hook(const Hook & hook) const = 0;
+ };
+}
+
+#endif
diff --git a/0.4.0/paludis/fake_repository.cc b/0.4.0/paludis/fake_repository.cc
new file mode 100644
index 000000000..208ebd934
--- /dev/null
+++ b/0.4.0/paludis/fake_repository.cc
@@ -0,0 +1,273 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <map>
+#include <paludis/fake_repository.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/version_metadata.hh>
+#include <paludis/portage_dep_parser.hh>
+
+/** \file
+ * Implementation for FakeRepository.
+ *
+ * \ingroup grpfakerepository
+ */
+
+using namespace paludis;
+
+namespace paludis
+{
+ /**
+ * Implementation data for FakeRepository.
+ *
+ * \ingroup grpfakerepository
+ */
+ template<>
+ struct Implementation<FakeRepository> :
+ private InstantiationPolicy<Implementation<FakeRepository>, instantiation_method::NonCopyableTag>,
+ InternalCounted<Implementation<FakeRepository> >
+ {
+ /// Our category names.
+ CategoryNamePartCollection::Pointer category_names;
+
+ /// Our package names.
+ std::map<CategoryNamePart, PackageNamePartCollection::Pointer > package_names;
+
+ /// Our versions.
+ std::map<QualifiedPackageName, VersionSpecCollection::Pointer > versions;
+
+ /// Our metadata.
+ std::map<std::string, VersionMetadata::Pointer > metadata;
+
+ /// (Empty) provides map.
+ const std::map<QualifiedPackageName, QualifiedPackageName> provide_map;
+
+ /// Constructor.
+ Implementation() :
+ category_names(new CategoryNamePartCollection)
+ {
+ }
+ };
+}
+
+FakeRepository::FakeRepository(const RepositoryName & name) :
+ Repository(name, RepositoryCapabilities::create((
+ param<repo_installable>(static_cast<InstallableInterface *>(0)),
+ param<repo_installed>(static_cast<InstalledInterface *>(0)),
+ param<repo_mask>(this),
+ param<repo_news>(static_cast<NewsInterface *>(0)),
+ param<repo_sets>(static_cast<SetsInterface *>(0)),
+ param<repo_syncable>(static_cast<SyncableInterface *>(0)),
+ param<repo_uninstallable>(static_cast<UninstallableInterface *>(0)),
+ param<repo_use>(this),
+ param<repo_world>(static_cast<WorldInterface *>(0)),
+ param<repo_environment_variable>(static_cast<EnvironmentVariableInterface *>(0))
+ ))),
+ Repository::MaskInterface(),
+ Repository::UseInterface(),
+ PrivateImplementationPattern<FakeRepository>(new Implementation<FakeRepository>)
+{
+ RepositoryInfoSection config_info("Configuration information");
+ config_info.add_kv("format", "fake");
+
+ _info->add_section(config_info);
+}
+
+FakeRepository::~FakeRepository()
+{
+}
+
+bool
+FakeRepository::do_has_category_named(const CategoryNamePart & c) const
+{
+ return (_imp->category_names->end() != _imp->category_names->find(c));
+}
+
+bool
+FakeRepository::do_has_package_named(const QualifiedPackageName & q) const
+{
+ return has_category_named(q.get<qpn_category>()) &&
+ (_imp->package_names.find(q.get<qpn_category>())->second->end() !=
+ _imp->package_names.find(q.get<qpn_category>())->second->find(q.get<qpn_package>()));
+}
+
+CategoryNamePartCollection::ConstPointer
+FakeRepository::do_category_names() const
+{
+ return _imp->category_names;
+}
+
+QualifiedPackageNameCollection::ConstPointer
+FakeRepository::do_package_names(const CategoryNamePart & c) const
+{
+ if (! has_category_named(c))
+ throw InternalError(PALUDIS_HERE, "no category named " + stringify(c));
+ QualifiedPackageNameCollection::Pointer result(new QualifiedPackageNameCollection);
+ PackageNamePartCollection::Iterator p(_imp->package_names.find(c)->second->begin()),
+ p_end(_imp->package_names.find(c)->second->end());
+ for ( ; p != p_end ; ++p)
+ result->insert(c + *p);
+ return result;
+}
+
+VersionSpecCollection::ConstPointer
+FakeRepository::do_version_specs(const QualifiedPackageName & n) const
+{
+ if (! has_category_named(n.get<qpn_category>()))
+ throw InternalError(PALUDIS_HERE, "no category");
+ if (! has_package_named(n))
+ throw InternalError(PALUDIS_HERE, "no package");
+ return _imp->versions.find(n)->second;
+}
+
+bool
+FakeRepository::do_has_version(const QualifiedPackageName & q, const VersionSpec & v) const
+{
+ if (! has_category_named(q.get<qpn_category>()))
+ throw InternalError(PALUDIS_HERE, "no category");
+ if (! has_package_named(q))
+ throw InternalError(PALUDIS_HERE, "no package");
+ return _imp->versions.find(q)->second->find(v) !=
+ _imp->versions.find(q)->second->end();
+}
+
+void
+FakeRepository::add_category(const CategoryNamePart & c)
+{
+ _imp->category_names->insert(c);
+ _imp->package_names.insert(std::make_pair(c, new PackageNamePartCollection));
+}
+
+void
+FakeRepository::add_package(const QualifiedPackageName & q)
+{
+ add_category(q.get<qpn_category>());
+ _imp->package_names.find(q.get<qpn_category>())->second->insert(q.get<qpn_package>());
+ _imp->versions.insert(std::make_pair(q, new VersionSpecCollection));
+}
+
+VersionMetadata::Pointer
+FakeRepository::add_version(const QualifiedPackageName & q, const VersionSpec & v)
+{
+ add_package(q);
+ _imp->versions.find(q)->second->insert(v);
+ _imp->metadata.insert(
+ std::make_pair(stringify(q) + "-" + stringify(v),
+ VersionMetadata::Pointer(new VersionMetadata::Ebuild(PortageDepParser::parse_depend))));
+ VersionMetadata::Pointer r(_imp->metadata.find(stringify(q) + "-" + stringify(v))->second);
+ r->set<vm_slot>(SlotName("0"));
+ r->set<vm_eapi>("0");
+ r->get_ebuild_interface()->set<evm_keywords>("test");
+ return r;
+}
+
+VersionMetadata::ConstPointer
+FakeRepository::do_version_metadata(
+ const QualifiedPackageName & q, const VersionSpec & v) const
+{
+ if (! has_version(q, v))
+ throw InternalError(PALUDIS_HERE, "no version");
+ return _imp->metadata.find(stringify(q) + "-" + stringify(v))->second;
+}
+
+bool
+FakeRepository::do_query_repository_masks(const QualifiedPackageName &,
+ const VersionSpec &) const
+{
+ return false;
+}
+
+bool
+FakeRepository::do_query_profile_masks(const QualifiedPackageName &, const VersionSpec &) const
+{
+ return false;
+}
+
+UseFlagState
+FakeRepository::do_query_use(const UseFlagName &, const PackageDatabaseEntry *) const
+{
+ return use_unspecified;
+}
+
+bool
+FakeRepository::do_query_use_mask(const UseFlagName &, const PackageDatabaseEntry *) const
+{
+ return false;
+}
+
+bool
+FakeRepository::do_query_use_force(const UseFlagName &, const PackageDatabaseEntry *) const
+{
+ return false;
+}
+
+bool
+FakeRepository::do_is_arch_flag(const UseFlagName &) const
+{
+ return false;
+}
+
+bool
+FakeRepository::do_is_expand_flag(const UseFlagName &) const
+{
+ return false;
+}
+
+
+bool
+FakeRepository::do_is_expand_hidden_flag(const UseFlagName &) const
+{
+ return false;
+}
+
+std::string::size_type
+FakeRepository::do_expand_flag_delim_pos(const UseFlagName &) const
+{
+ return 0;
+}
+
+bool
+FakeRepository::do_is_licence(const std::string &) const
+{
+ return false;
+}
+
+bool
+FakeRepository::do_is_mirror(const std::string &) const
+{
+ return false;
+}
+
+void
+FakeRepository::invalidate() const
+{
+}
+
+Repository::ProvideMapIterator
+FakeRepository::begin_provide_map() const
+{
+ return _imp->provide_map.begin();
+}
+
+Repository::ProvideMapIterator
+FakeRepository::end_provide_map() const
+{
+ return _imp->provide_map.end();
+}
+
diff --git a/0.4.0/paludis/fake_repository.hh b/0.4.0/paludis/fake_repository.hh
new file mode 100644
index 000000000..ce94dfa82
--- /dev/null
+++ b/0.4.0/paludis/fake_repository.hh
@@ -0,0 +1,147 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_FAKE_REPOSITORY_HH
+#define PALUDIS_GUARD_PALUDIS_FAKE_REPOSITORY_HH 1
+
+#include <paludis/repository.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+
+/** \file
+ * Declarations for the FakeRepository class.
+ *
+ * \ingroup grpfakerepository
+ */
+
+namespace paludis
+{
+ /**
+ * A FakeRepository is a Repository subclass that is used for
+ * various test cases.
+ *
+ * \ingroup grpfakerepository
+ */
+ class FakeRepository :
+ public Repository,
+ public Repository::MaskInterface,
+ public Repository::UseInterface,
+ private PrivateImplementationPattern<FakeRepository>
+ {
+ protected:
+ virtual bool do_has_category_named(const CategoryNamePart &) const;
+
+ virtual bool do_has_package_named(const QualifiedPackageName &) const;
+
+ virtual CategoryNamePartCollection::ConstPointer do_category_names() const;
+
+ virtual QualifiedPackageNameCollection::ConstPointer do_package_names(
+ const CategoryNamePart &) const;
+
+ virtual VersionSpecCollection::ConstPointer do_version_specs(
+ const QualifiedPackageName &) const;
+
+ virtual bool do_has_version(const QualifiedPackageName &,
+ const VersionSpec &) const;
+
+ virtual VersionMetadata::ConstPointer do_version_metadata(
+ const QualifiedPackageName &,
+ const VersionSpec &) const;
+
+ virtual bool do_query_repository_masks(const QualifiedPackageName &,
+ const VersionSpec &) const;
+
+ virtual bool do_query_profile_masks(const QualifiedPackageName &,
+ const VersionSpec &) const;
+
+ virtual UseFlagState do_query_use(const UseFlagName &, const PackageDatabaseEntry *) const;
+
+ virtual bool do_query_use_mask(const UseFlagName &, const PackageDatabaseEntry *) const;
+
+ virtual bool do_query_use_force(const UseFlagName &, const PackageDatabaseEntry *) const;
+
+ virtual bool do_is_arch_flag(const UseFlagName &) const;
+
+ virtual bool do_is_expand_flag(const UseFlagName &) const;
+ virtual bool do_is_expand_hidden_flag(const UseFlagName &) const;
+ virtual std::string::size_type do_expand_flag_delim_pos(const UseFlagName &) const;
+
+ virtual bool do_is_licence(const std::string &) const;
+
+ virtual bool do_is_mirror(const std::string &) const;
+
+ public:
+ /**
+ * Constructor.
+ */
+ FakeRepository(const RepositoryName & name);
+
+ /**
+ * Destructor.
+ */
+
+ ~FakeRepository();
+
+ /**
+ * Add a category.
+ */
+ void add_category(const CategoryNamePart &);
+
+ /**
+ * Add a package, and a category if necessary.
+ */
+ void add_package(const QualifiedPackageName &);
+
+ /**
+ * Add a version, and a package and category if necessary, and set some
+ * default values for its metadata, and return said metadata.
+ */
+ VersionMetadata::Pointer add_version(
+ const QualifiedPackageName &, const VersionSpec &);
+
+ /**
+ * Add a version, and a package and category if necessary, and set some
+ * default values for its metadata, and return said metadata (convenience
+ * overload taking strings).
+ */
+ VersionMetadata::Pointer add_version(
+ const std::string & c, const std::string & p, const std::string & v)
+ {
+ return add_version(CategoryNamePart(c) + PackageNamePart(p), VersionSpec(v));
+ }
+
+ /**
+ * A non-constant smart pointer to ourself.
+ */
+ typedef CountedPtr<FakeRepository, count_policy::InternalCountTag> Pointer;
+
+ /**
+ * A constant smart pointer to ourself.
+ */
+ typedef CountedPtr<const FakeRepository, count_policy::InternalCountTag> ConstPointer;
+
+ virtual void invalidate() const;
+
+ virtual ProvideMapIterator begin_provide_map() const;
+
+ virtual ProvideMapIterator end_provide_map() const;
+ };
+}
+
+
+#endif
diff --git a/0.4.0/paludis/files.m4 b/0.4.0/paludis/files.m4
new file mode 100644
index 000000000..539aafa06
--- /dev/null
+++ b/0.4.0/paludis/files.m4
@@ -0,0 +1,43 @@
+dnl vim: set ft=m4 et :
+dnl This file is used by Makefile.am.m4 and paludis.hh.m4. You should
+dnl use the provided autogen.bash script to do all the hard work.
+dnl
+dnl This file is used to avoid having to make lots of repetitive changes in
+dnl Makefile.am every time we add a source or test file. The first parameter is
+dnl the base filename with no extension; later parameters can be `hh', `cc',
+dnl `test', `impl', `testscript'. Note that there isn't much error checking done
+dnl on this file at present...
+
+add(`about', `hh', `test')
+add(`config_file', `hh', `cc', `test', `testscript')
+add(`contents', `hh', `cc')
+add(`default_config', `hh', `cc')
+add(`default_environment', `hh', `cc')
+add(`dep_atom', `hh', `cc', `test')
+add(`dep_atom_dumper', `hh', `cc', `test')
+add(`dep_atom_flattener', `hh', `cc')
+add(`dep_atom_pretty_printer', `hh', `cc')
+add(`dep_list', `hh', `cc', `test')
+add(`dep_tag', `hh', `cc')
+add(`ebuild', `hh', `cc')
+add(`environment', `hh', `cc')
+add(`fake_repository', `hh', `cc')
+add(`hashed_containers', `hh', `cc', `test')
+add(`mask_reasons', `hh', `cc')
+add(`match_package', `hh', `cc')
+add(`name', `hh', `cc', `test')
+add(`nothing_repository', `hh', `cc')
+add(`package_database', `hh', `cc', `test')
+add(`package_database_entry', `hh')
+add(`paludis', `hh', `cc')
+add(`portage_repository', `hh', `cc', `test', `testscript')
+add(`portage_dep_lexer', `hh', `cc', `test')
+add(`portage_dep_parser', `hh', `cc', `test')
+add(`repository', `hh', `cc')
+add(`syncer', `hh', `cc')
+add(`test_environment', `hh', `cc')
+add(`vdb_repository', `hh', `cc', `test', `testscript')
+add(`version_metadata', `hh', `cc')
+add(`version_operator', `hh', `cc', `test')
+add(`version_spec', `hh', `cc', `test')
+
diff --git a/0.4.0/paludis/hashed_containers.cc b/0.4.0/paludis/hashed_containers.cc
new file mode 100644
index 000000000..ddee11807
--- /dev/null
+++ b/0.4.0/paludis/hashed_containers.cc
@@ -0,0 +1,108 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "hashed_containers.hh"
+
+/** \file
+ * Implementation for hashed_containers.hh.
+ *
+ * \ingroup grphashedcontainers
+ */
+
+using namespace paludis;
+
+#if PALUDIS_HAVE_TR1_HASHES || PALUDIS_HAVE_EXT_HASHES || PALUDIS_HAVE_STD_HASHES
+
+#ifndef DOXYGEN
+
+std::size_t
+CRCHash<QualifiedPackageName>::operator() (const QualifiedPackageName & val) const
+{
+ const std::string & s1(val.get<qpn_category>().data()), s2(val.get<qpn_package>().data());
+ std::size_t h(0);
+
+ for (std::string::size_type t(0) ; t < s1.length() ; ++t)
+ {
+ std::size_t hh(h & h_mask);
+ h <<= 5;
+ h ^= (hh >> h_shift);
+ h ^= s1[t];
+ }
+
+ for (std::string::size_type t(0) ; t < s2.length() ; ++t)
+ {
+ std::size_t hh(h & h_mask);
+ h <<= 5;
+ h ^= (hh >> h_shift);
+ h ^= s2[t];
+ }
+
+ return h;
+}
+
+std::size_t
+CRCHash<std::string>::operator() (const std::string & val) const
+{
+ std::size_t h(0);
+
+ for (std::string::size_type t(0) ; t < val.length() ; ++t)
+ {
+ std::size_t hh(h & h_mask);
+ h <<= 5;
+ h ^= (hh >> h_shift);
+ h ^= val[t];
+ }
+
+ return h;
+}
+
+std::size_t
+CRCHash<std::pair<QualifiedPackageName, VersionSpec> >::operator() (
+ const std::pair<QualifiedPackageName, VersionSpec> & val) const
+{
+ const std::string & s1(val.first.get<qpn_category>().data()),
+ s2(val.first.get<qpn_package>().data());
+
+ std::size_t h(0);
+
+ for (std::string::size_type t(0) ; t < s1.length() ; ++t)
+ {
+ std::size_t hh(h & h_mask);
+ h <<= 5;
+ h ^= (hh >> h_shift);
+ h ^= s1[t];
+ }
+
+ for (std::string::size_type t(0) ; t < s2.length() ; ++t)
+ {
+ std::size_t hh(h & h_mask);
+ h <<= 5;
+ h ^= (hh >> h_shift);
+ h ^= s2[t];
+ }
+
+ h ^= val.second.hash_value();
+
+ return h;
+}
+
+#endif
+
+#endif
+
diff --git a/0.4.0/paludis/hashed_containers.hh.in b/0.4.0/paludis/hashed_containers.hh.in
new file mode 100644
index 000000000..857d06417
--- /dev/null
+++ b/0.4.0/paludis/hashed_containers.hh.in
@@ -0,0 +1,293 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+@GENERATED_FILE@
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_HASHED_CONTAINERS_HH
+#define PALUDIS_GUARD_PALUDIS_HASHED_CONTAINERS_HH 1
+
+/** \file
+ * Declarations for the MakeHashedMap and MakeHashedSet classes, and related
+ * utilities.
+ *
+ * \ingroup grphashedcontainers
+ */
+
+/**
+ * Non-zero if we have std::tr1:: hashes (g++-4).
+ *
+ * \ingroup grphashedcontainers
+ */
+#define PALUDIS_HAVE_TR1_HASHES @HAVE_TR1_HASHES@
+
+/**
+ * Non-zero if we have __gnu_cxx:: hashes under ext/ (g++-3).
+ *
+ * \ingroup grphashedcontainers
+ */
+#define PALUDIS_HAVE_EXT_HASHES @HAVE_EXT_HASHES@
+
+
+/**
+ * Non-zero if we have std:: hashes (icc70).
+ *
+ * \ingroup grphashedcontainers
+ */
+#define PALUDIS_HAVE_STD_HASHES @HAVE_STD_HASHES@
+
+#include <paludis/name.hh>
+#include <paludis/util/validated.hh>
+#include <paludis/version_spec.hh>
+
+#if PALUDIS_HAVE_TR1_HASHES
+# include <tr1/unordered_set>
+# include <tr1/unordered_map>
+#elif PALUDIS_HAVE_EXT_HASHES
+# include <ext/hash_set>
+# include <ext/hash_map>
+#elif PALUDIS_HAVE_STD_HASHES
+# include <hash_set>
+# include <hash_map>
+#else
+# include <set>
+# include <map>
+#endif
+
+#include <limits>
+#include <string>
+#include <functional>
+
+namespace paludis
+{
+ /**
+ * Hash function base template.
+ *
+ * \ingroup grphashedcontainers
+ */
+ template <typename T_>
+ struct CRCHash;
+
+ /**
+ * Make a hashed map of some kind from Key_ to Value_.
+ *
+ * \ingroup grphashedcontainers
+ */
+ template <typename Key_, typename Value_>
+ struct MakeHashedMap
+ {
+#if PALUDIS_HAVE_TR1_HASHES
+ /// Our map type.
+ typedef std::tr1::unordered_map<Key_, Value_, CRCHash<Key_> > Type;
+
+#elif PALUDIS_HAVE_EXT_HASHES
+ /// Our map type.
+ typedef __gnu_cxx::hash_map<Key_, Value_, CRCHash<Key_> > Type;
+
+#elif PALUDIS_HAVE_STD_HASHES
+ /// Our map type.
+ typedef std::hash_map<Key_, Value_, CRCHash<Key_> > Type;
+
+#else
+ /// Our map type.
+ typedef std::map<Key_, Value_> Type;
+#endif
+ };
+
+ /**
+ * Make a hashed set of some kind of Key_.
+ *
+ * \ingroup grphashedcontainers
+ */
+ template <typename Key_>
+ struct MakeHashedSet
+ {
+#if PALUDIS_HAVE_TR1_HASHES
+ /// Our set type.
+ typedef std::tr1::unordered_set<Key_, CRCHash<Key_> > Type;
+
+#elif PALUDIS_HAVE_EXT_HASHES
+ /// Our set type.
+ typedef __gnu_cxx::hash_set<Key_, CRCHash<Key_> > Type;
+
+#elif PALUDIS_HAVE_STD_HASHES
+ /// Our set type.
+ typedef std::hash_set<Key_, CRCHash<Key_> > Type;
+
+#else
+ /// Our set type.
+ typedef std::set<Key_> Type;
+#endif
+ };
+
+#if PALUDIS_HAVE_TR1_HASHES || PALUDIS_HAVE_EXT_HASHES || PALUDIS_HAVE_STD_HASHES
+ namespace hashed_containers_internals
+ {
+ /**
+ * Base definitions for our CRCHash.
+ *
+ * \ingroup grphashedcontainers
+ */
+ struct CRCHashBase
+ {
+ /// Shift value.
+ static const std::size_t h_shift = std::numeric_limits<std::size_t>::digits - 5;
+
+ /// Mask value.
+ static const std::size_t h_mask = static_cast<std::size_t>(0x1f) << h_shift;
+ };
+ }
+
+ /**
+ * Hash, for QualifiedPackageName.
+ *
+ * \ingroup grphashedcontainers
+ */
+ template <>
+ class CRCHash<QualifiedPackageName> :
+ public std::unary_function<QualifiedPackageName, std::size_t>,
+ protected hashed_containers_internals::CRCHashBase
+ {
+ public:
+ /// Hash function.
+ std::size_t operator() (const QualifiedPackageName & val) const;
+
+#if (! PALUDIS_HAVE_TR1_HASHES) && (! PALUDIS_HAVE_EXT_HASHES)
+ enum
+ {
+ min_buckets = 32,
+ bucket_size = 4
+ };
+
+ bool operator() (const QualifiedPackageName & i1, const QualifiedPackageName & i2) const
+ {
+ return i1 < i2;
+ }
+#endif
+ };
+
+ /**
+ * Hash, for a validated string type.
+ *
+ * \ingroup grphashedcontainers
+ */
+ template <typename Validated_>
+ class CRCHash<Validated<std::string, Validated_> > :
+ public std::unary_function<Validated<std::string, Validated_>, std::size_t>,
+ protected hashed_containers_internals::CRCHashBase
+ {
+ public:
+ /// Hash function.
+ std::size_t operator() (const Validated<std::string, Validated_> & val) const;
+
+#if (! PALUDIS_HAVE_TR1_HASHES) && (! PALUDIS_HAVE_EXT_HASHES)
+ enum
+ {
+ min_buckets = 32,
+ bucket_size = 4
+ };
+
+ bool operator() (const Validated<std::string, Validated_> i1,
+ const Validated<std::string, Validated_> & i2) const
+ {
+ return i1 < i2;
+ }
+#endif
+ };
+
+
+ /**
+ * Hash, for a string.
+ *
+ * \ingroup grphashedcontainers
+ */
+ template<>
+ class CRCHash<std::string> :
+ public std::unary_function<std::string, std::size_t>,
+ protected hashed_containers_internals::CRCHashBase
+ {
+ public:
+ /// Hash function.
+ std::size_t operator() (const std::string & val) const;
+
+#if (! PALUDIS_HAVE_TR1_HASHES) && (! PALUDIS_HAVE_EXT_HASHES)
+ enum
+ {
+ min_buckets = 32,
+ bucket_size = 4
+ };
+
+ bool operator() (const std::string & i1, const std::string & i2) const
+ {
+ return i1 < i2;
+ }
+#endif
+ };
+
+ /**
+ * Hash, for a QualifiedPackageName + VersionSpec pair.
+ *
+ * \ingroup grphashedcontainers
+ */
+ template <>
+ class CRCHash<std::pair<QualifiedPackageName, VersionSpec> > :
+ public std::unary_function<std::pair<QualifiedPackageName, VersionSpec>, std::size_t>,
+ protected hashed_containers_internals::CRCHashBase
+ {
+ public:
+ /// Hash function.
+ std::size_t operator() (const std::pair<QualifiedPackageName, VersionSpec> & val) const;
+
+#if (! PALUDIS_HAVE_TR1_HASHES) && (! PALUDIS_HAVE_EXT_HASHES)
+ enum
+ {
+ min_buckets = 32,
+ bucket_size = 4
+ };
+
+ bool operator() (const std::pair<QualifiedPackageName, VersionSpec> & i1,
+ const std::pair<QualifiedPackageName, VersionSpec> & i2) const
+ {
+ return i1 < i2;
+ }
+#endif
+ };
+
+ template <typename Validated_>
+ std::size_t
+ CRCHash<Validated<std::string, Validated_> >::operator() (const Validated<std::string, Validated_> & val) const
+ {
+ const std::string & s1(val.data());
+ std::size_t h(0);
+
+ for (std::string::size_type t(0) ; t < s1.length() ; ++t)
+ {
+ std::size_t hh(h & h_mask);
+ h <<= 5;
+ h ^= (hh >> h_shift);
+ h ^= s1[t];
+ }
+
+ return h;
+ }
+
+#endif
+
+}
+
+#endif
diff --git a/0.4.0/paludis/hashed_containers_TEST.cc b/0.4.0/paludis/hashed_containers_TEST.cc
new file mode 100644
index 000000000..4de5cd9aa
--- /dev/null
+++ b/0.4.0/paludis/hashed_containers_TEST.cc
@@ -0,0 +1,50 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "hashed_containers.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace paludis;
+using namespace test;
+
+namespace test_cases
+{
+ /**
+ * \test Test HashSet.
+ *
+ * \ingroup grptestcases
+ */
+ struct HashSetTestQPN : TestCase
+ {
+ HashSetTestQPN() : TestCase("hash set qpn") { }
+
+ void run()
+ {
+ MakeHashedSet<QualifiedPackageName>::Type s;
+ TEST_CHECK(s.empty());
+ TEST_CHECK(s.end() == s.find(QualifiedPackageName("foo/bar")));
+ TEST_CHECK(s.insert(QualifiedPackageName("foo/bar")).second);
+ TEST_CHECK(s.end() != s.find(QualifiedPackageName("foo/bar")));
+ TEST_CHECK(! s.empty());
+ TEST_CHECK(! s.insert(QualifiedPackageName("foo/bar")).second);
+ }
+ } test_hash_set_qpn;
+}
+
diff --git a/0.4.0/paludis/mask_reasons.cc b/0.4.0/paludis/mask_reasons.cc
new file mode 100644
index 000000000..d26dbc38d
--- /dev/null
+++ b/0.4.0/paludis/mask_reasons.cc
@@ -0,0 +1,72 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <paludis/mask_reasons.hh>
+#include <paludis/util/exception.hh>
+#include <ostream>
+
+/** \file
+ * Implementation of MaskReason classes.
+ *
+ * \ingroup grpmaskreasons
+ */
+
+std::ostream &
+paludis::operator<< (std::ostream & s, const MaskReason & r)
+{
+ do
+ {
+ switch (r)
+ {
+ case mr_keyword:
+ s << "keyword";
+ continue;
+
+ case mr_user_mask:
+ s << "user mask";
+ continue;
+
+ case mr_profile_mask:
+ s << "profile mask";
+ continue;
+
+ case mr_repository_mask:
+ s << "repository mask";
+ continue;
+
+ case mr_eapi:
+ s << "EAPI";
+ continue;
+
+ case mr_license:
+ s << "license";
+ continue;
+
+ case last_mr:
+ ;
+ }
+
+ throw InternalError(PALUDIS_HERE, "Bad MaskReason value");
+ }
+ while (false);
+
+ return s;
+}
+
diff --git a/0.4.0/paludis/mask_reasons.hh b/0.4.0/paludis/mask_reasons.hh
new file mode 100644
index 000000000..da4044319
--- /dev/null
+++ b/0.4.0/paludis/mask_reasons.hh
@@ -0,0 +1,70 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_MASK_REASONS_HH
+#define PALUDIS_GUARD_PALUDIS_MASK_REASONS_HH 1
+
+#include <bitset>
+#include <iosfwd>
+
+/** \file
+ * Declarations for MaskReasons and related classes.
+ *
+ * \ingroup grpmaskreasons
+ */
+
+namespace paludis
+{
+ /**
+ * Each value represents one reason for a package being
+ * masked.
+ *
+ * \see MaskReasons
+ *
+ * \ingroup grpmaskreasons
+ */
+ enum MaskReason
+ {
+ mr_keyword, ///< no keyword match
+ mr_user_mask, ///< user package.mask
+ mr_profile_mask, ///< profile package.mask
+ mr_repository_mask, ///< repository package.mask
+ mr_eapi, ///< unknown eapi
+ mr_license, ///< unaccepted license
+ mr_licence = mr_license, ///< convenience alias for those who can spell
+ last_mr ///< number of entries
+ };
+
+ /**
+ * A collection of reasons for why a package is masked.
+ *
+ * \ingroup grpmaskreasons
+ */
+ typedef std::bitset<last_mr> MaskReasons;
+
+ /**
+ * Stringify a MaskReason.
+ *
+ * \ingroup grpmaskreasons
+ */
+ std::ostream &
+ operator<< (std::ostream &, const MaskReason &);
+}
+
+#endif
diff --git a/0.4.0/paludis/match_package.cc b/0.4.0/paludis/match_package.cc
new file mode 100644
index 000000000..60e528015
--- /dev/null
+++ b/0.4.0/paludis/match_package.cc
@@ -0,0 +1,135 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/match_package.hh>
+
+/** \file
+ * Implementation for match_package.hh.
+ *
+ * \ingroup grpmatchpackage
+ */
+
+using namespace paludis;
+
+bool
+match_package_internals::do_match(
+ const Environment * const env,
+ const PackageDepAtom * const atom,
+ const PackageDatabaseEntry * const entry)
+{
+ if (atom->package() != entry->get<pde_name>())
+ return false;
+
+ if (atom->version_spec_ptr() && ! (((entry->get<pde_version>()).*
+ (atom->version_operator().as_version_spec_operator()))
+ (*atom->version_spec_ptr())))
+ return false;
+
+ if (atom->repository_ptr())
+ if (*atom->repository_ptr() != entry->get<pde_repository>())
+ return false;
+
+ if (atom->slot_ptr() || atom->use_requirements_ptr())
+ {
+ VersionMetadata::ConstPointer metadata(env->package_database()->fetch_repository(
+ entry->get<pde_repository>())->version_metadata(
+ entry->get<pde_name>(), entry->get<pde_version>()));
+
+ if (atom->slot_ptr())
+ if (*atom->slot_ptr() != SlotName(metadata->get<vm_slot>()))
+ return false;
+
+ if (atom->use_requirements_ptr())
+ {
+ for (UseRequirements::Iterator u(atom->use_requirements_ptr()->begin()),
+ u_end(atom->use_requirements_ptr()->end()) ; u != u_end ; ++u)
+ {
+ switch (u->second)
+ {
+ case use_unspecified:
+ continue;
+
+ case use_enabled:
+ if (! env->query_use(u->first, entry))
+ return false;
+ continue;
+
+ case use_disabled:
+ if (env->query_use(u->first, entry))
+ return false;
+ continue;
+ }
+ throw InternalError(PALUDIS_HERE, "bad UseFlagState");
+ }
+ }
+ }
+
+ return true;
+}
+
+bool
+match_package_internals::do_match(
+ const Environment * const env,
+ const PackageDepAtom * const atom,
+ const DepListEntry * const entry)
+{
+ if (atom->package() != entry->get<dle_name>())
+ return false;
+
+ if (atom->version_spec_ptr() && ! (((entry->get<dle_version>()).*
+ (atom->version_operator().as_version_spec_operator()))
+ (*atom->version_spec_ptr())))
+ return false;
+
+ if (atom->repository_ptr() && (*atom->repository_ptr() != entry->get<dle_repository>()))
+ return false;
+
+ if (atom->slot_ptr() && (*atom->slot_ptr() != entry->get<dle_metadata>()->get<vm_slot>()))
+ return false;
+
+ if (atom->use_requirements_ptr())
+ {
+ PackageDatabaseEntry e(entry->get<dle_name>(), entry->get<dle_version>(),
+ entry->get<dle_repository>());
+
+ for (UseRequirements::Iterator u(atom->use_requirements_ptr()->begin()),
+ u_end(atom->use_requirements_ptr()->end()) ; u != u_end ; ++u)
+ {
+ switch (u->second)
+ {
+ case use_unspecified:
+ continue;
+
+ case use_enabled:
+ if (! env->query_use(u->first, &e))
+ return false;
+ continue;
+
+ case use_disabled:
+ if (env->query_use(u->first, &e))
+ return false;
+ continue;
+ }
+ throw InternalError(PALUDIS_HERE, "bad UseFlagState");
+ }
+ }
+
+ return true;
+}
+
diff --git a/0.4.0/paludis/match_package.hh b/0.4.0/paludis/match_package.hh
new file mode 100644
index 000000000..a9cc62023
--- /dev/null
+++ b/0.4.0/paludis/match_package.hh
@@ -0,0 +1,149 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#ifndef PALUDIS_GUARD_PALUDIS_MATCH_PACKAGE_HH
+#define PALUDIS_GUARD_PALUDIS_MATCH_PACKAGE_HH 1
+
+/** \file
+ * Declare the match_package function.
+ *
+ * Do not merge this file into dep_atom. It will cause all sorts of horrible
+ * circular dependency issues. Avoid including this file in headers if at all
+ * possible.
+ *
+ * \ingroup grpmatchpackage
+ */
+
+#include <paludis/dep_atom.hh>
+#include <paludis/dep_list.hh>
+#include <paludis/environment.hh>
+#include <paludis/util/attributes.hh>
+
+namespace paludis
+{
+ /**
+ * For internal use by match_package.
+ *
+ * \ingroup grpmatchpackage
+ */
+ namespace match_package_internals
+ {
+ /**
+ * Do the match on a PackageDatabaseEntry.
+ *
+ * \ingroup grpmatchpackage
+ */
+ bool do_match(
+ const Environment * const env,
+ const PackageDepAtom * const atom,
+ const PackageDatabaseEntry * const entry)
+ PALUDIS_ATTRIBUTE((nonnull(1, 2, 3)));
+
+ /**
+ * Do the match on a DepListEntry.
+ *
+ * \ingroup grpmatchpackage
+ */
+ bool do_match(
+ const Environment * const env,
+ const PackageDepAtom * const atom,
+ const DepListEntry * const entry)
+ PALUDIS_ATTRIBUTE((nonnull(2, 3)));
+
+ /**
+ * Normalise env type.
+ *
+ * \ingroup grpmatchpackage
+ */
+ inline const Environment * sanitise_env(const Environment * env)
+ {
+ return env;
+ }
+
+ /**
+ * Normalise DB type.
+ *
+ * \ingroup grpmatchpackage
+ */
+ template <typename P1_, typename P2_>
+ inline const Environment * sanitise_env(const CountedPtr<const Environment, P1_, P2_> env)
+ {
+ return env.raw_pointer();
+ }
+
+ /**
+ * Normalise atom type.
+ *
+ * \ingroup grpmatchpackage
+ */
+ inline const PackageDepAtom * sanitise_atom(const PackageDepAtom * atom)
+ {
+ return atom;
+ }
+
+ /**
+ * Normalise atom type.
+ *
+ * \ingroup grpmatchpackage
+ */
+ inline const PackageDepAtom * sanitise_atom(const PackageDepAtom & atom)
+ {
+ return &atom;
+ }
+
+ /**
+ * Normalise atom type.
+ *
+ * \ingroup grpmatchpackage
+ */
+ template <typename P1_, typename P2_>
+ inline const PackageDepAtom * sanitise_atom(const CountedPtr<const PackageDepAtom, P1_, P2_> atom)
+ {
+ return atom.raw_pointer();
+ }
+
+ /**
+ * Normalise target type.
+ *
+ * \ingroup grpmatchpackage
+ */
+ template <typename T_>
+ inline const T_ * sanitise_target(const T_ * e)
+ {
+ return e;
+ }
+
+ /**
+ * Normalise target type.
+ *
+ * \ingroup grpmatchpackage
+ */
+ template <typename T_>
+ inline const T_ * sanitise_target(const T_ & e)
+ {
+ return &e;
+ }
+ }
+
+ /**
+ * Return whether the specified atom matches the specified target.
+ *
+ * \param env Some kind of environment
+ * \param atom Some kind of package dep atom
+ * \param target Some kind of target
+ *
+ * \ingroup grpmatchpackage
+ */
+ template <typename Env_, typename Atom_, typename Target_>
+ bool match_package(
+ const Env_ & env,
+ const Atom_ & atom,
+ const Target_ & target)
+ {
+ return match_package_internals::do_match(
+ match_package_internals::sanitise_env(env),
+ match_package_internals::sanitise_atom(atom),
+ match_package_internals::sanitise_target(target));
+ }
+}
+
+#endif
diff --git a/0.4.0/paludis/name.cc b/0.4.0/paludis/name.cc
new file mode 100644
index 000000000..7ee2328b8
--- /dev/null
+++ b/0.4.0/paludis/name.cc
@@ -0,0 +1,273 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/name.hh>
+#include <paludis/util/stringify.hh>
+#include <ostream>
+
+/** \file
+ * Implementation of name.hh things.
+ *
+ * \ingroup grpnames
+ */
+
+using namespace paludis;
+
+QualifiedPackageNameError::QualifiedPackageNameError(const std::string & s) throw () :
+ NameError(s, "qualified package name")
+{
+}
+
+std::ostream &
+paludis::operator<< (std::ostream & s, const QualifiedPackageName & q)
+{
+ s << q.get<qpn_category>() << "/" << q.get<qpn_package>();
+ return s;
+}
+
+MakeSmartRecord<QualifiedPackageNameTag>::Type
+QualifiedPackageName::_make_parent(
+ const std::string & s)
+{
+ Context c("When splitting out category and package names from '" + s + "':");
+
+ std::string::size_type p(s.find('/'));
+ if (std::string::npos == p)
+ throw QualifiedPackageNameError(s);
+
+ return MakeSmartRecord<QualifiedPackageNameTag>::Type(
+ CategoryNamePart(s.substr(0, p)),
+ PackageNamePart(s.substr(p + 1)));
+}
+
+void
+UseFlagNameValidator::validate(const std::string & s)
+{
+ static const std::string allowed_chars(
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789-+_:@");
+
+ do
+ {
+ if (s.empty())
+ break;
+
+ if ('-' == s.at(0))
+ break;
+
+ if (std::string::npos != s.find_first_not_of(allowed_chars))
+ break;
+
+ return;
+
+ } while (false);
+
+ Context c("When validating use flag name '" + s + "':");
+
+ throw UseFlagNameError(s);
+}
+
+UseFlagNameError::UseFlagNameError(const std::string & name) throw () :
+ NameError(name, "use flag name")
+{
+}
+
+SlotNameError::SlotNameError(const std::string & name) throw () :
+ NameError(name, "slot name")
+{
+}
+
+void
+SlotNameValidator::validate(const std::string & s)
+{
+ static const std::string allowed_chars(
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789-+_.");
+
+ do
+ {
+ if (s.empty())
+ break;
+
+ if ('-' == s.at(0))
+ break;
+
+ if (std::string::npos != s.find_first_not_of(allowed_chars))
+ break;
+
+ return;
+
+ } while (false);
+
+ Context c("When validating slot name '" + s + "':");
+
+ throw SlotNameError(s);
+}
+
+PackageNamePartError::PackageNamePartError(const std::string & name) throw () :
+ NameError(name, "package name part")
+{
+}
+
+void
+PackageNamePartValidator::validate(const std::string & s)
+{
+ /* this gets called a lot, make it fast */
+
+ static const std::string allowed_chars(
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789-+_");
+
+ static const std::string number_chars(
+ "0123456789");
+
+ if (s.empty() || '-' == s.at(0))
+ {
+ Context c("When validating package name part '" + s + "':");
+ throw PackageNamePartError(s);
+ }
+
+ for (std::string::size_type p(0) ; p < s.length() ; ++p)
+ {
+ if (std::string::npos == allowed_chars.find(s[p]))
+ {
+ Context c("When validating package name part '" + s + "':");
+ throw PackageNamePartError(s);
+ }
+
+ if ((p + 1 < s.length()) && (s[p] == '-') &&
+ (std::string::npos != number_chars.find(s[p + 1])))
+ if (std::string::npos == s.find_first_not_of(number_chars, p + 1))
+ throw PackageNamePartError(s);
+ }
+}
+
+void
+CategoryNamePartValidator::validate(const std::string & s)
+{
+ /* this gets called a lot, make it fast */
+
+ static const std::string allowed_chars(
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789-+_");
+
+ do
+ {
+ if (s.empty())
+ break;
+
+ if ('-' == s.at(0))
+ break;
+
+ if (std::string::npos != s.find_first_not_of(allowed_chars))
+ break;
+
+ return;
+
+ } while (false);
+
+ Context c("When validating category name '" + s + "':");
+ throw CategoryNamePartError(s);
+}
+
+CategoryNamePartError::CategoryNamePartError(const std::string & name) throw () :
+ NameError(name, "category name part")
+{
+}
+
+void
+RepositoryNameValidator::validate(const std::string & s)
+{
+ static const std::string allowed_chars(
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789-+_");
+
+ do
+ {
+ if (s.empty())
+ break;
+
+ if ('-' == s.at(0))
+ break;
+
+ if (std::string::npos != s.find_first_not_of(allowed_chars))
+ break;
+
+ return;
+
+ } while (false);
+
+ Context c("When validating repository name '" + s + "':");
+ throw RepositoryNameError(s);
+}
+
+RepositoryNameError::RepositoryNameError(const std::string & name) throw () :
+ NameError(name, "repository")
+{
+}
+
+KeywordNameError::KeywordNameError(const std::string & name) throw () :
+ NameError(name, "keyword name")
+{
+}
+
+void
+KeywordNameValidator::validate(const std::string & s)
+{
+ static const std::string allowed_chars(
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789-+_");
+
+ do
+ {
+ switch (s.length())
+ {
+ case 0:
+ continue;
+
+ case 1:
+ if ("*" == s)
+ return;
+ continue;
+
+ case 2:
+ if ("-*" == s)
+ return;
+
+ /* fall throuth */
+ default:
+ if (std::string::npos != s.find_first_not_of(allowed_chars,
+ ('~' == s.at(0) ? 1 : 0)))
+ continue;
+ }
+
+ return;
+
+ } while (false);
+
+ Context c("When validating keyword name '" + s + "':");
+ throw KeywordNameError(s);
+}
+
diff --git a/0.4.0/paludis/name.hh b/0.4.0/paludis/name.hh
new file mode 100644
index 000000000..03f7fcfbc
--- /dev/null
+++ b/0.4.0/paludis/name.hh
@@ -0,0 +1,438 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_NAME_HH
+#define PALUDIS_GUARD_PALUDIS_NAME_HH 1
+
+#include <paludis/util/collection.hh>
+#include <paludis/util/exception.hh>
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/util/smart_record.hh>
+#include <paludis/util/validated.hh>
+
+#include <string>
+#include <iosfwd>
+
+/** \file
+ * Declarations for various Name classes.
+ *
+ * \ingroup grpnames
+ */
+
+namespace paludis
+{
+ /**
+ * A PackageNamePartError is thrown if an invalid value is assigned to
+ * a PackageNamePart.
+ *
+ * \ingroup grpnames
+ * \ingroup grpexceptions
+ */
+ class PackageNamePartError : public NameError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ PackageNamePartError(const std::string & name) throw ();
+ };
+
+ /**
+ * A PackageNamePartValidator handles validation rules for the value
+ * of a PackageNamePart.
+ *
+ * \ingroup grpnames
+ */
+ struct PackageNamePartValidator :
+ private InstantiationPolicy<PackageNamePartValidator, instantiation_method::NonInstantiableTag>
+ {
+ /**
+ * If the parameter is not a valid value for a PackageNamePart,
+ * throw a PackageNamePartError.
+ */
+ static void validate(const std::string &);
+ };
+
+ /**
+ * A PackageNamePart holds a std::string that is a valid name for the
+ * category part of a QualifiedPackageName.
+ *
+ * \ingroup grpnames
+ */
+ typedef Validated<std::string, PackageNamePartValidator> PackageNamePart;
+
+ /**
+ * Holds a set of PackageNamePart instances.
+ *
+ * \ingroup grpnames
+ */
+ typedef SortedCollection<PackageNamePart> PackageNamePartCollection;
+
+ /**
+ * A CategoryNamePartError is thrown if an invalid value is assigned to
+ * a CategoryNamePart.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grpnames
+ */
+ class CategoryNamePartError : public NameError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ CategoryNamePartError(const std::string & name) throw ();
+ };
+
+ /**
+ * A CategoryNamePartValidator handles validation rules for the value
+ * of a CategoryNamePart.
+ *
+ * \ingroup grpnames
+ */
+ struct CategoryNamePartValidator :
+ private InstantiationPolicy<CategoryNamePartValidator, instantiation_method::NonInstantiableTag>
+ {
+ /**
+ * If the parameter is not a valid value for a CategoryNamePart,
+ * throw a CategoryNamePartError.
+ */
+ static void validate(const std::string &);
+ };
+
+ /**
+ * A CategoryNamePart holds a std::string that is a valid name for the
+ * category part of a QualifiedPackageName.
+ *
+ * \ingroup grpnames
+ */
+ typedef Validated<std::string, CategoryNamePartValidator> CategoryNamePart;
+
+ /**
+ * Holds a set of CategoryNamePart instances.
+ *
+ * \ingroup grpnames
+ */
+ typedef SortedCollection<CategoryNamePart> CategoryNamePartCollection;
+
+ /**
+ * Keys for a QualifiedPackageName.
+ *
+ * \ingroup grpnames
+ *
+ * \see QualifiedPackageName
+ */
+ enum QualifiedPackageNameKeys
+ {
+ qpn_category, ///< The CategoryNamePart part
+ qpn_package, ///< The PackageNamePart part
+ last_qpn ///< Number of values
+ };
+
+ /**
+ * Tags for a QualifiedPackageName.
+ *
+ * \ingroup grpnames
+ *
+ * \see QualifiedPackageName
+ */
+ struct QualifiedPackageNameTag :
+ SmartRecordTag<comparison_mode::FullComparisonTag, comparison_method::SmartRecordCompareByAllTag>,
+ SmartRecordKeys<QualifiedPackageNameKeys, last_qpn>,
+ SmartRecordKey<qpn_category, CategoryNamePart>,
+ SmartRecordKey<qpn_package, PackageNamePart>
+ {
+ };
+
+ /**
+ * A QualifiedPackageName instance holds a CategoryNamePart and
+ * a PackageNamePart.
+ *
+ * \ingroup grpnames
+ */
+ class QualifiedPackageName :
+ public MakeSmartRecord<QualifiedPackageNameTag>::Type
+ {
+ private:
+ static MakeSmartRecord<QualifiedPackageNameTag>::Type _make_parent(
+ const std::string & s);
+
+ public:
+ /**
+ * Constructor.
+ */
+ QualifiedPackageName(const CategoryNamePart & c, const PackageNamePart & p) :
+ MakeSmartRecord<QualifiedPackageNameTag>::Type(c, p)
+ {
+ }
+
+ /**
+ * Copy constructor.
+ */
+ QualifiedPackageName(const QualifiedPackageName & other) :
+ MakeSmartRecord<QualifiedPackageNameTag>::Type(other)
+ {
+ }
+
+ /**
+ * Constructor, from a raw string.
+ */
+ explicit QualifiedPackageName(const std::string & s) :
+ MakeSmartRecord<QualifiedPackageNameTag>::Type(_make_parent(s))
+ {
+ }
+
+ /**
+ * Assignment.
+ */
+ const QualifiedPackageName & operator= (const QualifiedPackageName & other)
+ {
+ MakeSmartRecord<QualifiedPackageNameTag>::Type::operator= (other);
+ return *this;
+ }
+ };
+
+ /**
+ * Output a QualifiedPackageName to a stream.
+ *
+ * \ingroup grpnames
+ */
+ std::ostream & operator<< (std::ostream &, const QualifiedPackageName &);
+
+ /**
+ * Holds a collection of QualifiedPackageName instances.
+ *
+ * \ingroup grpnames
+ */
+ typedef SortedCollection<QualifiedPackageName> QualifiedPackageNameCollection;
+
+ /**
+ * A QualifiedPackageNameError may be thrown if an invalid name is
+ * assigned to a QualifiedPackageName (alternatively, the exception
+ * raised may be a PackageNamePartError or a CategoryNamePartError).
+ *
+ * \ingroup grpnames
+ * \ingroup grpexceptions
+ */
+ class QualifiedPackageNameError : public NameError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ QualifiedPackageNameError(const std::string &) throw ();
+ };
+
+ /**
+ * Convenience operator to make a QualifiedPackageName from a
+ * PackageNamePart and a CategoryNamePart.
+ *
+ * \ingroup grpnames
+ */
+ inline const QualifiedPackageName
+ operator+ (const CategoryNamePart & c, const PackageNamePart & p)
+ {
+ return QualifiedPackageName(c, p);
+ }
+
+ /**
+ * A UseFlagNameError is thrown if an invalid value is assigned to
+ * a UseFlagName.
+ *
+ * \ingroup grpnames
+ * \ingroup grpexceptions
+ */
+ class UseFlagNameError : public NameError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ UseFlagNameError(const std::string & name) throw ();
+ };
+
+ /**
+ * A UseFlagNameValidator handles validation rules for the value of a
+ * UseFlagName.
+ *
+ * \ingroup grpnames
+ */
+ struct UseFlagNameValidator :
+ private InstantiationPolicy<UseFlagNameValidator, instantiation_method::NonInstantiableTag>
+ {
+ /**
+ * If the parameter is not a valid value for a UseFlagName,
+ * throw a UseFlagNameError.
+ */
+ static void validate(const std::string &);
+ };
+
+ /**
+ * A UseFlagName holds a std::string that is a valid name for a USE flag.
+ *
+ * \ingroup grpnames
+ */
+ typedef Validated<std::string, UseFlagNameValidator> UseFlagName;
+
+ /**
+ * A collection of UseFlagName instances.
+ *
+ * \ingroup grpnames
+ */
+ typedef SortedCollection<UseFlagName> UseFlagNameCollection;
+
+ /**
+ * A SlotNameError is thrown if an invalid value is assigned to
+ * a SlotName.
+ *
+ * \ingroup grpnames
+ * \ingroup grpexceptions
+ */
+ class SlotNameError : public NameError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ SlotNameError(const std::string & name) throw ();
+ };
+
+ /**
+ * A SlotNameValidator handles validation rules for the value of a
+ * SlotName.
+ *
+ * \ingroup grpnames
+ */
+ struct SlotNameValidator :
+ private InstantiationPolicy<SlotNameValidator, instantiation_method::NonInstantiableTag>
+ {
+ /**
+ * If the parameter is not a valid value for a SlotName,
+ * throw a SlotNameError.
+ */
+ static void validate(const std::string &);
+ };
+
+ /**
+ * A SlotName holds a std::string that is a valid name for a SLOT.
+ *
+ * \ingroup grpnames
+ */
+ typedef Validated<std::string, SlotNameValidator> SlotName;
+
+ /**
+ * A RepositoryNameError is thrown if an invalid value is assigned to
+ * a RepositoryName.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grpnames
+ */
+ class RepositoryNameError : public NameError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ RepositoryNameError(const std::string & name) throw ();
+ };
+
+ /**
+ * A RepositoryNameValidator handles validation rules for the value
+ * of a RepositoryName.
+ *
+ * \ingroup grpnames
+ */
+ struct RepositoryNameValidator :
+ private InstantiationPolicy<RepositoryNameValidator, instantiation_method::NonInstantiableTag>
+ {
+ /**
+ * If the parameter is not a valid value for a RepositoryName,
+ * throw a RepositoryNameError.
+ */
+ static void validate(const std::string &);
+ };
+
+ /**
+ * A RepositoryNamePart holds a std::string that is a valid name for a
+ * Repository.
+ *
+ * \ingroup grpnames
+ */
+ typedef Validated<std::string, RepositoryNameValidator> RepositoryName;
+
+ /**
+ * Holds a collection of RepositoryName instances.
+ *
+ * \ingroup grpnames
+ */
+ typedef SequentialCollection<RepositoryName> RepositoryNameCollection;
+
+ /**
+ * A KeywordNameValidator handles validation rules for the value of a
+ * UseFlagName.
+ *
+ * \ingroup grpnames
+ */
+ struct KeywordNameValidator :
+ private InstantiationPolicy<KeywordNameValidator, instantiation_method::NonInstantiableTag>
+ {
+ /**
+ * If the parameter is not a valid value for a KeywordName,
+ * throw a KeywordNameError.
+ */
+ static void validate(const std::string &);
+ };
+
+ /**
+ * A KeywordNameError is thrown if an invalid value is assigned to
+ * a KeywordNameName.
+ *
+ * \ingroup grpnames
+ * \ingroup grpexceptions
+ */
+ class KeywordNameError : public NameError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ KeywordNameError(const std::string & name) throw ();
+ };
+
+ /**
+ * A KeywordName holds a std::string that is a valid name for a KEYWORD.
+ *
+ * \ingroup grpnames
+ */
+ typedef Validated<std::string, KeywordNameValidator> KeywordName;
+
+ /**
+ * A USE flag can be on, off or unspecified.
+ *
+ * \ingroup grpnames
+ */
+ enum UseFlagState
+ {
+ use_unspecified, /// unspecified
+ use_disabled, /// disabled
+ use_enabled /// enabled
+ };
+}
+
+#endif
diff --git a/0.4.0/paludis/name_TEST.cc b/0.4.0/paludis/name_TEST.cc
new file mode 100644
index 000000000..c3a9e5a0b
--- /dev/null
+++ b/0.4.0/paludis/name_TEST.cc
@@ -0,0 +1,209 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/name.hh>
+#include <paludis/util/exception.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for QualifiedPackageName.
+ *
+ * \ingroup grptestcases
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Basic QualifiedPackageName tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct QualifiedPackageNameTest : TestCase
+ {
+ QualifiedPackageNameTest() : TestCase("basic") { }
+
+ void run()
+ {
+ QualifiedPackageName a("foo/bar1");
+ TEST_CHECK(true);
+ }
+ } test_qualified_package_name;
+
+ /**
+ * \test Validate QualifiedPackageName tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct QualifiedPackageNameValidateTest : TestCase
+ {
+ QualifiedPackageNameValidateTest() : TestCase("validate") { }
+
+ void run()
+ {
+ QualifiedPackageName a("foo/bar");
+ TEST_CHECK_THROWS(a = QualifiedPackageName("moo"), NameError);
+ TEST_CHECK_THROWS(a = QualifiedPackageName("foo/bar!"), NameError);
+ TEST_CHECK_THROWS(a = QualifiedPackageName("foo/bar/baz"), NameError);
+ }
+ } test_qualified_package_name_validate;
+
+ /**
+ * \test Compare QualifiedPackageName tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct QualifiedPackageNameCompareTest : TestCase
+ {
+ QualifiedPackageNameCompareTest() : TestCase("compare") { }
+
+ void run()
+ {
+ QualifiedPackageName foo1_bar1("foo1/bar1");
+ QualifiedPackageName foo1_bar2("foo1/bar2");
+ QualifiedPackageName foo2_bar1("foo2/bar1");
+
+ TEST_CHECK( (foo1_bar1 < foo1_bar2));
+ TEST_CHECK( (foo1_bar1 <= foo1_bar2));
+ TEST_CHECK(!(foo1_bar1 == foo1_bar2));
+ TEST_CHECK( (foo1_bar1 != foo1_bar2));
+ TEST_CHECK(!(foo1_bar1 >= foo1_bar2));
+ TEST_CHECK(!(foo1_bar1 > foo1_bar2));
+
+ TEST_CHECK(!(foo2_bar1 < foo1_bar2));
+ TEST_CHECK(!(foo2_bar1 <= foo1_bar2));
+ TEST_CHECK(!(foo2_bar1 == foo1_bar2));
+ TEST_CHECK( (foo2_bar1 != foo1_bar2));
+ TEST_CHECK( (foo2_bar1 >= foo1_bar2));
+ TEST_CHECK( (foo2_bar1 > foo1_bar2));
+ }
+ } test_qualified_package_name_compare;
+
+ /**
+ * \test Test CategoryNamePart creation.
+ *
+ * \ingroup grptestcases
+ */
+ struct CategoryNamePartCreationTest : public TestCase
+ {
+ CategoryNamePartCreationTest() : TestCase("creation") { }
+
+ void run()
+ {
+ CategoryNamePart p("foo");
+ TEST_CHECK(true);
+ }
+ } category_package_name_part_creation;
+
+ /**
+ * \test Test CategoryNamePart validation
+ *
+ * \ingroup grptestcases
+ */
+ struct CategoryNamePartValidationTest : public TestCase
+ {
+ CategoryNamePartValidationTest() : TestCase("validation") {}
+
+ void run()
+ {
+ CategoryNamePart p = CategoryNamePart("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-+_");
+
+ TEST_CHECK_THROWS(p = CategoryNamePart(""), CategoryNamePartError);
+ TEST_CHECK_THROWS(p = CategoryNamePart("*"), CategoryNamePartError);
+ TEST_CHECK_THROWS(p = CategoryNamePart("foo bar"), CategoryNamePartError);
+ }
+ } category_package_name_part_validation;
+
+ /**
+ * \test Test PackageNamePart creation.
+ *
+ * \ingroup grptestcases
+ */
+ struct PackageNamePartCreationTest : public TestCase
+ {
+ PackageNamePartCreationTest() : TestCase("creation") { }
+
+ void run()
+ {
+ PackageNamePart p("foo");
+ TEST_CHECK(true);
+ }
+ } test_package_name_part_creation;
+
+ /**
+ * \test Test PackageNamePart validation.
+ *
+ * \ingroup grptestcases
+ */
+ struct PackageNamePartValidationTest : public TestCase
+ {
+ PackageNamePartValidationTest() : TestCase("validation") { }
+
+ void run()
+ {
+ PackageNamePart p("foo-200dpi");
+ TEST_CHECK_THROWS(p = PackageNamePart(""), NameError);
+ TEST_CHECK_THROWS(p = PackageNamePart("!!!"), NameError);
+ TEST_CHECK_THROWS(p = PackageNamePart("foo-2"), NameError);
+ TEST_CHECK_THROWS(p = PackageNamePart("foo-200"), NameError);
+ }
+ } test_package_name_part_validation;
+
+ /**
+ * \test Test PackageNamePart comparison.
+ *
+ * \ingroup grptestcases
+ */
+ struct PackageNamePartComparisonTest : public TestCase
+ {
+ PackageNamePartComparisonTest() : TestCase("comparison") { }
+
+ void run()
+ {
+ PackageNamePart p1("p1");
+ PackageNamePart p2("p2");
+
+ TEST_CHECK( (p1 < p2));
+ TEST_CHECK( (p1 <= p2));
+ TEST_CHECK(!(p1 == p2));
+ TEST_CHECK(!(p1 > p2));
+ TEST_CHECK(!(p1 >= p2));
+ TEST_CHECK( (p1 != p2));
+
+ TEST_CHECK(!(p2 < p2));
+ TEST_CHECK( (p2 <= p2));
+ TEST_CHECK( (p2 == p2));
+ TEST_CHECK(!(p2 > p2));
+ TEST_CHECK( (p2 >= p2));
+ TEST_CHECK(!(p2 != p2));
+
+ TEST_CHECK(!(p2 < p1));
+ TEST_CHECK(!(p2 <= p1));
+ TEST_CHECK(!(p2 == p1));
+ TEST_CHECK( (p2 > p1));
+ TEST_CHECK( (p2 >= p1));
+ TEST_CHECK( (p2 != p1));
+ }
+ } test_package_name_part_comparison;
+
+}
+
diff --git a/0.4.0/paludis/nothing_repository.cc b/0.4.0/paludis/nothing_repository.cc
new file mode 100644
index 000000000..e7769997e
--- /dev/null
+++ b/0.4.0/paludis/nothing_repository.cc
@@ -0,0 +1,257 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+
+#include <paludis/nothing_repository.hh>
+#include <paludis/portage_dep_parser.hh>
+#include <paludis/syncer.hh>
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/tokeniser.hh>
+
+/** \file
+ * Implementation of NothingRepository.
+ *
+ * \ingroup grpnothingrepository
+ */
+
+using namespace paludis;
+
+namespace paludis
+{
+ /**
+ * Implementation data for a NothingRepository.
+ *
+ * \ingroup grpnothingrepository
+ */
+ template <>
+ struct Implementation<NothingRepository> :
+ InternalCounted<Implementation<NothingRepository> >
+ {
+ /// Our name
+ std::string name;
+
+ /// Our location
+ FSEntry location;
+
+ /// Sync URL
+ std::string sync;
+
+ /// Sync exclude file
+ std::string sync_exclude;
+
+ /// (Empty) provides map.
+ const std::map<QualifiedPackageName, QualifiedPackageName> provide_map;
+
+ /// Constructor.
+ Implementation(const NothingRepositoryParams &);
+
+ /// Destructor.
+ ~Implementation();
+ };
+}
+
+Implementation<NothingRepository>::Implementation(const NothingRepositoryParams & p) :
+ name(p.get<nrpk_name>()),
+ location(p.get<nrpk_location>()),
+ sync(p.get<nrpk_sync>()),
+ sync_exclude(p.get<nrpk_sync_exclude>())
+{
+}
+
+Implementation<NothingRepository>::~Implementation()
+{
+}
+
+NothingRepository::NothingRepository(const NothingRepositoryParams & p) try :
+ Repository(RepositoryName(p.get<nrpk_name>()),
+ RepositoryCapabilities::create((
+ param<repo_mask>(static_cast<MaskInterface *>(0)),
+ param<repo_installable>(static_cast<InstallableInterface *>(0)),
+ param<repo_installed>(static_cast<InstalledInterface *>(0)),
+ param<repo_news>(static_cast<NewsInterface *>(0)),
+ param<repo_sets>(static_cast<SetsInterface *>(0)),
+ param<repo_syncable>(this),
+ param<repo_uninstallable>(static_cast<UninstallableInterface *>(0)),
+ param<repo_use>(static_cast<UseInterface *>(0)),
+ param<repo_world>(static_cast<WorldInterface *>(0)),
+ param<repo_environment_variable>(static_cast<EnvironmentVariableInterface *>(0))
+ ))),
+ PrivateImplementationPattern<NothingRepository>(new Implementation<NothingRepository>(p))
+{
+ RepositoryInfoSection config_info("Configuration information");
+ config_info.add_kv("sync", _imp->sync);
+ config_info.add_kv("sync_exclude", _imp->sync_exclude);
+ config_info.add_kv("location", stringify(_imp->location));
+
+ _info->add_section(config_info);
+}
+catch (const NameError & e)
+{
+ Context context("When making Nothing repository '" + p.get<nrpk_name>() + "':");
+ throw NothingRepositoryConfigurationError("Caught NameError: " + e.message());
+}
+
+NothingRepository::~NothingRepository()
+{
+}
+
+bool
+NothingRepository::do_has_category_named(const CategoryNamePart &) const
+{
+ return false;
+}
+
+bool
+NothingRepository::do_has_package_named(const QualifiedPackageName &) const
+{
+ return false;
+}
+
+CategoryNamePartCollection::ConstPointer
+NothingRepository::do_category_names() const
+{
+ CategoryNamePartCollection::Pointer result(new CategoryNamePartCollection);
+ return result;
+}
+
+QualifiedPackageNameCollection::ConstPointer
+NothingRepository::do_package_names(const CategoryNamePart &) const
+{
+ QualifiedPackageNameCollection::Pointer result(new QualifiedPackageNameCollection);
+ return result;
+}
+
+VersionSpecCollection::ConstPointer
+NothingRepository::do_version_specs(const QualifiedPackageName &) const
+{
+ return VersionSpecCollection::Pointer(new VersionSpecCollection);
+}
+
+bool
+NothingRepository::do_has_version(const QualifiedPackageName &,
+ const VersionSpec &) const
+{
+ return false;
+}
+
+VersionMetadata::ConstPointer
+NothingRepository::do_version_metadata(
+ const QualifiedPackageName & q, const VersionSpec & v) const
+{
+ Log::get_instance()->message(ll_warning, lc_context, "has_version failed for request for '" +
+ stringify(q) + "-" + stringify(v) + "' in repository '" +
+ stringify(name()) + "'");
+ return VersionMetadata::ConstPointer(new VersionMetadata::Ebuild(
+ PortageDepParser::parse_depend));
+}
+
+CountedPtr<Repository>
+NothingRepository::make_nothing_repository(
+ const Environment * const,
+ const PackageDatabase * const,
+ const std::map<std::string, std::string> & m)
+{
+ std::string repo_file(m.end() == m.find("repo_file") ? std::string("?") :
+ m.find("repo_file")->second);
+
+ Context context("When making Nothing repository from repo_file '" + repo_file + "':");
+
+ std::string location;
+ if (m.end() == m.find("location") || ((location = m.find("location")->second)).empty())
+ throw NothingRepositoryConfigurationError("Key 'location' not specified or empty");
+
+ std::string sync;
+ if (m.end() == m.find("sync") || ((sync = m.find("sync")->second)).empty())
+ ; // nothing
+
+ std::string name;
+ if (m.end() == m.find("name") || ((name = m.find("name")->second)).empty())
+ throw NothingRepositoryConfigurationError("Key 'name' not specified or empty in '"
+ + repo_file + "'");
+
+ std::string sync_exclude;
+ if (m.end() == m.find("sync_exclude") || ((sync_exclude = m.find("sync_exclude")->second)).empty())
+ ; // nothing
+
+ return CountedPtr<Repository>(new NothingRepository(NothingRepositoryParams::create((
+ param<nrpk_name>(name),
+ param<nrpk_location>(location),
+ param<nrpk_sync>(sync),
+ param<nrpk_sync_exclude>(sync_exclude)))));
+}
+
+NothingRepositoryConfigurationError::NothingRepositoryConfigurationError(
+ const std::string & msg) throw () :
+ ConfigurationError("Nothing repository configuration error: " + msg)
+{
+}
+
+bool
+NothingRepository::do_is_licence(const std::string &) const
+{
+ return false;
+}
+
+bool
+NothingRepository::do_is_mirror(const std::string &) const
+{
+ return false;
+}
+
+bool
+NothingRepository::do_sync() const
+{
+ Context context("When syncing repository '" + stringify(name()) + "':");
+
+ if (_imp->sync.empty())
+ return false;
+
+ std::string::size_type p(_imp->sync.find("://")), q(_imp->sync.find(":"));
+ if (std::string::npos == p)
+ throw NoSuchSyncerError(_imp->sync);
+
+ SyncOptions opts(_imp->sync_exclude);
+
+ SyncerMaker::get_instance()->find_maker(_imp->sync.substr(0, std::min(p, q)))(
+ stringify(_imp->location), _imp->sync.substr(q < p ? q + 1 : 0))->sync(opts);
+
+ return true;
+}
+
+void
+NothingRepository::invalidate() const
+{
+}
+
+Repository::ProvideMapIterator
+NothingRepository::begin_provide_map() const
+{
+ return _imp->provide_map.begin();
+}
+
+Repository::ProvideMapIterator
+NothingRepository::end_provide_map() const
+{
+ return _imp->provide_map.end();
+}
+
diff --git a/0.4.0/paludis/nothing_repository.hh b/0.4.0/paludis/nothing_repository.hh
new file mode 100644
index 000000000..f862250c8
--- /dev/null
+++ b/0.4.0/paludis/nothing_repository.hh
@@ -0,0 +1,167 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_NOTHING_REPOSITORY_HH
+#define PALUDIS_GUARD_PALUDIS_NOTHING_REPOSITORY_HH 1
+
+#include <paludis/repository.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/smart_record.hh>
+
+/** \file
+ * Declarations for the NothingRepository class.
+ *
+ * \ingroup grpnothingrepository
+ */
+
+namespace paludis
+{
+ class PackageDatabase;
+ class FSEntry;
+
+ /**
+ * Keys for NothingRepositoryParams.
+ *
+ * \see NothingRepositoryParams
+ * \ingroup grpnothingrepository
+ */
+ enum NothingRepositoryParamsKeys
+ {
+ nrpk_name,
+ nrpk_location,
+ nrpk_sync,
+ nrpk_sync_exclude,
+ last_nrpk
+ };
+
+ /**
+ * Tag for NothingRepositoryParams.
+ *
+ * \see NothingRepositoryParams
+ * \ingroup grpnothingrepository
+ */
+ struct NothingRepositoryParamsTag :
+ SmartRecordTag<comparison_mode::NoComparisonTag, void>,
+ SmartRecordKeys<NothingRepositoryParamsKeys, last_nrpk>,
+ SmartRecordKey<nrpk_location, const FSEntry>,
+ SmartRecordKey<nrpk_name, const std::string>,
+ SmartRecordKey<nrpk_sync, const std::string>,
+ SmartRecordKey<nrpk_sync_exclude, const std::string>
+ {
+ };
+
+ /**
+ * Constructor parameters for NothingRepository.
+ *
+ * \see NothingRepository
+ * \ingroup grpnothingrepository
+ */
+ typedef MakeSmartRecord<NothingRepositoryParamsTag>::Type NothingRepositoryParams;
+
+ /**
+ * A NothingRepository is a Repository that has no content, but can be
+ * synced along with other repositories.
+ *
+ * \ingroup grpnothingrepository
+ */
+ class NothingRepository :
+ public Repository,
+ public Repository::SyncableInterface,
+ private PrivateImplementationPattern<NothingRepository>
+ {
+ protected:
+ virtual bool do_has_category_named(const CategoryNamePart &) const;
+
+ virtual bool do_has_package_named(const QualifiedPackageName &) const;
+
+ virtual CategoryNamePartCollection::ConstPointer do_category_names() const;
+
+ virtual QualifiedPackageNameCollection::ConstPointer do_package_names(
+ const CategoryNamePart &) const;
+
+ virtual VersionSpecCollection::ConstPointer do_version_specs(
+ const QualifiedPackageName &) const;
+
+ virtual bool do_has_version(const QualifiedPackageName &, const VersionSpec &) const;
+
+ virtual VersionMetadata::ConstPointer do_version_metadata(
+ const QualifiedPackageName &,
+ const VersionSpec &) const;
+
+ virtual bool do_is_licence(const std::string &) const;
+
+ virtual bool do_is_mirror(const std::string &) const;
+
+ virtual bool do_sync() const;
+
+ public:
+ /**
+ * Constructor.
+ */
+ NothingRepository(const NothingRepositoryParams &);
+
+ /**
+ * Virtual constructor.
+ */
+ static CountedPtr<Repository> make_nothing_repository(
+ const Environment * const env,
+ const PackageDatabase * const db,
+ const std::map<std::string, std::string> &);
+
+ /**
+ * Destructor.
+ */
+ ~NothingRepository();
+
+ virtual void invalidate() const;
+
+ virtual ProvideMapIterator begin_provide_map() const;
+
+ virtual ProvideMapIterator end_provide_map() const;
+
+ typedef CountedPtr<NothingRepository, count_policy::InternalCountTag> Pointer;
+ typedef CountedPtr<const NothingRepository, count_policy::InternalCountTag> ConstPointer;
+ };
+
+ /**
+ * Thrown if invalid parameters are provided for
+ * NothingRepository::make_nothing_repository.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grpnothingrepository
+ */
+ class NothingRepositoryConfigurationError : public ConfigurationError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ NothingRepositoryConfigurationError(const std::string & msg) throw ();
+ };
+
+ /**
+ * Register NothingRepository.
+ */
+ static const RepositoryMaker::RegisterMaker register_nothing_repository(
+ "nothing", &NothingRepository::make_nothing_repository);
+
+}
+
+
+#endif
diff --git a/0.4.0/paludis/package_database.cc b/0.4.0/paludis/package_database.cc
new file mode 100644
index 000000000..ff74a6582
--- /dev/null
+++ b/0.4.0/paludis/package_database.cc
@@ -0,0 +1,245 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/dep_atom.hh>
+#include <paludis/match_package.hh>
+#include <paludis/package_database.hh>
+#include <paludis/util/iterator.hh>
+#include <paludis/util/stringify.hh>
+
+#include <list>
+#include <map>
+#include <set>
+
+/** \file
+ * Implementation of PackageDatabase.
+ */
+
+using namespace paludis;
+
+std::ostream &
+paludis::operator<< (std::ostream & s, const PackageDatabaseEntry & v)
+{
+ s << v.get<pde_name>() << "-" << v.get<pde_version>() << "::" << v.get<pde_repository>();
+ return s;
+}
+
+PackageDatabaseError::PackageDatabaseError(const std::string & message) throw () :
+ Exception(message)
+{
+}
+
+PackageDatabaseLookupError::PackageDatabaseLookupError(const std::string & message) throw () :
+ PackageDatabaseError(message)
+{
+}
+
+DuplicateRepositoryError::DuplicateRepositoryError(const std::string & name) throw () :
+ PackageDatabaseError("A repository named '" + name + "' already exists")
+{
+}
+
+NoSuchPackageError::NoSuchPackageError(const std::string & name) throw () :
+ PackageDatabaseLookupError("Could not find '" + name + "'"),
+ _name(name)
+{
+}
+
+NoSuchRepositoryError::NoSuchRepositoryError(const std::string & name) throw () :
+ PackageDatabaseLookupError("Could not find repository '" + name + "'")
+{
+}
+
+NoSuchVersionError::NoSuchVersionError(const std::string & name,
+ const VersionSpec & version) throw () :
+ PackageDatabaseLookupError("No version of '" + name + "' named '" + stringify(version) + "'")
+{
+}
+
+namespace paludis
+{
+ /**
+ * Implementation data for a PackageDatabase.
+ *
+ * \ingroup grppackagedatabase
+ */
+ template<>
+ struct Implementation<PackageDatabase> :
+ InternalCounted<Implementation<PackageDatabase> >
+ {
+ /**
+ * Our Repository instances.
+ */
+ std::list<Repository::ConstPointer> repositories;
+
+ /// Our environment.
+ const Environment * environment;
+ };
+}
+PackageDatabase::PackageDatabase(const Environment * const e) :
+ PrivateImplementationPattern<PackageDatabase>(new Implementation<PackageDatabase>)
+{
+ _imp->environment = e;
+}
+
+PackageDatabase::~PackageDatabase()
+{
+}
+
+void
+PackageDatabase::add_repository(const Repository::ConstPointer r)
+{
+ Context c("When adding a repository named '" + stringify(r->name()) + "':");
+
+ IndirectIterator<std::list<Repository::ConstPointer>::const_iterator, const Repository>
+ r_c(_imp->repositories.begin()),
+ r_end(_imp->repositories.end());
+ for ( ; r_c != r_end ; ++r_c)
+ if (r_c->name() == r->name())
+ throw DuplicateRepositoryError(stringify(r->name()));
+
+ _imp->repositories.push_back(r);
+}
+
+QualifiedPackageName
+PackageDatabase::fetch_unique_qualified_package_name(
+ const PackageNamePart & p) const
+{
+ QualifiedPackageNameCollection::Pointer result(new QualifiedPackageNameCollection);
+
+ IndirectIterator<std::list<Repository::ConstPointer>::const_iterator, const Repository>
+ r(_imp->repositories.begin()),
+ r_end(_imp->repositories.end());
+ for ( ; r != r_end ; ++r)
+ {
+ CategoryNamePartCollection::ConstPointer cats(r->category_names());
+ CategoryNamePartCollection::Iterator c(cats->begin()), c_end(cats->end());
+ for ( ; c != c_end ; ++c)
+ if (r->has_package_named(*c + p))
+ result->insert(*c + p);
+ }
+
+ if (result->empty())
+ throw NoSuchPackageError(stringify(p));
+ if (result->size() > 1)
+ throw AmbiguousPackageNameError(stringify(p), result->begin(), result->end());
+
+ return *(result->begin());
+}
+
+PackageDatabaseEntryCollection::Pointer
+PackageDatabase::_do_query(const PackageDepAtom & a, const InstallState installed_state) const
+{
+ PackageDatabaseEntryCollection::Pointer result(new PackageDatabaseEntryCollection);
+
+ IndirectIterator<std::list<Repository::ConstPointer>::const_iterator, const Repository>
+ r(_imp->repositories.begin()),
+ r_end(_imp->repositories.end());
+ for ( ; r != r_end ; ++r)
+ {
+ if ((installed_state == is_installed_only) && ! r->get_interface<repo_installed>())
+ continue;
+
+ if ((installed_state == is_uninstalled_only) && r->get_interface<repo_installed>())
+ continue;
+
+ if (! r->has_category_named(a.package().get<qpn_category>()))
+ continue;
+
+ if (! r->has_package_named(a.package()))
+ continue;
+
+ VersionSpecCollection::ConstPointer versions(r->version_specs(a.package()));
+ VersionSpecCollection::Iterator v(versions->begin()), v_end(versions->end());
+ for ( ; v != v_end ; ++v)
+ {
+ PackageDatabaseEntry e(a.package(), *v, r->name());
+ if (! match_package(_imp->environment, a, e))
+ continue;
+
+ result->insert(e);
+ }
+ }
+
+ return result;
+}
+
+PackageDatabaseEntryCollection::Pointer
+PackageDatabase::query(const PackageDepAtom & a, const InstallState s) const
+{
+ return _do_query(a, s);
+}
+
+Repository::ConstPointer
+PackageDatabase::fetch_repository(const RepositoryName & n) const
+{
+ std::list<Repository::ConstPointer>::const_iterator
+ r(_imp->repositories.begin()),
+ r_end(_imp->repositories.end());
+ for ( ; r != r_end ; ++r)
+ if ((*r)->name() == n)
+ return *r;
+
+ throw NoSuchRepositoryError(stringify(n));
+}
+
+const RepositoryName &
+PackageDatabase::better_repository(const RepositoryName & r1,
+ const RepositoryName & r2) const
+{
+ IndirectIterator<std::list<Repository::ConstPointer>::const_iterator, const Repository>
+ r(_imp->repositories.begin()),
+ r_end(_imp->repositories.end());
+ for ( ; r != r_end ; ++r)
+ {
+ if (r->name() == r1)
+ return r2;
+ else if (r->name() == r2)
+ return r1;
+ }
+
+ throw InternalError(PALUDIS_HERE, "better_repository called on non-owned repositories");
+}
+
+RepositoryName
+PackageDatabase::favourite_repository() const
+{
+ if (_imp->repositories.empty())
+ return RepositoryName("unnamed");
+ else
+ return (*_imp->repositories.begin())->name();
+}
+
+PackageDatabaseEntryCollection::Pointer
+PackageDatabase::query(PackageDepAtom::ConstPointer a, const InstallState s) const
+{
+ return _do_query(*a.raw_pointer(), s);
+}
+
+PackageDatabase::RepositoryIterator
+PackageDatabase::begin_repositories() const
+{
+ return _imp->repositories.begin();
+}
+
+PackageDatabase::RepositoryIterator
+PackageDatabase::end_repositories() const
+{
+ return _imp->repositories.end();
+}
diff --git a/0.4.0/paludis/package_database.hh b/0.4.0/paludis/package_database.hh
new file mode 100644
index 000000000..00faf84b5
--- /dev/null
+++ b/0.4.0/paludis/package_database.hh
@@ -0,0 +1,341 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_PACKAGE_DATABASE_HH
+#define PALUDIS_GUARD_PALUDIS_PACKAGE_DATABASE_HH 1
+
+#include <paludis/dep_atom.hh>
+#include <paludis/name.hh>
+#include <paludis/repository.hh>
+#include <paludis/util/counted_ptr.hh>
+#include <paludis/util/exception.hh>
+#include <paludis/util/iterator.hh>
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/util/join.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/smart_record.hh>
+#include <paludis/util/collection.hh>
+#include <paludis/version_metadata.hh>
+#include <paludis/version_spec.hh>
+#include <paludis/package_database_entry.hh>
+#include <paludis/contents.hh>
+
+#include <ostream>
+#include <algorithm>
+#include <functional>
+#include <iterator>
+
+/** \file
+ * Declarations for the PackageDatabase class and related utilities.
+ *
+ * \ingroup grppackagedatabase
+ */
+
+namespace paludis
+{
+ class PackageDepAtom;
+ class Environment;
+
+ /**
+ * A PackageDatabaseError is an error that occurs when performing some
+ * operation upon a PackageDatabase.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grppackagedatabase
+ */
+ class PackageDatabaseError : public Exception
+ {
+ protected:
+ /**
+ * Constructor.
+ */
+ PackageDatabaseError(const std::string & message) throw ();
+ };
+
+ /**
+ * A PackageDatabaseLookupError descendent is thrown if an error occurs
+ * when looking for something in a PackageDatabase.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grppackagedatabase
+ */
+ class PackageDatabaseLookupError : public PackageDatabaseError
+ {
+ protected:
+ /**
+ * Constructor.
+ */
+ PackageDatabaseLookupError(const std::string & message) throw ();
+ };
+
+ /**
+ * Thrown if a PackageDatabase query results in more than one matching
+ * Package.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grppackagedatabase
+ */
+ class AmbiguousPackageNameError : public PackageDatabaseLookupError
+ {
+ private:
+ std::string _name;
+ std::list<std::string> _names;
+
+ public:
+ /**
+ * Constructor.
+ */
+ template <typename I_>
+ AmbiguousPackageNameError(const std::string & name,
+ I_ begin, const I_ end) throw ();
+
+ /**
+ * Destructor.
+ */
+ virtual ~AmbiguousPackageNameError() throw ()
+ {
+ }
+
+ /**
+ * The name of the package.
+ */
+ const std::string & name() const
+ {
+ return _name;
+ }
+
+ /**
+ * Iterator over possible matches.
+ */
+ typedef std::list<std::string>::const_iterator OptionsIterator;
+
+ /**
+ * Start of our options.
+ */
+ OptionsIterator begin_options() const
+ {
+ return _names.begin();
+ }
+
+ /**
+ * Past the end of our options.
+ */
+ OptionsIterator end_options() const
+ {
+ return _names.end();
+ }
+ };
+
+ template <typename I_>
+ AmbiguousPackageNameError::AmbiguousPackageNameError(const std::string & name,
+ I_ begin, const I_ end) throw () :
+ PackageDatabaseLookupError("Ambiguous package name '" + name + "' (candidates are " +
+ join(begin, end, ", ") + ")"),
+ _name(name)
+ {
+ std::transform(begin, end, std::back_inserter(_names),
+ &stringify<typename std::iterator_traits<I_>::value_type>);
+ }
+
+ /**
+ * Thrown if a Repository with the same name as an existing member is added
+ * to a PackageDatabase.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grppackagedatabase
+ */
+ class DuplicateRepositoryError : public PackageDatabaseError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ DuplicateRepositoryError(const std::string & name) throw ();
+ };
+
+ /**
+ * Thrown if there is no Package in a PackageDatabase with the given
+ * name.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grppackagedatabase
+ */
+ class NoSuchPackageError : public PackageDatabaseLookupError
+ {
+ private:
+ std::string _name;
+
+ public:
+ /**
+ * Constructor.
+ */
+ NoSuchPackageError(const std::string & name) throw ();
+
+ /**
+ * Destructor.
+ */
+ virtual ~NoSuchPackageError() throw ()
+ {
+ }
+
+ /**
+ * Name of the package.
+ */
+ const std::string & name() const
+ {
+ return _name;
+ }
+ };
+
+ /**
+ * Thrown if there is no Repository in a RepositoryDatabase with the given
+ * name.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grppackagedatabase
+ */
+ class NoSuchRepositoryError : public PackageDatabaseLookupError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ NoSuchRepositoryError(const std::string & name) throw ();
+ };
+
+ /**
+ * Thrown if there is no Version in a PackageDatabase with the given
+ * name.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grppackagedatabase
+ */
+ class NoSuchVersionError : public PackageDatabaseLookupError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ NoSuchVersionError(const std::string & pkg_name,
+ const VersionSpec & version) throw ();
+ };
+
+ /**
+ * Do we want installed, uninstalled or either when querying?
+ *
+ * \ingroup grppackagedatabase
+ */
+ enum InstallState
+ {
+ is_installed_only, ///< Installed only
+ is_uninstalled_only, ///< Uninstalled only
+ is_either ///< Either
+ };
+
+ /**
+ * A PackageDatabase can be queried for Package instances.
+ *
+ * \ingroup grppackagedatabase
+ */
+ class PackageDatabase :
+ private PrivateImplementationPattern<PackageDatabase>,
+ private InstantiationPolicy<PackageDatabase, instantiation_method::NonCopyableTag>,
+ public InternalCounted<PackageDatabase>
+ {
+ private:
+ PackageDatabaseEntryCollection::Pointer _do_query(
+ const PackageDepAtom & a, const InstallState) const;
+
+ public:
+ /**
+ * Constructor.
+ */
+ explicit PackageDatabase(const Environment * const);
+
+ /**
+ * Destructor.
+ */
+ ~PackageDatabase();
+
+ /**
+ * Add a repository.
+ *
+ * \exception DuplicateRepositoryError if a Repository with the
+ * same name as the new Repository already exists in our
+ * collection.
+ */
+ void add_repository(Repository::ConstPointer);
+
+ /**
+ * Fetch a named repository.
+ */
+ Repository::ConstPointer fetch_repository(const RepositoryName &) const;
+
+ /**
+ * Fetch the name of our 'favourite' repository (if a repository's
+ * name matches this when doing a graphical display, the repository
+ * name part may be omitted).
+ */
+ RepositoryName favourite_repository() const;
+
+ /**
+ * Disambiguate a package name.
+ */
+ QualifiedPackageName fetch_unique_qualified_package_name(
+ const PackageNamePart &) const;
+
+ /**
+ * Query the repository.
+ */
+ PackageDatabaseEntryCollection::Pointer query(
+ const PackageDepAtom & a,
+ const InstallState) const;
+
+ /**
+ * Query the repository (overload for a CountedPtr)
+ */
+ PackageDatabaseEntryCollection::Pointer query(
+ PackageDepAtom::ConstPointer a,
+ const InstallState) const;
+
+ /**
+ * Which repository is better?
+ */
+ const RepositoryName & better_repository(const RepositoryName &,
+ const RepositoryName &) const;
+
+ /**
+ * Iterate over all of our repositories.
+ */
+ typedef std::list<Repository::ConstPointer>::const_iterator RepositoryIterator;
+
+ /**
+ * Iterator to the start of our repositories.
+ */
+ RepositoryIterator begin_repositories() const;
+
+ /**
+ * Iterator to past the end of our repositories.
+ */
+ RepositoryIterator end_repositories() const;
+ };
+}
+
+#endif
diff --git a/0.4.0/paludis/package_database_TEST.cc b/0.4.0/paludis/package_database_TEST.cc
new file mode 100644
index 000000000..b8fd41031
--- /dev/null
+++ b/0.4.0/paludis/package_database_TEST.cc
@@ -0,0 +1,197 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/paludis.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace paludis;
+using namespace test;
+
+/** \file
+ * Test cases for package_database.hh.
+ *
+ * \ingroup grptestcases
+ */
+
+namespace test_cases
+{
+ /**
+ * \test PackageDatabase repository tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct PackageDatabaseRepositoryTest : TestCase
+ {
+ PackageDatabaseRepositoryTest() : TestCase("package database repository") { }
+
+ void run()
+ {
+ TestEnvironment e;
+ PackageDatabase & p(*e.package_database());
+
+ FakeRepository::Pointer r1(new FakeRepository(RepositoryName("repo1")));
+ FakeRepository::Pointer r2(new FakeRepository(RepositoryName("repo2")));
+
+ TEST_CHECK_THROWS(p.fetch_repository(RepositoryName("repo1")), PackageDatabaseLookupError);
+ TEST_CHECK_THROWS(p.fetch_repository(RepositoryName("repo2")), PackageDatabaseLookupError);
+
+ p.add_repository(r1);
+ TEST_CHECK(p.fetch_repository(RepositoryName("repo1")));
+ TEST_CHECK_EQUAL(p.fetch_repository(RepositoryName("repo1"))->name(),
+ RepositoryName("repo1"));
+ TEST_CHECK_THROWS(p.fetch_repository(RepositoryName("repo2")), PackageDatabaseLookupError);
+
+ TEST_CHECK_THROWS(p.add_repository(r1), DuplicateRepositoryError);
+
+ p.add_repository(r2);
+ TEST_CHECK(p.fetch_repository(RepositoryName("repo1")));
+ TEST_CHECK_EQUAL(p.fetch_repository(RepositoryName("repo1"))->name(),
+ RepositoryName("repo1"));
+ TEST_CHECK(p.fetch_repository(RepositoryName("repo2")));
+ TEST_CHECK_EQUAL(p.fetch_repository(RepositoryName("repo2"))->name(),
+ RepositoryName("repo2"));
+
+ TEST_CHECK_THROWS(p.add_repository(r1), DuplicateRepositoryError);
+ TEST_CHECK_THROWS(p.add_repository(r2), DuplicateRepositoryError);
+
+ TEST_CHECK(p.fetch_repository(RepositoryName("repo1")));
+ TEST_CHECK_EQUAL(p.fetch_repository(RepositoryName("repo1"))->name(),
+ RepositoryName("repo1"));
+ TEST_CHECK(p.fetch_repository(RepositoryName("repo2")));
+ TEST_CHECK_EQUAL(p.fetch_repository(RepositoryName("repo2"))->name(),
+ RepositoryName("repo2"));
+
+ TEST_CHECK_EQUAL(p.better_repository(RepositoryName("repo1"), RepositoryName("repo2")),
+ RepositoryName("repo2"));
+ TEST_CHECK_EQUAL(p.better_repository(RepositoryName("repo2"), RepositoryName("repo1")),
+ RepositoryName("repo2"));
+ TEST_CHECK_EQUAL(p.better_repository(RepositoryName("repo2"), RepositoryName("repo2")),
+ RepositoryName("repo2"));
+ TEST_CHECK_EQUAL(p.better_repository(RepositoryName("repo1"), RepositoryName("repo1")),
+ RepositoryName("repo1"));
+ }
+ } package_database_repository_test;
+
+ /**
+ * \test PackageDatabase query tests.
+ *
+ * \ingroup grptestcases