cupt-2.10.0/0000755000000000000000000000000013204267373007442 5ustar cupt-2.10.0/.gitignore0000644000000000000000000000020313204267373011425 0ustar CMakeFiles/ CMakeCache.txt *.cmake Makefile !/doc/examples/show-upgradeable/Makefile *.gch *.so *.so.* *.bin install_manifest.txt cupt-2.10.0/CMakeLists.txt0000644000000000000000000000021413204267373012177 0ustar cmake_minimum_required(VERSION 2.6) project(Cupt) add_subdirectory(cpp) add_subdirectory(doc) add_subdirectory(po) add_subdirectory(test) cupt-2.10.0/cpp/0000755000000000000000000000000013204267373010224 5ustar cupt-2.10.0/cpp/CMakeLists.txt0000644000000000000000000000140013204267373012757 0ustar IF(NOT EXISTS /usr/include/boost/xpressive/xpressive_dynamic.hpp) message(FATAL_ERROR "missing Boost.Xpressive library") ENDIF() IF(NOT EXISTS /usr/include/boost/program_options.hpp) message(FATAL_ERROR "missing Boost.ProgramOptions library") ENDIF() find_package(Boost 1.42.0) IF(Boost_FOUND) IF(Boost_VERSION LESS 104200) message(FATAL_ERROR "need Boost of version 1.42.0") ENDIF(Boost_VERSION LESS 104200) ELSE() message(FATAL_ERROR "missing Boost") ENDIF() IF(NOT EXISTS /usr/include/readline/readline.h) message(FATAL_ERROR "missing GNU Readline library") ENDIF() OPTION(LOCAL "is build local" ON) include(flags.cmake) include(version.cmake) include_directories(.) add_subdirectory(console) add_subdirectory(lib) add_subdirectory(downloadmethods) cupt-2.10.0/cpp/common/0000755000000000000000000000000013204267373011514 5ustar cupt-2.10.0/cpp/common/common.hpp0000644000000000000000000000030613204267373013514 0ustar #define FORIT(variableName, storage) for (auto variableName = (storage).begin(), variableName##End = (storage).end(); variableName != variableName##End; ++variableName) #include cupt-2.10.0/cpp/common/regex.hpp0000644000000000000000000000337413204267373013346 0ustar /************************************************************************** * Copyright (C) 2010 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #ifndef CUPT_COMMON_REGEX_SEEN #define CUPT_COMMON_REGEX_SEEN #include namespace cupt { using boost::xpressive::sregex; using boost::xpressive::sregex_token_iterator; using boost::xpressive::smatch; using boost::xpressive::cregex; using boost::xpressive::cmatch; using boost::xpressive::regex_match; using boost::xpressive::regex_search; using boost::xpressive::regex_error; namespace regex_constants = boost::xpressive::regex_constants; } #endif cupt-2.10.0/cpp/console/0000755000000000000000000000000013204267373011666 5ustar cupt-2.10.0/cpp/console/CMakeLists.txt0000644000000000000000000000106013204267373014423 0ustar include_directories(../lib/include) add_executable(cupt.bin common.cpp common.hpp cupt.cpp cupt.hpp misc.cpp misc.hpp handlers.hpp handlers/search.cpp handlers/misc.cpp handlers/managepackages.cpp handlers/shell.cpp handlers/download.cpp handlers/snapshot.cpp handlers/why.cpp colorizer.cpp colorizer.hpp functionselectors.cpp functionselectors.hpp selectors.cpp selectors.hpp ) set_property(TARGET cupt.bin PROPERTY OUTPUT_NAME cupt) target_link_libraries(cupt.bin libcupt boost_program_options) install(TARGETS cupt.bin DESTINATION bin) cupt-2.10.0/cpp/console/colorizer.cpp0000644000000000000000000000453213204267373014406 0ustar /************************************************************************** * Copyright (C) 2011 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #include #include #include "colorizer.hpp" const string noColor = "\e[0m"; Colorizer::Colorizer(const Config& config) { string optionName("cupt::console::use-colors"); auto stringEnabledValue = config.getString(optionName); if (stringEnabledValue != "auto") { __enabled = config.getBool(optionName); } else // guessing... { __enabled = false; if (isatty(STDOUT_FILENO)) { const char* term = getenv("TERM"); if (term) { if (strcmp(term, "xterm") == 0 || strcmp(term, "linux") == 0) { __enabled = true; } } } } } string Colorizer::makeBold(const string& input) const { if (__enabled) { return string("\e[1m") + input + noColor; } else { return input; } } string Colorizer::colorize(const string& input, Color color, bool bold) const { if (color == Default) { return bold ? makeBold(input) : input; } if (__enabled) { auto boldPrefix = bold ? "1;" : ""; return format2("\e[%s3%cm", boldPrefix, color) + input + noColor; } else { return input; } } bool Colorizer::enabled() const { return __enabled; } cupt-2.10.0/cpp/console/colorizer.hpp0000644000000000000000000000323313204267373014410 0ustar /************************************************************************** * Copyright (C) 2011 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #ifndef COLORIZER_SEEN #define COLORIZER_SEEN #include "common.hpp" class Colorizer { bool __enabled; public: enum Color { Default = ' ', Red = '1', Green = '2', Blue = '4', Yellow = '3', Cyan = '6', Magenta = '5' }; Colorizer(const Config& config); string makeBold(const string& input) const; string colorize(const string& input, Color, bool bold) const; bool enabled() const; }; #endif cupt-2.10.0/cpp/console/common.cpp0000644000000000000000000001222113204267373013660 0ustar /************************************************************************** * Copyright (C) 2012 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #include "common.hpp" #include #include #include bool isPackageInstalled(const Cache& cache, const string& packageName) { auto&& installedInfo = cache.getSystemState()->getInstalledInfo(packageName); return (installedInfo && installedInfo->status != system::State::InstalledRecord::Status::ConfigFiles); } template < typename VersionT > ReverseDependsIndex< VersionT >::ReverseDependsIndex(const Cache& cache) : __cache(cache), __architecture(cache.getSystemState()->getArchitecture()) {} template < typename VersionT > void ReverseDependsIndex< VersionT >::add(RelationTypeT relationType) { auto insertResult = __data.insert({ relationType, PerRelationType() }); if (insertResult.second) { __add(relationType, &insertResult.first->second); } } namespace { template < typename T > struct TraitsPlus; template<> struct TraitsPlus< BinaryVersion > { static Range< Cache::PackageNameIterator > getPackageNames(const Cache& cache) { return cache.getBinaryPackageNames(); }; static const BinaryPackage* getPackage(const Cache& cache, const string& packageName) { return cache.getBinaryPackage(packageName); } }; template<> struct TraitsPlus< SourceVersion > { static Range< Cache::PackageNameIterator > getPackageNames(const Cache& cache) { return cache.getSourcePackageNames(); }; static const SourcePackage* getPackage(const Cache& cache, const string& packageName) { return cache.getSourcePackage(packageName); }; }; } template < typename VersionT > const RelationLine& ReverseDependsIndex< VersionT >::__getRelationLine(const RelationLine& rl) const { return rl; } template < typename VersionT > RelationLine ReverseDependsIndex< VersionT >::__getRelationLine(const ArchitecturedRelationLine& arl) const { return arl.toRelationLine(__architecture); } template < typename VersionT > void ReverseDependsIndex< VersionT >::__add(RelationTypeT relationType, PerRelationType* storage) { typedef TraitsPlus< VersionT > TP; for (const string& packageName: TP::getPackageNames(__cache)) { auto package = TP::getPackage(__cache, packageName); for (const auto& version: *package) { auto&& relationLine = __getRelationLine(version->relations[relationType]); for (const auto& relationExpression: relationLine) { auto satisfyingVersions = __cache.getSatisfyingVersions(relationExpression); for (const auto& satisfyingVersion: satisfyingVersions) { const string& satisfyingPackageName = satisfyingVersion->packageName; auto& packageList = (*storage)[satisfyingPackageName]; if (packageList.back() != package) { packageList.push_back(package); } } } } } } template < typename VersionT > void ReverseDependsIndex< VersionT >::foreachReverseDependency( const BinaryVersion* version, RelationTypeT relationType, const std::function< void (const VersionT*, const RelationExpression&) > callback) { auto storageIt = __data.find(relationType); if (storageIt == __data.end()) return; const auto& storage = storageIt->second; auto packageCandidatesIt = storage.find(version->packageName); if (packageCandidatesIt != storage.end()) { const auto& packageCandidates = packageCandidatesIt->second; for (auto packageCandidate: packageCandidates) { for (const auto& candidateVersion: *packageCandidate) { auto&& relationLine = __getRelationLine(candidateVersion->relations[relationType]); for (const auto& relationExpression: relationLine) { auto satisfyingVersions = __cache.getSatisfyingVersions(relationExpression); for (const auto& satisfyingVersion: satisfyingVersions) { if (satisfyingVersion == version) { callback(candidateVersion, relationExpression); goto candidate; } } } candidate: ; } } } } template class ReverseDependsIndex< BinaryVersion >; template class ReverseDependsIndex< SourceVersion >; cupt-2.10.0/cpp/console/common.hpp0000644000000000000000000000562713204267373013701 0ustar /************************************************************************** * Copyright (C) 2010 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #ifndef COMMON_SEEN #define COMMON_SEEN #include using std::unordered_map; #include using std::list; #include #include #include #include #include #include using namespace cupt; using namespace cupt::cache; using namespace cupt::system; using namespace cupt::download; template < typename T > struct VersionTraits; template<> struct VersionTraits< BinaryVersion > { typedef BinaryPackage PackageT; typedef BinaryVersion::RelationTypes::Type RelationTypeT; }; template<> struct VersionTraits< SourceVersion > { typedef SourcePackage PackageT; typedef SourceVersion::RelationTypes::Type RelationTypeT; }; template < typename VersionT > class ReverseDependsIndex { typedef VersionTraits< VersionT > VT; typedef typename VT::PackageT PackageT; typedef typename VT::RelationTypeT RelationTypeT; typedef unordered_map< string, list< const PackageT* > > PerRelationType; const Cache& __cache; map< RelationTypeT, PerRelationType > __data; const string __architecture; void __add(RelationTypeT relationType, PerRelationType*); const RelationLine& __getRelationLine(const RelationLine&) const; RelationLine __getRelationLine(const ArchitecturedRelationLine&) const; public: ReverseDependsIndex(const Cache&); void add(RelationTypeT relationType); void foreachReverseDependency( const BinaryVersion* version, RelationTypeT relationType, const std::function< void (const VersionT*, const RelationExpression&) > callback); }; bool isPackageInstalled(const Cache&, const string& packageName); #endif cupt-2.10.0/cpp/console/cupt.cpp0000644000000000000000000001316513204267373013353 0ustar /************************************************************************** * Copyright (C) 2010-2011 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #include #include using std::cout; using std::endl; #include #include "cupt.hpp" #include "misc.hpp" #include "version.hpp" void showOwnVersion(); void showHelp(const char*); int main(int argc, char* argv[]) { setlocale(LC_ALL, ""); cupt::messageFd = STDERR_FILENO; Context context; return mainEx(argc, argv, context); } namespace { bool showHelpOrOwnVersion(int argc, char* argv[]) { if (argc > 1) { if (!strcmp(argv[1], "version") || !strcmp(argv[1], "--version") || !strcmp(argv[1], "-v")) { if (argc > 2) { warn2(__("the command '%s' doesn't accept arguments"), argv[1]); } showOwnVersion(); return true; } if (!strcmp(argv[1], "help") || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) { if (argc > 2) { warn2(__("the command '%s' doesn't accept arguments"), argv[1]); } showHelp(argv[0]); return true; } } else { showHelp(argv[0]); return true; } return false; } } int mainEx(int argc, char* argv[], Context& context) { try { if (showHelpOrOwnVersion(argc, argv)) return 0; auto command = parseCommonOptions(argc, argv, /* in */ *context.getConfig(), /* out */ context.unparsed); context.argc = argc; context.argv = argv; std::function< int (Context&) > handler = getHandler(command); try { return handler(context); } catch (Exception&) { fatal2(__("error performing the command '%s'"), command); } } catch (Exception&) { return 1; } return 255; // we should not reach it, and gcc issues internal error on __builtin_unreachable } void showOwnVersion() { cout << "executable: " << CUPT_VERSION << endl; cout << "library: " << cupt::libraryVersion << endl; } void showHelp(const char* argv0) { using std::map; map< string, string > actionDescriptions = { { "help", __("prints a short help") }, { "version", __("prints versions of this program and the underlying library") }, { "config-dump", __("prints values of configuration variables") }, { "show", __("prints the info about binary package(s)") }, { "showsrc", __("prints the info about source packages(s)") }, { "search", __("searches for packages using regular expression(s)") }, { "depends", __("prints dependencies of binary package(s)") }, { "rdepends", __("print reverse-dependencies of binary package(s)") }, { "why", __("finds a dependency path between a package set and a package") }, { "policy", __("prints the pin info for the binary package(s)") }, { "policysrc", __("prints the pin info for the source package(s)") }, { "pkgnames", __("prints available package names") }, { "changelog", __("views the Debian changelog(s) of binary package(s)") }, { "copyright", __("views the Debian copyright(s) info of binary package(s)") }, { "screenshots", __("views Debian screenshot web pages for binary package(s)") }, { "update", __("updates repository metadata") }, { "install", __("installs/upgrades/downgrades binary package(s)") }, { "reinstall", __("reinstalls binary packages(s)") }, { "remove", __("removes binary package(s)") }, { "purge", __("removes binary package(s) along with their configuration files") }, { "iii", __("\"install if installed\": upgrades/downgrades binary packages(s)") }, { "satisfy", __("performs actions to make relation expressions satisfied") }, { "safe-upgrade", __("upgrades the system without removing non-automatically installed packages") }, { "full-upgrade", __("upgrades the system") }, { "dist-upgrade", __("does a two-stage full upgrade") }, { "build-dep", __("satisfies build dependencies for source package(s)") }, { "source", __("fetches and unpacks source package(s)") }, { "clean", __("cleans the whole binary package cache") }, { "autoclean", __("cleans packages from the binary package cache if not available from repositories") }, { "markauto", __("marks binary package(s) as automatically installed") }, { "unmarkauto", __("marks binary package(s) as manually installed") }, { "showauto", __("shows the list of manually or automatically installed packages") }, { "shell", __("starts an interactive package manager shell") }, { "snapshot", __("works with system snapshots") }, }; cout << format2(__("Usage: %s []"), argv0) << endl; cout << endl; cout << __("Actions:") << endl; for (const auto& pair: actionDescriptions) { cout << " " << pair.first << ": " << pair.second << endl; } } cupt-2.10.0/cpp/console/cupt.hpp0000644000000000000000000000255713204267373013363 0ustar /************************************************************************** * Copyright (C) 2010 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #include "common.hpp" #include "misc.hpp" int mainEx(int argc, char* argv[], Context& context); cupt-2.10.0/cpp/console/functionselectors.cpp0000644000000000000000000010773613204267373016161 0ustar /************************************************************************** * Copyright (C) 2012 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #include #include #include #include #include #include #include #include "functionselectors.hpp" FunctionalSelector::Query::Query() {} FunctionalSelector::Query::~Query() {} namespace { typedef FunctionalSelector::Query FS; // rename to FSQ typedef const Version* SPCV; // former shared_ptr< const Version > typedef list< SPCV > FSResult; typedef BinaryVersion::RelationTypes BRT; typedef SourceVersion::RelationTypes SRT; const RelationLine& getRelationLine(const Version* v, BRT::Type relationType) { return static_cast< const BinaryVersion* >(v)->relations[relationType]; } RelationLine getRelationLine(const Version* v, SRT::Type relationType) { return static_cast< const SourceVersion* >(v)->relations[relationType].toRelationLine(""); } template < typename RelationType > struct IsBinary {}; template <> struct IsBinary< BRT::Type > { static const bool value = true; }; template <> struct IsBinary< SRT::Type > { static const bool value = false; }; bool __spcv_less(const Cache& cache, const SPCV& left, const SPCV& right) { if (left->packageName > right->packageName) { return true; } if (left->packageName < right->packageName) { return false; } auto leftPin = cache.getPin(left); auto rightPin = cache.getPin(right); if (leftPin < rightPin) { return true; } if (leftPin > rightPin) { return false; } return left->versionString < right->versionString; } struct SpcvGreater { private: const Cache& __cache; public: SpcvGreater(const Cache& cache) : __cache(cache) {} bool operator()(const SPCV& left, const SPCV& right) { return __spcv_less(__cache, right, left); } }; class VersionSetGetter { bool __binary; // source if false const Cache& __cache; mutable FSResult* __cached_all_versions; static vector< string > __sort(vector< string >&& input) { std::sort(input.begin(), input.end()); return input; } Range< Cache::PackageNameIterator > __get_package_names() const { return __binary ? __cache.getBinaryPackageNames() : __cache.getSourcePackageNames(); } const Package* __get_package(const string& packageName) const { return __binary ? (const Package*)__cache.getBinaryPackage(packageName) : (const Package*)__cache.getSourcePackage(packageName); } void __add_package_to_result(const string& packageName, FSResult* result) const { // we call getSortedPinnedVersions() to place versions of the same package in the preference order for (auto&& pinnedVersion: __cache.getSortedVersionsWithPriorities(__get_package(packageName))) { result->emplace_back(std::move(pinnedVersion.version)); } } public: explicit VersionSetGetter(const Cache& cache, bool binary) : __binary(binary), __cache(cache), __cached_all_versions(NULL) {} const FSResult& getAll() const { if (!__cached_all_versions) { __cached_all_versions = new FSResult; for (const string& packageName: __sort(__get_package_names().asVector())) { __add_package_to_result(packageName, __cached_all_versions); } } return *__cached_all_versions; } FSResult get(const sregex& regex) const { FSResult result; smatch m; vector< string > matchedPackageNames; for (const string& packageName: __get_package_names()) { if (regex_match(packageName, m, regex)) { matchedPackageNames.push_back(packageName); } } for (const string& packageName: __sort(std::move(matchedPackageNames))) { __add_package_to_result(packageName, &result); } return result; } ~VersionSetGetter() { delete __cached_all_versions; } }; class VersionSet { const VersionSetGetter* __binary_getter; const VersionSetGetter* __source_getter; const VersionSetGetter* __current_getter; bool __filtered; FSResult __versions; std::map< string, FSResult > __variables; VersionSet(const VersionSet& from, FSResult&& versions) : __binary_getter(from.__binary_getter) , __source_getter(from.__source_getter) , __current_getter(from.__current_getter) , __filtered(true), __versions(std::move(versions)), __variables(from.__variables) {} public: explicit VersionSet(const VersionSetGetter* binaryGetter, const VersionSetGetter* sourceGetter) : __binary_getter(binaryGetter), __source_getter(sourceGetter), __filtered(false) {} VersionSet generate(FSResult&& versions) const { return VersionSet(*this, std::move(versions)); } void selectGetterType(bool binary) { __current_getter = binary ? __binary_getter : __source_getter; } const FSResult& get() const { if (__filtered) { return __versions; } else { return __current_getter->getAll(); } } FSResult get(const sregex& regex) const { if (__filtered) { smatch m; FSResult result(__versions); result.remove_if([®ex, &m](const SPCV& version) { return !regex_match(version->packageName, m, regex); }); return result; } else { return __current_getter->get(regex); } } void setVariable(const string& name, FSResult&& versions) { __variables[name] = std::move(versions); } const FSResult& getFromVariable(const string& name) const { auto it = __variables.find(name); if (it == __variables.end()) { fatal2("the variable '%s' is not defined", name); } return it->second; } VersionSet getUnfiltered() const { VersionSet result(__binary_getter, __source_getter); result.__variables = this->__variables; result.__current_getter = this->__current_getter; return result; } bool isFiltered() const { return __filtered; } }; struct Context { const Cache& cache; ReverseDependsIndex< BinaryVersion > reverseIndex; ReverseDependsIndex< SourceVersion > reverseBuildIndex; Context(const Cache& cache_) : cache(cache_), reverseIndex(cache), reverseBuildIndex(cache) {} SpcvGreater getSorter() const { return SpcvGreater(cache); } void mergeFsResults(FSResult* main, FSResult&& other) { main->merge(std::move(other), getSorter()); main->unique(); } FSResult filterThrough(const FSResult& versions, const VersionSet& allowedSet) { if (allowedSet.isFiltered()) { const auto& allowedVersions = allowedSet.get(); FSResult result; std::set_intersection(allowedVersions.begin(), allowedVersions.end(), versions.begin(), versions.end(), std::back_inserter(result), getSorter()); return result; } else { return versions; } } }; class CommonFS: public FS { public: typedef vector< string > Arguments; virtual FSResult select(Context&, const VersionSet& from) const = 0; }; unique_ptr< CommonFS > internalParseFunctionQuery(const string& query, bool binary); void __require_n_arguments(const CommonFS::Arguments& arguments, size_t n) { if (arguments.size() != n) { fatal2(__("the function requires exactly %zu arguments"), n); } } class BestFS: public CommonFS { unique_ptr< CommonFS > __leaf_fs; public: BestFS(bool binary, const Arguments& arguments) { __require_n_arguments(arguments, 1); __leaf_fs = internalParseFunctionQuery(arguments[0], binary); } FSResult select(Context& context, const VersionSet& from) const { auto result = __leaf_fs->select(context, from); result.unique([](const SPCV& left, const SPCV& right) { return left->packageName == right->packageName; }); return result; } }; class DefineVariableFS: public CommonFS { string __name; unique_ptr< CommonFS > __value_fs; unique_ptr< CommonFS > __leaf_fs; public: DefineVariableFS(bool binary, const Arguments& arguments) { __require_n_arguments(arguments, 3); __name = arguments[0]; __value_fs = internalParseFunctionQuery(arguments[1], binary); __leaf_fs = internalParseFunctionQuery(arguments[2], binary); } FSResult select(Context& context, const VersionSet& from) const { VersionSet modifiedFrom(from); modifiedFrom.setVariable(__name, __value_fs->select(context, from.getUnfiltered())); return __leaf_fs->select(context, modifiedFrom); } }; class ExtractVariableFS: public CommonFS { const string __name; public: ExtractVariableFS(const string& name, const Arguments& arguments) : __name(name) { __require_n_arguments(arguments, 0); } FSResult select(Context& context, const VersionSet& from) const { return context.filterThrough(from.getFromVariable(__name), from); } }; class AlgeFS: public CommonFS { protected: list< unique_ptr< CommonFS > > _leaves; public: // postcondition: _leaves are not empty AlgeFS(bool binary, const Arguments& arguments) { if (arguments.empty()) { fatal2(__("the function should have at least one argument")); } for (const auto& argument: arguments) { _leaves.push_back(internalParseFunctionQuery(argument, binary)); } } }; class AndFS: public AlgeFS { public: AndFS(bool binary, const Arguments& arguments) : AlgeFS(binary, arguments) {} FSResult select(Context& context, const VersionSet& from) const { auto result = _leaves.front()->select(context, from); for (auto it = ++_leaves.begin(); it != _leaves.end(); ++it) { result = (*it)->select(context, from.generate(std::move(result))); } return result; } }; class NotFS: public AlgeFS { static const Arguments& __check_and_return_arguments(const Arguments& arguments) { __require_n_arguments(arguments, 1); return arguments; } public: NotFS(bool binary, const Arguments& arguments) : AlgeFS(binary, __check_and_return_arguments(arguments)) {} FSResult select(Context& context, const VersionSet& from) const { const auto& fromVersions = from.get(); auto notVersions = _leaves.front()->select(context, from); FSResult result; std::set_difference(fromVersions.begin(), fromVersions.end(), notVersions.begin(), notVersions.end(), std::back_inserter(result), context.getSorter()); return result; } }; class XorFS: public AlgeFS { static const Arguments& __check_and_return_arguments(const Arguments& arguments) { __require_n_arguments(arguments, 2); return arguments; } public: XorFS(bool binary, const Arguments& arguments) : AlgeFS(binary, __check_and_return_arguments(arguments)) {} FSResult select(Context& context, const VersionSet& from) const { auto leftVersions = _leaves.front()->select(context, from); auto rightVersions = _leaves.back()->select(context, from); FSResult result; std::set_symmetric_difference(leftVersions.begin(), leftVersions.end(), rightVersions.begin(), rightVersions.end(), std::back_inserter(result), context.getSorter()); return result; } }; // for determining, is function selector binary or source class BinaryTagDummyFS: public CommonFS { unique_ptr< CommonFS > __real_fs; public: BinaryTagDummyFS(unique_ptr< CommonFS >&& realFS) : __real_fs(std::move(realFS)) {} FSResult select(Context& context, const VersionSet& from) const { return __real_fs->select(context, from); } }; class OrFS: public AlgeFS { public: OrFS(bool binary, const Arguments& arguments) : AlgeFS(binary, arguments) {} FSResult select(Context& context, const VersionSet& from) const { auto result = _leaves.front()->select(context, from); for (auto it = ++_leaves.begin(); it != _leaves.end(); ++it) { auto part = (*it)->select(context, from); context.mergeFsResults(&result, std::move(part)); } return result; } }; class PredicateFS: public CommonFS { protected: virtual bool _match(const Cache&, const SPCV&) const = 0; public: FSResult select(Context& context, const VersionSet& from) const { FSResult result = from.get(); result.remove_if([this, &context](const SPCV& version) { return !this->_match(context.cache, version); }); return result; } }; sregex __parse_regex(const string& input) { try { return sregex::compile(input, regex_constants::optimize); } catch (regex_error&) { fatal2(__("regular expression '%s' is not valid"), input); __builtin_unreachable(); } } sregex __get_regex_from_arguments(const CommonFS::Arguments& arguments) { __require_n_arguments(arguments, 1); return __parse_regex(arguments[0]); } class RegexMatcher { sregex __regex; mutable smatch __m; public: RegexMatcher(const CommonFS::Arguments& arguments) : __regex(__get_regex_from_arguments(arguments)) {} bool match(const string& input) const { return regex_match(input, __m, __regex); } }; class PackageNameFS: public CommonFS { sregex __regex; public: PackageNameFS(const Arguments& arguments) : __regex(__get_regex_from_arguments(arguments)) {} FSResult select(Context&, const VersionSet& from) const { return from.get(__regex); } }; class RegexMatchBaseFS: public PredicateFS { protected: RegexMatcher _matcher; public: RegexMatchBaseFS(const Arguments& arguments) : _matcher(arguments) {} }; class RegexMatchFS: public RegexMatchBaseFS { std::function< string (const Cache&, const SPCV&) > __get_attribute; public: RegexMatchFS(decltype(__get_attribute) getAttribute, const Arguments& arguments) : RegexMatchBaseFS(arguments), __get_attribute(getAttribute) {} protected: bool _match(const Cache& cache, const SPCV& version) const { return _matcher.match(__get_attribute(cache, version)); } }; class SourceRegexMatchFS: public RegexMatchBaseFS { std::function< string (const Version::Source&) > __get_source_attribute; public: SourceRegexMatchFS(decltype(__get_source_attribute) getter, const Arguments& arguments) : RegexMatchBaseFS(arguments), __get_source_attribute(getter) {} protected: bool _match(const Cache&, const SPCV& version) const { for (const auto& source: version->sources) { if (_matcher.match(__get_source_attribute(source))) { return true; } } return false; } }; class ProvidesFS: public RegexMatchBaseFS { public: ProvidesFS(const Arguments& arguments) : RegexMatchBaseFS(arguments) {} protected: bool _match(const Cache&, const SPCV& v) const { auto version = static_cast< const BinaryVersion* >(v); for (const auto& elem: version->provides) { if (_matcher.match(elem.packageName)) { return true; } } return false; } }; class UploadersFS: public RegexMatchBaseFS { public: UploadersFS(const Arguments& arguments) : RegexMatchBaseFS(arguments) {} protected: bool _match(const Cache&, const SPCV& v) const { auto version = static_cast< const SourceVersion* >(v); for (const string& uploader: version->uploaders) { if (_matcher.match(uploader)) return true; } return false; } }; class BoolMatchFS: public PredicateFS { std::function< bool (const Cache&, const SPCV&) > __get_attribute; public: BoolMatchFS(decltype(__get_attribute) getAttribute, const Arguments& arguments) : __get_attribute(getAttribute) { __require_n_arguments(arguments, 0); } bool _match(const Cache& cache, const SPCV& version) const { return __get_attribute(cache, version); } }; class OtherFieldRegexMatchFS: public RegexMatchFS { string __field_name; static string __extract_second_argument(const Arguments& arguments) { __require_n_arguments(arguments, 2); return arguments[1]; } public: OtherFieldRegexMatchFS(const Arguments& arguments) : RegexMatchFS([this](const Cache&, const SPCV& version) -> string { if (!version->others) { return string(); } auto it = version->others->find(this->__field_name); if (it != version->others->end()) { return it->second; } else { return string(); } }, { __extract_second_argument(arguments) }), __field_name(arguments[0]) {} }; class TransformFS: public CommonFS { unique_ptr< CommonFS > __leaf; bool __binary; protected: virtual FSResult _transform(Context&, const SPCV& version) const = 0; public: TransformFS(bool binary, const Arguments& arguments) : __binary(binary) { __require_n_arguments(arguments, 1); __leaf = internalParseFunctionQuery(arguments[0], binary); } FSResult select(Context& context, const VersionSet& from) const { FSResult allTransformed; auto newVersionSet = from.getUnfiltered(); newVersionSet.selectGetterType(__binary); for (const auto& version: __leaf->select(context, newVersionSet)) { auto transformedList = _transform(context, version); context.mergeFsResults(&allTransformed, std::move(transformedList)); } return context.filterThrough(allTransformed, from); } }; class RecursiveFS: public CommonFS { string __variable_name; unique_ptr< CommonFS > __initial_variable_value_fs; unique_ptr< CommonFS > __iterating_fs; public: RecursiveFS(bool binary, const Arguments& arguments) { __require_n_arguments(arguments, 3); __variable_name = arguments[0]; __initial_variable_value_fs = internalParseFunctionQuery(arguments[1], binary); __iterating_fs = internalParseFunctionQuery(arguments[2], binary); } FSResult select(Context& context, const VersionSet& from) const { FSResult result; FSResult variableValue = __initial_variable_value_fs->select(context, from.getUnfiltered()); size_t previousResultSize; do { previousResultSize = result.size(); VersionSet iterationSet = from.getUnfiltered(); iterationSet.setVariable(__variable_name, std::move(variableValue)); context.mergeFsResults(&result, __iterating_fs->select(context, iterationSet)); variableValue = result; } while (result.size() != previousResultSize); return context.filterThrough(result, from); } }; template < typename RelationType > class DependencyFS: public TransformFS { const RelationType __relation_type; public: DependencyFS(RelationType relationType, const Arguments& arguments) : TransformFS(IsBinary::value, arguments), __relation_type(relationType) {} protected: FSResult _transform(Context& context, const SPCV& version) const { auto sorter = context.getSorter(); FSResult result; for (const auto& relationExpression: getRelationLine(version, __relation_type)) { auto satisfyingVersions = context.cache.getSatisfyingVersions(relationExpression); std::sort(satisfyingVersions.begin(), satisfyingVersions.end(), sorter); list< SPCV > sortedList; std::move(satisfyingVersions.begin(), satisfyingVersions.end(), std::back_inserter(sortedList)); context.mergeFsResults(&result, std::move(sortedList)); } return result; } }; class ReverseDependencyFS: public TransformFS { BRT::Type __relation_type; public: ReverseDependencyFS(BRT::Type relationType, const Arguments& arguments) : TransformFS(true, arguments), __relation_type(relationType) {} protected: FSResult _transform(Context& context, const SPCV& version) const { context.reverseIndex.add(__relation_type); FSResult result; auto binaryVersion = static_cast< const BinaryVersion* >(version); context.reverseIndex.foreachReverseDependency(binaryVersion, __relation_type, [&context, &result](const BinaryVersion* reverseVersion, const RelationExpression&) { context.mergeFsResults(&result, { reverseVersion }); }); return result; } }; class ReverseBuildDependencyFS: public TransformFS { SRT::Type __relationType; public: ReverseBuildDependencyFS(SRT::Type relationType, const Arguments& arguments) : TransformFS(true, arguments), __relationType(relationType) {} protected: FSResult _transform(Context& context, const SPCV& version) const { context.reverseBuildIndex.add(__relationType); FSResult result; auto binaryVersion = static_cast< const BinaryVersion* >(version); context.reverseBuildIndex.foreachReverseDependency(binaryVersion, __relationType, [&context, &result](const SourceVersion* reverseVersion, const RelationExpression&) { context.mergeFsResults(&result, { reverseVersion }); }); return result; } }; class BinaryToSourceFS: public TransformFS { public: BinaryToSourceFS(const Arguments& arguments) : TransformFS(true, arguments) {} protected: FSResult _transform(Context& context, const SPCV& version) const { auto binaryVersion = static_cast< const BinaryVersion* >(version); if (auto sourcePackage = context.cache.getSourcePackage(binaryVersion->sourcePackageName)) { for (auto sourceVersion: *sourcePackage) { if (sourceVersion->versionString == binaryVersion->sourceVersionString) { return { sourceVersion }; } } } return {}; } }; class SourceToBinaryFS: public TransformFS { public: SourceToBinaryFS(const Arguments& arguments) : TransformFS(false, arguments) {} protected: FSResult _transform(Context& context, const SPCV& version) const { auto sourceVersion = static_cast< const SourceVersion* >(version); FSResult result; for (const auto& packageName: sourceVersion->binaryPackageNames) { if (auto binaryPackage = context.cache.getBinaryPackage(packageName)) { for (auto binaryVersion: *binaryPackage) { if (binaryVersion->sourceVersionString == sourceVersion->versionString) { context.mergeFsResults(&result, { binaryVersion }); } } } } return result; } }; class PackageIsInstalledFS: public PredicateFS { protected: bool _match(const Cache& cache, const SPCV& version) const { return isPackageInstalled(cache, version->packageName); } public: PackageIsInstalledFS(const Arguments& arguments) { __require_n_arguments(arguments, 0); } }; class PackageIsAutoInstalledFS: public PredicateFS { protected: bool _match(const Cache& cache, const SPCV& version) const { return cache.isAutomaticallyInstalled(version->packageName); } public: PackageIsAutoInstalledFS(const Arguments& arguments) { __require_n_arguments(arguments, 0); } }; /// namespace attr { string priority(const Cache&, const SPCV& version) { return Version::Priorities::strings[version->priority]; } } CommonFS* constructFSByName(const string& functionName, const CommonFS::Arguments& arguments, bool binary) { #define VERSION_MEMBER(member) [](const Cache&, const SPCV& version) { return version-> member; } #define VERSION_RELEASE_MEMBER(member) [](const Version::Source& source) { return source.release-> member; } #define BINARY_VERSION_MEMBER(member) [](const Cache&, const SPCV& version) \ { return static_cast< const BinaryVersion* >(version)-> member; } #define CONSTRUCT_FS(name, code) if (functionName == name) { return new code; } #define CONSTRUCT_RELEASE_MEMBER_FS(name, member) \ CONSTRUCT_FS(name, SourceRegexMatchFS(VERSION_RELEASE_MEMBER(member), arguments)) // variables if (functionName.front() == '_') { return new ExtractVariableFS(functionName, arguments); } CONSTRUCT_FS("with", DefineVariableFS(binary, arguments)) CONSTRUCT_FS("recursive", RecursiveFS(binary, arguments)) // logic CONSTRUCT_FS("and", AndFS(binary, arguments)) CONSTRUCT_FS("or", OrFS(binary, arguments)) CONSTRUCT_FS("not", NotFS(binary, arguments)) CONSTRUCT_FS("xor", XorFS(binary, arguments)) // narrowing/widening CONSTRUCT_FS("best", BestFS(binary, arguments)) // common CONSTRUCT_FS("package:name", PackageNameFS(arguments)) CONSTRUCT_FS("version", RegexMatchFS(VERSION_MEMBER(versionString), arguments)) CONSTRUCT_FS("maintainer", RegexMatchFS(VERSION_MEMBER(maintainer), arguments)) CONSTRUCT_FS("priority", RegexMatchFS(attr::priority, arguments)) CONSTRUCT_FS("section", RegexMatchFS(VERSION_MEMBER(section), arguments)) CONSTRUCT_FS("trusted", BoolMatchFS(VERSION_MEMBER(isVerified()), arguments)) CONSTRUCT_FS("field", OtherFieldRegexMatchFS(arguments)) CONSTRUCT_RELEASE_MEMBER_FS("release:archive", archive) CONSTRUCT_RELEASE_MEMBER_FS("release:codename", codename) CONSTRUCT_RELEASE_MEMBER_FS("release:component", component) CONSTRUCT_RELEASE_MEMBER_FS("release:version", version) CONSTRUCT_RELEASE_MEMBER_FS("release:vendor", vendor) CONSTRUCT_RELEASE_MEMBER_FS("release:origin", baseUri) if (binary) { CONSTRUCT_FS("source-package", RegexMatchFS(BINARY_VERSION_MEMBER(sourcePackageName), arguments)) CONSTRUCT_FS("source-version", RegexMatchFS(BINARY_VERSION_MEMBER(sourceVersionString), arguments)) CONSTRUCT_FS("essential", BoolMatchFS(BINARY_VERSION_MEMBER(essential), arguments)) CONSTRUCT_FS("important", BoolMatchFS(BINARY_VERSION_MEMBER(important), arguments)) CONSTRUCT_FS("installed", BoolMatchFS(BINARY_VERSION_MEMBER(isInstalled()), arguments)) CONSTRUCT_FS("description", RegexMatchFS(BINARY_VERSION_MEMBER(description), arguments)) CONSTRUCT_FS("package:installed", PackageIsInstalledFS(arguments)) CONSTRUCT_FS("package:automatically-installed", PackageIsAutoInstalledFS(arguments)) // relations CONSTRUCT_FS("pre-depends", DependencyFS(BRT::PreDepends, arguments)) CONSTRUCT_FS("depends", DependencyFS(BRT::Depends, arguments)) CONSTRUCT_FS("recommends", DependencyFS(BRT::Recommends, arguments)) CONSTRUCT_FS("suggests", DependencyFS(BRT::Suggests, arguments)) CONSTRUCT_FS("conflicts", DependencyFS(BRT::Conflicts, arguments)) CONSTRUCT_FS("breaks", DependencyFS(BRT::Breaks, arguments)) CONSTRUCT_FS("replaces", DependencyFS(BRT::Replaces, arguments)) CONSTRUCT_FS("enhances", DependencyFS(BRT::Enhances, arguments)) CONSTRUCT_FS("reverse-pre-depends", ReverseDependencyFS(BRT::PreDepends, arguments)) CONSTRUCT_FS("reverse-depends", ReverseDependencyFS(BRT::Depends, arguments)) CONSTRUCT_FS("reverse-recommends", ReverseDependencyFS(BRT::Recommends, arguments)) CONSTRUCT_FS("reverse-suggests", ReverseDependencyFS(BRT::Suggests, arguments)) CONSTRUCT_FS("reverse-conflicts", ReverseDependencyFS(BRT::Conflicts, arguments)) CONSTRUCT_FS("reverse-breaks", ReverseDependencyFS(BRT::Breaks, arguments)) CONSTRUCT_FS("reverse-enhances", ReverseDependencyFS(BRT::Enhances, arguments)) CONSTRUCT_FS("reverse-replaces", ReverseDependencyFS(BRT::Replaces, arguments)) CONSTRUCT_FS("provides", ProvidesFS(arguments)) CONSTRUCT_FS("build-depends", DependencyFS(SRT::BuildDepends, arguments)) CONSTRUCT_FS("build-depends-indep", DependencyFS(SRT::BuildDependsIndep, arguments)) CONSTRUCT_FS("build-depends-arch", DependencyFS(SRT::BuildDependsArch, arguments)) CONSTRUCT_FS("build-conflicts", DependencyFS(SRT::BuildConflicts, arguments)) CONSTRUCT_FS("build-conflicts-indep", DependencyFS(SRT::BuildConflictsIndep, arguments)) CONSTRUCT_FS("build-conflicts-arch", DependencyFS(SRT::BuildConflictsArch, arguments)) CONSTRUCT_FS("source-to-binary", SourceToBinaryFS(arguments)) } else { CONSTRUCT_FS("uploaders", UploadersFS(arguments)) CONSTRUCT_FS("reverse-build-depends", ReverseBuildDependencyFS(SRT::BuildDepends, arguments)) CONSTRUCT_FS("reverse-build-depends-indep", ReverseBuildDependencyFS(SRT::BuildDependsIndep, arguments)) CONSTRUCT_FS("reverse-build-depends-arch", ReverseBuildDependencyFS(SRT::BuildDependsArch, arguments)) CONSTRUCT_FS("reverse-build-conflicts", ReverseBuildDependencyFS(SRT::BuildConflicts, arguments)) CONSTRUCT_FS("reverse-build-conflicts-indep", ReverseBuildDependencyFS(SRT::BuildConflictsIndep, arguments)) CONSTRUCT_FS("reverse-build-conflicts-arch", ReverseBuildDependencyFS(SRT::BuildConflictsArch, arguments)) CONSTRUCT_FS("binary-to-source", BinaryToSourceFS(arguments)) } fatal2(__("unknown %s selector function '%s'"), binary ? __("binary") : __("source"), functionName); __builtin_unreachable(); } vector< string > split(const string& input, const char delimiter = ',') { if (input.empty()) { return {}; } vector< string > result; size_t argumentStartPosition = 0; size_t position = 0; size_t level = 0; char delimiters[] = "d()/"; delimiters[0] = delimiter; while (position = input.find_first_of(delimiters, position), position != string::npos) { if (input[position] == delimiter && level == 0) { result.push_back(input.substr(argumentStartPosition, position - argumentStartPosition)); argumentStartPosition = position+1; } else switch (input[position]) { case '(': ++level; break; case ')': if (level == 0) { fatal2(__("unexpected closing bracket ')' after '%s'"), input.substr(0, position)); } --level; break; case '/': // quoting position = input.find('/', position+1); if (position == string::npos) { fatal2(__("unable to find closing quoting character '/'")); } } ++position; } if (level != 0) { fatal2(__("too few closing brackets")); } result.push_back(input.substr(argumentStartPosition, input.size() - argumentStartPosition)); return result; } void trim(string& s) { const char* trimmedCharacters = " \t\n"; if (s.size() > 0) { auto firstValuablePosition = s.find_first_not_of(trimmedCharacters); auto lastValuablePosition = s.find_last_not_of(trimmedCharacters); s = s.substr(firstValuablePosition, lastValuablePosition - firstValuablePosition + 1); } } void stripArgumentQuotes(string& argument) { if (argument.size() >= 2) { if (argument.front() == '/' && argument.back() == '/') { argument = argument.substr(1, argument.size()-2); } } } void processNonTrivialAliases(string* functionNamePtr, vector< string >* argumentsPtr) { auto getUniqueVariableName = []() { static size_t anonymousVariableId = 0; return format2("__anon%zu", anonymousVariableId++); }; if (*functionNamePtr == "package-with-installed-dependencies") { __require_n_arguments(*argumentsPtr, 1); *functionNamePtr = "recursive"; auto variableName = getUniqueVariableName(); auto recursiveExpression = format2( "best( fmap(%s, Ypd,Yd,Yr) & Pi )", variableName); *argumentsPtr = { variableName, argumentsPtr->front(), recursiveExpression }; } else if (*functionNamePtr == "fmap") { if (argumentsPtr->size() < 2) { fatal2("the function '%s' requires at least %zu arguments", "fmap", 2); } auto argument = argumentsPtr->front(); argumentsPtr->erase(argumentsPtr->begin()); auto variableName = getUniqueVariableName(); auto bracedVariableName = format2("(%s)", variableName); vector< string > mappedCalls; for (const auto& e: *argumentsPtr) { mappedCalls.push_back(e + bracedVariableName); } string expression = format2("or(%s)", join(",", mappedCalls)); *functionNamePtr = "with"; *argumentsPtr = { variableName, argument, expression }; } } void processAliases(string* functionNamePtr, vector< string >* argumentsPtr) { { // simple aliases static map< string, string > aliases = { { "Pn", "package:name" }, { "Pi", "package:installed" }, { "Pai", "package:automatically-installed" }, { "v", "version" }, { "m", "maintainer" }, { "p", "priority" }, { "s", "section" }, { "t", "trusted" }, { "f", "field" }, { "sp", "source-package" }, { "sv", "source-version" }, { "e", "essential" }, { "i", "installed" }, { "d", "description" }, { "o", "provides" }, { "u", "uploaders" }, { "Ypd", "pre-depends" }, { "Yd", "depends" }, { "Yr", "recommends" }, { "Ys", "suggests" }, { "Ye", "enhances" }, { "Yc", "conflicts" }, { "Yb", "breaks" }, { "Yrp", "replaces" }, { "YRpd", "reverse-pre-depends" }, { "YRd", "reverse-depends" }, { "YRr", "reverse-recommends" }, { "YRs", "reverse-suggests" }, { "YRe", "reverse-enhances" }, { "YRc", "reverse-conflicts" }, { "YRb", "reverse-breaks" }, { "YRrp", "reverse-replaces" }, { "Zbd", "build-depends" }, { "Zbdi", "build-depends-indep" }, { "Zbda", "build-depends-arch" }, { "Zbc", "build-conflicts" }, { "Zbci", "build-conflicts-indep" }, { "Zbca", "build-conflicts-arch" }, { "ZRbd", "reverse-build-depends" }, { "ZRbdi", "reverse-build-depends-indep" }, { "ZRbda", "reverse-build-depends-arch" }, { "ZRbc", "reverse-build-conflicts" }, { "ZRbci", "reverse-build-conflicts-indep" }, { "ZRbca", "reverse-build-conflicts-arch" }, { "Ra", "release:archive" }, { "Rn", "release:codename" }, { "Rc", "release:component" }, { "Rv", "release:version" }, { "Ro", "release:vendor" }, { "Ru", "release:origin" }, }; auto it = aliases.find(*functionNamePtr); if (it != aliases.end()) { *functionNamePtr = it->second; return; } } processNonTrivialAliases(functionNamePtr, argumentsPtr); } void parseFunctionNameAndArguments(const string& query, string* functionNamePtr, vector< string >* argumentsPtr) { vector< string > possibleArguments; possibleArguments = split(query, '|'); if (possibleArguments.size() > 1) { *functionNamePtr = "or"; *argumentsPtr = std::move(possibleArguments); return; } possibleArguments = split(query, '&'); if (possibleArguments.size() > 1) { *functionNamePtr = "and"; *argumentsPtr = std::move(possibleArguments); return; } auto argumentsPosition = query.find_first_of("()"); if (argumentsPosition == string::npos) { *functionNamePtr = query; // assume that the function takes no parameters } else { if (query[argumentsPosition] == ')') { fatal2(__("closing bracket ')' doesn't have a corresponding opening bracket '('")); } // now we know it's surely '(' if (query.back() != ')') { fatal2(__("the last query character is not a closing bracket ')'")); } *functionNamePtr = query.substr(0, argumentsPosition); *argumentsPtr = split(query.substr(argumentsPosition + 1, query.size() - argumentsPosition - 2)); } } unique_ptr< CommonFS > internalParseFunctionQuery(const string& query, bool binary) { try { if (query.empty()) { fatal2(__("query cannot be empty")); } string functionName; vector< string > arguments; parseFunctionNameAndArguments(query, &functionName, &arguments); for (string& argument: arguments) { trim(argument); stripArgumentQuotes(argument); } processAliases(&functionName, &arguments); return unique_ptr< CommonFS >(constructFSByName(functionName, arguments, binary)); } catch (Exception&) { fatal2(__("unable to parse the query '%s'"), query); __builtin_unreachable(); } } } struct FunctionalSelector::Data { Context context; VersionSetGetter binaryGetter; VersionSetGetter sourceGetter; Data(const Cache& cache_) : context(cache_), binaryGetter(cache_, true), sourceGetter(cache_, false) {} }; FunctionalSelector::FunctionalSelector(const Cache& cache) { __data = new Data(cache); } FunctionalSelector::~FunctionalSelector() { delete __data; } unique_ptr< FS > FunctionalSelector::parseQuery(const string& query, bool binary) { Cache::memoize = true; auto trimmedQuery = query; trim(trimmedQuery); auto result = internalParseFunctionQuery(trimmedQuery, binary); if (binary) { unique_ptr< CommonFS > newResult(new BinaryTagDummyFS(std::move(result))); result.swap(newResult); } return std::move(result); } list< SPCV > FunctionalSelector::selectAllVersions(const FS& functionSelector) { const CommonFS* commonFS = dynamic_cast< const CommonFS* >(&functionSelector); if (!commonFS) { fatal2i("selectVersion: functionSelector is not an ancestor of CommonFS"); } bool binary = (dynamic_cast< const BinaryTagDummyFS* >(commonFS)); VersionSet versionSet(&__data->binaryGetter, &__data->sourceGetter); versionSet.selectGetterType(binary); return commonFS->select(__data->context, versionSet); } list< SPCV > FunctionalSelector::selectBestVersions(const FS& functionSelector) { auto result = selectAllVersions(functionSelector); result.unique([](const SPCV& left, const SPCV& right) { return left->packageName == right->packageName; }); return result; } cupt-2.10.0/cpp/console/functionselectors.hpp0000644000000000000000000000351713204267373016156 0ustar /************************************************************************** * Copyright (C) 2012 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #ifndef CUPT_CONSOLE_FUNCTION_SELECTORS_SEEN #define CUPT_CONSOLE_FUNCTION_SELECTORS_SEEN #include #include #include "common.hpp" using std::unique_ptr; using std::list; class FunctionalSelector { struct Data; Data* __data; public: class Query { protected: Query(); public: virtual ~Query(); }; FunctionalSelector(const Cache&); ~FunctionalSelector(); static unique_ptr< Query > parseQuery(const string&, bool); list< const Version* > selectAllVersions(const Query&); list< const Version* > selectBestVersions(const Query&); }; #endif cupt-2.10.0/cpp/console/handlers/0000755000000000000000000000000013204267373013466 5ustar cupt-2.10.0/cpp/console/handlers/download.cpp0000644000000000000000000002457613204267373016017 0ustar /************************************************************************** * Copyright (C) 2010-2011 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #include using std::cout; using std::endl; #include "../common.hpp" #include "../handlers.hpp" #include "../selectors.hpp" #include #include #include #include int downloadSourcePackage(Context& context) { auto config = context.getConfig(); vector< string > arguments; bpo::options_description options(""); options.add_options() ("download-only,d", "") ("tar-only", "") ("diff-only", "") ("dsc-only", ""); auto variables = parseOptions(context, options, arguments); if (arguments.empty()) { fatal2(__("no source package expressions specified")); } if (!shellMode) { Version::parseInfoOnly = false; Version::parseRelations = false; } auto cache = context.getCache(true, true, true); vector< SourceVersion::FileParts::Type > partsToDownload = { SourceVersion::FileParts::Tarball, SourceVersion::FileParts::Diff, SourceVersion::FileParts::Dsc }; bool downloadOnly = false; if (variables.count("download-only")) { downloadOnly = true; } if (variables.count("tar-only")) { partsToDownload = { SourceVersion::FileParts::Tarball }; downloadOnly = true; } if (variables.count("diff-only")) { partsToDownload = { SourceVersion::FileParts::Diff }; downloadOnly = true; } if (variables.count("dsc-only")) { partsToDownload = { SourceVersion::FileParts::Dsc }; downloadOnly = true; } vector< Manager::DownloadEntity > downloadEntities; vector< string > dscFilenames; for (const auto& argument: arguments) { for (const auto& version: selectSourceVersionsWildcarded(*cache, argument)) { const string& packageName = version->packageName; const string& versionString = version->versionString; auto downloadInfo = version->getDownloadInfo(); for (auto part: partsToDownload) { for (const Version::FileRecord& record: version->files[part]) { const string& filename = record.name; if (part == SourceVersion::FileParts::Dsc) { dscFilenames.push_back(filename); // for unpacking after } { // exclude from downloading packages that are already present decltype(cupt::messageFd) oldMessageFd = cupt::messageFd; cupt::messageFd = -1; // don't print errors if any try { if (record.hashSums.verify(filename)) { continue; } } catch (Exception&) {} cupt::messageFd = oldMessageFd; } Manager::DownloadEntity downloadEntity; for (const auto& downloadRecord: downloadInfo) { string shortAlias = packageName + ' ' + SourceVersion::FileParts::strings[part]; string longAlias = format2("%s %s %s %s %s", downloadRecord.baseUri, version->getCodenameAndComponentString(downloadRecord.baseUri), packageName, versionString, SourceVersion::FileParts::strings[part]); string uri = downloadRecord.baseUri + '/' + downloadRecord.directory + '/' + filename; downloadEntity.extendedUris.push_back( Manager::ExtendedUri(uri, shortAlias, longAlias)); } downloadEntity.targetPath = filename; downloadEntity.size = record.size; downloadEntity.postAction = [record, filename]() -> string { if (!record.hashSums.verify(filename)) { if (unlink(filename.c_str()) == -1) { warn2e(__("unable to remove the file '%s'"), filename); } return __("hash sums mismatch"); } return ""; }; downloadEntities.push_back(std::move(downloadEntity)); } } } } { // downloading auto downloadProgress = getDownloadProgress(*config); Manager downloadManager(config, downloadProgress); auto downloadError = downloadManager.download(downloadEntities); if (!downloadError.empty()) { fatal2(__("there were download errors")); } }; // make sure that download manager is already destroyed at this point if (!downloadOnly) { // unpack downloaded sources for (const auto& filename: dscFilenames) { string command = "dpkg-source -x " + filename; if (::system(command.c_str())) { warn2(__("dpkg-source on the file '%s' failed"), filename); } } } // all's good return 0; } int downloadChangelogOrCopyright(Context& context, ChangelogOrCopyright::Type type) { if (!shellMode) { Version::parseInfoOnly = false; Version::parseRelations = false; } auto config = context.getConfig(); vector< string > arguments; bpo::options_description options(""); options.add_options() ("installed-only", ""); auto variables = parseOptions(context, options, arguments); if (arguments.empty()) { fatal2(__("no binary package expressions specified")); } auto cache = context.getCache(false, !variables.count("installed-only"), true); const string typeString = (type == ChangelogOrCopyright::Changelog ? "changelog" : "copyright"); const map< string, string > baseUrisByVendor = { { "Debian", "http://packages.debian.org/changelogs/pool" }, { "Ubuntu", "http://changelogs.ubuntu.com/changelogs/pool" }, // yes, 'changelogs' even for copyrights :) }; string pagerProgram; { auto systemState = cache->getSystemState(); auto installedStatus = State::InstalledRecord::Status::Installed; auto sensibleUtilsInstalledInfo = systemState->getInstalledInfo("sensible-utils"); if (sensibleUtilsInstalledInfo && sensibleUtilsInstalledInfo->status == installedStatus) { pagerProgram = "sensible-pager"; } else { auto lessInstalledInfo = systemState->getInstalledInfo("less"); if (lessInstalledInfo && lessInstalledInfo->status == installedStatus) { pagerProgram = "less"; } else { pagerProgram = "cat"; } } } for (const auto& argument: arguments) { auto versions = selectBinaryVersionsWildcarded(*cache, argument); for (const auto& version: versions) { string localTargetPath; if (type == ChangelogOrCopyright::Changelog) { localTargetPath = Cache::getPathOfChangelog(version); } else { localTargetPath = Cache::getPathOfCopyright(version); } if (!localTargetPath.empty()) { // there is a local changelog/copyright, display it auto preparedCommand = (type == ChangelogOrCopyright::Changelog ? "zcat" : "cat"); auto result = ::system(format2("%s %s | %s", preparedCommand, localTargetPath, pagerProgram).c_str()); // return non-zero code in case of some error if (result) { return result; } } else { Manager::DownloadEntity downloadEntity; for (const auto& source: version->sources) { if (source.release->vendor != "Debian" && source.release->vendor != "Ubuntu") { // this is probably not a package from Debian or Ubuntu archive continue; } // all following is only good guessings string sourceVersionString = version->sourceVersionString; { // a hack to work around dropping epoch on Debian/Ubuntu web links auto position = sourceVersionString.find(':'); if (position != string::npos) { sourceVersionString = sourceVersionString.substr(position+1); } } const string& sourcePackageName = version->sourcePackageName; string shortPrefix = sourcePackageName.compare(0, 3, "lib") ? sourcePackageName.substr(0, 1) : sourcePackageName.substr(0, 4); string uri = baseUrisByVendor.find(source.release->vendor)->second + '/' + source.release->component + '/' + shortPrefix + '/' + sourcePackageName + '/' + sourcePackageName + '_' + sourceVersionString + '/' + typeString; const string& shortAlias = version->packageName; string longAlias = version->packageName + ' ' + version->versionString + ' ' + typeString; downloadEntity.extendedUris.push_back(Manager::ExtendedUri( uri, shortAlias, longAlias)); } if (!downloadEntity.extendedUris.empty()) { downloadEntity.size = (size_t)-1; char tempFilename[] = "cupt-download-XXXXXX"; if (mkstemp(tempFilename) == -1) { fatal2e(__("%s() failed"), "mkstemp"); } try { downloadEntity.targetPath = tempFilename; downloadEntity.postAction = []() { return string(); // no action }; string downloadError; { // downloading auto downloadProgress = getDownloadProgress(*config); Manager downloadManager(config, downloadProgress); downloadError = downloadManager.download( vector< Manager::DownloadEntity >{ downloadEntity }); } if (!downloadError.empty()) { fatal2(__("there were download errors")); } auto viewResult = ::system((pagerProgram + ' ' + tempFilename).c_str()); // remove the file if (unlink(tempFilename) == -1) { fatal2e(__("unable to remove the file '%s'"), tempFilename); } // return non-zero code in case of some error if (viewResult) { return viewResult; } } catch (...) { unlink(tempFilename); // without checking errors throw; } } else { fatal2(__("no info where to acquire %s for version '%s' of package '%s'"), typeString, version->versionString, version->packageName); } } } } return 0; } cupt-2.10.0/cpp/console/handlers/managepackages.cpp0000644000000000000000000015101013204267373017117 0ustar /************************************************************************** * Copyright (C) 2010-2011 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #include using std::cout; using std::endl; #include #include #include #include #include #include "../common.hpp" #include "../handlers.hpp" #include "../misc.hpp" #include "../selectors.hpp" #include "../colorizer.hpp" #include #include #include #include #include #include #include #include #include #include typedef Worker::Action WA; const WA::Type fakeNotPreferredVersionAction = WA::Type(999); const WA::Type fakeAutoRemove = WA::Type(1000); const WA::Type fakeAutoPurge = WA::Type(1001); const WA::Type fakeBecomeAutomaticallyInstalled = WA::Type(1002); const WA::Type fakeBecomeManuallyInstalled = WA::Type(1003); struct VersionChoices { string packageName; vector< const BinaryVersion* > versions; string getFullAnnotation(const string& requestAnnotation) const { return requestAnnotation + format2(" | for package '%s'", packageName); } }; struct ManagePackagesContext { enum class AutoInstall { Yes, No, Nop }; enum class SelectType { Traditional, Flexible }; ManagePackages::Mode mode; AutoInstall autoinstall; SelectType selectType; Resolver::RequestImportance importance; Config* config; const Cache* cache; Resolver* resolver; Worker* worker; bool oneLetterSuffixDeprecationWarningIssued = false; typedef vector< VersionChoices > SelectedVersions; SelectedVersions selectVersions(const string& expression, bool throwOnError = true) { auto selector = (selectType == SelectType::Traditional ? selectBinaryVersionsWildcarded : selectAllBinaryVersionsWildcarded); SelectedVersions result; // grouping by package for (auto version: selector(*cache, expression, throwOnError)) { if (result.empty() || result.back().packageName != version->packageName) { result.push_back(VersionChoices{version->packageName, {}}); } result.back().versions.push_back(version); } return result; } void install(const VersionChoices& versionChoices, const string& requestAnnotation) { resolver->installVersion(versionChoices.versions, versionChoices.getFullAnnotation(requestAnnotation), importance); } void remove(const VersionChoices& versionChoices, const string& requestAnnotation) { const auto& fullAnnotation = versionChoices.getFullAnnotation(requestAnnotation); if (selectType == SelectType::Traditional) { // removing all the package regardless of what versions of packages // were chosen if (!versionChoices.versions.empty()) { const string& packageName = versionChoices.packageName; resolver->removeVersions(cache->getBinaryPackage(packageName)->getVersions(), fullAnnotation, importance); } } else { resolver->removeVersions(versionChoices.versions, fullAnnotation, importance); } } void satisfy(const RelationExpression& relationExpression, bool inverted, const string& requestAnnotation) { resolver->satisfyRelationExpression(relationExpression, inverted, requestAnnotation, importance, autoinstall != AutoInstall::No); } }; static const char* modeToString(ManagePackages::Mode mode) { switch (mode) { case ManagePackages::Install: return "install"; case ManagePackages::InstallIfInstalled: return "iii"; case ManagePackages::Remove: return "remove"; case ManagePackages::Purge: return "purge"; case ManagePackages::BuildDepends: return "build-dependencies of"; case ManagePackages::Reinstall: return "reinstall"; default: return ""; } } static string getRequestAnnotation(ManagePackages::Mode mode, const string& expression) { return format2("%s %s", modeToString(mode), expression); } static void preProcessMode(ManagePackagesContext& mpc) { if (mpc.mode == ManagePackages::SelfUpgrade) { mpc.mode = ManagePackages::Install; } if (mpc.mode == ManagePackages::FullUpgrade || mpc.mode == ManagePackages::SafeUpgrade) { if (mpc.mode == ManagePackages::SafeUpgrade) { mpc.config->setScalar("cupt::resolver::no-remove", "yes"); } mpc.resolver->upgrade(); // despite the main action is {safe,full}-upgrade, allow package // modifiers in the command line just as with the install command mpc.mode = ManagePackages::Install; } else if (mpc.mode == ManagePackages::Satisfy || mpc.mode == ManagePackages::BuildDepends) { mpc.config->setScalar("apt::install-recommends", "no"); mpc.config->setScalar("apt::install-suggests", "no"); } else if (mpc.mode == ManagePackages::BuildDepends) { mpc.satisfy(RelationExpression("build-essential"), false, string()); } } static void unrollFileArguments(vector< string >& arguments) { vector< string > newArguments; for (const string& argument: arguments) { if (!argument.empty() && argument[0] == '@') { const string path = argument.substr(1); // reading package expressions from file RequiredFile file(path, "r"); string line; while (!file.getLine(line).eof()) { newArguments.push_back(line); } } else { newArguments.push_back(argument); } } arguments.swap(newArguments); } void __satisfy_or_unsatisfy(ManagePackagesContext& mpc, const RelationLine& relationLine, ManagePackages::Mode mode, const string& annotation = string()) { for (const auto& relationExpression: relationLine) { mpc.satisfy(relationExpression, (mode == ManagePackages::Unsatisfy), annotation); } } static void processSatisfyExpression(ManagePackagesContext& mpc, string packageExpression) { auto localMode = mpc.mode; if (localMode == ManagePackages::Satisfy && !packageExpression.empty() && *(packageExpression.rbegin()) == '-') { localMode = ManagePackages::Unsatisfy; packageExpression.erase(packageExpression.end() - 1); } auto relationLine = ArchitecturedRelationLine(packageExpression) .toRelationLine(mpc.config->getString("apt::architecture")); __satisfy_or_unsatisfy(mpc, relationLine, localMode); } static void processBuildDependsExpression(ManagePackagesContext& mpc, const string& packageExpression) { auto architecture = mpc.config->getString("apt::architecture"); auto versions = selectSourceVersionsWildcarded(*mpc.cache, packageExpression); auto annotation = getRequestAnnotation(mpc.mode, packageExpression); for (const auto& version: versions) { __satisfy_or_unsatisfy(mpc, version->relations[SourceVersion::RelationTypes::BuildDepends] .toRelationLine(architecture), ManagePackages::Satisfy, annotation); __satisfy_or_unsatisfy(mpc, version->relations[SourceVersion::RelationTypes::BuildDependsIndep] .toRelationLine(architecture), ManagePackages::Satisfy, annotation); __satisfy_or_unsatisfy(mpc, version->relations[SourceVersion::RelationTypes::BuildDependsArch] .toRelationLine(architecture), ManagePackages::Satisfy, annotation); __satisfy_or_unsatisfy(mpc, version->relations[SourceVersion::RelationTypes::BuildConflicts] .toRelationLine(architecture), ManagePackages::Unsatisfy, annotation); __satisfy_or_unsatisfy(mpc, version->relations[SourceVersion::RelationTypes::BuildConflictsIndep] .toRelationLine(architecture), ManagePackages::Unsatisfy, annotation); __satisfy_or_unsatisfy(mpc, version->relations[SourceVersion::RelationTypes::BuildConflictsArch] .toRelationLine(architecture), ManagePackages::Unsatisfy, annotation); } } static void processInstallOrRemoveExpression(ManagePackagesContext& mpc, string packageExpression) { auto localMode = mpc.mode; auto versions = mpc.selectVersions(packageExpression, false); if (versions.empty()) { /* we have a funny situation with package names like 'g++', where one don't know is there simple package name or '+'/'-' modifier at the end of package name, so we enter here only if it seems that there is no such binary package */ // "localizing" action to make it modifiable by package modifiers if (!packageExpression.empty()) { const auto oldPackageExpression = packageExpression; const char& lastLetter = *(packageExpression.end() - 1); if (lastLetter == '+') { localMode = ManagePackages::Install; packageExpression.erase(packageExpression.end() - 1); } else if (lastLetter == '-') { localMode = ManagePackages::Remove; packageExpression.erase(packageExpression.end() - 1); } if (!mpc.oneLetterSuffixDeprecationWarningIssued && oldPackageExpression != packageExpression) { warn2("Package suffixes '+' and '-' are deprecated. Please use '--install' and '--remove', respectively."); mpc.oneLetterSuffixDeprecationWarningIssued = true; } } } if (localMode == ManagePackages::Install || localMode == ManagePackages::InstallIfInstalled) { if (versions.empty()) { versions = mpc.selectVersions(packageExpression); } for (const auto& versionChoices: versions) { const auto& packageName = versionChoices.packageName; if (localMode == ManagePackages::InstallIfInstalled) { if (!isPackageInstalled(*mpc.cache, packageName)) { continue; } } mpc.install(versionChoices, getRequestAnnotation(localMode, packageExpression)); if (mpc.autoinstall == ManagePackagesContext::AutoInstall::Yes) { mpc.resolver->setAutomaticallyInstalledFlag(packageName, true); } else if (mpc.autoinstall == ManagePackagesContext::AutoInstall::No) { mpc.resolver->setAutomaticallyInstalledFlag(packageName, false); } } } else // ManagePackages::Remove or ManagePackages::Purge { if (versions.empty()) { // retry, still non-fatal to deal with packages in 'config-files' state versions = mpc.selectVersions(packageExpression, false); } auto scheduleRemoval = [&mpc, localMode, &packageExpression](const VersionChoices& versionChoices) { mpc.remove(versionChoices, getRequestAnnotation(localMode, packageExpression)); if (localMode == ManagePackages::Purge) { mpc.worker->setPackagePurgeFlag(versionChoices.packageName, true); } }; if (!versions.empty()) { for (const auto& versionChoices: versions) { scheduleRemoval(versionChoices); } } else { checkPackageName(packageExpression); if (!mpc.cache->getSystemState()->getInstalledInfo(packageExpression) && !getBinaryPackage(*mpc.cache, packageExpression, false)) { fatal2(__("unable to find binary package/expression '%s'"), packageExpression); } scheduleRemoval(VersionChoices{packageExpression, {}}); } } } static void processAutoFlagChangeExpression(ManagePackagesContext& mpc, const string& packageExpression) { getBinaryPackage(*mpc.cache, packageExpression); // will throw if package name is wrong mpc.resolver->setAutomaticallyInstalledFlag(packageExpression, (mpc.mode == ManagePackages::Markauto)); } static void processReinstallExpression(ManagePackagesContext& mpc, const string& packageExpression) { auto package = getBinaryPackage(*mpc.cache, packageExpression); auto installedVersion = package->getInstalledVersion(); if (!installedVersion) { fatal2(__("the package '%s' is not installed"), packageExpression); } const auto targetVersionString = getOriginalVersionString(installedVersion->versionString); std::vector candidates; for (auto version: *package) { if (version != installedVersion) { if (getOriginalVersionString(version->versionString).equal(targetVersionString)) { candidates.push_back(version); } } } if (!candidates.empty()) { mpc.resolver->installVersion(candidates, getRequestAnnotation(mpc.mode, packageExpression), mpc.importance); } else { const auto message = format2(__("the package '%s' cannot be reinstalled because there is no corresponding version (%s) available in repositories"), packageExpression, targetVersionString.toStdString()); if (mpc.importance == Resolver::RequestImportance::Must) { fatal2(message); } else { warn2(message); } } } static bool processNumericImportanceOption(ManagePackagesContext& mpc, const string& arg) { const char field[] = "--importance="; const size_t fieldLength = sizeof(field)-1; if (arg.compare(0, fieldLength, field) == 0) { try { mpc.importance = boost::lexical_cast< Resolver::RequestImportance::Value >(arg.substr(fieldLength)); } catch (boost::bad_lexical_cast&) { fatal2("option '--importance' requires non-negative numeric value"); } return true; } else { return false; } } static bool processPositionalOption(ManagePackagesContext& mpc, const string& arg) { if (arg == "--remove") mpc.mode = ManagePackages::Remove; else if (arg == "--purge") mpc.mode = ManagePackages::Purge; else if (arg == "--install") mpc.mode = ManagePackages::Install; else if (arg == "--satisfy") mpc.mode = ManagePackages::Satisfy; else if (arg == "--unsatisfy") mpc.mode = ManagePackages::Unsatisfy; else if (arg == "--markauto") mpc.mode = ManagePackages::Markauto; else if (arg == "--unmarkauto") mpc.mode = ManagePackages::Unmarkauto; else if (arg == "--iii") mpc.mode = ManagePackages::InstallIfInstalled; else if (arg == "--reinstall") mpc.mode = ManagePackages::Reinstall; else if (arg == "--asauto=yes") mpc.autoinstall = ManagePackagesContext::AutoInstall::Yes; else if (arg == "--asauto=no") mpc.autoinstall = ManagePackagesContext::AutoInstall::No; else if (arg == "--asauto=default") mpc.autoinstall = ManagePackagesContext::AutoInstall::Nop; else if (arg == "--select=traditional" || arg == "--st") mpc.selectType = ManagePackagesContext::SelectType::Traditional; else if (arg == "--select=flexible" || arg == "--sf") mpc.selectType = ManagePackagesContext::SelectType::Flexible; else if (arg == "--importance=wish" || arg == "--wish") mpc.importance = Resolver::RequestImportance::Wish; else if (arg == "--importance=try" || arg == "--try") mpc.importance = Resolver::RequestImportance::Try; else if (arg == "--importance=must" || arg == "--must") mpc.importance = Resolver::RequestImportance::Must; else if (processNumericImportanceOption(mpc, arg)) ; else return false; return true; // if some option was processed } static void processPackageExpressions(ManagePackagesContext& mpc, const vector< string >& packageExpressions) { for (const auto& packageExpression: packageExpressions) { if (processPositionalOption(mpc, packageExpression)) continue; if (mpc.mode == ManagePackages::Satisfy || mpc.mode == ManagePackages::Unsatisfy) { processSatisfyExpression(mpc, packageExpression); } else if (mpc.mode == ManagePackages::BuildDepends) { processBuildDependsExpression(mpc, packageExpression); } else if (mpc.mode == ManagePackages::Markauto || mpc.mode == ManagePackages::Unmarkauto) { processAutoFlagChangeExpression(mpc, packageExpression); } else if (mpc.mode == ManagePackages::Reinstall) { processReinstallExpression(mpc, packageExpression); } else { processInstallOrRemoveExpression(mpc, packageExpression); } } } void printUnpackedSizeChanges(const map< string, ssize_t >& unpackedSizesPreview) { ssize_t totalUnpackedSizeChange = 0; for (const auto& previewRecord: unpackedSizesPreview) { totalUnpackedSizeChange += previewRecord.second; } string message; if (totalUnpackedSizeChange >= 0) { message = format2(__("After unpacking %s will be used."), humanReadableSizeString(totalUnpackedSizeChange)); } else { message = format2(__("After unpacking %s will be freed."), humanReadableSizeString(-totalUnpackedSizeChange)); } cout << message << endl; } void printDownloadSizes(const pair< size_t, size_t >& downloadSizes) { auto total = downloadSizes.first; auto need = downloadSizes.second; cout << format2(__("Need to get %s/%s of archives. "), humanReadableSizeString(need), humanReadableSizeString(total)); } struct VersionInfoFlags { bool versionString; enum class DistributionType { None, Archive, Codename }; DistributionType distributionType; bool component; bool vendor; bool showEmpty; VersionInfoFlags(const Config& config) { versionString = config.getBool("cupt::console::actions-preview::show-versions"); if (config.getBool("cupt::console::actions-preview::show-archives")) { distributionType = DistributionType::Archive; } else if (config.getBool("cupt::console::actions-preview::show-codenames")) { distributionType = DistributionType::Codename; } else { distributionType = DistributionType::None; } component = config.getBool("cupt::console::actions-preview::show-components"); vendor = config.getBool("cupt::console::actions-preview::show-vendors"); showEmpty = config.getBool("cupt::console::actions-preview::show-empty-versions"); } bool empty() const { return !versionString && distributionType == DistributionType::None && !component && !vendor; } }; void showVersionInfoIfNeeded(const Cache& cache, const string& packageName, const Resolver::SuggestedPackage& suggestedPackage, WA::Type actionType, VersionInfoFlags flags) { if (flags.empty()) { return; // nothing to print } auto getVersionString = [&flags](const Version* version) -> string { if (!version) { return flags.showEmpty ? "" : ""; } string result; if (flags.versionString) { result += version->versionString; } if ((flags.distributionType != VersionInfoFlags::DistributionType::None) || flags.component || flags.vendor) { result += '('; vector< string > chunks; for (const auto& source: version->sources) { string chunk; if (flags.vendor && !source.release->vendor.empty()) { chunk += source.release->vendor; chunk += ':'; } if (flags.distributionType == VersionInfoFlags::DistributionType::Archive) { chunk += source.release->archive; } else if (flags.distributionType == VersionInfoFlags::DistributionType::Codename) { chunk += source.release->codename; } if (flags.component && !source.release->component.empty()) { chunk += "/"; chunk += source.release->component; } if (!chunk.empty() && std::find(chunks.begin(), chunks.end(), chunk) == chunks.end()) { chunks.push_back(chunk); } } result += join(",", chunks); result += ')'; } return result; }; auto package = cache.getBinaryPackage(packageName); string oldVersionString = getVersionString(package ? package->getInstalledVersion() : nullptr); string newVersionString = getVersionString(suggestedPackage.version); if (!oldVersionString.empty() && !newVersionString.empty() && (actionType != fakeNotPreferredVersionAction || oldVersionString != newVersionString)) { cout << format2(" [%s -> %s]", oldVersionString, newVersionString); } else if (!oldVersionString.empty()) { cout << format2(" [%s]", oldVersionString); } else { cout << format2(" [%s]", newVersionString); } if (actionType == fakeNotPreferredVersionAction) { cout << ", " << __("preferred") << ": " << getVersionString(cache.getPreferredVersion(package)); } } void showSizeChange(ssize_t bytes) { if (bytes != 0) { auto sizeChangeString = (bytes >= 0) ? string("+") + humanReadableSizeString(bytes) : string("-") + humanReadableSizeString(-bytes); cout << " <" << sizeChangeString << '>'; } } void printByLine(const vector< string >& strings) { cout << endl; for (const auto& s: strings) { cout << s << endl; } cout << endl; } void checkForUntrustedPackages(const Worker::ActionsPreview& actionsPreview, bool* isDangerous) { vector< string > untrustedPackageNames; // generate loud warning for unsigned versions const WA::Type affectedActionTypes[] = { WA::Reinstall, WA::Install, WA::Upgrade, WA::Downgrade }; for (auto actionType: affectedActionTypes) { for (const auto& suggestedRecord: actionsPreview.groups[actionType]) { if (!(suggestedRecord.second.version->isVerified())) { untrustedPackageNames.push_back(suggestedRecord.first); } } } if (!untrustedPackageNames.empty()) { *isDangerous = true; cout << __("WARNING! The untrusted versions of the following packages will be used:") << endl; printByLine(untrustedPackageNames); } } void checkForRemovalOfPackages(const Cache& cache, const Worker::ActionsPreview& actionsPreview, bool* isDangerous, const char* desc, const std::function& predicate) { vector affectedPackageNames; const WA::Type affectedActionTypes[] = { WA::Remove, WA::Purge }; for (auto actionType: affectedActionTypes) { for (const auto& suggestedRecord: actionsPreview.groups[actionType]) { const string& packageName = suggestedRecord.first; auto package = cache.getBinaryPackage(packageName); if (package) { auto version = package->getInstalledVersion(); if (version) // may return false when purge of config-files package when candidates available { if (predicate(version)) { affectedPackageNames.push_back(packageName); } } } } } if (!affectedPackageNames.empty()) { *isDangerous = true; cout << __(desc) << endl; printByLine(affectedPackageNames); } } void checkForRemovalOfEssentialPackages(const Cache& cache, const Worker::ActionsPreview& actionsPreview, bool* isDangerous) { const char desc[] = "WARNING! The following essential packages will be removed:"; checkForRemovalOfPackages(cache, actionsPreview, isDangerous, desc, [](const BinaryVersion* v) { return v->essential; }); } void checkForRemovalOfImportantPackages(const Cache& cache, const Worker::ActionsPreview& actionsPreview, bool* isDangerous) { const char desc[] = "WARNING! The following important packages will be removed:"; checkForRemovalOfPackages(cache, actionsPreview, isDangerous, desc, [](const BinaryVersion* v) { return v->important; }); } void checkForIgnoredHolds(const Cache& cache, const Worker::ActionsPreview& actionsPreview, bool* isDangerous) { vector< string > ignoredHoldsPackageNames; const WA::Type affectedActionTypes[] = { WA::Install, WA::Upgrade, WA::Downgrade, WA::Remove, WA::Purge }; for (auto actionType: affectedActionTypes) { for (const auto& suggestedRecord: actionsPreview.groups[actionType]) { const string& packageName = suggestedRecord.first; auto installedInfo = cache.getSystemState()->getInstalledInfo(packageName); if (installedInfo && installedInfo->want == system::State::InstalledRecord::Want::Hold && installedInfo->status != system::State::InstalledRecord::Status::ConfigFiles) { ignoredHoldsPackageNames.push_back(packageName); } } } if (!ignoredHoldsPackageNames.empty()) { *isDangerous = true; cout << __("WARNING! The following packages on hold will change their state:") << endl; printByLine(ignoredHoldsPackageNames); } } void checkForMultiArchSystem(const Config& config, bool* isDangerousAction) { auto foreignArchitectures = config.getList("cupt::cache::foreign-architectures"); if (!foreignArchitectures.empty()) { *isDangerousAction = true; cout << __("WARNING! You are running cupt on MultiArch-enabled system. This setup is not supported at the moment.") << endl; cout << __("Any actions may break your system.") << endl; cout << format2(__("Detected foreign architectures: %s"), join(", ", foreignArchitectures)) << endl; cout << endl; } } void checkAndPrintDangerousActions(const Config& config, const Cache& cache, const Worker::ActionsPreview& actionsPreview, bool* isDangerousAction) { if (!config.getBool("cupt::console::allow-untrusted")) { checkForUntrustedPackages(actionsPreview, isDangerousAction); } if (config.getBool("cupt::console::warnings::removal-of-essential")) { checkForRemovalOfEssentialPackages(cache, actionsPreview, isDangerousAction); } if (config.getBool("cupt::console::warnings::removal-of-important")) { checkForRemovalOfImportantPackages(cache, actionsPreview, isDangerousAction); } checkForIgnoredHolds(cache, actionsPreview, isDangerousAction); checkForMultiArchSystem(config, isDangerousAction); if (!actionsPreview.groups[WA::Downgrade].empty()) { *isDangerousAction = true; } } void showReason(const Resolver::SuggestedPackage& suggestedPackage) { for (const auto& reason: suggestedPackage.reasons) { cout << " " << __("reason: ") << reason->toString() << endl; } if (!suggestedPackage.reasonPackageNames.empty()) { cout << " " << __("caused by changes in: ") << join(", ", suggestedPackage.reasonPackageNames) << endl; } cout << endl; } void showUnsatisfiedSoftDependencies(const Resolver::Offer& offer, bool showDetails, std::stringstream* summaryStreamPtr) { vector< string > messages; for (const auto& unresolvedProblem: offer.unresolvedProblems) { messages.push_back(unresolvedProblem->toString()); } if (!messages.empty()) { if (showDetails) { cout << __("Leave the following dependencies unresolved:") << endl; printByLine(messages); } *summaryStreamPtr << format2(__(" %u dependency problems will stay unresolved"), offer.unresolvedProblems.size()) << endl; } } void showReasonChainForAskedPackage(const Resolver::SuggestedPackages& suggestedPackages, const Worker::ActionsPreview& actionsPreview) { auto isPackageChangingItsState = [&actionsPreview](const string& packageName) { for (const auto& group: actionsPreview.groups) { if (group.count(packageName)) return true; } return false; }; cout << __("Enter a binary package name to show reason chain for (empty to cancel): "); string answer; std::getline(std::cin, answer); if (answer.empty()) return; const auto& topPackageName = answer; if (!isPackageChangingItsState(topPackageName)) { cout << format2(__("The package '%s' is not going to change its state."), topPackageName) << endl; return; } struct PackageAndLevel { string packageName; size_t level; }; std::stack< PackageAndLevel > reasonStack({ PackageAndLevel{ topPackageName, 0 } }); cout << endl; while (!reasonStack.empty()) { const string& packageName = reasonStack.top().packageName; if (!isPackageChangingItsState(packageName)) { reasonStack.pop(); continue; } auto reasonIt = suggestedPackages.find(packageName); const auto& reasons = reasonIt->second.reasons; if (reasons.empty()) { fatal2i("no reasons available for the package '%s'", packageName); } const auto& reasonPtr = reasons[0]; size_t level = reasonStack.top().level; cout << format2("%s%s: %s", string(level*2, ' '), packageName, reasonPtr->toString()) << endl; reasonStack.pop(); for (const string& reasonPackageName: reasonIt->second.reasonPackageNames) { reasonStack.push({ reasonPackageName, level + 1 }); } } cout << endl; } Resolver::UserAnswer::Type askUserAboutSolution(const Config& config, const Resolver::SuggestedPackages& suggestedPackages, const Worker::ActionsPreview& actionsPreview, bool isDangerous, bool& addArgumentsFlag) { string answer; if (config.getBool("cupt::console::assume-yes")) { answer = isDangerous ? "q" : "y"; if (isDangerous) { cout << __("Didn't confirm dangerous actions.") << endl; } } else { ask: cout << __("Do you want to continue? [y/N/q/a/rc/?] "); std::getline(std::cin, answer); if (!std::cin) { return Resolver::UserAnswer::Abandon; } for (char& c: answer) { c = std::tolower(c); } // lowercasing } // deciding if (answer == "y") { if (isDangerous) { const string confirmationForDangerousAction = __("Yes, do as I say!"); cout << format2(__("Dangerous actions selected. Type '%s' if you want to continue, or anything else to go back:"), confirmationForDangerousAction) << endl; std::getline(std::cin, answer); if (answer != confirmationForDangerousAction) { goto ask; } } return Resolver::UserAnswer::Accept; } else if (answer == "q") { return Resolver::UserAnswer::Abandon; } else if (answer == "a") { addArgumentsFlag = true; return Resolver::UserAnswer::Abandon; } else if (answer == "rc") { showReasonChainForAskedPackage(suggestedPackages, actionsPreview); goto ask; } else if (answer == "?") { cout << __("y: accept the solution") << endl; cout << __("n: reject the solution, try to find other ones") << endl; cout << __("q: reject the solution and exit") << endl; cout << __("a: specify an additional binary package expression") << endl; cout << __("rc: show a reason chain for a package") << endl; cout << __("?: output this help") << endl << endl; goto ask; } else { // user haven't chosen this solution, try next one cout << __("Resolving further... ") << endl; return Resolver::UserAnswer::Decline; } } Resolver::SuggestedPackages generateNotPreferredVersionList(const Cache& cache, const Resolver::SuggestedPackages& packages) { Resolver::SuggestedPackages result; for (const auto& suggestedPackage: packages) { const auto& suggestedVersion = suggestedPackage.second.version; if (suggestedVersion) { auto preferredVersion = cache.getPreferredVersion( getBinaryPackage(cache, suggestedVersion->packageName)); if (!(preferredVersion == suggestedVersion)) { result.insert(suggestedPackage); } } } return result; } static string colorizeByActionType(const Colorizer& colorizer, const string& input, WA::Type actionType, bool isAutoInstalled) { Colorizer::Color color = Colorizer::Default; switch (actionType) { case WA::Install: color = Colorizer::Cyan; break; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wswitch" case WA::Remove: case fakeAutoRemove: color = Colorizer::Yellow; break; case WA::Upgrade: color = Colorizer::Green; break; case WA::Purge: case fakeAutoPurge: color = Colorizer::Red; break; #pragma GCC diagnostic pop case WA::Downgrade: color = Colorizer::Magenta; break; case WA::Configure: color = Colorizer::Blue; break; default: ; } return colorizer.colorize(input, color, !isAutoInstalled /* bold */); } bool wasOrWillBePackageAutoInstalled(const Resolver::SuggestedPackage& suggestedPackage) { return suggestedPackage.automaticallyInstalledFlag; } static void printPackageName(const Colorizer& colorizer, const string& packageName, WA::Type actionType, const Resolver::SuggestedPackage& suggestedPackage) { bool isAutoInstalled = wasOrWillBePackageAutoInstalled(suggestedPackage); cout << colorizeByActionType(colorizer, packageName, actionType, isAutoInstalled); } static string colorizeActionName(const Colorizer& colorizer, const string& actionName, WA::Type actionType) { if (actionType != WA::Install && actionType != WA::Upgrade && actionType != WA::Configure && actionType != WA::ProcessTriggers && actionType != fakeAutoRemove && actionType != fakeAutoPurge && actionType != fakeBecomeAutomaticallyInstalled && actionType != fakeBecomeManuallyInstalled) { return colorizer.makeBold(actionName); } else { return actionName; } } void addActionToSummary(WA::Type actionType, const string& actionName, const Resolver::SuggestedPackages& suggestedPackages, Colorizer& colorizer, std::stringstream* summaryStreamPtr) { size_t manuallyInstalledCount = std::count_if(suggestedPackages.begin(), suggestedPackages.end(), [](const pair< string, Resolver::SuggestedPackage >& arg) { return !wasOrWillBePackageAutoInstalled(arg.second); }); size_t autoInstalledCount = suggestedPackages.size() - manuallyInstalledCount; auto getManualCountString = [manuallyInstalledCount, actionType, &colorizer]() { auto s = std::to_string(manuallyInstalledCount); return colorizeByActionType(colorizer, s, actionType, false); }; auto getAutoCountString = [autoInstalledCount, actionType, &colorizer]() { auto s = std::to_string(autoInstalledCount); return colorizeByActionType(colorizer, s, actionType, true); }; *summaryStreamPtr << " "; if (!manuallyInstalledCount) { *summaryStreamPtr << format2(__("%s automatically installed packages %s"), getAutoCountString(), actionName); } else if (!autoInstalledCount) { *summaryStreamPtr << format2(__("%s manually installed packages %s"), getManualCountString(), actionName); } else { *summaryStreamPtr << format2(__("%s manually installed and %s automatically installed packages %s"), getManualCountString(), getAutoCountString(), actionName); } *summaryStreamPtr << endl; } struct PackageIndicators { bool manuallyInstalled = false; bool autoInstalled = false; PackageIndicators(const Config& config, const Colorizer& colorizer) { if (colorizer.enabled()) return; const string optionPrefix("cupt::console::actions-preview::package-indicators"); manuallyInstalled = config.getBool(optionPrefix + "::manually-installed"); autoInstalled = config.getBool(optionPrefix + "::automatically-installed"); } }; struct PackageChangeInfoFlags { bool sizeChange; bool reasons; VersionInfoFlags versionFlags; PackageIndicators packageIndicators; PackageChangeInfoFlags(const Config& config, WA::Type actionType, const Colorizer& colorizer) : versionFlags(config) , packageIndicators(config, colorizer) { sizeChange = (config.getBool("cupt::console::actions-preview::show-size-changes") && actionType != fakeNotPreferredVersionAction); reasons = (config.getBool("cupt::console::actions-preview::show-reasons") && actionType != fakeNotPreferredVersionAction); } bool packagesTakeSameLine() const { return versionFlags.empty() && !sizeChange && !reasons; } }; static void printPackageIndicators(const Resolver::SuggestedPackage& suggestedPackage, PackageIndicators indicators) { bool isAutoInstalled = wasOrWillBePackageAutoInstalled(suggestedPackage); if (indicators.autoInstalled && isAutoInstalled) cout << "{a}"; if (indicators.manuallyInstalled && !isAutoInstalled) cout << "{m}"; } void showPackageChanges(const Config& config, const Cache& cache, Colorizer& colorizer, WA::Type actionType, const Resolver::SuggestedPackages& actionSuggestedPackages, const map< string, ssize_t >& unpackedSizesPreview) { PackageChangeInfoFlags showFlags(config, actionType, colorizer); for (const auto& it: actionSuggestedPackages) { const string& packageName = it.first; const auto& suggestedPackage = it.second; printPackageName(colorizer, packageName, actionType, suggestedPackage); printPackageIndicators(suggestedPackage, showFlags.packageIndicators); showVersionInfoIfNeeded(cache, packageName, suggestedPackage, actionType, showFlags.versionFlags); if (showFlags.sizeChange) showSizeChange(unpackedSizesPreview.find(packageName)->second); if (!showFlags.packagesTakeSameLine()) cout << endl; else cout << ' '; if (showFlags.reasons) showReason(suggestedPackage); } if (showFlags.packagesTakeSameLine()) cout << endl; cout << endl; } Resolver::SuggestedPackages filterNoLongerNeeded(const Resolver::SuggestedPackages& source, bool invert) { Resolver::SuggestedPackages result; for (const auto& suggestedPackage: source) { bool isNoLongerNeeded = false; for (const auto& reasonPtr: suggestedPackage.second.reasons) { if (dynamic_pointer_cast< const Resolver::AutoRemovalReason >(reasonPtr)) { isNoLongerNeeded = true; break; } } if (isNoLongerNeeded != invert) { result.insert(result.end(), suggestedPackage); } } return result; } Resolver::SuggestedPackages filterPureAutoStatusChanges(const Cache& cache, const Worker::ActionsPreview& actionsPreview, bool targetAutoStatus) { static const shared_ptr< Resolver::UserReason > userReason; Resolver::SuggestedPackages result; for (const auto& autoStatusChange: actionsPreview.autoFlagChanges) { if (autoStatusChange.second == targetAutoStatus) { const string& packageName = autoStatusChange.first; for (size_t ai = 0; ai < WA::Count; ++ai) { if (targetAutoStatus && ai != WA::Install) continue; if (!targetAutoStatus && (ai != WA::Remove && ai != WA::Purge)) continue; if (actionsPreview.groups[ai].count(packageName)) { goto next_package; // natural, non-pure change } } { Resolver::SuggestedPackage& entry = result[packageName]; entry.version = cache.getBinaryPackage(packageName)->getInstalledVersion(); entry.automaticallyInstalledFlag = !targetAutoStatus; entry.reasons.push_back(userReason); } next_package: ; } } return result; } Resolver::SuggestedPackages getSuggestedPackagesByAction(const Cache& cache, const Resolver::Offer& offer, const Worker::ActionsPreview& actionsPreview, WA::Type actionType) { switch (actionType) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wswitch" case fakeNotPreferredVersionAction: return generateNotPreferredVersionList(cache, offer.suggestedPackages); case fakeAutoRemove: return filterNoLongerNeeded(actionsPreview.groups[WA::Remove], false); case fakeAutoPurge: return filterNoLongerNeeded(actionsPreview.groups[WA::Purge], false); case fakeBecomeAutomaticallyInstalled: return filterPureAutoStatusChanges(cache, actionsPreview, true); case fakeBecomeManuallyInstalled: return filterPureAutoStatusChanges(cache, actionsPreview, false); #pragma GCC diagnostic pop case WA::Remove: return filterNoLongerNeeded(actionsPreview.groups[WA::Remove], true); case WA::Purge: return filterNoLongerNeeded(actionsPreview.groups[WA::Purge], true); default: return actionsPreview.groups[actionType]; } } map< WA::Type, string > getActionDescriptionMap() { return map< WA::Type, string > { { WA::Install, __("will be installed") }, { WA::Remove, __("will be removed") }, { WA::Upgrade, __("will be upgraded") }, { WA::Purge, __("will be purged") }, { WA::Downgrade, __("will be downgraded") }, { WA::Configure, __("will be configured") }, { WA::Deconfigure, __("will be deconfigured") }, { WA::ProcessTriggers, __("will have triggers processed") }, { WA::Reinstall, __("will be reinstalled") }, { fakeNotPreferredVersionAction, __("will have a not preferred version") }, { fakeAutoRemove, __("are no longer needed and thus will be auto-removed") }, { fakeAutoPurge, __("are no longer needed and thus will be auto-purged") }, { fakeBecomeAutomaticallyInstalled, __("will be marked as automatically installed") }, { fakeBecomeManuallyInstalled, __("will be marked as manually installed") }, }; } vector< WA::Type > getActionTypesInPrintOrder(bool showNotPreferred) { vector< WA::Type > result = { fakeBecomeAutomaticallyInstalled, fakeBecomeManuallyInstalled, WA::Reinstall, WA::Install, WA::Upgrade, WA::Remove, WA::Purge, WA::Downgrade, WA::Configure, WA::ProcessTriggers, WA::Deconfigure }; if (showNotPreferred) { result.push_back(fakeNotPreferredVersionAction); } result.push_back(fakeAutoRemove); result.push_back(fakeAutoPurge); return result; } bool isSummaryEnabled(const Config& config, size_t actionCount) { auto configValue = config.getString("cupt::console::actions-preview::show-summary"); return (configValue == "yes") || (actionCount > 100 && configValue == "auto"); } Resolver::CallbackType generateManagementPrompt(ManagePackagesContext& mpc, bool showNotPreferred, bool& addArgumentsFlag, bool& thereIsNothingToDo) { auto result = [&mpc, showNotPreferred, &addArgumentsFlag, &thereIsNothingToDo] (const Resolver::Offer& offer) -> Resolver::UserAnswer::Type { addArgumentsFlag = false; thereIsNothingToDo = false; auto showDetails = mpc.config->getBool("cupt::console::actions-preview::show-details"); mpc.worker->setDesiredState(offer); auto actionsPreview = mpc.worker->getActionsPreview(); auto unpackedSizesPreview = mpc.worker->getUnpackedSizesPreview(); Colorizer colorizer(*mpc.config); std::stringstream summaryStream; size_t actionCount = 0; { // print planned actions const auto actionDescriptions = getActionDescriptionMap(); cout << endl; for (const WA::Type& actionType: getActionTypesInPrintOrder(showNotPreferred)) { auto actionSuggestedPackages = getSuggestedPackagesByAction(*mpc.cache, offer, *actionsPreview, actionType); if (actionSuggestedPackages.empty()) continue; if (actionType != fakeNotPreferredVersionAction) { actionCount += actionSuggestedPackages.size(); } const string& actionName = actionDescriptions.find(actionType)->second; addActionToSummary(actionType, actionName, actionSuggestedPackages, colorizer, &summaryStream); if (!showDetails) continue; cout << format2(__("The following packages %s:"), colorizeActionName(colorizer, actionName, actionType)) << endl << endl; showPackageChanges(*mpc.config, *mpc.cache, colorizer, actionType, actionSuggestedPackages, unpackedSizesPreview); } showUnsatisfiedSoftDependencies(offer, showDetails, &summaryStream); }; // nothing to do maybe? if (actionCount == 0) { thereIsNothingToDo = true; return Resolver::UserAnswer::Abandon; } if (isSummaryEnabled(*mpc.config, actionCount)) { cout << __("Action summary:") << endl << summaryStream.str() << endl; summaryStream.clear(); } bool isDangerousAction = false; checkAndPrintDangerousActions(*mpc.config, *mpc.cache, *actionsPreview, &isDangerousAction); { // print size estimations auto downloadSizesPreview = mpc.worker->getDownloadSizesPreview(); printDownloadSizes(downloadSizesPreview); printUnpackedSizeChanges(unpackedSizesPreview); } return askUserAboutSolution(*mpc.config, offer.suggestedPackages, *actionsPreview, isDangerousAction, addArgumentsFlag); }; return result; } void parseManagementOptions(Context& context, ManagePackages::Mode mode, vector< string >& packageExpressions, bool& showNotPreferred) { bpo::options_description options; options.add_options() ("no-install-recommends,R", "") ("no-remove", "") ("no-auto-remove", "") ("max-solution-count", bpo::value< string >()) ("resolver", bpo::value< string >()) ("show-versions,V", "") ("show-size-changes,Z", "") ("show-reasons,D", "") ("show-archives,A", "") ("show-codenames,N", "") ("show-components,C", "") ("show-deps", "") ("show-not-preferred", "") ("show-vendors,O", "") ("download-only,d", "") ("summary-only", "") ("no-summary", "") ("assume-yes", "") ("yes,y", ""); // use action modifiers as arguments, not options auto extraParser = [](const string& input) -> pair< string, string > { ManagePackagesContext dummyMpc = { ManagePackages::Mode::Install, ManagePackagesContext::AutoInstall::Nop, ManagePackagesContext::SelectType::Traditional, 0, nullptr, nullptr, nullptr, nullptr }; if (processPositionalOption(dummyMpc, input)) { return make_pair("arguments", input); } else { return make_pair(string(), string()); } }; auto variables = parseOptions(context, options, packageExpressions, extraParser); auto config = context.getConfig(); if (variables.count("max-solution-count")) { config->setScalar("cupt::resolver::max-solution-count", variables["max-solution-count"].as()); } if (variables.count("resolver")) { config->setScalar("cupt::resolver::type", variables["resolver"].as()); } if (variables.count("assume-yes") || variables.count("yes")) { config->setScalar("cupt::console::assume-yes", "yes"); } if (variables.count("show-reasons") || variables.count("show-deps")) { config->setScalar("cupt::console::actions-preview::show-reasons", "yes"); } // we now always need reason tracking config->setScalar("cupt::resolver::track-reasons", "yes"); if (variables.count("no-install-recommends")) { config->setScalar("apt::install-recommends", "no"); } if (variables.count("no-remove")) { config->setScalar("cupt::resolver::no-remove", "yes"); } if (variables.count("download-only")) { config->setScalar("cupt::worker::download-only", "yes"); } if (variables.count("no-auto-remove")) { config->setScalar("cupt::resolver::auto-remove", "no"); } if (variables.count("summary-only")) { config->setScalar("cupt::console::actions-preview::show-summary", "yes"); config->setScalar("cupt::console::actions-preview::show-details", "no"); } if (variables.count("no-summary")) { config->setScalar("cupt::console::actions-preview::show-summary", "no"); config->setScalar("cupt::console::actions-preview::show-details", "yes"); } if (variables.count("show-versions")) { config->setScalar("cupt::console::actions-preview::show-versions", "yes"); } if (variables.count("show-size-changes")) { config->setScalar("cupt::console::actions-preview::show-size-changes", "yes"); } if (variables.count("show-archives")) { config->setScalar("cupt::console::actions-preview::show-archives", "yes"); } if (variables.count("show-codenames")) { config->setScalar("cupt::console::actions-preview::show-codenames", "yes"); } if (config->getBool("cupt::console::actions-preview::show-archives") && config->getBool("cupt::console::actions-preview::show-codenames")) { fatal2(__("options 'cupt::console::actions-preview::show-archives' and 'cupt::console::actions-preview::show-codenames' cannot be used together")); } if (variables.count("show-components")) { config->setScalar("cupt::console::actions-preview::show-components", "yes"); } if (variables.count("show-vendors")) { config->setScalar("cupt::console::actions-preview::show-vendors", "yes"); } string showNotPreferredConfigValue = config->getString("cupt::console::actions-preview::show-not-preferred"); showNotPreferred = variables.count("show-not-preferred") || showNotPreferredConfigValue == "yes" || ((mode == ManagePackages::FullUpgrade || mode == ManagePackages::SafeUpgrade) && showNotPreferredConfigValue == "for-upgrades"); if (mode == ManagePackages::SelfUpgrade) { packageExpressions = {"dpkg", "cupt"}; } } Resolver* getResolver(const shared_ptr< const Config >& config, const shared_ptr< const Cache >& cache) { if (!config->getString("cupt::resolver::external-command").empty()) { fatal2(__("using an external resolver is not supported now")); } return new NativeResolver(config, cache); } void queryAndProcessAdditionalPackageExpressions(ManagePackagesContext& mpc) { string answer; do { cout << __("Enter package expression(s) (empty to finish): "); std::getline(std::cin, answer); if (!answer.empty()) { processPackageExpressions(mpc, convertLineToShellArguments(answer)); } else { break; } } while (true); } class ProgressStage { bool p_print; public: ProgressStage(const Config& config) : p_print(config.getBool("cupt::console::show-progress-messages")) {} void operator()(const char* message) { if (p_print) { cout << message << endl; } } }; int managePackages(Context& context, ManagePackages::Mode mode) { auto config = context.getConfig(); ProgressStage stage(*config); // turn off info parsing, we don't need it if (!shellMode) { Version::parseInfoOnly = false; } Cache::memoize = true; vector< string > packageExpressions; bool showNotPreferred; parseManagementOptions(context, mode, packageExpressions, showNotPreferred); unrollFileArguments(packageExpressions); // snapshot handling string snapshotName; // empty if not applicable if (mode == ManagePackages::LoadSnapshot) { if (packageExpressions.size() != 1) { fatal2(__("exactly one argument (the snapshot name) should be specified")); } snapshotName = packageExpressions[0]; packageExpressions.clear(); { Snapshots snapshots(config); snapshots.setupConfigForSnapshotOnly(snapshotName); } mode = ManagePackages::Install; } shared_ptr< const Cache > cache; { // source packages are needed for for synchronizing source versions bool buildSource = (mode == ManagePackages::BuildDepends || config->getString("cupt::resolver::synchronize-by-source-versions") != "none"); stage(__("Building the package cache... ")); cache = context.getCache(buildSource, true, true); } stage(__("Initializing package resolver and worker... ")); std::unique_ptr< Resolver > resolver(getResolver(config, cache)); if (!snapshotName.empty()) { Snapshots snapshots(config); snapshots.setupResolverForSnapshotOnly(snapshotName, *cache, *resolver); } shared_ptr< Worker > worker(new Worker(config, cache)); ManagePackagesContext mpc = { mode, ManagePackagesContext::AutoInstall::Nop, ManagePackagesContext::SelectType::Traditional, Resolver::RequestImportance::Must, config.get(), cache.get(), resolver.get(), worker.get() }; stage(__("Scheduling requested actions... ")); preProcessMode(mpc); processPackageExpressions(mpc, packageExpressions); stage(__("Resolving possible unmet dependencies... ")); bool addArgumentsFlag, thereIsNothingToDo; auto callback = generateManagementPrompt(mpc, showNotPreferred, addArgumentsFlag, thereIsNothingToDo); resolve: addArgumentsFlag = false; thereIsNothingToDo = false; bool resolved = resolver->resolve(callback); if (addArgumentsFlag && std::cin) { queryAndProcessAdditionalPackageExpressions(mpc); goto resolve; } // at this stage resolver has done its work, so to does not consume the RAM resolver.reset(); if (thereIsNothingToDo) { cout << __("Nothing to do.") << endl; return 0; } else if (resolved) { // if some solution was found and user has accepted it auto downloadProgress = getDownloadProgress(*config); cout << __("Performing requested actions:") << endl; context.invalidate(); try { worker->changeSystem(downloadProgress); } catch (Exception&) { fatal2(__("unable to do requested actions")); } return 0; } else { cout << __("Abandoned or no more solutions.") << endl; return 1; } } int distUpgrade(Context& context) { if (shellMode) { fatal2(__("'dist-upgrade' command cannot be run in the shell mode")); } { // 1st stage: upgrading of package management tools cout << __("[ upgrading package management tools ]") << endl; cout << endl; if (managePackages(context, ManagePackages::SelfUpgrade) != 0) { fatal2(__("upgrading of the package management tools failed")); } } { // 2nd stage: full upgrade cout << endl; cout << __("[ upgrading the system ]"); cout << endl; auto argc = context.argc; auto argv = context.argv; for (int i = 0; i < argc; ++i) { if (!strcmp(argv[i], "dist-upgrade")) { strcpy(argv[i], "full-upgrade"); } } execvp(argv[0], argv); fatal2e(__("%s() failed"), "execvp"); } return 0; // unreachable due to exec } int updateReleaseAndIndexData(Context& context) { bpo::options_description noOptions; vector< string > arguments; auto variables = parseOptions(context, noOptions, arguments); checkNoExtraArguments(arguments); auto config = context.getConfig(); auto cache = context.getCache(false, false, false); auto downloadProgress = getDownloadProgress(*config); Worker worker(config, cache); context.invalidate(); // may throw exception worker.updateReleaseAndIndexData(downloadProgress); return 0; } int cleanArchives(Context& context, bool leaveAvailable) { if (!shellMode) { Version::parseInfoOnly = false; Version::parseRelations = false; } bpo::options_description noOptions; vector< string > arguments; auto variables = parseOptions(context, noOptions, arguments); checkNoExtraArguments(arguments); auto config = context.getConfig(); auto cache = context.getCache(false, leaveAvailable, leaveAvailable); Worker worker(config, cache); uint64_t totalDeletedBytes = 0; auto info = worker.getArchivesInfo(); for (const auto& infoRecord: info) { if (leaveAvailable && infoRecord.second /* version is not empty */) { continue; // skip this one } const string& path = infoRecord.first; struct stat stat_structure; if (lstat(path.c_str(), &stat_structure)) { fatal2e(__("%s() failed: '%s'"), "lstat", path); } else { size_t size = stat_structure.st_size; totalDeletedBytes += size; cout << format2(__("Deleting '%s' <%s>..."), path, humanReadableSizeString(size)) << endl; worker.deleteArchive(path); } } cout << format2(__("Freed %s of disk space."), humanReadableSizeString(totalDeletedBytes)) << endl; cout << __("Deleting partial archives...") << endl; worker.deletePartialArchives(); return 0; } cupt-2.10.0/cpp/console/handlers/misc.cpp0000644000000000000000000005216713204267373015140 0ustar /************************************************************************** * Copyright (C) 2010-2011 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #include using std::cout; using std::endl; #include using std::set; #include using std::queue; #include #include #include #include #include #include #include "../common.hpp" #include "../handlers.hpp" #include "../misc.hpp" #include "../selectors.hpp" namespace { // "print tag" void p(const string& first, const string& second, bool withNewLine = true) { if (!second.empty()) { cout << first << ": " << second; if (withNewLine) cout << endl; } } string getPrintableInstalledStatus(const Cache& cache, const string& packageName) { auto installedInfo = cache.getSystemState()->getInstalledInfo(packageName); string status = __(system::State::InstalledRecord::Status::strings[installedInfo->status].c_str()); if (installedInfo->want == system::State::InstalledRecord::Want::Hold) { status += string(" (") + __("on hold") + ")"; } return status; } vector toStrings(const vector& input) { vector result; for (const auto& elem: input) { result.push_back(elem.toString()); } return result; } } int showBinaryVersions(Context& context) { auto config = context.getConfig(); vector< string > arguments; bpo::options_description options(""); options.add_options() ("installed-only", "") ("with-release-info", ""); auto variables = parseOptions(context, options, arguments); if (arguments.empty()) { fatal2(__("no binary package expressions specified")); } if (!shellMode) { Version::parseOthers = true; } auto cache = context.getCache( /* source */ any_of(arguments.begin(), arguments.end(), &isFunctionExpression), /* binary */ variables.count("installed-only") == 0, /* installed */ true); auto getReverseProvides = [&cache](const string& packageName) -> RelationLine { RelationLine result; if (!checkPackageName(packageName, false)) { return result; } RelationExpression virtualRelationExpression(packageName); for (const auto& version: cache->getSatisfyingVersions(virtualRelationExpression)) { // we don't need versions of the same package const auto& newPackageName = version->packageName; if (newPackageName == packageName) continue; result.push_back(RelationExpression{ newPackageName + " (= " + version->versionString + ")" }); } return result; }; for (const string& packageExpression: arguments) { vector< const BinaryVersion* > versions; if (config->getBool("apt::cache::allversions")) { versions = selectAllBinaryVersionsWildcarded(*cache, packageExpression); } else { if (!cache->getBinaryPackage(packageExpression)) { // there is no such binary package, maybe it's virtual? auto reverseProvides = getReverseProvides(packageExpression); if (!reverseProvides.empty()) { p(__("Pure virtual package, provided by"), reverseProvides.toString()); continue; } } versions = selectBinaryVersionsWildcarded(*cache, packageExpression); } for (const auto& version: versions) { auto packageName = version->packageName; p(__("Package"), packageName); p(__("Version"), version->versionString); if (version->isInstalled()) { p(__("Status"), getPrintableInstalledStatus(*cache, packageName)); bool isAutoInstalled = cache->isAutomaticallyInstalled(packageName); p(__("Automatically installed"), isAutoInstalled ? __("yes") : __("no")); } else { p(__("Status"), __("not installed")); } p(__("Source"), version->sourcePackageName); if (version->sourceVersionString != version->versionString) { p(__("Source version"), version->sourceVersionString); } if (version->essential) { p(__("Essential"), __("yes")); } if (version->important) { p(__("Important"), __("yes")); } p(__("Priority"), __(Version::Priorities::strings[version->priority].c_str())); p(__("Section"), version->section); if (version->file.size) { p(__("Size"), humanReadableSizeString(version->file.size)); } p(__("Uncompressed size"), humanReadableSizeString(version->installedSize)); p(__("Maintainer"), version->maintainer); p(__("Architecture"), version->architecture); if (variables.count("with-release-info")) { for (size_t i = 0; i < version->sources.size(); ++i) { const Version::Source& entry = version->sources[i]; p(__("Release"), entry.release->description); } } for (size_t i = 0; i < BinaryVersion::RelationTypes::Count; ++i) { p(__(BinaryVersion::RelationTypes::strings[i].c_str()), version->relations[i].toString()); } p(__("Provides"), join(", ", toStrings(version->provides))); auto reverseProvides = getReverseProvides(packageName); p(__("Provided by"), reverseProvides.toString()); { for (const auto& downloadRecord: version->getDownloadInfo()) { p("URI", downloadRecord.baseUri + '/' + downloadRecord.directory + '/' + version->file.name); } } p("Multi-Arch", version->multiarch); p("MD5", version->file.hashSums[HashSums::MD5]); p("SHA1", version->file.hashSums[HashSums::SHA1]); p("SHA256", version->file.hashSums[HashSums::SHA256]); p(__("Description"), cache->getLocalizedDescription(version), false); p(__("Tags"), version->tags); if (version->others) { for (const auto& field: *(version->others)) { p(field.first, field.second); } } cout << endl; } } return 0; } int showSourceVersions(Context& context) { auto config = context.getConfig(); vector< string > arguments; bpo::options_description options(""); options.add_options() ("with-release-info", ""); auto variables = parseOptions(context, options, arguments); if (arguments.empty()) { fatal2(__("no source package expressions specified")); } if (!shellMode) { Version::parseOthers = true; } auto cache = context.getCache(/* source */ true, /* binary */ true, /* installed */ true); for (size_t i = 0; i < arguments.size(); ++i) { const string& packageExpression = arguments[i]; vector< const SourceVersion* > versions; if (config->getBool("apt::cache::allversions")) { versions = selectAllSourceVersionsWildcarded(*cache, packageExpression); } else { versions = selectSourceVersionsWildcarded(*cache, packageExpression); } for (const auto& version: versions) { auto packageName = version->packageName; p(__("Package"), packageName); p(__("Binary"), join(", ", version->binaryPackageNames)); p(__("Version"), version->versionString); p(__("Priority"), __(Version::Priorities::strings[version->priority].c_str())); p(__("Section"), version->section); p(__("Maintainer"), version->maintainer); if (!version->uploaders.empty()) { p(__("Uploaders"), join(", ", version->uploaders)); } p(__("Architectures"), join(" ", version->architectures)); if (variables.count("with-release-info")) { for (size_t i = 0; i < version->sources.size(); ++i) { const Version::Source& entry = version->sources[i]; p(__("Release"), entry.release->description); } } for (size_t i = 0; i < SourceVersion::RelationTypes::Count; ++i) { p(__(SourceVersion::RelationTypes::strings[i].c_str()), version->relations[i].toString()); } { // download info for (size_t i = 0; i < SourceVersion::FileParts::Count; ++i) { for (const Version::FileRecord& fileRecord: version->files[i]) { cout << __(SourceVersion::FileParts::strings[i].c_str()) << ':' << endl; p(string(" ") + __("Size"), humanReadableSizeString(fileRecord.size)); p(" MD5", fileRecord.hashSums[HashSums::MD5]); p(" SHA1", fileRecord.hashSums[HashSums::SHA1]); p(" SHA256", fileRecord.hashSums[HashSums::SHA256]); for (const auto& it: version->getDownloadInfo()) { p(" URI", it.baseUri + "/" + it.directory + "/" + fileRecord.name); } } } } if (version->others) { for (const auto& it: *(version->others)) { p(it.first, it.second); } } cout << endl; } } return 0; } int showRelations(Context& context, bool reverse) { // turn off info parsing, we don't need it, only relations :) if (!shellMode) { Version::parseInfoOnly = false; } auto config = context.getConfig(); vector< string > arguments; bpo::options_description options(""); options.add_options() ("installed-only", "") ("with-suggests", ""); auto variables = parseOptions(context, options, arguments); if (arguments.empty()) { fatal2(__("no binary package expressions specified")); } if (reverse) { Cache::memoize = true; } auto cache = context.getCache(/* source */ false, /* binary */ variables.count("installed-only") == 0, /* installed */ true); queue< const BinaryVersion* > versions; for (const string& arg: arguments) { for (auto selectedVersion: selectBinaryVersionsWildcarded(*cache, arg)) { versions.push(selectedVersion); } } vector< BinaryVersion::RelationTypes::Type > relationGroups; relationGroups.push_back(BinaryVersion::RelationTypes::PreDepends); relationGroups.push_back(BinaryVersion::RelationTypes::Depends); if (!config->getBool("apt::cache::important")) { relationGroups.push_back(BinaryVersion::RelationTypes::Recommends); if (variables.count("with-suggests")) { relationGroups.push_back(BinaryVersion::RelationTypes::Suggests); } } // don't output the same version more than one time set< const BinaryVersion* > processedVersions; // used only by rdepends ReverseDependsIndex< BinaryVersion > reverseDependsIndex(*cache); if (reverse) { for (auto relationType: relationGroups) { reverseDependsIndex.add(relationType); } } bool recurse = config->getBool("apt::cache::recursedepends"); bool allVersions = config->getBool("apt::cache::allversions"); while (!versions.empty()) { auto version = versions.front(); versions.pop(); const string& packageName = version->packageName; const string& versionString = version->versionString; if (!processedVersions.insert(version).second) { continue; } cout << packageName << ' ' << versionString << ':' << endl; for (const auto& relationGroup: relationGroups) { const string& caption = __(BinaryVersion::RelationTypes::strings[relationGroup].c_str()); if (!reverse) { // just plain normal dependencies for (const auto& relationExpression: version->relations[relationGroup]) { cout << " " << caption << ": " << relationExpression.toString() << endl; if (recurse) { // insert recursive depends into queue auto satisfyingVersions = cache->getSatisfyingVersions(relationExpression); if (allVersions) { for (auto satisfyingVersion: satisfyingVersions) { versions.push(satisfyingVersion); } } else { // push the version with the maximum pin if (!satisfyingVersions.empty()) { auto preferredVersion = satisfyingVersions[0]; for (auto satisfyingVersionIt = satisfyingVersions.begin() + 1; satisfyingVersionIt != satisfyingVersions.end(); ++satisfyingVersionIt) { if (cache->getPin(*satisfyingVersionIt) > cache->getPin(preferredVersion)) { preferredVersion = *satisfyingVersionIt; } } versions.push(preferredVersion); } } } } } else { struct ReverseRecord { const BinaryVersion* version; const RelationExpression* relationExpressionPtr; bool operator<(const ReverseRecord& other) const { return (*this->version < *other.version); } }; vector< ReverseRecord > reverseRecords; reverseDependsIndex.foreachReverseDependency(version, relationGroup, [&reverseRecords](const BinaryVersion* reverseVersion, const RelationExpression& relationExpression) { reverseRecords.push_back({ reverseVersion, &relationExpression }); }); std::sort(reverseRecords.begin(), reverseRecords.end()); for (const auto& record: reverseRecords) { cout << " " << __("Reverse-") << caption << ": " << record.version->packageName << ' ' << record.version->versionString << ": " << record.relationExpressionPtr->toString() << endl; if (recurse) { versions.push(record.version); } } } } } return 0; } int dumpConfig(Context& context) { auto config = context.getConfig(); vector< string > arguments; parseOptions(context, {""}, arguments); checkNoExtraArguments(arguments); auto outputScalar = [&](const string& name) { auto value = config->getString(name); if (value.empty()) return; cout << format2("%s \"%s\";\n", name, value); }; auto outputList = [&](const string& name) { cout << format2("%s {};\n", name); for (const auto& value: config->getList(name)) { cout << format2("%s { \"%s\"; };\n", name, value); } }; for (const auto& name: config->getScalarOptionNames()) { outputScalar(name); } for (const auto& name: config->getListOptionNames()) { outputList(name); } return 0; } int policy(Context& context, bool source) { auto config = context.getConfig(); // turn off info and relations parsing, we don't need it if (!shellMode) { Version::parseInfoOnly = false; Version::parseRelations = false; } vector< string > arguments; bpo::options_description options(""); options.add_options() ("show-dates", ""); auto variables = parseOptions(context, options, arguments); if (!arguments.empty() && variables.count("show-dates")) { fatal2(__("the option '--show-dates' can be used only with no package names supplied")); } auto cache = context.getCache(/* source */ source, /* binary */ !source, /* installed */ !source); if (!arguments.empty()) { // print release info for supplied package names for (const string& packageName: arguments) { const Package* package = (!source ? (const Package*)getBinaryPackage(*cache, packageName) : (const Package*)getSourcePackage(*cache, packageName)); auto preferredVersion = cache->getPreferredVersion(package); if (!preferredVersion) { fatal2(__("no versions available for the package '%s'"), packageName); } cout << packageName << ':' << endl; const Version* installedVersion = nullptr; if (!source) { auto binaryPackage = dynamic_cast< const BinaryPackage* >(package); if (!binaryPackage) fatal2i("binary package expected"); installedVersion = binaryPackage->getInstalledVersion(); const auto& installedVersionString = (installedVersion ? installedVersion->versionString : __("")); cout << format2(" %s: %s\n", __("Installed"), installedVersionString); } cout << format2(" %s: %s\n", __("Preferred"), preferredVersion->versionString); cout << format2(" %s:\n", __("Version table")); auto pinnedVersions = cache->getSortedVersionsWithPriorities(package); for (const auto& pinnedVersion: pinnedVersions) { const auto& version = pinnedVersion.version; cout << format2(" %s %s %zd\n", (version == installedVersion ? "***" : " "), version->versionString, pinnedVersion.priority); for (const auto& source: version->sources) { const ReleaseInfo* release = source.release; static const string spaces(8, ' '); cout << spaces; auto origin = release->baseUri; if (origin.empty()) { origin = config->getPath("dir::state::status"); } cout << format2("%s %s/%s (%s)\n", origin, release->archive, release->component, (release->verified ? __("signed") : __("unsigned"))); } } } } else { auto showDates = variables.count("show-dates"); auto sayReleaseInfo = [&config, &showDates](const shared_ptr< const ReleaseInfo >& releaseInfo) { string origin = releaseInfo->baseUri; if (origin.empty()) { origin = config->getPath("dir::state::status"); } const string& archive = releaseInfo->archive; const string& component = releaseInfo->component; cout << " " << origin << ' ' << archive << '/' << component << ": "; cout << "o=" << releaseInfo->vendor; cout << ",a=" << archive; cout << ",l=" << releaseInfo->label; cout << ",c=" << component; cout << ",v=" << releaseInfo->version; cout << ",n=" << releaseInfo->codename; if (showDates && !releaseInfo->baseUri.empty()) { cout << format2(" (%s: %s, ", __("published"), releaseInfo->date); if (releaseInfo->validUntilDate.empty()) { cout << __("does not expire"); } else { cout << format2("%s: %s", __("expires"), releaseInfo->validUntilDate); } cout << ")"; } cout << endl; }; vector< shared_ptr< const ReleaseInfo > > data; if (!source) { cout << "Package files:" << endl; data = cache->getBinaryReleaseData(); } else { cout << "Source files:" << endl; data = cache->getSourceReleaseData(); } FORIT(releaseInfoIt, data) { sayReleaseInfo(*releaseInfoIt); } } return 0; } int showPackageNames(Context& context) { auto config = context.getConfig(); vector< string > arguments; bpo::options_description options(""); options.add_options() ("installed-only", ""); auto variables = parseOptions(context, options, arguments); auto cache = context.getCache(/* source */ false, /* binary */ variables.count("installed-only") == 0, /* installed */ true); string prefix; if (!arguments.empty()) { prefix = arguments[0]; arguments.erase(arguments.begin()); } auto prefixSize = prefix.size(); checkNoExtraArguments(arguments); for (const string& packageName: cache->getBinaryPackageNames()) { // check package name for pattern and output it if (!packageName.compare(0, prefixSize, prefix)) { cout << packageName << endl; } } return 0; } int showScreenshotUris(Context& context) { vector< string > arguments; bpo::options_description noOptions(""); parseOptions(context, noOptions, arguments); if (arguments.empty()) { fatal2(__("no binary package names specified")); } auto cache = context.getCache(false, true, true); // binary and installed FORIT(argumentIt, arguments) { const string& packageName = *argumentIt; // check for existence getBinaryPackage(*cache, packageName); cout << "http://screenshots.debian.net/package/" << packageName << endl; } return 0; } int tarMetadata(Context& context) { vector< string > arguments; bpo::options_description noOptions(""); parseOptions(context, noOptions, arguments); checkNoExtraArguments(arguments); auto config = context.getConfig(); auto listsDirectory = config->getPath("cupt::directory::state::lists"); vector< string > pathList = { config->getPath("dir::etc::main"), config->getPath("dir::etc::parts"), config->getPath("cupt::directory::configuration::main"), config->getPath("cupt::directory::configuration::main-parts"), config->getPath("dir::etc::sourcelist"), config->getPath("dir::etc::sourceparts"), config->getPath("dir::etc::preferences"), config->getPath("dir::etc::preferencesparts"), config->getPath("dir::state::extendedstates"), config->getPath("dir::state::status"), listsDirectory + "/*Release", listsDirectory + "/*Release.gpg", listsDirectory + "/*Packages", listsDirectory + "/*Sources", }; string tarCommand = "tar -cf -"; FORIT(pathIt, pathList) { tarCommand += ' '; tarCommand += *pathIt; } return ::system(tarCommand.c_str()); } int showAutoInstalled(Context& context) { vector< string > arguments; bpo::options_description options; options.add_options()("invert", ""); auto variables = parseOptions(context, options, arguments); checkNoExtraArguments(arguments); bool showManual = variables.count("invert"); auto cache = context.getCache(false, false, true); // installed only auto installedPackageNames = cache->getBinaryPackageNames(); FORIT(packageNameIt, installedPackageNames) { const string& packageName = *packageNameIt; bool isAutoInstalled = cache->isAutomaticallyInstalled(packageName); if (isAutoInstalled == !showManual) { cout << packageName << endl; } } return 0; } cupt-2.10.0/cpp/console/handlers/search.cpp0000644000000000000000000001250513204267373015442 0ustar /************************************************************************** * Copyright (C) 2010-2011 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #include using std::cout; using std::endl; #include #include #include #include "../common.hpp" #include "../misc.hpp" #include "../handlers.hpp" #include "../functionselectors.hpp" namespace { vector< sregex > generateSearchRegexes(const vector< string >& patterns, bool caseSensitive) { int regexFlags = regex_constants::ECMAScript | regex_constants::optimize; if (!caseSensitive) { regexFlags |= regex_constants::icase; } vector< sregex > result; for (const string& pattern: patterns) { try { result.push_back(sregex::compile(pattern.c_str(), regex_constants::syntax_option_type(regexFlags))); } catch (regex_error&) { fatal2(__("invalid regular expression '%s'"), pattern); } }; return result; } void searchInPackageNames(const vector< string >& packageNames, const vector< sregex >& regexes, smatch& m) { for (const auto& packageName: packageNames) { bool matched = true; for (const auto& regex: regexes) { if (!regex_search(packageName, m, regex)) { matched = false; break; } } if (matched) { cout << packageName << endl; } } } inline string getShortDescription(const string& description) { return description.substr(0, description.find('\n')); } void searchInPackageNamesAndDescriptions(const Cache& cache, const vector< string >& packageNames, const vector< sregex >& regexes, smatch& m) { for (const string& packageName: packageNames) { auto package = cache.getBinaryPackage(packageName); set< string > printedShortDescriptions; for (const auto& v: *package) { bool matched = true; auto description = cache.getLocalizedDescription(v); for (const sregex& regex: regexes) { if (regex_search(packageName, m, regex)) { continue; } if (regex_search(description, m, regex)) { continue; } matched = false; break; } if (matched) { auto shortDescription = getShortDescription(description); if (printedShortDescriptions.insert(shortDescription).second) { cout << packageName << " - " << shortDescription << endl; } } } } } void searchByFSE(const Cache& cache, vector< string >& patterns) { string fse = patterns[0]; patterns.erase(patterns.begin()); checkNoExtraArguments(patterns); auto functionalQuery = FunctionalSelector::parseQuery(fse, true); auto&& foundVersions = FunctionalSelector(cache).selectBestVersions(*functionalQuery); for (const auto& version: foundVersions) { auto binaryVersion = static_cast< const BinaryVersion* >(version); cout << format2("%s - %s\n", binaryVersion->packageName, getShortDescription(binaryVersion->description)); } } } int search(Context& context) { auto config = context.getConfig(); vector< string > patterns; bpo::options_description options; options.add_options() ("names-only,n", "") ("case-sensitive", "") ("fse,f", "") ("installed-only", ""); auto variables = parseOptions(context, options, patterns); if (variables.count("names-only")) { config->setScalar("apt::cache::namesonly", "yes"); } if (!shellMode && config->getBool("apt::cache::namesonly")) { BinaryVersion::parseInfoOnly = false; } if (patterns.empty()) { fatal2(__("no search patterns specified")); } if (variables.count("fse")) { Version::parseOthers = true; auto cache = context.getCache(true, true, true); searchByFSE(*cache, patterns); } else { if (!shellMode) { BinaryVersion::parseRelations = false; } auto cache = context.getCache(/* source */ false, /* binary */ variables.count("installed-only") == 0, /* installed */ true); auto regexes = generateSearchRegexes(patterns, variables.count("case-sensitive")); smatch m; vector< string > packageNames = cache->getBinaryPackageNames().asVector(); std::sort(packageNames.begin(), packageNames.end()); if (config->getBool("apt::cache::namesonly")) { searchInPackageNames(packageNames, regexes, m); } else { searchInPackageNamesAndDescriptions(*cache, packageNames, regexes, m); } } return 0; } cupt-2.10.0/cpp/console/handlers/shell.cpp0000644000000000000000000001043413204267373015303 0ustar /************************************************************************** * Copyright (C) 2010-2011 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #include using std::cout; using std::endl; using std::cin; #include #include #include #include #include "../common.hpp" #include "../cupt.hpp" #include "../handlers.hpp" bool shellMode = false; class Readline { string __prompt; static char* (*__dl_readline)(const char*); static void (*__dl_add_history)(const char*); string __gnu_readline() { char* buffer = __dl_readline(__prompt.c_str()); if (!buffer) { return string(); } string result(buffer); free(buffer); if (!result.empty()) { __dl_add_history(result.c_str()); } return result; } string __simple_get_line() { string result; cout << __prompt; std::getline(cin, result); return result; } public: Readline(const string& prompt) : __prompt(prompt) {} string getLine() { string result; start: result = (__dl_readline && __dl_add_history) ? __gnu_readline() : __simple_get_line(); if (result.empty()) { goto start; } else if (result == "exit" || result == "quit" || result == ":q" || result == "q") { result.clear(); } return result; } static void init() { auto handle = dlopen("libreadline.so.7", RTLD_NOW); if (!handle) { warn2(__("unable to dynamically find libreadline.so.7: dlopen: %s"), dlerror()); return; } __dl_readline = reinterpret_cast< decltype(__dl_readline) >(dlsym(handle, "readline")); if (!__dl_readline) { warn2(__("unable to dynamically bind the symbol '%s': %s"), "readline", dlerror()); } __dl_add_history = reinterpret_cast< decltype(__dl_add_history) >(dlsym(handle, "add_history")); if (!__dl_add_history) { warn2(__("unable to dynamically bind the symbol '%s': %s"), "add_history", dlerror()); } } }; char* (*Readline::__dl_readline)(const char*) = NULL; void (*Readline::__dl_add_history)(const char*) = NULL; void convertLineToArgcArgv(const string& cuptCommand, const string& line, int& argc, char**& argv) { auto arguments = convertLineToShellArguments(line); argc = arguments.size() + 1; argv = new char*[argc]; argv[0] = strdup(cuptCommand.c_str()); for (int i = 1; i < argc; ++i) { argv[i] = strdup(arguments[i-1].c_str()); } } void freeArgcArgv(int argc, char** argv) { for (int i = 0; i < argc; ++i) { free(argv[i]); } delete [] argv; } int shell(Context& context) { shellMode = true; vector< string > arguments; bpo::options_description noOptions; parseOptions(context, noOptions, arguments); checkNoExtraArguments(arguments); Readline::init(); cout << __("This is an interactive shell of the cupt package manager.\n"); const shared_ptr< Config > oldConfig(new Config(*(context.getConfig()))); const string cuptCommand = context.argv[0]; Readline term(/* prompt */ "cupt> "); string line; while (line = term.getLine(), !line.empty()) { int argc; char** argv; convertLineToArgcArgv(cuptCommand, line, argc, argv); mainEx(argc, argv, context); *(context.getConfig()) = *oldConfig; freeArgcArgv(argc, argv); } return 0; } cupt-2.10.0/cpp/console/handlers/snapshot.cpp0000644000000000000000000000660613204267373016041 0ustar /************************************************************************** * Copyright (C) 2010-2011 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #include using std::cout; using std::endl; #include #include #include "../handlers.hpp" int snapshot(Context& context) { if (context.unparsed.size() >= 2 && context.unparsed[0] == "load") { // handling 'snapshot load' subcommand context.unparsed.erase(context.unparsed.begin()); // cutting 'load' return managePackages(context, ManagePackages::LoadSnapshot); } vector< string > arguments; bpo::options_description noOptions; auto variables = parseOptions(context, noOptions, arguments); if (arguments.empty()) { fatal2(__("the action is not specified")); } string action = arguments[0]; arguments.erase(arguments.begin()); auto config = context.getConfig(); Snapshots snapshots(config); if (action == "list") { checkNoExtraArguments(arguments); auto snapshotNames = snapshots.getSnapshotNames(); for (const auto& name: snapshotNames) { cout << name << endl; } } else if (action == "save" || action == "remove") { if (arguments.empty()) { fatal2(__("no snapshot name specified")); } string snapshotName = arguments[0]; arguments.erase(arguments.begin()); checkNoExtraArguments(arguments); if (action == "save") { auto cache = context.getCache(false, false, true); Worker worker(config, cache); worker.saveSnapshot(snapshots, snapshotName); } else // remove { auto cache = context.getCache(false, false, false); Worker worker(config, cache); worker.removeSnapshot(snapshots, snapshotName); } } else if (action == "rename") { if (arguments.empty()) { fatal2(__("no previous snapshot name specified")); } string oldSnapshotName = arguments[0]; if (arguments.size() < 2) { fatal2(__("no new snapshot name specified")); } string newSnapshotName = arguments[1]; arguments.erase(arguments.begin(), arguments.begin() + 2); checkNoExtraArguments(arguments); auto cache = context.getCache(false, false, false); Worker worker(config, cache); worker.renameSnapshot(snapshots, oldSnapshotName, newSnapshotName); } else { fatal2(__("unsupported action '%s'"), action); } return 0; } cupt-2.10.0/cpp/console/handlers/why.cpp0000644000000000000000000001511113204267373015000 0ustar /************************************************************************** * Copyright (C) 2010-2015 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #include #include "../handlers.hpp" #include "../selectors.hpp" #include using std::priority_queue; #include using std::stack; using std::cout; using std::endl; struct PathEntry { size_t length = 0; const BinaryVersion* version = nullptr; BinaryVersion::RelationTypes::Type dependencyType; const RelationExpression* relationExpressionPtr; }; struct Edge { const BinaryVersion* version; PathEntry pathEntry; bool operator<(const Edge& other) const { return pathEntry.length > other.pathEntry.length; } }; inline size_t getDependencyTypePenalty(BinaryVersion::RelationTypes::Type dp) { switch (dp) { case BinaryVersion::RelationTypes::Recommends: return 5; case BinaryVersion::RelationTypes::Suggests: return 14; default: return 0; } } struct VersionsAndLinks { priority_queue versions; map links; void addStartingVersion(const BinaryVersion* version) { versions.push({ version, PathEntry() }); } void initialise(const Cache& cache, const vector& arguments) { if (!arguments.empty()) { // selected packages for (const auto& argument: arguments) { for (auto version: selectBinaryVersionsWildcarded(cache, argument)) { addStartingVersion(version); } } } else { // the whole system for (const auto& installedVersion: cache.getInstalledVersions()) { if (!cache.isAutomaticallyInstalled(installedVersion->packageName)) { addStartingVersion(installedVersion); } } } } bool setEdge(const Edge& edge) { auto insertResult = links.insert({ edge.version, edge.pathEntry }); return insertResult.second; } void addVersionRelationExpressions(const Cache& cache, Edge edge, BinaryVersion::RelationTypes::Type dependencyType) { auto version = edge.version; auto newLength = edge.pathEntry.length + getDependencyTypePenalty(dependencyType); for (const auto& relationExpression: version->relations[dependencyType]) { size_t index = 0; for (const auto& newVersion: cache.getSatisfyingVersions(relationExpression)) { PathEntry newPathEntry; newPathEntry.length = newLength + index; newPathEntry.version = version; newPathEntry.dependencyType = dependencyType; newPathEntry.relationExpressionPtr = &relationExpression; versions.push({ newVersion, newPathEntry }); ++index; } } } }; void printPath(const VersionsAndLinks& val, const BinaryVersion* version) { stack path; const BinaryVersion* currentVersion = version; decltype(val.links.find(currentVersion)) it; while ((it = val.links.find(currentVersion)), it->second.version) { const PathEntry& pathEntry = it->second; path.push(pathEntry); currentVersion = pathEntry.version; } while (!path.empty()) { const auto& pathEntry = path.top(); path.pop(); cout << format2("%s %s: %s: %s", pathEntry.version->packageName, pathEntry.version->versionString, __(BinaryVersion::RelationTypes::strings[pathEntry.dependencyType].c_str()), pathEntry.relationExpressionPtr->toString()) << endl; } } vector getSignificantRelationGroups(const Config& config) { vector result; result.push_back(BinaryVersion::RelationTypes::PreDepends); result.push_back(BinaryVersion::RelationTypes::Depends); if (config.getBool("cupt::resolver::keep-recommends")) { result.push_back(BinaryVersion::RelationTypes::Recommends); } if (config.getBool("cupt::resolver::keep-suggests")) { result.push_back(BinaryVersion::RelationTypes::Suggests); } return result; } std::tuple, vector> parseArguments(Context& context) { vector< string > arguments; bpo::options_description options(""); options.add_options() ("installed-only", ""); auto variables = parseOptions(context, options, arguments); if (arguments.empty()) { fatal2(__("no binary package expressions specified")); } bool installedOnly = variables.count("installed-only") || (arguments.size() == 1); auto cache = context.getCache(/* source */ false, /* binary */ !installedOnly, /* installed */ true); return make_tuple(std::move(cache), std::move(arguments)); } const BinaryVersion* extractLeafVersion(const Cache& cache, vector* arguments) { auto leafPackageExpression = arguments->back(); arguments->erase(arguments->end() - 1); return selectBinaryVersionsWildcarded(cache, leafPackageExpression, true)[0]; } int findDependencyChain(Context& context) { // turn off info parsing, we don't need it, only relations if(!shellMode) { Version::parseInfoOnly = false; } vector arguments; shared_ptr cache; std::tie(cache, arguments) = parseArguments(context); auto leafVersion = extractLeafVersion(*cache, &arguments); VersionsAndLinks val; val.initialise(*cache, arguments); auto config = context.getConfig(); auto relationGroups = getSignificantRelationGroups(*config); while (!val.versions.empty()) { auto edge = val.versions.top(); val.versions.pop(); bool isNewEdge = val.setEdge(edge); if (edge.version == leafVersion) { printPath(val, edge.version); // we found a path, re-walk it break; } if (isNewEdge) { for (auto dependencyType: relationGroups) { val.addVersionRelationExpressions(*cache, edge, dependencyType); } } } return 0; } cupt-2.10.0/cpp/console/handlers.hpp0000644000000000000000000000446413204267373014207 0ustar /************************************************************************** * Copyright (C) 2010 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #ifndef HANDLERS_SEEN #define HANDLERS_SEEN #include "common.hpp" #include "misc.hpp" int search(Context&); int showBinaryVersions(Context&); int showSourceVersions(Context&); int showRelations(Context&, bool); int dumpConfig(Context&); int policy(Context&, bool); int shell(Context&); int showPackageNames(Context&); int findDependencyChain(Context&); int updateReleaseAndIndexData(Context&); int downloadSourcePackage(Context&); int cleanArchives(Context&, bool); int showScreenshotUris(Context&); int snapshot(Context&); int tarMetadata(Context&); int showAutoInstalled(Context&); struct ManagePackages { enum Mode { FullUpgrade, SafeUpgrade, Install, Reinstall, Purge, Remove, Satisfy, Unsatisfy, Markauto, Unmarkauto, BuildDepends, LoadSnapshot, InstallIfInstalled, SelfUpgrade }; }; int managePackages(Context&, ManagePackages::Mode); int distUpgrade(Context&); struct ChangelogOrCopyright { enum Type { Changelog, Copyright }; }; int downloadChangelogOrCopyright(Context& context, ChangelogOrCopyright::Type); extern bool shellMode; #endif cupt-2.10.0/cpp/console/misc.cpp0000644000000000000000000002773713204267373013345 0ustar /************************************************************************** * Copyright (C) 2010-2011 by Eugene V. Lyubimkin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program 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 GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * **************************************************************************/ #include #include using std::map; #include #include #include #include #include "common.hpp" #include "misc.hpp" #include "handlers.hpp" void parseReleaseLimit(Config& config, const string& limitName, const string& included, const string& excluded) { auto setLimitList = [&config](const string& listOptionName, const string& valuesString) { std::istringstream valueStream(valuesString); string value; while (std::getline(valueStream, value, ',')) { config.setList(listOptionName, value); } }; auto limitOptionName = string("cupt::cache::limit-releases::by-") + limitName; if (!included.empty() && !excluded.empty()) { fatal2(__("options '--include-%ss' and '--exclude-%ss' cannot be specified together"), limitName, limitName); } else if (!included.empty()) { config.setScalar(limitOptionName + "::type", "include"); setLimitList(limitOptionName, included); } else if (!excluded.empty()) { config.setScalar(limitOptionName + "::type", "exclude"); setLimitList(limitOptionName, excluded); } } void parseReleaseLimits(Config& config, const string& includedArchives, const string& excludedArchives, const string& includedCodenames, const string& excludedCodenames) { parseReleaseLimit(config, "archive", includedArchives, excludedArchives); parseReleaseLimit(config, "codename", includedCodenames, excludedCodenames); } void handleQuietOption(const Config&); string parseCommonOptions(int argc, char** argv, Config& config, vector< string >& unparsed) { if (argc == 3) { if (!strcmp(argv[1], "get") && !strcmp(argv[2], "ride")) { printf("You've got ride\n"); exit(0); } } string command; // parsing bpo::options_description options("Common options"); vector< string > directOptions; string targetRelease; string includedArchives, excludedArchives, includedCodenames, excludedCodenames; options.add_options() ("important,i", "") ("option,o", bpo::value< vector< string > >(&directOptions)) ("recurse", "") ("all-versions,a", "") ("no-all-versions", "") ("target-release", bpo::value< string >(&targetRelease)) ("default-release,t", bpo::value< string >(&targetRelease)) ("include-archives", bpo::value< string >(&includedArchives)) ("exclude-archives", bpo::value< string >(&excludedArchives)) ("include-codenames", bpo::value< string >(&includedCodenames)) ("exclude-codenames", bpo::value< string >(&excludedCodenames)) ("simulate,s", "") ("quiet,q", "") ("command", bpo::value< string >(&command)) ("arguments", bpo::value< vector< string > >()); bpo::positional_options_description positionalOptions; positionalOptions.add("command", 1); positionalOptions.add("arguments", -1); try { bpo::variables_map variablesMap; bpo::parsed_options parsed = bpo::command_line_parser(argc, argv).options(options) .style(bpo::command_line_style::default_style & ~bpo::command_line_style::allow_guessing) .positional(positionalOptions).allow_unregistered().run(); bpo::store(parsed, variablesMap); bpo::notify(variablesMap); { // do not pass 'command' further auto commandOptionIt = std::find_if(parsed.options.begin(), parsed.options.end(), [](const bpo::option& o) { return o.string_key == "command"; }); if (commandOptionIt != parsed.options.end()) { parsed.options.erase(commandOptionIt); } } unparsed = bpo::collect_unrecognized(parsed.options, bpo::include_positional); { // processing if (command.empty()) { fatal2(__("no command specified")); } if (variablesMap.count("important")) { config.setScalar("apt::cache::important", "yes"); } if (variablesMap.count("recurse")) { config.setScalar("apt::cache::recursedepends", "yes"); } if (!targetRelease.empty()) { config.setScalar("apt::default-release", targetRelease); } if (variablesMap.count("all-versions")) { config.setScalar("apt::cache::allversions", "yes"); } if (variablesMap.count("no-all-versions")) { config.setScalar("apt::cache::allversions", "no"); } if (variablesMap.count("simulate")) { config.setScalar("cupt::worker::simulate", "yes"); } if (variablesMap.count("quiet")) { config.setScalar("quiet", "yes"); handleQuietOption(config); } parseReleaseLimits(config, includedArchives, excludedArchives, includedCodenames, excludedCodenames); } smatch m; for (const string& directOption: directOptions) { static const sregex optionRegex = sregex::compile("(.*?)=(.*)"); if (!regex_match(directOption, m, optionRegex)) { fatal2(__("invalid option syntax in '%s' (right is '