##################################################################### */
/*}}}*/
// Include Files /*{{{*/
-#include "apt-ftparchive.h"
-
+#include <config.h>
+
#include <apt-pkg/error.h>
#include <apt-pkg/configuration.h>
#include <apt-pkg/cmndline.h>
#include <apt-pkg/strutl.h>
#include <apt-pkg/init.h>
-#include <config.h>
-#include <apti18n.h>
-#include <algorithm>
+#include <apt-pkg/fileutl.h>
+#include <algorithm>
#include <climits>
#include <sys/time.h>
-#include <regex.h>
+#include <locale.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <functional>
+#include <iostream>
+#include <string>
+#include <vector>
-#include "contents.h"
+#include "cachedb.h"
+#include "override.h"
+#include "apt-ftparchive.h"
#include "multicompress.h"
-#include "writer.h"
+#include "writer.h"
+
+#include <apti18n.h>
/*}}}*/
using namespace std;
// Stuff for the Package File
string PkgFile;
string BinCacheDB;
+ string SrcCacheDB;
string BinOverride;
string ExtraOverride;
string SrcOverride;
string SrcExtraOverride;
+ // Translation master file
+ bool LongDesc;
+ TranslationWriter *TransWriter;
+
// Contents
string Contents;
string ContentsHead;
inline bool operator() (const PackageMap &x,const PackageMap &y)
{return x.BinCacheDB < y.BinCacheDB;};
};
+
+ struct SrcDBCompare : public binary_function<PackageMap,PackageMap,bool>
+ {
+ inline bool operator() (const PackageMap &x,const PackageMap &y)
+ {return x.SrcCacheDB < y.SrcCacheDB;};
+ };
void GetGeneral(Configuration &Setup,Configuration &Block);
bool GenPackages(Configuration &Setup,struct CacheDB::Stats &Stats);
vector<PackageMap>::iterator End,
unsigned long &Left);
- PackageMap() : DeLinkLimit(0), Permissions(1), ContentsDone(false),
- PkgDone(false), SrcDone(false), ContentsMTime(0) {};
+ PackageMap() : LongDesc(true), TransWriter(NULL), DeLinkLimit(0), Permissions(1),
+ ContentsDone(false), PkgDone(false), SrcDone(false),
+ ContentsMTime(0) {};
};
/*}}}*/
Setup.Find("Default::Packages::Extensions",".deb").c_str());
Permissions = Setup.FindI("Default::FileMode",0644);
-
+
if (FLFile.empty() == false)
FLFile = flCombine(Setup.Find("Dir::FileListDir"),FLFile);
Packages.DirStrip = ArchiveDir;
Packages.InternalPrefix = flCombine(ArchiveDir,InternalPrefix);
+ Packages.TransWriter = TransWriter;
+ Packages.LongDescription = LongDesc;
+
Packages.Stats.DeLinkBytes = Stats.DeLinkBytes;
Packages.DeLinkLimit = DeLinkLimit;
Packages.Output = 0; // Just in case
// Finish compressing
- unsigned long Size;
+ unsigned long long Size;
if (Comp.Finalize(Size) == false)
{
c0out << endl;
gettimeofday(&NewTime,0);
double Delta = NewTime.tv_sec - StartTime.tv_sec +
(NewTime.tv_usec - StartTime.tv_usec)/1000000.0;
-
+
c0out << Packages.Stats.Packages << " files " <<
/* SizeToStr(Packages.Stats.MD5Bytes) << "B/" << */
SizeToStr(Packages.Stats.Bytes) << "B " <<
TimeToStr((long)Delta) << endl;
+
+ if(_config->FindB("APT::FTPArchive::ShowCacheMisses", false) == true)
+ c0out << " Misses in Cache: " << Packages.Stats.Misses<< endl;
Stats.Add(Packages.Stats);
Stats.DeLinkBytes = Packages.Stats.DeLinkBytes;
SrcDone = true;
// Create a package writer object.
- SourcesWriter Sources(flCombine(OverrideDir,BinOverride),
+ SourcesWriter Sources(flCombine(CacheDir, SrcCacheDB),
+ flCombine(OverrideDir,BinOverride),
flCombine(OverrideDir,SrcOverride),
flCombine(OverrideDir,SrcExtraOverride));
if (SrcExt.empty() == false && Sources.SetExts(SrcExt) == false)
Sources.Output = 0; // Just in case
// Finish compressing
- unsigned long Size;
+ unsigned long long Size;
if (Comp.Finalize(Size) == false)
{
c0out << endl;
c0out << Sources.Stats.Packages << " pkgs in " <<
TimeToStr((long)Delta) << endl;
+ if(_config->FindB("APT::FTPArchive::ShowCacheMisses", false) == true)
+ c0out << " Misses in Cache: " << Sources.Stats.Misses << endl;
+
Stats.Add(Sources.Stats);
Stats.DeLinkBytes = Sources.Stats.DeLinkBytes;
if (_error->PendingError() == true)
return false;
- unsigned long Size = Head.Size();
+ unsigned long long Size = Head.Size();
unsigned char Buf[4096];
while (Size != 0)
{
- unsigned long ToRead = Size;
+ unsigned long long ToRead = Size;
if (Size > sizeof(Buf))
ToRead = sizeof(Buf);
files associated with this contents file into one great big honking
memory structure, then dump the sorted version */
c0out << ' ' << this->Contents << ":" << flush;
- for (vector<PackageMap>::iterator I = Begin; I != End; I++)
+ for (vector<PackageMap>::iterator I = Begin; I != End; ++I)
{
if (I->Contents != this->Contents)
continue;
Contents.Finish();
// Finish compressing
- unsigned long Size;
+ unsigned long long Size;
if (Comp.Finalize(Size) == false || _error->PendingError() == true)
{
c0out << endl;
double Delta = NewTime.tv_sec - StartTime.tv_sec +
(NewTime.tv_usec - StartTime.tv_usec)/1000000.0;
+ if(_config->FindB("APT::FTPArchive::ShowCacheMisses", false) == true)
+ c0out << " Misses in Cache: " << Contents.Stats.Misses<< endl;
+
c0out << Contents.Stats.Packages << " files " <<
SizeToStr(Contents.Stats.Bytes) << "B " <<
TimeToStr((long)Delta) << endl;
// ---------------------------------------------------------------------
/* This populates the PkgList with all the possible permutations of the
section/arch lists. */
-void LoadTree(vector<PackageMap> &PkgList,Configuration &Setup)
+static void LoadTree(vector<PackageMap> &PkgList,Configuration &Setup)
{
// Load the defaults
string DDir = Setup.Find("TreeDefault::Directory",
"$(DIST)/$(SECTION)/source/");
string DPkg = Setup.Find("TreeDefault::Packages",
"$(DIST)/$(SECTION)/binary-$(ARCH)/Packages");
+ string DTrans = Setup.Find("TreeDefault::Translation",
+ "$(DIST)/$(SECTION)/i18n/Translation-en");
string DIPrfx = Setup.Find("TreeDefault::InternalPrefix",
"$(DIST)/$(SECTION)/");
string DContents = Setup.Find("TreeDefault::Contents",
- "$(DIST)/Contents-$(ARCH)");
+ "$(DIST)/$(SECTION)/Contents-$(ARCH)");
string DContentsH = Setup.Find("TreeDefault::Contents::Header","");
string DBCache = Setup.Find("TreeDefault::BinCacheDB",
"packages-$(ARCH).db");
+ string SrcDBCache = Setup.Find("TreeDefault::SrcCacheDB",
+ "sources-$(SECTION).db");
string DSources = Setup.Find("TreeDefault::Sources",
"$(DIST)/$(SECTION)/source/Sources");
string DFLFile = Setup.Find("TreeDefault::FileList", "");
string DSFLFile = Setup.Find("TreeDefault::SourceFileList", "");
+ mode_t const Permissions = Setup.FindI("Default::FileMode",0644);
+
+ bool const LongDescription = Setup.FindB("Default::LongDescription",
+ _config->FindB("APT::FTPArchive::LongDescription", true));
+ string const TranslationCompress = Setup.Find("Default::Translation::Compress",". gzip").c_str();
+
// Process 'tree' type sections
const Configuration::Item *Top = Setup.Tree("tree");
for (Top = (Top == 0?0:Top->Child); Top != 0;)
string Section;
while (ParseQuoteWord(Sections,Section) == true)
{
- string Tmp2 = Block.Find("Architectures");
string Arch;
+ struct SubstVar const Vars[] = {{"$(DIST)",&Dist},
+ {"$(SECTION)",&Section},
+ {"$(ARCH)",&Arch},
+ {NULL, NULL}};
+ mode_t const Perms = Block.FindI("FileMode", Permissions);
+ bool const LongDesc = Block.FindB("LongDescription", LongDescription);
+ TranslationWriter *TransWriter;
+ if (DTrans.empty() == false && LongDesc == false)
+ {
+ string const TranslationFile = flCombine(Setup.FindDir("Dir::ArchiveDir"),
+ SubstVar(Block.Find("Translation", DTrans.c_str()), Vars));
+ string const TransCompress = Block.Find("Translation::Compress", TranslationCompress);
+ TransWriter = new TranslationWriter(TranslationFile, TransCompress, Perms);
+ }
+ else
+ TransWriter = NULL;
+
+ string const Tmp2 = Block.Find("Architectures");
const char *Archs = Tmp2.c_str();
while (ParseQuoteWord(Archs,Arch) == true)
{
- struct SubstVar Vars[] = {{"$(DIST)",&Dist},
- {"$(SECTION)",&Section},
- {"$(ARCH)",&Arch},
- {}};
PackageMap Itm;
-
+ Itm.Permissions = Perms;
Itm.BinOverride = SubstVar(Block.Find("BinOverride"),Vars);
Itm.InternalPrefix = SubstVar(Block.Find("InternalPrefix",DIPrfx.c_str()),Vars);
Itm.Tag = SubstVar("$(DIST)/$(SECTION)/source",Vars);
Itm.FLFile = SubstVar(Block.Find("SourceFileList",DSFLFile.c_str()),Vars);
Itm.SrcExtraOverride = SubstVar(Block.Find("SrcExtraOverride"),Vars);
+ Itm.SrcCacheDB = SubstVar(Block.Find("SrcCacheDB",SrcDBCache.c_str()),Vars);
}
else
{
Itm.PkgFile = SubstVar(Block.Find("Packages",DPkg.c_str()),Vars);
Itm.Tag = SubstVar("$(DIST)/$(SECTION)/$(ARCH)",Vars);
Itm.Arch = Arch;
+ Itm.LongDesc = LongDesc;
+ if (TransWriter != NULL)
+ {
+ TransWriter->IncreaseRefCounter();
+ Itm.TransWriter = TransWriter;
+ }
Itm.Contents = SubstVar(Block.Find("Contents",DContents.c_str()),Vars);
Itm.ContentsHead = SubstVar(Block.Find("Contents::Header",DContentsH.c_str()),Vars);
Itm.FLFile = SubstVar(Block.Find("FileList",DFLFile.c_str()),Vars);
Itm.GetGeneral(Setup,Block);
PkgList.push_back(Itm);
}
+ // we didn't use this TransWriter, so we can release it
+ if (TransWriter != NULL && TransWriter->GetRefCounter() == 0)
+ delete TransWriter;
}
Top = Top->Next;
// LoadBinDir - Load a 'bindirectory' section from the Generate Config /*{{{*/
// ---------------------------------------------------------------------
/* */
-void LoadBinDir(vector<PackageMap> &PkgList,Configuration &Setup)
+static void LoadBinDir(vector<PackageMap> &PkgList,Configuration &Setup)
{
+ mode_t const Permissions = Setup.FindI("Default::FileMode",0644);
+
// Process 'bindirectory' type sections
const Configuration::Item *Top = Setup.Tree("bindirectory");
for (Top = (Top == 0?0:Top->Child); Top != 0;)
Itm.PkgFile = Block.Find("Packages");
Itm.SrcFile = Block.Find("Sources");
Itm.BinCacheDB = Block.Find("BinCacheDB");
+ Itm.SrcCacheDB = Block.Find("SrcCacheDB");
Itm.BinOverride = Block.Find("BinOverride");
Itm.ExtraOverride = Block.Find("ExtraOverride");
Itm.SrcExtraOverride = Block.Find("SrcExtraOverride");
Itm.InternalPrefix = Block.Find("InternalPrefix",Top->Tag.c_str());
Itm.Contents = Block.Find("Contents");
Itm.ContentsHead = Block.Find("Contents::Header");
+ Itm.Permissions = Block.FindI("FileMode", Permissions);
Itm.GetGeneral(Setup,Block);
PkgList.push_back(Itm);
// ShowHelp - Show the help text /*{{{*/
// ---------------------------------------------------------------------
/* */
-bool ShowHelp(CommandLine &CmdL)
+static bool ShowHelp(CommandLine &)
{
- ioprintf(cout,_("%s %s for %s compiled on %s %s\n"),PACKAGE,VERSION,
+ ioprintf(cout,_("%s %s for %s compiled on %s %s\n"),PACKAGE,PACKAGE_VERSION,
COMMON_ARCH,__DATE__,__TIME__);
if (_config->FindB("version") == true)
return true;
// SimpleGenPackages - Generate a Packages file for a directory tree /*{{{*/
// ---------------------------------------------------------------------
/* This emulates dpkg-scanpackages's command line interface. 'mostly' */
-bool SimpleGenPackages(CommandLine &CmdL)
+static bool SimpleGenPackages(CommandLine &CmdL)
{
if (CmdL.FileSize() < 2)
return ShowHelp(CmdL);
if (Packages.RecursiveScan(CmdL.FileList[1]) == false)
return false;
+ // Give some stats if asked for
+ if(_config->FindB("APT::FTPArchive::ShowCacheMisses", false) == true)
+ c0out << " Misses in Cache: " << Packages.Stats.Misses<< endl;
+
return true;
}
/*}}}*/
// SimpleGenContents - Generate a Contents listing /*{{{*/
// ---------------------------------------------------------------------
/* */
-bool SimpleGenContents(CommandLine &CmdL)
+static bool SimpleGenContents(CommandLine &CmdL)
{
if (CmdL.FileSize() < 2)
return ShowHelp(CmdL);
// SimpleGenSources - Generate a Sources file for a directory tree /*{{{*/
// ---------------------------------------------------------------------
/* This emulates dpkg-scanpackages's command line interface. 'mostly' */
-bool SimpleGenSources(CommandLine &CmdL)
+static bool SimpleGenSources(CommandLine &CmdL)
{
if (CmdL.FileSize() < 2)
return ShowHelp(CmdL);
SOverride.c_str());
// Create a package writer object.
- SourcesWriter Sources(Override,SOverride);
+ SourcesWriter Sources(_config->Find("APT::FTPArchive::DB"),Override,SOverride);
if (_error->PendingError() == true)
return false;
if (Sources.RecursiveScan(CmdL.FileList[1]) == false)
return false;
+ // Give some stats if asked for
+ if(_config->FindB("APT::FTPArchive::ShowCacheMisses", false) == true)
+ c0out << " Misses in Cache: " << Sources.Stats.Misses<< endl;
+
return true;
}
/*}}}*/
// SimpleGenRelease - Generate a Release file for a directory tree /*{{{*/
// ---------------------------------------------------------------------
-bool SimpleGenRelease(CommandLine &CmdL)
+static bool SimpleGenRelease(CommandLine &CmdL)
{
if (CmdL.FileSize() < 2)
return ShowHelp(CmdL);
}
/*}}}*/
-// Generate - Full generate, using a config file /*{{{*/
+// DoGeneratePackagesAndSources - Helper for Generate /*{{{*/
// ---------------------------------------------------------------------
-/* */
-bool Generate(CommandLine &CmdL)
+static bool DoGeneratePackagesAndSources(Configuration &Setup,
+ vector<PackageMap> &PkgList,
+ struct CacheDB::Stats &SrcStats,
+ struct CacheDB::Stats &Stats,
+ CommandLine &CmdL)
{
- struct CacheDB::Stats SrcStats;
- if (CmdL.FileSize() < 2)
- return ShowHelp(CmdL);
-
- struct timeval StartTime;
- gettimeofday(&StartTime,0);
- struct CacheDB::Stats Stats;
-
- // Read the configuration file.
- Configuration Setup;
- if (ReadConfigFile(Setup,CmdL.FileList[1],true) == false)
- return false;
-
- vector<PackageMap> PkgList;
- LoadTree(PkgList,Setup);
- LoadBinDir(PkgList,Setup);
-
- // Sort by cache DB to improve IO locality.
- stable_sort(PkgList.begin(),PkgList.end(),PackageMap::DBCompare());
-
- // Generate packages
if (CmdL.FileSize() <= 2)
{
- for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); I++)
+ for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); ++I)
if (I->GenPackages(Setup,Stats) == false)
_error->DumpErrors();
- for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); I++)
+ for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); ++I)
if (I->GenSources(Setup,SrcStats) == false)
_error->DumpErrors();
}
// Make a choice list out of the package list..
RxChoiceList *List = new RxChoiceList[2*PkgList.size()+1];
RxChoiceList *End = List;
- for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); I++)
+ for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); ++I)
{
End->UserData = &(*I);
End->Str = I->BaseDir.c_str();
delete [] List;
}
-
- if (_config->FindB("APT::FTPArchive::Contents",true) == false)
- return true;
-
+
+ // close the Translation master files
+ for (vector<PackageMap>::reverse_iterator I = PkgList.rbegin(); I != PkgList.rend(); ++I)
+ if (I->TransWriter != NULL && I->TransWriter->DecreaseRefCounter() == 0)
+ delete I->TransWriter;
+
+ return true;
+}
+
+ /*}}}*/
+// DoGenerateContents - Helper for Generate to generate the Contents /*{{{*/
+// ---------------------------------------------------------------------
+static bool DoGenerateContents(Configuration &Setup,
+ vector<PackageMap> &PkgList,
+ CommandLine &CmdL)
+{
c1out << "Packages done, Starting contents." << endl;
// Sort the contents file list by date
string ArchiveDir = Setup.FindDir("Dir::ArchiveDir");
- for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); I++)
+ for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); ++I)
{
struct stat A;
if (MultiCompress::GetStat(flCombine(ArchiveDir,I->Contents),
hashes of the .debs this means they have not changed either so the
contents must be up to date. */
unsigned long MaxContentsChange = Setup.FindI("Default::MaxContentsChange",UINT_MAX)*1024;
- for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); I++)
+ for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); ++I)
{
- // This record is not relevent
+ // This record is not relevant
if (I->ContentsDone == true ||
I->Contents.empty() == true)
continue;
break;
}
}
+
+ return true;
+}
+
+ /*}}}*/
+// Generate - Full generate, using a config file /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+static bool Generate(CommandLine &CmdL)
+{
+ struct CacheDB::Stats SrcStats;
+ if (CmdL.FileSize() < 2)
+ return ShowHelp(CmdL);
+
+ struct timeval StartTime;
+ gettimeofday(&StartTime,0);
+ struct CacheDB::Stats Stats;
+ // Read the configuration file.
+ Configuration Setup;
+ if (ReadConfigFile(Setup,CmdL.FileList[1],true) == false)
+ return false;
+
+ vector<PackageMap> PkgList;
+ LoadTree(PkgList,Setup);
+ LoadBinDir(PkgList,Setup);
+
+ // Sort by cache DB to improve IO locality.
+ stable_sort(PkgList.begin(),PkgList.end(),PackageMap::DBCompare());
+ stable_sort(PkgList.begin(),PkgList.end(),PackageMap::SrcDBCompare());
+
+ // Generate packages
+ if (_config->FindB("APT::FTPArchive::ContentsOnly", false) == false)
+ {
+ if(DoGeneratePackagesAndSources(Setup, PkgList, SrcStats, Stats, CmdL) == false)
+ return false;
+ } else {
+ c1out << "Skipping Packages/Sources generation" << endl;
+ }
+
+ // do Contents if needed
+ if (_config->FindB("APT::FTPArchive::Contents", true) == true)
+ if (DoGenerateContents(Setup, PkgList, CmdL) == false)
+ return false;
+
struct timeval NewTime;
- gettimeofday(&NewTime,0);
- double Delta = NewTime.tv_sec - StartTime.tv_sec +
+ gettimeofday(&NewTime,0);
+ double Delta = NewTime.tv_sec - StartTime.tv_sec +
(NewTime.tv_usec - StartTime.tv_usec)/1000000.0;
- c1out << "Done. " << SizeToStr(Stats.Bytes) << "B in " << Stats.Packages
+ c1out << "Done. " << SizeToStr(Stats.Bytes) << "B in " << Stats.Packages
<< " archives. Took " << TimeToStr((long)Delta) << endl;
-
+
return true;
}
- /*}}}*/
+
+ /*}}}*/
// Clean - Clean out the databases /*{{{*/
// ---------------------------------------------------------------------
/* */
-bool Clean(CommandLine &CmdL)
+static bool Clean(CommandLine &CmdL)
{
if (CmdL.FileSize() != 2)
return ShowHelp(CmdL);
// Sort by cache DB to improve IO locality.
stable_sort(PkgList.begin(),PkgList.end(),PackageMap::DBCompare());
+ stable_sort(PkgList.begin(),PkgList.end(),PackageMap::SrcDBCompare());
string CacheDir = Setup.FindDir("Dir::CacheDir");
for (vector<PackageMap>::iterator I = PkgList.begin(); I != PkgList.end(); )
{
- c0out << I->BinCacheDB << endl;
+ if(I->BinCacheDB != "")
+ c0out << I->BinCacheDB << endl;
+ if(I->SrcCacheDB != "")
+ c0out << I->SrcCacheDB << endl;
CacheDB DB(flCombine(CacheDir,I->BinCacheDB));
+ CacheDB DB_SRC(flCombine(CacheDir,I->SrcCacheDB));
if (DB.Clean() == false)
_error->DumpErrors();
+ if (DB_SRC.Clean() == false)
+ _error->DumpErrors();
string CacheDB = I->BinCacheDB;
- for (; I != PkgList.end() && I->BinCacheDB == CacheDB; I++);
+ string SrcCacheDB = I->SrcCacheDB;
+ while(I != PkgList.end() &&
+ I->BinCacheDB == CacheDB &&
+ I->SrcCacheDB == SrcCacheDB)
+ ++I;
+
}
-
+
+
return true;
}
/*}}}*/
CommandLine::Args Args[] = {
{'h',"help","help",0},
{0,"md5","APT::FTPArchive::MD5",0},
+ {0,"sha1","APT::FTPArchive::SHA1",0},
+ {0,"sha256","APT::FTPArchive::SHA256",0},
{'v',"version","version",0},
{'d',"db","APT::FTPArchive::DB",CommandLine::HasArg},
{'s',"source-override","APT::FTPArchive::SourceOverride",CommandLine::HasArg},