porg/porg/db.cc

374 lines
7.1 KiB
C++

//=======================================================================
// db.cc
//-----------------------------------------------------------------------
// This file is part of the package porg
// Copyright (C) 2015 David Ricart
// For more information visit http://porg.sourceforge.net
//=======================================================================
#include "config.h"
#include "porg/file.h"
#include "db.h"
#include "util.h"
#include "main.h"
#include "opt.h"
#include "out.h"
#include "pkg.h"
#include <algorithm>
#include <iomanip>
using std::cout;
using std::endl;
using std::vector;
using std::setw;
using std::string;
using std::max;
using namespace Porg;
static int get_digits(ulong);
static int get_width(ulong);
static bool match_pkg(string const&, string const&);
DB::DB()
:
vector<Pkg*>(),
m_total_size(0),
m_total_files(0)
{ }
DB::~DB()
{
for (iterator p(begin()); p != end(); delete *p++) ;
}
//
// get all packages logged in database
//
void DB::get_pkgs_all()
{
Dir dir(Opt::logdir());
for (string name; dir.read(name); add_pkg(name)) ;
if (empty())
Out::vrb("porg: No packages logged in '" + Opt::logdir() + "'");
}
//
// Search the database for packages matching any of the strings in args given
// by the command line
//
void DB::get_pkgs(vector<string> const& args)
{
Dir dir(Opt::logdir());
for (uint i = 0; i < args.size(); ++i, dir.rewind()) {
bool found = false;
for (string name; dir.read(name); )
found |= (match_pkg(args[i], name) && add_pkg(name));
if (!found) {
Out::vrb("porg: " + args[i] + ": Package not logged");
g_exit_status = EXIT_FAILURE;
}
}
}
bool DB::add_pkg(string const& name)
{
try
{
Pkg* pkg = new Pkg(name);
push_back(pkg);
m_total_size += pkg->size();
m_total_files += pkg->nfiles();
return true;
}
catch (...)
{
return false;
}
}
//
// get widths for printing pkg sizes and number of files
//
void DB::get_pkg_list_widths(int& size_w, int& nfiles_w) const
{
size_w = Opt::print_totals() ? get_width(m_total_size) : 0;
ulong max_nfiles(Opt::print_totals() ? m_total_files : 0);
for (const_iterator p(begin()); p != end(); ++p) {
size_w = max(size_w, get_width((*p)->size()));
if (!Opt::print_totals())
max_nfiles = max(max_nfiles, (*p)->nfiles());
}
nfiles_w = get_digits(max_nfiles);
}
//
// get width for printing file sizes
//
int DB::get_file_size_width() const
{
int size_w = Opt::print_totals() ? get_width(m_total_size) : 0;
for (const_iterator p(begin()); p != end(); ++p) {
for (Pkg::const_iter f((*p)->files().begin()); f != (*p)->files().end(); ++f)
size_w = max(size_w, get_width((*f)->size()));
}
return size_w;
}
void DB::print_conf_opts() const
{
for (const_iterator p(begin()); p != end(); ++p) {
if (size() > 1)
cout << (*p)->name() << ":" << endl;
cout << (*p)->conf_opts() << endl;
if (!(*p)->conf_opts().empty() && size() > 1 && p != end() - 1)
cout << endl;
}
}
void DB::query() const
{
for (uint i(0); i < Opt::args().size(); ++i) {
bool found = false;
string path(clear_path(Opt::args()[i]));
cout << path << ':';
for (const_iterator p(begin()); p != end(); ++p) {
if ((*p)->find_file(path)) {
found = true;
cout << " " << (*p)->name();
}
}
cout << endl;
if (!found)
g_exit_status = EXIT_FAILURE;
}
}
void DB::print_info() const
{
for (const_iterator p(begin()); p != end(); (*p++)->print_info()) ;
}
void DB::sort_pkgs( sort_t type, // = SORT_BY_NAME
bool reverse) // = false
{
std::sort(begin(), end(), Sorter(type));
if (reverse)
std::reverse(begin(), end());
}
void DB::remove() const
{
// ask the user, if needed
if (!Opt::remove_batch()) {
cout << "The following packages will be "
<< (Opt::remove_unlog() ? "unlogged:" : "removed:") << endl;
for (const_iterator p(begin()); p != end(); ++p)
cout << " " << (*p)->name() << endl;
cout << "Do you want to proceed (y/N) ? ";
string buf;
if (getline(std::cin, buf) && buf != "y")
return;
}
if (Opt::remove_unlog()) {
for (const_iterator p(begin()); p != end(); (*p++)->unlog()) ;
return;
}
// auxiliary DB to check for shared files
DB aux;
aux.get_pkgs_all();
for (const_iterator p(begin()); p != end(); ++p) {
(*p)->remove(aux);
aux.del_pkg((*p)->name());
}
}
void DB::del_pkg(string const& name)
{
for (iterator p(begin()); p != end(); ++p) {
if ((*p)->name() == name) {
erase(p);
break;
}
}
}
void DB::list_pkgs() const
{
int size_w = 0, nfiles_w = 0;
// get widths for printing pkg sizes and number of files
if (Opt::print_sizes() || Opt::print_nfiles())
get_pkg_list_widths(size_w, nfiles_w);
// list packages
for (const_iterator p(begin()); p != end(); ++p)
(*p)->list(size_w, nfiles_w);
// print totals, if needed
if (Opt::print_totals()) {
if (Opt::print_sizes())
cout << setw(size_w) << fmt_size(m_total_size) << " ";
if (Opt::print_nfiles())
cout << setw(nfiles_w) << m_total_files << " ";
if (Opt::print_date())
cout << fmt_date(0, Opt::print_hour()) << " ";
cout << "TOTAL" << endl;
}
}
void DB::list_files() const
{
int size_w(get_file_size_width());
for (const_iterator p(begin()); p != end(); ++p) {
(*p)->list_files(size_w);
if (!Opt::print_no_pkg_name() && size() > 1)
cout << endl;
}
if (Opt::print_totals())
cout << setw(size_w) << fmt_size(m_total_size) << " TOTAL" << endl;
}
//------------//
// DB::Sorter //
//------------//
DB::Sorter::Sorter(sort_t const& t /* = SORT_BY_NAME */)
:
m_sort_func()
{
switch (t) {
case SORT_BY_SIZE: m_sort_func = &Sorter::sort_by_size; break;
case SORT_BY_NFILES: m_sort_func = &Sorter::sort_by_nfiles; break;
case SORT_BY_DATE: m_sort_func = &Sorter::sort_by_date; break;
default: m_sort_func = &Sorter::sort_by_name;
}
}
bool DB::Sorter::operator()(Pkg* left, Pkg* right) const
{
return (this->*m_sort_func)(right, left);
}
bool DB::Sorter::sort_by_name(Pkg* left, Pkg* right) const
{
return left->name() > right->name();
}
bool DB::Sorter::sort_by_size(Pkg* left, Pkg* right) const
{
return left->size() < right->size();
}
bool DB::Sorter::sort_by_nfiles(Pkg* left, Pkg* right) const
{
return left->nfiles() < right->nfiles();
}
bool DB::Sorter::sort_by_date(Pkg* left, Pkg* right) const
{
return left->date() > right->date();
}
//-------------------//
// static free funcs //
//-------------------//
//
// Return the number of digits of a number
//
static int get_digits(ulong n)
{
int ret;
for (ret = 0; n; n /= 10, ret++) ;
return max(1, ret);
}
inline static int get_width(ulong size)
{
return fmt_size(size).size();
}
static bool match_pkg(string const& str, string const& pkg)
{
if (Opt::exact_version())
return str == pkg;
string str_base = Pkg::get_base(str);
string pkg_base = Pkg::get_base(pkg);
string str_version = Pkg::get_version(str);
string pkg_version = Pkg::get_version(pkg);
if (pkg_base != str_base)
return false;
else if (str_version.empty() || str_version == pkg_version)
return true;
else if (str_version.compare(0, str_version.size(),
pkg_version.c_str(), str_version.size()))
return false;
return ispunct(pkg_version[str_version.size()]);
}