📄 pkg.cc
字号:
//=======================================================================// Pkg.cc//-----------------------------------------------------------------------// This file is part of the package paco// Copyright (C) 2004-2007 David Rosal <david.3r@gmail.com>// For more information visit http://paco.sourceforge.net//=======================================================================#include "config.h"#include "global.h"#include "Pkg.h"#include "PkgSet.h"#include "Options.h"#include <string>#include <iostream>#include <iomanip>#include <fstream>using std::endl;using std::cout;using std::string;using std::setw;using namespace Paco;// Forward declsstatic void cutPrint(string);static void removeDir(string const&);static void removeParentDir(string const&);static int getDigits(long);template <typename T, typename U> static T max(T const&, U const&);Pkg::Pkg(string const& aName): BasePkg(aName){ }// [virtual]Pkg::~Pkg(){ }void Pkg::unlog() const{ if (!access(mLog.c_str(), W_OK)) { if (!unlink(mLog.c_str())) gOut.vrb("Package " + mName + " removed from the database\n"); else gOut.vrb("unlink(" + mLog + ")", errno); }}void Pkg::printInfo() const{ FileStream<std::ifstream> f(mLog); string buf; bool printed(false); string line(mName.size() + 2, '-'); cout << line << "\n " << mName << " \n" << line << "\n" << endl; while (getline(f, buf) && buf[0] == '#') { if (buf == "#:Description") cout << "Description:\n" << endl; else if (!buf.find("#:")) { cutPrint(buf.substr(2)); printed = true; } } if (printed) cout << endl;}bool Pkg::update() const{ gOut.vrb("Updating " + mName + "... "); bool ret = updateLog(mLog); gOut.vrb(ret ? "ok\n" : "no files logged (removed)\n"); return ret;}void Pkg::upgradeLog() const{ std::ifstream fLog(mLog.c_str()); if (!fLog) return; string buf; getline(fLog, buf); if (!buf.find("#!paco-2.")) return; std::ostringstream s; s << "#!paco-" PACKAGE_VERSION "\n"; string::size_type p = buf.rfind(" "); if (p != string::npos) s << "#d:" << str2num<int>(buf.substr(p)) << '\n'; string infoLog = Config::logdir() + "/_info/" + mName; std::ifstream fInfoLog(infoLog.c_str()); if (fInfoLog) { getline(fInfoLog, buf); while (getline(fInfoLog, buf)) s << (buf[0] == '#' ? "" : "#:") << buf << '\n'; } while (getline(fLog, buf)) { if (buf[0] != '#' || !fInfoLog) s << buf << '\n'; } unlink(infoLog.c_str()); fLog.close(); FileStream<std::ofstream> fLog2(mLog); fLog2 << s.str();}long Pkg::countShared(PkgSet& all){ long cnt(0); for (iterator f = begin(); f != end(); ++f) cnt += shares(*f, all); return cnt;}void Pkg::printConfOpts(bool printPkgName) const{ if (printPkgName) cout << mName << ":\n"; if (mConfOpts.size()) cout << mConfOpts << endl; if (printPkgName) cout << endl;}void Pkg::remove(Options& opt){ if (!opt.batch()) { cout << "Remove package " << mName << " (y/N) ? "; string buf; if (!(getline(std::cin, buf) && (buf == "y" || buf == "yes"))) return; } PkgSet all; if (!opt.removeShared()) { all.getAllPkgs(); all.getFiles(); } { Out::Silencer s; update(); } getFiles(); struct stat s; bool keepLog(false); for (iterator f = begin(); f != end(); ++f) { if (lstat((*f)->name().c_str(), &s) < 0) continue; else if (inPaths((*f)->name(), opt.skip())) { gOut.vrb((*f)->name() + ": skipped\n"); keepLog = true; } else if (!opt.removeShared() && shares(*f, all)) { gOut.vrb((*f)->name() + ": shared\n"); keepLog = true; } else if (!unlink((*f)->name().c_str())) { if (S_ISLNK(s.st_mode)) gOut.vrb("Removed symlink '" + (*f)->name() + "'\n"); else gOut.vrb("Removed '" + (*f)->name() + "'\n"); removeParentDir((*f)->name()); } else { gOut.vrb("unlink(" + (*f)->name() + ")", errno); keepLog = true; } } if (opt.unlog() || !keepLog) unlog(); else { Out::Silencer silencer; update(); }}// [static]string Pkg::getVersion(string const& name){ for (string::size_type i = 1; i < name.size(); ++i) { if (isdigit(name.at(i)) && name.at(i - 1) == '-') return name.substr(i); } return "";}// [static]string Pkg::getBase(string const& name){ bool dash(false); string::size_type i; for (i = 1; i < name.size(); ++i) { if (name.at(i) == '-') dash = true; else if (dash) { if (isdigit(name.at(i))) break; dash = false; } } return dash ? name.substr(0, i - 1) : name;}//-------------//// Pkg::Lister ////-------------//Pkg::Lister::Lister(Options& __opt, PkgSet& __set): mOpt(__opt), mSet(__set), mAllPkgs(), mSizeInstWidth(mOpt.size() ? getSizeInstWidth() : 0), mSizeMissWidth(mOpt.sizeMiss() ? getSizeMissWidth() : 0), mFilesInstWidth(mOpt.filesInst() ? getFilesInstWidth() : 0), mFilesMissWidth(mOpt.filesMiss() ? getFilesMissWidth() : 0), mFilesSharedWidth(mOpt.filesShared() ? getDigits(mSet.filesInst() + mSet.filesMiss()) : 0){ if (mOpt.filesShared()) { mAllPkgs.getAllPkgs(); mAllPkgs.getFiles(); mSet.getFiles(); }} Pkg::Lister::~Lister(){ if (!mOpt.total()) return; if (mOpt.size()) printSizeInst(mSet.sizeInst()); if (mOpt.sizeMiss()) printSizeMiss(mSet.sizeMiss()); if (mOpt.filesInst()) printFilesInst(mSet.filesInst()); if (mOpt.filesMiss()) printFilesMiss(mSet.filesMiss()); if (mOpt.filesShared()) cout << setw(mFilesSharedWidth + 4) << " "; if (mOpt.day()) printDate(0); cout << "TotaL" << endl;}int Pkg::Lister::getSizeMissWidth(){ int n = mOpt.total() ? sizeStr(mOpt.sizeUnit(), mSet.sizeMiss()).size() : 0; for (PkgSet::iterator p = mSet.begin(); p != mSet.end(); ++p) n = max(n, sizeStr(mOpt.sizeUnit(), (*p)->sizeMiss()).size()); return n;}int Pkg::Lister::getSizeInstWidth(){ int n = mOpt.total() ? sizeStr(mOpt.sizeUnit(), mSet.sizeInst()).size() : 0; for (PkgSet::iterator p = mSet.begin(); p != mSet.end(); ++p) n = max(n, sizeStr(mOpt.sizeUnit(), (*p)->sizeInst()).size()); return n;}int Pkg::Lister::getFilesInstWidth(){ if (mOpt.total()) return getDigits(mSet.filesInst()); int n = 0; for (PkgSet::iterator p = mSet.begin(); p != mSet.end(); ++p) n = max(n, (*p)->filesInst()); return getDigits(n);}int Pkg::Lister::getFilesMissWidth(){ if (mOpt.total()) return getDigits(mSet.filesMiss()); int n = 0; for (PkgSet::iterator p = mSet.begin(); p != mSet.end(); ++p) n = max(n, (*p)->filesMiss()); return getDigits(n);}void Pkg::Lister::printDate(int __time) const{ char dat[32] = ""; struct tm* t; time_t timeT = static_cast<time_t>(__time); if (!__time || !(t = localtime(&timeT))) snprintf(dat, sizeof(dat), "%*c", mOpt.hour() ? 17 : 11, ' '); else if (mOpt.hour()) strftime(dat, sizeof(dat) - 1, "%d-%b-%Y %H:%M", t); else strftime(dat, sizeof(dat) - 1, "%d-%b-%Y", t); cout << dat << " ";}void Pkg::Lister::printFilesInst(long n) const{ cout << setw(mFilesInstWidth) << n << ((mOpt.filesMiss() || mOpt.filesShared()) ? " " : " ");}template <typename T> // T = {float,long}void Pkg::Lister::printSizeInst(T size) const{ cout << setw(mSizeInstWidth) << sizeStr(mOpt.sizeUnit(), size) << (mOpt.sizeMiss() ? " " : " ");}template <typename T> // T = {float,long}void Pkg::Lister::printSizeMiss(T size) const{ cout << "[" << setw(mSizeMissWidth) << (size ? sizeStr(mOpt.sizeUnit(), size) : " ") << "] ";}void Pkg::Lister::printFilesMiss(long n) const{ cout << "[" << setw(mFilesMissWidth); if (n) cout << n << "] "; else cout << " " << "] "; if (!mOpt.filesShared()) cout << " ";}void Pkg::Lister::printFilesShared(long n) const{ cout << "(" << setw(mFilesSharedWidth); if (n) cout << n << ") "; else cout << " " << ") ";}Pkg* Pkg::Lister::operator()(Pkg* pkg){ if (mOpt.size()) printSizeInst(pkg->sizeInst()); if (mOpt.sizeMiss()) printSizeMiss(pkg->sizeMiss()); if (mOpt.filesInst()) printFilesInst(pkg->filesInst()); if (mOpt.filesMiss()) printFilesMiss(pkg->filesMiss()); if (mOpt.filesShared()) printFilesShared(pkg->countShared(mAllPkgs)); if (mOpt.day()) printDate(pkg->date()); cout << pkg->name() << endl; return pkg;}//-----------------//// Pkg::FileLister ////-----------------//Pkg::FileLister::FileLister(Options& __opt, PkgSet& __set): mOpt(__opt), mSet(__set), mSizeWidth(0), mPrintTotal(mOpt.total() && mOpt.size()), mTotalSize(0), mAllPkgs(), mPkgCnt(0), mFileCnt(0){ if (mOpt.size()) { mTotalSize = mOpt.filesInst() ? mSet.sizeInst() : 0; if (mOpt.filesMiss()) mTotalSize += mSet.sizeMiss(); mSizeWidth = getSizeWidth(); } if (mOpt.filesShared() || mOpt.filesNonShared()) { mTotalSize = 0; mAllPkgs.getAllPkgs(); mAllPkgs.getFiles(); }}Pkg::FileLister::~FileLister(){ if (mPrintTotal && mFileCnt) { cout << endl << setw(mSizeWidth) << (mTotalSize < 0 ? "0" : sizeStr(mOpt.sizeUnit(), mTotalSize)) << " TotaL" << endl; }}int Pkg::FileLister::getSizeWidth(){ int n = mOpt.total() ? sizeStr(mOpt.sizeUnit(), mTotalSize).size() : 0; for (PkgSet::iterator p = mSet.begin(); p != mSet.end(); ++p) { for (Pkg::iterator f = (*p)->begin(); f != (*p)->end(); ++f) n = max(n, sizeStr(mOpt.sizeUnit(), (*f)->size()).size()); } return n;}Pkg* Pkg::FileLister::operator()(Pkg* pkg){ if (mOpt.filesShared() || mOpt.filesNonShared()) { if (!mOpt.noPkgName()) cout << pkg->name() << ":" << endl; if (mOpt.filesShared()) listSharedFiles(pkg); else listNonSharedFiles(pkg); } else listFiles(pkg); if (++mPkgCnt < mSet.size() && !mOpt.noPkgName()) cout << endl; return pkg;}inline void Pkg::FileLister::printFile(File* file){ if (mOpt.size()) { cout << setw(mSizeWidth) << sizeStr(mOpt.sizeUnit(), file->size()) << " "; } cout << file->name(); if (file->symlink() && mOpt.symlinks()) { char ln[4096]; int cnt = readlink(file->name().c_str(), ln, sizeof(ln) - 1); if (cnt > 0) ln[cnt] = 0; else memcpy(ln, "?", 2); cout << " -> " << ln; } cout << "\n"; ++mFileCnt;}void Pkg::FileLister::listFiles(Pkg* pkg){ if (!mOpt.noPkgName()) cout << pkg->name() << ":" << endl; pkg->sort(mOpt.sortType(), mOpt.reverse()); for (iterator f = pkg->begin(); f != pkg->end(); ++f) printFile(*f);}void Pkg::FileLister::listSharedFiles(Pkg* pkg){ for (PkgSet::iterator p = mAllPkgs.begin(); p != mAllPkgs.end(); ++p) { if ((*p)->name() == pkg->name()) continue; uint cnt = 0; for (iterator f = pkg->begin(); f != pkg->end(); ++f) { if (LIKELY(!(*p)->hasFile(*f))) continue; else if (mOpt.whoShares()) { if (!cnt++) cout << "(" << (*p)->name() << ")" << endl; } else if (!(*f)->shared()) (*f)->shared(true); // do not repeat files else continue; printFile(*f); mTotalSize += (*f)->size(); } }} void Pkg::FileLister::listNonSharedFiles(Pkg* pkg){ for (iterator f = pkg->begin(); f != pkg->end(); ++f) { if (LIKELY(!pkg->shares(*f, mAllPkgs))) { printFile(*f); mTotalSize += (*f)->size(); } }} //-------------------//// static free funcs ////-------------------//template <typename T, typename U>inline static T max(T const& a, U const& b){ return static_cast<size_t>(a) > static_cast<size_t>(b) ? a : b;}//// Return the number of digits of a number//static int getDigits(long n){ int ret; for (ret = 0; n; n /= 10, ret++); return ret;}static void removeParentDir(string const& path){ string dir(path); string::size_type i, j; for (i = dir.size() - 1; i > 0 && dir.at(i) == '/'; --i) dir.erase(i); if ((j = dir.rfind('/', i)) && j != string::npos) dir.erase(j); removeDir(dir);}static void removeDir(string const& dir){ if (!rmdir(dir.c_str())) { gOut.vrb("Removed directory '" + dir + "'\n"); removeParentDir(dir); } else if (errno != ENOTEMPTY) gOut.vrb("rmdir(" + dir + ")", errno);}//// This function takes a string and prints it out in pieces not// longer than a given maximmum length. The cut points are not in the middle// of words if possible.//static void cutPrint(string buf){ uint width = Out::screenWidth(); // If the buffer is short enough, just print it and return if (buf.size() <= width) { cout << buf << endl; return; } string out; bool beggining = true, // Leading spaces indicator spaces = false; // True if there are any space to cut at for (uint j, i = 0, len = 0; i < buf.size(); ) { if (buf.at(i) == ' ') spaces = !beggining; else beggining = false; if (len < width) { ++len; out += buf.at(i++); continue; } // len >= width else if (spaces && !beggining) { for (j = out.size(); j && i && buf.at(i) != ' '; --j, --i); ++i; out.erase(j); } for ( ; i < buf.size() && buf.at(i) == ' '; ++i); cout << out << endl; out.clear(); len = 0; spaces = false; } // The remaining piece cout << out << endl;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -